recipe creator FINISH
This commit is contained in:
parent
3da36de9f6
commit
3b9c66ebfd
|
@ -17,7 +17,7 @@ rest
|
|||
const commandFiles = fs.readdirSync("./dist/commands").filter((file) => file.endsWith(".js") && !file.startsWith('.'));
|
||||
|
||||
for (const file of commandFiles) {
|
||||
const command = require(`./dist/commands/${file}`);
|
||||
const command = require(`./dist/commands/${file}`).default;
|
||||
commands.push(command);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
*/
|
||||
exports.up = function(knex) {
|
||||
return knex.schema
|
||||
.createTable('craftingRecipes', (table) => {
|
||||
.createTable('customCraftingRecipes', (table) => {
|
||||
table.increments('id');
|
||||
table.string('table');
|
||||
table.string('station');
|
||||
})
|
||||
.createTable('craftingRecipeItems', (table) => {
|
||||
table.integer('id').references('id').inTable('craftingRecipes').notNullable();
|
||||
.createTable('customCraftingRecipeItems', (table) => {
|
||||
table.integer('id').references('id').inTable('customCraftingRecipes').notNullable();
|
||||
table.integer('item').notNullable();
|
||||
table.integer('quantity').defaultTo(1);
|
||||
table.enum('type', ['input', 'output', 'requirement']);
|
||||
|
@ -22,6 +22,6 @@ exports.up = function(knex) {
|
|||
*/
|
||||
exports.down = function(knex) {
|
||||
return knex.schema
|
||||
.dropTable('craftingRecipes')
|
||||
.dropTable('craftingRecipeItems');
|
||||
.dropTable('customCraftingRecipes')
|
||||
.dropTable('customCraftingRecipes');
|
||||
};
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import { CommandInteraction, SlashCommandBuilder } from 'discord.js';
|
||||
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()
|
||||
|
@ -16,15 +20,188 @@ export default {
|
|||
execute: async (interaction: CommandInteraction) => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
|
||||
interaction.deferReply({ ephemeral: true });
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
|
||||
const sub = interaction.options.getSubcommand(true);
|
||||
|
||||
if (sub === 'create') {
|
||||
interaction.reply({
|
||||
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.`
|
||||
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;
|
|
@ -733,6 +733,7 @@ export default {
|
|||
});
|
||||
bot.on(Events.InteractionCreate, interaction => {
|
||||
if (!interaction.isModalSubmit()) return;
|
||||
if (!interaction.customId.startsWith('survey-')) return;
|
||||
if (!interaction.member) return;
|
||||
|
||||
const member = interaction.member as GuildMember;
|
||||
|
|
|
@ -68,4 +68,14 @@ export interface CraftingStationCooldown {
|
|||
station: string,
|
||||
user: string,
|
||||
usedAt: number
|
||||
}
|
||||
export interface CustomCraftingRecipe {
|
||||
id: number,
|
||||
station: string
|
||||
}
|
||||
export interface CustomCraftingRecipeItem {
|
||||
id: number,
|
||||
item: number,
|
||||
quantity: number,
|
||||
type: 'input' | 'output' | 'requirement'
|
||||
}
|
Loading…
Reference in New Issue