mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 17:28:27 -04:00
.bank withdraw <expression> will now correctly use bank amount for calculations. Fixed .br giving double win amounts
This commit is contained in:
19
src/Nadeko.Common/ShmartBankAmount.cs
Normal file
19
src/Nadeko.Common/ShmartBankAmount.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
namespace Nadeko.Common;
|
||||||
|
|
||||||
|
public readonly struct ShmartBankAmount
|
||||||
|
{
|
||||||
|
public long Amount { get; }
|
||||||
|
public ShmartBankAmount(long amount)
|
||||||
|
{
|
||||||
|
Amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator ShmartBankAmount(long num)
|
||||||
|
=> new(num);
|
||||||
|
|
||||||
|
public static implicit operator long(ShmartBankAmount num)
|
||||||
|
=> num.Amount;
|
||||||
|
|
||||||
|
public static implicit operator ShmartBankAmount(int num)
|
||||||
|
=> new(num);
|
||||||
|
}
|
@@ -3,12 +3,10 @@
|
|||||||
public readonly struct ShmartNumber : IEquatable<ShmartNumber>
|
public readonly struct ShmartNumber : IEquatable<ShmartNumber>
|
||||||
{
|
{
|
||||||
public long Value { get; }
|
public long Value { get; }
|
||||||
public string? Input { get; }
|
|
||||||
|
|
||||||
public ShmartNumber(long val, string? input = null)
|
public ShmartNumber(long val)
|
||||||
{
|
{
|
||||||
Value = val;
|
Value = val;
|
||||||
Input = input;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static implicit operator ShmartNumber(long num)
|
public static implicit operator ShmartNumber(long num)
|
||||||
|
@@ -0,0 +1,94 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using NadekoBot.Db;
|
||||||
|
using NadekoBot.Modules.Gambling.Services;
|
||||||
|
using NCalc;
|
||||||
|
using OneOf;
|
||||||
|
|
||||||
|
namespace NadekoBot.Common.TypeReaders;
|
||||||
|
|
||||||
|
public class BaseShmartInputAmountReader
|
||||||
|
{
|
||||||
|
private static readonly Regex _percentRegex = new(@"^((?<num>100|\d{1,2})%)$", RegexOptions.Compiled);
|
||||||
|
protected readonly DbService _db;
|
||||||
|
protected readonly GamblingConfigService _gambling;
|
||||||
|
|
||||||
|
public BaseShmartInputAmountReader(DbService db, GamblingConfigService gambling)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
_gambling = gambling;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<OneOf<long, OneOf.Types.Error<string>>> ReadAsync(ICommandContext context, string input)
|
||||||
|
{
|
||||||
|
var i = input.Trim().ToUpperInvariant();
|
||||||
|
|
||||||
|
i = i.Replace("K", "000");
|
||||||
|
|
||||||
|
//can't add m because it will conflict with max atm
|
||||||
|
|
||||||
|
if (await TryHandlePercentage(context, i) is long num)
|
||||||
|
{
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var expr = new Expression(i, EvaluateOptions.IgnoreCase);
|
||||||
|
expr.EvaluateParameter += (str, ev) => EvaluateParam(str, ev, context).GetAwaiter().GetResult();
|
||||||
|
return (long)decimal.Parse(expr.Evaluate().ToString()!);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return new OneOf.Types.Error<string>($"Invalid input: {input}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task EvaluateParam(string name, ParameterArgs args, ICommandContext ctx)
|
||||||
|
{
|
||||||
|
switch (name.ToUpperInvariant())
|
||||||
|
{
|
||||||
|
case "PI":
|
||||||
|
args.Result = Math.PI;
|
||||||
|
break;
|
||||||
|
case "E":
|
||||||
|
args.Result = Math.E;
|
||||||
|
break;
|
||||||
|
case "ALL":
|
||||||
|
case "ALLIN":
|
||||||
|
args.Result = await Cur(ctx);
|
||||||
|
break;
|
||||||
|
case "HALF":
|
||||||
|
args.Result = await Cur(ctx) / 2;
|
||||||
|
break;
|
||||||
|
case "MAX":
|
||||||
|
args.Result = await Max(ctx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual async Task<long> Cur(ICommandContext ctx)
|
||||||
|
{
|
||||||
|
await using var uow = _db.GetDbContext();
|
||||||
|
return await uow.DiscordUser.GetUserCurrencyAsync(ctx.User.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual async Task<long> Max(ICommandContext ctx)
|
||||||
|
{
|
||||||
|
var settings = _gambling.Data;
|
||||||
|
var max = settings.MaxBet;
|
||||||
|
return max == 0 ? await Cur(ctx) : max;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<long?> TryHandlePercentage(ICommandContext ctx, string input)
|
||||||
|
{
|
||||||
|
var m = _percentRegex.Match(input);
|
||||||
|
|
||||||
|
if (m.Captures.Count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (!long.TryParse(m.Groups["num"].ToString(), out var percent))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return (long)(await Cur(ctx) * (percent / 100.0f));
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,32 @@
|
|||||||
|
#nullable disable
|
||||||
|
using NadekoBot.Modules.Gambling.Bank;
|
||||||
|
using NadekoBot.Modules.Gambling.Services;
|
||||||
|
|
||||||
|
namespace NadekoBot.Common.TypeReaders;
|
||||||
|
|
||||||
|
public sealed class ShmartBankAmountTypeReader : NadekoTypeReader<ShmartBankAmount>
|
||||||
|
{
|
||||||
|
private readonly IBankService _bank;
|
||||||
|
private readonly ShmartBankInputAmountReader _tr;
|
||||||
|
|
||||||
|
public ShmartBankAmountTypeReader(IBankService bank, DbService db, GamblingConfigService gambling)
|
||||||
|
{
|
||||||
|
_bank = bank;
|
||||||
|
_tr = new ShmartBankInputAmountReader(bank, db, gambling);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async ValueTask<TypeReaderResult<ShmartBankAmount>> ReadAsync(ICommandContext ctx, string input)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(input))
|
||||||
|
return TypeReaderResult.FromError<ShmartBankAmount>(CommandError.ParseFailed, "Input is empty.");
|
||||||
|
|
||||||
|
var result = await _tr.ReadAsync(ctx, input);
|
||||||
|
|
||||||
|
if (result.TryPickT0(out var val, out var err))
|
||||||
|
{
|
||||||
|
return TypeReaderResult.FromSuccess<ShmartBankAmount>(new(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
return TypeReaderResult.FromError<ShmartBankAmount>(CommandError.Unsuccessful, err.Value);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
using NadekoBot.Modules.Gambling.Bank;
|
||||||
|
using NadekoBot.Modules.Gambling.Services;
|
||||||
|
|
||||||
|
namespace NadekoBot.Common.TypeReaders;
|
||||||
|
|
||||||
|
public sealed class ShmartBankInputAmountReader : BaseShmartInputAmountReader
|
||||||
|
{
|
||||||
|
private readonly IBankService _bank;
|
||||||
|
|
||||||
|
public ShmartBankInputAmountReader(IBankService bank, DbService db, GamblingConfigService gambling)
|
||||||
|
: base(db, gambling)
|
||||||
|
{
|
||||||
|
_bank = bank;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task<long> Cur(ICommandContext ctx)
|
||||||
|
=> _bank.GetBalanceAsync(ctx.User.Id);
|
||||||
|
|
||||||
|
protected override Task<long> Max(ICommandContext ctx)
|
||||||
|
=> Cur(ctx);
|
||||||
|
}
|
@@ -0,0 +1,29 @@
|
|||||||
|
#nullable disable
|
||||||
|
using NadekoBot.Modules.Gambling.Services;
|
||||||
|
|
||||||
|
namespace NadekoBot.Common.TypeReaders;
|
||||||
|
|
||||||
|
public sealed class ShmartNumberTypeReader : NadekoTypeReader<ShmartNumber>
|
||||||
|
{
|
||||||
|
private readonly BaseShmartInputAmountReader _tr;
|
||||||
|
|
||||||
|
public ShmartNumberTypeReader(DbService db, GamblingConfigService gambling)
|
||||||
|
{
|
||||||
|
_tr = new BaseShmartInputAmountReader(db, gambling);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async ValueTask<TypeReaderResult<ShmartNumber>> ReadAsync(ICommandContext ctx, string input)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(input))
|
||||||
|
return TypeReaderResult.FromError<ShmartNumber>(CommandError.ParseFailed, "Input is empty.");
|
||||||
|
|
||||||
|
var result = await _tr.ReadAsync(ctx, input);
|
||||||
|
|
||||||
|
if (result.TryPickT0(out var val, out var err))
|
||||||
|
{
|
||||||
|
return TypeReaderResult.FromSuccess<ShmartNumber>(new(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
return TypeReaderResult.FromError<ShmartNumber>(CommandError.Unsuccessful, err.Value);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,100 +0,0 @@
|
|||||||
#nullable disable
|
|
||||||
using NadekoBot.Db;
|
|
||||||
using NadekoBot.Modules.Gambling.Services;
|
|
||||||
using NCalc;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using Nadeko.Common;
|
|
||||||
|
|
||||||
namespace NadekoBot.Common.TypeReaders;
|
|
||||||
|
|
||||||
public sealed class ShmartNumberTypeReader : NadekoTypeReader<ShmartNumber>
|
|
||||||
{
|
|
||||||
private static readonly Regex _percentRegex = new(@"^((?<num>100|\d{1,2})%)$", RegexOptions.Compiled);
|
|
||||||
private readonly DbService _db;
|
|
||||||
private readonly GamblingConfigService _gambling;
|
|
||||||
|
|
||||||
public ShmartNumberTypeReader(DbService db, GamblingConfigService gambling)
|
|
||||||
{
|
|
||||||
_db = db;
|
|
||||||
_gambling = gambling;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ValueTask<TypeReaderResult<ShmartNumber>> ReadAsync(ICommandContext context, string input)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(input))
|
|
||||||
return new(TypeReaderResult.FromError<ShmartNumber>(CommandError.ParseFailed, "Input is empty."));
|
|
||||||
|
|
||||||
var i = input.Trim().ToUpperInvariant();
|
|
||||||
|
|
||||||
i = i.Replace("K", "000");
|
|
||||||
|
|
||||||
//can't add m because it will conflict with max atm
|
|
||||||
|
|
||||||
if (TryHandlePercentage(context, i, out var num))
|
|
||||||
return new(TypeReaderResult.FromSuccess(new ShmartNumber(num, i)));
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var expr = new Expression(i, EvaluateOptions.IgnoreCase);
|
|
||||||
expr.EvaluateParameter += (str, ev) => EvaluateParam(str, ev, context);
|
|
||||||
var lon = (long)decimal.Parse(expr.Evaluate().ToString());
|
|
||||||
return new(TypeReaderResult.FromSuccess(new ShmartNumber(lon, input)));
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return ValueTask.FromResult(
|
|
||||||
TypeReaderResult.FromError<ShmartNumber>(CommandError.ParseFailed, $"Invalid input: {input}"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EvaluateParam(string name, ParameterArgs args, ICommandContext ctx)
|
|
||||||
{
|
|
||||||
switch (name.ToUpperInvariant())
|
|
||||||
{
|
|
||||||
case "PI":
|
|
||||||
args.Result = Math.PI;
|
|
||||||
break;
|
|
||||||
case "E":
|
|
||||||
args.Result = Math.E;
|
|
||||||
break;
|
|
||||||
case "ALL":
|
|
||||||
case "ALLIN":
|
|
||||||
args.Result = Cur(ctx);
|
|
||||||
break;
|
|
||||||
case "HALF":
|
|
||||||
args.Result = Cur(ctx) / 2;
|
|
||||||
break;
|
|
||||||
case "MAX":
|
|
||||||
args.Result = Max(ctx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private long Cur(ICommandContext ctx)
|
|
||||||
{
|
|
||||||
using var uow = _db.GetDbContext();
|
|
||||||
return uow.DiscordUser.GetUserCurrency(ctx.User.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long Max(ICommandContext ctx)
|
|
||||||
{
|
|
||||||
var settings = _gambling.Data;
|
|
||||||
var max = settings.MaxBet;
|
|
||||||
return max == 0 ? Cur(ctx) : max;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryHandlePercentage(ICommandContext ctx, string input, out long num)
|
|
||||||
{
|
|
||||||
num = 0;
|
|
||||||
var m = _percentRegex.Match(input);
|
|
||||||
if (m.Captures.Count != 0)
|
|
||||||
{
|
|
||||||
if (!long.TryParse(m.Groups["num"].ToString(), out var percent))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
num = (long)(Cur(ctx) * (percent / 100.0f));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -108,8 +108,8 @@ public static class DiscordUserExtensions
|
|||||||
.Take(count)
|
.Take(count)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
public static long GetUserCurrency(this DbSet<DiscordUser> users, ulong userId)
|
public static async Task<long> GetUserCurrencyAsync(this DbSet<DiscordUser> users, ulong userId)
|
||||||
=> users.AsNoTracking().FirstOrDefault(x => x.UserId == userId)?.CurrencyAmount ?? 0;
|
=> (await users.FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId))?.CurrencyAmount ?? 0;
|
||||||
|
|
||||||
public static void RemoveFromMany(this DbSet<DiscordUser> users, IEnumerable<ulong> ids)
|
public static void RemoveFromMany(this DbSet<DiscordUser> users, IEnumerable<ulong> ids)
|
||||||
{
|
{
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Nadeko.Common;
|
using Nadeko.Common;
|
||||||
|
using NadekoBot.Common.TypeReaders;
|
||||||
using NadekoBot.Modules.Gambling.Bank;
|
using NadekoBot.Modules.Gambling.Bank;
|
||||||
using NadekoBot.Modules.Gambling.Common;
|
using NadekoBot.Modules.Gambling.Common;
|
||||||
using NadekoBot.Modules.Gambling.Services;
|
using NadekoBot.Modules.Gambling.Services;
|
||||||
@@ -35,7 +36,7 @@ public partial class Gambling
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
public async Task BankWithdraw(ShmartNumber amount)
|
public async Task BankWithdraw(ShmartBankAmount amount)
|
||||||
{
|
{
|
||||||
if (amount <= 0)
|
if (amount <= 0)
|
||||||
return;
|
return;
|
||||||
|
@@ -663,7 +663,6 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
if (win > 0)
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@@ -142,7 +142,7 @@ public class GamblingService : INService, IReadyExecutor
|
|||||||
var onePercent = uow.DiscordUser.GetTopOnePercentCurrency(_client.CurrentUser.Id);
|
var onePercent = uow.DiscordUser.GetTopOnePercentCurrency(_client.CurrentUser.Id);
|
||||||
decimal planted = uow.PlantedCurrency.AsQueryable().Sum(x => x.Amount);
|
decimal planted = uow.PlantedCurrency.AsQueryable().Sum(x => x.Amount);
|
||||||
var waifus = uow.WaifuInfo.GetTotalValue();
|
var waifus = uow.WaifuInfo.GetTotalValue();
|
||||||
var bot = uow.DiscordUser.GetUserCurrency(_client.CurrentUser.Id);
|
var bot = await uow.DiscordUser.GetUserCurrencyAsync(_client.CurrentUser.Id);
|
||||||
decimal bank = await uow.GetTable<BankUser>()
|
decimal bank = await uow.GetTable<BankUser>()
|
||||||
.SumAsyncLinqToDB(x => x.Balance);
|
.SumAsyncLinqToDB(x => x.Balance);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user