diff --git a/src/commands/fun/eco.ts b/src/commands/fun/eco.ts index 557b2aa..5be316f 100644 --- a/src/commands/fun/eco.ts +++ b/src/commands/fun/eco.ts @@ -3,7 +3,6 @@ import {isAuthorized, getMoneyEmbed} from "./subcommands/eco-utils"; import {DailyCommand, PayCommand, GuildCommand, LeaderboardCommand} from "./subcommands/eco-core"; import {BuyCommand, ShopCommand} from "./subcommands/eco-shop"; import {MondayCommand} from "./subcommands/eco-extras"; -import {BetCommand} from "./subcommands/eco-bet"; export default new Command({ description: "Economy command for Monika.", @@ -17,8 +16,7 @@ export default new Command({ leaderboard: LeaderboardCommand, buy: BuyCommand, shop: ShopCommand, - monday: MondayCommand, - bet: BetCommand + monday: MondayCommand }, user: new Command({ description: "See how much money someone else has by using their user ID or pinging them.", diff --git a/src/commands/fun/subcommands/eco-bet.ts b/src/commands/fun/subcommands/eco-bet.ts deleted file mode 100644 index 01c6c96..0000000 --- a/src/commands/fun/subcommands/eco-bet.ts +++ /dev/null @@ -1,190 +0,0 @@ -import Command from "../../../core/command"; -import $ from "../../../core/lib"; -import {Storage} from "../../../core/structures"; -import {isAuthorized, getMoneyEmbed, getSendEmbed, ECO_EMBED_COLOR} from "./eco-utils"; -import {User} from "discord.js"; - -export const BetCommand = new Command({ - description: "Bet your Mons with other people.", - usage: " ", - run: "Who are you betting with?", - user: new Command({ - description: "User to bet with.", - // handles missing amount argument - async run({args, author, channel, guild}): Promise { - if (isAuthorized(guild, channel)) { - const target = args[0]; - - // handle invalid target - if (target.id == author.id) - return channel.send("You can't bet Mons with yourself!"); - else if (target.bot && process.argv[2] !== "dev") - return channel.send("You can't bet Mons with a bot!"); - - return channel.send("How much are you betting?"); - } - }, - number: new Command({ - description: "Amount of Mons to bet.", - // handles missing duration argument - async run({args, author, channel, guild}): Promise { - 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 - if (target.id == author.id) - return channel.send("You can't bet Mons with yourself!"); - else if (target.bot && process.argv[2] !== "dev") - return channel.send("You can't bet Mons with a bot!"); - - // handle invalid amount - if (amount <= 0) - return channel.send("You must bet at least one Mon!"); - else if (sender.money < amount) - return channel.send("You don't have enough Mons for that.", getMoneyEmbed(author)); - else if (receiver.money < amount) - return channel.send("They don't have enough Mons for that.", getMoneyEmbed(target)); - - return channel.send("How long until the bet ends?"); - } - }, - any: new Command({ - description: "Duration of the bet.", - async run({client, args, author, message, channel, guild, askYesOrNo}): Promise { - if (isAuthorized(guild, channel)) { - // [Pertinence to make configurable on the fly.] - // Lower and upper bounds for bet - const durationBounds = { min:"1m", max:"1d" }; - - const sender = Storage.getUser(author.id); - const target = args[0] as User; - const receiver = Storage.getUser(target.id); - const amount = Math.floor(args[1]); - const duration = parseDuration(args[2].trim()); - - // handle invalid target - if (target.id == author.id) - return channel.send("You can't bet Mons with yourself!"); - else if (target.bot && process.argv[2] !== "dev") - return channel.send("You can't bet Mons with a bot!"); - - // handle invalid amount - if (amount <= 0) - return channel.send("You must bet at least one Mon!"); - else if (sender.money < amount) - return channel.send("You don't have enough Mons for that.", getMoneyEmbed(author)); - else if (receiver.money < amount) - return channel.send("They don't have enough Mons for that.", getMoneyEmbed(target)); - - // handle invalid duration - if (duration <= 0) - return channel.send("Invalid bet duration"); - else if (duration <= parseDuration(durationBounds.min)) - return channel.send(`Bet duration is too short, maximum duration is ${durationBounds.min}`); - else if (duration >= parseDuration(durationBounds.max)) - return channel.send(`Bet duration is too long, maximum duration is ${durationBounds.max}`); - - // Ask target whether or not they want to take the bet. - const takeBet = await askYesOrNo( - await channel.send(`<@${target.id}>, do you want to take this bet of ${$(amount).pluralise("Mon", "s")}`), - target.id - ); - - if (takeBet) { - // [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. - await channel.send(`<@${target.id}> has taken <@${author.id}>'s bet, the bet amount of ${$(amount).pluralise("Mon", "s")} has been deducted from each of them.`); - - // Wait for the duration of the bet. - client.setTimeout(async () => { - // 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. - const voteMsg = await channel.send(`VOTE: do you think that <@${target.id}> has won the bet?\nhttps://discord.com/channels/${guild!.id}/${channel.id}/${message.id}`); - await voteMsg.react("✅"); - await voteMsg.react("❌"); - - // Filter reactions to only collect the pertinent ones. - voteMsg.awaitReactions( - (reaction, user) => { - return ["✅", "❌"].includes(reaction.emoji.name); - }, - // [Pertinence to make configurable on the fly.] - { time: parseDuration("2m") } - ).then(reactions => { - // Count votes - const okReaction = reactions.get("✅"); - const noReaction = reactions.get("❌"); - const ok = okReaction ? (okReaction.count ?? 1) - 1 : 0; - const no = noReaction ? (noReaction.count ?? 1) - 1 : 0; - - if (ok > no) { - receiver.money += amount * 2; - channel.send(`By the people's votes, <@${target.id}> has won the bet that <@${author.id}> had sent them.`); - } - else if (ok < no) { - sender.money += amount * 2; - channel.send(`By the people's votes, <@${target.id}> has lost the bet that <@${author.id}> had sent them.`); - } - else { - sender.money += amount; - receiver.money += amount; - channel.send(`By the people's votes, <@${target.id}> couldn't be determined to have won or lost the bet that <@${author.id}> had sent them.`); - } - sender.ecoBetInsurance -= amount; - receiver.ecoBetInsurance -= amount; - Storage.save(); - }); - }, duration); - } - else - await channel.send(`<@${target.id}> has rejected your bet, <@${author.id}>`); - } - } - }) - }) - }) -}); - - -/** - * Parses a duration string into milliseconds - * Examples: - * - 3d -> 3 days -> 259200000ms - * - 2h -> 2 hours -> 7200000ms - * - 7m -> 7 minutes -> 420000ms - * - 3s -> 3 seconds -> 3000ms - */ -function parseDuration(duration: string): number { - // extract last char as unit - const unit = duration[duration.length - 1].toLowerCase(); - // get the rest as value - let value: number = +duration.substring(0, duration.length - 1); - - if (!["d","h","m","s"].includes(unit) || isNaN(value)) - return 0; - - if (unit === "d") - value *= 86400000; // 1000ms * 60s * 60m * 24h - else if (unit === "h") - value *= 3600000; // 1000ms * 60s * 60m - else if (unit === "m") - value *= 60000; // 1000ms * 60s - else if (unit === "s") - value *= 1000; // 1000ms - - return value; -} diff --git a/src/core/structures.ts b/src/core/structures.ts index 8dd38a9..0e77494 100644 --- a/src/core/structures.ts +++ b/src/core/structures.ts @@ -31,7 +31,6 @@ class User { public timezone: number | null; // This is for the standard timezone only, not the daylight savings timezone public daylightSavingsRegion: "na" | "eu" | "sh" | null; public todoList: {[timestamp: string]: string}; - public ecoBetInsurance: number; constructor(data?: GenericJSON) { this.money = select(data?.money, 0, Number); @@ -51,7 +50,6 @@ class User { } } } - this.ecoBetInsurance = select(data?.ecoBetInsurance, 0, Number); } } diff --git a/src/events/ready.ts b/src/events/ready.ts index f147fa2..b8467aa 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -1,7 +1,7 @@ import Event from "../core/event"; import {client} from "../index"; import $ from "../core/lib"; -import {Config, Storage} from "../core/structures"; +import {Config} from "../core/structures"; import {updateGlobalEmoteRegistry} from "../core/lib"; export default new Event<"ready">({ @@ -16,17 +16,5 @@ export default new Event<"ready">({ }); } updateGlobalEmoteRegistry(); - - // Run this setup block once to restore eco bet money in case the bot went down. (And I guess search the client for those users to let them know too.) - for (const id in Storage.users) { - const user = Storage.users[id]; - - if(user.ecoBetInsurance > 0) { - client.users.cache.get(id)?.send(`Because my system either crashed or restarted while you had a pending bet, the total amount of money that you bet, which was \`${user.ecoBetInsurance}\`, has been restored.`); - user.money += user.ecoBetInsurance; - user.ecoBetInsurance = 0; - } - } - Storage.save(); } });