Skip to content

Commit

Permalink
Petfree command work #2273
Browse files Browse the repository at this point in the history
  • Loading branch information
BastLast committed Jul 6, 2024
1 parent c4f61ca commit 8278aac
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 84 deletions.
136 changes: 74 additions & 62 deletions Core/src/commands/pet/PetFreeCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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<void> {
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<void> {
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<void> {
const player = await Players.getByKeycloakId(packet.keycloakId);

console.log(packet.keycloakId);
if (BlockingUtils.appendBlockedPacket(player, response)) {
return;
}
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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, {}));
Expand Down
46 changes: 29 additions & 17 deletions Discord/src/commands/pet/PetFreeCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -23,15 +26,14 @@ function getPacket(interaction: DraftbotInteraction, keycloakUser: KeycloakUser)

export async function handleCommandPetFreePacketRes(packet: CommandPetFreePacketRes, context: PacketContext): Promise<void> {
const interaction = DiscordCache.getInteraction(context.discord!.interaction);

if (interaction) {
if (!packet.foundPet) {
await interaction.reply({
embeds: [
new DraftBotErrorEmbed(
interaction.user,
interaction,
i18n.t("error:PetDoesntExist", {lng: interaction.userLanguage})
i18n.t("error:petDoesntExist", {lng: interaction.userLanguage})
)
]
});
Expand All @@ -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<void> {
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,
Expand Down
7 changes: 7 additions & 0 deletions Discord/src/packetHandlers/handlers/CommandHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -52,6 +54,11 @@ export default class CommandHandlers {
await handleCommandPetPacketRes(packet, context);
}

@packetHandler(CommandPetPacketRes)
async petFreeRes(socket: WebSocket, packet: CommandPetFreePacketRes, context: PacketContext): Promise<void> {
await handleCommandPetFreePacketRes(packet, context);
}

@packetHandler(CommandGuildPacketRes)
async guildRes(socket: WebSocket, packet: CommandGuildPacketRes, context: PacketContext): Promise<void> {
await handleCommandGuildPacketRes(packet, context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions Lang/en/discordBuilder.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@
}
}
},
"petFree": {
"description": "Free a pet.",
"name": "petfree"
},
"guild": {
"description": "Displays information about a guild.",
"name": "guild",
Expand Down
11 changes: 7 additions & 4 deletions Lang/fr/commands.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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"
}
}
4 changes: 4 additions & 0 deletions Lang/fr/discordBuilder.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@
}
}
},
"petFree": {
"description": "Libérer son familier.",
"name": "libererfamilier",
},

Check failure on line 63 in Lang/fr/discordBuilder.json

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

Lang/fr/discordBuilder.json#L63

Unexpected character ('}' (code 125)): was expecting double-quote to start field name
"guild": {
"description": "Affiche des informations sur une guilde.",
"name": "guilde",
Expand Down
4 changes: 3 additions & 1 deletion Lang/fr/error.json
Original file line number Diff line number Diff line change
Expand Up @@ -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}}."
}

0 comments on commit 8278aac

Please sign in to comment.