From 7996e50a455ca7247cc74cc6a26ab942fe34b8ff Mon Sep 17 00:00:00 2001 From: BastLast Date: Thu, 28 Nov 2024 00:26:04 +0100 Subject: [PATCH 01/17] wip unlock command #2273 --- Discord/src/commands/player/UnlockCommand.ts | 166 ++++++++++++++++++ .../packets/commands/CommandUnlockPacket.ts | 30 ++++ .../interaction/ReactionCollectorUnlock.ts | 34 ++++ 3 files changed, 230 insertions(+) create mode 100644 Discord/src/commands/player/UnlockCommand.ts create mode 100644 Lib/src/packets/commands/CommandUnlockPacket.ts create mode 100644 Lib/src/packets/interaction/ReactionCollectorUnlock.ts diff --git a/Discord/src/commands/player/UnlockCommand.ts b/Discord/src/commands/player/UnlockCommand.ts new file mode 100644 index 000000000..3cb0f69e9 --- /dev/null +++ b/Discord/src/commands/player/UnlockCommand.ts @@ -0,0 +1,166 @@ +import {ICommand} from "../ICommand"; +import {makePacket, PacketContext} from "../../../../Lib/src/packets/DraftBotPacket"; +import {DraftbotInteraction} from "../../messages/DraftbotInteraction"; +import i18n from "../../translations/i18n"; +import {SlashCommandBuilderGenerator} from "../SlashCommandBuilderGenerator"; +import {SlashCommandBuilder} from "@discordjs/builders"; +import {DiscordCache} from "../../bot/DiscordCache"; +import {KeycloakUser} from "../../../../Lib/src/keycloak/KeycloakUser"; +import { + CommandUnlockAcceptPacketRes, + CommandUnlockPacketReq, + CommandUnlockPacketRes, + CommandUnlockRefusePacketRes +} from "../../../../Lib/src/packets/commands/CommandUnlockPacket"; +import {ReactionCollectorCreationPacket} from "../../../../Lib/src/packets/interaction/ReactionCollectorPacket"; +import {DraftBotEmbed} from "../../messages/DraftBotEmbed"; +import {DiscordCollectorUtils} from "../../utils/DiscordCollectorUtils"; +import {ReactionCollectorUnlockData} from "../../../../Lib/src/packets/interaction/ReactionCollectorUnlock"; +import {PacketUtils} from "../../utils/PacketUtils"; +import {CommandProfilePacketReq} from "../../../../Lib/src/packets/commands/CommandProfilePacket"; +import {sendErrorMessage, SendManner} from "../../utils/ErrorUtils"; +import {KeycloakUtils} from "../../../../Lib/src/keycloak/KeycloakUtils"; +import {keycloakConfig} from "../../bot/DraftBotShard"; +import {UnlockConstants} from "../../../../Lib/src/constants/UnlockConstants"; + +/** + * Free a player from the prison + */ +async function getPacket(interaction: DraftbotInteraction, user: KeycloakUser): Promise { + const askedPlayer = await PacketUtils.prepareAskedPlayer(interaction, user); + if (!askedPlayer) { + return null; + } + return makePacket(CommandUnlockPacketReq, {keycloakId: user.id, askedPlayer}); +} + +/** + * Handle the answer from the server after an unlock command request + * This packet is only sent if the unlocking cannot be done for some reason + * @param packet + * @param context + */ +export async function handleCommandUnlockPacketRes(packet: CommandUnlockPacketRes, context: PacketContext): Promise { + const interaction = DiscordCache.getInteraction(context.discord!.interaction); + if (interaction) { + if (!packet.foundPlayer) { + await sendErrorMessage( + interaction.user, + interaction, + i18n.t("commands:unlock.noPlayer", {lng: interaction.userLanguage}), + {sendManner: SendManner.REPLY} + ); + return; + } + if (packet.money < UnlockConstants.PRICE_FOR_UNLOCK) { + await sendErrorMessage( + interaction.user, + interaction, + i18n.t("commands:unlock.notEnoughMoney", { + lng: interaction.userLanguage, + missingMoney: UnlockConstants.PRICE_FOR_UNLOCK - packet.money + }), + {sendManner: SendManner.REPLY} + ); + return; + } + if (packet.himself) { + await sendErrorMessage( + interaction.user, + interaction, + i18n.t("commands:unlock.himself", {lng: interaction.userLanguage}), + {sendManner: SendManner.REPLY} + ); + } + } +} + +/** + * Create a collector to confirm the unlocking + * @param packet + * @param context + */ +export async function createUnlockCollector(packet: ReactionCollectorCreationPacket, context: PacketContext): Promise { + const interaction = DiscordCache.getInteraction(context.discord!.interaction)!; + await interaction.deferReply(); + const data = packet.data.data as ReactionCollectorUnlockData; + const unlockedPlayer = (await KeycloakUtils.getUserByKeycloakId(keycloakConfig, data.unlockedKeycloakId))!; + const embed = new DraftBotEmbed().formatAuthor(i18n.t("commands:unlock.title", { + lng: interaction.userLanguage, + pseudo: interaction.user.displayName + }), interaction.user) + .setDescription( + i18n.t("commands:unlock.confirmDesc", { + lng: interaction.userLanguage, + kickedPseudo: unlockedPlayer.attributes.gameUsername + }) + ); + + await DiscordCollectorUtils.createAcceptRefuseCollector(interaction, embed, packet, context); +} + +/** + * Handle the server response after an unlock command has been canceled + * @param packet + * @param context + */ +export async function handleCommandUnlockRefusePacketRes(packet: CommandUnlockRefusePacketRes, context: PacketContext): Promise { + const originalInteraction = DiscordCache.getInteraction(context.discord!.interaction!); + const buttonInteraction = DiscordCache.getButtonInteraction(context.discord!.buttonInteraction!); + if (buttonInteraction && originalInteraction) { + await buttonInteraction.editReply({ + embeds: [ + new DraftBotEmbed().formatAuthor(i18n.t("commands:unlock.canceledTitle", { + lng: originalInteraction.userLanguage, + pseudo: originalInteraction.user.displayName + }), originalInteraction.user) + .setDescription( + i18n.t("commands:unlock.canceledDesc", { + lng: originalInteraction.userLanguage + }) + ) + .setErrorColor() + ] + }); + } +} + +/** + * Handle the response of the server after a guild kick, + * this packet is only sent if the kick is accepted + * @param packet + * @param context + */ +export async function handleCommandUnlockAcceptPacketRes(packet: CommandUnlockAcceptPacketRes, context: PacketContext): Promise { + const originalInteraction = DiscordCache.getInteraction(context.discord!.interaction!); + const buttonInteraction = DiscordCache.getButtonInteraction(context.discord!.buttonInteraction!); + const unlockedPlayer = (await KeycloakUtils.getUserByKeycloakId(keycloakConfig, packet.unlockedKeycloakId!))!; + if (buttonInteraction && originalInteraction) { + await buttonInteraction.editReply({ + embeds: [ + new DraftBotEmbed().formatAuthor(i18n.t("commands:unlock.title", { + lng: originalInteraction.userLanguage, + pseudo: originalInteraction.user.displayName + }), originalInteraction.user) + .setDescription( + i18n.t("commands:unlock.acceptedDesc", { + lng: originalInteraction.userLanguage, + kickedPseudo: unlockedPlayer.attributes.gameUsername + }) + ) + ] + }); + } +} + +export const commandInfo: ICommand = { + slashCommandBuilder: SlashCommandBuilderGenerator.generateBaseCommand("Unlock") + .addUserOption(option => + SlashCommandBuilderGenerator.generateOption("unlock", "user", option) + .setRequired(false)) + .addIntegerOption(option => + SlashCommandBuilderGenerator.generateOption("unlock", "rank", option) + .setRequired(false)) as SlashCommandBuilder, + getPacket, + mainGuildCommand: false +}; \ No newline at end of file diff --git a/Lib/src/packets/commands/CommandUnlockPacket.ts b/Lib/src/packets/commands/CommandUnlockPacket.ts new file mode 100644 index 000000000..761397355 --- /dev/null +++ b/Lib/src/packets/commands/CommandUnlockPacket.ts @@ -0,0 +1,30 @@ +import {DraftBotPacket, PacketDirection, sendablePacket} from "../DraftBotPacket"; + +@sendablePacket(PacketDirection.FRONT_TO_BACK) +export class CommandUnlockPacketReq extends DraftBotPacket { + keycloakId!: string; + + askedPlayer!: { + rank?: number, + keycloakId?: string + }; +} + +@sendablePacket(PacketDirection.BACK_TO_FRONT) +export class CommandUnlockPacketRes extends DraftBotPacket { + foundPlayer!: boolean; + + money!: number; + + himself!: boolean; +} + +@sendablePacket(PacketDirection.BACK_TO_FRONT) +export class CommandUnlockAcceptPacketRes extends DraftBotPacket { + unlockedKeycloakId!: string; +} + +@sendablePacket(PacketDirection.BACK_TO_FRONT) +export class CommandUnlockRefusePacketRes extends DraftBotPacket { + +} \ No newline at end of file diff --git a/Lib/src/packets/interaction/ReactionCollectorUnlock.ts b/Lib/src/packets/interaction/ReactionCollectorUnlock.ts new file mode 100644 index 000000000..88660c955 --- /dev/null +++ b/Lib/src/packets/interaction/ReactionCollectorUnlock.ts @@ -0,0 +1,34 @@ +import { + ReactionCollector, + ReactionCollectorAcceptReaction, + ReactionCollectorCreationPacket, + ReactionCollectorData, + ReactionCollectorRefuseReaction +} from "./ReactionCollectorPacket"; + +export class ReactionCollectorUnlockData extends ReactionCollectorData { + unlockedKeycloakId!: string; +} + +export class ReactionCollectorUnlock extends ReactionCollector { + private readonly unlockedKeycloakId: string; + + constructor(unlockedKeycloakId: string) { + super(); + this.unlockedKeycloakId = unlockedKeycloakId; + } + + creationPacket(id: string, endTime: number): ReactionCollectorCreationPacket { + return { + id, + endTime, + reactions: [ + this.buildReaction(ReactionCollectorAcceptReaction, {}), + this.buildReaction(ReactionCollectorRefuseReaction, {}) + ], + data: this.buildData(ReactionCollectorUnlockData, { + unlockedKeycloakId: this.unlockedKeycloakId + }) + }; + } +} \ No newline at end of file From ff5b4e3102e4bd3a126063cd45e4815bd31e0c3d Mon Sep 17 00:00:00 2001 From: BastLast Date: Thu, 28 Nov 2024 00:31:09 +0100 Subject: [PATCH 02/17] error cleanup #2273 --- Discord/src/commands/player/UnlockCommand.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Discord/src/commands/player/UnlockCommand.ts b/Discord/src/commands/player/UnlockCommand.ts index 3cb0f69e9..6b425bfbb 100644 --- a/Discord/src/commands/player/UnlockCommand.ts +++ b/Discord/src/commands/player/UnlockCommand.ts @@ -47,7 +47,7 @@ export async function handleCommandUnlockPacketRes(packet: CommandUnlockPacketRe await sendErrorMessage( interaction.user, interaction, - i18n.t("commands:unlock.noPlayer", {lng: interaction.userLanguage}), + i18n.t("error:playerDoesntExist", {lng: interaction.userLanguage}), {sendManner: SendManner.REPLY} ); return; @@ -56,9 +56,9 @@ export async function handleCommandUnlockPacketRes(packet: CommandUnlockPacketRe await sendErrorMessage( interaction.user, interaction, - i18n.t("commands:unlock.notEnoughMoney", { + i18n.t("error:notEnoughMoney", { lng: interaction.userLanguage, - missingMoney: UnlockConstants.PRICE_FOR_UNLOCK - packet.money + money: UnlockConstants.PRICE_FOR_UNLOCK - packet.money }), {sendManner: SendManner.REPLY} ); From 6788babc195ecd5311627397df13a942bfbb617c Mon Sep 17 00:00:00 2001 From: BastLast Date: Sun, 8 Dec 2024 22:57:08 +0100 Subject: [PATCH 03/17] fix emote + codestyle unlockcommand #2273 --- Discord/src/commands/player/UnlockCommand.ts | 137 +++++++++--------- Lang/de/advices.json | 2 +- Lang/de/commands.json | 14 +- Lang/de/error.json | 2 +- Lang/de/smallEvents.json | 2 +- Lang/en/advices.json | 2 +- Lang/en/commands.json | 14 +- Lang/en/error.json | 2 +- Lang/en/smallEvents.json | 2 +- Lang/es/advices.json | 2 +- Lang/es/commands.json | 14 +- Lang/es/error.json | 2 +- Lang/es/smallEvents.json | 2 +- Lang/fr/advices.json | 2 +- Lang/fr/commands.json | 14 +- Lang/fr/error.json | 2 +- Lang/fr/smallEvents.json | 2 +- Lang/it/advices.json | 2 +- Lang/it/commands.json | 14 +- Lang/it/error.json | 2 +- Lang/it/smallEvents.json | 2 +- Lang/pt/advices.json | 2 +- Lang/pt/commands.json | 14 +- Lang/pt/error.json | 2 +- Lang/pt/smallEvents.json | 2 +- .../packets/commands/CommandUnlockPacket.ts | 2 - 26 files changed, 128 insertions(+), 131 deletions(-) diff --git a/Discord/src/commands/player/UnlockCommand.ts b/Discord/src/commands/player/UnlockCommand.ts index 6b425bfbb..29eda22db 100644 --- a/Discord/src/commands/player/UnlockCommand.ts +++ b/Discord/src/commands/player/UnlockCommand.ts @@ -6,12 +6,7 @@ import {SlashCommandBuilderGenerator} from "../SlashCommandBuilderGenerator"; import {SlashCommandBuilder} from "@discordjs/builders"; import {DiscordCache} from "../../bot/DiscordCache"; import {KeycloakUser} from "../../../../Lib/src/keycloak/KeycloakUser"; -import { - CommandUnlockAcceptPacketRes, - CommandUnlockPacketReq, - CommandUnlockPacketRes, - CommandUnlockRefusePacketRes -} from "../../../../Lib/src/packets/commands/CommandUnlockPacket"; +import {CommandUnlockAcceptPacketRes, CommandUnlockPacketReq, CommandUnlockPacketRes, CommandUnlockRefusePacketRes} from "../../../../Lib/src/packets/commands/CommandUnlockPacket"; import {ReactionCollectorCreationPacket} from "../../../../Lib/src/packets/interaction/ReactionCollectorPacket"; import {DraftBotEmbed} from "../../messages/DraftBotEmbed"; import {DiscordCollectorUtils} from "../../utils/DiscordCollectorUtils"; @@ -31,7 +26,7 @@ async function getPacket(interaction: DraftbotInteraction, user: KeycloakUser): if (!askedPlayer) { return null; } - return makePacket(CommandUnlockPacketReq, {keycloakId: user.id, askedPlayer}); + return makePacket(CommandUnlockPacketReq, {askedPlayer}); } /** @@ -42,36 +37,37 @@ async function getPacket(interaction: DraftbotInteraction, user: KeycloakUser): */ export async function handleCommandUnlockPacketRes(packet: CommandUnlockPacketRes, context: PacketContext): Promise { const interaction = DiscordCache.getInteraction(context.discord!.interaction); - if (interaction) { - if (!packet.foundPlayer) { - await sendErrorMessage( - interaction.user, - interaction, - i18n.t("error:playerDoesntExist", {lng: interaction.userLanguage}), - {sendManner: SendManner.REPLY} - ); - return; - } - if (packet.money < UnlockConstants.PRICE_FOR_UNLOCK) { - await sendErrorMessage( - interaction.user, - interaction, - i18n.t("error:notEnoughMoney", { - lng: interaction.userLanguage, - money: UnlockConstants.PRICE_FOR_UNLOCK - packet.money - }), - {sendManner: SendManner.REPLY} - ); - return; - } - if (packet.himself) { - await sendErrorMessage( - interaction.user, - interaction, - i18n.t("commands:unlock.himself", {lng: interaction.userLanguage}), - {sendManner: SendManner.REPLY} - ); - } + if (!interaction) { + return; + } + if (!packet.foundPlayer) { + await sendErrorMessage( + interaction.user, + interaction, + i18n.t("error:playerDoesntExist", {lng: interaction.userLanguage}), + {sendManner: SendManner.REPLY} + ); + return; + } + if (packet.money < UnlockConstants.PRICE_FOR_UNLOCK) { + await sendErrorMessage( + interaction.user, + interaction, + i18n.t("error:notEnoughMoney", { + lng: interaction.userLanguage, + money: UnlockConstants.PRICE_FOR_UNLOCK - packet.money + }), + {sendManner: SendManner.REPLY} + ); + return; + } + if (packet.himself) { + await sendErrorMessage( + interaction.user, + interaction, + i18n.t("commands:unlock.himself", {lng: interaction.userLanguage}), + {sendManner: SendManner.REPLY} + ); } } @@ -106,23 +102,24 @@ export async function createUnlockCollector(packet: ReactionCollectorCreationPac */ export async function handleCommandUnlockRefusePacketRes(packet: CommandUnlockRefusePacketRes, context: PacketContext): Promise { const originalInteraction = DiscordCache.getInteraction(context.discord!.interaction!); - const buttonInteraction = DiscordCache.getButtonInteraction(context.discord!.buttonInteraction!); - if (buttonInteraction && originalInteraction) { - await buttonInteraction.editReply({ - embeds: [ - new DraftBotEmbed().formatAuthor(i18n.t("commands:unlock.canceledTitle", { - lng: originalInteraction.userLanguage, - pseudo: originalInteraction.user.displayName - }), originalInteraction.user) - .setDescription( - i18n.t("commands:unlock.canceledDesc", { - lng: originalInteraction.userLanguage - }) - ) - .setErrorColor() - ] - }); + if (!originalInteraction) { + return; } + const buttonInteraction = DiscordCache.getButtonInteraction(context.discord!.buttonInteraction!); + await buttonInteraction?.editReply({ + embeds: [ + new DraftBotEmbed().formatAuthor(i18n.t("commands:unlock.canceledTitle", { + lng: originalInteraction.userLanguage, + pseudo: originalInteraction.user.displayName + }), originalInteraction.user) + .setDescription( + i18n.t("commands:unlock.canceledDesc", { + lng: originalInteraction.userLanguage + }) + ) + .setErrorColor() + ] + }); } /** @@ -133,24 +130,26 @@ export async function handleCommandUnlockRefusePacketRes(packet: CommandUnlockRe */ export async function handleCommandUnlockAcceptPacketRes(packet: CommandUnlockAcceptPacketRes, context: PacketContext): Promise { const originalInteraction = DiscordCache.getInteraction(context.discord!.interaction!); + if (!originalInteraction) { + return; + } const buttonInteraction = DiscordCache.getButtonInteraction(context.discord!.buttonInteraction!); const unlockedPlayer = (await KeycloakUtils.getUserByKeycloakId(keycloakConfig, packet.unlockedKeycloakId!))!; - if (buttonInteraction && originalInteraction) { - await buttonInteraction.editReply({ - embeds: [ - new DraftBotEmbed().formatAuthor(i18n.t("commands:unlock.title", { - lng: originalInteraction.userLanguage, - pseudo: originalInteraction.user.displayName - }), originalInteraction.user) - .setDescription( - i18n.t("commands:unlock.acceptedDesc", { - lng: originalInteraction.userLanguage, - kickedPseudo: unlockedPlayer.attributes.gameUsername - }) - ) - ] - }); - } + await buttonInteraction?.editReply({ + embeds: [ + new DraftBotEmbed().formatAuthor(i18n.t("commands:unlock.title", { + lng: originalInteraction.userLanguage, + pseudo: originalInteraction.user.displayName + }), originalInteraction.user) + .setDescription( + i18n.t("commands:unlock.acceptedDesc", { + lng: originalInteraction.userLanguage, + kickedPseudo: unlockedPlayer.attributes.gameUsername + }) + ) + ] + }); + } export const commandInfo: ICommand = { diff --git a/Lang/de/advices.json b/Lang/de/advices.json index 959aae6ab..dc3178d6d 100644 --- a/Lang/de/advices.json +++ b/Lang/de/advices.json @@ -53,7 +53,7 @@ "Geld beiseite zu legen ist sinnvoll, um sich selbst behandeln zu können.", "Jede Woche wird eine Rangliste erstellt, um den Spieler der Woche zu ermitteln, der die meisten Punkte gewonnen hat. Um diese Rangliste einzusehen, verwenden Sie den Befehl {command:top score} und geben Sie die Option `Dauer` an.", "Geld ist eine der wichtigsten Ressourcen im Spiel. Verdienen Sie es durch Berichte ({command:report}), Items mit täglichen Effekten ({command:dailybonus}) oder tägliche Gildenbelohnungen ({command:guilddailybonus}).", - "Haben Sie zu wenig Lebenspunkte? Bevor du die Pflege für 3000 💰 kaufst, überprüfe, ob es im Laden nicht einen profitableren Trank gibt!", + "Haben Sie zu wenig Lebenspunkte? Bevor du die Pflege für 3000 {emote:unitValues.money} kaufst, überprüfe, ob es im Laden nicht einen profitableren Trank gibt!", "Die im Laden verkauften Tränke sind oft zu sehr attraktiven Preisen erhältlich.", "Um der Erste in der Wochenwertung zu sein und ein Abzeichen zu gewinnen, berichten Sie fleißig und scheuen Sie keine Kämpfe.", "Die Gesamtwertung ist mit dem Befehl {command:top score}verfügbar.", diff --git a/Lang/de/commands.json b/Lang/de/commands.json index de24664fe..f024c52c6 100644 --- a/Lang/de/commands.json +++ b/Lang/de/commands.json @@ -196,7 +196,7 @@ "description": "Ändern Sie den Spitznamen Ihres Vertrauten. Wenn kein Name angegeben wird, wird der aktuelle Name gelöscht." }, "PET_SELL": { - "description": "Verkauft einen Begleiter. Die folgenden Bedingungen gelten: \n -Der Verkaufspreis muss höher sein als `{{petSellMinPrice}}💰` und kleiner als '{{petSellMaxPrice}}💰`. \n-Der Verkäufer wird bei der Transaktion kein Geld verdienen, sondern von der Gilde-Erfahrung. \n-Der Verkäufer und der Käufer können nicht zu derselben Gilde gehören." + "description": "Verkauft einen Begleiter. Die folgenden Bedingungen gelten: \n -Der Verkaufspreis muss höher sein als `{{petSellMinPrice}}{emote:unitValues.money}` und kleiner als '{{petSellMaxPrice}}{emote:unitValues.money}`. \n-Der Verkäufer wird bei der Transaktion kein Geld verdienen, sondern von der Gilde-Erfahrung. \n-Der Verkäufer und der Käufer können nicht zu derselben Gilde gehören." }, "PET_TRADE": { "description": "Stellt einen Austausch Ihrer Tiere mit der genannten Person bereit." @@ -211,7 +211,7 @@ "description": "Diese Funktion wurde aus dem Spiel entfernt, als eine Aktualisierung der von Discord angebotenen Funktionen." }, "PROFILE": { - "description": "Zeigt Informationen über deinen Charakter an:\n\n😃 Gesundheitszustand | Nickname | Level\n\n឵឵Informationen:\n❤️ Leben | ⭐ XP | 💰 Geld\n\nStatistiken :\n⚡ Energie | 🗡️ Angriff | 🛡️ Verteidigung | 🚀 Geschwindigkeit | 🌬️ Atem | 🫁 Erholung\n\nAufgaben:\n💎 Gemmen | 📖 Kampagnenfortschritt %\n\nRangliste und Punktzahl:\n🏆 Rangliste | 🏅 Punktzahl\n\nKlasse:\nSiehe {command:classes}\n\nRuhm und Liga:\n✨ Ruhm | Siehe {{topGloryCommandMention}}\n\nGilde:\n🏟️ Gilde\n\nReiseziel:\nSiehe {{mapCommandMention}}\n\nVertraut:\nSiehe {{petCommandMention}}\n\n💡-Die Abzeichen werden in deinem Profil als Reaktion angezeigt." + "description": "Zeigt Informationen über deinen Charakter an:\n\n😃 Gesundheitszustand | Nickname | Level\n\n឵឵Informationen:\n❤️ Leben | ⭐ XP | {emote:unitValues.money} Geld\n\nStatistiken :\n⚡ Energie | 🗡️ Angriff | 🛡️ Verteidigung | 🚀 Geschwindigkeit | 🌬️ Atem | 🫁 Erholung\n\nAufgaben:\n💎 Gemmen | 📖 Kampagnenfortschritt %\n\nRangliste und Punktzahl:\n🏆 Rangliste | 🏅 Punktzahl\n\nKlasse:\nSiehe {command:classes}\n\nRuhm und Liga:\n✨ Ruhm | Siehe {{topGloryCommandMention}}\n\nGilde:\n🏟️ Gilde\n\nReiseziel:\nSiehe {{mapCommandMention}}\n\nVertraut:\nSiehe {{petCommandMention}}\n\n💡-Die Abzeichen werden in deinem Profil als Reaktion angezeigt." }, "RARITY": { "description": "Wählen Sie diese Option aus, um die Wahrscheinlichkeit eines item nach der Knappheit zu erkennen." @@ -511,15 +511,15 @@ "fullRegen": "💓 Sie wurden vollständig versorgt.", "alreadyHaveBadge": "Sie besitzen diesen Ausweis bereits.", "badgeBought": "Sie haben einen neuen Ausweis erhalten: {emote:badges.richPerson} !", - "notEnoughMoney": "Sie haben nicht genug Geld, um diesen Gegenstand zu kaufen! Es fehlt Ihnen `{{missingMoney}}💰`.", + "notEnoughMoney": "Sie haben nicht genug Geld, um diesen Gegenstand zu kaufen! Es fehlt Ihnen `{{missingMoney}}{emote:unitValues.money}`.", "boughtTooMuchDailyPotions": "Es gibt keinen Trank des Tages mehr, der zum Verkauf angeboten wird... Kommen Sie morgen wieder!", "title": "🛒 Anzeige des Magazins", - "currentMoney": "Sie haben `{{money}}💰`.", - "shopItemsDisplaySingle": "{{name}} | `{{price}}💰`", - "shopItemsDisplayMultiple": "**{{amount}}x** {{name}} | `{{price}}💰`", + "currentMoney": "Sie haben `{{money}}{emote:unitValues.money}`.", + "shopItemsDisplaySingle": "{{name}} | `{{price}}{emote:unitValues.money}`", + "shopItemsDisplayMultiple": "**{{amount}}x** {{name}} | `{{price}}{emote:unitValues.money}`", "shopSelectPlaceholder": "Wählen Sie einen Gegenstand zum Kauf aus", "buyCategorySlotSuccess": "Sie haben einen neuen Inventarplatz gekauft!", - "shopItemsSelectDescription": "{{price}}💰", + "shopItemsSelectDescription": "{{price}}{emote:unitValues.money}", "closeShopButton": "❌ Laden schließen", "shopConfirmationTitle": "{{pseudo}}Sie haben das folgende Produkt ausgewählt:", "shopConfirmationTitleMultiple": "{{pseudo}}Wählen Sie eine Menge für dieses Produkt:", diff --git a/Lang/de/error.json b/Lang/de/error.json index cf87b39ba..1d8c6b52d 100644 --- a/Lang/de/error.json +++ b/Lang/de/error.json @@ -59,7 +59,7 @@ "unexpectedError": "Es ist ein Fehler aufgetreten: (", "pleaseWaitForHeal": "Bitte warten Sie, bis die Heilung Ihrer Zustandsveränderung abgeschlossen ist, bevor Sie weiterspielen: {{time}}\n\n:information_source: Sie können den Befehl {command:shop} verwenden, um eine Heilung zu kaufen.", "pleaseWaitForHisHeal": "Bitte warten Sie bis zum Ende der Pflege seines veränderten Zustands: {{time}}", - "notEnoughMoney": "Sie haben nicht genug Geld, um diese Aktion durchzuführen. Es fehlt Ihnen {{money}}💰.", + "notEnoughMoney": "Sie haben nicht genug Geld, um diese Aktion durchzuführen. Es fehlt Ihnen {{money}}{emote:unitValues.money}.", "cooldownPetFree": "Sie können nur einen Begleiter pro Stunde befreien. Sie können einen weiteren befreien {{remainingTime}}.", "unknownPlayer": "Pseudo 404", "petNickNotValid": "Die Regeln für den Namen eines Vertrauten lauten wie folgt:\n$t(error:stringRules)", diff --git a/Lang/de/smallEvents.json b/Lang/de/smallEvents.json index 4c0d3e55a..10c0d4374 100644 --- a/Lang/de/smallEvents.json +++ b/Lang/de/smallEvents.json @@ -129,7 +129,7 @@ "end": "Ohne der Person weitere Beachtung zu schenken, setzen Sie Ihren Weg fort.", "rewardTypeText": { "xp": " Sie haben gewonnen **{{xpWon}}⭐**.", - "money": " Sie haben gewonnen **{{moneyWon}}💰**!", + "money": " Sie haben gewonnen **{{moneyWon}}{emote:unitValues.money}**!", "guildXp": " Deine Gilde gewinnt **{{guildXpWon}}⭐**.", "points": " Sie haben gewonnen **{{pointsWon}}🏅**." } diff --git a/Lang/en/advices.json b/Lang/en/advices.json index 748484de0..63d250ac8 100644 --- a/Lang/en/advices.json +++ b/Lang/en/advices.json @@ -53,7 +53,7 @@ "It's a good idea to keep some money aside so you can take care of yourself.", "Each week, a ranking is made to determine which player has earned the most points. To view this ranking, use the {command:top score} command and specify the `timing` option.", "Money is one of the game's most important resources, and you can earn it through reports ({command:report}), daily bonus items ({command:dailybonus}) or daily guild rewards ({command:guilddailybonus}).", - "Out of HP? Before buying healing at 3000 💰, make sure the shop doesn't contain any more profitable potions!", + "Out of HP? Before buying healing at 3000 {emote:unitValues.money}, make sure the shop doesn't contain any more profitable potions!", "The potions sold in the shop are often available at very attractive prices.", "To top the weekly leaderboard and win a badge, be diligent in your reporting and don't be afraid to fight.", "The overall ranking is available using the {command:top score} command.", diff --git a/Lang/en/commands.json b/Lang/en/commands.json index 098b8a247..6049d69f2 100644 --- a/Lang/en/commands.json +++ b/Lang/en/commands.json @@ -196,7 +196,7 @@ "description": "Change your pet's nickname. If no name is given, the nickname will be cleared." }, "PET_SELL": { - "description": "Allows to sell a pet. The following conditions apply: \n - The selling price must be higher than `{{petSellMinPrice}}💰` and lower than `{{petSellMaxPrice}}💰`. \n- The seller will not earn money for the transaction, but guild experience. \n- The seller and the buyer cannot be part of the same guild." + "description": "Allows to sell a pet. The following conditions apply: \n - The selling price must be higher than `{{petSellMinPrice}}{emote:unitValues.money}` and lower than `{{petSellMaxPrice}}{emote:unitValues.money}`. \n- The seller will not earn money for the transaction, but guild experience. \n- The seller and the buyer cannot be part of the same guild." }, "PET_TRADE": { "description": "Offers to exchange your pet with the mentioned player." @@ -211,7 +211,7 @@ "description": "This feature was removed from the bot after an update to Discord's features." }, "PROFILE": { - "description": "Displays information about your character:\n\n😃 Health status | Nickname | Level\n\n឵឵឵Information:\n❤️ Life | ⭐ XP | 💰 Money\n\nStatistics :\n⚡ Energy | 🗡️ Attack | 🛡️ Defense | 🚀 Speed | 🌬️ Breath | 🫁 Recovery\n\nMissions :\n💎 Gems | 📖 Advanced campaign %\n\nRank and score:\n🏆 Rank | 🏅 Score\n\nClass:\nSee {command:classes}\n\nGlory and League:\n✨ Glory | See {{topGloryCommandMention}}\n\nGuild:\n🏟️ Guild\n\nDestination:\nSee {{mapCommandMention}}\n\nFamiliar:\nSee {{petCommandMention}}\n\n💡-Badges are displayed on your profile as a reaction." + "description": "Displays information about your character:\n\n😃 Health status | Nickname | Level\n\n឵឵឵Information:\n❤️ Life | ⭐ XP | {emote:unitValues.money} Money\n\nStatistics :\n⚡ Energy | 🗡️ Attack | 🛡️ Defense | 🚀 Speed | 🌬️ Breath | 🫁 Recovery\n\nMissions :\n💎 Gems | 📖 Advanced campaign %\n\nRank and score:\n🏆 Rank | 🏅 Score\n\nClass:\nSee {command:classes}\n\nGlory and League:\n✨ Glory | See {{topGloryCommandMention}}\n\nGuild:\n🏟️ Guild\n\nDestination:\nSee {{mapCommandMention}}\n\nFamiliar:\nSee {{petCommandMention}}\n\n💡-Badges are displayed on your profile as a reaction." }, "RARITY": { "description": "Allows you to see the probability of getting an item by its rarity." @@ -511,15 +511,15 @@ "fullRegen": "💓 You have been fully cared for.", "alreadyHaveBadge": "You already have this badge.", "badgeBought": "You have received a new badge: {emote:badges.richPerson}!", - "notEnoughMoney": "You don't have enough money to buy this item! You are missing `{{missingMoney}}💰`.", + "notEnoughMoney": "You don't have enough money to buy this item! You are missing `{{missingMoney}}{emote:unitValues.money}`.", "boughtTooMuchDailyPotions": "There are no more potions available for sale... Come back tomorrow!", "title": "🛒 Store Display", - "currentMoney": "You have `{{money}}💰`.", - "shopItemsDisplaySingle": "{{name}} | `{{price}}💰`", - "shopItemsDisplayMultiple": "**{{amount}}x** {{name}} | `{{price}}💰`", + "currentMoney": "You have `{{money}}{emote:unitValues.money}`.", + "shopItemsDisplaySingle": "{{name}} | `{{price}}{emote:unitValues.money}`", + "shopItemsDisplayMultiple": "**{{amount}}x** {{name}} | `{{price}}{emote:unitValues.money}`", "shopSelectPlaceholder": "Select an item to buy", "buyCategorySlotSuccess": "You bought a new inventory slot!", - "shopItemsSelectDescription": "{{price}}💰", + "shopItemsSelectDescription": "{{price}}{emote:unitValues.money}", "closeShopButton": "❌ Close Store", "shopConfirmationTitle": "{{pseudo}}, you selected the following product:", "shopConfirmationTitleMultiple": "{{pseudo}}, select a quantity for this product:", diff --git a/Lang/en/error.json b/Lang/en/error.json index e210c14b2..46a762033 100644 --- a/Lang/en/error.json +++ b/Lang/en/error.json @@ -59,7 +59,7 @@ "unexpectedError": "An error occurred. :(", "pleaseWaitForHeal": "Please wait for the healing end of your state to continue playing: {{time}}\n\n:information_source: You can use the {command:shop} command to purchase care.", "pleaseWaitForHisHeal": "Please wait until the end of healing of its state alteration: {{time}}", - "notEnoughMoney": "You don't have enough money to perform this action. You are missing {{money}}💰.", + "notEnoughMoney": "You don't have enough money to perform this action. You are missing {{money}}{emote:unitValues.money}.", "cooldownPetFree": "You can only release one pet per hour. You will be able to release another one {{remainingTime}}.", "unknownPlayer": "Nickname 404", "petNickNotValid": "The rules for naming a pet are as follows:\n$t(error:stringRules)", diff --git a/Lang/en/smallEvents.json b/Lang/en/smallEvents.json index c87c22863..b91c3d058 100644 --- a/Lang/en/smallEvents.json +++ b/Lang/en/smallEvents.json @@ -129,7 +129,7 @@ "end": "Without paying any further attention to the individual, you continue on your way.", "rewardTypeText": { "xp": " You earned **{{xpWon}}⭐**.", - "money": " You won **{{moneyWon}}💰**!", + "money": " You won **{{moneyWon}}{emote:unitValues.money}**!", "guildXp": " Your guild earns **{{guildXpWon}}⭐**.", "points": " You won **{{pointsWon}}🏅**." } diff --git a/Lang/es/advices.json b/Lang/es/advices.json index d07b031e0..b32f22430 100644 --- a/Lang/es/advices.json +++ b/Lang/es/advices.json @@ -53,7 +53,7 @@ "Es una buena idea reservar algo de dinero para el tratamiento.", "Cada semana se elabora una clasificación para determinar qué jugador ha ganado más puntos. Para ver esta clasificación, utilice el comando {command:top score} y especifique la opción `duration`.", "El dinero es uno de los recursos más importantes del juego, y puedes ganarlo a través de informes ({command:report}), objetos de efecto diario ({command:dailybonus}) o recompensas diarias de gremio ({command:guilddailybonus}).", - "¿Te quedas sin PV? Antes de comprar el tratamiento de 3000 💰, ¡comprueba que en la tienda no haya una poción más rentable!", + "¿Te quedas sin PV? Antes de comprar el tratamiento de 3000 {emote:unitValues.money}, ¡comprueba que en la tienda no haya una poción más rentable!", "Las pociones que se venden en la tienda suelen estar disponibles a precios muy atractivos.", "Para encabezar la clasificación semanal y ganar una insignia, sé diligente en tus informes y no temas una pelea.", "{command:top score}La clasificación general está disponible mediante el comando .", diff --git a/Lang/es/commands.json b/Lang/es/commands.json index 0edf35044..d981f4314 100644 --- a/Lang/es/commands.json +++ b/Lang/es/commands.json @@ -196,7 +196,7 @@ "description": "Cambia el apodo de tu mascota. Si no se proporciona ningún nombre, se eliminará el nombre actual." }, "PET_SELL": { - "description": "Permite vender una mascota. Se aplican las siguientes condiciones: \n - el precio de venta debe ser mayor que `{{petSellMinPrice}}💰` y menor que `{{petSellMaxPrice}}💰`. \n- El vendedor no ganará dinero con la transacción, solo experiencia de gremio. \n- El vendedor y el comprador no pueden ser miembros del mismo gremio." + "description": "Permite vender una mascota. Se aplican las siguientes condiciones: \n - el precio de venta debe ser mayor que `{{petSellMinPrice}}{emote:unitValues.money}` y menor que `{{petSellMaxPrice}}{emote:unitValues.money}`. \n- El vendedor no ganará dinero con la transacción, solo experiencia de gremio. \n- El vendedor y el comprador no pueden ser miembros del mismo gremio." }, "PET_TRADE": { "description": "Proponga un intercambio de sus animales con la persona mencionada." @@ -211,7 +211,7 @@ "description": "Esta función se ha eliminado del juego tras una actualización de la funcionalidad de Discord." }, "PROFILE": { - "description": "\n\n\n\n\n\n\nMuestra información sobre tu personaje: 😃 Estado de salud | Apodo | Nivel ឵឵Información: ❤️ Vida | ⭐ XP | 💰 Dinero Estadísticas :\n\n\n⚡ Energía | 🗡️ Ataque | 🛡️ Defensa | 🚀 Velocidad | 🌬️ Aliento | 🫁 Recuperación Misiones :\n\n\n\n\n\n\n {command:classes}\n\n\n {{topGloryCommandMention}}\n\n\n\n\n\n {{mapCommandMention}}\n\n\n {{petCommandMention}}\n\n💎 Gemas | 📖 Campaña avanzada % Rango y puntuación: 🏆 Rango | 🏅 Puntuación Clase: Ver Gloria y Liga: ✨ Gloria | Ver Gremio: 🏟️ Gremio Destino: Ver Familiar: Ver 💡-Las insignias se muestran en tu perfil como reacción." + "description": "\n\n\n\n\n\n\nMuestra información sobre tu personaje: 😃 Estado de salud | Apodo | Nivel ឵឵Información: ❤️ Vida | ⭐ XP | {emote:unitValues.money} Dinero Estadísticas :\n\n\n⚡ Energía | 🗡️ Ataque | 🛡️ Defensa | 🚀 Velocidad | 🌬️ Aliento | 🫁 Recuperación Misiones :\n\n\n\n\n\n\n {command:classes}\n\n\n {{topGloryCommandMention}}\n\n\n\n\n\n {{mapCommandMention}}\n\n\n {{petCommandMention}}\n\n💎 Gemas | 📖 Campaña avanzada % Rango y puntuación: 🏆 Rango | 🏅 Puntuación Clase: Ver Gloria y Liga: ✨ Gloria | Ver Gremio: 🏟️ Gremio Destino: Ver Familiar: Ver 💡-Las insignias se muestran en tu perfil como reacción." }, "RARITY": { "description": "Muestra la probabilidad de tener un objeto según su rareza." @@ -511,15 +511,15 @@ "fullRegen": "💓 Te han cuidado por completo.", "alreadyHaveBadge": "Ya tienes esta insignia.", "badgeBought": "{emote:badges.richPerson} Has recibido una nueva insignia: .", - "notEnoughMoney": "¡No tienes suficiente dinero para comprar este artículo!{{missingMoney}} Te falta ` 💰`.", + "notEnoughMoney": "¡No tienes suficiente dinero para comprar este artículo!{{missingMoney}} Te falta ` {emote:unitValues.money}`.", "boughtTooMuchDailyPotions": "No hay más pociones del día a la venta... ¡Vuelve mañana!", "title": "🛒 Pantalla de la tienda", - "currentMoney": "{{money}}Tienes ` 💰`.", - "shopItemsDisplaySingle": "{{name}}{{price}}| 💰`", - "shopItemsDisplayMultiple": "{{amount}} {{name}}{{price}}** x** | ` 💰`", + "currentMoney": "{{money}}Tienes ` {emote:unitValues.money}`.", + "shopItemsDisplaySingle": "{{name}}{{price}}| {emote:unitValues.money}`", + "shopItemsDisplayMultiple": "{{amount}} {{name}}{{price}}** x** | ` {emote:unitValues.money}`", "shopSelectPlaceholder": "Seleccione un artículo para comprar", "buyCategorySlotSuccess": "Has comprado un nuevo espacio de inventario.", - "shopItemsSelectDescription": "{{price}}💰", + "shopItemsSelectDescription": "{{price}}{emote:unitValues.money}", "closeShopButton": "❌ Cerrar tienda", "shopConfirmationTitle": "{{pseudo}}ha seleccionado el siguiente producto:", "shopConfirmationTitleMultiple": "{{pseudo}}Seleccione una cantidad para este producto:", diff --git a/Lang/es/error.json b/Lang/es/error.json index 32926e279..e5eed5f59 100644 --- a/Lang/es/error.json +++ b/Lang/es/error.json @@ -59,7 +59,7 @@ "unexpectedError": "Se ha producido un error :(", "pleaseWaitForHeal": "Por favor, espera hasta el final de la curación para tu alteración de estado antes de continuar jugando: {{time}}\n\n:information_source: {command:shop} Puedes usar el comando para comprar una curación.", "pleaseWaitForHisHeal": "{{time}}Por favor, espere hasta el final de la atención para su estado de deterioro:", - "notEnoughMoney": "No tienes dinero suficiente para llevar a cabo esta acción. {{money}} Te falta dinero 💰.", + "notEnoughMoney": "No tienes dinero suficiente para llevar a cabo esta acción. {{money}} Te falta dinero {emote:unitValues.money}.", "cooldownPetFree": "Sólo puedes liberar una mascota por hora. {{remainingTime}}Puedes liberar otra .", "unknownPlayer": "Nombre de usuario 404", "petNickNotValid": "Las normas para poner nombre a una mascota son las siguientes:\n$t(error:stringRules)", diff --git a/Lang/es/smallEvents.json b/Lang/es/smallEvents.json index 1e30f752b..cade33d89 100644 --- a/Lang/es/smallEvents.json +++ b/Lang/es/smallEvents.json @@ -129,7 +129,7 @@ "end": "Sin prestar más atención al individuo, continúa su camino.", "rewardTypeText": { "xp": " {{xpWon}} Has ganado ** ⭐**.", - "money": " {{moneyWon}} ¡Has ganado ** 💰**!", + "money": " {{moneyWon}} ¡Has ganado ** {emote:unitValues.money}**!", "guildXp": " {{guildXpWon}} Tu gremio gana ** ⭐**.", "points": " {{pointsWon}} Has ganado ** 🏅**." } diff --git a/Lang/fr/advices.json b/Lang/fr/advices.json index 11bede362..0af4273d1 100644 --- a/Lang/fr/advices.json +++ b/Lang/fr/advices.json @@ -53,7 +53,7 @@ "Garder de l'argent de côté est judicieux pour pouvoir se soigner.", "Chaque semaine un classement est effectué pour désigner le joueur de la semaine qui a gagné le plus de points. Pour consulter ce classement, utilisez la commande {command:top score} et précisez l'option `durée`.", "L'argent est l'une des ressources les plus importantes du jeu, obtenez-en grâce aux rapports ({command:report}), aux items à effets journaliers ({command:dailybonus}) ou aux récompenses journalières de guildes ({command:guilddailybonus}).", - "En manque de PV ? Avant d'acheter le soin à 3000 💰, vérifiez que le magasin ne contient pas de potion plus rentable !", + "En manque de PV ? Avant d'acheter le soin à 3000 {emote:unitValues.money}, vérifiez que le magasin ne contient pas de potion plus rentable !", "Les potions vendues dans le magasin sont souvent disponibles à des prix très attractifs.", "Pour être le premier au classement de la semaine et remporter un badge, soyez assidus dans vos rapports et n'ayez pas peur des combats.", "Le classement général est disponible en utilisant la commande {command:top score}.", diff --git a/Lang/fr/commands.json b/Lang/fr/commands.json index c0982a011..cd94e11cb 100644 --- a/Lang/fr/commands.json +++ b/Lang/fr/commands.json @@ -196,7 +196,7 @@ "description": "Change le surnom de votre familier. Si aucun nom n'est fourni, le nom actuel sera effacé." }, "PET_SELL": { - "description": "Permet de vendre un familier. Les conditions suivantes s'appliquent : \n - le prix de vente doit être être supérieur à `{{petSellMinPrice}}💰` et inférieur à `{{petSellMaxPrice}}💰`. \n- Le vendeur ne gagnera pas d'argent lors de la transaction, mais de l'expérience de guilde. \n- Le vendeur et l'acheteur ne peuvent pas faire partie de la même guilde." + "description": "Permet de vendre un familier. Les conditions suivantes s'appliquent : \n - le prix de vente doit être être supérieur à `{{petSellMinPrice}}{emote:unitValues.money}` et inférieur à `{{petSellMaxPrice}}{emote:unitValues.money}`. \n- Le vendeur ne gagnera pas d'argent lors de la transaction, mais de l'expérience de guilde. \n- Le vendeur et l'acheteur ne peuvent pas faire partie de la même guilde." }, "PET_TRADE": { "description": "Propose un échange de vos animaux avec la personne mentionnée." @@ -211,7 +211,7 @@ "description": "Cette fonctionnalité a été supprimée du jeu suite à une mise à jour des fonctionnalités proposées par Discord." }, "PROFILE": { - "description": "Affiche des informations sur votre personnage :\n\n😃 État de santé | Pseudo | Level\n\n឵឵឵Informations :\n❤️ Vie | ⭐ XP | 💰 Argent\n\nStatistiques :\n⚡ Énergie | 🗡️ Attaque | 🛡️ Défense | 🚀 Vitesse | 🌬️ Souffle | 🫁 Récupération\n\nMissions :\n💎 Gemmes | 📖 Avancé de la campagne %\n\nClassement et score :\n🏆 Classement | 🏅 Score\n\nClasse :\nVoir {command:classes}\n\nGloire et Ligue :\n✨ Gloire | Voir {{topGloryCommandMention}}\n\nGuilde :\n🏟️ Guilde\n\nDestination :\nVoir {{mapCommandMention}}\n\nFamilier :\nVoir {{petCommandMention}}\n\n💡-Les badges sont affichés sur votre profil sous forme de réaction." + "description": "Affiche des informations sur votre personnage :\n\n😃 État de santé | Pseudo | Level\n\n឵឵឵Informations :\n❤️ Vie | ⭐ XP | {emote:unitValues.money} Argent\n\nStatistiques :\n⚡ Énergie | 🗡️ Attaque | 🛡️ Défense | 🚀 Vitesse | 🌬️ Souffle | 🫁 Récupération\n\nMissions :\n💎 Gemmes | 📖 Avancé de la campagne %\n\nClassement et score :\n🏆 Classement | 🏅 Score\n\nClasse :\nVoir {command:classes}\n\nGloire et Ligue :\n✨ Gloire | Voir {{topGloryCommandMention}}\n\nGuilde :\n🏟️ Guilde\n\nDestination :\nVoir {{mapCommandMention}}\n\nFamilier :\nVoir {{petCommandMention}}\n\n💡-Les badges sont affichés sur votre profil sous forme de réaction." }, "RARITY": { "description": "Permet de voir la probabilité d'avoir un item selon sa rareté." @@ -511,15 +511,15 @@ "fullRegen": "💓 Vous avez été complétement soigné.", "alreadyHaveBadge": "Vous possédez déjà ce badge.", "badgeBought": "Vous avez reçu un nouveau badge : {emote:badges.richPerson} !", - "notEnoughMoney": "Vous n'avez pas assez d'argent pour acheter cet objet ! Il vous manque `{{missingMoney}} 💰`.", + "notEnoughMoney": "Vous n'avez pas assez d'argent pour acheter cet objet ! Il vous manque `{{missingMoney}} {emote:unitValues.money}`.", "boughtTooMuchDailyPotions": "Il n'y a plus aucune potion du jour disponible à la vente... Revenez demain !", "title": "🛒 Affichage du Magasin", - "currentMoney": "Vous avez `{{money}}💰`.", - "shopItemsDisplaySingle": "{{name}} | `{{price}}💰`", - "shopItemsDisplayMultiple": "**{{amount}}x** {{name}} | `{{price}}💰`", + "currentMoney": "Vous avez `{{money}}{emote:unitValues.money}`.", + "shopItemsDisplaySingle": "{{name}} | `{{price}}{emote:unitValues.money}`", + "shopItemsDisplayMultiple": "**{{amount}}x** {{name}} | `{{price}}{emote:unitValues.money}`", "shopSelectPlaceholder": "Sélectionnez un objet à acheter", "buyCategorySlotSuccess": "Vous avez acheté un nouvel emplacement d'inventaire !", - "shopItemsSelectDescription": "{{price}}💰", + "shopItemsSelectDescription": "{{price}}{emote:unitValues.money}", "closeShopButton": "❌ Fermer le magasin", "shopConfirmationTitle": "{{pseudo}}, vous avez sélectionné le produit suivant :", "shopConfirmationTitleMultiple": "{{pseudo}}, sélectionnez une quantité pour ce produit :", diff --git a/Lang/fr/error.json b/Lang/fr/error.json index ccbe7ff93..862645fdf 100644 --- a/Lang/fr/error.json +++ b/Lang/fr/error.json @@ -59,7 +59,7 @@ "unexpectedError": "Une erreur est survenue :(", "pleaseWaitForHeal": "Veuillez attendre la fin des soins de votre altération d'état pour continuer à jouer : {{time}}\n\n:information_source: Vous pouvez utiliser la commande {command:shop} pour acheter un soin.", "pleaseWaitForHisHeal": "Veuillez attendre la fin des soins de son altération d'état : {{time}}", - "notEnoughMoney": "Vous n'avez pas assez d'argent pour effectuer cette action. Il vous manque {{money}} 💰.", + "notEnoughMoney": "Vous n'avez pas assez d'argent pour effectuer cette action. Il vous manque {{money}} {emote:unitValues.money}.", "cooldownPetFree": "Vous ne pouvez libérer qu'un familier par heure. Vous pourrez en libérer un autre {{remainingTime}}.", "unknownPlayer": "Pseudo 404", "petNickNotValid": "Les règles pour le nom d'un familier sont les suivantes:\n$t(error:stringRules)", diff --git a/Lang/fr/smallEvents.json b/Lang/fr/smallEvents.json index 1c38dbdc9..179724796 100644 --- a/Lang/fr/smallEvents.json +++ b/Lang/fr/smallEvents.json @@ -129,7 +129,7 @@ "end": "Sans prêter plus d'attention à l'individu, vous continuez votre route.", "rewardTypeText": { "xp": " Vous avez gagné **{{xpWon}} ⭐**.", - "money": " Vous avez gagné **{{moneyWon}} 💰** !", + "money": " Vous avez gagné **{{moneyWon}} {emote:unitValues.money}** !", "guildXp": " Votre guilde gagne **{{guildXpWon}} ⭐**.", "points": " Vous avez gagné **{{pointsWon}} 🏅**." } diff --git a/Lang/it/advices.json b/Lang/it/advices.json index 9eaedd772..be6bdd1be 100644 --- a/Lang/it/advices.json +++ b/Lang/it/advices.json @@ -53,7 +53,7 @@ "È una buona idea tenere da parte un po' di denaro per le cure.", "Ogni settimana viene stilata una classifica per determinare quale giocatore ha guadagnato più punti. Per visualizzare questa classifica, utilizzare il comando {command:top score} e specificare l'opzione `durata`.", "Il denaro è una delle risorse più importanti del gioco e si può guadagnare attraverso le segnalazioni ({command:report}), gli oggetti a effetto giornaliero ({command:dailybonus}) o le ricompense giornaliere della gilda ({command:guilddailybonus}).", - "Siete a corto di FV? Prima di acquistare il trattamento da 3000 💰, controllate che il negozio non contenga una pozione più redditizia!", + "Siete a corto di FV? Prima di acquistare il trattamento da 3000 {emote:unitValues.money}, controllate che il negozio non contenga una pozione più redditizia!", "Le pozioni vendute nel negozio sono spesso disponibili a prezzi molto interessanti.", "Per raggiungere la vetta della classifica settimanale e vincere un distintivo, siate diligenti nei rapporti e non abbiate paura di combattere.", "{command:top score}La classifica generale è disponibile utilizzando il comando .", diff --git a/Lang/it/commands.json b/Lang/it/commands.json index 7ff485616..17e5cf810 100644 --- a/Lang/it/commands.json +++ b/Lang/it/commands.json @@ -196,7 +196,7 @@ "description": "Modifica il soprannome dell'animale domestico. Se non viene fornito alcun nome, il nome attuale verrà cancellato." }, "PET_SELL": { - "description": "Permette di vendere un animale domestico. Si applicano le seguenti condizioni: \n - il prezzo di vendita deve essere superiore a `{{petSellMinPrice}}💰` e inferiore a `{{petSellMaxPrice}}💰`. \n- Il venditore non guadagnerà denaro dalla transazione, ma solo esperienza di gilda. \n- Il venditore e l'acquirente non possono essere membri della stessa gilda." + "description": "Permette di vendere un animale domestico. Si applicano le seguenti condizioni: \n - il prezzo di vendita deve essere superiore a `{{petSellMinPrice}}{emote:unitValues.money}` e inferiore a `{{petSellMaxPrice}}{emote:unitValues.money}`. \n- Il venditore non guadagnerà denaro dalla transazione, ma solo esperienza di gilda. \n- Il venditore e l'acquirente non possono essere membri della stessa gilda." }, "PET_TRADE": { "description": "Proponete uno scambio di animali con la persona indicata." @@ -211,7 +211,7 @@ "description": "Questa funzione è stata rimossa dal gioco in seguito a un aggiornamento delle funzionalità di Discord." }, "PROFILE": { - "description": "\n\n\n\n\n\n\nVisualizza le informazioni sul personaggio: 😃 Stato di salute | Nickname | Livello ឵឵Informazioni: ❤️ Vita | ⭐ XP | 💰 Denaro Statistiche :\n\n\n⚡ Energia | 🗡️ Attacco | 🛡️ Difesa | 🚀 Velocità | 🌬️ Respiro | 🫁 Recupero Missioni :\n\n\n\n\n\n\n {command:classes}\n\n\n {{topGloryCommandMention}}\n\n\n\n\n\n {{mapCommandMention}}\n\n\n {{petCommandMention}}\n\n💎 Gemme | 📖 Campagna avanzata % Rango e punteggio: 🏆 Rango | 🏅 Punteggio Classe: Vedi Gloria e Lega: ✨ Gloria | Vedi Gilda: 🏟️ Destinazione Gilda: Vedi Familiare: Vedi 💡 I distintivi vengono visualizzati sul tuo profilo come reazione." + "description": "\n\n\n\n\n\n\nVisualizza le informazioni sul personaggio: 😃 Stato di salute | Nickname | Livello ឵឵Informazioni: ❤️ Vita | ⭐ XP | {emote:unitValues.money} Denaro Statistiche :\n\n\n⚡ Energia | 🗡️ Attacco | 🛡️ Difesa | 🚀 Velocità | 🌬️ Respiro | 🫁 Recupero Missioni :\n\n\n\n\n\n\n {command:classes}\n\n\n {{topGloryCommandMention}}\n\n\n\n\n\n {{mapCommandMention}}\n\n\n {{petCommandMention}}\n\n💎 Gemme | 📖 Campagna avanzata % Rango e punteggio: 🏆 Rango | 🏅 Punteggio Classe: Vedi Gloria e Lega: ✨ Gloria | Vedi Gilda: 🏟️ Destinazione Gilda: Vedi Familiare: Vedi 💡 I distintivi vengono visualizzati sul tuo profilo come reazione." }, "RARITY": { "description": "Mostra la probabilità di avere un oggetto in base alla sua rarità." @@ -511,15 +511,15 @@ "fullRegen": "💓 Sei stato completamente accudito.", "alreadyHaveBadge": "Avete già questo distintivo.", "badgeBought": "{emote:badges.richPerson} Hai ricevuto un nuovo badge: .", - "notEnoughMoney": "Non hai abbastanza soldi per acquistare questo articolo!{{missingMoney}} Ti manca ` 💰`.", + "notEnoughMoney": "Non hai abbastanza soldi per acquistare questo articolo!{{missingMoney}} Ti manca ` {emote:unitValues.money}`.", "boughtTooMuchDailyPotions": "Non ci sono più pozioni del giorno disponibili per la vendita... Tornate domani!", "title": "🛒 Display del negozio", - "currentMoney": "{{money}}Avete ` 💰`.", - "shopItemsDisplaySingle": "{{name}}{{price}}| 💰`", - "shopItemsDisplayMultiple": "{{amount}} {{name}}{{price}}** x** | ` 💰`", + "currentMoney": "{{money}}Avete ` {emote:unitValues.money}`.", + "shopItemsDisplaySingle": "{{name}}{{price}}| {emote:unitValues.money}`", + "shopItemsDisplayMultiple": "{{amount}} {{name}}{{price}}** x** | ` {emote:unitValues.money}`", "shopSelectPlaceholder": "Selezionare un articolo da acquistare", "buyCategorySlotSuccess": "Avete acquistato un nuovo slot d'inventario!", - "shopItemsSelectDescription": "{{price}}💰", + "shopItemsSelectDescription": "{{price}}{emote:unitValues.money}", "closeShopButton": "❌ Chiudere il negozio", "shopConfirmationTitle": "{{pseudo}}avete selezionato il seguente prodotto:", "shopConfirmationTitleMultiple": "{{pseudo}}Selezionare una quantità per questo prodotto:", diff --git a/Lang/it/error.json b/Lang/it/error.json index 926bf96d6..428ddd564 100644 --- a/Lang/it/error.json +++ b/Lang/it/error.json @@ -59,7 +59,7 @@ "unexpectedError": "Si è verificato un errore :(", "pleaseWaitForHeal": "Attendere la fine della guarigione per la modifica dello stato prima di continuare a giocare: {{time}}\n\n:information_source: {command:shop} È possibile utilizzare il comando per acquistare una guarigione.", "pleaseWaitForHisHeal": "{{time}}Per favore, aspettate fino alla fine delle cure per il deterioramento delle sue condizioni:", - "notEnoughMoney": "Non avete abbastanza soldi per realizzare questa azione. {{money}} Siete a corto di denaro 💰.", + "notEnoughMoney": "Non avete abbastanza soldi per realizzare questa azione. {{money}} Siete a corto di denaro {emote:unitValues.money}.", "cooldownPetFree": "È possibile liberare un solo animale domestico all'ora. {{remainingTime}}È possibile liberare un altro .", "unknownPlayer": "Nome utente 404", "petNickNotValid": "Le regole per dare un nome a un animale domestico sono le seguenti:\n$t(error:stringRules)", diff --git a/Lang/it/smallEvents.json b/Lang/it/smallEvents.json index 0adf1d3f7..ed2a9021f 100644 --- a/Lang/it/smallEvents.json +++ b/Lang/it/smallEvents.json @@ -129,7 +129,7 @@ "end": "Senza prestare ulteriore attenzione all'individuo, continuate per la vostra strada.", "rewardTypeText": { "xp": " {{xpWon}} Avete vinto ** ⭐**.", - "money": " {{moneyWon}} Hai vinto ** 💰**!", + "money": " {{moneyWon}} Hai vinto ** {emote:unitValues.money}**!", "guildXp": " {{guildXpWon}} La tua gilda vince ** ⭐**.", "points": " {{pointsWon}} Hai vinto ** 🏅**." } diff --git a/Lang/pt/advices.json b/Lang/pt/advices.json index 8c0b26d99..b4d4a5106 100644 --- a/Lang/pt/advices.json +++ b/Lang/pt/advices.json @@ -53,7 +53,7 @@ "É uma boa ideia reservar algum dinheiro para o tratamento.", "Todas as semanas é elaborado um ranking para determinar qual o jogador que ganhou mais pontos. {command:top score} Para ver este ranking, utilize o comando e especifique a opção `duração`.", "{command:report}{command:dailybonus}{command:guilddailybonus}O dinheiro é um dos recursos mais importantes do jogo, e podes ganhá-lo através de relatórios ( ), itens de efeito diário ( ) ou recompensas diárias do grémio ( ).", - "Estás a ficar sem PV? Antes de comprar o tratamento 3000 💰, verifica se na loja não existe uma poção mais rentável!", + "Estás a ficar sem PV? Antes de comprar o tratamento 3000 {emote:unitValues.money}, verifica se na loja não existe uma poção mais rentável!", "As poções vendidas na loja estão frequentemente disponíveis a preços muito atractivos.", "Para chegar ao topo da tabela de classificação semanal e ganhar um crachá, seja diligente nos seus relatórios e não tenha medo de uma luta.", "{command:top score}A classificação geral está disponível utilizando o comando .", diff --git a/Lang/pt/commands.json b/Lang/pt/commands.json index 7fd2bb1be..3aebfd939 100644 --- a/Lang/pt/commands.json +++ b/Lang/pt/commands.json @@ -196,7 +196,7 @@ "description": "Altera a alcunha do seu animal de estimação. Se não for fornecido um nome, o nome atual será eliminado." }, "PET_SELL": { - "description": "Permite-lhe vender um animal de estimação. Aplicam-se as seguintes condições: \n{{petSellMinPrice}}{{petSellMaxPrice}}- o preço de venda deve ser maior que ` 💰` e menor que ` 💰`. \n- O vendedor não ganhará dinheiro com a transação, apenas experiência de guilda. \n- O vendedor e o comprador não podem ser membros da mesma guilda." + "description": "Permite-lhe vender um animal de estimação. Aplicam-se as seguintes condições: \n{{petSellMinPrice}}{{petSellMaxPrice}}- o preço de venda deve ser maior que ` {emote:unitValues.money}` e menor que ` {emote:unitValues.money}`. \n- O vendedor não ganhará dinheiro com a transação, apenas experiência de guilda. \n- O vendedor e o comprador não podem ser membros da mesma guilda." }, "PET_TRADE": { "description": "Proponha uma troca dos seus animais com a pessoa mencionada." @@ -211,7 +211,7 @@ "description": "Esta caraterística foi removida do jogo na sequência de uma atualização da funcionalidade do Discord." }, "PROFILE": { - "description": "\n\n\n\n\n\n\nMostra informações sobre o seu personagem: 😃 Estado de saúde | Apelido | Nível ឵឵Informações: ❤️ Vida | ⭐ XP | 💰 Dinheiro Estatísticas :\n\n\n⚡ Energia | 🗡️ Ataque | 🛡️ Defesa | 🚀 Velocidade | 🌬️ Respiração | 🫁 Recuperação Missões :\n\n\n\n\n\n\n {command:classes}\n\n\n {{topGloryCommandMention}}\n\n\n\n\n\n {{mapCommandMention}}\n\n\n {{petCommandMention}}\n\n💎 Gemas | 📖 Campanha avançada % Classificação e pontuação: 🏆 Classificação | 🏅 Pontuação Classe: Ver Glória e Liga: ✨ Glória | Ver Grémio: 🏟️ Destino do Grémio: Ver Familiar: Ver 💡-Os emblemas são apresentados no teu perfil como uma reação." + "description": "\n\n\n\n\n\n\nMostra informações sobre o seu personagem: 😃 Estado de saúde | Apelido | Nível ឵឵Informações: ❤️ Vida | ⭐ XP | {emote:unitValues.money} Dinheiro Estatísticas :\n\n\n⚡ Energia | 🗡️ Ataque | 🛡️ Defesa | 🚀 Velocidade | 🌬️ Respiração | 🫁 Recuperação Missões :\n\n\n\n\n\n\n {command:classes}\n\n\n {{topGloryCommandMention}}\n\n\n\n\n\n {{mapCommandMention}}\n\n\n {{petCommandMention}}\n\n💎 Gemas | 📖 Campanha avançada % Classificação e pontuação: 🏆 Classificação | 🏅 Pontuação Classe: Ver Glória e Liga: ✨ Glória | Ver Grémio: 🏟️ Destino do Grémio: Ver Familiar: Ver 💡-Os emblemas são apresentados no teu perfil como uma reação." }, "RARITY": { "description": "Mostra a probabilidade de ter um item de acordo com a sua raridade." @@ -511,15 +511,15 @@ "fullRegen": "Foi completamente tratado.", "alreadyHaveBadge": "Já tem este distintivo.", "badgeBought": "{emote:badges.richPerson} Recebeu um novo distintivo: .", - "notEnoughMoney": "Não tens dinheiro suficiente para comprar este artigo!{{missingMoney}} Está a faltar ` 💰`.", + "notEnoughMoney": "Não tens dinheiro suficiente para comprar este artigo!{{missingMoney}} Está a faltar ` {emote:unitValues.money}`.", "boughtTooMuchDailyPotions": "Não há mais poções do dia disponíveis para venda... Volta amanhã!", "title": "Ecrã da loja", - "currentMoney": "{{money}}Tem ` 💰`.", - "shopItemsDisplaySingle": "{{name}}{{price}}| 💰`", - "shopItemsDisplayMultiple": "{{amount}} {{name}}{{price}}** x** | ` 💰`", + "currentMoney": "{{money}}Tem ` {emote:unitValues.money}`.", + "shopItemsDisplaySingle": "{{name}}{{price}}| {emote:unitValues.money}`", + "shopItemsDisplayMultiple": "{{amount}} {{name}}{{price}}** x** | ` {emote:unitValues.money}`", "shopSelectPlaceholder": "Selecionar um artigo para comprar", "buyCategorySlotSuccess": "Comprou uma nova ranhura de inventário!", - "shopItemsSelectDescription": "{{price}}💰", + "shopItemsSelectDescription": "{{price}}{emote:unitValues.money}", "closeShopButton": "Fechar a loja", "shopConfirmationTitle": "{{pseudo}}selecionou o seguinte produto:", "shopConfirmationTitleMultiple": "{{pseudo}}Selecionar uma quantidade para este produto:", diff --git a/Lang/pt/error.json b/Lang/pt/error.json index 4aabb7cc2..7fdd4d62c 100644 --- a/Lang/pt/error.json +++ b/Lang/pt/error.json @@ -59,7 +59,7 @@ "unexpectedError": "Ocorreu um erro :(", "pleaseWaitForHeal": "Por favor, espera até ao fim da cura para a tua alteração de estado antes de continuares a jogar: {{time}}\n\n:information_source: {command:shop} Podes usar o comando para comprar uma cura.", "pleaseWaitForHisHeal": "{{time}}Por favor, aguarde até ao fim dos cuidados para o seu estado de deterioração:", - "notEnoughMoney": "Não tem dinheiro suficiente para levar a cabo esta ação. {{money}} Estás em falta 💰.", + "notEnoughMoney": "Não tem dinheiro suficiente para levar a cabo esta ação. {{money}} Estás em falta {emote:unitValues.money}.", "cooldownPetFree": "Só é possível libertar um animal de estimação por hora. {{remainingTime}}Pode libertar outro .", "unknownPlayer": "Nome de utilizador 404", "petNickNotValid": "As regras para dar nome a um animal de estimação são as seguintes:\n$t(error:stringRules)", diff --git a/Lang/pt/smallEvents.json b/Lang/pt/smallEvents.json index 96a2a91b3..4b1b7438a 100644 --- a/Lang/pt/smallEvents.json +++ b/Lang/pt/smallEvents.json @@ -129,7 +129,7 @@ "end": "Sem prestar mais atenção ao indivíduo, continua o seu caminho.", "rewardTypeText": { "xp": " {{xpWon}} Ganhou ** ⭐**.", - "money": " {{moneyWon}} Ganhou ** 💰**!", + "money": " {{moneyWon}} Ganhou ** {emote:unitValues.money}**!", "guildXp": " {{guildXpWon}} A tua guilda ganha ** ⭐**.", "points": " {{pointsWon}} Ganhou ** 🏅**." } diff --git a/Lib/src/packets/commands/CommandUnlockPacket.ts b/Lib/src/packets/commands/CommandUnlockPacket.ts index 761397355..f128a8a4d 100644 --- a/Lib/src/packets/commands/CommandUnlockPacket.ts +++ b/Lib/src/packets/commands/CommandUnlockPacket.ts @@ -2,8 +2,6 @@ import {DraftBotPacket, PacketDirection, sendablePacket} from "../DraftBotPacket @sendablePacket(PacketDirection.FRONT_TO_BACK) export class CommandUnlockPacketReq extends DraftBotPacket { - keycloakId!: string; - askedPlayer!: { rank?: number, keycloakId?: string From 0402d3b0c0d91a235494d64a00e3aeea22febbff Mon Sep 17 00:00:00 2001 From: BastLast Date: Sun, 8 Dec 2024 23:02:27 +0100 Subject: [PATCH 04/17] code style improvements guildKick command #2273 --- .../src/commands/guild/GuildKickCommand.ts | 99 +++++++++---------- .../commands/CommandGuildKickPacket.ts | 2 - 2 files changed, 48 insertions(+), 53 deletions(-) diff --git a/Discord/src/commands/guild/GuildKickCommand.ts b/Discord/src/commands/guild/GuildKickCommand.ts index 66e475bf9..8a4ccf6fe 100644 --- a/Discord/src/commands/guild/GuildKickCommand.ts +++ b/Discord/src/commands/guild/GuildKickCommand.ts @@ -6,12 +6,7 @@ import {SlashCommandBuilderGenerator} from "../SlashCommandBuilderGenerator"; import {SlashCommandBuilder} from "@discordjs/builders"; import {DiscordCache} from "../../bot/DiscordCache"; import {KeycloakUser} from "../../../../Lib/src/keycloak/KeycloakUser"; -import { - CommandGuildKickAcceptPacketRes, - CommandGuildKickPacketReq, - CommandGuildKickPacketRes, - CommandGuildKickRefusePacketRes -} from "../../../../Lib/src/packets/commands/CommandGuildKickPacket"; +import {CommandGuildKickAcceptPacketRes, CommandGuildKickPacketReq, CommandGuildKickPacketRes, CommandGuildKickRefusePacketRes} from "../../../../Lib/src/packets/commands/CommandGuildKickPacket"; import {ReactionCollectorCreationPacket} from "../../../../Lib/src/packets/interaction/ReactionCollectorPacket"; import {DraftBotEmbed} from "../../messages/DraftBotEmbed"; import {DiscordCollectorUtils} from "../../utils/DiscordCollectorUtils"; @@ -30,7 +25,7 @@ async function getPacket(interaction: DraftbotInteraction, user: KeycloakUser): if (!askedPlayer) { return null; } - return makePacket(CommandGuildKickPacketReq, {keycloakId: user.id, askedPlayer}); + return makePacket(CommandGuildKickPacketReq, {askedPlayer}); } /** @@ -41,33 +36,34 @@ async function getPacket(interaction: DraftbotInteraction, user: KeycloakUser): */ export async function handleCommandGuildKickPacketRes(packet: CommandGuildKickPacketRes, context: PacketContext): Promise { const interaction = DiscordCache.getInteraction(context.discord!.interaction); - if (interaction) { - if (!packet.foundPlayer) { - await sendErrorMessage( - interaction.user, - interaction, - i18n.t("commands:guildKick.noPlayer", {lng: interaction.userLanguage}), - {sendManner: SendManner.REPLY} - ); - return; - } - if (!packet.sameGuild) { - await sendErrorMessage( - interaction.user, - interaction, - i18n.t("commands:guildKick.notSameGuild", {lng: interaction.userLanguage}), - {sendManner: SendManner.REPLY} - ); - return; - } - if (packet.himself) { - await sendErrorMessage( - interaction.user, - interaction, - i18n.t("commands:guildKick.himself", {lng: interaction.userLanguage}), - {sendManner: SendManner.REPLY} - ); - } + if (!interaction) { + return; + } + if (!packet.foundPlayer) { + await sendErrorMessage( + interaction.user, + interaction, + i18n.t("commands:guildKick.noPlayer", {lng: interaction.userLanguage}), + {sendManner: SendManner.REPLY} + ); + return; + } + if (!packet.sameGuild) { + await sendErrorMessage( + interaction.user, + interaction, + i18n.t("commands:guildKick.notSameGuild", {lng: interaction.userLanguage}), + {sendManner: SendManner.REPLY} + ); + return; + } + if (packet.himself) { + await sendErrorMessage( + interaction.user, + interaction, + i18n.t("commands:guildKick.himself", {lng: interaction.userLanguage}), + {sendManner: SendManner.REPLY} + ); } } @@ -104,25 +100,26 @@ export async function createGuildKickCollector(packet: ReactionCollectorCreation */ export async function handleCommandGuildKickRefusePacketRes(packet: CommandGuildKickRefusePacketRes, context: PacketContext): Promise { const originalInteraction = DiscordCache.getInteraction(context.discord!.interaction!); + if (!originalInteraction) { + return; + } const buttonInteraction = DiscordCache.getButtonInteraction(context.discord!.buttonInteraction!); const kickedPlayer = (await KeycloakUtils.getUserByKeycloakId(keycloakConfig, packet.kickedKeycloakId))!; - if (buttonInteraction && originalInteraction) { - await buttonInteraction.editReply({ - embeds: [ - new DraftBotEmbed().formatAuthor(i18n.t("commands:guildKick.canceledTitle", { - lng: originalInteraction.userLanguage, - pseudo: originalInteraction.user.displayName - }), originalInteraction.user) - .setDescription( - i18n.t("commands:guildKick.canceledDesc", { - lng: originalInteraction.userLanguage, - kickedPseudo: kickedPlayer.attributes.gameUsername - }) - ) - .setErrorColor() - ] - }); - } + await buttonInteraction?.editReply({ + embeds: [ + new DraftBotEmbed().formatAuthor(i18n.t("commands:guildKick.canceledTitle", { + lng: originalInteraction.userLanguage, + pseudo: originalInteraction.user.displayName + }), originalInteraction.user) + .setDescription( + i18n.t("commands:guildKick.canceledDesc", { + lng: originalInteraction.userLanguage, + kickedPseudo: kickedPlayer.attributes.gameUsername + }) + ) + .setErrorColor() + ] + }); } /** diff --git a/Lib/src/packets/commands/CommandGuildKickPacket.ts b/Lib/src/packets/commands/CommandGuildKickPacket.ts index 700421ac2..561f913a5 100644 --- a/Lib/src/packets/commands/CommandGuildKickPacket.ts +++ b/Lib/src/packets/commands/CommandGuildKickPacket.ts @@ -2,8 +2,6 @@ import {DraftBotPacket, PacketDirection, sendablePacket} from "../DraftBotPacket @sendablePacket(PacketDirection.FRONT_TO_BACK) export class CommandGuildKickPacketReq extends DraftBotPacket { - keycloakId!: string; - askedPlayer!: { rank?: number, keycloakId?: string From f2b9abae39eee0cd8e3c648c9b532436ff7c41f0 Mon Sep 17 00:00:00 2001 From: BastLast Date: Mon, 9 Dec 2024 01:13:56 +0100 Subject: [PATCH 05/17] end of unlock command #2273 --- Core/src/commands/player/UnlockCommand.ts | 109 ++++++++++++++++++ Core/src/core/database/logs/LogsDatabase.ts | 2 +- Discord/src/commands/player/UnlockCommand.ts | 11 +- .../handlers/CommandHandlers.ts | 25 ++++ .../handlers/ReactionCollectorHandlers.ts | 3 + Lang/en/discordBuilder.json | 14 +++ Lang/fr/commands.json | 9 ++ Lang/fr/discordBuilder.json | 14 +++ .../packets/commands/CommandUnlockPacket.ts | 2 + 9 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 Core/src/commands/player/UnlockCommand.ts diff --git a/Core/src/commands/player/UnlockCommand.ts b/Core/src/commands/player/UnlockCommand.ts new file mode 100644 index 000000000..970f1d7e7 --- /dev/null +++ b/Core/src/commands/player/UnlockCommand.ts @@ -0,0 +1,109 @@ +import {DraftBotPacket, makePacket, PacketContext} from "../../../../Lib/src/packets/DraftBotPacket"; +import {Player, Players} from "../../core/database/game/models/Player"; +import { + CommandUnlockAcceptPacketRes, + CommandUnlockPacketReq, + CommandUnlockPacketRes, + CommandUnlockRefusePacketRes +} from "../../../../Lib/src/packets/commands/CommandUnlockPacket"; +import {EndCallback, ReactionCollectorInstance} from "../../core/utils/ReactionsCollector"; +import {ReactionCollectorAcceptReaction} from "../../../../Lib/src/packets/interaction/ReactionCollectorPacket"; +import {BlockingConstants} from "../../../../Lib/src/constants/BlockingConstants"; +import {BlockingUtils} from "../../core/utils/BlockingUtils"; +import {commandRequires, CommandUtils} from "../../core/utils/CommandUtils"; +import {ReactionCollectorUnlock} from "../../../../Lib/src/packets/interaction/ReactionCollectorUnlock"; +import {draftBotInstance} from "../../index"; +import {UnlockConstants} from "../../../../Lib/src/constants/UnlockConstants"; +import {TravelTime} from "../../core/maps/TravelTime"; +import {NumberChangeReason} from "../../../../Lib/src/constants/LogsConstants"; +import {Effect} from "../../../../Lib/src/enums/Effect"; + +async function acceptUnlock(player: Player, freedPlayer: Player, response: DraftBotPacket[]): Promise { + await player.reload(); + // Do all necessary checks again just in case something changed during the menu + if (unlockCannotBeDone(player, freedPlayer, response)) { + return; + } + + await TravelTime.removeEffect(freedPlayer, NumberChangeReason.UNLOCK); + await player.spendMoney({ + amount: UnlockConstants.PRICE_FOR_UNLOCK, + response, + reason: NumberChangeReason.UNLOCK + }); + + await Promise.all([ + player.save(), + freedPlayer.save() + ]); + + draftBotInstance.logsDatabase.logUnlock(player.keycloakId, freedPlayer.keycloakId).then(); + + response.push(makePacket(CommandUnlockAcceptPacketRes, { + unlockedKeycloakId: freedPlayer.keycloakId + })); +} + +/** + * Check if the player can unlock another player + * @param player The player who wants to kick a member + * @param freedPlayer The player who will be freed from the prison + * @param response The response to send + */ +function unlockCannotBeDone(player: Player, freedPlayer: Player, response: DraftBotPacket[]): boolean { + if (freedPlayer === null || player.money < UnlockConstants.PRICE_FOR_UNLOCK || player.id === freedPlayer.id || freedPlayer.effectId !== Effect.JAILED.id) { + // There is a problem + response.push(makePacket(CommandUnlockPacketRes, { + foundPlayer: freedPlayer === null, + notInJail: freedPlayer?.effectId !== Effect.JAILED.id, + money: player.money, + himself: player.id === freedPlayer.id + })); + return true; + } + return false; +} + +export default class UnlockCommand { + @commandRequires(CommandUnlockPacketReq, { + notBlocked: true, + allowedEffects: CommandUtils.ALLOWED_EFFECTS.NO_EFFECT + }) + async execute(response: DraftBotPacket[], player: Player, packet: CommandUnlockPacketReq, context: PacketContext): Promise { + const freedPlayer = await Players.getAskedPlayer(packet.askedPlayer, player); + + if (unlockCannotBeDone(player, freedPlayer, response)) { + return; + } + + // Send collector + const collector = new ReactionCollectorUnlock( + freedPlayer.keycloakId + ); + + const endCallback: EndCallback = async (collector: ReactionCollectorInstance, response: DraftBotPacket[]): Promise => { + const reaction = collector.getFirstReaction(); + if (reaction && reaction.reaction.type === ReactionCollectorAcceptReaction.name) { + await acceptUnlock(player, freedPlayer, response); + } + else { + response.push(makePacket(CommandUnlockRefusePacketRes, {})); + } + BlockingUtils.unblockPlayer(player.id, BlockingConstants.REASONS.UNLOCK); + }; + + const collectorPacket = new ReactionCollectorInstance( + collector, + context, + { + allowedPlayerKeycloakIds: [player.keycloakId], + reactionLimit: 1 + }, + endCallback + ) + .block(player.id, BlockingConstants.REASONS.UNLOCK) + .build(); + + response.push(collectorPacket); + } +} \ No newline at end of file diff --git a/Core/src/core/database/logs/LogsDatabase.ts b/Core/src/core/database/logs/LogsDatabase.ts index 933d49b75..259d1ff1c 100644 --- a/Core/src/core/database/logs/LogsDatabase.ts +++ b/Core/src/core/database/logs/LogsDatabase.ts @@ -511,7 +511,7 @@ export class LogsDatabase extends Database { * @param buyerKeycloakId * @param releasedKeycloakId */ - public async logUnlocks(buyerKeycloakId: string, releasedKeycloakId: string): Promise { + public async logUnlock(buyerKeycloakId: string, releasedKeycloakId: string): Promise { const [buyer] = await LogsPlayers.findOrCreate({ where: { keycloakId: buyerKeycloakId diff --git a/Discord/src/commands/player/UnlockCommand.ts b/Discord/src/commands/player/UnlockCommand.ts index 29eda22db..3c4492fff 100644 --- a/Discord/src/commands/player/UnlockCommand.ts +++ b/Discord/src/commands/player/UnlockCommand.ts @@ -49,6 +49,15 @@ export async function handleCommandUnlockPacketRes(packet: CommandUnlockPacketRe ); return; } + if (packet.notInJail) { + await sendErrorMessage( + interaction.user, + interaction, + i18n.t("commands:unlock.notInJail", {lng: interaction.userLanguage}), + {sendManner: SendManner.REPLY} + ); + return; + } if (packet.money < UnlockConstants.PRICE_FOR_UNLOCK) { await sendErrorMessage( interaction.user, @@ -153,7 +162,7 @@ export async function handleCommandUnlockAcceptPacketRes(packet: CommandUnlockAc } export const commandInfo: ICommand = { - slashCommandBuilder: SlashCommandBuilderGenerator.generateBaseCommand("Unlock") + slashCommandBuilder: SlashCommandBuilderGenerator.generateBaseCommand("unlock") .addUserOption(option => SlashCommandBuilderGenerator.generateOption("unlock", "user", option) .setRequired(false)) diff --git a/Discord/src/packetHandlers/handlers/CommandHandlers.ts b/Discord/src/packetHandlers/handlers/CommandHandlers.ts index 4c9da561a..652adaf4f 100644 --- a/Discord/src/packetHandlers/handlers/CommandHandlers.ts +++ b/Discord/src/packetHandlers/handlers/CommandHandlers.ts @@ -153,6 +153,16 @@ import { handleDailyBonusCooldownError, handleDailyBonusRes } from "../../commands/player/DailyBonusCommand"; +import { + CommandUnlockAcceptPacketRes, + CommandUnlockPacketRes, + CommandUnlockRefusePacketRes +} from "../../../../Lib/src/packets/commands/CommandUnlockPacket"; +import { + handleCommandUnlockAcceptPacketRes, + handleCommandUnlockPacketRes, + handleCommandUnlockRefusePacketRes +} from "../../commands/player/UnlockCommand"; export default class CommandHandlers { @packetHandler(CommandPingPacketRes) @@ -464,4 +474,19 @@ export default class CommandHandlers { async dailyBonusInCooldown(packet: CommandDailyBonusInCooldown, context: PacketContext): Promise { await handleDailyBonusCooldownError(context, packet.lastDailyTimestamp, packet.timeBetweenDailies); } + + @packetHandler(CommandUnlockPacketRes) + async unlockRes(packet: CommandUnlockPacketRes, context: PacketContext): Promise { + await handleCommandUnlockPacketRes(packet, context); + } + + @packetHandler(CommandUnlockRefusePacketRes) + async unlockRefuseRes(packet: CommandUnlockRefusePacketRes, context: PacketContext): Promise { + await handleCommandUnlockRefusePacketRes(packet, context); + } + + @packetHandler(CommandUnlockAcceptPacketRes) + async unlockAcceptRes(packet: CommandUnlockAcceptPacketRes, context: PacketContext): Promise { + await handleCommandUnlockAcceptPacketRes(packet, context); + } } \ No newline at end of file diff --git a/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts b/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts index 35e9b837c..06149265d 100644 --- a/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts +++ b/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts @@ -33,6 +33,8 @@ import {ReactionCollectorGuildKickData} from "../../../../Lib/src/packets/intera import {createGuildKickCollector} from "../../commands/guild/GuildKickCommand"; import {ReactionCollectorGobletsGameData} from "../../../../Lib/src/packets/interaction/ReactionCollectorGobletsGame"; import {gobletsGameCollector} from "../../smallEvents/gobletsGame"; +import {createUnlockCollector} from "../../commands/player/UnlockCommand"; +import {ReactionCollectorUnlockData} from "../../../../Lib/src/packets/interaction/ReactionCollectorUnlock"; export default class ReactionCollectorHandler { @@ -57,6 +59,7 @@ export default class ReactionCollectorHandler { ReactionCollectorHandler.collectorMap.set(ReactionCollectorFightPetData.name, fightPetCollector); ReactionCollectorHandler.collectorMap.set(ReactionCollectorGuildInviteData.name, createGuildInviteCollector); ReactionCollectorHandler.collectorMap.set(ReactionCollectorGobletsGameData.name, gobletsGameCollector); + ReactionCollectorHandler.collectorMap.set(ReactionCollectorUnlockData.name, createUnlockCollector); } @packetHandler(ReactionCollectorCreationPacket) diff --git a/Lang/en/discordBuilder.json b/Lang/en/discordBuilder.json index 9004e809e..1020fcaec 100644 --- a/Lang/en/discordBuilder.json +++ b/Lang/en/discordBuilder.json @@ -232,5 +232,19 @@ "daily": { "description": "Use your equipped item to get a daily bonus.", "name": "dailybonus" + }, + "unlock": { + "description": "Free a player from jail.", + "name": "unlock", + "options": { + "rank": { + "description": "The rank of the player who must be unlocked.", + "name": "rank" + }, + "user": { + "description": "The user who must be unlocked.", + "name": "user" + } + } } } \ No newline at end of file diff --git a/Lang/fr/commands.json b/Lang/fr/commands.json index cd94e11cb..50365ed1a 100644 --- a/Lang/fr/commands.json +++ b/Lang/fr/commands.json @@ -701,5 +701,14 @@ "money": "Argent gagné :", "time": "Vous avez avancé de" } + }, + "unlock": { + "himself": "Vous ne pouvez pas vous libérer vous-même, demandez à un ami de le faire.", + "notInJail": "Ce joueur n'est pas en prison.", + "title": "Libération de {{pseudo}}", + "confirmDesc": "Êtes-vous sûr de vouloir libérer **{{pseudo}}** ?", + "canceledTitle": "Libération annulée", + "canceledDesc": "La libération de **{{pseudo}}** a été annulée.", + "acceptedDesc": "Vous avez libéré **{{pseudo}}** !" } } \ No newline at end of file diff --git a/Lang/fr/discordBuilder.json b/Lang/fr/discordBuilder.json index 1cef05ca7..50edc8941 100644 --- a/Lang/fr/discordBuilder.json +++ b/Lang/fr/discordBuilder.json @@ -232,5 +232,19 @@ "daily": { "description": "Utiliser votre objet équipé pour obtenir un bonus journalier.", "name": "bonusjournalier" + }, + "unlock": { + "description": "Délivrer un autre joueur de la prison.", + "name": "delivrer", + "options": { + "rank": { + "description": "Le classement du joueur à délivrer.", + "name": "classement" + }, + "user": { + "description": "L'utilisateur à délivrer.", + "name": "utilisateur" + } + } } } \ No newline at end of file diff --git a/Lib/src/packets/commands/CommandUnlockPacket.ts b/Lib/src/packets/commands/CommandUnlockPacket.ts index f128a8a4d..195181e69 100644 --- a/Lib/src/packets/commands/CommandUnlockPacket.ts +++ b/Lib/src/packets/commands/CommandUnlockPacket.ts @@ -12,6 +12,8 @@ export class CommandUnlockPacketReq extends DraftBotPacket { export class CommandUnlockPacketRes extends DraftBotPacket { foundPlayer!: boolean; + notInJail!: boolean; + money!: number; himself!: boolean; From 276ee09bafb6abf35f18fb4e5c245adedb125a15 Mon Sep 17 00:00:00 2001 From: romain22222 Date: Mon, 9 Dec 2024 15:20:47 +0100 Subject: [PATCH 06/17] some slight fixes, nothing too shady "#2697" I don't think there anything wrong, at least not from what I tested --- Discord/src/commands/player/UnlockCommand.ts | 7 ++++++- .../packetHandlers/handlers/CommandRequirementHandlers.ts | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Discord/src/commands/player/UnlockCommand.ts b/Discord/src/commands/player/UnlockCommand.ts index 3c4492fff..7fc069a5b 100644 --- a/Discord/src/commands/player/UnlockCommand.ts +++ b/Discord/src/commands/player/UnlockCommand.ts @@ -6,7 +6,12 @@ import {SlashCommandBuilderGenerator} from "../SlashCommandBuilderGenerator"; import {SlashCommandBuilder} from "@discordjs/builders"; import {DiscordCache} from "../../bot/DiscordCache"; import {KeycloakUser} from "../../../../Lib/src/keycloak/KeycloakUser"; -import {CommandUnlockAcceptPacketRes, CommandUnlockPacketReq, CommandUnlockPacketRes, CommandUnlockRefusePacketRes} from "../../../../Lib/src/packets/commands/CommandUnlockPacket"; +import { + CommandUnlockAcceptPacketRes, + CommandUnlockPacketReq, + CommandUnlockPacketRes, + CommandUnlockRefusePacketRes +} from "../../../../Lib/src/packets/commands/CommandUnlockPacket"; import {ReactionCollectorCreationPacket} from "../../../../Lib/src/packets/interaction/ReactionCollectorPacket"; import {DraftBotEmbed} from "../../messages/DraftBotEmbed"; import {DiscordCollectorUtils} from "../../utils/DiscordCollectorUtils"; diff --git a/Discord/src/packetHandlers/handlers/CommandRequirementHandlers.ts b/Discord/src/packetHandlers/handlers/CommandRequirementHandlers.ts index 3261a63d0..274b70a4d 100644 --- a/Discord/src/packetHandlers/handlers/CommandRequirementHandlers.ts +++ b/Discord/src/packetHandlers/handlers/CommandRequirementHandlers.ts @@ -25,7 +25,7 @@ export default class CommandRequirementHandlers { if (interaction.deferred) { interaction.deleteReply(); } - interaction?.followUp({ + await (interaction.replied ? interaction.followUp : interaction.reply)({ embeds: [ new DraftBotEmbed() .setErrorColor() From 58f3ffa9b77b2ec8d635bb37f15ef9a60b202145 Mon Sep 17 00:00:00 2001 From: romain22222 Date: Mon, 9 Dec 2024 16:25:54 +0100 Subject: [PATCH 07/17] fixing several issues issues concerning DraftbotInteraction's error management #2590 (maybe #2661 ?) --- Discord/src/messages/DraftbotInteraction.ts | 25 ++++++++++++--------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Discord/src/messages/DraftbotInteraction.ts b/Discord/src/messages/DraftbotInteraction.ts index 67438bc7b..b50ae3396 100644 --- a/Discord/src/messages/DraftbotInteraction.ts +++ b/Discord/src/messages/DraftbotInteraction.ts @@ -28,11 +28,9 @@ type ReplyFunctionLike = (options: OptionValue) => Promise export class DraftbotInteraction extends DraftbotInteractionWithoutSendCommands { public userLanguage: Language = LANGUAGE.DEFAULT_LANGUAGE; - // @ts-expect-error - Property 'options' is initialized in the caster, which is the only normal way to create a DraftbotInteraction - public options: CommandInteractionOptionResolver; + public options!: CommandInteractionOptionResolver; - // @ts-expect-error - Property '_channel' is initialized in the caster, which is the only normal way to create a DraftbotInteraction - private _channel: DraftbotChannel; + private _channel!: DraftbotChannel; /** * Get the channel of the interaction @@ -179,8 +177,8 @@ export class DraftbotInteraction extends DraftbotInteractionWithoutSendCommands * @param fallback function to execute if the bot can't send the message */ public async reply(options: OptionLike, fallback?: () => void | Promise): Promise { - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - return await DraftbotInteraction.prototype.commonSendCommand(CommandInteraction.prototype.reply.bind(this), options as ReplyOptionsSpecial, fallback ?? (() => { + // @ts-expect-error - We consider that the following function passed as argument has the correct typing + return await DraftbotInteraction.prototype.commonSendCommand.call(this, CommandInteraction.prototype.reply.bind(this), options, fallback ?? (() => { // Do nothing by default if no fallback is provided })) as Message; } @@ -191,8 +189,7 @@ export class DraftbotInteraction extends DraftbotInteractionWithoutSendCommands * @param fallback function to execute if the bot can't send the message */ public async followUp(options: OptionLike, fallback?: () => void | Promise): Promise { - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - return await DraftbotInteraction.prototype.commonSendCommand(CommandInteraction.prototype.followUp.bind(this), options, fallback ?? (() => { + return await DraftbotInteraction.prototype.commonSendCommand.call(this, CommandInteraction.prototype.followUp.bind(this), options, fallback ?? (() => { // Do nothing by default if no fallback is provided })) as Message; } @@ -215,7 +212,7 @@ export class DraftbotInteraction extends DraftbotInteractionWithoutSendCommands return await functionPrototype(options); } catch (e) { - console.error(`Weird Permission Error ${(e as Error).stack}`); + console.error(`An error occured during a send, either a permission issue or a send/reply/followUp/editReply conflict : ${(e as Error).stack}`); await DraftbotInteraction.prototype.manageFallback.bind(this)(functionPrototype); await fallback(); return null; @@ -227,7 +224,7 @@ export class DraftbotInteraction extends DraftbotInteractionWithoutSendCommands * @private */ private async manageFallback(functionPrototype: ReplyFunctionLike): Promise { - const errorText = i18n.t("bot:noSpeakPermission", {lng: this.channel.language}); + const errorText = i18n.t("bot:noSpeakPermission", {lng: this.userLanguage}); try { // @ts-expect-error - We consider that the functionPrototype is a function that can be called with these parameters (i.e, accepts a InteractionReplyOptions) await functionPrototype.call(this, { @@ -236,12 +233,18 @@ export class DraftbotInteraction extends DraftbotInteractionWithoutSendCommands }); } catch (e) { + if (functionPrototype !== DraftbotChannel.prototype.send) { + // try again to manage fallback with the send function + // @ts-expect-error - We consider that the functionPrototype is a function that can be called with these parameters (i.e, accepts a InteractionReplyOptions) + await DraftbotInteraction.prototype.manageFallback.bind(this)(BaseGuildTextChannel.prototype.send.bind(this.channel)); + return; + } // We can't send ephemeral message, so we send the message in DM try { await CommandInteraction.prototype.user.send.bind(this.user)({content: errorText}); } catch (e) { - console.log(`Unable to alert user of no speak permission : c:${this.channel.id} / u:${this.user.id}`); + console.log(`Unable to alert user of no speak permission : c:${this.channel?.id} / u:${this.user?.id}`); } } } From 912ed72a265945d74e64f79344e2a937d1e075c7 Mon Sep 17 00:00:00 2001 From: BastLast Date: Tue, 10 Dec 2024 00:17:30 +0100 Subject: [PATCH 08/17] fixes unlock command #2273 --- Core/src/commands/player/UnlockCommand.ts | 2 +- Discord/src/commands/player/UnlockCommand.ts | 5 +++-- Discord/src/messages/DraftbotInteraction.ts | 6 +++--- Lang/fr/commands.json | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Core/src/commands/player/UnlockCommand.ts b/Core/src/commands/player/UnlockCommand.ts index 970f1d7e7..932ec90d2 100644 --- a/Core/src/commands/player/UnlockCommand.ts +++ b/Core/src/commands/player/UnlockCommand.ts @@ -57,7 +57,7 @@ function unlockCannotBeDone(player: Player, freedPlayer: Player, response: Draft foundPlayer: freedPlayer === null, notInJail: freedPlayer?.effectId !== Effect.JAILED.id, money: player.money, - himself: player.id === freedPlayer.id + himself: player.id === freedPlayer?.id })); return true; } diff --git a/Discord/src/commands/player/UnlockCommand.ts b/Discord/src/commands/player/UnlockCommand.ts index 7fc069a5b..9c98606c4 100644 --- a/Discord/src/commands/player/UnlockCommand.ts +++ b/Discord/src/commands/player/UnlockCommand.ts @@ -102,7 +102,8 @@ export async function createUnlockCollector(packet: ReactionCollectorCreationPac .setDescription( i18n.t("commands:unlock.confirmDesc", { lng: interaction.userLanguage, - kickedPseudo: unlockedPlayer.attributes.gameUsername + pseudo: unlockedPlayer.attributes.gameUsername, + price: UnlockConstants.PRICE_FOR_UNLOCK }) ); @@ -158,7 +159,7 @@ export async function handleCommandUnlockAcceptPacketRes(packet: CommandUnlockAc .setDescription( i18n.t("commands:unlock.acceptedDesc", { lng: originalInteraction.userLanguage, - kickedPseudo: unlockedPlayer.attributes.gameUsername + pseudo: unlockedPlayer.attributes.gameUsername }) ) ] diff --git a/Discord/src/messages/DraftbotInteraction.ts b/Discord/src/messages/DraftbotInteraction.ts index b50ae3396..de9f32e00 100644 --- a/Discord/src/messages/DraftbotInteraction.ts +++ b/Discord/src/messages/DraftbotInteraction.ts @@ -178,7 +178,7 @@ export class DraftbotInteraction extends DraftbotInteractionWithoutSendCommands */ public async reply(options: OptionLike, fallback?: () => void | Promise): Promise { // @ts-expect-error - We consider that the following function passed as argument has the correct typing - return await DraftbotInteraction.prototype.commonSendCommand.call(this, CommandInteraction.prototype.reply.bind(this), options, fallback ?? (() => { + return await DraftbotInteraction.prototype.commonSendCommand.call(this, CommandInteraction.prototype.reply.bind(this), options, fallback ?? ((): void => { // Do nothing by default if no fallback is provided })) as Message; } @@ -189,7 +189,7 @@ export class DraftbotInteraction extends DraftbotInteractionWithoutSendCommands * @param fallback function to execute if the bot can't send the message */ public async followUp(options: OptionLike, fallback?: () => void | Promise): Promise { - return await DraftbotInteraction.prototype.commonSendCommand.call(this, CommandInteraction.prototype.followUp.bind(this), options, fallback ?? (() => { + return await DraftbotInteraction.prototype.commonSendCommand.call(this, CommandInteraction.prototype.followUp.bind(this), options, fallback ?? ((): void => { // Do nothing by default if no fallback is provided })) as Message; } @@ -234,7 +234,7 @@ export class DraftbotInteraction extends DraftbotInteractionWithoutSendCommands } catch (e) { if (functionPrototype !== DraftbotChannel.prototype.send) { - // try again to manage fallback with the send function + // Try again to manage fallback with the send function // @ts-expect-error - We consider that the functionPrototype is a function that can be called with these parameters (i.e, accepts a InteractionReplyOptions) await DraftbotInteraction.prototype.manageFallback.bind(this)(BaseGuildTextChannel.prototype.send.bind(this.channel)); return; diff --git a/Lang/fr/commands.json b/Lang/fr/commands.json index 50365ed1a..6652661bc 100644 --- a/Lang/fr/commands.json +++ b/Lang/fr/commands.json @@ -706,9 +706,9 @@ "himself": "Vous ne pouvez pas vous libérer vous-même, demandez à un ami de le faire.", "notInJail": "Ce joueur n'est pas en prison.", "title": "Libération de {{pseudo}}", - "confirmDesc": "Êtes-vous sûr de vouloir libérer **{{pseudo}}** ?", + "confirmDesc": "Êtes-vous sûr de vouloir libérer **{{pseudo}}** pour **{{price}} {emote:unitValues.money}**?", "canceledTitle": "Libération annulée", - "canceledDesc": "La libération de **{{pseudo}}** a été annulée.", + "canceledDesc": "La libération a été annulée.", "acceptedDesc": "Vous avez libéré **{{pseudo}}** !" } } \ No newline at end of file From cc6639a0bd705c42e1c701d039e30a8fa24aba88 Mon Sep 17 00:00:00 2001 From: romain22222 Date: Wed, 11 Dec 2024 11:15:22 +0100 Subject: [PATCH 09/17] light test command upgrades --- .../testCommands/Infos/HelpTestCommand.ts | 10 ++++++++-- .../testCommands/Infos/MyIDTestCommand.ts | 2 +- .../testCommands/Map/SmallEventTestCommand.ts | 1 + .../testCommands/Player/UnblockTestCommand.ts | 20 +++++++++++++++++++ Core/src/core/CommandsTest.ts | 19 ++++++++++++++---- Core/src/core/utils/BlockingUtils.ts | 4 ++-- Core/src/core/utils/CommandUtils.ts | 2 +- Lib/src/utils/StringUtils.ts | 2 +- 8 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 Core/src/commands/admin/testCommands/Player/UnblockTestCommand.ts diff --git a/Core/src/commands/admin/testCommands/Infos/HelpTestCommand.ts b/Core/src/commands/admin/testCommands/Infos/HelpTestCommand.ts index 4a14c0edc..dac80a74b 100644 --- a/Core/src/commands/admin/testCommands/Infos/HelpTestCommand.ts +++ b/Core/src/commands/admin/testCommands/Infos/HelpTestCommand.ts @@ -1,4 +1,10 @@ -import {CommandsTest, ExecuteTestCommandLike, ITestCommand, TypeKey} from "../../../../core/CommandsTest"; +import { + CommandsTest, + ExecuteTestCommandLike, + formatTypeWaited, + ITestCommand, + TypeKey +} from "../../../../core/CommandsTest"; export const commandInfo: ITestCommand = { name: "help", @@ -29,7 +35,7 @@ ${helpOnCommand.description} **Utilisation :** \`test ${helpOnCommand.name}${helpOnCommand.commandFormat === "" ? "" : ` ${helpOnCommand.commandFormat}`}\` ${hasArguments ? `**Argument${argsAmount === 1 ? "" : "s"} attendu${argsAmount === 1 ? "" : "s"} :**` : ""} ${hasArguments ? Object.keys(helpOnCommand.typeWaited) - .map((arg) => `- \`<${arg}>\` : ${helpOnCommand.typeWaited[arg]}`) + .map((arg) => `- \`<${arg}>\` : ${formatTypeWaited(helpOnCommand.typeWaited[arg])}`) .join("\n") : ""} ${hasAliases ? `**Alias :** \`${helpOnCommand.aliases.join("`, `")}\`` : ""}`; }; diff --git a/Core/src/commands/admin/testCommands/Infos/MyIDTestCommand.ts b/Core/src/commands/admin/testCommands/Infos/MyIDTestCommand.ts index ac7a0e5c6..ea1517d55 100644 --- a/Core/src/commands/admin/testCommands/Infos/MyIDTestCommand.ts +++ b/Core/src/commands/admin/testCommands/Infos/MyIDTestCommand.ts @@ -8,6 +8,6 @@ export const commandInfo: ITestCommand = { /** * Show your player's ID */ -const myIDTestCommand: ExecuteTestCommandLike = (player) => `Player id: ${player.id}`; +const myIDTestCommand: ExecuteTestCommandLike = (player) => `Player id: ${player.id}\nKeycloak id: ${player.keycloakId}`; commandInfo.execute = myIDTestCommand; \ No newline at end of file diff --git a/Core/src/commands/admin/testCommands/Map/SmallEventTestCommand.ts b/Core/src/commands/admin/testCommands/Map/SmallEventTestCommand.ts index fe9304118..65f5d96b7 100644 --- a/Core/src/commands/admin/testCommands/Map/SmallEventTestCommand.ts +++ b/Core/src/commands/admin/testCommands/Map/SmallEventTestCommand.ts @@ -12,6 +12,7 @@ smallEventsKeys export const commandInfo: ITestCommand = { name: "smallEvent", + aliases: ["se"], commandFormat: "", typeWaited: { seName: TypeKey.STRING diff --git a/Core/src/commands/admin/testCommands/Player/UnblockTestCommand.ts b/Core/src/commands/admin/testCommands/Player/UnblockTestCommand.ts new file mode 100644 index 000000000..c8304ddc4 --- /dev/null +++ b/Core/src/commands/admin/testCommands/Player/UnblockTestCommand.ts @@ -0,0 +1,20 @@ +import {ExecuteTestCommandLike, ITestCommand} from "../../../../core/CommandsTest"; +import {BlockingUtils} from "../../../../core/utils/BlockingUtils"; + +export const commandInfo: ITestCommand = { + name: "unblock", + description: "Vous permet de vous débloquer lorsqu'une commande vous bloque (ATTENTION: si vous obtenez un exploit avec cette commande, ce n'en est pas un)" +}; + +/** + * Unblock the player + */ +const unblockTestCommand: ExecuteTestCommandLike = async (player, _args, response) => { + const reasons = BlockingUtils.getPlayerBlockingReason(player.id).map(r => { + BlockingUtils.unblockPlayer(player.id, r); + return r; + }); + return "Vous vous êtes débloqué des raisons suivantes : " + reasons.join(", "); +}; + +commandInfo.execute = unblockTestCommand; diff --git a/Core/src/core/CommandsTest.ts b/Core/src/core/CommandsTest.ts index 02f144397..8ed551d58 100644 --- a/Core/src/core/CommandsTest.ts +++ b/Core/src/core/CommandsTest.ts @@ -1,6 +1,6 @@ import {readdir} from "fs/promises"; import {readdirSync} from "fs"; -import {isAnId, isAnEmoji} from "../../../Lib/src/utils/StringUtils"; +import {isAnEmoji, isAnId} from "../../../Lib/src/utils/StringUtils"; import {DraftBotPacket, PacketContext} from "../../../Lib/src/packets/DraftBotPacket"; import Player from "./database/game/models/Player"; @@ -14,12 +14,23 @@ export enum TypeKey { } const typeVariableChecks: Map = new Map([ - [TypeKey.INTEGER, (v: string): boolean => !isNaN(parseInt(v, 10))], [TypeKey.ID, (v: string): boolean => isAnId(v)], + [TypeKey.INTEGER, (v: string): boolean => !isNaN(parseInt(v, 10))], [TypeKey.EMOJI, (v: string): boolean => isAnEmoji(v)], [TypeKey.STRING, (): boolean => false] ]); +const typeVariableFormatLike: Map = new Map([ + [TypeKey.ID, "0a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c (voir `/test command:myids`)"], + [TypeKey.INTEGER, "###"], + [TypeKey.EMOJI, "<:emoteName:123456789012345678>"], + [TypeKey.STRING, "texte"] +]); + +export function formatTypeWaited(typeWaited: TypeKey): string { + return `\`${typeWaited}\`(${typeVariableFormatLike.get(typeWaited)})`; +} + export interface ITestCommand { name: string, aliases?: string[], @@ -88,8 +99,8 @@ export class CommandsTest { description: `❌ Mauvais argument pour la commande test ${commandTest.name} **Format attendu** : \`test ${commandTest.name} ${commandTest.commandFormat}\` -**Format de l'argument** \`<${commandTypeKeys[i]}>\` : ${commandTest.typeWaited[commandTypeKeys[i]]} -**Format reçu** : ${CommandsTest.getTypeOf(args[i])}` +**Format de l'argument** \`<${commandTypeKeys[i]}>\` : ${formatTypeWaited(commandTest.typeWaited[commandTypeKeys[i]])} +**Format reçu** : ${formatTypeWaited(CommandsTest.getTypeOf(args[i]))}` }; } } diff --git a/Core/src/core/utils/BlockingUtils.ts b/Core/src/core/utils/BlockingUtils.ts index b42478134..b30057eb1 100644 --- a/Core/src/core/utils/BlockingUtils.ts +++ b/Core/src/core/utils/BlockingUtils.ts @@ -65,9 +65,9 @@ export class BlockingUtils { * Gets why this player is blocked (empty list means it isn't blocked) * @param playerId */ - static getPlayerBlockingReason(playerId: number): string[] { + static getPlayerBlockingReason(playerId: number): BlockingReason[] { const blockedPlayer = BlockingUtils.blockedPlayers.get(playerId); - const response = []; + const response: BlockingReason[] = []; if (blockedPlayer) { for (const block of blockedPlayer) { if (block.limitTimestamp !== 0 && block.limitTimestamp < Date.now()) { diff --git a/Core/src/core/utils/CommandUtils.ts b/Core/src/core/utils/CommandUtils.ts index de150e37c..985b89ee1 100644 --- a/Core/src/core/utils/CommandUtils.ts +++ b/Core/src/core/utils/CommandUtils.ts @@ -191,7 +191,7 @@ export const commandRequires = (packet: PacketLike, draftBotInstance.packetListener.addPacketListener(packet, async (response: DraftBotPacket[], packet: T, context: PacketContext): Promise => { const player = await Players.getOrRegister(context.keycloakId); // Warning: order of the checks is important, as appendBlockedPacket can add a packet to the response - if (!requirements.notBlocked && BlockingUtils.appendBlockedPacket(player, response)) { + if (requirements.notBlocked && BlockingUtils.appendBlockedPacket(player, response)) { return; } diff --git a/Lib/src/utils/StringUtils.ts b/Lib/src/utils/StringUtils.ts index 1b33cfbb7..d8a37ba6b 100644 --- a/Lib/src/utils/StringUtils.ts +++ b/Lib/src/utils/StringUtils.ts @@ -71,7 +71,7 @@ export function discordIdToMention(id: string): string { } /** - * Check if the given variable is a Discord Mention + * Check if the given variable is a Keycloak id * @param {String} variable * @return {boolean} */ From 2a5e2800c88f906e2f009e3f0b701f7cd323579f Mon Sep 17 00:00:00 2001 From: romain22222 Date: Wed, 11 Dec 2024 11:34:21 +0100 Subject: [PATCH 10/17] effect messers prevention to avoid stupid non coherent situations --- .../admin/testCommands/Player/UnblockTestCommand.ts | 4 ++-- .../admin/testCommands/Time/JailPlayerTestCommand.ts | 4 ++++ .../admin/testCommands/Time/PlayerEffectTestCommand.ts | 7 +++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Core/src/commands/admin/testCommands/Player/UnblockTestCommand.ts b/Core/src/commands/admin/testCommands/Player/UnblockTestCommand.ts index c8304ddc4..9d047873c 100644 --- a/Core/src/commands/admin/testCommands/Player/UnblockTestCommand.ts +++ b/Core/src/commands/admin/testCommands/Player/UnblockTestCommand.ts @@ -9,12 +9,12 @@ export const commandInfo: ITestCommand = { /** * Unblock the player */ -const unblockTestCommand: ExecuteTestCommandLike = async (player, _args, response) => { +const unblockTestCommand: ExecuteTestCommandLike = (player) => { const reasons = BlockingUtils.getPlayerBlockingReason(player.id).map(r => { BlockingUtils.unblockPlayer(player.id, r); return r; }); - return "Vous vous êtes débloqué des raisons suivantes : " + reasons.join(", "); + return `Vous vous êtes débloqué des raisons suivantes : ${reasons.join(", ")}`; }; commandInfo.execute = unblockTestCommand; diff --git a/Core/src/commands/admin/testCommands/Time/JailPlayerTestCommand.ts b/Core/src/commands/admin/testCommands/Time/JailPlayerTestCommand.ts index 600c992a9..130b19f69 100644 --- a/Core/src/commands/admin/testCommands/Time/JailPlayerTestCommand.ts +++ b/Core/src/commands/admin/testCommands/Time/JailPlayerTestCommand.ts @@ -19,6 +19,10 @@ export const commandInfo: ITestCommand = { */ const jailPlayerTestCommand: ExecuteTestCommandLike = async (player, args) => { const jailPlayer = await Players.getByKeycloakId(player.keycloakId); + if (jailPlayer.effectId === Effect.NOT_STARTED.id) { + // Prevent the non initialized player to mess with the game's travel logic + throw new Error("Ce joueur n'a pas encore démarré l'aventure, laissez lui le temps de commencer !"); + } await TravelTime.applyEffect(jailPlayer, Effect.JAILED, 0, new Date(), NumberChangeReason.TEST); await jailPlayer.save(); return `Vous avez enfermé ${args[0]} !`; diff --git a/Core/src/commands/admin/testCommands/Time/PlayerEffectTestCommand.ts b/Core/src/commands/admin/testCommands/Time/PlayerEffectTestCommand.ts index 3b9d71185..fd3a8fd16 100644 --- a/Core/src/commands/admin/testCommands/Time/PlayerEffectTestCommand.ts +++ b/Core/src/commands/admin/testCommands/Time/PlayerEffectTestCommand.ts @@ -27,6 +27,13 @@ const playerEffectTestCommand: ExecuteTestCommandLike = async (player, args) => if (!effect) { throw new Error("Effet inconnu !"); } + if ([Effect.NOT_STARTED, Effect.NO_EFFECT, Effect.DEAD, Effect.OCCUPIED].includes(effect)) { + throw new Error("Cet effet ne peut pas être appliqué !"); + } + if (player.effectId === Effect.NOT_STARTED.id) { + // Prevent the non initialized player to mess with the game's travel logic + throw new Error("Vous n'avez pas encore démarré l'aventure, laisse toi le temps de commencer (`/test command:init`) !"); + } await TravelTime.applyEffect(player, effect, 0, new Date(), NumberChangeReason.TEST); await player.save(); return `Vous avez maintenant l'effet ${effect.id} !`; From c971106c0ae55812cf33416e1eb969a975724673 Mon Sep 17 00:00:00 2001 From: romain22222 Date: Wed, 11 Dec 2024 11:58:45 +0100 Subject: [PATCH 11/17] small fixes --- Core/resources/mapLinks/29.json | 6 +++--- Core/resources/mapLinks/35.json | 6 +++--- Lang/fr/commands.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Core/resources/mapLinks/29.json b/Core/resources/mapLinks/29.json index 5e2e72da7..ad67f57c7 100644 --- a/Core/resources/mapLinks/29.json +++ b/Core/resources/mapLinks/29.json @@ -1,5 +1,5 @@ { - "startMap": 23, - "endMap": 21, - "tripDuration": 420 + "startMap": 23, + "endMap": 21, + "tripDuration": 240 } \ No newline at end of file diff --git a/Core/resources/mapLinks/35.json b/Core/resources/mapLinks/35.json index 0f218739d..613ba68a6 100644 --- a/Core/resources/mapLinks/35.json +++ b/Core/resources/mapLinks/35.json @@ -1,5 +1,5 @@ { - "startMap": 21, - "endMap": 23, - "tripDuration": 420 + "startMap": 21, + "endMap": 23, + "tripDuration": 240 } \ No newline at end of file diff --git a/Lang/fr/commands.json b/Lang/fr/commands.json index 6652661bc..1e62a217b 100644 --- a/Lang/fr/commands.json +++ b/Lang/fr/commands.json @@ -424,7 +424,7 @@ "destinationTitle": "{{pseudo}}, destination du voyage", "doChoice": "{{emoji}} {{choiceText}}\n", "doEvent": ":newspaper: **Journal de {{pseudo}} :** {{event}}\n*- Utilisez les réactions pour effectuer une action ⚠️ Ne pas répondre est considéré comme un choix à part.*", - "doPossibility": ":newspaper: **Journal de {{pseudo}} {{result}}** | {{emoji}}{{event}} {{alte}}", + "doPossibility": ":newspaper: **Journal de {{pseudo}} {{result}}** | {{emoji}} {{event}} {{alte}}", "encounterMonster": [ "Vous arrivez à votre destination quand soudain, vous entendez un bruit derrière vous... Un monstre vous attaque !" ], From 1b490e2b98c15f653a736a36b45985396c04ded7 Mon Sep 17 00:00:00 2001 From: romain22222 Date: Wed, 11 Dec 2024 14:27:00 +0100 Subject: [PATCH 12/17] fix error handlers unlock command #2273 --- Core/src/commands/player/UnlockCommand.ts | 25 ++++++--- .../src/commands/guild/GuildDailyCommand.ts | 14 ----- .../src/commands/player/DailyBonusCommand.ts | 20 ------- Discord/src/commands/player/RespawnCommand.ts | 13 ----- Discord/src/commands/player/UnlockCommand.ts | 54 +++++-------------- .../handlers/CommandHandlers.ts | 53 ++++++++++-------- Discord/src/utils/ErrorUtils.ts | 25 +++++++++ .../packets/commands/CommandUnlockPacket.ts | 18 +++++-- 8 files changed, 101 insertions(+), 121 deletions(-) diff --git a/Core/src/commands/player/UnlockCommand.ts b/Core/src/commands/player/UnlockCommand.ts index 932ec90d2..985d8fa7e 100644 --- a/Core/src/commands/player/UnlockCommand.ts +++ b/Core/src/commands/player/UnlockCommand.ts @@ -2,8 +2,11 @@ import {DraftBotPacket, makePacket, PacketContext} from "../../../../Lib/src/pac import {Player, Players} from "../../core/database/game/models/Player"; import { CommandUnlockAcceptPacketRes, + CommandUnlockHimself, + CommandUnlockNoPlayerFound, + CommandUnlockNotEnoughMoney, + CommandUnlockNotInJail, CommandUnlockPacketReq, - CommandUnlockPacketRes, CommandUnlockRefusePacketRes } from "../../../../Lib/src/packets/commands/CommandUnlockPacket"; import {EndCallback, ReactionCollectorInstance} from "../../core/utils/ReactionsCollector"; @@ -51,16 +54,24 @@ async function acceptUnlock(player: Player, freedPlayer: Player, response: Draft * @param response The response to send */ function unlockCannotBeDone(player: Player, freedPlayer: Player, response: DraftBotPacket[]): boolean { - if (freedPlayer === null || player.money < UnlockConstants.PRICE_FOR_UNLOCK || player.id === freedPlayer.id || freedPlayer.effectId !== Effect.JAILED.id) { - // There is a problem - response.push(makePacket(CommandUnlockPacketRes, { - foundPlayer: freedPlayer === null, - notInJail: freedPlayer?.effectId !== Effect.JAILED.id, + if (freedPlayer === null) { + response.push(makePacket(CommandUnlockNoPlayerFound, {})); + return true; + } + if (player.money < UnlockConstants.PRICE_FOR_UNLOCK) { + response.push(makePacket(CommandUnlockNotEnoughMoney, { money: player.money, - himself: player.id === freedPlayer?.id })); return true; } + if (player.id === freedPlayer.id) { + response.push(makePacket(CommandUnlockHimself, {})); + return true; + } + if (freedPlayer.effectId !== Effect.JAILED.id) { + response.push(makePacket(CommandUnlockNotInJail, {})); + return true; + } return false; } diff --git a/Discord/src/commands/guild/GuildDailyCommand.ts b/Discord/src/commands/guild/GuildDailyCommand.ts index 1e0677430..0e95844b0 100644 --- a/Discord/src/commands/guild/GuildDailyCommand.ts +++ b/Discord/src/commands/guild/GuildDailyCommand.ts @@ -2,7 +2,6 @@ import {makePacket, PacketContext} from "../../../../Lib/src/packets/DraftBotPac import { CommandGuildDailyCooldownErrorPacket, CommandGuildDailyPacketReq, - CommandGuildDailyPveIslandErrorPacket, CommandGuildDailyRewardPacket } from "../../../../Lib/src/packets/commands/CommandGuildDailyPacket"; import {ICommand} from "../ICommand"; @@ -96,19 +95,6 @@ export async function handleCommandGuildDailyCooldownErrorPacket(packet: Command }); } -export async function handleCommandGuildDailyPveIslandErrorPacket(packet: CommandGuildDailyPveIslandErrorPacket, context: PacketContext): Promise { - const interaction = DiscordCache.getInteraction(context.discord!.interaction!)!; - await interaction.reply({ - embeds: [ - new DraftBotErrorEmbed( - interaction.user, - interaction, - i18n.t("commands:guildDaily.pveIslandError", {lng: context.discord!.language}) - ) - ] - }); -} - export const commandInfo: ICommand = { slashCommandBuilder: SlashCommandBuilderGenerator.generateBaseCommand("guildDaily") as SlashCommandBuilder, getPacket, diff --git a/Discord/src/commands/player/DailyBonusCommand.ts b/Discord/src/commands/player/DailyBonusCommand.ts index 1133477ca..78411bce0 100644 --- a/Discord/src/commands/player/DailyBonusCommand.ts +++ b/Discord/src/commands/player/DailyBonusCommand.ts @@ -22,26 +22,6 @@ async function getPacket(interaction: DraftbotInteraction): Promise { - const interaction = DiscordCache.getInteraction(context.discord!.interaction); - await interaction?.editReply({ - embeds: [ - new DraftBotErrorEmbed( - interaction.user, - interaction, - i18n.t(errorKey, { - lng: interaction.userLanguage - }) - ) - ] - }); -} - /** * Handle daily bonus cooldown error * @param context diff --git a/Discord/src/commands/player/RespawnCommand.ts b/Discord/src/commands/player/RespawnCommand.ts index bf5166886..4e8d5cc5a 100644 --- a/Discord/src/commands/player/RespawnCommand.ts +++ b/Discord/src/commands/player/RespawnCommand.ts @@ -2,7 +2,6 @@ import {ICommand} from "../ICommand"; import {makePacket, PacketContext} from "../../../../Lib/src/packets/DraftBotPacket"; import {SlashCommandBuilderGenerator} from "../SlashCommandBuilderGenerator"; import { - CommandRespawnErrorAlreadyAlive, CommandRespawnPacketReq, CommandRespawnPacketRes } from "../../../../Lib/src/packets/commands/CommandRespawnPacket"; @@ -40,18 +39,6 @@ export async function handleCommandRespawnPacketRes(packet: CommandRespawnPacket }); } -/** - * Handle the error when the player is already alive - * @param packet - * @param context - */ -export async function handleCommandRespawnErrorAlreadyAlive(packet: CommandRespawnErrorAlreadyAlive, context: PacketContext): Promise { - const interaction = DiscordCache.getInteraction(context.discord!.interaction); - await interaction?.editReply({ - content: i18n.t("commands:respawn.alreadyAlive", {lng: interaction.userLanguage}) - }); -} - export const commandInfo: ICommand = { slashCommandBuilder: SlashCommandBuilderGenerator.generateBaseCommand("respawn"), getPacket, diff --git a/Discord/src/commands/player/UnlockCommand.ts b/Discord/src/commands/player/UnlockCommand.ts index 9c98606c4..c330a061a 100644 --- a/Discord/src/commands/player/UnlockCommand.ts +++ b/Discord/src/commands/player/UnlockCommand.ts @@ -8,8 +8,8 @@ import {DiscordCache} from "../../bot/DiscordCache"; import {KeycloakUser} from "../../../../Lib/src/keycloak/KeycloakUser"; import { CommandUnlockAcceptPacketRes, + CommandUnlockNotEnoughMoney, CommandUnlockPacketReq, - CommandUnlockPacketRes, CommandUnlockRefusePacketRes } from "../../../../Lib/src/packets/commands/CommandUnlockPacket"; import {ReactionCollectorCreationPacket} from "../../../../Lib/src/packets/interaction/ReactionCollectorPacket"; @@ -35,54 +35,24 @@ async function getPacket(interaction: DraftbotInteraction, user: KeycloakUser): } /** - * Handle the answer from the server after an unlock command request - * This packet is only sent if the unlocking cannot be done for some reason + * * @param packet * @param context */ -export async function handleCommandUnlockPacketRes(packet: CommandUnlockPacketRes, context: PacketContext): Promise { +export async function handleCommandUnlockNotEnoughMoneyError(packet: CommandUnlockNotEnoughMoney, context: PacketContext): Promise { const interaction = DiscordCache.getInteraction(context.discord!.interaction); if (!interaction) { return; } - if (!packet.foundPlayer) { - await sendErrorMessage( - interaction.user, - interaction, - i18n.t("error:playerDoesntExist", {lng: interaction.userLanguage}), - {sendManner: SendManner.REPLY} - ); - return; - } - if (packet.notInJail) { - await sendErrorMessage( - interaction.user, - interaction, - i18n.t("commands:unlock.notInJail", {lng: interaction.userLanguage}), - {sendManner: SendManner.REPLY} - ); - return; - } - if (packet.money < UnlockConstants.PRICE_FOR_UNLOCK) { - await sendErrorMessage( - interaction.user, - interaction, - i18n.t("error:notEnoughMoney", { - lng: interaction.userLanguage, - money: UnlockConstants.PRICE_FOR_UNLOCK - packet.money - }), - {sendManner: SendManner.REPLY} - ); - return; - } - if (packet.himself) { - await sendErrorMessage( - interaction.user, - interaction, - i18n.t("commands:unlock.himself", {lng: interaction.userLanguage}), - {sendManner: SendManner.REPLY} - ); - } + await sendErrorMessage( + interaction.user, + interaction, + i18n.t("error:notEnoughMoney", { + lng: interaction.userLanguage, + money: UnlockConstants.PRICE_FOR_UNLOCK - packet.money + }), + {sendManner: SendManner.REPLY} + ); } /** diff --git a/Discord/src/packetHandlers/handlers/CommandHandlers.ts b/Discord/src/packetHandlers/handlers/CommandHandlers.ts index 652adaf4f..c22b7bb71 100644 --- a/Discord/src/packetHandlers/handlers/CommandHandlers.ts +++ b/Discord/src/packetHandlers/handlers/CommandHandlers.ts @@ -15,10 +15,7 @@ import {CommandRarityPacketRes} from "../../../../Lib/src/packets/commands/Comma import {handleCommandRarityPacketRes} from "../../commands/player/RarityCommand"; import {handleCommandTestPacketRes} from "../../commands/admin/TestCommand"; import {handleCommandGuildPacketRes} from "../../commands/guild/GuildCommand"; -import { - handleCommandRespawnErrorAlreadyAlive, - handleCommandRespawnPacketRes -} from "../../commands/player/RespawnCommand"; +import {handleCommandRespawnPacketRes} from "../../commands/player/RespawnCommand"; import {CommandGuildPacketRes} from "../../../../Lib/src/packets/commands/CommandGuildPacket"; import { handleCommandGuildCreateAcceptPacketRes, @@ -128,7 +125,6 @@ import { } from "../../../../Lib/src/packets/commands/CommandGuildDailyPacket"; import { handleCommandGuildDailyCooldownErrorPacket, - handleCommandGuildDailyPveIslandErrorPacket, handleCommandGuildDailyRewardPacket } from "../../commands/guild/GuildDailyCommand"; import { @@ -148,21 +144,21 @@ import { CommandDailyBonusObjectIsActiveDuringFights, CommandDailyBonusPacketRes } from "../../../../Lib/src/packets/commands/CommandDailyBonusPacket"; -import { - handleDailyBonusClassicError, - handleDailyBonusCooldownError, - handleDailyBonusRes -} from "../../commands/player/DailyBonusCommand"; +import {handleDailyBonusCooldownError, handleDailyBonusRes} from "../../commands/player/DailyBonusCommand"; import { CommandUnlockAcceptPacketRes, - CommandUnlockPacketRes, + CommandUnlockHimself, + CommandUnlockNoPlayerFound, + CommandUnlockNotEnoughMoney, + CommandUnlockNotInJail, CommandUnlockRefusePacketRes } from "../../../../Lib/src/packets/commands/CommandUnlockPacket"; import { handleCommandUnlockAcceptPacketRes, - handleCommandUnlockPacketRes, + handleCommandUnlockNotEnoughMoneyError, handleCommandUnlockRefusePacketRes } from "../../commands/player/UnlockCommand"; +import {handleClassicError} from "../../utils/ErrorUtils"; export default class CommandHandlers { @packetHandler(CommandPingPacketRes) @@ -346,8 +342,8 @@ export default class CommandHandlers { } @packetHandler(CommandRespawnErrorAlreadyAlive) - async respawnErrorAlreadyAlive(packet: CommandRespawnErrorAlreadyAlive, context: PacketContext): Promise { - await handleCommandRespawnErrorAlreadyAlive(packet, context); + async respawnErrorAlreadyAlive(_packet: CommandRespawnErrorAlreadyAlive, context: PacketContext): Promise { + await handleClassicError(context, "commands:respawn.alreadyAlive"); } @packetHandler(CommandShopClosed) @@ -447,7 +443,7 @@ export default class CommandHandlers { @packetHandler(CommandGuildDailyPveIslandErrorPacket) async guildDailyPveIslandError(packet: CommandGuildDailyPveIslandErrorPacket, context: PacketContext): Promise { - await handleCommandGuildDailyPveIslandErrorPacket(packet, context); + await handleClassicError(context, "commands:guildDaily.pveIslandError"); } @packetHandler(CommandDailyBonusPacketRes) @@ -457,17 +453,17 @@ export default class CommandHandlers { @packetHandler(CommandDailyBonusObjectDoNothing) async dailyBonusObjectDoNothing(_packet: CommandDailyBonusObjectDoNothing, context: PacketContext): Promise { - await handleDailyBonusClassicError(context, "commands:daily.errors.objectDoNothingError"); + await handleClassicError(context, "commands:daily.errors.objectDoNothingError"); } @packetHandler(CommandDailyBonusObjectIsActiveDuringFights) async dailyBonusObjectIsActiveDuringFights(_packet: CommandDailyBonusObjectIsActiveDuringFights, context: PacketContext): Promise { - await handleDailyBonusClassicError(context, "commands:daily.errors.objectIsActiveDuringFights"); + await handleClassicError(context, "commands:daily.errors.objectIsActiveDuringFights"); } @packetHandler(CommandDailyBonusNoActiveObject) async dailyBonusNoActiveObject(_packet: CommandDailyBonusNoActiveObject, context: PacketContext): Promise { - await handleDailyBonusClassicError(context, "commands:daily.errors.noActiveObject"); + await handleClassicError(context, "commands:daily.errors.noActiveObject"); } @packetHandler(CommandDailyBonusInCooldown) @@ -475,9 +471,24 @@ export default class CommandHandlers { await handleDailyBonusCooldownError(context, packet.lastDailyTimestamp, packet.timeBetweenDailies); } - @packetHandler(CommandUnlockPacketRes) - async unlockRes(packet: CommandUnlockPacketRes, context: PacketContext): Promise { - await handleCommandUnlockPacketRes(packet, context); + @packetHandler(CommandUnlockHimself) + async unlockHimself(_packet: CommandUnlockHimself, context: PacketContext): Promise { + await handleClassicError(context, "commands:unlock.himself"); + } + + @packetHandler(CommandUnlockNotInJail) + async unlockNotInJail(_packet: CommandUnlockNotInJail, context: PacketContext): Promise { + await handleClassicError(context, "commands:unlock.notInJail"); + } + + @packetHandler(CommandUnlockNoPlayerFound) + async unlockNoPlayerFound(_packet: CommandUnlockNoPlayerFound, context: PacketContext): Promise { + await handleClassicError(context, "error:playerDoesntExist"); + } + + @packetHandler(CommandUnlockNotEnoughMoney) + async unlockNotEnoughMoney(packet: CommandUnlockNotEnoughMoney, context: PacketContext): Promise { + await handleCommandUnlockNotEnoughMoneyError(packet, context); } @packetHandler(CommandUnlockRefusePacketRes) diff --git a/Discord/src/utils/ErrorUtils.ts b/Discord/src/utils/ErrorUtils.ts index 0c6adc491..e9e2c9f0a 100644 --- a/Discord/src/utils/ErrorUtils.ts +++ b/Discord/src/utils/ErrorUtils.ts @@ -8,6 +8,8 @@ import {escapeUsername} from "../../../Lib/src/utils/StringUtils"; import {KeycloakUser} from "../../../Lib/src/keycloak/KeycloakUser"; import {millisecondsToMinutes, minutesDisplay} from "../../../Lib/src/utils/TimeUtils"; import {Effect} from "../../../Lib/src/enums/Effect"; +import {PacketContext} from "../../../Lib/src/packets/DraftBotPacket"; +import {DiscordCache} from "../bot/DiscordCache"; /** * Reply to an interaction with an ephemeral error PREFER {@link sendErrorMessage} for most cases @@ -126,4 +128,27 @@ export function effectsErrorTextValue(user: KeycloakUser, lng: Language, self: b time: minutesDisplay(millisecondsToMinutes(effectRemainingTime)) }) }; +} + +/** + * Handle classical errors + * @param context + * @param errorKey + */ +export async function handleClassicError(context: PacketContext, errorKey: string): Promise { + const interaction = DiscordCache.getInteraction(context.discord!.interaction); + if (!interaction) { + return; + } + await (interaction.deferred ? interaction.editReply : interaction.reply)({ + embeds: [ + new DraftBotErrorEmbed( + interaction.user, + interaction, + i18n.t(errorKey, { + lng: interaction.userLanguage + }) + ) + ] + }); } \ No newline at end of file diff --git a/Lib/src/packets/commands/CommandUnlockPacket.ts b/Lib/src/packets/commands/CommandUnlockPacket.ts index 195181e69..3626df1d7 100644 --- a/Lib/src/packets/commands/CommandUnlockPacket.ts +++ b/Lib/src/packets/commands/CommandUnlockPacket.ts @@ -8,15 +8,25 @@ export class CommandUnlockPacketReq extends DraftBotPacket { }; } +@sendablePacket(PacketDirection.NONE) +export class CommandUnlockErrorPacket extends DraftBotPacket { +} + @sendablePacket(PacketDirection.BACK_TO_FRONT) -export class CommandUnlockPacketRes extends DraftBotPacket { - foundPlayer!: boolean; +export class CommandUnlockNoPlayerFound extends CommandUnlockErrorPacket { +} - notInJail!: boolean; +@sendablePacket(PacketDirection.BACK_TO_FRONT) +export class CommandUnlockNotInJail extends CommandUnlockErrorPacket { +} +@sendablePacket(PacketDirection.BACK_TO_FRONT) +export class CommandUnlockNotEnoughMoney extends CommandUnlockErrorPacket { money!: number; +} - himself!: boolean; +@sendablePacket(PacketDirection.BACK_TO_FRONT) +export class CommandUnlockHimself extends CommandUnlockErrorPacket { } @sendablePacket(PacketDirection.BACK_TO_FRONT) From 7addb5a9b007e6ca4aa06b32122a580cce7ab029 Mon Sep 17 00:00:00 2001 From: romain22222 Date: Wed, 11 Dec 2024 16:43:20 +0100 Subject: [PATCH 13/17] fix profile command issues #2273 --- Core/src/commands/player/ProfileCommand.ts | 17 +- Core/src/core/database/game/models/Player.ts | 6 +- .../core/smallEvents/interactOtherPlayers.ts | 2 +- Discord/src/commands/player/ProfileCommand.ts | 304 +++++++----------- .../handlers/CommandHandlers.ts | 10 +- Discord/src/translations/i18n.ts | 8 +- Discord/src/utils/PetUtils.ts | 2 +- Lang/fr/bot.json | 6 +- Lang/fr/commands.json | 41 +-- Lib/src/DraftBotIcons.ts | 11 +- .../packets/commands/CommandProfilePacket.ts | 17 +- Lib/src/utils/TimeUtils.ts | 4 +- 12 files changed, 192 insertions(+), 236 deletions(-) diff --git a/Core/src/commands/player/ProfileCommand.ts b/Core/src/commands/player/ProfileCommand.ts index cb2c4c357..b185e4c75 100644 --- a/Core/src/commands/player/ProfileCommand.ts +++ b/Core/src/commands/player/ProfileCommand.ts @@ -5,7 +5,8 @@ import {FightConstants} from "../../../../Lib/src/constants/FightConstants"; import {DraftBotPacket, makePacket} from "../../../../Lib/src/packets/DraftBotPacket"; import { CommandProfilePacketReq, - CommandProfilePacketRes + CommandProfilePacketRes, + CommandProfilePlayerNotFound } from "../../../../Lib/src/packets/commands/CommandProfilePacket"; import {Campaign} from "../../core/missions/Campaign"; import {Player, Players} from "../../core/database/game/models/Player"; @@ -32,9 +33,7 @@ export default class ProfileCommand { const toCheckPlayer = await Players.getAskedPlayer(packet.askedPlayer, player); if (!toCheckPlayer) { - response.push(makePacket(CommandProfilePacketRes, { - foundPlayer: false - })); + response.push(makePacket(CommandProfilePlayerNotFound, {})); return; } const guild = toCheckPlayer.guildId ? await Guilds.getById(toCheckPlayer.guildId) : null; @@ -49,9 +48,8 @@ export default class ProfileCommand { const destinationId = toCheckPlayer.getDestinationId(); response.push(makePacket(CommandProfilePacketRes, { - foundPlayer: true, keycloakId: toCheckPlayer.keycloakId, - data: { + playerData: { badges, guild: guild?.name, level: toCheckPlayer.level, @@ -71,11 +69,12 @@ export default class ProfileCommand { } : null, destinationId, mapTypeId: destinationId ? MapLocationDataController.instance.getById(destinationId).type : null, - effect: toCheckPlayer.checkEffect() ? { + effect: { effect: toCheckPlayer.effectId, timeLeft: toCheckPlayer.effectEndDate.valueOf() - Date.now(), - healed: new Date() >= toCheckPlayer.effectEndDate - } : null, + healed: new Date() >= toCheckPlayer.effectEndDate, + hasTimeDisplay: toCheckPlayer.isUnderEffect() + }, fightRanking: toCheckPlayer.level >= FightConstants.REQUIRED_LEVEL ? { glory: toCheckPlayer.gloryPoints, league: toCheckPlayer.getLeague().id diff --git a/Core/src/core/database/game/models/Player.ts b/Core/src/core/database/game/models/Player.ts index 7fe8655cb..8b796b96b 100644 --- a/Core/src/core/database/game/models/Player.ts +++ b/Core/src/core/database/game/models/Player.ts @@ -415,8 +415,8 @@ export class Player extends Model { /** * Check if the player is under some effect (except dead or baby) */ - public checkEffect(): boolean { - return [Effect.NOT_STARTED.id, Effect.NO_EFFECT.id, Effect.DEAD.id].indexOf(this.effectId) !== -1; + public isUnderEffect(): boolean { + return [Effect.NOT_STARTED.id, Effect.NO_EFFECT.id, Effect.DEAD.id].indexOf(this.effectId) === -1; } /** @@ -543,7 +543,7 @@ export class Player extends Model { attack: number, defense: number, speed: number - } { + } { const playerClass = ClassDataController.instance.getById(this.class); return { attack: playerClass.getAttackValue(this.level), diff --git a/Core/src/core/smallEvents/interactOtherPlayers.ts b/Core/src/core/smallEvents/interactOtherPlayers.ts index 4ed0a91fd..26d625f30 100644 --- a/Core/src/core/smallEvents/interactOtherPlayers.ts +++ b/Core/src/core/smallEvents/interactOtherPlayers.ts @@ -193,7 +193,7 @@ async function checkGuildResponsibilities(otherPlayer: Player, guild: Guild, int * @param interactionsList */ function checkEffects(otherPlayer: Player, interactionsList: InteractOtherPlayerInteraction[]): void { - if (!otherPlayer.checkEffect()) { + if (otherPlayer.isUnderEffect()) { interactionsList.push(InteractOtherPlayerInteraction.EFFECT); } } diff --git a/Discord/src/commands/player/ProfileCommand.ts b/Discord/src/commands/player/ProfileCommand.ts index ca7986567..0b4af592d 100644 --- a/Discord/src/commands/player/ProfileCommand.ts +++ b/Discord/src/commands/player/ProfileCommand.ts @@ -1,7 +1,7 @@ import {ICommand} from "../ICommand"; import {makePacket, PacketContext} from "../../../../Lib/src/packets/DraftBotPacket"; import {DraftbotInteraction} from "../../messages/DraftbotInteraction"; -import i18n from "../../translations/i18n"; +import i18n, {TranslationOption} from "../../translations/i18n"; import {SlashCommandBuilderGenerator} from "../SlashCommandBuilderGenerator"; import { CommandProfilePacketReq, @@ -12,17 +12,16 @@ import {DraftBotEmbed} from "../../messages/DraftBotEmbed"; import {ColorResolvable, EmbedField, Message, MessageReaction} from "discord.js"; import {Constants} from "../../../../Lib/src/constants/Constants"; import {DiscordCache} from "../../bot/DiscordCache"; -import {DraftBotErrorEmbed} from "../../messages/DraftBotErrorEmbed"; import {ProfileConstants} from "../../../../Lib/src/constants/ProfileConstants"; import {Language} from "../../../../Lib/src/Language"; import {KeycloakUser} from "../../../../Lib/src/keycloak/KeycloakUser"; import {KeycloakUtils} from "../../../../Lib/src/keycloak/KeycloakUtils"; import {keycloakConfig} from "../../bot/DraftBotShard"; -import {DraftBotIcons} from "../../../../Lib/src/DraftBotIcons"; import {PetUtils} from "../../utils/PetUtils"; -import {ClassUtils} from "../../utils/ClassUtils"; -import {EmoteUtils} from "../../utils/EmoteUtils"; import {PacketUtils} from "../../utils/PacketUtils"; +import {EmoteUtils} from "../../utils/EmoteUtils"; +import {DraftBotIcons} from "../../../../Lib/src/DraftBotIcons"; +import {millisecondsToMinutes, minutesDisplay} from "../../../../Lib/src/utils/TimeUtils"; /** * Display the profile of a player @@ -56,152 +55,103 @@ async function sendMessageAllBadgesTooMuchBadges(gameUsername: string, badges: s async function displayBadges(badges: string[], msg: Message): Promise { if (badges.length >= Constants.PROFILE.MAX_EMOTE_DISPLAY_NUMBER) { await msg.react(Constants.PROFILE.DISPLAY_ALL_BADGE_EMOTE); + return; } - else { - for (const badgeId in badges) { - if (Object.prototype.hasOwnProperty.call(badges, badgeId)) { - await msg.react(badges[badgeId]); - } - } + for (const badgeId in badges) { + await msg.react(badges[badgeId]); } } -function generateFields(packet: CommandProfilePacketRes, lng: Language): EmbedField[] { - const fields: EmbedField[] = []; - - fields.push({ - name: i18n.t("commands:profile.information.fieldName", {lng}), - value: i18n.t("commands:profile.information.fieldValue", { - lng, - health: packet.data?.health.value, - maxHealth: packet.data?.health.max, - money: packet.data?.money, - experience: packet.data?.experience.value, - experienceNeededToLevelUp: packet.data?.experience.max - }), - inline: false - }); - - if (packet.data?.stats) { +/** + * Add a field to the profile embed + * @param fields + * @param fieldKey + * @param shouldBeFielded + * @param replacements + */ +function addField(fields: EmbedField[], fieldKey: string, shouldBeFielded: boolean, replacements: TranslationOption & { + returnObjects?: false +}): void { + if (shouldBeFielded) { fields.push({ - name: i18n.t("commands:profile.statistics.fieldName", {lng}), - value: i18n.t("commands:profile.statistics.fieldValue", { - lng, - baseBreath: packet.data?.stats.breath.base, - breathRegen: packet.data?.stats.breath.regen, - cumulativeAttack: packet.data?.stats.attack, - cumulativeDefense: packet.data?.stats.defense, - cumulativeHealth: packet.data.stats.energy.value, - cumulativeSpeed: packet.data.stats.speed, - cumulativeMaxHealth: packet.data.stats.energy.max, - maxBreath: packet.data.stats.breath.max - }), + name: i18n.t(`commands:profile.${fieldKey}.fieldName`, replacements), + value: i18n.t(`commands:profile.${fieldKey}.fieldValue`, replacements), inline: false }); } +} - fields.push({ - name: i18n.t("commands:profile.mission.fieldName", {lng}), - value: i18n.t("commands:profile.mission.fieldValue", { - lng, - gems: packet.data?.missions.gems, - campaign: packet.data?.missions.campaignProgression - }), - inline: false +function generateFields(packet: CommandProfilePacketRes, lng: Language): EmbedField[] { + const fields: EmbedField[] = []; + addField(fields, "information", true, { + lng, + health: packet.playerData.health.value, + maxHealth: packet.playerData.health.max, + money: packet.playerData.money, + experience: packet.playerData.experience.value, + experienceNeededToLevelUp: packet.playerData.experience.max }); - fields.push({ - name: i18n.t("commands:profile.ranking.fieldName", {lng}), - value: packet.data?.rank.unranked ? i18n.t("commands:profile.ranking.fieldValueUnranked", { - lng, - score: packet.data.rank.score - }) : i18n.t("commands:profile.ranking.fieldValue", { - lng, - rank: packet.data?.rank.rank, - numberOfPlayer: packet.data?.rank.numberOfPlayers, - score: packet.data?.rank.score - }), - inline: false + addField(fields, "statistics", Boolean(packet.playerData.stats), { + lng, + baseBreath: packet.playerData.stats?.breath.base, + breathRegen: packet.playerData.stats?.breath.regen, + cumulativeAttack: packet.playerData.stats?.attack, + cumulativeDefense: packet.playerData.stats?.defense, + cumulativeHealth: packet.playerData.stats?.energy.value, + cumulativeSpeed: packet.playerData.stats?.speed, + cumulativeMaxHealth: packet.playerData.stats?.energy.max, + maxBreath: packet.playerData.stats?.breath.max }); - if (packet.data?.effect?.healed) { - fields.push({ - name: i18n.t("commands:profile.noTimeLeft.fieldName", {lng}), - value: i18n.t("commands:profile.noTimeLeft.fieldValue", { - lng - }), - inline: false - }); - } - else if (packet.data?.effect) { - fields.push({ - name: i18n.t("commands:profile.timeLeft.fieldName", {lng}), - value: i18n.t("commands:profile.timeLeft.fieldValue", { - lng, - effect: EmoteUtils.translateEmojiToDiscord(DraftBotIcons.effects[packet.data.effect.effect]), - timeLeft: packet.data.effect.timeLeft - }), - inline: false - }); - } + addField(fields, "mission", true, { + lng, + gems: packet.playerData.missions.gems, + campaign: packet.playerData.missions.campaignProgression + }); - if (packet.data?.classId) { - fields.push({ - name: i18n.t("commands:profile.playerClass.fieldName", {lng}), - value: i18n.t("commands:profile.playerClass.fieldValue", { - lng, - className: ClassUtils.classToString(lng, packet.data.classId) - }), - inline: false - }); - } + addField(fields, packet.playerData.rank.unranked ? "unranked" : "ranking", true, { + lng, + score: packet.playerData.rank.score, + rank: packet.playerData.rank.rank, + numberOfPlayer: packet.playerData.rank.numberOfPlayers + }) + + addField(fields, packet.playerData.effect.healed ? "noTimeLeft" : "timeLeft", Boolean(packet.playerData.effect.hasTimeDisplay), { + lng, + effectId: packet.playerData.effect.effect, + timeLeft: minutesDisplay(millisecondsToMinutes(packet.playerData.effect.timeLeft), lng) + }); - if (packet.data?.fightRanking) { - fields.push({ - name: i18n.t("commands:profile.fightRanking.fieldName", {lng}), - value: i18n.t("commands:profile.fightRanking.fieldValue", { - lng, - league: packet.data.fightRanking.league, - gloryPoints: packet.data.fightRanking.glory - }), - inline: false - }); - } + addField(fields, "playerClass", Boolean(packet.playerData.classId), { + lng, + id: packet.playerData.classId + }); - if (packet.data?.guild) { - fields.push({ - name: i18n.t("commands:profile.guild.fieldName", {lng}), - value: i18n.t("commands:profile.guild.fieldValue", { - lng, - guild: packet.data.guild - }), - inline: false - }); - } + addField(fields, "fightRanking", Boolean(packet.playerData.fightRanking), { + lng, + league: packet.playerData.fightRanking?.league, + gloryPoints: packet.playerData.fightRanking?.glory + }); - if (packet.data?.destinationId && packet.data?.mapTypeId) { - fields.push({ - name: i18n.t("commands:profile.map.fieldName", {lng}), - value: i18n.t("commands:profile.map.fieldValue", { - lng, - mapEmote: EmoteUtils.translateEmojiToDiscord(DraftBotIcons.map_types[packet.data.mapTypeId]), - mapName: i18n.t(`models:map_locations.${packet.data.destinationId}.name`, {lng}) - }), - inline: false - }); - } + addField(fields, "guild", Boolean(packet.playerData.guild), { + lng, + guild: packet.playerData.guild + }); - if (packet.data?.pet) { - fields.push({ - name: i18n.t("commands:profile.pet.fieldName", {lng}), - value: i18n.t("commands:profile.pet.fieldValue", { - lng, - emote: PetUtils.getPetIcon(packet.data.pet.typeId, packet.data.pet.sex), - rarity: PetUtils.getRarityDisplay(packet.data.pet.rarity) - }) + PetUtils.petToShortString(lng, packet.data.pet.nickname, packet.data.pet.typeId, packet.data.pet.sex), - inline: false - }); - } + addField(fields, "map", Boolean(packet.playerData.destinationId && packet.playerData.mapTypeId), { + lng, + mapTypeId: packet.playerData.mapTypeId, + mapName: packet.playerData.destinationId, + interpolation: {escapeValue: false} + }); + + addField(fields, "pet", Boolean(packet.playerData.pet), { + lng, + rarity: EmoteUtils.translateEmojiToDiscord(DraftBotIcons.unitValues.petRarity).repeat(packet.playerData.pet?.rarity ?? 0), + emote: packet.playerData.pet ? PetUtils.getPetIcon(packet.playerData.pet?.typeId, packet.playerData.pet?.sex) : "", + name: packet.playerData.pet ? packet.playerData.pet?.nickname ?? PetUtils.getPetTypeName(lng, packet.playerData.pet?.typeId, packet.playerData.pet?.sex) : "" + }); return fields; } @@ -209,60 +159,44 @@ function generateFields(packet: CommandProfilePacketRes, lng: Language): EmbedFi export async function handleCommandProfilePacketRes(packet: CommandProfilePacketRes, context: PacketContext): Promise { const interaction = DiscordCache.getInteraction(context.discord!.interaction); - if (interaction) { - if (!packet.foundPlayer) { - await interaction.reply({ - embeds: [ - new DraftBotErrorEmbed( - interaction.user, - interaction, - i18n.t("error:playerDoesntExist", {lng: interaction.userLanguage}) - ) - ] - }); - return; + if (!interaction) { + return; + } + const keycloakUser = (await KeycloakUtils.getUserByKeycloakId(keycloakConfig, packet.keycloakId))!; + const titleEffect = packet.playerData.effect.healed ? "healed" : packet.playerData.effect.effect; + const reply = await interaction.reply({ + embeds: [ + new DraftBotEmbed() + .setColor(packet.playerData!.color) + .setTitle(i18n.t("commands:profile.title", { + lng: interaction.userLanguage, + effectId: titleEffect, + pseudo: keycloakUser.attributes.gameUsername, + level: packet.playerData?.level + })) + .addFields(generateFields(packet, interaction.userLanguage)) + ], + fetchReply: true + }) as Message; + const collector = reply.createReactionCollector({ + filter: (reaction: MessageReaction) => reaction.me && !reaction.users.cache.last()!.bot, + time: Constants.MESSAGES.COLLECTOR_TIME, + max: ProfileConstants.BADGE_MAXIMUM_REACTION + }); + collector.on("collect", async (reaction) => { + if (reaction.emoji.name === Constants.PROFILE.DISPLAY_ALL_BADGE_EMOTE) { + collector.stop(); // Only one is allowed to avoid spam + await sendMessageAllBadgesTooMuchBadges(keycloakUser.attributes.gameUsername[0], packet.playerData!.badges!, interaction); } - - const keycloakUser = (await KeycloakUtils.getUserByKeycloakId(keycloakConfig, packet.keycloakId!))!; - - const titleEffect = packet.data?.effect?.healed ? Constants.DEFAULT_HEALED_EFFECT : packet.data?.effect; - const reply = await interaction.reply({ - embeds: [ - new DraftBotEmbed() - .setColor(packet.data!.color) - .setTitle(i18n.t("commands:profile.title", { - lng: interaction.userLanguage, - effect: titleEffect, - pseudo: keycloakUser.attributes.gameUsername, - level: packet.data?.level - })) - .addFields(generateFields(packet, interaction.userLanguage)) - ], - fetchReply: true - }) as Message; - - const collector = reply.createReactionCollector({ - filter: (reaction: MessageReaction) => reaction.me && !reaction.users.cache.last()!.bot, - time: Constants.MESSAGES.COLLECTOR_TIME, - max: ProfileConstants.BADGE_MAXIMUM_REACTION - }); - - collector.on("collect", async (reaction) => { - if (reaction.emoji.name === Constants.PROFILE.DISPLAY_ALL_BADGE_EMOTE) { - collector.stop(); // Only one is allowed to avoid spam - await sendMessageAllBadgesTooMuchBadges(keycloakUser.attributes.gameUsername[0], packet.data!.badges!, interaction); - } - else { - interaction.channel.send({content: i18n.t(`commands:profile.badges.${reaction.emoji.name}`, {lng: interaction.userLanguage})}) - .then((msg: Message | null) => { - setTimeout(() => msg?.delete(), ProfileConstants.BADGE_DESCRIPTION_TIMEOUT); - }); - } - }); - - if (packet.data?.badges.length !== 0) { - await displayBadges(packet.data!.badges, reply); + else { + interaction.channel.send({content: i18n.t(`commands:profile.badges.${reaction.emoji.name}`, {lng: interaction.userLanguage})}) + .then((msg: Message | null) => { + setTimeout(() => msg?.delete(), ProfileConstants.BADGE_DESCRIPTION_TIMEOUT); + }); } + }); + if (packet.playerData?.badges.length !== 0) { + await displayBadges(packet.playerData!.badges, reply); } } diff --git a/Discord/src/packetHandlers/handlers/CommandHandlers.ts b/Discord/src/packetHandlers/handlers/CommandHandlers.ts index c22b7bb71..53bdb9b35 100644 --- a/Discord/src/packetHandlers/handlers/CommandHandlers.ts +++ b/Discord/src/packetHandlers/handlers/CommandHandlers.ts @@ -4,7 +4,10 @@ import {CommandPingPacketRes} from "../../../../Lib/src/packets/commands/Command import {DiscordCache} from "../../bot/DiscordCache"; import i18n from "../../translations/i18n"; import {draftBotClient, shardId} from "../../bot/DraftBotShard"; -import {CommandProfilePacketRes} from "../../../../Lib/src/packets/commands/CommandProfilePacket"; +import { + CommandProfilePacketRes, + CommandProfilePlayerNotFound +} from "../../../../Lib/src/packets/commands/CommandProfilePacket"; import {handleCommandProfilePacketRes} from "../../commands/player/ProfileCommand"; import {CommandInventoryPacketRes} from "../../../../Lib/src/packets/commands/CommandInventoryPacket"; import {handleCommandInventoryPacketRes} from "../../commands/player/InventoryCommand"; @@ -175,6 +178,11 @@ export default class CommandHandlers { }); } + @packetHandler(CommandProfilePlayerNotFound) + async profilePlayerNotFound(_packet: CommandProfilePlayerNotFound, context: PacketContext): Promise { + await handleClassicError(context, "error:playerDoesntExist"); + } + @packetHandler(CommandProfilePacketRes) async profileRes(packet: CommandProfilePacketRes, context: PacketContext): Promise { await handleCommandProfilePacketRes(packet, context); diff --git a/Discord/src/translations/i18n.ts b/Discord/src/translations/i18n.ts index c0fb0a2bc..c93a9972f 100644 --- a/Discord/src/translations/i18n.ts +++ b/Discord/src/translations/i18n.ts @@ -46,6 +46,10 @@ function convertEmoteFormat(str: string): string { type EmotePathFolder = Record | string[]; type EmotePath = EmotePathFolder | string; +export type TranslationOption = { + lng: Language +} & i18next.TOptions; + /** * Get the corresponding to emote for the given emote name * @param emote @@ -103,9 +107,7 @@ export class I18nDraftbot { * @param key * @param options */ - static t(key: string | string[], options: { - lng: Language - } & i18next.TOptions): string | string[] { + static t(key: string | string[], options: TranslationOption): string | string[] { const value: string | string[] = i18next.t(key, options); if (Array.isArray(value)) { return (value as string[]).map(draftbotFormat); diff --git a/Discord/src/utils/PetUtils.ts b/Discord/src/utils/PetUtils.ts index 2e5e0f2c1..dcebda9d5 100644 --- a/Discord/src/utils/PetUtils.ts +++ b/Discord/src/utils/PetUtils.ts @@ -88,7 +88,7 @@ export class PetUtils { const sexStringContext: string = sex === PetConstants.SEX.MALE ? PetConstants.SEX.MALE_FULL : PetConstants.SEX.FEMALE_FULL; return i18n.t( `models:pets:${typeId}`, - {lng, context: sexStringContext as unknown} + {lng, context: sexStringContext} ); } diff --git a/Lang/fr/bot.json b/Lang/fr/bot.json index 4814b0c58..7c4a8997c 100644 --- a/Lang/fr/bot.json +++ b/Lang/fr/bot.json @@ -12,14 +12,14 @@ "noReacPermission": ":x: | **Bonjour ! Vous recevez ce message car vous avez tenté d'utiliser une de mes commandes dans un salon où j'ai la permission de voir les messages, mais pas celle de mettre des réactions !**\n\nVotre requête a donc été annulée. Pour résoudre ce problème merci d'envoyer un message au propriétaire du serveur sur lequel vous avez essayé de m'utiliser. Si vous ne parvenez pas à résoudre ce problème je vous invite à lire le guide du bot disponible à adresse suivante : https://guide.draftbot.com !", "noSpeakInThreadPermission": ":zipper_mouth: | **Bonjour ! Vous recevez ce message car vous avez tenté d'utiliser une de mes commandes dans un fil où j'ai la permission de voir les messages, mais pas celle d'en envoyer !**\n\nVotre requête a donc été annulée. Pour résoudre ce problème merci d'envoyer un message au propriétaire du serveur sur lequel vous avez essayé de m'utiliser. Si vous ne parvenez pas à résoudre ce problème je vous invite à rejoindre le discord support du bot disponible à adresse suivante : https://guide.draftbot.com !", "noSpeakPermission": ":zipper_mouth: | **Bonjour ! Vous recevez ce message car vous avez tenté d'utiliser une de mes commandes dans un salon où j'ai la permission de voir les messages, mais pas celle d'en envoyer !**\n\nVotre requête a donc été annulée. Pour résoudre ce problème merci d'envoyer un message au propriétaire du serveur sur lequel vous avez essayé de m'utiliser. Si vous ne parvenez pas à résoudre ce problème je vous invite à rejoindre le discord support du bot disponible à adresse suivante : https://guide.draftbot.com !", - "resetIsNow": ":trophy: Le classement de la semaine est en cours de réinitialisation ! Le gagnant sera annoncé sous peu sur le serveur du bot ! Le jeu reprendra dans moins de 5 minutes !", + "resetIsNow": "{emote:announcements.trophy} Le classement de la semaine est en cours de réinitialisation ! Le gagnant sera annoncé sous peu sur le serveur du bot ! Le jeu reprendra dans moins de 5 minutes !", "seasonEndAnnouncement": ":sparkles: **La saison de combat est terminée ! Le gagnant est :** {{mention}}", "seasonEndAnnouncementNoWinner": ":sparkles: **La saison de combat est terminée ! Malheureusement, il n'y a pas de participant et donc de gagnant cette saison.**", "seasonEndIsNow": ":sparkles: La saison de combat est en cours de réinitialisation ! Le gagnant sera annoncé sous peu sur le serveur du bot ! Le jeu reprendra dans moins de 20 minutes !", "serverList": "**:outbox_tray: Serveur {{count}} :** `{{guild}}` | :bust_in_silhouette: : `{{humans}}` | :robot: : `{{robots}}` | Ratio bot/Humain : `{{ratio}}` % | Validation : {{validation}}", "supportAlert": ":love_letter: | **Nouveau message privé reçu !** \n`Auteur: {{username}} (id : {{id}})\n\n`", - "topWeekAnnouncement": ":trophy: **Le classement de la semaine est terminé ! Le gagnant est :** {{mention}}", - "topWeekAnnouncementNoWinner": ":trophy: **Le classement de la semaine est terminé ! Malheureusement, il n'y a pas de participant et donc de gagnant cette semaine.**", + "topWeekAnnouncement": "{emote:announcements.trophy} **Le classement de la semaine est terminé ! Le gagnant est :** {{mention}}", + "topWeekAnnouncementNoWinner": "{emote:announcements.trophy} **Le classement de la semaine est terminé ! Malheureusement, il n'y a pas de participant et donc de gagnant cette semaine.**", "totalUsersCount": "**Nombre total d'utilisateurs : `{{count}}`**", "notificationTitle": "Notification", "notificationFooter": "Vous recevez ce message car les notifications sont activées. Pour changer ce paramètre, utilisez la commande {command:notifications}", diff --git a/Lang/fr/commands.json b/Lang/fr/commands.json index 1e62a217b..99ec78929 100644 --- a/Lang/fr/commands.json +++ b/Lang/fr/commands.json @@ -44,11 +44,11 @@ "cannotBeJoinedOnBoat": "👻" }, "separator": " | ", - "memberInfos": "{{icon}} - **{{pseudo}}** ({{ranking}} :trophy: | {{score}} :medal:{{islandStatusIcon}})\n", + "memberInfos": "{{icon}} - **{{pseudo}}** ({{ranking}} {emote:announcements.trophy} | {{score}} {emote:unitValues.score}{{islandStatusIcon}})\n", "members": ":person_pouting: {{memberCount}} / {{maxGuildMembers}} membres", "infoTitle": "Informations", "islandInfo": ":island: Nombre d'alliés sur l'île mystérieuse : {{membersOnPveIsland}}\n", - "info": ":star: {{experience}} | :mirror_ball: {{guildPoints}} | :trophy: {{ranking}}", + "info": ":star: {{experience}} | :mirror_ball: {{guildPoints}} | {emote:announcements.trophy} {{ranking}}", "xpNeeded": "{{xp}} / {{xpToLevelUp}}", "xpMax": "Max", "ranking": "{{rank}} / {{rankTotal}}", @@ -336,15 +336,15 @@ "⚙️": ":gear: `Équipe technique`", "⛑️": ":helmet_with_cross: `Personne faisant partie des 20 premières à avoir rejoint le serveur du bot`", "✨": ":sparkles: `Personne ayant remporté le plus de gloire durant une saison de combat`", - "❤️": ":heart: `Personne ayant le grade Soutien sur le serveur du bot`", + "❤️": "{emote:unitValues.health} `Personne ayant le grade Soutien sur le serveur du bot`", "🌍": ":earth_africa: `Traducteur`", "🌟": ":star2: `Personne ayant aidé à mettre le bot sur un serv de plus de 2000 membres`", "🍀": ":four_leaf_clover: `Badge pouvant être gagné de temps en temps dans des concours sur le serveur du bot ou sur twitter`", "🎄": ":christmas_tree: `Badge pouvant être gagné chaque noël lors d'un concours`", "🎗️": ":reminder_ribbon: `Personne ayant dominé un classement de la semaine`", "🎰": ":slot_machine: `Badge donné de manière totalement random`", - "🏅": ":medal: `Joueur dans le top 10 au reset de la 1.0`", - "🏆": ":trophy: `Meilleur joueur au moment du reset de la 1.0`", + "🏅": "{emote:unitValues.score} `Joueur dans le top 10 au reset de la 1.0`", + "🏆": "{emote:announcements.trophy} `Meilleur joueur au moment du reset de la 1.0`", "🐞": ":lady_beetle: `Personne ayant signalé des bugs majeurs`", "👑": ":crown: `Propriétaire du bot`", "💍": ":ring: `Badge acheté dans le shop des Missions`", @@ -370,11 +370,11 @@ }, "information": { "fieldName": "Informations :", - "fieldValue": ":heart: {{health}}/{{maxHealth}} | :star: {{experience}}/{{experienceNeededToLevelUp}} | :moneybag: {{money}}" + "fieldValue": "{emote:unitValues.health} {{health}}/{{maxHealth}} | :star: {{experience}}/{{experienceNeededToLevelUp}} | :moneybag: {{money}}" }, "map": { "fieldName": "Destination :", - "fieldValue": "{{mapEmote}} {{mapName}}" + "fieldValue": "{emote:map_types.{{mapTypeId}}} $t(models:map_locations.{{mapName}}.name)" }, "mission": { "fieldName": "Missions :", @@ -382,30 +382,33 @@ }, "noTimeLeft": { "fieldName": "Temps restant :", - "fieldValue": ":hospital: Reprise du jeu possible" + "fieldValue": "{emote:effects.healed} Reprise du jeu possible" }, "pet": { "fieldName": "Familier :", - "fieldValue": "Rareté: {{rarity}}\n" + "fieldValue": "Rareté: {{rarity}}\n$t(commands:pet.shortPetField)" }, "playerClass": { "fieldName": "Classe :", - "fieldValue": "{{className}}" + "fieldValue": "$t(models:classFormat)" }, "ranking": { "fieldName": "Classement et Score :", - "fieldValue": ":trophy: {{rank}}/{{numberOfPlayer}} | :medal: {{score}}", - "fieldValueUnranked": ":trophy: Non classé | :medal: {{score}}" + "fieldValue": "{emote:announcements.trophy} {{rank}}/{{numberOfPlayer}} | {emote:unitValues.score} {{score}}" + }, + "unranked": { + "fieldName": "Classement et Score :", + "fieldValue": "{emote:announcements.trophy} Non classé | {emote:unitValues.score} {{score}}" }, "statistics": { "fieldName": "Statistiques :", - "fieldValue": ":zap: {{cumulativeHealth}} / {{cumulativeMaxHealth}} | :dagger: {{cumulativeAttack}} | :shield: {{cumulativeDefense}} | :rocket: {{cumulativeSpeed}} | :wind_blowing_face: {{baseBreath}} / {{maxBreath}} | :lungs: {{breathRegen}}" + "fieldValue": "{emote:unitValues.energy} {{cumulativeHealth}} / {{cumulativeMaxHealth}} | {emote:unitValues.attack} {{cumulativeAttack}} | {emote:unitValues.defense} {{cumulativeDefense}} | {emote:unitValues.speed} {{cumulativeSpeed}} | {emote:unitValues.breath} {{baseBreath}} / {{maxBreath}} | {emote:unitValues.breathRegen} {{breathRegen}}" }, "timeLeft": { "fieldName": "Temps restant :", - "fieldValue": "{{effect}} {{timeLeft}}" + "fieldValue": "{emote:effects.{{effectId}}} {{timeLeft}}" }, - "title": "{{effect}} | {{pseudo}} | Niveau {{level}}" + "title": "{emote:effects.{{effectId}}} | {{pseudo}} | Niveau {{level}}" }, "rarity": { "rarities": ":small_orange_diamond: Basique | Possédé en début de jeu\n:large_orange_diamond: Commun | {{common}}%\n:fire: Peu commun | {{uncommon}}%\n:trident: Exotique | {{exotic}}%\n:comet: Rare | {{rare}}%\n:dizzy: Spécial | {{special}}%\n:star: Épique | {{epic}}%\n:star2: Légendaire | {{legendary}}%\n:gem: Mythique | {{unique}}%", @@ -430,10 +433,10 @@ ], "encounterMonsterStats": "> **{{emoji}} {{monsterName}} **| **Niveau {{level}}**\n> {{description}}\n\n⚡ {{fightPoints}} | 🗡 {{attack}} | 🛡 {{defense}} | 🚀 {{speed}}", "endPoint": "Point d'arrivée :", - "energy": "** | :zap: Énergie gagnée : **{{energy}}", + "energy": "** | {emote:unitValues.energy} Énergie gagnée : **{{energy}}", "experience": "** | :star: XP gagné : **{{experience}}", "gems": "** | :gem: Gemmes gagnées : **{{gems}}", - "health": "** | :heart: Vie gagnée : **{{health}}", + "health": "** | {emote:unitValues.health} Vie gagnée : **{{health}}", "healthLoose": "** | :broken_heart: Vie perdue : **{{health}}", "journal": "Journal de {{pseudo}}", "money": "** | :moneybag: Argent gagné : **{{money}}", @@ -444,7 +447,7 @@ "monsterRewardsTitle": "{{pseudo}}, récompenses de combat", "newBigEvent": ":flag_fr: Vous êtes arrivé à **{{destination}}** !", "noFight": ":newspaper: **Journal de {{pseudo}} :** {{waitABitReaction}} | Vous vous enfuyez rapidement et trouvez une petite cachette ! Le monstre vous attend patiemment dehors...", - "points": ":** :medal: Points gagnés : **{{score}}", + "points": ":** {emote:unitValues.score} Points gagnés : **{{score}}", "pveEvent": ":newspaper: **Journal de {{pseudo}} :** {{event}}\n\n{{monsterDisplay}}\n\n{{startTheFightReaction}} Commencer le combat\n{{waitABitReaction}} Attendre un peu avant de commencer le combat\n\n*- Utilisez les réactions pour effectuer une action*", "remainingEnergyTitle": "Énergie restante :", "startPoint": "Point de départ :", @@ -616,7 +619,7 @@ "displays": { "listing": "{{headerText}}\n\n{{classesList}}", "details": "{{classDetails}}{{attacksHeader}}\n{{attacksList}}", - "class": "### {{emoji}} {{name}}\n:zap: {{fightPoint}} | :dagger: {{attack}} | :shield: {{defense}} | :rocket: {{speed}} | :wind_blowing_face: {{baseBreath}} / {{maxBreath}} | :lungs: {{breathRegen}} | :heart: {{health}}", + "class": "### {{emoji}} {{name}}\n{emote:unitValues.energy} {{fightPoint}} | {emote:unitValues.attack} {{attack}} | {emote:unitValues.defense} {{defense}} | {emote:unitValues.speed} {{speed}} | :wind_blowing_face: {{baseBreath}} / {{maxBreath}} | {emote:unitValues.breathRegen} {{breathRegen}} | {emote:unitValues.health} {{health}}", "attack": "### {{emoji}} {{name}} | {{cost}} :wind_blowing_face:\n{{description}}" } }, diff --git a/Lib/src/DraftBotIcons.ts b/Lib/src/DraftBotIcons.ts index f9f622c96..0ec4aee6f 100644 --- a/Lib/src/DraftBotIcons.ts +++ b/Lib/src/DraftBotIcons.ts @@ -117,7 +117,8 @@ export const DraftBotIcons: { "starving": "🤤", "confounded": "😖", "scared:": "😱", - "lost": "🧐" + "lost": "🧐", + "healed": "🏥" }, "events": { "1": { @@ -1626,7 +1627,13 @@ export const DraftBotIcons: { "lostHealth": "💔", "energy": "⚡", "rage": "💢", - "time": "🕜" + "time": "🕜", + "attack": "🗡️", + "defense": "🛡️", + "speed": "🚀", + "breath": "🌬️", + "breathRegen": "🫁", + "petRarity": "⭐" }, "shopItems": { "randomItem": "❓", diff --git a/Lib/src/packets/commands/CommandProfilePacket.ts b/Lib/src/packets/commands/CommandProfilePacket.ts index bfa91baf6..20ac0f4c9 100644 --- a/Lib/src/packets/commands/CommandProfilePacket.ts +++ b/Lib/src/packets/commands/CommandProfilePacket.ts @@ -9,12 +9,14 @@ export class CommandProfilePacketReq extends DraftBotPacket { } @sendablePacket(PacketDirection.BACK_TO_FRONT) -export class CommandProfilePacketRes extends DraftBotPacket { - foundPlayer!: boolean; +export class CommandProfilePlayerNotFound extends DraftBotPacket { +} - keycloakId?: string; +@sendablePacket(PacketDirection.BACK_TO_FRONT) +export class CommandProfilePacketRes extends DraftBotPacket { + keycloakId!: string; - data?: { + playerData!: { stats?: { energy: { value: number, @@ -39,10 +41,11 @@ export class CommandProfilePacketRes extends DraftBotPacket { numberOfPlayers: number, score: number }, - effect?: { + effect: { healed: boolean, timeLeft: number, - effect: string + effect: string, + hasTimeDisplay: boolean }, classId?: number, fightRanking?: { @@ -56,7 +59,7 @@ export class CommandProfilePacketRes extends DraftBotPacket { typeId: number, sex: string, rarity: number, - nickname?: string + nickname: string }, color: string, level: number, diff --git a/Lib/src/utils/TimeUtils.ts b/Lib/src/utils/TimeUtils.ts index 013f97215..7c16e4898 100644 --- a/Lib/src/utils/TimeUtils.ts +++ b/Lib/src/utils/TimeUtils.ts @@ -1,4 +1,4 @@ -import {LANGUAGE} from "../Language"; +import {Language, LANGUAGE} from "../Language"; /** * Get the elements to display a remaining time in the given language @@ -275,7 +275,7 @@ export function getTimeFromXHoursAgo(hours: number): Date { * @param minutes - the time in minutes * @param language */ -export function minutesDisplay(minutes: number, language = ""): string { +export function minutesDisplay(minutes: number, language: Language = LANGUAGE.DEFAULT_LANGUAGE): string { const hours = Math.floor(minutesToHours(minutes)); minutes = Math.floor(minutes % 60); const displayConstantValues = getMinutesDisplayStringConstants(language); From 3fcd94e7a1a338384ac43d140020422a7785cba5 Mon Sep 17 00:00:00 2001 From: romain22222 Date: Wed, 11 Dec 2024 16:53:36 +0100 Subject: [PATCH 14/17] qual bots fixes --- Core/src/commands/player/ReportCommand.ts | 2 +- Core/src/commands/player/UnlockCommand.ts | 8 +++++- Core/src/core/CommandsTest.ts | 4 +++ Core/src/core/database/game/models/Player.ts | 7 ++--- Core/src/core/utils/ItemUtils.ts | 3 ++- Core/src/data/MainItem.ts | 4 +-- Core/src/data/ObjectItem.ts | 4 +-- Core/src/data/SupportItem.ts | 4 +-- Discord/src/commands/player/ProfileCommand.ts | 27 ++++++++++++++++--- Discord/src/utils/DiscordItemUtils.ts | 4 +-- Lib/src/types/MaxStatsValues.ts | 1 - Lib/src/types/StatValues.ts | 1 + 12 files changed, 49 insertions(+), 20 deletions(-) delete mode 100644 Lib/src/types/MaxStatsValues.ts create mode 100644 Lib/src/types/StatValues.ts diff --git a/Core/src/commands/player/ReportCommand.ts b/Core/src/commands/player/ReportCommand.ts index 648b7ca22..b11e25130 100644 --- a/Core/src/commands/player/ReportCommand.ts +++ b/Core/src/commands/player/ReportCommand.ts @@ -281,7 +281,7 @@ async function doEvent(event: BigEvent, player: Player, time: number, context: P async function doRandomBigEvent( context: PacketContext, response: DraftBotPacket[], - player: Player, + player: Player ): Promise { await completeMissionsBigEvent(player, response); const travelData = TravelTime.getTravelDataSimplified(player, new Date()); diff --git a/Core/src/commands/player/UnlockCommand.ts b/Core/src/commands/player/UnlockCommand.ts index 985d8fa7e..8c8bcc14e 100644 --- a/Core/src/commands/player/UnlockCommand.ts +++ b/Core/src/commands/player/UnlockCommand.ts @@ -21,6 +21,12 @@ import {TravelTime} from "../../core/maps/TravelTime"; import {NumberChangeReason} from "../../../../Lib/src/constants/LogsConstants"; import {Effect} from "../../../../Lib/src/enums/Effect"; +/** + * Accept the unlock of a player + * @param player + * @param freedPlayer + * @param response + */ async function acceptUnlock(player: Player, freedPlayer: Player, response: DraftBotPacket[]): Promise { await player.reload(); // Do all necessary checks again just in case something changed during the menu @@ -60,7 +66,7 @@ function unlockCannotBeDone(player: Player, freedPlayer: Player, response: Draft } if (player.money < UnlockConstants.PRICE_FOR_UNLOCK) { response.push(makePacket(CommandUnlockNotEnoughMoney, { - money: player.money, + money: player.money })); return true; } diff --git a/Core/src/core/CommandsTest.ts b/Core/src/core/CommandsTest.ts index 8ed551d58..58887b79b 100644 --- a/Core/src/core/CommandsTest.ts +++ b/Core/src/core/CommandsTest.ts @@ -27,6 +27,10 @@ const typeVariableFormatLike: Map = new Map([ [TypeKey.STRING, "texte"] ]); +/** + * Format the type waited for the command + * @param typeWaited + */ export function formatTypeWaited(typeWaited: TypeKey): string { return `\`${typeWaited}\`(${typeVariableFormatLike.get(typeWaited)})`; } diff --git a/Core/src/core/database/game/models/Player.ts b/Core/src/core/database/game/models/Player.ts index 8b796b96b..0008ba8f2 100644 --- a/Core/src/core/database/game/models/Player.ts +++ b/Core/src/core/database/game/models/Player.ts @@ -40,6 +40,7 @@ import {BlockingConstants} from "../../../../../../Lib/src/constants/BlockingCon import {Effect} from "../../../../../../Lib/src/enums/Effect"; import {ScheduledReportNotifications} from "./ScheduledReportNotification"; import {PacketUtils} from "../../../utils/PacketUtils"; +import {StatValues} from "../../../../../../Lib/src/types/StatValues"; import moment = require("moment"); export type PlayerEditValueParameters = { @@ -539,11 +540,7 @@ export class Player extends Model { ); } - public getMaxStatsValue(): { - attack: number, - defense: number, - speed: number - } { + public getMaxStatsValue(): StatValues { const playerClass = ClassDataController.instance.getById(this.class); return { attack: playerClass.getAttackValue(this.level), diff --git a/Core/src/core/utils/ItemUtils.ts b/Core/src/core/utils/ItemUtils.ts index df3b66bc8..302b04183 100644 --- a/Core/src/core/utils/ItemUtils.ts +++ b/Core/src/core/utils/ItemUtils.ts @@ -28,6 +28,7 @@ import {ReactionCollectorAcceptReaction} from "../../../../Lib/src/packets/inter import {ItemWithDetails} from "../../../../Lib/src/interfaces/ItemWithDetails"; import {MainItem} from "../../data/MainItem"; import {SupportItem} from "../../data/SupportItem"; +import {StatValues} from "../../../../Lib/src/types/StatValues"; /** * Get the value of an item @@ -84,7 +85,7 @@ const getSupportItemDetails = function(item: SupportItem): { nature: ItemNature, }; }; -const getMainItemDetails = function(item: MainItem): { stats: { attack: number, defense: number, speed: number } } { +const getMainItemDetails = function(item: MainItem): { stats: StatValues } { return { stats: { attack: item.getAttack(), diff --git a/Core/src/data/MainItem.ts b/Core/src/data/MainItem.ts index 3a65663bf..09e94cb2d 100644 --- a/Core/src/data/MainItem.ts +++ b/Core/src/data/MainItem.ts @@ -1,6 +1,6 @@ import {GenericItem} from "./GenericItem"; import {MainItemDisplayPacket} from "../../../Lib/src/packets/commands/CommandInventoryPacket"; -import {MaxStatsValues} from "../../../Lib/src/types/MaxStatsValues"; +import {StatValues} from "../../../Lib/src/types/StatValues"; import {InventoryConstants} from "../../../Lib/src/constants/InventoryConstants"; export abstract class MainItem extends GenericItem { @@ -26,7 +26,7 @@ export abstract class MainItem extends GenericItem { return Math.round(before * 0.5) + (this.speed ?? 0); } - public getDisplayPacket(maxStatsValue: MaxStatsValues): MainItemDisplayPacket { + public getDisplayPacket(maxStatsValue: StatValues): MainItemDisplayPacket { return { attack: { value: this.getAttack(), diff --git a/Core/src/data/ObjectItem.ts b/Core/src/data/ObjectItem.ts index 10fc78b13..656462029 100644 --- a/Core/src/data/ObjectItem.ts +++ b/Core/src/data/ObjectItem.ts @@ -3,7 +3,7 @@ import {ItemDataController} from "./DataController"; import {SupportItem} from "./SupportItem"; import {RandomUtils} from "../../../Lib/src/utils/RandomUtils"; import {SupportItemDisplayPacket} from "../../../Lib/src/packets/commands/CommandInventoryPacket"; -import {MaxStatsValues} from "../../../Lib/src/types/MaxStatsValues"; +import {StatValues} from "../../../Lib/src/types/StatValues"; export class ObjectItem extends SupportItem { categoryName = "objects"; @@ -16,7 +16,7 @@ export class ObjectItem extends SupportItem { return this.power; } - public getDisplayPacket(maxStatsValue: MaxStatsValues): SupportItemDisplayPacket { + public getDisplayPacket(maxStatsValue: StatValues): SupportItemDisplayPacket { let maxPower = this.power; if (maxStatsValue.speed >= this.power / 2) { maxPower = this.power; diff --git a/Core/src/data/SupportItem.ts b/Core/src/data/SupportItem.ts index 6ddcb21ae..5881e9924 100644 --- a/Core/src/data/SupportItem.ts +++ b/Core/src/data/SupportItem.ts @@ -1,7 +1,7 @@ import {GenericItem} from "./GenericItem"; import {ItemNature} from "../../../Lib/src/constants/ItemConstants"; import {SupportItemDisplayPacket} from "../../../Lib/src/packets/commands/CommandInventoryPacket"; -import {MaxStatsValues} from "../../../Lib/src/types/MaxStatsValues"; +import {StatValues} from "../../../Lib/src/types/StatValues"; export abstract class SupportItem extends GenericItem { declare readonly power: number; @@ -20,5 +20,5 @@ export abstract class SupportItem extends GenericItem { return this.nature === ItemNature.SPEED ? this.power : 0; } - public abstract getDisplayPacket(maxStatsValue: MaxStatsValues): SupportItemDisplayPacket; + public abstract getDisplayPacket(maxStatsValue: StatValues): SupportItemDisplayPacket; } diff --git a/Discord/src/commands/player/ProfileCommand.ts b/Discord/src/commands/player/ProfileCommand.ts index 0b4af592d..dccd906f6 100644 --- a/Discord/src/commands/player/ProfileCommand.ts +++ b/Discord/src/commands/player/ProfileCommand.ts @@ -34,6 +34,12 @@ async function getPacket(interaction: DraftbotInteraction, keycloakUser: Keycloa return makePacket(CommandProfilePacketReq, {askedPlayer}); } +/** + * Send a message with all the badges of the player in case there are too many + * @param gameUsername + * @param badges + * @param interaction + */ async function sendMessageAllBadgesTooMuchBadges(gameUsername: string, badges: string[], interaction: DraftbotInteraction): Promise { let content = ""; for (const badgeSentence of badges) { @@ -52,13 +58,18 @@ async function sendMessageAllBadgesTooMuchBadges(gameUsername: string, badges: s }); } +/** + * Display the badges of the player as reactions + * @param badges + * @param msg + */ async function displayBadges(badges: string[], msg: Message): Promise { if (badges.length >= Constants.PROFILE.MAX_EMOTE_DISPLAY_NUMBER) { await msg.react(Constants.PROFILE.DISPLAY_ALL_BADGE_EMOTE); return; } - for (const badgeId in badges) { - await msg.react(badges[badgeId]); + for (const badgeId of badges) { + await msg.react(badgeId); } } @@ -81,6 +92,11 @@ function addField(fields: EmbedField[], fieldKey: string, shouldBeFielded: boole } } +/** + * Generate the fields of the profile embed + * @param packet + * @param lng + */ function generateFields(packet: CommandProfilePacketRes, lng: Language): EmbedField[] { const fields: EmbedField[] = []; addField(fields, "information", true, { @@ -115,7 +131,7 @@ function generateFields(packet: CommandProfilePacketRes, lng: Language): EmbedFi score: packet.playerData.rank.score, rank: packet.playerData.rank.rank, numberOfPlayer: packet.playerData.rank.numberOfPlayers - }) + }); addField(fields, packet.playerData.effect.healed ? "noTimeLeft" : "timeLeft", Boolean(packet.playerData.effect.hasTimeDisplay), { lng, @@ -156,6 +172,11 @@ function generateFields(packet: CommandProfilePacketRes, lng: Language): EmbedFi return fields; } +/** + * Handle the response of the profile command + * @param packet + * @param context + */ export async function handleCommandProfilePacketRes(packet: CommandProfilePacketRes, context: PacketContext): Promise { const interaction = DiscordCache.getInteraction(context.discord!.interaction); diff --git a/Discord/src/utils/DiscordItemUtils.ts b/Discord/src/utils/DiscordItemUtils.ts index cb9725ced..5052b5f30 100644 --- a/Discord/src/utils/DiscordItemUtils.ts +++ b/Discord/src/utils/DiscordItemUtils.ts @@ -7,7 +7,7 @@ import { import {EmbedField} from "discord.js"; import {ItemNature} from "../../../Lib/src/constants/ItemConstants"; import {minutesDisplay} from "../../../Lib/src/utils/TimeUtils"; -import {MaxStatsValues} from "../../../Lib/src/types/MaxStatsValues"; +import {StatValues} from "../../../Lib/src/types/StatValues"; import {DraftBotIcons} from "../../../Lib/src/DraftBotIcons"; import {EmoteUtils} from "./EmoteUtils"; @@ -47,7 +47,7 @@ export class DiscordItemUtils { * @param maxStatsValue * @protected */ - static getValues(attack: number, defense: number, speed: number, language: Language, maxStatsValue: MaxStatsValues | null = null): string { + static getValues(attack: number, defense: number, speed: number, language: Language, maxStatsValue: StatValues | null = null): string { if (!maxStatsValue) { maxStatsValue = { attack: Infinity, diff --git a/Lib/src/types/MaxStatsValues.ts b/Lib/src/types/MaxStatsValues.ts deleted file mode 100644 index b13736afe..000000000 --- a/Lib/src/types/MaxStatsValues.ts +++ /dev/null @@ -1 +0,0 @@ -export type MaxStatsValues = { attack: number, defense: number, speed: number } \ No newline at end of file diff --git a/Lib/src/types/StatValues.ts b/Lib/src/types/StatValues.ts new file mode 100644 index 000000000..e8121f1cf --- /dev/null +++ b/Lib/src/types/StatValues.ts @@ -0,0 +1 @@ +export type StatValues = { attack: number, defense: number, speed: number } \ No newline at end of file From 71ee4aa270eda1265c9cb7766872d46d15e33e5f Mon Sep 17 00:00:00 2001 From: Draftbot <158776144+Draphtbot@users.noreply.github.com> Date: Thu, 12 Dec 2024 01:34:03 +0100 Subject: [PATCH 15/17] New Crowdin updates (#2700) * New translations bot.json (Spanish) [ci skip] * New translations bot.json (German) [ci skip] * New translations bot.json (Italian) [ci skip] * New translations bot.json (Portuguese) [ci skip] * New translations bot.json (English) [ci skip] * New translations commands.json (Spanish) [ci skip] * New translations commands.json (German) [ci skip] * New translations commands.json (Italian) [ci skip] * New translations commands.json (Portuguese) [ci skip] * New translations commands.json (English) [ci skip] * New translations discordbuilder.json (Spanish) [ci skip] * New translations discordbuilder.json (German) [ci skip] * New translations discordbuilder.json (Italian) [ci skip] * New translations discordbuilder.json (Portuguese) [ci skip] --- Lang/de/bot.json | 6 ++--- Lang/de/commands.json | 16 +++++++++++-- Lang/de/discordBuilder.json | 14 +++++++++++ Lang/en/bot.json | 6 ++--- Lang/en/commands.json | 46 +++++++++++++++++++++++-------------- Lang/es/bot.json | 6 ++--- Lang/es/commands.json | 16 +++++++++++-- Lang/es/discordBuilder.json | 14 +++++++++++ Lang/it/bot.json | 6 ++--- Lang/it/commands.json | 16 +++++++++++-- Lang/it/discordBuilder.json | 14 +++++++++++ Lang/pt/bot.json | 6 ++--- Lang/pt/commands.json | 16 +++++++++++-- Lang/pt/discordBuilder.json | 14 +++++++++++ 14 files changed, 156 insertions(+), 40 deletions(-) diff --git a/Lang/de/bot.json b/Lang/de/bot.json index d658578ab..9beca6a29 100644 --- a/Lang/de/bot.json +++ b/Lang/de/bot.json @@ -12,14 +12,14 @@ "noReacPermission": ":x: | **Hallo ! Sie erhalten diese Nachricht, weil Sie versucht haben, einen meiner Befehle in einem Lounge zu verwenden, in dem ich zwar Nachrichten lesen, aber keine Reaktionen darauf hinzufügen darf !**\n\nIhre Abfrage wurde infolgedessen abgebrochen. Um dieses Problem zu beheben, senden Sie eine Nachricht an den Eigner des Servers, auf dem Sie versucht haben, mich zu verwenden. Wenn Sie dieses Problem nicht lösen können, lade ich Sie ein, den Leitfaden zu lesen, der unter https://guide.draftbot.com verfügbar ist !", "noSpeakInThreadPermission": ":zipper_mouth: | **Hallo ! Sie erhalten diese Nachricht, weil Sie versucht haben, einen meiner Befehle in einem Thread zu verwenden, in dem ich die Erlaubnis habe, Nachrichten zu sehen, aber nicht, welche zu senden !**\n\nIhre Anfrage wurde infolgedessen abgebrochen. Um dieses Problem zu lösen, senden Sie bitte eine Nachricht an den Besitzer des Servers, auf dem Sie versucht haben, mich zu benutzen. Wenn Sie dieses Problem nicht lösen können, bitte ich Sie, dem Support-Discord des Bots beizutreten, der unter folgender Adresse erreichbar ist: https://guide.draftbot.com !", "noSpeakPermission": ":zipper_mouth: | **Hallo ! Sie erhalten diese Nachricht, weil Sie versucht haben, einen meiner Befehle in einem Lounge zu verwenden, in dem ich die Erlaubnis habe, Nachrichten zu sehen, aber nicht, welche zu senden !**\n\nIhre Anfrage wurde infolgedessen abgebrochen. Um dieses Problem zu lösen, senden Sie bitte eine Nachricht an den Besitzer des Servers, auf dem Sie versucht haben, mich zu benutzen. Wenn Sie dieses Problem nicht lösen können, bitte ich Sie, dem Support-Discord des Bots beizutreten, der unter folgender Adresse erreichbar ist: https://guide.draftbot.com !", - "resetIsNow": ":trophy: Die Rangliste der Woche wird zurückgesetzt! Der Gewinner wird in Kürze auf dem Bot-Server bekannt gegeben! Das Spiel wird in weniger als 5 Minuten fortgesetzt!", + "resetIsNow": "{emote:announcements.trophy} Die Rangliste der Woche wird zurückgesetzt! Der Gewinner wird in Kürze auf dem Bot-Server bekannt gegeben! Das Spiel wird in weniger als 5 Minuten fortgesetzt!", "seasonEndAnnouncement": ":sparkles: ** Die Kampfsaison ist vorbei! Der Gewinner ist: ** {{mention}}", "seasonEndAnnouncementNoWinner": ":sparkles: **Die Kampfsaison ist vorbei! Leider gibt es in dieser Saison keinen Teilnehmer und somit auch keinen Gewinner.**", "seasonEndIsNow": ":sparkles: Die Kampfsaison wird gerade zurückgesetzt! Der Gewinner wird in Kürze auf dem Bot-Server bekannt gegeben! Das Spiel wird in weniger als 20 Minuten fortgesetzt!", "serverList": "**:outbox_tray: Server {{count}} : ** `{{guild}}'| :bust_in_silhouette: ' '{{humans}}' | :robot: : '{{robots}}' | Ratio bot/Humain: '{{ratio}}'% | Validation: {{validation}}", "supportAlert": ":love_letter: | ** Neue private Nachricht erhalten! ** \n' Verfasser: {{username}} (id : {{id}})", - "topWeekAnnouncement": ":trophy: ** Die Rangliste der Woche ist beendet! Der Gewinner ist: ** {{mention}}", - "topWeekAnnouncementNoWinner": ":trophy: **Die Rangliste der Woche ist fertig! Leider gibt es diese Woche keine Teilnehmer und somit auch keinen Gewinner.**", + "topWeekAnnouncement": "{emote:announcements.trophy} ** Die Rangliste der Woche ist beendet! Der Gewinner ist: ** {{mention}}", + "topWeekAnnouncementNoWinner": "{emote:announcements.trophy} **Die Rangliste der Woche ist fertig! Leider gibt es in dieser Woche keinen Teilnehmer und somit auch keinen Gewinner.**", "totalUsersCount": "** Gesamtzahl der Benutzer: '{{count}} ` * *", "notificationTitle": "Benachrichtigung", "notificationFooter": "Sie erhalten diese Nachricht, weil die Benachrichtigungen aktiviert sind. Um diese Einstellung zu ändern, verwenden Sie den Befehl {command:notifications}", diff --git a/Lang/de/commands.json b/Lang/de/commands.json index f024c52c6..55ecfb1e2 100644 --- a/Lang/de/commands.json +++ b/Lang/de/commands.json @@ -394,8 +394,11 @@ }, "ranking": { "fieldName": "Bewertung und Score:", - "fieldValue": ":trophy: {{rank}}/{{numberOfPlayer}} | :medal: {{score}}", - "fieldValueUnranked": ":trophy: Nicht klassifiziert | :medal: {{score}}" + "fieldValue": ":trophy: {{rank}}/{{numberOfPlayer}} | :medal: {{score}}" + }, + "unranked": { + "fieldName": "Rangliste und Punktestand :", + "fieldValue": "{emote:announcements.trophy} Nicht klassifiziert | {emote:unitValues.score} {{score}}" }, "statistics": { "fieldName": "Statistik:", @@ -701,5 +704,14 @@ "money": "Verdientes Geld :", "time": "Sie haben sich um" } + }, + "unlock": { + "himself": "Wenn Sie sich nicht selbst befreien können, bitten Sie einen Freund, dies zu tun.", + "notInJail": "Dieser Spieler befindet sich nicht im Gefängnis.", + "title": "Befreiung von {{pseudo}}", + "confirmDesc": "Sind Sie sicher, dass Sie **{{pseudo}}** für **{{price}} {emote:unitValues.money}** freigeben möchten?", + "canceledTitle": "Befreiung abgebrochen", + "canceledDesc": "Die Freilassung wurde rückgängig gemacht.", + "acceptedDesc": "Sie haben **{{pseudo}}** befreit!" } } \ No newline at end of file diff --git a/Lang/de/discordBuilder.json b/Lang/de/discordBuilder.json index 9bbadb8ba..5646ff77e 100644 --- a/Lang/de/discordBuilder.json +++ b/Lang/de/discordBuilder.json @@ -232,5 +232,19 @@ "daily": { "description": "Benutzen Sie Ihren ausgerüsteten Gegenstand, um einen täglichen Bonus zu erhalten.", "name": "Bonustag" + }, + "unlock": { + "description": "Befreie einen anderen Spieler aus dem Gefängnis.", + "name": "liefern", + "options": { + "rank": { + "description": "Die Einstufung des auszustellenden Spielers.", + "name": "Rangliste" + }, + "user": { + "description": "Der zu liefernde Nutzer.", + "name": "Benutzer" + } + } } } \ No newline at end of file diff --git a/Lang/en/bot.json b/Lang/en/bot.json index fd9634ec8..4cc4c4e88 100644 --- a/Lang/en/bot.json +++ b/Lang/en/bot.json @@ -12,14 +12,14 @@ "noReacPermission": ":x: | **Hello! You are receiving this message because you tried using one of my commands in a channel where I have the permissions to see messages but not react to them!**\n\nYour request was thus voided. To resolve this problem, please send a message to the owner of the server you tried to use me in. If you can't resolve this problem, I invite you to read the bot's guide available here: https://guide.draftbot.com/v/en/ !", "noSpeakInThreadPermission": ":zipper_mouth: | **Hello! You are receiving this message because you tried using one of my commands in a thread where I have the permissions to see messages but not send them!**\n\nYour request was thus voided. To resolve this problem, please send a message to the owner of the server you tried to use me in. If you can't resolve this problem, I invite you to read the bot's guide available here: https://guide.draftbot.com/v/en/ !", "noSpeakPermission": ":zipper_mouth: | **Hello! You are receiving this message because you tried using one of my commands in a channel where I have the permissions to see messages but not send them!**\n\nYour request was thus voided. To resolve this problem, please send a message to the owner of the server you tried to use me in. If you can't resolve this problem, I invite you to read the bot's guide available here: https://guide.draftbot.com/v/en/ !", - "resetIsNow": ":trophy: The weekly ranking is currently being reinitialized. The winner will soon be announced on the bot's server! The game will resume in less than 5 minutes!", + "resetIsNow": "{emote:announcements.trophy} The weekly ranking is currently being reinitialized. The winner will soon be announced on the bot's server! The game will resume in less than 5 minutes!", "seasonEndAnnouncement": ":sparkles: **The combat season has come to an end! The winner is:** {{mention}}", "seasonEndAnnouncementNoWinner": ":sparkles: **The battle season is over! Unfortunately, there is no participant and therefore winner this season.**", "seasonEndIsNow": ":sparkles: The combat season is currently being restored! The winner will soon be announced on the bot's server! The game will resume in less than 20 minutes!", "serverList": "**:outbox_tray: Server {{count}} :** `{{guild}}` | :bust_in_silhouette: : `{{humans}}` | :robot: : `{{robots}}` | Bot/human ratio : `{{ratio}}` % | Validation : {{validation}}", "supportAlert": ":love_letter: | **New DM received!** \n`Author: {{username}} (id : {{id}})\n\n`", - "topWeekAnnouncement": ":trophy: **The weekly ranking has ended! The winner is:** {{mention}}", - "topWeekAnnouncementNoWinner": ":trophy: **The Week Ranking is over! Unfortunately, there are no participants and therefore winners this week.**", + "topWeekAnnouncement": "{emote:announcements.trophy} **The weekly ranking has ended! The winner is:** {{mention}}", + "topWeekAnnouncementNoWinner": "{emote:announcements.trophy} **This week's ranking is over! Unfortunately, there is no participant and therefore a winner this week.**", "totalUsersCount": "**Total users count : `{{count}}`**", "notificationTitle": "Notify", "notificationFooter": "You are receiving this message because notifications are active. To change this setting, use the command {command:notifications}", diff --git a/Lang/en/commands.json b/Lang/en/commands.json index 6049d69f2..7154765bc 100644 --- a/Lang/en/commands.json +++ b/Lang/en/commands.json @@ -196,7 +196,7 @@ "description": "Change your pet's nickname. If no name is given, the nickname will be cleared." }, "PET_SELL": { - "description": "Allows to sell a pet. The following conditions apply: \n - The selling price must be higher than `{{petSellMinPrice}}{emote:unitValues.money}` and lower than `{{petSellMaxPrice}}{emote:unitValues.money}`. \n- The seller will not earn money for the transaction, but guild experience. \n- The seller and the buyer cannot be part of the same guild." + "description": "Can sell a pet. The following conditions apply: \n - the selling price must be higher at `{{petSellMinPrice}}{emote:unitValues.money}` and `{{petSellMaxPrice}}{emote:unitValues.money}`. \n- The vendor will not earn money during the transaction, but guild experience. \n- The seller and the buyer cannot be part of the same guild." }, "PET_TRADE": { "description": "Offers to exchange your pet with the mentioned player." @@ -343,7 +343,7 @@ "🎄": ":christmas_tree: `Badge that can be won every Christmas during a contest`", "🎗️": ":reminder_ribbon: `Person who dominated a weekly ranking`", "🎰": ":slot_machine: `Badge given in a completely random way`", - "🏅": ":medal: `Player in the top 10 by rank at the 1.0 reset`", + "🏅": "{emote:unitValues.score} `Player in top 10 to reset 1.0`", "🏆": ":trophy: `Best player by rank at the 1.0 reset`", "🐞": ":lady_beetle: `Person who reported major bugs`", "👑": ":crown: `Bot owner`", @@ -370,11 +370,11 @@ }, "information": { "fieldName": "Information:", - "fieldValue": ":heart: {{health}}/{{maxHealth}} | :star: {{experience}}/{{experienceNeededToLevelUp}} | :moneybag: {{money}}" + "fieldValue": "{emote:unitValues.health} {{health}}/{{maxHealth}} | :star: {{experience}}/{{experienceNeededToLevelUp}} | :moneybag: {{money}}" }, "map": { "fieldName": "Destination:", - "fieldValue": "{{mapEmote}} {{mapName}}" + "fieldValue": "{emote:map_types.{{mapTypeId}}} $t(models:map_locations.{{mapName}}.name)" }, "mission": { "fieldName": "Missions:", @@ -382,30 +382,33 @@ }, "noTimeLeft": { "fieldName": "Time left:", - "fieldValue": ":hospital: You can continue playing now" + "fieldValue": "{emote:effects.healed} Game Resume Possible" }, "pet": { "fieldName": "Pet:", - "fieldValue": "Rarity: {{rarity}}\n" + "fieldValue": "Rare: {{rarity}}\n$t(commands:pet.shortPetField)" }, "playerClass": { "fieldName": "Class:", - "fieldValue": "{{className}}" + "fieldValue": "$t(templates:classFormat)" }, "ranking": { "fieldName": "Ranking and score:", - "fieldValue": ":trophy: {{rank}}/{{numberOfPlayer}} | :medal: {{score}}", - "fieldValueUnranked": ":trophy: Unranked | :medal: {{score}}" + "fieldValue": ":trophy: {{rank}}/{{numberOfPlayer}} | :medal: {{score}}" + }, + "unranked": { + "fieldName": "Ranking and score:", + "fieldValue": "{emote:announcements.trophy} Unranked | {emote:unitValues.score} {{score}}" }, "statistics": { "fieldName": "Stats:", - "fieldValue": ":zap: {{cumulativeHealth}} / {{cumulativeMaxHealth}} | :dagger: {{cumulativeAttack}} | :shield: {{cumulativeDefense}} | :rocket: {{cumulativeSpeed}} | :wind_blowing_face: {{baseBreath}} / {{maxBreath}} | :lungs: {{breathRegen}}" + "fieldValue": "{emote:unitValues.energy} {{cumulativeHealth}} / {{cumulativeMaxHealth}} | {emote:unitValues.attack} {{cumulativeAttack}} | {emote:unitValues.defense} {{cumulativeDefense}} | {emote:unitValues.speed} {{cumulativeSpeed}} | {emote:unitValues.breath} {{baseBreath}} / {{maxBreath}} | {emote:unitValues.breathRegen} {{breathRegen}}" }, "timeLeft": { "fieldName": "Time left:", - "fieldValue": "{{effect}} {{timeLeft}}" + "fieldValue": "{emote:effects.{{effectId}}} {{timeLeft}}" }, - "title": "{{effect}} | {{pseudo}} | Level {{level}}" + "title": "{emote:effects.{{effectId}}} | {{pseudo}} | Level {{level}}" }, "rarity": { "rarities": ":small_orange_diamond: Basic | Owned at the beginning of the game\n:large_orange_diamond: Common | {{common}}%\n:fire: Uncommon | {{uncommon}}%\n:trident: Exotic | {{exotic}}%\n:comet: Rare | {{rare}}%\n:dizzy: Special | {{special}}%\n:star: Epic | {{epic}}%\n:star2: Legendary | {{legendary}}%\n:gem: Mythical | {{unique}}%", @@ -424,7 +427,7 @@ "destinationTitle": "{{pseudo}}, travel destination", "doChoice": "{{emoji}} {{choiceText}}\n", "doEvent": ":newspaper: **Journal of {{pseudo}}:** {{event}}\n*- Use reactions to make an action ⚠️ Not responding is considered a separate choice!*", - "doPossibility": ":newspaper: **Journal of {{pseudo}}{{result}}** | {{emoji}}{{event}} {{alte}}", + "doPossibility": ":newspaper: ** {{pseudo}} Log {{result}}** | {{emoji}} {{event}} {{alte}}", "encounterMonster": [ "You arrive at your destination when suddenly, you hear a noise behind you... A monster attacks you!" ], @@ -433,7 +436,7 @@ "energy": "** | :zap: Energy earned: **{{energy}}", "experience": "** | :star: XP earned: **{{experience}}", "gems": "** | :gem: Gems earned: **{{gems}}", - "health": "** | :heart: Life gained: **{{health}}", + "health": "** | {emote:unitValues.health} Life: **{{health}}", "healthLoose": "** | :broken_heart: Life lost: **{{health}}", "journal": "{{pseudo}}'s log", "money": "** | :moneybag: Money earned: **{{money}}", @@ -444,7 +447,7 @@ "monsterRewardsTitle": "{{pseudo}}, fight rewards", "newBigEvent": ":flag_gb: You have reached **{{destination}}**!", "noFight": ":newspaper: **{{pseudo}}'s log:** {{waitABitReaction}} | You run away as fast as possible and find a small hiding place! The monster is waiting patiently outside...", - "points": ":** :medal: Points earned: **{{score}}", + "points": ":** {emote:unitValues.score} Points earned: **{{score}}", "pveEvent": ":newspaper: **{{pseudo}}'s log:** {{event}}\n\n{{monsterDisplay}}\n\n- {{startTheFightReaction}} Start the fight\n- {{waitABitReaction}} Wait a bit before starting the fight\n\n*- Use reactions to make an action*", "remainingEnergyTitle": "Remaining energy:", "startPoint": "Start point:", @@ -511,7 +514,7 @@ "fullRegen": "💓 You have been fully cared for.", "alreadyHaveBadge": "You already have this badge.", "badgeBought": "You have received a new badge: {emote:badges.richPerson}!", - "notEnoughMoney": "You don't have enough money to buy this item! You are missing `{{missingMoney}}{emote:unitValues.money}`.", + "notEnoughMoney": "You don't have enough money to buy this item! You are missing `{{missingMoney}} {emote:unitValues.money}`.", "boughtTooMuchDailyPotions": "There are no more potions available for sale... Come back tomorrow!", "title": "🛒 Store Display", "currentMoney": "You have `{{money}}{emote:unitValues.money}`.", @@ -616,7 +619,7 @@ "displays": { "listing": "{{headerText}}\n\n{{classesList}}", "details": "{{classDetails}}{{attacksHeader}}\n{{attacksList}}", - "class": "### {{emoji}} {{name}}\n:zap: {{fightPoint}} | :dagger: {{attack}} | :shield: {{defense}} | :rocket: {{speed}} | :wind_blowing_face: {{baseBreath}} / {{maxBreath}} | :lungs: {{breathRegen}} | :heart: {{health}}", + "class": "### {{emoji}} {{name}}\n{emote:unitValues.energy} {{fightPoint}} | {emote:unitValues.attack} {{attack}} | {emote:unitValues.defense} {{defense}} | {emote:unitValues.speed} {{speed}} | :wind_blowing_face: {{baseBreath}} / {{maxBreath}} | {emote:unitValues.breathRegen} {{breathRegen}} | {emote:unitValues.health} {{health}}", "attack": "### {{emoji}} {{name}} | {{cost}} :wind_blowing_face:\n> {{description}}" } }, @@ -701,5 +704,14 @@ "money": "Money won:", "time": "You have advanced by" } + }, + "unlock": { + "himself": "You cannot libe-yourself, ask a friend to do so.", + "notInJail": "This player is not in prison.", + "title": "Libeation of {{pseudo}}", + "confirmDesc": "Are you sure you want to link **{{pseudo}}** to **{{price}} {emote:unitValues.money}**?", + "canceledTitle": "Libeation cancelled", + "canceledDesc": "The libeation has been cancelled.", + "acceptedDesc": "You have **{{pseudo}}**!" } } \ No newline at end of file diff --git a/Lang/es/bot.json b/Lang/es/bot.json index e2aa8f1cc..b4f93cdf8 100644 --- a/Lang/es/bot.json +++ b/Lang/es/bot.json @@ -12,14 +12,14 @@ "noReacPermission": ":x: | ¡Hola! Estás recibiendo este mensaje porque has intentado utilizar uno de mis comandos en una sala en la que tengo permiso para ver mensajes, pero no para publicar reacciones!**\n\nPor lo tanto, tu solicitud ha sido cancelada. Para resolver este problema, envía un mensaje al propietario del servidor en el que has intentado utilizarme. ¡Si no puedes resolver este problema, por favor lee la guía del bot disponible en la siguiente dirección: https://guide.draftbot.com !", "noSpeakInThreadPermission": ":zipper_mouth: | ¡Hola! Estás recibiendo este mensaje porque has intentado utilizar uno de mis comandos en un hilo en el que tengo permiso para ver mensajes, pero no para enviar ninguno!**\n\nPor lo tanto, tu solicitud ha sido cancelada. Para resolver este problema, envía un mensaje al propietario del servidor en el que has intentado utilizarme. ¡Si no puedes resolver este problema, por favor únete al discord de soporte del bot, que está disponible en la siguiente dirección: https://guide.draftbot.com !", "noSpeakPermission": ":zipper_mouth: | ¡Hola! Estás recibiendo este mensaje porque has intentado utilizar uno de mis comandos en una sala en la que tengo permiso para ver mensajes, pero no para enviar ninguno!**\n\nPor lo tanto, tu solicitud ha sido cancelada. Para resolver este problema, envía un mensaje al propietario del servidor en el que has intentado utilizarme. ¡Si no puedes resolver este problema, por favor únete al discord de soporte del bot, que está disponible en la siguiente dirección: https://guide.draftbot.com !", - "resetIsNow": ":trophy: ¡Se restablecen las clasificaciones de esta semana! El ganador se anunciará en breve en el servidor de bots. El juego se reanudará en menos de 5 minutos.", + "resetIsNow": "{emote:announcements.trophy} ¡Se restablecen las clasificaciones de esta semana! El ganador se anunciará en breve en el servidor de bots. El juego se reanudará en menos de 5 minutos.", "seasonEndAnnouncement": ":sparkles: **¡La temporada de lucha ha terminado! El ganador es:** {{mention}}", "seasonEndAnnouncementNoWinner": ":sparkles: **¡La temporada de combates ha terminado! Desafortunadamente, no hay participantes y por lo tanto no hay ganadores esta temporada **.", "seasonEndIsNow": ":sparkles: ¡Se reinicia la temporada de combates! ¡El ganador será anunciado en breve en el servidor bot! ¡El juego se reanudará en menos de 20 minutos!", "serverList": "**:outbox_tray: Servidor {{count}} :** `{{guild}}` | :bust_in_silhouette: `{{humans}}` :robot: : `{{robots}}` | Ratio bot/Humano : `{{ratio}}` % | Validación : {{validation}}", "supportAlert": ":love_letter: **¡Nuevo mensaje privado recibido!** \n`Autor: {{username}} (id : {{id}})\n\n`", - "topWeekAnnouncement": ":trophy: **¡La clasificación de esta semana ha terminado! El ganador es:** {{mention}}", - "topWeekAnnouncementNoWinner": ":trophy: **¡Las clasificaciones de esta semana ya están completas! Desafortunadamente, no hay participantes y por lo tanto no hay ganadores esta semana **.", + "topWeekAnnouncement": "{emote:announcements.trophy} **¡La clasificación de esta semana ha terminado! {{mention}}El ganador es:**", + "topWeekAnnouncementNoWinner": "{emote:announcements.trophy} **¡Las clasificaciones de esta semana ya están completas! Desafortunadamente, no hay participantes y por lo tanto no hay ganadores esta semana **.", "totalUsersCount": "**Número total de usuarios: `{{count}}`**", "notificationTitle": "Notificación", "notificationFooter": "Está recibiendo este mensaje porque las notificaciones están activadas. {command:notifications}Para cambiar esta configuración, utilice el comando", diff --git a/Lang/es/commands.json b/Lang/es/commands.json index d981f4314..77c7496c4 100644 --- a/Lang/es/commands.json +++ b/Lang/es/commands.json @@ -394,8 +394,11 @@ }, "ranking": { "fieldName": "Clasificación y puntuación :", - "fieldValue": ":trophy: {{rank}}/{{numberOfPlayer}} | :medal: {{score}}", - "fieldValueUnranked": ":trophy: Sin categoría | :medal: {{score}}" + "fieldValue": ":trophy: {{rank}}/{{numberOfPlayer}} | :medal: {{score}}" + }, + "unranked": { + "fieldName": "Clasificación y puntuación :", + "fieldValue": "{emote:announcements.trophy} {emote:unitValues.score} {{score}}Sin categoría" }, "statistics": { "fieldName": "Estadísticas :", @@ -701,5 +704,14 @@ "money": "Dinero ganado :", "time": "Has avanzado por" } + }, + "unlock": { + "himself": "Si no puedes liberarte tú mismo, pide a un amigo que lo haga por ti.", + "notInJail": "Este jugador no está en la cárcel.", + "title": "{{pseudo}}Liberación de", + "confirmDesc": "{{pseudo}}{{price}} {emote:unitValues.money}¿Estás seguro de que quieres liberar a ** ** para ** **?", + "canceledTitle": "Liberación cancelada", + "canceledDesc": "El lanzamiento fue cancelado.", + "acceptedDesc": "{{pseudo}}¡Has liberado a ** ** !" } } \ No newline at end of file diff --git a/Lang/es/discordBuilder.json b/Lang/es/discordBuilder.json index 014b0fbe9..c94f1085b 100644 --- a/Lang/es/discordBuilder.json +++ b/Lang/es/discordBuilder.json @@ -232,5 +232,19 @@ "daily": { "description": "Utiliza tu objeto equipado para obtener una bonificación diaria.", "name": "bonificación diaria" + }, + "unlock": { + "description": "Libera a otro jugador de la prisión.", + "name": "Entregar", + "options": { + "rank": { + "description": "La clasificación del jugador que se emitirá.", + "name": "clasificación" + }, + "user": { + "description": "El usuario a entregar.", + "name": "usuario" + } + } } } \ No newline at end of file diff --git a/Lang/it/bot.json b/Lang/it/bot.json index f1f543e7d..25b0abe88 100644 --- a/Lang/it/bot.json +++ b/Lang/it/bot.json @@ -12,14 +12,14 @@ "noReacPermission": ":x: | **Ciao ! Avete ricevuto questo messaggio perché avete provato di utilizzare uno dei miei comandi in un chat dove ho la permissione di vedere i messagi, ma non di mettere delle reazione !**\n\nVostra richiesta e allora stata annullata, per risolvere questo problema grazie di inviare un messagio al proprietario del server sul quale avete provato di utilizarmi. Se non riucite a risolvere questo problema, vi propongo di andare nel discord di supporto disponibile qui : https://guide.draftbot.com !", "noSpeakInThreadPermission": ":zipper_mouth: | **Ciao ! Avete ricevuto questo messaggio perché avete provato di utilizzare uno dei miei comandi in un thread dove ho la permissione di vedere i messagi, ma non di inviarni !**\n\nVostra richiesta e allora stata annullata, per risolvere questo problema grazie di inviare un messagio al proprietario del server sul quale avete provato di utilizarmi. Se non riucite a risolvere questo problema, vi propongo di andare nel discord di supporto disponibile qui : https://guide.draftbot.com !", "noSpeakPermission": ":zipper_mouth: | **Ciao ! Avete ricevuto questo messaggio perché avete provato di utilizzare uno dei miei comandi in un thread dove ho la permissione di vedere i messagi, ma non di inviarni !**\n\nVostra richiesta e allora stata annullata, per risolvere questo problema grazie di inviare un messagio al proprietario del server sul quale avete provato di utilizarmi. Se non riucite a risolvere questo problema, vi propongo di andare nel discord di supporto disponibile qui : https://guide.draftbot.com !", - "resetIsNow": ":trophy: Le classifiche della settimana sono in corso di reimpostazione ! Il vincitore sarà annunciato tra poco sul server del bot ! Il gioco riprenderà tra 5 minuti !", + "resetIsNow": "{emote:announcements.trophy} Le classifiche della settimana sono in corso di reimpostazione ! Il vincitore sarà annunciato tra poco sul server del bot ! Il gioco riprenderà tra 5 minuti !", "seasonEndAnnouncement": ":sparkles: **La stagione di combattimento e finita ! Il vincitore e :** {{mention}}", "seasonEndAnnouncementNoWinner": ":sparkles: **La stagione dei combattimenti è finita! Purtroppo non ci sono partecipanti e quindi non ci sono vincitori per questa stagione **.", "seasonEndIsNow": ":sparkles: Le classifiche della settimana sono in corso di reimpostazione ! Il vincitore sarà annunciato tra poco sul server del bot ! Il gioco riprenderà tra 5 minuti !", "serverList": "**:outbox_tray: Server {{count}} :** `{{guild}}` | :bust_in_silhouette: : `{{humans}}` | :robot: : `{{robots}}` | Rapporto bot/Umano : `{{ratio}}` % | Validazione : {{validation}}", "supportAlert": ":love_letter: | **Nuovo messaggio privato ricevuto !** \n`Autore: {{username}} (id : {{id}})", - "topWeekAnnouncement": ":trophy: **La classifica della settimana e finita ! Il vincitore e :** {{mention}}", - "topWeekAnnouncementNoWinner": ":trophy: **Le classifiche di questa settimana sono ora complete! Purtroppo questa settimana non ci sono partecipanti e quindi non ci sono vincitori **.", + "topWeekAnnouncement": "{emote:announcements.trophy} **La classifica della settimana e finita ! Il vincitore e :** {{mention}}", + "topWeekAnnouncementNoWinner": "{emote:announcements.trophy} **Le classifiche di questa settimana sono ora complete! Purtroppo questa settimana non ci sono partecipanti e quindi non ci sono vincitori **.", "totalUsersCount": "**Numero totale di utilizzatori : `{{count}}`**", "notificationTitle": "Notifica", "notificationFooter": "Si riceve questo messaggio perché le notifiche sono abilitate. {command:notifications}Per modificare questa impostazione, utilizzare il comando", diff --git a/Lang/it/commands.json b/Lang/it/commands.json index 17e5cf810..cdff8814c 100644 --- a/Lang/it/commands.json +++ b/Lang/it/commands.json @@ -394,8 +394,11 @@ }, "ranking": { "fieldName": "Classifica e punti :", - "fieldValue": ":trophy: {{rank}}/{{numberOfPlayer}} | :medal: {{score}}", - "fieldValueUnranked": ":trophy: Non estimato | :medal: {{score}}" + "fieldValue": ":trophy: {{rank}}/{{numberOfPlayer}} | :medal: {{score}}" + }, + "unranked": { + "fieldName": "Classifica e punti :", + "fieldValue": "{emote:announcements.trophy} Non estimato | {emote:unitValues.score} {{score}}" }, "statistics": { "fieldName": "Statistiche :", @@ -701,5 +704,14 @@ "money": "Soldi guadagnati :", "time": "Siete avanzati di" } + }, + "unlock": { + "himself": "Se non riuscite a liberarvi da soli, chiedete a un amico di farlo per voi.", + "notInJail": "Questo giocatore non è in prigione.", + "title": "{{pseudo}}Liberazione di", + "confirmDesc": "{{pseudo}}{{price}} {emote:unitValues.money}Sei sicuro di voler rilasciare ** ** per ** **?", + "canceledTitle": "Rilascio annullato", + "canceledDesc": "L'uscita è stata annullata.", + "acceptedDesc": "{{pseudo}}Avete liberato ** ** !" } } \ No newline at end of file diff --git a/Lang/it/discordBuilder.json b/Lang/it/discordBuilder.json index 8b63f9064..a8b709f18 100644 --- a/Lang/it/discordBuilder.json +++ b/Lang/it/discordBuilder.json @@ -232,5 +232,19 @@ "daily": { "description": "Usa l'oggetto equipaggiato per ottenere un bonus giornaliero.", "name": "bonus giornaliero" + }, + "unlock": { + "description": "Liberare un altro giocatore dalla prigione.", + "name": "consegnare", + "options": { + "rank": { + "description": "La classifica del giocatore da emettere.", + "name": "classifica" + }, + "user": { + "description": "L'utente da consegnare.", + "name": "utilizzatore" + } + } } } \ No newline at end of file diff --git a/Lang/pt/bot.json b/Lang/pt/bot.json index 3d4d2fdc3..85d8022d1 100644 --- a/Lang/pt/bot.json +++ b/Lang/pt/bot.json @@ -12,14 +12,14 @@ "noReacPermission": ":x: | Olá!\n\nEstá a receber esta mensagem porque tentou utilizar um dos meus comandos numa sala onde tenho permissão para ver mensagens, mas não para publicar reacções!** O seu pedido foi, portanto, cancelado. Para resolver este problema, envia uma mensagem ao proprietário do servidor em que tentaste utilizar-me. Se não conseguires resolver este problema, lê o guia do bot disponível no seguinte endereço: https://guide.draftbot.com !", "noSpeakInThreadPermission": ":zipper_mouth: | Olá!\n\nEstás a receber esta mensagem porque tentaste utilizar um dos meus comandos num tópico onde tenho permissão para ver mensagens, mas não para enviar nenhuma!** O teu pedido foi, portanto, cancelado. Para resolver este problema, por favor envia uma mensagem ao dono do servidor onde tentaste usar-me. Se não conseguires resolver este problema, junta-te ao discord de suporte do bot, que está disponível no seguinte endereço: https://guide.draftbot.com !", "noSpeakPermission": ":zipper_mouth: | Olá!\n\nEstás a receber esta mensagem porque tentaste utilizar um dos meus comandos numa sala onde tenho permissão para ver mensagens, mas não para as enviar!** O teu pedido foi, portanto, cancelado. Para resolver este problema, por favor envia uma mensagem ao proprietário do servidor onde tentaste utilizar-me. Se não conseguires resolver este problema, junta-te ao discord de suporte do bot, que está disponível no seguinte endereço: https://guide.draftbot.com !", - "resetIsNow": ":trophy: As classificações desta semana estão a ser repostas! O vencedor será anunciado em breve no servidor bot! O jogo será retomado em menos de 5 minutos!", + "resetIsNow": "{emote:announcements.trophy} As classificações desta semana estão a ser repostas! O vencedor será anunciado em breve no servidor bot! O jogo será retomado em menos de 5 minutos!", "seasonEndAnnouncement": ":sparkles: **A época de combates terminou! {{mention}}O vencedor é: **", "seasonEndAnnouncementNoWinner": ":sparkles: **A época de combates terminou! Infelizmente, não há participantes e, portanto, não há vencedores nesta temporada **.", "seasonEndIsNow": ":sparkles: A época de combates está a ser reiniciada! O vencedor será anunciado em breve no servidor bot! O jogo será retomado em menos de 20 minutos!", "serverList": ":outbox_tray: {{count}}{{guild}} :bust_in_silhouette:{{humans}} :robot:{{robots}}{{ratio}} {{validation}}** Servidor :** ` ` | ` ` : ` ` | Rácio bot/Humano : ` ` % | Validação :", "supportAlert": ":love_letter: \n {{username}} {{id}}\n\n**Nova mensagem privada recebida!** `Autor: (id : ) `", - "topWeekAnnouncement": ":trophy: **As classificações desta semana terminaram! {{mention}}O vencedor é:**", - "topWeekAnnouncementNoWinner": ":trophy: **As classificações desta semana estão completas! Infelizmente, não há participantes e, portanto, não há vencedores esta semana **.", + "topWeekAnnouncement": "{emote:announcements.trophy} **As classificações desta semana terminaram! {{mention}}O vencedor é:**", + "topWeekAnnouncementNoWinner": "{emote:announcements.trophy} **As classificações desta semana estão completas! Infelizmente, não há participantes e, portanto, não há vencedores esta semana **.", "totalUsersCount": "{{count}}**Número total de utilizadores: ` `**", "notificationTitle": "Notificação", "notificationFooter": "Está a receber esta mensagem porque as notificações estão activadas. {command:notifications}Para alterar esta definição, utilize o comando", diff --git a/Lang/pt/commands.json b/Lang/pt/commands.json index 3aebfd939..38970de96 100644 --- a/Lang/pt/commands.json +++ b/Lang/pt/commands.json @@ -394,8 +394,11 @@ }, "ranking": { "fieldName": "Classificação e pontuação :", - "fieldValue": ":trophy: {{rank}}{{numberOfPlayer}} :medal: {{score}}/ |", - "fieldValueUnranked": ":trophy: :medal: {{score}}Sem categoria" + "fieldValue": ":trophy: {{rank}}{{numberOfPlayer}} :medal: {{score}}/ |" + }, + "unranked": { + "fieldName": "Classificação e pontuação :", + "fieldValue": "{emote:announcements.trophy} {emote:unitValues.score} {{score}}Sem categoria" }, "statistics": { "fieldName": "Estatísticas :", @@ -701,5 +704,14 @@ "money": "Dinheiro ganho :", "time": "Avançou por" } + }, + "unlock": { + "himself": "Se não se conseguir libertar sozinho, peça a um amigo que o faça por si.", + "notInJail": "Este jogador não está na prisão.", + "title": "{{pseudo}}Libertação de", + "confirmDesc": "{{pseudo}}{{price}} {emote:unitValues.money}Tem a certeza de que pretende libertar ** ** para ** **?", + "canceledTitle": "Lançamento cancelado", + "canceledDesc": "O lançamento foi cancelado.", + "acceptedDesc": "{{pseudo}}Libertaste ** ** !" } } \ No newline at end of file diff --git a/Lang/pt/discordBuilder.json b/Lang/pt/discordBuilder.json index fc898c204..849fb148b 100644 --- a/Lang/pt/discordBuilder.json +++ b/Lang/pt/discordBuilder.json @@ -232,5 +232,19 @@ "daily": { "description": "Utilize o seu item equipado para obter um bónus diário.", "name": "bónus diário" + }, + "unlock": { + "description": "Libertar outro jogador da prisão.", + "name": "entregar", + "options": { + "rank": { + "description": "A classificação do jogador a ser emitida.", + "name": "classificação" + }, + "user": { + "description": "O utilizador a ser entregue.", + "name": "utilizador" + } + } } } \ No newline at end of file From b462941b52ef199aeb28f0e42c003471fbbf6db1 Mon Sep 17 00:00:00 2001 From: Ntalcme Date: Fri, 22 Nov 2024 13:33:11 +0100 Subject: [PATCH 16/17] WIP on front shop SE #2318 --- Discord/src/smallEvents/shop.ts | 39 ++++++++++++++++++ Lang/fr/smallEvents.json | 72 ++++++++++++++++++++++++++++----- 2 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 Discord/src/smallEvents/shop.ts diff --git a/Discord/src/smallEvents/shop.ts b/Discord/src/smallEvents/shop.ts new file mode 100644 index 000000000..e363bab55 --- /dev/null +++ b/Discord/src/smallEvents/shop.ts @@ -0,0 +1,39 @@ +import {ReactionCollectorCreationPacket} from "../../../Lib/src/packets/interaction/ReactionCollectorPacket"; +import {PacketContext} from "../../../Lib/src/packets/DraftBotPacket"; +import {DiscordCache} from "../bot/DiscordCache"; +import {DraftbotSmallEventEmbed} from "../messages/DraftbotSmallEventEmbed"; +import {StringUtils} from "../utils/StringUtils"; +import {DiscordCollectorUtils} from "../utils/DiscordCollectorUtils"; +import {ReactionCollectorMerchantData} from "../../../Lib/src/packets/interaction/ReactionCollectorMerchant"; +import {RandomUtils} from "../../../Lib/src/utils/RandomUtils"; +import {KeycloakUtils} from "../../../Lib/src/keycloak/KeycloakUtils"; +import {keycloakConfig} from "../bot/DraftBotShard"; +import {SmallEventShopPacket} from "../../../Lib/src/packets/smallEvents/SmallEventShopPacket"; + +export async function shopCollector(packet: ReactionCollectorCreationPacket, context: PacketContext): Promise { + const interaction = DiscordCache.getInteraction(context.discord!.interaction)!; + const data = packet.data.data as ReactionCollectorMerchantData; + const gender = RandomUtils.draftbotRandom.bool() ? "m" : "f"; + const name = StringUtils.getRandomTranslation("smallEvents:shop.names", interaction.userLanguage, {context: gender}); + + const embed = new DraftbotSmallEventEmbed( + "shop", + StringUtils.getRandomTranslation("smallEvents:shop.intro", interaction.userLanguage, {context: gender, name}) + + StringUtils.getRandomTranslation("smallEvents:shop.end", interaction.userLanguage, { + item: /* TODO: Renvoyer l'item avec ses stats etc */, + price: data.price, + type: data.item.category + }), + interaction.user, + interaction.userLanguage + ); + + await DiscordCollectorUtils.createAcceptRefuseCollector(interaction, embed, packet, context); +} + +export async function shopResult(packet: SmallEventShopPacket, context: PacketContext): Promise { + const user = (await KeycloakUtils.getUserByKeycloakId(keycloakConfig, context.keycloakId!))!; + const interaction = DiscordCache.getButtonInteraction(context.discord!.buttonInteraction!); + + /* TODO : Renvoyer une réponse/Trouver les textes ?? */ +} \ No newline at end of file diff --git a/Lang/fr/smallEvents.json b/Lang/fr/smallEvents.json index 179724796..b41f5a428 100644 --- a/Lang/fr/smallEvents.json +++ b/Lang/fr/smallEvents.json @@ -602,15 +602,15 @@ "before_search_format": "{{seIntro}}{{intro}}. {{searchAction}}.\n\n:telescope: *{{search}}*.", "after_search_format": "{{oldMessage}}\n\n{{actionIntro}}, {{action}} **{{specific}}**. {{outro}}.", "intro": [ - "vous rencontrez un oracle prétendant se nommer **{{name}}**", - "un homme vous semble étrange, alors vous allez à sa rencontre. Il dit être un oracle du nom de **{{name}}**", - "vous rencontrez un oracle s'appelant **{{name}}**", - "vous passez à côté d'un oracle qui vous interpelle. Il dit s'appeler **{{name}}**", - "vous êtes interpelé par un homme disant s'appeler **{{name}}**", - "un oracle du nom de **{{name}}** vous apostrophe", - "un étranger prétendant s'appeler **{{name}}** vous demande d'approcher", - "un homme surgissant de nulle part court vers vous et se présente sous le nom de **{{name}}**", - "un inconnu suspect vous demande d'approcher, ce après quoi il vous dit s'appeler **{{name}}**" + "vous rencontrez un oracle prétendant se nommer **{{{name}}}**", + "un homme vous semble étrange, alors vous allez à sa rencontre. Il dit être un oracle du nom de **{{{name}}}**", + "vous rencontrez un oracle s'appelant **{{{name}}}**", + "vous passez à côté d'un oracle qui vous interpelle. Il dit s'appeler **{{{name}}}**", + "vous êtes interpelé par un homme disant s'appeler **{{{name}}}**", + "un oracle du nom de **{{{name}}}** vous apostrophe", + "un étranger prétendant s'appeler **{{{name}}}** vous demande d'approcher", + "un homme surgissant de nulle part court vers vous et se présente sous le nom de **{{{name}}}**", + "un inconnu suspect vous demande d'approcher, ce après quoi il vous dit s'appeler **{{{name}}}**" ], "searchAction": [ "Il vous dit qu'il peut vous donner des informations sur le ciel, mais qu'il a besoin de temps pour l'observer", @@ -1500,5 +1500,59 @@ "nothing": "Vous soulevez doucement le gobelet $t(smallEvents:gobletsGame.goblets.{{goblet}}.name) et remarquez qu'il n'y a rien dessous. Déçu, vous repartez tristement en vous disant que vous aurez peut-être plus de chance une autre fois.", "end": "Devant votre manque de réaction, l'homme a la mauvaise idée d'essayer de vous voler. Remarquant sa manoeuvre, vous intervenez, mais vous êtes rapidement surpris de la force de l'homme qui parvient à se dégager d'un brusque mouvement, avant de s'enfuir. Vous vous en sortez avec une légère blessure **{{quantity}} {emote:unitValues.lostHealth}**." } + }, + "shop": { + "intro_m": [ + "Alors que vous voyagez tranquillement, vous rencontrez {{name}}. Ce dernier est un marchand ambulant, et vous propose une offre spéciale.", + "Tandis que vous avancez tranquillement sur votre route, vous tombez nez à nez avec {{name}}, qui vous propose rapidement une offre alléchante.", + "Alors que vous vous apprêtez à vous remettre en marche après une petite pause, un homme se présentant comme \"{{name}} - marchand ambulant\" vous propose un échange.", + "Au détour d'un rocher, vous tombez nez à nez avec un marchand ambulant nommé {{name}}, qui semble vendre des choses fortes intéressantes.", + "Alors que vous vous baladez tranquillement, une charrette arborant l'enseigne \"{{name}} - super marchand ambulant d'items\" apparaît devant vous. Une transaction s'amorce immédiatement.", + "À un certain point de votre voyage, un marchand vous interpelle. Il dit s'appeler {{name}} et avoir des objets pouvant vous aider pendant votre aventure.", + "Après de longues heures de marche, un homme vous aborde. Vous apprenez qu'il se nomme {{name}} – marchand de première qualité. Il vous montre rapidement un de ses nombreux objets.", + "Au cours d'une petite pause contre un arbre, un homme vient à vous et se présente comme étant marchand ambulant. L'homme qui se nomme {{name}} semble proposer une offre alléchante." + ], + "intro_f": [ + "Tandis que vous avancez tranquillement sur votre route, vous tombez nez à nez avec {{name}} qui vous propose rapidement une offre alléchante.", + "En parcourant les routes vous rencontrez souvent des marchands ambulants. Aujourd'hui c'est une marchande, nommée {{name}} qui vous propose son offre.", + "Pendant votre voyage, une marchande vous interpelle. Elle dit s'appeler {{name}} et avoir des objets pouvant vous aider pendant votre aventure.", + "Tandis que vous avancez tranquillement sur votre route, vous croisez une charrette dans laquelle se trouve une marchande du nom de {{name}}. Celle-ci vous propose de lui acheter l'un de ses objets, vous affirmant qu'il pourrait vous être utile dans votre aventure." + ], + "end": "\n\n{{item}} | `{{price}}\uD83D\uDCB0`\n\n**Type :** {{type}}", + "types": [ + "Arme", + "Armure/Bouclier", + "Potion", + "Objet" + ], + "names_m": [ + "Terry", + "Marco", + "Didier", + "Bernard", + "Georges", + "Louis", + "Kilton", + "Kikolou", + "Araj", + "Lavio", + "Bugri", + "Faras", + "Finn", + "Russel", + "Ullure", + "Vivian", + "Belethor" + ], + "names_f": [ + "Karine", + "Cremia", + "Fouyaya", + "Ember", + "Embry", + "Emirel", + "Fressah", + "Ullure" + ] } } \ No newline at end of file From d1bed014f3942475dce15d507631b48a712689ef Mon Sep 17 00:00:00 2001 From: Ntalcme Date: Sun, 8 Dec 2024 19:09:34 +0100 Subject: [PATCH 17/17] WIP on SE shop #2318 --- Core/src/core/smallEvents/interfaces/Shop.ts | 7 +-- .../handlers/ReactionCollectorHandlers.ts | 48 +++++++++++++++++++ Discord/src/smallEvents/shop.ts | 3 +- Lang/fr/smallEvents.json | 6 +-- .../interaction/ReactionCollectorMerchant.ts | 4 +- 5 files changed, 57 insertions(+), 11 deletions(-) diff --git a/Core/src/core/smallEvents/interfaces/Shop.ts b/Core/src/core/smallEvents/interfaces/Shop.ts index 3ac11a1ef..4562f2b83 100644 --- a/Core/src/core/smallEvents/interfaces/Shop.ts +++ b/Core/src/core/smallEvents/interfaces/Shop.ts @@ -2,7 +2,7 @@ import {GenericItem} from "../../../data/GenericItem"; import Player from "../../database/game/models/Player"; import {Maps} from "../../maps/Maps"; import {ExecuteSmallEventLike} from "../../../data/SmallEvent"; -import {getItemValue, giveItemToPlayer} from "../../utils/ItemUtils"; +import {getItemValue, giveItemToPlayer, toItemWithDetails} from "../../utils/ItemUtils"; import {EndCallback, ReactionCollectorInstance} from "../../utils/ReactionsCollector"; import {BlockingConstants} from "../../../../../Lib/src/constants/BlockingConstants"; import {BlockingUtils} from "../../utils/BlockingUtils"; @@ -34,10 +34,7 @@ export abstract class Shop { this.itemPrice = Math.round(getItemValue(this.randomItem) * this.itemMultiplier); const collector = new ReactionCollectorMerchant({ - item: { - category: this.randomItem.getCategory(), - id: this.randomItem.id - }, + item: toItemWithDetails(this.randomItem), price: this.itemPrice }); diff --git a/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts b/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts index 06149265d..f0a8b4840 100644 --- a/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts +++ b/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts @@ -26,6 +26,10 @@ import {shopCollector, shopInventoryExtensionCollector} from "../../commands/pla import {ReactionCollectorBuyCategorySlotData} from "../../../../Lib/src/packets/interaction/ReactionCollectorBuyCategorySlot"; import {ReactionCollectorCartData} from "../../../../Lib/src/packets/interaction/ReactionCollectorCart"; import {cartCollector} from "../../smallEvents/cart"; +import { + ReactionCollectorMerchant, + ReactionCollectorMerchantData +} from "../../../../Lib/src/packets/interaction/ReactionCollectorMerchant"; import {ReactionCollectorFightPetData} from "../../../../Lib/src/packets/interaction/ReactionCollectorFightPet"; import {fightPetCollector} from "../../smallEvents/fightPet"; import {PacketListenerCallbackClient} from "../../../../Lib/src/packets/PacketListener"; @@ -64,6 +68,50 @@ export default class ReactionCollectorHandler { @packetHandler(ReactionCollectorCreationPacket) async collectorCreation(packet: ReactionCollectorCreationPacket, context: PacketContext): Promise { + switch (packet.data.type) { + case ReactionCollectorBigEventData.name: + await createBigEventCollector(packet, context); + break; + case ReactionCollectorChooseDestinationData.name: + await chooseDestinationCollector(packet, context); + break; + case ReactionCollectorGoToPVEIslandData.name: + await goToPVEIslandCollector(packet, context); + break; + case ReactionCollectorPetFreeData.name: + await createPetFreeCollector(packet, context); + break; + case ReactionCollectorGuildCreateData.name: + await createGuildCreateCollector(packet, context); + break; + case ReactionCollectorLotteryData.name: + await lotteryCollector(packet, context); + break; + case ReactionCollectorInteractOtherPlayersPoorData.name: + await interactOtherPlayersCollector(packet, context); + break; + case ReactionCollectorWitchData.name: + await witchCollector(packet, context); + break; + case ReactionCollectorItemChoiceData.name: + await itemChoiceCollector(packet, context); + break; + case ReactionCollectorItemAcceptData.name: + await itemAcceptCollector(packet, context); + break; + case ReactionCollectorShopData.name: + await shopCollector(packet, context); + break; + case ReactionCollectorBuyCategorySlotData.name: + await shopInventoryExtensionCollector(packet, context); + break; + case ReactionCollectorCartData.name: + await cartCollector(packet, context); + break; + case ReactionCollectorMerchantData.name: + await shopCollector(packet, context); + break; + default: if (!ReactionCollectorHandler.collectorMap) { ReactionCollectorHandler.initCollectorMap(); } diff --git a/Discord/src/smallEvents/shop.ts b/Discord/src/smallEvents/shop.ts index e363bab55..461365806 100644 --- a/Discord/src/smallEvents/shop.ts +++ b/Discord/src/smallEvents/shop.ts @@ -9,6 +9,7 @@ import {RandomUtils} from "../../../Lib/src/utils/RandomUtils"; import {KeycloakUtils} from "../../../Lib/src/keycloak/KeycloakUtils"; import {keycloakConfig} from "../bot/DraftBotShard"; import {SmallEventShopPacket} from "../../../Lib/src/packets/smallEvents/SmallEventShopPacket"; +import {DisplayUtils} from "../utils/DisplayUtils"; export async function shopCollector(packet: ReactionCollectorCreationPacket, context: PacketContext): Promise { const interaction = DiscordCache.getInteraction(context.discord!.interaction)!; @@ -20,7 +21,7 @@ export async function shopCollector(packet: ReactionCollectorCreationPacket, con "shop", StringUtils.getRandomTranslation("smallEvents:shop.intro", interaction.userLanguage, {context: gender, name}) + StringUtils.getRandomTranslation("smallEvents:shop.end", interaction.userLanguage, { - item: /* TODO: Renvoyer l'item avec ses stats etc */, + item: DisplayUtils.getItemDisplayWithStats(data.item,interaction.userLanguage), price: data.price, type: data.item.category }), diff --git a/Lang/fr/smallEvents.json b/Lang/fr/smallEvents.json index b41f5a428..19ec12fd5 100644 --- a/Lang/fr/smallEvents.json +++ b/Lang/fr/smallEvents.json @@ -62,9 +62,9 @@ }, "boatAdvice": { "intro": [ - "Vous montez sur le pont et vous discutez avec un membre de l'équipage. Il vous donne un conseil pour vous aider dans votre aventure sur l'île :\n**{{{advice}}}**.", - "Vous grimpez sur le mât pour admirer l'horizon. Un homme baisse sa longue-vue et tient à vous donner ce conseil avant votre départ pour l'île :\n**{{{advice}}}**.", - "Dans les joies d'un repas au vent frais de la mer, vous discutez avec les matelots. Votre voisin de table vous donne le conseil suivant à propos de l'île :\n**{{{advice}}}**." + "Vous montez sur le pont et vous discutez avec un membre de l'équipage. Il vous donne un conseil pour vous aider dans votre aventure sur l'île :\n**{{advice}}**.", + "Vous grimpez sur le mât pour admirer l'horizon. Un homme baisse sa longue-vue et tient à vous donner ce conseil avant votre départ pour l'île :\n**{{advice}}**.", + "Dans les joies d'un repas au vent frais de la mer, vous discutez avec les matelots. Votre voisin de table vous donne le conseil suivant à propos de l'île :\n**{{advice}}**." ], "advices": [ "Il y a beaucoup plus d'évènements qui vous attendent sur l'île mystérieuse", diff --git a/Lib/src/packets/interaction/ReactionCollectorMerchant.ts b/Lib/src/packets/interaction/ReactionCollectorMerchant.ts index 5d95a7aef..c132e5607 100644 --- a/Lib/src/packets/interaction/ReactionCollectorMerchant.ts +++ b/Lib/src/packets/interaction/ReactionCollectorMerchant.ts @@ -4,10 +4,10 @@ import { ReactionCollectorData, ReactionCollectorReaction } from "./ReactionCollectorPacket"; -import {Item} from "../../interfaces/Item"; +import {ItemWithDetails} from "../../interfaces/ItemWithDetails"; export class ReactionCollectorMerchantData extends ReactionCollectorData { - item!: Item; + item!: ItemWithDetails; price!: number; }