diff --git a/Common/Master/TriggerPhraseMaster.cs b/Common/Master/TriggerPhraseMaster.cs index 25aa487..a9c1249 100644 --- a/Common/Master/TriggerPhraseMaster.cs +++ b/Common/Master/TriggerPhraseMaster.cs @@ -12,8 +12,9 @@ public enum TriggerType GachaExecute, GachaGet, Marugame, - PurchaseGet, + GachaRanking, SlotExecute, + SlotRanking, } [SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")] diff --git a/Common/Models/AppService.cs b/Common/Models/AppService.cs index ccff7e8..4a5f037 100644 --- a/Common/Models/AppService.cs +++ b/Common/Models/AppService.cs @@ -26,7 +26,7 @@ public async Task FindOrCreateUserAsync(ulong discordId) return user; } - user = new User { DiscordID = discordId }; + user = new User { DiscordId = discordId }; Add(user); return user; } diff --git a/Common/Models/User.cs b/Common/Models/User.cs index 1d9fe99..ca07e4a 100644 --- a/Common/Models/User.cs +++ b/Common/Models/User.cs @@ -4,9 +4,9 @@ namespace Approvers.King.Common; public class User { - [Key] public ulong DiscordID { get; set; } - public int MonthlyPurchase { get; set; } - public int MonthlySlotReward { get; set; } + [Key] public ulong DiscordId { get; set; } + public int MonthlyGachaPurchasePrice { get; set; } + public int MonthlySlotProfitPrice { get; set; } public int TodaySlotExecuteCount { get; set; } public User DeepCopy() @@ -17,8 +17,8 @@ public User DeepCopy() public void ResetMonthlyState() { - MonthlyPurchase = 0; - MonthlySlotReward = 0; + MonthlyGachaPurchasePrice = 0; + MonthlySlotProfitPrice = 0; } public void ResetDailyState() @@ -28,20 +28,20 @@ public void ResetDailyState() public GachaProbability? RollGachaOnce() { - MonthlyPurchase += MasterManager.SettingMaster.PricePerGachaOnce; + MonthlyGachaPurchasePrice += MasterManager.SettingMaster.PricePerGachaOnce; return GachaManager.Instance.Roll(); } public GachaProbability RollGachaOnceCertain() { - MonthlyPurchase += MasterManager.SettingMaster.PricePerGachaOnceCertain; + MonthlyGachaPurchasePrice += MasterManager.SettingMaster.PricePerGachaOnceCertain; return GachaManager.Instance.RollWithoutNone(); } public List RollGachaTenTimes() { const int pickCount = 10; - MonthlyPurchase += MasterManager.SettingMaster.PricePerGachaTenTimes; + MonthlyGachaPurchasePrice += MasterManager.SettingMaster.PricePerGachaTenTimes; return Enumerable.Range(0, pickCount).Select(_ => GachaManager.Instance.Roll()).ToList(); } @@ -55,8 +55,7 @@ public SlotExecuteResult ExecuteSlot() var price = MasterManager.SettingMaster.PricePerSlotOnce; var result = SlotManager.Instance.Execute(); var reward = (int)(NumberUtility.GetPercentFromPermillage(result.ResultRatePermillage) * price); - MonthlyPurchase += price; - MonthlySlotReward += reward; + MonthlySlotProfitPrice += reward - price; TodaySlotExecuteCount++; return result; } diff --git a/Events/DailyReset/DailyResetPresenter.cs b/Events/DailyReset/DailyResetPresenter.cs index db904cf..97bf589 100644 --- a/Events/DailyReset/DailyResetPresenter.cs +++ b/Events/DailyReset/DailyResetPresenter.cs @@ -45,7 +45,7 @@ private async Task NotifySlotMaxUsers(IReadOnlyList users) sb.AppendLine(); foreach (var user in users) { - sb.AppendLine($"- {MentionUtils.MentionUser(user.DiscordID)}"); + sb.AppendLine($"- {MentionUtils.MentionUser(user.DiscordId)}"); } await DiscordManager.GetMainChannel().SendMessageAsync(sb.ToString()); diff --git a/Events/Gacha/GachaCommandPresenter.cs b/Events/Gacha/GachaCommandPresenter.cs index cae9325..8685807 100644 --- a/Events/Gacha/GachaCommandPresenter.cs +++ b/Events/Gacha/GachaCommandPresenter.cs @@ -39,7 +39,7 @@ private async Task SendReplyAsync(User user, IReadOnlyList re } builder.AppendLine(); - builder.AppendLine($"おまえの今月の課金額 → {user.MonthlyPurchase:N0}†カス†(税込)"); + builder.AppendLine($"おまえの今月の課金額 → {user.MonthlyGachaPurchasePrice:N0}†カス†(税込)"); await Message.ReplyAsync(builder.ToString()); } diff --git a/Events/Gacha/GachaRankingPresenter.cs b/Events/Gacha/GachaRankingPresenter.cs new file mode 100644 index 0000000..f81e97f --- /dev/null +++ b/Events/Gacha/GachaRankingPresenter.cs @@ -0,0 +1,33 @@ +using Approvers.King.Common; +using Discord; +using Microsoft.EntityFrameworkCore; + +namespace Approvers.King.Events; + +public class GachaRankingPresenter : DiscordMessagePresenterBase +{ + protected override async Task MainAsync() + { + await using var app = AppService.CreateSession(); + + var selfUser = await app.FindOrCreateUserAsync(Message.Author.Id); + var users = await app.Users + .OrderByDescending(user => user.MonthlyGachaPurchasePrice) + .Take(MasterManager.SettingMaster.PurchaseInfoRankingViewUserCount) + .ToListAsync(); + + await SendReplyAsync(selfUser, users); + } + + private async Task SendReplyAsync(User selfUser, IReadOnlyList users) + { + var embed = new EmbedBuilder() + .WithColor(Color.LightOrange) + .AddField("おまえの今月のガチャ課金額", $"{selfUser.MonthlyGachaPurchasePrice:N0}†カス†(税込)", inline: true) + .AddField("ガチャ課金額ランキング", GachaUtility.CreateRankingView(users)) + .WithCurrentTimestamp() + .Build(); + + await Message.ReplyAsync(embed: embed); + } +} diff --git a/Events/Gacha/GachaUtility.cs b/Events/Gacha/GachaUtility.cs index f7ecb54..ee27bf1 100644 --- a/Events/Gacha/GachaUtility.cs +++ b/Events/Gacha/GachaUtility.cs @@ -1,4 +1,5 @@ -using Approvers.King.Common; +using System.Text; +using Approvers.King.Common; using Discord; namespace Approvers.King.Events; @@ -18,4 +19,22 @@ public static EmbedBuilder GetInfoEmbedBuilder() .WithDescription($"本日は {Format.Bold($"{GachaManager.Instance.RareReplyRate:P0}")} の確率で反応します") .AddField("排出確率", DiscordMessageUtility.Table(records)); } + + public static string CreateRankingView(IReadOnlyList rankingUsers) + { + var embedBuilder = new StringBuilder(); + var order = 1; + foreach (var user in rankingUsers) + { + var scoreText = Math.Min(999_999_999, user.MonthlyGachaPurchasePrice).ToString("N0"); + var whiteSpace = Math.Max(0, 11 - scoreText.Length); + var line = + Format.Code($"#{order:D2} - {"".PadLeft(whiteSpace, ' ')}{scoreText}†カス†(税込)") + " " + + MentionUtils.MentionUser(user.DiscordId); + embedBuilder.AppendLine(line); + order++; + } + + return embedBuilder.ToString(); + } } diff --git a/Events/MonthlyReset/MonthlyResetPresenter.cs b/Events/MonthlyReset/MonthlyResetPresenter.cs index 3e15b62..fcb5cb4 100644 --- a/Events/MonthlyReset/MonthlyResetPresenter.cs +++ b/Events/MonthlyReset/MonthlyResetPresenter.cs @@ -11,12 +11,12 @@ protected override async Task MainAsync() await using var app = AppService.CreateSession(); var purchaseRankingUsers = await app.Users - .OrderByDescending(user => user.MonthlyPurchase) + .OrderByDescending(user => user.MonthlyGachaPurchasePrice) .Take(MasterManager.SettingMaster.PurchaseInfoRankingViewUserCount) .Select(x => x.DeepCopy()) .ToListAsync(); var slotRewardRankingUsers = await app.Users - .OrderByDescending(user => user.MonthlySlotReward) + .OrderByDescending(user => user.MonthlySlotProfitPrice) .Take(MasterManager.SettingMaster.PurchaseInfoRankingViewUserCount) .Select(x => x.DeepCopy()) .ToListAsync(); @@ -33,8 +33,8 @@ private async Task SendSummaryAsync(IReadOnlyList purchaseRankingUsers, IR .WithColor(Color.LightOrange) .WithTitle(Format.Bold($"{IssoUtility.SmileStamp} †今月も貢げカス† {IssoUtility.SmileStamp}")) .WithDescription("月が変わったから課金額をリセットした") - .AddField("先月の課金額ランキング", PurchaseUtility.CreatePurchaseView(purchaseRankingUsers)) - .AddField("先月の利益ランキング", PurchaseUtility.CreateSlotRewardView(slotRewardRankingUsers)) + .AddField("先月の課金額ランキング", GachaUtility.CreateRankingView(purchaseRankingUsers)) + .AddField("先月の利益ランキング", SlotUtility.CreateRankingView(slotRewardRankingUsers)) .WithCurrentTimestamp() .Build(); diff --git a/Events/Purchase/PurchaseShowPresenter.cs b/Events/Purchase/PurchaseShowPresenter.cs deleted file mode 100644 index 209b33f..0000000 --- a/Events/Purchase/PurchaseShowPresenter.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Approvers.King.Common; -using Discord; -using Microsoft.EntityFrameworkCore; - -namespace Approvers.King.Events; - -public class PurchaseShowPresenter : DiscordMessagePresenterBase -{ - protected override async Task MainAsync() - { - await using var app = AppService.CreateSession(); - - var selfUser = await app.FindOrCreateUserAsync(Message.Author.Id); - var purchaseRankingUsers = await app.Users - .OrderByDescending(user => user.MonthlyPurchase) - .Take(MasterManager.SettingMaster.PurchaseInfoRankingViewUserCount) - .ToListAsync(); - var slotRewardRankingUsers = await app.Users - .OrderByDescending(user => user.MonthlySlotReward) - .Take(MasterManager.SettingMaster.PurchaseInfoRankingViewUserCount) - .ToListAsync(); - - await SendReplyAsync(selfUser, purchaseRankingUsers, slotRewardRankingUsers); - } - - private async Task SendReplyAsync(User selfUser, IReadOnlyList purchaseRankingUsers, IReadOnlyList slotRewardRankingUsers) - { - var embed = new EmbedBuilder() - .WithColor(Color.LightOrange) - .AddField("おまえの今月の課金額", $"{selfUser.MonthlyPurchase:N0}†カス†(税込)", inline: true) - .AddField("課金額ランキング", PurchaseUtility.CreatePurchaseView(purchaseRankingUsers)) - .AddField("利益ランキング", PurchaseUtility.CreateSlotRewardView(slotRewardRankingUsers)) - .WithCurrentTimestamp() - .Build(); - - await Message.ReplyAsync(embed: embed); - } -} diff --git a/Events/Purchase/PurchaseUtility.cs b/Events/Purchase/PurchaseUtility.cs deleted file mode 100644 index ef93710..0000000 --- a/Events/Purchase/PurchaseUtility.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Text; -using Approvers.King.Common; -using Discord; - -namespace Approvers.King.Events; - -public static class PurchaseUtility -{ - public static string CreatePurchaseView(IReadOnlyList rankingUsers) - { - var embedBuilder = new StringBuilder(); - var order = 1; - foreach (var user in rankingUsers) - { - var scoreText = Math.Min(999_999_999, user.MonthlyPurchase).ToString("N0"); - var whiteSpace = Math.Max(0, 11 - scoreText.Length); - var line = - Format.Code($"#{order:D2} - {"".PadLeft(whiteSpace, ' ')}{scoreText}†カス†(税込)") + " " + - MentionUtils.MentionUser(user.DiscordID); - embedBuilder.AppendLine(line); - order++; - } - - return embedBuilder.ToString(); - } - - public static string CreateSlotRewardView(IReadOnlyList rankingUsers) - { - var embedBuilder = new StringBuilder(); - var order = 1; - foreach (var user in rankingUsers) - { - var scoreText = Math.Min(999_999_999, user.MonthlySlotReward).ToString("N0"); - var whiteSpace = Math.Max(0, 11 - scoreText.Length); - var line = - Format.Code($"#{order:D2} - {"".PadLeft(whiteSpace, ' ')}{scoreText}†カス†(税込)") + " " + - MentionUtils.MentionUser(user.DiscordID); - embedBuilder.AppendLine(line); - order++; - } - - return embedBuilder.ToString(); - } -} diff --git a/Events/Slot/SlotExecutePresenter.cs b/Events/Slot/SlotExecutePresenter.cs index 8845ce2..92f9dd9 100644 --- a/Events/Slot/SlotExecutePresenter.cs +++ b/Events/Slot/SlotExecutePresenter.cs @@ -83,7 +83,7 @@ private static string CreatePurchaseMessage(SlotExecuteResult result, User user, } else { - sb.AppendLine($"おまえの今月の利益 → {user.MonthlySlotReward:N0}†カス†(税込)"); + sb.AppendLine($"おまえの今月の利益 → {user.MonthlySlotProfitPrice:N0}†カス†(税込)"); } return sb.ToString(); diff --git a/Events/Slot/SlotRankingPresenter.cs b/Events/Slot/SlotRankingPresenter.cs new file mode 100644 index 0000000..77b4964 --- /dev/null +++ b/Events/Slot/SlotRankingPresenter.cs @@ -0,0 +1,33 @@ +using Approvers.King.Common; +using Discord; +using Microsoft.EntityFrameworkCore; + +namespace Approvers.King.Events; + +public class SlotRankingPresenter : DiscordMessagePresenterBase +{ + protected override async Task MainAsync() + { + await using var app = AppService.CreateSession(); + + var selfUser = await app.FindOrCreateUserAsync(Message.Author.Id); + var users = await app.Users + .OrderByDescending(user => user.MonthlySlotProfitPrice) + .Take(MasterManager.SettingMaster.PurchaseInfoRankingViewUserCount) + .ToListAsync(); + + await SendReplyAsync(selfUser, users); + } + + private async Task SendReplyAsync(User selfUser, IReadOnlyList users) + { + var embed = new EmbedBuilder() + .WithColor(Color.LightOrange) + .AddField("おまえの今月のスロット利益額", $"{selfUser.MonthlySlotProfitPrice:N0}†カス†(税込)", inline: true) + .AddField("スロット利益額ランキング", SlotUtility.CreateRankingView(users)) + .WithCurrentTimestamp() + .Build(); + + await Message.ReplyAsync(embed: embed); + } +} diff --git a/Events/Slot/SlotUtility.cs b/Events/Slot/SlotUtility.cs new file mode 100644 index 0000000..e384ebf --- /dev/null +++ b/Events/Slot/SlotUtility.cs @@ -0,0 +1,26 @@ +using System.Text; +using Approvers.King.Common; +using Discord; + +namespace Approvers.King.Events; + +public static class SlotUtility +{ + public static string CreateRankingView(IReadOnlyList rankingUsers) + { + var embedBuilder = new StringBuilder(); + var order = 1; + foreach (var user in rankingUsers) + { + var scoreText = Math.Min(999_999_999, user.MonthlySlotProfitPrice).ToString("N0"); + var whiteSpace = Math.Max(0, 11 - scoreText.Length); + var line = + Format.Code($"#{order:D2} - {"".PadLeft(whiteSpace, ' ')}{scoreText}†カス†(税込)") + " " + + MentionUtils.MentionUser(user.DiscordId); + embedBuilder.AppendLine(line); + order++; + } + + return embedBuilder.ToString(); + } +} diff --git a/Migrations/20241127165904_SeparatePurchase.Designer.cs b/Migrations/20241127165904_SeparatePurchase.Designer.cs new file mode 100644 index 0000000..a072db1 --- /dev/null +++ b/Migrations/20241127165904_SeparatePurchase.Designer.cs @@ -0,0 +1,71 @@ +// +using Approvers.King.Common; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Approvers.King.Migrations +{ + [DbContext(typeof(AppService))] + [Migration("20241127165904_SeparatePurchase")] + partial class SeparatePurchase + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); + + modelBuilder.Entity("Approvers.King.Common.AppState", b => + { + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Type"); + + b.ToTable("AppStates"); + }); + + modelBuilder.Entity("Approvers.King.Common.GachaProbability", b => + { + b.Property("RandomMessageId") + .HasColumnType("TEXT"); + + b.Property("Probability") + .HasColumnType("REAL"); + + b.HasKey("RandomMessageId"); + + b.ToTable("GachaProbabilities"); + }); + + modelBuilder.Entity("Approvers.King.Common.User", b => + { + b.Property("DiscordId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("MonthlyGachaPurchasePrice") + .HasColumnType("INTEGER"); + + b.Property("MonthlySlotProfitPrice") + .HasColumnType("INTEGER"); + + b.Property("TodaySlotExecuteCount") + .HasColumnType("INTEGER"); + + b.HasKey("DiscordId"); + + b.ToTable("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/20241127165904_SeparatePurchase.cs b/Migrations/20241127165904_SeparatePurchase.cs new file mode 100644 index 0000000..4cc0f96 --- /dev/null +++ b/Migrations/20241127165904_SeparatePurchase.cs @@ -0,0 +1,48 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Approvers.King.Migrations +{ + /// + public partial class SeparatePurchase : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "DiscordID", + table: "Users", + newName: "DiscordId"); + + migrationBuilder.RenameColumn( + name: "MonthlySlotReward", + table: "Users", + newName: "MonthlySlotProfitPrice"); + + migrationBuilder.RenameColumn( + name: "MonthlyPurchase", + table: "Users", + newName: "MonthlyGachaPurchasePrice"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "DiscordId", + table: "Users", + newName: "DiscordID"); + + migrationBuilder.RenameColumn( + name: "MonthlySlotProfitPrice", + table: "Users", + newName: "MonthlySlotReward"); + + migrationBuilder.RenameColumn( + name: "MonthlyGachaPurchasePrice", + table: "Users", + newName: "MonthlyPurchase"); + } + } +} diff --git a/Migrations/AppServiceModelSnapshot.cs b/Migrations/AppServiceModelSnapshot.cs index 2b00fac..f3eae2a 100644 --- a/Migrations/AppServiceModelSnapshot.cs +++ b/Migrations/AppServiceModelSnapshot.cs @@ -45,20 +45,20 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Approvers.King.Common.User", b => { - b.Property("DiscordID") + b.Property("DiscordId") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("MonthlyPurchase") + b.Property("MonthlyGachaPurchasePrice") .HasColumnType("INTEGER"); - b.Property("MonthlySlotReward") + b.Property("MonthlySlotProfitPrice") .HasColumnType("INTEGER"); b.Property("TodaySlotExecuteCount") .HasColumnType("INTEGER"); - b.HasKey("DiscordID"); + b.HasKey("DiscordId"); b.ToTable("Users"); }); diff --git a/Program.cs b/Program.cs index e86ab54..d6c464b 100644 --- a/Program.cs +++ b/Program.cs @@ -69,10 +69,17 @@ private static void OnMessageReceived(SocketMessage message) return; } - if (IsContainsTriggerPhrase(userMessage.Content, TriggerType.PurchaseGet)) + if (IsContainsTriggerPhrase(userMessage.Content, TriggerType.GachaRanking)) { - // 課金情報の表示 - DiscordManager.ExecuteAsync(userMessage).Run(); + // ガチャランキングの表示 + DiscordManager.ExecuteAsync(userMessage).Run(); + return; + } + + if (IsContainsTriggerPhrase(userMessage.Content, TriggerType.SlotRanking)) + { + // スロットランキングの表示 + DiscordManager.ExecuteAsync(userMessage).Run(); return; }