diff --git a/KfChatDotNetBot/Commands/KasinoUserCommands.cs b/KfChatDotNetBot/Commands/KasinoUserCommands.cs new file mode 100644 index 0000000..db22272 --- /dev/null +++ b/KfChatDotNetBot/Commands/KasinoUserCommands.cs @@ -0,0 +1,107 @@ +using System.Text.RegularExpressions; +using Humanizer; +using Humanizer.Localisation; +using KfChatDotNetBot.Extensions; +using KfChatDotNetBot.Models.DbModels; +using KfChatDotNetBot.Services; +using KfChatDotNetWsClient.Models.Events; +using Microsoft.EntityFrameworkCore; + +namespace KfChatDotNetBot.Commands; + +[KasinoCommand] +public class GetBalanceCommand : ICommand +{ + public List Patterns => [ + new Regex("^balance", RegexOptions.IgnoreCase), + new Regex("^bal$", RegexOptions.IgnoreCase) + ]; + public string? HelpText => "Get your gamba balance"; + public UserRight RequiredRight => UserRight.Loser; + public TimeSpan Timeout => TimeSpan.FromSeconds(10); + + public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + CancellationToken ctx) + { + var gambler = await user.GetGamblerEntity(ct: ctx); + await botInstance.SendChatMessageAsync( + $"@{user.KfUsername}, your balance is {await gambler!.Balance.FormatKasinoCurrencyAsync()}", true); + } +} + +[KasinoCommand] +public class GetExclusionCommand : ICommand +{ + public List Patterns => [ + new Regex("^exclusion$", RegexOptions.IgnoreCase), + ]; + public string? HelpText => "Get your exclusion status"; + public UserRight RequiredRight => UserRight.Loser; + public TimeSpan Timeout => TimeSpan.FromSeconds(10); + + public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + CancellationToken ctx) + { + var gambler = await user.GetGamblerEntity(ct: ctx); + var exclusion = await gambler!.GetActiveExclusion(ct: ctx); + if (exclusion == null) + { + await botInstance.SendChatMessageAsync($"@{user.KfUsername}, you are currently not excluded.", true); + return; + } + + var duration = + (exclusion.Expires - exclusion.Created).Humanize(precision: 1, minUnit: TimeUnit.Second, + maxUnit: TimeUnit.Day); + var expires = + (exclusion.Expires - DateTimeOffset.UtcNow).Humanize(precision: 2, minUnit: TimeUnit.Second, + maxUnit: TimeUnit.Day); + await botInstance.SendChatMessageAsync( + $"@{user.KfUsername}, your exclusion for {duration} expires in {expires}", true); + } +} + +[KasinoCommand] +public class SendJuiceCommand : ICommand +{ + public List Patterns => [ + new Regex(@"^juice (?\d+) (?\d+)$", RegexOptions.IgnoreCase), + new Regex(@"^juice (?\d+) (?\d+\.\d+)$", RegexOptions.IgnoreCase) + ]; + public string? HelpText => "Send juice to somebody"; + public UserRight RequiredRight => UserRight.Loser; + public TimeSpan Timeout => TimeSpan.FromSeconds(10); + + public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + CancellationToken ctx) + { + await using var db = new ApplicationDbContext(); + var gambler = await user.GetGamblerEntity(ct: ctx); + var targetUser = await db.Users.FirstOrDefaultAsync(u => u.KfId == int.Parse(arguments["user_id"].Value), ctx); + var amount = decimal.Parse(arguments["amount"].Value); + if (gambler!.Balance < amount) + { + await botInstance.SendChatMessageAsync($"@{user.KfUsername}, you don't have enough money to juice this much.", true); + return; + } + + if (targetUser == null) + { + await botInstance.SendChatMessageAsync($"@{user.KfUsername}, the user ID you gave doesn't exist.", true); + return; + } + + var targetGambler = await targetUser.GetGamblerEntity(ct: ctx); + if (targetGambler == null) + { + await botInstance.SendChatMessageAsync($"@{user.KfUsername}, you can't juice a banned user", true); + return; + } + + await gambler.ModifyBalance(-amount, TransactionSourceEventType.Juicer, + $"Juice sent to {targetUser.KfUsername}", ct: ctx); + await targetGambler.ModifyBalance(amount, TransactionSourceEventType.Juicer, $"Juice from {user.KfUsername}", + gambler, ctx); + await botInstance.SendChatMessageAsync($"@{user.KfUsername}, {await amount.FormatKasinoCurrencyAsync()} has been sent to {targetUser.KfUsername}", true); + } +} \ No newline at end of file diff --git a/KfChatDotNetBot/Extensions/MoneyExtensions.cs b/KfChatDotNetBot/Extensions/MoneyExtensions.cs index 1016c84..4dd03e6 100644 --- a/KfChatDotNetBot/Extensions/MoneyExtensions.cs +++ b/KfChatDotNetBot/Extensions/MoneyExtensions.cs @@ -225,6 +225,13 @@ public static class MoneyExtensions return perk; } + /// + /// Upgrade to the given VIP level. Grants a bonus as part of the level up. + /// + /// The gambler you wish to level up + /// VIP level to grant them + /// Cancellation token + /// The bonus they received public static async Task UpgradeVipLevel(this GamblerDbModel gambler, NextVipLevelModel nextVipLevel, CancellationToken ct = default) { @@ -251,4 +258,43 @@ public static class MoneyExtensions $"VIP Level '{nextVipLevel.VipLevel.Icon} {nextVipLevel.VipLevel.Name}' Tier {nextVipLevel.Tier} level up bonus", ct: ct); return payout; } + + /// + /// Format an amount of money using configured symbols + /// + /// The amount you wish to format + /// Whether to suffix the symbol + /// Whether to prefix the symbol + /// Whether to wrap the resulting string in [plain][/plain] BBCode to avoid characters being interpreted as emotes + /// + public static async Task FormatKasinoCurrencyAsync(this decimal amount, bool suffixSymbol = true, + bool prefixSymbol = false, bool wrapInPlainBbCode = true) + { + var settings = await + SettingsProvider.GetMultipleValuesAsync([BuiltIn.Keys.MoneySymbolPrefix, BuiltIn.Keys.MoneySymbolSuffix]); + var result = string.Empty; + if (wrapInPlainBbCode) + { + result = "[plain]"; + } + + if (prefixSymbol) + { + result += settings[BuiltIn.Keys.MoneySymbolPrefix].Value; + } + + result += $"{amount:N2}"; + + if (suffixSymbol) + { + result += $" {settings[BuiltIn.Keys.MoneySymbolSuffix].Value}"; + } + + if (wrapInPlainBbCode) + { + result += "[/plain]"; + } + + return result; + } } diff --git a/KfChatDotNetBot/Services/BotCommands.cs b/KfChatDotNetBot/Services/BotCommands.cs index 2235332..05b251b 100644 --- a/KfChatDotNetBot/Services/BotCommands.cs +++ b/KfChatDotNetBot/Services/BotCommands.cs @@ -121,9 +121,7 @@ internal class BotCommands return; } - var moneySettings = - await SettingsProvider.GetMultipleValuesAsync([BuiltIn.Keys.MoneyEnabled, BuiltIn.Keys.MoneySymbolSuffix]); - if (!moneySettings[BuiltIn.Keys.MoneyEnabled].ToBoolean()) return; + if (!(await SettingsProvider.GetValueAsync(BuiltIn.Keys.MoneyEnabled)).ToBoolean()) return; var wagerCommand = HasAttribute(command); if (!wagerCommand) return; var gambler = await user.GetGamblerEntity(ct: _cancellationToken); @@ -136,7 +134,7 @@ internal class BotCommands var payout = await gambler.UpgradeVipLevel(newLevel, _cancellationToken); await _bot.SendChatMessageAsync( $"🤑🤑 {user.KfUsername} has leveled up to to {newLevel.VipLevel.Icon} {newLevel.VipLevel.Name} Tier {newLevel.Tier} " + - $"and received a bonus of {payout:N2} {moneySettings[BuiltIn.Keys.MoneySymbolSuffix].Value}", true); + $"and received a bonus of {await payout.FormatKasinoCurrencyAsync()}", true); } private static bool HasAttribute(ICommand command) where T : Attribute