Create use effect command #419
40 changed files with 1158 additions and 1133 deletions
|
@ -34,8 +34,6 @@ DB_LOGGING=
|
|||
DB_DATA_LOCATION=./.temp/database
|
||||
DB_ROOT_HOST=0.0.0.0
|
||||
|
||||
DB_CARD_FILE=:memory:
|
||||
|
||||
EXPRESS_PORT=3302
|
||||
|
||||
GDRIVESYNC_AUTO=true
|
||||
GDRIVESYNC_AUTO=false
|
||||
|
|
|
@ -4,9 +4,10 @@ import Inventory from "../database/entities/app/Inventory";
|
|||
import { CoreClient } from "../client/client";
|
||||
import { default as eClaim } from "../database/entities/app/Claim";
|
||||
import AppLogger from "../client/appLogger";
|
||||
import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata";
|
||||
import User from "../database/entities/app/User";
|
||||
import CardConstants from "../constants/CardConstants";
|
||||
import GetCardsHelper from "../helpers/DropHelpers/GetCardsHelper";
|
||||
import DropEmbedHelper from "../helpers/DropHelpers/DropEmbedHelper";
|
||||
|
||||
export default class Claim extends ButtonEvent {
|
||||
public override async execute(interaction: ButtonInteraction) {
|
||||
|
@ -69,16 +70,18 @@ export default class Claim extends ButtonEvent {
|
|||
|
||||
await claim.Save(eClaim, claim);
|
||||
|
||||
const card = CardDropHelperMetadata.GetCardByCardNumber(cardNumber);
|
||||
const card = GetCardsHelper.GetCardByCardNumber(cardNumber);
|
||||
|
||||
if (!card) {
|
||||
AppLogger.LogError("Button/Claim", `Unable to find card, ${cardNumber}`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const imageFileName = card.card.path.split("/").pop()!;
|
||||
|
||||
const embed = CardDropHelperMetadata.GenerateDropEmbed(card, inventory.Quantity, imageFileName, interaction.user.username, user.Currency);
|
||||
const row = CardDropHelperMetadata.GenerateDropButtons(card, claimId, interaction.user.id, true);
|
||||
const embed = DropEmbedHelper.GenerateDropEmbed(card, inventory.Quantity, imageFileName, interaction.user.username, user.Currency);
|
||||
const row = DropEmbedHelper.GenerateDropButtons(card, claimId, interaction.user.id, true);
|
||||
|
||||
await interaction.editReply({
|
||||
embeds: [ embed ],
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import {ButtonInteraction} from "discord.js";
|
||||
import {ButtonEvent} from "../type/buttonEvent";
|
||||
import EffectHelper from "../helpers/EffectHelper";
|
||||
import { ButtonInteraction } from "discord.js";
|
||||
import { ButtonEvent } from "../type/buttonEvent";
|
||||
import List from "./Effects/List";
|
||||
import Use from "./Effects/Use";
|
||||
import AppLogger from "../client/appLogger";
|
||||
|
||||
export default class Effects extends ButtonEvent {
|
||||
public override async execute(interaction: ButtonInteraction) {
|
||||
|
@ -8,26 +10,13 @@ export default class Effects extends ButtonEvent {
|
|||
|
||||
switch (action) {
|
||||
case "list":
|
||||
await this.List(interaction);
|
||||
await List(interaction);
|
||||
break;
|
||||
case "use":
|
||||
await Use.Execute(interaction);
|
||||
break;
|
||||
default:
|
||||
AppLogger.LogError("Buttons/Effects", `Unknown action, ${action}`);
|
||||
}
|
||||
}
|
||||
|
||||
private async List(interaction: ButtonInteraction) {
|
||||
const pageOption = interaction.customId.split(" ")[2];
|
||||
|
||||
const page = Number(pageOption);
|
||||
|
||||
if (!page) {
|
||||
await interaction.reply("Page option is not a valid number");
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await EffectHelper.GenerateEffectEmbed(interaction.user.id, page);
|
||||
|
||||
await interaction.update({
|
||||
embeds: [ result.embed ],
|
||||
components: [ result.row ],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
20
src/buttonEvents/Effects/List.ts
Normal file
20
src/buttonEvents/Effects/List.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { ButtonInteraction } from "discord.js";
|
||||
import EffectHelper from "../../helpers/EffectHelper";
|
||||
|
||||
export default async function List(interaction: ButtonInteraction) {
|
||||
const pageOption = interaction.customId.split(" ")[2];
|
||||
|
||||
const page = Number(pageOption);
|
||||
|
||||
if (!page) {
|
||||
await interaction.reply("Page option is not a valid number");
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await EffectHelper.GenerateEffectEmbed(interaction.user.id, page);
|
||||
|
||||
await interaction.update({
|
||||
embeds: [ result.embed ],
|
||||
components: [ result.row ],
|
||||
});
|
||||
}
|
132
src/buttonEvents/Effects/Use.ts
Normal file
132
src/buttonEvents/Effects/Use.ts
Normal file
|
@ -0,0 +1,132 @@
|
|||
import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, EmbedBuilder } from "discord.js";
|
||||
import { EffectDetails } from "../../constants/EffectDetails";
|
||||
import EffectHelper from "../../helpers/EffectHelper";
|
||||
import EmbedColours from "../../constants/EmbedColours";
|
||||
import TimeLengthInput from "../../helpers/TimeLengthInput";
|
||||
import AppLogger from "../../client/appLogger";
|
||||
|
||||
export default class Use {
|
||||
public static async Execute(interaction: ButtonInteraction) {
|
||||
const subaction = interaction.customId.split(" ")[2];
|
||||
|
||||
switch (subaction) {
|
||||
case "confirm":
|
||||
await this.UseConfirm(interaction);
|
||||
break;
|
||||
case "cancel":
|
||||
await this.UseCancel(interaction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static async UseConfirm(interaction: ButtonInteraction) {
|
||||
const id = interaction.customId.split(" ")[3];
|
||||
|
||||
const effectDetail = EffectDetails.get(id);
|
||||
|
||||
if (!effectDetail) {
|
||||
AppLogger.LogError("Button/Effects/Use", `Effect not found, ${id}`);
|
||||
|
||||
await interaction.reply("Effect not found in system!");
|
||||
return;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
|
||||
const whenExpires = new Date(now.getTime() + effectDetail.duration);
|
||||
|
||||
const result = await EffectHelper.UseEffect(interaction.user.id, id, whenExpires);
|
||||
|
||||
if (!result) {
|
||||
await interaction.reply("Unable to use effect! Please make sure you have it in your inventory and is not on cooldown");
|
||||
return;
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle("Effect Used")
|
||||
.setDescription("You now have an active effect!")
|
||||
.setColor(EmbedColours.Green)
|
||||
.addFields([
|
||||
{
|
||||
name: "Effect",
|
||||
value: effectDetail.friendlyName,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: "Expires",
|
||||
value: `<t:${Math.round(whenExpires.getTime() / 1000)}:f>`,
|
||||
inline: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const row = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents([
|
||||
new ButtonBuilder()
|
||||
.setLabel("Confirm")
|
||||
.setCustomId(`effects use confirm ${effectDetail.id}`)
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setDisabled(true),
|
||||
new ButtonBuilder()
|
||||
.setLabel("Cancel")
|
||||
.setCustomId(`effects use cancel ${effectDetail.id}`)
|
||||
.setStyle(ButtonStyle.Danger)
|
||||
.setDisabled(true),
|
||||
]);
|
||||
|
||||
await interaction.update({
|
||||
embeds: [ embed ],
|
||||
components: [ row ],
|
||||
});
|
||||
}
|
||||
|
||||
private static async UseCancel(interaction: ButtonInteraction) {
|
||||
const id = interaction.customId.split(" ")[3];
|
||||
|
||||
const effectDetail = EffectDetails.get(id);
|
||||
|
||||
if (!effectDetail) {
|
||||
AppLogger.LogError("Button/Effects/Cancel", `Effect not found, ${id}`);
|
||||
|
||||
await interaction.reply("Effect not found in system!");
|
||||
return;
|
||||
}
|
||||
|
||||
const timeLengthInput = TimeLengthInput.ConvertFromMilliseconds(effectDetail.duration);
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle("Effect Use Cancelled")
|
||||
.setDescription("The effect from your inventory has not been used")
|
||||
.setColor(EmbedColours.Grey)
|
||||
.addFields([
|
||||
{
|
||||
name: "Effect",
|
||||
value: effectDetail.friendlyName,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: "Expires",
|
||||
value: timeLengthInput.GetLengthShort(),
|
||||
inline: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const row = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents([
|
||||
new ButtonBuilder()
|
||||
.setLabel("Confirm")
|
||||
.setCustomId(`effects use confirm ${effectDetail.id}`)
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setDisabled(true),
|
||||
new ButtonBuilder()
|
||||
.setLabel("Cancel")
|
||||
.setCustomId(`effects use cancel ${effectDetail.id}`)
|
||||
.setStyle(ButtonStyle.Danger)
|
||||
.setDisabled(true),
|
||||
]);
|
||||
|
||||
await interaction.update({
|
||||
embeds: [ embed ],
|
||||
components: [ row ],
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
import { AttachmentBuilder, ButtonInteraction, EmbedBuilder } from "discord.js";
|
||||
import { ButtonEvent } from "../type/buttonEvent";
|
||||
import AppLogger from "../client/appLogger";
|
||||
import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata";
|
||||
import Inventory from "../database/entities/app/Inventory";
|
||||
import EmbedColours from "../constants/EmbedColours";
|
||||
import { readFileSync } from "fs";
|
||||
|
@ -9,6 +8,8 @@ import path from "path";
|
|||
import ErrorMessages from "../constants/ErrorMessages";
|
||||
import User from "../database/entities/app/User";
|
||||
import { GetSacrificeAmount } from "../constants/CardRarity";
|
||||
import GetCardsHelper from "../helpers/DropHelpers/GetCardsHelper";
|
||||
import MultidropEmbedHelper from "../helpers/DropHelpers/MultidropEmbedHelper";
|
||||
|
||||
export default class Multidrop extends ButtonEvent {
|
||||
public override async execute(interaction: ButtonInteraction) {
|
||||
|
@ -37,7 +38,7 @@ export default class Multidrop extends ButtonEvent {
|
|||
return;
|
||||
}
|
||||
|
||||
const card = CardDropHelperMetadata.GetCardByCardNumber(cardNumber);
|
||||
const card = GetCardsHelper.GetCardByCardNumber(cardNumber);
|
||||
|
||||
if (!card) {
|
||||
await interaction.reply("Unable to find card.");
|
||||
|
@ -85,7 +86,7 @@ export default class Multidrop extends ButtonEvent {
|
|||
}
|
||||
|
||||
// Drop next card
|
||||
const randomCard = CardDropHelperMetadata.GetRandomCard();
|
||||
const randomCard = GetCardsHelper.GetRandomCard();
|
||||
cardsRemaining -= 1;
|
||||
|
||||
if (!randomCard) {
|
||||
|
@ -105,9 +106,9 @@ export default class Multidrop extends ButtonEvent {
|
|||
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.card.id);
|
||||
const quantityClaimed = inventory ? inventory.Quantity : 0;
|
||||
|
||||
const embed = CardDropHelperMetadata.GenerateMultidropEmbed(randomCard, quantityClaimed, imageFileName, cardsRemaining, undefined, user.Currency);
|
||||
const embed = MultidropEmbedHelper.GenerateMultidropEmbed(randomCard, quantityClaimed, imageFileName, cardsRemaining, undefined, user.Currency);
|
||||
|
||||
const row = CardDropHelperMetadata.GenerateMultidropButtons(randomCard, cardsRemaining, interaction.user.id, cardsRemaining < 0);
|
||||
const row = MultidropEmbedHelper.GenerateMultidropButtons(randomCard, cardsRemaining, interaction.user.id, cardsRemaining < 0);
|
||||
|
||||
await interaction.editReply({
|
||||
embeds: [ embed ],
|
||||
|
@ -131,7 +132,7 @@ export default class Multidrop extends ButtonEvent {
|
|||
return;
|
||||
}
|
||||
|
||||
const card = CardDropHelperMetadata.GetCardByCardNumber(cardNumber);
|
||||
const card = GetCardsHelper.GetCardByCardNumber(cardNumber);
|
||||
|
||||
if (!card) {
|
||||
await interaction.reply("Unable to find card.");
|
||||
|
@ -175,7 +176,7 @@ export default class Multidrop extends ButtonEvent {
|
|||
}
|
||||
|
||||
// Drop next card
|
||||
const randomCard = CardDropHelperMetadata.GetRandomCard();
|
||||
const randomCard = GetCardsHelper.GetRandomCard();
|
||||
cardsRemaining -= 1;
|
||||
|
||||
if (!randomCard) {
|
||||
|
@ -195,9 +196,9 @@ export default class Multidrop extends ButtonEvent {
|
|||
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.card.id);
|
||||
const quantityClaimed = inventory ? inventory.Quantity : 0;
|
||||
|
||||
const embed = CardDropHelperMetadata.GenerateMultidropEmbed(randomCard, quantityClaimed, imageFileName, cardsRemaining, undefined, user.Currency);
|
||||
const embed = MultidropEmbedHelper.GenerateMultidropEmbed(randomCard, quantityClaimed, imageFileName, cardsRemaining, undefined, user.Currency);
|
||||
|
||||
const row = CardDropHelperMetadata.GenerateMultidropButtons(randomCard, cardsRemaining, interaction.user.id, cardsRemaining < 0);
|
||||
const row = MultidropEmbedHelper.GenerateMultidropButtons(randomCard, cardsRemaining, interaction.user.id, cardsRemaining < 0);
|
||||
|
||||
await interaction.editReply({
|
||||
embeds: [ embed ],
|
||||
|
|
|
@ -5,11 +5,12 @@ import { v4 } from "uuid";
|
|||
import { CoreClient } from "../client/client";
|
||||
import Inventory from "../database/entities/app/Inventory";
|
||||
import Config from "../database/entities/app/Config";
|
||||
import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata";
|
||||
import path from "path";
|
||||
import AppLogger from "../client/appLogger";
|
||||
import User from "../database/entities/app/User";
|
||||
import CardConstants from "../constants/CardConstants";
|
||||
import GetCardsHelper from "../helpers/DropHelpers/GetCardsHelper";
|
||||
import DropEmbedHelper from "../helpers/DropHelpers/DropEmbedHelper";
|
||||
|
||||
export default class Reroll extends ButtonEvent {
|
||||
public override async execute(interaction: ButtonInteraction) {
|
||||
|
@ -39,7 +40,7 @@ export default class Reroll extends ButtonEvent {
|
|||
return;
|
||||
}
|
||||
|
||||
const randomCard = CardDropHelperMetadata.GetRandomCard();
|
||||
const randomCard = GetCardsHelper.GetRandomCard();
|
||||
|
||||
if (!randomCard) {
|
||||
await interaction.reply("Unable to fetch card, please try again.");
|
||||
|
@ -66,11 +67,11 @@ export default class Reroll extends ButtonEvent {
|
|||
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.card.id);
|
||||
const quantityClaimed = inventory ? inventory.Quantity : 0;
|
||||
|
||||
const embed = CardDropHelperMetadata.GenerateDropEmbed(randomCard, quantityClaimed, imageFileName, undefined, user.Currency);
|
||||
const embed = DropEmbedHelper.GenerateDropEmbed(randomCard, quantityClaimed, imageFileName, undefined, user.Currency);
|
||||
|
||||
const claimId = v4();
|
||||
|
||||
const row = CardDropHelperMetadata.GenerateDropButtons(randomCard, claimId, interaction.user.id);
|
||||
const row = DropEmbedHelper.GenerateDropButtons(randomCard, claimId, interaction.user.id);
|
||||
|
||||
await interaction.editReply({
|
||||
embeds: [ embed ],
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, EmbedBuilder } from "discord.js";
|
||||
import { ButtonEvent } from "../type/buttonEvent";
|
||||
import Inventory from "../database/entities/app/Inventory";
|
||||
import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata";
|
||||
import { CardRarityToString, GetSacrificeAmount } from "../constants/CardRarity";
|
||||
import EmbedColours from "../constants/EmbedColours";
|
||||
import User from "../database/entities/app/User";
|
||||
import GetCardsHelper from "../helpers/DropHelpers/GetCardsHelper";
|
||||
|
||||
export default class Sacrifice extends ButtonEvent {
|
||||
public override async execute(interaction: ButtonInteraction) {
|
||||
|
@ -42,7 +42,7 @@ export default class Sacrifice extends ButtonEvent {
|
|||
return;
|
||||
}
|
||||
|
||||
const cardData = CardDropHelperMetadata.GetCardByCardNumber(cardNumber);
|
||||
const cardData = GetCardsHelper.GetCardByCardNumber(cardNumber);
|
||||
|
||||
if (!cardData) {
|
||||
await interaction.reply("Unable to find card in the database.");
|
||||
|
@ -124,7 +124,7 @@ export default class Sacrifice extends ButtonEvent {
|
|||
return;
|
||||
}
|
||||
|
||||
const cardData = CardDropHelperMetadata.GetCardByCardNumber(cardNumber);
|
||||
const cardData = GetCardsHelper.GetCardByCardNumber(cardNumber);
|
||||
|
||||
if (!cardData) {
|
||||
await interaction.reply("Unable to find card in the database.");
|
||||
|
|
|
@ -5,12 +5,16 @@ import { CoreClient } from "../client/client";
|
|||
import { v4 } from "uuid";
|
||||
import Inventory from "../database/entities/app/Inventory";
|
||||
import Config from "../database/entities/app/Config";
|
||||
import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata";
|
||||
import path from "path";
|
||||
import AppLogger from "../client/appLogger";
|
||||
import User from "../database/entities/app/User";
|
||||
import CardConstants from "../constants/CardConstants";
|
||||
import ErrorMessages from "../constants/ErrorMessages";
|
||||
import { DropResult } from "../contracts/SeriesMetadata";
|
||||
import EffectHelper from "../helpers/EffectHelper";
|
||||
import GetUnclaimedCardsHelper from "../helpers/DropHelpers/GetUnclaimedCardsHelper";
|
||||
import GetCardsHelper from "../helpers/DropHelpers/GetCardsHelper";
|
||||
import DropEmbedHelper from "../helpers/DropHelpers/DropEmbedHelper";
|
||||
|
||||
export default class Drop extends Command {
|
||||
constructor() {
|
||||
|
@ -47,7 +51,15 @@ export default class Drop extends Command {
|
|||
return;
|
||||
}
|
||||
|
||||
const randomCard = CardDropHelperMetadata.GetRandomCard();
|
||||
let randomCard: DropResult | undefined;
|
||||
|
||||
const hasChanceUpEffect = await EffectHelper.HasEffect(interaction.user.id, "unclaimed");
|
||||
|
||||
if (hasChanceUpEffect && Math.random() <= CardConstants.UnusedChanceUpChance) {
|
||||
randomCard = await GetUnclaimedCardsHelper.GetRandomCardUnclaimed(interaction.user.id);
|
||||
} else {
|
||||
randomCard = GetCardsHelper.GetRandomCard();
|
||||
}
|
||||
|
||||
if (!randomCard) {
|
||||
AppLogger.LogWarn("Commands/Drop", ErrorMessages.UnableToFetchCard);
|
||||
|
@ -73,11 +85,11 @@ export default class Drop extends Command {
|
|||
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.card.id);
|
||||
const quantityClaimed = inventory ? inventory.Quantity : 0;
|
||||
|
||||
const embed = CardDropHelperMetadata.GenerateDropEmbed(randomCard, quantityClaimed, imageFileName, undefined, user.Currency);
|
||||
const embed = DropEmbedHelper.GenerateDropEmbed(randomCard, quantityClaimed, imageFileName, undefined, user.Currency);
|
||||
|
||||
const claimId = v4();
|
||||
|
||||
const row = CardDropHelperMetadata.GenerateDropButtons(randomCard, claimId, interaction.user.id);
|
||||
const row = DropEmbedHelper.GenerateDropButtons(randomCard, claimId, interaction.user.id);
|
||||
|
||||
await interaction.editReply({
|
||||
embeds: [ embed ],
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import {CommandInteraction, SlashCommandBuilder} from "discord.js";
|
||||
import {Command} from "../type/command";
|
||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, CommandInteraction, EmbedBuilder, SlashCommandBuilder } from "discord.js";
|
||||
import { Command } from "../type/command";
|
||||
import EffectHelper from "../helpers/EffectHelper";
|
||||
import { EffectDetails } from "../constants/EffectDetails";
|
||||
import TimeLengthInput from "../helpers/TimeLengthInput";
|
||||
import EmbedColours from "../constants/EmbedColours";
|
||||
import AppLogger from "../client/appLogger";
|
||||
|
||||
export default class Effects extends Command {
|
||||
constructor() {
|
||||
|
@ -15,7 +19,17 @@ export default class Effects extends Command {
|
|||
.addNumberOption(x => x
|
||||
.setName("page")
|
||||
.setDescription("The page number")
|
||||
.setMinValue(1)));
|
||||
.setMinValue(1)))
|
||||
.addSubcommand(x => x
|
||||
.setName("use")
|
||||
.setDescription("Use an effect in your inventory")
|
||||
.addStringOption(y => y
|
||||
.setName("id")
|
||||
.setDescription("The effect id to use")
|
||||
.setRequired(true)
|
||||
.setChoices([
|
||||
{ name: "Unclaimed Chance Up", value: "unclaimed" },
|
||||
])));
|
||||
}
|
||||
|
||||
public override async execute(interaction: CommandInteraction) {
|
||||
|
@ -27,6 +41,9 @@ export default class Effects extends Command {
|
|||
case "list":
|
||||
await this.List(interaction);
|
||||
break;
|
||||
case "use":
|
||||
await this.Use(interaction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,4 +59,60 @@ export default class Effects extends Command {
|
|||
components: [ result.row ],
|
||||
});
|
||||
}
|
||||
|
||||
private async Use(interaction: CommandInteraction) {
|
||||
const id = interaction.options.get("id", true).value!.toString();
|
||||
|
||||
const effectDetail = EffectDetails.get(id);
|
||||
|
||||
if (!effectDetail) {
|
||||
Vylpes marked this conversation as resolved
|
||||
AppLogger.LogWarn("Commands/Effects", `Unable to find effect details for ${id}`);
|
||||
|
||||
await interaction.reply("Unable to find effect!");
|
||||
return;
|
||||
}
|
||||
|
||||
const canUseEffect = await EffectHelper.CanUseEffect(interaction.user.id, id);
|
||||
|
||||
if (!canUseEffect) {
|
||||
await interaction.reply("Unable to use effect! Please make sure you have it in your inventory and is not on cooldown");
|
||||
return;
|
||||
}
|
||||
|
||||
const timeLengthInput = TimeLengthInput.ConvertFromMilliseconds(effectDetail.duration);
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle("Effect Confirmation")
|
||||
.setDescription("Would you like to use this effect?")
|
||||
.setColor(EmbedColours.Ok)
|
||||
.addFields([
|
||||
{
|
||||
name: "Effect",
|
||||
value: effectDetail.friendlyName,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: "Length",
|
||||
value: timeLengthInput.GetLengthShort(),
|
||||
inline: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const row = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents([
|
||||
new ButtonBuilder()
|
||||
.setLabel("Confirm")
|
||||
.setCustomId(`effects use confirm ${effectDetail.id}`)
|
||||
.setStyle(ButtonStyle.Primary),
|
||||
new ButtonBuilder()
|
||||
.setLabel("Cancel")
|
||||
.setCustomId(`effects use cancel ${effectDetail.id}`)
|
||||
.setStyle(ButtonStyle.Danger),
|
||||
]);
|
||||
|
||||
await interaction.reply({
|
||||
embeds: [ embed ],
|
||||
components: [ row ],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ import { CacheType, CommandInteraction, PermissionsBitField, SlashCommandBuilder
|
|||
import { Command } from "../type/command";
|
||||
import { CoreClient } from "../client/client";
|
||||
import Config from "../database/entities/app/Config";
|
||||
import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata";
|
||||
import Inventory from "../database/entities/app/Inventory";
|
||||
import AppLogger from "../client/appLogger";
|
||||
import User from "../database/entities/app/User";
|
||||
import GetCardsHelper from "../helpers/DropHelpers/GetCardsHelper";
|
||||
|
||||
export default class Give extends Command {
|
||||
constructor() {
|
||||
|
@ -81,7 +81,7 @@ export default class Give extends Command {
|
|||
|
||||
AppLogger.LogSilly("Commands/Give/GiveCard", `Parameters: cardNumber=${cardNumber.value}, user=${user.id}`);
|
||||
|
||||
const card = CardDropHelperMetadata.GetCardByCardNumber(cardNumber.value!.toString());
|
||||
const card = GetCardsHelper.GetCardByCardNumber(cardNumber.value!.toString());
|
||||
|
||||
if (!card) {
|
||||
await interaction.reply("Unable to fetch card, please try again.");
|
||||
|
|
|
@ -4,8 +4,8 @@ import { CoreClient } from "../client/client";
|
|||
import { readFileSync } from "fs";
|
||||
import path from "path";
|
||||
import Inventory from "../database/entities/app/Inventory";
|
||||
import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata";
|
||||
import AppLogger from "../client/appLogger";
|
||||
import DropEmbedHelper from "../helpers/DropHelpers/DropEmbedHelper";
|
||||
|
||||
export default class Id extends Command {
|
||||
constructor() {
|
||||
|
@ -60,7 +60,7 @@ export default class Id extends Command {
|
|||
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, card.id);
|
||||
const quantityClaimed = inventory ? inventory.Quantity : 0;
|
||||
|
||||
const embed = CardDropHelperMetadata.GenerateDropEmbed({ card, series }, quantityClaimed, imageFileName);
|
||||
const embed = DropEmbedHelper.GenerateDropEmbed({ card, series }, quantityClaimed, imageFileName);
|
||||
|
||||
try {
|
||||
await interaction.editReply({
|
||||
|
|
|
@ -6,10 +6,11 @@ import Config from "../database/entities/app/Config";
|
|||
import AppLogger from "../client/appLogger";
|
||||
import User from "../database/entities/app/User";
|
||||
import CardConstants from "../constants/CardConstants";
|
||||
import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata";
|
||||
import { readFileSync } from "fs";
|
||||
import path from "path";
|
||||
import Inventory from "../database/entities/app/Inventory";
|
||||
import GetCardsHelper from "../helpers/DropHelpers/GetCardsHelper";
|
||||
import MultidropEmbedHelper from "../helpers/DropHelpers/MultidropEmbedHelper";
|
||||
|
||||
export default class Multidrop extends Command {
|
||||
constructor() {
|
||||
|
@ -49,7 +50,7 @@ export default class Multidrop extends Command {
|
|||
user.RemoveCurrency(CardConstants.MultidropCost);
|
||||
await user.Save(User, user);
|
||||
|
||||
const randomCard = CardDropHelperMetadata.GetRandomCard();
|
||||
const randomCard = GetCardsHelper.GetRandomCard();
|
||||
const cardsRemaining = CardConstants.MultidropQuantity - 1;
|
||||
|
||||
if (!randomCard) {
|
||||
|
@ -69,9 +70,9 @@ export default class Multidrop extends Command {
|
|||
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.card.id);
|
||||
const quantityClaimed = inventory ? inventory.Quantity : 0;
|
||||
|
||||
const embed = CardDropHelperMetadata.GenerateMultidropEmbed(randomCard, quantityClaimed, imageFileName, cardsRemaining, undefined, user.Currency);
|
||||
const embed = MultidropEmbedHelper.GenerateMultidropEmbed(randomCard, quantityClaimed, imageFileName, cardsRemaining, undefined, user.Currency);
|
||||
|
||||
const row = CardDropHelperMetadata.GenerateMultidropButtons(randomCard, cardsRemaining, interaction.user.id);
|
||||
const row = MultidropEmbedHelper.GenerateMultidropButtons(randomCard, cardsRemaining, interaction.user.id);
|
||||
|
||||
await interaction.editReply({
|
||||
embeds: [ embed ],
|
||||
|
|
|
@ -2,8 +2,8 @@ import { ActionRowBuilder, ButtonBuilder, ButtonStyle, CacheType, CommandInterac
|
|||
import { Command } from "../type/command";
|
||||
import Inventory from "../database/entities/app/Inventory";
|
||||
import { CardRarityToString, GetSacrificeAmount } from "../constants/CardRarity";
|
||||
import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata";
|
||||
import EmbedColours from "../constants/EmbedColours";
|
||||
import GetCardsHelper from "../helpers/DropHelpers/GetCardsHelper";
|
||||
|
||||
export default class Sacrifice extends Command {
|
||||
constructor() {
|
||||
|
@ -41,7 +41,7 @@ export default class Sacrifice extends Command {
|
|||
return;
|
||||
}
|
||||
|
||||
const cardData = CardDropHelperMetadata.GetCardByCardNumber(cardnumber.value! as string);
|
||||
const cardData = GetCardsHelper.GetCardByCardNumber(cardnumber.value! as string);
|
||||
|
||||
if (!cardData) {
|
||||
await interaction.reply("Unable to find card in the database.");
|
||||
|
|
|
@ -5,7 +5,7 @@ import Inventory from "../../database/entities/app/Inventory";
|
|||
import { v4 } from "uuid";
|
||||
import { CoreClient } from "../../client/client";
|
||||
import path from "path";
|
||||
import CardDropHelperMetadata from "../../helpers/CardDropHelperMetadata";
|
||||
import DropEmbedHelper from "../../helpers/DropHelpers/DropEmbedHelper";
|
||||
|
||||
export default class Dropnumber extends Command {
|
||||
constructor() {
|
||||
|
@ -60,11 +60,11 @@ export default class Dropnumber extends Command {
|
|||
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, card.id);
|
||||
const quantityClaimed = inventory ? inventory.Quantity : 0;
|
||||
|
||||
const embed = CardDropHelperMetadata.GenerateDropEmbed({ card, series }, quantityClaimed, imageFileName);
|
||||
const embed = DropEmbedHelper.GenerateDropEmbed({ card, series }, quantityClaimed, imageFileName);
|
||||
|
||||
const claimId = v4();
|
||||
|
||||
const row = CardDropHelperMetadata.GenerateDropButtons({ card, series }, claimId, interaction.user.id);
|
||||
const row = DropEmbedHelper.GenerateDropButtons({ card, series }, claimId, interaction.user.id);
|
||||
|
||||
try {
|
||||
await interaction.editReply({
|
||||
|
|
|
@ -5,8 +5,9 @@ import { readFileSync } from "fs";
|
|||
import Inventory from "../../database/entities/app/Inventory";
|
||||
import { v4 } from "uuid";
|
||||
import { CoreClient } from "../../client/client";
|
||||
import CardDropHelperMetadata from "../../helpers/CardDropHelperMetadata";
|
||||
import path from "path";
|
||||
import GetCardsHelper from "../../helpers/DropHelpers/GetCardsHelper";
|
||||
import DropEmbedHelper from "../../helpers/DropHelpers/DropEmbedHelper";
|
||||
|
||||
export default class Droprarity extends Command {
|
||||
constructor() {
|
||||
|
@ -39,7 +40,7 @@ export default class Droprarity extends Command {
|
|||
return;
|
||||
}
|
||||
|
||||
const card = await CardDropHelperMetadata.GetRandomCardByRarity(rarityType);
|
||||
const card = await GetCardsHelper.GetRandomCardByRarity(rarityType);
|
||||
|
||||
if (!card) {
|
||||
await interaction.reply("Card not found");
|
||||
|
@ -61,11 +62,11 @@ export default class Droprarity extends Command {
|
|||
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, card.card.id);
|
||||
const quantityClaimed = inventory ? inventory.Quantity : 0;
|
||||
|
||||
const embed = CardDropHelperMetadata.GenerateDropEmbed(card, quantityClaimed, imageFileName);
|
||||
const embed = DropEmbedHelper.GenerateDropEmbed(card, quantityClaimed, imageFileName);
|
||||
|
||||
const claimId = v4();
|
||||
|
||||
const row = CardDropHelperMetadata.GenerateDropButtons(card, claimId, interaction.user.id);
|
||||
const row = DropEmbedHelper.GenerateDropButtons(card, claimId, interaction.user.id);
|
||||
|
||||
try {
|
||||
await interaction.editReply({
|
||||
|
|
|
@ -7,4 +7,7 @@ export default class CardConstants {
|
|||
// Multidrop
|
||||
public static readonly MultidropCost = this.ClaimCost * 10;
|
||||
public static readonly MultidropQuantity = 11;
|
||||
|
||||
// Effects
|
||||
public static readonly UnusedChanceUpChance = 0.5;
|
||||
}
|
19
src/constants/EffectDetails.ts
Normal file
19
src/constants/EffectDetails.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
class EffectDetail {
|
||||
public readonly id: string;
|
||||
public readonly friendlyName: string;
|
||||
public readonly duration: number;
|
||||
public readonly cost: number;
|
||||
public readonly cooldown: number;
|
||||
|
||||
constructor(id: string, friendlyName: string, duration: number, cost: number, cooldown: number) {
|
||||
this.id = id;
|
||||
this.friendlyName = friendlyName;
|
||||
this.duration = duration;
|
||||
this.cost = cost;
|
||||
this.cooldown = cooldown;
|
||||
}
|
||||
};
|
||||
|
||||
export const EffectDetails = new Map<string, EffectDetail>([
|
||||
[ "unclaimed", new EffectDetail("unclaimed", "Unclaimed Chance Up", 10 * 60 * 1000, 100, 3 * 60 * 60 * 1000) ],
|
||||
]);
|
|
@ -1,180 +0,0 @@
|
|||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
|
||||
import { CardRarity, CardRarityToColour, CardRarityToString, GetSacrificeAmount } from "../constants/CardRarity";
|
||||
import CardRarityChances from "../constants/CardRarityChances";
|
||||
import { DropResult } from "../contracts/SeriesMetadata";
|
||||
import { CoreClient } from "../client/client";
|
||||
import AppLogger from "../client/appLogger";
|
||||
import CardConstants from "../constants/CardConstants";
|
||||
import StringTools from "./StringTools";
|
||||
|
||||
export default class CardDropHelperMetadata {
|
||||
public static GetRandomCard(): DropResult | undefined {
|
||||
const randomRarity = Math.random() * 100;
|
||||
|
||||
let cardRarity: CardRarity;
|
||||
|
||||
const bronzeChance = CardRarityChances.Bronze;
|
||||
const silverChance = bronzeChance + CardRarityChances.Silver;
|
||||
const goldChance = silverChance + CardRarityChances.Gold;
|
||||
const mangaChance = goldChance + CardRarityChances.Manga;
|
||||
|
||||
if (randomRarity < bronzeChance) cardRarity = CardRarity.Bronze;
|
||||
else if (randomRarity < silverChance) cardRarity = CardRarity.Silver;
|
||||
else if (randomRarity < goldChance) cardRarity = CardRarity.Gold;
|
||||
else if (randomRarity < mangaChance) cardRarity = CardRarity.Manga;
|
||||
else cardRarity = CardRarity.Legendary;
|
||||
|
||||
const randomCard = this.GetRandomCardByRarity(cardRarity);
|
||||
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GetRandomCard", `Random card: ${randomCard?.card.id} ${randomCard?.card.name}`);
|
||||
|
||||
return randomCard;
|
||||
}
|
||||
|
||||
public static GetRandomCardByRarity(rarity: CardRarity): DropResult | undefined {
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GetRandomCardByRarity", `Parameters: rarity=${rarity}`);
|
||||
|
||||
const allCards = CoreClient.Cards
|
||||
.flatMap(x => x.cards)
|
||||
.filter(x => x.type == rarity);
|
||||
|
||||
const randomCardIndex = Math.floor(Math.random() * allCards.length);
|
||||
|
||||
const card = allCards[randomCardIndex];
|
||||
const series = CoreClient.Cards
|
||||
.find(x => x.cards.includes(card));
|
||||
|
||||
if (!series) {
|
||||
AppLogger.LogWarn("CardDropHelperMetadata/GetRandomCardByRarity", `Series not found for card ${card.id}`);
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GetRandomCardByRarity", `Random card: ${card.id} ${card.name}`);
|
||||
|
||||
return {
|
||||
series: series,
|
||||
card: card,
|
||||
};
|
||||
}
|
||||
|
||||
public static GetCardByCardNumber(cardNumber: string): DropResult | undefined {
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GetCardByCardNumber", `Parameters: cardNumber=${cardNumber}`);
|
||||
|
||||
const card = CoreClient.Cards
|
||||
.flatMap(x => x.cards)
|
||||
.find(x => x.id == cardNumber);
|
||||
|
||||
const series = CoreClient.Cards
|
||||
.find(x => x.cards.find(y => y.id == card?.id));
|
||||
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GetCardByCardNumber", `Card: ${card?.id} ${card?.name}`);
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GetCardByCardNumber", `Series: ${series?.id} ${series?.name}`);
|
||||
|
||||
if (!card || !series) {
|
||||
AppLogger.LogVerbose("CardDropHelperMetadata/GetCardByCardNumber", `Unable to find card metadata: ${cardNumber}`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return { card, series };
|
||||
}
|
||||
|
||||
public static GenerateDropEmbed(drop: DropResult, quantityClaimed: number, imageFileName: string, claimedBy?: string, currency?: number): EmbedBuilder {
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GenerateDropEmbed", `Parameters: drop=${drop.card.id}, quantityClaimed=${quantityClaimed}, imageFileName=${imageFileName}`);
|
||||
|
||||
const description = drop.card.subseries ?? drop.series.name;
|
||||
let colour = CardRarityToColour(drop.card.type);
|
||||
|
||||
if (drop.card.colour && StringTools.IsHexCode(drop.card.colour)) {
|
||||
const hexCode = Number("0x" + drop.card.colour);
|
||||
|
||||
if (hexCode) {
|
||||
colour = hexCode;
|
||||
} else {
|
||||
AppLogger.LogWarn("CardDropHelperMetadata/GenerateDropEmbed", `Card's colour override is invalid: ${drop.card.id}, ${drop.card.colour}`);
|
||||
}
|
||||
} else if (drop.card.colour) {
|
||||
AppLogger.LogWarn("CardDropHelperMetadata/GenerateDropEmbed", `Card's colour override is invalid: ${drop.card.id}, ${drop.card.colour}`);
|
||||
}
|
||||
|
||||
let imageUrl = `attachment://${imageFileName}`;
|
||||
|
||||
if (drop.card.path.startsWith("http://") || drop.card.path.startsWith("https://")) {
|
||||
imageUrl = drop.card.path;
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle(drop.card.name)
|
||||
.setDescription(description)
|
||||
.setFooter({ text: `${CardRarityToString(drop.card.type)} · ${drop.card.id}` })
|
||||
.setColor(colour)
|
||||
.setImage(imageUrl)
|
||||
.addFields([
|
||||
{
|
||||
name: "Claimed",
|
||||
value: `${quantityClaimed}`,
|
||||
inline: true,
|
||||
}
|
||||
]);
|
||||
|
||||
if (claimedBy != null) {
|
||||
embed.addFields([
|
||||
{
|
||||
name: "Claimed by",
|
||||
value: claimedBy,
|
||||
inline: true,
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
if (currency != null) {
|
||||
embed.addFields([
|
||||
{
|
||||
name: "Currency",
|
||||
value: `${currency}`,
|
||||
inline: true,
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
return embed;
|
||||
}
|
||||
|
||||
public static GenerateDropButtons(drop: DropResult, claimId: string, userId: string, disabled: boolean = false): ActionRowBuilder<ButtonBuilder> {
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GenerateDropButtons", `Parameters: drop=${drop.card.id}, claimId=${claimId}, userId=${userId}`);
|
||||
|
||||
return new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId(`claim ${drop.card.id} ${claimId} ${userId}`)
|
||||
.setLabel(`Claim (${CardConstants.ClaimCost} 🪙)`)
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setDisabled(disabled),
|
||||
new ButtonBuilder()
|
||||
.setCustomId("reroll")
|
||||
.setLabel("Reroll")
|
||||
.setStyle(ButtonStyle.Secondary));
|
||||
}
|
||||
|
||||
public static GenerateMultidropEmbed(drop: DropResult, quantityClaimed: number, imageFileName: string, cardsRemaining: number, claimedBy?: string, currency?: number): EmbedBuilder {
|
||||
const dropEmbed = this.GenerateDropEmbed(drop, quantityClaimed, imageFileName, claimedBy, currency);
|
||||
|
||||
dropEmbed.setFooter({ text: `${dropEmbed.data.footer?.text} · ${cardsRemaining} Remaining`});
|
||||
|
||||
return dropEmbed;
|
||||
}
|
||||
|
||||
public static GenerateMultidropButtons(drop: DropResult, cardsRemaining: number, userId: string, disabled = false): ActionRowBuilder<ButtonBuilder> {
|
||||
return new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId(`multidrop keep ${drop.card.id} ${cardsRemaining} ${userId}`)
|
||||
.setLabel("Keep")
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setDisabled(disabled),
|
||||
new ButtonBuilder()
|
||||
.setCustomId(`multidrop sacrifice ${drop.card.id} ${cardsRemaining} ${userId}`)
|
||||
.setLabel(`Sacrifice (+${GetSacrificeAmount(drop.card.type)} 🪙)`)
|
||||
.setStyle(ButtonStyle.Secondary));
|
||||
}
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
import {ActionRowBuilder, AttachmentBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder} from "discord.js";
|
||||
import Fuse from "fuse.js";
|
||||
import {CoreClient} from "../client/client.js";
|
||||
import CardDropHelperMetadata from "./CardDropHelperMetadata.js";
|
||||
import Inventory from "../database/entities/app/Inventory.js";
|
||||
import {readFileSync} from "fs";
|
||||
import path from "path";
|
||||
import AppLogger from "../client/appLogger.js";
|
||||
import GetCardsHelper from "./DropHelpers/GetCardsHelper.js";
|
||||
import DropEmbedHelper from "./DropHelpers/DropEmbedHelper.js";
|
||||
|
||||
interface ReturnedPage {
|
||||
embed: EmbedBuilder,
|
||||
|
@ -32,7 +33,7 @@ export default class CardSearchHelper {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
const card = CardDropHelperMetadata.GetCardByCardNumber(entry.item.id);
|
||||
const card = GetCardsHelper.GetCardByCardNumber(entry.item.id);
|
||||
|
||||
if (!card) return undefined;
|
||||
|
||||
|
@ -51,7 +52,7 @@ export default class CardSearchHelper {
|
|||
const inventory = await Inventory.FetchOneByCardNumberAndUserId(userid, card.card.id);
|
||||
const quantityClaimed = inventory?.Quantity ?? 0;
|
||||
|
||||
const embed = CardDropHelperMetadata.GenerateDropEmbed(card, quantityClaimed, imageFileName);
|
||||
const embed = DropEmbedHelper.GenerateDropEmbed(card, quantityClaimed, imageFileName);
|
||||
|
||||
const row = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
|
@ -72,7 +73,7 @@ export default class CardSearchHelper {
|
|||
public static async GenerateSearchPageFromQuery(results: string[], userid: string, page: number): Promise<ReturnedPage | undefined> {
|
||||
const currentPageId = results[page - 1];
|
||||
|
||||
const card = CardDropHelperMetadata.GetCardByCardNumber(currentPageId);
|
||||
const card = GetCardsHelper.GetCardByCardNumber(currentPageId);
|
||||
|
||||
if (!card) {
|
||||
AppLogger.LogError("CardSearchHelper/GenerateSearchPageFromQuery", `Unable to find card by id: ${currentPageId}.`);
|
||||
|
@ -95,7 +96,7 @@ export default class CardSearchHelper {
|
|||
const inventory = await Inventory.FetchOneByCardNumberAndUserId(userid, card.card.id);
|
||||
const quantityClaimed = inventory?.Quantity ?? 0;
|
||||
|
||||
const embed = CardDropHelperMetadata.GenerateDropEmbed(card, quantityClaimed, imageFileName);
|
||||
const embed = DropEmbedHelper.GenerateDropEmbed(card, quantityClaimed, imageFileName);
|
||||
|
||||
const row = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
|
|
85
src/helpers/DropHelpers/DropEmbedHelper.ts
Normal file
85
src/helpers/DropHelpers/DropEmbedHelper.ts
Normal file
|
@ -0,0 +1,85 @@
|
|||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
|
||||
import { DropResult } from "../../contracts/SeriesMetadata";
|
||||
import AppLogger from "../../client/appLogger";
|
||||
import { CardRarityToColour, CardRarityToString } from "../../constants/CardRarity";
|
||||
import StringTools from "../StringTools";
|
||||
import CardConstants from "../../constants/CardConstants";
|
||||
|
||||
export default class DropEmbedHelper {
|
||||
public static GenerateDropEmbed(drop: DropResult, quantityClaimed: number, imageFileName: string, claimedBy?: string, currency?: number): EmbedBuilder {
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GenerateDropEmbed", `Parameters: drop=${drop.card.id}, quantityClaimed=${quantityClaimed}, imageFileName=${imageFileName}`);
|
||||
|
||||
const description = drop.card.subseries ?? drop.series.name;
|
||||
let colour = CardRarityToColour(drop.card.type);
|
||||
|
||||
if (drop.card.colour && StringTools.IsHexCode(drop.card.colour)) {
|
||||
const hexCode = Number("0x" + drop.card.colour);
|
||||
|
||||
if (hexCode) {
|
||||
colour = hexCode;
|
||||
} else {
|
||||
AppLogger.LogWarn("CardDropHelperMetadata/GenerateDropEmbed", `Card's colour override is invalid: ${drop.card.id}, ${drop.card.colour}`);
|
||||
}
|
||||
} else if (drop.card.colour) {
|
||||
AppLogger.LogWarn("CardDropHelperMetadata/GenerateDropEmbed", `Card's colour override is invalid: ${drop.card.id}, ${drop.card.colour}`);
|
||||
}
|
||||
|
||||
let imageUrl = `attachment://${imageFileName}`;
|
||||
|
||||
if (drop.card.path.startsWith("http://") || drop.card.path.startsWith("https://")) {
|
||||
imageUrl = drop.card.path;
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle(drop.card.name)
|
||||
.setDescription(description)
|
||||
.setFooter({ text: `${CardRarityToString(drop.card.type)} · ${drop.card.id}` })
|
||||
.setColor(colour)
|
||||
.setImage(imageUrl)
|
||||
.addFields([
|
||||
{
|
||||
name: "Claimed",
|
||||
value: `${quantityClaimed}`,
|
||||
inline: true,
|
||||
}
|
||||
]);
|
||||
|
||||
if (claimedBy != null) {
|
||||
embed.addFields([
|
||||
{
|
||||
name: "Claimed by",
|
||||
value: claimedBy,
|
||||
inline: true,
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
if (currency != null) {
|
||||
embed.addFields([
|
||||
{
|
||||
name: "Currency",
|
||||
value: `${currency}`,
|
||||
inline: true,
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
return embed;
|
||||
}
|
||||
|
||||
public static GenerateDropButtons(drop: DropResult, claimId: string, userId: string, disabled: boolean = false): ActionRowBuilder<ButtonBuilder> {
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GenerateDropButtons", `Parameters: drop=${drop.card.id}, claimId=${claimId}, userId=${userId}`);
|
||||
|
||||
return new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId(`claim ${drop.card.id} ${claimId} ${userId}`)
|
||||
.setLabel(`Claim (${CardConstants.ClaimCost} 🪙)`)
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setDisabled(disabled),
|
||||
new ButtonBuilder()
|
||||
.setCustomId("reroll")
|
||||
.setLabel("Reroll")
|
||||
.setStyle(ButtonStyle.Secondary));
|
||||
}
|
||||
}
|
78
src/helpers/DropHelpers/GetCardsHelper.ts
Normal file
78
src/helpers/DropHelpers/GetCardsHelper.ts
Normal file
|
@ -0,0 +1,78 @@
|
|||
import AppLogger from "../../client/appLogger";
|
||||
import { CoreClient } from "../../client/client";
|
||||
import { CardRarity } from "../../constants/CardRarity";
|
||||
import CardRarityChances from "../../constants/CardRarityChances";
|
||||
import { DropResult } from "../../contracts/SeriesMetadata";
|
||||
|
||||
export default class GetCardsHelper {
|
||||
public static GetRandomCard(): DropResult | undefined {
|
||||
const randomRarity = Math.random() * 100;
|
||||
|
||||
let cardRarity: CardRarity;
|
||||
|
||||
const bronzeChance = CardRarityChances.Bronze;
|
||||
const silverChance = bronzeChance + CardRarityChances.Silver;
|
||||
const goldChance = silverChance + CardRarityChances.Gold;
|
||||
const mangaChance = goldChance + CardRarityChances.Manga;
|
||||
|
||||
if (randomRarity < bronzeChance) cardRarity = CardRarity.Bronze;
|
||||
else if (randomRarity < silverChance) cardRarity = CardRarity.Silver;
|
||||
else if (randomRarity < goldChance) cardRarity = CardRarity.Gold;
|
||||
else if (randomRarity < mangaChance) cardRarity = CardRarity.Manga;
|
||||
else cardRarity = CardRarity.Legendary;
|
||||
|
||||
const randomCard = this.GetRandomCardByRarity(cardRarity);
|
||||
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GetRandomCard", `Random card: ${randomCard?.card.id} ${randomCard?.card.name}`);
|
||||
|
||||
return randomCard;
|
||||
}
|
||||
|
||||
public static GetRandomCardByRarity(rarity: CardRarity): DropResult | undefined {
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GetRandomCardByRarity", `Parameters: rarity=${rarity}`);
|
||||
|
||||
const allCards = CoreClient.Cards
|
||||
.flatMap(x => x.cards)
|
||||
.filter(x => x.type == rarity);
|
||||
|
||||
const randomCardIndex = Math.floor(Math.random() * allCards.length);
|
||||
|
||||
const card = allCards[randomCardIndex];
|
||||
const series = CoreClient.Cards
|
||||
.find(x => x.cards.includes(card));
|
||||
|
||||
if (!series) {
|
||||
AppLogger.LogWarn("CardDropHelperMetadata/GetRandomCardByRarity", `Series not found for card ${card.id}`);
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GetRandomCardByRarity", `Random card: ${card.id} ${card.name}`);
|
||||
|
||||
return {
|
||||
series: series,
|
||||
card: card,
|
||||
};
|
||||
}
|
||||
|
||||
public static GetCardByCardNumber(cardNumber: string): DropResult | undefined {
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GetCardByCardNumber", `Parameters: cardNumber=${cardNumber}`);
|
||||
|
||||
const card = CoreClient.Cards
|
||||
.flatMap(x => x.cards)
|
||||
.find(x => x.id == cardNumber);
|
||||
|
||||
const series = CoreClient.Cards
|
||||
.find(x => x.cards.find(y => y.id == card?.id));
|
||||
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GetCardByCardNumber", `Card: ${card?.id} ${card?.name}`);
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GetCardByCardNumber", `Series: ${series?.id} ${series?.name}`);
|
||||
|
||||
if (!card || !series) {
|
||||
AppLogger.LogVerbose("CardDropHelperMetadata/GetCardByCardNumber", `Unable to find card metadata: ${cardNumber}`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return { card, series };
|
||||
}
|
||||
}
|
69
src/helpers/DropHelpers/GetUnclaimedCardsHelper.ts
Normal file
69
src/helpers/DropHelpers/GetUnclaimedCardsHelper.ts
Normal file
|
@ -0,0 +1,69 @@
|
|||
import AppLogger from "../../client/appLogger";
|
||||
import { CoreClient } from "../../client/client";
|
||||
import { CardRarity } from "../../constants/CardRarity";
|
||||
import CardRarityChances from "../../constants/CardRarityChances";
|
||||
import { DropResult } from "../../contracts/SeriesMetadata";
|
||||
import Inventory from "../../database/entities/app/Inventory";
|
||||
import GetCardsHelper from "./GetCardsHelper";
|
||||
|
||||
export default class GetUnclaimedCardsHelper {
|
||||
public static async GetRandomCardUnclaimed(userId: string): Promise<DropResult | undefined> {
|
||||
const randomRarity = Math.random() * 100;
|
||||
|
||||
let cardRarity: CardRarity;
|
||||
|
||||
const bronzeChance = CardRarityChances.Bronze;
|
||||
const silverChance = bronzeChance + CardRarityChances.Silver;
|
||||
const goldChance = silverChance + CardRarityChances.Gold;
|
||||
const mangaChance = goldChance + CardRarityChances.Manga;
|
||||
|
||||
if (randomRarity < bronzeChance) cardRarity = CardRarity.Bronze;
|
||||
else if (randomRarity < silverChance) cardRarity = CardRarity.Silver;
|
||||
else if (randomRarity < goldChance) cardRarity = CardRarity.Gold;
|
||||
else if (randomRarity < mangaChance) cardRarity = CardRarity.Manga;
|
||||
else cardRarity = CardRarity.Legendary;
|
||||
|
||||
const randomCard = await this.GetRandomCardByRarityUnclaimed(cardRarity, userId);
|
||||
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GetRandomCardUnclaimed", `Random card: ${randomCard?.card.id} ${randomCard?.card.name}`);
|
||||
|
||||
return randomCard;
|
||||
}
|
||||
|
||||
public static async GetRandomCardByRarityUnclaimed(rarity: CardRarity, userId: string): Promise<DropResult | undefined> {
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GetRandomCardByRarityUnclaimed", `Parameters: rarity=${rarity}, userId=${userId}`);
|
||||
|
||||
const claimedCards = await Inventory.FetchAllByUserId(userId);
|
||||
|
||||
if (!claimedCards) {
|
||||
// They don't have any cards, so safe to get any random card
|
||||
return GetCardsHelper.GetRandomCardByRarity(rarity);
|
||||
}
|
||||
|
||||
const allCards = CoreClient.Cards
|
||||
.flatMap(x => x.cards)
|
||||
.filter(x => x.type == rarity)
|
||||
.filter(x => !claimedCards.find(y => y.CardNumber == x.id));
|
||||
|
||||
if (!allCards) return undefined;
|
||||
|
||||
const randomCardIndex = Math.floor(Math.random() * allCards.length);
|
||||
|
||||
const card = allCards[randomCardIndex];
|
||||
const series = CoreClient.Cards
|
||||
.find(x => x.cards.includes(card));
|
||||
|
||||
if (!series) {
|
||||
AppLogger.LogWarn("CardDropHelperMetadata/GetRandomCardByRarityUnclaimed", `Series not found for card ${card.id}`);
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
AppLogger.LogSilly("CardDropHelperMetadata/GetRandomCardByRarityUnclaimed", `Random card: ${card.id} ${card.name}`);
|
||||
|
||||
return {
|
||||
series: series,
|
||||
card: card,
|
||||
};
|
||||
}
|
||||
}
|
28
src/helpers/DropHelpers/MultidropEmbedHelper.ts
Normal file
28
src/helpers/DropHelpers/MultidropEmbedHelper.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
|
||||
import { DropResult } from "../../contracts/SeriesMetadata";
|
||||
import { GetSacrificeAmount } from "../../constants/CardRarity";
|
||||
import DropEmbedHelper from "./DropEmbedHelper";
|
||||
|
||||
export default class MultidropEmbedHelper {
|
||||
public static GenerateMultidropEmbed(drop: DropResult, quantityClaimed: number, imageFileName: string, cardsRemaining: number, claimedBy?: string, currency?: number): EmbedBuilder {
|
||||
const dropEmbed = DropEmbedHelper.GenerateDropEmbed(drop, quantityClaimed, imageFileName, claimedBy, currency);
|
||||
|
||||
dropEmbed.setFooter({ text: `${dropEmbed.data.footer?.text} · ${cardsRemaining} Remaining`});
|
||||
|
||||
return dropEmbed;
|
||||
}
|
||||
|
||||
public static GenerateMultidropButtons(drop: DropResult, cardsRemaining: number, userId: string, disabled = false): ActionRowBuilder<ButtonBuilder> {
|
||||
return new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId(`multidrop keep ${drop.card.id} ${cardsRemaining} ${userId}`)
|
||||
.setLabel("Keep")
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setDisabled(disabled),
|
||||
new ButtonBuilder()
|
||||
.setCustomId(`multidrop sacrifice ${drop.card.id} ${cardsRemaining} ${userId}`)
|
||||
.setLabel(`Sacrifice (+${GetSacrificeAmount(drop.card.type)} 🪙)`)
|
||||
.setStyle(ButtonStyle.Secondary));
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import {ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder} from "discord.js";
|
||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
|
||||
import UserEffect from "../database/entities/app/UserEffect";
|
||||
import EmbedColours from "../constants/EmbedColours";
|
||||
import { EffectDetails } from "../constants/EffectDetails";
|
||||
|
||||
export default class EffectHelper {
|
||||
public static async AddEffectToUserInventory(userId: string, name: string, quantity: number = 1) {
|
||||
|
@ -16,6 +17,20 @@ export default class EffectHelper {
|
|||
}
|
||||
|
||||
public static async UseEffect(userId: string, name: string, whenExpires: Date): Promise<boolean> {
|
||||
const canUseEffect = await this.CanUseEffect(userId, name);
|
||||
|
||||
if (!canUseEffect) return false;
|
||||
|
||||
const effect = await UserEffect.FetchOneByUserIdAndName(userId, name);
|
||||
|
||||
effect!.UseEffect(whenExpires);
|
||||
|
||||
await effect!.Save(UserEffect, effect!);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async CanUseEffect(userId: string, name: string): Promise<boolean> {
|
||||
const effect = await UserEffect.FetchOneByUserIdAndName(userId, name);
|
||||
const now = new Date();
|
||||
|
||||
|
@ -23,13 +38,15 @@ export default class EffectHelper {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (effect.WhenExpires && now < effect.WhenExpires) {
|
||||
const effectDetail = EffectDetails.get(effect.Name);
|
||||
|
||||
if (!effectDetail) {
|
||||
return false;
|
||||
}
|
||||
|
||||
effect.UseEffect(whenExpires);
|
||||
|
||||
await effect.Save(UserEffect, effect);
|
||||
if (effect.WhenExpires && now < new Date(effect.WhenExpires.getTime() + effectDetail.cooldown)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -118,4 +118,19 @@ export default class TimeLengthInput {
|
|||
|
||||
return desNumber;
|
||||
}
|
||||
|
||||
public static ConvertFromMilliseconds(ms: number): TimeLengthInput {
|
||||
Vylpes marked this conversation as resolved
VylpesTester
commented
I want tests generated for this I want tests generated for this
|
||||
const seconds = Math.floor(ms / 1000);
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const days = Math.floor(hours / 24);
|
||||
|
||||
const remainingSeconds = seconds % 60;
|
||||
const remainingMinutes = minutes % 60;
|
||||
const remainingHours = hours % 24;
|
||||
|
||||
const timeString = `${days}d ${remainingHours}h ${remainingMinutes}m ${remainingSeconds}s`;
|
||||
|
||||
return new TimeLengthInput(timeString);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import { ButtonInteraction } from "../../__types__/discord.js";
|
||||
|
||||
export default function GenerateButtonInteractionMock(): ButtonInteraction {
|
||||
return {
|
||||
guild: {},
|
||||
guildId: "guildId",
|
||||
channel: {
|
||||
isSendable: jest.fn().mockReturnValue(true),
|
||||
send: jest.fn(),
|
||||
},
|
||||
deferUpdate: jest.fn(),
|
||||
editReply: jest.fn(),
|
||||
message: {
|
||||
createdAt: new Date(1000 * 60 * 27),
|
||||
},
|
||||
user: {
|
||||
id: "userId",
|
||||
},
|
||||
customId: "customId",
|
||||
};
|
||||
}
|
17
tests/__types__/discord.js.ts
Normal file
17
tests/__types__/discord.js.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
export type ButtonInteraction = {
|
||||
guild: object | null,
|
||||
guildId: string | null,
|
||||
channel: {
|
||||
isSendable: jest.Func,
|
||||
send: jest.Func,
|
||||
} | null,
|
||||
deferUpdate: jest.Func,
|
||||
editReply: jest.Func,
|
||||
message: {
|
||||
createdAt: Date,
|
||||
} | null,
|
||||
user: {
|
||||
id: string,
|
||||
} | null,
|
||||
customId: string,
|
||||
}
|
109
tests/buttonEvents/Claim.test.ts
Normal file
109
tests/buttonEvents/Claim.test.ts
Normal file
|
@ -0,0 +1,109 @@
|
|||
import { ButtonInteraction, TextChannel } from "discord.js";
|
||||
import Claim from "../../src/buttonEvents/Claim";
|
||||
import { ButtonInteraction as ButtonInteractionType } from "../__types__/discord.js";
|
||||
import User from "../../src/database/entities/app/User";
|
||||
import GenerateButtonInteractionMock from "../__functions__/discord.js/GenerateButtonInteractionMock";
|
||||
|
||||
jest.mock("../../src/client/appLogger");
|
||||
|
||||
let interaction: ButtonInteractionType;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
jest.setSystemTime(1000 * 60 * 30);
|
||||
|
||||
interaction = GenerateButtonInteractionMock();
|
||||
interaction.customId = "claim cardNumber claimId droppedBy userId";
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
test("GIVEN interaction.guild is null, EXPECT nothing to happen", async () => {
|
||||
// Arrange
|
||||
interaction.guild = null;
|
||||
|
||||
// Act
|
||||
const claim = new Claim();
|
||||
await claim.execute(interaction as unknown as ButtonInteraction);
|
||||
|
||||
// Assert
|
||||
expect(interaction.deferUpdate).not.toHaveBeenCalled();
|
||||
expect(interaction.editReply).not.toHaveBeenCalled();
|
||||
expect((interaction.channel as TextChannel).send).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("GIVEN interaction.guildId is null, EXPECT nothing to happen", async () => {
|
||||
// Arrange
|
||||
interaction.guildId = null;
|
||||
|
||||
// Act
|
||||
const claim = new Claim();
|
||||
await claim.execute(interaction as unknown as ButtonInteraction);
|
||||
|
||||
// Assert
|
||||
expect(interaction.deferUpdate).not.toHaveBeenCalled();
|
||||
expect(interaction.editReply).not.toHaveBeenCalled();
|
||||
expect((interaction.channel as TextChannel).send).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("GIVEN interaction.channel is null, EXPECT nothing to happen", async () => {
|
||||
// Arrange
|
||||
interaction.channel = null;
|
||||
|
||||
// Act
|
||||
const claim = new Claim();
|
||||
await claim.execute(interaction as unknown as ButtonInteraction);
|
||||
|
||||
// Assert
|
||||
expect(interaction.deferUpdate).not.toHaveBeenCalled();
|
||||
expect(interaction.editReply).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("GIVEN channel is not sendable, EXPECT nothing to happen", async () => {
|
||||
// Arrange
|
||||
interaction.channel!.isSendable = jest.fn().mockReturnValue(false);
|
||||
|
||||
// Act
|
||||
const claim = new Claim();
|
||||
await claim.execute(interaction as unknown as ButtonInteraction);
|
||||
|
||||
// Assert
|
||||
expect(interaction.deferUpdate).not.toHaveBeenCalled();
|
||||
expect(interaction.editReply).not.toHaveBeenCalled();
|
||||
expect((interaction.channel as TextChannel).send).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("GIVEN interaction.message was created more than 5 minutes ago, EXPECT error", async () => {
|
||||
// Arrange
|
||||
interaction.message!.createdAt = new Date(0);
|
||||
|
||||
// Act
|
||||
const claim = new Claim();
|
||||
await claim.execute(interaction as unknown as ButtonInteraction);
|
||||
|
||||
// Assert
|
||||
expect(interaction.channel!.send).toHaveBeenCalledTimes(1);
|
||||
expect(interaction.channel!.send).toHaveBeenCalledWith("[object Object], Cards can only be claimed within 5 minutes of it being dropped!");
|
||||
|
||||
expect(interaction.editReply).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("GIVEN user.RemoveCurrency fails, EXPECT error", async () => {
|
||||
// Arrange
|
||||
User.FetchOneById = jest.fn().mockResolvedValue({
|
||||
RemoveCurrency: jest.fn().mockReturnValue(false),
|
||||
Currency: 5,
|
||||
});
|
||||
|
||||
// Act
|
||||
const claim = new Claim();
|
||||
await claim.execute(interaction as unknown as ButtonInteraction);
|
||||
|
||||
// Assert
|
||||
expect(interaction.channel!.send).toHaveBeenCalledTimes(1);
|
||||
expect(interaction.channel!.send).toHaveBeenCalledWith("[object Object], Not enough currency! You need 10 currency, you have 5!");
|
||||
|
||||
expect(interaction.editReply).not.toHaveBeenCalled();
|
||||
});
|
|
@ -1,127 +1,66 @@
|
|||
import {ButtonInteraction} from "discord.js";
|
||||
import { ButtonInteraction } from "discord.js";
|
||||
import Effects from "../../src/buttonEvents/Effects";
|
||||
import EffectHelper from "../../src/helpers/EffectHelper";
|
||||
import GenerateButtonInteractionMock from "../__functions__/discord.js/GenerateButtonInteractionMock";
|
||||
import { ButtonInteraction as ButtonInteractionType } from "../__types__/discord.js";
|
||||
import List from "../../src/buttonEvents/Effects/List";
|
||||
import Use from "../../src/buttonEvents/Effects/Use";
|
||||
import AppLogger from "../../src/client/appLogger";
|
||||
|
||||
describe("execute", () => {
|
||||
describe("GIVEN action in custom id is list", () => {
|
||||
const interaction = {
|
||||
customId: "effects list",
|
||||
} as unknown as ButtonInteraction;
|
||||
jest.mock("../../src/client/appLogger");
|
||||
jest.mock("../../src/buttonEvents/Effects/List");
|
||||
jest.mock("../../src/buttonEvents/Effects/Use");
|
||||
|
||||
let listSpy: jest.SpyInstance;
|
||||
let interaction: ButtonInteractionType;
|
||||
|
||||
beforeAll(async () => {
|
||||
const effects = new Effects();
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
|
||||
listSpy = jest.spyOn(effects as unknown as {"List": () => object}, "List")
|
||||
.mockImplementation();
|
||||
|
||||
await effects.execute(interaction);
|
||||
});
|
||||
|
||||
test("EXPECT list function to be called", () => {
|
||||
expect(listSpy).toHaveBeenCalledTimes(1);
|
||||
expect(listSpy).toHaveBeenCalledWith(interaction);
|
||||
});
|
||||
});
|
||||
interaction = GenerateButtonInteractionMock();
|
||||
interaction.customId = "effects";
|
||||
});
|
||||
|
||||
describe("List", () => {
|
||||
let interaction: ButtonInteraction;
|
||||
test("GIVEN action is list, EXPECT list function to be called", async () => {
|
||||
// Arrange
|
||||
interaction.customId = "effects list";
|
||||
|
||||
const embed = {
|
||||
name: "Embed",
|
||||
};
|
||||
// Act
|
||||
const effects = new Effects();
|
||||
await effects.execute(interaction as unknown as ButtonInteraction);
|
||||
|
||||
const row = {
|
||||
name: "Row",
|
||||
};
|
||||
// Assert
|
||||
expect(List).toHaveBeenCalledTimes(1);
|
||||
expect(List).toHaveBeenCalledWith(interaction);
|
||||
|
||||
beforeEach(() => {
|
||||
interaction = {
|
||||
customId: "effects list",
|
||||
user: {
|
||||
id: "userId",
|
||||
},
|
||||
update: jest.fn(),
|
||||
reply: jest.fn(),
|
||||
} as unknown as ButtonInteraction;
|
||||
});
|
||||
|
||||
describe("GIVEN page is a valid number", () => {
|
||||
beforeEach(async () => {
|
||||
interaction.customId += " 1";
|
||||
|
||||
EffectHelper.GenerateEffectEmbed = jest.fn()
|
||||
.mockResolvedValue({
|
||||
embed,
|
||||
row,
|
||||
});
|
||||
|
||||
const effects = new Effects();
|
||||
|
||||
await effects.execute(interaction);
|
||||
});
|
||||
|
||||
test("EXPECT EffectHelper.GenerateEffectEmbed to be called", () => {
|
||||
expect(EffectHelper.GenerateEffectEmbed).toHaveBeenCalledTimes(1);
|
||||
expect(EffectHelper.GenerateEffectEmbed).toHaveBeenCalledWith("userId", 1);
|
||||
});
|
||||
|
||||
test("EXPECT interaction to be updated", () => {
|
||||
expect(interaction.update).toHaveBeenCalledTimes(1);
|
||||
expect(interaction.update).toHaveBeenCalledWith({
|
||||
embeds: [ embed ],
|
||||
components: [ row ],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("GIVEN page in custom id is not supplied", () => {
|
||||
beforeEach(async () => {
|
||||
EffectHelper.GenerateEffectEmbed = jest.fn()
|
||||
.mockResolvedValue({
|
||||
embed,
|
||||
row,
|
||||
});
|
||||
|
||||
const effects = new Effects();
|
||||
|
||||
await effects.execute(interaction);
|
||||
});
|
||||
|
||||
test("EXPECT interaction to be replied with error", () => {
|
||||
expect(interaction.reply).toHaveBeenCalledTimes(1);
|
||||
expect(interaction.reply).toHaveBeenCalledWith("Page option is not a valid number");
|
||||
});
|
||||
|
||||
test("EXPECT interaction to not be updated", () => {
|
||||
expect(interaction.update).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("GIVEN page in custom id is not a number", () => {
|
||||
beforeEach(async () => {
|
||||
interaction.customId += " test";
|
||||
|
||||
EffectHelper.GenerateEffectEmbed = jest.fn()
|
||||
.mockResolvedValue({
|
||||
embed,
|
||||
row,
|
||||
});
|
||||
|
||||
const effects = new Effects();
|
||||
|
||||
await effects.execute(interaction);
|
||||
});
|
||||
|
||||
test("EXPECT interaction to be replied with error", () => {
|
||||
expect(interaction.reply).toHaveBeenCalledTimes(1);
|
||||
expect(interaction.reply).toHaveBeenCalledWith("Page option is not a valid number");
|
||||
});
|
||||
|
||||
test("EXPECT interaction to not be updated", () => {
|
||||
expect(interaction.update).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
expect(Use.Execute).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("GIVEN action is use, EXPECT use function to be called", async () => {
|
||||
// Arrange
|
||||
interaction.customId = "effects use";
|
||||
|
||||
// Act
|
||||
const effects = new Effects();
|
||||
await effects.execute(interaction as unknown as ButtonInteraction);
|
||||
|
||||
// Assert
|
||||
expect(Use.Execute).toHaveBeenCalledTimes(1);
|
||||
expect(Use.Execute).toHaveBeenCalledWith(interaction);
|
||||
|
||||
expect(List).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("GIVEN action is invalid, EXPECT nothing to be called", async () => {
|
||||
// Arrange
|
||||
interaction.customId = "effects invalid";
|
||||
|
||||
// Act
|
||||
const effects = new Effects();
|
||||
await effects.execute(interaction as unknown as ButtonInteraction);
|
||||
|
||||
// Assert
|
||||
expect(List).not.toHaveBeenCalled();
|
||||
expect(Use.Execute).not.toHaveBeenCalled();
|
||||
|
||||
expect(AppLogger.LogError).toHaveBeenCalledTimes(1);
|
||||
expect(AppLogger.LogError).toHaveBeenCalledWith("Buttons/Effects", "Unknown action, invalid");
|
||||
});
|
50
tests/buttonEvents/Effects/List.test.ts
Normal file
50
tests/buttonEvents/Effects/List.test.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, EmbedBuilder } from "discord.js";
|
||||
import List from "../../../src/buttonEvents/Effects/List";
|
||||
import EffectHelper from "../../../src/helpers/EffectHelper";
|
||||
import { mock } from "jest-mock-extended";
|
||||
|
||||
jest.mock("../../../src/helpers/EffectHelper");
|
||||
|
||||
let interaction: ReturnType<typeof mock<ButtonInteraction>>;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
|
||||
(EffectHelper.GenerateEffectEmbed as jest.Mock).mockResolvedValue({
|
||||
embed: mock<EmbedBuilder>(),
|
||||
row: mock<ActionRowBuilder<ButtonBuilder>>(),
|
||||
});
|
||||
|
||||
interaction = mock<ButtonInteraction>();
|
||||
interaction.user.id = "userId";
|
||||
interaction.customId = "effects list 1";
|
||||
});
|
||||
|
||||
test("GIVEN pageOption is NOT a number, EXPECT error", async () => {
|
||||
// Arrange
|
||||
interaction.customId = "effects list invalid";
|
||||
|
||||
// Act
|
||||
await List(interaction);
|
||||
|
||||
// Assert
|
||||
expect(interaction.reply).toHaveBeenCalledTimes(1);
|
||||
expect(interaction.reply).toHaveBeenCalledWith("Page option is not a valid number")
|
||||
|
||||
expect(EffectHelper.GenerateEffectEmbed).not.toHaveBeenCalled();
|
||||
expect(interaction.update).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("GIVEN pageOption is a number, EXPECT interaction updated", async () => {
|
||||
// Arrange
|
||||
interaction.customId = "effects list 1";
|
||||
|
||||
// Act
|
||||
await List(interaction);
|
||||
|
||||
// Assert
|
||||
expect(EffectHelper.GenerateEffectEmbed).toHaveBeenCalledTimes(1);
|
||||
expect(EffectHelper.GenerateEffectEmbed).toHaveBeenCalledWith("userId", 1);
|
||||
|
||||
expect(interaction.update).toHaveBeenCalledTimes(1);
|
||||
});
|
148
tests/buttonEvents/Effects/Use.test.ts
Normal file
148
tests/buttonEvents/Effects/Use.test.ts
Normal file
|
@ -0,0 +1,148 @@
|
|||
import { ButtonInteraction, InteractionResponse, InteractionUpdateOptions, MessagePayload } from "discord.js";
|
||||
import Use from "../../../src/buttonEvents/Effects/Use";
|
||||
import { mock } from "jest-mock-extended";
|
||||
import AppLogger from "../../../src/client/appLogger";
|
||||
import EffectHelper from "../../../src/helpers/EffectHelper";
|
||||
|
||||
jest.mock("../../../src/client/appLogger");
|
||||
jest.mock("../../../src/helpers/EffectHelper");
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
|
||||
jest.useFakeTimers();
|
||||
jest.setSystemTime(0);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
describe("Execute", () => {
|
||||
test("GIVEN subaction is unknown, EXPECT nothing to be called", async () => {
|
||||
// Arrange
|
||||
const interaction = mock<ButtonInteraction>();
|
||||
interaction.customId = "effects use invalud";
|
||||
|
||||
// Act
|
||||
await Use.Execute(interaction);
|
||||
|
||||
// Assert
|
||||
expect(interaction.reply).not.toHaveBeenCalled();
|
||||
expect(interaction.update).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("UseConfirm", () => {
|
||||
let interaction = mock<ButtonInteraction>();
|
||||
|
||||
beforeEach(() => {
|
||||
interaction = mock<ButtonInteraction>();
|
||||
interaction.customId = "effects use confirm";
|
||||
});
|
||||
|
||||
test("GIVEN effectDetail is not found, EXPECT error", async () => {
|
||||
// Arrange
|
||||
interaction.customId += " invalid";
|
||||
|
||||
// Act
|
||||
await Use.Execute(interaction);
|
||||
|
||||
// Assert
|
||||
expect(AppLogger.LogError).toHaveBeenCalledTimes(1);
|
||||
expect(AppLogger.LogError).toHaveBeenCalledWith("Button/Effects/Use", "Effect not found, invalid");
|
||||
|
||||
expect(interaction.reply).toHaveBeenCalledTimes(1);
|
||||
expect(interaction.reply).toHaveBeenCalledWith("Effect not found in system!");
|
||||
});
|
||||
|
||||
test("GIVEN EffectHelper.UseEffect failed, EXPECT error", async () => {
|
||||
// Arrange
|
||||
interaction.customId += " unclaimed";
|
||||
interaction.user.id = "userId";
|
||||
|
||||
(EffectHelper.UseEffect as jest.Mock).mockResolvedValue(false);
|
||||
|
||||
const whenExpires = new Date(Date.now() + 10 * 60 * 1000);
|
||||
|
||||
// Act
|
||||
await Use.Execute(interaction);
|
||||
|
||||
// Assert
|
||||
expect(EffectHelper.UseEffect).toHaveBeenCalledTimes(1);
|
||||
expect(EffectHelper.UseEffect).toHaveBeenCalledWith("userId", "unclaimed", whenExpires);
|
||||
|
||||
expect(interaction.reply).toHaveBeenCalledTimes(1);
|
||||
expect(interaction.reply).toHaveBeenCalledWith("Unable to use effect! Please make sure you have it in your inventory and is not on cooldown");
|
||||
});
|
||||
|
||||
test("GIVEN EffectHelper.UseEffect succeeded, EXPECT interaction updated", async () => {
|
||||
let updatedWith;
|
||||
|
||||
// Arrange
|
||||
interaction.customId += " unclaimed";
|
||||
interaction.user.id = "userId";
|
||||
interaction.update.mockImplementation(async (opts: string | MessagePayload | InteractionUpdateOptions) => {
|
||||
updatedWith = opts;
|
||||
|
||||
return mock<InteractionResponse<boolean>>();
|
||||
});
|
||||
|
||||
(EffectHelper.UseEffect as jest.Mock).mockResolvedValue(true);
|
||||
|
||||
const whenExpires = new Date(Date.now() + 10 * 60 * 1000);
|
||||
|
||||
// Act
|
||||
await Use.Execute(interaction);
|
||||
|
||||
// Assert
|
||||
expect(EffectHelper.UseEffect).toHaveBeenCalledTimes(1);
|
||||
expect(EffectHelper.UseEffect).toHaveBeenCalledWith("userId", "unclaimed", whenExpires);
|
||||
|
||||
expect(interaction.update).toHaveBeenCalledTimes(1);
|
||||
expect(updatedWith).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("UseCancel", () => {
|
||||
let interaction = mock<ButtonInteraction>();
|
||||
|
||||
beforeEach(() => {
|
||||
interaction = mock<ButtonInteraction>();
|
||||
interaction.customId = "effects use cancel";
|
||||
});
|
||||
|
||||
test("GIVEN effectDetail is not found, EXPECT error", async () => {
|
||||
// Arrange
|
||||
interaction.customId += " invalid";
|
||||
|
||||
// Act
|
||||
await Use.Execute(interaction);
|
||||
|
||||
// Assert
|
||||
expect(AppLogger.LogError).toHaveBeenCalledTimes(1);
|
||||
expect(AppLogger.LogError).toHaveBeenCalledWith("Button/Effects/Cancel", "Effect not found, invalid");
|
||||
|
||||
expect(interaction.reply).toHaveBeenCalledTimes(1);
|
||||
expect(interaction.reply).toHaveBeenCalledWith("Effect not found in system!");
|
||||
});
|
||||
|
||||
test("GIVEN effectDetail is found, EXPECT interaction updated", async () => {
|
||||
let updatedWith;
|
||||
|
||||
// Arrange
|
||||
interaction.customId += " unclaimed";
|
||||
interaction.user.id = "userId";
|
||||
interaction.update.mockImplementation(async (opts: string | MessagePayload | InteractionUpdateOptions) => {
|
||||
updatedWith = opts;
|
||||
|
||||
return mock<InteractionResponse<boolean>>();
|
||||
});
|
||||
// Act
|
||||
await Use.Execute(interaction);
|
||||
|
||||
// Assert
|
||||
expect(interaction.update).toHaveBeenCalledTimes(1);
|
||||
expect(updatedWith).toMatchSnapshot();
|
||||
});
|
||||
});
|
95
tests/buttonEvents/Effects/__snapshots__/Use.test.ts.snap
Normal file
95
tests/buttonEvents/Effects/__snapshots__/Use.test.ts.snap
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`UseCancel GIVEN effectDetail is found, EXPECT interaction updated 1`] = `
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"custom_id": "effects use confirm unclaimed",
|
||||
"disabled": true,
|
||||
"emoji": undefined,
|
||||
"label": "Confirm",
|
||||
"style": 1,
|
||||
"type": 2,
|
||||
},
|
||||
{
|
||||
"custom_id": "effects use cancel unclaimed",
|
||||
"disabled": true,
|
||||
"emoji": undefined,
|
||||
"label": "Cancel",
|
||||
"style": 4,
|
||||
"type": 2,
|
||||
},
|
||||
],
|
||||
"type": 1,
|
||||
},
|
||||
],
|
||||
"embeds": [
|
||||
{
|
||||
"color": 13882323,
|
||||
"description": "The effect from your inventory has not been used",
|
||||
"fields": [
|
||||
{
|
||||
"inline": true,
|
||||
"name": "Effect",
|
||||
"value": "Unclaimed Chance Up",
|
||||
},
|
||||
{
|
||||
"inline": true,
|
||||
"name": "Expires",
|
||||
"value": "10m",
|
||||
},
|
||||
],
|
||||
"title": "Effect Use Cancelled",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`UseConfirm GIVEN EffectHelper.UseEffect succeeded, EXPECT interaction updated 1`] = `
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"custom_id": "effects use confirm unclaimed",
|
||||
"disabled": true,
|
||||
"emoji": undefined,
|
||||
"label": "Confirm",
|
||||
"style": 1,
|
||||
"type": 2,
|
||||
},
|
||||
{
|
||||
"custom_id": "effects use cancel unclaimed",
|
||||
"disabled": true,
|
||||
"emoji": undefined,
|
||||
"label": "Cancel",
|
||||
"style": 4,
|
||||
"type": 2,
|
||||
},
|
||||
],
|
||||
"type": 1,
|
||||
},
|
||||
],
|
||||
"embeds": [
|
||||
{
|
||||
"color": 2263842,
|
||||
"description": "You now have an active effect!",
|
||||
"fields": [
|
||||
{
|
||||
"inline": true,
|
||||
"name": "Effect",
|
||||
"value": "Unclaimed Chance Up",
|
||||
},
|
||||
{
|
||||
"inline": true,
|
||||
"name": "Expires",
|
||||
"value": "<t:600:f>",
|
||||
},
|
||||
],
|
||||
"title": "Effect Used",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
|
@ -1,40 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`constructor EXPECT CommandBuilder to be defined 1`] = `
|
||||
{
|
||||
"contexts": undefined,
|
||||
"default_member_permissions": undefined,
|
||||
"default_permission": undefined,
|
||||
"description": "Effects",
|
||||
"description_localizations": undefined,
|
||||
"dm_permission": undefined,
|
||||
"integration_types": undefined,
|
||||
"name": "effects",
|
||||
"name_localizations": undefined,
|
||||
"nsfw": undefined,
|
||||
"options": [
|
||||
{
|
||||
"description": "List all effects I have",
|
||||
"description_localizations": undefined,
|
||||
"name": "list",
|
||||
"name_localizations": undefined,
|
||||
"options": [
|
||||
{
|
||||
"autocomplete": undefined,
|
||||
"choices": undefined,
|
||||
"description": "The page number",
|
||||
"description_localizations": undefined,
|
||||
"max_value": undefined,
|
||||
"min_value": 1,
|
||||
"name": "page",
|
||||
"name_localizations": undefined,
|
||||
"required": false,
|
||||
"type": 10,
|
||||
},
|
||||
],
|
||||
"type": 1,
|
||||
},
|
||||
],
|
||||
"type": 1,
|
||||
}
|
||||
`;
|
|
@ -1,164 +0,0 @@
|
|||
import {ChatInputCommandInteraction} from "discord.js";
|
||||
import Effects from "../../src/commands/effects";
|
||||
import EffectHelper from "../../src/helpers/EffectHelper";
|
||||
|
||||
describe("constructor", () => {
|
||||
let effects: Effects;
|
||||
|
||||
beforeEach(() => {
|
||||
effects = new Effects();
|
||||
});
|
||||
|
||||
test("EXPECT CommandBuilder to be defined", () => {
|
||||
expect(effects.CommandBuilder).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("execute", () => {
|
||||
describe("GIVEN interaction is not a chat input command", () => {
|
||||
let interaction: ChatInputCommandInteraction;
|
||||
|
||||
let listSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(async () => {
|
||||
interaction = {
|
||||
isChatInputCommand: jest.fn().mockReturnValue(false),
|
||||
} as unknown as ChatInputCommandInteraction;
|
||||
|
||||
const effects = new Effects();
|
||||
|
||||
listSpy = jest.spyOn(effects as unknown as {"List": () => object}, "List")
|
||||
.mockImplementation();
|
||||
|
||||
await effects.execute(interaction);
|
||||
});
|
||||
|
||||
test("EXPECT isChatInputCommand to have been called", () => {
|
||||
expect(interaction.isChatInputCommand).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("EXPECT nothing to happen", () => {
|
||||
expect(listSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("GIVEN subcommand is list", () => {
|
||||
let interaction: ChatInputCommandInteraction;
|
||||
|
||||
let listSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(async () => {
|
||||
interaction = {
|
||||
isChatInputCommand: jest.fn().mockReturnValue(true),
|
||||
options: {
|
||||
getSubcommand: jest.fn().mockReturnValue("list"),
|
||||
},
|
||||
} as unknown as ChatInputCommandInteraction;
|
||||
|
||||
const effects = new Effects();
|
||||
|
||||
listSpy = jest.spyOn(effects as unknown as {"List": () => object}, "List")
|
||||
.mockImplementation();
|
||||
|
||||
await effects.execute(interaction);
|
||||
});
|
||||
|
||||
test("EXPECT subcommand function to be called", () => {
|
||||
expect(interaction.options.getSubcommand).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("EXPECT list function to be called", () => {
|
||||
expect(listSpy).toHaveBeenCalledTimes(1);
|
||||
expect(listSpy).toHaveBeenCalledWith(interaction);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("List", () => {
|
||||
const effects: Effects = new Effects();
|
||||
let interaction: ChatInputCommandInteraction;
|
||||
|
||||
const embed = {
|
||||
name: "embed",
|
||||
};
|
||||
|
||||
const row = {
|
||||
name: "row",
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
interaction = {
|
||||
isChatInputCommand: jest.fn().mockReturnValue(true),
|
||||
options: {
|
||||
getSubcommand: jest.fn().mockReturnValue("list"),
|
||||
},
|
||||
reply: jest.fn(),
|
||||
user: {
|
||||
id: "userId",
|
||||
},
|
||||
} as unknown as ChatInputCommandInteraction;
|
||||
|
||||
const effects = new Effects();
|
||||
|
||||
EffectHelper.GenerateEffectEmbed = jest.fn().mockReturnValue({
|
||||
embed,
|
||||
row,
|
||||
});
|
||||
|
||||
jest.spyOn(effects as unknown as {"List": () => object}, "List")
|
||||
.mockImplementation();
|
||||
});
|
||||
|
||||
describe("GIVEN page option is supplied", () => {
|
||||
describe("AND page is a valid number", () => {
|
||||
beforeEach(async () => {
|
||||
interaction.options.get = jest.fn().mockReturnValueOnce({
|
||||
value: "2",
|
||||
});
|
||||
|
||||
await effects.execute(interaction);
|
||||
});
|
||||
|
||||
test("EXPECT EffectHelper.GenerateEffectEmbed to have been called with page", () => {
|
||||
expect(EffectHelper.GenerateEffectEmbed).toHaveBeenCalledTimes(1);
|
||||
expect(EffectHelper.GenerateEffectEmbed).toHaveBeenCalledWith("userId", 2);
|
||||
});
|
||||
|
||||
test("EXPECT interaction to have been replied", () => {
|
||||
expect(interaction.reply).toHaveBeenCalledTimes(1);
|
||||
expect(interaction.reply).toHaveBeenCalledWith({
|
||||
embeds: [ embed ],
|
||||
components: [ row ],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("AND page is not a valid number", () => {
|
||||
beforeEach(async () => {
|
||||
interaction.options.get = jest.fn().mockReturnValueOnce({
|
||||
value: "test",
|
||||
});
|
||||
|
||||
await effects.execute(interaction);
|
||||
});
|
||||
|
||||
test("EXPECT EffectHelper.GenerateEffectEmbed to have been called with page of 1", () => {
|
||||
expect(EffectHelper.GenerateEffectEmbed).toHaveBeenCalledTimes(1);
|
||||
expect(EffectHelper.GenerateEffectEmbed).toHaveBeenCalledWith("userId", 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("GIVEN page option is not supplied", () => {
|
||||
beforeEach(async () => {
|
||||
interaction.options.get = jest.fn().mockReturnValueOnce(undefined);
|
||||
|
||||
await effects.execute(interaction);
|
||||
});
|
||||
|
||||
test("EXPECT EffectHelper.GenerateEffectEmbed to have been called with page of 1", () => {
|
||||
expect(EffectHelper.GenerateEffectEmbed).toHaveBeenCalledTimes(1);
|
||||
expect(EffectHelper.GenerateEffectEmbed).toHaveBeenCalledWith("userId", 1);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,103 +0,0 @@
|
|||
import UserEffect from "../../../../src/database/entities/app/UserEffect";
|
||||
|
||||
let userEffect: UserEffect;
|
||||
const now = new Date();
|
||||
|
||||
beforeEach(() => {
|
||||
userEffect = new UserEffect("name", "userId", 1);
|
||||
});
|
||||
|
||||
describe("AddUnused", () => {
|
||||
beforeEach(() => {
|
||||
userEffect.AddUnused(1);
|
||||
});
|
||||
|
||||
test("EXPECT unused to be the amount more", () => {
|
||||
expect(userEffect.Unused).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("UseEffect", () => {
|
||||
describe("GIVEN Unused is 0", () => {
|
||||
let result: boolean;
|
||||
|
||||
beforeEach(() => {
|
||||
userEffect.Unused = 0;
|
||||
|
||||
result = userEffect.UseEffect(now);
|
||||
});
|
||||
|
||||
test("EXPECT false returned", () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
test("EXPECT details not to be changed", () => {
|
||||
expect(userEffect.Unused).toBe(0);
|
||||
expect(userEffect.WhenExpires).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("GIVEN Unused is greater than 0", () => {
|
||||
let result: boolean;
|
||||
|
||||
beforeEach(() => {
|
||||
result = userEffect.UseEffect(now);
|
||||
});
|
||||
|
||||
test("EXPECT true returned", () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
test("EXPECT Unused to be subtracted by 1", () => {
|
||||
expect(userEffect.Unused).toBe(0);
|
||||
});
|
||||
|
||||
test("EXPECT WhenExpires to be set", () => {
|
||||
expect(userEffect.WhenExpires).toBe(now);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("IsEffectActive", () => {
|
||||
describe("GIVEN WhenExpires is null", () => {
|
||||
let result: boolean;
|
||||
|
||||
beforeEach(() => {
|
||||
result = userEffect.IsEffectActive();
|
||||
});
|
||||
|
||||
test("EXPECT false returned", () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("GIVEN WhenExpires is defined", () => {
|
||||
describe("AND WhenExpires is in the past", () => {
|
||||
let result: boolean;
|
||||
|
||||
beforeEach(() => {
|
||||
userEffect.WhenExpires = new Date(now.getTime() - 100);
|
||||
|
||||
result = userEffect.IsEffectActive();
|
||||
});
|
||||
|
||||
test("EXPECT false returned", () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("AND WhenExpires is in the future", () => {
|
||||
let result: boolean;
|
||||
|
||||
beforeEach(() => {
|
||||
userEffect.WhenExpires = new Date(now.getTime() + 100);
|
||||
|
||||
result = userEffect.IsEffectActive();
|
||||
});
|
||||
|
||||
test("EXPECT true returned", () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,380 +0,0 @@
|
|||
import {ActionRowBuilder, ButtonBuilder, EmbedBuilder} from "discord.js";
|
||||
import UserEffect from "../../src/database/entities/app/UserEffect";
|
||||
import EffectHelper from "../../src/helpers/EffectHelper";
|
||||
|
||||
describe("AddEffectToUserInventory", () => {
|
||||
describe("GIVEN effect is in database", () => {
|
||||
const effectMock = {
|
||||
AddUnused: jest.fn(),
|
||||
Save: jest.fn(),
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
UserEffect.FetchOneByUserIdAndName = jest.fn().mockResolvedValue(effectMock);
|
||||
|
||||
await EffectHelper.AddEffectToUserInventory("userId", "name", 1);
|
||||
});
|
||||
|
||||
test("EXPECT database to be fetched", () => {
|
||||
expect(UserEffect.FetchOneByUserIdAndName).toHaveBeenCalledTimes(1);
|
||||
expect(UserEffect.FetchOneByUserIdAndName).toHaveBeenCalledWith("userId", "name");
|
||||
});
|
||||
|
||||
test("EXPECT effect to be updated", () => {
|
||||
expect(effectMock.AddUnused).toHaveBeenCalledTimes(1);
|
||||
expect(effectMock.AddUnused).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
test("EXPECT effect to be saved", () => {
|
||||
expect(effectMock.Save).toHaveBeenCalledTimes(1);
|
||||
expect(effectMock.Save).toHaveBeenCalledWith(UserEffect, effectMock);
|
||||
});
|
||||
});
|
||||
|
||||
describe("GIVEN effect is not in database", () => {
|
||||
beforeAll(async () => {
|
||||
UserEffect.FetchOneByUserIdAndName = jest.fn().mockResolvedValue(null);
|
||||
UserEffect.prototype.Save = jest.fn();
|
||||
|
||||
await EffectHelper.AddEffectToUserInventory("userId", "name", 1);
|
||||
});
|
||||
|
||||
test("EXPECT effect to be saved", () => {
|
||||
expect(UserEffect.prototype.Save).toHaveBeenCalledTimes(1);
|
||||
expect(UserEffect.prototype.Save).toHaveBeenCalledWith(UserEffect, expect.any(UserEffect));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("UseEffect", () => {
|
||||
describe("GIVEN effect is in database", () => {
|
||||
describe("GIVEN now is before effect.WhenExpires", () => {
|
||||
let result: boolean | undefined;
|
||||
|
||||
// nowMock < whenExpires
|
||||
const nowMock = new Date(2024, 11, 3, 13, 30);
|
||||
const whenExpires = new Date(2024, 11, 3, 14, 0);
|
||||
|
||||
const userEffect = {
|
||||
Unused: 1,
|
||||
WhenExpires: whenExpires,
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
jest.setSystemTime(nowMock);
|
||||
|
||||
UserEffect.FetchOneByUserIdAndName = jest.fn().mockResolvedValue(userEffect);
|
||||
|
||||
result = await EffectHelper.UseEffect("userId", "name", new Date());
|
||||
});
|
||||
|
||||
test("EXPECT false returned", () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("GIVEN currently used effect is inactive", () => {
|
||||
let result: boolean | undefined;
|
||||
|
||||
// nowMock > whenExpires
|
||||
const nowMock = new Date(2024, 11, 3, 13, 30);
|
||||
const whenExpires = new Date(2024, 11, 3, 13, 0);
|
||||
const whenExpiresNew = new Date(2024, 11, 3, 15, 0);
|
||||
|
||||
const userEffect = {
|
||||
Unused: 1,
|
||||
WhenExpires: whenExpires,
|
||||
UseEffect: jest.fn(),
|
||||
Save: jest.fn(),
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
jest.setSystemTime(nowMock);
|
||||
|
||||
UserEffect.FetchOneByUserIdAndName = jest.fn().mockResolvedValue(userEffect);
|
||||
|
||||
result = await EffectHelper.UseEffect("userId", "name", whenExpiresNew);
|
||||
});
|
||||
|
||||
test("EXPECT UseEffect to be called", () => {
|
||||
expect(userEffect.UseEffect).toHaveReturnedTimes(1);
|
||||
expect(userEffect.UseEffect).toHaveBeenCalledWith(whenExpiresNew);
|
||||
});
|
||||
|
||||
test("EXPECT effect to be saved", () => {
|
||||
expect(userEffect.Save).toHaveBeenCalledTimes(1);
|
||||
expect(userEffect.Save).toHaveBeenCalledWith(UserEffect, userEffect);
|
||||
});
|
||||
|
||||
test("EXPECT true returned", () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("GIVEN effect.WhenExpires is null", () => {
|
||||
let result: boolean | undefined;
|
||||
|
||||
// nowMock > whenExpires
|
||||
const nowMock = new Date(2024, 11, 3, 13, 30);
|
||||
const whenExpiresNew = new Date(2024, 11, 3, 15, 0);
|
||||
|
||||
const userEffect = {
|
||||
Unused: 1,
|
||||
WhenExpires: null,
|
||||
UseEffect: jest.fn(),
|
||||
Save: jest.fn(),
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
jest.setSystemTime(nowMock);
|
||||
|
||||
UserEffect.FetchOneByUserIdAndName = jest.fn().mockResolvedValue(userEffect);
|
||||
|
||||
result = await EffectHelper.UseEffect("userId", "name", whenExpiresNew);
|
||||
});
|
||||
|
||||
test("EXPECT UseEffect to be called", () => {
|
||||
expect(userEffect.UseEffect).toHaveBeenCalledTimes(1);
|
||||
expect(userEffect.UseEffect).toHaveBeenCalledWith(whenExpiresNew);
|
||||
});
|
||||
|
||||
test("EXPECT effect to be saved", () => {
|
||||
expect(userEffect.Save).toHaveBeenCalledTimes(1);
|
||||
expect(userEffect.Save).toHaveBeenCalledWith(UserEffect, userEffect);
|
||||
});
|
||||
|
||||
test("EXPECT true returned", () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("GIVEN effect is not in database", () => {
|
||||
let result: boolean | undefined;
|
||||
|
||||
// nowMock > whenExpires
|
||||
const nowMock = new Date(2024, 11, 3, 13, 30);
|
||||
const whenExpiresNew = new Date(2024, 11, 3, 15, 0);
|
||||
|
||||
beforeAll(async () => {
|
||||
jest.setSystemTime(nowMock);
|
||||
|
||||
UserEffect.FetchOneByUserIdAndName = jest.fn().mockResolvedValue(null);
|
||||
|
||||
result = await EffectHelper.UseEffect("userId", "name", whenExpiresNew);
|
||||
});
|
||||
|
||||
test("EXPECT false returned", () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("GIVEN effect.Unused is 0", () => {
|
||||
let result: boolean | undefined;
|
||||
|
||||
// nowMock > whenExpires
|
||||
const nowMock = new Date(2024, 11, 3, 13, 30);
|
||||
const whenExpiresNew = new Date(2024, 11, 3, 15, 0);
|
||||
|
||||
const userEffect = {
|
||||
Unused: 0,
|
||||
WhenExpires: null,
|
||||
UseEffect: jest.fn(),
|
||||
Save: jest.fn(),
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
jest.setSystemTime(nowMock);
|
||||
|
||||
UserEffect.FetchOneByUserIdAndName = jest.fn().mockResolvedValue(userEffect);
|
||||
|
||||
result = await EffectHelper.UseEffect("userId", "name", whenExpiresNew);
|
||||
});
|
||||
|
||||
test("EXPECT false returned", () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("HasEffect", () => {
|
||||
describe("GIVEN effect is in database", () => {
|
||||
describe("GIVEN effect.WhenExpires is defined", () => {
|
||||
describe("GIVEN now is before effect.WhenExpires", () => {
|
||||
let result: boolean | undefined;
|
||||
|
||||
const nowMock = new Date(2024, 11, 3, 13, 30);
|
||||
const whenExpires = new Date(2024, 11, 3, 15, 0);
|
||||
|
||||
const userEffect = {
|
||||
WhenExpires: whenExpires,
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
jest.setSystemTime(nowMock);
|
||||
|
||||
UserEffect.FetchOneByUserIdAndName = jest.fn().mockResolvedValue(userEffect);
|
||||
|
||||
result = await EffectHelper.HasEffect("userId", "name");
|
||||
});
|
||||
|
||||
test("EXPECT true returned", () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("GIVEN now is after effect.WhenExpires", () => {
|
||||
let result: boolean | undefined;
|
||||
|
||||
const nowMock = new Date(2024, 11, 3, 16, 30);
|
||||
const whenExpires = new Date(2024, 11, 3, 15, 0);
|
||||
|
||||
const userEffect = {
|
||||
WhenExpires: whenExpires,
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
jest.setSystemTime(nowMock);
|
||||
|
||||
UserEffect.FetchOneByUserIdAndName = jest.fn().mockResolvedValue(userEffect);
|
||||
|
||||
result = await EffectHelper.HasEffect("userId", "name");
|
||||
});
|
||||
|
||||
test("EXPECT false returned", () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("GIVEN effect.WhenExpires is undefined", () => {
|
||||
let result: boolean | undefined;
|
||||
|
||||
const userEffect = {
|
||||
WhenExpires: undefined,
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
UserEffect.FetchOneByUserIdAndName = jest.fn().mockResolvedValue(userEffect);
|
||||
|
||||
result = await EffectHelper.HasEffect("userId", "name");
|
||||
});
|
||||
|
||||
test("EXPECT false returned", () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("GIVEN effect is not in database", () => {
|
||||
let result: boolean | undefined;
|
||||
|
||||
beforeAll(async () => {
|
||||
UserEffect.FetchOneByUserIdAndName = jest.fn().mockResolvedValue(null);
|
||||
|
||||
result = await EffectHelper.HasEffect("userId", "name");
|
||||
});
|
||||
|
||||
test("EXPECT false returned", () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("GenerateEffectEmbed", () => {
|
||||
beforeEach(async () => {
|
||||
UserEffect.FetchAllByUserIdPaginated = jest.fn()
|
||||
.mockResolvedValue([
|
||||
[],
|
||||
0,
|
||||
]);
|
||||
|
||||
await EffectHelper.GenerateEffectEmbed("userId", 1);
|
||||
});
|
||||
|
||||
test("EXPECT UserEffect.FetchAllByUserIdPaginated to be called", () => {
|
||||
expect(UserEffect.FetchAllByUserIdPaginated).toHaveBeenCalledTimes(1);
|
||||
expect(UserEffect.FetchAllByUserIdPaginated).toHaveBeenCalledWith("userId", 0, 10);
|
||||
});
|
||||
|
||||
describe("GIVEN there are no effects returned", () => {
|
||||
let result: {
|
||||
embed: EmbedBuilder,
|
||||
row: ActionRowBuilder<ButtonBuilder>,
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
UserEffect.FetchAllByUserIdPaginated = jest.fn()
|
||||
.mockResolvedValue([
|
||||
[],
|
||||
0,
|
||||
]);
|
||||
|
||||
result = await EffectHelper.GenerateEffectEmbed("userId", 1);
|
||||
});
|
||||
|
||||
test("EXPECT result returned", () => {
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("GIVEN there are effects returned", () => {
|
||||
let result: {
|
||||
embed: EmbedBuilder,
|
||||
row: ActionRowBuilder<ButtonBuilder>,
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
UserEffect.FetchAllByUserIdPaginated = jest.fn()
|
||||
.mockResolvedValue([
|
||||
[
|
||||
{
|
||||
Name: "name",
|
||||
Unused: 1,
|
||||
},
|
||||
],
|
||||
1,
|
||||
]);
|
||||
|
||||
result = await EffectHelper.GenerateEffectEmbed("userId", 1);
|
||||
});
|
||||
|
||||
test("EXPECT result returned", () => {
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("AND it is the first page", () => {
|
||||
beforeEach(async () => {
|
||||
result = await EffectHelper.GenerateEffectEmbed("userId", 1)
|
||||
});
|
||||
|
||||
test("EXPECT Previous button to be disabled", () => {
|
||||
const button = result.row.components[0].data as unknown as {
|
||||
label: string,
|
||||
disabled: boolean
|
||||
};
|
||||
|
||||
expect(button).toBeDefined();
|
||||
expect(button.label).toBe("Previous");
|
||||
expect(button.disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("AND it is the last page", () => {
|
||||
beforeEach(async () => {
|
||||
result = await EffectHelper.GenerateEffectEmbed("userId", 1)
|
||||
});
|
||||
|
||||
test("EXPECT Next button to be disabled", () => {
|
||||
const button = result.row.components[1].data as unknown as {
|
||||
label: string,
|
||||
disabled: boolean
|
||||
};
|
||||
|
||||
expect(button).toBeDefined();
|
||||
expect(button.label).toBe("Next");
|
||||
expect(button.disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
38
tests/helpers/TimeLengthInput.test.ts
Normal file
38
tests/helpers/TimeLengthInput.test.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import TimeLengthInput from "../../src/helpers/TimeLengthInput";
|
||||
|
||||
describe("ConvertFromMilliseconds", () => {
|
||||
test("EXPECT 1000ms to be outputted as a second", () => {
|
||||
const timeLength = TimeLengthInput.ConvertFromMilliseconds(1000);
|
||||
expect(timeLength.GetLengthShort()).toBe("1s");
|
||||
});
|
||||
|
||||
test("EXPECT 60000ms to be outputted as a minute", () => {
|
||||
const timeLength = TimeLengthInput.ConvertFromMilliseconds(60000);
|
||||
expect(timeLength.GetLengthShort()).toBe("1m");
|
||||
});
|
||||
|
||||
test("EXPECT 3600000ms to be outputted as an hour", () => {
|
||||
const timeLength = TimeLengthInput.ConvertFromMilliseconds(3600000);
|
||||
expect(timeLength.GetLengthShort()).toBe("1h");
|
||||
});
|
||||
|
||||
test("EXPECT 86400000ms to be outputted as a day", () => {
|
||||
const timeLength = TimeLengthInput.ConvertFromMilliseconds(86400000);
|
||||
expect(timeLength.GetLengthShort()).toBe("1d");
|
||||
});
|
||||
|
||||
test("EXPECT a combination to be outputted correctly", () => {
|
||||
const timeLength = TimeLengthInput.ConvertFromMilliseconds(90061000);
|
||||
expect(timeLength.GetLengthShort()).toBe("1d 1h 1m 1s");
|
||||
});
|
||||
|
||||
test("EXPECT 0ms to be outputted as empty", () => {
|
||||
const timeLength = TimeLengthInput.ConvertFromMilliseconds(0);
|
||||
expect(timeLength.GetLengthShort()).toBe("");
|
||||
});
|
||||
|
||||
test("EXPECT 123456789ms to be outputted correctly", () => {
|
||||
const timeLength = TimeLengthInput.ConvertFromMilliseconds(123456789);
|
||||
expect(timeLength.GetLengthShort()).toBe("1d 10h 17m 36s");
|
||||
});
|
||||
});
|
|
@ -1,71 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`GenerateEffectEmbed GIVEN there are effects returned EXPECT result returned 1`] = `
|
||||
{
|
||||
"embed": {
|
||||
"color": 3166394,
|
||||
"description": "name x1",
|
||||
"footer": {
|
||||
"icon_url": undefined,
|
||||
"text": "Page 1 of 1",
|
||||
},
|
||||
"title": "Effects",
|
||||
},
|
||||
"row": {
|
||||
"components": [
|
||||
{
|
||||
"custom_id": "effects list 0",
|
||||
"disabled": true,
|
||||
"emoji": undefined,
|
||||
"label": "Previous",
|
||||
"style": 1,
|
||||
"type": 2,
|
||||
},
|
||||
{
|
||||
"custom_id": "effects list 2",
|
||||
"disabled": true,
|
||||
"emoji": undefined,
|
||||
"label": "Next",
|
||||
"style": 1,
|
||||
"type": 2,
|
||||
},
|
||||
],
|
||||
"type": 1,
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GenerateEffectEmbed GIVEN there are no effects returned EXPECT result returned 1`] = `
|
||||
{
|
||||
"embed": {
|
||||
"color": 3166394,
|
||||
"description": "*none*",
|
||||
"footer": {
|
||||
"icon_url": undefined,
|
||||
"text": "Page 1 of 1",
|
||||
},
|
||||
"title": "Effects",
|
||||
},
|
||||
"row": {
|
||||
"components": [
|
||||
{
|
||||
"custom_id": "effects list 0",
|
||||
"disabled": true,
|
||||
"emoji": undefined,
|
||||
"label": "Previous",
|
||||
"style": 1,
|
||||
"type": 2,
|
||||
},
|
||||
{
|
||||
"custom_id": "effects list 2",
|
||||
"disabled": true,
|
||||
"emoji": undefined,
|
||||
"label": "Next",
|
||||
"style": 1,
|
||||
"type": 2,
|
||||
},
|
||||
],
|
||||
"type": 1,
|
||||
},
|
||||
}
|
||||
`;
|
Loading…
Reference in a new issue
I think we should log a warning in this case, since it shouldn't be possible