From 5e855665778bc0bb8163d1279742474c51ac4f0d Mon Sep 17 00:00:00 2001 From: barelyprofessional <150058423+barelyprofessional@users.noreply.github.com> Date: Mon, 6 Apr 2026 21:13:19 -0500 Subject: [PATCH] Refactored krash --- .../Commands/Kasino/KrashCommand.cs | 2 +- .../Models/DbModels/MoneyDbModels.cs | 3 +- KfChatDotNetBot/Services/KasinoKrash.cs | 144 ++++++++---------- 3 files changed, 70 insertions(+), 79 deletions(-) diff --git a/KfChatDotNetBot/Commands/Kasino/KrashCommand.cs b/KfChatDotNetBot/Commands/Kasino/KrashCommand.cs index 86f7f70..02c12be 100644 --- a/KfChatDotNetBot/Commands/Kasino/KrashCommand.cs +++ b/KfChatDotNetBot/Commands/Kasino/KrashCommand.cs @@ -67,7 +67,7 @@ public class KrashBetCommand : ICommand true, autoDeleteAfter: TimeSpan.FromSeconds(5)); return; } - if (botInstance.BotServices.KasinoKrash.theGame == null) + if (botInstance.BotServices.KasinoKrash.TheGame == null) { //start a new game await botInstance.BotServices.KasinoKrash.StartGame(gambler, wager, multi); diff --git a/KfChatDotNetBot/Models/DbModels/MoneyDbModels.cs b/KfChatDotNetBot/Models/DbModels/MoneyDbModels.cs index fdced86..aa9fb3e 100644 --- a/KfChatDotNetBot/Models/DbModels/MoneyDbModels.cs +++ b/KfChatDotNetBot/Models/DbModels/MoneyDbModels.cs @@ -416,7 +416,8 @@ public enum WagerGame [Description("Plinko")] Plinko, [Description("Roulette but live")] - Roulette + Roulette, + Krash } public enum GamblerState diff --git a/KfChatDotNetBot/Services/KasinoKrash.cs b/KfChatDotNetBot/Services/KasinoKrash.cs index 627832b..675b324 100644 --- a/KfChatDotNetBot/Services/KasinoKrash.cs +++ b/KfChatDotNetBot/Services/KasinoKrash.cs @@ -1,12 +1,9 @@ using System.Text.Json; using KfChatDotNetBot.Extensions; -using KfChatDotNetBot.Models; using KfChatDotNetBot.Models.DbModels; using KfChatDotNetBot.Settings; using NLog; using StackExchange.Redis; -using System.Text.Json.Serialization; -using KfChatDotNetBot.Commands.Kasino; using RandN; using RandN.Compat; @@ -19,8 +16,7 @@ public class KasinoKrash : IDisposable private IDatabase? _redisDb; private ChatBot _kfChatBot; private CancellationToken _ct; - public decimal HOUSE_EDGE = 0.98m; - public KasinoKrashModel? theGame; + public KasinoKrashModel? TheGame; public KasinoKrash(ChatBot kfChatBot, CancellationToken ct = default) //the service itself @@ -37,8 +33,8 @@ public class KasinoKrash : IDisposable var redis = ConnectionMultiplexer.Connect(connectionString.Value); _redisDb = redis.GetDatabase(); //attempt to pull a game from the db in case the bot crashed while a game was ongoing. if so it will restart the run - theGame = GetKrashState().Result; - if (theGame != null) _ = RunGame(); + TheGame = GetKrashState().Result; + if (TheGame != null) _ = RunGame(); } public bool IsInitialized() { @@ -56,7 +52,7 @@ public class KasinoKrash : IDisposable { if (_redisDb == null) throw new InvalidOperationException("Kasino krash service isn't initialized"); await _redisDb.KeyDeleteAsync("Krash.State"); - theGame = null; + TheGame = null; } public async Task SaveKrashState(KasinoKrashModel krash) { @@ -67,78 +63,72 @@ public class KasinoKrash : IDisposable public async Task AttemptKrash(GamblerDbModel gambler) { - if (theGame == null) + if (TheGame == null) { throw new InvalidOperationException("Failed to retrieve state or no krash is in progress"); } - if (!theGame.bets.Any(x => x.gambler.User.KfId == gambler.User.KfId)) return; - if (!theGame.krashAccepted) return; + if (TheGame.Bets.All(x => x.Gambler.User.KfId != gambler.User.KfId)) return; + if (!TheGame.KrashAccepted) return; //find which bet is yours - int index = 0; - foreach (var bet in theGame.bets) - { - if (bet.gambler.User.KfId == gambler.User.KfId) break; - index++; - } + var index = TheGame.Bets.TakeWhile(bet => bet.Gambler.User.KfId != gambler.User.KfId).Count(); - var krashBet = theGame.bets[index]; - theGame.bets.RemoveAt(index); - decimal payout = theGame.currentMulti * krashBet.wager - krashBet.wager; - var newBalance = await Money.NewWagerAsync(krashBet.gambler.Id, krashBet.wager, payout, WagerGame.Krash); + var krashBet = TheGame.Bets[index]; + TheGame.Bets.RemoveAt(index); + var payout = TheGame.CurrentMulti * krashBet.Wager - krashBet.Wager; + var newBalance = await Money.NewWagerAsync(krashBet.Gambler.Id, krashBet.Wager, payout, WagerGame.Krash, ct: _ct); await _kfChatBot.SendChatMessageAsync( - $"{krashBet.gambler.User.FormatUsername()}, you [color=limegreen][b]won[/b][/color] {await payout.FormatKasinoCurrencyAsync()}!", + $"{krashBet.Gambler.User.FormatUsername()}, you [color=limegreen][b]won[/b][/color] {await payout.FormatKasinoCurrencyAsync()}!", true, autoDeleteAfter: TimeSpan.FromSeconds(10)); if (_kfChatBot.BotServices.KasinoShop != null) { - await _kfChatBot.BotServices.KasinoShop.ProcessWagerTracking(krashBet.gambler, WagerGame.Krash, krashBet.wager, + await _kfChatBot.BotServices.KasinoShop.ProcessWagerTracking(krashBet.Gambler, WagerGame.Krash, krashBet.Wager, payout, newBalance); } - await SaveKrashState(theGame); + await SaveKrashState(TheGame); } public async Task AddParticipant(GamblerDbModel gambler, decimal wager, decimal multi = -1) { - if (theGame == null) + if (TheGame == null) { - theGame = await GetKrashState(); - if (theGame == null) throw new InvalidOperationException("Failed to retrieve state or no krash is in progress"); + TheGame = await GetKrashState(); + if (TheGame == null) throw new InvalidOperationException("Failed to retrieve state or no krash is in progress"); _ = RunGame(); } - if (theGame.bets.Any(x => x.gambler.User.KfId == gambler.User.KfId)) return; - if (!theGame.betsAccepted) return; - KrashBet bet = new KrashBet{gambler = gambler, wager = wager, multi = multi}; - theGame.bets.Add(bet); - await SaveKrashState(theGame); + if (TheGame.Bets.Any(x => x.Gambler.User.KfId == gambler.User.KfId)) return; + if (!TheGame.BetsAccepted) return; + var bet = new KrashBet{Gambler = gambler, Wager = wager, Multi = multi}; + TheGame.Bets.Add(bet); + await SaveKrashState(TheGame); } public async Task StartGame(GamblerDbModel creator, decimal wager, decimal multi = -1) { - theGame = new KasinoKrashModel(creator); - theGame.bets.Add(new KrashBet{gambler = creator, wager = wager, multi = multi}); - await SaveKrashState(theGame); + TheGame = new KasinoKrashModel(creator); + TheGame.Bets.Add(new KrashBet{Gambler = creator, Wager = wager, Multi = multi}); + await SaveKrashState(TheGame); _ = RunGame(); } public async Task RunGame() //running the actual game { - if (theGame == null) + if (TheGame == null) { await RemoveKrashState(); await _kfChatBot.SendChatMessageAsync("Krash error 1", true); return; } var msg = await _kfChatBot.SendChatMessageAsync( - $"{theGame.creator.User.FormatUsername()} started a Krash! You have 30 seconds to place your bets.", true); - TimeSpan preGameTimer = TimeSpan.FromSeconds(30); - TimeSpan interval = TimeSpan.FromSeconds(1); + $"{TheGame.Creator.User.FormatUsername()} started a Krash! You have 30 seconds to place your bets.", true); + var preGameTimer = TimeSpan.FromSeconds(30); + var interval = TimeSpan.FromSeconds(1); var timer = new PeriodicTimer(interval); - string bets; while (await timer.WaitForNextTickAsync(_ct)) //timer before starting the game { - bets = ""; - foreach (var bet in theGame.bets) bets += $"{bet.gambler.User.FormatUsername()} is betting {bet.wager}[br]"; + var bets = ""; + foreach (var bet in TheGame.Bets) bets += $"{bet.Gambler.User.FormatUsername()} is betting {bet.Wager}[br]"; await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageUuid, - $"{theGame.creator.User.FormatUsername()} started a Krash! You have {preGameTimer} to place your bets.[br]{bets}"); + $"{TheGame.Creator.User.FormatUsername()} started a Krash! You have {preGameTimer} to place your bets.[br]{bets}"); preGameTimer -= interval; if (preGameTimer <= TimeSpan.Zero) { @@ -147,56 +137,56 @@ public class KasinoKrash : IDisposable } //any bets placed after this point will be cancelled, must wait until the last game finishes to start a new one. - theGame.betsAccepted = false; - await SaveKrashState(theGame); + TheGame.BetsAccepted = false; + await SaveKrashState(TheGame); //start the display of the game //change these to change the speed of the game - decimal growthRate = 1.02m; - decimal growthAcceleration = 1.00185m; + var growthRate = 1.02m; + var growthAcceleration = 1.00185m; await _kfChatBot.KfClient.DeleteMessageAsync(msg.ChatMessageUuid!); - msg = await _kfChatBot.SendChatMessageAsync($"[center][b][size=200][color=limegreen]{theGame.currentMulti}x"); - decimal defaultGrowth = 0.01m; + msg = await _kfChatBot.SendChatMessageAsync($"[center][b][size=200][color=limegreen]{TheGame.CurrentMulti}x"); + var defaultGrowth = 0.01m; interval = TimeSpan.FromSeconds(0.1); timer = new PeriodicTimer(interval); while (await timer.WaitForNextTickAsync(_ct)) { - await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageUuid!, $"[center][b][size=200][color=limegreen]{theGame.currentMulti}x"); - theGame.currentMulti += defaultGrowth; + await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageUuid!, $"[center][b][size=200][color=limegreen]{TheGame.CurrentMulti}x"); + TheGame.CurrentMulti += defaultGrowth; defaultGrowth *= growthRate; growthRate *= growthAcceleration; - if (theGame.currentMulti >= theGame.finalMulti) break; + if (TheGame.CurrentMulti >= TheGame.FinalMulti) break; } //at this point the game crashes and everybody who did not cash out or pre bet on a multi will have balance subtracted, winners will be paid out. - await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageUuid!, $"[center][b][size=200][color=red]{theGame.finalMulti}x"); - foreach (var bet in theGame.bets) + await _kfChatBot.KfClient.EditMessageAsync(msg.ChatMessageUuid!, $"[center][b][size=200][color=red]{TheGame.FinalMulti}x"); + foreach (var bet in TheGame.Bets) { - if (bet.multi <= theGame.finalMulti) + if (bet.Multi <= TheGame.FinalMulti) { //you win - decimal payout = theGame.currentMulti * bet.wager - bet.wager; - var newBalance = await Money.NewWagerAsync(bet.gambler.Id, bet.wager, payout, WagerGame.Krash); + var payout = TheGame.CurrentMulti * bet.Wager - bet.Wager; + var newBalance = await Money.NewWagerAsync(bet.Gambler.Id, bet.Wager, payout, WagerGame.Krash, ct: _ct); await _kfChatBot.SendChatMessageAsync( - $"{bet.gambler.User.FormatUsername()}, you [color=limegreen][b]won[/b][/color] {await payout.FormatKasinoCurrencyAsync()}!", + $"{bet.Gambler.User.FormatUsername()}, you [color=limegreen][b]won[/b][/color] {await payout.FormatKasinoCurrencyAsync()}!", true, autoDeleteAfter: TimeSpan.FromSeconds(10)); if (_kfChatBot.BotServices.KasinoShop != null) { - await _kfChatBot.BotServices.KasinoShop.ProcessWagerTracking(bet.gambler, WagerGame.Krash, bet.wager, + await _kfChatBot.BotServices.KasinoShop.ProcessWagerTracking(bet.Gambler, WagerGame.Krash, bet.Wager, payout, newBalance); } } else { //automatically lose, no pre entered multi or it was greater than the final multi and failed to cash out - var newBalance = await Money.NewWagerAsync(bet.gambler.Id, bet.wager, -bet.wager, WagerGame.Krash); + var newBalance = await Money.NewWagerAsync(bet.Gambler.Id, bet.Wager, -bet.Wager, WagerGame.Krash, ct: _ct); await _kfChatBot.SendChatMessageAsync( - $"{bet.gambler.User.FormatUsername()}, you [color=red][b]lost[/b][/color] {await bet.wager.FormatKasinoCurrencyAsync()}!", + $"{bet.Gambler.User.FormatUsername()}, you [color=red][b]lost[/b][/color] {await bet.Wager.FormatKasinoCurrencyAsync()}!", true, autoDeleteAfter: TimeSpan.FromSeconds(10)); if (_kfChatBot.BotServices.KasinoShop != null) { - await _kfChatBot.BotServices.KasinoShop.ProcessWagerTracking(bet.gambler, WagerGame.Krash, bet.wager, - -bet.wager, newBalance); + await _kfChatBot.BotServices.KasinoShop.ProcessWagerTracking(bet.Gambler, WagerGame.Krash, bet.Wager, + -bet.Wager, newBalance); } } } @@ -210,26 +200,26 @@ public class KasinoKrash : IDisposable public class KasinoKrashModel { - public GamblerDbModel creator; - public decimal finalMulti = 0; - public decimal currentMulti = 1.01m; - public List bets = new(); - public decimal HOUSE_EDGE = 0.98m; - public bool betsAccepted = true; - public bool krashAccepted = false; + public GamblerDbModel Creator; + public decimal FinalMulti = 0; + public decimal CurrentMulti = 1.01m; + public List Bets = new(); + public decimal HouseEdge = 0.98m; + public bool BetsAccepted = true; + public bool KrashAccepted = false; public KasinoKrashModel(GamblerDbModel creator) { - this.creator = creator; - finalMulti = GetLinearWeightedRandom(1.01, 25000); + this.Creator = creator; + FinalMulti = GetLinearWeightedRandom(1.01, 25000); } private decimal GetLinearWeightedRandom(double minValue, double maxValue) { var random = RandomShim.Create(StandardRng.Create()); - double r = random.NextDouble(); // Returns 0.0 to 1.0 + var r = random.NextDouble(); // Returns 0.0 to 1.0 // The core 1/x logic - double result = 1.0 / (1.0 - r); + var result = 1.0 / (1.0 - r); // Clamp the result to your specific range if (result < minValue) result = minValue; @@ -241,9 +231,9 @@ public class KasinoKrash : IDisposable public class KrashBet { - public required GamblerDbModel gambler{ get; set;} - public required decimal wager { get; set; } - public required decimal multi { get; set; } + public required GamblerDbModel Gambler{ get; set;} + public required decimal Wager { get; set; } + public required decimal Multi { get; set; } } public void Dispose() {