2023-11-15 16:04:36 +01:00
import { AutocompleteInteraction , GuildMember , Interaction , SlashCommandBuilder } from 'discord.js' ;
import { CraftingStationCooldown , db } from '../lib/db' ;
2023-11-15 17:09:15 +01:00
import { getStation , canUseStation , craftingStations , verb } from '../lib/rpg/craftingStations' ;
2023-11-15 16:11:48 +01:00
import { formatItem , getItemQuantity , formatItems , getMaxStack , giveItem , formatItemsArray } from '../lib/rpg/items' ;
import { getRecipe , defaultRecipes , formatRecipe } from '../lib/rpg/recipes' ;
2023-11-15 16:04:36 +01:00
module .exports = {
data : new SlashCommandBuilder ( )
. setName ( 'craft' )
. setDescription ( 'Craft an item with items you have' )
. addStringOption ( option = >
option
. setName ( 'station' )
. setAutocomplete ( true )
. setDescription ( 'Which station to use' )
. setRequired ( true )
)
. addStringOption ( option = >
option
. setName ( 'recipe' )
. setAutocomplete ( true )
. setDescription ( 'What to craft' )
. setRequired ( true )
)
. setDMPermission ( false ) ,
execute : async ( interaction : Interaction , member : GuildMember ) = > {
if ( ! interaction . isChatInputCommand ( ) ) return ;
const recipeID = parseInt ( interaction . options . getString ( 'recipe' , true ) ) ;
await interaction . deferReply ( { ephemeral : true } ) ;
const recipe = getRecipe ( recipeID ) ;
if ( ! recipe ) return interaction . followUp ( 'Recipe does not exist!' ) ;
const station = getStation ( recipe . station ) ! ;
if ( ! canUseStation ( member . id , station ) ) return interaction . followUp ( ` ${ station . emoji } You need ${ formatItem ( station . requires ) } to use this station! ` ) ;
for ( const input of recipe . inputs ) {
const inv = await getItemQuantity ( member . id , input . item . id ) ;
if ( inv . quantity < input . quantity ) return interaction . followUp ( ` You need ${ formatItems ( input . item , input . quantity ) } for this recipe! (You have ${ formatItems ( input . item , inv . quantity ) } ) ` ) ;
}
for ( const req of recipe . requirements ) {
const inv = await getItemQuantity ( member . id , req . item . id ) ;
if ( inv . quantity < req . quantity ) return interaction . followUp ( ` You need ${ formatItems ( req . item , req . quantity ) } to begin this recipe! (You have ${ formatItems ( req . item , inv . quantity ) } . Don't worry, these items will not be consumed.) ` ) ;
}
for ( const out of recipe . outputs ) {
const inv = await getItemQuantity ( member . id , out . item . id ) ;
2023-11-15 17:09:15 +01:00
if ( inv . quantity + out . quantity > getMaxStack ( out . item ) ) return interaction . followUp ( ` You do not have enough inventory storage for this recipe! ( ${ formatItems ( out . item , inv . quantity + out . quantity ) } is bigger than the stack size of ${ getMaxStack ( out . item ) } x.) ` ) ;
2023-11-15 16:04:36 +01:00
}
let cooldown ;
if ( station . cooldown ) {
cooldown = await db < CraftingStationCooldown > ( 'craftingStationCooldowns' )
. where ( 'station' , station . key )
. where ( 'user' , member . id )
. first ( ) ;
if ( cooldown && ( cooldown . usedAt + station . cooldown * 1000 ) > Date . now ( ) )
return interaction . followUp ( ` ${ station . emoji } You can use this station again <t: ${ Math . floor ( cooldown . usedAt / 1000 + station . cooldown ) } :R>! ` ) ;
}
// proceed with crafting!
for ( const input of recipe . inputs ) {
giveItem ( member . id , input . item , - input . quantity ) ;
}
const outputs = station . manipulateResults ? station . manipulateResults ( recipe . outputs ) : recipe . outputs ;
for ( const output of outputs ) {
giveItem ( member . id , output . item , output . quantity ) ;
}
let nextUsableAt ;
if ( station . cooldown ) {
if ( ! cooldown ) {
await db < CraftingStationCooldown > ( 'craftingStationCooldowns' )
. insert ( {
station : station.key ,
user : member.id ,
2023-11-15 16:22:57 +01:00
usedAt : Date.now ( )
2023-11-15 16:04:36 +01:00
} ) ;
} else {
await db < CraftingStationCooldown > ( 'craftingStationCooldowns' )
. where ( 'station' , station . key )
. where ( 'user' , member . id )
. update ( {
2023-11-15 16:22:57 +01:00
usedAt : Date.now ( )
2023-11-15 16:04:36 +01:00
} ) ;
}
nextUsableAt = Date . now ( ) + station . cooldown * 1000 ;
}
2023-11-15 17:09:15 +01:00
return interaction . followUp ( ` ${ station . emoji } ${ verb ( station ) } ${ formatItemsArray ( outputs ) } ! ${ nextUsableAt ? ` \ n ${ station . name } usable again <t: ${ Math . floor ( nextUsableAt / 1000 ) } :R> ` : '' } ` ) ;
2023-11-15 16:04:36 +01:00
} ,
autocomplete : async ( interaction : AutocompleteInteraction ) = > {
const focused = interaction . options . getFocused ( true ) ;
if ( focused . name === 'station' ) {
const found = craftingStations
. filter ( station = > canUseStation ( interaction . user . id , station ) )
. filter ( station = > station . name . toLowerCase ( ) . includes ( focused . value . toLowerCase ( ) ) )
. map ( station = > ( {
name : ` ${ station . emoji } ${ station . name } ` ,
value : station.key
} ) ) ;
return interaction . respond ( found ) ;
} else if ( focused . name === 'recipe' ) {
const found = defaultRecipes
. filter ( recipe = > recipe . station === interaction . options . getString ( 'station' ) )
. filter ( recipe = > recipe . outputs . filter ( n = > n . item . name . toLowerCase ( ) . includes ( focused . value . toLowerCase ( ) ) ) . length > 0 )
. map ( recipe = > ( {
2023-11-15 16:22:57 +01:00
name : formatRecipe ( recipe , true ) ,
value : recipe.id.toString ( )
2023-11-15 16:04:36 +01:00
} ) ) ;
return interaction . respond ( found ) ;
}
}
} ;