Merge pull request #17 from keanuplayz/dev

Ported over the eco command from TravBot 2
This commit is contained in:
WatDuhHekBro 2020-12-15 02:30:24 -06:00 committed by GitHub
commit eeed9766b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 512 additions and 301 deletions

View File

@ -1,41 +1,42 @@
{
"name": "d.js-v12-bot",
"version": "0.0.1",
"description": "A Discord bot built on Discord.JS v12",
"main": "dist/index.js",
"private": true,
"dependencies": {
"chalk": "^4.1.0",
"discord.js": "^12.4.0",
"discord.js-lavalink-lib": "^0.1.7",
"inquirer": "^7.3.3",
"moment": "^2.29.1",
"ms": "^2.1.2",
"os": "^0.1.1"
},
"devDependencies": {
"@types/inquirer": "^6.5.0",
"@types/mocha": "^8.0.3",
"@types/ms": "^0.7.31",
"@types/node": "^14.14.2",
"@types/ws": "^7.2.7",
"mocha": "^8.2.0",
"prettier": "2.1.2",
"ts-node": "^9.0.0",
"tsc-watch": "^4.2.9",
"typescript": "^3.9.7"
},
"scripts": {
"build": "tsc && npm prune --production",
"start": "node dist/index.js",
"once": "tsc && npm start",
"dev": "tsc-watch --onSuccess \"node dist/index.js dev\"",
"test": "mocha --require ts-node/register --extension ts --recursive"
},
"keywords": [
"discord.js",
"bot"
],
"author": "Keanu Timmermans",
"license": "MIT"
}
{
"name": "d.js-v12-bot",
"version": "0.0.1",
"description": "A Discord bot built on Discord.JS v12",
"main": "dist/index.js",
"private": true,
"dependencies": {
"chalk": "^4.1.0",
"discord.js": "^12.4.0",
"discord.js-lavalink-lib": "^0.1.7",
"inquirer": "^7.3.3",
"moment": "^2.29.1",
"ms": "^2.1.2",
"os": "^0.1.1"
},
"devDependencies": {
"@types/inquirer": "^6.5.0",
"@types/mocha": "^8.0.3",
"@types/ms": "^0.7.31",
"@types/node": "^14.14.2",
"@types/ws": "^7.2.7",
"mocha": "^8.2.0",
"prettier": "2.1.2",
"ts-node": "^9.0.0",
"tsc-watch": "^4.2.9",
"typescript": "^3.9.7"
},
"scripts": {
"build": "tsc && npm prune --production",
"start": "node dist/index.js",
"once": "tsc && npm start",
"dev": "tsc-watch --onSuccess \"node dist/index.js dev\"",
"test": "mocha --require ts-node/register --extension ts --recursive",
"format": "prettier --write **/*"
},
"keywords": [
"discord.js",
"bot"
],
"author": "Keanu Timmermans",
"license": "MIT"
}

View File

@ -10,4 +10,5 @@ module.exports = {
bracketSpacing: true,
jsxBracketSameLine: true,
arrowParens: 'always',
endOfLine: 'auto',
};

35
src/commands/fun/eco.ts Normal file
View File

@ -0,0 +1,35 @@
import Command from '../../core/command';
import { isAuthorized, getMoneyEmbed } from './subcommands/eco-utils';
import { DailyCommand, PayCommand, GuildCommand } from './subcommands/eco-core';
import { BuyCommand, ShopCommand } from './subcommands/eco-shop';
export default new Command({
description: 'Economy command for Monika.',
async run({ guild, channel, author }) {
if (isAuthorized(guild, channel)) channel.send(getMoneyEmbed(author));
},
subcommands: {
daily: DailyCommand,
pay: PayCommand,
guild: GuildCommand,
buy: BuyCommand,
shop: ShopCommand,
},
user: new Command({
description:
'See how much money someone else has by using their user ID or pinging them.',
async run({ guild, channel, args }) {
if (isAuthorized(guild, channel)) channel.send(getMoneyEmbed(args[0]));
},
}),
any: new Command({
description: 'See how much money someone else has by using their username.',
async run({ guild, channel, args, callMemberByUsername, message }) {
if (isAuthorized(guild, channel))
callMemberByUsername(message, args.join(' '), (member) => {
channel.send(getMoneyEmbed(member.user));
});
},
}),
});

View File

@ -0,0 +1,180 @@
import Command from '../../../core/command';
import $ from '../../../core/lib';
import { Storage } from '../../../core/structures';
import { isAuthorized, getMoneyEmbed, getSendEmbed } from './eco-utils';
export const DailyCommand = new Command({
description:
'Pick up your daily Mons. The cooldown is per user and every 22 hours to allow for some leeway.',
async run({ author, channel, guild }) {
if (isAuthorized(guild, channel)) {
const user = Storage.getUser(author.id);
const now = Date.now();
if (now - user.lastReceived >= 79200000) {
user.money++;
user.lastReceived = now;
Storage.save();
channel.send({
embed: {
title: 'Daily Reward',
description: 'You received 1 Mon!',
color: 0xf1c40f,
},
});
} else
channel.send({
embed: {
title: 'Daily Reward',
description: `It's too soon to pick up your daily credits. You have about ${(
(user.lastReceived + 79200000 - now) /
3600000
).toFixed(1)} hours to go.`,
color: 0xf1c40f,
},
});
}
},
});
export const GuildCommand = new Command({
description: 'See the richest players.',
async run({ guild, channel, client }) {
if (isAuthorized(guild, channel)) {
const users = Storage.users;
const ids = Object.keys(users);
ids.sort((a, b) => users[b].money - users[a].money);
const fields = [];
for (let i = 0, limit = Math.min(10, ids.length); i < limit; i++) {
const id = ids[i];
const user = await client.users.fetch(id);
fields.push({
name: `#${i + 1}. ${user.username}#${user.discriminator}`,
value: $(users[id].money).pluralise('credit', 's'),
});
}
channel.send({
embed: {
title: 'Top 10 Richest Players',
color: '#ffff00',
fields: fields,
},
});
}
},
});
export const PayCommand = new Command({
description: 'Send money to someone.',
usage: '<user> <amount>',
run: 'Who are you sending this money to?',
user: new Command({
run: "You need to enter an amount you're sending!",
number: new Command({
async run({ args, author, channel, guild }): Promise<any> {
if (isAuthorized(guild, channel)) {
const amount = Math.floor(args[1]);
const sender = Storage.getUser(author.id);
const target = args[0];
const receiver = Storage.getUser(target.id);
if (amount <= 0)
return channel.send('You must send at least one Mon!');
else if (sender.money < amount)
return channel.send(
"You don't have enough Mons for that.",
getMoneyEmbed(author),
);
else if (target.id === author.id)
return channel.send("You can't send Mons to yourself!");
else if (target.bot && process.argv[2] !== 'dev')
return channel.send("You can't send Mons to a bot!");
sender.money -= amount;
receiver.money += amount;
Storage.save();
return channel.send(getSendEmbed(author, target, amount));
}
},
}),
}),
number: new Command({
run: 'You must use the format `money send <user> <amount>`!',
}),
any: new Command({
async run({ args, author, channel, guild, prompt }) {
if (isAuthorized(guild, channel)) {
const last = args.pop();
if (!/\d+/g.test(last) && args.length === 0)
return channel.send("You need to enter an amount you're sending!");
const amount = Math.floor(last);
const sender = Storage.getUser(author.id);
if (amount <= 0)
return channel.send('You must send at least one credit!');
else if (sender.money < amount)
return channel.send(
"You don't have enough money to do that!",
getMoneyEmbed(author),
);
else if (!guild)
return channel.send(
'You have to use this in a server if you want to send money with a username!',
);
const username = args.join(' ');
const member = (
await guild.members.fetch({
query: username,
limit: 1,
})
).first();
if (!member)
return channel.send(
`Couldn't find a user by the name of \`${username}\`! If you want to send money to someone in a different server, you have to use their user ID!`,
);
else if (member.user.id === author.id)
return channel.send("You can't send money to yourself!");
else if (member.user.bot && process.argv[2] !== 'dev')
return channel.send("You can't send money to a bot!");
const target = member.user;
return prompt(
await channel.send(
`Are you sure you want to send ${$(amount).pluralise(
'credit',
's',
)} to this person?\n*(This message will automatically be deleted after 10 seconds.)*`,
{
embed: {
color: '#ffff00',
author: {
name: `${target.username}#${target.discriminator}`,
icon_url: target.displayAvatarURL({
format: 'png',
dynamic: true,
}),
},
},
},
),
author.id,
() => {
const receiver = Storage.getUser(target.id);
sender.money -= amount;
receiver.money += amount;
Storage.save();
channel.send(getSendEmbed(author, target, amount));
},
);
}
},
}),
});

View File

@ -0,0 +1,73 @@
import { Message } from 'discord.js';
import $ from '../../../core/lib';
export interface ShopItem {
cost: number;
title: string;
description: string;
usage: string;
run(message: Message, cost: number, amount: number): void;
}
export const ShopItems: ShopItem[] = [
{
cost: 1,
title: 'Hug',
description: 'Hug Monika.',
usage: 'hug',
run(message, cost) {
message.channel.send(
`Transaction of ${cost} Mon completed successfully. <@394808963356688394>`,
);
},
},
{
cost: 2,
title: 'Handholding',
description: "Hold Monika's hand.",
usage: 'handhold',
run(message, cost) {
message.channel.send(
`Transaction of ${cost} Mons completed successfully. <@394808963356688394>`,
);
},
},
{
cost: 1,
title: 'Cute',
description: 'Calls Monika cute.',
usage: 'cute',
run(message) {
message.channel.send('<:MoniCheeseBlushRed:637513137083383826>');
},
},
{
cost: 3,
title: 'Laser Bridge',
description: 'Buys what is technically a laser bridge.',
usage: 'laser bridge',
run(message) {
message.channel.send($(lines).random(), {
files: [
{
attachment:
'https://raw.githubusercontent.com/keanuplayz/TravBot/dev/assets/TheUltimateLaser.gif',
},
],
});
},
},
];
const lines = [
"It's technically a laser bridge. No refunds.",
'You want a laser bridge? You got one!',
"Now what'd they say about building bridges... Oh wait, looks like I nuked the planet again. Whoops!",
'I saw this redhead the other day who was so excited to buy what I was selling. Needless to say, she was not very happy with me afterward.',
"Sorry, but you'll have to wait until the Laser Bridge Builder leaves early access.",
'Thank you for your purchase! For you see, this is the legendary laser of obliteration that has been defended and preserved for countless generations!',
'They say that a certain troll dwells under this laser bridge, waiting for an unlucky person to fall for th- I mean- Thank you for your purchase!',
"Buy?! Hah! How about our new rental service for just under $9.99 a month? But wait, there's more! For just $99.99, you can rent this laser bridge for an entire year and save 16.67% as opposed to renting it monthly!",
'Good choice. Owning a laser bridge is the penultimate experience that all true seekers strive for!',
'I can already imagine the reviews...\n"9/10 needs more lasers"',
];

View File

@ -0,0 +1,100 @@
import Command from '../../../core/command';
import $ from '../../../core/lib';
import { Storage, getPrefix } from '../../../core/structures';
import { isAuthorized, getMoneyEmbed, getSendEmbed } from './eco-utils';
import { ShopItems, ShopItem } from './eco-shop-items';
import { EmbedField } from 'discord.js';
export const ShopCommand = new Command({
description: 'Displays the list of items you can buy in the shop.',
async run({ guild, channel, author }) {
if (isAuthorized(guild, channel)) {
function getShopEmbed(selection: ShopItem[], title = 'Shop') {
const fields: EmbedField[] = [];
for (const item of selection)
fields.push({
name: `**${item.title}** (${getPrefix(guild)}eco buy ${
item.usage
})`,
value: `${item.description} Costs ${$(item.cost).pluralise(
'Mon',
's',
)}.`,
inline: false,
});
return {
embed: {
color: 0xf1c40f,
title: title,
fields: fields,
footer: {
text: 'Mon Shop | TravBot Services',
},
},
};
}
// In case there's just one page, omit unnecessary details.
if (ShopItems.length <= 5) channel.send(getShopEmbed(ShopItems));
else {
const shopPages = $(ShopItems).split(5);
const pageAmount = shopPages.length;
const msg = await channel.send(
getShopEmbed(shopPages[0], `Shop (Page 1 of ${pageAmount})`),
);
$.paginate(msg, author.id, pageAmount, (page) => {
msg.edit(
getShopEmbed(
shopPages[page],
`Shop (Page ${page + 1} of ${pageAmount})`,
),
);
});
}
}
},
});
export const BuyCommand = new Command({
description: 'Buys an item from the shop.',
usage: '<item>',
async run({ guild, channel, args, message, author }) {
if (isAuthorized(guild, channel)) {
let found = false;
let amount = 1; // The amount the user is buying.
// For now, no shop items support being bought multiple times. Uncomment these 2 lines when it's supported/needed.
//if (/\d+/g.test(args[args.length - 1]))
//amount = parseInt(args.pop());
let requested = args.join(' '); // The item the user is buying.
for (let item of ShopItems) {
if (item.usage === requested) {
const user = Storage.getUser(author.id);
const cost = item.cost * amount;
if (cost > user.money) {
channel.send('Not enough Mons!');
} else {
user.money -= cost;
Storage.save();
item.run(message, cost, amount);
}
found = true;
break;
}
}
if (!found)
channel.send(
`There's no item in the shop that goes by \`${requested}\`!`,
);
}
},
});

View File

@ -0,0 +1,81 @@
import $ from '../../../core/lib';
import { Storage } from '../../../core/structures';
import { User, Guild, TextChannel, DMChannel, NewsChannel } from 'discord.js';
export function getMoneyEmbed(user: User): object {
const profile = Storage.getUser(user.id);
return {
embed: {
color: 0xffff00,
author: {
name: user.username,
icon_url: user.displayAvatarURL({
format: 'png',
dynamic: true,
}),
},
fields: [
{
name: 'Balance',
value: $(profile.money).pluralise('credit', 's'),
},
],
},
};
}
export function getSendEmbed(
sender: User,
receiver: User,
amount: number,
): object {
return {
embed: {
color: 0xffff00,
author: {
name: sender.username,
icon_url: sender.displayAvatarURL({
format: 'png',
dynamic: true,
}),
},
title: 'Transaction',
description: `${sender.toString()} has sent ${$(amount).pluralise(
'credit',
's',
)} to ${receiver.toString()}!`,
fields: [
{
name: `Sender: ${sender.username}#${sender.discriminator}`,
value: $(Storage.getUser(sender.id).money).pluralise('credit', 's'),
},
{
name: `Receiver: ${receiver.username}#${receiver.discriminator}`,
value: $(Storage.getUser(receiver.id).money).pluralise('credit', 's'),
},
],
footer: {
text: receiver.username,
icon_url: receiver.displayAvatarURL({
format: 'png',
dynamic: true,
}),
},
},
};
}
export function isAuthorized(
guild: Guild | null,
channel: TextChannel | DMChannel | NewsChannel,
): boolean {
if (guild?.id === '637512823676600330' || process.argv[2] === 'dev')
return true;
else {
channel.send(
"Sorry, this command can only be used in Monika's emote server.",
);
return false;
}
}

View File

@ -1,260 +0,0 @@
import Command from '../core/command';
import $, { CommonLibrary } from '../core/lib';
import { Storage } from '../core/structures';
import { User } from 'discord.js';
export function getMoneyEmbed(user: User): object {
const profile = Storage.getUser(user.id);
return {
embed: {
color: 0xffff00,
author: {
name: user.username,
icon_url: user.displayAvatarURL({
format: 'png',
dynamic: true,
}),
},
fields: [
{
name: 'Balance',
value: $(profile.money).pluralise('credit', 's'),
},
],
},
};
}
function getSendEmbed(sender: User, receiver: User, amount: number): object {
return {
embed: {
color: 0xffff00,
author: {
name: sender.username,
icon_url: sender.displayAvatarURL({
format: 'png',
dynamic: true,
}),
},
title: 'Transaction',
description: `${sender.toString()} has sent ${$(amount).pluralise(
'credit',
's',
)} to ${receiver.toString()}!`,
fields: [
{
name: `Sender: ${sender.username}#${sender.discriminator}`,
value: $(Storage.getUser(sender.id).money).pluralise('credit', 's'),
},
{
name: `Receiver: ${receiver.username}#${receiver.discriminator}`,
value: $(Storage.getUser(receiver.id).money).pluralise('credit', 's'),
},
],
footer: {
text: receiver.username,
icon_url: receiver.displayAvatarURL({
format: 'png',
dynamic: true,
}),
},
},
};
}
export default new Command({
description:
'See how much money you have. Also provides other commands related to money.',
async run($: CommonLibrary): Promise<any> {
$.channel.send(getMoneyEmbed($.author));
},
subcommands: {
get: new Command({
description:
'Pick up your daily credits. The cooldown is per user and every 22 hours to allow for some leeway.',
async run($: CommonLibrary): Promise<any> {
const user = Storage.getUser($.author.id);
const now = Date.now();
if (user.lastReceived === -1) {
user.money = 100;
user.lastReceived = now;
Storage.save();
$.channel.send(
"Here's 100 credits to get started, the price of a sandwich in Rookie Harbor.",
getMoneyEmbed($.author),
);
} else if (now - user.lastReceived >= 79200000) {
user.money += 25;
user.lastReceived = now;
Storage.save();
$.channel.send(
"Here's your daily 25 credits.",
getMoneyEmbed($.author),
);
} else
$.channel.send(
`It's too soon to pick up your daily credits. You have about ${(
(user.lastReceived + 79200000 - now) /
3600000
).toFixed(1)} hours to go.`,
);
},
}),
send: new Command({
description: 'Send money to someone.',
usage: '<user> <amount>',
run: 'Who are you sending this money to?',
user: new Command({
run: "You need to enter an amount you're sending!",
number: new Command({
async run($: CommonLibrary): Promise<any> {
const amount = Math.floor($.args[1]);
const author = $.author;
const sender = Storage.getUser(author.id);
const target = $.args[0];
const receiver = Storage.getUser(target.id);
if (amount <= 0)
return $.channel.send('You must send at least one credit!');
else if (sender.money < amount)
return $.channel.send(
"You don't have enough money to do that!",
getMoneyEmbed(author),
);
else if (target.id === author.id)
return $.channel.send("You can't send money to yourself!");
else if (target.bot && process.argv[2] !== 'dev')
return $.channel.send("You can't send money to a bot!");
sender.money -= amount;
receiver.money += amount;
Storage.save();
$.channel.send(getSendEmbed(author, target, amount));
},
}),
}),
number: new Command({
run: 'You must use the format `money send <user> <amount>`!',
}),
any: new Command({
async run($: CommonLibrary): Promise<any> {
const last = $.args.pop();
if (!/\d+/g.test(last) && $.args.length === 0)
return $.channel.send(
"You need to enter an amount you're sending!",
);
const amount = Math.floor(last);
const author = $.author;
const sender = Storage.getUser(author.id);
if (amount <= 0)
return $.channel.send('You must send at least one credit!');
else if (sender.money < amount)
return $.channel.send(
"You don't have enough money to do that!",
getMoneyEmbed(author),
);
else if (!$.guild)
return $.channel.send(
'You have to use this in a server if you want to send money with a username!',
);
const username = $.args.join(' ');
const member = (
await $.guild.members.fetch({
query: username,
limit: 1,
})
).first();
if (!member)
return $.channel.send(
`Couldn't find a user by the name of \`${username}\`! If you want to send money to someone in a different server, you have to use their user ID!`,
);
else if (member.user.id === author.id)
return $.channel.send("You can't send money to yourself!");
else if (member.user.bot && process.argv[2] !== 'dev')
return $.channel.send("You can't send money to a bot!");
const target = member.user;
$.prompt(
await $.channel.send(
`Are you sure you want to send ${$(amount).pluralise(
'credit',
's',
)} to this person?\n*(This message will automatically be deleted after 10 seconds.)*`,
{
embed: {
color: '#ffff00',
author: {
name: `${target.username}#${target.discriminator}`,
icon_url: target.displayAvatarURL({
format: 'png',
dynamic: true,
}),
},
},
},
),
$.author.id,
() => {
const receiver = Storage.getUser(target.id);
sender.money -= amount;
receiver.money += amount;
Storage.save();
$.channel.send(getSendEmbed(author, target, amount));
},
);
},
}),
}),
leaderboard: new Command({
description:
'See the richest players tracked by this bot (across servers).',
async run($: CommonLibrary): Promise<any> {
const users = Storage.users;
const ids = Object.keys(users);
ids.sort((a, b) => users[b].money - users[a].money);
const fields = [];
for (let i = 0, limit = Math.min(10, ids.length); i < limit; i++) {
const id = ids[i];
const user = await $.client.users.fetch(id);
fields.push({
name: `#${i + 1}. ${user.username}#${user.discriminator}`,
value: $(users[id].money).pluralise('credit', 's'),
});
}
$.channel.send({
embed: {
title: 'Top 10 Richest Players',
color: '#ffff00',
fields: fields,
},
});
},
}),
},
user: new Command({
description:
'See how much money someone else has by using their user ID or pinging them.',
async run($: CommonLibrary): Promise<any> {
$.channel.send(getMoneyEmbed($.args[0]));
},
}),
any: new Command({
description: 'See how much money someone else has by using their username.',
async run($: CommonLibrary): Promise<any> {
$.callMemberByUsername($.message, $.args.join(' '), (member) => {
$.channel.send(getMoneyEmbed(member.user));
});
},
}),
});