TravBot-v3/src/commands/fun/modules/eco-bet.ts

170 lines
8.7 KiB
TypeScript
Raw Normal View History

import {Command, NamedCommand, confirm, poll} from "onion-lasers";
import {pluralise, parseDuration} from "../../../lib";
import {Storage} from "../../../structures";
2021-04-11 08:02:56 +00:00
import {isAuthorized, getMoneyEmbed} from "./eco-utils";
import {User} from "discord.js";
2021-01-25 22:06:12 +00:00
export const BetCommand = new NamedCommand({
2021-04-06 06:39:11 +00:00
description: "Bet your Mons with other people.",
2021-01-25 22:06:12 +00:00
usage: "<user> <amount> <duration>",
run: "Who are you betting with?",
user: new Command({
2021-04-06 06:39:11 +00:00
description: "User to bet with.",
// handles missing amount argument
2021-04-10 13:34:55 +00:00
async run({send, args, author, channel, guild}) {
if (isAuthorized(guild, channel)) {
const target = args[0];
// handle invalid target
2021-04-10 13:34:55 +00:00
if (target.id == author.id) return send("You can't bet Mons with yourself!");
else if (target.bot && process.argv[2] !== "dev") return send("You can't bet Mons with a bot!");
2021-04-10 13:34:55 +00:00
return send("How much are you betting?");
} else return;
},
2021-01-25 22:06:12 +00:00
number: new Command({
2021-04-06 06:39:11 +00:00
description: "Amount of Mons to bet.",
// handles missing duration argument
2021-04-10 13:34:55 +00:00
async run({send, args, author, channel, guild}) {
if (isAuthorized(guild, channel)) {
const sender = Storage.getUser(author.id);
const target = args[0] as User;
const receiver = Storage.getUser(target.id);
const amount = Math.floor(args[1]);
// handle invalid target
2021-04-10 13:34:55 +00:00
if (target.id == author.id) return send("You can't bet Mons with yourself!");
else if (target.bot && process.argv[2] !== "dev") return send("You can't bet Mons with a bot!");
// handle invalid amount
2021-04-10 13:34:55 +00:00
if (amount <= 0) return send("You must bet at least one Mon!");
else if (sender.money < amount)
2021-11-03 11:18:26 +00:00
return send({
content: "You don't have enough Mons for that.",
embeds: [getMoneyEmbed(author, true)]
});
else if (receiver.money < amount)
return send({
content: "They don't have enough Mons for that.",
2021-11-03 11:18:26 +00:00
embeds: [getMoneyEmbed(target, true)]
});
2021-04-10 13:34:55 +00:00
return send("How long until the bet ends?");
} else return;
},
2021-01-25 22:06:12 +00:00
any: new Command({
2021-04-06 06:39:11 +00:00
description: "Duration of the bet.",
2021-04-10 13:34:55 +00:00
async run({send, client, args, author, message, channel, guild}) {
2021-01-25 22:06:12 +00:00
if (isAuthorized(guild, channel)) {
// [Pertinence to make configurable on the fly.]
// Lower and upper bounds for bet
const durationBounds = {min: "1m", max: "1d"};
2021-01-25 22:06:12 +00:00
const sender = Storage.getUser(author.id);
const target = args[0] as User;
const receiver = Storage.getUser(target.id);
2021-01-25 22:06:12 +00:00
const amount = Math.floor(args[1]);
const duration = parseDuration(args[2].trim());
// handle invalid target
2021-04-10 13:34:55 +00:00
if (target.id == author.id) return send("You can't bet Mons with yourself!");
2021-04-10 19:08:36 +00:00
else if (target.bot && !IS_DEV_MODE) return send("You can't bet Mons with a bot!");
2021-01-25 22:06:12 +00:00
// handle invalid amount
2021-04-10 13:34:55 +00:00
if (amount <= 0) return send("You must bet at least one Mon!");
else if (sender.money < amount)
return send({
content: "You don't have enough Mons for that.",
2021-11-03 11:18:26 +00:00
embeds: [getMoneyEmbed(author, true)]
});
else if (receiver.money < amount)
return send({
content: "They don't have enough Mons for that.",
2021-11-03 11:18:26 +00:00
embeds: [getMoneyEmbed(target, true)]
});
// handle invalid duration
2021-04-10 13:34:55 +00:00
if (duration <= 0) return send("Invalid bet duration");
else if (duration <= parseDuration(durationBounds.min))
2021-04-10 13:34:55 +00:00
return send(`Bet duration is too short, maximum duration is ${durationBounds.min}`);
else if (duration >= parseDuration(durationBounds.max))
2021-04-10 13:34:55 +00:00
return send(`Bet duration is too long, maximum duration is ${durationBounds.max}`);
2021-01-25 22:06:12 +00:00
// Ask target whether or not they want to take the bet.
2021-04-11 08:02:56 +00:00
const takeBet = await confirm(
2021-04-10 13:34:55 +00:00
await send(
`<@${target.id}>, do you want to take this bet of ${pluralise(amount, "Mon", "s")}`
),
2021-01-26 18:37:31 +00:00
target.id
);
2021-04-11 08:02:56 +00:00
if (!takeBet) return send(`<@${target.id}> has rejected your bet, <@${author.id}>`);
// [MEDIUM PRIORITY: bet persistence to prevent losses in case of shutdown.]
// Remove amount money from both parts at the start to avoid duplication of money.
sender.money -= amount;
receiver.money -= amount;
// Very hacky solution for persistence but better than no solution, backup returns runs during the bot's setup code.
sender.ecoBetInsurance += amount;
receiver.ecoBetInsurance += amount;
Storage.save();
// Notify both users.
send(
`<@${target.id}> has taken <@${author.id}>'s bet, the bet amount of ${pluralise(
amount,
"Mon",
"s"
)} has been deducted from each of them.`
);
2021-01-26 18:37:31 +00:00
2021-04-11 08:02:56 +00:00
// Wait for the duration of the bet.
return setTimeout(async () => {
2021-04-11 08:02:56 +00:00
// In debug mode, saving the storage will break the references, so you have to redeclare sender and receiver for it to actually save.
const sender = Storage.getUser(author.id);
const receiver = Storage.getUser(target.id);
// [TODO: when D.JSv13 comes out, inline reply to clean up.]
// When bet is over, give a vote to ask people their thoughts.
// Filter reactions to only collect the pertinent ones.
const results = await poll(
await send(
`VOTE: do you think that <@${
target.id
}> has won the bet?\nhttps://discord.com/channels/${guild!.id}/${channel.id}/${
message.id
}`
),
["✅", "❌"],
// [Pertinence to make configurable on the fly.]
parseDuration("2m")
2021-04-11 08:02:56 +00:00
);
// Count votes
const ok = results["✅"];
const no = results["❌"];
if (ok > no) {
receiver.money += amount * 2;
send(`By the people's votes, ${target} has won the bet that ${author} had sent them.`);
} else if (ok < no) {
sender.money += amount * 2;
send(`By the people's votes, ${target} has lost the bet that ${author} had sent them.`);
} else {
sender.money += amount;
receiver.money += amount;
send(
`By the people's votes, ${target} couldn't be determined to have won or lost the bet that ${author} had sent them.`
);
}
sender.ecoBetInsurance -= amount;
receiver.ecoBetInsurance -= amount;
Storage.save();
2021-04-11 08:02:56 +00:00
}, duration);
} else return;
2021-01-25 22:06:12 +00:00
}
})
})
})
});