Compare commits

...

4 Commits

Author SHA1 Message Date
Jill 68d7e28335
stop using string keys in objects everywhere ffs 2023-11-15 14:01:51 +03:00
Jill b0389f3e58
move items, recipes etc to data file 2023-11-15 13:59:38 +03:00
Jill c6e5b9a00f
move stuff to rpg folder 2023-11-15 13:57:20 +03:00
Jill 7f6607f3d9
rough data draft of recipes 2023-11-15 13:56:46 +03:00
10 changed files with 157 additions and 49 deletions

View File

@ -1,8 +1,8 @@
import { AutocompleteInteraction, Interaction, SlashCommandBuilder } from 'discord.js'; import { AutocompleteInteraction, Interaction, SlashCommandBuilder } from 'discord.js';
import { Counter, CounterUserLink, db } from '../lib/db'; import { Counter, CounterUserLink, db } from '../lib/db';
import { counterAutocomplete, counterConfigs, findCounter, getCounterConfigRaw, getOptions, parseConfig, setCounterConfig, toStringConfig, updateCounter } from '../lib/counter'; import { counterAutocomplete, counterConfigs, findCounter, getCounterConfigRaw, getOptions, parseConfig, setCounterConfig, toStringConfig, updateCounter } from '../lib/rpg/counter';
import { outdent } from 'outdent'; import { outdent } from 'outdent';
import { formatItem, formatItems, getItem, itemAutocomplete } from '../lib/items'; import { formatItem, formatItems, getItem, itemAutocomplete } from '../lib/rpg/items';
function extendOption(t: string) { function extendOption(t: string) {
return {name: t, value: t}; return {name: t, value: t};

View File

@ -1,5 +1,5 @@
import { GuildMember, Interaction, SlashCommandBuilder } from 'discord.js'; import { GuildMember, Interaction, SlashCommandBuilder } from 'discord.js';
import { changeCounterInteraction, counterAutocomplete } from '../lib/counter'; import { changeCounterInteraction, counterAutocomplete } from '../lib/rpg/counter';
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()

View File

@ -1,5 +1,5 @@
import { GuildMember, Interaction, SlashCommandBuilder } from 'discord.js'; import { GuildMember, Interaction, SlashCommandBuilder } from 'discord.js';
import { changeCounterInteraction, counterAutocomplete } from '../lib/counter'; import { changeCounterInteraction, counterAutocomplete } from '../lib/rpg/counter';
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()

View File

@ -1,6 +1,6 @@
import { GuildMember, Interaction, SlashCommandBuilder } from 'discord.js'; import { GuildMember, Interaction, SlashCommandBuilder } from 'discord.js';
import { ItemInventory, db } from '../lib/db'; import { ItemInventory, db } from '../lib/db';
import { formatItems, getItem } from '../lib/items'; import { formatItems, getItem } from '../lib/rpg/items';
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()

View File

@ -1,6 +1,6 @@
import { AutocompleteInteraction, Interaction, SlashCommandBuilder } from 'discord.js'; import { AutocompleteInteraction, Interaction, SlashCommandBuilder } from 'discord.js';
import { CustomItem, ItemInventory, db } from '../lib/db'; import { CustomItem, db } from '../lib/db';
import { behaviors, formatItems, getItem, getMaxStack, giveItem, itemAutocomplete } from '../lib/items'; import { behaviors, formatItems, getItem, giveItem, itemAutocomplete } from '../lib/rpg/items';
//function extendOption(t: string) { //function extendOption(t: string) {
// return {name: t, value: t}; // return {name: t, value: t};

View File

@ -1,5 +1,5 @@
import { GuildMember, Interaction, SlashCommandBuilder } from 'discord.js'; import { GuildMember, Interaction, SlashCommandBuilder } from 'discord.js';
import { changeLinkedCounterInteraction, linkedCounterAutocomplete } from '../lib/counter'; import { changeLinkedCounterInteraction, linkedCounterAutocomplete } from '../lib/rpg/counter';
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()

View File

@ -1,5 +1,5 @@
import { GuildMember, Interaction, SlashCommandBuilder } from 'discord.js'; import { GuildMember, Interaction, SlashCommandBuilder } from 'discord.js';
import { changeLinkedCounterInteraction, linkedCounterAutocomplete } from '../lib/counter'; import { changeLinkedCounterInteraction, linkedCounterAutocomplete } from '../lib/rpg/counter';
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()

View File

@ -1,6 +1,6 @@
import { Client, CommandInteraction, GuildMember, EmbedBuilder, TextChannel, AutocompleteInteraction, User } from 'discord.js'; import { Client, CommandInteraction, GuildMember, EmbedBuilder, TextChannel, AutocompleteInteraction, User } from 'discord.js';
import { getSign } from './util'; import { getSign } from '../util';
import { Counter, CounterConfiguration, CounterUserLink, db } from './db'; import { Counter, CounterConfiguration, CounterUserLink, db } from '../db';
import { formatItems, getItem, getItemQuantity, getMaxStack, giveItem } from './items'; import { formatItems, getItem, getItemQuantity, getMaxStack, giveItem } from './items';
export async function getCounter(id: number) { export async function getCounter(id: number) {
@ -90,7 +90,7 @@ export async function setCounterConfig(counter: Counter, option: string, value:
await db<Counter>('counters') await db<Counter>('counters')
.where('id', counter.id) .where('id', counter.id)
.update({ .update({
'emoji': value emoji: value
}); });
return; return;
} }
@ -105,9 +105,9 @@ export async function setCounterConfig(counter: Counter, option: string, value:
if (updated === 0) { if (updated === 0) {
await db<CounterConfiguration>('counterConfigurations') await db<CounterConfiguration>('counterConfigurations')
.insert({ .insert({
'id': counter.id, id: counter.id,
'configName': option, configName: option,
'value': value value: value
}); });
} }
} }
@ -238,7 +238,7 @@ export async function updateCounter(bot: Client, counter: Counter, value: number
await db<Counter>('counters') await db<Counter>('counters')
.where('id', counter.id) .where('id', counter.id)
.update({ .update({
'message': message.id message: message.id
}); });
} }
} }

95
src/lib/rpg/data.ts Normal file
View File

@ -0,0 +1,95 @@
import { Behavior, CraftingStation, DefaultItem, Recipe, formatItems, getDefaultItem } from './items';
export enum DefaultItems {
COIN = 1,
WORKBENCH = 2,
PEBBLE = 3
}
export const defaultItems: DefaultItem[] = [
{
id: -1,
name: 'Coin',
emoji: '🪙',
type: 'plain',
maxStack: 9999,
untradable: false
},
{
id: -2,
name: 'Workbench',
description: 'A place for you to work with tools, for simple things',
emoji: '🛠️',
type: 'plain',
maxStack: 1,
untradable: false
},
{
id: -3,
name: 'Pebble',
description: 'If you get 5 of them you will instantly ! !!!',
emoji: '🪨',
type: 'plain',
maxStack: 64,
untradable: false
}
];
export const behaviors: Behavior[] = [
{
name: 'heal',
description: 'Heals the user by `behaviorValue`',
itemType: 'consumable',
action: async (item, user) => {
// todo
return false;
}
}
];
export const craftingStations: CraftingStation[] = [
{
key: 'forage',
name: 'Forage',
description: 'Pick up various sticks and stones from the forest',
emoji: '🌲',
cooldown: 60 * 5,
formatRecipe: (_inputs, _requirements, outputs) => `${outputs.map(i => formatItems(i.item, i.quantity) + '?').join(' ')}`,
manipulateResults: (outputs) =>
outputs.map(o => ({item: o.item, quantity: Math.floor(o.quantity * Math.random())})).filter(o => o.quantity !== 0)
},
{
key: 'hand',
name: 'Hand',
description: 'You can use your hands to make a small assortment of things',
emoji: '✋'
},
{
key: 'workbench',
name: 'Workbench',
description: 'A place for you to work with tools, for simple things',
emoji: '🛠️',
requires: getDefaultItem(DefaultItems.WORKBENCH)
}
];
export const recipes: Recipe[] = [
{
station: 'forage',
inputs: [],
requirements: [],
outputs: [
{ item: getDefaultItem(DefaultItems.PEBBLE), quantity: 2 }
]
},
{
station: 'workbench',
inputs: [
{ item: getDefaultItem(DefaultItems.PEBBLE), quantity: 2 }
],
requirements: [],
outputs: [
{ item: getDefaultItem(DefaultItems.WORKBENCH), quantity: 1 }
]
}
];

View File

@ -1,10 +1,11 @@
import { AutocompleteInteraction, User } from 'discord.js'; import { AutocompleteInteraction, User } from 'discord.js';
import { CustomItem, ItemInventory, db } from './db'; import { CustomItem, ItemInventory, db } from '../db';
import { DefaultItems, defaultItems } from './data';
type DefaultItem = Omit<CustomItem, 'guild'>; // uses negative IDs export type DefaultItem = Omit<CustomItem, 'guild'>; // uses negative IDs
type Item = DefaultItem | CustomItem; export type Item = DefaultItem | CustomItem;
interface Behavior { export interface Behavior {
name: string, name: string,
description: string, description: string,
itemType: 'plain' | 'weapon' | 'consumable', itemType: 'plain' | 'weapon' | 'consumable',
@ -16,28 +17,32 @@ interface Behavior {
action?: (item: Item, user: User) => Promise<boolean> action?: (item: Item, user: User) => Promise<boolean>
} }
export const defaultItems: DefaultItem[] = [ export interface Items {
{ item: Item,
'id': -1, quantity: number
'name': 'Coin', }
'emoji': '🪙',
'type': 'plain',
'maxStack': 9999,
'untradable': false
}
];
export const behaviors: Behavior[] = [ const defaultFormatRecipe = (inputs: Items[], requirements: Items[], outputs: Items[]) =>
{ `${formatItemsArray(inputs)}${requirements.length === 0 ? '' : ` w/ ${formatItemsArray(requirements)}`} => ${formatItemsArray(outputs)}`;
'name': 'heal',
'description': 'Heals the user by `behaviorValue`', export interface CraftingStation {
'itemType': 'consumable', key: string,
'action': async (item: Item, user: User) => { name: string,
// todo description: string,
return false; emoji: string,
} requires?: Item,
} // in seconds
]; cooldown?: number,
formatRecipe?: (inputs: Items[], requirements: Items[], outputs: Items[]) => string,
manipulateResults?: (outputs: Items[]) => Items[]
}
export interface Recipe {
station: string,
inputs: Items[],
requirements: Items[],
outputs: Items[]
}
export async function getCustomItem(id: number) { export async function getCustomItem(id: number) {
return await db<CustomItem>('customItems') return await db<CustomItem>('customItems')
@ -45,11 +50,16 @@ export async function getCustomItem(id: number) {
.first(); .first();
} }
export function getDefaultItem(id: DefaultItems): Item
export function getDefaultItem(id: number): Item | undefined {
return defaultItems.find(item => Math.abs(item.id) === Math.abs(id));
}
export async function getItem(id: number): Promise<Item | undefined> { export async function getItem(id: number): Promise<Item | undefined> {
if (id >= 0) { if (id >= 0) {
return await getCustomItem(id); return await getCustomItem(id);
} else { } else {
return defaultItems.find(item => item.id === id); return getDefaultItem(id);
} }
} }
@ -59,9 +69,9 @@ export async function getItemQuantity(user: string, itemID: number) {
.where('user', user) .where('user', user)
.first()) .first())
|| { || {
'user': user, user: user,
'item': itemID, item: itemID,
'quantity': 0 quantity: 0
}; };
} }
@ -75,7 +85,7 @@ export async function giveItem(user: string, item: Item, quantity = 1) {
if (storedItem) { if (storedItem) {
inv = await db<ItemInventory>('itemInventories') inv = await db<ItemInventory>('itemInventories')
.update({ .update({
'quantity': db.raw('MIN(quantity + ?, ?)', [quantity, getMaxStack(item)]) quantity: db.raw('MIN(quantity + ?, ?)', [quantity, getMaxStack(item)])
}) })
.limit(1) .limit(1)
.where('user', user) .where('user', user)
@ -84,9 +94,9 @@ export async function giveItem(user: string, item: Item, quantity = 1) {
} else { } else {
inv = await db<ItemInventory>('itemInventories') inv = await db<ItemInventory>('itemInventories')
.insert({ .insert({
'user': user, user: user,
'item': Math.min(item.id, getMaxStack(item)), item: Math.min(item.id, getMaxStack(item)),
'quantity': quantity quantity: quantity
}) })
.returning('*'); .returning('*');
} }
@ -105,6 +115,9 @@ export function formatItem(item: Item | undefined) {
export function formatItems(item: Item | undefined, quantity: number) { export function formatItems(item: Item | undefined, quantity: number) {
return `${quantity}x ${formatItem(item)}`; return `${quantity}x ${formatItem(item)}`;
} }
export function formatItemsArray(items: Items[]) {
return items.map(i => formatItems(i.item, i.quantity)).join(' ');
}
export async function itemAutocomplete(interaction: AutocompleteInteraction) { export async function itemAutocomplete(interaction: AutocompleteInteraction) {
const focused = interaction.options.getFocused(); const focused = interaction.options.getFocused();