diff --git a/Core/src/commands/pet/PetFreeCommand.ts b/Core/src/commands/pet/PetFreeCommand.ts index fdfcd8f258..8af02bfb91 100644 --- a/Core/src/commands/pet/PetFreeCommand.ts +++ b/Core/src/commands/pet/PetFreeCommand.ts @@ -6,7 +6,8 @@ import {PetEntities, PetEntity} from "../../core/database/game/models/PetEntity" import { CommandPetFreeAcceptPacketRes, CommandPetFreePacketReq, - CommandPetFreePacketRes, CommandPetFreeRefusePacketRes + CommandPetFreePacketRes, + CommandPetFreeRefusePacketRes } from "../../../../Lib/src/packets/commands/CommandPetFreePacket"; import {BlockingUtils} from "../../core/utils/BlockingUtils"; import {PetFreeConstants} from "../../../../Lib/src/constants/PetFreeConstants"; @@ -22,76 +23,87 @@ import {getFoodIndexOf} from "../../core/utils/FoodUtils"; import {RandomUtils} from "../../core/utils/RandomUtils"; import {Constants} from "../../../../Lib/src/constants/Constants"; -export default class PetFreeCommand { - - /** - * Send the number of milliseconds that remain before the player is allowed to free his pet - * (a player cannot free pets too often) - * @param player - */ - getCooldownRemainingTimeMs(player: Player): number { - return PetFreeConstants.FREE_COOLDOWN - (new Date().valueOf() - player.lastPetFree.valueOf()); - } - - /** - * Returns the amount of money the player is missing to free his pet (0 if the player has enough money) - * @param player - * @param playerPet - */ - getMissingMoneyToFreePet(player: Player, playerPet: PetEntity): number { - return playerPet.isFeisty() ? PetFreeConstants.FREE_FEISTY_COST - player.money : 0; - } - luckyMeat(guild: Guild, pPet: PetEntity): boolean { - return guild.carnivorousFood + 1 <= GuildConstants.MAX_PET_FOOD[getFoodIndexOf(Constants.PET_FOOD.CARNIVOROUS_FOOD)] - && RandomUtils.draftbotRandom.realZeroToOneInclusive() <= PetFreeConstants.GIVE_MEAT_PROBABILITY - && !pPet.isFeisty(); +/** + * Send the number of milliseconds that remain before the player is allowed to free his pet + * (a player cannot free pets too often) + * @param player + */ +function getCooldownRemainingTimeMs(player: Player): number { + return PetFreeConstants.FREE_COOLDOWN - (new Date().valueOf() - player.lastPetFree.valueOf()); +} + +/** + * Returns the amount of money the player is missing to free his pet (0 if the player has enough money) + * @param player + * @param playerPet + */ +function getMissingMoneyToFreePet(player: Player, playerPet: PetEntity): number { + return playerPet.isFeisty() ? PetFreeConstants.FREE_FEISTY_COST - player.money : 0; +} + +/** + * Return true if the player is "lucky" and wins a meat piece for freeing his pet + * @param guild + * @param pPet + */ +function generateLuckyMeat(guild: Guild, pPet: PetEntity): boolean { + return guild.carnivorousFood + 1 <= GuildConstants.MAX_PET_FOOD[getFoodIndexOf(Constants.PET_FOOD.CARNIVOROUS_FOOD)] + && RandomUtils.draftbotRandom.realZeroToOneInclusive() <= PetFreeConstants.GIVE_MEAT_PROBABILITY + && !pPet.isFeisty(); +} + +/** + * Accept the petfree request and free the pet + * @param player + * @param playerPet + * @param response + */ +async function acceptPetFree(player: Player, playerPet: PetEntity, response: DraftBotPacket[]): Promise { + if (playerPet.isFeisty()) { + await player.addMoney({ + amount: -PetFreeConstants.FREE_FEISTY_COST, + response, + reason: NumberChangeReason.PET_FREE + }); } - async acceptPetFree(player: Player, playerPet: PetEntity, response: DraftBotPacket[]): Promise { - if (playerPet.isFeisty()) { - await player.addMoney({ - amount: -PetFreeConstants.FREE_FEISTY_COST, - response, - reason: NumberChangeReason.PET_FREE - }); - } - - LogsDatabase.logPetFree(playerPet).then(); - - await playerPet.destroy(); - player.petId = null; - player.lastPetFree = new Date(); - await player.save(); + LogsDatabase.logPetFree(playerPet).then(); - let guild: Guild; - try { - guild = await Guilds.getById(player.guildId); - } - catch (error) { - guild = null; - } + await playerPet.destroy(); + player.petId = null; + player.lastPetFree = new Date(); + await player.save(); - const luckyMeat = this.luckyMeat(guild, playerPet); - if (guild !== null && luckyMeat) { - guild.carnivorousFood += PetFreeConstants.MEAT_GIVEN; - await guild.save(); - } + let guild: Guild; + try { + guild = await Guilds.getById(player.guildId); + } + catch (error) { + guild = null; + } - response.push(makePacket(CommandPetFreeAcceptPacketRes, { - petId: playerPet.typeId, - petSex: playerPet.sex, - petNickname: playerPet.nickname, - freeCost: playerPet.isFeisty() ? PetFreeConstants.FREE_FEISTY_COST : 0, - luckyMeat - })); + const luckyMeat = generateLuckyMeat(guild, playerPet); + if (guild !== null && luckyMeat) { + guild.carnivorousFood += PetFreeConstants.MEAT_GIVEN; + await guild.save(); } + response.push(makePacket(CommandPetFreeAcceptPacketRes, { + petId: playerPet.typeId, + petSex: playerPet.sex, + petNickname: playerPet.nickname, + freeCost: playerPet.isFeisty() ? PetFreeConstants.FREE_FEISTY_COST : 0, + luckyMeat + })); +} + +export default class PetFreeCommand { @packetHandler(CommandPetFreePacketReq) async execute(client: WebsocketClient, packet: CommandPetFreePacketReq, context: PacketContext, response: DraftBotPacket[]): Promise { const player = await Players.getByKeycloakId(packet.keycloakId); - + console.log(packet.keycloakId); if (BlockingUtils.appendBlockedPacket(player, response)) { return; } @@ -105,7 +117,7 @@ export default class PetFreeCommand { } // Check cooldown - const cooldownRemainingTimeMs = this.getCooldownRemainingTimeMs(player); + const cooldownRemainingTimeMs = getCooldownRemainingTimeMs(player); if (cooldownRemainingTimeMs > 0) { response.push(makePacket(CommandPetFreePacketRes, { foundPet: true, @@ -116,7 +128,7 @@ export default class PetFreeCommand { } // Check money - const missingMoney = this.getMissingMoneyToFreePet(player, playerPet); + const missingMoney = getMissingMoneyToFreePet(player, playerPet); if (missingMoney > 0) { response.push(makePacket(CommandPetFreePacketRes, { foundPet: true, @@ -138,7 +150,7 @@ export default class PetFreeCommand { const reaction = collector.getFirstReaction(); if (reaction && reaction.reaction.type === ReactionCollectorAcceptReaction.name) { - await this.acceptPetFree(player, playerPet, response); + await acceptPetFree(player, playerPet, response); } else { response.push(makePacket(CommandPetFreeRefusePacketRes, {})); diff --git a/Discord/src/commands/pet/PetFreeCommand.ts b/Discord/src/commands/pet/PetFreeCommand.ts index 4437bb8a3b..28fe61ac77 100644 --- a/Discord/src/commands/pet/PetFreeCommand.ts +++ b/Discord/src/commands/pet/PetFreeCommand.ts @@ -11,7 +11,10 @@ import {DiscordCache} from "../../bot/DiscordCache"; import {DraftBotErrorEmbed} from "../../messages/DraftBotErrorEmbed"; import {KeycloakUser} from "../../../../Lib/src/keycloak/KeycloakUser"; import {Effect} from "../../../../Lib/src/enums/Effect"; -import {millisecondsToMinutes} from "../../../../Lib/src/utils/TimeUtils"; +import {printTimeBeforeDate} from "../../../../Lib/src/utils/TimeUtils"; +import {ReactionCollectorCreationPacket} from "../../../../Lib/src/packets/interaction/ReactionCollectorPacket"; +import {DiscordCollectorUtils} from "../../utils/DiscordCollectorUtils"; +import {DraftBotEmbed} from "../../messages/DraftBotEmbed"; /** * Destroy a pet forever... RIP @@ -23,7 +26,6 @@ function getPacket(interaction: DraftbotInteraction, keycloakUser: KeycloakUser) export async function handleCommandPetFreePacketRes(packet: CommandPetFreePacketRes, context: PacketContext): Promise { const interaction = DiscordCache.getInteraction(context.discord!.interaction); - if (interaction) { if (!packet.foundPet) { await interaction.reply({ @@ -31,7 +33,7 @@ export async function handleCommandPetFreePacketRes(packet: CommandPetFreePacket new DraftBotErrorEmbed( interaction.user, interaction, - i18n.t("error:PetDoesntExist", {lng: interaction.userLanguage}) + i18n.t("error:petDoesntExist", {lng: interaction.userLanguage}) ) ] }); @@ -49,24 +51,34 @@ export async function handleCommandPetFreePacketRes(packet: CommandPetFreePacket ] }); } - else { - await interaction.reply({ - embeds: [ - new DraftBotErrorEmbed( - interaction.user, - interaction, - i18n.t("error:cooldownPetFree", { - lng: interaction.userLanguage, - remainingTime: millisecondsToMinutes(packet.cooldownRemainingTimeMs!) - }) - ) - ] - }); - } + await interaction.reply({ + embeds: [ + new DraftBotErrorEmbed( + interaction.user, + interaction, + i18n.t("error:cooldownPetFree", { + lng: interaction.userLanguage, + remainingTime: printTimeBeforeDate(packet.cooldownRemainingTimeMs! + new Date().valueOf()) + }) + ) + ] + }); } } } +export async function createPetFreeCollector(packet: ReactionCollectorCreationPacket, context: PacketContext): Promise { + const interaction = DiscordCache.getInteraction(context.discord!.interaction)!; + // Const data = packet.data.data as ReactionCollectorPetFreeData; + + const embed = new DraftBotEmbed().formatAuthor(i18n.t("commands:petFree.title", { + lng: interaction.userLanguage, + pseudo: interaction.user.displayName + }), interaction.user); + + await DiscordCollectorUtils.createAcceptRefuseCollector(interaction, embed, packet, context); +} + export const commandInfo: ICommand = { slashCommandBuilder: SlashCommandBuilderGenerator.generateBaseCommand("petFree"), getPacket, diff --git a/Discord/src/packetHandlers/handlers/CommandHandlers.ts b/Discord/src/packetHandlers/handlers/CommandHandlers.ts index dfa2662dac..f2964ce75a 100644 --- a/Discord/src/packetHandlers/handlers/CommandHandlers.ts +++ b/Discord/src/packetHandlers/handlers/CommandHandlers.ts @@ -26,6 +26,8 @@ import {CommandMapDisplayRes} from "../../../../Lib/src/packets/commands/Command import {handleCommandMapDisplayRes} from "../../commands/player/MapCommand"; import { CommandPetPacketRes } from "../../../../Lib/src/packets/commands/CommandPetPacket"; import {handleCommandPetPacketRes} from "../../commands/pet/PetCommand"; +import {handleCommandPetFreePacketRes} from "../../commands/pet/PetFreeCommand"; +import {CommandPetFreePacketRes} from "../../../../Lib/src/packets/commands/CommandPetFreePacket"; export default class CommandHandlers { @packetHandler(CommandPingPacketRes) @@ -52,6 +54,11 @@ export default class CommandHandlers { await handleCommandPetPacketRes(packet, context); } + @packetHandler(CommandPetPacketRes) + async petFreeRes(socket: WebSocket, packet: CommandPetFreePacketRes, context: PacketContext): Promise { + await handleCommandPetFreePacketRes(packet, context); + } + @packetHandler(CommandGuildPacketRes) async guildRes(socket: WebSocket, packet: CommandGuildPacketRes, context: PacketContext): Promise { await handleCommandGuildPacketRes(packet, context); diff --git a/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts b/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts index 77582f6c2c..d9467b899f 100644 --- a/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts +++ b/Discord/src/packetHandlers/handlers/ReactionCollectorHandlers.ts @@ -9,6 +9,8 @@ import {ReactionCollectorGoToPVEIslandData} from "../../../../Lib/src/packets/in import {goToPVEIslandCollector} from "../../smallEvents/goToPVEIsland"; import {ReactionCollectorLotteryData} from "../../../../Lib/src/packets/interaction/ReactionCollectorLottery"; import {lotteryCollector} from "../../smallEvents/lottery"; +import {ReactionCollectorPetFree} from "../../../../Lib/src/packets/interaction/ReactionCollectorPetFree"; +import {createPetFreeCollector} from "../../commands/pet/PetFreeCommand"; export default class ReactionCollectorHandler { @packetHandler(ReactionCollectorCreationPacket) @@ -23,6 +25,9 @@ export default class ReactionCollectorHandler { case ReactionCollectorGoToPVEIslandData.name: await goToPVEIslandCollector(packet, context); break; + case ReactionCollectorPetFree.name: + await createPetFreeCollector(packet, context); + break; case ReactionCollectorLotteryData.name: await lotteryCollector(packet, context); break; diff --git a/Lang/en/discordBuilder.json b/Lang/en/discordBuilder.json index 8757f662fa..8be15e97fb 100644 --- a/Lang/en/discordBuilder.json +++ b/Lang/en/discordBuilder.json @@ -57,6 +57,10 @@ } } }, + "petFree": { + "description": "Free a pet.", + "name": "petfree" + }, "guild": { "description": "Displays information about a guild.", "name": "guild", diff --git a/Lang/fr/commands.json b/Lang/fr/commands.json index 52546eadb1..0b60b7bbbf 100644 --- a/Lang/fr/commands.json +++ b/Lang/fr/commands.json @@ -19,11 +19,11 @@ "4_male": ":heart_eyes_cat: Dressé", "4_female": ":heart_eyes_cat: Dressée" }, - "hungry": "\uD83E\uDD24 affamé", + "hungry": "🤤 affamé", "diet": { - "diet_null": "\uD83E\uDD6A Omnivore", - "diet_herbivorous": "\uD83E\uDD6C Herbivore", - "diet_carnivorous": "\uD83E\uDD69 Carnivore" + "diet_null": "🥪 Omnivore", + "diet_herbivorous": "🥬 Herbivore", + "diet_carnivorous": "🥩 Carnivore" }, "sexDisplay": { "female": "Femelle", @@ -433,5 +433,8 @@ "ongoing": "Actuellement, vous vous dirigez {{particle}} **{{emote}} {{destination}}**.\n> {{description}}", "arrived": "Vous êtes arrivé à votre destination.\n> **{{emote}} {{destination}}**.\n> {{description}}" } + }, + "petFree": { + "title": "{{pseudo}}, libération d'un familier" } } \ No newline at end of file diff --git a/Lang/fr/discordBuilder.json b/Lang/fr/discordBuilder.json index 5c68515480..51a3031ab0 100644 --- a/Lang/fr/discordBuilder.json +++ b/Lang/fr/discordBuilder.json @@ -57,6 +57,10 @@ } } }, + "petFree": { + "description": "Libérer son familier.", + "name": "libererfamilier", + }, "guild": { "description": "Affiche des informations sur une guilde.", "name": "guilde", diff --git a/Lang/fr/error.json b/Lang/fr/error.json index 575e27a90d..f4711474c6 100644 --- a/Lang/fr/error.json +++ b/Lang/fr/error.json @@ -52,5 +52,7 @@ "petDoesntExist": "Aucun familier n'a été trouvé.", "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 /shop pour acheter un soin.", - "pleaseWaitForHisHeal": "Veuillez attendre la fin des soins de son altération d'état : {{time}}" + "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}} 💰.", + "cooldownPetFree": "Vous ne pouvez libérer qu'un familier par heure. Vous pourrez en libérer un autre {{time}}." } \ No newline at end of file