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('.'));
|
const commandFiles = fs.readdirSync("./dist/commands").filter((file) => file.endsWith(".js") && !file.startsWith('.'));
|
||||||
|
|
||||||
for (const file of commandFiles) {
|
for (const file of commandFiles) {
|
||||||
const command = require(`./dist/commands/${file}`);
|
const command = require(`./dist/commands/${file}`).default;
|
||||||
commands.push(command);
|
commands.push(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
*/
|
*/
|
||||||
exports.up = function(knex) {
|
exports.up = function(knex) {
|
||||||
return knex.schema
|
return knex.schema
|
||||||
.createTable('craftingRecipes', (table) => {
|
.createTable('customCraftingRecipes', (table) => {
|
||||||
table.increments('id');
|
table.increments('id');
|
||||||
table.string('table');
|
table.string('station');
|
||||||
})
|
})
|
||||||
.createTable('craftingRecipeItems', (table) => {
|
.createTable('customCraftingRecipeItems', (table) => {
|
||||||
table.integer('id').references('id').inTable('craftingRecipes').notNullable();
|
table.integer('id').references('id').inTable('customCraftingRecipes').notNullable();
|
||||||
table.integer('item').notNullable();
|
table.integer('item').notNullable();
|
||||||
table.integer('quantity').defaultTo(1);
|
table.integer('quantity').defaultTo(1);
|
||||||
table.enum('type', ['input', 'output', 'requirement']);
|
table.enum('type', ['input', 'output', 'requirement']);
|
||||||
|
@ -22,6 +22,6 @@ exports.up = function(knex) {
|
||||||
*/
|
*/
|
||||||
exports.down = function(knex) {
|
exports.down = function(knex) {
|
||||||
return knex.schema
|
return knex.schema
|
||||||
.dropTable('craftingRecipes')
|
.dropTable('customCraftingRecipes')
|
||||||
.dropTable('craftingRecipeItems');
|
.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 { 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 {
|
export default {
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
|
@ -16,15 +20,188 @@ export default {
|
||||||
execute: async (interaction: CommandInteraction) => {
|
execute: async (interaction: CommandInteraction) => {
|
||||||
if (!interaction.isChatInputCommand()) return;
|
if (!interaction.isChatInputCommand()) return;
|
||||||
|
|
||||||
interaction.deferReply({ ephemeral: true });
|
await interaction.deferReply({ ephemeral: true });
|
||||||
|
|
||||||
const sub = interaction.options.getSubcommand(true);
|
const sub = interaction.options.getSubcommand(true);
|
||||||
|
|
||||||
if (sub === 'create') {
|
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,
|
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;
|
} satisfies Command;
|
|
@ -733,6 +733,7 @@ export default {
|
||||||
});
|
});
|
||||||
bot.on(Events.InteractionCreate, interaction => {
|
bot.on(Events.InteractionCreate, interaction => {
|
||||||
if (!interaction.isModalSubmit()) return;
|
if (!interaction.isModalSubmit()) return;
|
||||||
|
if (!interaction.customId.startsWith('survey-')) return;
|
||||||
if (!interaction.member) return;
|
if (!interaction.member) return;
|
||||||
|
|
||||||
const member = interaction.member as GuildMember;
|
const member = interaction.member as GuildMember;
|
||||||
|
|
|
@ -68,4 +68,14 @@ export interface CraftingStationCooldown {
|
||||||
station: string,
|
station: string,
|
||||||
user: string,
|
user: string,
|
||||||
usedAt: number
|
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