Updated Gambling module

I really need to rename this module.
This commit is contained in:
Toastie (DCS Team) 2024-07-15 15:44:07 +12:00
parent 32db627aef
commit 90dd47e013
Signed by: toastie_t0ast
GPG key ID: 27F3B6855AFD40A4
5 changed files with 239 additions and 133 deletions

View file

@ -74,6 +74,27 @@ public partial class Gambling
} }
} }
[Cmd]
[OwnerOnly]
public async Task BankBalance([Leftover] IUser user)
{
var bal = await _bank.GetBalanceAsync(user.Id);
var eb = _sender.CreateEmbed()
.WithOkColor()
.WithDescription(GetText(strs.bank_balance_other(user.ToString(), N(bal))));
try
{
await Response().User(ctx.User).Embed(eb).SendAsync();
await ctx.OkAsync();
}
catch
{
await Response().Error(strs.cant_dm).SendAsync();
}
}
private async Task BankTakeInternalAsync(long amount, ulong userId) private async Task BankTakeInternalAsync(long amount, ulong userId)
{ {
if (await _bank.TakeAsync(userId, amount)) if (await _bank.TakeAsync(userId, amount))

View file

@ -3,6 +3,7 @@ using EllieBot.Modules.Gambling.Common;
using EllieBot.Modules.Gambling.Common.Waifu; using EllieBot.Modules.Gambling.Common.Waifu;
using EllieBot.Modules.Gambling.Services; using EllieBot.Modules.Gambling.Services;
using EllieBot.Db.Models; using EllieBot.Db.Models;
using TwitchLib.Api.Helix.Models.Teams;
namespace EllieBot.Modules.Gambling; namespace EllieBot.Modules.Gambling;
@ -21,8 +22,8 @@ public partial class Gambling
{ {
var price = _service.GetResetPrice(ctx.User); var price = _service.GetResetPrice(ctx.User);
var embed = _sender.CreateEmbed() var embed = _sender.CreateEmbed()
.WithTitle(GetText(strs.waifu_reset_confirm)) .WithTitle(GetText(strs.waifu_reset_confirm))
.WithDescription(GetText(strs.waifu_reset_price(Format.Bold(N(price))))); .WithDescription(GetText(strs.waifu_reset_price(Format.Bold(N(price)))));
if (!await PromptUserConfirmAsync(embed)) if (!await PromptUserConfirmAsync(embed))
return; return;
@ -307,24 +308,26 @@ public partial class Gambling
fansStr = "-"; fansStr = "-";
var embed = _sender.CreateEmbed() var embed = _sender.CreateEmbed()
.WithOkColor() .WithOkColor()
.WithTitle(GetText(strs.waifu) .WithTitle(GetText(strs.waifu)
+ " " + " "
+ (wi.FullName ?? name ?? targetId.ToString()) + (wi.FullName ?? name ?? targetId.ToString())
+ " - \"the " + " - \"the "
+ _service.GetClaimTitle(wi.ClaimCount) + _service.GetClaimTitle(wi.ClaimCount)
+ "\"") + "\"")
.AddField(GetText(strs.price), N(wi.Price), true) .AddField(GetText(strs.price), N(wi.Price), true)
.AddField(GetText(strs.claimed_by), wi.ClaimerName ?? nobody, true) .AddField(GetText(strs.claimed_by), wi.ClaimerName ?? nobody, true)
.AddField(GetText(strs.likes), wi.AffinityName ?? nobody, true) .AddField(GetText(strs.likes), wi.AffinityName ?? nobody, true)
.AddField(GetText(strs.changes_of_heart), $"{wi.AffinityCount} - \"the {affInfo}\"", true) .AddField(GetText(strs.changes_of_heart),
.AddField(GetText(strs.divorces), wi.DivorceCount.ToString(), true) $"{wi.AffinityCount} - \"the {affInfo}\"",
.AddField("\u200B", "\u200B", true) true)
.AddField(GetText(strs.fans(fansList.Count)), fansStr, true) .AddField(GetText(strs.divorces), wi.DivorceCount.ToString(), true)
.AddField($"Waifus ({wi.ClaimCount})", .AddField("\u200B", "\u200B", true)
wi.ClaimCount == 0 ? nobody : claimsStr, .AddField(GetText(strs.fans(fansList.Count)), fansStr, true)
true) .AddField($"Waifus ({wi.ClaimCount})",
.AddField(GetText(strs.gifts), itemsStr, true); wi.ClaimCount == 0 ? nobody : claimsStr,
true)
.AddField(GetText(strs.gifts), itemsStr, true);
await Response().Embed(embed).SendAsync(); await Response().Embed(embed).SendAsync();
} }
@ -348,7 +351,7 @@ public partial class Gambling
.Page((items, _) => .Page((items, _) =>
{ {
var embed = _sender.CreateEmbed().WithTitle(GetText(strs.waifu_gift_shop)).WithOkColor(); var embed = _sender.CreateEmbed().WithTitle(GetText(strs.waifu_gift_shop)).WithOkColor();
items items
.ToList() .ToList()
.ForEach(x => embed.AddField( .ForEach(x => embed.AddField(
@ -364,30 +367,27 @@ public partial class Gambling
[Cmd] [Cmd]
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
[Priority(0)] [Priority(0)]
public async Task WaifuGift(string itemName, [Leftover] IUser waifu) public async Task WaifuGift(MultipleWaifuItems items, [Leftover] IUser waifu)
{ {
if (waifu.Id == ctx.User.Id) if (waifu.Id == ctx.User.Id)
return; return;
var allItems = _service.GetWaifuItems(); var sucess = await _service.GiftWaifuAsync(ctx.User, waifu, items.Item, items.Count);
var item = allItems.FirstOrDefault(x => x.Name.ToLowerInvariant() == itemName.ToLowerInvariant());
if (item is null)
{
await Response().Error(strs.waifu_gift_not_exist).SendAsync();
return;
}
var sucess = await _service.GiftWaifuAsync(ctx.User, waifu, item);
if (sucess) if (sucess)
{ {
await Response() await Response()
.Confirm(strs.waifu_gift(Format.Bold(item + " " + item.ItemEmoji), .Confirm(strs.waifu_gift(Format.Bold($"{GetCountString(items)}{items.Item} {items.Item.ItemEmoji}"),
Format.Bold(waifu.ToString()))) Format.Bold(waifu.ToString())))
.SendAsync(); .SendAsync();
} }
else else
await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
} }
private static string GetCountString(MultipleWaifuItems items)
=> items.Count > 1
? $"{items.Count}x "
: string.Empty;
} }
} }

View file

@ -7,6 +7,7 @@ using EllieBot.Db;
using EllieBot.Db.Models; using EllieBot.Db.Models;
using EllieBot.Modules.Gambling.Common; using EllieBot.Modules.Gambling.Common;
using EllieBot.Modules.Gambling.Common.Waifu; using EllieBot.Modules.Gambling.Common.Waifu;
using SixLabors.ImageSharp;
namespace EllieBot.Modules.Gambling.Services; namespace EllieBot.Modules.Gambling.Services;
@ -89,9 +90,14 @@ public class WaifuService : IEService, IReadyExecutor
if (waifu is null) if (waifu is null)
return settings.Waifu.MinPrice; return settings.Waifu.MinPrice;
var divorces = uow.Set<WaifuUpdate>().Count(x var divorces = uow.Set<WaifuUpdate>()
=> x.Old != null && x.Old.UserId == user.Id && x.UpdateType == WaifuUpdateType.Claimed && x.New == null); .Count(x
var affs = uow.Set<WaifuUpdate>().AsQueryable() => x.Old != null
&& x.Old.UserId == user.Id
&& x.UpdateType == WaifuUpdateType.Claimed
&& x.New == null);
var affs = uow.Set<WaifuUpdate>()
.AsQueryable()
.Where(w => w.User.UserId == user.Id .Where(w => w.User.UserId == user.Id
&& w.UpdateType == WaifuUpdateType.AffinityChanged && w.UpdateType == WaifuUpdateType.AffinityChanged
&& w.New != null) && w.New != null)
@ -110,12 +116,14 @@ public class WaifuService : IEService, IReadyExecutor
if (!await _cs.RemoveAsync(user.Id, price, new("waifu", "reset"))) if (!await _cs.RemoveAsync(user.Id, price, new("waifu", "reset")))
return false; return false;
var affs = uow.Set<WaifuUpdate>().AsQueryable() var affs = uow.Set<WaifuUpdate>()
.AsQueryable()
.Where(w => w.User.UserId == user.Id .Where(w => w.User.UserId == user.Id
&& w.UpdateType == WaifuUpdateType.AffinityChanged && w.UpdateType == WaifuUpdateType.AffinityChanged
&& w.New != null); && w.New != null);
var divorces = uow.Set<WaifuUpdate>().AsQueryable() var divorces = uow.Set<WaifuUpdate>()
.AsQueryable()
.Where(x => x.Old != null .Where(x => x.Old != null
&& x.Old.UserId == user.Id && x.Old.UserId == user.Id
&& x.UpdateType == WaifuUpdateType.Claimed && x.UpdateType == WaifuUpdateType.Claimed
@ -158,20 +166,22 @@ public class WaifuService : IEService, IReadyExecutor
result = WaifuClaimResult.NotEnoughFunds; result = WaifuClaimResult.NotEnoughFunds;
else else
{ {
uow.Set<WaifuInfo>().Add(w = new() uow.Set<WaifuInfo>()
{ .Add(w = new()
Waifu = waifu, {
Claimer = claimer, Waifu = waifu,
Affinity = null, Claimer = claimer,
Price = amount Affinity = null,
}); Price = amount
uow.Set<WaifuUpdate>().Add(new() });
{ uow.Set<WaifuUpdate>()
User = waifu, .Add(new()
Old = null, {
New = claimer, User = waifu,
UpdateType = WaifuUpdateType.Claimed Old = null,
}); New = claimer,
UpdateType = WaifuUpdateType.Claimed
});
result = WaifuClaimResult.Success; result = WaifuClaimResult.Success;
} }
} }
@ -186,13 +196,14 @@ public class WaifuService : IEService, IReadyExecutor
w.Price = amount + (amount / 4); w.Price = amount + (amount / 4);
result = WaifuClaimResult.Success; result = WaifuClaimResult.Success;
uow.Set<WaifuUpdate>().Add(new() uow.Set<WaifuUpdate>()
{ .Add(new()
User = w.Waifu, {
Old = oldClaimer, User = w.Waifu,
New = w.Claimer, Old = oldClaimer,
UpdateType = WaifuUpdateType.Claimed New = w.Claimer,
}); UpdateType = WaifuUpdateType.Claimed
});
} }
} }
else if (amount >= w.Price * settings.Waifu.Multipliers.NormalClaim) // if no affinity else if (amount >= w.Price * settings.Waifu.Multipliers.NormalClaim) // if no affinity
@ -206,13 +217,14 @@ public class WaifuService : IEService, IReadyExecutor
w.Price = amount; w.Price = amount;
result = WaifuClaimResult.Success; result = WaifuClaimResult.Success;
uow.Set<WaifuUpdate>().Add(new() uow.Set<WaifuUpdate>()
{ .Add(new()
User = w.Waifu, {
Old = oldClaimer, User = w.Waifu,
New = w.Claimer, Old = oldClaimer,
UpdateType = WaifuUpdateType.Claimed New = w.Claimer,
}); UpdateType = WaifuUpdateType.Claimed
});
} }
} }
else else
@ -241,29 +253,31 @@ public class WaifuService : IEService, IReadyExecutor
remaining = await _cache.GetRatelimitAsync(GetAffinityKey(user.Id), remaining = await _cache.GetRatelimitAsync(GetAffinityKey(user.Id),
30.Minutes()); 30.Minutes());
if (remaining is not null) if (remaining is not null)
{ {
} }
else if (w is null) else if (w is null)
{ {
var thisUser = uow.GetOrCreateUser(user); var thisUser = uow.GetOrCreateUser(user);
uow.Set<WaifuInfo>().Add(new() uow.Set<WaifuInfo>()
{ .Add(new()
Affinity = newAff, {
Waifu = thisUser, Affinity = newAff,
Price = 1, Waifu = thisUser,
Claimer = null Price = 1,
}); Claimer = null
});
success = true; success = true;
uow.Set<WaifuUpdate>().Add(new() uow.Set<WaifuUpdate>()
{ .Add(new()
User = thisUser, {
Old = null, User = thisUser,
New = newAff, Old = null,
UpdateType = WaifuUpdateType.AffinityChanged New = newAff,
}); UpdateType = WaifuUpdateType.AffinityChanged
});
} }
else else
{ {
@ -272,13 +286,14 @@ public class WaifuService : IEService, IReadyExecutor
w.Affinity = newAff; w.Affinity = newAff;
success = true; success = true;
uow.Set<WaifuUpdate>().Add(new() uow.Set<WaifuUpdate>()
{ .Add(new()
User = w.Waifu, {
Old = oldAff, User = w.Waifu,
New = newAff, Old = oldAff,
UpdateType = WaifuUpdateType.AffinityChanged New = newAff,
}); UpdateType = WaifuUpdateType.AffinityChanged
});
} }
await uow.SaveChangesAsync(); await uow.SaveChangesAsync();
@ -301,10 +316,10 @@ public class WaifuService : IEService, IReadyExecutor
private static TypedKey<long> GetDivorceKey(ulong userId) private static TypedKey<long> GetDivorceKey(ulong userId)
=> new($"waifu:divorce_cd:{userId}"); => new($"waifu:divorce_cd:{userId}");
private static TypedKey<long> GetAffinityKey(ulong userId) private static TypedKey<long> GetAffinityKey(ulong userId)
=> new($"waifu:affinity:{userId}"); => new($"waifu:affinity:{userId}");
public async Task<(WaifuInfo, DivorceResult, long, TimeSpan?)> DivorceWaifuAsync(IUser user, ulong targetId) public async Task<(WaifuInfo, DivorceResult, long, TimeSpan?)> DivorceWaifuAsync(IUser user, ulong targetId)
{ {
DivorceResult result; DivorceResult result;
@ -343,13 +358,14 @@ public class WaifuService : IEService, IReadyExecutor
var oldClaimer = w.Claimer; var oldClaimer = w.Claimer;
w.Claimer = null; w.Claimer = null;
uow.Set<WaifuUpdate>().Add(new() uow.Set<WaifuUpdate>()
{ .Add(new()
User = w.Waifu, {
Old = oldClaimer, User = w.Waifu,
New = null, Old = oldClaimer,
UpdateType = WaifuUpdateType.Claimed New = null,
}); UpdateType = WaifuUpdateType.Claimed
});
} }
await uow.SaveChangesAsync(); await uow.SaveChangesAsync();
@ -358,40 +374,54 @@ public class WaifuService : IEService, IReadyExecutor
return (w, result, amount, remaining); return (w, result, amount, remaining);
} }
public async Task<bool> GiftWaifuAsync(IUser from, IUser giftedWaifu, WaifuItemModel itemObj) public async Task<bool> GiftWaifuAsync(
IUser from,
IUser giftedWaifu,
WaifuItemModel itemObj,
int count)
{ {
if (!await _cs.RemoveAsync(from, itemObj.Price, new("waifu", "item"))) ArgumentOutOfRangeException.ThrowIfLessThan(count, 1, nameof(count));
if (!await _cs.RemoveAsync(from, itemObj.Price * count, new("waifu", "item")))
return false; return false;
var totalValue = itemObj.Price * count;
await using var uow = _db.GetDbContext(); await using var uow = _db.GetDbContext();
var w = uow.Set<WaifuInfo>().ByWaifuUserId(giftedWaifu.Id, set => set.Include(x => x.Items).Include(x => x.Claimer)); var w = uow.Set<WaifuInfo>()
.ByWaifuUserId(giftedWaifu.Id,
set => set
.Include(x => x.Items)
.Include(x => x.Claimer));
if (w is null) if (w is null)
{ {
uow.Set<WaifuInfo>().Add(w = new() uow.Set<WaifuInfo>()
{ .Add(w = new()
Affinity = null, {
Claimer = null, Affinity = null,
Price = 1, Claimer = null,
Waifu = uow.GetOrCreateUser(giftedWaifu) Price = 1,
}); Waifu = uow.GetOrCreateUser(giftedWaifu)
});
} }
if (!itemObj.Negative) if (!itemObj.Negative)
{ {
w.Items.Add(new() w.Items.AddRange(Enumerable.Range(0, count)
{ .Select((_) => new WaifuItem()
Name = itemObj.Name.ToLowerInvariant(), {
ItemEmoji = itemObj.ItemEmoji Name = itemObj.Name.ToLowerInvariant(),
}); ItemEmoji = itemObj.ItemEmoji
}));
if (w.Claimer?.UserId == from.Id) if (w.Claimer?.UserId == from.Id)
w.Price += (long)(itemObj.Price * _gss.Data.Waifu.Multipliers.GiftEffect); w.Price += (long)(totalValue * _gss.Data.Waifu.Multipliers.GiftEffect);
else else
w.Price += itemObj.Price / 2; w.Price += totalValue / 2;
} }
else else
{ {
w.Price -= (long)(itemObj.Price * _gss.Data.Waifu.Multipliers.NegativeGiftEffect); w.Price -= (long)(totalValue * _gss.Data.Waifu.Multipliers.NegativeGiftEffect);
if (w.Price < 1) if (w.Price < 1)
w.Price = 1; w.Price = 1;
} }
@ -492,6 +522,7 @@ public class WaifuService : IEService, IReadyExecutor
} }
private static readonly TypedKey<long> _waifuDecayKey = $"waifu:last_decay"; private static readonly TypedKey<long> _waifuDecayKey = $"waifu:last_decay";
public async Task OnReadyAsync() public async Task OnReadyAsync()
{ {
// only decay waifu values from shard 0 // only decay waifu values from shard 0
@ -513,7 +544,7 @@ public class WaifuService : IEService, IReadyExecutor
var nowB = now.ToBinary(); var nowB = now.ToBinary();
var result = await _cache.GetAsync(_waifuDecayKey); var result = await _cache.GetAsync(_waifuDecayKey);
if (result.TryGetValue(out var val)) if (result.TryGetValue(out var val))
{ {
var lastDecay = DateTime.FromBinary(val); var lastDecay = DateTime.FromBinary(val);
@ -533,7 +564,6 @@ public class WaifuService : IEService, IReadyExecutor
{ {
Price = (long)(old.Price * multi) Price = (long)(old.Price * multi)
}); });
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -550,33 +580,35 @@ public class WaifuService : IEService, IReadyExecutor
{ {
await using var ctx = _db.GetDbContext(); await using var ctx = _db.GetDbContext();
return await ctx.GetTable<DiscordUser>() return await ctx.GetTable<DiscordUser>()
.Where(x => ctx.GetTable<WaifuInfo>() .Where(x => ctx.GetTable<WaifuInfo>()
.Where(wi => wi.ClaimerId == waifuId) .Where(wi => wi.ClaimerId == waifuId)
.Select(wi => wi.WaifuId) .Select(wi => wi.WaifuId)
.Contains(x.Id)) .Contains(x.Id))
.Select(x => $"{x.Username}#{x.Discriminator}") .Select(x => $"{x.Username}#{x.Discriminator}")
.ToListAsyncEF(); .ToListAsyncEF();
} }
public async Task<IReadOnlyCollection<string>> GetFansNames(int waifuId) public async Task<IReadOnlyCollection<string>> GetFansNames(int waifuId)
{ {
await using var ctx = _db.GetDbContext(); await using var ctx = _db.GetDbContext();
return await ctx.GetTable<DiscordUser>() return await ctx.GetTable<DiscordUser>()
.Where(x => ctx.GetTable<WaifuInfo>() .Where(x => ctx.GetTable<WaifuInfo>()
.Where(wi => wi.AffinityId == waifuId) .Where(wi => wi.AffinityId == waifuId)
.Select(wi => wi.WaifuId) .Select(wi => wi.WaifuId)
.Contains(x.Id)) .Contains(x.Id))
.Select(x => $"{x.Username}#{x.Discriminator}") .Select(x => $"{x.Username}#{x.Discriminator}")
.ToListAsyncEF(); .ToListAsyncEF();
} }
public async Task<IReadOnlyCollection<WaifuItem>> GetItems(int waifuId) public async Task<IReadOnlyCollection<WaifuItem>> GetItems(int waifuId)
{ {
await using var ctx = _db.GetDbContext(); await using var ctx = _db.GetDbContext();
return await ctx.GetTable<WaifuItem>() return await ctx.GetTable<WaifuItem>()
.Where(x => x.WaifuInfoId == ctx.GetTable<WaifuInfo>() .Where(x => x.WaifuInfoId
.Where(x => x.WaifuId == waifuId) == ctx.GetTable<WaifuInfo>()
.Select(x => x.Id) .Where(x => x.WaifuId == waifuId)
.FirstOrDefault()) .Select(x => x.Id)
.ToListAsyncEF(); .FirstOrDefault())
.ToListAsyncEF();
} }
} }

View file

@ -0,0 +1,6 @@
#nullable disable
using EllieBot.Modules.Gambling.Common;
namespace EllieBot.Modules.Gambling;
public record class MultipleWaifuItems(int Count, WaifuItemModel Item);

View file

@ -0,0 +1,47 @@
#nullable disable
using EllieBot.Common.TypeReaders;
using EllieBot.Modules.Gambling.Services;
using System.Text.RegularExpressions;
namespace EllieBot.Modules.Gambling;
public partial class MultipleWaifuItemsTypeReader : EllieTypeReader<MultipleWaifuItems>
{
private readonly WaifuService _service;
[GeneratedRegex(@"(?:(?<count>\d+)[x*])?(?<item>.+)")]
private static partial Regex ItemRegex();
public MultipleWaifuItemsTypeReader(WaifuService service)
{
_service = service;
}
public override ValueTask<TypeReaderResult<MultipleWaifuItems>> ReadAsync(ICommandContext ctx, string input)
{
input = input.ToLowerInvariant();
var match = ItemRegex().Match(input);
if (!match.Success)
{
return new(Discord.Commands.TypeReaderResult.FromError(CommandError.ParseFailed, "Invalid input."));
}
var count = 1;
if (match.Groups["count"].Success)
{
if (!int.TryParse(match.Groups["count"].Value, out count) || count < 1)
{
return new(Discord.Commands.TypeReaderResult.FromError(CommandError.ParseFailed, "Invalid count."));
}
}
var itemName = match.Groups["item"].Value?.ToLowerInvariant();
var allItems = _service.GetWaifuItems();
var item = allItems.FirstOrDefault(x => x.Name.ToLowerInvariant() == itemName);
if (item is null)
{
return new(Discord.Commands.TypeReaderResult.FromError(CommandError.ParseFailed, "Waifu gift does not exist."));
}
return new(Discord.Commands.TypeReaderResult.FromSuccess(new MultipleWaifuItems(count, item)));
}
}