diff --git a/Core/src/commands/player/MapCommand.ts b/Core/src/commands/player/MapCommand.ts new file mode 100644 index 000000000..d6459ce54 --- /dev/null +++ b/Core/src/commands/player/MapCommand.ts @@ -0,0 +1,84 @@ +import {packetHandler} from "../../core/packetHandlers/PacketHandler"; +import {CommandMapDisplayRes, CommandMapPacketReq} from "../../../../Lib/src/packets/commands/CommandMapPacket"; +import {DraftBotPacket, makePacket, PacketContext} from "../../../../Lib/src/packets/DraftBotPacket"; +import {WebsocketClient} from "../../../../Lib/src/instances/WebsocketClient"; +import {Player, Players} from "../../core/database/game/models/Player"; +import {MapLocation} from "../../data/MapLocation"; +import {Language} from "../../../../Lib/src/Language"; +import {MapLinkDataController} from "../../data/MapLink"; + +/** + * Get the map information for the player + * @param player + * @param destination + * @param isInEvent + * @param language + */ +function getMapInformation(player: Player, destination: MapLocation, isInEvent: boolean, language: Language): { + name: string, + fallback?: string, + forced: boolean +} { + const mapLink = MapLinkDataController.instance.getById(destination.id); + + if (!isInEvent && mapLink.forcedImage) { + return { + name: mapLink.forcedImage, + forced: true + }; + } + + const departure = player.getPreviousMap(); + + if (isInEvent) { + return { + name: mapLink.forcedImage ?? `${language}_${destination.id}_`, + fallback: mapLink.forcedImage ? null : `en_${destination.id}_`, + forced: Boolean(destination.forcedImage) + }; + } + + if (destination.id < departure.id) { + return { + name: `${language}_${destination.id}_${departure.id}_`, + fallback: `en_${destination.id}_${departure.id}_`, + forced: false + }; + } + + return { + name: `${language}_${departure.id}_${destination.id}_`, + fallback: `en_${departure.id}_${destination.id}_`, + forced: false + }; +} + +export class MapCommand { + @packetHandler(CommandMapPacketReq) + async execute(client: WebsocketClient, packet: CommandMapPacketReq, context: PacketContext, response: DraftBotPacket[]): Promise { + const player = await Players.getByKeycloakId(packet.keycloakId); + + if (!player) { + response.push(makePacket(CommandMapDisplayRes, { + foundPlayer: false + })); + } + else { + const isInEvent = player.isInEvent(); + const destinationMap = player.getDestination(); + + const mapInformation = getMapInformation(player, destinationMap, isInEvent, packet.language); + + response.push(makePacket(CommandMapDisplayRes, { + foundPlayer: true, + keycloakId: player.keycloakId, + data: { + mapId: destinationMap.id, + mapLink: mapInformation, + mapType: destinationMap.type, + inEvent: isInEvent + } + })); + } + } +} \ No newline at end of file diff --git a/Discord/src/commands/player/MapCommand.ts b/Discord/src/commands/player/MapCommand.ts new file mode 100644 index 000000000..d4dac0f89 --- /dev/null +++ b/Discord/src/commands/player/MapCommand.ts @@ -0,0 +1,113 @@ +import {DraftbotInteraction} from "../../messages/DraftbotInteraction"; +import {KeycloakUser} from "../../../../Lib/src/keycloak/KeycloakUser"; +import {CommandMapDisplayRes, CommandMapPacketReq} from "../../../../Lib/src/packets/commands/CommandMapPacket"; +import {makePacket, PacketContext} from "../../../../Lib/src/packets/DraftBotPacket"; +import {ICommand} from "../ICommand"; +import {SlashCommandBuilderGenerator} from "../SlashCommandBuilderGenerator"; +import {Effect} from "../../../../Lib/src/enums/Effect"; +import {DiscordCache} from "../../bot/DiscordCache"; +import {DraftBotEmbed} from "../../messages/DraftBotEmbed"; +import i18n from "../../translations/i18n"; +import {MapConstants} from "../../../../Lib/src/constants/MapConstants"; +import {DraftBotIcons} from "../../../../Lib/src/DraftBotIcons"; + +function getPacket(interaction: DraftbotInteraction, user: KeycloakUser): Promise { + return Promise.resolve(makePacket(CommandMapPacketReq, {keycloakId: user.id, language: interaction.userLanguage})); +} + +/** + * Sets the map image in the embed + * @param embed + * @param mapLink + */ +async function setEmbedMap(embed: DraftBotEmbed, mapLink: {name: string, fallback?: string, forced: boolean}): Promise { + if (mapLink.forced && !mapLink.fallback) { + embed.setImage(MapConstants.FORCED_MAPS_URL.replace("{name}", mapLink.name)); + } + else { + await fetch(mapLink.forced + ? MapConstants.FORCED_MAPS_URL.replace("{name}", mapLink.name) + : MapConstants.MAP_URL_WITH_CURSOR.replace("{mapLink}", mapLink.name)) + .then((res) => { + if (res.status !== 200 && mapLink.fallback) { + embed.setImage(mapLink.forced + ? MapConstants.FORCED_MAPS_URL.replace("{name}", mapLink.fallback) + : MapConstants.MAP_URL_WITH_CURSOR.replace("{mapLink}", mapLink.fallback)); + } + else { + embed.setImage(mapLink.forced + ? MapConstants.FORCED_MAPS_URL.replace("{name}", mapLink.name) + : MapConstants.MAP_URL_WITH_CURSOR.replace("{mapLink}", mapLink.name)); + } + }) + .catch(() => { + if (mapLink.fallback) { + embed.setImage(mapLink.forced + ? MapConstants.FORCED_MAPS_URL.replace("{name}", mapLink.fallback) + : MapConstants.MAP_URL_WITH_CURSOR.replace("{mapLink}", mapLink.fallback)); + } + }); + } +} + +/** + * Handles the response of the map command + * @param packet + * @param context + */ +export async function handleCommandMapDisplayRes(packet: CommandMapDisplayRes, context: PacketContext): Promise { + const interaction = DiscordCache.getInteraction(context.discord!.interaction); + + if (interaction) { + if (!packet.foundPlayer) { + await interaction.reply({ + content: "commands:map.playerNotFound", + ephemeral: true + }); + return; + } + + const embed = new DraftBotEmbed().formatAuthor(i18n.t("commands:map.title", { + lng: interaction.userLanguage, + pseudo: interaction.user.displayName + }), interaction.user); + + await setEmbedMap(embed, packet.data!.mapLink); + + const mapName = i18n.t(`models:map_locations.${packet.data?.mapId}.name`, { + lng: interaction.userLanguage, + interpolation: { escapeValue: false } + }); + + const mapParticle = i18n.t(`models:map_locations.${packet.data?.mapId}.particle`, { + lng: interaction.userLanguage + }); + + const mapDescription = i18n.t(`models:map_locations.${packet.data?.mapId}.description`, { + lng: interaction.userLanguage, + interpolation: { escapeValue: false } + }); + + embed.setDescription(i18n.t(packet.data!.inEvent + ? "commands:map.description.arrived" + : "commands:map.description.ongoing", { + lng: interaction.userLanguage, + destination: mapName, + particle: mapParticle, + emote: DraftBotIcons.map_types[packet.data!.mapType], + description: mapDescription, + interpolation: { escapeValue: false } + })); + + await interaction.reply({embeds: [embed]}); + } +} + +export const commandInfo: ICommand = { + slashCommandBuilder: SlashCommandBuilderGenerator.generateBaseCommand("map"), + getPacket, + requirements: { + disallowEffects: [Effect.DEAD, Effect.NOT_STARTED] + }, + mainGuildCommand: false +}; \ No newline at end of file diff --git a/Discord/src/packetHandlers/handlers/CommandHandlers.ts b/Discord/src/packetHandlers/handlers/CommandHandlers.ts index 09eb955fd..14528b0d3 100644 --- a/Discord/src/packetHandlers/handlers/CommandHandlers.ts +++ b/Discord/src/packetHandlers/handlers/CommandHandlers.ts @@ -19,6 +19,8 @@ import {handleCommandGuildPacketRes} from "../../commands/guild/GuildCommand"; import {CommandGuildPacketRes} from "../../../../Lib/src/packets/commands/CommandGuildPacket"; import {reportResult} from "../../commands/player/ReportCommand"; import {CommandReportBigEventResultRes} from "../../../../Lib/src/packets/commands/CommandReportPacket"; +import {CommandMapDisplayRes} from "../../../../Lib/src/packets/commands/CommandMapPacket"; +import {handleCommandMapDisplayRes} from "../../commands/player/MapCommand"; import { CommandPetPacketRes } from "../../../../Lib/src/packets/commands/CommandPetPacket"; import {handleCommandPetPacketRes} from "../../commands/pet/PetCommand"; @@ -76,4 +78,9 @@ export default class CommandHandlers { async reportResultRes(socket: WebSocket, packet: CommandReportBigEventResultRes, context: PacketContext): Promise { await reportResult(packet, context); } + + @packetHandler(CommandMapDisplayRes) + async mapRes(socket: WebSocket, packet: CommandMapDisplayRes, context: PacketContext): Promise { + await handleCommandMapDisplayRes(packet, context); + } } \ No newline at end of file diff --git a/Lang/fr/commands.json b/Lang/fr/commands.json index ba554daba..52546eadb 100644 --- a/Lang/fr/commands.json +++ b/Lang/fr/commands.json @@ -426,5 +426,12 @@ "vote": { "description": "Voici le lien permettant de soutenir le bot :\nhttps://top.gg/bot/448110812801007618", "title": ":ballot_box: Voter" + }, + "map": { + "title": "{{pseudo}}, voici la carte !", + "description": { + "ongoing": "Actuellement, vous vous dirigez {{particle}} **{{emote}} {{destination}}**.\n> {{description}}", + "arrived": "Vous êtes arrivé à votre destination.\n> **{{emote}} {{destination}}**.\n> {{description}}" + } } } \ No newline at end of file diff --git a/Lang/fr/discordBuilder.json b/Lang/fr/discordBuilder.json index 56779ca46..5c6851548 100644 --- a/Lang/fr/discordBuilder.json +++ b/Lang/fr/discordBuilder.json @@ -118,5 +118,9 @@ "vote": { "description": "Afficher le lien permettant de voter pour le bot.", "name": "vote" + }, + "map": { + "description": "Affiche la carte pour indiquer où vous allez.", + "name": "carte" } } \ No newline at end of file diff --git a/Lib/src/packets/commands/CommandMapPacket.ts b/Lib/src/packets/commands/CommandMapPacket.ts new file mode 100644 index 000000000..2dbc10dc8 --- /dev/null +++ b/Lib/src/packets/commands/CommandMapPacket.ts @@ -0,0 +1,35 @@ +import {DraftBotPacket} from "../DraftBotPacket"; +import {Language} from "../../Language"; + +/** + * Packet sent by the bot to get the map of a player + */ +export class CommandMapPacketReq extends DraftBotPacket { + keycloakId!: string; + + language!: Language; +} + + +/** + * Packet sent by the bot to display the map of a player + */ +export class CommandMapDisplayRes extends DraftBotPacket { + foundPlayer!: boolean; + + keycloakId?: string; + + data?: { + mapId: number; + + mapType: string; + + mapLink: { + name: string; + fallback?: string; + forced: boolean; + }; + + inEvent: boolean; + }; +} \ No newline at end of file