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/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..9d047873c --- /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 = (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(", ")}`; +}; + +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} !`; 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/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 new file mode 100644 index 000000000..8c8bcc14e --- /dev/null +++ b/Core/src/commands/player/UnlockCommand.ts @@ -0,0 +1,126 @@ +import {DraftBotPacket, makePacket, PacketContext} from "../../../../Lib/src/packets/DraftBotPacket"; +import {Player, Players} from "../../core/database/game/models/Player"; +import { + CommandUnlockAcceptPacketRes, + CommandUnlockHimself, + CommandUnlockNoPlayerFound, + CommandUnlockNotEnoughMoney, + CommandUnlockNotInJail, + CommandUnlockPacketReq, + 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"; + +/** + * 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 + 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) { + response.push(makePacket(CommandUnlockNoPlayerFound, {})); + return true; + } + if (player.money < UnlockConstants.PRICE_FOR_UNLOCK) { + response.push(makePacket(CommandUnlockNotEnoughMoney, { + money: player.money + })); + 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; +} + +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/CommandsTest.ts b/Core/src/core/CommandsTest.ts index 02f144397..58887b79b 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,27 @@ 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"] +]); + +/** + * Format the type waited for the command + * @param typeWaited + */ +export function formatTypeWaited(typeWaited: TypeKey): string { + return `\`${typeWaited}\`(${typeVariableFormatLike.get(typeWaited)})`; +} + export interface ITestCommand { name: string, aliases?: string[], @@ -88,8 +103,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/database/game/models/Player.ts b/Core/src/core/database/game/models/Player.ts index 7fe8655cb..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 = { @@ -415,8 +416,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; } /** @@ -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/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/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/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/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/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/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/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/ProfileCommand.ts b/Discord/src/commands/player/ProfileCommand.ts index ca7986567..dccd906f6 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 @@ -35,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) { @@ -53,216 +58,166 @@ 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; } - else { - for (const badgeId in badges) { - if (Object.prototype.hasOwnProperty.call(badges, badgeId)) { - await msg.react(badges[badgeId]); - } - } + for (const badgeId of badges) { + await msg.react(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 +/** + * 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, { + 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 + }); - 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, 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?.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, "playerClass", Boolean(packet.playerData.classId), { + lng, + id: packet.playerData.classId + }); - 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, "fightRanking", Boolean(packet.playerData.fightRanking), { + lng, + league: packet.playerData.fightRanking?.league, + gloryPoints: packet.playerData.fightRanking?.glory + }); - 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, "guild", Boolean(packet.playerData.guild), { + lng, + guild: packet.playerData.guild + }); + + 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; } +/** + * 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); - 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/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 new file mode 100644 index 000000000..c330a061a --- /dev/null +++ b/Discord/src/commands/player/UnlockCommand.ts @@ -0,0 +1,150 @@ +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, + CommandUnlockNotEnoughMoney, + CommandUnlockPacketReq, + 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, {askedPlayer}); +} + +/** + * + * @param packet + * @param context + */ +export async function handleCommandUnlockNotEnoughMoneyError(packet: CommandUnlockNotEnoughMoney, context: PacketContext): Promise { + const interaction = DiscordCache.getInteraction(context.discord!.interaction); + if (!interaction) { + return; + } + await sendErrorMessage( + interaction.user, + interaction, + i18n.t("error:notEnoughMoney", { + lng: interaction.userLanguage, + money: UnlockConstants.PRICE_FOR_UNLOCK - packet.money + }), + {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, + pseudo: unlockedPlayer.attributes.gameUsername, + price: UnlockConstants.PRICE_FOR_UNLOCK + }) + ); + + 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!); + 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() + ] + }); +} + +/** + * 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!); + if (!originalInteraction) { + return; + } + const buttonInteraction = DiscordCache.getButtonInteraction(context.discord!.buttonInteraction!); + const unlockedPlayer = (await KeycloakUtils.getUserByKeycloakId(keycloakConfig, packet.unlockedKeycloakId!))!; + 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, + pseudo: 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/Discord/src/messages/DraftbotInteraction.ts b/Discord/src/messages/DraftbotInteraction.ts index 67438bc7b..de9f32e00 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 ?? ((): void => { // 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 ?? ((): void => { // 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}`); } } } diff --git a/Discord/src/packetHandlers/handlers/CommandHandlers.ts b/Discord/src/packetHandlers/handlers/CommandHandlers.ts index 4c9da561a..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"; @@ -15,10 +18,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 +128,6 @@ import { } from "../../../../Lib/src/packets/commands/CommandGuildDailyPacket"; import { handleCommandGuildDailyCooldownErrorPacket, - handleCommandGuildDailyPveIslandErrorPacket, handleCommandGuildDailyRewardPacket } from "../../commands/guild/GuildDailyCommand"; import { @@ -148,11 +147,21 @@ import { CommandDailyBonusObjectIsActiveDuringFights, CommandDailyBonusPacketRes } from "../../../../Lib/src/packets/commands/CommandDailyBonusPacket"; +import {handleDailyBonusCooldownError, handleDailyBonusRes} from "../../commands/player/DailyBonusCommand"; +import { + CommandUnlockAcceptPacketRes, + CommandUnlockHimself, + CommandUnlockNoPlayerFound, + CommandUnlockNotEnoughMoney, + CommandUnlockNotInJail, + CommandUnlockRefusePacketRes +} from "../../../../Lib/src/packets/commands/CommandUnlockPacket"; import { - handleDailyBonusClassicError, - handleDailyBonusCooldownError, - handleDailyBonusRes -} from "../../commands/player/DailyBonusCommand"; + handleCommandUnlockAcceptPacketRes, + handleCommandUnlockNotEnoughMoneyError, + handleCommandUnlockRefusePacketRes +} from "../../commands/player/UnlockCommand"; +import {handleClassicError} from "../../utils/ErrorUtils"; export default class CommandHandlers { @packetHandler(CommandPingPacketRes) @@ -169,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); @@ -336,8 +350,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) @@ -437,7 +451,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) @@ -447,21 +461,51 @@ 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) async dailyBonusInCooldown(packet: CommandDailyBonusInCooldown, context: PacketContext): Promise { await handleDailyBonusCooldownError(context, packet.lastDailyTimestamp, packet.timeBetweenDailies); } + + @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) + 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/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() diff --git a/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts b/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts index 917e41d8d..d13e9f926 100644 --- a/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts +++ b/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts @@ -35,6 +35,8 @@ import {createGuildKickCollector} from "../../commands/guild/GuildKickCommand"; import {ReactionCollectorGobletsGameData} from "../../../../Lib/src/packets/interaction/ReactionCollectorGobletsGame"; import {gobletsGameCollector} from "../../smallEvents/gobletsGame"; import {smallShopCollector} from "../../smallEvents/shop"; +import {createUnlockCollector} from "../../commands/player/UnlockCommand"; +import {ReactionCollectorUnlockData} from "../../../../Lib/src/packets/interaction/ReactionCollectorUnlock"; export default class ReactionCollectorHandler { @@ -59,7 +61,6 @@ 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(ReactionCollectorMerchantData.name, smallShopCollector); } @packetHandler(ReactionCollectorCreationPacket) 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/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/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/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/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/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 de24664fe..55ecfb1e2 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." @@ -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:", @@ -511,15 +514,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:", @@ -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/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/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 098b8a247..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}}💰` 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": "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." @@ -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." @@ -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,15 +514,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:", @@ -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/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/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/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 0edf35044..77c7496c4 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." @@ -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 :", @@ -511,15 +514,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:", @@ -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/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/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 c0982a011..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}}", @@ -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é." @@ -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}}%", @@ -424,16 +427,16 @@ "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 !" ], "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 :", @@ -511,15 +514,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 :", @@ -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": "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}}** pour **{{price}} {emote:unitValues.money}**?", + "canceledTitle": "Libération annulée", + "canceledDesc": "La libération 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/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 d79d8e839..de7e9f33f 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/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 7ff485616..cdff8814c 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à." @@ -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 :", @@ -511,15 +514,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:", @@ -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/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/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 7fd2bb1be..38970de96 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." @@ -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 :", @@ -511,15 +514,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:", @@ -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 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/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/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 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/packets/commands/CommandUnlockPacket.ts b/Lib/src/packets/commands/CommandUnlockPacket.ts new file mode 100644 index 000000000..3626df1d7 --- /dev/null +++ b/Lib/src/packets/commands/CommandUnlockPacket.ts @@ -0,0 +1,40 @@ +import {DraftBotPacket, PacketDirection, sendablePacket} from "../DraftBotPacket"; + +@sendablePacket(PacketDirection.FRONT_TO_BACK) +export class CommandUnlockPacketReq extends DraftBotPacket { + askedPlayer!: { + rank?: number, + keycloakId?: string + }; +} + +@sendablePacket(PacketDirection.NONE) +export class CommandUnlockErrorPacket extends DraftBotPacket { +} + +@sendablePacket(PacketDirection.BACK_TO_FRONT) +export class CommandUnlockNoPlayerFound extends CommandUnlockErrorPacket { +} + +@sendablePacket(PacketDirection.BACK_TO_FRONT) +export class CommandUnlockNotInJail extends CommandUnlockErrorPacket { +} + +@sendablePacket(PacketDirection.BACK_TO_FRONT) +export class CommandUnlockNotEnoughMoney extends CommandUnlockErrorPacket { + money!: number; +} + +@sendablePacket(PacketDirection.BACK_TO_FRONT) +export class CommandUnlockHimself extends CommandUnlockErrorPacket { +} + +@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 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 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} */ 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);