add: Added multiplier option for waifu gifts. For example .waifugift 3xRose @user will give that user 3 roses

This commit is contained in:
Kwoth
2024-07-12 17:18:47 +00:00
parent e1892c4ff4
commit 8523abd6f1
6 changed files with 228 additions and 141 deletions

View File

@@ -181,9 +181,9 @@ dotnet_naming_rule.private_readonly_field.symbols = private_readonly_field
dotnet_naming_rule.private_readonly_field.style = begins_with_underscore dotnet_naming_rule.private_readonly_field.style = begins_with_underscore
dotnet_naming_rule.private_readonly_field.severity = warning dotnet_naming_rule.private_readonly_field.severity = warning
dotnet_naming_rule.private_field.symbols = private_field # dotnet_naming_rule.private_field.symbols = private_field
dotnet_naming_rule.private_field.style = camel_case # dotnet_naming_rule.private_field.style = camel_case
dotnet_naming_rule.private_field.severity = warning # dotnet_naming_rule.private_field.severity = warning
dotnet_naming_rule.const_fields.symbols = const_fields dotnet_naming_rule.const_fields.symbols = const_fields
dotnet_naming_rule.const_fields.style = all_upper dotnet_naming_rule.const_fields.style = all_upper

View File

@@ -3,6 +3,7 @@ using NadekoBot.Modules.Gambling.Common;
using NadekoBot.Modules.Gambling.Common.Waifu; using NadekoBot.Modules.Gambling.Common.Waifu;
using NadekoBot.Modules.Gambling.Services; using NadekoBot.Modules.Gambling.Services;
using NadekoBot.Db.Models; using NadekoBot.Db.Models;
using TwitchLib.Api.Helix.Models.Teams;
namespace NadekoBot.Modules.Gambling; namespace NadekoBot.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();
} }
@@ -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 NadekoBot.Db;
using NadekoBot.Db.Models; using NadekoBot.Db.Models;
using NadekoBot.Modules.Gambling.Common; using NadekoBot.Modules.Gambling.Common;
using NadekoBot.Modules.Gambling.Common.Waifu; using NadekoBot.Modules.Gambling.Common.Waifu;
using SixLabors.ImageSharp;
namespace NadekoBot.Modules.Gambling.Services; namespace NadekoBot.Modules.Gambling.Services;
@@ -89,9 +90,14 @@ public class WaifuService : INService, 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 : INService, 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 : INService, 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 : INService, 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 : INService, 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
@@ -248,22 +260,24 @@ public class WaifuService : INService, IReadyExecutor
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 : INService, 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();
@@ -343,13 +358,14 @@ public class WaifuService : INService, 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 : INService, 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 : INService, 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
@@ -533,7 +564,6 @@ public class WaifuService : INService, IReadyExecutor
{ {
Price = (long)(old.Price * multi) Price = (long)(old.Price * multi)
}); });
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -550,33 +580,35 @@ public class WaifuService : INService, 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 NadekoBot.Modules.Gambling.Common;
namespace NadekoBot.Modules.Gambling;
public record class MultipleWaifuItems(int Count, WaifuItemModel Item);

View File

@@ -0,0 +1,47 @@
#nullable disable
using NadekoBot.Common.TypeReaders;
using NadekoBot.Modules.Gambling.Services;
using System.Text.RegularExpressions;
namespace NadekoBot.Modules.Gambling;
public partial class MultipleWaifuItemsTypeReader : NadekoTypeReader<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)));
}
}

View File

@@ -2753,8 +2753,10 @@ waifutransfer:
desc: "The user to whom ownership of the waifu is being transferred." desc: "The user to whom ownership of the waifu is being transferred."
waifugift: waifugift:
desc: -| desc: -|
Gift an item to someone. Gift an item to a waifu user.
This will increase their waifu value by a percentage of the gift's value. The waifu's value will be increased by the percentage of the gift's value.
You can optionally prefix the gift with a multiplier to gift the item that many times.
For example, 3xRose will give the waifu 3 roses, 10xBread will give the waifu 10 breads. Do not use plural forms.
Negative gifts will not show up in waifuinfo. Negative gifts will not show up in waifuinfo.
Provide no parameters to see a list of items that you can gift. Provide no parameters to see a list of items that you can gift.
ex: ex:
@@ -2762,9 +2764,9 @@ waifugift:
- Rose @Himesama - Rose @Himesama
params: params:
- page: - page:
desc: "The number of pages to display when listing available gifting options." desc: "The number of the page to display."
- itemName: - items:
desc: "The name of an item to be gifted, which is used to determine the percentage increase in waifu value." desc: "The name of an item to be gifted. With an optional multiplier prefix."
waifu: waifu:
desc: "The user who is receiving the gift." desc: "The user who is receiving the gift."
waifulb: waifulb: