items part 1
This commit is contained in:
@@ -5,20 +5,18 @@ import type { CommandData } from "./index";
|
||||
import type { User } from "../db";
|
||||
import config from "../config.json";
|
||||
import { get_user } from "../db";
|
||||
import { BotError } from "./error";
|
||||
import { BotError } from "./common/error";
|
||||
|
||||
async function run(interaction: ChatInputCommandInteraction, user: User) {
|
||||
const options = interaction.options;
|
||||
const target = (await options.get("target"))?.user;
|
||||
let embeds = [];
|
||||
let bal_embed = new EmbedBuilder();
|
||||
let bal_target = target ?? interaction.user;
|
||||
let bal_user = target ? await get_user(target.id) : user;
|
||||
if (!bal_user) throw new BotError("Target is not registered"); //must be target
|
||||
bal_embed.setTitle(`${bal_target.tag}'s Balance`);
|
||||
bal_embed.setDescription(`${bal_user.balance} ${ bal_user.balance === 1 ? config.currency : config.currency_plural }`);
|
||||
embeds.push(bal_embed);
|
||||
return await interaction.editReply({ embeds });
|
||||
return await interaction.editReply({ embeds: [ bal_embed ] });
|
||||
}
|
||||
|
||||
const data: CommandData = {
|
||||
|
||||
@@ -3,9 +3,10 @@ import type { ChatInputCommandInteraction } from "discord.js";
|
||||
import type { CommandData } from "./index";
|
||||
import type { User } from "../db";
|
||||
import { get_user, add_balance, sub_balance } from "../db";
|
||||
import { BotError } from "./error";
|
||||
import { BotError } from "./common/error";
|
||||
|
||||
async function run(interaction: ChatInputCommandInteraction, _user: User) {
|
||||
async function run(interaction: ChatInputCommandInteraction) {
|
||||
await interaction.deferReply();
|
||||
const options = interaction.options;
|
||||
const target_id: string = (await options.get("target")).user.id;
|
||||
const amount: number = (await options.get("amount")).value as number;
|
||||
@@ -24,7 +25,7 @@ async function run(interaction: ChatInputCommandInteraction, _user: User) {
|
||||
const data: CommandData = {
|
||||
name: "change_bal",
|
||||
description: "Change a user's balance",
|
||||
registered_only: true,
|
||||
registered_only: false,
|
||||
ephemeral: false,
|
||||
admin_only: true,
|
||||
run,
|
||||
|
||||
37
commands/change_item_balance.ts
Normal file
37
commands/change_item_balance.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { ChatInputCommandInteraction } from "discord.js";
|
||||
|
||||
import type { CommandData } from "./index";
|
||||
import type { Items, StoreItem, User } from "../db";
|
||||
import { get_item, get_user, add_item_to_user, sub_item_to_user } from "../db";
|
||||
import { BotError } from "./common/error";
|
||||
import { item_name_autocomplete } from "./common/autocompletes";
|
||||
|
||||
async function run(interaction: ChatInputCommandInteraction) {
|
||||
await interaction.deferReply();
|
||||
const options = interaction.options;
|
||||
const name: string = (await options.get("name")).value as string;
|
||||
const quantity: number = (await options.get("quantity")).value as number;
|
||||
const target = (await options.get("target")).user;
|
||||
if (!(await get_user(target.id))) throw new BotError("Target is not registered");
|
||||
if (!(await get_item(name))) throw new BotError("No such item exists");
|
||||
if (quantity < 0) {
|
||||
if (!(await sub_item_to_user(target.id, name, -quantity))) throw new BotError("Cannot remove more items from that user's inventory than they actually have");
|
||||
return await interaction.editReply(`Removed ${-quantity} of item \`${name}\` to <@${target.id}>`);
|
||||
} else {
|
||||
await add_item_to_user(target.id, name, quantity);
|
||||
return await interaction.editReply(`Added ${quantity} of item \`${name}\` to <@${target.id}>`);
|
||||
}
|
||||
}
|
||||
|
||||
const data: CommandData = {
|
||||
name: "change_item_balance",
|
||||
description: "Add/remove items from a user (admin only)",
|
||||
registered_only: false,
|
||||
ephemeral: false,
|
||||
admin_only: true,
|
||||
run,
|
||||
autocomplete: item_name_autocomplete, //autocompletes for the "name" option
|
||||
};
|
||||
|
||||
export default data;
|
||||
|
||||
12
commands/common/autocompletes.ts
Normal file
12
commands/common/autocompletes.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import type { AutocompleteInteraction } from "discord.js";
|
||||
|
||||
import { get_all_items } from "../../db";
|
||||
|
||||
export async function item_name_autocomplete(interaction: AutocompleteInteraction) {
|
||||
return await interaction.respond((await get_all_items()).filter(
|
||||
(item) => item.name.startsWith(interaction.options.getFocused(true).value)
|
||||
).map(
|
||||
(item) => ({ name: item.name, value: item.name })
|
||||
));
|
||||
}
|
||||
|
||||
46
commands/create_item.ts
Normal file
46
commands/create_item.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
//also: edit_item, delete_item, store, buy, use_item, (admin: /take_item, /add_item)
|
||||
|
||||
import type { ChatInputCommandInteraction } from "discord.js";
|
||||
|
||||
import type { CommandData } from "./index";
|
||||
import type { Items, StoreItem, User } from "../db";
|
||||
import { create_item, get_item } from "../db";
|
||||
import { BotError } from "./common/error";
|
||||
|
||||
async function run(interaction: ChatInputCommandInteraction) {
|
||||
await interaction.deferReply();
|
||||
const options = interaction.options;
|
||||
const name: string = (await options.get("name")).value as string;
|
||||
const price: number = (await options.get("price")).value as number;
|
||||
const description: string = (await options.get("description")).value as string;
|
||||
const usable: boolean = ((await options.get("usable"))?.value ?? true) as boolean;
|
||||
if (name.includes("`")) throw new BotError("Item name cannot include the ` character"); //don't want to escape shit
|
||||
//to add multiple roles, people will have to use /edit_item, I guess? augh
|
||||
const required_role = (await options.get("required_role"))?.role;
|
||||
if (price < 0) throw new BotError("Price cannot be negative");
|
||||
//name and description char limits (based on discord embed field name/value limits)
|
||||
if (name.length > 200) throw new BotError("Item name cannot be more than 256 characters"); //true limit is 256 (still might error if currency name is more than like 50 characters, or price is absurdly huge)
|
||||
if (description.length > 900) throw new BotError("Item description cannot be more than 1024 characters"); //true limit is 1024 but we want some margin for other info
|
||||
if (await get_item(name)) throw new BotError("Item with that name already exists. Use a different name, or /edit_item or /delete_item");
|
||||
const store_item: StoreItem = {
|
||||
name,
|
||||
price,
|
||||
description,
|
||||
roles_required: required_role ? [required_role.id] : [],
|
||||
usable,
|
||||
};
|
||||
await create_item(store_item);
|
||||
return await interaction.editReply("Item created");
|
||||
}
|
||||
|
||||
const data: CommandData = {
|
||||
name: "create_item",
|
||||
description: "Create item",
|
||||
registered_only: false,
|
||||
ephemeral: false,
|
||||
admin_only: true,
|
||||
run,
|
||||
};
|
||||
|
||||
export default data;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { ChatInputCommandInteraction, GuildMember } from "discord.js";
|
||||
import type { AutocompleteInteraction, ChatInputCommandInteraction, GuildMember } from "discord.js";
|
||||
import { EmbedBuilder } from "discord.js";
|
||||
|
||||
import type { User } from "../db";
|
||||
import { get_user } from "../db";
|
||||
import { BotError } from "./error";
|
||||
import { BotError } from "./common/error";
|
||||
import config from "../config.json";
|
||||
|
||||
import say from "./say";
|
||||
@@ -12,6 +12,10 @@ import register_user from "./register_user";
|
||||
import bal from "./bal";
|
||||
import change_bal from "./change_bal";
|
||||
import transfer from "./transfer";
|
||||
import items from "./items";
|
||||
import create_item from "./create_item";
|
||||
import store from "./store";
|
||||
import change_item_balance from "./change_item_balance";
|
||||
|
||||
export interface CommandData {
|
||||
name: string;
|
||||
@@ -20,17 +24,16 @@ export interface CommandData {
|
||||
ephemeral: boolean;
|
||||
admin_only: boolean;
|
||||
run: (interaction: ChatInputCommandInteraction, user?: User) => Promise<any>;
|
||||
autocomplete?: (interaction: AutocompleteInteraction) => Promise<any>;
|
||||
};
|
||||
|
||||
const commands: CommandData[] = [say, roll, register_user, bal, change_bal, transfer];
|
||||
const commands: CommandData[] = [say, roll, register_user, bal, change_bal, transfer, items, create_item, store, change_item_balance];
|
||||
|
||||
function is_admin(interaction: ChatInputCommandInteraction): boolean {
|
||||
return (interaction.member as GuildMember).roles.cache.some((r) => r.id === config.admin_role);
|
||||
}
|
||||
|
||||
export default async function run(interaction: ChatInputCommandInteraction) {
|
||||
const name = interaction.commandName;
|
||||
|
||||
async function run(interaction: ChatInputCommandInteraction, found: CommandData, name: string) {
|
||||
//help command is "auto-generated"
|
||||
if (name === "help") {
|
||||
//max of 25 fields per embed, so if too many commands, this section needs a rewrite
|
||||
@@ -58,7 +61,6 @@ export default async function run(interaction: ChatInputCommandInteraction) {
|
||||
return await interaction.reply({ embeds, ephemeral: true });
|
||||
}
|
||||
|
||||
const found = commands.find((c) => c.name === name);
|
||||
try {
|
||||
//admin stuff should be ideally handled by register.ts, but this is a fallback
|
||||
if (found.admin_only && !is_admin(interaction)) throw new BotError("Admin permission needed to run that command");
|
||||
@@ -87,3 +89,14 @@ export default async function run(interaction: ChatInputCommandInteraction) {
|
||||
}
|
||||
}
|
||||
|
||||
export default async function handle_interaction(interaction: AutocompleteInteraction | ChatInputCommandInteraction) {
|
||||
const name = interaction.commandName;
|
||||
const found = commands.find((c) => c.name === name);
|
||||
|
||||
if (interaction.isChatInputCommand()) {
|
||||
return await run(interaction, found, name);
|
||||
} else if (interaction.isAutocomplete()) {
|
||||
return await found.autocomplete(interaction);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
89
commands/items.ts
Normal file
89
commands/items.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import type { ChatInputCommandInteraction } from "discord.js";
|
||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
|
||||
|
||||
import type { CommandData } from "./index";
|
||||
import type { Items, User } from "../db";
|
||||
import { get_user } from "../db";
|
||||
import { BotError } from "./common/error";
|
||||
|
||||
async function run(interaction: ChatInputCommandInteraction, user: User) {
|
||||
function gen_items_embed(items_target, items: Items, page: number, pages: number) {
|
||||
let items_embed = new EmbedBuilder();
|
||||
items_embed.setTitle(`${items_target.tag} Items (Page ${page}/${pages})`);
|
||||
if (Object.keys(items).length === 0) {
|
||||
items_embed.setDescription("No items");
|
||||
} else {
|
||||
items_embed.addFields(
|
||||
Object.keys(items)
|
||||
.slice((page - 1) * 10, page * 10)
|
||||
.map(
|
||||
(item_name) =>
|
||||
({
|
||||
name: item_name,
|
||||
value: String(items[item_name]),
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
return items_embed;
|
||||
}
|
||||
function gen_action_row(page: number, pages: number) {
|
||||
let action_row = new ActionRowBuilder<ButtonBuilder>();
|
||||
let action_prev = new ButtonBuilder()
|
||||
.setCustomId(String(page - 1))
|
||||
.setLabel("Prev")
|
||||
.setEmoji("⬅️")
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setDisabled(page - 1 === 0);
|
||||
let action_next = new ButtonBuilder()
|
||||
.setCustomId(String(page + 1))
|
||||
.setLabel("Next")
|
||||
.setEmoji("➡️")
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setDisabled(page + 1 > pages);
|
||||
action_row.addComponents(action_prev, action_next);
|
||||
return action_row;
|
||||
}
|
||||
const options = interaction.options;
|
||||
const target = (await options.get("target"))?.user;
|
||||
let items_target = target ?? interaction.user;
|
||||
let items_user = target ? await get_user(target.id) : user;
|
||||
if (!items_user) throw new BotError("Target is not registered"); //must be target
|
||||
//filter out items which the user owns 0 of, but is in their items record thing
|
||||
const items: Items = Object.keys(items_user.items).filter((item) => items_user.items[item] > 0).reduce((accum, item) => {
|
||||
accum[item] = items_user.items[item];
|
||||
return accum;
|
||||
}, {});
|
||||
//list items in items embed, if too many, make sure pagination buttons work
|
||||
const pages: number = Math.ceil(Object.keys(items).length / 10) || 1; //min of 1
|
||||
let page = 1;
|
||||
const dresp = await interaction.editReply({
|
||||
embeds: [ gen_items_embed(items_target, items, page, pages) ],
|
||||
components: [ gen_action_row(page, pages) ],
|
||||
});
|
||||
while (true) {
|
||||
try {
|
||||
let dresp_bin = await dresp.awaitMessageComponent({ filter: (bin) => bin.user.id === interaction.user.id, time: 60000 }); //bin = button interaction
|
||||
page = Number(dresp_bin.customId);
|
||||
await dresp_bin.update({
|
||||
embeds: [ gen_items_embed(items_target, items, page, pages) ],
|
||||
components: [ gen_action_row(page, pages) ],
|
||||
});
|
||||
} catch (_) {
|
||||
//errors when people stop pressing the button
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const data: CommandData = {
|
||||
name: "items",
|
||||
description: "See you or someone else's items",
|
||||
registered_only: true,
|
||||
ephemeral: false,
|
||||
admin_only: false,
|
||||
run,
|
||||
};
|
||||
|
||||
export default data;
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { ChatInputCommandInteraction } from "discord.js";
|
||||
|
||||
import type { CommandData } from "./index";
|
||||
import { get_user, add_new_user } from "../db";
|
||||
import { BotError } from "./error";
|
||||
import { BotError } from "./common/error";
|
||||
|
||||
async function run(interaction: ChatInputCommandInteraction) {
|
||||
await interaction.deferReply();
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { ChatInputCommandInteraction } from "discord.js";
|
||||
import { randomInt } from "crypto";
|
||||
|
||||
import type { CommandData } from "./index";
|
||||
import { BotError } from "./error";
|
||||
import { BotError } from "./common/error";
|
||||
|
||||
const MAX_DICE: number = 100;
|
||||
const MAX_FACES: number = 9999;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { ChatInputCommandInteraction } from "discord.js";
|
||||
|
||||
import type { CommandData } from "./index";
|
||||
import { BotError } from "./error";
|
||||
import { BotError } from "./common/error";
|
||||
import { is_text_channel } from "../guards";
|
||||
|
||||
async function run(interaction: ChatInputCommandInteraction) {
|
||||
|
||||
85
commands/store.ts
Normal file
85
commands/store.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import type { ChatInputCommandInteraction } from "discord.js";
|
||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
|
||||
|
||||
import type { CommandData } from "./index";
|
||||
import type { StoreItem } from "../db";
|
||||
import config from "../config.json";
|
||||
import { get_all_items } from "../db";
|
||||
import { BotError } from "./common/error";
|
||||
|
||||
async function run(interaction: ChatInputCommandInteraction) {
|
||||
function gen_store_embed(store_items: StoreItem[], page: number, pages: number) {
|
||||
let store_embed = new EmbedBuilder();
|
||||
store_embed.setTitle(`Store (Page ${page}/${pages})`);
|
||||
//
|
||||
if (store_items.length === 0) {
|
||||
store_embed.setDescription("No items");
|
||||
} else {
|
||||
//
|
||||
store_embed.addFields(
|
||||
store_items
|
||||
.slice((page - 1) * 10, page * 10)
|
||||
.map(
|
||||
(store_item: StoreItem) =>
|
||||
({
|
||||
name: `${store_item.name} (${store_item.price} ${ store_item.price === 1 ? config.currency : config.currency_plural })`,
|
||||
value: `${store_item.description}\nUsable: ${store_item.usable}${ store_item.roles_required.length === 0 ? "" : `\nRoles required: ${store_item.roles_required.map((role_id) => `<@&${role_id}>`).join("")}` }`,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
return store_embed;
|
||||
}
|
||||
function gen_action_row(page: number, pages: number) {
|
||||
let action_row = new ActionRowBuilder<ButtonBuilder>();
|
||||
let action_prev = new ButtonBuilder()
|
||||
.setCustomId(String(page - 1))
|
||||
.setLabel("Prev")
|
||||
.setEmoji("⬅️")
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setDisabled(page - 1 === 0);
|
||||
let action_next = new ButtonBuilder()
|
||||
.setCustomId(String(page + 1))
|
||||
.setLabel("Next")
|
||||
.setEmoji("➡️")
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setDisabled(page + 1 > pages);
|
||||
action_row.addComponents(action_prev, action_next);
|
||||
return action_row;
|
||||
}
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
const store_items: StoreItem[] = await get_all_items();
|
||||
//list items in items embed, if too many, make sure pagination buttons work
|
||||
const pages: number = Math.ceil(store_items.length / 10) || 1; //min of 1
|
||||
let page = 1;
|
||||
const dresp = await interaction.editReply({
|
||||
embeds: [ gen_store_embed(store_items, page, pages) ],
|
||||
components: [ gen_action_row(page, pages) ],
|
||||
});
|
||||
while (true) {
|
||||
try {
|
||||
let dresp_bin = await dresp.awaitMessageComponent({ filter: (bin) => bin.user.id === interaction.user.id, time: 60000 }); //bin = button interaction
|
||||
page = Number(dresp_bin.customId);
|
||||
await dresp_bin.update({
|
||||
embeds: [ gen_store_embed(store_items, page, pages) ],
|
||||
components: [ gen_action_row(page, pages) ],
|
||||
});
|
||||
} catch (_) {
|
||||
//errors when people stop pressing the button
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const data: CommandData = {
|
||||
name: "store",
|
||||
description: "See info about all items",
|
||||
registered_only: false,
|
||||
ephemeral: true,
|
||||
admin_only: false,
|
||||
run,
|
||||
};
|
||||
|
||||
export default data;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { CommandData } from "./index";
|
||||
import type { User } from "../db";
|
||||
import config from "../config.json";
|
||||
import { get_user, add_balance, sub_balance } from "../db";
|
||||
import { BotError } from "./error";
|
||||
import { BotError } from "./common/error";
|
||||
|
||||
async function run(interaction: ChatInputCommandInteraction, user: User) {
|
||||
const options = interaction.options;
|
||||
@@ -31,4 +31,3 @@ const data: CommandData = {
|
||||
|
||||
export default data;
|
||||
|
||||
|
||||
|
||||
49
db.ts
49
db.ts
@@ -18,14 +18,21 @@ client.connect().then(() => {
|
||||
|
||||
//db structure types
|
||||
|
||||
export type Items = Record<string, number>;
|
||||
|
||||
export interface StoreItem {
|
||||
name: string;
|
||||
price: number;
|
||||
description: string;
|
||||
roles_required: string[];
|
||||
usable: boolean;
|
||||
//
|
||||
};
|
||||
|
||||
export interface User {
|
||||
user: `${number}`; //discord user id
|
||||
balance: number;
|
||||
items: Record<string, number>;
|
||||
items: Items;
|
||||
//
|
||||
};
|
||||
|
||||
@@ -85,7 +92,7 @@ export async function add_item_to_user(user: string, item: string, amount: numbe
|
||||
}
|
||||
|
||||
export async function sub_item_to_user(user: string, item: string, amount: number): Promise<boolean> {
|
||||
return await users.updateOne({
|
||||
return did_update(await users.updateOne({
|
||||
user,
|
||||
[`items.${item}`]: {
|
||||
$gte: amount,
|
||||
@@ -94,8 +101,46 @@ export async function sub_item_to_user(user: string, item: string, amount: numbe
|
||||
$inc: {
|
||||
[`items.${item}`]: -amount,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
//to use when admin deletes an item
|
||||
async function del_item_from_all_users(item: string) {
|
||||
return await users.updateMany({
|
||||
[`items.${item}`]: {
|
||||
$gte: 1,
|
||||
},
|
||||
}, {
|
||||
$set: {
|
||||
[`items.${item}`]: 0,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
//store collection db functions
|
||||
//so, "Submarine", "submarine", and "suBMARine" are different items. deal with it
|
||||
|
||||
export async function get_all_items(): Promise<StoreItem[]> {
|
||||
return await (await store.find()).toArray();
|
||||
}
|
||||
|
||||
export async function get_item(item: string): Promise<StoreItem[]> {
|
||||
return await store.findOne({ name: item });
|
||||
}
|
||||
|
||||
export async function create_item(store_item: StoreItem) {
|
||||
return await store.insertOne(store_item);
|
||||
}
|
||||
|
||||
//assume name cannot be edited
|
||||
export async function edit_item(store_item: StoreItem) {
|
||||
return await store.updateOne({ name: store_item.name }, store_item);
|
||||
}
|
||||
|
||||
export async function delete_item(item: string) {
|
||||
await del_item_from_all_users(item);
|
||||
return await store.deleteOne({ name: item });
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
|
||||
7
index.ts
7
index.ts
@@ -4,7 +4,7 @@ import { config } from "dotenv";
|
||||
config();
|
||||
|
||||
import {} from "./db";
|
||||
import run from "./commands";
|
||||
import handle_interaction from "./commands";
|
||||
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
|
||||
|
||||
@@ -14,9 +14,8 @@ client.on("ready", async () => {
|
||||
});
|
||||
|
||||
client.on("interactionCreate", async (interaction: BaseInteraction) => {
|
||||
//
|
||||
if (interaction.isChatInputCommand()) {
|
||||
return await run(interaction);
|
||||
if (interaction.isChatInputCommand() || interaction.isAutocomplete()) {
|
||||
return await handle_interaction(interaction);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
81
register.ts
81
register.ts
@@ -95,7 +95,7 @@ const commands = [
|
||||
{
|
||||
type: 4,
|
||||
name: "amount",
|
||||
description: "Amount to add/subtract",
|
||||
description: "Amount to add/subtract (negative allowed)",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
@@ -124,6 +124,85 @@ const commands = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "items",
|
||||
description: "See you or someone else's items",
|
||||
options: [
|
||||
{
|
||||
type: 6,
|
||||
name: "target",
|
||||
description: "The user to check the items of",
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "create_item",
|
||||
description: "Create item (admin only)",
|
||||
options: [
|
||||
{
|
||||
type: 3,
|
||||
name: "name",
|
||||
description: "Name of the item",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
type: 4,
|
||||
name: "price",
|
||||
description: "Price of the item",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
type: 3,
|
||||
name: "description",
|
||||
description: "Description of the item",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
type: 5,
|
||||
name: "usable",
|
||||
description: "Whether it can be /use'd (default: true)",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
type: 8,
|
||||
name: "required_role",
|
||||
description: "Roles that are required to buy this item. /edit_item to add multiple",
|
||||
required: false,
|
||||
},
|
||||
//
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "store",
|
||||
description: "See info about all items",
|
||||
options: [],
|
||||
},
|
||||
{
|
||||
name: "change_item_balance",
|
||||
description: "Add/remove items from a user",
|
||||
options: [
|
||||
{
|
||||
type: 3,
|
||||
name: "name",
|
||||
description: "Name of the item",
|
||||
required: true,
|
||||
autocomplete: true,
|
||||
},
|
||||
{
|
||||
type: 4,
|
||||
name: "quantity",
|
||||
description: "Amount to add/subtract (negative allowed)",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
type: 6,
|
||||
name: "target",
|
||||
description: "The user to check the items of",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
(new REST().setToken(process.env.DISCORD_TOKEN)).put(Routes.applicationCommands(process.env.CLIENT_ID), { body: commands }).then(() => console.log("Finished reloading slash commands"));
|
||||
|
||||
Reference in New Issue
Block a user