From 07e6e162ff90484449c77a887f258ae1d85d19e8 Mon Sep 17 00:00:00 2001 From: "Jill \"oatmealine\" Monoids" Date: Sat, 18 Nov 2023 15:24:56 +0300 Subject: [PATCH] =?UTF-8?q?CUSTOM=20RECIPES=20=F0=9F=8E=89=F0=9F=8E=89?= =?UTF-8?q?=F0=9F=8E=89=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- migrations/20231117173052_craftingRecipes.js | 3 +- src/commands/craft.ts | 36 +++++++++----- src/commands/recipe.ts | 3 +- src/lib/db.ts | 1 + src/lib/rpg/recipes.ts | 50 ++++++++++++++++++-- 5 files changed, 75 insertions(+), 18 deletions(-) diff --git a/migrations/20231117173052_craftingRecipes.js b/migrations/20231117173052_craftingRecipes.js index 3c9bd11..66a37e7 100644 --- a/migrations/20231117173052_craftingRecipes.js +++ b/migrations/20231117173052_craftingRecipes.js @@ -6,6 +6,7 @@ exports.up = function(knex) { return knex.schema .createTable('customCraftingRecipes', (table) => { table.increments('id'); + table.string('guild'); table.string('station'); }) .createTable('customCraftingRecipeItems', (table) => { @@ -23,5 +24,5 @@ exports.up = function(knex) { exports.down = function(knex) { return knex.schema .dropTable('customCraftingRecipes') - .dropTable('customCraftingRecipes'); + .dropTable('customCraftingRecipeItems'); }; diff --git a/src/commands/craft.ts b/src/commands/craft.ts index a644819..5577302 100644 --- a/src/commands/craft.ts +++ b/src/commands/craft.ts @@ -1,8 +1,8 @@ import { AutocompleteInteraction, GuildMember, CommandInteraction, SlashCommandBuilder } from 'discord.js'; -import { CraftingStationCooldown, db } from '../lib/db'; +import { CraftingStationCooldown, CustomCraftingRecipe, db } from '../lib/db'; import { getStation, canUseStation, craftingStations, verb, CraftingStation } from '../lib/rpg/craftingStations'; import { formatItem, getItemQuantity, formatItems, getMaxStack, giveItem, formatItemsArray } from '../lib/rpg/items'; -import { getRecipe, defaultRecipes, formatRecipe } from '../lib/rpg/recipes'; +import { getRecipe, defaultRecipes, formatRecipe, resolveCustomRecipe } from '../lib/rpg/recipes'; import { Command } from '../types/index'; export default { @@ -34,7 +34,7 @@ export default { await interaction.deferReply({ephemeral: true}); - const recipe = getRecipe(recipeID); + const recipe = await getRecipe(recipeID); if (!recipe) return interaction.followUp('Recipe does not exist!'); const station = getStation(recipe.station)!; @@ -118,15 +118,29 @@ export default { 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 => ({ - name: formatRecipe(recipe, true), - value: recipe.id.toString() - })); + const station = interaction.options.getString('station'); - return interaction.respond(found); + const foundDefaultRecipes = defaultRecipes + .filter(recipe => recipe.station === station) + .filter(recipe => recipe.outputs.filter(n => n.item.name.toLowerCase().includes(focused.value.toLowerCase())).length > 0); + + const customRecipes = await db('customCraftingRecipes') + .where('station', station); + + const resolvedCustomRecipes = await Promise.all(customRecipes.map(resolveCustomRecipe)); + + const foundCustomRecipes = resolvedCustomRecipes + .filter(recipe => recipe.outputs.filter(n => n.item.name.toLowerCase().includes(focused.value.toLowerCase())).length > 0); + + const recipes = [...foundDefaultRecipes, ...foundCustomRecipes]; + + return interaction.respond( + recipes + .map(recipe => ({ + name: formatRecipe(recipe, true), + value: recipe.id.toString() + })) + ); } } } satisfies Command; \ No newline at end of file diff --git a/src/commands/recipe.ts b/src/commands/recipe.ts index ef196e3..e6e5919 100644 --- a/src/commands/recipe.ts +++ b/src/commands/recipe.ts @@ -44,7 +44,7 @@ export default { if (!interaction.member) return; if (id.startsWith('recipe-create-')) { - //const guildID = id.split('-')[2]; + const guildID = id.split('-')[2]; if (interaction.isMessageComponent()) { const modal = new ModalBuilder() @@ -164,6 +164,7 @@ export default { const [customRecipe] = await db('customCraftingRecipes') .insert({ + guild: guildID, station: recipe.station }) .returning('id'); diff --git a/src/lib/db.ts b/src/lib/db.ts index d9bbca1..8e78d22 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -71,6 +71,7 @@ export interface CraftingStationCooldown { } export interface CustomCraftingRecipe { id: number, + guild: string, station: string } export interface CustomCraftingRecipeItem { diff --git a/src/lib/rpg/recipes.ts b/src/lib/rpg/recipes.ts index 00548c8..9addbab 100644 --- a/src/lib/rpg/recipes.ts +++ b/src/lib/rpg/recipes.ts @@ -1,5 +1,6 @@ +import { CustomCraftingRecipe, CustomCraftingRecipeItem, db } from '../db'; import { getStation } from './craftingStations'; -import { DefaultItems, Items, formatItemsArray, getDefaultItem } from './items'; +import { DefaultItems, Items, formatItemsArray, getDefaultItem, getItem } from './items'; export interface DefaultRecipe { id: number, @@ -8,7 +9,15 @@ export interface DefaultRecipe { requirements: Items[], outputs: Items[] } -export type Recipe = DefaultRecipe +export interface ResolvedCustomRecipe { + id: number, + guild: string, + station: string, + inputs: Items[], + requirements: Items[], + outputs: Items[] +} +export type Recipe = DefaultRecipe | ResolvedCustomRecipe export const defaultRecipes: DefaultRecipe[] = [ { @@ -147,14 +156,45 @@ export const defaultRecipes: DefaultRecipe[] = [ export function getDefaultRecipe(id: number): DefaultRecipe | undefined { return defaultRecipes.find(recipe => recipe.id === id); } -export function getRecipe(id: number): Recipe | undefined { - return getDefaultRecipe(id); // currently just a stub +export async function getCustomRecipe(id: number): Promise { + const recipe = await db('customCraftingRecipes') + .where('id', id) + .first(); + + if (!recipe) return; + + return await resolveCustomRecipe(recipe); +} +export async function getRecipe(id: number): Promise { + if (id >= 0) { + return await getCustomRecipe(id); + } else { + return getDefaultRecipe(id); + } } const defaultFormatRecipe = (inputs: Items[], requirements: Items[], outputs: Items[], disableBold = false) => `${formatItemsArray(inputs, disableBold)}${requirements.length === 0 ? '' : ` w/ ${formatItemsArray(requirements, disableBold)}`} => ${formatItemsArray(outputs, disableBold)}`; -export function formatRecipe(recipe: DefaultRecipe, disableBold = false) { +export function formatRecipe(recipe: Recipe, disableBold = false) { const station = getStation(recipe.station); return (station?.formatRecipe || defaultFormatRecipe)(recipe.inputs, recipe.requirements, recipe.outputs, disableBold); +} + +function resolveItems(items: CustomCraftingRecipeItem[]) { + return Promise.all(items.map(async i => ({item: (await getItem(i.item))!, quantity: i.quantity}))); +} + +export async function resolveCustomRecipe(recipe: CustomCraftingRecipe): Promise { + const items = await db('customCraftingRecipeItems') + .where('id', recipe.id); + + return { + id: recipe.id, + guild: recipe.guild, + station: recipe.station, + inputs: await resolveItems(items.filter(i => i.type === 'input')), + requirements: await resolveItems(items.filter(i => i.type === 'requirement')), + outputs: await resolveItems(items.filter(i => i.type === 'output')), + }; } \ No newline at end of file