#nullable disable warnings using EllieBot.Db.Models; using EllieBot.Modules.Gambling.Common; using EllieBot.Modules.Gambling.Services; using SixLabors.Fonts; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Drawing.Processing; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using EllieBot.Common.TypeReaders; using Color = SixLabors.ImageSharp.Color; using Image = SixLabors.ImageSharp.Image; namespace EllieBot.Modules.Gambling; public enum GamblingError { InsufficientFunds, } public partial class Gambling { [Group] public partial class SlotCommands : GamblingSubmodule<IGamblingService> { private readonly IImageCache _images; private readonly FontProvider _fonts; private readonly DbService _db; private object _slotStatsLock = new(); public SlotCommands( IImageCache images, FontProvider fonts, DbService db, GamblingConfigService gamb) : base(gamb) { _images = images; _fonts = fonts; _db = db; } public Task Test() => Task.CompletedTask; [Cmd] public async Task Slot([OverrideTypeReader(typeof(BalanceTypeReader))] long amount) { if (!await CheckBetMandatory(amount)) return; // var slotInteraction = CreateSlotInteractionIntenal(amount); await ctx.Channel.TriggerTypingAsync(); if (await InternalSlotAsync(amount) is not SlotResult result) { await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); return; } var text = GetSlotMessageTextInternal(result); using var image = await GenerateSlotImageAsync(amount, result); await using var imgStream = await image.ToStreamAsync(); var eb = _sender.CreateEmbed() .WithAuthor(ctx.User) .WithDescription(Format.Bold(text)) .WithImageUrl($"attachment://result.png") .WithOkColor(); var bb = new ButtonBuilder(emote: Emoji.Parse("🔁"), customId: "slot:again", label: "Pull Again"); var inter = _inter.Create(ctx.User.Id, bb, smc => { smc.DeferAsync(); return Slot(amount); }); var msg = await ctx.Channel.SendFileAsync(imgStream, "result.png", embed: eb.Build(), components: inter.CreateComponent() ); await inter.RunAsync(msg); } // private SlotInteraction CreateSlotInteractionIntenal(long amount) // { // return new SlotInteraction((DiscordSocketClient)ctx.Client, // ctx.User.Id, // async (smc) => // { // try // { // if (await InternalSlotAsync(amount) is not SlotResult result) // { // await smc.RespondErrorAsync(_eb, GetText(strs.not_enough(CurrencySign)), true); // return; // } // // var msg = GetSlotMessageInternal(result); // // using var image = await GenerateSlotImageAsync(amount, result); // await using var imgStream = await image.ToStreamAsync(); // // var guid = Guid.NewGuid(); // var imgName = $"result_{guid}.png"; // // var slotInteraction = CreateSlotInteractionIntenal(amount).GetInteraction(); // // await smc.Message.ModifyAsync(m => // { // m.Content = msg; // m.Attachments = new[] // { // new FileAttachment(imgStream, imgName) // }; // m.Components = slotInteraction.CreateComponent(); // }); // // _ = slotInteraction.RunAsync(smc.Message); // } // catch (Exception ex) // { // Log.Error(ex, "Error pulling slot again"); // } // // finally // // { // // await Task.Delay(1000); // // _runningUsers.TryRemove(ctx.User.Id); // // } // }); // } private string GetSlotMessageTextInternal(SlotResult result) { var multi = result.Multiplier.ToString("0.##"); var msg = result.WinType switch { SlotWinType.SingleJoker => GetText(strs.slot_single(CurrencySign, multi)), SlotWinType.DoubleJoker => GetText(strs.slot_two(CurrencySign, multi)), SlotWinType.TrippleNormal => GetText(strs.slot_three(multi)), SlotWinType.TrippleJoker => GetText(strs.slot_jackpot(multi)), _ => GetText(strs.better_luck), }; return msg; } private async Task<SlotResult?> InternalSlotAsync(long amount) { var maybeResult = await _service.SlotAsync(ctx.User.Id, amount); if (!maybeResult.TryPickT0(out var result, out var error)) { return null; } return result; } private async Task<Image<Rgba32>> GenerateSlotImageAsync(long amount, SlotResult result) { long ownedAmount; await using (var uow = _db.GetDbContext()) { ownedAmount = uow.Set<DiscordUser>().FirstOrDefault(x => x.UserId == ctx.User.Id)?.CurrencyAmount ?? 0; } var slotBg = await _images.GetSlotBgAsync(); var bgImage = Image.Load<Rgba32>(slotBg); var numbers = new int[3]; result.Rolls.CopyTo(numbers, 0); Color fontColor = Config.Slots.CurrencyFontColor; bgImage.Mutate<Rgba32>(x => x.DrawText(new RichTextOptions(_fonts.DottyFont.CreateFont(65)) { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, WrappingLength = 140, Origin = new(298, 100) }, ((long)result.Won).ToString(), fontColor)); var bottomFont = _fonts.DottyFont.CreateFont(50); bgImage.Mutate(x => x.DrawText(new RichTextOptions(bottomFont) { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, WrappingLength = 135, Origin = new(196, 480) }, amount.ToString(), fontColor)); bgImage.Mutate(x => x.DrawText(new(bottomFont) { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, Origin = new(393, 480) }, ownedAmount.ToString(), fontColor)); //sw.PrintLap("drew red text"); for (var i = 0; i < 3; i++) { using var img = Image.Load(await _images.GetSlotEmojiAsync(numbers[i])); bgImage.Mutate(x => x.DrawImage(img, new Point(148 + (105 * i), 217), 1f)); } return bgImage; } } }