207 lines
7.4 KiB
TypeScript
207 lines
7.4 KiB
TypeScript
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, CommandInteraction, ComponentType, Events, ModalBuilder, SlashCommandBuilder, StringSelectMenuBuilder, TextInputBuilder, TextInputStyle } from 'discord.js';
|
|
import { Command } from '../types/index';
|
|
import { Items, getItem } from '../lib/rpg/items';
|
|
import { formatRecipe } from '../lib/rpg/recipes';
|
|
import { craftingStations, getStation } from '../lib/rpg/craftingStations';
|
|
import { CustomCraftingRecipe, CustomCraftingRecipeItem, db } from '../lib/db';
|
|
|
|
export default {
|
|
data: new SlashCommandBuilder()
|
|
.setName('recipe')
|
|
.setDescription('[ADMIN] Manage custom recipes for items')
|
|
.addSubcommand(sub =>
|
|
sub
|
|
.setName('create')
|
|
.setDescription('[ADMIN] Create a custom recipe')
|
|
)
|
|
.setDMPermission(false)
|
|
.setDefaultMemberPermissions(0),
|
|
|
|
execute: async (interaction: CommandInteraction) => {
|
|
if (!interaction.isChatInputCommand()) return;
|
|
|
|
await interaction.deferReply({ ephemeral: true });
|
|
|
|
const sub = interaction.options.getSubcommand(true);
|
|
|
|
if (sub === 'create') {
|
|
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
|
new ButtonBuilder().setCustomId(`recipe-create-${interaction.guildId}`).setLabel('I\'ve got my string ready!').setStyle(ButtonStyle.Primary)
|
|
);
|
|
await interaction.followUp({
|
|
ephemeral: true,
|
|
content: `To create a recipe, go here: ${interaction.client.config.siteURL}/create-recipe/?guild=${interaction.guildId}\nOnce done, click the button below and paste the resulting string in.`,
|
|
components: [row]
|
|
});
|
|
}
|
|
},
|
|
|
|
async onClientReady(bot) {
|
|
bot.on(Events.InteractionCreate, async (interaction) => {
|
|
if (!('customId' in interaction)) return;
|
|
const id = interaction.customId;
|
|
if (!id.startsWith('recipe-')) return;
|
|
if (!interaction.member) return;
|
|
|
|
if (id.startsWith('recipe-create-')) {
|
|
//const guildID = id.split('-')[2];
|
|
|
|
if (interaction.isMessageComponent()) {
|
|
const modal = new ModalBuilder()
|
|
.setCustomId(interaction.customId)
|
|
.setTitle('Recipe Creator');
|
|
|
|
const input = new TextInputBuilder()
|
|
.setCustomId('recipe-create-textbox')
|
|
.setLabel('Paste in your recipe string here:')
|
|
.setStyle(TextInputStyle.Paragraph)
|
|
.setRequired(true);
|
|
|
|
const row = new ActionRowBuilder<TextInputBuilder>().addComponents(input);
|
|
modal.addComponents(row);
|
|
interaction.showModal(modal);
|
|
} else if (interaction.isModalSubmit()) {
|
|
const field = interaction.fields.getField('recipe-create-textbox', ComponentType.TextInput);
|
|
const recipeString = field.value;
|
|
|
|
await interaction.deferReply({ ephemeral: true });
|
|
|
|
let parsed;
|
|
try {
|
|
parsed = await Promise.all(
|
|
recipeString
|
|
.split('|')
|
|
.map(items =>
|
|
Promise.all(
|
|
items
|
|
.split(';')
|
|
.map(itemStack =>
|
|
itemStack.split(',')
|
|
)
|
|
.map(async ([itemID, quantity]) => (
|
|
{
|
|
item: (await getItem(parseInt(itemID)))!,
|
|
quantity: parseInt(quantity)
|
|
}
|
|
))
|
|
)
|
|
)
|
|
) as Items[][];
|
|
} catch (err) {
|
|
await interaction.followUp(`This is not a valid string!: \`${(err as Error).message}\``);
|
|
return;
|
|
}
|
|
|
|
const
|
|
inputs = parsed[0] || [],
|
|
requirements = parsed[1] || [],
|
|
outputs = parsed[2] || [];
|
|
|
|
const recipe = {
|
|
inputs, requirements, outputs,
|
|
station: 'hands',
|
|
id: 0
|
|
};
|
|
|
|
const components = [
|
|
new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
|
|
new StringSelectMenuBuilder()
|
|
.addOptions(
|
|
...craftingStations
|
|
.map(station => ({
|
|
label: `${station.emoji} ${station.name}`,
|
|
value: station.key,
|
|
description: station.description
|
|
}))
|
|
)
|
|
.setMinValues(1)
|
|
.setMaxValues(1)
|
|
.setCustomId('recipe-select-station')
|
|
),
|
|
new ActionRowBuilder<ButtonBuilder>().addComponents(
|
|
new ButtonBuilder()
|
|
.setCustomId('recipe-select-done')
|
|
.setLabel('Done')
|
|
.setStyle(ButtonStyle.Primary)
|
|
.setDisabled(true)
|
|
)
|
|
];
|
|
|
|
const msg = await interaction.followUp({
|
|
content: `${formatRecipe(recipe)}\n_Select a crafting station, and you're good to go!_`,
|
|
components: components,
|
|
fetchReply: true
|
|
});
|
|
|
|
const selectCollector = msg.createMessageComponentCollector({
|
|
componentType: ComponentType.StringSelect,
|
|
time: 60_000 * 5,
|
|
});
|
|
|
|
selectCollector.on('collect', selectInteraction => {
|
|
const newStation = selectInteraction.values[0];
|
|
recipe.station = newStation;
|
|
components[1].components[0].setDisabled(false);
|
|
interaction.editReply({
|
|
content: `${formatRecipe(recipe)}\n_Select a crafting station, and you're good to go!_`,
|
|
components: components
|
|
});
|
|
const station = getStation(newStation);
|
|
selectInteraction.reply({
|
|
content: `Set station to ${station?.emoji} **${station?.name}**`,
|
|
ephemeral: true
|
|
});
|
|
});
|
|
selectCollector.on('end', () => {
|
|
interaction.editReply({
|
|
content: msg.content,
|
|
components: []
|
|
});
|
|
});
|
|
|
|
const buttonInteraction = await msg.awaitMessageComponent({ componentType: ComponentType.Button, time: 60_000 * 5 });
|
|
selectCollector.stop();
|
|
|
|
const [customRecipe] = await db<CustomCraftingRecipe>('customCraftingRecipes')
|
|
.insert({
|
|
station: recipe.station
|
|
})
|
|
.returning('id');
|
|
|
|
for (const input of recipe.inputs) {
|
|
await db<CustomCraftingRecipeItem>('customCraftingRecipeItems')
|
|
.insert({
|
|
id: customRecipe.id,
|
|
item: input.item.id,
|
|
quantity: input.quantity,
|
|
type: 'input'
|
|
});
|
|
}
|
|
for (const req of recipe.requirements) {
|
|
await db<CustomCraftingRecipeItem>('customCraftingRecipeItems')
|
|
.insert({
|
|
id: customRecipe.id,
|
|
item: req.item.id,
|
|
quantity: req.quantity,
|
|
type: 'requirement'
|
|
});
|
|
}
|
|
for (const output of recipe.outputs) {
|
|
await db<CustomCraftingRecipeItem>('customCraftingRecipeItems')
|
|
.insert({
|
|
id: customRecipe.id,
|
|
item: output.item.id,
|
|
quantity: output.quantity,
|
|
type: 'output'
|
|
});
|
|
}
|
|
|
|
buttonInteraction.reply({
|
|
ephemeral: true,
|
|
content: 'Your recipe has been created 🎉'
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
} satisfies Command; |