mirror of
				https://gitlab.com/Kwoth/nadekobot.git
				synced 2025-11-04 08:34:27 -05:00 
			
		
		
		
	Reworked currency service. Some features are missing
This commit is contained in:
		@@ -342,6 +342,7 @@ resharper_place_simple_embedded_statement_on_same_line = false
 | 
			
		||||
resharper_wrap_chained_binary_expressions = chop_if_long
 | 
			
		||||
resharper_wrap_chained_binary_patterns = chop_if_long
 | 
			
		||||
resharper_wrap_chained_method_calls = chop_if_long
 | 
			
		||||
resharper_wrap_object_and_collection_initializer_style = chop_always
 | 
			
		||||
 | 
			
		||||
resharper_csharp_wrap_before_first_type_parameter_constraint = true
 | 
			
		||||
resharper_csharp_place_type_constraints_on_same_line = false
 | 
			
		||||
@@ -349,4 +350,4 @@ resharper_csharp_wrap_before_extends_colon = true
 | 
			
		||||
resharper_csharp_place_constructor_initializer_on_same_line = false
 | 
			
		||||
resharper_force_attribute_style = separate
 | 
			
		||||
resharper_braces_for_ifelse = required_for_multiline
 | 
			
		||||
resharper_arrange_redundant_parentheses_highlighting = hint
 | 
			
		||||
resharper_arrange_redundant_parentheses_highlighting = hint
 | 
			
		||||
 
 | 
			
		||||
@@ -75,7 +75,7 @@ public sealed class AnimalRace : IDisposable
 | 
			
		||||
            if (CurrentPhase != Phase.WaitingForPlayers)
 | 
			
		||||
                throw new AlreadyStartedException();
 | 
			
		||||
 | 
			
		||||
            if (!await _currency.RemoveAsync(userId, "BetRace", bet))
 | 
			
		||||
            if (!await _currency.RemoveAsync(userId, bet, new("animalrace", "bet")))
 | 
			
		||||
                throw new NotEnoughFundsException();
 | 
			
		||||
 | 
			
		||||
            if (_users.Contains(user))
 | 
			
		||||
@@ -100,7 +100,7 @@ public sealed class AnimalRace : IDisposable
 | 
			
		||||
        {
 | 
			
		||||
            foreach (var user in _users)
 | 
			
		||||
                if (user.Bet > 0)
 | 
			
		||||
                    await _currency.AddAsync(user.UserId, "Race refund", user.Bet);
 | 
			
		||||
                    await _currency.AddAsync(user.UserId, user.Bet, new("animalrace", "refund"));
 | 
			
		||||
 | 
			
		||||
            _ = OnStartingFailed?.Invoke(this);
 | 
			
		||||
            CurrentPhase = Phase.Ended;
 | 
			
		||||
@@ -130,8 +130,8 @@ public sealed class AnimalRace : IDisposable
 | 
			
		||||
 | 
			
		||||
            if (FinishedUsers[0].Bet > 0)
 | 
			
		||||
                await _currency.AddAsync(FinishedUsers[0].UserId,
 | 
			
		||||
                    "Won a Race",
 | 
			
		||||
                    FinishedUsers[0].Bet * (_users.Count - 1));
 | 
			
		||||
                    FinishedUsers[0].Bet * (_users.Count - 1),
 | 
			
		||||
                    new("animalrace", "win"));
 | 
			
		||||
 | 
			
		||||
            _ = OnEnded?.Invoke(this);
 | 
			
		||||
        });
 | 
			
		||||
 
 | 
			
		||||
@@ -120,7 +120,7 @@ public class Blackjack
 | 
			
		||||
            if (Players.Count >= 5)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            if (!await _cs.RemoveAsync(user, "BlackJack-gamble", bet, gamble: true)) return false;
 | 
			
		||||
            if (!await _cs.RemoveAsync(user, bet, new("blackjack","gamble"))) return false;
 | 
			
		||||
 | 
			
		||||
            Players.Add(new(user, bet));
 | 
			
		||||
            _= PrintState();
 | 
			
		||||
@@ -210,7 +210,7 @@ public class Blackjack
 | 
			
		||||
 | 
			
		||||
        foreach (var usr in Players)
 | 
			
		||||
            if (usr.State is User.UserState.Won or User.UserState.Blackjack)
 | 
			
		||||
                await _cs.AddAsync(usr.DiscordUser.Id, "BlackJack-win", usr.Bet * 2, true);
 | 
			
		||||
                await _cs.AddAsync(usr.DiscordUser.Id, usr.Bet * 2, new("blackjack", "win"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task<bool> Double(IUser u)
 | 
			
		||||
@@ -234,7 +234,7 @@ public class Blackjack
 | 
			
		||||
            if (CurrentUser != u)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            if (!await _cs.RemoveAsync(u.DiscordUser.Id, "Blackjack-double", u.Bet))
 | 
			
		||||
            if (!await _cs.RemoveAsync(u.DiscordUser.Id, u.Bet, new("blackjack", "double")))
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            u.Bet *= 2;
 | 
			
		||||
 
 | 
			
		||||
@@ -98,7 +98,7 @@ public sealed class Connect4Game : IDisposable
 | 
			
		||||
                {
 | 
			
		||||
                    var __ = OnGameFailedToStart?.Invoke(this);
 | 
			
		||||
                    CurrentPhase = Phase.Ended;
 | 
			
		||||
                    await _cs.AddAsync(_players[0].Value.UserId, "Connect4-refund", _options.Bet, true);
 | 
			
		||||
                    await _cs.AddAsync(_players[0].Value.UserId, _options.Bet, new("connect4", "refund"));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            finally { _locker.Release(); }
 | 
			
		||||
@@ -119,7 +119,7 @@ public sealed class Connect4Game : IDisposable
 | 
			
		||||
            if (bet != _options.Bet) // can't join if bet amount is not the same
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            if (!await _cs.RemoveAsync(userId, "Connect4-bet", bet, true)) // user doesn't have enough money to gamble
 | 
			
		||||
            if (!await _cs.RemoveAsync(userId, bet, new("connect4", "bet"))) // user doesn't have enough money to gamble
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            if (_rng.Next(0, 2) == 0) //rolling from 0-1, if number is 0, join as first player
 | 
			
		||||
@@ -342,13 +342,13 @@ public sealed class Connect4Game : IDisposable
 | 
			
		||||
 | 
			
		||||
        if (result == Result.Draw)
 | 
			
		||||
        {
 | 
			
		||||
            _cs.AddAsync(CurrentPlayer.UserId, "Connect4-draw", _options.Bet, true);
 | 
			
		||||
            _cs.AddAsync(OtherPlayer.UserId, "Connect4-draw", _options.Bet, true);
 | 
			
		||||
            _cs.AddAsync(CurrentPlayer.UserId, _options.Bet, new("connect4", "draw"));
 | 
			
		||||
            _cs.AddAsync(OtherPlayer.UserId, _options.Bet, new("connect4", "draw"));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (winId is not null)
 | 
			
		||||
            _cs.AddAsync(winId.Value, "Connnect4-win", (long)(_options.Bet * 1.98), true);
 | 
			
		||||
            _cs.AddAsync(winId.Value, (long)(_options.Bet * 1.98), new("connect4", "win"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Field GetPlayerPiece(ulong userId)
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,7 @@ public partial class Gambling
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (options.Bet > 0)
 | 
			
		||||
                if (!await _cs.RemoveAsync(ctx.User.Id, "Connect4-bet", options.Bet, true))
 | 
			
		||||
                if (!await _cs.RemoveAsync(ctx.User.Id, options.Bet, new("connect4", "bet")))
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                    _service.Connect4Games.TryRemove(ctx.Channel.Id, out _);
 | 
			
		||||
 
 | 
			
		||||
@@ -76,9 +76,9 @@ public class GameStatusEvent : ICurrencyEvent
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            await _cs.AddBulkAsync(toAward,
 | 
			
		||||
                toAward.Select(_ => "GameStatus Event"),
 | 
			
		||||
                toAward.Select(_ => _amount),
 | 
			
		||||
                true);
 | 
			
		||||
                _amount,
 | 
			
		||||
                new("event", "gamestatus")
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            if (_isPotLimited)
 | 
			
		||||
                await msg.ModifyAsync(m =>
 | 
			
		||||
 
 | 
			
		||||
@@ -71,7 +71,7 @@ public class ReactionEvent : ICurrencyEvent
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            await _cs.AddBulkAsync(toAward, toAward.Select(_ => "Reaction Event"), toAward.Select(_ => _amount), true);
 | 
			
		||||
            await _cs.AddBulkAsync(toAward, _amount, new("event", "reaction"));
 | 
			
		||||
 | 
			
		||||
            if (_isPotLimited)
 | 
			
		||||
                await msg.ModifyAsync(m =>
 | 
			
		||||
 
 | 
			
		||||
@@ -80,7 +80,7 @@ public partial class Gambling
 | 
			
		||||
            if (!await CheckBetMandatory(amount) || amount == 1)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var removed = await _cs.RemoveAsync(ctx.User, "Betflip Gamble", amount, false, true);
 | 
			
		||||
            var removed = await _cs.RemoveAsync(ctx.User, amount, new("betflip", "bet"));
 | 
			
		||||
            if (!removed)
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
@@ -106,7 +106,7 @@ public partial class Gambling
 | 
			
		||||
            {
 | 
			
		||||
                var toWin = (long)(amount * Config.BetFlip.Multiplier);
 | 
			
		||||
                str = Format.Bold(ctx.User.ToString()) + " " + GetText(strs.flip_guess(toWin + CurrencySign));
 | 
			
		||||
                await _cs.AddAsync(ctx.User, "Betflip Gamble", toWin, false, true);
 | 
			
		||||
                await _cs.AddAsync(ctx.User, toWin, new("betflip", "win"));
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,12 +3,14 @@ using NadekoBot.Db;
 | 
			
		||||
using NadekoBot.Db.Models;
 | 
			
		||||
using NadekoBot.Modules.Gambling.Common;
 | 
			
		||||
using NadekoBot.Modules.Gambling.Services;
 | 
			
		||||
using NadekoBot.Services.Currency;
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.Numerics;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Gambling;
 | 
			
		||||
 | 
			
		||||
// todo leave empty servers
 | 
			
		||||
public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
{
 | 
			
		||||
    public enum RpsPick
 | 
			
		||||
@@ -67,10 +69,11 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        return cur.ToString("C0", flowersCi);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public string GetCurrency(ulong id)
 | 
			
		||||
    public async Task<string> GetBalanceStringAsync(ulong userId)
 | 
			
		||||
    {
 | 
			
		||||
        using var uow = _db.GetDbContext();
 | 
			
		||||
        return n(uow.DiscordUser.GetUserCurrency(id));
 | 
			
		||||
        var wallet = await _cs.GetWalletAsync(userId);
 | 
			
		||||
        var bal = await wallet.GetBalance();
 | 
			
		||||
        return n(bal);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -78,9 +81,11 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
    {
 | 
			
		||||
        var ec = _service.GetEconomy();
 | 
			
		||||
        decimal onePercent = 0;
 | 
			
		||||
        
 | 
			
		||||
        // This stops the top 1% from owning more than 100% of the money
 | 
			
		||||
        if (ec.Cash > 0)
 | 
			
		||||
            onePercent =
 | 
			
		||||
                ec.OnePercent / (ec.Cash - ec.Bot); // This stops the top 1% from owning more than 100% of the money
 | 
			
		||||
            onePercent = ec.OnePercent / (ec.Cash - ec.Bot);
 | 
			
		||||
        
 | 
			
		||||
        // [21:03] Bob Page: Kinda remids me of US economy
 | 
			
		||||
        var embed = _eb.Create()
 | 
			
		||||
                       .WithTitle(GetText(strs.economy_state))
 | 
			
		||||
@@ -93,6 +98,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
                       .AddField(GetText(strs.total),
 | 
			
		||||
                           ((BigInteger)(ec.Cash + ec.Planted + ec.Waifus)).ToString("N", Culture) + CurrencySign)
 | 
			
		||||
                       .WithOkColor();
 | 
			
		||||
        
 | 
			
		||||
        // ec.Cash already contains ec.Bot as it's the total of all values in the CurrencyAmount column of the DiscordUser table
 | 
			
		||||
        await ctx.Channel.EmbedAsync(embed);
 | 
			
		||||
    }
 | 
			
		||||
@@ -114,7 +120,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await _cs.AddAsync(ctx.User.Id, "Timely claim", val);
 | 
			
		||||
        await _cs.AddAsync(ctx.User.Id, val, new("timely", "claim"));
 | 
			
		||||
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.timely(n(val), period));
 | 
			
		||||
    }
 | 
			
		||||
@@ -225,14 +231,18 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
    [Cmd]
 | 
			
		||||
    [Priority(0)]
 | 
			
		||||
    public async partial Task Cash(ulong userId)
 | 
			
		||||
        => await ReplyConfirmLocalizedAsync(strs.has(Format.Code(userId.ToString()), $"{GetCurrency(userId)}"));
 | 
			
		||||
    {
 | 
			
		||||
        var cur = await GetBalanceStringAsync(userId);
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.has(Format.Code(userId.ToString()), cur));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
    [Priority(1)]
 | 
			
		||||
    public async partial Task Cash([Leftover] IUser user = null)
 | 
			
		||||
    {
 | 
			
		||||
        user ??= ctx.User;
 | 
			
		||||
        await ConfirmLocalizedAsync(strs.has(Format.Bold(user.ToString()), $"{GetCurrency(user.Id)}"));
 | 
			
		||||
        var cur = await GetBalanceStringAsync(user.Id);
 | 
			
		||||
        await ConfirmLocalizedAsync(strs.has(Format.Bold(user.ToString()), cur));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
@@ -242,15 +252,13 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
    {
 | 
			
		||||
        if (amount <= 0 || ctx.User.Id == receiver.Id || receiver.IsBot)
 | 
			
		||||
            return;
 | 
			
		||||
        var success =
 | 
			
		||||
            await _cs.RemoveAsync((IGuildUser)ctx.User, $"Gift to {receiver.Username} ({receiver.Id}).", amount);
 | 
			
		||||
        if (!success)
 | 
			
		||||
        
 | 
			
		||||
        if (!await _cs.TransferAsync(ctx.User.Id, receiver.Id, amount, msg))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await _cs.AddAsync(receiver, $"Gift from {ctx.User.Username} ({ctx.User.Id}) - {msg}.", amount, true);
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.gifted(n(amount), Format.Bold(receiver.ToString())));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -290,10 +298,10 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await _cs.AddAsync(usr,
 | 
			
		||||
            $"Awarded by bot owner. ({ctx.User.Username}/{ctx.User.Id}) {msg ?? ""}",
 | 
			
		||||
        await _cs.AddAsync(usr.Id,
 | 
			
		||||
            amount,
 | 
			
		||||
            gamble: ctx.Client.CurrentUser.Id != usrId);
 | 
			
		||||
            new Extra("owner", "award", $"Awarded by bot owner. ({ctx.User.Username}/{ctx.User.Id}) {msg ?? ""}")
 | 
			
		||||
        );
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.awarded(n(amount), $"<@{usrId}>"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -305,10 +313,11 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
    {
 | 
			
		||||
        var users = (await ctx.Guild.GetUsersAsync()).Where(u => u.GetRoles().Contains(role)).ToList();
 | 
			
		||||
 | 
			
		||||
        await _cs.AddBulkAsync(users.Select(x => x.Id),
 | 
			
		||||
            users.Select(_ => $"Awarded by bot owner to **{role.Name}** role. ({ctx.User.Username}/{ctx.User.Id})"),
 | 
			
		||||
            users.Select(_ => amount),
 | 
			
		||||
            true);
 | 
			
		||||
        await _cs.AddBulkAsync(users.Select(x => x.Id).ToList(),
 | 
			
		||||
            amount,
 | 
			
		||||
            new("owner",
 | 
			
		||||
                "award",
 | 
			
		||||
                $"Awarded by bot owner to **{role.Name}** role. ({ctx.User.Username}/{ctx.User.Id})"));
 | 
			
		||||
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.mass_award(n(amount),
 | 
			
		||||
            Format.Bold(users.Count.ToString()),
 | 
			
		||||
@@ -323,10 +332,9 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
    {
 | 
			
		||||
        var users = (await role.GetMembersAsync()).ToList();
 | 
			
		||||
 | 
			
		||||
        await _cs.RemoveBulkAsync(users.Select(x => x.Id),
 | 
			
		||||
            users.Select(_ => $"Taken by bot owner from **{role.Name}** role. ({ctx.User.Username}/{ctx.User.Id})"),
 | 
			
		||||
            users.Select(_ => amount),
 | 
			
		||||
            true);
 | 
			
		||||
        await _cs.RemoveBulkAsync(users.Select(x => x.Id).ToList(),
 | 
			
		||||
            amount,
 | 
			
		||||
            new("owner", "take", $"Taken by bot owner from **{role.Name}** role. ({ctx.User.Username}/{ctx.User.Id})"));
 | 
			
		||||
 | 
			
		||||
        await ReplyConfirmLocalizedAsync(strs.mass_take(n(amount),
 | 
			
		||||
            Format.Bold(users.Count.ToString()),
 | 
			
		||||
@@ -342,10 +350,9 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        if (amount <= 0)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (await _cs.RemoveAsync(user,
 | 
			
		||||
                $"Taken by bot owner.({ctx.User.Username}/{ctx.User.Id})",
 | 
			
		||||
        if (await _cs.RemoveAsync(user.Id,
 | 
			
		||||
                amount,
 | 
			
		||||
                gamble: ctx.Client.CurrentUser.Id != user.Id))
 | 
			
		||||
                new("owner", "take", $"Taken by bot owner. ({ctx.User.Username}/{ctx.User.Id})")))
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.take(n(amount), Format.Bold(user.ToString())));
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.take_fail(n(amount), Format.Bold(user.ToString()), CurrencySign));
 | 
			
		||||
@@ -360,9 +367,8 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (await _cs.RemoveAsync(usrId,
 | 
			
		||||
                $"Taken by bot owner.({ctx.User.Username}/{ctx.User.Id})",
 | 
			
		||||
                amount,
 | 
			
		||||
                ctx.Client.CurrentUser.Id != usrId))
 | 
			
		||||
                new("owner", "take", $"Taken by bot owner. ({ctx.User.Username}/{ctx.User.Id})")))
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.take(n(amount), $"<@{usrId}>"));
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.take_fail(n(amount), Format.Code(usrId.ToString()), CurrencySign));
 | 
			
		||||
@@ -467,7 +473,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        if (!await CheckBetMandatory(amount))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (!await _cs.RemoveAsync(ctx.User, "Betroll Gamble", amount, false, true))
 | 
			
		||||
        if (!await _cs.RemoveAsync(ctx.User, amount, new("betroll", "bet")))
 | 
			
		||||
        {
 | 
			
		||||
            await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
            return;
 | 
			
		||||
@@ -483,7 +489,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        {
 | 
			
		||||
            var win = (long)(amount * result.Multiplier);
 | 
			
		||||
            str += GetText(strs.br_win(n(win), result.Threshold + (result.Roll == 100 ? " 👑" : "")));
 | 
			
		||||
            await _cs.AddAsync(ctx.User, "Betroll Gamble", win, false, true);
 | 
			
		||||
            await _cs.AddAsync(ctx.User, win, new("betroll", "win"));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
@@ -600,16 +606,20 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
        var nadekoPick = (RpsPick)new NadekoRandom().Next(0, 3);
 | 
			
		||||
 | 
			
		||||
        if (amount > 0)
 | 
			
		||||
            if (!await _cs.RemoveAsync(ctx.User.Id, "Rps-bet", amount, true))
 | 
			
		||||
        {
 | 
			
		||||
            if (!await _cs.RemoveAsync(ctx.User.Id,
 | 
			
		||||
                    amount,
 | 
			
		||||
                    new("rps", "bet", "")))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        string msg;
 | 
			
		||||
        if (pick == nadekoPick)
 | 
			
		||||
        {
 | 
			
		||||
            await _cs.AddAsync(ctx.User.Id, "Rps-draw", amount, true);
 | 
			
		||||
            await _cs.AddAsync(ctx.User.Id, amount, new("rps", "draw"));
 | 
			
		||||
            embed.WithOkColor();
 | 
			
		||||
            msg = GetText(strs.rps_draw(GetRpsPick(pick)));
 | 
			
		||||
        }
 | 
			
		||||
@@ -618,7 +628,7 @@ public partial class Gambling : GamblingModule<GamblingService>
 | 
			
		||||
                 || (pick == RpsPick.Scissors && nadekoPick == RpsPick.Paper))
 | 
			
		||||
        {
 | 
			
		||||
            amount = (long)(amount * Config.BetFlip.Multiplier);
 | 
			
		||||
            await _cs.AddAsync(ctx.User.Id, "Rps-win", amount, true);
 | 
			
		||||
            await _cs.AddAsync(ctx.User.Id, amount, new("rps", "win"));
 | 
			
		||||
            embed.WithOkColor();
 | 
			
		||||
            embed.AddField(GetText(strs.won), n(amount));
 | 
			
		||||
            msg = GetText(strs.rps_win(ctx.User.Mention, GetRpsPick(pick), GetRpsPick(nadekoPick)));
 | 
			
		||||
 
 | 
			
		||||
@@ -83,7 +83,7 @@ WHERE CurrencyAmount > {config.Decay.MinThreshold} AND UserId!={_client.CurrentU
 | 
			
		||||
 | 
			
		||||
    public async Task<SlotResponse> SlotAsync(ulong userId, long amount)
 | 
			
		||||
    {
 | 
			
		||||
        var takeRes = await _cs.RemoveAsync(userId, "Slot Machine", amount, true);
 | 
			
		||||
        var takeRes = await _cs.RemoveAsync(userId, amount, new("slot", "bet"));
 | 
			
		||||
 | 
			
		||||
        if (!takeRes)
 | 
			
		||||
            return new() { Error = GamblingError.NotEnough };
 | 
			
		||||
@@ -96,7 +96,7 @@ WHERE CurrencyAmount > {config.Decay.MinThreshold} AND UserId!={_client.CurrentU
 | 
			
		||||
        {
 | 
			
		||||
            won = (long)(result.Multiplier * amount);
 | 
			
		||||
 | 
			
		||||
            await _cs.AddAsync(userId, $"Slot Machine x{result.Multiplier}", won, true);
 | 
			
		||||
            await _cs.AddAsync(userId, won, new("slot", "win", $"Slot Machine x{result.Multiplier}"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var toReturn = new SlotResponse { Multiplier = result.Multiplier, Won = won };
 | 
			
		||||
 
 | 
			
		||||
@@ -270,7 +270,7 @@ public class PlantPickService : INService
 | 
			
		||||
 | 
			
		||||
                if (amount > 0)
 | 
			
		||||
                    // give the picked currency to the user
 | 
			
		||||
                    await _cs.AddAsync(uid, "Picked currency", amount);
 | 
			
		||||
                    await _cs.AddAsync(uid, amount, new("currency", "collect"));
 | 
			
		||||
                uow.SaveChanges();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -337,14 +337,14 @@ public class PlantPickService : INService
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        // remove currency from the user who's planting
 | 
			
		||||
        if (await _cs.RemoveAsync(uid, "Planted currency", amount))
 | 
			
		||||
        if (await _cs.RemoveAsync(uid, amount, new("put/collect", "put")))
 | 
			
		||||
        {
 | 
			
		||||
            // try to send the message with the currency image
 | 
			
		||||
            var msgId = await SendPlantMessageAsync(gid, ch, user, amount, pass);
 | 
			
		||||
            if (msgId is null)
 | 
			
		||||
            {
 | 
			
		||||
                // if it fails it will return null, if it returns null, refund
 | 
			
		||||
                await _cs.AddAsync(uid, "Planted currency refund", amount);
 | 
			
		||||
                await _cs.AddAsync(uid, amount, new("put/collect", "refund"));
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ public class CurrencyRaffleService : INService
 | 
			
		||||
 | 
			
		||||
            //remove money, and stop the game if this 
 | 
			
		||||
            // user created it and doesn't have the money
 | 
			
		||||
            if (!await _cs.RemoveAsync(user.Id, "Currency Raffle Join", amount))
 | 
			
		||||
            if (!await _cs.RemoveAsync(user.Id, amount, new("raffle", "join")))
 | 
			
		||||
            {
 | 
			
		||||
                if (newGame)
 | 
			
		||||
                    Games.Remove(channelId);
 | 
			
		||||
@@ -47,7 +47,7 @@ public class CurrencyRaffleService : INService
 | 
			
		||||
 | 
			
		||||
            if (!crg.AddUser(user, amount))
 | 
			
		||||
            {
 | 
			
		||||
                await _cs.AddAsync(user.Id, "Curency Raffle Refund", amount);
 | 
			
		||||
                await _cs.AddAsync(user.Id, amount, new("raffle", "refund"));
 | 
			
		||||
                return (null, JoinErrorType.AlreadyJoinedOrInvalidAmount);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -62,7 +62,7 @@ public class CurrencyRaffleService : INService
 | 
			
		||||
                        var winner = crg.GetWinner();
 | 
			
		||||
                        var won = crg.Users.Sum(x => x.Amount);
 | 
			
		||||
 | 
			
		||||
                        await _cs.AddAsync(winner.DiscordUser.Id, "Currency Raffle Win", won);
 | 
			
		||||
                        await _cs.AddAsync(winner.DiscordUser.Id, won, new("raffle", "win"));
 | 
			
		||||
                        Games.Remove(channelId, out _);
 | 
			
		||||
                        _ = onEnded(winner.DiscordUser, won);
 | 
			
		||||
                    }
 | 
			
		||||
 
 | 
			
		||||
@@ -115,7 +115,7 @@ public partial class Gambling
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (await _cs.RemoveAsync(ctx.User.Id, $"Shop purchase - {entry.Type}", entry.Price))
 | 
			
		||||
                if (await _cs.RemoveAsync(ctx.User.Id, entry.Price, new("shop", "buy", entry.Type.ToString())))
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
@@ -124,14 +124,14 @@ public partial class Gambling
 | 
			
		||||
                    catch (Exception ex)
 | 
			
		||||
                    {
 | 
			
		||||
                        Log.Warning(ex, "Error adding shop role");
 | 
			
		||||
                        await _cs.AddAsync(ctx.User.Id, "Shop error refund", entry.Price);
 | 
			
		||||
                        await _cs.AddAsync(ctx.User.Id, entry.Price, new("shop", "error-refund"));
 | 
			
		||||
                        await ReplyErrorLocalizedAsync(strs.shop_role_purchase_error);
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    var profit = GetProfitAmount(entry.Price);
 | 
			
		||||
                    await _cs.AddAsync(entry.AuthorId, $"Shop sell item - {entry.Type}", profit);
 | 
			
		||||
                    await _cs.AddAsync(ctx.Client.CurrentUser.Id, "Shop sell item - cut", entry.Price - profit);
 | 
			
		||||
                    await _cs.AddAsync(entry.AuthorId, profit, new("shop", "sell", $"Shop sell item - {entry.Type}"));
 | 
			
		||||
                    await _cs.AddAsync(ctx.Client.CurrentUser.Id, entry.Price - profit, new("shop", "cut"));
 | 
			
		||||
                    await ReplyConfirmLocalizedAsync(strs.shop_role_purchase(Format.Bold(role.Name)));
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
@@ -150,7 +150,7 @@ public partial class Gambling
 | 
			
		||||
 | 
			
		||||
                var item = entry.Items.ToArray()[new NadekoRandom().Next(0, entry.Items.Count)];
 | 
			
		||||
 | 
			
		||||
                if (await _cs.RemoveAsync(ctx.User.Id, $"Shop purchase - {entry.Type}", entry.Price))
 | 
			
		||||
                if (await _cs.RemoveAsync(ctx.User.Id, entry.Price, new("shop", "buy", entry.Type.ToString())))
 | 
			
		||||
                {
 | 
			
		||||
                    await using (var uow = _db.GetDbContext())
 | 
			
		||||
                    {
 | 
			
		||||
@@ -168,12 +168,12 @@ public partial class Gambling
 | 
			
		||||
                                                     .AddField(GetText(strs.name), entry.Name, true));
 | 
			
		||||
 | 
			
		||||
                        await _cs.AddAsync(entry.AuthorId,
 | 
			
		||||
                            $"Shop sell item - {entry.Name}",
 | 
			
		||||
                            GetProfitAmount(entry.Price));
 | 
			
		||||
                            GetProfitAmount(entry.Price),
 | 
			
		||||
                            new("shop", "sell", entry.Name));
 | 
			
		||||
                    }
 | 
			
		||||
                    catch
 | 
			
		||||
                    {
 | 
			
		||||
                        await _cs.AddAsync(ctx.User.Id, $"Shop error refund - {entry.Name}", entry.Price);
 | 
			
		||||
                        await _cs.AddAsync(ctx.User.Id, entry.Price, new("shop", "error-refund", entry.Name));
 | 
			
		||||
                        await using (var uow = _db.GetDbContext())
 | 
			
		||||
                        {
 | 
			
		||||
                            var entries = new IndexedCollection<ShopEntry>(uow.GuildConfigsForId(ctx.Guild.Id,
 | 
			
		||||
@@ -411,6 +411,7 @@ public partial class Gambling
 | 
			
		||||
            var embed = _eb.Create().WithOkColor();
 | 
			
		||||
 | 
			
		||||
            if (entry.Type == ShopEntryType.Role)
 | 
			
		||||
            {
 | 
			
		||||
                return embed
 | 
			
		||||
                       .AddField(GetText(strs.name),
 | 
			
		||||
                           GetText(strs.shop_role(Format.Bold(ctx.Guild.GetRole(entry.RoleId)?.Name
 | 
			
		||||
@@ -418,10 +419,15 @@ public partial class Gambling
 | 
			
		||||
                           true)
 | 
			
		||||
                       .AddField(GetText(strs.price), entry.Price.ToString(), true)
 | 
			
		||||
                       .AddField(GetText(strs.type), entry.Type.ToString(), true);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (entry.Type == ShopEntryType.List)
 | 
			
		||||
            {
 | 
			
		||||
                return embed.AddField(GetText(strs.name), entry.Name, true)
 | 
			
		||||
                            .AddField(GetText(strs.price), entry.Price.ToString(), true)
 | 
			
		||||
                            .AddField(GetText(strs.type), GetText(strs.random_unique_item), true);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //else if (entry.Type == ShopEntryType.Infinite_List)
 | 
			
		||||
            //    return embed.AddField(GetText(strs.name), GetText(strs.shop_role(Format.Bold(entry.RoleName)), true))
 | 
			
		||||
            //            .AddField(GetText(strs.price), entry.Price.ToString(), true)
 | 
			
		||||
 
 | 
			
		||||
@@ -61,9 +61,8 @@ public class VoteRewardService : INService, IReadyExecutor
 | 
			
		||||
                        var ids = data.Select(x => x.UserId).ToList();
 | 
			
		||||
 | 
			
		||||
                        await _currencyService.AddBulkAsync(ids,
 | 
			
		||||
                            data.Select(_ => "top.gg vote reward"),
 | 
			
		||||
                            data.Select(_ => _gamb.Data.VoteReward),
 | 
			
		||||
                            true);
 | 
			
		||||
                            _gamb.Data.VoteReward,
 | 
			
		||||
                            new("vote", "top.gg", "top.gg vote reward"));
 | 
			
		||||
 | 
			
		||||
                        Log.Information("Rewarding {Count} top.gg voters", ids.Count());
 | 
			
		||||
                    }
 | 
			
		||||
@@ -90,9 +89,8 @@ public class VoteRewardService : INService, IReadyExecutor
 | 
			
		||||
                        var ids = data.Select(x => x.UserId).ToList();
 | 
			
		||||
 | 
			
		||||
                        await _currencyService.AddBulkAsync(ids,
 | 
			
		||||
                            data.Select(_ => "discords.com vote reward"),
 | 
			
		||||
                            data.Select(_ => _gamb.Data.VoteReward),
 | 
			
		||||
                            true);
 | 
			
		||||
                            _gamb.Data.VoteReward,
 | 
			
		||||
                            new("vote", "discords", "discords.com vote reward"));
 | 
			
		||||
 | 
			
		||||
                        Log.Information("Rewarding {Count} discords.com voters", ids.Count());
 | 
			
		||||
                    }
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@ public class WaifuService : INService
 | 
			
		||||
        // if waifu likes the person, gotta pay the penalty
 | 
			
		||||
        if (waifu.AffinityId == ownerUser.Id)
 | 
			
		||||
        {
 | 
			
		||||
            if (!await _cs.RemoveAsync(owner.Id, "Waifu Transfer - affinity penalty", (int)(waifu.Price * 0.6), true))
 | 
			
		||||
            if (!await _cs.RemoveAsync(owner.Id, (int)(waifu.Price * 0.6), new("waifu", "affinity-penalty")))
 | 
			
		||||
                // unable to pay 60% penalty
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
@@ -55,7 +55,7 @@ public class WaifuService : INService
 | 
			
		||||
        }
 | 
			
		||||
        else // if not, pay 10% fee
 | 
			
		||||
        {
 | 
			
		||||
            if (!await _cs.RemoveAsync(owner.Id, "Waifu Transfer", waifu.Price / 10, true)) return false;
 | 
			
		||||
            if (!await _cs.RemoveAsync(owner.Id, waifu.Price / 10, new("waifu", "transfer"))) return false;
 | 
			
		||||
 | 
			
		||||
            waifu.Price = (int)(waifu.Price * 0.95); // half of 10% = 5% price reduction
 | 
			
		||||
            if (waifu.Price < settings.Waifu.MinPrice)
 | 
			
		||||
@@ -97,7 +97,7 @@ public class WaifuService : INService
 | 
			
		||||
    {
 | 
			
		||||
        await using var uow = _db.GetDbContext();
 | 
			
		||||
        var price = GetResetPrice(user);
 | 
			
		||||
        if (!await _cs.RemoveAsync(user.Id, "Waifu Reset", price, true))
 | 
			
		||||
        if (!await _cs.RemoveAsync(user.Id, price, new("waifu", "reset")))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        var affs = uow.WaifuUpdates.AsQueryable()
 | 
			
		||||
@@ -144,7 +144,7 @@ public class WaifuService : INService
 | 
			
		||||
            {
 | 
			
		||||
                var claimer = uow.GetOrCreateUser(user);
 | 
			
		||||
                var waifu = uow.GetOrCreateUser(target);
 | 
			
		||||
                if (!await _cs.RemoveAsync(user.Id, "Claimed Waifu", amount, true))
 | 
			
		||||
                if (!await _cs.RemoveAsync(user.Id, amount, new("waifu", "claim")))
 | 
			
		||||
                {
 | 
			
		||||
                    result = WaifuClaimResult.NotEnoughFunds;
 | 
			
		||||
                }
 | 
			
		||||
@@ -160,7 +160,7 @@ public class WaifuService : INService
 | 
			
		||||
            }
 | 
			
		||||
            else if (isAffinity && amount > w.Price * settings.Waifu.Multipliers.CrushClaim)
 | 
			
		||||
            {
 | 
			
		||||
                if (!await _cs.RemoveAsync(user.Id, "Claimed Waifu", amount, true))
 | 
			
		||||
                if (!await _cs.RemoveAsync(user.Id, amount, new("waifu", "claim")))
 | 
			
		||||
                {
 | 
			
		||||
                    result = WaifuClaimResult.NotEnoughFunds;
 | 
			
		||||
                }
 | 
			
		||||
@@ -179,7 +179,7 @@ public class WaifuService : INService
 | 
			
		||||
            }
 | 
			
		||||
            else if (amount >= w.Price * settings.Waifu.Multipliers.NormalClaim) // if no affinity
 | 
			
		||||
            {
 | 
			
		||||
                if (!await _cs.RemoveAsync(user.Id, "Claimed Waifu", amount, true))
 | 
			
		||||
                if (!await _cs.RemoveAsync(user.Id, amount, new("waifu", "claim")))
 | 
			
		||||
                {
 | 
			
		||||
                    result = WaifuClaimResult.NotEnoughFunds;
 | 
			
		||||
                }
 | 
			
		||||
@@ -288,13 +288,13 @@ public class WaifuService : INService
 | 
			
		||||
 | 
			
		||||
                if (w.Affinity?.UserId == user.Id)
 | 
			
		||||
                {
 | 
			
		||||
                    await _cs.AddAsync(w.Waifu.UserId, "Waifu Compensation", amount, true);
 | 
			
		||||
                    await _cs.AddAsync(w.Waifu.UserId, amount, new("waifu", "compensation"));
 | 
			
		||||
                    w.Price = (int)Math.Floor(w.Price * _gss.Data.Waifu.Multipliers.DivorceNewValue);
 | 
			
		||||
                    result = DivorceResult.SucessWithPenalty;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    await _cs.AddAsync(user.Id, "Waifu Refund", amount, true);
 | 
			
		||||
                    await _cs.AddAsync(user.Id, amount, new("waifu", "refund"));
 | 
			
		||||
 | 
			
		||||
                    result = DivorceResult.Success;
 | 
			
		||||
                }
 | 
			
		||||
@@ -316,7 +316,7 @@ public class WaifuService : INService
 | 
			
		||||
 | 
			
		||||
    public async Task<bool> GiftWaifuAsync(IUser from, IUser giftedWaifu, WaifuItemModel itemObj)
 | 
			
		||||
    {
 | 
			
		||||
        if (!await _cs.RemoveAsync(from, "Bought waifu item", itemObj.Price, gamble: true)) return false;
 | 
			
		||||
        if (!await _cs.RemoveAsync(from, itemObj.Price, new("waifu", "item"))) return false;
 | 
			
		||||
 | 
			
		||||
        await using var uow = _db.GetDbContext();
 | 
			
		||||
        var w = uow.WaifuInfo.ByWaifuUserId(giftedWaifu.Id, set => set.Include(x => x.Items).Include(x => x.Claimer));
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ public class WheelOfFortuneGame
 | 
			
		||||
        var amount = (long)(_bet * _config.WheelOfFortune.Multipliers[result]);
 | 
			
		||||
 | 
			
		||||
        if (amount > 0)
 | 
			
		||||
            await _cs.AddAsync(_userId, "Wheel Of Fortune - won", amount, true);
 | 
			
		||||
            await _cs.AddAsync(_userId, amount, new("wheel", "win"));
 | 
			
		||||
 | 
			
		||||
        return new() { Index = result, Amount = amount };
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ public partial class Gambling
 | 
			
		||||
            if (!await CheckBetMandatory(amount))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            if (!await _cs.RemoveAsync(ctx.User.Id, "Wheel Of Fortune - bet", amount, true))
 | 
			
		||||
            if (!await _cs.RemoveAsync(ctx.User.Id, amount, new("wheel", "bet")))
 | 
			
		||||
            {
 | 
			
		||||
                await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
 | 
			
		||||
                return;
 | 
			
		||||
 
 | 
			
		||||
@@ -86,16 +86,16 @@ public class RollDuelGame
 | 
			
		||||
            _locker.Release();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!await _cs.RemoveAsync(P1, "Roll Duel", Amount))
 | 
			
		||||
        if (!await _cs.RemoveAsync(P1, Amount, new("rollduel", "bet")))
 | 
			
		||||
        {
 | 
			
		||||
            await OnEnded?.Invoke(this, Reason.NoFunds);
 | 
			
		||||
            CurrentState = State.Ended;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!await _cs.RemoveAsync(P2, "Roll Duel", Amount))
 | 
			
		||||
        if (!await _cs.RemoveAsync(P2, Amount, new("rollduel", "bet")))
 | 
			
		||||
        {
 | 
			
		||||
            await _cs.AddAsync(P1, "Roll Duel - refund", Amount);
 | 
			
		||||
            await _cs.AddAsync(P1, Amount, new("rollduel", "refund"));
 | 
			
		||||
            await OnEnded?.Invoke(this, Reason.NoFunds);
 | 
			
		||||
            CurrentState = State.Ended;
 | 
			
		||||
            return;
 | 
			
		||||
@@ -114,9 +114,9 @@ public class RollDuelGame
 | 
			
		||||
                else
 | 
			
		||||
                    Winner = P2;
 | 
			
		||||
                var won = (long)(Amount * 2 * 0.98f);
 | 
			
		||||
                await _cs.AddAsync(Winner, "Roll Duel win", won);
 | 
			
		||||
                await _cs.AddAsync(Winner, won, new("rollduel", "win"));
 | 
			
		||||
 | 
			
		||||
                await _cs.AddAsync(_botId, "Roll Duel fee", (Amount * 2) - won);
 | 
			
		||||
                await _cs.AddAsync(_botId, (Amount * 2) - won, new("rollduel", "fee"));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            try { await OnGameTick?.Invoke(this); }
 | 
			
		||||
 
 | 
			
		||||
@@ -96,7 +96,7 @@ public sealed class HangmanService : IHangmanService, ILateExecutor
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (rew > 0)
 | 
			
		||||
                await _cs.AddAsync(msg.Author, "hangman win", rew, gamble: true);
 | 
			
		||||
                await _cs.AddAsync(msg.Author, rew, new("hangman", "win"));
 | 
			
		||||
 | 
			
		||||
            await SendState((ITextChannel)msg.Channel, msg.Author, msg.Content, state);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -251,7 +251,7 @@ public class TriviaGame
 | 
			
		||||
 | 
			
		||||
                    var reward = _config.Trivia.CurrencyReward;
 | 
			
		||||
                    if (reward > 0)
 | 
			
		||||
                        await _cs.AddAsync(guildUser, "Won trivia", reward, true);
 | 
			
		||||
                        await _cs.AddAsync(guildUser, reward, new("trivia", "win"));
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -234,7 +234,7 @@ public class PatreonRewardsService : INService, IReadyExecutor
 | 
			
		||||
 | 
			
		||||
                await uow.SaveChangesAsync();
 | 
			
		||||
 | 
			
		||||
                await _currency.AddAsync(userId, "Patreon reward - new", eligibleFor, true);
 | 
			
		||||
                await _currency.AddAsync(userId, eligibleFor, new("patreon", "new"));
 | 
			
		||||
 | 
			
		||||
                Log.Information("Sending new currency reward to {UserId}", userId);
 | 
			
		||||
                await SendMessageToUser(userId,
 | 
			
		||||
@@ -249,7 +249,7 @@ public class PatreonRewardsService : INService, IReadyExecutor
 | 
			
		||||
 | 
			
		||||
                await uow.SaveChangesAsync();
 | 
			
		||||
 | 
			
		||||
                await _currency.AddAsync(userId, "Patreon reward - recurring", eligibleFor, true);
 | 
			
		||||
                await _currency.AddAsync(userId, eligibleFor, new("patreon", "recurring"));
 | 
			
		||||
 | 
			
		||||
                Log.Information("Sending recurring currency reward to {UserId}", userId);
 | 
			
		||||
                await SendMessageToUser(userId,
 | 
			
		||||
@@ -267,7 +267,7 @@ public class PatreonRewardsService : INService, IReadyExecutor
 | 
			
		||||
                usr.AmountRewardedThisMonth = toAward;
 | 
			
		||||
                await uow.SaveChangesAsync();
 | 
			
		||||
 | 
			
		||||
                await _currency.AddAsync(userId, "Patreon reward - update", toAward, true);
 | 
			
		||||
                await _currency.AddAsync(userId, toAward, new("patreon", "update"));
 | 
			
		||||
 | 
			
		||||
                Log.Information("Sending updated currency reward to {UserId}", userId);
 | 
			
		||||
                await SendMessageToUser(userId,
 | 
			
		||||
 
 | 
			
		||||
@@ -210,7 +210,7 @@ public class XpService : INService
 | 
			
		||||
                                var crew = crews.FirstOrDefault(x => x.Level == i);
 | 
			
		||||
                                if (crew is not null)
 | 
			
		||||
                                    //give the user the reward if it exists
 | 
			
		||||
                                    await _cs.AddAsync(item.Key.User.Id, "Level-up Reward", crew.Amount);
 | 
			
		||||
                                    await _cs.AddAsync(item.Key.User.Id, crew.Amount, new("xp", "level-up"));
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										123
									
								
								src/NadekoBot/Services/Currency/CurrencyService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								src/NadekoBot/Services/Currency/CurrencyService.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,123 @@
 | 
			
		||||
#nullable disable
 | 
			
		||||
using LinqToDB;
 | 
			
		||||
using NadekoBot.Services.Currency;
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Services;
 | 
			
		||||
 | 
			
		||||
public class CurrencyService : ICurrencyService, INService
 | 
			
		||||
{
 | 
			
		||||
    private readonly DbService _db;
 | 
			
		||||
 | 
			
		||||
    public CurrencyService(DbService db)
 | 
			
		||||
        => _db = db;
 | 
			
		||||
 | 
			
		||||
    public Task<IWallet> GetWalletAsync(ulong userId, CurrencyType type = CurrencyType.Default)
 | 
			
		||||
    {
 | 
			
		||||
        if (type == CurrencyType.Default)
 | 
			
		||||
        {
 | 
			
		||||
            return Task.FromResult<IWallet>(new DefaultWallet(userId, _db.GetDbContext()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        throw new ArgumentOutOfRangeException(nameof(type));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task AddBulkAsync(
 | 
			
		||||
        IReadOnlyCollection<ulong> userIds,
 | 
			
		||||
        long amount,
 | 
			
		||||
        Extra extra,
 | 
			
		||||
        CurrencyType type = CurrencyType.Default)
 | 
			
		||||
    {
 | 
			
		||||
        if (type == CurrencyType.Default)
 | 
			
		||||
        {
 | 
			
		||||
            await using var ctx = _db.GetDbContext();
 | 
			
		||||
            foreach (var userId in userIds)
 | 
			
		||||
            {
 | 
			
		||||
                var wallet = new DefaultWallet(userId, ctx);
 | 
			
		||||
                await wallet.Add(amount, extra);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ctx.SaveChangesAsync();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        throw new ArgumentOutOfRangeException(nameof(type));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task RemoveBulkAsync(
 | 
			
		||||
        IReadOnlyCollection<ulong> userIds,
 | 
			
		||||
        long amount,
 | 
			
		||||
        Extra extra,
 | 
			
		||||
        CurrencyType type = CurrencyType.Default)
 | 
			
		||||
    {
 | 
			
		||||
        if (type == CurrencyType.Default)
 | 
			
		||||
        {
 | 
			
		||||
            await using var ctx = _db.GetDbContext();
 | 
			
		||||
            await ctx.DiscordUser
 | 
			
		||||
                     .Where(x => userIds.Contains(x.UserId))
 | 
			
		||||
                     .UpdateAsync(du => new()
 | 
			
		||||
                     {
 | 
			
		||||
                         CurrencyAmount = du.CurrencyAmount >= amount
 | 
			
		||||
                             ? du.CurrencyAmount - amount
 | 
			
		||||
                             : 0
 | 
			
		||||
                     });
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        throw new ArgumentOutOfRangeException(nameof(type));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private CurrencyTransaction GetCurrencyTransaction(ulong userId, string reason, long amount)
 | 
			
		||||
        => new() { Amount = amount, UserId = userId, Reason = reason ?? "-" };
 | 
			
		||||
 | 
			
		||||
    public async Task AddAsync(
 | 
			
		||||
        ulong userId,
 | 
			
		||||
        long amount,
 | 
			
		||||
        Extra extra)
 | 
			
		||||
    {
 | 
			
		||||
        await using var wallet = await GetWalletAsync(userId);
 | 
			
		||||
        await wallet.Add(amount, extra);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task AddAsync(
 | 
			
		||||
        IUser user,
 | 
			
		||||
        long amount,
 | 
			
		||||
        Extra extra)
 | 
			
		||||
    {
 | 
			
		||||
        await using var wallet = await GetWalletAsync(user.Id);
 | 
			
		||||
        await wallet.Add(amount, extra);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task<bool> RemoveAsync(
 | 
			
		||||
        ulong userId,
 | 
			
		||||
        long amount,
 | 
			
		||||
        Extra extra)
 | 
			
		||||
    {
 | 
			
		||||
        await using var wallet = await GetWalletAsync(userId);
 | 
			
		||||
        return await wallet.Take(amount, extra);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task<bool> RemoveAsync(
 | 
			
		||||
        IUser user,
 | 
			
		||||
        long amount,
 | 
			
		||||
        Extra extra)
 | 
			
		||||
    {
 | 
			
		||||
        await using var wallet = await GetWalletAsync(user.Id);
 | 
			
		||||
        return await wallet.Take(amount, extra);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task<bool> TransferAsync(
 | 
			
		||||
        ulong from,
 | 
			
		||||
        ulong to,
 | 
			
		||||
        long amount,
 | 
			
		||||
        string note)
 | 
			
		||||
    {
 | 
			
		||||
        await using var fromWallet = await GetWalletAsync(@from);
 | 
			
		||||
        await using var toWallet = await GetWalletAsync(to);
 | 
			
		||||
        
 | 
			
		||||
        var extra = new Extra("transfer", "gift", note);
 | 
			
		||||
        
 | 
			
		||||
        return await fromWallet.Transfer(amount, toWallet, extra);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								src/NadekoBot/Services/Currency/CurrencyType.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/NadekoBot/Services/Currency/CurrencyType.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
namespace NadekoBot.Services.Currency;
 | 
			
		||||
 | 
			
		||||
public enum CurrencyType
 | 
			
		||||
{
 | 
			
		||||
    Default,
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										104
									
								
								src/NadekoBot/Services/Currency/DefaultWallet.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/NadekoBot/Services/Currency/DefaultWallet.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
using LinqToDB;
 | 
			
		||||
using LinqToDB.EntityFrameworkCore;
 | 
			
		||||
using NadekoBot.Services.Database;
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Services.Currency;
 | 
			
		||||
 | 
			
		||||
public class DefaultWallet : IWallet
 | 
			
		||||
{
 | 
			
		||||
    public ulong UserId { get; }
 | 
			
		||||
 | 
			
		||||
    private readonly NadekoContext _ctx;
 | 
			
		||||
 | 
			
		||||
    public DefaultWallet(ulong userId, NadekoContext ctx)
 | 
			
		||||
    {
 | 
			
		||||
        UserId = userId;
 | 
			
		||||
        _ctx = ctx;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Task<long> GetBalance()
 | 
			
		||||
        => _ctx.DiscordUser
 | 
			
		||||
               .ToLinqToDBTable()
 | 
			
		||||
               .Where(x => x.UserId == UserId)
 | 
			
		||||
               .Select(x => x.CurrencyAmount)
 | 
			
		||||
               .FirstOrDefaultAsync();
 | 
			
		||||
 | 
			
		||||
    public async Task<bool> Take(long amount, Extra extra)
 | 
			
		||||
    {
 | 
			
		||||
        if (amount < 0)
 | 
			
		||||
            throw new ArgumentOutOfRangeException(nameof(amount), "Amount to take must be non negative.");
 | 
			
		||||
 | 
			
		||||
        var changed = await _ctx.DiscordUser
 | 
			
		||||
                                .Where(x => x.UserId == UserId && x.CurrencyAmount >= amount)
 | 
			
		||||
                                .UpdateAsync(x => new()
 | 
			
		||||
                                {
 | 
			
		||||
                                    CurrencyAmount = x.CurrencyAmount - amount
 | 
			
		||||
                                });
 | 
			
		||||
 | 
			
		||||
        if (changed == 0)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        // todo type, subtype
 | 
			
		||||
        // todo from? by?
 | 
			
		||||
        await _ctx.CreateLinqToDbContext()
 | 
			
		||||
                  .InsertAsync(new CurrencyTransaction()
 | 
			
		||||
                  {
 | 
			
		||||
                      Amount = -amount,
 | 
			
		||||
                      Reason = extra.Note,
 | 
			
		||||
                      UserId = UserId,
 | 
			
		||||
                  });
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task Add(long amount, Extra extra)
 | 
			
		||||
    {
 | 
			
		||||
        if (amount <= 0)
 | 
			
		||||
            throw new ArgumentOutOfRangeException(nameof(amount), "Amount must be greater than 0.");
 | 
			
		||||
 | 
			
		||||
        await using (var tran = await _ctx.Database.BeginTransactionAsync())
 | 
			
		||||
        {
 | 
			
		||||
            var changed = await _ctx.DiscordUser
 | 
			
		||||
                                    .UpdateAsync(x => new()
 | 
			
		||||
                                    {
 | 
			
		||||
                                        CurrencyAmount = x.CurrencyAmount + amount
 | 
			
		||||
                                    });
 | 
			
		||||
            
 | 
			
		||||
            if (changed == 0)
 | 
			
		||||
            {
 | 
			
		||||
                await _ctx.DiscordUser
 | 
			
		||||
                          .ToLinqToDBTable()
 | 
			
		||||
                          .Value(x => x.UserId, UserId)
 | 
			
		||||
                          .Value(x => x.Username, "Unknown")
 | 
			
		||||
                          .Value(x => x.Discriminator, "????")
 | 
			
		||||
                          .Value(x => x.CurrencyAmount, amount)
 | 
			
		||||
                          .InsertAsync();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await tran.CommitAsync();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var ct = new CurrencyTransaction()
 | 
			
		||||
        {
 | 
			
		||||
            Amount = amount,
 | 
			
		||||
            Reason = extra.Note,
 | 
			
		||||
            UserId = UserId,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        await _ctx.CreateLinqToDbContext()
 | 
			
		||||
                  .InsertAsync(ct);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Dispose()
 | 
			
		||||
    {
 | 
			
		||||
        _ctx.SaveChanges();
 | 
			
		||||
        _ctx.Dispose();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public async ValueTask DisposeAsync()
 | 
			
		||||
    {
 | 
			
		||||
        await _ctx.SaveChangesAsync();
 | 
			
		||||
        await _ctx.DisposeAsync();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								src/NadekoBot/Services/Currency/Extra.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/NadekoBot/Services/Currency/Extra.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
namespace NadekoBot.Services.Currency;
 | 
			
		||||
 | 
			
		||||
public record class Extra(string Type, string Subtype, string Note = "", ulong OtherId = 0);
 | 
			
		||||
							
								
								
									
										47
									
								
								src/NadekoBot/Services/Currency/ICurrencyService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/NadekoBot/Services/Currency/ICurrencyService.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
using NadekoBot.Services.Currency;
 | 
			
		||||
 | 
			
		||||
#nullable disable
 | 
			
		||||
namespace NadekoBot.Services;
 | 
			
		||||
 | 
			
		||||
public interface ICurrencyService
 | 
			
		||||
{
 | 
			
		||||
    Task<IWallet> GetWalletAsync(ulong userId, CurrencyType type = CurrencyType.Default);
 | 
			
		||||
 | 
			
		||||
    Task AddBulkAsync(
 | 
			
		||||
        IReadOnlyCollection<ulong> userIds,
 | 
			
		||||
        long amount,
 | 
			
		||||
        Extra extra,
 | 
			
		||||
        CurrencyType type = CurrencyType.Default);
 | 
			
		||||
 | 
			
		||||
    Task RemoveBulkAsync(
 | 
			
		||||
        IReadOnlyCollection<ulong> userIds,
 | 
			
		||||
        long amount,
 | 
			
		||||
        Extra extra,
 | 
			
		||||
        CurrencyType type = CurrencyType.Default);
 | 
			
		||||
 | 
			
		||||
    Task AddAsync(
 | 
			
		||||
        ulong userId,
 | 
			
		||||
        long amount,
 | 
			
		||||
        Extra extra);
 | 
			
		||||
 | 
			
		||||
    Task AddAsync(
 | 
			
		||||
        IUser user,
 | 
			
		||||
        long amount,
 | 
			
		||||
        Extra extra);
 | 
			
		||||
 | 
			
		||||
    Task<bool> RemoveAsync(
 | 
			
		||||
        ulong userId,
 | 
			
		||||
        long amount,
 | 
			
		||||
        Extra extra);
 | 
			
		||||
 | 
			
		||||
    Task<bool> RemoveAsync(
 | 
			
		||||
        IUser user,
 | 
			
		||||
        long amount,
 | 
			
		||||
        Extra extra);
 | 
			
		||||
 | 
			
		||||
    Task<bool> TransferAsync(
 | 
			
		||||
        ulong from,
 | 
			
		||||
        ulong to,
 | 
			
		||||
        long amount,
 | 
			
		||||
        string note);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								src/NadekoBot/Services/Currency/IWallet.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/NadekoBot/Services/Currency/IWallet.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
namespace NadekoBot.Services.Currency;
 | 
			
		||||
 | 
			
		||||
public interface IWallet : IDisposable, IAsyncDisposable
 | 
			
		||||
{
 | 
			
		||||
    public ulong UserId { get; }
 | 
			
		||||
    
 | 
			
		||||
    public Task<long> GetBalance();
 | 
			
		||||
    public Task<bool> Take(long amount, Extra extra);
 | 
			
		||||
    public Task Add(long amount, Extra extra);
 | 
			
		||||
    
 | 
			
		||||
    public async Task<bool> Transfer(
 | 
			
		||||
        long amount,
 | 
			
		||||
        IWallet to,
 | 
			
		||||
        Extra extra)
 | 
			
		||||
    {
 | 
			
		||||
        if (amount <= 0)
 | 
			
		||||
            throw new ArgumentOutOfRangeException(nameof(amount), "Amount must be greater than 0.");
 | 
			
		||||
 | 
			
		||||
        var succ = await Take(amount,
 | 
			
		||||
            extra with
 | 
			
		||||
            {
 | 
			
		||||
                OtherId = to.UserId
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        if (!succ)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        await to.Add(amount,
 | 
			
		||||
            extra with
 | 
			
		||||
            {
 | 
			
		||||
                OtherId = UserId
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,43 +0,0 @@
 | 
			
		||||
#nullable disable
 | 
			
		||||
namespace NadekoBot.Services;
 | 
			
		||||
 | 
			
		||||
public interface ICurrencyService
 | 
			
		||||
{
 | 
			
		||||
    Task AddAsync(
 | 
			
		||||
        ulong userId,
 | 
			
		||||
        string reason,
 | 
			
		||||
        long amount,
 | 
			
		||||
        bool gamble = false);
 | 
			
		||||
 | 
			
		||||
    Task AddAsync(
 | 
			
		||||
        IUser user,
 | 
			
		||||
        string reason,
 | 
			
		||||
        long amount,
 | 
			
		||||
        bool sendMessage = false,
 | 
			
		||||
        bool gamble = false);
 | 
			
		||||
 | 
			
		||||
    Task AddBulkAsync(
 | 
			
		||||
        IEnumerable<ulong> userIds,
 | 
			
		||||
        IEnumerable<string> reasons,
 | 
			
		||||
        IEnumerable<long> amounts,
 | 
			
		||||
        bool gamble = false);
 | 
			
		||||
 | 
			
		||||
    Task<bool> RemoveAsync(
 | 
			
		||||
        ulong userId,
 | 
			
		||||
        string reason,
 | 
			
		||||
        long amount,
 | 
			
		||||
        bool gamble = false);
 | 
			
		||||
 | 
			
		||||
    Task<bool> RemoveAsync(
 | 
			
		||||
        IUser userId,
 | 
			
		||||
        string reason,
 | 
			
		||||
        long amount,
 | 
			
		||||
        bool sendMessage = false,
 | 
			
		||||
        bool gamble = false);
 | 
			
		||||
 | 
			
		||||
    Task RemoveBulkAsync(
 | 
			
		||||
        IEnumerable<ulong> userIds,
 | 
			
		||||
        IEnumerable<string> reasons,
 | 
			
		||||
        IEnumerable<long> amounts,
 | 
			
		||||
        bool gamble = false);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
using NadekoBot.Services.Currency;
 | 
			
		||||
 | 
			
		||||
#nullable disable
 | 
			
		||||
namespace NadekoBot.Services;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,185 +0,0 @@
 | 
			
		||||
#nullable disable
 | 
			
		||||
using NadekoBot.Db;
 | 
			
		||||
using NadekoBot.Modules.Gambling.Services;
 | 
			
		||||
using NadekoBot.Services.Database;
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Services;
 | 
			
		||||
 | 
			
		||||
public class CurrencyService : ICurrencyService, INService
 | 
			
		||||
{
 | 
			
		||||
    private readonly DbService _db;
 | 
			
		||||
    private readonly GamblingConfigService _gss;
 | 
			
		||||
    private readonly IEmbedBuilderService _eb;
 | 
			
		||||
    private readonly IUser _bot;
 | 
			
		||||
 | 
			
		||||
    public CurrencyService(
 | 
			
		||||
        DbService db,
 | 
			
		||||
        DiscordSocketClient c,
 | 
			
		||||
        GamblingConfigService gss,
 | 
			
		||||
        IEmbedBuilderService eb)
 | 
			
		||||
    {
 | 
			
		||||
        _db = db;
 | 
			
		||||
        _gss = gss;
 | 
			
		||||
        _eb = eb;
 | 
			
		||||
        _bot = c.CurrentUser;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private CurrencyTransaction GetCurrencyTransaction(ulong userId, string reason, long amount)
 | 
			
		||||
        => new() { Amount = amount, UserId = userId, Reason = reason ?? "-" };
 | 
			
		||||
 | 
			
		||||
    private bool InternalChange(
 | 
			
		||||
        ulong userId,
 | 
			
		||||
        string userName,
 | 
			
		||||
        string discrim,
 | 
			
		||||
        string avatar,
 | 
			
		||||
        string reason,
 | 
			
		||||
        long amount,
 | 
			
		||||
        bool gamble,
 | 
			
		||||
        NadekoContext uow)
 | 
			
		||||
    {
 | 
			
		||||
        var result = uow.TryUpdateCurrencyState(userId, userName, discrim, avatar, amount);
 | 
			
		||||
        if (result)
 | 
			
		||||
        {
 | 
			
		||||
            var t = GetCurrencyTransaction(userId, reason, amount);
 | 
			
		||||
            uow.CurrencyTransactions.Add(t);
 | 
			
		||||
 | 
			
		||||
            if (gamble)
 | 
			
		||||
            {
 | 
			
		||||
                var t2 = GetCurrencyTransaction(_bot.Id, reason, -amount);
 | 
			
		||||
                uow.CurrencyTransactions.Add(t2);
 | 
			
		||||
                uow.TryUpdateCurrencyState(_bot.Id, _bot.Username, _bot.Discriminator, _bot.AvatarId, -amount, true);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async Task InternalAddAsync(
 | 
			
		||||
        ulong userId,
 | 
			
		||||
        string userName,
 | 
			
		||||
        string discrim,
 | 
			
		||||
        string avatar,
 | 
			
		||||
        string reason,
 | 
			
		||||
        long amount,
 | 
			
		||||
        bool gamble)
 | 
			
		||||
    {
 | 
			
		||||
        if (amount < 0)
 | 
			
		||||
            throw new ArgumentException("You can't add negative amounts. Use RemoveAsync method for that.",
 | 
			
		||||
                nameof(amount));
 | 
			
		||||
 | 
			
		||||
        await using var uow = _db.GetDbContext();
 | 
			
		||||
        InternalChange(userId, userName, discrim, avatar, reason, amount, gamble, uow);
 | 
			
		||||
        await uow.SaveChangesAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Task AddAsync(
 | 
			
		||||
        ulong userId,
 | 
			
		||||
        string reason,
 | 
			
		||||
        long amount,
 | 
			
		||||
        bool gamble = false)
 | 
			
		||||
        => InternalAddAsync(userId, null, null, null, reason, amount, gamble);
 | 
			
		||||
 | 
			
		||||
    public async Task AddAsync(
 | 
			
		||||
        IUser user,
 | 
			
		||||
        string reason,
 | 
			
		||||
        long amount,
 | 
			
		||||
        bool sendMessage = false,
 | 
			
		||||
        bool gamble = false)
 | 
			
		||||
    {
 | 
			
		||||
        await InternalAddAsync(user.Id, user.Username, user.Discriminator, user.AvatarId, reason, amount, gamble);
 | 
			
		||||
        if (sendMessage)
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var sign = _gss.Data.Currency.Sign;
 | 
			
		||||
                await user.EmbedAsync(_eb.Create()
 | 
			
		||||
                                         .WithOkColor()
 | 
			
		||||
                                         .WithTitle("Received Currency")
 | 
			
		||||
                                         .AddField("Amount", amount + sign)
 | 
			
		||||
                                         .AddField("Reason", reason));
 | 
			
		||||
            }
 | 
			
		||||
            catch
 | 
			
		||||
            {
 | 
			
		||||
                // ignored
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task AddBulkAsync(
 | 
			
		||||
        IEnumerable<ulong> userIds,
 | 
			
		||||
        IEnumerable<string> reasons,
 | 
			
		||||
        IEnumerable<long> amounts,
 | 
			
		||||
        bool gamble = false)
 | 
			
		||||
    {
 | 
			
		||||
        var idArray = userIds as ulong[] ?? userIds.ToArray();
 | 
			
		||||
        var reasonArray = reasons as string[] ?? reasons.ToArray();
 | 
			
		||||
        var amountArray = amounts as long[] ?? amounts.ToArray();
 | 
			
		||||
 | 
			
		||||
        if (idArray.Length != reasonArray.Length || reasonArray.Length != amountArray.Length)
 | 
			
		||||
            throw new ArgumentException("Cannot perform bulk operation. Arrays are not of equal length.");
 | 
			
		||||
 | 
			
		||||
        var userIdHashSet = new HashSet<ulong>(idArray.Length);
 | 
			
		||||
        await using var uow = _db.GetDbContext();
 | 
			
		||||
        for (var i = 0; i < idArray.Length; i++)
 | 
			
		||||
            // i have to prevent same user changing more than once as it will cause db error
 | 
			
		||||
            if (userIdHashSet.Add(idArray[i]))
 | 
			
		||||
                InternalChange(idArray[i], null, null, null, reasonArray[i], amountArray[i], gamble, uow);
 | 
			
		||||
        await uow.SaveChangesAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task RemoveBulkAsync(
 | 
			
		||||
        IEnumerable<ulong> userIds,
 | 
			
		||||
        IEnumerable<string> reasons,
 | 
			
		||||
        IEnumerable<long> amounts,
 | 
			
		||||
        bool gamble = false)
 | 
			
		||||
    {
 | 
			
		||||
        var idArray = userIds as ulong[] ?? userIds.ToArray();
 | 
			
		||||
        var reasonArray = reasons as string[] ?? reasons.ToArray();
 | 
			
		||||
        var amountArray = amounts as long[] ?? amounts.ToArray();
 | 
			
		||||
 | 
			
		||||
        if (idArray.Length != reasonArray.Length || reasonArray.Length != amountArray.Length)
 | 
			
		||||
            throw new ArgumentException("Cannot perform bulk operation. Arrays are not of equal length.");
 | 
			
		||||
 | 
			
		||||
        var userIdHashSet = new HashSet<ulong>(idArray.Length);
 | 
			
		||||
        await using var uow = _db.GetDbContext();
 | 
			
		||||
        for (var i = 0; i < idArray.Length; i++)
 | 
			
		||||
            // i have to prevent same user changing more than once as it will cause db error
 | 
			
		||||
            if (userIdHashSet.Add(idArray[i]))
 | 
			
		||||
                InternalChange(idArray[i], null, null, null, reasonArray[i], -amountArray[i], gamble, uow);
 | 
			
		||||
        await uow.SaveChangesAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async Task<bool> InternalRemoveAsync(
 | 
			
		||||
        ulong userId,
 | 
			
		||||
        string userName,
 | 
			
		||||
        string userDiscrim,
 | 
			
		||||
        string avatar,
 | 
			
		||||
        string reason,
 | 
			
		||||
        long amount,
 | 
			
		||||
        bool gamble = false)
 | 
			
		||||
    {
 | 
			
		||||
        if (amount < 0)
 | 
			
		||||
            throw new ArgumentException("You can't remove negative amounts. Use AddAsync method for that.",
 | 
			
		||||
                nameof(amount));
 | 
			
		||||
 | 
			
		||||
        bool result;
 | 
			
		||||
        await using var uow = _db.GetDbContext();
 | 
			
		||||
        result = InternalChange(userId, userName, userDiscrim, avatar, reason, -amount, gamble, uow);
 | 
			
		||||
        await uow.SaveChangesAsync();
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Task<bool> RemoveAsync(
 | 
			
		||||
        ulong userId,
 | 
			
		||||
        string reason,
 | 
			
		||||
        long amount,
 | 
			
		||||
        bool gamble = false)
 | 
			
		||||
        => InternalRemoveAsync(userId, null, null, null, reason, amount, gamble);
 | 
			
		||||
 | 
			
		||||
    public Task<bool> RemoveAsync(
 | 
			
		||||
        IUser user,
 | 
			
		||||
        string reason,
 | 
			
		||||
        long amount,
 | 
			
		||||
        bool sendMessage = false,
 | 
			
		||||
        bool gamble = false)
 | 
			
		||||
        => InternalRemoveAsync(user.Id, user.Username, user.Discriminator, user.AvatarId, reason, amount, gamble);
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user