2023-11-18 12:59:29 +01:00
import { ActionRowBuilder , ButtonBuilder , ButtonStyle , CommandInteraction , ComponentType , Events , ModalBuilder , SlashCommandBuilder , StringSelectMenuBuilder , TextInputBuilder , TextInputStyle } from 'discord.js' ;
2023-11-17 19:23:35 +01:00
import { Command } from '../types/index' ;
2023-11-18 12:59:29 +01:00
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' ;
2023-11-17 19:23:35 +01:00
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 ;
2023-11-18 12:59:29 +01:00
await interaction . deferReply ( { ephemeral : true } ) ;
2023-11-17 19:23:35 +01:00
const sub = interaction . options . getSubcommand ( true ) ;
if ( sub === 'create' ) {
2023-11-18 12:59:29 +01:00
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 ( {
2023-11-17 19:23:35 +01:00
ephemeral : true ,
2023-11-18 12:59:29 +01:00
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 ]
2023-11-17 19:23:35 +01:00
} ) ;
}
2023-11-18 12:59:29 +01:00
} ,
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 🎉'
} ) ;
}
}
} ) ;
2023-11-17 19:23:35 +01:00
}
} satisfies Command ;