From 619e83e0be78b0d638cd5bf5ee35572e1b3c448a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 16 Jan 2017 14:27:39 +0100 Subject: [PATCH 01/27] Repeater will stop if channel was deleted or bot can't write to that channel --- .../Utility/Commands/MessageRepeater.cs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs index 71bd6748..619b71fa 100644 --- a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs @@ -1,5 +1,6 @@ using Discord; using Discord.Commands; +using Discord.Net; using Microsoft.EntityFrameworkCore; using NadekoBot.Attributes; using NadekoBot.Extensions; @@ -64,7 +65,24 @@ namespace NadekoBot.Modules.Utility if (oldMsg != null) try { await oldMsg.DeleteAsync(); } catch { } - try { oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } + try + { + oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false); + } + catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + _log.Warn("Missing permissions. Repeater stopped. ChannelId : {0}", Channel?.Id); + return; + } + catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound) + { + _log.Warn("Channel not found. Repeater stopped. ChannelId : {0}", Channel?.Id); + return; + } + catch (Exception ex) + { + _log.Warn(ex); + } } } catch (OperationCanceledException) { } From f49a64d7a427fce52c445326c3f19cb47a18323a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 16 Jan 2017 14:46:17 +0100 Subject: [PATCH 02/27] fixed role changes --- Discord.Net | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Discord.Net b/Discord.Net index f27cce08..58766448 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit f27cce0854abc42b92d29f9040625238a8991999 +Subproject commit 58766448d79ac9adec228f341f258aa262a3f278 From 1358b2b524a8fc69ffeec24a4a740ff316872c7b Mon Sep 17 00:00:00 2001 From: samvaio Date: Mon, 16 Jan 2017 19:31:43 +0530 Subject: [PATCH 03/27] Update Windows Guide.md --- docs/guides/Windows Guide.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/guides/Windows Guide.md b/docs/guides/Windows Guide.md index 1f996b1c..0d569909 100644 --- a/docs/guides/Windows Guide.md +++ b/docs/guides/Windows Guide.md @@ -16,8 +16,8 @@ ________________________________________________________________________________ ####Guide - Make sure you have installed both [Git][Git] and the [.NET Core SDK][.NET Core SDK]. - Create a **new folder** anywhere you like and name it `Nadeko`. -- Next, [Right-Click on this link](https://github.com/Kwoth/NadekoBotInstallerWin/raw/master/NadekoInstaller.bat) and select **Save link as** and save the file `NadekoInstaller.bat` inside the `Nadeko` folder that we created earlier. (**DO NOT** rename the file `NadekoInstaller.bat`) -- Once that's done, double-click on `NadekoInstaller.bat` to run it. +- Next, [Right-Click on this link](https://github.com/Kwoth/NadekoBotInstallerWin/raw/master/NadekoInstaller.bat) and select **Save link as** and save the file `NadekoInstaller.bat` inside the `Nadeko` folder that we created earlier. (Please **DO NOT** rename the file `NadekoInstaller.bat`.) +- Once that's done, right-click on `NadekoInstaller.bat` to run it as Administrator. - From the options, - Choose `1` to get the **most recent build**. - Choose `2` to get the **stable build**. @@ -58,7 +58,7 @@ ________________________________________________________________________________ - The bot should have been added to your server. ####Starting the bot -- Go to the `Nadeko` folder that we have created earlier, and run the `NadekoInstaller.bat` file. +- Go to the `Nadeko` folder that we have created earlier, and run the `NadekoInstaller.bat` file as Administrator. - From the options, - Choose `3` to **run the bot normally**. (with normal-run the bot will shutdown and will stay offline if it disconnects by the use of `.die` command until you manually run it again. Useful if you want to test the bot.) @@ -83,6 +83,16 @@ ________________________________________________________________________________ In order to have a functioning music module, you need to install ffmpeg and setup api keys. +#### Setting up `ffmpeg` using NadekoBot Client! +- Go to the `Nadeko` folder that we have created earlier, and run the `NadekoInstaller.bat` file as Administrator. +- From the options select `6` Install ffmpeg (for music) +- Next, **Press Any Key** if you are running as Administrator or just close and relaunch it as Administrator using mouse right-click. +- Wait for it to finish installing and backing up existing. +- Once done, you should see "ffmpeg Installation complete!". +- Next, **Press Any Key** to go back to NadekoBot Client. +- Press `3` to run the bot normally just to test music. (optional) +- `ffmpeg` installation for Music is now complete. + #### Manual `ffmpeg` setup - Create a folder named `ffmpeg` in your main Windows directory. We will use **C:\ffmpeg** (for our guide) - Download FFMPEG through the link https://ffmpeg.zeranoe.com/builds/ (download static build) From 7188f901ccad1c9da0e478560d2e4ef736e01229 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 16 Jan 2017 15:12:51 +0100 Subject: [PATCH 04/27] Fixed !!lq when there are radio links in the queue --- src/NadekoBot/Modules/Music/Classes/MusicControls.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index 701bc937..6d101975 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -43,7 +43,12 @@ namespace NadekoBot.Modules.Music.Classes /// public uint MaxPlaytimeSeconds { get; set; } = 0; - public TimeSpan TotalPlaytime => new TimeSpan(playlist.Sum(s => s.TotalTime.Ticks)); + + // this should be written better + public TimeSpan TotalPlaytime => + playlist.Any(s => s.TotalTime == TimeSpan.MaxValue) ? + TimeSpan.MaxValue : + new TimeSpan(playlist.Sum(s => s.TotalTime.Ticks)); /// /// Users who recently got their music wish From 8e7d697bb24b0d37f021e3dcc14be20951646476 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 16 Jan 2017 15:13:07 +0100 Subject: [PATCH 05/27] woops --- src/NadekoBot/Modules/Music/Music.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 0cb28121..352821c5 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -204,6 +204,7 @@ namespace NadekoBot.Modules.Music const int itemsPerPage = 10; var total = musicPlayer.TotalPlaytime; + var totalStr = total == TimeSpan.MaxValue ? "∞" : $"{(int)total.TotalHours}h {total.Minutes}m {total.Seconds}s"; var maxPlaytime = musicPlayer.MaxPlaytimeSeconds; var lastPage = musicPlayer.Playlist.Count / itemsPerPage; Func printAction = (curPage) => @@ -218,7 +219,7 @@ namespace NadekoBot.Modules.Music .Take(itemsPerPage) .Select(v => $"`{++number}.` {v.PrettyFullName}"))) .WithFooter(ef => ef.WithText($"{musicPlayer.PrettyVolume} | {musicPlayer.Playlist.Count} " + - $"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {(int)total.TotalHours}h {total.Minutes}m {total.Seconds}s | " + + $"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {totalStr} | " + (musicPlayer.FairPlay ? "✔️fairplay" : "✖️fairplay") + $" | " + (maxPlaytime == 0 ? "unlimited" : $"{maxPlaytime}s limit"))) .WithOkColor(); From 9a81de1b457cfe0e82e8e3860dab8a6669de19f0 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 16 Jan 2017 15:21:10 +0100 Subject: [PATCH 06/27] gifs now work in >plant, >gc and $bf --- .../Modules/Gambling/Commands/FlipCoinCommand.cs | 2 +- .../Modules/Games/Commands/PlantAndPickCommands.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs index 6cb49f71..85092dc7 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs @@ -93,7 +93,7 @@ namespace NadekoBot.Modules.Gambling str = $"{Context.User.Mention}`Better luck next time.`"; } - await Context.Channel.SendFileAsync(File.Open(imgPathToSend, FileMode.OpenOrCreate), "coin.jpg", str).ConfigureAwait(false); + await Context.Channel.SendFileAsync(File.Open(imgPathToSend, FileMode.OpenOrCreate), new FileInfo(imgPathToSend).Name, str).ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 3782fe78..272ced2a 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -93,10 +93,10 @@ namespace NadekoBot.Modules.Games { firstPart = $"{dropAmount} random { NadekoBot.BotConfig.CurrencyPluralName } appeared!"; } - + var file = GetRandomCurrencyImagePath(); var sent = await channel.SendFileAsync( - File.Open(GetRandomCurrencyImagePath(), FileMode.OpenOrCreate), - "RandomFlower.jpg", + File.Open(file, FileMode.OpenOrCreate), + new FileInfo(file).Name, $"❗ {firstPart} Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`") .ConfigureAwait(false); @@ -167,7 +167,7 @@ namespace NadekoBot.Modules.Games } else { - msg = await Context.Channel.SendFileAsync(File.Open(file, FileMode.OpenOrCreate), "plant.jpg", msgToSend).ConfigureAwait(false); + msg = await Context.Channel.SendFileAsync(File.Open(file, FileMode.OpenOrCreate), new FileInfo(file).Name, msgToSend).ConfigureAwait(false); } plantedFlowers.AddOrUpdate(Context.Channel.Id, new List() { msg }, (id, old) => { old.Add(msg); return old; }); } From 35d2ada373cfdeee05187841ab28b3d6dc13653c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 16 Jan 2017 15:25:50 +0100 Subject: [PATCH 07/27] Don't download users. It breaks the bot for some people?!?!??! --- src/NadekoBot/NadekoBot.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index c8084905..a019476a 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -96,7 +96,7 @@ namespace NadekoBot //connect await Client.LoginAsync(TokenType.Bot, Credentials.Token).ConfigureAwait(false); await Client.ConnectAsync().ConfigureAwait(false); - await Client.DownloadAllUsersAsync().ConfigureAwait(false); + //await Client.DownloadAllUsersAsync().ConfigureAwait(false); Stats.Initialize(); _log.Info("Connected"); From df05f7dae945249e2cc87ec20f1215c42e399df2 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 16 Jan 2017 15:28:47 +0100 Subject: [PATCH 08/27] Upped version to 1.1.2 --- src/NadekoBot/Services/Impl/StatsService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index 86955b83..7e3f4406 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -15,7 +15,7 @@ namespace NadekoBot.Services.Impl private DiscordShardedClient client; private DateTime started; - public const string BotVersion = "1.1.1"; + public const string BotVersion = "1.1.2"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From c04e376492c8298bad82e92cc214830455cebc2c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 17 Jan 2017 03:23:13 +0100 Subject: [PATCH 09/27] autohentai requires manage messages permission --- src/NadekoBot/Modules/NSFW/NSFW.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index ae9f8568..8e520c6c 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -66,6 +66,7 @@ namespace NadekoBot.Modules.NSFW InternalHentai(Context.Channel, tag, false); [NadekoCommand, Usage, Description, Aliases] + [RequireUserPermission(ChannelPermission.ManageMessages)] public async Task AutoHentai(int interval = 0, string tags = null) { Timer t; From 4f07f9efd28a365a780ae6249c96a04f09373af6 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 17 Jan 2017 03:26:24 +0100 Subject: [PATCH 10/27] Fixed queue error message when user is not in a voice channel --- src/NadekoBot/Modules/Music/Music.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 352821c5..868a0885 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -805,7 +805,7 @@ namespace NadekoBot.Modules.Music if (voiceCh == null || voiceCh.Guild != textCh.Guild) { if (!silent) - await textCh.SendErrorAsync("💢 You need to be in a voice channel on this server.\n If you are already in a voice (ITextChannel)Context.Channel, try rejoining.").ConfigureAwait(false); + await textCh.SendErrorAsync($"💢 You need to be in a voice channel on this server.").ConfigureAwait(false); throw new ArgumentNullException(nameof(voiceCh)); } if (string.IsNullOrWhiteSpace(query) || query.Length < 3) From 9cb9529b14e7aa6fec22003e0594d0b476c370f3 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 18 Jan 2017 01:42:28 +0100 Subject: [PATCH 11/27] .uinfo is no longer COUNTING the everyone role --- src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs index 8814c50c..f8b5c7ff 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -92,7 +92,7 @@ namespace NadekoBot.Modules.Utility embed.AddField(fb => fb.WithName("**ID**").WithValue(user.Id.ToString()).WithIsInline(true)) .AddField(fb => fb.WithName("**Joined Server**").WithValue($"{user.JoinedAt?.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) .AddField(fb => fb.WithName("**Joined Discord**").WithValue($"{user.CreatedAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count})** - {string.Join(", ", user.GetRoles().Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count - 1})** - {string.Join(", ", user.GetRoles().Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true)) .WithThumbnailUrl(user.AvatarUrl) .WithColor(NadekoBot.OkColor); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); From 8bde87c071065adc7dad9dc1c6b8a05888a0ea80 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 18 Jan 2017 02:44:48 +0100 Subject: [PATCH 12/27] .sinfo shows both names of the emojis and actual emojis --- src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs index f8b5c7ff..0ab94ada 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -34,6 +34,9 @@ namespace NadekoBot.Modules.Utility var createdAt = new DateTime(2015, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(guild.Id >> 22); var sb = new StringBuilder(); var users = await guild.GetUsersAsync().ConfigureAwait(false); + var features = string.Join("\n", guild.Features); + if (string.IsNullOrWhiteSpace(features)) + features = "-"; var embed = new EmbedBuilder() .WithAuthor(eab => eab.WithName("Server Info")) .WithTitle(guild.Name) @@ -45,11 +48,12 @@ namespace NadekoBot.Modules.Utility .AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) .AddField(fb => fb.WithName("**Region**").WithValue(guild.VoiceRegionId.ToString()).WithIsInline(true)) .AddField(fb => fb.WithName("**Roles**").WithValue((guild.Roles.Count - 1).ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName("**Features**").WithValue(features).WithIsInline(true)) .WithImageUrl(guild.IconUrl) .WithColor(NadekoBot.OkColor); if (guild.Emojis.Count() > 0) { - embed.AddField(fb => fb.WithName("**Custom Emojis**").WithValue(Format.Italics(string.Join(", ", guild.Emojis))).WithIsInline(true)); + embed.AddField(fb => fb.WithName("**Custom Emojis**").WithValue(Format.Italics(string.Join(" | ", guild.Emojis.Select(e => $"{e.Name} <:{e.Name}:{e.Id}>"))))); } await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } @@ -92,7 +96,7 @@ namespace NadekoBot.Modules.Utility embed.AddField(fb => fb.WithName("**ID**").WithValue(user.Id.ToString()).WithIsInline(true)) .AddField(fb => fb.WithName("**Joined Server**").WithValue($"{user.JoinedAt?.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) .AddField(fb => fb.WithName("**Joined Discord**").WithValue($"{user.CreatedAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count - 1})** - {string.Join(", ", user.GetRoles().Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count - 1})** - {string.Join("\n", user.GetRoles().Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true)) .WithThumbnailUrl(user.AvatarUrl) .WithColor(NadekoBot.OkColor); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); From 6861965c5b0c3e41fa79f58e023b66bb5b79b3d3 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 18 Jan 2017 05:48:15 +0100 Subject: [PATCH 13/27] sinfo custom emojis no longer italic --- src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs index 0ab94ada..eaea37f0 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -53,7 +53,7 @@ namespace NadekoBot.Modules.Utility .WithColor(NadekoBot.OkColor); if (guild.Emojis.Count() > 0) { - embed.AddField(fb => fb.WithName("**Custom Emojis**").WithValue(Format.Italics(string.Join(" | ", guild.Emojis.Select(e => $"{e.Name} <:{e.Name}:{e.Id}>"))))); + embed.AddField(fb => fb.WithName("**Custom Emojis**").WithValue(string.Join(" ", guild.Emojis.Select(e => $"{e.Name} <:{e.Name}:{e.Id}>")))); } await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } From 4141ab4a9e29bd42bf06aacf8f1f92f83fee5cf5 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 18 Jan 2017 05:49:12 +0100 Subject: [PATCH 14/27] $slot, $slottest and $slotstats added --- .../Modules/Gambling/Commands/Slots.cs | 301 ++++++++++++++++++ .../Resources/CommandStrings.Designer.cs | 81 +++++ src/NadekoBot/Resources/CommandStrings.resx | 27 ++ src/NadekoBot/data/slots/0.png | Bin 0 -> 551 bytes src/NadekoBot/data/slots/1.png | Bin 0 -> 392 bytes src/NadekoBot/data/slots/2.png | Bin 0 -> 553 bytes src/NadekoBot/data/slots/3.png | Bin 0 -> 539 bytes src/NadekoBot/data/slots/4.png | Bin 0 -> 471 bytes src/NadekoBot/data/slots/5.png | Bin 0 -> 542 bytes src/NadekoBot/data/slots/6.png | Bin 0 -> 562 bytes src/NadekoBot/data/slots/7.png | Bin 0 -> 417 bytes src/NadekoBot/data/slots/8.png | Bin 0 -> 597 bytes src/NadekoBot/data/slots/9.png | Bin 0 -> 578 bytes src/NadekoBot/data/slots/background.png | Bin 0 -> 114008 bytes src/NadekoBot/data/slots/emojis/0.png | Bin 0 -> 8966 bytes src/NadekoBot/data/slots/emojis/1.png | Bin 0 -> 2183 bytes src/NadekoBot/data/slots/emojis/2.png | Bin 0 -> 3478 bytes src/NadekoBot/data/slots/emojis/3.png | Bin 0 -> 5804 bytes src/NadekoBot/data/slots/emojis/4.png | Bin 0 -> 3461 bytes src/NadekoBot/data/slots/emojis/5.png | Bin 0 -> 6302 bytes 20 files changed, 409 insertions(+) create mode 100644 src/NadekoBot/Modules/Gambling/Commands/Slots.cs create mode 100644 src/NadekoBot/data/slots/0.png create mode 100644 src/NadekoBot/data/slots/1.png create mode 100644 src/NadekoBot/data/slots/2.png create mode 100644 src/NadekoBot/data/slots/3.png create mode 100644 src/NadekoBot/data/slots/4.png create mode 100644 src/NadekoBot/data/slots/5.png create mode 100644 src/NadekoBot/data/slots/6.png create mode 100644 src/NadekoBot/data/slots/7.png create mode 100644 src/NadekoBot/data/slots/8.png create mode 100644 src/NadekoBot/data/slots/9.png create mode 100644 src/NadekoBot/data/slots/background.png create mode 100644 src/NadekoBot/data/slots/emojis/0.png create mode 100644 src/NadekoBot/data/slots/emojis/1.png create mode 100644 src/NadekoBot/data/slots/emojis/2.png create mode 100644 src/NadekoBot/data/slots/emojis/3.png create mode 100644 src/NadekoBot/data/slots/emojis/4.png create mode 100644 src/NadekoBot/data/slots/emojis/5.png diff --git a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs new file mode 100644 index 00000000..05c46af5 --- /dev/null +++ b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs @@ -0,0 +1,301 @@ +using Discord; +using Discord.Commands; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Services; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Gambling +{ + public partial class Gambling + { + [Group] + public class Slots : ModuleBase + { + private static int totalBet = 0; + private static int totalPaidOut = 0; + + private const string backgroundPath = "data/slots/background.png"; + + private static readonly byte[] backgroundBuffer; + private static readonly byte[][] numbersBuffer = new byte[10][]; + private static readonly byte[][] emojiBuffer; + + const int alphaCutOut = byte.MaxValue / 3; + + static Slots() + { + backgroundBuffer = File.ReadAllBytes(backgroundPath); + + for (int i = 0; i < 10; i++) + { + numbersBuffer[i] = File.ReadAllBytes("data/slots/" + i + ".png"); + } + int throwaway; + var emojiFiles = Directory.GetFiles("data/slots/emojis/", "*.png") + .Where(f => int.TryParse(Path.GetFileNameWithoutExtension(f), out throwaway)) + .OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f))) + .ToArray(); + + emojiBuffer = new byte[emojiFiles.Length][]; + for (int i = 0; i < emojiFiles.Length; i++) + { + emojiBuffer[i] = File.ReadAllBytes(emojiFiles[i]); + } + } + + + private static MemoryStream InternalGetStream(string path) + { + var ms = new MemoryStream(); + using (var fs = File.Open(path, FileMode.Open)) + { + fs.CopyTo(ms); + fs.Flush(); + } + ms.Position = 0; + return ms; + } + + //here is a payout chart + //https://lh6.googleusercontent.com/-i1hjAJy_kN4/UswKxmhrbPI/AAAAAAAAB1U/82wq_4ZZc-Y/DE6B0895-6FC1-48BE-AC4F-14D1B91AB75B.jpg + //thanks to judge for helping me with this + + public class SlotMachine + { + public const int MaxValue = 5; + + static readonly List> winningCombos = new List>() + { + //three flowers + (arr) => arr.All(a=>a==MaxValue) ? 30 : 0, + //three of the same + (arr) => !arr.Any(a => a != arr[0]) ? 10 : 0, + //two flowers + (arr) => arr.Count(a => a == MaxValue) == 2 ? 4 : 0, + //one flower + (arr) => arr.Any(a => a == MaxValue) ? 1 : 0, + }; + + public static SlotResult Pull() + { + var numbers = new int[3]; + for (int i = 0; i < numbers.Length; i++) + { + numbers[i] = new NadekoRandom().Next(0, MaxValue + 1); + } + int multi = 0; + for (int i = 0; i < winningCombos.Count; i++) + { + multi = winningCombos[i](numbers); + if (multi != 0) + break; + } + + return new SlotResult(numbers, multi); + } + + public struct SlotResult + { + public int[] Numbers { get; } + public int Multiplier { get; } + public SlotResult(int[] nums, int multi) + { + this.Numbers = nums; + this.Multiplier = multi; + } + } + } + + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task SlotStats() + { + //i remembered to not be a moron + var paid = totalPaidOut; + var bet = totalBet; + + if (bet <= 0) + bet = 1; + + var embed = new EmbedBuilder() + .WithOkColor() + .WithTitle("Slot Stats") + .AddField(efb => efb.WithName("Total Bet").WithValue(bet.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName("Paid Out").WithValue(paid.ToString()).WithIsInline(true)) + .WithFooter(efb => efb.WithText($"Payout Rate: {paid * 1.0 / bet * 100:f4}%")); + + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task SlotTest(int tests = 1000) + { + if (tests <= 0) + return; + //multi vs how many times it occured + var dict = new Dictionary(); + for (int i = 0; i < tests; i++) + { + var res = SlotMachine.Pull(); + if (dict.ContainsKey(res.Multiplier)) + dict[res.Multiplier] += 1; + else + dict.Add(res.Multiplier, 1); + } + + var sb = new StringBuilder(); + const int bet = 1; + int payout = 0; + foreach (var key in dict.Keys.OrderByDescending(x=>x)) + { + sb.AppendLine($"x{key} occured {dict[key]} times. {dict[key] * 1.0f / tests * 100}%"); + payout += key * dict[key]; + } + await Context.Channel.SendConfirmAsync("Slot Test Results", sb.ToString(), + footer: $"Total Bet: {tests * bet} | Payout: {payout * bet} | {payout * 1.0f / tests * 100}%"); + } + + static HashSet runningUsers = new HashSet(); + [NadekoCommand, Usage, Description, Aliases] + public async Task Slot(int amount = 0) + { + if (!runningUsers.Add(Context.User.Id)) + return; + try + { + if (amount < 1) + { + await Context.Channel.SendErrorAsync($"You can't bet less than 1{NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); + return; + } + + if (amount > 999) + { + await Context.Channel.SendErrorAsync($"You can't bet more than 999{NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); + return; + } + + if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User, "Slot Machine", amount, false)) + return; + Interlocked.Add(ref totalBet, amount); + using (var bgFileStream = new MemoryStream(backgroundBuffer)) + { + var bgImage = new ImageSharp.Image(bgFileStream); + + var result = SlotMachine.Pull(); + int[] numbers = result.Numbers; + using (var bgPixels = bgImage.Lock()) + { + for (int i = 0; i < 3; i++) + { + using (var file = new MemoryStream(emojiBuffer[numbers[i]])) + { + var randomImage = new ImageSharp.Image(file); + using (var toAdd = randomImage.Lock()) + { + for (int j = 0; j < toAdd.Width; j++) + { + for (int k = 0; k < toAdd.Height; k++) + { + var x = 95 + 142 * i + j; + int y = 330 + k; + var toSet = toAdd[j, k]; + if (toSet.A < alphaCutOut) + continue; + bgPixels[x, y] = toAdd[j, k]; + } + } + } + } + } + + var won = amount * result.Multiplier; + var printWon = won; + var n = 0; + do + { + var digit = printWon % 10; + using (var fs = new MemoryStream(numbersBuffer[digit])) + { + var img = new ImageSharp.Image(fs); + using (var pixels = img.Lock()) + { + for (int i = 0; i < pixels.Width; i++) + { + for (int j = 0; j < pixels.Height; j++) + { + if (pixels[i, j].A < alphaCutOut) + continue; + var x = 230 - n * 16 + i; + bgPixels[x, 462 + j] = pixels[i, j]; + } + } + } + } + n++; + } while ((printWon /= 10) != 0); + + var printAmount = amount; + n = 0; + do + { + var digit = printAmount % 10; + using (var fs = new MemoryStream(numbersBuffer[digit])) + { + var img = new ImageSharp.Image(fs); + using (var pixels = img.Lock()) + { + for (int i = 0; i < pixels.Width; i++) + { + for (int j = 0; j < pixels.Height; j++) + { + if (pixels[i, j].A < alphaCutOut) + continue; + var x = 395 - n * 16 + i; + bgPixels[x, 462 + j] = pixels[i, j]; + } + } + } + } + n++; + } while ((printAmount /= 10) != 0); + } + + var msg = "Better luck next time ^_^"; + if (result.Multiplier != 0) + { + await CurrencyHandler.AddCurrencyAsync(Context.User, $"Slot Machine x{result.Multiplier}", amount * result.Multiplier, false); + Interlocked.Add(ref totalPaidOut, amount * result.Multiplier); + if (result.Multiplier == 1) + msg = $"A single {NadekoBot.BotConfig.CurrencySign}, x1 - Try again!"; + else if (result.Multiplier == 4) + msg = $"Good job! Two {NadekoBot.BotConfig.CurrencySign} - bet x4"; + else if (result.Multiplier == 10) + msg = "Wow! Lucky! Three of a kind! x10"; + else if (result.Multiplier == 30) + msg = "WOAAHHHHHH!!! Congratulations!!! x30"; + } + + await Context.Channel.SendFileAsync(bgImage.ToStream(), "result.png", Context.User.Mention + " " + msg + $"\n`Bet:`{amount} `Won:` {amount * result.Multiplier}{NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); + } + } + finally + { + var t = Task.Run(async () => + { + await Task.Delay(3000); + runningUsers.Remove(Context.User.Id); + }); + } + } + } + } +} diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 717d767e..5fe6ae20 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -7079,6 +7079,87 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to slot. + /// + public static string slot_cmd { + get { + return ResourceManager.GetString("slot_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Play Nadeko slots. Max bet is 999. 3 seconds cooldown per user.. + /// + public static string slot_desc { + get { + return ResourceManager.GetString("slot_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}slot 5`. + /// + public static string slot_usage { + get { + return ResourceManager.GetString("slot_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to slotstats. + /// + public static string slotstats_cmd { + get { + return ResourceManager.GetString("slotstats_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows the total stats of the slot command for this bot's session.. + /// + public static string slotstats_desc { + get { + return ResourceManager.GetString("slotstats_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}slotstats`. + /// + public static string slotstats_usage { + get { + return ResourceManager.GetString("slotstats_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to slottest. + /// + public static string slottest_cmd { + get { + return ResourceManager.GetString("slottest_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tests to see how much slots payout for X number of plays.. + /// + public static string slottest_desc { + get { + return ResourceManager.GetString("slottest_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}slottest 1000`. + /// + public static string slottest_usage { + get { + return ResourceManager.GetString("slottest_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to slowmode. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 1e9ba5d4..460d6b7c 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2952,4 +2952,31 @@ `{0}startevent flowerreaction` + + slotstats + + + Shows the total stats of the slot command for this bot's session. + + + `{0}slotstats` + + + slottest + + + Tests to see how much slots payout for X number of plays. + + + `{0}slottest 1000` + + + slot + + + Play Nadeko slots. Max bet is 999. 3 seconds cooldown per user. + + + `{0}slot 5` + \ No newline at end of file diff --git a/src/NadekoBot/data/slots/0.png b/src/NadekoBot/data/slots/0.png new file mode 100644 index 0000000000000000000000000000000000000000..e260e4004e0ca9251acfc9ba7e324db4036e7122 GIT binary patch literal 551 zcmV+?0@(eDP)N2bZe?^J zG%heMF)*zP3cvsW0i;PpK~y+TwNg(nLqQN97Y9O>gFm6w-SqR&SbJ*#)vvFWlB#=0xawVG*P$DgM9;`reb_`-bfSYo3h zV*SoUvg5l|tazUiWE~$q!Yh_T=eTM|BSEQeaL2nl6{m+4w z;yn8v^8S%r);)82)QIddn$uE(;$}fIvZa0*(3$AzK>0RZZazZ^7vfp*t}yo_^zRNc z7N82y62=-L;9-@gvY4~*O<|g|P4*QB+{p?T2LNgz0hqubD5Xk#5zp?S-+U7Z5 zrNfUd&YwH=nL}$K^8z-tNhWKO5)$fOb6t6`tmaAY=0iCv4DuK*E@0W>`1FHx_|M3I z#5)XcR3`AQ^K!qxOGDr(`?2kLL178J=UlQXo~mSiIToABYM?i3!J!`q)vM(u^7nD& z>91YFv%o2YEnlZ)NxZe@v6_Nu#f@AK*%a(+3Z|IUy0=U>pXkXf#lOC@lfA-c_eGOs2kQb<^gcG4>?xmS#G>{-HGl3?>4iW`w4*IgZr3}N k`2Ouu*#%A}%se~{dy5JSCsn@l1BM!dr>mdKI;Vst02?`#bpQYW literal 0 HcmV?d00001 diff --git a/src/NadekoBot/data/slots/2.png b/src/NadekoBot/data/slots/2.png new file mode 100644 index 0000000000000000000000000000000000000000..57c5525a367bd7995c092fff02151dc99adf2787 GIT binary patch literal 553 zcmV+^0@nSBP)N2bZe?^J zG%heMF)*zP3cvsW0j5brK~y+T#golT8$lSxC)V1FnE0^}MPrhgiI5%?iUDy|Vs<|C z)}ntz51zcJw;pO^kGA(>|DGNzf_SM_L3d_$jSB50@trZDArN~KA9z^y-QT=CJMRp# zGC|%qj2;?B{u+*N4JTlDGWtjJ!l4#;&Vg2SKkaEwb|X%{Ye~Mf90_s&^^cdUUK$p> zc5nlso|+_H7)*?HI<92$ALwnq}rS#}f8aw5%B6rkq`j*yKzk@COI0 z<@{UC>F=7PbuIq++P#x=CFncIkU(L8H^XvvDwc#pr?qx#M%Ie5hIKuBU_TX@bmqsx&mvEOi$Q z;zV)0Vdk=vHJ^AF9kyo!u!MsZr=_cfkx>=U9k?l9LqYaihMV%mK>e4WvN2bZe?^J zG%heMF)*zP3cvsW0hmcdK~y+T)swp~1wjst=hkWo>JN$v9e(Bl_acviuA@ zZ$)mt=M(Tz+=qqp*lg{6_n#CvJQsNU2%lO=t!%}k!U`n6MsX>%vh`6cF3qJ=D_ehE z%&$!Dsg*4~VC8*}9f#5`(1qf4f#OYi%xeD16);)*uC){^u|WuX0y!Syc@yHe3J@1R zEqG!%A*xFHsTQ-rrb5N=g88B1Ph})4fZNF9tH}&i&k$A9tJ~giuXyW&Yqfo)1pjHc zli}1kUy7CV8rcemSSQjrLB87O&VyCWo d>8d9pdIN$55})4PsJQ?D002ovPDHLkV1oCU=fwa3 literal 0 HcmV?d00001 diff --git a/src/NadekoBot/data/slots/4.png b/src/NadekoBot/data/slots/4.png new file mode 100644 index 0000000000000000000000000000000000000000..d494165020c36f702bc12ec349508d1f5edd547d GIT binary patch literal 471 zcmV;|0Vw{7P)N2bZe?^J zG%heMF)*zP3cvsW0aQsuK~y+TwUIqe!$1&)Hx1NC5h6&~&hFX;1qDJvNJxR$Ya0*+ z6r2DW&X7CsQ&B+f5Q&Z^zzLwFqu?*`uALOnVP>o~k_#t_1Wy`SGw)mb?U?+Zq|c5b zVYl7{oz6&ZOt?%?ax(zGblYw)P7xo`63kTpw8`f&}sbQm5m4ZJEx12Nzo$tH`&_mwG=XGNy z15qgd}?FRI|R+hi4qHLnZ3F8vj)V59Wmf<<$(xd@Th%&xldNZ2)`+ zi)ianxe9w8r^#W6k^Pi$`t;`)vI~0bOpnTyz>byR$FWEE_2|z<$Pa$Lt-4DAXF~u0 N002ovPDHLkV1l({#=Zam literal 0 HcmV?d00001 diff --git a/src/NadekoBot/data/slots/5.png b/src/NadekoBot/data/slots/5.png new file mode 100644 index 0000000000000000000000000000000000000000..bc78e972e3bb28390cd3a4aba4c28691d59b70af GIT binary patch literal 542 zcmV+(0^$9MP)N2bZe?^J zG%heMF)*zP3cvsW0h>ugK~y+TwUfO|12GuJQ$=0WQmsQpkM@!%xHxoBY(~4&vbFsP2M)kE2BpCq=>blDl3j=+gS;y!uf%Hy?QJ$ipvrFPAsSNHM#h8LenW z-ZjTf%?TLZjJ_#8RZ$!-grFv-yr8J3a z&g6Kv14+jA5b6ox*VU;ulssuIj1GmtU-Biu0w4Q)VkC;<^?z`~z#O0Y#bhdq;^hfi z2YB~sDU-g=qrPsp5$cUlI1oYin>;&Pb+Svoz(V~r$MR*_Dws(j3^Nn1L)R6jkAb8u znEd5>I3`anv)4k{=w=4>`+_=(kqwuT^0#wkC9^Qoj}_&9)*j-q(^MJol(bm+k^j-q(|A6$cOR16gjpddlCkG5 zYsa==gPShL_aWSxA0E*T-GQ5OQ4{2>V^5HCSJ0j6Vmjk8Iv2tXI1mUQ%tbI=*l`oa g06ln)y@C)zA9^tAg^I~y82|tP07*qoM6N<$f-C*!djJ3c literal 0 HcmV?d00001 diff --git a/src/NadekoBot/data/slots/6.png b/src/NadekoBot/data/slots/6.png new file mode 100644 index 0000000000000000000000000000000000000000..b596051d730aa5e6693765a126fedde721c4a189 GIT binary patch literal 562 zcmV-20?qx2P)N2bZe?^J zG%heMF)*zP3cvsW0k26!K~y+TwUf^;13?tWCq!IOrA<_*wKGHF;?RW9N;P(VI1>Mb zxR8i&;Ns^IcZt8pRV30AX%pR@+3l)?3*M|H+5{)x6LdaW6G z(Hu84Ct&z8`mFfawc>a-0zFA4Y9gCaob3CYTq;Q}zHHVI4|83q4_M$EmyNDIl!meE z3=g(Clq9{2P+J5)EsniG%H!AB{_ZI7n*s^2z()Ze>Wf1^>;K?K19N;56cWie^s{_H z>j3XmikZ|^4t2Ep4WafJg$ogMufeU!nqw6Mfra{Rj^)FAHg68aIP}_~%Zk(cP|{a8 z{N;MICKZp_OA%OOc-<{o$AqY$`1`y3RqNf@RBAGm*n8}Zb6Q++-0ev@37 zM#b=mUKs7M+SzC{oH>NS%G}c0*}aI z1_nI^5N5n8BPR_Mlq_+LC<)F_D=AMbN@XZW%*-p%%S$a$Fwry6Gc;Js#dUyzfl+D&_yu&M*7wCR< zU|#09^#NOaY|7GmJ66XqXw~tF9^$pLSgp0UEO;k>$vO2E0(lHUe~!g|J!j3ol|Ml7 zPQ$gX(0BWa!+&!CRqnfeTARW7(W~h4t>Hkq2a8uuF)(PF6}NlEnRc#+?7t-?BK|Em z+~BnH$H96wwrA77EwTyF%lmNCGf?Km!APJN%pF<_n!j%=>T)=0-Z-y@9cZQp*RF%2 zcfWUdEqdR0@$WI;r;n`puPz6fzI2+#`DpQ_C%(Ts<;qY$W1doq-0ECla58wh`njxg HN@xNAC=sow literal 0 HcmV?d00001 diff --git a/src/NadekoBot/data/slots/8.png b/src/NadekoBot/data/slots/8.png new file mode 100644 index 0000000000000000000000000000000000000000..48ceed0291e537e5dfc486bd14faf206f77dbe3f GIT binary patch literal 597 zcmV-b0;>IqP)N2bZe?^J zG%heMF)*zP3cvsW0n$lCK~y+T&66=t8!;5eJy2z#4FMvNh=j}828j*~5maddQIxZN zWkh_5D(aGH3@;=~`bsGLv1RX%Cp{vmv0V2;nCaxyjX$4qY}7Zk(Ip@Fra1AsqvDw*Z)MfBuv zjVoyGdON!W@CU;oDd_QtJ6nCvsYC(`c+W?LjBr(T_7wQFz{fUJ=+Oho>93(r?_u+! z2KJwHLO~BK*k`yARGp2;Cmc>XjH_@cg(C*l>;|0NK-#BLarb?5=;lua&vYfZU_;HADyEY5HU6Utnr<>(7w#-RoA_fEKsTDMGr1wj@m0w2TUBz_ zhGmlO&PaJ~9ulkrbA>`qclx`_87RyVOv<-FkS|lgqf99ci3FKj4irW!1^%^;W@ jrZQIqsI5J>h7dvzg||36;!=3100000NkvXXu0mjfW+?(G literal 0 HcmV?d00001 diff --git a/src/NadekoBot/data/slots/9.png b/src/NadekoBot/data/slots/9.png new file mode 100644 index 0000000000000000000000000000000000000000..b71dceec27b3ca167c21a1d17a85533648b367d7 GIT binary patch literal 578 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 Ds+YWF literal 0 HcmV?d00001 diff --git a/src/NadekoBot/data/slots/emojis/2.png b/src/NadekoBot/data/slots/emojis/2.png new file mode 100644 index 0000000000000000000000000000000000000000..c567b887a54b0d256a5a3c69b9e0eb62beb609a4 GIT binary patch literal 3478 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∾mYXAcd~HpAg1ULFHsO->KR;PgY;MaX-W2 zNA5BWmInj(yhH2J%EVm7*E+joiyo1kj3Lez>4g_BHF&rfsyNzRgvRsqe~jD-?VNGE zoAC5l6Q-N4RVKa}6n&Rpv`Tj}vM_l#8&5}fku=K$K9sv-|0%8YVMCNRNo>it-vAl6 zUVH?tqFiKS%#^724=*KS%`6Cx>pU5-lHyQ#023HuR&?I=4dW}iNR}Nu0*__VPmReoWjP)YU>V; zwv9U?b(dEUG7+DgBw;>Sy4jm%{1Ns=MLZzl-6q}4J`o0tXi;zpE1wS5QF0%Y?k$r# z1Omkncw%xZ-W@V~^7<&RrPBcl49xtve5DT~bQ;T9oh$VEqlNp*kjXg*m1-|_RI5QL zJtmm7OXi3{@~@H;S^_(RPrvk3opyiL$`$d|M(jr#5&WEFx3=mn6X?BpA9IN2SZNRwx83mlgseUEb1Nph`Htzuhl759t6=ZrNdX4Hqfb)G#58GD%lIs=)>LFacq?&YWjH*lyaydKH-_+x~uWXc-L%yR000)kTJn-3(t z+%|rSnz)+C1;uToalu|_XqGrqsO<bL6d0Cn?wfxWHLM!AV)lHC5SE&CyP zbshtTEp(EW%7)f+Tj=8}1L{IIe1&UiGQlUjDtgMlU?!Rh2W3tIz9V=GmbQ? zpX$%x@PA{mpZKP~uYo5qgo0c^iKI8HR$Ed`=dACFg|6GLN3s5l(jEy!lHN+5j@r5m z(kv|UQWxu9l9s#pNo>|U+PWTO9GJhXwslv+Yf>#&qGZ{km!o_jDj=WZuVsDoXUw14 zI~LtqDEL;`sNn z$G%lEep}$zc4~iHfLDaa=INK8yqWIU_l5|2CbxB(4N0j7-Vd+O3_n*WO3)2ryi13m zz80845{x{m0WE)W%ERjwSZ>+XydQ1ZTGc<;wPB^Rf>Q6;A!A+AUXsbZV}ql*>#%a} zUCF@VG9LC=3?1;&Fx{D|Pa`rWS<1Z8+<6S@nM)*xAx|{t+B+lUCbQ#Y*^Ai*IxP<- zL#&OZt&feHR^`IsU+XToQTLU&JT3${Y}y8F`ex+$?UC?H+k@98QuKomvLdfBNKN#z&cv_$pfRj*nS_{@uN7I2QAj&a_QQu$U)U`dftHV*l4ozw%fv>=F zPqr*CtN7L9!=@wmh)%VqSui)iA`Wm`q-S|8;IixJzC{ZwLqFWA{V$V;K)P1Zexij?X)klGUekd1Z!N$?@< zrAom>%p}}$w_4*`ej}70s8+tbP@TDVjO7yn?c{r!Q0o?69Q1QcY6bQ e3U;-1gy=zR?V%n6kpC!T09Zv^xkkw*{C@yJmJ1jF literal 0 HcmV?d00001 diff --git a/src/NadekoBot/data/slots/emojis/4.png b/src/NadekoBot/data/slots/emojis/4.png new file mode 100644 index 0000000000000000000000000000000000000000..36dd054c70e6cf2c4a517bdd48021af2c84f469c GIT binary patch literal 3461 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 literal 0 HcmV?d00001 diff --git a/src/NadekoBot/data/slots/emojis/5.png b/src/NadekoBot/data/slots/emojis/5.png new file mode 100644 index 0000000000000000000000000000000000000000..84b4db13e176f198a90d758ee0d6a0957623d709 GIT binary patch literal 6302 zcmZ`;WmFtIvtD3vXK`t)-!+iOlnvd&pB9sbMKh}ZKTws z0D#}Ixc6r0&t-ZGMJ+V|z=s6@2n+=PZl6Vg&+R;T0e}Nj005E-08qGOG-!%GS74Z{ zD98ey{!2N{#fi@nY!^j+Hvj+^^dF%B(lRKYg_!P2YI2zCD8zV}AdDlO%I6+zm1L!~ zVGGL{4(`SZ9=!qlyPqn`E&CI=1{17$KW%h*(r(RR#{m9r|7lKoB;L)_`4q}1#8sG(!}`vNIZ3ave!rig~fnuldHVDhQK z!&{;!T0N(eW)AcZTrbQQcf=@(rt8fQj8OJco2ceO;}hm@lPTL)tpXgZv$! zlW^*bz@lGp?dr@93POc*k%Oyo7cb>tFR+4Mh|1khFm$L05nVWi+NLp&EX?BhZi#sR z>dux>=*)7God&4BTSc$1qz zWQTH$mSw5@b67J}GDVrx|BT<#Z86~vjdC){(W|B*b!l__>ki0_-& zoCBBIr~!4w-!+j4ZGPll)~Y$!PR&A~#mP4esBF0YvyD88orup($ya9rcbH_2V2v<{ zhhclQ@3Nb9x{W?8TYN50h1lL*bxmn&L$D+I@HE+DL|7+8jYdhGAg{NFSWW+2J#YL* z^n(UP`+`7u`OkZaOJ|h)+9%*O(U{{&FZ;r->r>=M+p)0I> z+#TprpT5KUt4PO75a{ZoFBuYCtqaSNb#Tw17ggFx`-${T*1*(s!14<|_w9SS-u;%f z=*-NY-hOz@=-2(q8izGvvSc&$#|jowe632-8Amww<|LMmr55$+nD^W%WZNPe~ZEzI!BY!%Yc;=vpuvnNd~ z@J9aPp5fd-A&}@}TZ^;zjkx@5VUXcoQM-5l3F@(1st9<-vrEvRU{uyp1<(>F-Tmb* zDaL|d(GFfrdM)nbo?(e3?NHg5VHi^iHfriyg5o&aVfs4@LDa{(89&mq{mj;^_6L?Z z%NzpB1PtCX=-Zxh3es@tQX~BaJm-nz`#)}}e#ZQp+@O~>PWqcis?4ie-n07qT^c)U zFg30GHQ5%`{@5)O>_x{FXzT@6wKDzJ-M!ZG1k;&Nn;p9VWF0>u(``-x&Kv@hE>8ar$+MKo0~8Gn6z(ycP_L^er0c~f5SF4)VU}U)8zEQ_ zfAkOj=P=gY$B8E$sMVL80XCjk%7EaPN}sh|DSiITE`HA@OU#%q7s|j$6MO>ou@*XQ zK}*UJY72X~Q;Ljc>ccFE^#B%(VN`Y6{wly$IizW{!RKxO%r8h+KcQdD3IA!1HeE*F zTJc2tlaEi;+r>jG6&)qLm#Y)(=q$+0UaJTDkvlng@f|6;@qjt58P#V!@Rq{qmcmT& z;vVS-!P@l%SjzwN|E{E8>ZRGhwi*uzZ-L0gpzf5<1dzCmu;7!yEnlEh% z-20M(0y;jLp@D3C`5V5Z*>jPz^_1}rX{gVeEnW8!{a~98hzPk3>s{Z*gCWLhP;~Ud zs8g^^(h#of($_DZjYL^PLWPev9BBi-+NmWe=2(`WZvkG%#P*Lyva1*^j0(MlwS37M zf-c-J_n(6HWEp_rMxgdW8Z2(%R@Z+jDwZvh`}=5?jE^WPge>TKa4>wSjkX1Hex5 zM?o>#K-*pSB#7pu){-WL`t8m3V2xNKie9+qDxR)q(gPoFcB$SDsp!iZF!3>rt0*9K z%i2!*+gnE4`YI#^zjO3Ja%JlYWI~M>Px&z4Eoal$*_L@1y{WHlis_JPmBP=Eu6~nJ z?3$1Rl5^>Y$gYi&E0h!qx4Y_PvVupns8L57(l$bPsE`@>yWAE-B#0FoBdr$M6y-hh ze#I|>A#9@A6O)Z*t0q*)V1hV?9Lc%AYOFib-#^8qpBh|(U?ylfKqo)SXMMZWfa5)N zOh5Y{XLO`51JbtU=ozt)?>V#i3Os1D@sYH;tjx$tnW}j5P*!56vc2kh zzJKo|^WuipV9S|3F)G?3Y~Qev5DJic3&1|%20@7)&e+fYr2H7fs;G`fP4kYr5lW%b zgY!dfwIj0gzzlmytb!pN6pTBfV9944A2&ht8mJgSot?8^Fc*7cjjRnWA>X@R4Bkv((T{P%7@<0y_ z8n^qH%SMVdQ_+2hD7;vbO4tn9^ZRY|UO5ijB}0FI!(a4@FC!F2n;A>5UKB_oWs3K_ zbQfJ)Q!!h3fqH-R;B<5Ai!Wcccj1@kI!X?SR~#L8n2d+`SO7DkeI^%T{CM##X|K6Rnf z$wcZYDqZxBUN1nC2{#gLq*m`9cZYtAd4>t0`%P(WIhA(vp#+EfR@XQFH|}R{@<#Ql1 zg|tK3c)Tv~_FO4_AW!!~1CjG*#+248PJ8i=gb`Yx?v|rq)~MWj&XmdL6k~Z%sMe>+ zvb=e}X6U6WJ6B8Ky{<+?h7cBv%GvkdpZ2UI8B3cew^71Sm!j0|Nz8;Ye2s{uQ-JwH zL=QVsKB}be+$cqMTanXH6wJP(vi*ebL%!Y^#Dg-6Qfnbf?2sxVy!jcbsuX^bkD-x^ z@da)l!$` z*(hRwCicYQSs@RQuOSt3FgcK|*Rf9-yC@R(;u;vrPFO9O$QGo<+WFq(ks#n-X?}wq zEvQ8zN=dDRdw;0PPD#!#&_0>U6*zewK%D~l>SGC=oK4JK7b35DGTQVuPs_U$o9bgj z1i)F>ccQy62{jko@FeD>#!hiVvjE@GiQh5ALxPzJR~Yrq8S*A83a$?o)Eq^&jmUyD zT#tZZbg?;+a-i4f?zF6ovs>PoD#v(tf{*a?lji7tr^U>cti;;yt}hR3K3gj(Uw}_1 z499P281WYKb_suMu?F;pk72)*1lf*Y8P|OP#*7!HT1>?em&XeDv8le1i|&;l%Py1MX{Wm<6eORB z*q6UI%O}dwU{+$p*@@j~uAR?}rpVqAz`7N@rfcqq0lmx3-pXv1DVsr2wxyE_pFOJv%E78&1f$X+io$j58j;l463L7(=Bv6>JYqy z&U`Arv5x!BUSK@SpGj?GV2pY`fvM?28ZF@$o+WW_&-XQ6uB6H}k6lOH#NP+D{K^#WC zhgkvm5ULCAHonv9NuUZhMR>yolXFybg7T`x3~mkpDJeoc832I$nzdy1SWq1s!bGQg{L@zD}M z#o?DPONU&Df`^j-VbJK*DvWf)83#Kv&(VK#)9Gza-KeE1!V%xV(ciVS@-WmB@Ul<~ z;}Mak4UI*T7(`})X{oX`f>eZ~dDb0+f{csg;8SNpZ4z@YkeYMTg0SshL6SqIJU9>3 zXU9AAL}R}ha@nx2-6Vt}p>(R3BA!w8g%tLYV-{UBy8nBY7@4{Q7Ag%7MzwOcY?OIy z?2F>+bL^=;yQ*UOO%Km8_fCPhew`kdVv@nez824_c;Q7)KP1s}SckGI^xLHRlk+fs zo(h7di@D=vamJYtYk2h5P`&&~yQP1R+l)qcFvqc!2%SYQ6U&>i4E`EERIw}@^TXJ_ zmdCUUVhoFzP?Xd7%`TqH&Ft3Ty&DRur(3}d3PPH(f-b|FZ_hezKAz_jyf>1tSKYL% zissPyi)SXa;iQ^w2>%0hr9CSe%O}2t##Pl?dftg|Z2W)GUdHzmJ)b*SHq051(_$2RE&K{j3#x?_YPFWdG<9%+AC}5%R2d zh!t*W{G=6>#rPYlMqW?P->lRrmLw+}3147d-<+7?^JURo)2%z0IqlDnad4j4o#P8L zV*-WZJaHRu52&v{KvyZdry%fRVO)g&%Z;^LMLI(N-zkU6U)~$u&dwf>Y;C8>q~!^G zJi!fN4`}`D*?}muN_pK#vaXX|KT5-KeZr<4Tp!@XLTu-wt$~I$dPq@k)H+|L2cAg& z#SA8HpU3FQI(DRgy<33n{1z)UR3dq3hlC9L-sES58?Xm^IH>JNLrQH(dO@LMD_^$_ z|hjM?DR3`qo51K!$sMm?twrikz~+S6V)sk5E|S@DzB z^0egQgrr%OCu!F%`7>=U)>IT{)O%QejXd~wNuN@kNGoPG0p`m+YiJamU-02vdFoKF zFQ8LBHW%WSUqATZ&S3ADVY}MS7p}}yK)>Y9zA`{|-mmQ9S6%5M;Q|< z%It=>$3oNOQFT*Q%`_&Bj%AxTm-B`LtWcIFQl%>efp01e^@j!LI|#~%_EyBJ)xPibh@Rk$7%4WmZ1Z)~U zOWT3>XjQx&RNIzm`s|C;+qlc+=5MV=^NRh31~Mvl#DjxL$+e%wi$!-yvx0&)Qzs!Lp!Y5Vk0f^=#2WhX z``Cx7ss3IShfz$f=KKy&aLR;E@o>cy;j{ZN4R$IGPFAC2{G9rWr7f^^Z>iqjs6J~N z6VdHaeW<%cJS3!%T^vKkGu>))*fd|GIXZB}89r-hkjblk4i$n`w(0yj@Wnkre-!yQ zN4$5dn2jW+41?3K z4a*wdK1G;pnLpflb{e@Feda;KN zJo#B>Z$C!mjT&0tfj=W@c)!qK+P*WJh4tc31v;JM*TniS+O$u&)E4er4{#u<<~1L9 z_Hz~bBu!7>KR?62a+lL{w={FNf>^j(Ju?6wFIb3+7t93~(gyQEc!eNf5iVW<2rn-g z>tOHy0XR8Z+F5)5{{TxLH{WLf)qf*Eovq!y%v`MiQkKr Date: Wed, 18 Jan 2017 17:02:48 +0100 Subject: [PATCH 15/27] Trailing whitespace remove --- src/NadekoBot/Modules/Gambling/Commands/Slots.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs index 05c46af5..7ed1f9ee 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs @@ -63,7 +63,7 @@ namespace NadekoBot.Modules.Gambling return ms; } - //here is a payout chart + //here is a payout chart //https://lh6.googleusercontent.com/-i1hjAJy_kN4/UswKxmhrbPI/AAAAAAAAB1U/82wq_4ZZc-Y/DE6B0895-6FC1-48BE-AC4F-14D1B91AB75B.jpg //thanks to judge for helping me with this @@ -153,7 +153,7 @@ namespace NadekoBot.Modules.Gambling var sb = new StringBuilder(); const int bet = 1; - int payout = 0; + int payout = 0; foreach (var key in dict.Keys.OrderByDescending(x=>x)) { sb.AppendLine($"x{key} occured {dict[key]} times. {dict[key] * 1.0f / tests * 100}%"); @@ -293,7 +293,7 @@ namespace NadekoBot.Modules.Gambling { await Task.Delay(3000); runningUsers.Remove(Context.User.Id); - }); + }); } } } From cf13e959516cba894339d48b4fa12faa153d9c0d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 18 Jan 2017 17:48:16 +0100 Subject: [PATCH 16/27] public nadeko will only have ~boobs and ~butts out of all nsfw commands on next restart --- src/NadekoBot/Modules/NSFW/NSFW.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index 8e520c6c..589d421a 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -19,6 +19,7 @@ namespace NadekoBot.Modules.NSFW [NadekoModule("NSFW", "~")] public class NSFW : DiscordModule { +#if !GLOBAL_NADEKO private static ConcurrentDictionary AutoHentaiTimers { get; } = new ConcurrentDictionary(); private static ConcurrentHashSet _hentaiBombBlacklist { get; } = new ConcurrentHashSet(); @@ -189,7 +190,7 @@ namespace NadekoBot.Modules.NSFW .WithFooter(efb => efb.WithText("e621"))) .ConfigureAwait(false); } - +#endif [NadekoCommand, Usage, Description, Aliases] public async Task Cp() { @@ -204,7 +205,7 @@ namespace NadekoBot.Modules.NSFW JToken obj; using (var http = new HttpClient()) { - obj = JArray.Parse(await http.GetStringAsync($"http://api.oboobs.ru/boobs/{ new NadekoRandom().Next(0, 10229) }").ConfigureAwait(false))[0]; + obj = JArray.Parse(await http.GetStringAsync($"http://api.oboobs.ru/boobs/{ new NadekoRandom().Next(0, 10330) }").ConfigureAwait(false))[0]; } await Context.Channel.SendMessageAsync($"http://media.oboobs.ru/{ obj["preview"].ToString() }").ConfigureAwait(false); } @@ -222,7 +223,7 @@ namespace NadekoBot.Modules.NSFW JToken obj; using (var http = new HttpClient()) { - obj = JArray.Parse(await http.GetStringAsync($"http://api.obutts.ru/butts/{ new NadekoRandom().Next(0, 4222) }").ConfigureAwait(false))[0]; + obj = JArray.Parse(await http.GetStringAsync($"http://api.obutts.ru/butts/{ new NadekoRandom().Next(0, 4335) }").ConfigureAwait(false))[0]; } await Context.Channel.SendMessageAsync($"http://media.obutts.ru/{ obj["preview"].ToString() }").ConfigureAwait(false); } @@ -231,7 +232,7 @@ namespace NadekoBot.Modules.NSFW await Context.Channel.SendErrorAsync(ex.Message).ConfigureAwait(false); } } - +#if !GLOBAL_NADEKO public static Task GetDanbooruImageLink(string tag) => Task.Run(async () => { try @@ -289,4 +290,5 @@ namespace NadekoBot.Modules.NSFW public static Task GetRule34ImageLink(string tag) => Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Rule34); } +#endif } \ No newline at end of file From 1c142a0fc587e60b711c9857a2f7f4bf59c6b167 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 18 Jan 2017 18:38:31 +0100 Subject: [PATCH 17/27] ~av and .uinfo now show gif avatars properly --- src/NadekoBot/Modules/Searches/Searches.cs | 8 ++++++-- src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs | 2 +- src/NadekoBot/_Extensions/Extensions.cs | 7 +++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 60bebedf..34ef1074 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -618,9 +618,13 @@ namespace NadekoBot.Modules.Searches if (usr == null) usr = Context.User; + var avatarUrl = usr.RealAvatarUrl(); + var shortenedAvatarUrl = await NadekoBot.Google.ShortenUrl(avatarUrl).ConfigureAwait(false); await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithTitle($"{usr}'s Avatar") - .WithImageUrl(usr.AvatarUrl)).ConfigureAwait(false); + .AddField(efb => efb.WithName("Username").WithValue(usr.ToString()).WithIsInline(false)) + .AddField(efb => efb.WithName("Avatar Url").WithValue(shortenedAvatarUrl).WithIsInline(false)) + //.AddField(efb => efb.WithName("Avatar Id").WithValue(usr.AvatarId).WithIsInline(false)) + .WithThumbnailUrl(avatarUrl), Context.User.Mention).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs index eaea37f0..7d57ff8a 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -97,7 +97,7 @@ namespace NadekoBot.Modules.Utility .AddField(fb => fb.WithName("**Joined Server**").WithValue($"{user.JoinedAt?.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) .AddField(fb => fb.WithName("**Joined Discord**").WithValue($"{user.CreatedAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) .AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count - 1})** - {string.Join("\n", user.GetRoles().Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true)) - .WithThumbnailUrl(user.AvatarUrl) + .WithThumbnailUrl(user.RealAvatarUrl()) .WithColor(NadekoBot.OkColor); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index d2dd36fc..46be1172 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -425,5 +425,12 @@ namespace NadekoBot.Extensions public static bool IsDiscordInvite(this string str) => filterRegex.IsMatch(str); + + public static string RealAvatarUrl(this IUser usr) + { + return usr.AvatarId.StartsWith("a_") + ? $"{DiscordConfig.CDNUrl}avatars/{usr.Id}/{usr.AvatarId}.gif" + : usr.AvatarUrl; + } } } \ No newline at end of file From 54ddab13c172e06ffbb0ced754bf76bd707b4f0d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 18 Jan 2017 21:52:42 +0100 Subject: [PATCH 18/27] global command cooldown reduced to 750ms on self hosted (still 1500 on public bot). Global command cooldown no longer triggers on any message, only on command. --- src/NadekoBot/Services/CommandHandler.cs | 39 +++++++++++++----------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 16bf8e89..13c8bac5 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -30,7 +30,11 @@ namespace NadekoBot.Services } public class CommandHandler { +#if GLOBAL_NADEKO public const int GlobalCommandsCooldown = 1500; +#else + public const int GlobalCommandsCooldown = 750; +#endif private readonly DiscordShardedClient _client; private readonly CommandService _commandService; @@ -119,18 +123,18 @@ namespace NadekoBot.Services private void LogErroredExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int ticks) { _log.Warn("Command Errored after {5}s\n\t" + - "User: {0}\n\t" + - "Server: {1}\n\t" + - "Channel: {2}\n\t" + - "Message: {3}\n\t" + - "Error: {4}", - usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0} - (channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1} - (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2} - usrMsg.Content,// {3} - exec.Result.ErrorReason, // {4} - ticks * oneThousandth // {5} - ); + "User: {0}\n\t" + + "Server: {1}\n\t" + + "Channel: {2}\n\t" + + "Message: {3}\n\t" + + "Error: {4}", + usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0} + (channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1} + (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2} + usrMsg.Content,// {3} + exec.Result.ErrorReason, // {4} + ticks * oneThousandth // {5} + ); } private async Task InviteFiltered(IGuild guild, SocketUserMessage usrMsg) @@ -196,11 +200,6 @@ namespace NadekoBot.Services // track how many messagges each user is sending UserMessagesSent.AddOrUpdate(usrMsg.Author.Id, 1, (key, old) => ++old); - // Bot will ignore commands which are ran more often than what specified by - // GlobalCommandsCooldown constant (miliseconds) - if (!UsersOnShortCooldown.Add(usrMsg.Author.Id)) - return; - var channel = msg.Channel as SocketTextChannel; var guild = channel?.Guild; @@ -367,9 +366,13 @@ namespace NadekoBot.Services } } + // Bot will ignore commands which are ran more often than what specified by + // GlobalCommandsCooldown constant (miliseconds) + if (!UsersOnShortCooldown.Add(context.Message.Author.Id)) + return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, $"You are on a global cooldown.")); if (CmdCdsCommands.HasCooldown(cmd, context.Guild, context.User)) - return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, $"That command is on cooldown for you.")); + return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, $"That command is on a cooldown for you.")); return new ExecuteCommandResult(cmd, null, await commands[i].ExecuteAsync(context, parseResult, dependencyMap)); } From 7bdbf227cda90fc8cf313dc2ecccc8a7f2b226a8 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 18 Jan 2017 21:56:31 +0100 Subject: [PATCH 19/27] Ok and error colors are now in bot config table. Default $bf multiplier increased from 1.8x to 1.95x --- .../20170112185538_currency-modifications.cs | 4 +- ...20170118202307_ok-error-colors.Designer.cs | 988 ++++++++++++++++++ .../20170118202307_ok-error-colors.cs | 35 + .../NadekoSqliteContextModelSnapshot.cs | 6 + src/NadekoBot/NadekoBot.cs | 6 +- .../Services/Database/Models/BotConfig.cs | 7 +- src/NadekoBot/_Extensions/Extensions.cs | 16 +- 7 files changed, 1048 insertions(+), 14 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170118202307_ok-error-colors.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170118202307_ok-error-colors.cs diff --git a/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs b/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs index ad0af9e3..3f2f8c22 100644 --- a/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs +++ b/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs @@ -12,7 +12,7 @@ namespace NadekoBot.Migrations name: "BetflipMultiplier", table: "BotConfig", nullable: false, - defaultValue: 1.8f); + defaultValue: 1.95f); migrationBuilder.AddColumn( name: "Betroll100Multiplier", @@ -42,7 +42,7 @@ namespace NadekoBot.Migrations name: "MinimumBetAmount", table: "BotConfig", nullable: false, - defaultValue: 3); + defaultValue: 2); migrationBuilder.AddColumn( name: "TriviaCurrencyReward", diff --git a/src/NadekoBot/Migrations/20170118202307_ok-error-colors.Designer.cs b/src/NadekoBot/Migrations/20170118202307_ok-error-colors.Designer.cs new file mode 100644 index 00000000..b13f8275 --- /dev/null +++ b/src/NadekoBot/Migrations/20170118202307_ok-error-colors.Designer.cs @@ -0,0 +1,988 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NadekoBot.Modules.Music.Classes; + +namespace NadekoBot.Migrations +{ + [DbContext(typeof(NadekoContext))] + [Migration("20170118202307_ok-error-colors")] + partial class okerrorcolors + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("ProductVersion", "1.1.0-rtm-22752"); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.Property("UserThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiRaidSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AntiSpamSettingId"); + + b.Property("ChannelId"); + + b.HasKey("Id"); + + b.HasIndex("AntiSpamSettingId"); + + b.ToTable("AntiSpamIgnore"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("GuildConfigId"); + + b.Property("MessageThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiSpamSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ItemId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("BlacklistItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BetflipMultiplier"); + + b.Property("Betroll100Multiplier"); + + b.Property("Betroll67Multiplier"); + + b.Property("Betroll91Multiplier"); + + b.Property("BufferSize"); + + b.Property("CurrencyDropAmount"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("DMHelpString"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("MigrationVersion"); + + b.Property("MinimumBetAmount"); + + b.Property("OkColor"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + b.Property("TriviaCurrencyReward"); + + b.HasKey("Id"); + + b.ToTable("BotConfig"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BaseDestroyed"); + + b.Property("CallUser"); + + b.Property("ClashWarId"); + + b.Property("SequenceNumber"); + + b.Property("Stars"); + + b.Property("TimeAdded"); + + b.HasKey("Id"); + + b.HasIndex("ClashWarId"); + + b.ToTable("ClashCallers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("EnemyClan"); + + b.Property("GuildId"); + + b.Property("Size"); + + b.Property("StartedAt"); + + b.Property("WarState"); + + b.HasKey("Id"); + + b.ToTable("ClashOfClans"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandCooldown"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("CommandName"); + + b.Property("Price"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.HasIndex("Price") + .IsUnique(); + + b.ToTable("CommandPrice"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("InternalTrigger"); + + b.Property("Modifier"); + + b.Property("UnitType"); + + b.HasKey("Id"); + + b.ToTable("ConversionUnits"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Currency"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("CurrencyTransactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildId"); + + b.Property("IsRegex"); + + b.Property("OwnerOnly"); + + b.Property("Response"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.ToTable("CustomReactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("Name"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Donators"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("EightBallResponses"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildConfigId1"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.HasIndex("GuildConfigId1"); + + b.ToTable("FilterChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildConfigId"); + + b.Property("Word"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilteredWord"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Type"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FollowedStream"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GCChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoAssignRoleId"); + + b.Property("AutoDeleteByeMessages"); + + b.Property("AutoDeleteByeMessagesTimer"); + + b.Property("AutoDeleteGreetMessages"); + + b.Property("AutoDeleteGreetMessagesTimer"); + + b.Property("AutoDeleteSelfAssignedRoleMessages"); + + b.Property("ByeMessageChannelId"); + + b.Property("ChannelByeMessageText"); + + b.Property("ChannelGreetMessageText"); + + b.Property("CleverbotEnabled"); + + b.Property("DefaultMusicVolume"); + + b.Property("DeleteMessageOnCommand"); + + b.Property("DmGreetMessageText"); + + b.Property("ExclusiveSelfAssignedRoles"); + + b.Property("FilterInvites"); + + b.Property("FilterWords"); + + b.Property("GreetMessageChannelId"); + + b.Property("GuildId"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.HasIndex("LogSettingId"); + + b.HasIndex("RootPermissionId"); + + b.ToTable("GuildConfigs"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Interval"); + + b.Property("Message"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GuildRepeater"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredLogChannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredVoicePresenceCHannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelCreated"); + + b.Property("ChannelCreatedId"); + + b.Property("ChannelDestroyed"); + + b.Property("ChannelDestroyedId"); + + b.Property("ChannelId"); + + b.Property("ChannelUpdated"); + + b.Property("ChannelUpdatedId"); + + b.Property("IsLogging"); + + b.Property("LogOtherId"); + + b.Property("LogUserPresence"); + + b.Property("LogUserPresenceId"); + + b.Property("LogVoicePresence"); + + b.Property("LogVoicePresenceId"); + + b.Property("LogVoicePresenceTTSId"); + + b.Property("MessageDeleted"); + + b.Property("MessageDeletedId"); + + b.Property("MessageUpdated"); + + b.Property("MessageUpdatedId"); + + b.Property("UserBanned"); + + b.Property("UserBannedId"); + + b.Property("UserJoined"); + + b.Property("UserJoinedId"); + + b.Property("UserLeft"); + + b.Property("UserLeftId"); + + b.Property("UserMutedId"); + + b.Property("UserPresenceChannelId"); + + b.Property("UserUnbanned"); + + b.Property("UserUnbannedId"); + + b.Property("UserUpdated"); + + b.Property("UserUpdatedId"); + + b.Property("VoicePresenceChannelId"); + + b.HasKey("Id"); + + b.ToTable("LogSettings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ModuleName"); + + b.Property("Prefix"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("ModulePrefixes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Author"); + + b.Property("AuthorId"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("MutedUserId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("NextId"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("NextId") + .IsUnique(); + + b.ToTable("Permission"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Status"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("PlayingStatus"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("MusicPlaylistId"); + + b.Property("Provider"); + + b.Property("ProviderType"); + + b.Property("Query"); + + b.Property("Title"); + + b.Property("Uri"); + + b.HasKey("Id"); + + b.HasIndex("MusicPlaylistId"); + + b.ToTable("PlaylistSong"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("AuthorName") + .IsRequired(); + + b.Property("GuildId"); + + b.Property("Keyword") + .IsRequired(); + + b.Property("Text") + .IsRequired(); + + b.HasKey("Id"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Icon"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("RaceAnimals"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("IsPrivate"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("UserId"); + + b.Property("When"); + + b.HasKey("Id"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiRaidSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.HasOne("NadekoBot.Services.Database.Models.AntiSpamSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiSpamSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("Blacklist") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar") + .WithMany("Bases") + .HasForeignKey("ClashWarId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("CommandPrices") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("EightBallResponses") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId"); + + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId1"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany() + .HasForeignKey("LogSettingId"); + + b.HasOne("NadekoBot.Services.Database.Models.Permission", "RootPermission") + .WithMany() + .HasForeignKey("RootPermissionId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GuildRepeaters") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredVoicePresenceChannelIds") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("ModulePrefixes") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next") + .WithOne("Previous") + .HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RotatingStatusMessages") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist") + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RaceAnimals") + .HasForeignKey("BotConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170118202307_ok-error-colors.cs b/src/NadekoBot/Migrations/20170118202307_ok-error-colors.cs new file mode 100644 index 00000000..b52bee10 --- /dev/null +++ b/src/NadekoBot/Migrations/20170118202307_ok-error-colors.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class okerrorcolors : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ErrorColor", + table: "BotConfig", + nullable: false, + defaultValue: "ee281f"); + + migrationBuilder.AddColumn( + name: "OkColor", + table: "BotConfig", + nullable: false, + defaultValue: "71cd40"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ErrorColor", + table: "BotConfig"); + + migrationBuilder.DropColumn( + name: "OkColor", + table: "BotConfig"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 91f7b6fc..454c641f 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -4,6 +4,8 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NadekoBot.Modules.Music.Classes; namespace NadekoBot.Migrations { @@ -118,6 +120,8 @@ namespace NadekoBot.Migrations b.Property("DMHelpString"); + b.Property("ErrorColor"); + b.Property("ForwardMessages"); b.Property("ForwardToAllOwners"); @@ -128,6 +132,8 @@ namespace NadekoBot.Migrations b.Property("MinimumBetAmount"); + b.Property("OkColor"); + b.Property("RemindMessageFormat"); b.Property("RotatingStatuses"); diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index a019476a..2e4d3daf 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -23,8 +23,8 @@ namespace NadekoBot { private Logger _log; - public static Color OkColor { get; } = new Color(0x71cd40); - public static Color ErrorColor { get; } = new Color(0xee281f); + public static Color OkColor { get; } + public static Color ErrorColor { get; } public static CommandService CommandService { get; private set; } public static CommandHandler CommandHandler { get; private set; } @@ -49,6 +49,8 @@ namespace NadekoBot { AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(); BotConfig = uow.BotConfig.GetOrCreate(); + OkColor = new Color(Convert.ToUInt32(BotConfig.OkColor, 16)); + ErrorColor = new Color(Convert.ToUInt32(BotConfig.ErrorColor, 16)); } } diff --git a/src/NadekoBot/Services/Database/Models/BotConfig.cs b/src/NadekoBot/Services/Database/Models/BotConfig.cs index 080770ec..2aa973f6 100644 --- a/src/NadekoBot/Services/Database/Models/BotConfig.cs +++ b/src/NadekoBot/Services/Database/Models/BotConfig.cs @@ -25,8 +25,8 @@ namespace NadekoBot.Services.Database.Models public string CurrencyPluralName { get; set; } = "Nadeko Flowers"; public int TriviaCurrencyReward { get; set; } = 0; - public int MinimumBetAmount { get; set; } = 3; - public float BetflipMultiplier { get; set; } = 1.8f; + public int MinimumBetAmount { get; set; } = 2; + public float BetflipMultiplier { get; set; } = 1.95f; public int CurrencyDropAmount { get; set; } = 1; public float Betroll67Multiplier { get; set; } = 2; public float Betroll91Multiplier { get; set; } = 3; @@ -57,6 +57,9 @@ For a specific command help, use `{1}h CommandName` (for example {1}h !!q) Nadeko Support Server: https://discord.gg/0ehQwTK2RBjAxzEY"; public int MigrationVersion { get; set; } + + public string OkColor { get; set; } = "71cd40"; + public string ErrorColor { get; set; } = "ee281f"; } public class PlayingStatus :DbEntity diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index 46be1172..fc50058f 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -183,18 +183,18 @@ namespace NadekoBot.Extensions await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendMessageAsync(message, isTTS).ConfigureAwait(false); public static async Task SendConfirmAsync(this IUser user, string text) - => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(text)); + => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text)); public static async Task SendConfirmAsync(this IUser user, string title, string text, string url = null) - => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(text) + => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text) .WithTitle(title).WithUrl(url)); public static async Task SendErrorAsync(this IUser user, string title, string error, string url = null) - => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(error) + => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithErrorColor().WithDescription(error) .WithTitle(title).WithUrl(url)); public static async Task SendErrorAsync(this IUser user, string error) - => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(error)); + => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithErrorColor().WithDescription(error)); public static async Task SendFileAsync(this IUser user, string filePath, string caption = null, string text = null, bool isTTS = false) => await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(File.Open(filePath, FileMode.Open), caption ?? "x", text, isTTS).ConfigureAwait(false); @@ -212,18 +212,18 @@ namespace NadekoBot.Extensions => ch.SendMessageAsync(msg, embed: embed); public static Task SendErrorAsync(this IMessageChannel ch, string title, string error, string url = null, string footer = null) - => ch.SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.ErrorColor).WithDescription(error) + => ch.SendMessageAsync("", embed: new EmbedBuilder().WithErrorColor().WithDescription(error) .WithTitle(title).WithUrl(url).WithFooter(efb => efb.WithText(footer))); public static Task SendErrorAsync(this IMessageChannel ch, string error) - => ch.SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(error)); + => ch.SendMessageAsync("", embed: new EmbedBuilder().WithErrorColor().WithDescription(error)); public static Task SendConfirmAsync(this IMessageChannel ch, string title, string text, string url = null, string footer = null) - => ch.SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(text) + => ch.SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text) .WithTitle(title).WithUrl(url).WithFooter(efb => efb.WithText(footer))); public static Task SendConfirmAsync(this IMessageChannel ch, string text) - => ch.SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).WithDescription(text)); + => ch.SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text)); public static Task SendTableAsync(this IMessageChannel ch, string seed, IEnumerable items, Func howToPrint, int columns = 3) { From fd97927fdea2d2833d00d00979cd634b026bebf2 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 18 Jan 2017 21:56:53 +0100 Subject: [PATCH 20/27] Version upped to 1.1.3 --- src/NadekoBot/Services/Impl/StatsService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index 7e3f4406..0a170399 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -15,7 +15,7 @@ namespace NadekoBot.Services.Impl private DiscordShardedClient client; private DateTime started; - public const string BotVersion = "1.1.2"; + public const string BotVersion = "1.1.3"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From bef907f61921d66ecc53fdad29d3a968edee6e2f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 19 Jan 2017 19:36:57 +0100 Subject: [PATCH 21/27] $bf is at 1.95 by default, $br > 90 is 4x --- .../20170112185538_currency-modifications.cs | 2 +- src/NadekoBot/Modules/Gambling/Gambling.cs | 50 +++++++++++++++++++ .../Services/Database/Models/BotConfig.cs | 2 +- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs b/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs index 3f2f8c22..e29e5c8c 100644 --- a/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs +++ b/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs @@ -30,7 +30,7 @@ namespace NadekoBot.Migrations name: "Betroll91Multiplier", table: "BotConfig", nullable: false, - defaultValue: 3f); + defaultValue: 4f); migrationBuilder.AddColumn( name: "CurrencyDropAmount", diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index a52ea433..f52109ee 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -145,6 +145,56 @@ namespace NadekoBot.Modules.Gambling await Context.Channel.SendErrorAsync($"{Context.User.Mention} was unable to take {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from `{usrId}` because the user doesn't have that much {CurrencyPluralName}!").ConfigureAwait(false); } + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task BrTest(int tests = 1000) + { + var t = Task.Run(async () => + { + if (tests <= 0) + return; + //multi vs how many times it occured + var dict = new Dictionary(); + var generator = new NadekoRandom(); + for (int i = 0; i < tests; i++) + { + var rng = generator.Next(0, 101); + var mult = 0; + if (rng < 67) + { + mult = 0; + } + else if (rng < 91) + { + mult = 2; + } + else if (rng < 100) + { + mult = 4; + } + else + mult = 10; + + if (dict.ContainsKey(mult)) + dict[mult] += 1; + else + dict.Add(mult, 1); + } + + var sb = new StringBuilder(); + const int bet = 1; + int payout = 0; + foreach (var key in dict.Keys.OrderByDescending(x => x)) + { + sb.AppendLine($"x{key} occured {dict[key]} times. {dict[key] * 1.0f / tests * 100}%"); + payout += key * dict[key]; + } + await Context.Channel.SendConfirmAsync("BetRoll Test Results", sb.ToString(), + footer: $"Total Bet: {tests * bet} | Payout: {payout * bet} | {payout * 1.0f / tests * 100}%"); + + }); + } + [NadekoCommand, Usage, Description, Aliases] public async Task BetRoll(long amount) { diff --git a/src/NadekoBot/Services/Database/Models/BotConfig.cs b/src/NadekoBot/Services/Database/Models/BotConfig.cs index 2aa973f6..d96d4cc8 100644 --- a/src/NadekoBot/Services/Database/Models/BotConfig.cs +++ b/src/NadekoBot/Services/Database/Models/BotConfig.cs @@ -29,7 +29,7 @@ namespace NadekoBot.Services.Database.Models public float BetflipMultiplier { get; set; } = 1.95f; public int CurrencyDropAmount { get; set; } = 1; public float Betroll67Multiplier { get; set; } = 2; - public float Betroll91Multiplier { get; set; } = 3; + public float Betroll91Multiplier { get; set; } = 4; public float Betroll100Multiplier { get; set; } = 10; //public HashSet CommandCosts { get; set; } = new HashSet(); From ce6b0f383ebee6a952f7276fb113255f84acf333 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 19 Jan 2017 21:55:13 +0100 Subject: [PATCH 22/27] $slot now tells you if you don't have enough currency --- src/NadekoBot/Modules/Gambling/Commands/Slots.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs index 7ed1f9ee..e1671a6d 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs @@ -184,7 +184,10 @@ namespace NadekoBot.Modules.Gambling } if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User, "Slot Machine", amount, false)) + { + await Context.Channel.SendErrorAsync($"You don't have enough {NadekoBot.BotConfig.CurrencySign}.").ConfigureAwait(false); return; + } Interlocked.Add(ref totalBet, amount); using (var bgFileStream = new MemoryStream(backgroundBuffer)) { From 14b797cfb694228b1ad2da50f7c2d6c6a87c06d5 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 19 Jan 2017 22:04:57 +0100 Subject: [PATCH 23/27] fixed >cleverbot on locally hosted bots? --- src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs b/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs index 08269207..d5df8dfe 100644 --- a/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs +++ b/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs @@ -32,7 +32,7 @@ namespace Services.CleverBotApi #if GLOBAL_NADEKO var url = "http://www.cleverbot.com/webservicemin?uc=3210&botapi=nadekobot"; #else - var url = "http://www.cleverbot.com/webservicemin?uc=3210"; + var url = "http://www.cleverbot.com/webservicemin?uc=3210&botapi=chatterbotapi"; #endif switch (type) From 3fa6e6b1628667ccefe4ece0d41a1e9fe6e81d80 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 20 Jan 2017 08:04:24 +0100 Subject: [PATCH 24/27] Some random changes to commandhandler --- src/NadekoBot/Services/CommandHandler.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 13c8bac5..a9689be1 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -215,19 +215,19 @@ namespace NadekoBot.Services if (IsBlacklisted(guild, usrMsg)) return; - var cleverBotRan = await TryRunCleverbot(usrMsg, guild).ConfigureAwait(false); + var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false); if (cleverBotRan) return; // maybe this message is a custom reaction - var crExecuted = await CustomReactions.TryExecuteCustomReaction(usrMsg).ConfigureAwait(false); + var crExecuted = await Task.Run(() => CustomReactions.TryExecuteCustomReaction(usrMsg)).ConfigureAwait(false); if (crExecuted) //if it was, don't execute the command return; string messageContent = usrMsg.Content; // execute the command and measure the time it took - var exec = await ExecuteCommand(new CommandContext(_client, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best); + var exec = await Task.Run(() => ExecuteCommand(new CommandContext(_client, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best)).ConfigureAwait(false); execTime = Environment.TickCount - execTime; if (exec.Result.IsSuccess) From 65be4279b89dce762c1db9740b843ac54f05a1b6 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 22 Jan 2017 21:06:10 +0100 Subject: [PATCH 25/27] $claim, $waifuinfo, $affinity and $divorce commands added for a waifu currency game --- .../20170122044958_waifus.Designer.cs | 1089 +++++++++++++++++ .../Migrations/20170122044958_waifus.cs | 140 +++ .../NadekoSqliteContextModelSnapshot.cs | 101 ++ .../Gambling/Commands/WaifuClaimCommands.cs | 516 ++++++++ src/NadekoBot/Modules/Gambling/Gambling.cs | 11 +- .../Modules/Utility/Commands/QuoteCommands.cs | 2 +- .../Resources/CommandStrings.Designer.cs | 135 ++ src/NadekoBot/Resources/CommandStrings.resx | 45 + src/NadekoBot/Services/CommandHandler.cs | 2 + src/NadekoBot/Services/CurrencyHandler.cs | 58 +- .../Services/Database/IUnitOfWork.cs | 2 + .../Services/Database/Models/DiscordUser.cs | 19 + .../Services/Database/Models/Waifu.cs | 49 + .../Services/Database/Models/WaifuUpdate.cs | 27 + .../Services/Database/NadekoContext.cs | 48 +- .../Repositories/IDiscordUserRepository.cs | 15 + .../Database/Repositories/IWaifuRepository.cs | 13 + .../Impl/DiscordUserRepository.cs | 36 + .../Repositories/Impl/WaifuRepository.cs | 49 + src/NadekoBot/Services/Database/UnitOfWork.cs | 6 + src/NadekoBot/Services/DbHandler.cs | 21 +- 21 files changed, 2344 insertions(+), 40 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170122044958_waifus.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170122044958_waifus.cs create mode 100644 src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs create mode 100644 src/NadekoBot/Services/Database/Models/DiscordUser.cs create mode 100644 src/NadekoBot/Services/Database/Models/Waifu.cs create mode 100644 src/NadekoBot/Services/Database/Models/WaifuUpdate.cs create mode 100644 src/NadekoBot/Services/Database/Repositories/IDiscordUserRepository.cs create mode 100644 src/NadekoBot/Services/Database/Repositories/IWaifuRepository.cs create mode 100644 src/NadekoBot/Services/Database/Repositories/Impl/DiscordUserRepository.cs create mode 100644 src/NadekoBot/Services/Database/Repositories/Impl/WaifuRepository.cs diff --git a/src/NadekoBot/Migrations/20170122044958_waifus.Designer.cs b/src/NadekoBot/Migrations/20170122044958_waifus.Designer.cs new file mode 100644 index 00000000..46eebfab --- /dev/null +++ b/src/NadekoBot/Migrations/20170122044958_waifus.Designer.cs @@ -0,0 +1,1089 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NadekoBot.Modules.Music.Classes; + +namespace NadekoBot.Migrations +{ + [DbContext(typeof(NadekoContext))] + [Migration("20170122044958_waifus")] + partial class waifus + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("ProductVersion", "1.1.0-rtm-22752"); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.Property("UserThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiRaidSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AntiSpamSettingId"); + + b.Property("ChannelId"); + + b.HasKey("Id"); + + b.HasIndex("AntiSpamSettingId"); + + b.ToTable("AntiSpamIgnore"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("GuildConfigId"); + + b.Property("MessageThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiSpamSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ItemId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("BlacklistItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BetflipMultiplier"); + + b.Property("Betroll100Multiplier"); + + b.Property("Betroll67Multiplier"); + + b.Property("Betroll91Multiplier"); + + b.Property("BufferSize"); + + b.Property("CurrencyDropAmount"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("DMHelpString"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("MigrationVersion"); + + b.Property("MinimumBetAmount"); + + b.Property("OkColor"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + b.Property("TriviaCurrencyReward"); + + b.HasKey("Id"); + + b.ToTable("BotConfig"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BaseDestroyed"); + + b.Property("CallUser"); + + b.Property("ClashWarId"); + + b.Property("SequenceNumber"); + + b.Property("Stars"); + + b.Property("TimeAdded"); + + b.HasKey("Id"); + + b.HasIndex("ClashWarId"); + + b.ToTable("ClashCallers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("EnemyClan"); + + b.Property("GuildId"); + + b.Property("Size"); + + b.Property("StartedAt"); + + b.Property("WarState"); + + b.HasKey("Id"); + + b.ToTable("ClashOfClans"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandCooldown"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("CommandName"); + + b.Property("Price"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.HasIndex("Price") + .IsUnique(); + + b.ToTable("CommandPrice"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("InternalTrigger"); + + b.Property("Modifier"); + + b.Property("UnitType"); + + b.HasKey("Id"); + + b.ToTable("ConversionUnits"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Currency"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("CurrencyTransactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildId"); + + b.Property("IsRegex"); + + b.Property("OwnerOnly"); + + b.Property("Response"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.ToTable("CustomReactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AvatarId"); + + b.Property("Discriminator"); + + b.Property("UserId"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId"); + + b.ToTable("DiscordUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("Name"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Donators"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("EightBallResponses"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildConfigId1"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.HasIndex("GuildConfigId1"); + + b.ToTable("FilterChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildConfigId"); + + b.Property("Word"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilteredWord"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Type"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FollowedStream"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GCChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoAssignRoleId"); + + b.Property("AutoDeleteByeMessages"); + + b.Property("AutoDeleteByeMessagesTimer"); + + b.Property("AutoDeleteGreetMessages"); + + b.Property("AutoDeleteGreetMessagesTimer"); + + b.Property("AutoDeleteSelfAssignedRoleMessages"); + + b.Property("ByeMessageChannelId"); + + b.Property("ChannelByeMessageText"); + + b.Property("ChannelGreetMessageText"); + + b.Property("CleverbotEnabled"); + + b.Property("DefaultMusicVolume"); + + b.Property("DeleteMessageOnCommand"); + + b.Property("DmGreetMessageText"); + + b.Property("ExclusiveSelfAssignedRoles"); + + b.Property("FilterInvites"); + + b.Property("FilterWords"); + + b.Property("GreetMessageChannelId"); + + b.Property("GuildId"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.HasIndex("LogSettingId"); + + b.HasIndex("RootPermissionId"); + + b.ToTable("GuildConfigs"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Interval"); + + b.Property("Message"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GuildRepeater"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredLogChannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredVoicePresenceCHannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelCreated"); + + b.Property("ChannelCreatedId"); + + b.Property("ChannelDestroyed"); + + b.Property("ChannelDestroyedId"); + + b.Property("ChannelId"); + + b.Property("ChannelUpdated"); + + b.Property("ChannelUpdatedId"); + + b.Property("IsLogging"); + + b.Property("LogOtherId"); + + b.Property("LogUserPresence"); + + b.Property("LogUserPresenceId"); + + b.Property("LogVoicePresence"); + + b.Property("LogVoicePresenceId"); + + b.Property("LogVoicePresenceTTSId"); + + b.Property("MessageDeleted"); + + b.Property("MessageDeletedId"); + + b.Property("MessageUpdated"); + + b.Property("MessageUpdatedId"); + + b.Property("UserBanned"); + + b.Property("UserBannedId"); + + b.Property("UserJoined"); + + b.Property("UserJoinedId"); + + b.Property("UserLeft"); + + b.Property("UserLeftId"); + + b.Property("UserMutedId"); + + b.Property("UserPresenceChannelId"); + + b.Property("UserUnbanned"); + + b.Property("UserUnbannedId"); + + b.Property("UserUpdated"); + + b.Property("UserUpdatedId"); + + b.Property("VoicePresenceChannelId"); + + b.HasKey("Id"); + + b.ToTable("LogSettings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ModuleName"); + + b.Property("Prefix"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("ModulePrefixes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Author"); + + b.Property("AuthorId"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("MutedUserId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("NextId"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("NextId") + .IsUnique(); + + b.ToTable("Permission"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Status"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("PlayingStatus"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("MusicPlaylistId"); + + b.Property("Provider"); + + b.Property("ProviderType"); + + b.Property("Query"); + + b.Property("Title"); + + b.Property("Uri"); + + b.HasKey("Id"); + + b.HasIndex("MusicPlaylistId"); + + b.ToTable("PlaylistSong"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("AuthorName") + .IsRequired(); + + b.Property("GuildId"); + + b.Property("Keyword") + .IsRequired(); + + b.Property("Text") + .IsRequired(); + + b.HasKey("Id"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("Icon"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("RaceAnimals"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("IsPrivate"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("UserId"); + + b.Property("When"); + + b.HasKey("Id"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("Price"); + + b.Property("WaifuId"); + + b.HasKey("Id"); + + b.HasIndex("AffinityId"); + + b.HasIndex("ClaimerId"); + + b.HasIndex("WaifuId") + .IsUnique(); + + b.ToTable("WaifuInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("NewId"); + + b.Property("OldId"); + + b.Property("UpdateType"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("NewId"); + + b.HasIndex("OldId"); + + b.HasIndex("UserId"); + + b.ToTable("WaifuUpdates"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiRaidSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.HasOne("NadekoBot.Services.Database.Models.AntiSpamSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiSpamSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("Blacklist") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar") + .WithMany("Bases") + .HasForeignKey("ClashWarId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("CommandPrices") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("EightBallResponses") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId"); + + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId1"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany() + .HasForeignKey("LogSettingId"); + + b.HasOne("NadekoBot.Services.Database.Models.Permission", "RootPermission") + .WithMany() + .HasForeignKey("RootPermissionId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GuildRepeaters") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredVoicePresenceChannelIds") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("ModulePrefixes") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next") + .WithOne("Previous") + .HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RotatingStatusMessages") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist") + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RaceAnimals") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("NadekoBot.Services.Database.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170122044958_waifus.cs b/src/NadekoBot/Migrations/20170122044958_waifus.cs new file mode 100644 index 00000000..4396ae77 --- /dev/null +++ b/src/NadekoBot/Migrations/20170122044958_waifus.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class waifus : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "DiscordUser", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AvatarId = table.Column(nullable: true), + Discriminator = table.Column(nullable: true), + UserId = table.Column(nullable: false), + Username = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DiscordUser", x => x.Id); + table.UniqueConstraint("AK_DiscordUser_UserId", x => x.UserId); + }); + + migrationBuilder.CreateTable( + name: "WaifuInfo", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AffinityId = table.Column(nullable: true), + ClaimerId = table.Column(nullable: true), + Price = table.Column(nullable: false), + WaifuId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_WaifuInfo", x => x.Id); + table.ForeignKey( + name: "FK_WaifuInfo_DiscordUser_AffinityId", + column: x => x.AffinityId, + principalTable: "DiscordUser", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_WaifuInfo_DiscordUser_ClaimerId", + column: x => x.ClaimerId, + principalTable: "DiscordUser", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_WaifuInfo_DiscordUser_WaifuId", + column: x => x.WaifuId, + principalTable: "DiscordUser", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "WaifuUpdates", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + NewId = table.Column(nullable: true), + OldId = table.Column(nullable: true), + UpdateType = table.Column(nullable: false), + UserId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_WaifuUpdates", x => x.Id); + table.ForeignKey( + name: "FK_WaifuUpdates_DiscordUser_NewId", + column: x => x.NewId, + principalTable: "DiscordUser", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_WaifuUpdates_DiscordUser_OldId", + column: x => x.OldId, + principalTable: "DiscordUser", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_WaifuUpdates_DiscordUser_UserId", + column: x => x.UserId, + principalTable: "DiscordUser", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_WaifuInfo_AffinityId", + table: "WaifuInfo", + column: "AffinityId"); + + migrationBuilder.CreateIndex( + name: "IX_WaifuInfo_ClaimerId", + table: "WaifuInfo", + column: "ClaimerId"); + + migrationBuilder.CreateIndex( + name: "IX_WaifuInfo_WaifuId", + table: "WaifuInfo", + column: "WaifuId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_WaifuUpdates_NewId", + table: "WaifuUpdates", + column: "NewId"); + + migrationBuilder.CreateIndex( + name: "IX_WaifuUpdates_OldId", + table: "WaifuUpdates", + column: "OldId"); + + migrationBuilder.CreateIndex( + name: "IX_WaifuUpdates_UserId", + table: "WaifuUpdates", + column: "UserId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "WaifuInfo"); + + migrationBuilder.DropTable( + name: "WaifuUpdates"); + + migrationBuilder.DropTable( + name: "DiscordUser"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 454c641f..dd9bb84d 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -299,6 +299,26 @@ namespace NadekoBot.Migrations b.ToTable("CustomReactions"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AvatarId"); + + b.Property("Discriminator"); + + b.Property("UserId"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId"); + + b.ToTable("DiscordUser"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => { b.Property("Id") @@ -817,6 +837,55 @@ namespace NadekoBot.Migrations b.ToTable("PokeGame"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("Price"); + + b.Property("WaifuId"); + + b.HasKey("Id"); + + b.HasIndex("AffinityId"); + + b.HasIndex("ClaimerId"); + + b.HasIndex("WaifuId") + .IsUnique(); + + b.ToTable("WaifuInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("NewId"); + + b.Property("OldId"); + + b.Property("UpdateType"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("NewId"); + + b.HasIndex("OldId"); + + b.HasIndex("UserId"); + + b.ToTable("WaifuUpdates"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => { b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") @@ -982,6 +1051,38 @@ namespace NadekoBot.Migrations .WithMany("RaceAnimals") .HasForeignKey("BotConfigId"); }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("NadekoBot.Services.Database.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); } } } diff --git a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs new file mode 100644 index 00000000..3a365bf0 --- /dev/null +++ b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs @@ -0,0 +1,516 @@ +using Discord; +using Discord.Commands; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Services; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Gambling +{ + public partial class Gambling + { + public enum ClaimTitles + { + Lonely, + Devoted, + Rookie, + Schemer, + Dilettante, + Intermediate, + Seducer, + Expert, + Veteran, + Incubis, + Harem_King, + Harem_God, + } + + public enum AffinityTitles + { + Pure, + Faithful, + Defiled, + Cheater, + Tainted, + Corrupted, + Lewd, + Sloot, + Depraved, + Harlot + } + + [Group] + public class WaifuClaimCommands : ModuleBase + { + private static ConcurrentDictionary _divorceCooldowns { get; } = new ConcurrentDictionary(); + private static ConcurrentDictionary _affinityCooldowns { get; } = new ConcurrentDictionary(); + + enum WaifuClaimResult + { + Success, + NotEnoughFunds, + InsufficientAmount + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task WaifuClaim(int amount, [Remainder]IUser target) + { + if (amount < 50) + { + await Context.Channel.SendErrorAsync($"{Context.User.Mention} No waifu is that cheap. You must pay at least 50{NadekoBot.BotConfig.CurrencySign} to get a waifu, even if their actual value is lower.").ConfigureAwait(false); + return; + } + + if (target.Id == Context.User.Id) + { + await Context.Channel.SendErrorAsync(Context.User.Mention + " You can't claim yourself.").ConfigureAwait(false); + return; + } + + WaifuClaimResult result = WaifuClaimResult.NotEnoughFunds; + int? oldPrice = null; + WaifuInfo w; + var isAffinity = false; + using (var uow = DbHandler.UnitOfWork()) + { + w = uow.Waifus.ByWaifuUserId(target.Id); + isAffinity = (w?.Affinity?.UserId == Context.User.Id); + if (w == null) + { + var claimer = uow.DiscordUsers.GetOrCreate(Context.User); + var waifu = uow.DiscordUsers.GetOrCreate(target); + if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User.Id, "Claimed Waifu", amount, uow).ConfigureAwait(false)) + { + result = WaifuClaimResult.NotEnoughFunds; + } + else + { + uow.Waifus.Add(w = new WaifuInfo() + { + Waifu = waifu, + Claimer = claimer, + Affinity = null, + Price = amount + }); + uow._context.WaifuUpdates.Add(new WaifuUpdate() + { + User = waifu, + Old = null, + New = claimer, + UpdateType = WaifuUpdateType.Claimed + }); + result = WaifuClaimResult.Success; + } + } + else if (isAffinity && amount >= w.Price * 0.88f) + { + if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User.Id, "Claimed Waifu", amount, uow).ConfigureAwait(false)) + { + result = WaifuClaimResult.NotEnoughFunds; + } + else + { + var oldClaimer = w.Claimer; + w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User); + oldPrice = w.Price; + w.Price = amount + (amount / 4); + result = WaifuClaimResult.Success; + + uow._context.WaifuUpdates.Add(new WaifuUpdate() + { + User = w.Waifu, + Old = oldClaimer, + New = w.Claimer, + UpdateType = WaifuUpdateType.Claimed + }); + } + } + else if (amount >= w.Price * 1.1f) // if no affinity + { + if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User.Id, "Claimed Waifu", amount, uow).ConfigureAwait(false)) + { + result = WaifuClaimResult.NotEnoughFunds; + } + else + { + var oldClaimer = w.Claimer; + w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User); + oldPrice = w.Price; + w.Price = amount; + result = WaifuClaimResult.Success; + + uow._context.WaifuUpdates.Add(new WaifuUpdate() + { + User = w.Waifu, + Old = oldClaimer, + New = w.Claimer, + UpdateType = WaifuUpdateType.Claimed + }); + } + } + else + result = WaifuClaimResult.InsufficientAmount; + + + await uow.CompleteAsync().ConfigureAwait(false); + } + + if (result == WaifuClaimResult.InsufficientAmount) + { + await Context.Channel.SendErrorAsync($"{Context.User.Mention} You must pay {Math.Ceiling(w.Price * (isAffinity ? 0.88f : 1.1f))} or more to claim that waifu!").ConfigureAwait(false); + return; + } + else if (result == WaifuClaimResult.NotEnoughFunds) + { + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} you don't have {amount}{NadekoBot.BotConfig.CurrencySign}!") + .ConfigureAwait(false); + } + else + { + var msg = $"{Context.User.Mention} claimed {target.Mention} as their waifu for {amount}{NadekoBot.BotConfig.CurrencySign}!"; + if (w.Affinity?.UserId == Context.User.Id) + msg += $"\n🎉 Their love is fulfilled! 🎉\n**{target}'s** new value is {w.Price}{NadekoBot.BotConfig.CurrencySign}!"; + await Context.Channel.SendConfirmAsync(msg) + .ConfigureAwait(false); + } + } + + public enum DivorceResult + { + Success, + SucessWithPenalty, + NotYourWife, + Cooldown + } + + + private static readonly TimeSpan DivorceLimit = TimeSpan.FromHours(6); + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task Divorce([Remainder]IUser target) + { + var channel = (ITextChannel)Context.Channel; + + if (target.Id == Context.User.Id) + return; + + var result = DivorceResult.NotYourWife; + TimeSpan difference = TimeSpan.Zero; + var amount = 0; + WaifuInfo w = null; + using (var uow = DbHandler.UnitOfWork()) + { + w = uow.Waifus.ByWaifuUserId(target.Id); + var now = DateTime.UtcNow; + if (w == null || w.Claimer == null || w.Claimer.UserId != Context.User.Id) + result = DivorceResult.NotYourWife; + else if (_divorceCooldowns.AddOrUpdate(Context.User.Id, + now, + (key, old) => ((difference = now.Subtract(old)) > DivorceLimit) ? now : old) != now) + { + result = DivorceResult.Cooldown; + } + else + { + amount = w.Price / 2; + + if (w.Affinity?.UserId == Context.User.Id) + { + await CurrencyHandler.AddCurrencyAsync(w.Waifu.UserId, "Waifu Compensation", amount, uow).ConfigureAwait(false); + w.Price = (int)Math.Floor(w.Price * 0.75f); + result = DivorceResult.SucessWithPenalty; + } + else + { + await CurrencyHandler.AddCurrencyAsync(Context.User.Id, "Waifu Refund", amount, uow).ConfigureAwait(false); + + result = DivorceResult.Success; + } + var oldClaimer = w.Claimer; + w.Claimer = null; + + uow._context.WaifuUpdates.Add(new WaifuUpdate() + { + User = w.Waifu, + Old = oldClaimer, + New = null, + UpdateType = WaifuUpdateType.Claimed + }); + } + + await uow.CompleteAsync().ConfigureAwait(false); + } + + if (result == DivorceResult.SucessWithPenalty) + { + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} You have divorced a waifu who likes you. You heartless monster.\n{w.Waifu} received {amount}{NadekoBot.BotConfig.CurrencySign} as a compensation.").ConfigureAwait(false); + } + else if (result == DivorceResult.Success) + { + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} You have divorced a waifu who doesn't like you. You received {amount}{NadekoBot.BotConfig.CurrencySign} back.").ConfigureAwait(false); + } + else if (result == DivorceResult.NotYourWife) + { + await Context.Channel.SendErrorAsync($"{Context.User.Mention} That waifu is not yours.").ConfigureAwait(false); + } + else + { + var remaining = DivorceLimit.Subtract(difference); + await Context.Channel.SendErrorAsync($"{Context.User.Mention} You divorced recently. You must wait **{remaining.Hours} hours and {remaining.Minutes} minutes** to divorce again.").ConfigureAwait(false); + } + } + + private static readonly TimeSpan AffinityLimit = TimeSpan.FromMinutes(30); + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task WaifuClaimerAffinity([Remainder]IUser u = null) + { + if (u?.Id == Context.User.Id) + { + await Context.Channel.SendErrorAsync($"{Context.User.Mention} you can't set affinity to yourself, you egomaniac.").ConfigureAwait(false); + return; + } + DiscordUser oldAff = null; + var sucess = false; + var cooldown = false; + TimeSpan difference = TimeSpan.Zero; + using (var uow = DbHandler.UnitOfWork()) + { + var w = uow.Waifus.ByWaifuUserId(Context.User.Id); + var newAff = u == null ? null : uow.DiscordUsers.GetOrCreate(u); + var now = DateTime.UtcNow; + if (w?.Affinity?.UserId == u?.Id) + { + sucess = false; + } + else if (_affinityCooldowns.AddOrUpdate(Context.User.Id, + now, + (key, old) => ((difference = now.Subtract(old)) > AffinityLimit) ? now : old) != now) + { + sucess = false; + cooldown = true; + } + else if (w == null) + { + var thisUser = uow.DiscordUsers.GetOrCreate(Context.User); + uow.Waifus.Add(new WaifuInfo() + { + Affinity = newAff, + Waifu = thisUser, + Price = 1, + Claimer = null + }); + sucess = true; + + uow._context.WaifuUpdates.Add(new WaifuUpdate() + { + User = thisUser, + Old = null, + New = newAff, + UpdateType = WaifuUpdateType.AffinityChanged + }); + } + else + { + if (w.Affinity != null) + oldAff = w.Affinity; + w.Affinity = newAff; + sucess = true; + + uow._context.WaifuUpdates.Add(new WaifuUpdate() + { + User = w.Waifu, + Old = oldAff, + New = newAff, + UpdateType = WaifuUpdateType.AffinityChanged + }); + } + + await uow.CompleteAsync().ConfigureAwait(false); + } + if (!sucess) + { + if (cooldown) + { + var remaining = AffinityLimit.Subtract(difference); + await Context.Channel.SendErrorAsync($"{Context.User.Mention} You must wait **{remaining.Hours} hours and {remaining.Minutes} minutes** in order to change your affinity again.").ConfigureAwait(false); + } + else + await Context.Channel.SendErrorAsync($"{Context.User.Mention} your affinity is already set to that waifu or you're trying to remove your affinity while not having one.").ConfigureAwait(false); + return; + } + if (u == null) + await Context.Channel.SendConfirmAsync("Affinity Reset", $"{Context.User.Mention} Your affinity is reset. You no longer have a person you like.").ConfigureAwait(false); + else if (oldAff == null) + await Context.Channel.SendConfirmAsync("Affinity Set", $"{Context.User.Mention} wants to be {u.Mention}'s waifu. Aww <3").ConfigureAwait(false); + else + await Context.Channel.SendConfirmAsync("Affinity Changed", $"{Context.User.Mention} changed their affinity from {oldAff} to {u.Mention}.\n\n*This is morally questionable.*🤔").ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task WaifuLeaderboard() + { + IList waifus; + using (var uow = DbHandler.UnitOfWork()) + { + waifus = uow.Waifus.GetTop(9); + } + + if (waifus.Count == 0) + { + await Context.Channel.SendConfirmAsync("No waifus have been claimed yet.").ConfigureAwait(false); + return; + } + + var embed = new EmbedBuilder() + .WithTitle("Top Waifus") + .WithOkColor(); + + for (int i = 0; i < waifus.Count; i++) + { + var w = waifus[i]; + + embed.AddField(efb => efb.WithName("#" + (i + 1) + " - " + w.Price + NadekoBot.BotConfig.CurrencySign).WithValue(w.ToString()).WithIsInline(false)); + } + + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task WaifuInfo([Remainder]IUser target = null) + { + if (target == null) + target = Context.User; + WaifuInfo w; + IList claims; + int divorces = 0; + using (var uow = DbHandler.UnitOfWork()) + { + w = uow.Waifus.ByWaifuUserId(target.Id); + claims = uow.Waifus.ByClaimerUserId(target.Id); + divorces = uow._context.WaifuUpdates.Count(x => x.Old != null && + x.Old.UserId == target.Id && + x.UpdateType == WaifuUpdateType.Claimed && + x.New == null); + if (w == null) + uow.Waifus.Add(w = new WaifuInfo() + { + Affinity = null, + Claimer = null, + Price = 1, + Waifu = uow.DiscordUsers.GetOrCreate(target), + }); + await uow.CompleteAsync().ConfigureAwait(false); + } + + var claimInfo = GetClaimTitle(target.Id); + var affInfo = GetAffinityTitle(target.Id); + + var embed = new EmbedBuilder() + .WithOkColor() + .WithTitle("Waifu " + w.Waifu.ToString() + " - \"the " + claimInfo.Title + "\"") + .AddField(efb => efb.WithName("Price").WithValue(w.Price.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName("Claimed by").WithValue(w.Claimer?.ToString() ?? "No one").WithIsInline(true)) + .AddField(efb => efb.WithName("Likes").WithValue(w.Affinity?.ToString() ?? "Nobody").WithIsInline(true)) + .AddField(efb => efb.WithName("Changes Of Heart").WithValue($"{affInfo.Count} - \"the {affInfo.Title}\"").WithIsInline(true)) + .AddField(efb => efb.WithName("Divorces").WithValue(divorces.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName($"Waifus ({claims.Count})").WithValue(claims.Count == 0 ? "Nobody" : string.Join("\n", claims.Select(x => x.Waifu))).WithIsInline(true)); + + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + + + public struct WaifuProfileTitle + { + public int Count { get; } + public string Title { get; } + + public WaifuProfileTitle(int count, string title) + { + Count = count; + Title = title; + } + } + + private static WaifuProfileTitle GetClaimTitle(ulong userId) + { + int count = 0; + using (var uow = DbHandler.UnitOfWork()) + { + count = uow.Waifus.ByClaimerUserId(userId).Count; + } + + ClaimTitles title = ClaimTitles.Lonely; + if (count == 0) + title = ClaimTitles.Lonely; + else if (count == 1) + title = ClaimTitles.Devoted; + else if (count < 4) + title = ClaimTitles.Rookie; + else if (count < 6) + title = ClaimTitles.Schemer; + else if (count < 8) + title = ClaimTitles.Dilettante; + else if (count < 10) + title = ClaimTitles.Intermediate; + else if (count < 12) + title = ClaimTitles.Seducer; + else if (count < 15) + title = ClaimTitles.Expert; + else if (count < 17) + title = ClaimTitles.Veteran; + else if (count < 25) + title = ClaimTitles.Incubis; + else if (count < 50) + title = ClaimTitles.Harem_King; + else + title = ClaimTitles.Harem_God; + + return new WaifuProfileTitle(count, title.ToString().Replace('_', ' ')); + } + + private static WaifuProfileTitle GetAffinityTitle(ulong userId) + { + int count = 0; + using (var uow = DbHandler.UnitOfWork()) + { + count = uow._context.WaifuUpdates.Count(w => w.User.UserId == userId && w.UpdateType == WaifuUpdateType.AffinityChanged); + } + + AffinityTitles title = AffinityTitles.Pure; + if (count < 1) + title = AffinityTitles.Pure; + else if (count < 2) + title = AffinityTitles.Faithful; + else if (count < 4) + title = AffinityTitles.Defiled; + else if (count < 7) + title = AffinityTitles.Cheater; + else if (count < 9) + title = AffinityTitles.Tainted; + else if (count < 11) + title = AffinityTitles.Corrupted; + else if (count < 13) + title = AffinityTitles.Lewd; + else if (count < 15) + title = AffinityTitles.Sloot; + else if (count < 17) + title = AffinityTitles.Depraved; + else if (count < 20) + title = AffinityTitles.Harlot; + + return new WaifuProfileTitle(count, title.ToString().Replace('_', ' ')); + } + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index f52109ee..ff1360b5 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -147,7 +147,7 @@ namespace NadekoBot.Modules.Gambling [NadekoCommand, Usage, Description, Aliases] [OwnerOnly] - public async Task BrTest(int tests = 1000) + public Task BrTest(int tests = 1000) { var t = Task.Run(async () => { @@ -189,10 +189,15 @@ namespace NadekoBot.Modules.Gambling sb.AppendLine($"x{key} occured {dict[key]} times. {dict[key] * 1.0f / tests * 100}%"); payout += key * dict[key]; } - await Context.Channel.SendConfirmAsync("BetRoll Test Results", sb.ToString(), - footer: $"Total Bet: {tests * bet} | Payout: {payout * bet} | {payout * 1.0f / tests * 100}%"); + try + { + await Context.Channel.SendConfirmAsync("BetRoll Test Results", sb.ToString(), + footer: $"Total Bet: {tests * bet} | Payout: {payout * bet} | {payout * 1.0f / tests * 100}%"); + } + catch { } }); + return Task.CompletedTask; } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index 7796571d..fd60a591 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -48,7 +48,7 @@ namespace NadekoBot.Modules.Utility keyword = keyword.ToUpperInvariant(); Quote quote; - using (var uow = DbHandler.Instance.GetUnitOfWork()) + using (var uow = DbHandler.UnitOfWork()) { quote = await uow.Quotes.GetRandomQuoteByKeywordAsync(Context.Guild.Id, keyword).ConfigureAwait(false); } diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 5fe6ae20..7510733e 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -2489,6 +2489,33 @@ namespace NadekoBot.Resources { } } + ///

+ /// Looks up a localized string similar to divorce. + /// + public static string divorce_cmd { + get { + return ResourceManager.GetString("divorce_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Releases your claim on a specific waifu. You will get a part of your money back unless that waifu has an affinity towards you.. + /// + public static string divorce_desc { + get { + return ResourceManager.GetString("divorce_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}divorce @CheatingSloot`. + /// + public static string divorce_usage { + get { + return ResourceManager.GetString("divorce_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to donadd. /// @@ -8375,6 +8402,114 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to claimwaifu claim. + /// + public static string waifuclaim_cmd { + get { + return ResourceManager.GetString("waifuclaim_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Claim a waifu for yourself by spending currency. You must spend atleast 10% more than her current value unless she set `{0}affinity` towards you.. + /// + public static string waifuclaim_desc { + get { + return ResourceManager.GetString("waifuclaim_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}claim 50 @Himesama`. + /// + public static string waifuclaim_usage { + get { + return ResourceManager.GetString("waifuclaim_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to affinity. + /// + public static string waifuclaimeraffinity_cmd { + get { + return ResourceManager.GetString("waifuclaimeraffinity_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `{0}claim` on you by 20%. + /// + public static string waifuclaimeraffinity_desc { + get { + return ResourceManager.GetString("waifuclaimeraffinity_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}affinity`. + /// + public static string waifuclaimeraffinity_usage { + get { + return ResourceManager.GetString("waifuclaimeraffinity_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to waifuinfo waifustats. + /// + public static string waifuinfo_cmd { + get { + return ResourceManager.GetString("waifuinfo_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows waifu stats for a target person.. + /// + public static string waifuinfo_desc { + get { + return ResourceManager.GetString("waifuinfo_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}waifuinfo @MyCrush`. + /// + public static string waifuinfo_usage { + get { + return ResourceManager.GetString("waifuinfo_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to waifus waifulb. + /// + public static string waifuleaderboard_cmd { + get { + return ResourceManager.GetString("waifuleaderboard_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows top 10 waifus.. + /// + public static string waifuleaderboard_desc { + get { + return ResourceManager.GetString("waifuleaderboard_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}waifus`. + /// + public static string waifuleaderboard_usage { + get { + return ResourceManager.GetString("waifuleaderboard_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to weather we. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 460d6b7c..2a0be4b8 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2979,4 +2979,49 @@ `{0}slot 5` + + affinity + + + Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `{0}claim` on you by 20% + + + `{0}affinity` + + + claimwaifu claim + + + Claim a waifu for yourself by spending currency. You must spend atleast 10% more than her current value unless she set `{0}affinity` towards you. + + + `{0}claim 50 @Himesama` + + + waifus waifulb + + + Shows top 10 waifus. + + + `{0}waifus` + + + divorce + + + Releases your claim on a specific waifu. You will get a part of your money back unless that waifu has an affinity towards you. + + + `{0}divorce @CheatingSloot` + + + waifuinfo waifustats + + + Shows waifu stats for a target person. + + + `{0}waifuinfo @MyCrush` + \ No newline at end of file diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index a9689be1..f2aab51c 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -197,8 +197,10 @@ namespace NadekoBot.Services if (usrMsg == null) //has to be an user message, not system/other messages. return; +#if !GLOBAL_NADEKO // track how many messagges each user is sending UserMessagesSent.AddOrUpdate(usrMsg.Author.Id, 1, (key, old) => ++old); +#endif var channel = msg.Channel as SocketTextChannel; var guild = channel?.Guild; diff --git a/src/NadekoBot/Services/CurrencyHandler.cs b/src/NadekoBot/Services/CurrencyHandler.cs index f2d699a0..7e2939e4 100644 --- a/src/NadekoBot/Services/CurrencyHandler.cs +++ b/src/NadekoBot/Services/CurrencyHandler.cs @@ -4,6 +4,7 @@ using Discord; using NadekoBot.Extensions; using NadekoBot.Modules.Gambling; using NadekoBot.Services.Database.Models; +using NadekoBot.Services.Database; namespace NadekoBot.Services { @@ -19,26 +20,36 @@ namespace NadekoBot.Services return success; } - public static async Task RemoveCurrencyAsync(ulong authorId, string reason, long amount) + public static async Task RemoveCurrencyAsync(ulong authorId, string reason, long amount, IUnitOfWork uow = null) { if (amount < 0) throw new ArgumentNullException(nameof(amount)); - using (var uow = DbHandler.UnitOfWork()) + if (uow == null) { - var success = uow.Currency.TryUpdateState(authorId, -amount); - if (!success) - return false; - uow.CurrencyTransactions.Add(new CurrencyTransaction() + using (uow = DbHandler.UnitOfWork()) { - UserId = authorId, - Reason = reason, - Amount = -amount, - }); - await uow.CompleteAsync().ConfigureAwait(false); + var toReturn = InternalRemoveCurrency(authorId, reason, amount, uow); + await uow.CompleteAsync().ConfigureAwait(false); + return toReturn; + } } + return InternalRemoveCurrency(authorId, reason, amount, uow); + } + + private static bool InternalRemoveCurrency(ulong authorId, string reason, long amount, IUnitOfWork uow) + { + var success = uow.Currency.TryUpdateState(authorId, -amount); + if (!success) + return false; + uow.CurrencyTransactions.Add(new CurrencyTransaction() + { + UserId = authorId, + Reason = reason, + Amount = -amount, + }); return true; } @@ -50,22 +61,29 @@ namespace NadekoBot.Services try { await author.SendConfirmAsync($"`You received:` {amount} {NadekoBot.BotConfig.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { } } - public static async Task AddCurrencyAsync(ulong receiverId, string reason, long amount) + public static async Task AddCurrencyAsync(ulong receiverId, string reason, long amount, IUnitOfWork uow = null) { if (amount < 0) throw new ArgumentNullException(nameof(amount)); + var transaction = new CurrencyTransaction() + { + UserId = receiverId, + Reason = reason, + Amount = amount, + }; - using (var uow = DbHandler.UnitOfWork()) + if (uow == null) + using (uow = DbHandler.UnitOfWork()) + { + uow.Currency.TryUpdateState(receiverId, amount); + uow.CurrencyTransactions.Add(transaction); + await uow.CompleteAsync(); + } + else { uow.Currency.TryUpdateState(receiverId, amount); - uow.CurrencyTransactions.Add(new CurrencyTransaction() - { - UserId = receiverId, - Reason = reason, - Amount = amount, - }); - await uow.CompleteAsync(); + uow.CurrencyTransactions.Add(transaction); } } } diff --git a/src/NadekoBot/Services/Database/IUnitOfWork.cs b/src/NadekoBot/Services/Database/IUnitOfWork.cs index f17e1f6a..c1c9479e 100644 --- a/src/NadekoBot/Services/Database/IUnitOfWork.cs +++ b/src/NadekoBot/Services/Database/IUnitOfWork.cs @@ -21,6 +21,8 @@ namespace NadekoBot.Services.Database ICurrencyTransactionsRepository CurrencyTransactions { get; } IMusicPlaylistRepository MusicPlaylists { get; } IPokeGameRepository PokeGame { get; } + IWaifuRepository Waifus { get; } + IDiscordUserRepository DiscordUsers { get; } int Complete(); Task CompleteAsync(); diff --git a/src/NadekoBot/Services/Database/Models/DiscordUser.cs b/src/NadekoBot/Services/Database/Models/DiscordUser.cs new file mode 100644 index 00000000..608daf81 --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/DiscordUser.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Models +{ + public class DiscordUser : DbEntity + { + public ulong UserId { get; set; } + public string Username { get; set; } + public string Discriminator { get; set; } + public string AvatarId { get; set; } + + public override string ToString() => + Username + "#" + Discriminator; + } +} diff --git a/src/NadekoBot/Services/Database/Models/Waifu.cs b/src/NadekoBot/Services/Database/Models/Waifu.cs new file mode 100644 index 00000000..947bf516 --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/Waifu.cs @@ -0,0 +1,49 @@ +using NadekoBot.Extensions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Models +{ + public class WaifuInfo : DbEntity + { + public int WaifuId { get; set; } + public DiscordUser Waifu { get; set; } + + public int? ClaimerId { get; set; } + public DiscordUser Claimer { get; set; } + + public int? AffinityId { get; set; } + public DiscordUser Affinity { get; set; } + + public int Price { get; set; } + + public override string ToString() + { + var claimer = "no one"; + var status = ""; + + var waifuUsername = Waifu.Username.TrimTo(20); + var claimerUsername = Claimer?.Username.TrimTo(20); + + if (Claimer != null) + { + claimer = $"{ claimerUsername }#{Claimer.Discriminator}"; + } + if (AffinityId == null) + { + status = $"... but {waifuUsername}'s heart is empty"; + } + else if (AffinityId == ClaimerId) + { + status = $"... and {waifuUsername} likes {claimerUsername} too <3"; + } + else { + status = $"... but {waifuUsername}'s heart belongs to {Affinity.Username.TrimTo(20)}#{Affinity.Discriminator}"; + } + return $"**{waifuUsername}#{Waifu.Discriminator}** - claimed by **{claimer}**\n\t{status}"; + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/Models/WaifuUpdate.cs b/src/NadekoBot/Services/Database/Models/WaifuUpdate.cs new file mode 100644 index 00000000..1c48826e --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/WaifuUpdate.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Models +{ + public class WaifuUpdate : DbEntity + { + public int UserId { get; set; } + public DiscordUser User { get; set; } + public WaifuUpdateType UpdateType { get; set; } + + public int? OldId { get; set; } + public DiscordUser Old { get; set; } + + public int? NewId { get; set; } + public DiscordUser New { get; set; } + } + + public enum WaifuUpdateType + { + AffinityChanged, + Claimed + } +} diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index b49439f6..102c6703 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -3,9 +3,26 @@ using System.Collections.Generic; using System.Linq; using NadekoBot.Services.Database.Models; using NadekoBot.Extensions; +using Microsoft.EntityFrameworkCore.Infrastructure; namespace NadekoBot.Services.Database { + + public class NadekoContextFactory : IDbContextFactory + { + /// + /// :\ Used for migrations + /// + /// + /// + public NadekoContext Create(DbContextFactoryOptions options) + { + var optionsBuilder = new DbContextOptionsBuilder(); + optionsBuilder.UseSqlite("Filename=./data/NadekoBot.db"); + return new NadekoContext(optionsBuilder.Options); + } + } + public class NadekoContext : DbContext { public DbSet Quotes { get; set; } @@ -22,6 +39,7 @@ namespace NadekoBot.Services.Database public DbSet CustomReactions { get; set; } public DbSet CurrencyTransactions { get; set; } public DbSet PokeGame { get; set; } + public DbSet WaifuUpdates { get; set; } //logging public DbSet LogSettings { get; set; } @@ -33,23 +51,15 @@ namespace NadekoBot.Services.Database public DbSet RaceAnimals { get; set; } public DbSet ModulePrefixes { get; set; } - public NadekoContext() + public NadekoContext() : base() { - this.Database.Migrate(); + } public NadekoContext(DbContextOptions options) : base(options) { - this.Database.Migrate(); - EnsureSeedData(); } - ////Uncomment this to db initialisation with dotnet ef migration add [module] - //protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - //{ - // optionsBuilder.UseSqlite("Filename=./data/NadekoBot.db"); - //} - public void EnsureSeedData() { if (!BotConfig.Any()) @@ -244,6 +254,24 @@ namespace NadekoBot.Services.Database // .HasIndex(cp => cp.CommandName) // .IsUnique(); #endregion + + #region Waifus + + var wi = modelBuilder.Entity(); + wi.HasOne(x => x.Waifu) + .WithOne(); + // //.HasForeignKey(w => w.WaifuId) + // //.IsRequired(true); + + //wi.HasOne(x => x.Claimer) + // .WithOne(); + // //.HasForeignKey(w => w.ClaimerId) + // //.IsRequired(false); + + var du = modelBuilder.Entity(); + du.HasAlternateKey(w => w.UserId); + + #endregion } } } diff --git a/src/NadekoBot/Services/Database/Repositories/IDiscordUserRepository.cs b/src/NadekoBot/Services/Database/Repositories/IDiscordUserRepository.cs new file mode 100644 index 00000000..c80608dd --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/IDiscordUserRepository.cs @@ -0,0 +1,15 @@ +using Discord; +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Repositories +{ + public interface IDiscordUserRepository : IRepository + { + DiscordUser GetOrCreate(IUser original); + } +} diff --git a/src/NadekoBot/Services/Database/Repositories/IWaifuRepository.cs b/src/NadekoBot/Services/Database/Repositories/IWaifuRepository.cs new file mode 100644 index 00000000..2f2dc0f6 --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/IWaifuRepository.cs @@ -0,0 +1,13 @@ +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; + +namespace NadekoBot.Services.Database.Repositories +{ + public interface IWaifuRepository : IRepository + { + IList GetTop(int count); + WaifuInfo ByWaifuUserId(ulong userId); + IList ByClaimerUserId(ulong userId); + } +} diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/DiscordUserRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/DiscordUserRepository.cs new file mode 100644 index 00000000..9425f049 --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/Impl/DiscordUserRepository.cs @@ -0,0 +1,36 @@ +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Discord; + +namespace NadekoBot.Services.Database.Repositories.Impl +{ + public class DiscordUserRepository : Repository, IDiscordUserRepository + { + public DiscordUserRepository(DbContext context) : base(context) + { + } + + public DiscordUser GetOrCreate(IUser original) + { + DiscordUser toReturn; + + toReturn = _set.FirstOrDefault(u => u.UserId == original.Id); + + if (toReturn == null) + _set.Add(toReturn = new DiscordUser() + { + AvatarId = original.AvatarId, + Discriminator = original.Discriminator, + UserId = original.Id, + Username = original.Username, + }); + + return toReturn; + } + } +} diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/WaifuRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/WaifuRepository.cs new file mode 100644 index 00000000..8a973202 --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/Impl/WaifuRepository.cs @@ -0,0 +1,49 @@ +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; + +namespace NadekoBot.Services.Database.Repositories.Impl +{ + public class WaifuRepository : Repository, IWaifuRepository + { + public WaifuRepository(DbContext context) : base(context) + { + } + + public WaifuInfo ByWaifuUserId(ulong userId) + { + return _set.Include(wi => wi.Waifu) + .Include(wi => wi.Affinity) + .Include(wi => wi.Claimer) + .FirstOrDefault(wi => wi.Waifu.UserId == userId); + } + + public IList ByClaimerUserId(ulong userId) + { + return _set.Include(wi => wi.Waifu) + .Include(wi => wi.Affinity) + .Include(wi => wi.Claimer) + .Where(wi => wi.Claimer != null && wi.Claimer.UserId == userId) + .ToList(); + } + + public IList GetTop(int count) + { + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count)); + if (count == 0) + return new List(); + + return _set.Include(wi => wi.Waifu) + .Include(wi => wi.Affinity) + .Include(wi => wi.Claimer) + .OrderByDescending(wi => wi.Price) + .Take(count) + .ToList(); + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/UnitOfWork.cs b/src/NadekoBot/Services/Database/UnitOfWork.cs index 88231d6b..032c0bb7 100644 --- a/src/NadekoBot/Services/Database/UnitOfWork.cs +++ b/src/NadekoBot/Services/Database/UnitOfWork.cs @@ -48,6 +48,12 @@ namespace NadekoBot.Services.Database private IPokeGameRepository _pokegame; public IPokeGameRepository PokeGame => _pokegame ?? (_pokegame = new PokeGameRepository(_context)); + private IWaifuRepository _waifus; + public IWaifuRepository Waifus => _waifus ?? (_waifus = new WaifuRepository(_context)); + + private IDiscordUserRepository _discordUsers; + public IDiscordUserRepository DiscordUsers => _discordUsers ?? (_discordUsers = new DiscordUserRepository(_context)); + public UnitOfWork(NadekoContext context) { _context = context; diff --git a/src/NadekoBot/Services/DbHandler.cs b/src/NadekoBot/Services/DbHandler.cs index 03d12a94..9a4ab212 100644 --- a/src/NadekoBot/Services/DbHandler.cs +++ b/src/NadekoBot/Services/DbHandler.cs @@ -1,4 +1,6 @@ -using Microsoft.EntityFrameworkCore; +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; using NadekoBot.Services.Database; namespace NadekoBot.Services @@ -13,7 +15,8 @@ namespace NadekoBot.Services static DbHandler() { } - private DbHandler() { + private DbHandler() + { connectionString = NadekoBot.Credentials.Db.ConnectionString; var optionsBuilder = new DbContextOptionsBuilder(); optionsBuilder.UseSqlite(NadekoBot.Credentials.Db.ConnectionString); @@ -32,13 +35,19 @@ namespace NadekoBot.Services //} } - public NadekoContext GetDbContext() => - new NadekoContext(options); + public NadekoContext GetDbContext() + { + var context = new NadekoContext(options); + context.Database.Migrate(); + context.EnsureSeedData(); - public IUnitOfWork GetUnitOfWork() => + return context; + } + + private IUnitOfWork GetUnitOfWork() => new UnitOfWork(GetDbContext()); public static IUnitOfWork UnitOfWork() => DbHandler.Instance.GetUnitOfWork(); } -} +} \ No newline at end of file From 1e7a3bf3bc82c6f5ccd12956348ba1c036c6f32a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 22 Jan 2017 21:20:23 +0100 Subject: [PATCH 26/27] Fixeed compile error on public bot --- src/NadekoBot/Modules/NSFW/NSFW.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index 589d421a..266ffa68 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -289,6 +289,6 @@ namespace NadekoBot.Modules.NSFW public static Task GetRule34ImageLink(string tag) => Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Rule34); - } #endif + } } \ No newline at end of file From 53b0b7d3a538ec6c4bf495ae401fb52695c06060 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 22 Jan 2017 21:29:41 +0100 Subject: [PATCH 27/27] Updated commandlist --- docs/Commands List.md | 13 ++- src/NadekoBot/Modules/Gambling/Gambling.cs | 102 +++++++++--------- .../Resources/CommandStrings.Designer.cs | 12 +-- src/NadekoBot/Resources/CommandStrings.resx | 12 +-- src/NadekoBot/Services/Impl/StatsService.cs | 2 +- 5 files changed, 75 insertions(+), 66 deletions(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index 1d354c4a..ed71757c 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -125,6 +125,14 @@ Command and aliases | Description | Usage ### Gambling Command and aliases | Description | Usage ----------------|--------------|------- +`$claimwaifu` `$claim` | Claim a waifu for yourself by spending currency. You must spend atleast 10% more than her current value unless she set `$affinity` towards you. | `$claim 50 @Himesama` +`$divorce` | Releases your claim on a specific waifu. You will get some of the money you've spent back unless that waifu has an affinity towards you. 6 hours cooldown. | `$divorce @CheatingSloot` +`$affinity` | Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `$claim` on you by 20%. You can leave second argument empty to clear your affinity. 30 minutes cooldown. | `$affinity @MyHusband` or `$affinity` +`$waifus` `$waifulb` | Shows top 9 waifus. | `$waifus` +`$waifuinfo` `$waifustats` | Shows waifu stats for a target person. Defaults to you if no user is provided. | `$waifuinfo @MyCrush` or `$waifuinfo` +`$slotstats` | Shows the total stats of the slot command for this bot's session. **Bot Owner only.** | `$slotstats` +`$slottest` | Tests to see how much slots payout for X number of plays. **Bot Owner only.** | `$slottest 1000` +`$slot` | Play Nadeko slots. Max bet is 999. 3 seconds cooldown per user. | `$slot 5` `$flip` | Flips coin(s) - heads or tails, and shows an image. | `$flip` or `$flip 3` `$betflip` `$bf` | Bet to guess will the result be heads or tails. Guessing awards you 1.8x the currency you've bet. | `$bf 5 heads` or `$bf 3 t` `$draw` | Draws a card from the deck.If you supply number X, she draws up to 5 cards from the deck. | `$draw` or `$draw 5` @@ -132,6 +140,7 @@ Command and aliases | Description | Usage `$roll` | Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. Y can be a letter 'F' if you want to roll fate dice instead of dnd. | `$roll` or `$roll 7` or `$roll 3d5` or `$roll 5dF` `$rolluo` | Rolls X normal dice (up to 30) unordered. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | `$rolluo` or `$rolluo 7` or `$rolluo 3d5` `$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15` +`$startevent` | Starts one of the events seen on public nadeko. **Bot Owner only.** | `$startevent flowerreaction` `$race` | Starts a new animal race. | `$race` `$joinrace` `$jr` | Joins a new race. You can specify an amount of currency for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5` `$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName` @@ -206,7 +215,6 @@ Command and aliases | Description | Usage `!!localplaylst` `!!lopl` | Queues all songs from a directory. **Bot Owner only.** | `!!lopl C:/music/classical` `!!radio` `!!ra` | Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: ) | `!!ra radio link here` `!!local` `!!lo` | Queues a local file by specifying a full path. **Bot Owner only.** | `!!lo C:/music/mysong.mp3` -`!!move` `!!mv` | Moves the bot to your voice channel. (works only if music is already playing) | `!!mv` `!!remove` `!!rm` | Remove a song by its # in the queue, or 'all' to remove whole queue. | `!!rm 5` `!!movesong` `!!ms` | Moves a song from one position to another. | `!!ms 5>3` `!!setmaxqueue` `!!smq` | Sets a maximum queue size. Supply 0 or no argument to have no limit. | `!!smq 50` or `!!smq` @@ -226,7 +234,7 @@ Command and aliases | Description | Usage Command and aliases | Description | Usage ----------------|--------------|------- `~hentai` | Shows a hentai image from a random website (gelbooru or danbooru or konachan or atfbooru or yandere) with a given tag. Tag is optional but preferred. Only 1 tag allowed. | `~hentai yuri` -`~autohentai` | Posts a hentai every X seconds with a random tag from the provided tags. Use `|` to separate tags. 20 seconds minimum. Provide no arguments to disable. | `~autohentai 30 yuri|tail|long_hair` or `~autohentai` +`~autohentai` | Posts a hentai every X seconds with a random tag from the provided tags. Use `|` to separate tags. 20 seconds minimum. Provide no arguments to disable. **Requires ManageMessages channel permission.** | `~autohentai 30 yuri|tail|long_hair` or `~autohentai` `~hentaibomb` | Shows a total 5 images (from gelbooru, danbooru, konachan, yandere and atfbooru). Tag is optional but preferred. | `~hentaibomb yuri` `~danbooru` | Shows a random hentai image from danbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~danbooru yuri+kissing` `~yandere` | Shows a random image from yandere with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~yandere tag1+tag2` @@ -249,6 +257,7 @@ Command and aliases | Description | Usage `;chnlfilterwords` `;cfw` | Toggles automatic deleting of messages containing banned words on the channel. Does not negate the ;srvrfilterwords enabled setting. Does not affect bot owner. | `;cfw` `;fw` | Adds or removes (if it exists) a word from the list of filtered words. Use`;sfw` or `;cfw` to toggle filtering. | `;fw poop` `;lstfilterwords` `;lfw` | Shows a list of filtered words. | `;lfw` +`;cmdcosts` | Shows a list of command costs. Paginated with 9 command per page. | `;cmdcosts` or `;cmdcosts 2` `;cmdcooldown` `;cmdcd` | Sets a cooldown per user for a command. Set to 0 to remove the cooldown. | `;cmdcd "some cmd" 5` `;allcmdcooldowns` `;acmdcds` | Shows a list of all commands and their respective cooldowns. | `;acmdcds` `;ubl` | Either [add]s or [rem]oves a user specified by a mention or ID from a blacklist. **Bot Owner only.** | `;ubl add @SomeUser` or `;ubl rem 12312312313` diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index ff1360b5..12071254 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -145,60 +145,60 @@ namespace NadekoBot.Modules.Gambling await Context.Channel.SendErrorAsync($"{Context.User.Mention} was unable to take {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from `{usrId}` because the user doesn't have that much {CurrencyPluralName}!").ConfigureAwait(false); } - [NadekoCommand, Usage, Description, Aliases] - [OwnerOnly] - public Task BrTest(int tests = 1000) - { - var t = Task.Run(async () => - { - if (tests <= 0) - return; - //multi vs how many times it occured - var dict = new Dictionary(); - var generator = new NadekoRandom(); - for (int i = 0; i < tests; i++) - { - var rng = generator.Next(0, 101); - var mult = 0; - if (rng < 67) - { - mult = 0; - } - else if (rng < 91) - { - mult = 2; - } - else if (rng < 100) - { - mult = 4; - } - else - mult = 10; + //[NadekoCommand, Usage, Description, Aliases] + //[OwnerOnly] + //public Task BrTest(int tests = 1000) + //{ + // var t = Task.Run(async () => + // { + // if (tests <= 0) + // return; + // //multi vs how many times it occured + // var dict = new Dictionary(); + // var generator = new NadekoRandom(); + // for (int i = 0; i < tests; i++) + // { + // var rng = generator.Next(0, 101); + // var mult = 0; + // if (rng < 67) + // { + // mult = 0; + // } + // else if (rng < 91) + // { + // mult = 2; + // } + // else if (rng < 100) + // { + // mult = 4; + // } + // else + // mult = 10; - if (dict.ContainsKey(mult)) - dict[mult] += 1; - else - dict.Add(mult, 1); - } + // if (dict.ContainsKey(mult)) + // dict[mult] += 1; + // else + // dict.Add(mult, 1); + // } - var sb = new StringBuilder(); - const int bet = 1; - int payout = 0; - foreach (var key in dict.Keys.OrderByDescending(x => x)) - { - sb.AppendLine($"x{key} occured {dict[key]} times. {dict[key] * 1.0f / tests * 100}%"); - payout += key * dict[key]; - } - try - { - await Context.Channel.SendConfirmAsync("BetRoll Test Results", sb.ToString(), - footer: $"Total Bet: {tests * bet} | Payout: {payout * bet} | {payout * 1.0f / tests * 100}%"); - } - catch { } + // var sb = new StringBuilder(); + // const int bet = 1; + // int payout = 0; + // foreach (var key in dict.Keys.OrderByDescending(x => x)) + // { + // sb.AppendLine($"x{key} occured {dict[key]} times. {dict[key] * 1.0f / tests * 100}%"); + // payout += key * dict[key]; + // } + // try + // { + // await Context.Channel.SendConfirmAsync("BetRoll Test Results", sb.ToString(), + // footer: $"Total Bet: {tests * bet} | Payout: {payout * bet} | {payout * 1.0f / tests * 100}%"); + // } + // catch { } - }); - return Task.CompletedTask; - } + // }); + // return Task.CompletedTask; + //} [NadekoCommand, Usage, Description, Aliases] public async Task BetRoll(long amount) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 7510733e..0f25ceb5 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -2499,7 +2499,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Releases your claim on a specific waifu. You will get a part of your money back unless that waifu has an affinity towards you.. + /// Looks up a localized string similar to Releases your claim on a specific waifu. You will get some of the money you've spent back unless that waifu has an affinity towards you. 6 hours cooldown.. /// public static string divorce_desc { get { @@ -8439,7 +8439,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `{0}claim` on you by 20%. + /// Looks up a localized string similar to Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `{0}claim` on you by 20%. You can leave second argument empty to clear your affinity. 30 minutes cooldown.. /// public static string waifuclaimeraffinity_desc { get { @@ -8448,7 +8448,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}affinity`. + /// Looks up a localized string similar to `{0}affinity @MyHusband` or `{0}affinity`. /// public static string waifuclaimeraffinity_usage { get { @@ -8466,7 +8466,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Shows waifu stats for a target person.. + /// Looks up a localized string similar to Shows waifu stats for a target person. Defaults to you if no user is provided.. /// public static string waifuinfo_desc { get { @@ -8475,7 +8475,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}waifuinfo @MyCrush`. + /// Looks up a localized string similar to `{0}waifuinfo @MyCrush` or `{0}waifuinfo`. /// public static string waifuinfo_usage { get { @@ -8493,7 +8493,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Shows top 10 waifus.. + /// Looks up a localized string similar to Shows top 9 waifus.. /// public static string waifuleaderboard_desc { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 2a0be4b8..2b742f4a 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2983,10 +2983,10 @@ affinity - Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `{0}claim` on you by 20% + Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `{0}claim` on you by 20%. You can leave second argument empty to clear your affinity. 30 minutes cooldown. - `{0}affinity` + `{0}affinity @MyHusband` or `{0}affinity` claimwaifu claim @@ -3001,7 +3001,7 @@ waifus waifulb - Shows top 10 waifus. + Shows top 9 waifus. `{0}waifus` @@ -3010,7 +3010,7 @@ divorce - Releases your claim on a specific waifu. You will get a part of your money back unless that waifu has an affinity towards you. + Releases your claim on a specific waifu. You will get some of the money you've spent back unless that waifu has an affinity towards you. 6 hours cooldown. `{0}divorce @CheatingSloot` @@ -3019,9 +3019,9 @@ waifuinfo waifustats - Shows waifu stats for a target person. + Shows waifu stats for a target person. Defaults to you if no user is provided. - `{0}waifuinfo @MyCrush` + `{0}waifuinfo @MyCrush` or `{0}waifuinfo` \ No newline at end of file diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index 0a170399..cdd6fd8f 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -15,7 +15,7 @@ namespace NadekoBot.Services.Impl private DiscordShardedClient client; private DateTime started; - public const string BotVersion = "1.1.3"; + public const string BotVersion = "1.1.4"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net";