From 60e0c76b72606b91a5d81a28ab61384b263c0ee2 Mon Sep 17 00:00:00 2001 From: barelyprofessional <150058423+barelyprofessional@users.noreply.github.com> Date: Sat, 15 Nov 2025 16:48:36 -0600 Subject: [PATCH 1/7] Added pocketwatch command --- .../Commands/Kasino/KasinoUserCommands.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/KfChatDotNetBot/Commands/Kasino/KasinoUserCommands.cs b/KfChatDotNetBot/Commands/Kasino/KasinoUserCommands.cs index 80b8ab0..0e16d8c 100644 --- a/KfChatDotNetBot/Commands/Kasino/KasinoUserCommands.cs +++ b/KfChatDotNetBot/Commands/Kasino/KasinoUserCommands.cs @@ -268,4 +268,36 @@ public class AbandonKasinoCommand : ICommand await db.SaveChangesAsync(ctx); await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, Kasino account with ID {gambler.Id} has been marked as abandoned.", true); } +} + +[KasinoCommand] +public class PocketWatchCommand : ICommand +{ + public List Patterns => [ + new Regex(@"^pocketwatch (?\d+)", RegexOptions.IgnoreCase), + ]; + public string? HelpText => "Check a user's balance"; + public UserRight RequiredRight => UserRight.Loser; + public TimeSpan Timeout => TimeSpan.FromSeconds(10); + public RateLimitOptionsModel? RateLimitOptions => null; + public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + CancellationToken ctx) + { + await using var db = new ApplicationDbContext(); + var targetUser = await db.Users.FirstOrDefaultAsync(u => u.KfId == int.Parse(arguments["user_id"].Value), ctx); + if (targetUser == null) + { + await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, the user ID you gave doesn't exist.", true); + return; + } + + var targetGambler = await Money.GetGamblerEntityAsync(targetUser.Id, ct: ctx); + if (targetGambler == null) + { + await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, this user is excluded from the kasino", true); + return; + } + + await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, {targetUser.KfUsername} has {await targetGambler.Balance.FormatKasinoCurrencyAsync()}", true); + } } \ No newline at end of file From e2ae5c20c2cabd0fe202b2dfeed0e676c6dfdca5 Mon Sep 17 00:00:00 2001 From: barelyprofessional <150058423+barelyprofessional@users.noreply.github.com> Date: Sat, 15 Nov 2025 16:50:33 -0600 Subject: [PATCH 2/7] Log the DLive exception --- KfChatDotNetBot/Services/DLive.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/KfChatDotNetBot/Services/DLive.cs b/KfChatDotNetBot/Services/DLive.cs index bf54c9d..7ebc3a1 100644 --- a/KfChatDotNetBot/Services/DLive.cs +++ b/KfChatDotNetBot/Services/DLive.cs @@ -188,6 +188,7 @@ public class DLive(ChatBot kfChatBot) : IDisposable { logger.Error($"Bot shit itself while trying to check if {username} is live. JSON payload follows"); logger.Error(content.GetRawText); + logger.Error(e); throw; } } From e99434f5dfa837f0439e723f64f1f166a467604b Mon Sep 17 00:00:00 2001 From: barelyprofessional <150058423+barelyprofessional@users.noreply.github.com> Date: Sun, 16 Nov 2025 00:45:41 -0600 Subject: [PATCH 3/7] Refactored and corrected compiler warnings on Keno and Planes --- .../Commands/Kasino/KenoCommand.cs | 11 +++- .../Commands/Kasino/PlanesCommand.cs | 57 ++++++++----------- 2 files changed, 31 insertions(+), 37 deletions(-) diff --git a/KfChatDotNetBot/Commands/Kasino/KenoCommand.cs b/KfChatDotNetBot/Commands/Kasino/KenoCommand.cs index 928161b..0547baa 100644 --- a/KfChatDotNetBot/Commands/Kasino/KenoCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/KenoCommand.cs @@ -34,7 +34,7 @@ public class KenoCommand : ICommand private const string MatchRevealDisplay = "💠"; private const string BlankSpaceDisplay = "⬛"; - private SentMessageTrackerModel _kenoTable; + private SentMessageTrackerModel? _kenoTable; public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) @@ -97,7 +97,7 @@ public class KenoCommand : ICommand await botInstance.SendChatMessageAsync( $"{user.FormatUsername()}, you [color={colors[BuiltIn.Keys.KiwiFarmsRedColor].Value}]lost {await wager.FormatKasinoCurrencyAsync()}[/color]. Your balance is now: {await newBalance.FormatKasinoCurrencyAsync()}.", true, autoDeleteAfter: cleanupDelay); - botInstance.ScheduleMessageAutoDelete(_kenoTable, cleanupDelay); + botInstance.ScheduleMessageAutoDelete(_kenoTable ?? throw new Exception("Cannot clean up _kenoTable as it's null"), cleanupDelay); return; } @@ -109,7 +109,7 @@ public class KenoCommand : ICommand await botInstance.SendChatMessageAsync( $"{user.FormatUsername()}, you [color={colors[BuiltIn.Keys.KiwiFarmsGreenColor].Value}]won {await win.FormatKasinoCurrencyAsync()} with a {payoutMulti}x multi![/color]. Your balance is now: {await newBalance.FormatKasinoCurrencyAsync()}.", true, autoDeleteAfter: cleanupDelay); - botInstance.ScheduleMessageAutoDelete(_kenoTable, cleanupDelay); + botInstance.ScheduleMessageAutoDelete(_kenoTable ?? throw new Exception("Cannot clean up _kenotable as it's null"), cleanupDelay); } private async Task AnimatedDisplayTable(List playerNumbers, List casinoNumbers, List matches, ChatBot botInstance) @@ -141,6 +141,11 @@ public class KenoCommand : ICommand await Task.Delay(100); } + if (_kenoTable.ChatMessageId == null) + { + throw new Exception($"_kenoTable chat message ID never got populated. Tracker status is: {_kenoTable?.Status}"); + } + var frameDelay = (await SettingsProvider.GetValueAsync(BuiltIn.Keys.KasinoKenoFrameDelay)).ToType(); //FIRST FRAME 11111111111111111111111111111 for (var frame = 0; frame < 10; frame++) //1 frame per casino number diff --git a/KfChatDotNetBot/Commands/Kasino/PlanesCommand.cs b/KfChatDotNetBot/Commands/Kasino/PlanesCommand.cs index b37bc69..725490b 100644 --- a/KfChatDotNetBot/Commands/Kasino/PlanesCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/PlanesCommand.cs @@ -39,8 +39,8 @@ public class Planes : ICommand private const string Water = "🌊"; private const string Air = "\u2B1C"; // White square private const string BlankSpace = "⠀"; //need 35? - private bool rigged = false; - private bool superRigged = false; + private bool _rigged; + private bool _superRigged; public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx) { @@ -68,21 +68,19 @@ public class Planes : ICommand return; } - var carrierCount = 6; + const int carrierCount = 6; var planesBoard = CreatePlanesBoard(gambler,0); var planesBoard2 = CreatePlanesBoard(gambler); var planesBoard3 = CreatePlanesBoard(gambler); - if (rigged) + if (_rigged) { planesBoard2 = RigPlanesBoard(planesBoard2, carrierCount, 0); planesBoard3 = RigPlanesBoard(planesBoard3, carrierCount, 0); } - List planesBoards = new List(){planesBoard, planesBoard2, planesBoard3}; + List planesBoards = [planesBoard, planesBoard2, planesBoard3]; var plane = new Plane(gambler); - var frameLength = 1000.0; + const double frameLength = 1000.0; var fullCounter = 0; - bool firstBoard = true; - var counter = 0; var noseUp = true; var planesDisplay = GetPreGameBoard(-3, planesBoard2, plane, carrierCount, noseUp); var msgId = await botInstance.SendChatMessageAsync(planesDisplay, true); @@ -102,8 +100,7 @@ public class Planes : ICommand */ do { - if ((fullCounter-3) > 19) firstBoard = false; - counter = (fullCounter - 3) % 20; + var counter = (fullCounter - 3) % 20; await Task.Delay(TimeSpan.FromMilliseconds(frameLength / 3), ctx); @@ -217,20 +214,20 @@ public class Planes : ICommand plane.Gravity(); if ((fullCounter - 3) % 20 == 0 && fullCounter != 3)//removes old planesboard, adds new planeboard when necessary **********************************************************************NEEDS MORE UPDATES { - if (Money.GetRandomNumber(gambler, 0, 100) == 0 && settings[BuiltIn.Keys.KasinoPlanesRandomRiggeryEnabled].ToBoolean()) rigged = true; + if (Money.GetRandomNumber(gambler, 0, 100) == 0 && settings[BuiltIn.Keys.KasinoPlanesRandomRiggeryEnabled].ToBoolean()) _rigged = true; if (settings[BuiltIn.Keys.KasinoPlanesTargetedRiggeryEnabled].ToBoolean() && settings[BuiltIn.Keys.KasinoPlanesTargetedRiggeryVictims].JsonDeserialize>()!.Contains(user.KfId)) { - rigged = true; + _rigged = true; } logger.Info($"Switching planes boards. FullCounter: {fullCounter} | Counter: {counter}"); planesBoards.RemoveAt(0); planesBoards.Add(CreatePlanesBoard(gambler)); - if (rigged && Money.GetRandomNumber(gambler, 0, 100) == 0) { + if (_rigged && Money.GetRandomNumber(gambler, 0, 100) == 0) { planesBoards[1] = CreatePlanesBoard(gambler, 1); //1% chance to update to a board full of rockets if rigged - superRigged = true; + _superRigged = true; } - else if (rigged) + else if (_rigged) { planesBoards[1] = RigPlanesBoard(planesBoards[1], carrierCount, fullCounter); planesBoards[2] = RigPlanesBoard(planesBoards[2], carrierCount, fullCounter); @@ -334,8 +331,6 @@ public class Planes : ICommand private string GetGameBoard(int fullCounter, List planesBoards, Plane plane, int carrierCount, bool noseUp) { var output = ""; - int counter; - var logger = LogManager.GetCurrentClassLogger(); for (var row = 0; row < 8; row++) { @@ -344,6 +339,7 @@ public class Planes : ICommand column++) //plane starts out 3 space behind to give some space to the view, { var useBoard = 1; + int counter; if (fullCounter < 23) counter = fullCounter % 23 - 3; else counter = (fullCounter - 3) % 20; //--- @@ -404,7 +400,7 @@ public class Planes : ICommand } // Was https://i.postimg.cc/rmX59qtV/avelloonaircall2.webp previously - if (superRigged && row == 0) output += "[img]https://i.ddos.lgbt/u/6v8WJ5.webp[/img]"; + if (_superRigged && row == 0) output += "[img]https://i.ddos.lgbt/u/6v8WJ5.webp[/img]"; output += "[br]"; } return output; @@ -419,18 +415,13 @@ public class Planes : ICommand { var randomNum = Money.GetRandomNumber(gambler, 1, 100); if (forceTiles != -1) board[row, column] = forceTiles; - else if (randomNum < 49) - { - board[row, column] = 0; //neutral - } - else if (randomNum > 79) - { - board[row, column] = 1; //rocket - } else - { - board[row, column] = 2; //multi - } + board[row, column] = randomNum switch + { + < 49 => 0, + > 79 => 1, + _ => 2 + }; } } return board; @@ -438,11 +429,9 @@ public class Planes : ICommand private int[,] RigPlanesBoard(int[,] planesBoard, int carrierCount, int fullCounter) { - int[,] returnBoard = new int[6,20]; - int boardCounter = (fullCounter-3) / 20; - var spaceToUpdate = 0; - bool startUpdating = true; - spaceToUpdate = (fullCounter-3) % 20; //how far along is the game into the current board + var returnBoard = new int[6,20]; + bool startUpdating; + var spaceToUpdate = (fullCounter-3) % 20; //how far along is the game into the current board if (spaceToUpdate > 0) startUpdating = false; for (var row = 0; row < 6; row++) From 4bf9308fa7b0dc8e2beb2eed8e7e811b0bade7dd Mon Sep 17 00:00:00 2001 From: barelyprofessional <150058423+barelyprofessional@users.noreply.github.com> Date: Sun, 16 Nov 2025 02:03:02 -0600 Subject: [PATCH 4/7] Created initial models for kasino events --- .../Models/DbModels/MoneyDbModels.cs | 2 +- KfChatDotNetBot/Models/MoneyMetaModels.cs | 39 +++++++- KfChatDotNetBot/Models/MoneyModels.cs | 91 ++++++++++++++++++- 3 files changed, 129 insertions(+), 3 deletions(-) diff --git a/KfChatDotNetBot/Models/DbModels/MoneyDbModels.cs b/KfChatDotNetBot/Models/DbModels/MoneyDbModels.cs index ed503f6..ae26c81 100644 --- a/KfChatDotNetBot/Models/DbModels/MoneyDbModels.cs +++ b/KfChatDotNetBot/Models/DbModels/MoneyDbModels.cs @@ -289,7 +289,7 @@ public enum WagerGame /// Event, [Description("Guess what number I'm thinking of")] - GuessWhatNumber + GuessWhatNumber, } public enum GamblerState diff --git a/KfChatDotNetBot/Models/MoneyMetaModels.cs b/KfChatDotNetBot/Models/MoneyMetaModels.cs index c73fd18..43d6813 100644 --- a/KfChatDotNetBot/Models/MoneyMetaModels.cs +++ b/KfChatDotNetBot/Models/MoneyMetaModels.cs @@ -1,3 +1,40 @@ namespace KfChatDotNetBot.Models; -// Stash all the models used for perk or game metadata here \ No newline at end of file +// Stash all the models used for perk or game metadata here +public class KasinoWagerBaseEventMetaModel +{ + /// + /// Event type for this meta model for the purposes of figuring out which model to use when deserializing + /// + public required KasinoEventType EventType { get; set; } + /// + /// Unique reference tracking the shared event ID stored in the settings + /// + public required string SharedEventId { get; set; } + /// + /// How long it took the user to make a selection. This is based on the event announcement msg recv - sent timestamp + /// that SneedChat provided so the bot won't unfairly penalize users who were delayed by chat lag + /// + public required TimeSpan SelectionDelay { get; set; } +} +/// +/// Metadata model tracking a gambler's wager information related to win/lose games specifically +/// +public class KasinoWagerWinLoseEventMetaModel : KasinoWagerBaseEventMetaModel +{ + /// + /// Unique reference tracking the option the gambler selected. Tracked as a GUID in case the option text changes + /// + public required string OptionId { get; set; } +} + +/// +/// Metadata model tracking a gambler's wager information related to win/lose games specifically +/// +public class KasinoWagerPredictionEventMetaModel : KasinoWagerBaseEventMetaModel +{ + /// + /// The absolute time when the user predicted the thing was going to happen + /// + public required DateTimeOffset PredictedTime { get; set; } +} \ No newline at end of file diff --git a/KfChatDotNetBot/Models/MoneyModels.cs b/KfChatDotNetBot/Models/MoneyModels.cs index 485d766..97e7313 100644 --- a/KfChatDotNetBot/Models/MoneyModels.cs +++ b/KfChatDotNetBot/Models/MoneyModels.cs @@ -1,4 +1,4 @@ -using KfChatDotNetBot.Models.DbModels; +using System.ComponentModel; namespace KfChatDotNetBot.Models; @@ -54,4 +54,93 @@ public class NextVipLevelModel /// The wager requirement to reach this tier that factors in the tier /// public required decimal WagerRequirement { get; set; } +} + +public class KasinoEventModel +{ + /// + /// Text summary of the event itself such as: "How long until the chase ends?" or "Parole granted?" + /// + public required string EventText { get; set; } + /// + /// Unique reference used for tying this event to wagers gamblers are placing + /// + public required string EventId { get; set; } + /// + /// The set of options available for gamblers to select. This is only applicable to WinLose-type bets + /// It'll be an empty array for closest to finish + /// + public required List Options { get; set; } = []; + /// + /// The type of event this is, which is important for the purposes of calculating the payout correctly + /// + public required KasinoEventType EventType { get; set; } + /// + /// Timestamp of when the announcement message was received by the client for the purposes of calculating selection + /// delay. This value is null when the message hasn't been seen yet (either event not started or message lost. + /// Do not accept wagers where this is null. + /// + public DateTimeOffset? EventAnnouncementReceived { get; set; } = null; + /// + /// State of the kasino event + /// + public required KasinoEventState EventState { get; set; } = KasinoEventState.Incomplete; +} + +public class KasinoEventOptionModel +{ + /// + /// Unique reference used for tying a gambler's selection to a given option + /// + public required string OptionId { get; set; } + /// + /// Text to describe the option that users are picking + /// + public required string OptionText { get; set; } + /// + /// Whether this option won or not, null while incomplete + /// + public bool? Won { get; set; } = null; +} + +public enum KasinoEventType +{ + [Description("Win/Lose")] + WinLose, + [Description("Closest to prediction")] + Prediction, + [Description("Closest to prediction (payout weighted to favor early bets)")] + PredictionSelectionTimeWeighted, + [Description("Win/Lose (payout weighted to favor early bets)")] + WinLoseSelectionTimeWeighted +} + +public enum KasinoEventState +{ + /// + /// Event still under construction. This is the initial state when an admin creates an event but hasn't yet launched it + /// + Incomplete, + /// + /// Event has been launched but the announcement message hasn't yet been acknowledged by Sneedchat + /// No bets will be processed until the message is seen + /// If the message is ultimately lost, the event will never launch + /// + PendingAnnouncement, + /// + /// The event announcement message was seen, the event has started and wagers can now be placed + /// + Started, + /// + /// Closed to new wagers but the event is still ongoing + /// + Closed, + /// + /// Event has closed, it's so over. + /// + Over, + /// + /// Event was abandoned and all wagers canceled + /// + Abandoned } \ No newline at end of file From 24db30b7890ad57c0ce41af0a27c16ad89b25205 Mon Sep 17 00:00:00 2001 From: barelyprofessional <150058423+barelyprofessional@users.noreply.github.com> Date: Sun, 16 Nov 2025 12:50:21 -0600 Subject: [PATCH 5/7] Add an option to disable Jackpot --- KfChatDotNetBot/Services/BotServices.cs | 12 +++++++++--- KfChatDotNetBot/Settings/BuiltIn.cs | 2 ++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/KfChatDotNetBot/Services/BotServices.cs b/KfChatDotNetBot/Services/BotServices.cs index 1bbc370..d3eeeae 100644 --- a/KfChatDotNetBot/Services/BotServices.cs +++ b/KfChatDotNetBot/Services/BotServices.cs @@ -172,7 +172,13 @@ public class BotServices private async Task BuildJackpot() { - var proxy = (await SettingsProvider.GetValueAsync(BuiltIn.Keys.Proxy)).Value; + var settings = await SettingsProvider.GetMultipleValuesAsync([BuiltIn.Keys.Proxy, BuiltIn.Keys.JackpotEnabled]); + if (!settings[BuiltIn.Keys.JackpotEnabled].ToBoolean()) + { + _logger.Debug("Jackpot.bet is disabled"); + return; + } + var proxy = settings[BuiltIn.Keys.Proxy].Value; _jackpot = new Jackpot(proxy, _cancellationToken); _jackpot.OnJackpotBet += OnJackpotBet; await _jackpot.StartWsClient(); @@ -378,7 +384,7 @@ public class BotServices var settings = await SettingsProvider.GetMultipleValuesAsync([ BuiltIn.Keys.KickEnabled, BuiltIn.Keys.HowlggEnabled, BuiltIn.Keys.ChipsggEnabled, BuiltIn.Keys.ClashggEnabled, BuiltIn.Keys.BetBoltEnabled, BuiltIn.Keys.YeetEnabled, - BuiltIn.Keys.RainbetEnabled, BuiltIn.Keys.PartiEnabled + BuiltIn.Keys.RainbetEnabled, BuiltIn.Keys.PartiEnabled, BuiltIn.Keys.JackpotEnabled ]); try { @@ -422,7 +428,7 @@ public class BotServices await BuildHowlgg(); } - if (_jackpot != null && !_jackpot.IsConnected()) + if (_jackpot != null && settings[BuiltIn.Keys.JackpotEnabled].ToBoolean() && !_jackpot.IsConnected()) { _logger.Error("Jackpot died, recreating it"); _jackpot.Dispose(); diff --git a/KfChatDotNetBot/Settings/BuiltIn.cs b/KfChatDotNetBot/Settings/BuiltIn.cs index d385307..4ed1b54 100644 --- a/KfChatDotNetBot/Settings/BuiltIn.cs +++ b/KfChatDotNetBot/Settings/BuiltIn.cs @@ -200,6 +200,8 @@ public static class BuiltIn [BuiltInSetting("Bossman's usernames on Jackpot", SettingValueType.Array, "[\"TheBossmanJack\", \"Austingambless757\"]")] public static string JackpotBmjUsernames = "Jackpot.BmjUsernames"; + [BuiltInSetting("Whether Jackpot is enabled", SettingValueType.Boolean, "true", BooleanRegex)] + public static string JackpotEnabled = "Jackpot.Enabled"; [BuiltInSetting("Bossman's rainbet public IDs", SettingValueType.Array, "[\"Ir04170wLulcjtePCL7P6lmeOlepRaNp\", \"IA9RHFR1NLHL33AVOM9GL2G2CINM9I6P\"]")] public static string RainbetBmjPublicIds = "Rainbet.BmjPublicIds"; From 3c70fea2bace0fbddef63d64e62b4a51f683a4ab Mon Sep 17 00:00:00 2001 From: barelyprofessional <150058423+barelyprofessional@users.noreply.github.com> Date: Tue, 25 Nov 2025 00:54:11 -0600 Subject: [PATCH 6/7] Added admin commands for everything but abandon and close. Changed selection time weighted payout to a property instead of having different types --- .../Commands/Kasino/KasinoEventCommands.cs | 367 ++++++++++++++++++ KfChatDotNetBot/Models/MoneyModels.cs | 8 +- KfChatDotNetBot/Services/Money.cs | 8 + KfChatDotNetBot/Settings/BuiltIn.cs | 13 + 4 files changed, 392 insertions(+), 4 deletions(-) create mode 100644 KfChatDotNetBot/Commands/Kasino/KasinoEventCommands.cs diff --git a/KfChatDotNetBot/Commands/Kasino/KasinoEventCommands.cs b/KfChatDotNetBot/Commands/Kasino/KasinoEventCommands.cs new file mode 100644 index 0000000..9db968f --- /dev/null +++ b/KfChatDotNetBot/Commands/Kasino/KasinoEventCommands.cs @@ -0,0 +1,367 @@ +using System.Text.RegularExpressions; +using Humanizer; +using KfChatDotNetBot.Extensions; +using KfChatDotNetBot.Models; +using KfChatDotNetBot.Models.DbModels; +using KfChatDotNetBot.Services; +using KfChatDotNetBot.Settings; +using KfChatDotNetWsClient.Models.Events; + +namespace KfChatDotNetBot.Commands.Kasino; + +public class KasinoNewEventCommand : ICommand +{ + public List Patterns => + [ + new Regex("^kasino event new$", RegexOptions.IgnoreCase), + new Regex(@"^kasino event new (?\w+)$", RegexOptions.IgnoreCase), + new Regex(@"^kasino event new (?\w+) (?.+)$", RegexOptions.IgnoreCase), + ]; + + public string? HelpText => "Create a new kasino event"; + public UserRight RequiredRight => UserRight.TrueAndHonest; + public TimeSpan Timeout => TimeSpan.FromSeconds(10); + public RateLimitOptionsModel? RateLimitOptions => null; + + public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, + CancellationToken ctx) + { + var settings = await SettingsProvider.GetMultipleValuesAsync([ + BuiltIn.Keys.KasinoEventWeightWinAgainstSelectionTime, BuiltIn.Keys.KasinoEventData, + BuiltIn.Keys.KasinoEventTextLengthLimit + ]); + if (!arguments.TryGetValue("type", out var type)) + { + await botInstance.SendChatMessageAsync( + $"{user.FormatUsername()}, not enough arguments. !kasino event new ", + true, autoDeleteAfter: TimeSpan.FromSeconds(60)); + return; + } + + if (!arguments.TryGetValue("description", out var description)) + { + await botInstance.SendChatMessageAsync( + $"{user.FormatUsername()}, not enough arguments. !kasino event new ", + true, autoDeleteAfter: TimeSpan.FromSeconds(60)); + return; + } + + if (description.Length > settings[BuiltIn.Keys.KasinoEventTextLengthLimit].ToType()) + { + await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, your event description / text with a length of " + + $"{description.Length} characters exceeds the limit of " + + $"{settings[BuiltIn.Keys.KasinoEventTextLengthLimit].ToType()} " + + $"characters", true); + return; + } + + var useTimeWeightedPayout = settings[BuiltIn.Keys.KasinoEventWeightWinAgainstSelectionTime].ToBoolean(); + KasinoEventType eventType; + var guide = string.Empty; + if (type.Value.Equals("win-lose", StringComparison.CurrentCultureIgnoreCase)) + { + eventType = KasinoEventType.WinLose; + guide = "Add option: !kasino event {EventId} options add|new [br]" + + "Remove option: !kasino event {EventId} options del|remove