mirror of
				https://gitlab.com/Kwoth/nadekobot.git
				synced 2025-11-04 00:34:26 -05:00 
			
		
		
		
	Improved how .bf and .br look like. Improved .slot result calculation performance (because of .slottest). Some string changes
This commit is contained in:
		@@ -11,16 +11,16 @@ namespace NadekoBot.Modules.Gambling;
 | 
			
		||||
public partial class Gambling
 | 
			
		||||
{
 | 
			
		||||
    [Group]
 | 
			
		||||
    public partial class FlipCoinCommands : GamblingSubmodule<GamblingService>
 | 
			
		||||
    public partial class FlipCoinCommands : GamblingSubmodule<IGamblingService>
 | 
			
		||||
    {
 | 
			
		||||
        public enum BetFlipGuess
 | 
			
		||||
        public enum BetFlipGuess : byte
 | 
			
		||||
        {
 | 
			
		||||
            H = 1,
 | 
			
		||||
            Head = 1,
 | 
			
		||||
            Heads = 1,
 | 
			
		||||
            T = 2,
 | 
			
		||||
            Tail = 2,
 | 
			
		||||
            Tails = 2
 | 
			
		||||
            H = 0,
 | 
			
		||||
            Head = 0,
 | 
			
		||||
            Heads = 0,
 | 
			
		||||
            T = 1,
 | 
			
		||||
            Tail = 1,
 | 
			
		||||
            Tails = 1
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static readonly NadekoRandom _rng = new();
 | 
			
		||||
@@ -52,11 +52,14 @@ public partial class Gambling
 | 
			
		||||
            var headCount = 0;
 | 
			
		||||
            var tailCount = 0;
 | 
			
		||||
            var imgs = new Image<Rgba32>[count];
 | 
			
		||||
            for (var i = 0; i < count; i++)
 | 
			
		||||
            var headsArr = await _images.GetHeadsImageAsync();
 | 
			
		||||
            var tailsArr = await _images.GetTailsImageAsync();
 | 
			
		||||
 | 
			
		||||
            var result = await _service.FlipAsync(count);
 | 
			
		||||
            
 | 
			
		||||
            for (var i = 0; i < result.Length; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var headsArr = await _images.GetHeadsImageAsync();
 | 
			
		||||
                var tailsArr = await _images.GetTailsImageAsync();
 | 
			
		||||
                if (_rng.Next(0, 10) < 5)
 | 
			
		||||
                if (result[i].Side == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    imgs[i] = Image.Load(headsArr);
 | 
			
		||||
                    headCount++;
 | 
			
		||||
@@ -69,7 +72,7 @@ public partial class Gambling
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            using var img = imgs.Merge(out var format);
 | 
			
		||||
            await using var stream = img.ToStream(format);
 | 
			
		||||
            await using var stream = await img.ToStreamAsync(format);
 | 
			
		||||
            foreach (var i in imgs)
 | 
			
		||||
                i.Dispose();
 | 
			
		||||
 | 
			
		||||
@@ -92,38 +95,37 @@ public partial class Gambling
 | 
			
		||||
            if (!await CheckBetMandatory(amount) || amount == 1)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var removed = await _cs.RemoveAsync(ctx.User, amount, new("betflip", "bet"));
 | 
			
		||||
            if (!removed)
 | 
			
		||||
            var res = await _service.BetFlipAsync(ctx.User.Id, amount, (byte)guess);
 | 
			
		||||
            if (!res.TryPickT0(out var result, out _))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            BetFlipGuess result;
 | 
			
		||||
            Uri imageToSend;
 | 
			
		||||
            var coins = _ic.Data.Coins;
 | 
			
		||||
            if (_rng.Next(0, 1000) <= 499)
 | 
			
		||||
            if (result.Side == 0)
 | 
			
		||||
            {
 | 
			
		||||
                imageToSend = coins.Heads[_rng.Next(0, coins.Heads.Length)];
 | 
			
		||||
                result = BetFlipGuess.Heads;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                imageToSend = coins.Tails[_rng.Next(0, coins.Tails.Length)];
 | 
			
		||||
                result = BetFlipGuess.Tails;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            string str;
 | 
			
		||||
            if (guess == result)
 | 
			
		||||
            var won = (long)result.Won;
 | 
			
		||||
            if (won > 0)
 | 
			
		||||
            {
 | 
			
		||||
                var toWin = (long)(amount * Config.BetFlip.Multiplier);
 | 
			
		||||
                str = Format.Bold(ctx.User.ToString()) + " " + GetText(strs.flip_guess(N(toWin)));
 | 
			
		||||
                await _cs.AddAsync(ctx.User, toWin, new("betflip", "win"));
 | 
			
		||||
                str = Format.Bold(GetText(strs.flip_guess(N(won))));
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                str = Format.Bold(ctx.User.ToString()) + " " + GetText(strs.better_luck);
 | 
			
		||||
            {
 | 
			
		||||
                str = Format.Bold(GetText(strs.better_luck));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ctx.Channel.EmbedAsync(_eb.Create()
 | 
			
		||||
                .WithAuthor(ctx.User)
 | 
			
		||||
                                            .WithDescription(str)
 | 
			
		||||
                                            .WithOkColor()
 | 
			
		||||
                                            .WithImageUrl(imageToSend.ToString()));
 | 
			
		||||
 
 | 
			
		||||
@@ -655,19 +655,26 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        var win = (long)result.Won;
 | 
			
		||||
        var str = Format.Bold(ctx.User.ToString()) + Format.Code(GetText(strs.roll(result.Roll)));
 | 
			
		||||
        string str;
 | 
			
		||||
        if (win > 0)
 | 
			
		||||
        {
 | 
			
		||||
            str += GetText(strs.br_win(N(win), result.Threshold + (result.Roll == 100 ? " 👑" : "")));
 | 
			
		||||
            str = GetText(strs.br_win(N(win), result.Threshold + (result.Roll == 100 ? " 👑" : "")));
 | 
			
		||||
            await _cs.AddAsync(ctx.User, win, new("betroll", "win"));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            str += GetText(strs.better_luck);
 | 
			
		||||
            str = GetText(strs.better_luck);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await SendConfirmAsync(str);
 | 
			
		||||
        var eb = _eb.Create(ctx)
 | 
			
		||||
            .WithAuthor(ctx.User)
 | 
			
		||||
            .WithFooter(str)
 | 
			
		||||
            .AddField(GetText(strs.roll2), result.Roll.ToString(CultureInfo.InvariantCulture))
 | 
			
		||||
            .WithOkColor();
 | 
			
		||||
 | 
			
		||||
        await ctx.Channel.EmbedAsync(eb);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ public partial class Gambling
 | 
			
		||||
        private static decimal totalBet;
 | 
			
		||||
        private static decimal totalPaidOut;
 | 
			
		||||
 | 
			
		||||
        private static readonly HashSet<ulong> _runningUsers = new();
 | 
			
		||||
        private static readonly ConcurrentHashSet<ulong> _runningUsers = new();
 | 
			
		||||
 | 
			
		||||
        //here is a payout chart
 | 
			
		||||
        //https://lh6.googleusercontent.com/-i1hjAJy_kN4/UswKxmhrbPI/AAAAAAAAB1U/82wq_4ZZc-Y/DE6B0895-6FC1-48BE-AC4F-14D1B91AB75B.jpg
 | 
			
		||||
@@ -84,11 +84,12 @@ public partial class Gambling
 | 
			
		||||
            var dict = new Dictionary<decimal, int>();
 | 
			
		||||
            for (var i = 0; i < tests; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var res = SlotMachine.Pull(0);
 | 
			
		||||
                if (dict.ContainsKey(res.Multiplier))
 | 
			
		||||
                    dict[res.Multiplier] += 1;
 | 
			
		||||
                var res = await _service.SlotAsync(ctx.User.Id, 0);
 | 
			
		||||
                var multi = res.AsT0.Multiplier;
 | 
			
		||||
                if (dict.ContainsKey(multi))
 | 
			
		||||
                    dict[multi] += 1;
 | 
			
		||||
                else
 | 
			
		||||
                    dict.Add(res.Multiplier, 1);
 | 
			
		||||
                    dict.Add(multi, 1);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var sb = new StringBuilder();
 | 
			
		||||
@@ -157,7 +158,7 @@ public partial class Gambling
 | 
			
		||||
                                WrapTextWidth = 140
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        result.Won.ToString(),
 | 
			
		||||
                        ((long)result.Won).ToString(),
 | 
			
		||||
                        _fonts.DottyFont.CreateFont(65),
 | 
			
		||||
                        fontColor,
 | 
			
		||||
                        new(227, 92)));
 | 
			
		||||
@@ -219,50 +220,9 @@ public partial class Gambling
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                _ = Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    await Task.Delay(1000);
 | 
			
		||||
                    _runningUsers.Remove(ctx.User.Id);
 | 
			
		||||
                });
 | 
			
		||||
                await Task.Delay(1000);
 | 
			
		||||
                _runningUsers.TryRemove(ctx.User.Id);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public sealed class SlotMachine
 | 
			
		||||
{
 | 
			
		||||
    public const int MAX_VALUE = 5;
 | 
			
		||||
 | 
			
		||||
    private static readonly List<Func<int[], int>> _winningCombos = new()
 | 
			
		||||
    {
 | 
			
		||||
        //three flowers
 | 
			
		||||
        arr => arr.All(a => a == MAX_VALUE) ? 30 : 0,
 | 
			
		||||
        //three of the same
 | 
			
		||||
        arr => arr.All(a => a == arr[0]) ? 10 : 0,
 | 
			
		||||
        //two flowers
 | 
			
		||||
        arr => arr.Count(a => a == MAX_VALUE) == 2 ? 4 : 0,
 | 
			
		||||
        //one flower
 | 
			
		||||
        arr => arr.Any(a => a == MAX_VALUE) ? 1 : 0
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    public static SlotResult Pull(decimal amount)
 | 
			
		||||
    {
 | 
			
		||||
        var numbers = new int[3];
 | 
			
		||||
        for (var i = 0; i < numbers.Length; i++)
 | 
			
		||||
            numbers[i] = new NadekoRandom().Next(0, MAX_VALUE + 1);
 | 
			
		||||
        var multi = 0M;
 | 
			
		||||
        foreach (var t in _winningCombos)
 | 
			
		||||
        {
 | 
			
		||||
            multi = t(numbers);
 | 
			
		||||
            if (multi != 0)
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new()
 | 
			
		||||
        {
 | 
			
		||||
            Rolls = numbers,
 | 
			
		||||
            Multiplier = multi,
 | 
			
		||||
            Won = multi * amount,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -8,7 +8,7 @@ public interface IGamblingService
 | 
			
		||||
{
 | 
			
		||||
    Task<OneOf<WofResult, GamblingError>> WofAsync(ulong userId, long amount);
 | 
			
		||||
    Task<OneOf<BetrollResult, GamblingError>> BetRollAsync(ulong userId, long amount);
 | 
			
		||||
    Task<OneOf<BetflipResult, GamblingError>> BetFlipAsync(ulong userId, long amount, int guess);
 | 
			
		||||
    Task<OneOf<BetflipResult, GamblingError>> BetFlipAsync(ulong userId, long amount, byte guess);
 | 
			
		||||
    Task<OneOf<SlotResult, GamblingError>> SlotAsync(ulong userId, long amount);
 | 
			
		||||
    Task<FlipResult[]> FlipAsync(int count);
 | 
			
		||||
}
 | 
			
		||||
@@ -17,6 +17,7 @@ public sealed class NewGamblingService : IGamblingService, INService
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // todo input checks
 | 
			
		||||
    // todo ladder of fortune
 | 
			
		||||
    public async Task<OneOf<WofResult, GamblingError>> WofAsync(ulong userId, long amount)
 | 
			
		||||
    {
 | 
			
		||||
        var isTakeSuccess = await _cs.RemoveAsync(userId, amount, new("wof", "bet"));
 | 
			
		||||
@@ -61,7 +62,7 @@ public sealed class NewGamblingService : IGamblingService, INService
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task<OneOf<BetflipResult, GamblingError>> BetFlipAsync(ulong userId, long amount, int guess)
 | 
			
		||||
    public async Task<OneOf<BetflipResult, GamblingError>> BetFlipAsync(ulong userId, long amount, byte guess)
 | 
			
		||||
    {
 | 
			
		||||
        var isTakeSuccess = await _cs.RemoveAsync(userId, amount, new("betflip", "bet"));
 | 
			
		||||
 | 
			
		||||
@@ -84,11 +85,14 @@ public sealed class NewGamblingService : IGamblingService, INService
 | 
			
		||||
 | 
			
		||||
    public async Task<OneOf<SlotResult, GamblingError>> SlotAsync(ulong userId, long amount)
 | 
			
		||||
    {
 | 
			
		||||
        var isTakeSuccess = await _cs.RemoveAsync(userId, amount, new("slot", "bet"));
 | 
			
		||||
 | 
			
		||||
        if (!isTakeSuccess)
 | 
			
		||||
        if (amount > 0)
 | 
			
		||||
        {
 | 
			
		||||
            return GamblingError.InsufficientFunds;
 | 
			
		||||
            var isTakeSuccess = await _cs.RemoveAsync(userId, amount, new("slot", "bet"));
 | 
			
		||||
 | 
			
		||||
            if (!isTakeSuccess)
 | 
			
		||||
            {
 | 
			
		||||
                return GamblingError.InsufficientFunds;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var game = new SlotGame();
 | 
			
		||||
 
 | 
			
		||||
@@ -231,7 +231,7 @@
 | 
			
		||||
  "not_enough": "You don't have enough {0}",
 | 
			
		||||
  "no_more_cards": "No more cards in the deck.",
 | 
			
		||||
  "raffled_user": "Raffled user",
 | 
			
		||||
  "roll": "You rolled {0}.",
 | 
			
		||||
  "roll2": "Roll",
 | 
			
		||||
  "slot_bet": "Bet",
 | 
			
		||||
  "slot_jackpot": "WOAAHHHHHH!!! Congratulations!!! x{0}",
 | 
			
		||||
  "slot_single": "A single {0}, x{1}",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user