From a7fc482ff7d32eb37024a11d760ec5f55e4454e7 Mon Sep 17 00:00:00 2001 From: samvaio Date: Wed, 28 Dec 2016 21:43:38 +0530 Subject: [PATCH 001/746] Songs Thumbnail fixed --- src/NadekoBot/Modules/Music/Classes/Song.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/Song.cs b/src/NadekoBot/Modules/Music/Classes/Song.cs index c7dfeaf0..4405f4e0 100644 --- a/src/NadekoBot/Modules/Music/Classes/Song.cs +++ b/src/NadekoBot/Modules/Music/Classes/Song.cs @@ -58,7 +58,7 @@ namespace NadekoBot.Modules.Music.Classes private string PrettyTotalTime { get { if (TotalTime == TimeSpan.Zero) - return "(?)"; + return "-"; else if (TotalTime == TimeSpan.MaxValue) return "∞"; else @@ -68,17 +68,18 @@ namespace NadekoBot.Modules.Music.Classes public string Thumbnail { get { - switch (SongInfo.ProviderType) + switch (SongInfo.Provider) { - case MusicType.Radio: + + case "YouTube": //todo have videoid in songinfo from the start var videoId = Regex.Match(SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+"); return $"https://img.youtube.com/vi/{ videoId }/0.jpg"; - case MusicType.Normal: + case "Radio Stream": return $"https://cdn.discordapp.com/attachments/155726317222887425/261850925063340032/1482522097_radio.png"; //test links - case MusicType.Local: + case "Local File": return $"https://cdn.discordapp.com/attachments/155726317222887425/261850914783100928/1482522077_music.png"; //test links - case MusicType.Soundcloud: + case "SoundCloud": return SongInfo.AlbumArt; default: return ""; From 0ef9e356e5fd4957b909ef695b68463500cc1f3f Mon Sep 17 00:00:00 2001 From: samvaio Date: Wed, 28 Dec 2016 21:46:36 +0530 Subject: [PATCH 002/746] Google Search fixed - All searches url now uses shorturl to fix the issue with links having more than 250+ characters - Title, Texts and terms trimmed to fit in embeds --- src/NadekoBot/Modules/Searches/Searches.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 20cd6361..83f55bfe 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -266,7 +266,7 @@ namespace NadekoBot.Modules.Searches var embed = new EmbedBuilder() .WithOkColor() - .WithAuthor(eab => eab.WithName("Search For: " + terms) + .WithAuthor(eab => eab.WithName("Search For: " + terms.TrimTo(50)) .WithUrl(fullQueryLink) .WithIconUrl("http://i.imgur.com/G46fm8J.png")) .WithTitle(umsg.Author.Mention) @@ -274,7 +274,8 @@ namespace NadekoBot.Modules.Searches string desc = ""; foreach (GoogleSearchResult res in results) { - desc += $"[{Format.Bold(res.Title)}]({res.Link})\n{res.Text}\n\n"; + var shortlinks = await NadekoBot.Google.ShortenUrl(res.Link).ConfigureAwait(false); + desc += $"[{Format.Bold(res.Title.TrimTo(70))}]({shortlinks})\n{res.Text.TrimTo(150)}\n\n"; } await channel.EmbedAsync(embed.WithDescription(desc).Build()).ConfigureAwait(false); } From c4354112c625dbf47bba1c886c387f1b6c477204 Mon Sep 17 00:00:00 2001 From: samvaio Date: Thu, 29 Dec 2016 12:04:12 +0530 Subject: [PATCH 003/746] Revert "Google Search fixed" This reverts commit 0ef9e356e5fd4957b909ef695b68463500cc1f3f. --- src/NadekoBot/Modules/Searches/Searches.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 83f55bfe..20cd6361 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -266,7 +266,7 @@ namespace NadekoBot.Modules.Searches var embed = new EmbedBuilder() .WithOkColor() - .WithAuthor(eab => eab.WithName("Search For: " + terms.TrimTo(50)) + .WithAuthor(eab => eab.WithName("Search For: " + terms) .WithUrl(fullQueryLink) .WithIconUrl("http://i.imgur.com/G46fm8J.png")) .WithTitle(umsg.Author.Mention) @@ -274,8 +274,7 @@ namespace NadekoBot.Modules.Searches string desc = ""; foreach (GoogleSearchResult res in results) { - var shortlinks = await NadekoBot.Google.ShortenUrl(res.Link).ConfigureAwait(false); - desc += $"[{Format.Bold(res.Title.TrimTo(70))}]({shortlinks})\n{res.Text.TrimTo(150)}\n\n"; + desc += $"[{Format.Bold(res.Title)}]({res.Link})\n{res.Text}\n\n"; } await channel.EmbedAsync(embed.WithDescription(desc).Build()).ConfigureAwait(false); } From b150bc9a85eeaef37a550a60f8c60d45d7e2829f Mon Sep 17 00:00:00 2001 From: samvaio Date: Thu, 29 Dec 2016 19:18:57 +0530 Subject: [PATCH 004/746] ups --- src/NadekoBot/Modules/Music/Classes/Song.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/Song.cs b/src/NadekoBot/Modules/Music/Classes/Song.cs index 4405f4e0..6a614eec 100644 --- a/src/NadekoBot/Modules/Music/Classes/Song.cs +++ b/src/NadekoBot/Modules/Music/Classes/Song.cs @@ -58,7 +58,7 @@ namespace NadekoBot.Modules.Music.Classes private string PrettyTotalTime { get { if (TotalTime == TimeSpan.Zero) - return "-"; + return "(?)"; else if (TotalTime == TimeSpan.MaxValue) return "∞"; else @@ -68,18 +68,17 @@ namespace NadekoBot.Modules.Music.Classes public string Thumbnail { get { - switch (SongInfo.Provider) + switch (SongInfo.ProviderType) { - - case "YouTube": + case MusicType.Radio: + return $"https://cdn.discordapp.com/attachments/155726317222887425/261850925063340032/1482522097_radio.png"; //test links + case MusicType.Normal: //todo have videoid in songinfo from the start var videoId = Regex.Match(SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+"); return $"https://img.youtube.com/vi/{ videoId }/0.jpg"; - case "Radio Stream": - return $"https://cdn.discordapp.com/attachments/155726317222887425/261850925063340032/1482522097_radio.png"; //test links - case "Local File": + case MusicType.Local: return $"https://cdn.discordapp.com/attachments/155726317222887425/261850914783100928/1482522077_music.png"; //test links - case "SoundCloud": + case MusicType.Soundcloud: return SongInfo.AlbumArt; default: return ""; From a48fdd1fdce01c95261c61352f76ec28b01df4da Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 10 Jan 2017 00:52:25 +0100 Subject: [PATCH 005/746] .repeat, .repinv, .replst, .reprm added/improved --- .../Commands/MessageRepeater.cs | 149 ++++++++++++------ .../Resources/CommandStrings.Designer.cs | 60 ++++++- src/NadekoBot/Resources/CommandStrings.resx | 24 ++- .../Services/Database/Models/GuildConfig.cs | 1 + 4 files changed, 179 insertions(+), 55 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs index 8d50a80e..2e06347a 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs @@ -1,14 +1,18 @@ using Discord; using Discord.Commands; +using Microsoft.EntityFrameworkCore; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; +using NadekoBot.Services.Database; using NadekoBot.Services.Database.Models; using NLog; using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; @@ -19,7 +23,8 @@ namespace NadekoBot.Modules.Administration [Group] public class RepeatCommands : ModuleBase { - public static ConcurrentDictionary repeaters { get; } + //guildid/RepeatRunners + public static ConcurrentDictionary> repeaters { get; } public class RepeatRunner { @@ -83,7 +88,10 @@ namespace NadekoBot.Modules.Administration var sw = Stopwatch.StartNew(); using (var uow = DbHandler.UnitOfWork()) { - repeaters = new ConcurrentDictionary(uow.Repeaters.GetAll().Select(r => new RepeatRunner(r)).Where(r => r != null).ToDictionary(r => r.Repeater.ChannelId)); + repeaters = new ConcurrentDictionary>(NadekoBot.AllGuildConfigs + .ToDictionary(gc => gc.GuildId, + gc => new ConcurrentQueue(gc.GuildRepeaters.Select(gr => new RepeatRunner(gr)) + .Where(gr => gr.Channel != null)))); } sw.Stop(); @@ -93,41 +101,70 @@ namespace NadekoBot.Modules.Administration [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageMessages)] - public async Task RepeatInvoke() + public async Task RepeatInvoke(int index) { - RepeatRunner rep; + index -= 1; + ConcurrentQueue rep; if (!repeaters.TryGetValue(Context.Channel.Id, out rep)) { await Context.Channel.SendErrorAsync("ℹ️ **No repeating message found on this server.**").ConfigureAwait(false); return; } - rep.Reset(); - await Context.Channel.SendMessageAsync("🔄 " + rep.Repeater.Message).ConfigureAwait(false); - } - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.ManageMessages)] - public async Task Repeat() - { - RepeatRunner rep; - if (repeaters.TryRemove(Context.Channel.Id, out rep)) + var repList = rep.ToList(); + + if (index >= repList.Count) { - using (var uow = DbHandler.UnitOfWork()) - { - uow.Repeaters.Remove(rep.Repeater); - await uow.CompleteAsync(); - } - rep.Stop(); - await Context.Channel.SendConfirmAsync("✅ **Stopped repeating a message.**").ConfigureAwait(false); + await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false); + return; } - else - await Context.Channel.SendConfirmAsync("ℹ️ **No message is repeating.**").ConfigureAwait(false); + var repeater = repList[index].Repeater; + + await Context.Channel.SendMessageAsync("🔄 " + repeater.Message).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageMessages)] + [Priority(0)] + public async Task RepeatRemove(int index) + { + if (index < 1) + return; + index -= 1; + + ConcurrentQueue rep; + if (!repeaters.TryGetValue(Context.Guild.Id, out rep)) + return; + + var repeaterList = rep.ToList(); + + if (index >= repeaterList.Count) + { + await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false); + return; + } + + var repeater = repeaterList[index]; + repeater.Stop(); + repeaterList.RemoveAt(index); + + using (var uow = DbHandler.UnitOfWork()) + { + var guildConfig = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(gc => gc.GuildRepeaters)); + + guildConfig.GuildRepeaters.RemoveWhere(r=>r.Id == repeater.Repeater.Id); + await uow.CompleteAsync().ConfigureAwait(false); + } + + if (repeaters.TryUpdate(Context.Guild.Id, new ConcurrentQueue(repeaterList), rep)) + await Context.Channel.SendConfirmAsync("✅ **Stopped repeating a message.**").ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + [Priority(1)] public async Task Repeat(int minutes, [Remainder] string message) { if (minutes < 1 || minutes > 10080) @@ -136,38 +173,52 @@ namespace NadekoBot.Modules.Administration if (string.IsNullOrWhiteSpace(message)) return; - RepeatRunner rep; + var toAdd = new Repeater() + { + ChannelId = Context.Channel.Id, + GuildId = Context.Guild.Id, + Interval = TimeSpan.FromMinutes(minutes), + Message = message + }; - rep = repeaters.AddOrUpdate(Context.Channel.Id, (cid) => + var rep = new RepeatRunner(toAdd, (ITextChannel)Context.Channel); + + repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue(new[] { rep }), (key, old) => { - using (var uow = DbHandler.UnitOfWork()) - { - var localRep = new Repeater - { - ChannelId = Context.Channel.Id, - GuildId = Context.Guild.Id, - Interval = TimeSpan.FromMinutes(minutes), - Message = message, - }; - uow.Repeaters.Add(localRep); - uow.Complete(); - return new RepeatRunner(localRep, (ITextChannel)Context.Channel); - } - }, (cid, old) => - { - using (var uow = DbHandler.UnitOfWork()) - { - old.Repeater.Message = message; - old.Repeater.Interval = TimeSpan.FromMinutes(minutes); - uow.Repeaters.Update(old.Repeater); - uow.Complete(); - } - old.Reset(); + old.Enqueue(rep); return old; }); - + await Context.Channel.SendConfirmAsync($"🔁 Repeating **\"{rep.Repeater.Message}\"** every `{rep.Repeater.Interval.Days} day(s), {rep.Repeater.Interval.Hours} hour(s) and {rep.Repeater.Interval.Minutes} minute(s)`.").ConfigureAwait(false); } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + public async Task RepeatList() + { + ConcurrentQueue repRunners; + if (!repeaters.TryGetValue(Context.Guild.Id, out repRunners)) + { + await Context.Channel.SendConfirmAsync("No repeaters running on this server.").ConfigureAwait(false); + return; + } + + var replist = repRunners.ToList(); + var sb = new StringBuilder(); + + for (int i = 0; i < replist.Count; i++) + { + var rep = replist[i]; + + sb.AppendLine($"`{i + 1}.` {rep.Channel.Mention} | {(int)rep.Repeater.Interval.TotalHours}:{rep.Repeater.Interval:mm} | {rep.Repeater.Message.TrimTo(20)}"); + } + + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle("List Of Repeaters") + .WithDescription(sb.ToString())) + .ConfigureAwait(false); + } } } } diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 58126412..fc8637da 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -5712,7 +5712,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Repeat a message every X minutes. If no parameters are specified, repeat is disabled.. + /// Looks up a localized string similar to Repeat a message every X minutes in the current channel.. /// public static string repeat_desc { get { @@ -5739,7 +5739,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Immediately shows the repeat message and restarts the timer.. + /// Looks up a localized string similar to Immediately shows the repeat message on a certain index and restarts its timer.. /// public static string repeatinvoke_desc { get { @@ -5748,7 +5748,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}repinv`. + /// Looks up a localized string similar to `{0}repinv 1`. /// public static string repeatinvoke_usage { get { @@ -5756,6 +5756,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to repeatlist replst. + /// + public static string repeatlist_cmd { + get { + return ResourceManager.GetString("repeatlist_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows currently repeating messages and their indexes.. + /// + public static string repeatlist_desc { + get { + return ResourceManager.GetString("repeatlist_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}repeatlist`. + /// + public static string repeatlist_usage { + get { + return ResourceManager.GetString("repeatlist_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to rpeatplaylst rpl. /// @@ -5783,6 +5810,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to repeatremove reprm. + /// + public static string repeatremove_cmd { + get { + return ResourceManager.GetString("repeatremove_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes.. + /// + public static string repeatremove_desc { + get { + return ResourceManager.GetString("repeatremove_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}reprm 2`. + /// + public static string repeatremove_usage { + get { + return ResourceManager.GetString("repeatremove_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to reptcursong rcs. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 3b13300e..cc144d2d 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -265,16 +265,16 @@ repeatinvoke repinv - Immediately shows the repeat message and restarts the timer. + Immediately shows the repeat message on a certain index and restarts its timer. - `{0}repinv` + `{0}repinv 1` repeat - Repeat a message every X minutes. If no parameters are specified, repeat is disabled. + Repeat a message every X minutes in the current channel. `{0}repeat 5 Hello there` @@ -2889,4 +2889,22 @@ `{0}pollstats` + + repeatlist replst + + + Shows currently repeating messages and their indexes. + + + `{0}repeatlist` + + + repeatremove reprm + + + Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes. + + + `{0}reprm 2` + \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs index 99608eff..e4ed7c97 100644 --- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs +++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs @@ -58,6 +58,7 @@ namespace NadekoBot.Services.Database.Models public string MuteRoleName { get; set; } public bool CleverbotEnabled { get; set; } + public HashSet GuildRepeaters { get; set; } } public class FilterChannelId : DbEntity From f2df011d636b6c303f4acc6097ba3184e253ae76 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 10 Jan 2017 13:37:35 +0100 Subject: [PATCH 006/746] Migration and fixes for .repeat commands --- .../20170110111159_repeater-drop.Designer.cs | 834 +++++++++++++++++ .../20170110111159_repeater-drop.cs | 40 + .../20170110111302_repeater-new.Designer.cs | 863 ++++++++++++++++++ .../Migrations/20170110111302_repeater-new.cs | 46 + .../NadekoSqliteContextModelSnapshot.cs | 53 +- .../Commands/MessageRepeater.cs | 34 +- .../Services/Database/IUnitOfWork.cs | 1 - .../Services/Database/Models/GuildConfig.cs | 2 +- .../Services/Database/Models/Repeater.cs | 7 +- .../Services/Database/NadekoContext.cs | 12 +- .../Repositories/IRepeaterRepository.cs | 9 - .../Impl/GuildConfigRepository.cs | 1 + .../Repositories/Impl/RepeaterRepository.cs | 12 - src/NadekoBot/Services/Database/UnitOfWork.cs | 3 - 14 files changed, 1848 insertions(+), 69 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170110111159_repeater-drop.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170110111159_repeater-drop.cs create mode 100644 src/NadekoBot/Migrations/20170110111302_repeater-new.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170110111302_repeater-new.cs delete mode 100644 src/NadekoBot/Services/Database/Repositories/IRepeaterRepository.cs delete mode 100644 src/NadekoBot/Services/Database/Repositories/Impl/RepeaterRepository.cs diff --git a/src/NadekoBot/Migrations/20170110111159_repeater-drop.Designer.cs b/src/NadekoBot/Migrations/20170110111159_repeater-drop.Designer.cs new file mode 100644 index 00000000..db95f728 --- /dev/null +++ b/src/NadekoBot/Migrations/20170110111159_repeater-drop.Designer.cs @@ -0,0 +1,834 @@ +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("20170110111159_repeater-drop")] + partial class repeaterdrop + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("ProductVersion", "1.1.0-rtm-22752"); + + 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("BufferSize"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("DMHelpString"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("MigrationVersion"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + 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.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.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.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.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.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/20170110111159_repeater-drop.cs b/src/NadekoBot/Migrations/20170110111159_repeater-drop.cs new file mode 100644 index 00000000..d05e6672 --- /dev/null +++ b/src/NadekoBot/Migrations/20170110111159_repeater-drop.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class repeaterdrop : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Repeaters"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Repeaters", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + ChannelId = table.Column(nullable: false), + GuildId = table.Column(nullable: false), + Interval = table.Column(nullable: false), + Message = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Repeaters", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_Repeaters_ChannelId", + table: "Repeaters", + column: "ChannelId", + unique: true); + } + } +} diff --git a/src/NadekoBot/Migrations/20170110111302_repeater-new.Designer.cs b/src/NadekoBot/Migrations/20170110111302_repeater-new.Designer.cs new file mode 100644 index 00000000..09bee367 --- /dev/null +++ b/src/NadekoBot/Migrations/20170110111302_repeater-new.Designer.cs @@ -0,0 +1,863 @@ +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("20170110111302_repeater-new")] + partial class repeaternew + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("ProductVersion", "1.1.0-rtm-22752"); + + 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("BufferSize"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("DMHelpString"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("MigrationVersion"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + 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.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.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.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/20170110111302_repeater-new.cs b/src/NadekoBot/Migrations/20170110111302_repeater-new.cs new file mode 100644 index 00000000..0decfad8 --- /dev/null +++ b/src/NadekoBot/Migrations/20170110111302_repeater-new.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class repeaternew : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "GuildRepeater", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + ChannelId = table.Column(nullable: false), + GuildConfigId = table.Column(nullable: true), + GuildId = table.Column(nullable: false), + Interval = table.Column(nullable: false), + Message = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_GuildRepeater", x => x.Id); + table.ForeignKey( + name: "FK_GuildRepeater_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_GuildRepeater_GuildConfigId", + table: "GuildRepeater", + column: "GuildConfigId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "GuildRepeater"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index c9b359e1..8038530d 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -2,7 +2,10 @@ 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 { @@ -381,6 +384,28 @@ namespace NadekoBot.Migrations 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") @@ -663,27 +688,6 @@ namespace NadekoBot.Migrations b.ToTable("Reminders"); }); - modelBuilder.Entity("NadekoBot.Services.Database.Models.Repeater", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("ChannelId"); - - b.Property("GuildId"); - - b.Property("Interval"); - - b.Property("Message"); - - b.HasKey("Id"); - - b.HasIndex("ChannelId") - .IsUnique(); - - b.ToTable("Repeaters"); - }); - modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => { b.Property("Id") @@ -790,6 +794,13 @@ namespace NadekoBot.Migrations .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") diff --git a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs index 2e06347a..da737ce4 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs @@ -58,9 +58,9 @@ namespace NadekoBot.Modules.Administration var toSend = "🔄 " + Repeater.Message; await Task.Delay(Repeater.Interval, token).ConfigureAwait(false); - //var lastMsgInChannel = (await Channel.GetMessagesAsync(2)).FirstOrDefault(); - // if (lastMsgInChannel.Id == oldMsg?.Id) //don't send if it's the same message in the channel - // continue; + //var lastMsgInChannel = (await Channel.GetMessagesAsync(2)).FirstOrDefault(); + // if (lastMsgInChannel.Id == oldMsg?.Id) //don't send if it's the same message in the channel + // continue; if (oldMsg != null) try { await oldMsg.DeleteAsync(); } catch { } @@ -80,6 +80,11 @@ namespace NadekoBot.Modules.Administration { source.Cancel(); } + + public override string ToString() + { + return $"{this.Channel.Mention} | {(int)this.Repeater.Interval.TotalHours}:{this.Repeater.Interval:mm} | {this.Repeater.Message.TrimTo(33)}"; + } } static RepeatCommands() @@ -105,7 +110,7 @@ namespace NadekoBot.Modules.Administration { index -= 1; ConcurrentQueue rep; - if (!repeaters.TryGetValue(Context.Channel.Id, out rep)) + if (!repeaters.TryGetValue(Context.Guild.Id, out rep)) { await Context.Channel.SendErrorAsync("ℹ️ **No repeating message found on this server.**").ConfigureAwait(false); return; @@ -153,12 +158,12 @@ namespace NadekoBot.Modules.Administration { var guildConfig = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(gc => gc.GuildRepeaters)); - guildConfig.GuildRepeaters.RemoveWhere(r=>r.Id == repeater.Repeater.Id); + guildConfig.GuildRepeaters.RemoveWhere(r => r.Id == repeater.Repeater.Id); await uow.CompleteAsync().ConfigureAwait(false); } if (repeaters.TryUpdate(Context.Guild.Id, new ConcurrentQueue(repeaterList), rep)) - await Context.Channel.SendConfirmAsync("✅ **Stopped repeating a message.**").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync("Message Repeater",$"#{index+1} stopped.\n\n{repeater.ToString()}").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -173,7 +178,7 @@ namespace NadekoBot.Modules.Administration if (string.IsNullOrWhiteSpace(message)) return; - var toAdd = new Repeater() + var toAdd = new GuildRepeater() { ChannelId = Context.Channel.Id, GuildId = Context.Guild.Id, @@ -181,6 +186,15 @@ namespace NadekoBot.Modules.Administration Message = message }; + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.GuildRepeaters)); + + gc.GuildRepeaters.Add(toAdd); + + await uow.CompleteAsync().ConfigureAwait(false); + } + var rep = new RepeatRunner(toAdd, (ITextChannel)Context.Channel); repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue(new[] { rep }), (key, old) => @@ -188,7 +202,7 @@ namespace NadekoBot.Modules.Administration old.Enqueue(rep); return old; }); - + await Context.Channel.SendConfirmAsync($"🔁 Repeating **\"{rep.Repeater.Message}\"** every `{rep.Repeater.Interval.Days} day(s), {rep.Repeater.Interval.Hours} hour(s) and {rep.Repeater.Interval.Minutes} minute(s)`.").ConfigureAwait(false); } @@ -211,7 +225,7 @@ namespace NadekoBot.Modules.Administration { var rep = replist[i]; - sb.AppendLine($"`{i + 1}.` {rep.Channel.Mention} | {(int)rep.Repeater.Interval.TotalHours}:{rep.Repeater.Interval:mm} | {rep.Repeater.Message.TrimTo(20)}"); + sb.AppendLine($"`{i + 1}.` {rep.ToString()}"); } await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() @@ -221,4 +235,4 @@ namespace NadekoBot.Modules.Administration } } } -} +} \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/IUnitOfWork.cs b/src/NadekoBot/Services/Database/IUnitOfWork.cs index c90d9736..f17e1f6a 100644 --- a/src/NadekoBot/Services/Database/IUnitOfWork.cs +++ b/src/NadekoBot/Services/Database/IUnitOfWork.cs @@ -15,7 +15,6 @@ namespace NadekoBot.Services.Database IReminderRepository Reminders { get; } ISelfAssignedRolesRepository SelfAssignedRoles { get; } IBotConfigRepository BotConfig { get; } - IRepeaterRepository Repeaters { get; } IUnitConverterRepository ConverterUnits { get; } ICustomReactionRepository CustomReactions { get; } ICurrencyRepository Currency { get; } diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs index e4ed7c97..2dc13474 100644 --- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs +++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs @@ -58,7 +58,7 @@ namespace NadekoBot.Services.Database.Models public string MuteRoleName { get; set; } public bool CleverbotEnabled { get; set; } - public HashSet GuildRepeaters { get; set; } + public HashSet GuildRepeaters { get; set; } = new HashSet(); } public class FilterChannelId : DbEntity diff --git a/src/NadekoBot/Services/Database/Models/Repeater.cs b/src/NadekoBot/Services/Database/Models/Repeater.cs index cf887b43..f8c07bfe 100644 --- a/src/NadekoBot/Services/Database/Models/Repeater.cs +++ b/src/NadekoBot/Services/Database/Models/Repeater.cs @@ -2,11 +2,16 @@ namespace NadekoBot.Services.Database.Models { - public class Repeater :DbEntity + public class Repeater : DbEntity { public ulong GuildId { get; set; } public ulong ChannelId { get; set; } public string Message { get; set; } public TimeSpan Interval { get; set; } } + + public class GuildRepeater : Repeater + { + + } } diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index ec7c2288..dcf73c5e 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -16,7 +16,6 @@ namespace NadekoBot.Services.Database public DbSet Reminders { get; set; } public DbSet SelfAssignableRoles { get; set; } public DbSet BotConfig { get; set; } - public DbSet Repeaters { get; set; } public DbSet Currency { get; set; } public DbSet ConversionUnits { get; set; } public DbSet MusicPlaylists { get; set; } @@ -44,6 +43,7 @@ namespace NadekoBot.Services.Database this.Database.Migrate(); EnsureSeedData(); } + ////Uncomment this to db initialisation with dotnet ef migration add [module] //protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) //{ @@ -172,16 +172,6 @@ namespace NadekoBot.Services.Database #endregion - #region Repeater - - var repeaterEntity = modelBuilder.Entity(); - - repeaterEntity - .HasIndex(r => r.ChannelId) - .IsUnique(); - - #endregion - #region Currency var currencyEntity = modelBuilder.Entity(); diff --git a/src/NadekoBot/Services/Database/Repositories/IRepeaterRepository.cs b/src/NadekoBot/Services/Database/Repositories/IRepeaterRepository.cs deleted file mode 100644 index 2446c275..00000000 --- a/src/NadekoBot/Services/Database/Repositories/IRepeaterRepository.cs +++ /dev/null @@ -1,9 +0,0 @@ -using NadekoBot.Services.Database.Models; - -namespace NadekoBot.Services.Database.Repositories -{ - public interface IRepeaterRepository : IRepository - { - - } -} diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index 0720e8ad..b2cce5a0 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -26,6 +26,7 @@ namespace NadekoBot.Services.Database.Repositories.Impl .Include(gc => gc.FilterWordsChannelIds) .Include(gc => gc.FilteredWords) .Include(gc => gc.CommandCooldowns) + .Include(gc => gc.GuildRepeaters) .ToList(); /// diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/RepeaterRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/RepeaterRepository.cs deleted file mode 100644 index 94827f95..00000000 --- a/src/NadekoBot/Services/Database/Repositories/Impl/RepeaterRepository.cs +++ /dev/null @@ -1,12 +0,0 @@ -using NadekoBot.Services.Database.Models; -using Microsoft.EntityFrameworkCore; - -namespace NadekoBot.Services.Database.Repositories.Impl -{ - public class RepeaterRepository : Repository, IRepeaterRepository - { - public RepeaterRepository(DbContext context) : base(context) - { - } - } -} diff --git a/src/NadekoBot/Services/Database/UnitOfWork.cs b/src/NadekoBot/Services/Database/UnitOfWork.cs index 9601145d..88231d6b 100644 --- a/src/NadekoBot/Services/Database/UnitOfWork.cs +++ b/src/NadekoBot/Services/Database/UnitOfWork.cs @@ -30,9 +30,6 @@ namespace NadekoBot.Services.Database private IBotConfigRepository _botConfig; public IBotConfigRepository BotConfig => _botConfig ?? (_botConfig = new BotConfigRepository(_context)); - private IRepeaterRepository _repeaters; - public IRepeaterRepository Repeaters => _repeaters ?? (_repeaters = new RepeaterRepository(_context)); - private ICurrencyRepository _currency; public ICurrencyRepository Currency => _currency ?? (_currency = new CurrencyRepository(_context)); From c705c0494c9a09e9c9cfecd5550da7793152331a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 10 Jan 2017 13:44:26 +0100 Subject: [PATCH 007/746] Commandlist updated --- docs/Commands List.md | 12 +++++++++--- src/NadekoBot/Modules/Music/Music.cs | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index f435ab6d..049143f8 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -31,6 +31,7 @@ Command and aliases | Description | Usage `.leave` | Makes Nadeko leave the server. Either name or id required. **Bot Owner only.** | `.leave 123123123331` `.die` | Shuts the bot down. **Bot Owner only.** | `.die` `.setname` `.newnm` | Gives the bot a new name. **Bot Owner only.** | `.newnm BotName` +`.setstatus` | Sets the bot's status. (Online/Idle/Dnd/Invisible) **Bot Owner only.** | `.setstatus Idle` `.setavatar` `.setav` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner only.** | `.setav http://i.imgur.com/xTG3a1I.jpg` `.setgame` | Sets the bots game. **Bot Owner only.** | `.setgame with snakes` `.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot Owner only.** | `.setstream TWITCHLINK Hello` @@ -56,8 +57,10 @@ Command and aliases | Description | Usage `.voicemute` | Prevents a mentioned user from speaking in voice channels. **Requires MuteMembers server permission.** | `.voicemute @Someone` `.voiceunmute` | Gives a previously voice-muted user a permission to speak. **Requires MuteMembers server permission.** | `.voiceunmute @Someguy` `.migratedata` | Migrate data from old bot configuration **Bot Owner only.** | `.migratedata` -`.repeatinvoke` `.repinv` | Immediately shows the repeat message and restarts the timer. **Requires ManageMessages server permission.** | `.repinv` -`.repeat` | Repeat a message every X minutes. If no parameters are specified, repeat is disabled. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` +`.repeatinvoke` `.repinv` | Immediately shows the repeat message on a certain index and restarts its timer. **Requires ManageMessages server permission.** | `.repinv 1` +`.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2` +`.repeat` | Repeat a message every X minutes in the current channel. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` +`.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist` `.logserver` | Enables or Disables ALL log events. If enabled, all log events will log to this channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logserver enable` or `.logserver disable` `.logignore` | Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logignore` `.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot Owner only.** | `.logevents` @@ -160,13 +163,14 @@ Command and aliases | Description | Usage `>typedel` | Deletes a typing article given the ID. **Bot Owner only.** | `>typedel 3` `>poll` | Creates a poll which requires users to send the number of the voting option to the bot. **Requires ManageMessages server permission.** | `>poll Question?;Answer1;Answ 2;A_3` `>publicpoll` `>ppoll` | Creates a public poll which requires users to type a number of the voting option in the channel command is ran in. **Requires ManageMessages server permission.** | `>ppoll Question?;Answer1;Answ 2;A_3` +`>pollstats` | Shows the poll results without stopping the poll on this server. **Requires ManageMessages server permission.** | `>pollstats` `>pollend` | Stops active poll on this server and prints the results in this channel. **Requires ManageMessages server permission.** | `>pollend` `>pick` | Picks the currency planted in this channel. 60 seconds cooldown. | `>pick` `>plant` | Spend a unit of currency to plant it in this channel. (If bot is restarted or crashes, the currency will be lost) | `>plant` `>gencurrency` `>gc` | Toggles currency generation on this channel. Every posted message will have chance to spawn currency. Chance is specified by the Bot Owner. (default is 2%) **Requires ManageMessages server permission.** | `>gc` `>hangmanlist` | Shows a list of hangman term types. | `> hangmanlist` `>hangman` | Starts a game of hangman in the channel. Use `>hangmanlist` to see a list of available term types. Defaults to 'all'. | `>hangman` or `>hangman movies` -`>cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. **Requires ManageMessages channel permission.** | `>cleverbot` +`>cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. **Requires ManageMessages server permission.** | `>cleverbot` `>acrophobia` `>acro` | Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60) | `>acro` or `>acro 30` `>choose` | Chooses a thing from a list of things | `>choose Get up;Sleep;Sleep more` `>8ball` | Ask the 8ball a yes/no question. | `>8ball should I do something` @@ -366,6 +370,7 @@ Command and aliases | Description | Usage `.userinfo` `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | `.uinfo @SomeUser` `.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1` `.calcops` | Shows all available operations in .calc command | `.calcops` +`.rotaterolecolor` `.rrc` | Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. **Bot Owner only.** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole` `.togethertube` `.totube` | Creates a new room on and shows the link in the chat. | `.totube` `.whosplaying` `.whpl` | Shows a list of users who are playing the specified game. | `.whpl Overwatch` `.inrole` | Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission. | `.inrole Role` @@ -375,6 +380,7 @@ Command and aliases | Description | Usage `.serverid` `.sid` | Shows current server ID. | `.sid` `.roles` | List roles on this server or a roles of a specific user if specified. Paginated. 20 roles per page. | `.roles 2` or `.roles @Someone` `.channeltopic` `.ct` | Sends current channel's topic as a message. | `.ct` +`.createinvite` `.crinv` | Creates a new invite which has infinite max uses and never expires. **Requires CreateInstantInvite channel permission.** | `.crinv` `.stats` | Shows some basic stats for Nadeko. | `.stats` `.showemojis` `.se` | Shows a name and a link to every SPECIAL emoji in the message. | `.se A message full of SPECIAL emojis` `.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot Owner only.** | `.listservers 3` diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 536a00ae..3ffb104c 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -300,7 +300,7 @@ $"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {(int)total.TotalHours}h {tota return; if (((IGuildUser)Context.User).VoiceChannel?.Guild != Context.Guild) { - await Context.Channel.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 it.").ConfigureAwait(false); + await Context.Channel.SendErrorAsync($"💢 You need to be in a **voice channel** on this server.").ConfigureAwait(false); return; } var plId = (await NadekoBot.Google.GetPlaylistIdsByKeywordsAsync(arg).ConfigureAwait(false)).FirstOrDefault(); From 74d05a54a90585ce42dc3309510ff9f6c474010e Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 10 Jan 2017 20:17:53 +0100 Subject: [PATCH 008/746] .prune fix (now will delete 1 more message than before) --- src/NadekoBot/Modules/Administration/Administration.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 5b97b69a..e0a9bf0b 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -460,6 +460,9 @@ namespace NadekoBot.Modules.Administration [RequireUserPermission(ChannelPermission.ManageMessages)] public async Task Prune(int count) { + if (count < 1) + return; + count += 1; await Context.Message.DeleteAsync().ConfigureAwait(false); int limit = (count < 100) ? count : 100; var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten().ConfigureAwait(false)); @@ -472,6 +475,11 @@ namespace NadekoBot.Modules.Administration [RequireUserPermission(ChannelPermission.ManageMessages)] public async Task Prune(IGuildUser user, int count = 100) { + if (count < 1) + return; + + if (user.Id == Context.User.Id) + count += 1; int limit = (count < 100) ? count : 100; var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten()).Where(m => m.Author == user); From 27b0d9fe36f15aa7db45b6f1f7c6a8ea4bcc4939 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 10 Jan 2017 20:37:17 +0100 Subject: [PATCH 009/746] Cleverbot fix --- src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs b/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs index 7b952b1c..08269207 100644 --- a/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs +++ b/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs @@ -30,9 +30,9 @@ namespace Services.CleverBotApi public static ChatterBot Create(ChatterBotType type, object arg) { #if GLOBAL_NADEKO - var url = "http://www.cleverbot.com/webservicemin?uc=321&botapi=nadekobot"; + var url = "http://www.cleverbot.com/webservicemin?uc=3210&botapi=nadekobot"; #else - var url = "http://www.cleverbot.com/webservicemin?uc=321"; + var url = "http://www.cleverbot.com/webservicemin?uc=3210"; #endif switch (type) From d848ef627076b6efede4ca506a185ae9a20c38b0 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 10 Jan 2017 20:37:41 +0100 Subject: [PATCH 010/746] .antiraid .antispam .antilist .antispamignore added/improved --- .../NadekoSqliteContextModelSnapshot.cs | 79 +++++ .../Commands/AntiRaidCommands.cs | 272 ------------------ .../Commands/MessageRepeater.cs | 12 +- .../Resources/CommandStrings.Designer.cs | 54 ++++ src/NadekoBot/Resources/CommandStrings.resx | 18 ++ .../Services/Database/Models/GuildConfig.cs | 6 + .../Services/Database/NadekoContext.cs | 16 ++ .../Impl/GuildConfigRepository.cs | 3 + 8 files changed, 181 insertions(+), 279 deletions(-) delete mode 100644 src/NadekoBot/Modules/Administration/Commands/AntiRaidCommands.cs diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 8038530d..190e425e 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -17,6 +17,62 @@ namespace NadekoBot.Migrations 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") @@ -722,6 +778,29 @@ namespace NadekoBot.Migrations 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") diff --git a/src/NadekoBot/Modules/Administration/Commands/AntiRaidCommands.cs b/src/NadekoBot/Modules/Administration/Commands/AntiRaidCommands.cs deleted file mode 100644 index 4551ef48..00000000 --- a/src/NadekoBot/Modules/Administration/Commands/AntiRaidCommands.cs +++ /dev/null @@ -1,272 +0,0 @@ -using Discord; -using Discord.Commands; -using NadekoBot.Attributes; -using NadekoBot.Extensions; -using NLog; -using System; -using System.Collections.Concurrent; -using System.Linq; -using System.Threading.Tasks; - -namespace NadekoBot.Modules.Administration -{ - public partial class Administration - { - public enum PunishmentAction - { - Mute, - Kick, - Ban, - } - - public enum ProtectionType - { - Raiding, - Spamming, - } - - private class AntiRaidSetting - { - public int UserThreshold { get; set; } - public int Seconds { get; set; } - public PunishmentAction Action { get; set; } - public int UsersCount { get; set; } - public ConcurrentHashSet RaidUsers { get; set; } = new ConcurrentHashSet(); - } - - private class AntiSpamSetting - { - public PunishmentAction Action { get; set; } - public int MessageThreshold { get; set; } = 3; - public ConcurrentDictionary UserStats { get; set; } - = new ConcurrentDictionary(); - } - - private class UserSpamStats - { - public int Count { get; set; } - public string LastMessage { get; set; } - - public UserSpamStats(string msg) - { - Count = 1; - LastMessage = msg.ToUpperInvariant(); - } - - public void ApplyNextMessage(string message) - { - var upperMsg = message.ToUpperInvariant(); - if (upperMsg == LastMessage) - Count++; - else - { - LastMessage = upperMsg; - Count = 0; - } - } - } - - [Group] - public class AntiRaidCommands : ModuleBase - { - private static ConcurrentDictionary antiRaidGuilds = - new ConcurrentDictionary(); - // guildId | (userId|messages) - private static ConcurrentDictionary antiSpamGuilds = - new ConcurrentDictionary(); - - private static Logger _log { get; } - - static AntiRaidCommands() - { - _log = LogManager.GetCurrentClassLogger(); - - NadekoBot.Client.MessageReceived += async (imsg) => - { - - try - { - var msg = imsg as IUserMessage; - if (msg == null || msg.Author.IsBot) - return; - - var channel = msg.Channel as ITextChannel; - if (channel == null) - return; - AntiSpamSetting spamSettings; - if (!antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings)) - return; - - var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, new UserSpamStats(msg.Content), - (id, old) => { old.ApplyNextMessage(msg.Content); return old; }); - - if (stats.Count >= spamSettings.MessageThreshold) - { - if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats)) - { - await PunishUsers(spamSettings.Action, ProtectionType.Spamming, (IGuildUser)msg.Author) - .ConfigureAwait(false); - } - } - } - catch { } - }; - - NadekoBot.Client.UserJoined += async (usr) => - { - try - { - if (usr.IsBot) - return; - AntiRaidSetting settings; - if (!antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings)) - return; - if (!settings.RaidUsers.Add(usr)) - return; - - ++settings.UsersCount; - - if (settings.UsersCount >= settings.UserThreshold) - { - var users = settings.RaidUsers.ToArray(); - settings.RaidUsers.Clear(); - - await PunishUsers(settings.Action, ProtectionType.Raiding, users).ConfigureAwait(false); - } - await Task.Delay(1000 * settings.Seconds).ConfigureAwait(false); - - settings.RaidUsers.TryRemove(usr); - --settings.UsersCount; - - } - catch { } - }; - } - - private static async Task PunishUsers(PunishmentAction action, ProtectionType pt, params IGuildUser[] gus) - { - foreach (var gu in gus) - { - switch (action) - { - case PunishmentAction.Mute: - try - { - await MuteCommands.MuteUser(gu).ConfigureAwait(false); - } - catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); } - break; - case PunishmentAction.Kick: - try - { - await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false); - try - { - await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false); - } - catch - { - await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false); - // try it twice, really don't want to ban user if - // only kick has been specified as the punishement - } - } - catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); } - break; - case PunishmentAction.Ban: - try - { - await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false); - } - catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); } - break; - default: - break; - } - } - await LogCommands.TriggeredAntiProtection(gus, action, pt).ConfigureAwait(false); - } - - - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.Administrator)] - public async Task AntiRaid(int userThreshold, int seconds, PunishmentAction action) - { - if (userThreshold < 2 || userThreshold > 30) - { - await Context.Channel.SendErrorAsync("❗️User threshold must be between **2** and **30**.").ConfigureAwait(false); - return; - } - - if (seconds < 2 || seconds > 300) - { - await Context.Channel.SendErrorAsync("❗️Time must be between **2** and **300** seconds.").ConfigureAwait(false); - return; - } - - try - { - await MuteCommands.GetMuteRole(Context.Guild).ConfigureAwait(false); - } - catch (Exception ex) - { - await Context.Channel.SendConfirmAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" + - "or create 'nadeko-mute' role with disabled SendMessages and try again.") - .ConfigureAwait(false); - _log.Warn(ex); - return; - } - - var setting = new AntiRaidSetting() - { - Action = action, - Seconds = seconds, - UserThreshold = userThreshold, - }; - antiRaidGuilds.AddOrUpdate(Context.Guild.Id, setting, (id, old) => setting); - - await Context.Channel.SendConfirmAsync($"ℹ️ {Context.User.Mention} If **{userThreshold}** or more users join within **{seconds}** seconds, I will **{action}** them.") - .ConfigureAwait(false); - } - - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.Administrator)] - public async Task AntiSpam(int messageCount=3, PunishmentAction action = PunishmentAction.Mute) - { - if (messageCount < 2 || messageCount > 10) - return; - - AntiSpamSetting throwaway; - if (antiSpamGuilds.TryRemove(Context.Guild.Id, out throwaway)) - { - await Context.Channel.SendConfirmAsync("🆗 **Anti-Spam feature** has been **disabled** on this server.").ConfigureAwait(false); - } - else - { - try - { - await MuteCommands.GetMuteRole(Context.Guild).ConfigureAwait(false); - } - catch (Exception ex) - { - await Context.Channel.SendErrorAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" + - "or create 'nadeko-mute' role with disabled SendMessages and try again.") - .ConfigureAwait(false); - _log.Warn(ex); - return; - } - - if (antiSpamGuilds.TryAdd(Context.Guild.Id, new AntiSpamSetting() - { - Action = action, - MessageThreshold = messageCount, - })) - await Context.Channel.SendConfirmAsync("✅ **Anti-Spam feature** has been **enabled** on this server.").ConfigureAwait(false); - } - - } - } - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs index da737ce4..2bbe9805 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs @@ -91,13 +91,11 @@ namespace NadekoBot.Modules.Administration { var _log = LogManager.GetCurrentClassLogger(); var sw = Stopwatch.StartNew(); - using (var uow = DbHandler.UnitOfWork()) - { - repeaters = new ConcurrentDictionary>(NadekoBot.AllGuildConfigs - .ToDictionary(gc => gc.GuildId, - gc => new ConcurrentQueue(gc.GuildRepeaters.Select(gr => new RepeatRunner(gr)) - .Where(gr => gr.Channel != null)))); - } + + repeaters = new ConcurrentDictionary>(NadekoBot.AllGuildConfigs + .ToDictionary(gc => gc.GuildId, + gc => new ConcurrentQueue(gc.GuildRepeaters.Select(gr => new RepeatRunner(gr)) + .Where(gr => gr.Channel != null)))); sw.Stop(); _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index fc8637da..eb72d8f1 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -437,6 +437,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to antilist antilst. + /// + public static string antilist_cmd { + get { + return ResourceManager.GetString("antilist_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows currently enabled protection features.. + /// + public static string antilist_desc { + get { + return ResourceManager.GetString("antilist_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}antilist`. + /// + public static string antilist_usage { + get { + return ResourceManager.GetString("antilist_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to antiraid. /// @@ -491,6 +518,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to antispamignore. + /// + public static string antispamignore_cmd { + get { + return ResourceManager.GetString("antispamignore_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Toggles whether antispam ignores current channel. Antispam must be enabled.. + /// + public static string antispamignore_desc { + get { + return ResourceManager.GetString("antispamignore_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}antispamignore`. + /// + public static string antispamignore_usage { + get { + return ResourceManager.GetString("antispamignore_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to asar. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index cc144d2d..d96b1c3f 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2907,4 +2907,22 @@ `{0}reprm 2` + + antilist antilst + + + Shows currently enabled protection features. + + + `{0}antilist` + + + antispamignore + + + Toggles whether antispam ignores current channel. Antispam must be enabled. + + + `{0}antispamignore` + \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs index 2dc13474..7931e8c9 100644 --- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs +++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using static NadekoBot.Modules.Administration.Administration; namespace NadekoBot.Services.Database.Models { @@ -59,6 +60,11 @@ namespace NadekoBot.Services.Database.Models public string MuteRoleName { get; set; } public bool CleverbotEnabled { get; set; } public HashSet GuildRepeaters { get; set; } = new HashSet(); + + public AntiRaidSetting AntiRaidSetting { get; set; } + public AntiSpamSetting AntiSpamSetting { get; set; } + + //public List ProtectionIgnoredChannels { get; set; } = new List(); } public class FilterChannelId : DbEntity diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index dcf73c5e..e955409f 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -142,6 +142,17 @@ namespace NadekoBot.Services.Database .HasIndex(c => c.GuildId) .IsUnique(); + modelBuilder.Entity() + .HasOne(x => x.GuildConfig) + .WithOne(x => x.AntiSpamSetting); + + modelBuilder.Entity() + .HasOne(x => x.GuildConfig) + .WithOne(x => x.AntiRaidSetting); + + //modelBuilder.Entity() + // .HasAlternateKey(c => new { c.ChannelId, c.ProtectionType }); + #endregion #region BotConfig @@ -221,6 +232,11 @@ namespace NadekoBot.Services.Database .IsUnique(); + #endregion + + #region Protection + + #endregion } } diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index b2cce5a0..89c59419 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -27,6 +27,9 @@ namespace NadekoBot.Services.Database.Repositories.Impl .Include(gc => gc.FilteredWords) .Include(gc => gc.CommandCooldowns) .Include(gc => gc.GuildRepeaters) + .Include(gc => gc.AntiRaidSetting) + .Include(gc => gc.AntiSpamSetting) + .ThenInclude(x => x.IgnoredChannels) .ToList(); /// From ef688d096b427fb860df08a4ed80970265433841 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 10 Jan 2017 20:40:52 +0100 Subject: [PATCH 011/746] Woopsie --- .../20170110180534_protection.Designer.cs | 942 ++++++++++++++++++ .../Migrations/20170110180534_protection.cs | 104 ++ .../Commands/ProtectionCommands.cs | 425 ++++++++ .../Database/Models/AntiProtection.cs | 53 + 4 files changed, 1524 insertions(+) create mode 100644 src/NadekoBot/Migrations/20170110180534_protection.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170110180534_protection.cs create mode 100644 src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs create mode 100644 src/NadekoBot/Services/Database/Models/AntiProtection.cs diff --git a/src/NadekoBot/Migrations/20170110180534_protection.Designer.cs b/src/NadekoBot/Migrations/20170110180534_protection.Designer.cs new file mode 100644 index 00000000..ecc134cd --- /dev/null +++ b/src/NadekoBot/Migrations/20170110180534_protection.Designer.cs @@ -0,0 +1,942 @@ +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("20170110180534_protection")] + partial class protection + { + 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("BufferSize"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("DMHelpString"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("MigrationVersion"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + 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.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.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/20170110180534_protection.cs b/src/NadekoBot/Migrations/20170110180534_protection.cs new file mode 100644 index 00000000..fca7f541 --- /dev/null +++ b/src/NadekoBot/Migrations/20170110180534_protection.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class protection : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AntiRaidSetting", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Action = table.Column(nullable: false), + GuildConfigId = table.Column(nullable: false), + Seconds = table.Column(nullable: false), + UserThreshold = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AntiRaidSetting", x => x.Id); + table.ForeignKey( + name: "FK_AntiRaidSetting_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "AntiSpamSetting", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Action = table.Column(nullable: false), + GuildConfigId = table.Column(nullable: false), + MessageThreshold = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AntiSpamSetting", x => x.Id); + table.ForeignKey( + name: "FK_AntiSpamSetting_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "AntiSpamIgnore", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AntiSpamSettingId = table.Column(nullable: true), + ChannelId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AntiSpamIgnore", x => x.Id); + table.ForeignKey( + name: "FK_AntiSpamIgnore_AntiSpamSetting_AntiSpamSettingId", + column: x => x.AntiSpamSettingId, + principalTable: "AntiSpamSetting", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_AntiRaidSetting_GuildConfigId", + table: "AntiRaidSetting", + column: "GuildConfigId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AntiSpamIgnore_AntiSpamSettingId", + table: "AntiSpamIgnore", + column: "AntiSpamSettingId"); + + migrationBuilder.CreateIndex( + name: "IX_AntiSpamSetting_GuildConfigId", + table: "AntiSpamSetting", + column: "GuildConfigId", + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AntiRaidSetting"); + + migrationBuilder.DropTable( + name: "AntiSpamIgnore"); + + migrationBuilder.DropTable( + name: "AntiSpamSetting"); + } + } +} diff --git a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs new file mode 100644 index 00000000..e37f4850 --- /dev/null +++ b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs @@ -0,0 +1,425 @@ +using Discord; +using Discord.Commands; +using Microsoft.EntityFrameworkCore; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Services; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NLog; +using System; +using System.Collections.Concurrent; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Administration +{ + public partial class Administration + { + public enum ProtectionType + { + Raiding, + Spamming, + } + + public class AntiRaidStats + { + public AntiRaidSetting AntiRaidSettings { get; set; } + public int UsersCount { get; set; } = 0; + public ConcurrentHashSet RaidUsers { get; set; } = new ConcurrentHashSet(); + + public override string ToString() => + $"If **{AntiRaidSettings.UserThreshold}** or more users join within **{AntiRaidSettings.Seconds}** seconds," + + $" I will **{AntiRaidSettings.Action}** them."; + } + + public class AntiSpamStats + { + public AntiSpamSetting AntiSpamSettings { get; set; } + public ConcurrentDictionary UserStats { get; set; } + = new ConcurrentDictionary(); + + public override string ToString() + { + var ignoredString = string.Join(", ", AntiSpamSettings.IgnoredChannels.Select(c => $"<#{c.ChannelId}>")); + + if (string.IsNullOrWhiteSpace(ignoredString)) + ignoredString = "none"; + return $"If a user posts **{AntiSpamSettings.MessageThreshold}** same messages in a row, I will **{AntiSpamSettings.Action}** them." + + $"\n\t__IgnoredChannels__: {ignoredString}"; + } + } + + public class UserSpamStats + { + public int Count { get; set; } + public string LastMessage { get; set; } + + public UserSpamStats(string msg) + { + Count = 1; + LastMessage = msg.ToUpperInvariant(); + } + + public void ApplyNextMessage(string message) + { + var upperMsg = message.ToUpperInvariant(); + if (upperMsg == LastMessage) + Count++; + else + { + LastMessage = upperMsg; + Count = 0; + } + } + } + + [Group] + public class ProtectionCommands : ModuleBase + { + private static ConcurrentDictionary antiRaidGuilds = + new ConcurrentDictionary(); + // guildId | (userId|messages) + private static ConcurrentDictionary antiSpamGuilds = + new ConcurrentDictionary(); + + private static Logger _log { get; } + + static ProtectionCommands() + { + _log = LogManager.GetCurrentClassLogger(); + + foreach (var gc in NadekoBot.AllGuildConfigs) + { + var raid = gc.AntiRaidSetting; + var spam = gc.AntiSpamSetting; + + if (raid != null) + { + var raidStats = new AntiRaidStats() { AntiRaidSettings = raid }; + antiRaidGuilds.TryAdd(gc.GuildId, raidStats); + } + + if (spam != null) + antiSpamGuilds.TryAdd(gc.GuildId, new AntiSpamStats() { AntiSpamSettings = spam }); + } + + NadekoBot.Client.MessageReceived += async (imsg) => + { + + try + { + var msg = imsg as IUserMessage; + if (msg == null || msg.Author.IsBot) + return; + + var channel = msg.Channel as ITextChannel; + if (channel == null) + return; + AntiSpamStats spamSettings; + if (!antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings) || + spamSettings.AntiSpamSettings.IgnoredChannels.Contains(new AntiSpamIgnore() + { + ChannelId = channel.Id + })) + return; + + var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, new UserSpamStats(msg.Content), + (id, old) => { old.ApplyNextMessage(msg.Content); return old; }); + + if (stats.Count >= spamSettings.AntiSpamSettings.MessageThreshold) + { + if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats)) + { + await PunishUsers(spamSettings.AntiSpamSettings.Action, ProtectionType.Spamming, (IGuildUser)msg.Author) + .ConfigureAwait(false); + } + } + } + catch { } + }; + + NadekoBot.Client.UserJoined += async (usr) => + { + try + { + if (usr.IsBot) + return; + AntiRaidStats settings; + if (!antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings)) + return; + if (!settings.RaidUsers.Add(usr)) + return; + + ++settings.UsersCount; + + if (settings.UsersCount >= settings.AntiRaidSettings.UserThreshold) + { + var users = settings.RaidUsers.ToArray(); + settings.RaidUsers.Clear(); + + await PunishUsers(settings.AntiRaidSettings.Action, ProtectionType.Raiding, users).ConfigureAwait(false); + } + await Task.Delay(1000 * settings.AntiRaidSettings.Seconds).ConfigureAwait(false); + + settings.RaidUsers.TryRemove(usr); + --settings.UsersCount; + + } + catch { } + }; + } + + private static async Task PunishUsers(PunishmentAction action, ProtectionType pt, params IGuildUser[] gus) + { + foreach (var gu in gus) + { + switch (action) + { + case PunishmentAction.Mute: + try + { + await MuteCommands.MuteUser(gu).ConfigureAwait(false); + } + catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); } + break; + case PunishmentAction.Kick: + try + { + await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false); + try + { + await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false); + } + catch + { + await gu.Guild.RemoveBanAsync(gu).ConfigureAwait(false); + // try it twice, really don't want to ban user if + // only kick has been specified as the punishement + } + } + catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); } + break; + case PunishmentAction.Ban: + try + { + await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false); + } + catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); } + break; + default: + break; + } + } + await LogCommands.TriggeredAntiProtection(gus, action, pt).ConfigureAwait(false); + } + + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.Administrator)] + public async Task AntiRaid(int userThreshold = 5, int seconds = 10, PunishmentAction action = PunishmentAction.Mute) + { + if (userThreshold < 2 || userThreshold > 30) + { + await Context.Channel.SendErrorAsync("❗️User threshold must be between **2** and **30**.").ConfigureAwait(false); + return; + } + + if (seconds < 2 || seconds > 300) + { + await Context.Channel.SendErrorAsync("❗️Time must be between **2** and **300** seconds.").ConfigureAwait(false); + return; + } + + AntiRaidStats throwaway; + if (antiRaidGuilds.TryRemove(Context.Guild.Id, out throwaway)) + { + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiRaidSetting)); + + gc.AntiRaidSetting = null; + await uow.CompleteAsync().ConfigureAwait(false); + } + await Context.Channel.SendConfirmAsync("**Anti-Raid** feature has been **disabled** on this server.").ConfigureAwait(false); + return; + } + + try + { + await MuteCommands.GetMuteRole(Context.Guild).ConfigureAwait(false); + } + catch (Exception ex) + { + await Context.Channel.SendConfirmAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" + + "or create 'nadeko-mute' role with disabled SendMessages and try again.") + .ConfigureAwait(false); + _log.Warn(ex); + return; + } + + var stats = new AntiRaidStats() + { + AntiRaidSettings = new AntiRaidSetting() + { + Action = action, + Seconds = seconds, + UserThreshold = userThreshold, + } + }; + + antiRaidGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats); + + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiRaidSetting)); + + gc.AntiRaidSetting = stats.AntiRaidSettings; + await uow.CompleteAsync().ConfigureAwait(false); + } + + await Context.Channel.SendConfirmAsync("Anti-Raid Enabled", $"{Context.User.Mention} {stats.ToString()}") + .ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.Administrator)] + public async Task AntiSpam(int messageCount = 3, PunishmentAction action = PunishmentAction.Mute) + { + if (messageCount < 2 || messageCount > 10) + return; + + AntiSpamStats throwaway; + if (antiSpamGuilds.TryRemove(Context.Guild.Id, out throwaway)) + { + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting) + .ThenInclude(x => x.IgnoredChannels)); + + gc.AntiSpamSetting = null; + await uow.CompleteAsync().ConfigureAwait(false); + } + await Context.Channel.SendConfirmAsync("**Anti-Spam** has been **disabled** on this server.").ConfigureAwait(false); + return; + } + + try + { + await MuteCommands.GetMuteRole(Context.Guild).ConfigureAwait(false); + } + catch (Exception ex) + { + await Context.Channel.SendErrorAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" + + "or create 'nadeko-mute' role with disabled SendMessages and try again.") + .ConfigureAwait(false); + _log.Warn(ex); + return; + } + + var stats = new AntiSpamStats + { + AntiSpamSettings = new AntiSpamSetting() + { + Action = action, + MessageThreshold = messageCount, + } + }; + + antiSpamGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats); + + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting)); + + gc.AntiSpamSetting = stats.AntiSpamSettings; + await uow.CompleteAsync().ConfigureAwait(false); + } + + await Context.Channel.SendConfirmAsync("Anti-Spam Enabled", $"{Context.User.Mention} {stats.ToString()}").ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task AntispamIgnore() + { + var channel = (ITextChannel)Context.Channel; + + var obj = new AntiSpamIgnore() + { + ChannelId = channel.Id + }; + bool added; + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.AntiSpamSetting).ThenInclude(x => x.IgnoredChannels)); + var spam = gc.AntiSpamSetting; + if (spam == null) + { + return; + } + + if (spam.IgnoredChannels.Add(obj)) + { + AntiSpamStats temp; + if (antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp)) + temp.AntiSpamSettings.IgnoredChannels.Add(obj); + added = true; + } + else + { + spam.IgnoredChannels.Remove(obj); + AntiSpamStats temp; + if (antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp)) + temp.AntiSpamSettings.IgnoredChannels.Remove(obj); + added = false; + } + + await uow.CompleteAsync().ConfigureAwait(false); + } + if (added) + await Context.Channel.SendConfirmAsync("Anti-Spam will ignore this channel.").ConfigureAwait(false); + else + await Context.Channel.SendConfirmAsync("Anti-Spam will no longer ignore this channel.").ConfigureAwait(false); + + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task AntiList() + { + var channel = (ITextChannel)Context.Channel; + + AntiSpamStats spam; + antiSpamGuilds.TryGetValue(Context.Guild.Id, out spam); + + AntiRaidStats raid; + antiRaidGuilds.TryGetValue(Context.Guild.Id, out raid); + + if (spam == null && raid == null) + { + await Context.Channel.SendConfirmAsync("No protections enabled."); + return; + } + + var embed = new EmbedBuilder().WithOkColor() + .WithTitle("Protections Enabled"); + + if (spam != null) + embed.AddField(efb => efb.WithName("Anti-Spam") + .WithValue(spam.ToString()) + .WithIsInline(true)); + + if (raid != null) + embed.AddField(efb => efb.WithName("Anti-Raid") + .WithValue(raid.ToString()) + .WithIsInline(true)); + + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/Models/AntiProtection.cs b/src/NadekoBot/Services/Database/Models/AntiProtection.cs new file mode 100644 index 00000000..0172dd90 --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/AntiProtection.cs @@ -0,0 +1,53 @@ +using Discord; +using NadekoBot.Services.Database.Models; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +namespace NadekoBot.Services.Database.Models +{ + public class AntiRaidSetting : DbEntity + { + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + public int UserThreshold { get; set; } + public int Seconds { get; set; } + public PunishmentAction Action { get; set; } + } + + public class AntiSpamSetting : DbEntity + { + public int GuildConfigId { get; set; } + public GuildConfig GuildConfig { get; set; } + + public PunishmentAction Action { get; set; } + public int MessageThreshold { get; set; } = 3; + public HashSet IgnoredChannels { get; set; } = new HashSet(); + } + + + public enum PunishmentAction + { + Mute, + Kick, + Ban, + } + + public class AntiSpamIgnore : DbEntity + { + public ulong ChannelId { get; set; } + + public override int GetHashCode() => ChannelId.GetHashCode(); + + public override bool Equals(object obj) + { + var inst = obj as AntiSpamIgnore; + + if (inst == null) + return false; + + return inst.ChannelId == ChannelId; + + } + } +} \ No newline at end of file From d7dc7bf3fb3c2a39fa0b2dbf87b7924dc49e0f41 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 10 Jan 2017 23:12:52 +0100 Subject: [PATCH 012/746] Up to 5 repeaters. --- .../Modules/Administration/Commands/MessageRepeater.cs | 2 ++ src/NadekoBot/Resources/CommandStrings.Designer.cs | 2 +- src/NadekoBot/Resources/CommandStrings.resx | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs index 2bbe9805..34281838 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs @@ -188,6 +188,8 @@ namespace NadekoBot.Modules.Administration { var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.GuildRepeaters)); + if (gc.GuildRepeaters.Count >= 5) + return; gc.GuildRepeaters.Add(toAdd); await uow.CompleteAsync().ConfigureAwait(false); diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index eb72d8f1..e58dbbbb 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -5766,7 +5766,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Repeat a message every X minutes in the current channel.. + /// Looks up a localized string similar to Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total.. /// public static string repeat_desc { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index d96b1c3f..d2ef3388 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -274,7 +274,7 @@ repeat - Repeat a message every X minutes in the current channel. + Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. `{0}repeat 5 Hello there` From b0d1b89ef23714f666c5e6438735dfc8daf275f7 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Wed, 11 Jan 2017 05:01:17 -0500 Subject: [PATCH 013/746] Update GoogleApiService.cs --- src/NadekoBot/Services/Impl/GoogleApiService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/Impl/GoogleApiService.cs b/src/NadekoBot/Services/Impl/GoogleApiService.cs index 56a40965..a6cdc590 100644 --- a/src/NadekoBot/Services/Impl/GoogleApiService.cs +++ b/src/NadekoBot/Services/Impl/GoogleApiService.cs @@ -51,7 +51,7 @@ namespace NadekoBot.Services.Impl return (await query.ExecuteAsync()).Items.Select(i => i.Id.PlaylistId); } - private readonly Regex YtVideoIdRegex = new Regex("(?:youtu\\.be\\/|v\\/|u\\/\\w\\/|embed\\/|watch\\?v=|\\&v=)(?[^#\\&\\?]*)", RegexOptions.Compiled); + private readonly Regex YtVideoIdRegex = new Regex("(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)([a-zA-Z0-9_-]{6,11})", RegexOptions.Compiled); public async Task> GetRelatedVideosAsync(string id, int count = 1) { From b2ee4f8e665c255c41fad3054d49bc8ad73124a0 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Wed, 11 Jan 2017 05:14:39 -0500 Subject: [PATCH 014/746] Update GoogleApiService.cs --- src/NadekoBot/Services/Impl/GoogleApiService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/Impl/GoogleApiService.cs b/src/NadekoBot/Services/Impl/GoogleApiService.cs index a6cdc590..eaa066ff 100644 --- a/src/NadekoBot/Services/Impl/GoogleApiService.cs +++ b/src/NadekoBot/Services/Impl/GoogleApiService.cs @@ -51,7 +51,7 @@ namespace NadekoBot.Services.Impl return (await query.ExecuteAsync()).Items.Select(i => i.Id.PlaylistId); } - private readonly Regex YtVideoIdRegex = new Regex("(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)([a-zA-Z0-9_-]{6,11})", RegexOptions.Compiled); + private readonly Regex YtVideoIdRegex = new Regex(@"(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)([a-zA-Z0-9_-]{6,11})", RegexOptions.Compiled); public async Task> GetRelatedVideosAsync(string id, int count = 1) { From c183ab15deec611f124b630a1bed11ff4a72c327 Mon Sep 17 00:00:00 2001 From: Poag Date: Wed, 11 Jan 2017 11:43:03 +0000 Subject: [PATCH 015/746] Updated guide with update instructions. --- docs/guides/Docker Guide.md | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/guides/Docker Guide.md b/docs/guides/Docker Guide.md index 9908a477..c689c2a5 100644 --- a/docs/guides/Docker Guide.md +++ b/docs/guides/Docker Guide.md @@ -8,7 +8,7 @@ Follow the respective guide for your operating system found here https://docs.do For this guide we will be using the folder /nadeko as our config root folder. ``` -docker create --name=nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data -v /nadeko/credentials.json:/opt/NadekoBot/src/NadekoBot/credentials.json kwoth/nadeko:dev +docker create --name=nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data -v /nadeko/credentials.json:/opt/NadekoBot/src/NadekoBot/credentials.json uirel/nadeko ``` -If you are coming from a previous version of nadeko (the old docker) make sure your crednetials.json has been copied into this directory and is the only thing in this folder. @@ -24,11 +24,27 @@ Once the log ends with "NadekoBot | Starting NadekoBot v1.0-rc2" the bot is read After a few moments you should be able to invite Nadeko to your server. If you cannot check the log file for errors -## Updates / Monitoring +## Monitoring -* Upgrade to the latest version of Nadeko simply `docker restart nadeko`. * Monitor the logs of the container in realtime `docker logs -f nadeko`. +## Updates + +* Manual +Updates are handled by pulling the new layer of the Docker Container which contains a pre compiled update to Nadeko. +The following commands are required for the default options +1. ```docker pull uirel/nadeko:latest``` +2. ```docker stop nadeko; docker rm nadeko``` +3. ```docker create --name=nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data -v /nadeko/credentials.json:/opt/NadekoBot/src/NadekoBot/credentials.json uirel/nadeko``` +4. ```docker start nadeko``` + +* Automatic Updates +Automatic update are now handled by watchertower https://github.com/CenturyLinkLabs/watchtower +To setup watchtower to keep Nadeko up-to-date for you with the default settings use the following command +```docker run -d --name watchtower -v /var/run/docker.sock:/var/run/docker.sock centurylink/watchtower --cleanup nadeko``` +This will check for updates to the docker every 5 minutes and update immediately. Alternatively using the ```--interval X``` command to change the interval, where X is the amount of time in seconds to wait. eg 21600 for 6 hours. + + If you have any issues with the docker setup, please ask in #help but indicate you are using the docker. For information about configuring your bot or its functionality, please check the http://nadekobot.readthedocs.io/en/latest guides. From 07c0018479bc2782a899f78266bdc63253c8baff Mon Sep 17 00:00:00 2001 From: Poag Date: Wed, 11 Jan 2017 12:50:39 +0000 Subject: [PATCH 016/746] Update Docker Guide.md --- docs/guides/Docker Guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/Docker Guide.md b/docs/guides/Docker Guide.md index c689c2a5..6ed3a33e 100644 --- a/docs/guides/Docker Guide.md +++ b/docs/guides/Docker Guide.md @@ -30,7 +30,7 @@ After a few moments you should be able to invite Nadeko to your server. If you c ## Updates -* Manual +# Manual Updates are handled by pulling the new layer of the Docker Container which contains a pre compiled update to Nadeko. The following commands are required for the default options 1. ```docker pull uirel/nadeko:latest``` @@ -38,7 +38,7 @@ The following commands are required for the default options 3. ```docker create --name=nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data -v /nadeko/credentials.json:/opt/NadekoBot/src/NadekoBot/credentials.json uirel/nadeko``` 4. ```docker start nadeko``` -* Automatic Updates +# Automatic Updates Automatic update are now handled by watchertower https://github.com/CenturyLinkLabs/watchtower To setup watchtower to keep Nadeko up-to-date for you with the default settings use the following command ```docker run -d --name watchtower -v /var/run/docker.sock:/var/run/docker.sock centurylink/watchtower --cleanup nadeko``` From 11da7c89b6715cde6344539459c6b11fbf6f05f3 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 11 Jan 2017 13:54:25 +0100 Subject: [PATCH 017/746] hangman fix? closes #956 --- .../Modules/Games/Commands/Hangman/HangmanGame.cs | 8 +++++++- src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index 58071453..23b76e9b 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -52,7 +52,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman } } - public class HangmanGame + public class HangmanGame: IDisposable { private readonly Logger _log; @@ -196,5 +196,11 @@ namespace NadekoBot.Modules.Games.Commands.Hangman {(Errors > 1 ? "/" : " ")} {(Errors > 2 ? "|" : " ")} {(Errors > 3 ? "\\" : " ")} | {(Errors > 4 ? "/" : " ")} {(Errors > 5 ? "\\" : " ")} | /-\"; + + public void Dispose() + { + NadekoBot.Client.MessageReceived -= PotentialGuess; + OnEnded = null; + } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs index 0827ab94..50596e4c 100644 --- a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs @@ -52,8 +52,12 @@ namespace NadekoBot.Modules.Games { hm.Start(); } - catch (Exception ex) { + catch (Exception ex) + { try { await Context.Channel.SendErrorAsync($"Starting errored: {ex.Message}").ConfigureAwait(false); } catch { } + HangmanGame throwaway; + HangmanGames.TryRemove(Context.Channel.Id, out throwaway); + throwaway.Dispose(); return; } From f7e9463a941a3ed8715d4e73575a36bbdab7799f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 11 Jan 2017 14:05:57 +0100 Subject: [PATCH 018/746] .savechat moved to utility module --- .../Modules/Administration/Administration.cs | 18 ---------------- src/NadekoBot/Modules/Utility/Utility.cs | 21 ++++++++++++++++++- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index e0a9bf0b..cf431be1 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -486,24 +486,6 @@ namespace NadekoBot.Modules.Administration await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false); } - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [OwnerOnly] - public async Task SaveChat(int cnt) - { - var sb = new StringBuilder(); - var msgs = new List(cnt); - await Context.Channel.GetMessagesAsync(cnt).ForEachAsync(dled => msgs.AddRange(dled)).ConfigureAwait(false); - - var title = $"Chatlog-{Context.Guild.Name}/#{Context.Channel.Name}-{DateTime.Now}.txt"; - var grouping = msgs.GroupBy(x => $"{x.CreatedAt.Date:dd.MM.yyyy}") - .Select(g => new { date = g.Key, messages = g.OrderBy(x => x.CreatedAt).Select(s => $"【{s.Timestamp:HH:mm:ss}】{s.Author}:" + s.ToString()) }); - await (Context.User as IGuildUser).SendFileAsync( - await JsonConvert.SerializeObject(grouping, Formatting.Indented).ToStream().ConfigureAwait(false), -title, title).ConfigureAwait(false); - } - - [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.MentionEveryone)] diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index b7d437d0..4a581108 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -13,6 +13,8 @@ using System.Net.Http; using System.Collections.Concurrent; using System.Threading; using ImageSharp; +using System.Collections.Generic; +using Newtonsoft.Json; namespace NadekoBot.Modules.Utility { @@ -82,7 +84,7 @@ namespace NadekoBot.Modules.Utility old.Change(Timeout.Infinite, Timeout.Infinite); return t; }); - + await channel.SendFileAsync(images, "magicalgirl.jpg", $"Rotating **{role.Name}** role's color.").ConfigureAwait(false); } @@ -326,5 +328,22 @@ namespace NadekoBot.Modules.Utility .WithIsInline(false)))) .ConfigureAwait(false); } + + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task SaveChat(int cnt) + { + var sb = new StringBuilder(); + var msgs = new List(cnt); + await Context.Channel.GetMessagesAsync(cnt).ForEachAsync(dled => msgs.AddRange(dled)).ConfigureAwait(false); + + var title = $"Chatlog-{Context.Guild.Name}/#{Context.Channel.Name}-{DateTime.Now}.txt"; + var grouping = msgs.GroupBy(x => $"{x.CreatedAt.Date:dd.MM.yyyy}") + .Select(g => new { date = g.Key, messages = g.OrderBy(x => x.CreatedAt).Select(s => $"【{s.Timestamp:HH:mm:ss}】{s.Author}:" + s.ToString()) }); + await Context.User.SendFileAsync( + await JsonConvert.SerializeObject(grouping, Formatting.Indented).ToStream().ConfigureAwait(false), title, title).ConfigureAwait(false); + } } } \ No newline at end of file From ceb1ed41a279b8d0e074a62c26470845290d1b48 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 11 Jan 2017 14:07:12 +0100 Subject: [PATCH 019/746] Cross server text moved to utility --- .../Commands/CrossServerTextChannel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/NadekoBot/Modules/{Administration => Utility}/Commands/CrossServerTextChannel.cs (97%) diff --git a/src/NadekoBot/Modules/Administration/Commands/CrossServerTextChannel.cs b/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs similarity index 97% rename from src/NadekoBot/Modules/Administration/Commands/CrossServerTextChannel.cs rename to src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs index 62af02da..b2ae710c 100644 --- a/src/NadekoBot/Modules/Administration/Commands/CrossServerTextChannel.cs +++ b/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs @@ -9,9 +9,9 @@ using System.Collections.Concurrent; using System.Linq; using System.Threading.Tasks; -namespace NadekoBot.Modules.Administration +namespace NadekoBot.Modules.Utility { - public partial class Administration + public partial class Utility { [Group] public class CrossServerTextChannel : ModuleBase From 819f4aae3811eda04cc8c3b890d3f6162d4475eb Mon Sep 17 00:00:00 2001 From: Poag Date: Wed, 11 Jan 2017 13:07:39 +0000 Subject: [PATCH 020/746] Update Docker Guide.md --- docs/guides/Docker Guide.md | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/docs/guides/Docker Guide.md b/docs/guides/Docker Guide.md index 6ed3a33e..474337d6 100644 --- a/docs/guides/Docker Guide.md +++ b/docs/guides/Docker Guide.md @@ -1,23 +1,22 @@ # NadekoBot a Discord bot -Nadeko is written in C# and Discord.net for more information visit https://github.com/Kwoth/NadekoBot +Nadeko is written in C# and Discord.net for more information visit ## Install Docker -Follow the respective guide for your operating system found here https://docs.docker.com/engine/installation/ +Follow the respective guide for your operating system found here [Docker Engine Install Guide](https://docs.docker.com/engine/installation/) ## Nadeko Setup Guide For this guide we will be using the folder /nadeko as our config root folder. -``` +```bash docker create --name=nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data -v /nadeko/credentials.json:/opt/NadekoBot/src/NadekoBot/credentials.json uirel/nadeko ``` -If you are coming from a previous version of nadeko (the old docker) make sure your crednetials.json has been copied into this directory and is the only thing in this folder. --If you are making a fresh install, create your credentials.json from the following guide and palce it in the /nadeko folder -http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/ +-If you are making a fresh install, create your credentials.json from the following guide and palce it in the /nadeko folder [Nadeko JSON Guide](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/) Next start the docker up with -```docker start nadeko; docker logs -f nadeko``` +`docker start nadeko; docker logs -f nadeko` The docker will start and the log file will start scrolling past. Depending on hardware the bot start can take up to 5 minutes on a small DigitalOcean droplet. Once the log ends with "NadekoBot | Starting NadekoBot v1.0-rc2" the bot is ready and can be invited to your server. Ctrl+C at this point to stop viewing the logs. @@ -33,18 +32,27 @@ After a few moments you should be able to invite Nadeko to your server. If you c # Manual Updates are handled by pulling the new layer of the Docker Container which contains a pre compiled update to Nadeko. The following commands are required for the default options -1. ```docker pull uirel/nadeko:latest``` -2. ```docker stop nadeko; docker rm nadeko``` -3. ```docker create --name=nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data -v /nadeko/credentials.json:/opt/NadekoBot/src/NadekoBot/credentials.json uirel/nadeko``` -4. ```docker start nadeko``` + +`docker pull uirel/nadeko:latest` + +`docker stop nadeko; docker rm nadeko` + +`docker create --name=nadeko -v /nadeko/data:/opt/NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data -v /nadeko/credentials.json:/opt/NadekoBot/src/NadekoBot/credentials.json uirel/nadeko` + +`docker start nadeko` + # Automatic Updates -Automatic update are now handled by watchertower https://github.com/CenturyLinkLabs/watchtower +Automatic update are now handled by watchertower [WatchTower GitHub](https://github.com/CenturyLinkLabs/watchtower) To setup watchtower to keep Nadeko up-to-date for you with the default settings use the following command -```docker run -d --name watchtower -v /var/run/docker.sock:/var/run/docker.sock centurylink/watchtower --cleanup nadeko``` -This will check for updates to the docker every 5 minutes and update immediately. Alternatively using the ```--interval X``` command to change the interval, where X is the amount of time in seconds to wait. eg 21600 for 6 hours. + +```bash +docker run -d --name watchtower -v /var/run/docker.sock:/var/run/docker.sock centurylink/watchtower --cleanup nadeko +``` + +This will check for updates to the docker every 5 minutes and update immediately. Alternatively using the `--interval X` command to change the interval, where X is the amount of time in seconds to wait. eg 21600 for 6 hours. If you have any issues with the docker setup, please ask in #help but indicate you are using the docker. -For information about configuring your bot or its functionality, please check the http://nadekobot.readthedocs.io/en/latest guides. +For information about configuring your bot or its functionality, please check the guides. From 5febe8453112e5ca0e94a0568c4d916235fd9f01 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 11 Jan 2017 14:08:50 +0100 Subject: [PATCH 021/746] Message repeater moved to utility --- .../{Administration => Utility}/Commands/MessageRepeater.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/NadekoBot/Modules/{Administration => Utility}/Commands/MessageRepeater.cs (99%) diff --git a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs similarity index 99% rename from src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs rename to src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs index 34281838..71bd6748 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs @@ -16,9 +16,9 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -namespace NadekoBot.Modules.Administration +namespace NadekoBot.Modules.Utility { - public partial class Administration + public partial class Utility { [Group] public class RepeatCommands : ModuleBase From f78188ce198b7b2d45b6c343ad4724ef7b16c899 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 11 Jan 2017 17:15:59 +0100 Subject: [PATCH 022/746] Added pagination to .lcr, .lcrg, !!lq. Contact me if you have more ideas where it's needed. It lasts for 30 seconds. --- .../CustomReactions/CustomReactions.cs | 51 +++++++----- src/NadekoBot/Modules/Music/Music.cs | 57 +++++++------ .../Discord/SocketMessageEventWrapper.cs | 52 +++++++----- src/NadekoBot/ShardedDiscordClient.cs | 6 ++ src/NadekoBot/_Extensions/Extensions.cs | 81 ++++++++++++++++--- 5 files changed, 172 insertions(+), 75 deletions(-) diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index d69c31ca..8d95e5d4 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -145,13 +145,17 @@ namespace NadekoBot.Modules.CustomReactions if (customReactions == null || !customReactions.Any()) await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync( - $"Page {page} of custom reactions:", - string.Join("\n", customReactions.OrderBy(cr => cr.Trigger) - .Skip((page - 1) * 20) + { + var lastPage = customReactions.Count / 20; + await Context.Channel.SendPaginatedConfirmAsync(page, curPage => + new EmbedBuilder().WithOkColor() + .WithTitle("Custom reactions") + .WithDescription(string.Join("\n", customReactions.OrderBy(cr => cr.Trigger) + .Skip((curPage - 1) * 20) .Take(20) - .Select(cr => $"`#{cr.Id}` `Trigger:` {cr.Trigger}"))) + .Select(cr => $"`#{cr.Id}` `Trigger:` {cr.Trigger}"))), lastPage) .ConfigureAwait(false); + } } public enum All @@ -200,14 +204,22 @@ namespace NadekoBot.Modules.CustomReactions if (customReactions == null || !customReactions.Any()) await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync($"Page {page} of custom reactions (grouped):", - string.Join("\r\n", customReactions - .GroupBy(cr => cr.Trigger) - .OrderBy(cr => cr.Key) - .Skip((page - 1) * 20) - .Take(20) - .Select(cr => $"**{cr.Key.Trim().ToLowerInvariant()}** `x{cr.Count()}`"))) + { + var ordered = customReactions + .GroupBy(cr => cr.Trigger) + .OrderBy(cr => cr.Key) + .ToList(); + + var lastPage = ordered.Count / 20; + await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) => + new EmbedBuilder().WithOkColor() + .WithTitle($"Custom Reactions (grouped)") + .WithDescription(string.Join("\r\n", ordered + .Skip((curPage - 1) * 20) + .Take(20) + .Select(cr => $"**{cr.Key.Trim().ToLowerInvariant()}** `x{cr.Count()}`"))), lastPage) .ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -300,13 +312,14 @@ namespace NadekoBot.Modules.CustomReactions { if (page < 1) return; - await Context.Channel.EmbedAsync(ReactionStats.OrderByDescending(x => x.Value) - .Skip((page - 1) * 9) - .Take(9) - .Aggregate(new EmbedBuilder().WithOkColor().WithTitle($"Custom Reaction stats page #{page}"), - (agg, cur) => agg.AddField(efb => efb.WithName(cur.Key).WithValue(cur.Value.ToString()).WithIsInline(true))) - ) - .ConfigureAwait(false); + var ordered = ReactionStats.OrderByDescending(x => x.Value).ToList(); + var lastPage = ordered.Count / 9; + await Context.Channel.SendPaginatedConfirmAsync(page, + (curPage) => ordered.Skip((curPage - 1) * 9) + .Take(9) + .Aggregate(new EmbedBuilder().WithOkColor().WithTitle($"Custom Reaction Stats"), + (agg, cur) => agg.AddField(efb => efb.WithName(cur.Key).WithValue(cur.Value.ToString()).WithIsInline(true))), lastPage) + .ConfigureAwait(false); } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 3ffb104c..381177a2 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -183,36 +183,41 @@ namespace NadekoBot.Modules.Music try { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { } const int itemsPerPage = 10; - int startAt = itemsPerPage * (page - 1); - var number = 0 + startAt; var total = musicPlayer.TotalPlaytime; var maxPlaytime = musicPlayer.MaxPlaytimeSeconds; - var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName($"Player Queue - Page {page}") - .WithMusicIcon()) - .WithDescription(string.Join("\n", musicPlayer.Playlist - .Skip(startAt) - .Take(10) - .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 | " + -(musicPlayer.FairPlay ? "✔️fairplay" : "✖️fairplay") + $" | " + (maxPlaytime == 0 ? "unlimited" : $"{maxPlaytime}s limit"))) - .WithOkColor(); + var lastPage = musicPlayer.Playlist.Count / itemsPerPage; + Func printAction = (curPage) => + { + int startAt = itemsPerPage * (curPage - 1); + var number = 0 + startAt; + var embed = new EmbedBuilder() + .WithAuthor(eab => eab.WithName($"Player Queue") + .WithMusicIcon()) + .WithDescription(string.Join("\n", musicPlayer.Playlist + .Skip(startAt) + .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 | " + + (musicPlayer.FairPlay ? "✔️fairplay" : "✖️fairplay") + $" | " + (maxPlaytime == 0 ? "unlimited" : $"{maxPlaytime}s limit"))) + .WithOkColor(); - if (musicPlayer.RepeatSong) - { - embed.WithTitle($"🔂 Repeating Song: {currentSong.SongInfo.Title} | {currentSong.PrettyFullTime}"); - } - else if (musicPlayer.RepeatPlaylist) - { - embed.WithTitle("🔁 Repeating Playlist"); - } - if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize) - { - embed.WithTitle("🎵 Song queue is full!"); - } - await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + if (musicPlayer.RepeatSong) + { + embed.WithTitle($"🔂 Repeating Song: {currentSong.SongInfo.Title} | {currentSong.PrettyFullTime}"); + } + else if (musicPlayer.RepeatPlaylist) + { + embed.WithTitle("🔁 Repeating Playlist"); + } + if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize) + { + embed.WithTitle("🎵 Song queue is full!"); + } + return embed; + }; + await Context.Channel.SendPaginatedConfirmAsync(page, printAction, lastPage).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs b/src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs index 7c24b564..b73961a0 100644 --- a/src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs +++ b/src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs @@ -10,48 +10,60 @@ namespace NadekoBot.Services.Discord { public class ReactionEventWrapper : IDisposable { - public SocketMessage Message { get; } + public IUserMessage Message { get; } public event Action OnReactionAdded = delegate { }; public event Action OnReactionRemoved = delegate { }; public event Action OnReactionsCleared = delegate { }; - public ReactionEventWrapper(SocketMessage msg) + public ReactionEventWrapper(IUserMessage msg) { if (msg == null) throw new ArgumentNullException(nameof(msg)); Message = msg; - msg.Discord.ReactionAdded += Discord_ReactionAdded; - msg.Discord.ReactionRemoved += Discord_ReactionRemoved; - msg.Discord.ReactionsCleared += Discord_ReactionsCleared; + NadekoBot.Client.ReactionAdded += Discord_ReactionAdded; + NadekoBot.Client.ReactionRemoved += Discord_ReactionRemoved; + NadekoBot.Client.ReactionsCleared += Discord_ReactionsCleared; } - private Task Discord_ReactionsCleared(ulong messageId, Optional reaction) + private void Discord_ReactionsCleared(ulong messageId, Optional reaction) { - if (messageId == Message.Id) - OnReactionsCleared?.Invoke(); - return Task.CompletedTask; + try + { + if (messageId == Message.Id) + OnReactionsCleared?.Invoke(); + } + catch { } } - private Task Discord_ReactionRemoved(ulong messageId, Optional arg2, SocketReaction reaction) + private void Discord_ReactionRemoved(ulong messageId, Optional arg2, SocketReaction reaction) { - if (messageId == Message.Id) - OnReactionRemoved?.Invoke(reaction); - return Task.CompletedTask; + try + { + if (messageId == Message.Id) + OnReactionRemoved?.Invoke(reaction); + } + catch { } } - private Task Discord_ReactionAdded(ulong messageId, Optional message, SocketReaction reaction) + private void Discord_ReactionAdded(ulong messageId, Optional message, SocketReaction reaction) { - if(messageId == Message.Id) - OnReactionAdded?.Invoke(reaction); - return Task.CompletedTask; + try + { + if (messageId == Message.Id) + OnReactionAdded?.Invoke(reaction); + } + catch { } } public void UnsubAll() { - Message.Discord.ReactionAdded -= Discord_ReactionAdded; - Message.Discord.ReactionRemoved -= Discord_ReactionRemoved; - Message.Discord.ReactionsCleared -= Discord_ReactionsCleared; + NadekoBot.Client.ReactionAdded -= Discord_ReactionAdded; + NadekoBot.Client.ReactionRemoved -= Discord_ReactionRemoved; + NadekoBot.Client.ReactionsCleared -= Discord_ReactionsCleared; + OnReactionAdded = null; + OnReactionRemoved = null; + OnReactionsCleared = null; } private bool disposing = false; diff --git a/src/NadekoBot/ShardedDiscordClient.cs b/src/NadekoBot/ShardedDiscordClient.cs index 7a538192..a59dece7 100644 --- a/src/NadekoBot/ShardedDiscordClient.cs +++ b/src/NadekoBot/ShardedDiscordClient.cs @@ -28,6 +28,9 @@ namespace NadekoBot public event Action ChannelCreated = delegate { }; public event Action ChannelDestroyed = delegate { }; public event Action ChannelUpdated = delegate { }; + public event Action, SocketReaction> ReactionAdded = delegate { }; + public event Action, SocketReaction> ReactionRemoved = delegate { }; + public event Action> ReactionsCleared = delegate { }; public event Action JoinedGuild = delegate { }; public event Action LeftGuild = delegate { }; @@ -74,6 +77,9 @@ namespace NadekoBot client.ChannelUpdated += (arg1, arg2) => { ChannelUpdated(arg1, arg2); return Task.CompletedTask; }; client.JoinedGuild += (arg1) => { JoinedGuild(arg1); ++_guildCount; return Task.CompletedTask; }; client.LeftGuild += (arg1) => { LeftGuild(arg1); --_guildCount; return Task.CompletedTask; }; + client.ReactionAdded += (arg1, arg2, arg3) => { ReactionAdded(arg1, arg2, arg3); return Task.CompletedTask; }; + client.ReactionRemoved += (arg1, arg2, arg3) => { ReactionRemoved(arg1, arg2, arg3); return Task.CompletedTask; }; + client.ReactionsCleared += (arg1, arg2) => { ReactionsCleared(arg1, arg2); return Task.CompletedTask; }; _log.Info($"Shard #{i} initialized."); #if GLOBAL_NADEKO diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index 3994e54f..310b5974 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -18,10 +18,70 @@ namespace NadekoBot.Extensions { public static class Extensions { - public static ReactionEventWrapper OnReactionAdded(this SocketMessage msg, Action reactionAdded) + private const string arrow_left = "⬅"; + private const string arrow_right = "➡"; + + /// + /// danny kamisama + /// + public static async Task SendPaginatedConfirmAsync(this IMessageChannel channel, int currentPage, Func pageFunc, int? lastPage = null) { + lastPage += 1; + var embed = pageFunc(currentPage).AddPaginatedFooter(currentPage, lastPage); + + var msg = await channel.EmbedAsync(embed) as IUserMessage; + + if (currentPage >= lastPage && lastPage == 1) + return; + + await msg.AddReactionAsync(arrow_left).ConfigureAwait(false); + await msg.AddReactionAsync(arrow_right).ConfigureAwait(false); + + await Task.Delay(2000).ConfigureAwait(false); + + Action changePage = async r => + { + try + { + if (r.Emoji.Name == arrow_left) + { + if (currentPage == 1) + return; + await msg.ModifyAsync(x => x.Embed = pageFunc(--currentPage).AddPaginatedFooter(currentPage, lastPage).Build()).ConfigureAwait(false); + } + else if (r.Emoji.Name == arrow_right) + { + if (lastPage == null || lastPage > currentPage) + await msg.ModifyAsync(x => x.Embed = pageFunc(++currentPage).AddPaginatedFooter(currentPage, lastPage).Build()).ConfigureAwait(false); + } + } + catch (Exception ex) { Console.WriteLine(ex); } + }; + + using (msg.OnReaction(changePage, changePage)) + { + await Task.Delay(30000).ConfigureAwait(false); + } + + await msg.RemoveAllReactionsAsync().ConfigureAwait(false); + } + + private static EmbedBuilder AddPaginatedFooter(this EmbedBuilder embed, int curPage, int? lastPage) + { + if (lastPage != null) + return embed.WithFooter(efb => efb.WithText($"page {curPage} / {lastPage}")); + else + return embed.WithFooter(efb => efb.WithText($"page {curPage}")); + } + + public static ReactionEventWrapper OnReaction(this IUserMessage msg, Action reactionAdded, Action reactionRemoved = null) + { + if (reactionRemoved == null) + reactionRemoved = delegate { }; + var wrap = new ReactionEventWrapper(msg); wrap.OnReactionAdded += reactionAdded; + wrap.OnReactionRemoved += reactionRemoved; return wrap; } @@ -53,7 +113,8 @@ namespace NadekoBot.Extensions public static string GetPrefix(this ModuleInfo module) => NadekoBot.ModulePrefixes[module.GetTopLevelModule().Name]; - public static ModuleInfo GetTopLevelModule(this ModuleInfo module) { + public static ModuleInfo GetTopLevelModule(this ModuleInfo module) + { while (module.Parent != null) { module = module.Parent; @@ -102,7 +163,7 @@ namespace NadekoBot.Extensions public static bool IsInteger(this decimal number) => number == Math.Truncate(number); - public static string SanitizeMentions(this string str) => + public static string SanitizeMentions(this string str) => str.Replace("@everyone", "@everyοne").Replace("@here", "@һere"); public static double UnixTimestamp(this DateTime dt) => dt.ToUniversalTime().Subtract(new DateTime(1970, 1, 1)).TotalSeconds; @@ -114,7 +175,7 @@ namespace NadekoBot.Extensions => await (await user.CreateDMChannelAsync()).SendMessageAsync("", embed: new EmbedBuilder().WithColor(NadekoBot.OkColor).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().WithColor(NadekoBot.OkColor).WithDescription(text) .WithTitle(title).WithUrl(url)); public static async Task SendErrorAsync(this IUser user, string title, string error, string url = null) @@ -135,7 +196,7 @@ namespace NadekoBot.Extensions public static IEnumerable Members(this IRole role) => role.Guild.GetUsersAsync().GetAwaiter().GetResult().Where(u => u.RoleIds.Contains(role.Id)) ?? Enumerable.Empty(); - + public static Task EmbedAsync(this IMessageChannel ch, EmbedBuilder embed, string msg = "") => ch.SendMessageAsync(msg, embed: embed); @@ -162,7 +223,7 @@ namespace NadekoBot.Extensions ```"); } - public static Task SendTableAsync(this IMessageChannel ch, IEnumerable items, Func howToPrint, int columns = 3) => + public static Task SendTableAsync(this IMessageChannel ch, IEnumerable items, Func howToPrint, int columns = 3) => ch.SendTableAsync("", items, howToPrint, columns); /// @@ -295,7 +356,7 @@ namespace NadekoBot.Extensions } - public static string ToJson(this T any, Formatting formatting = Formatting.Indented) => + public static string ToJson(this T any, Formatting formatting = Formatting.Indented) => JsonConvert.SerializeObject(any, formatting); public static int KiB(this int value) => value * 1024; @@ -326,7 +387,7 @@ namespace NadekoBot.Extensions var canvasPixels = canvas.Lock(); int offsetX = 0; - foreach (var img in imgList.Select(img=>img.Lock())) + foreach (var img in imgList.Select(img => img.Lock())) { for (int i = 0; i < img.Width; i++) { @@ -335,7 +396,7 @@ namespace NadekoBot.Extensions canvasPixels[i + offsetX, j] = img[i, j]; } } - offsetX += img.Width; + offsetX += img.Width; } return canvas; @@ -354,4 +415,4 @@ namespace NadekoBot.Extensions public static bool IsDiscordInvite(this string str) => filterRegex.IsMatch(str); } -} +} \ No newline at end of file From b2135e018f90a75b4050ff7e2f92e6b6b49e6c12 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 11 Jan 2017 17:48:57 +0100 Subject: [PATCH 023/746] Picking/planting will now correctly say your own currency name, instead of flower --- src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 078b9183..015b4328 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -129,7 +129,7 @@ namespace NadekoBot.Modules.Games await Task.WhenAll(msgs.Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false); - await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, "Picked flower(s).", msgs.Count, false).ConfigureAwait(false); + await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, $"Picked {Gambling.Gambling.CurrencyPluralName}", msgs.Count, false).ConfigureAwait(false); var msg = await channel.SendConfirmAsync($"**{Context.User}** picked {msgs.Count}{Gambling.Gambling.CurrencySign}!").ConfigureAwait(false); msg.DeleteAfter(10); } @@ -146,7 +146,7 @@ namespace NadekoBot.Modules.Games [RequireContext(ContextType.Guild)] public async Task Plant() { - var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, "Planted a flower.", 1, false).ConfigureAwait(false); + var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {Gambling.Gambling.CurrencyName}", 1, false).ConfigureAwait(false); if (!removed) { await Context.Channel.SendErrorAsync($"You don't have any {Gambling.Gambling.CurrencyPluralName}.").ConfigureAwait(false); From 16070d896d2305de47b9191612950477b353e2ca Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 11 Jan 2017 18:20:19 +0100 Subject: [PATCH 024/746] 1.1.0 version --- 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 558feed7..c6d22070 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -14,7 +14,7 @@ namespace NadekoBot.Services.Impl private ShardedDiscordClient client; private DateTime started; - public const string BotVersion = "1.1.0-beta"; + public const string BotVersion = "1.1.0"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From ecd751c24108543808e6e525872094094627bd5d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 11 Jan 2017 18:22:51 +0100 Subject: [PATCH 025/746] Commandlist update --- docs/Commands List.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index 049143f8..1d354c4a 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -45,6 +45,10 @@ Command and aliases | Description | Usage `.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | `.iam Gamer` `.iamnot` `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | `.iamn Gamer` `.slowmode` | Toggles slowmode. Disable by specifying no parameters. To enable, specify a number of messages each user can send, and an interval in seconds. For example 1 message every 5 seconds. **Requires ManageMessages server permission.** | `.slowmode 1 5` or `.slowmode` +`.antiraid` | Sets an anti-raid protection on the server. First argument is number of people which will trigger the protection. Second one is a time interval in which that number of people needs to join in order to trigger the protection, and third argument is punishment for those people (Kick, Ban, Mute) **Requires Administrator server permission.** | `.antiraid 5 20 Kick` +`.antispam` | Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. **Requires Administrator server permission.** | `.antispam 3 Mute` or `.antispam 4 Kick` or `.antispam 6 Ban` +`.antispamignore` | Toggles whether antispam ignores current channel. Antispam must be enabled. | `.antispamignore` +`.antilist` `.antilst` | Shows currently enabled protection features. | `.antilist` `.rotateplaying` `.ropl` | Toggles rotation of playing status of the dynamic strings you previously specified. **Bot Owner only.** | `.ropl` `.addplaying` `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued% **Bot Owner only.** | `.adpl` `.listplaying` `.lipl` | Lists all playing statuses with their corresponding number. **Bot Owner only.** | `.lipl` @@ -57,22 +61,13 @@ Command and aliases | Description | Usage `.voicemute` | Prevents a mentioned user from speaking in voice channels. **Requires MuteMembers server permission.** | `.voicemute @Someone` `.voiceunmute` | Gives a previously voice-muted user a permission to speak. **Requires MuteMembers server permission.** | `.voiceunmute @Someguy` `.migratedata` | Migrate data from old bot configuration **Bot Owner only.** | `.migratedata` -`.repeatinvoke` `.repinv` | Immediately shows the repeat message on a certain index and restarts its timer. **Requires ManageMessages server permission.** | `.repinv 1` -`.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2` -`.repeat` | Repeat a message every X minutes in the current channel. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` -`.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist` `.logserver` | Enables or Disables ALL log events. If enabled, all log events will log to this channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logserver enable` or `.logserver disable` `.logignore` | Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logignore` `.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot Owner only.** | `.logevents` `.log` | Toggles logging event. Disables it if it's active anywhere on the server. Enables if it's not active. Use `.logevents` to see a list of all events you can subscribe to. **Requires Administrator server permission.** **Bot Owner only.** | `.log userpresence` or `.log userbanned` `.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot Owner only.** | `.fwmsgs` `.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json **Bot Owner only.** | `.fwtoall` -`.scsc` | Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. **Bot Owner only.** | `.scsc` -`.jcsc` | Joins current channel to an instance of cross server channel using the token. **Requires ManageServer server permission.** | `.jcsc TokenHere` -`.lcsc` | Leaves Cross server channel instance from this channel. **Requires ManageServer server permission.** | `.lcsc` `.autoassignrole` `.aar` | Automaticaly assigns a specified role to every user who joins the server. **Requires ManageRoles server permission.** | `.aar` to disable, `.aar Role Name` to enable -`.antiraid` | Sets an anti-raid protection on the server. First argument is number of people which will trigger the protection. Second one is a time interval in which that number of people needs to join in order to trigger the protection, and third argument is punishment for those people (Kick, Ban, Mute) **Requires Administrator server permission.** | `.antiraid 5 20 Kick` -`.antispam` | Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. **Requires Administrator server permission.** | `.antispam 3 Mute` or `.antispam 4 Kick` or `.antispam 6 Ban` `.resetperms` | Resets BOT's permissions module on this server to the default value. **Requires Administrator server permission.** | `.resetperms` `.delmsgoncmd` | Toggles the automatic deletion of user's successful command message to prevent chat flood. **Requires Administrator server permission.** | `.delmsgoncmd` `.setrole` `.sr` | Sets a role for a given user. **Requires ManageRoles server permission.** | `.sr @User Guest` @@ -93,7 +88,6 @@ Command and aliases | Description | Usage `.settopic` `.st` | Sets a topic on the current channel. **Requires ManageChannels server permission.** | `.st My new topic` `.setchanlname` `.schn` | Changes the name of the current channel. **Requires ManageChannels server permission.** | `.schn NewName` `.prune` `.clr` | `.prune` removes all nadeko's messages in the last 100 messages.`.prune X` removes last X messages from the channel (up to 100)`.prune @Someone` removes all Someone's messages in the last 100 messages.`.prune @Someone X` removes last X 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X` -`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner only.** | `.savechat 150` `.mentionrole` `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. **Requires MentionEveryone server permission.** | `.menro RoleName` `.donators` | List of lovely people who donated to keep this project alive. | `.donators` `.donadd` | Add a donator to the database. **Bot Owner only.** | `.donadd Donate Amount` @@ -365,9 +359,16 @@ Command and aliases | Description | Usage `..` | Adds a new quote with the specified name and message. | `.. sayhi Hi` `.deletequote` `.delq` | Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. | `.delq abc` `.delallq` `.daq` | Deletes all quotes on a specified keyword. **Requires Administrator server permission.** | `.delallq kek` +`.repeatinvoke` `.repinv` | Immediately shows the repeat message on a certain index and restarts its timer. **Requires ManageMessages server permission.** | `.repinv 1` +`.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2` +`.repeat` | Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` +`.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist` `.serverinfo` `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | `.sinfo Some Server` `.channelinfo` `.cinfo` | Shows info about the channel. If no channel is supplied, it defaults to current one. | `.cinfo #some-channel` `.userinfo` `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | `.uinfo @SomeUser` +`.scsc` | Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. **Bot Owner only.** | `.scsc` +`.jcsc` | Joins current channel to an instance of cross server channel using the token. **Requires ManageServer server permission.** | `.jcsc TokenHere` +`.lcsc` | Leaves Cross server channel instance from this channel. **Requires ManageServer server permission.** | `.lcsc` `.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1` `.calcops` | Shows all available operations in .calc command | `.calcops` `.rotaterolecolor` `.rrc` | Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. **Bot Owner only.** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole` @@ -384,4 +385,5 @@ Command and aliases | Description | Usage `.stats` | Shows some basic stats for Nadeko. | `.stats` `.showemojis` `.se` | Shows a name and a link to every SPECIAL emoji in the message. | `.se A message full of SPECIAL emojis` `.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot Owner only.** | `.listservers 3` +`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner only.** | `.savechat 150` `.activity` | Checks for spammers. **Bot Owner only.** | `.activity` From cdd63786ffec770e96e9b9dc3c77fc326b373fd4 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 12 Jan 2017 00:35:58 +0100 Subject: [PATCH 026/746] Updated install scripts to work properly with autorun --- scripts/Latest.bat | 3 --- scripts/Stable.bat | 3 --- 2 files changed, 6 deletions(-) diff --git a/scripts/Latest.bat b/scripts/Latest.bat index f551c732..2ee46775 100644 --- a/scripts/Latest.bat +++ b/scripts/Latest.bat @@ -48,9 +48,6 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) GOTO :end :backupinstall TITLE Backing up old files - ECHO. - ECHO Make sure to close any files such as NadekoBot.db before PRESSing ANY KEY TO CONTINUE to prevent data loss - PAUSE >nul 2>&1 ::Recursively copies all files and folders from NadekoBot to NadekoBot_Old ROBOCOPY "%root%NadekoBot" "%root%NadekoBot_Old" /MIR >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) diff --git a/scripts/Stable.bat b/scripts/Stable.bat index f1e11147..bef9df85 100644 --- a/scripts/Stable.bat +++ b/scripts/Stable.bat @@ -48,9 +48,6 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) GOTO :end :backupinstall TITLE Backing up old files - ECHO. - ECHO Make sure to close any files such as NadekoBot.db before PRESSing ANY KEY TO CONTINUE to prevent data loss - PAUSE >nul 2>&1 ::Recursively copies all files and folders from NadekoBot to NadekoBot_Old ROBOCOPY "%root%NadekoBot" "%root%NadekoBot_Old" /MIR >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) From 4a2fc087f3fa77771a70dbf3e8b3330bca4b40aa Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 12 Jan 2017 01:21:32 +0100 Subject: [PATCH 027/746] Cleanup part1 --- .../Commands/PlayingRotateCommands.cs | 8 ++----- .../Modules/Gambling/Commands/AnimalRacing.cs | 2 +- src/NadekoBot/Modules/Gambling/Gambling.cs | 11 +++------ .../Games/Commands/PlantAndPickCommands.cs | 23 ++++--------------- src/NadekoBot/Modules/Games/Games.cs | 9 +------- src/NadekoBot/Modules/Help/Help.cs | 20 ++-------------- .../Modules/Utility/Commands/Remind.cs | 3 +-- src/NadekoBot/NadekoBot.cs | 9 ++++---- 8 files changed, 19 insertions(+), 66 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs index b2e8115f..e454809a 100644 --- a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs @@ -27,12 +27,8 @@ namespace NadekoBot.Modules.Administration { _log = LogManager.GetCurrentClassLogger(); - using (var uow = DbHandler.UnitOfWork()) - { - var conf = uow.BotConfig.GetOrCreate(); - RotatingStatusMessages = conf.RotatingStatusMessages; - RotatingStatuses = conf.RotatingStatuses; - } + RotatingStatusMessages = NadekoBot.BotConfig.RotatingStatusMessages; + RotatingStatuses = NadekoBot.BotConfig.RotatingStatuses; var t = Task.Run(async () => { diff --git a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs index 9acd88e4..8c5b0243 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs @@ -77,7 +77,7 @@ namespace NadekoBot.Modules.Gambling using (var uow = DbHandler.UnitOfWork()) { - animals = new ConcurrentQueue(uow.BotConfig.GetOrCreate().RaceAnimals.Select(ra => ra.Icon).Shuffle()); + animals = new ConcurrentQueue(NadekoBot.BotConfig.RaceAnimals.Select(ra => ra.Icon).Shuffle()); } diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index bbff2239..401f6995 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -20,14 +20,9 @@ namespace NadekoBot.Modules.Gambling static Gambling() { - using (var uow = DbHandler.UnitOfWork()) - { - var conf = uow.BotConfig.GetOrCreate(); - - CurrencyName = conf.CurrencyName; - CurrencySign = conf.CurrencySign; - CurrencyPluralName = conf.CurrencyPluralName; - } + CurrencyName = NadekoBot.BotConfig.CurrencyName; + CurrencyPluralName = NadekoBot.BotConfig.CurrencyPluralName; + CurrencySign = NadekoBot.BotConfig.CurrencySign; } public static long GetCurrency(ulong id) diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 015b4328..29a996fc 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -38,32 +38,17 @@ namespace NadekoBot.Modules.Games private static ConcurrentHashSet usersRecentlyPicked { get; } = new ConcurrentHashSet(); - private static float chance { get; } - private static int cooldown { get; } private static Logger _log { get; } static PlantPickCommands() { _log = LogManager.GetCurrentClassLogger(); - var sw = Stopwatch.StartNew(); - #if !GLOBAL_NADEKO NadekoBot.Client.MessageReceived += PotentialFlowerGeneration; #endif - - using (var uow = DbHandler.UnitOfWork()) - { - var conf = uow.BotConfig.GetOrCreate(); - var x = - generationChannels = new ConcurrentHashSet(NadekoBot.AllGuildConfigs - .SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId))); - chance = conf.CurrencyGenerationChance; - cooldown = conf.CurrencyGenerationCooldown; - } - - sw.Stop(); - _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); + generationChannels = new ConcurrentHashSet(NadekoBot.AllGuildConfigs + .SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId))); } private static async void PotentialFlowerGeneration(SocketMessage imsg) @@ -84,10 +69,10 @@ namespace NadekoBot.Modules.Games var lastGeneration = lastGenerations.GetOrAdd(channel.Id, DateTime.MinValue); var rng = new NadekoRandom(); - if (DateTime.Now - TimeSpan.FromSeconds(cooldown) < lastGeneration) //recently generated in this channel, don't generate again + if (DateTime.Now - TimeSpan.FromSeconds(NadekoBot.BotConfig.CurrencyGenerationCooldown) < lastGeneration) //recently generated in this channel, don't generate again return; - var num = rng.Next(1, 101) + chance * 100; + var num = rng.Next(1, 101) + NadekoBot.BotConfig.CurrencyGenerationChance * 100; if (num > 100) { diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index 3278518e..10d652b4 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -13,14 +13,7 @@ namespace NadekoBot.Modules.Games [NadekoModule("Games", ">")] public partial class Games : DiscordModule { - private IEnumerable _8BallResponses { - get { - using (var uow = DbHandler.UnitOfWork()) - { - return uow.BotConfig.GetOrCreate().EightBallResponses.Select(ebr => ebr.Text); - } - } - } + private static IEnumerable _8BallResponses { get; } = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text); [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Help/Help.cs b/src/NadekoBot/Modules/Help/Help.cs index 87f31de0..4fee9ae6 100644 --- a/src/NadekoBot/Modules/Help/Help.cs +++ b/src/NadekoBot/Modules/Help/Help.cs @@ -15,26 +15,10 @@ namespace NadekoBot.Modules.Help [NadekoModule("Help", "-")] public partial class Help : DiscordModule { - private static string helpString { get; } + private static string helpString { get; } = NadekoBot.BotConfig.HelpString; public static string HelpString => String.Format(helpString, NadekoBot.Credentials.ClientId, NadekoBot.ModulePrefixes[typeof(Help).Name]); - public static string DMHelpString { get; } - - static Help() - { - - //todo don't cache this, just query db when someone wants -h - using (var uow = DbHandler.UnitOfWork()) - { - var config = uow.BotConfig.GetOrCreate(); - helpString = config.HelpString; - DMHelpString = config.DMHelpString; - } - } - - public Help() : base() - { - } + public static string DMHelpString { get; } = NadekoBot.BotConfig.DMHelpString; [NadekoCommand, Usage, Description, Aliases] public async Task Modules() diff --git a/src/NadekoBot/Modules/Utility/Commands/Remind.cs b/src/NadekoBot/Modules/Utility/Commands/Remind.cs index 58660bce..7d371c22 100644 --- a/src/NadekoBot/Modules/Utility/Commands/Remind.cs +++ b/src/NadekoBot/Modules/Utility/Commands/Remind.cs @@ -40,9 +40,8 @@ namespace NadekoBot.Modules.Utility using (var uow = DbHandler.UnitOfWork()) { reminders = uow.Reminders.GetAll().ToList(); - - RemindMessageFormat = uow.BotConfig.GetOrCreate().RemindMessageFormat; } + RemindMessageFormat = NadekoBot.BotConfig.RemindMessageFormat; foreach (var r in reminders) { diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 9f72a07f..a0bce533 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -38,6 +38,7 @@ namespace NadekoBot public static bool Ready { get; private set; } public static IEnumerable AllGuildConfigs { get; } + public static BotConfig BotConfig { get; } static NadekoBot() { @@ -47,6 +48,7 @@ namespace NadekoBot using (var uow = DbHandler.UnitOfWork()) { AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(); + BotConfig = uow.BotConfig.GetOrCreate(); } } @@ -98,10 +100,9 @@ namespace NadekoBot _log.Info("Connected"); //load commands and prefixes - using (var uow = DbHandler.UnitOfWork()) - { - ModulePrefixes = new ConcurrentDictionary(uow.BotConfig.GetOrCreate().ModulePrefixes.OrderByDescending(mp => mp.Prefix.Length).ToDictionary(m => m.ModuleName, m => m.Prefix)); - } + + ModulePrefixes = new ConcurrentDictionary(NadekoBot.BotConfig.ModulePrefixes.OrderByDescending(mp => mp.Prefix.Length).ToDictionary(m => m.ModuleName, m => m.Prefix)); + // start handling messages received in commandhandler await CommandHandler.StartHandling().ConfigureAwait(false); From 68a757bd3b5211bc62354635d89ce1be91207d3b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 12 Jan 2017 01:26:47 +0100 Subject: [PATCH 028/746] cleanup part 2 --- .../Modules/Gambling/Commands/AnimalRacing.cs | 2 +- .../Gambling/Commands/FlipCoinCommand.cs | 6 ++--- src/NadekoBot/Modules/Gambling/Gambling.cs | 24 +++++++++---------- .../Games/Commands/PlantAndPickCommands.cs | 16 ++++++------- src/NadekoBot/Modules/Pokemon/Pokemon.cs | 13 +++++----- src/NadekoBot/Services/CurrencyHandler.cs | 4 ++-- 6 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs index 8c5b0243..c8e612f6 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs @@ -248,7 +248,7 @@ namespace NadekoBot.Modules.Gambling if (amount > 0) if (!await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)u, "BetRace", amount, false).ConfigureAwait(false)) { - try { await raceChannel.SendErrorAsync($"{u.Mention} You don't have enough {Gambling.CurrencyName}s.").ConfigureAwait(false); } catch { } + try { await raceChannel.SendErrorAsync($"{u.Mention} You don't have enough {NadekoBot.BotConfig.CurrencyPluralName}.").ConfigureAwait(false); } catch { } return; } participants.Add(p); diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs index 389c7927..7190eb58 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs @@ -55,14 +55,14 @@ namespace NadekoBot.Modules.Gambling if (amount < 3) { - await Context.Channel.SendErrorAsync($"You can't bet less than 3{Gambling.CurrencySign}.") + await Context.Channel.SendErrorAsync($"You can't bet less than 3{CurrencySign}.") .ConfigureAwait(false); return; } var removed = await CurrencyHandler.RemoveCurrencyAsync(Context.User, "Betflip Gamble", amount, false).ConfigureAwait(false); if (!removed) { - await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {Gambling.CurrencyPluralName}.").ConfigureAwait(false); + await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {CurrencyPluralName}.").ConfigureAwait(false); return; } //heads = true @@ -85,7 +85,7 @@ namespace NadekoBot.Modules.Gambling if (isHeads == result) { var toWin = (int)Math.Round(amount * 1.8); - str = $"{Context.User.Mention}`You guessed it!` You won {toWin}{Gambling.CurrencySign}"; + str = $"{Context.User.Mention}`You guessed it!` You won {toWin}{CurrencySign}"; await CurrencyHandler.AddCurrencyAsync(Context.User, "Betflip Gamble", toWin, false).ConfigureAwait(false); } else diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 401f6995..3eaef165 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -70,11 +70,11 @@ namespace NadekoBot.Modules.Gambling var success = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Gift to {receiver.Username} ({receiver.Id}).", amount, true).ConfigureAwait(false); if (!success) { - await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {Gambling.CurrencyPluralName}.").ConfigureAwait(false); + await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {CurrencyPluralName}.").ConfigureAwait(false); return; } await CurrencyHandler.AddCurrencyAsync(receiver, $"Gift from {Context.User.Username} ({Context.User.Id}).", amount, true).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully sent {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} to {receiver.Mention}!").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully sent {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} to {receiver.Mention}!").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -94,7 +94,7 @@ namespace NadekoBot.Modules.Gambling await CurrencyHandler.AddCurrencyAsync(usrId, $"Awarded by bot owner. ({Context.User.Username}/{Context.User.Id})", amount).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} awarded {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} to <@{usrId}>!").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} awarded {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} to <@{usrId}>!").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -112,7 +112,7 @@ namespace NadekoBot.Modules.Gambling amount))) .ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"Awarded `{amount}` {Gambling.CurrencyPluralName} to `{users.Count}` users from `{role.Name}` role.") + await Context.Channel.SendConfirmAsync($"Awarded `{amount}` {CurrencyPluralName} to `{users.Count}` users from `{role.Name}` role.") .ConfigureAwait(false); } @@ -126,9 +126,9 @@ namespace NadekoBot.Modules.Gambling return; if (await CurrencyHandler.RemoveCurrencyAsync(user, $"Taken by bot owner.({Context.User.Username}/{Context.User.Id})", amount, true).ConfigureAwait(false)) - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully took {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} from {user}!").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully took {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from {user}!").ConfigureAwait(false); else - await Context.Channel.SendErrorAsync($"{Context.User.Mention} was unable to take {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} from {user} because the user doesn't have that much {Gambling.CurrencyPluralName}!").ConfigureAwait(false); + await Context.Channel.SendErrorAsync($"{Context.User.Mention} was unable to take {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from {user} because the user doesn't have that much {CurrencyPluralName}!").ConfigureAwait(false); } @@ -140,9 +140,9 @@ namespace NadekoBot.Modules.Gambling return; if (await CurrencyHandler.RemoveCurrencyAsync(usrId, $"Taken by bot owner.({Context.User.Username}/{Context.User.Id})", amount).ConfigureAwait(false)) - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully took {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} from <@{usrId}>!").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully took {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from <@{usrId}>!").ConfigureAwait(false); else - await Context.Channel.SendErrorAsync($"{Context.User.Mention} was unable to take {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} from `{usrId}` because the user doesn't have that much {Gambling.CurrencyPluralName}!").ConfigureAwait(false); + 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] @@ -159,7 +159,7 @@ namespace NadekoBot.Modules.Gambling if (userFlowers < amount) { - await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {Gambling.CurrencyPluralName}. You only have {userFlowers}{Gambling.CurrencySign}.").ConfigureAwait(false); + await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {CurrencyPluralName}. You only have {userFlowers}{CurrencySign}.").ConfigureAwait(false); return; } @@ -173,17 +173,17 @@ namespace NadekoBot.Modules.Gambling } else if (rng < 91) { - str += $"Congratulations! You won {amount * 2}{Gambling.CurrencySign} for rolling above 66"; + str += $"Congratulations! You won {amount * 2}{CurrencySign} for rolling above 66"; await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", amount * 2, false).ConfigureAwait(false); } else if (rng < 100) { - str += $"Congratulations! You won {amount * 3}{Gambling.CurrencySign} for rolling above 90."; + str += $"Congratulations! You won {amount * 3}{CurrencySign} for rolling above 90."; await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", amount * 3, false).ConfigureAwait(false); } else { - str += $"👑 Congratulations! You won {amount * 10}{Gambling.CurrencySign} for rolling **100**. 👑"; + str += $"👑 Congratulations! You won {amount * 10}{CurrencySign} for rolling **100**. 👑"; await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", amount * 10, false).ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 29a996fc..e3694b24 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -81,7 +81,7 @@ namespace NadekoBot.Modules.Games var sent = await channel.SendFileAsync( File.Open(GetRandomCurrencyImagePath(), FileMode.OpenOrCreate), "RandomFlower.jpg", - $"❗ A random { Gambling.Gambling.CurrencyName } appeared! Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`") + $"❗ A random { NadekoBot.BotConfig.CurrencyName } appeared! Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`") .ConfigureAwait(false); plantedFlowers.AddOrUpdate(channel.Id, new List() { sent }, (id, old) => { old.Add(sent); return old; }); @@ -114,8 +114,8 @@ namespace NadekoBot.Modules.Games await Task.WhenAll(msgs.Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false); - await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, $"Picked {Gambling.Gambling.CurrencyPluralName}", msgs.Count, false).ConfigureAwait(false); - var msg = await channel.SendConfirmAsync($"**{Context.User}** picked {msgs.Count}{Gambling.Gambling.CurrencySign}!").ConfigureAwait(false); + await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, $"Picked {NadekoBot.BotConfig.CurrencyPluralName}", msgs.Count, false).ConfigureAwait(false); + var msg = await channel.SendConfirmAsync($"**{Context.User}** picked {msgs.Count}{NadekoBot.BotConfig.CurrencySign}!").ConfigureAwait(false); msg.DeleteAfter(10); } finally @@ -131,21 +131,21 @@ namespace NadekoBot.Modules.Games [RequireContext(ContextType.Guild)] public async Task Plant() { - var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {Gambling.Gambling.CurrencyName}", 1, false).ConfigureAwait(false); + var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {NadekoBot.BotConfig.CurrencyName}", 1, false).ConfigureAwait(false); if (!removed) { - await Context.Channel.SendErrorAsync($"You don't have any {Gambling.Gambling.CurrencyPluralName}.").ConfigureAwait(false); + await Context.Channel.SendErrorAsync($"You don't have any {NadekoBot.BotConfig.CurrencyPluralName}.").ConfigureAwait(false); return; } var file = GetRandomCurrencyImagePath(); IUserMessage msg; - var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(Gambling.Gambling.CurrencyName[0]); + var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.BotConfig.CurrencyName[0]); - var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(vowelFirst ? "an" : "a")} {Gambling.Gambling.CurrencyName}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick"; + var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(vowelFirst ? "an" : "a")} {NadekoBot.BotConfig.CurrencyName}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick"; if (file == null) { - msg = await Context.Channel.SendConfirmAsync(Gambling.Gambling.CurrencySign).ConfigureAwait(false); + msg = await Context.Channel.SendConfirmAsync(NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); } else { diff --git a/src/NadekoBot/Modules/Pokemon/Pokemon.cs b/src/NadekoBot/Modules/Pokemon/Pokemon.cs index 7f51deb0..2ce50745 100644 --- a/src/NadekoBot/Modules/Pokemon/Pokemon.cs +++ b/src/NadekoBot/Modules/Pokemon/Pokemon.cs @@ -12,7 +12,6 @@ using System; using Newtonsoft.Json; using System.IO; using System.Collections.Concurrent; -using static NadekoBot.Modules.Gambling.Gambling; namespace NadekoBot.Modules.Pokemon { @@ -254,7 +253,7 @@ namespace NadekoBot.Modules.Pokemon { if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"Poke-Heal {target}", amount, true).ConfigureAwait(false)) { - try { await Context.Channel.SendMessageAsync($"{user.Mention} You don't have enough {CurrencyName}s.").ConfigureAwait(false); } catch { } + try { await Context.Channel.SendMessageAsync($"{user.Mention} You don't have enough {NadekoBot.BotConfig.CurrencyName}s.").ConfigureAwait(false); } catch { } return; } } @@ -267,15 +266,15 @@ namespace NadekoBot.Modules.Pokemon Stats[targetUser.Id].Hp = (targetStats.MaxHp / 2); if (target == "yourself") { - await Context.Channel.SendMessageAsync($"You revived yourself with one {CurrencySign}").ConfigureAwait(false); + await Context.Channel.SendMessageAsync($"You revived yourself with one {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); } else { - await Context.Channel.SendMessageAsync($"{user.Mention} revived {targetUser.Mention} with one {CurrencySign}").ConfigureAwait(false); + await Context.Channel.SendMessageAsync($"{user.Mention} revived {targetUser.Mention} with one {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); } return; } - await Context.Channel.SendMessageAsync($"{user.Mention} healed {targetUser.Mention} with one {CurrencySign}").ConfigureAwait(false); + await Context.Channel.SendMessageAsync($"{user.Mention} healed {targetUser.Mention} with one {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); return; } else @@ -329,7 +328,7 @@ namespace NadekoBot.Modules.Pokemon { if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"{user.Mention} change type to {typeTargeted}", amount, true).ConfigureAwait(false)) { - try { await Context.Channel.SendMessageAsync($"{user.Mention} You don't have enough {CurrencyName}s.").ConfigureAwait(false); } catch { } + try { await Context.Channel.SendMessageAsync($"{user.Mention} You don't have enough {NadekoBot.BotConfig.CurrencyName}s.").ConfigureAwait(false); } catch { } return; } } @@ -362,7 +361,7 @@ namespace NadekoBot.Modules.Pokemon } //Now for the response - await Context.Channel.SendMessageAsync($"Set type of {user.Mention} to {typeTargeted}{targetType.Icon} for a {CurrencySign}").ConfigureAwait(false); + await Context.Channel.SendMessageAsync($"Set type of {user.Mention} to {typeTargeted}{targetType.Icon} for a {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); } } diff --git a/src/NadekoBot/Services/CurrencyHandler.cs b/src/NadekoBot/Services/CurrencyHandler.cs index 01e649a2..f2d699a0 100644 --- a/src/NadekoBot/Services/CurrencyHandler.cs +++ b/src/NadekoBot/Services/CurrencyHandler.cs @@ -14,7 +14,7 @@ namespace NadekoBot.Services var success = await RemoveCurrencyAsync(author.Id, reason, amount); if (success && sendMessage) - try { await author.SendErrorAsync($"`You lost:` {amount} {Gambling.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { } + try { await author.SendErrorAsync($"`You lost:` {amount} {NadekoBot.BotConfig.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { } return success; } @@ -47,7 +47,7 @@ namespace NadekoBot.Services await AddCurrencyAsync(author.Id, reason, amount); if (sendMessage) - try { await author.SendConfirmAsync($"`You received:` {amount} {Gambling.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { } + 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) From 4dc4ab00d8fb901c890d7575ce0b9a980fb586b5 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 12 Jan 2017 01:32:02 +0100 Subject: [PATCH 029/746] Owner Ids in stats will show in new lines --- src/NadekoBot/Modules/Utility/Utility.cs | 2 +- src/NadekoBot/Services/Impl/StatsService.cs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 4a581108..5ffae5fc 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -281,7 +281,7 @@ namespace NadekoBot.Modules.Utility .AddField(efb => efb.WithName(Format.Bold("Commands Ran")).WithValue(stats.CommandsRan.ToString()).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Messages")).WithValue($"{stats.MessageCounter} ({stats.MessagesPerSecond:F2}/sec)").WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Memory")).WithValue($"{stats.Heap} MB").WithIsInline(true)) - .AddField(efb => efb.WithName(Format.Bold("Owner ID(s)")).WithValue(stats.OwnerIds).WithIsInline(true)) + .AddField(efb => efb.WithName(Format.Bold("Owner ID(s)")).WithValue(string.Join("\n", NadekoBot.Credentials.OwnerIds)).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Uptime")).WithValue(stats.GetUptimeString("\n")).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Presence")).WithValue($"{NadekoBot.Client.GetGuildsCount()} Servers\n{stats.TextChannels} Text Channels\n{stats.VoiceChannels} Voice Channels").WithIsInline(true)) #if !GLOBAL_NADEKO diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index c6d22070..12e701e9 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -27,7 +27,6 @@ namespace NadekoBot.Services.Impl public int TextChannels => _textChannels; private int _voiceChannels = 0; public int VoiceChannels => _voiceChannels; - public string OwnerIds => string.Join(", ", NadekoBot.Credentials.OwnerIds); Timer carbonitexTimer { get; } @@ -111,7 +110,7 @@ namespace NadekoBot.Services.Impl Author: [{Author}] | Library: [{Library}] Bot Version: [{BotVersion}] Bot ID: {curUser.Id} -Owner ID(s): {OwnerIds} +Owner ID(s): {string.Join(", ", NadekoBot.Credentials.OwnerIds)} Uptime: {GetUptimeString()} Servers: {client.GetGuildsCount()} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels} Commands Ran this session: {CommandsRan} From cdad149b0d565190b91ed7b3c26af8a374ccb495 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 12 Jan 2017 18:18:16 +0100 Subject: [PATCH 030/746] Fixed hangman bug? Fixed current time in logs --- src/NadekoBot/Modules/Administration/Commands/LogCommand.cs | 2 +- src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index c7e5d513..7215e321 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -29,7 +29,7 @@ namespace NadekoBot.Modules.Administration private static Logger _log { get; } private static string prettyCurrentTime => $"【{DateTime.Now:HH:mm:ss}】"; - private static string currentTime = $"{DateTime.Now:HH:mm:ss}"; + private static string currentTime => $"{DateTime.Now:HH:mm:ss}"; public static ConcurrentDictionary GuildLogSettings { get; } diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index 23b76e9b..b209ecdc 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -45,7 +45,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman HangmanObject[] termTypes; data.TryGetValue(type, out termTypes); - if (termTypes.Length == 0) + if (termTypes == null || termTypes.Length == 0) return null; return termTypes[rng.Next(0, termTypes.Length)]; From 2ecec9d0a4830cecfa6ab95191b24070a9260a96 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 12 Jan 2017 20:19:56 +0100 Subject: [PATCH 031/746] Now modifyable: Trivia flower win amount (default 0), minimum bet amount (default 3), betflip multiplier (default 1.8), currency drop amount (default 1), betroll multipliers on 67+/91+/100+ (default 2/3/10) --- .../NadekoSqliteContextModelSnapshot.cs | 42 +++++++++++++++++++ .../Gambling/Commands/FlipCoinCommand.cs | 6 +-- src/NadekoBot/Modules/Gambling/Gambling.cs | 6 +-- .../Games/Commands/PlantAndPickCommands.cs | 38 ++++++++++++----- .../Games/Commands/Trivia/TriviaGame.cs | 6 ++- .../Services/Database/Models/BotConfig.cs | 14 ++++++- .../Services/Database/NadekoContext.cs | 7 ++-- 7 files changed, 97 insertions(+), 22 deletions(-) diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 190e425e..4d94b193 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -96,8 +96,18 @@ namespace NadekoBot.Migrations 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"); @@ -118,10 +128,14 @@ namespace NadekoBot.Migrations b.Property("MigrationVersion"); + b.Property("MinimumBetAmount"); + b.Property("RemindMessageFormat"); b.Property("RotatingStatuses"); + b.Property("TriviaCurrencyReward"); + b.HasKey("Id"); b.ToTable("BotConfig"); @@ -191,6 +205,27 @@ namespace NadekoBot.Migrations 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") @@ -823,6 +858,13 @@ namespace NadekoBot.Migrations .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") diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs index 7190eb58..6cb49f71 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs @@ -53,9 +53,9 @@ namespace NadekoBot.Modules.Gambling if (guessStr != "H" && guessStr != "T" && guessStr != "HEADS" && guessStr != "TAILS") return; - if (amount < 3) + if (amount < NadekoBot.BotConfig.MinimumBetAmount) { - await Context.Channel.SendErrorAsync($"You can't bet less than 3{CurrencySign}.") + await Context.Channel.SendErrorAsync($"You can't bet less than {NadekoBot.BotConfig.MinimumBetAmount}{CurrencySign}.") .ConfigureAwait(false); return; } @@ -84,7 +84,7 @@ namespace NadekoBot.Modules.Gambling string str; if (isHeads == result) { - var toWin = (int)Math.Round(amount * 1.8); + var toWin = (int)Math.Round(amount * NadekoBot.BotConfig.BetflipMultiplier); str = $"{Context.User.Mention}`You guessed it!` You won {toWin}{CurrencySign}"; await CurrencyHandler.AddCurrencyAsync(Context.User, "Betflip Gamble", toWin, false).ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 3eaef165..76dbaa06 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -173,17 +173,17 @@ namespace NadekoBot.Modules.Gambling } else if (rng < 91) { - str += $"Congratulations! You won {amount * 2}{CurrencySign} for rolling above 66"; + str += $"Congratulations! You won {amount * NadekoBot.BotConfig.Betroll67Multiplier}{CurrencySign} for rolling above 66"; await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", amount * 2, false).ConfigureAwait(false); } else if (rng < 100) { - str += $"Congratulations! You won {amount * 3}{CurrencySign} for rolling above 90."; + str += $"Congratulations! You won {amount * NadekoBot.BotConfig.Betroll91Multiplier}{CurrencySign} for rolling above 90."; await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", amount * 3, false).ConfigureAwait(false); } else { - str += $"👑 Congratulations! You won {amount * 10}{CurrencySign} for rolling **100**. 👑"; + str += $"👑 Congratulations! You won {amount * NadekoBot.BotConfig.Betroll100Multiplier}{CurrencySign} for rolling **100**. 👑"; await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", amount * 10, false).ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index e3694b24..5f33df5b 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -78,14 +78,32 @@ namespace NadekoBot.Modules.Games { lastGenerations.AddOrUpdate(channel.Id, DateTime.Now, (id, old) => DateTime.Now); - var sent = await channel.SendFileAsync( - File.Open(GetRandomCurrencyImagePath(), FileMode.OpenOrCreate), - "RandomFlower.jpg", - $"❗ A random { NadekoBot.BotConfig.CurrencyName } appeared! Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`") - .ConfigureAwait(false); - plantedFlowers.AddOrUpdate(channel.Id, new List() { sent }, (id, old) => { old.Add(sent); return old; }); + var dropAmount = NadekoBot.BotConfig.CurrencyDropAmount; + if (dropAmount > 0) + { + var msgs = new List(dropAmount); + string firstPart; + if (dropAmount == 1) + { + firstPart = $"A random { NadekoBot.BotConfig.CurrencyName } appeared!"; + } + else + { + firstPart = $"{dropAmount} random { NadekoBot.BotConfig.CurrencyPluralName } appeared!"; + } + + var sent = await channel.SendFileAsync( + File.Open(GetRandomCurrencyImagePath(), FileMode.OpenOrCreate), + "RandomFlower.jpg", + $"❗ {firstPart} Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`") + .ConfigureAwait(false); + + msgs.Add(sent); + + plantedFlowers.AddOrUpdate(channel.Id, msgs, (id, old) => { old.AddRange(msgs); return old; }); + } } } catch { } @@ -108,11 +126,11 @@ namespace NadekoBot.Modules.Games List msgs; - try { await Context.Message.DeleteAsync().ConfigureAwait(false); } catch { } - if (!plantedFlowers.TryRemove(channel.Id, out msgs)) - return; + try { await Context.Message.DeleteAsync().ConfigureAwait(false); } catch { } + if (!plantedFlowers.TryRemove(channel.Id, out msgs)) + return; - await Task.WhenAll(msgs.Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false); + await Task.WhenAll(msgs.Where(m => m != null).Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false); await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, $"Picked {NadekoBot.BotConfig.CurrencyPluralName}", msgs.Count, false).ConfigureAwait(false); var msg = await channel.SendConfirmAsync($"**{Context.User}** picked {msgs.Count}{NadekoBot.BotConfig.CurrencySign}!").ConfigureAwait(false); diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs index 2c989738..9bc27191 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs @@ -2,6 +2,7 @@ using Discord.Net; using Discord.WebSocket; using NadekoBot.Extensions; +using NadekoBot.Services; using NLog; using System; using System.Collections.Concurrent; @@ -177,7 +178,10 @@ namespace NadekoBot.Modules.Games.Trivia if (Users[guildUser] == WinRequirement) { ShouldStopGame = true; - await channel.SendConfirmAsync("Trivia Game", $"{guildUser.Mention} guessed it and WON the game! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false); + try { await channel.SendConfirmAsync("Trivia Game", $"{guildUser.Mention} guessed it and WON the game! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false); } catch { } + var reward = NadekoBot.BotConfig.TriviaCurrencyReward; + if (reward > 0) + await CurrencyHandler.AddCurrencyAsync(guildUser.Id, "Won trivia", reward).ConfigureAwait(false); return; } await channel.SendConfirmAsync("Trivia Game", $"{guildUser.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false); diff --git a/src/NadekoBot/Services/Database/Models/BotConfig.cs b/src/NadekoBot/Services/Database/Models/BotConfig.cs index b20263c8..38faf9ba 100644 --- a/src/NadekoBot/Services/Database/Models/BotConfig.cs +++ b/src/NadekoBot/Services/Database/Models/BotConfig.cs @@ -18,12 +18,22 @@ namespace NadekoBot.Services.Database.Models public bool RotatingStatuses { get; set; } = false; public string RemindMessageFormat { get; set; } = "❗⏰**I've been told to remind you to '%message%' now by %user%.**⏰❗"; - - + + //currency public string CurrencySign { get; set; } = "🌸"; public string CurrencyName { get; set; } = "Nadeko Flower"; 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 CurrencyDropAmount { get; set; } = 1; + public float Betroll67Multiplier { get; set; } = 2; + public float Betroll91Multiplier { get; set; } = 3; + public float Betroll100Multiplier { get; set; } = 10; + public HashSet CommandPrices { get; set; } = new HashSet(); + + public HashSet EightBallResponses { get; set; } = new HashSet(); public HashSet RaceAnimals { get; set; } = new HashSet(); diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index e955409f..c2696b93 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -234,9 +234,10 @@ namespace NadekoBot.Services.Database #endregion - #region Protection - - + #region CommandPrice + modelBuilder.Entity() + .HasIndex(cp => cp.Price) + .IsUnique(); #endregion } } From 09691adcc69afea3b88401b2e6aa3b46c80b4d57 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 12 Jan 2017 20:26:55 +0100 Subject: [PATCH 032/746] Woopsie --- ...2185538_currency-modifications.Designer.cs | 984 ++++++++++++++++++ .../20170112185538_currency-modifications.cs | 120 +++ .../Services/Database/Models/CommandPrice.cs | 14 + 3 files changed, 1118 insertions(+) create mode 100644 src/NadekoBot/Migrations/20170112185538_currency-modifications.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170112185538_currency-modifications.cs create mode 100644 src/NadekoBot/Services/Database/Models/CommandPrice.cs diff --git a/src/NadekoBot/Migrations/20170112185538_currency-modifications.Designer.cs b/src/NadekoBot/Migrations/20170112185538_currency-modifications.Designer.cs new file mode 100644 index 00000000..2f585147 --- /dev/null +++ b/src/NadekoBot/Migrations/20170112185538_currency-modifications.Designer.cs @@ -0,0 +1,984 @@ +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("20170112185538_currency-modifications")] + partial class currencymodifications + { + 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("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("MigrationVersion"); + + b.Property("MinimumBetAmount"); + + 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/20170112185538_currency-modifications.cs b/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs new file mode 100644 index 00000000..bff8c726 --- /dev/null +++ b/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class currencymodifications : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "BetflipMultiplier", + table: "BotConfig", + nullable: false, + defaultValue: 0f); + + migrationBuilder.AddColumn( + name: "Betroll100Multiplier", + table: "BotConfig", + nullable: false, + defaultValue: 0f); + + migrationBuilder.AddColumn( + name: "Betroll67Multiplier", + table: "BotConfig", + nullable: false, + defaultValue: 0f); + + migrationBuilder.AddColumn( + name: "Betroll91Multiplier", + table: "BotConfig", + nullable: false, + defaultValue: 0f); + + migrationBuilder.AddColumn( + name: "CurrencyDropAmount", + table: "BotConfig", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "MinimumBetAmount", + table: "BotConfig", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "TriviaCurrencyReward", + table: "BotConfig", + nullable: false, + defaultValue: 0); + + migrationBuilder.CreateTable( + name: "CommandPrice", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + BotConfigId = table.Column(nullable: true), + CommandName = table.Column(nullable: true), + Price = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CommandPrice", x => x.Id); + table.ForeignKey( + name: "FK_CommandPrice_BotConfig_BotConfigId", + column: x => x.BotConfigId, + principalTable: "BotConfig", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_CommandPrice_BotConfigId", + table: "CommandPrice", + column: "BotConfigId"); + + migrationBuilder.CreateIndex( + name: "IX_CommandPrice_Price", + table: "CommandPrice", + column: "Price", + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CommandPrice"); + + migrationBuilder.DropColumn( + name: "BetflipMultiplier", + table: "BotConfig"); + + migrationBuilder.DropColumn( + name: "Betroll100Multiplier", + table: "BotConfig"); + + migrationBuilder.DropColumn( + name: "Betroll67Multiplier", + table: "BotConfig"); + + migrationBuilder.DropColumn( + name: "Betroll91Multiplier", + table: "BotConfig"); + + migrationBuilder.DropColumn( + name: "CurrencyDropAmount", + table: "BotConfig"); + + migrationBuilder.DropColumn( + name: "MinimumBetAmount", + table: "BotConfig"); + + migrationBuilder.DropColumn( + name: "TriviaCurrencyReward", + table: "BotConfig"); + } + } +} diff --git a/src/NadekoBot/Services/Database/Models/CommandPrice.cs b/src/NadekoBot/Services/Database/Models/CommandPrice.cs new file mode 100644 index 00000000..6bc10439 --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/CommandPrice.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Models +{ + public class CommandPrice : DbEntity + { + public int Price { get; set; } + public string CommandName { get; set; } + } +} From 70bbecbc8fb475cdcf7026dc4b2c229ded009f73 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 12 Jan 2017 23:49:17 +0100 Subject: [PATCH 033/746] Guild owners can now run permission commands without permission role --- src/NadekoBot/Services/CommandHandler.cs | 3 ++- .../Services/Database/Models/CommandPrice.cs | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index e4e30c4d..98665bf0 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -348,7 +348,8 @@ namespace NadekoBot.Services if (module.Name == typeof(Permissions).Name) { - if (!((IGuildUser)context.User).GetRoles().Any(r => r.Name.Trim().ToLowerInvariant() == pc.PermRole.Trim().ToLowerInvariant())) + var guildUser = (IGuildUser)context.User; + if (!guildUser.GetRoles().Any(r => r.Name.Trim().ToLowerInvariant() == pc.PermRole.Trim().ToLowerInvariant()) && guildUser.Id != guildUser.Guild.OwnerId) { return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"You need the **{pc.PermRole}** role in order to use permission commands.")); } diff --git a/src/NadekoBot/Services/Database/Models/CommandPrice.cs b/src/NadekoBot/Services/Database/Models/CommandPrice.cs index 6bc10439..d8b21d76 100644 --- a/src/NadekoBot/Services/Database/Models/CommandPrice.cs +++ b/src/NadekoBot/Services/Database/Models/CommandPrice.cs @@ -9,6 +9,20 @@ namespace NadekoBot.Services.Database.Models public class CommandPrice : DbEntity { public int Price { get; set; } + //this is unique public string CommandName { get; set; } + + public override int GetHashCode() => + CommandName.GetHashCode(); + + public override bool Equals(object obj) + { + var instance = obj as CommandPrice; + + if (instance == null) + return false; + + return instance.CommandName == CommandName; + } } } From e64714215e82b55cca60814746f4ace8fa9d0cd0 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 13 Jan 2017 00:55:47 +0100 Subject: [PATCH 034/746] Updated -donate paypal link --- src/NadekoBot/Modules/Help/Help.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Help/Help.cs b/src/NadekoBot/Modules/Help/Help.cs index 4fee9ae6..6f062fd5 100644 --- a/src/NadekoBot/Modules/Help/Help.cs +++ b/src/NadekoBot/Modules/Help/Help.cs @@ -161,7 +161,7 @@ namespace NadekoBot.Modules.Help await channel.SendConfirmAsync( $@"You can support the NadekoBot project on patreon. or -You can send donations to `nadekodiscordbot@gmail.com` +Paypal Don't forget to leave your discord name or id in the message. **Thank you** ♥️").ConfigureAwait(false); From ba47912c09ac8b5ead9dcca09982176cbf92a34f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 13 Jan 2017 02:29:26 +0100 Subject: [PATCH 035/746] Fixed linux guide --- docs/guides/Linux Guide.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/guides/Linux Guide.md b/docs/guides/Linux Guide.md index c2e7e797..506704d0 100644 --- a/docs/guides/Linux Guide.md +++ b/docs/guides/Linux Guide.md @@ -74,10 +74,6 @@ sudo apt-get dist-upgrade **NOTE:** If you are running **Debian 8 Jessie**, please, follow these steps: -`wget http://luxcaeli.de/installer.sh && sudo bash installer.sh` *Thanks to Eleria <3* - -In case you are not able to install it with **installer**, follow these steps: - ``` sudo apt-get update echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/debian-backports.list From bde8570008cfcd32179889b07b60f03eca815b65 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 13 Jan 2017 02:47:03 +0100 Subject: [PATCH 036/746] Updated guides --- docs/guides/Windows Guide.md | 29 ++++++++++++++--------------- docs/guides/mii-chan.md | 2 -- 2 files changed, 14 insertions(+), 17 deletions(-) delete mode 100644 docs/guides/mii-chan.md diff --git a/docs/guides/Windows Guide.md b/docs/guides/Windows Guide.md index 04554aa2..42b88b72 100644 --- a/docs/guides/Windows Guide.md +++ b/docs/guides/Windows Guide.md @@ -80,11 +80,20 @@ ________________________________________________________________________________ - You've updated and are running again, easy as that! ________________________________________________________________________________ -#### Setting Up NadekoBot For Music -##### Prerequisites -- 1) [FFMPEG][FFMPEG] installed. -- 2) Setting up API keys. +### Setting Up NadekoBot For Music +In order to have a functioning music module, you need to install ffmpeg and setup api keys. + +#### 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) +- EXTRACT it using `7zip` and place the FOLDER `ffmpeg-xxxxx-git-xxxxx-xxxx-static` inside **C:\ffmpeg** +- Before proceeding, check out this gif to set up `ffmpeg` PATH correctly ![LINK TO gif](http://i.imgur.com/aR5l1Hn.gif) *(thanks to PooPeePants#7135)* +- Go to My Computer, right click and select Properties. On the left tab, select Advanced System Settings. Under the Advanced tab, select Environmental Variables near the bottom. One of the variables should be called "Path". Add a semi-colon (;) to the end followed by your FFMPEG's **bin** install location (**for example C:\ffmpeg\ffmpeg-xxxxx-git-xxxxx-xxxx-static\bin**). Save and close. +- Setup your API keys as explained above. +- **Restart your computer** + +#### Api keys setup - Follow these steps on how to setup Google API keys: - Go to [Google Console][Google Console] and log in. - Create a new project (name does not matter). Once the project is created, go into "Enable and manage APIs." @@ -98,22 +107,12 @@ ________________________________________________________________________________ - Enter a name for the app and create it. - You will need to fill out an application form to request access to the Soundcloud API. - All requests for an API key must go through the review process, where applications will be reviewed on a case by case basis, in line with Soundcloud API Terms of Use. If your application is successful, you will receive an API key. -- **Restart your computer**. +- **Restart your computer** -####Manual `ffmpeg` setup -**Do this step in case you were not able to install `ffmpeg` with the installer.** -- 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) -- Extract it using `7zip` and place the folder `ffmpeg-xxxxx-git-xxxxx-xxxx-static` inside **C:\ffmpeg** -- Before proceeding, check out this gif to set up `ffmpeg` PATH correctly ![LINK TO gif](http://i.imgur.com/aR5l1Hn.gif) *(thanks to PooPeePants#7135)* -- Go to My Computer, right click and select Properties. On the left tab, select Advanced System Settings. Under the Advanced tab, select Environmental Variables near the bottom. One of the variables should be called "Path". Add a semi-colon (;) to the end followed by your FFMPEG's **bin** install location (**for example C:\ffmpeg\ffmpeg-xxxxx-git-xxxxx-xxxx-static\bin**). Save and close. -- Setup your API keys as explained above. -- Restart your computer. [.NET Core SDK]: https://www.microsoft.com/net/core#windowscmd [Git]: https://git-scm.com/download/win -[FFMPEG]: https://github.com/Soundofdarkness/FFMPEG-Inst/releases [7zip]: http://www.7-zip.org/download.html [DiscordApp]: https://discordapp.com/developers/applications/me [Notepad++]: https://notepad-plus-plus.org/ diff --git a/docs/guides/mii-chan.md b/docs/guides/mii-chan.md deleted file mode 100644 index 76be958b..00000000 --- a/docs/guides/mii-chan.md +++ /dev/null @@ -1,2 +0,0 @@ -Docs are in the air. -Kwoth is magic. From f1a0105e79262ac184077feb17b17f584b73b7f6 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 13 Jan 2017 02:50:59 +0100 Subject: [PATCH 037/746] Slight fix --- docs/guides/Windows Guide.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/guides/Windows Guide.md b/docs/guides/Windows Guide.md index 42b88b72..1f996b1c 100644 --- a/docs/guides/Windows Guide.md +++ b/docs/guides/Windows Guide.md @@ -7,12 +7,11 @@ ________________________________________________________________________________ #### Prerequisites - 1) [.NET Core SDK][.NET Core SDK] - 2) [Git][Git] -- 3) [FFMPEG][FFMPEG] -- 4) Google Account -- 5) Soundcloud Account (if you want soundcloud support) -- 6) [7zip][7zip] (or whatever you are using, WinRar) -- 7) [Notepad++][Notepad++] -- 8) Windows 8 or later +- 3) Google Account +- 4) Soundcloud Account (if you want soundcloud support) +- 5) [7zip][7zip] (or whatever you are using, WinRar) +- 6) [Notepad++][Notepad++] +- 7) Windows 8 or later ####Guide - Make sure you have installed both [Git][Git] and the [.NET Core SDK][.NET Core SDK]. From 93f4e52e07d851e4b854d7dc8682eab18577b2d5 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 13 Jan 2017 13:32:48 +0100 Subject: [PATCH 038/746] Betroll multiplier fix --- src/NadekoBot/Modules/Gambling/Gambling.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 76dbaa06..a52ea433 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -174,17 +174,17 @@ namespace NadekoBot.Modules.Gambling else if (rng < 91) { str += $"Congratulations! You won {amount * NadekoBot.BotConfig.Betroll67Multiplier}{CurrencySign} for rolling above 66"; - await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", amount * 2, false).ConfigureAwait(false); + await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", (int)(amount * NadekoBot.BotConfig.Betroll67Multiplier), false).ConfigureAwait(false); } else if (rng < 100) { str += $"Congratulations! You won {amount * NadekoBot.BotConfig.Betroll91Multiplier}{CurrencySign} for rolling above 90."; - await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", amount * 3, false).ConfigureAwait(false); + await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", (int)(amount * NadekoBot.BotConfig.Betroll91Multiplier), false).ConfigureAwait(false); } else { str += $"👑 Congratulations! You won {amount * NadekoBot.BotConfig.Betroll100Multiplier}{CurrencySign} for rolling **100**. 👑"; - await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", amount * 10, false).ConfigureAwait(false); + await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", (int)(amount * NadekoBot.BotConfig.Betroll100Multiplier), false).ConfigureAwait(false); } await Context.Channel.SendConfirmAsync(str).ConfigureAwait(false); From bd422746e43c919d0242910473afed74bf329741 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 13 Jan 2017 14:44:50 +0100 Subject: [PATCH 039/746] Trivia reward fix? --- src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs index 9bc27191..ce8f0ebc 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs @@ -181,7 +181,7 @@ namespace NadekoBot.Modules.Games.Trivia try { await channel.SendConfirmAsync("Trivia Game", $"{guildUser.Mention} guessed it and WON the game! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false); } catch { } var reward = NadekoBot.BotConfig.TriviaCurrencyReward; if (reward > 0) - await CurrencyHandler.AddCurrencyAsync(guildUser.Id, "Won trivia", reward).ConfigureAwait(false); + await CurrencyHandler.AddCurrencyAsync(guildUser, "Won trivia", reward, true).ConfigureAwait(false); return; } await channel.SendConfirmAsync("Trivia Game", $"{guildUser.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false); From 915059c8b855fa408b487cff4bae00b1e05e66e7 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 13 Jan 2017 14:52:01 +0100 Subject: [PATCH 040/746] generation fix --- .../Modules/Games/Commands/PlantAndPickCommands.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 5f33df5b..6bc9eb4e 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -82,7 +82,7 @@ namespace NadekoBot.Modules.Games if (dropAmount > 0) { - var msgs = new List(dropAmount); + var msgs = new IUserMessage[dropAmount]; string firstPart; if (dropAmount == 1) @@ -100,9 +100,9 @@ namespace NadekoBot.Modules.Games $"❗ {firstPart} Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`") .ConfigureAwait(false); - msgs.Add(sent); + msgs[0] = sent; - plantedFlowers.AddOrUpdate(channel.Id, msgs, (id, old) => { old.AddRange(msgs); return old; }); + plantedFlowers.AddOrUpdate(channel.Id, msgs.ToList(), (id, old) => { old.AddRange(msgs); return old; }); } } } From 29da8e53593392f54dd438c93e6e67fe5a1ea93d Mon Sep 17 00:00:00 2001 From: The Oddball Date: Fri, 13 Jan 2017 08:17:39 -0600 Subject: [PATCH 041/746] Update Latest.bat --- scripts/Latest.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Latest.bat b/scripts/Latest.bat index 2ee46775..8d59ec86 100644 --- a/scripts/Latest.bat +++ b/scripts/Latest.bat @@ -109,5 +109,5 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) RMDIR /S /Q "%installtemp%" >nul 2>&1 ECHO. ECHO Installation complete, press any key to close this window! - PAUSE >nul 2>&1 + timeout /t 5 del Latest.bat From 22bc4a6c000472bf7e6bece90eb2b92ee5d4da07 Mon Sep 17 00:00:00 2001 From: The Oddball Date: Fri, 13 Jan 2017 08:18:03 -0600 Subject: [PATCH 042/746] Update Stable.bat --- scripts/Stable.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Stable.bat b/scripts/Stable.bat index bef9df85..a2016889 100644 --- a/scripts/Stable.bat +++ b/scripts/Stable.bat @@ -109,5 +109,5 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) RMDIR /S /Q "%installtemp%" >nul 2>&1 ECHO. ECHO Installation complete, press any key to close this window! - PAUSE >nul 2>&1 + timeout /t 5 del Stable.bat From f98c7d109b95bf240eac2d52f2b74ba8340bc82d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 13 Jan 2017 16:31:33 +0100 Subject: [PATCH 043/746] Fixed current time > 1hr --- src/NadekoBot/Modules/Music/Classes/Song.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/Song.cs b/src/NadekoBot/Modules/Music/Classes/Song.cs index 0ee23fd4..04e49a70 100644 --- a/src/NadekoBot/Modules/Music/Classes/Song.cs +++ b/src/NadekoBot/Modules/Music/Classes/Song.cs @@ -47,13 +47,23 @@ namespace NadekoBot.Modules.Music.Classes public string PrettyFullTime => PrettyCurrentTime + " / " + PrettyTotalTime; - public string PrettyName => $"**[{SongInfo.Title.TrimTo(65)}]({songUrl})**"; + public string PrettyName => $"**[{SongInfo.Title.TrimTo(65)}]({songUrl})**"; public string PrettyInfo => $"{MusicPlayer.PrettyVolume} | {PrettyTotalTime} | {PrettyProvider} | {QueuerName}"; public string PrettyFullName => $"{PrettyName}\n\t\t`{PrettyTotalTime} | {PrettyProvider} | {QueuerName}`"; - public string PrettyCurrentTime => CurrentTime.ToString(@"mm\:ss"); + public string PrettyCurrentTime { + get { + var time = CurrentTime.ToString(@"mm\:ss"); + var hrs = (int)CurrentTime.TotalHours; + + if (hrs > 0) + return hrs + ":" + time; + else + return time; + } + } private string PrettyTotalTime { get { From ddd48a1d4cc6edcd4663a719a1a0f5fc6cc6a182 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 13 Jan 2017 16:37:01 +0100 Subject: [PATCH 044/746] Fixed youtube regex if it contains something after the id --- src/NadekoBot/Services/Impl/GoogleApiService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/Impl/GoogleApiService.cs b/src/NadekoBot/Services/Impl/GoogleApiService.cs index eaa066ff..7da7ad7b 100644 --- a/src/NadekoBot/Services/Impl/GoogleApiService.cs +++ b/src/NadekoBot/Services/Impl/GoogleApiService.cs @@ -51,7 +51,7 @@ namespace NadekoBot.Services.Impl return (await query.ExecuteAsync()).Items.Select(i => i.Id.PlaylistId); } - private readonly Regex YtVideoIdRegex = new Regex(@"(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)([a-zA-Z0-9_-]{6,11})", RegexOptions.Compiled); + private readonly Regex YtVideoIdRegex = new Regex(@"(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)(?[a-zA-Z0-9_-]{6,11})", RegexOptions.Compiled); public async Task> GetRelatedVideosAsync(string id, int count = 1) { From b2e6d6729e459fbbddbc6c4737098c5ddcfba3a4 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 14 Jan 2017 14:07:07 +0100 Subject: [PATCH 045/746] fixed default values in currency multipliers --- .../20170112185538_currency-modifications.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs b/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs index bff8c726..ad0af9e3 100644 --- a/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs +++ b/src/NadekoBot/Migrations/20170112185538_currency-modifications.cs @@ -12,37 +12,37 @@ namespace NadekoBot.Migrations name: "BetflipMultiplier", table: "BotConfig", nullable: false, - defaultValue: 0f); + defaultValue: 1.8f); migrationBuilder.AddColumn( name: "Betroll100Multiplier", table: "BotConfig", nullable: false, - defaultValue: 0f); + defaultValue: 10f); migrationBuilder.AddColumn( name: "Betroll67Multiplier", table: "BotConfig", nullable: false, - defaultValue: 0f); + defaultValue: 2f); migrationBuilder.AddColumn( name: "Betroll91Multiplier", table: "BotConfig", nullable: false, - defaultValue: 0f); + defaultValue: 3f); migrationBuilder.AddColumn( name: "CurrencyDropAmount", table: "BotConfig", nullable: false, - defaultValue: 0); + defaultValue: 1); migrationBuilder.AddColumn( name: "MinimumBetAmount", table: "BotConfig", nullable: false, - defaultValue: 0); + defaultValue: 3); migrationBuilder.AddColumn( name: "TriviaCurrencyReward", From 3d71e550ce4d681f826cbac6b6f0fbcf3c1fd8b8 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 14 Jan 2017 17:37:11 +0100 Subject: [PATCH 046/746] Slight changes. Couldn't get commandprices to work for now --- .../NadekoSqliteContextModelSnapshot.cs | 2 - .../Commands/CommandCostCommands.cs | 101 ++++++++++++++++++ .../Resources/CommandStrings.Designer.cs | 54 ++++++++++ src/NadekoBot/Resources/CommandStrings.resx | 18 ++++ src/NadekoBot/Services/CommandHandler.cs | 35 +++--- .../Services/Database/Models/BotConfig.cs | 5 + .../Services/Database/Models/CommandCost.cs | 27 +++++ .../Services/Database/Models/CommandPrice.cs | 13 --- .../Services/Database/NadekoContext.cs | 5 + .../Repositories/Impl/BotConfigRepository.cs | 1 + 10 files changed, 234 insertions(+), 27 deletions(-) create mode 100644 src/NadekoBot/Modules/Permissions/Commands/CommandCostCommands.cs create mode 100644 src/NadekoBot/Services/Database/Models/CommandCost.cs diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 4d94b193..91f7b6fc 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -4,8 +4,6 @@ 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 { diff --git a/src/NadekoBot/Modules/Permissions/Commands/CommandCostCommands.cs b/src/NadekoBot/Modules/Permissions/Commands/CommandCostCommands.cs new file mode 100644 index 00000000..e0ef1a29 --- /dev/null +++ b/src/NadekoBot/Modules/Permissions/Commands/CommandCostCommands.cs @@ -0,0 +1,101 @@ +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.Permissions +{ + public partial class Permissions + { + [Group] + public class CommandCostCommands : ModuleBase + { + private static readonly ConcurrentDictionary _commandCosts = new ConcurrentDictionary(); + public static IReadOnlyDictionary CommandCosts => _commandCosts; + + static CommandCostCommands() + { + //_commandCosts = new ConcurrentDictionary(NadekoBot.BotConfig.CommandCosts.ToDictionary( + // x => x.CommandName.Trim().ToUpperInvariant(), + // x => x.Cost)); + } + + [NadekoCommand, Usage, Description, Aliases] + public async Task CmdCosts(int page = 1) + { + var prices = _commandCosts.ToList(); + + if (!prices.Any()) + { + await Context.Channel.SendConfirmAsync("No costs set.").ConfigureAwait(false); + return; + } + + await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) => { + var embed = new EmbedBuilder().WithOkColor() + .WithTitle("Command Costs"); + var current = prices.Skip((curPage - 1) * 9) + .Take(9); + foreach (var price in current) + { + embed.AddField(efb => efb.WithName(price.Key).WithValue(price.Value.ToString()).WithIsInline(true)); + } + return embed; + }, prices.Count / 9).ConfigureAwait(false); + } + + //[NadekoCommand, Usage, Description, Aliases] + //public async Task CommandCost(int cost, CommandInfo cmd) + //{ + // if (cost < 0) + // return; + + // var cmdName = cmd.Aliases.First().ToLowerInvariant(); + + // var cmdPrice = new CommandCost() + // { + // CommandName = cmdName, + // Cost = cost + // }; + + // using (var uow = DbHandler.UnitOfWork()) + // { + // var bc = uow.BotConfig.GetOrCreate(); + + // if (cost != 0) + // { + // var elem = bc.CommandCosts.Where(cc => cc.CommandName == cmdPrice.CommandName).FirstOrDefault(); + // if (elem == null) + // bc.CommandCosts.Add(cmdPrice); + // else + // elem.Cost = cost; + + // _commandCosts.AddOrUpdate(cmdName, cost, (key, old) => cost); + // } + // else + // { + // bc.CommandCosts.RemoveAt(bc.CommandCosts.IndexOf(cmdPrice)); + // int throwaway; + // _commandCosts.TryRemove(cmdName, out throwaway); + // } + + // await uow.CompleteAsync().ConfigureAwait(false); + // } + + // if (cost == 0) + // await Context.Channel.SendConfirmAsync($"Removed the cost from the {Format.Bold(cmd.Name)} command.").ConfigureAwait(false); + // else + // await Context.Channel.SendConfirmAsync($"{Format.Bold(cmd.Name)} now costs {cost}{NadekoBot.BotConfig.CurrencySign} to run.").ConfigureAwait(false); + //} + } + } +} diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index e58dbbbb..0d4f9d0a 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -1760,6 +1760,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to cmdcosts. + /// + public static string cmdcosts_cmd { + get { + return ResourceManager.GetString("cmdcosts_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows a list of command costs. Paginated with 9 command per page.. + /// + public static string cmdcosts_desc { + get { + return ResourceManager.GetString("cmdcosts_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}cmdcosts` or `{0}cmdcosts 2`. + /// + public static string cmdcosts_usage { + get { + return ResourceManager.GetString("cmdcosts_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to color clr. /// @@ -1787,6 +1814,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to commandcost cmdcost. + /// + public static string commandcost_cmd { + get { + return ResourceManager.GetString("commandcost_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sets a price for a command. Running that command will take currency from users. Set 0 to remove the price.. + /// + public static string commandcost_desc { + get { + return ResourceManager.GetString("commandcost_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}cmdcost 0 !!q` or `{0}cmdcost 1 >8ball`. + /// + public static string commandcost_usage { + get { + return ResourceManager.GetString("commandcost_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to commands cmds. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index d2ef3388..5599995f 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2925,4 +2925,22 @@ `{0}antispamignore` + + cmdcosts + + + Shows a list of command costs. Paginated with 9 command per page. + + + `{0}cmdcosts` or `{0}cmdcosts 2` + + + commandcost cmdcost + + + Sets a price for a command. Running that command will take currency from users. Set 0 to remove the price. + + + `{0}cmdcost 0 !!q` or `{0}cmdcost 1 >8ball` + \ No newline at end of file diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 98665bf0..d0dc776b 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -32,9 +32,9 @@ namespace NadekoBot.Services { public const int GlobalCommandsCooldown = 1500; - private ShardedDiscordClient _client; - private CommandService _commandService; - private Logger _log; + private readonly ShardedDiscordClient _client; + private readonly CommandService _commandService; + private readonly Logger _log; private List ownerChannels { get; set; } @@ -100,8 +100,8 @@ namespace NadekoBot.Services BlacklistCommands.BlacklistedChannels.Contains(usrMsg.Channel.Id) || BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id); - - private async Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, Stopwatch sw) + const float oneThousandth = 1.0f / 1000; + private async Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int ticks) { await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false); _log.Info("Command Executed after {4}s\n\t" + @@ -113,10 +113,10 @@ namespace NadekoBot.Services (channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1} (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2} usrMsg.Content, // {3} - sw.Elapsed.TotalSeconds); + ticks * oneThousandth); } - private void LogErroredExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, Stopwatch sw) + private void LogErroredExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int ticks) { _log.Warn("Command Errored after {5}s\n\t" + "User: {0}\n\t" + @@ -129,7 +129,7 @@ namespace NadekoBot.Services (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2} usrMsg.Content,// {3} exec.Result.ErrorReason, // {4} - sw.Elapsed.TotalSeconds // {5} + ticks * oneThousandth // {5} ); } @@ -187,6 +187,8 @@ namespace NadekoBot.Services if (msg.Author.IsBot || !NadekoBot.Ready) //no bots, wait until bot connected and initialized return; + var execTime = Environment.TickCount; + var usrMsg = msg as SocketUserMessage; if (usrMsg == null) //has to be an user message, not system/other messages. return; @@ -226,17 +228,16 @@ namespace NadekoBot.Services string messageContent = usrMsg.Content; // execute the command and measure the time it took - var sw = Stopwatch.StartNew(); var exec = await ExecuteCommand(new CommandContext(_client.MainClient, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best); - sw.Stop(); + execTime = Environment.TickCount - execTime; if (exec.Result.IsSuccess) { - await LogSuccessfulExecution(usrMsg, exec, channel, sw).ConfigureAwait(false); + await LogSuccessfulExecution(usrMsg, exec, channel, execTime).ConfigureAwait(false); } else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand) { - LogErroredExecution(usrMsg, exec, channel, sw); + LogErroredExecution(usrMsg, exec, channel, execTime); if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception) { if (exec.PermissionCache != null && exec.PermissionCache.Verbose) @@ -354,6 +355,16 @@ namespace NadekoBot.Services return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"You need the **{pc.PermRole}** role in order to use permission commands.")); } } + + int price; + if (Permissions.CommandCostCommands.CommandCosts.TryGetValue(cmd.Aliases.First().Trim().ToLowerInvariant(), out price) && price > 0) + { + var success = await CurrencyHandler.RemoveCurrencyAsync(context.User.Id, $"Running {cmd.Name} command.", price).ConfigureAwait(false); + if (!success) + { + return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"Insufficient funds. You need {price}{NadekoBot.BotConfig.CurrencySign} to run this command.")); + } + } } diff --git a/src/NadekoBot/Services/Database/Models/BotConfig.cs b/src/NadekoBot/Services/Database/Models/BotConfig.cs index 38faf9ba..080770ec 100644 --- a/src/NadekoBot/Services/Database/Models/BotConfig.cs +++ b/src/NadekoBot/Services/Database/Models/BotConfig.cs @@ -31,6 +31,11 @@ namespace NadekoBot.Services.Database.Models public float Betroll67Multiplier { get; set; } = 2; public float Betroll91Multiplier { get; set; } = 3; public float Betroll100Multiplier { get; set; } = 10; + //public HashSet CommandCosts { get; set; } = new HashSet(); + + /// + /// I messed up, don't use + /// public HashSet CommandPrices { get; set; } = new HashSet(); diff --git a/src/NadekoBot/Services/Database/Models/CommandCost.cs b/src/NadekoBot/Services/Database/Models/CommandCost.cs new file mode 100644 index 00000000..da5a255e --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/CommandCost.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 CommandCost : DbEntity + { + public int Cost { get; set; } + public string CommandName { get; set; } + + public override int GetHashCode() => + CommandName.GetHashCode(); + + public override bool Equals(object obj) + { + var instance = obj as CommandCost; + + if (instance == null) + return false; + + return instance.CommandName == CommandName; + } + } +} diff --git a/src/NadekoBot/Services/Database/Models/CommandPrice.cs b/src/NadekoBot/Services/Database/Models/CommandPrice.cs index d8b21d76..8c7ea739 100644 --- a/src/NadekoBot/Services/Database/Models/CommandPrice.cs +++ b/src/NadekoBot/Services/Database/Models/CommandPrice.cs @@ -11,18 +11,5 @@ namespace NadekoBot.Services.Database.Models public int Price { get; set; } //this is unique public string CommandName { get; set; } - - public override int GetHashCode() => - CommandName.GetHashCode(); - - public override bool Equals(object obj) - { - var instance = obj as CommandPrice; - - if (instance == null) - return false; - - return instance.CommandName == CommandName; - } } } diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index c2696b93..b49439f6 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -235,9 +235,14 @@ namespace NadekoBot.Services.Database #endregion #region CommandPrice + //well, i failed modelBuilder.Entity() .HasIndex(cp => cp.Price) .IsUnique(); + + //modelBuilder.Entity() + // .HasIndex(cp => cp.CommandName) + // .IsUnique(); #endregion } } diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs index e1ab3893..2aa0bf83 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs @@ -17,6 +17,7 @@ namespace NadekoBot.Services.Database.Repositories.Impl .Include(bc => bc.Blacklist) .Include(bc => bc.EightBallResponses) .Include(bc => bc.ModulePrefixes) + //.Include(bc => bc.CommandCosts) .FirstOrDefault(); if (config == null) From 8c1d603fa7f24a21316e9776b4f42b0b9bbb9ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82?= Date: Sat, 14 Jan 2017 17:45:59 +0100 Subject: [PATCH 047/746] Update Linux Guide.md --- docs/guides/Linux Guide.md | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/docs/guides/Linux Guide.md b/docs/guides/Linux Guide.md index 506704d0..5fee13a3 100644 --- a/docs/guides/Linux Guide.md +++ b/docs/guides/Linux Guide.md @@ -28,15 +28,21 @@ If you entered your Droplets IP address correctly, it should show **login as:** ![img1](https://cdn.discordapp.com/attachments/251504306010849280/251504416019054592/git.gif) +Ubuntu: + `sudo apt-get install git -y` +CentOS: + +`yum -y install git` + **NOTE:** If the command is not being initiated, hit **Enter** ####Installing .NET Core SDK ![img2](https://cdn.discordapp.com/attachments/251504306010849280/251504746987388938/dotnet.gif) -Go to [this link](https://www.microsoft.com/net/core#ubuntu) provided by microsoft for instructions on how to get the most up to date version of the dotnet core sdk! +Go to [this link](https://www.microsoft.com/net/core#ubuntu) (for Ubuntu) or to [this link](https://www.microsoft.com/net/core#linuxcentos) (for CentOS) provided by microsoft for instructions on how to get the most up to date version of the dotnet core sdk! Make sure that you're on the correct page for your distribution of linux as the guides are different for the various distributions We'll go over the steps here for Ubuntu 16.04 anyway (these will **only** work on Ubuntu 16.04), accurate as of 25/11/2016 @@ -53,14 +59,29 @@ sudo apt-get update && sudo apt-get install dotnet-dev-1.0.0-preview2.1-003177 - ![img3](https://cdn.discordapp.com/attachments/251504306010849280/251505294654308353/libopus.gif) +Ubuntu: + `sudo apt-get install libopus0 opus-tools libopus-dev libsodium-dev -y` +CentOS: + +`yum -y install opus opus-devel` + ####Installing FFMPEG ![img4](https://cdn.discordapp.com/attachments/251504306010849280/251505443111829505/ffmpeg.gif) +Ubuntu: + `apt-get install ffmpeg -y` +Centos: + +``` +yum -y install http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm epel-release +yum -y install ffmpeg +``` + **NOTE:** If you are running **UBUNTU 14.04**, you must run these first: ``` @@ -84,8 +105,14 @@ sudo apt-get update && sudo apt-get install ffmpeg -y ![img5](https://cdn.discordapp.com/attachments/251504306010849280/251505519758409728/tmux.gif) +Ubuntu: + `sudo apt-get install tmux -y` +Centos: + +`yum -y install tmux` + ####Getting NadekoBot Use the following command to get and run `linuxAIO.sh`: From e4bcb5a71376f0715e8408e7c66955e31859e624 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 14 Jan 2017 17:59:35 +0100 Subject: [PATCH 048/746] If announcement table can't be found, migration will skip it --- .../Administration/Commands/Migration.cs | 84 +++++++++++-------- 1 file changed, 48 insertions(+), 36 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/Migration.cs b/src/NadekoBot/Modules/Administration/Commands/Migration.cs index 433cfc7b..3a917698 100644 --- a/src/NadekoBot/Modules/Administration/Commands/Migration.cs +++ b/src/NadekoBot/Modules/Administration/Commands/Migration.cs @@ -89,54 +89,66 @@ namespace NadekoBot.Modules.Administration db.Open(); var com = db.CreateCommand(); - com.CommandText = "SELECT * FROM Announcement"; - - var reader = com.ExecuteReader(); var i = 0; - while (reader.Read()) + try { - var gid = (ulong)(long)reader["ServerId"]; - var greet = (long)reader["Greet"] == 1; - var greetDM = (long)reader["GreetPM"] == 1; - var greetChannel = (ulong)(long)reader["GreetChannelId"]; - var greetMsg = (string)reader["GreetText"]; - var bye = (long)reader["Bye"] == 1; - var byeDM = (long)reader["ByePM"] == 1; - var byeChannel = (ulong)(long)reader["ByeChannelId"]; - var byeMsg = (string)reader["ByeText"]; - var grdel = false; - var byedel = grdel; - var gc = uow.GuildConfigs.For(gid, set => set); + com.CommandText = "SELECT * FROM Announcement"; - if (greetDM) - gc.SendDmGreetMessage = greet; - else - gc.SendChannelGreetMessage = greet; - gc.GreetMessageChannelId = greetChannel; - gc.ChannelGreetMessageText = greetMsg; + var reader = com.ExecuteReader(); + while (reader.Read()) + { + var gid = (ulong)(long)reader["ServerId"]; + var greet = (long)reader["Greet"] == 1; + var greetDM = (long)reader["GreetPM"] == 1; + var greetChannel = (ulong)(long)reader["GreetChannelId"]; + var greetMsg = (string)reader["GreetText"]; + var bye = (long)reader["Bye"] == 1; + var byeDM = (long)reader["ByePM"] == 1; + var byeChannel = (ulong)(long)reader["ByeChannelId"]; + var byeMsg = (string)reader["ByeText"]; + var grdel = false; + var byedel = grdel; + var gc = uow.GuildConfigs.For(gid, set => set); - gc.SendChannelByeMessage = bye; - gc.ByeMessageChannelId = byeChannel; - gc.ChannelByeMessageText = byeMsg; + if (greetDM) + gc.SendDmGreetMessage = greet; + else + gc.SendChannelGreetMessage = greet; + gc.GreetMessageChannelId = greetChannel; + gc.ChannelGreetMessageText = greetMsg; - gc.AutoDeleteGreetMessagesTimer = gc.AutoDeleteByeMessagesTimer = grdel ? 30 : 0; - _log.Info(++i); + gc.SendChannelByeMessage = bye; + gc.ByeMessageChannelId = byeChannel; + gc.ChannelByeMessageText = byeMsg; + + gc.AutoDeleteGreetMessagesTimer = gc.AutoDeleteByeMessagesTimer = grdel ? 30 : 0; + _log.Info(++i); + } + } + catch { + _log.Warn("Greet/bye messages won't be migrated"); } - var com2 = db.CreateCommand(); com.CommandText = "SELECT * FROM CurrencyState GROUP BY UserId"; i = 0; - var reader2 = com.ExecuteReader(); - while (reader2.Read()) + try { - _log.Info(++i); - var curr = new Currency() + var reader2 = com.ExecuteReader(); + while (reader2.Read()) { - Amount = (long)reader2["Value"], - UserId = (ulong)(long)reader2["UserId"] - }; - uow.Currency.Add(curr); + _log.Info(++i); + var curr = new Currency() + { + Amount = (long)reader2["Value"], + UserId = (ulong)(long)reader2["UserId"] + }; + uow.Currency.Add(curr); + } + } + catch + { + _log.Warn("Currency won't be migrated"); } db.Close(); try { File.Move("data/nadekobot.sqlite", "data/DELETE_ME_nadekobot.sqlite"); } catch { } From 659ba913a163e4cadb098fcac21af761b7f1d6fd Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 14 Jan 2017 18:25:08 +0100 Subject: [PATCH 049/746] fix #967 !!ap fix, !!lq fix (it shows info in footer again) --- .../Modules/Music/Classes/MusicControls.cs | 13 +++++++++---- src/NadekoBot/Modules/Music/Music.cs | 6 +++--- src/NadekoBot/_Extensions/Extensions.cs | 19 +++++++++++++++---- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index 1e822f0a..b705a388 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -140,9 +140,15 @@ namespace NadekoBot.Modules.Music.Classes RemoveSongAt(index, true); OnStarted(this, CurrentSong); - await CurrentSong.Play(audioClient, cancelToken); - - OnCompleted(this, CurrentSong); + try + { + await CurrentSong.Play(audioClient, cancelToken); + } + catch(OperationCanceledException) + { + OnCompleted(this, CurrentSong); + } + if (RepeatPlaylist) AddSong(CurrentSong, CurrentSong.QueuerName); @@ -151,7 +157,6 @@ namespace NadekoBot.Modules.Music.Classes AddSong(CurrentSong, 0); } - catch (OperationCanceledException) { } catch (Exception ex) { Console.WriteLine("Music thread almost crashed."); diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 381177a2..efdd9e6a 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -192,7 +192,7 @@ namespace NadekoBot.Modules.Music int startAt = itemsPerPage * (curPage - 1); var number = 0 + startAt; var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName($"Player Queue") + .WithAuthor(eab => eab.WithName($"Player Queue - Page {curPage}/{lastPage + 1}") .WithMusicIcon()) .WithDescription(string.Join("\n", musicPlayer.Playlist .Skip(startAt) @@ -217,7 +217,7 @@ namespace NadekoBot.Modules.Music } return embed; }; - await Context.Channel.SendPaginatedConfirmAsync(page, printAction, lastPage).ConfigureAwait(false); + await Context.Channel.SendPaginatedConfirmAsync(page, printAction, lastPage, false).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -814,7 +814,7 @@ namespace NadekoBot.Modules.Music .WithFooter(ef => ef.WithText(song.PrettyInfo))) .ConfigureAwait(false); - if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.Provider == "YouTube") + if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.ProviderType == MusicType.Normal) { await QueueSong(await queuer.Guild.GetCurrentUserAsync(), textCh, voiceCh, (await NadekoBot.Google.GetRelatedVideosAsync(song.SongInfo.Query, 4)).ToList().Shuffle().FirstOrDefault(), silent, musicType).ConfigureAwait(false); } diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index 310b5974..634dd34a 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -24,10 +24,13 @@ namespace NadekoBot.Extensions /// /// danny kamisama /// - public static async Task SendPaginatedConfirmAsync(this IMessageChannel channel, int currentPage, Func pageFunc, int? lastPage = null) + public static async Task SendPaginatedConfirmAsync(this IMessageChannel channel, int currentPage, Func pageFunc, int? lastPage = null, bool addPaginatedFooter = true) { lastPage += 1; - var embed = pageFunc(currentPage).AddPaginatedFooter(currentPage, lastPage); + var embed = pageFunc(currentPage); + + if(addPaginatedFooter) + embed.AddPaginatedFooter(currentPage, lastPage); var msg = await channel.EmbedAsync(embed) as IUserMessage; @@ -47,12 +50,20 @@ namespace NadekoBot.Extensions { if (currentPage == 1) return; - await msg.ModifyAsync(x => x.Embed = pageFunc(--currentPage).AddPaginatedFooter(currentPage, lastPage).Build()).ConfigureAwait(false); + var toSend = pageFunc(--currentPage); + if (addPaginatedFooter) + toSend.AddPaginatedFooter(currentPage, lastPage); + await msg.ModifyAsync(x => x.Embed = toSend.Build()).ConfigureAwait(false); } else if (r.Emoji.Name == arrow_right) { if (lastPage == null || lastPage > currentPage) - await msg.ModifyAsync(x => x.Embed = pageFunc(++currentPage).AddPaginatedFooter(currentPage, lastPage).Build()).ConfigureAwait(false); + { + var toSend = pageFunc(++currentPage); + if (addPaginatedFooter) + toSend.AddPaginatedFooter(currentPage, lastPage); + await msg.ModifyAsync(x => x.Embed = toSend.Build()).ConfigureAwait(false); + } } } catch (Exception ex) { Console.WriteLine(ex); } From ae90282070e7602d949ffc4b2f39a27b1e7a2cd7 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 14 Jan 2017 19:57:38 +0100 Subject: [PATCH 050/746] fixed .setstream --- src/NadekoBot/ShardedDiscordClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/ShardedDiscordClient.cs b/src/NadekoBot/ShardedDiscordClient.cs index a59dece7..5d6e9fa3 100644 --- a/src/NadekoBot/ShardedDiscordClient.cs +++ b/src/NadekoBot/ShardedDiscordClient.cs @@ -178,7 +178,7 @@ namespace NadekoBot public Task SetGame(string game) => Task.WhenAll(Clients.Select(ms => ms.SetGameAsync(game))); - public Task SetStream(string name, string url) => Task.WhenAll(Clients.Select(ms => ms.SetGameAsync(name, url, StreamType.NotStreaming))); + public Task SetStream(string name, string url) => Task.WhenAll(Clients.Select(ms => ms.SetGameAsync(name, url, StreamType.Twitch))); public Task SetStatus(SettableUserStatus status) => Task.WhenAll(Clients.Select(ms => ms.SetStatusAsync(SettableUserStatusToUserStatus(status)))); From 88eabf6d907dbb3e0ab40d067f7161f84db6efd7 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 14 Jan 2017 23:23:11 +0100 Subject: [PATCH 051/746] Better implementation of .se --- src/NadekoBot/Modules/Utility/Utility.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 5ffae5fc..bc413919 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -290,14 +290,12 @@ namespace NadekoBot.Modules.Utility ); } - private Regex emojiFinder { get; } = new Regex(@"<:(?.+?):(?\d*)>", RegexOptions.Compiled); [NadekoCommand, Usage, Description, Aliases] public async Task Showemojis([Remainder] string emojis) { - var matches = emojiFinder.Matches(emojis); + var tags = Context.Message.Tags.Where(t => t.Type == TagType.Emoji).Select(t => (Emoji)t.Value); - var result = string.Join("\n", matches.Cast() - .Select(m => $"**Name:** {m.Groups["name"]} **Link:** http://discordapp.com/api/emojis/{m.Groups["id"]}.png")); + var result = string.Join("\n", tags.Select(m => $"**Name:** {m} **Link:** {m.Url}")); if (string.IsNullOrWhiteSpace(result)) await Context.Channel.SendErrorAsync("No special emojis found."); From 3926bc707b4def335fc50b80f627f765a863aeab Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 02:08:14 +0100 Subject: [PATCH 052/746] ready to use new client --- .../Administration/Commands/LogCommand.cs | 4 +-- .../Commands/PlayingRotateCommands.cs | 2 +- .../Administration/Commands/SelfCommands.cs | 29 +++++++++++++++---- .../Modules/CustomReactions/Extensions.cs | 2 +- .../Games/Commands/CleverBotCommands.cs | 2 +- src/NadekoBot/Modules/Games/Games.cs | 2 +- src/NadekoBot/Modules/Help/Help.cs | 2 +- .../Commands/CrossServerTextChannel.cs | 2 +- src/NadekoBot/Modules/Utility/Utility.cs | 2 +- src/NadekoBot/NadekoBot.cs | 15 ++++++++-- src/NadekoBot/Services/CommandHandler.cs | 4 +-- src/NadekoBot/Services/Impl/StatsService.cs | 28 +++++++++--------- src/NadekoBot/ShardedDiscordClient.cs | 19 ++---------- src/NadekoBot/_Extensions/Extensions.cs | 2 +- 14 files changed, 64 insertions(+), 51 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index 7215e321..31dfbdc8 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -25,7 +25,7 @@ namespace NadekoBot.Modules.Administration { private const string clockEmojiUrl = "https://cdn.discordapp.com/attachments/155726317222887425/258309524966866945/clock.png"; - private static ShardedDiscordClient _client { get; } + private static DiscordShardedClient _client { get; } private static Logger _log { get; } private static string prettyCurrentTime => $"【{DateTime.Now:HH:mm:ss}】"; @@ -81,7 +81,7 @@ namespace NadekoBot.Modules.Administration _client.UserPresenceUpdated += _client_UserPresenceUpdated; _client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated; _client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS; - _client.GuildUserUpdated += _client_GuildUserUpdated; + _client.GuildMemberUpdated += _client_GuildUserUpdated; #if !GLOBAL_NADEKO _client.UserUpdated += _client_UserUpdated; #endif diff --git a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs index e454809a..f8817db9 100644 --- a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs @@ -50,7 +50,7 @@ namespace NadekoBot.Modules.Administration if (string.IsNullOrWhiteSpace(status)) continue; PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value())); - await NadekoBot.Client.SetGame(status); + await NadekoBot.Client.SetGameAsync(status).ConfigureAwait(false); } } catch (Exception ex) diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index 753f85f5..a087e6f2 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -28,7 +28,7 @@ namespace NadekoBot.Modules.Administration await Context.Channel.SendErrorAsync("⚠️ Cannot find that server").ConfigureAwait(false); return; } - if (server.OwnerId != NadekoBot.Client.CurrentUser().Id) + if (server.OwnerId != NadekoBot.Client.CurrentUser.Id) { await server.LeaveAsync().ConfigureAwait(false); await Context.Channel.SendConfirmAsync("✅ Left server " + server.Name).ConfigureAwait(false); @@ -57,7 +57,7 @@ namespace NadekoBot.Modules.Administration if (string.IsNullOrWhiteSpace(newName)) return; - await NadekoBot.Client.CurrentUser().ModifyAsync(u => u.Username = newName).ConfigureAwait(false); + await NadekoBot.Client.CurrentUser.ModifyAsync(u => u.Username = newName).ConfigureAwait(false); await Context.Channel.SendConfirmAsync($"Bot name changed to **{newName}**").ConfigureAwait(false); } @@ -66,7 +66,7 @@ namespace NadekoBot.Modules.Administration [OwnerOnly] public async Task SetStatus([Remainder] SettableUserStatus status) { - await NadekoBot.Client.SetStatus(status); + await NadekoBot.Client.SetStatusAsync(SettableUserStatusToUserStatus(status)).ConfigureAwait(false); await Context.Channel.SendConfirmAsync($"Bot status changed to **{status}**").ConfigureAwait(false); } @@ -86,7 +86,7 @@ namespace NadekoBot.Modules.Administration await sr.CopyToAsync(imgStream); imgStream.Position = 0; - await NadekoBot.Client.CurrentUser().ModifyAsync(u => u.Avatar = new Image(imgStream)).ConfigureAwait(false); + await NadekoBot.Client.CurrentUser.ModifyAsync(u => u.Avatar = new Image(imgStream)).ConfigureAwait(false); } } @@ -97,7 +97,7 @@ namespace NadekoBot.Modules.Administration [OwnerOnly] public async Task SetGame([Remainder] string game = null) { - await NadekoBot.Client.SetGame(game).ConfigureAwait(false); + await NadekoBot.Client.SetGameAsync(game).ConfigureAwait(false); await Context.Channel.SendConfirmAsync("👾 **New game set.**").ConfigureAwait(false); } @@ -108,7 +108,7 @@ namespace NadekoBot.Modules.Administration { name = name ?? ""; - await NadekoBot.Client.SetStream(name, url).ConfigureAwait(false); + await NadekoBot.Client.SetGameAsync(name, url, StreamType.Twitch).ConfigureAwait(false); await Context.Channel.SendConfirmAsync("ℹ️ **New stream set.**").ConfigureAwait(false); } @@ -169,6 +169,23 @@ namespace NadekoBot.Modules.Administration await Context.Channel.SendConfirmAsync("🆗").ConfigureAwait(false); } + + private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus) + { + switch (sus) + { + case SettableUserStatus.Online: + return UserStatus.Online; + case SettableUserStatus.Invisible: + return UserStatus.Invisible; + case SettableUserStatus.Idle: + return UserStatus.AFK; + case SettableUserStatus.Dnd: + return UserStatus.DoNotDisturb; + } + + return UserStatus.Online; + } } } } diff --git a/src/NadekoBot/Modules/CustomReactions/Extensions.cs b/src/NadekoBot/Modules/CustomReactions/Extensions.cs index c6fe16c7..a894ad2e 100644 --- a/src/NadekoBot/Modules/CustomReactions/Extensions.cs +++ b/src/NadekoBot/Modules/CustomReactions/Extensions.cs @@ -18,7 +18,7 @@ namespace NadekoBot.Modules.CustomReactions public static Dictionary> placeholders = new Dictionary>() { - {"%mention%", (ctx) => { return $"<@{NadekoBot.Client.CurrentUser().Id}>"; } }, + {"%mention%", (ctx) => { return $"<@{NadekoBot.Client.CurrentUser.Id}>"; } }, {"%user%", (ctx) => { return ctx.Author.Mention; } }, {"%rnduser%", (ctx) => { var ch = ctx.Channel as ITextChannel; diff --git a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs index 8197035b..b6544256 100644 --- a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs @@ -58,7 +58,7 @@ namespace NadekoBot.Modules.Games if (!CleverbotGuilds.TryGetValue(channel.Guild.Id, out cleverbot)) return false; - var nadekoId = NadekoBot.Client.CurrentUser().Id; + var nadekoId = NadekoBot.Client.CurrentUser.Id; var normalMention = $"<@{nadekoId}> "; var nickMention = $"<@!{nadekoId}> "; string message; diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index 10d652b4..8dfd7d5a 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -80,7 +80,7 @@ namespace NadekoBot.Modules.Games else if ((pick == 0 && nadekoPick == 1) || (pick == 1 && nadekoPick == 2) || (pick == 2 && nadekoPick == 0)) - msg = $"{NadekoBot.Client.CurrentUser().Mention} won! {GetRPSPick(nadekoPick)} beats {GetRPSPick(pick)}"; + msg = $"{NadekoBot.Client.CurrentUser.Mention} won! {GetRPSPick(nadekoPick)} beats {GetRPSPick(pick)}"; else msg = $"{Context.User.Mention} won! {GetRPSPick(pick)} beats {GetRPSPick(nadekoPick)}"; diff --git a/src/NadekoBot/Modules/Help/Help.cs b/src/NadekoBot/Modules/Help/Help.cs index 6f062fd5..4a561ca6 100644 --- a/src/NadekoBot/Modules/Help/Help.cs +++ b/src/NadekoBot/Modules/Help/Help.cs @@ -137,7 +137,7 @@ namespace NadekoBot.Modules.Help } helpstr.AppendLine($"{string.Join(" ", com.Aliases.Select(a => "`" + a + "`"))} | {string.Format(com.Summary, com.Module.GetPrefix())} {GetCommandRequirements(com)} | {string.Format(com.Remarks, com.Module.GetPrefix())}"); } - helpstr = helpstr.Replace(NadekoBot.Client.CurrentUser().Username , "@BotName"); + helpstr = helpstr.Replace(NadekoBot.Client.CurrentUser.Username , "@BotName"); File.WriteAllText("../../docs/Commands List.md", helpstr.ToString()); await Context.Channel.SendConfirmAsync("Commandlist Regenerated").ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs b/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs index b2ae710c..decd705f 100644 --- a/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs +++ b/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs @@ -31,7 +31,7 @@ namespace NadekoBot.Modules.Utility var channel = imsg.Channel as ITextChannel; if (channel == null) return; - if (msg.Author.Id == NadekoBot.Client.CurrentUser().Id) return; + if (msg.Author.Id == NadekoBot.Client.CurrentUser.Id) return; foreach (var subscriber in Subscribers) { var set = subscriber.Value; diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index bc413919..4730b433 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -277,7 +277,7 @@ namespace NadekoBot.Modules.Utility .WithIconUrl("https://cdn.discordapp.com/avatars/116275390695079945/b21045e778ef21c96d175400e779f0fb.jpg")) .AddField(efb => efb.WithName(Format.Bold("Author")).WithValue(stats.Author).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Library")).WithValue(stats.Library).WithIsInline(true)) - .AddField(efb => efb.WithName(Format.Bold("Bot ID")).WithValue(NadekoBot.Client.CurrentUser().Id.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName(Format.Bold("Bot ID")).WithValue(NadekoBot.Client.CurrentUser.Id.ToString()).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Commands Ran")).WithValue(stats.CommandsRan.ToString()).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Messages")).WithValue($"{stats.MessageCounter} ({stats.MessagesPerSecond:F2}/sec)").WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Memory")).WithValue($"{stats.Heap} MB").WithIsInline(true)) diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index a0bce533..a79597af 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -28,7 +28,7 @@ namespace NadekoBot public static CommandService CommandService { get; private set; } public static CommandHandler CommandHandler { get; private set; } - public static ShardedDiscordClient Client { get; private set; } + public static DiscordShardedClient Client { get; private set; } public static BotCredentials Credentials { get; private set; } public static GoogleApiService Google { get; private set; } @@ -59,7 +59,7 @@ namespace NadekoBot _log.Info("Starting NadekoBot v" + StatsService.BotVersion); //create client - Client = new ShardedDiscordClient(new DiscordSocketConfig + Client = new DiscordShardedClient(new DiscordSocketConfig { AudioMode = Discord.Audio.AudioMode.Outgoing, MessageCacheSize = 10, @@ -68,6 +68,8 @@ namespace NadekoBot ConnectionTimeout = int.MaxValue }); + Client.Log += Client_Log; + //initialize Services CommandService = new CommandService(new CommandServiceConfig() { CaseSensitiveCommands = false @@ -114,6 +116,15 @@ namespace NadekoBot Console.WriteLine(await Stats.Print().ConfigureAwait(false)); } + private Task Client_Log(LogMessage arg) + { + _log.Warn(arg.Message); + if (arg.Exception != null) + _log.Warn(arg.Exception); + + return Task.CompletedTask; + } + public async Task RunAndBlockAsync(params string[] args) { await RunAsync(args).ConfigureAwait(false); diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index d0dc776b..bb1c54f1 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -32,7 +32,7 @@ namespace NadekoBot.Services { public const int GlobalCommandsCooldown = 1500; - private readonly ShardedDiscordClient _client; + private readonly DiscordShardedClient _client; private readonly CommandService _commandService; private readonly Logger _log; @@ -46,7 +46,7 @@ namespace NadekoBot.Services public ConcurrentHashSet UsersOnShortCooldown { get; } = new ConcurrentHashSet(); private Timer clearUsersOnShortCooldown { get; } - public CommandHandler(ShardedDiscordClient client, CommandService commandService) + public CommandHandler(DiscordShardedClient client, CommandService commandService) { _client = client; _commandService = commandService; diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index 12e701e9..3424b7ba 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -1,4 +1,5 @@ using Discord; +using Discord.WebSocket; using NadekoBot.Extensions; using System; using System.Collections.Generic; @@ -11,7 +12,7 @@ namespace NadekoBot.Services.Impl { public class StatsService : IStatsService { - private ShardedDiscordClient client; + private DiscordShardedClient client; private DateTime started; public const string BotVersion = "1.1.0"; @@ -30,7 +31,7 @@ namespace NadekoBot.Services.Impl Timer carbonitexTimer { get; } - public StatsService(ShardedDiscordClient client, CommandHandler cmdHandler) + public StatsService(DiscordShardedClient client, CommandHandler cmdHandler) { this.client = client; @@ -39,15 +40,6 @@ namespace NadekoBot.Services.Impl this.client.MessageReceived += _ => Task.FromResult(MessageCounter++); cmdHandler.CommandExecuted += (_, e) => Task.FromResult(CommandsRan++); - this.client.Disconnected += _ => Reset(); - - this.client.Connected += () => - { - var guilds = this.client.GetGuilds(); - _textChannels = guilds.Sum(g => g.Channels.Where(cx => cx is ITextChannel).Count()); - _voiceChannels = guilds.Sum(g => g.Channels.Count) - _textChannels; - }; - this.client.ChannelCreated += (c) => { if (c is ITextChannel) @@ -90,7 +82,7 @@ namespace NadekoBot.Services.Impl { using (var content = new FormUrlEncodedContent( new Dictionary { - { "servercount", this.client.GetGuildsCount().ToString() }, + { "servercount", this.client.GetGuildCount().ToString() }, { "key", NadekoBot.Credentials.CarbonKey }})) { content.Headers.Clear(); @@ -103,16 +95,24 @@ namespace NadekoBot.Services.Impl catch { } }, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1)); } + + public void Initialize() + { + var guilds = this.client.GetGuilds(); + _textChannels = guilds.Sum(g => g.Channels.Where(cx => cx is ITextChannel).Count()); + _voiceChannels = guilds.Sum(g => g.Channels.Count) - _textChannels; + } + public Task Print() { - var curUser = client.CurrentUser(); + var curUser = client.CurrentUser; return Task.FromResult($@" Author: [{Author}] | Library: [{Library}] Bot Version: [{BotVersion}] Bot ID: {curUser.Id} Owner ID(s): {string.Join(", ", NadekoBot.Credentials.OwnerIds)} Uptime: {GetUptimeString()} -Servers: {client.GetGuildsCount()} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels} +Servers: {client.GetGuildCount()} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels} Commands Ran this session: {CommandsRan} Messages: {MessageCounter} [{MessagesPerSecond:F2}/sec] Heap: [{Heap} MB]"); } diff --git a/src/NadekoBot/ShardedDiscordClient.cs b/src/NadekoBot/ShardedDiscordClient.cs index 5d6e9fa3..268a9a54 100644 --- a/src/NadekoBot/ShardedDiscordClient.cs +++ b/src/NadekoBot/ShardedDiscordClient.cs @@ -107,7 +107,7 @@ namespace NadekoBot public DiscordSocketClient MainClient => Clients[0]; - public SocketSelfUser CurrentUser() => + public SocketSelfUser CurrentUser => Clients[0].CurrentUser; public IEnumerable GetGuilds() => @@ -182,22 +182,7 @@ namespace NadekoBot public Task SetStatus(SettableUserStatus status) => Task.WhenAll(Clients.Select(ms => ms.SetStatusAsync(SettableUserStatusToUserStatus(status)))); - private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus) - { - switch (sus) - { - case SettableUserStatus.Online: - return UserStatus.Online; - case SettableUserStatus.Invisible: - return UserStatus.Invisible; - case SettableUserStatus.Idle: - return UserStatus.AFK; - case SettableUserStatus.Dnd: - return UserStatus.DoNotDisturb; - } - - return UserStatus.Online; - } + } public enum SettableUserStatus diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index 634dd34a..d2dd36fc 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -203,7 +203,7 @@ namespace NadekoBot.Extensions await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(fileStream, fileName, caption, isTTS).ConfigureAwait(false); public static bool IsAuthor(this IUserMessage msg) => - NadekoBot.Client.CurrentUser().Id == msg.Author.Id; + NadekoBot.Client.CurrentUser.Id == msg.Author.Id; public static IEnumerable Members(this IRole role) => role.Guild.GetUsersAsync().GetAwaiter().GetResult().Where(u => u.RoleIds.Contains(role.Id)) ?? Enumerable.Empty(); From c603efa6439103b30039ca9997563a534206f3bf Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 02:28:33 +0100 Subject: [PATCH 053/746] new sharded client --- .../Administration/Commands/LogCommand.cs | 28 +++++++++---------- .../Administration/Commands/MuteCommands.cs | 2 +- .../Commands/PlayingRotateCommands.cs | 2 +- .../Commands/ServerGreetCommands.cs | 4 +-- .../Commands/VoicePlusTextCommands.cs | 2 +- .../Modules/Gambling/Commands/AnimalRacing.cs | 8 +++--- .../Modules/Games/Commands/Acropobia.cs | 2 +- .../Games/Commands/Hangman/HangmanGame.cs | 2 +- .../Games/Commands/PlantAndPickCommands.cs | 2 +- .../Modules/Games/Commands/PollCommands.cs | 2 +- .../Games/Commands/SpeedTypingCommands.cs | 2 +- .../Games/Commands/Trivia/TriviaGame.cs | 2 +- src/NadekoBot/Modules/Music/Music.cs | 2 +- src/NadekoBot/Modules/Utility/Utility.cs | 2 +- src/NadekoBot/Services/CommandHandler.cs | 4 +-- .../Discord/SocketMessageEventWrapper.cs | 12 ++++++-- src/NadekoBot/Services/Impl/StatsService.cs | 8 ++++++ src/NadekoBot/ShardedDiscordClient.cs | 4 +-- 18 files changed, 51 insertions(+), 39 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index 31dfbdc8..96ecee55 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -94,7 +94,7 @@ namespace NadekoBot.Modules.Administration MuteCommands.UserUnmuted += MuteCommands_UserUnmuted; } - private static async void _client_UserUpdated(SocketUser before, SocketUser uAfter) + private static async Task _client_UserUpdated(SocketUser before, SocketUser uAfter) { try { @@ -162,7 +162,7 @@ namespace NadekoBot.Modules.Administration { } } - private static async void _client_UserVoiceStateUpdated_TTS(SocketUser iusr, SocketVoiceState before, SocketVoiceState after) + private static async Task _client_UserVoiceStateUpdated_TTS(SocketUser iusr, SocketVoiceState before, SocketVoiceState after) { try { @@ -317,7 +317,7 @@ namespace NadekoBot.Modules.Administration catch { } } - private static async void _client_GuildUserUpdated(SocketGuildUser before, SocketGuildUser after) + private static async Task _client_GuildUserUpdated(SocketGuildUser before, SocketGuildUser after) { try { @@ -360,7 +360,7 @@ namespace NadekoBot.Modules.Administration catch { } } - private static async void _client_ChannelUpdated(IChannel cbefore, IChannel cafter) + private static async Task _client_ChannelUpdated(IChannel cbefore, IChannel cafter) { try { @@ -403,7 +403,7 @@ namespace NadekoBot.Modules.Administration catch { } } - private static async void _client_ChannelDestroyed(IChannel ich) + private static async Task _client_ChannelDestroyed(IChannel ich) { try { @@ -430,7 +430,7 @@ namespace NadekoBot.Modules.Administration catch { } } - private static async void _client_ChannelCreated(IChannel ich) + private static async Task _client_ChannelCreated(IChannel ich) { try { @@ -456,7 +456,7 @@ namespace NadekoBot.Modules.Administration catch (Exception ex) { _log.Warn(ex); } } - private static async void _client_UserVoiceStateUpdated(SocketUser iusr, SocketVoiceState before, SocketVoiceState after) + private static async Task _client_UserVoiceStateUpdated(SocketUser iusr, SocketVoiceState before, SocketVoiceState after) { try { @@ -498,7 +498,7 @@ namespace NadekoBot.Modules.Administration catch { } } - private static async void _client_UserPresenceUpdated(Optional optGuild, SocketUser usr, SocketPresence before, SocketPresence after) + private static async Task _client_UserPresenceUpdated(Optional optGuild, SocketUser usr, SocketPresence before, SocketPresence after) { try { @@ -532,7 +532,7 @@ namespace NadekoBot.Modules.Administration catch { } } - private static async void _client_UserLeft(IGuildUser usr) + private static async Task _client_UserLeft(IGuildUser usr) { try { @@ -556,7 +556,7 @@ namespace NadekoBot.Modules.Administration catch { } } - private static async void _client_UserJoined(IGuildUser usr) + private static async Task _client_UserJoined(IGuildUser usr) { try { @@ -580,7 +580,7 @@ namespace NadekoBot.Modules.Administration catch (Exception ex) { _log.Warn(ex); } } - private static async void _client_UserUnbanned(IUser usr, IGuild guild) + private static async Task _client_UserUnbanned(IUser usr, IGuild guild) { try { @@ -604,7 +604,7 @@ namespace NadekoBot.Modules.Administration catch (Exception ex) { _log.Warn(ex); } } - private static async void _client_UserBanned(IUser usr, IGuild guild) + private static async Task _client_UserBanned(IUser usr, IGuild guild) { try { @@ -627,7 +627,7 @@ namespace NadekoBot.Modules.Administration catch (Exception ex) { _log.Warn(ex); } } - private static async void _client_MessageDeleted(ulong arg1, Optional imsg) + private static async Task _client_MessageDeleted(ulong arg1, Optional imsg) { try @@ -664,7 +664,7 @@ namespace NadekoBot.Modules.Administration catch { } } - private static async void _client_MessageUpdated(Optional optmsg, SocketMessage imsg2) + private static async Task _client_MessageUpdated(Optional optmsg, SocketMessage imsg2) { try { diff --git a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs index b4993bf2..fc69d1cb 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs @@ -55,7 +55,7 @@ namespace NadekoBot.Modules.Administration _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); } - private static async void Client_UserJoined(IGuildUser usr) + private static async Task Client_UserJoined(IGuildUser usr) { try { diff --git a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs index f8817db9..89eeb2c5 100644 --- a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs @@ -67,7 +67,7 @@ namespace NadekoBot.Modules.Administration public static Dictionary> PlayingPlaceholders { get; } = new Dictionary> { - {"%servers%", () => NadekoBot.Client.GetGuildsCount().ToString()}, + {"%servers%", () => NadekoBot.Client.GetGuildCount().ToString()}, {"%users%", () => NadekoBot.Client.GetGuilds().Sum(s => s.Users.Count).ToString()}, {"%playing%", () => { var cnt = Music.Music.MusicPlayers.Count(kvp => kvp.Value.CurrentSong != null); diff --git a/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs index 80b8c394..9fa0971c 100644 --- a/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs @@ -26,7 +26,7 @@ namespace NadekoBot.Modules.Administration _log = LogManager.GetCurrentClassLogger(); } //todo optimize ASAP - private static async void UserLeft(IGuildUser user) + private static async Task UserLeft(IGuildUser user) { try { @@ -58,7 +58,7 @@ namespace NadekoBot.Modules.Administration catch { } } - private static async void UserJoined(IGuildUser user) + private static async Task UserJoined(IGuildUser user) { try { diff --git a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs index 1d76b1e7..a52a2c60 100644 --- a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs @@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Administration _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); } - private static async void UserUpdatedEventHandler(SocketUser iuser, SocketVoiceState before, SocketVoiceState after) + private static async Task UserUpdatedEventHandler(SocketUser iuser, SocketVoiceState before, SocketVoiceState after) { var user = (iuser as SocketGuildUser); var guild = user?.Guild; diff --git a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs index c8e612f6..f2b6404c 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs @@ -207,15 +207,15 @@ namespace NadekoBot.Modules.Gambling } - private void Client_MessageReceived(SocketMessage imsg) + private Task Client_MessageReceived(SocketMessage imsg) { var msg = imsg as SocketUserMessage; if (msg == null) - return; + return Task.CompletedTask; if (msg.IsAuthor() || !(imsg.Channel is ITextChannel) || imsg.Channel != raceChannel) - return; + return Task.CompletedTask; messagesSinceGameStarted++; - return; + return Task.CompletedTask; } private async Task CheckForFullGameAsync(CancellationToken cancelToken) diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs index 4160754b..2a7307bb 100644 --- a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -168,7 +168,7 @@ namespace NadekoBot.Modules.Games await End().ConfigureAwait(false); } - private async void PotentialAcro(SocketMessage arg) + private async Task PotentialAcro(SocketMessage arg) { try { diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index b209ecdc..4dcb54e9 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -114,7 +114,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman await GameChannel.EmbedAsync(embed.WithOkColor()).ConfigureAwait(false); } - private async void PotentialGuess(SocketMessage msg) + private async Task PotentialGuess(SocketMessage msg) { try { diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 6bc9eb4e..3782fe78 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -51,7 +51,7 @@ namespace NadekoBot.Modules.Games .SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId))); } - private static async void PotentialFlowerGeneration(SocketMessage imsg) + private static async Task PotentialFlowerGeneration(SocketMessage imsg) { try { diff --git a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs index 01d0477c..3088546c 100644 --- a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs @@ -153,7 +153,7 @@ namespace NadekoBot.Modules.Games await originalMessage.Channel.EmbedAsync(GetStats("POLL CLOSED")).ConfigureAwait(false); } - private async void Vote(SocketMessage imsg) + private async Task Vote(SocketMessage imsg) { try { diff --git a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs index bb69063f..47724820 100644 --- a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs @@ -106,7 +106,7 @@ namespace NadekoBot.Modules.Games NadekoBot.Client.MessageReceived += AnswerReceived; } - private async void AnswerReceived(SocketMessage imsg) + private async Task AnswerReceived(SocketMessage imsg) { try { diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs index ce8f0ebc..e9469358 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs @@ -143,7 +143,7 @@ namespace NadekoBot.Modules.Games.Trivia try { await channel.SendConfirmAsync("Trivia Game", "Stopping after this question.").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } } - private async void PotentialGuess(SocketMessage imsg) + private async Task PotentialGuess(SocketMessage imsg) { try { diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index efdd9e6a..b27afe25 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -37,7 +37,7 @@ namespace NadekoBot.Modules.Music Directory.CreateDirectory(MusicDataPath); } - private static async void Client_UserVoiceStateUpdated(SocketUser iusr, SocketVoiceState oldState, SocketVoiceState newState) + private static async Task Client_UserVoiceStateUpdated(SocketUser iusr, SocketVoiceState oldState, SocketVoiceState newState) { var usr = iusr as SocketGuildUser; if (usr == null || diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 4730b433..ef075c78 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -283,7 +283,7 @@ namespace NadekoBot.Modules.Utility .AddField(efb => efb.WithName(Format.Bold("Memory")).WithValue($"{stats.Heap} MB").WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Owner ID(s)")).WithValue(string.Join("\n", NadekoBot.Credentials.OwnerIds)).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Uptime")).WithValue(stats.GetUptimeString("\n")).WithIsInline(true)) - .AddField(efb => efb.WithName(Format.Bold("Presence")).WithValue($"{NadekoBot.Client.GetGuildsCount()} Servers\n{stats.TextChannels} Text Channels\n{stats.VoiceChannels} Voice Channels").WithIsInline(true)) + .AddField(efb => efb.WithName(Format.Bold("Presence")).WithValue($"{NadekoBot.Client.GetGuildCount()} Servers\n{stats.TextChannels} Text Channels\n{stats.VoiceChannels} Voice Channels").WithIsInline(true)) #if !GLOBAL_NADEKO .WithFooter(efb => efb.WithText($"Playing {Music.Music.MusicPlayers.Where(mp => mp.Value.CurrentSong != null).Count()} songs, {Music.Music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count)} queued.")) #endif diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index bb1c54f1..16bf8e89 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -180,7 +180,7 @@ namespace NadekoBot.Services return false; } - private async void MessageReceivedHandler(SocketMessage msg) + private async Task MessageReceivedHandler(SocketMessage msg) { try { @@ -228,7 +228,7 @@ namespace NadekoBot.Services string messageContent = usrMsg.Content; // execute the command and measure the time it took - var exec = await ExecuteCommand(new CommandContext(_client.MainClient, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best); + var exec = await ExecuteCommand(new CommandContext(_client, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best); execTime = Environment.TickCount - execTime; if (exec.Result.IsSuccess) diff --git a/src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs b/src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs index b73961a0..57153ac2 100644 --- a/src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs +++ b/src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs @@ -26,7 +26,7 @@ namespace NadekoBot.Services.Discord NadekoBot.Client.ReactionsCleared += Discord_ReactionsCleared; } - private void Discord_ReactionsCleared(ulong messageId, Optional reaction) + private Task Discord_ReactionsCleared(ulong messageId, Optional reaction) { try { @@ -34,9 +34,11 @@ namespace NadekoBot.Services.Discord OnReactionsCleared?.Invoke(); } catch { } + + return Task.CompletedTask; } - private void Discord_ReactionRemoved(ulong messageId, Optional arg2, SocketReaction reaction) + private Task Discord_ReactionRemoved(ulong messageId, Optional arg2, SocketReaction reaction) { try { @@ -44,9 +46,11 @@ namespace NadekoBot.Services.Discord OnReactionRemoved?.Invoke(reaction); } catch { } + + return Task.CompletedTask; } - private void Discord_ReactionAdded(ulong messageId, Optional message, SocketReaction reaction) + private Task Discord_ReactionAdded(ulong messageId, Optional message, SocketReaction reaction) { try { @@ -54,6 +58,8 @@ namespace NadekoBot.Services.Discord OnReactionAdded?.Invoke(reaction); } catch { } + + return Task.CompletedTask; } public void UnsubAll() diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index 3424b7ba..b65f3219 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -46,6 +46,8 @@ namespace NadekoBot.Services.Impl ++_textChannels; else if (c is IVoiceChannel) ++_voiceChannels; + + return Task.CompletedTask; }; this.client.ChannelDestroyed += (c) => @@ -54,6 +56,8 @@ namespace NadekoBot.Services.Impl --_textChannels; else if (c is IVoiceChannel) --_voiceChannels; + + return Task.CompletedTask; }; this.client.JoinedGuild += (g) => @@ -62,6 +66,8 @@ namespace NadekoBot.Services.Impl var vc = g.Channels.Count - tc; _textChannels += tc; _voiceChannels += vc; + + return Task.CompletedTask; }; this.client.LeftGuild += (g) => @@ -70,6 +76,8 @@ namespace NadekoBot.Services.Impl var vc = g.Channels.Count - tc; _textChannels -= tc; _voiceChannels -= vc; + + return Task.CompletedTask; }; this.carbonitexTimer = new Timer(async (state) => diff --git a/src/NadekoBot/ShardedDiscordClient.cs b/src/NadekoBot/ShardedDiscordClient.cs index 268a9a54..0a6e747a 100644 --- a/src/NadekoBot/ShardedDiscordClient.cs +++ b/src/NadekoBot/ShardedDiscordClient.cs @@ -180,9 +180,7 @@ namespace NadekoBot public Task SetStream(string name, string url) => Task.WhenAll(Clients.Select(ms => ms.SetGameAsync(name, url, StreamType.Twitch))); - public Task SetStatus(SettableUserStatus status) => Task.WhenAll(Clients.Select(ms => ms.SetStatusAsync(SettableUserStatusToUserStatus(status)))); - - + //public Task SetStatus(SettableUserStatus status) => Task.WhenAll(Clients.Select(ms => ms.SetStatusAsync(SettableUserStatusToUserStatus(status)))); } public enum SettableUserStatus From 0c58b14663b527855276c35b0efb8d58afd87047 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 02:29:44 +0100 Subject: [PATCH 054/746] Updated my discord.net fork --- Discord.Net | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Discord.Net b/Discord.Net index b9f76733..ac1fa80d 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit b9f767337d2b7c07ed76eb83c3bc5030109d5238 +Subproject commit ac1fa80d8ad07f5c7753279974efda29f4aca6f8 From 2715f36aa92c682e9dfca58033822f95b8222c74 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 02:45:20 +0100 Subject: [PATCH 055/746] Trivia error fix --- src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs index e9469358..08e9a9c8 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs @@ -56,7 +56,9 @@ namespace NadekoBot.Modules.Games.Trivia // load question CurrentQuestion = TriviaQuestionPool.Instance.GetRandomQuestion(oldQuestions); - if (CurrentQuestion == null) + if (CurrentQuestion == null || + string.IsNullOrWhiteSpace(CurrentQuestion.Answer) || + string.IsNullOrWhiteSpace(CurrentQuestion.Question)) { await channel.SendErrorAsync("Trivia Game", "Failed loading a question.").ConfigureAwait(false); return; @@ -74,7 +76,9 @@ namespace NadekoBot.Modules.Games.Trivia questionMessage = await channel.EmbedAsync(questionEmbed).ConfigureAwait(false); } - catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound || ex.StatusCode == System.Net.HttpStatusCode.Forbidden) + catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound || + ex.StatusCode == System.Net.HttpStatusCode.Forbidden || + ex.StatusCode == System.Net.HttpStatusCode.BadRequest) { return; } From c04ff7ff94ecfd386d042b1d8ee6b7fd3ab43ff7 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 03:18:13 +0100 Subject: [PATCH 056/746] Auto pause/unpause fixes. !!mv disabled as it breaks music. Better logs --- .../Modules/Music/Classes/MusicControls.cs | 14 +++--- src/NadekoBot/Modules/Music/Music.cs | 44 +++++++++++++------ src/NadekoBot/NadekoBot.cs | 2 +- 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index b705a388..701bc937 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -342,13 +342,13 @@ namespace NadekoBot.Modules.Music.Classes }); } - public Task MoveToVoiceChannel(IVoiceChannel voiceChannel) - { - if (audioClient?.ConnectionState != ConnectionState.Connected) - throw new InvalidOperationException("Can't move while bot is not connected to voice channel."); - PlaybackVoiceChannel = voiceChannel; - return PlaybackVoiceChannel.ConnectAsync(); - } + //public async Task MoveToVoiceChannel(IVoiceChannel voiceChannel) + //{ + // if (audioClient?.ConnectionState != ConnectionState.Connected) + // throw new InvalidOperationException("Can't move while bot is not connected to voice channel."); + // PlaybackVoiceChannel = voiceChannel; + // audioClient = await voiceChannel.ConnectAsync().ConfigureAwait(false); + //} public bool ToggleRepeatSong() => this.RepeatSong = !this.RepeatSong; diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index b27afe25..77e1608e 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -47,18 +47,36 @@ namespace NadekoBot.Modules.Music MusicPlayer player; if (!MusicPlayers.TryGetValue(usr.Guild.Id, out player)) return; + try { - var users = await player.PlaybackVoiceChannel.GetUsersAsync().Flatten().ConfigureAwait(false); + + + //if bot moved + if ((player.PlaybackVoiceChannel == oldState.VoiceChannel) && + usr.Id == NadekoBot.Client.CurrentUser.Id) + { + if (player.Paused && newState.VoiceChannel.Users.Count > 1) //unpause if there are people in the new channel + player.TogglePause(); + else if (!player.Paused && newState.VoiceChannel.Users.Count <= 1) // pause if there are no users in the new channel + player.TogglePause(); + + return; + } + + + //if some other user moved if ((player.PlaybackVoiceChannel == newState.VoiceChannel && //if joined first, and player paused, unpause player.Paused && - users.Count() == 2) || // keep in mind bot is in the channel (+1) + newState.VoiceChannel.Users.Count == 2) || // keep in mind bot is in the channel (+1) (player.PlaybackVoiceChannel == oldState.VoiceChannel && // if left last, and player unpaused, pause !player.Paused && - users.Count() == 1)) + oldState.VoiceChannel.Users.Count == 1)) { player.TogglePause(); + return; } + } catch { } } @@ -448,17 +466,17 @@ namespace NadekoBot.Modules.Music } - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - public async Task Move() - { + //[NadekoCommand, Usage, Description, Aliases] + //[RequireContext(ContextType.Guild)] + //public async Task Move() + //{ - MusicPlayer musicPlayer; - var voiceChannel = ((IGuildUser)Context.User).VoiceChannel; - if (voiceChannel == null || voiceChannel.Guild != Context.Guild || !MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) - return; - await musicPlayer.MoveToVoiceChannel(voiceChannel); - } + // MusicPlayer musicPlayer; + // var voiceChannel = ((IGuildUser)Context.User).VoiceChannel; + // if (voiceChannel == null || voiceChannel.Guild != Context.Guild || !MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) + // return; + // await musicPlayer.MoveToVoiceChannel(voiceChannel); + //} [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index a79597af..4b1eb8ec 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -118,7 +118,7 @@ namespace NadekoBot private Task Client_Log(LogMessage arg) { - _log.Warn(arg.Message); + _log.Warn(arg.Source + " | " + arg.Message); if (arg.Exception != null) _log.Warn(arg.Exception); From 9051e44125addbf46ff3499bcb893c2ff434951f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 03:35:13 +0100 Subject: [PATCH 057/746] Stats initialize --- src/NadekoBot/NadekoBot.cs | 1 + src/NadekoBot/ShardedDiscordClient.cs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 4b1eb8ec..f6e4c89d 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -95,6 +95,7 @@ namespace NadekoBot //connect await Client.LoginAsync(TokenType.Bot, Credentials.Token).ConfigureAwait(false); await Client.ConnectAsync().ConfigureAwait(false); + Stats.Initialize(); #if !GLOBAL_NADEKO await Client.DownloadAllUsersAsync().ConfigureAwait(false); #endif diff --git a/src/NadekoBot/ShardedDiscordClient.cs b/src/NadekoBot/ShardedDiscordClient.cs index 0a6e747a..daa5276e 100644 --- a/src/NadekoBot/ShardedDiscordClient.cs +++ b/src/NadekoBot/ShardedDiscordClient.cs @@ -60,7 +60,8 @@ namespace NadekoBot client.MessageReceived += arg1 => { if (arg1.Author == null || arg1.Author.IsBot) - return Task.CompletedTask; MessageReceived(arg1); + return Task.CompletedTask; + MessageReceived(arg1); return Task.CompletedTask; }; client.UserLeft += arg1 => { UserLeft(arg1); return Task.CompletedTask; }; From 33687d8e390e1e42859b57446a225e6c6ccf6b23 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 03:36:28 +0100 Subject: [PATCH 058/746] updated discord.net fork --- Discord.Net | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Discord.Net b/Discord.Net index ac1fa80d..9155ac02 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit ac1fa80d8ad07f5c7753279974efda29f4aca6f8 +Subproject commit 9155ac02ee245193825aa307fe43ed25eac9a45c From 9052d96f227b366f8be7a690f092539f795476f8 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 13:45:14 +0100 Subject: [PATCH 059/746] nsfw perf improvements. ~hentaibomb has 5sec cooldown. events trigger in parallel --- Discord.Net | 2 +- .../Administration/Commands/MuteCommands.cs | 6 +- src/NadekoBot/Modules/NSFW/NSFW.cs | 66 +++++++++++-------- src/NadekoBot/Modules/Searches/Searches.cs | 37 ++++++----- 4 files changed, 63 insertions(+), 48 deletions(-) diff --git a/Discord.Net b/Discord.Net index 9155ac02..e9dca6c6 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit 9155ac02ee245193825aa307fe43ed25eac9a45c +Subproject commit e9dca6c648b23bd9e957d8f9eee516df6ce11091 diff --git a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs index fc69d1cb..f37a26ec 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs @@ -37,8 +37,7 @@ namespace NadekoBot.Modules.Administration static MuteCommands() { var _log = LogManager.GetCurrentClassLogger(); - var sw = Stopwatch.StartNew(); - + var configs = NadekoBot.AllGuildConfigs; GuildMuteRoles = new ConcurrentDictionary(configs .Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName)) @@ -50,9 +49,6 @@ namespace NadekoBot.Modules.Administration )); NadekoBot.Client.UserJoined += Client_UserJoined; - - sw.Stop(); - _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); } private static async Task Client_UserJoined(IGuildUser usr) diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index 4db4c1b3..ae9f8568 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -20,6 +20,7 @@ namespace NadekoBot.Modules.NSFW public class NSFW : DiscordModule { private static ConcurrentDictionary AutoHentaiTimers { get; } = new ConcurrentDictionary(); + private static ConcurrentHashSet _hentaiBombBlacklist { get; } = new ConcurrentHashSet(); private async Task InternalHentai(IMessageChannel channel, string tag, bool noError) { @@ -56,7 +57,8 @@ namespace NadekoBot.Modules.NSFW await channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithImageUrl(link) - .WithDescription("Tag: " + tag)).ConfigureAwait(false); + .WithDescription("Tag: " + tag)) + .ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -90,7 +92,7 @@ namespace NadekoBot.Modules.NSFW if (tagsArr == null || tagsArr.Length == 0) await InternalHentai(Context.Channel, null, true).ConfigureAwait(false); else - await InternalHentai(Context.Channel, tagsArr[new NadekoRandom().Next(0, tagsArr.Length)], true); + await InternalHentai(Context.Channel, tagsArr[new NadekoRandom().Next(0, tagsArr.Length)], true).ConfigureAwait(false); } catch { } }, null, interval * 1000, interval * 1000); @@ -101,29 +103,39 @@ namespace NadekoBot.Modules.NSFW return t; }); - await Context.Channel.SendConfirmAsync($"Autohentai started. Reposting every {interval}s with one of the following tags:\n{string.Join(", ", tagsArr)}").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"Autohentai started. Reposting every {interval}s with one of the following tags:\n{string.Join(", ", tagsArr)}") + .ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] public async Task HentaiBomb([Remainder] string tag = null) { - tag = tag?.Trim() ?? ""; - tag = "rating%3Aexplicit+" + tag; - - var links = await Task.WhenAll(GetGelbooruImageLink(tag), - GetDanbooruImageLink(tag), - GetKonachanImageLink(tag), - GetYandereImageLink(tag)).ConfigureAwait(false); - - var linksEnum = links?.Where(l => l != null); - if (links == null || !linksEnum.Any()) - { - await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false); + if (!_hentaiBombBlacklist.Add(Context.User.Id)) return; - } + try + { + tag = tag?.Trim() ?? ""; + tag = "rating%3Aexplicit+" + tag; - await Context.Channel.SendMessageAsync(String.Join("\n\n", linksEnum)).ConfigureAwait(false); + var links = await Task.WhenAll(GetGelbooruImageLink(tag), + GetDanbooruImageLink(tag), + GetKonachanImageLink(tag), + GetYandereImageLink(tag)).ConfigureAwait(false); + + var linksEnum = links?.Where(l => l != null); + if (links == null || !linksEnum.Any()) + { + await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false); + return; + } + + await Context.Channel.SendMessageAsync(String.Join("\n\n", linksEnum)).ConfigureAwait(false); + } + finally { + await Task.Delay(5000).ConfigureAwait(false); + _hentaiBombBlacklist.TryRemove(Context.User.Id); + } } @@ -135,12 +147,13 @@ namespace NadekoBot.Modules.NSFW var url = await GetDanbooruImageLink(tag).ConfigureAwait(false); if (url == null) - await Context.Channel.SendErrorAsync(Context.User.Mention + " No results."); + await Context.Channel.SendErrorAsync(Context.User.Mention + " No results.").ConfigureAwait(false); else await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithDescription(Context.User.Mention + " " + tag) .WithImageUrl(url) - .WithFooter(efb => efb.WithText("Danbooru"))).ConfigureAwait(false); + .WithFooter(efb => efb.WithText("Danbooru"))) + .ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -172,7 +185,8 @@ namespace NadekoBot.Modules.NSFW await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithDescription(Context.User.Mention + " " + tag) .WithImageUrl(url) - .WithFooter(efb => efb.WithText("e621"))).ConfigureAwait(false); + .WithFooter(efb => efb.WithText("e621"))) + .ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -217,14 +231,14 @@ namespace NadekoBot.Modules.NSFW } } - public static async Task GetDanbooruImageLink(string tag) + public static Task GetDanbooruImageLink(string tag) => Task.Run(async () => { try { using (var http = new HttpClient()) { http.AddFakeHeaders(); - var data = await http.GetStreamAsync("https://danbooru.donmai.us/posts.xml?limit=100&tags=" + tag); + var data = await http.GetStreamAsync("https://danbooru.donmai.us/posts.xml?limit=100&tags=" + tag).ConfigureAwait(false); var doc = new XmlDocument(); doc.Load(data); var nodes = doc.GetElementsByTagName("file-url"); @@ -237,17 +251,17 @@ namespace NadekoBot.Modules.NSFW { return null; } - } + }); - public static async Task GetE621ImageLink(string tag) + public static Task GetE621ImageLink(string tag) => Task.Run(async () => { try { using (var http = new HttpClient()) { http.AddFakeHeaders(); - var data = await http.GetStreamAsync("http://e621.net/post/index.xml?tags=" + tag); + var data = await http.GetStreamAsync("http://e621.net/post/index.xml?tags=" + tag).ConfigureAwait(false); var doc = new XmlDocument(); doc.Load(data); var nodes = doc.GetElementsByTagName("file_url"); @@ -260,7 +274,7 @@ namespace NadekoBot.Modules.NSFW { return null; } - } + }); public static Task GetYandereImageLink(string tag) => Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Yandere); diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 16b67e18..60bebedf 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -517,7 +517,8 @@ namespace NadekoBot.Modules.Searches .WithAuthor(eab => eab.WithUrl(link) .WithIconUrl("http://res.cloudinary.com/urbandictionary/image/upload/a_exif,c_fit,h_200,w_200/v1394975045/b8oszuu3tbq7ebyo7vo1.jpg") .WithName(query)) - .WithDescription(desc)); + .WithDescription(desc)) + .ConfigureAwait(false); } catch { @@ -572,9 +573,9 @@ namespace NadekoBot.Modules.Searches var result = await http.GetStringAsync("https://en.wikipedia.org//w/api.php?action=query&format=json&prop=info&redirects=1&formatversion=2&inprop=url&titles=" + Uri.EscapeDataString(query)); var data = JsonConvert.DeserializeObject(result); if (data.Query.Pages[0].Missing) - await Context.Channel.SendErrorAsync("That page could not be found."); + await Context.Channel.SendErrorAsync("That page could not be found.").ConfigureAwait(false); else - await Context.Channel.SendMessageAsync(data.Query.Pages[0].FullUrl); + await Context.Channel.SendMessageAsync(data.Query.Pages[0].FullUrl).ConfigureAwait(false); } } @@ -588,7 +589,7 @@ namespace NadekoBot.Modules.Searches img.BackgroundColor(new ImageSharp.Color(color)); - await Context.Channel.SendFileAsync(img.ToStream(), $"{color}.png"); + await Context.Channel.SendFileAsync(img.ToStream(), $"{color}.png").ConfigureAwait(false); ; } [NadekoCommand, Usage, Description, Aliases] @@ -642,7 +643,7 @@ namespace NadekoBot.Modules.Searches var response = $@"`Title:` {found["title"].ToString()} `Quality:` {found["quality"]} `URL:` {await NadekoBot.Google.ShortenUrl(found["url"].ToString()).ConfigureAwait(false)}"; - await Context.Channel.SendMessageAsync(response); + await Context.Channel.SendMessageAsync(response).ConfigureAwait(false); } catch { @@ -774,20 +775,24 @@ namespace NadekoBot.Modules.Searches } try { - using (var http = new HttpClient()) + var toReturn = await Task.Run(async () => { - http.AddFakeHeaders(); - var data = await http.GetStreamAsync(website); - var doc = new XmlDocument(); - doc.Load(data); + using (var http = new HttpClient()) + { + http.AddFakeHeaders(); + var data = await http.GetStreamAsync(website).ConfigureAwait(false); + var doc = new XmlDocument(); + doc.Load(data); - var node = doc.LastChild.ChildNodes[new NadekoRandom().Next(0, doc.LastChild.ChildNodes.Count)]; + var node = doc.LastChild.ChildNodes[new NadekoRandom().Next(0, doc.LastChild.ChildNodes.Count)]; - var url = node.Attributes["file_url"].Value; - if (!url.StartsWith("http")) - url = "https:" + url; - return url; - } + var url = node.Attributes["file_url"].Value; + if (!url.StartsWith("http")) + url = "https:" + url; + return url; + } + }).ConfigureAwait(false); + return toReturn; } catch { From 228c6b57cfd7070a915761c023af7d1c061735d1 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 14:28:06 +0100 Subject: [PATCH 060/746] version upped to 1.1.1 --- 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 b65f3219..86955b83 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.0"; + public const string BotVersion = "1.1.1"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From 33d810f03602927b8efe00cc3cd8aea030ec830f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 15:05:17 +0100 Subject: [PATCH 061/746] $startevent added --- .../Resources/CommandStrings.Designer.cs | 27 +++++++++++++++++++ src/NadekoBot/Resources/CommandStrings.resx | 9 +++++++ 2 files changed, 36 insertions(+) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 0d4f9d0a..717d767e 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -7295,6 +7295,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to startevent. + /// + public static string startevent_cmd { + get { + return ResourceManager.GetString("startevent_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Starts one of the events seen on public nadeko.. + /// + public static string startevent_desc { + get { + return ResourceManager.GetString("startevent_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}startevent flowerreaction`. + /// + public static string startevent_usage { + get { + return ResourceManager.GetString("startevent_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to startwar sw. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 5599995f..1e9ba5d4 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2943,4 +2943,13 @@ `{0}cmdcost 0 !!q` or `{0}cmdcost 1 >8ball` + + startevent + + + Starts one of the events seen on public nadeko. + + + `{0}startevent flowerreaction` + \ No newline at end of file From d8d657e6bd9569891144e529297c2cbb8abb2a20 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 15:09:48 +0100 Subject: [PATCH 062/746] Flower event is prettier --- .../Gambling/Commands/CurrencyEvents.cs | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs new file mode 100644 index 00000000..9b43f842 --- /dev/null +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -0,0 +1,67 @@ +using Discord; +using Discord.Commands; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Services; +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 + { + [Group] + public class CurrencyEvents : ModuleBase + { + public enum CurrencyEvent + { + FlowerReaction + } + //flower reaction event + public static readonly ConcurrentHashSet _flowerReactionAwardedUsers = new ConcurrentHashSet(); + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task StartEvent(CurrencyEvent e) + { + var channel = (ITextChannel)Context.Channel; + + switch (e) + { + case CurrencyEvent.FlowerReaction: + await FlowerReactionEvent(Context).ConfigureAwait(false); + break; + default: + break; + } + } + + + public static async Task FlowerReactionEvent(CommandContext Context) + { + var msg = await Context.Channel.SendConfirmAsync("Flower reaction event started!", + "Add 🌸 reaction to this message to get 100" + NadekoBot.BotConfig.CurrencySign, + footer: "This event is active for 24 hours.") + .ConfigureAwait(false); + await msg.AddReactionAsync("🌸").ConfigureAwait(false); + using (msg.OnReaction(async (r) => + { + if (r.Emoji.Name == "🌸" && r.User.IsSpecified && _flowerReactionAwardedUsers.Add(r.User.Value.Id)) + { + try { await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, true).ConfigureAwait(false); } catch { } + } + })) + { + await Task.Delay(TimeSpan.FromHours(24)).ConfigureAwait(false); + try { await msg.DeleteAsync().ConfigureAwait(false); } catch { } + _flowerReactionAwardedUsers.Clear(); + } + } + } + } +} From 257dbcb73824c312a5f970ee5ca76b54bc9bdd6b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 18:04:22 +0100 Subject: [PATCH 063/746] Fixed flower event hopefully. --- .../Gambling/Commands/CurrencyEvents.cs | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs index 9b43f842..d7d2d783 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -30,15 +30,19 @@ namespace NadekoBot.Modules.Gambling public async Task StartEvent(CurrencyEvent e) { var channel = (ITextChannel)Context.Channel; - - switch (e) + try { - case CurrencyEvent.FlowerReaction: - await FlowerReactionEvent(Context).ConfigureAwait(false); - break; - default: - break; + + switch (e) + { + case CurrencyEvent.FlowerReaction: + await FlowerReactionEvent(Context).ConfigureAwait(false); + break; + default: + break; + } } + catch { } } @@ -48,13 +52,26 @@ namespace NadekoBot.Modules.Gambling "Add 🌸 reaction to this message to get 100" + NadekoBot.BotConfig.CurrencySign, footer: "This event is active for 24 hours.") .ConfigureAwait(false); - await msg.AddReactionAsync("🌸").ConfigureAwait(false); + try { await msg.AddReactionAsync("🌸").ConfigureAwait(false); } + catch + { + try { await msg.AddReactionAsync("🌸").ConfigureAwait(false); } + catch + { + try { await msg.DeleteAsync().ConfigureAwait(false); } + catch { } + } + } using (msg.OnReaction(async (r) => { - if (r.Emoji.Name == "🌸" && r.User.IsSpecified && _flowerReactionAwardedUsers.Add(r.User.Value.Id)) + try { - try { await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, true).ConfigureAwait(false); } catch { } + if (r.Emoji.Name == "🌸" && r.User.IsSpecified && _flowerReactionAwardedUsers.Add(r.User.Value.Id)) + { + try { await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, true).ConfigureAwait(false); } catch { } + } } + catch { } })) { await Task.Delay(TimeSpan.FromHours(24)).ConfigureAwait(false); From d65b415ee8842fbd9994545407f4b3a4eda83058 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 18:25:53 +0100 Subject: [PATCH 064/746] Music warning removed --- src/NadekoBot/Modules/Music/Music.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 77e1608e..0cb28121 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -37,17 +37,17 @@ namespace NadekoBot.Modules.Music Directory.CreateDirectory(MusicDataPath); } - private static async Task Client_UserVoiceStateUpdated(SocketUser iusr, SocketVoiceState oldState, SocketVoiceState newState) + private static Task Client_UserVoiceStateUpdated(SocketUser iusr, SocketVoiceState oldState, SocketVoiceState newState) { var usr = iusr as SocketGuildUser; if (usr == null || oldState.VoiceChannel == newState.VoiceChannel) - return; + return Task.CompletedTask; MusicPlayer player; if (!MusicPlayers.TryGetValue(usr.Guild.Id, out player)) - return; - + return Task.CompletedTask; + try { @@ -61,7 +61,7 @@ namespace NadekoBot.Modules.Music else if (!player.Paused && newState.VoiceChannel.Users.Count <= 1) // pause if there are no users in the new channel player.TogglePause(); - return; + return Task.CompletedTask; } @@ -74,11 +74,12 @@ namespace NadekoBot.Modules.Music oldState.VoiceChannel.Users.Count == 1)) { player.TogglePause(); - return; + return Task.CompletedTask; } } catch { } + return Task.CompletedTask; } [NadekoCommand, Usage, Description, Aliases] From a3fd6442b7e0abcd756d06d0218525e97e1d7a34 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 18:56:18 +0100 Subject: [PATCH 065/746] download users --- src/NadekoBot/NadekoBot.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index f6e4c89d..85246fa3 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -95,10 +95,8 @@ namespace NadekoBot //connect await Client.LoginAsync(TokenType.Bot, Credentials.Token).ConfigureAwait(false); await Client.ConnectAsync().ConfigureAwait(false); - Stats.Initialize(); -#if !GLOBAL_NADEKO await Client.DownloadAllUsersAsync().ConfigureAwait(false); -#endif + Stats.Initialize(); _log.Info("Connected"); @@ -107,6 +105,7 @@ namespace NadekoBot ModulePrefixes = new ConcurrentDictionary(NadekoBot.BotConfig.ModulePrefixes.OrderByDescending(mp => mp.Prefix.Length).ToDictionary(m => m.ModuleName, m => m.Prefix)); // start handling messages received in commandhandler + await CommandHandler.StartHandling().ConfigureAwait(false); await CommandService.AddModulesAsync(this.GetType().GetTypeInfo().Assembly).ConfigureAwait(false); From bbdcfb3a16bfe36892b25c7c724d24b092f1d807 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 18:57:01 +0100 Subject: [PATCH 066/746] Update discord.net --- Discord.Net | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Discord.Net b/Discord.Net index e9dca6c6..f27cce08 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit e9dca6c648b23bd9e957d8f9eee516df6ce11091 +Subproject commit f27cce0854abc42b92d29f9040625238a8991999 From c80e1e07973a5256ddbfe8c976d03fe7e2a66919 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 19:18:16 +0100 Subject: [PATCH 067/746] Don't send messages on event --- src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs index d7d2d783..4dfa935f 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -68,7 +68,7 @@ namespace NadekoBot.Modules.Gambling { if (r.Emoji.Name == "🌸" && r.User.IsSpecified && _flowerReactionAwardedUsers.Add(r.User.Value.Id)) { - try { await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, true).ConfigureAwait(false); } catch { } + try { await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, false).ConfigureAwait(false); } catch { } } } catch { } From 8593127b1bd2c44aef605b40f0804f8fb677e145 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 15 Jan 2017 21:41:35 +0100 Subject: [PATCH 068/746] No logging on self hosted bots --- src/NadekoBot/NadekoBot.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 85246fa3..c8084905 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -67,8 +67,9 @@ namespace NadekoBot TotalShards = Credentials.TotalShards, ConnectionTimeout = int.MaxValue }); - +#if GLOBAL_NADEKO Client.Log += Client_Log; +#endif //initialize Services CommandService = new CommandService(new CommandServiceConfig() { From 42f7cc9a315f72566379d3c74ac63fc185e7e96c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 16 Jan 2017 14:15:24 +0100 Subject: [PATCH 069/746] Fixed empty log spam --- src/NadekoBot/Modules/Administration/Commands/LogCommand.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index 96ecee55..db339d4f 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -397,6 +397,8 @@ namespace NadekoBot.Modules.Administration .AddField(efb => efb.WithName("Old Topic").WithValue(beforeTextChannel.Topic)) .AddField(efb => efb.WithName("New Topic").WithValue(afterTextChannel.Topic)); } + else + return; await logChannel.EmbedAsync(embed).ConfigureAwait(false); } From 619e83e0be78b0d638cd5bf5ee35572e1b3c448a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 16 Jan 2017 14:27:39 +0100 Subject: [PATCH 070/746] 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 071/746] 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 072/746] 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 073/746] 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 074/746] 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 075/746] 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 076/746] 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 077/746] 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 078/746] 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 079/746] 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 080/746] .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 081/746] .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 082/746] 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 083/746] $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 zcmZ`+X*ARi7yiu*BWw0OBa95i5Pw3JLRmtVnz4nkW?u#g&7{Rh%9edAk$nl-jfs(^ zMFyi8Od(#|C^3q7{Xf1R-gD1$pL3t*Jm;SK@e*vUFY$6oasdFqYkt|p?uc!VaN`*C zsNcC{6mvvuzQ$LK0if{-_r3@F(JYI(Y;SkPA zA|81>Hs&VA4l!TW3vZ{mIGz|ZTpEpxS`B`qro`?{6XX@Xns)c4tm&N}ZwfbD|^n$$egAno4QLu=m59bfUK7?%K zc1HX7`glaWx!pVD<+DL=XBB+>TNshBM2|?gt`3S^d_Mj2Do9cZG6(7bn-D+ZoM%D= zh-%u*o0eaG4)KoE=N8k;x}vjo-^bJ|pKq*U%{<_E3c0`#Wzc4KU_d@jE4Vn^d71O6 zu-}(%Dc!;padie@r8`wF?e}go#fsIs1z{zdI_KQL zGQa`Qwbr_r^ho>Yrny&IT$wNkbI?t^aYMR+_jco(c`dp1bkswai3In;MC}DZ=ON9o z86{C!tn0##NVT3Qic_DX25KG2pE9BeR=-lTZJrn^8A{kIV0~}~s}eTA1U9O+ul>=aMjp~ADXWx zI~BY5HTHynSsh#N1_JWA6SFIPd4 zVDR-IV{3K_RGs9!)cRKb45a^hJlCdJ;K+5kZtFlZyJ$Q%ws*0wPPqHU6yHo#sSf#IMFt2PMUC zZP^EV8WMA7fAj8;c!4MUdqtR=@mipABjG`3DUxOlXw{x4W#pE@@=Zq}rG%x|z8P`AGM$|M64-eEv z>GI#DCD>k8KUeDbB>wu72~^mx_NqmxLtL^z$pi79UmdX9=jLeG!|(EXdzqD9c5%cA zhv=^!oml&Q_&zlgvWt_nvZ~A)tjs~VQmF}k#r;qHJsxsSxbgOxxX9&abte{SSNM!y z;cP|12S?k2ewVw?>$Q`@B8EBr>~Z%uusW>{!t@YRceN;D>2bZ-X6>*9n9p0;0I=0v zdG*umRuF4-ashimO^aJeM296}0 zHs7XhgG`Jt?F{{fd@Wc;DWYd2ME6|u}PK+B?AXLaYSA?CsGBU|Yw>z+l) zCziJtk3%aYjGf-Li>y)(p){Qfp1ZZ8{T_hO=Kf?bXH?RPKJ!jGHCes@N-4TLZDxkZ zj2fT@WfZ<>LR8l6AMVUGHe!|uvoaIjopU}&uVMAqiAAf{JXY#!+4sc!=hCVmzl z0E7&aLR!UX*p6o_ovz#DW0$PsEfPI%q=wnn^)$O(+~}F;@~c%Ov~37yuQ+A12Ks|3 z$ZH+YE`H};eRgT4YoRo=rP;2d0>>%mU|kx{C1kSvpA#jHdQkoa(mhqC%{kG7P?!7Y zFG#zjpfQ=g+0|Fi4~r}iR<`9^qwEVySfO=<;5s6`cp^ zCX{TxQ)8n%a-XU?ezN~N-9REyc_C>>l(Q&a3P<|!u+%rQS*ql+_*y?-Xy6Z&<4jgY zEJKE)e%Onq=zG7a!f0vw(dltdook!2s#y2eN+$p(Y>nx940GrR z&*Pw?Y>m`lN=k%z@ohwC5;?VLl-#MEUs>m6HxcMgAg40>blT0&8Y|RTf1+0U^>hS|?lz4fP$&9vn`T1=8CYOF(b7w%K|M0c}wwi zXslM$P(sMJL8}&cN-X}o-Lo4J%<1^FGKZ{)ns2D$(cXZIGR}_t4(#(d#a_dtq?dl@6+@fJB!&k zAMq-{lB%yLweP62nj~iDI}p?6wXwkeOvFe55Sdhub4w6krKDcu%vfry5$2Qae{FZT zGJBR=TGc}?CET|A9UtRllYdW(f+OwXMkjt{VwNkQsNU{Gg{-~H`|f0K2ZGb{?#2A3 zoX}cUh1E5Z=b71+TIY|h_7m8Q!fR*UCX-WOLy~C|8@C7A(gCg3jIO?*fB?;RVags2 zppo*MpwGCKU1sb76xYMTWQaY&hv(@ayxn^aP;2cb4! zV2Zg4OqT82lBz%5!Rrl~KVIO)2vQkClb1woy&3W-F*8USEJiK}aCBl^$8$&|ej?4A ze3LRfe>HhrB;AQ71I*%#MdHb^Q~N^cGsd|*I* z5Uuwj&8V5zTmPlw##=H;?H27+p2B;>(DX{2DDzMzUDR>;~uP7Tm{+A{>rrOK4pBJ+nps8KvL?F># zDFi|Ha-MgZLF(Z+TcK}UYnTxq0oEz0_cf>xd2V9<^mPR>Q!|>{Kx%Uem)i)iYP8S4 zsj_C@rtmdf=FlZUf6uGGY^q^=(5=s4^LXIX`~fP5_lYb3(=}gF2x0C%!JJssp5={s z0nP!Bv5M1rR2z72S!DJs&-Bhp(J6YhOPfCf@s`wUY3jJmdi zx`r-NTUP^l2C1csMDigCtp5oFg?Rb<-1`54J3;D}M*)d{H`s^xL`HjrdjrN^A)el{ e=0P65-ge#|Ubn)Ay#M`;0CQ7ole!D;cmE6ZI%R7B 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 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 Date: Wed, 18 Jan 2017 17:02:48 +0100 Subject: [PATCH 084/746] 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 085/746] 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 086/746] ~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 087/746] 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 088/746] 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 089/746] 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 090/746] $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 091/746] $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 092/746] 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 093/746] 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 094/746] $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 095/746] 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 096/746] 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"; From 58973b9082b0cf35ed07b4cd67743213fe6abb06 Mon Sep 17 00:00:00 2001 From: The Oddball Date: Sun, 22 Jan 2017 17:27:45 -0700 Subject: [PATCH 097/746] Rotate Role Color needs ManageRoles permission. --- src/NadekoBot/Modules/Utility/Utility.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 5ffae5fc..bea8206f 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -25,6 +25,7 @@ namespace NadekoBot.Modules.Utility [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageRoles)] [OwnerOnly] public async Task RotateRoleColor(int timeout, IRole role, params string[] hexes) { @@ -346,4 +347,4 @@ namespace NadekoBot.Modules.Utility await JsonConvert.SerializeObject(grouping, Formatting.Indented).ToStream().ConfigureAwait(false), title, title).ConfigureAwait(false); } } -} \ No newline at end of file +} From b6f44de8b5433b6d6d77991e0b6491da02fbd3e0 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 23 Jan 2017 01:33:07 +0100 Subject: [PATCH 098/746] $lb redesign --- src/NadekoBot/Modules/Gambling/Gambling.cs | 33 ++++++++++++------- .../Resources/CommandStrings.Designer.cs | 2 +- src/NadekoBot/Resources/CommandStrings.resx | 2 +- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 12071254..1edf0f9e 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -248,22 +248,33 @@ namespace NadekoBot.Modules.Gambling [NadekoCommand, Usage, Description, Aliases] public async Task Leaderboard() { - IEnumerable richest = new List(); + var richest = new List(); using (var uow = DbHandler.UnitOfWork()) { - richest = uow.Currency.GetTopRichest(10); + richest = uow.Currency.GetTopRichest(9).ToList(); } if (!richest.Any()) return; - await Context.Channel.SendMessageAsync( - richest.Aggregate(new StringBuilder( -$@"```xl -┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┓ -┃ Id ┃ $$$ ┃ -"), - (cur, cs) => cur.AppendLine($@"┣━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━┫ -┃{(Context.Guild.GetUserAsync(cs.UserId).GetAwaiter().GetResult()?.Username?.TrimTo(18, true) ?? cs.UserId.ToString()),-20} ┃ {cs.Amount,6} ┃") - ).ToString() + "┗━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━┛```").ConfigureAwait(false); + + + var embed = new EmbedBuilder() + .WithOkColor() + .WithTitle(NadekoBot.BotConfig.CurrencySign + " Leaderboard"); + + for (var i = 0; i < richest.Count; i++) + { + var x = richest[i]; + var usr = await Context.Guild.GetUserAsync(x.UserId).ConfigureAwait(false); + var usrStr = ""; + if (usr == null) + usrStr = x.UserId.ToString(); + else + usrStr = usr.Username?.TrimTo(20, true); + + embed.AddField(efb => efb.WithName("#" + (i + 1) + " " + usrStr).WithValue(x.Amount.ToString() + " " + NadekoBot.BotConfig.CurrencySign).WithIsInline(true)); + } + + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 0f25ceb5..f8097764 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -879,7 +879,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Bet to guess will the result be heads or tails. Guessing awards you 1.8x the currency you've bet.. + /// Looks up a localized string similar to Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner.. /// public static string betflip_desc { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 2b742f4a..c9fcc6a8 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -1183,7 +1183,7 @@ betflip bf - Bet to guess will the result be heads or tails. Guessing awards you 1.8x the currency you've bet. + Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. `{0}bf 5 heads` or `{0}bf 3 t` From e0aa06c93db3f8d03fa1e51a982cdebd36801235 Mon Sep 17 00:00:00 2001 From: samvaio Date: Mon, 23 Jan 2017 06:10:53 +0530 Subject: [PATCH 099/746] ~ow fix for no rank players --- .../Searches/Commands/OverwatchCommands.cs | 204 +++++++++--------- 1 file changed, 102 insertions(+), 102 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs index 019f7f20..b29f70d9 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs @@ -1,102 +1,102 @@ -using Discord; -using Discord.Commands; -using NadekoBot.Attributes; -using NadekoBot.Extensions; -using NadekoBot.Modules.Searches.Models; -using Newtonsoft.Json; -using NLog; -using System.Net.Http; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace NadekoBot.Modules.Searches -{ - public partial class Searches - { - [Group] - public class OverwatchCommands : ModuleBase - { - private readonly Logger _log; - public OverwatchCommands() - { - _log = LogManager.GetCurrentClassLogger(); - } - [NadekoCommand, Usage, Description, Aliases] - public async Task Overwatch(string region, [Remainder] string query = null) - { - if (string.IsNullOrWhiteSpace(query)) - return; - var battletag = Regex.Replace(query, "#", "-", RegexOptions.IgnoreCase); - - await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); - try - { - await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); - var model = await GetProfile(region, battletag); - - var rankimg = $"{model.Competitive.rank_img}"; - var rank = $"{model.Competitive.rank}"; - var competitiveplay = $"{model.Games.Competitive.played}"; - if (string.IsNullOrWhiteSpace(rank)) - { - var embed = new EmbedBuilder() - .WithAuthor(eau => eau.WithName($"{model.username}") - .WithUrl($"https://www.overbuff.com/players/pc/{battletag}") - .WithIconUrl($"{model.avatar}")) - .WithThumbnailUrl("https://cdn.discordapp.com/attachments/155726317222887425/255653487512256512/YZ4w2ey.png") - .AddField(fb => fb.WithName("**Level**").WithValue($"{model.level}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Current Competitive Wins**").WithValue($"{model.Games.Competitive.wins}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Current Competitive Loses**").WithValue($"{model.Games.Competitive.lost}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Current Competitive Played**").WithValue($"{model.Games.Competitive.played}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Competitive Rank**").WithValue("0").WithIsInline(true)) - .AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"{model.Playtime.competitive}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true)) - .WithOkColor(); - await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); - } - else - { - var embed = new EmbedBuilder() - .WithAuthor(eau => eau.WithName($"{model.username}") - .WithUrl($"https://www.overbuff.com/players/pc/{battletag}") - .WithIconUrl($"{model.avatar}")) - .WithThumbnailUrl(rankimg) - .AddField(fb => fb.WithName("**Level**").WithValue($"{model.level}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Current Competitive Wins**").WithValue($"{model.Games.Competitive.wins}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Current Competitive Loses**").WithValue($"{model.Games.Competitive.lost}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Current Competitive Played**").WithValue($"{model.Games.Competitive.played}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Competitive Rank**").WithValue(rank).WithIsInline(true)) - .AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"{model.Playtime.competitive}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true)) - .WithColor(NadekoBot.OkColor); - await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); - return; - } - } - catch - { - await Context.Channel.SendErrorAsync("Found no user! Please check the **Region** and **BattleTag** before trying again."); - } - } - public async Task GetProfile(string region, string battletag) - { - try - { - using (var http = new HttpClient()) - { - var Url = await http.GetStringAsync($"https://api.lootbox.eu/pc/{region.ToLower()}/{battletag}/profile"); - var model = JsonConvert.DeserializeObject(Url); - return model.data; - } - } - catch - { - return null; - } - } - - } - } -} +using Discord; +using Discord.Commands; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Modules.Searches.Models; +using Newtonsoft.Json; +using NLog; +using System.Net.Http; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Searches +{ + public partial class Searches + { + [Group] + public class OverwatchCommands : ModuleBase + { + private readonly Logger _log; + public OverwatchCommands() + { + _log = LogManager.GetCurrentClassLogger(); + } + [NadekoCommand, Usage, Description, Aliases] + public async Task Overwatch(string region, [Remainder] string query = null) + { + if (string.IsNullOrWhiteSpace(query)) + return; + var battletag = Regex.Replace(query, "#", "-", RegexOptions.IgnoreCase); + + await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); + try + { + await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); + var model = await GetProfile(region, battletag); + + var rankimg = $"{model.Competitive.rank_img}"; + var rank = $"{model.Competitive.rank}"; + var competitiveplay = $"{model.Games.Competitive.played}"; + if (string.IsNullOrWhiteSpace(rank)) + { + var embed = new EmbedBuilder() + .WithAuthor(eau => eau.WithName($"{model.username}") + .WithUrl($"https://www.overbuff.com/players/pc/{battletag}") + .WithIconUrl($"{model.avatar}")) + .WithThumbnailUrl("https://cdn.discordapp.com/attachments/155726317222887425/255653487512256512/YZ4w2ey.png") + .AddField(fb => fb.WithName("**Level**").WithValue($"{model.level}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true)) + //.AddField(fb => fb.WithName("**Current Competitive Wins**").WithValue($"{model.Games.Competitive.wins}").WithIsInline(true)) + //.AddField(fb => fb.WithName("**Current Competitive Loses**").WithValue($"{model.Games.Competitive.lost}").WithIsInline(true)) + //.AddField(fb => fb.WithName("**Current Competitive Played**").WithValue($"{model.Games.Competitive.played}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Competitive Rank**").WithValue("0").WithIsInline(true)) + //.AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"{model.Playtime.competitive}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true)) + .WithOkColor(); + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + else + { + var embed = new EmbedBuilder() + .WithAuthor(eau => eau.WithName($"{model.username}") + .WithUrl($"https://www.overbuff.com/players/pc/{battletag}") + .WithIconUrl($"{model.avatar}")) + .WithThumbnailUrl(rankimg) + .AddField(fb => fb.WithName("**Level**").WithValue($"{model.level}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Current Competitive Wins**").WithValue($"{model.Games.Competitive.wins}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Current Competitive Loses**").WithValue($"{model.Games.Competitive.lost}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Current Competitive Played**").WithValue($"{model.Games.Competitive.played}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Competitive Rank**").WithValue(rank).WithIsInline(true)) + .AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"{model.Playtime.competitive}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true)) + .WithColor(NadekoBot.OkColor); + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + return; + } + } + catch + { + await Context.Channel.SendErrorAsync("Found no user! Please check the **Region** and **BattleTag** before trying again."); + } + } + public async Task GetProfile(string region, string battletag) + { + try + { + using (var http = new HttpClient()) + { + var Url = await http.GetStringAsync($"https://api.lootbox.eu/pc/{region.ToLower()}/{battletag}/profile"); + var model = JsonConvert.DeserializeObject(Url); + return model.data; + } + } + catch + { + return null; + } + } + + } + } +} From 6e7165cc5a6713939983ee4d7dbc940877b30533 Mon Sep 17 00:00:00 2001 From: samvaio Date: Mon, 23 Jan 2017 06:14:13 +0530 Subject: [PATCH 100/746] Cleanups --- src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs index b29f70d9..bcb5e082 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs @@ -46,11 +46,7 @@ namespace NadekoBot.Modules.Searches .WithThumbnailUrl("https://cdn.discordapp.com/attachments/155726317222887425/255653487512256512/YZ4w2ey.png") .AddField(fb => fb.WithName("**Level**").WithValue($"{model.level}").WithIsInline(true)) .AddField(fb => fb.WithName("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true)) - //.AddField(fb => fb.WithName("**Current Competitive Wins**").WithValue($"{model.Games.Competitive.wins}").WithIsInline(true)) - //.AddField(fb => fb.WithName("**Current Competitive Loses**").WithValue($"{model.Games.Competitive.lost}").WithIsInline(true)) - //.AddField(fb => fb.WithName("**Current Competitive Played**").WithValue($"{model.Games.Competitive.played}").WithIsInline(true)) .AddField(fb => fb.WithName("**Competitive Rank**").WithValue("0").WithIsInline(true)) - //.AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"{model.Playtime.competitive}").WithIsInline(true)) .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true)) .WithOkColor(); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); From 1fde33676f200fe489ebe672cc4763c0f39fea87 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 23 Jan 2017 01:44:25 +0100 Subject: [PATCH 101/746] 1:44:25.47 can now be set in .adpl to show current server time --- .../Modules/Administration/Commands/PlayingRotateCommands.cs | 3 ++- src/NadekoBot/_Extensions/Extensions.cs | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs index 89eeb2c5..af1cc15d 100644 --- a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs @@ -81,7 +81,8 @@ namespace NadekoBot.Modules.Administration } } }, - {"%queued%", () => Music.Music.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()} + {"%queued%", () => Music.Music.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()}, + { "%time%", () => DateTime.Now.ToString("hh:mm "+TimeZoneInfo.Local.StandardName.GetInitials()) } }; [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index fc50058f..56479a6f 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -103,6 +103,9 @@ namespace NadekoBot.Extensions http.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); } + public static string GetInitials(this string txt, string glue = "") => + string.Join(glue, txt.Split(' ').Select(x => x.FirstOrDefault())); + public static DateTime ToUnixTimestamp(this double number) => new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(number); public static EmbedBuilder WithOkColor(this EmbedBuilder eb) => From 7da31331179404d21e69c31b030ac758f62ecf00 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 23 Jan 2017 02:04:15 +0100 Subject: [PATCH 102/746] !!lq now shows 'now playing' song --- .../Commands/PlayingRotateCommands.cs | 12 +++---- src/NadekoBot/Modules/Music/Music.cs | 32 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs index af1cc15d..b70c033b 100644 --- a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs @@ -67,9 +67,9 @@ namespace NadekoBot.Modules.Administration public static Dictionary> PlayingPlaceholders { get; } = new Dictionary> { - {"%servers%", () => NadekoBot.Client.GetGuildCount().ToString()}, - {"%users%", () => NadekoBot.Client.GetGuilds().Sum(s => s.Users.Count).ToString()}, - {"%playing%", () => { + { "%servers%", () => NadekoBot.Client.GetGuildCount().ToString()}, + { "%users%", () => NadekoBot.Client.GetGuilds().Sum(s => s.Users.Count).ToString()}, + { "%playing%", () => { var cnt = Music.Music.MusicPlayers.Count(kvp => kvp.Value.CurrentSong != null); if (cnt != 1) return cnt.ToString(); try { @@ -81,8 +81,8 @@ namespace NadekoBot.Modules.Administration } } }, - {"%queued%", () => Music.Music.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()}, - { "%time%", () => DateTime.Now.ToString("hh:mm "+TimeZoneInfo.Local.StandardName.GetInitials()) } + { "%queued%", () => Music.Music.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()}, + { "%time%", () => DateTime.Now.ToString("hh:mm " + TimeZoneInfo.Local.StandardName.GetInitials()) } }; [NadekoCommand, Usage, Description, Aliases] @@ -154,4 +154,4 @@ namespace NadekoBot.Modules.Administration } } } -} +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 868a0885..e90c910c 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -211,30 +211,30 @@ namespace NadekoBot.Modules.Music { int startAt = itemsPerPage * (curPage - 1); var number = 0 + startAt; + var desc = string.Join("\n", musicPlayer.Playlist + .Skip(startAt) + .Take(itemsPerPage) + .Select(v => $"`{++number}.` {v.PrettyFullName}")); + + if (currentSong != null) + desc = $"`🔊` {currentSong.PrettyFullName}\n\n" + desc; + + if (musicPlayer.RepeatSong) + desc = "🔂 Repeating Current Song\n\n" + desc; + else if (musicPlayer.RepeatPlaylist) + desc = "🔁 Repeating Playlist\n\n" + desc; + + + var embed = new EmbedBuilder() .WithAuthor(eab => eab.WithName($"Player Queue - Page {curPage}/{lastPage + 1}") .WithMusicIcon()) - .WithDescription(string.Join("\n", musicPlayer.Playlist - .Skip(startAt) - .Take(itemsPerPage) - .Select(v => $"`{++number}.` {v.PrettyFullName}"))) + .WithDescription(desc) .WithFooter(ef => ef.WithText($"{musicPlayer.PrettyVolume} | {musicPlayer.Playlist.Count} " + $"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {totalStr} | " + (musicPlayer.FairPlay ? "✔️fairplay" : "✖️fairplay") + $" | " + (maxPlaytime == 0 ? "unlimited" : $"{maxPlaytime}s limit"))) .WithOkColor(); - if (musicPlayer.RepeatSong) - { - embed.WithTitle($"🔂 Repeating Song: {currentSong.SongInfo.Title} | {currentSong.PrettyFullTime}"); - } - else if (musicPlayer.RepeatPlaylist) - { - embed.WithTitle("🔁 Repeating Playlist"); - } - if (musicPlayer.MaxQueueSize != 0 && musicPlayer.Playlist.Count >= musicPlayer.MaxQueueSize) - { - embed.WithTitle("🎵 Song queue is full!"); - } return embed; }; await Context.Channel.SendPaginatedConfirmAsync(page, printAction, lastPage, false).ConfigureAwait(false); From 93d8b24b597cc19508006be05177aa6284e26f9b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 23 Jan 2017 02:06:09 +0100 Subject: [PATCH 103/746] :eyes: --- src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs index bcb5e082..9a063715 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs @@ -33,7 +33,7 @@ namespace NadekoBot.Modules.Searches { await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); var model = await GetProfile(region, battletag); - + var rankimg = $"{model.Competitive.rank_img}"; var rank = $"{model.Competitive.rank}"; var competitiveplay = $"{model.Games.Competitive.played}"; @@ -92,7 +92,6 @@ namespace NadekoBot.Modules.Searches return null; } } - } } -} +} \ No newline at end of file From 1769a2a553dc97e8a75ffe1c209d051351e0b039 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 23 Jan 2017 02:35:53 +0100 Subject: [PATCH 104/746] You can now plant multiple flowers (default is still one) >plant 5 --- .../Games/Commands/PlantAndPickCommands.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 272ced2a..6b5da1b1 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -147,9 +147,12 @@ namespace NadekoBot.Modules.Games [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task Plant() + public async Task Plant(int amount = 1) { - var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {NadekoBot.BotConfig.CurrencyName}", 1, false).ConfigureAwait(false); + if (amount < 1) + return; + + var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {NadekoBot.BotConfig.CurrencyName}", amount, false).ConfigureAwait(false); if (!removed) { await Context.Channel.SendErrorAsync($"You don't have any {NadekoBot.BotConfig.CurrencyPluralName}.").ConfigureAwait(false); @@ -160,7 +163,7 @@ namespace NadekoBot.Modules.Games IUserMessage msg; var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.BotConfig.CurrencyName[0]); - var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(vowelFirst ? "an" : "a")} {NadekoBot.BotConfig.CurrencyName}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick"; + var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(amount == 1 ? (vowelFirst ? "an" : "a") : amount.ToString())} {(amount > 1 ? NadekoBot.BotConfig.CurrencyPluralName : NadekoBot.BotConfig.CurrencyName)}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick"; if (file == null) { msg = await Context.Channel.SendConfirmAsync(NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); @@ -169,7 +172,15 @@ namespace NadekoBot.Modules.Games { 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; }); + + var msgs = new IUserMessage[amount]; + msgs[0] = msg; + + plantedFlowers.AddOrUpdate(Context.Channel.Id, msgs.ToList(), (id, old) => + { + old.AddRange(msgs); + return old; + }); } [NadekoCommand, Usage, Description, Aliases] From 8b766655ac5bcf37621988541360dfb7dc42c4a2 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 23 Jan 2017 03:17:50 +0100 Subject: [PATCH 105/746] %shardid% %shardcount% and %shardguilds% added to .ropl --- Discord.Net | 2 +- .../Commands/PlayingRotateCommands.cs | 21 +++++++++++++++++-- .../Resources/CommandStrings.Designer.cs | 4 ++-- src/NadekoBot/Resources/CommandStrings.resx | 5 +++-- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Discord.Net b/Discord.Net index 58766448..7c0cce6d 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit 58766448d79ac9adec228f341f258aa262a3f278 +Subproject commit 7c0cce6d35b04d883cf5ec2d775b051e4bc8739f diff --git a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs index b70c033b..3f70f908 100644 --- a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs @@ -1,5 +1,6 @@ using Discord; using Discord.Commands; +using Discord.WebSocket; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; @@ -50,7 +51,16 @@ namespace NadekoBot.Modules.Administration if (string.IsNullOrWhiteSpace(status)) continue; PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value())); - await NadekoBot.Client.SetGameAsync(status).ConfigureAwait(false); + var shards = NadekoBot.Client.Shards; + for (int i = 0; i < shards.Count; i++) + { + ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(shards.ElementAt(i)))); + try { await shards.ElementAt(i).SetGameAsync(status).ConfigureAwait(false); } + catch (Exception ex) + { + _log.Warn(ex); + } + } } } catch (Exception ex) @@ -82,7 +92,14 @@ namespace NadekoBot.Modules.Administration } }, { "%queued%", () => Music.Music.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()}, - { "%time%", () => DateTime.Now.ToString("hh:mm " + TimeZoneInfo.Local.StandardName.GetInitials()) } + { "%time%", () => DateTime.Now.ToString("hh:mm " + TimeZoneInfo.Local.StandardName.GetInitials()) }, + { "%shardcount%", () => NadekoBot.Client.Shards.Count.ToString() }, + }; + + public static Dictionary> ShardSpecificPlaceholders { get; } = + new Dictionary> { + { "%shardid%", (client) => client.ShardId.ToString()}, + { "%shardguilds%", (client) => client.Guilds.Count.ToString()}, }; [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index f8097764..8a56ca9e 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -5118,7 +5118,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Spend a unit of currency to plant it in this channel. (If bot is restarted or crashes, the currency will be lost). + /// Looks up a localized string similar to Spend an amount of currency to plant it in this channel. Default is 1. (If bot is restarted or crashes, the currency will be lost). /// public static string plant_desc { get { @@ -5127,7 +5127,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}plant`. + /// Looks up a localized string similar to `{0}plant` or `{0}plant 5`. /// public static string plant_usage { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index c9fcc6a8..20d3b78e 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -1372,10 +1372,11 @@ plant - Spend a unit of currency to plant it in this channel. (If bot is restarted or crashes, the currency will be lost) + Spend an amount of currency to plant it in this channel. Default is 1. (If bot is restarted or crashes, the currency will be lost) - `{0}plant` + `{0}plant` or `{0}plant 5` + gencurrency gc From 14a026555c78eb47ad9c3354143bc1caddf9ff67 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 23 Jan 2017 20:41:48 +0100 Subject: [PATCH 106/746] .sinfo fix? --- src/NadekoBot/Modules/Gambling/Gambling.cs | 4 ++-- src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 1edf0f9e..53ad4389 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -67,14 +67,14 @@ namespace NadekoBot.Modules.Gambling { if (amount <= 0 || Context.User.Id == receiver.Id) return; - var success = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Gift to {receiver.Username} ({receiver.Id}).", amount, true).ConfigureAwait(false); + var success = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Gift to {receiver.Username} ({receiver.Id}).", amount, false).ConfigureAwait(false); if (!success) { await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {CurrencyPluralName}.").ConfigureAwait(false); return; } await CurrencyHandler.AddCurrencyAsync(receiver, $"Gift from {Context.User.Username} ({Context.User.Id}).", amount, true).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully sent {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} to {receiver.Mention}!").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully sent {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} to {receiver}!").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 7d57ff8a..d1a3e76a 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(string.Join(" ", guild.Emojis.Select(e => $"{e.Name} <:{e.Name}:{e.Id}>")))); + embed.AddField(fb => fb.WithName($"**Custom Emojis ({guild.Emojis.Count})**").WithValue(string.Join(" ", guild.Emojis.Take(30).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>")))); } await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } From f0415bb36907e7e6e570356267c848b2cb5bc5a9 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 23 Jan 2017 22:02:35 +0100 Subject: [PATCH 107/746] ;cmdcd confirmation response fix --- src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs b/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs index d00972eb..fbb41acd 100644 --- a/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs +++ b/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs @@ -65,12 +65,12 @@ namespace NadekoBot.Modules.Permissions { var activeCds = activeCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet()); activeCds.RemoveWhere(ac => ac.Command == command.Aliases.First().ToLowerInvariant()); - await channel.SendConfirmAsync($"🚮 Command **{command}** has no coooldown now and all existing cooldowns have been cleared.") + await channel.SendConfirmAsync($"🚮 Command **{command.Aliases.First()}** has no coooldown now and all existing cooldowns have been cleared.") .ConfigureAwait(false); } else { - await channel.SendConfirmAsync($"✅ Command **{command}** now has a **{secs} {"seconds".SnPl(secs)}** cooldown.") + await channel.SendConfirmAsync($"✅ Command **{command.Aliases.First()}** now has a **{secs} {"seconds".SnPl(secs)}** cooldown.") .ConfigureAwait(false); } } From 8cd12bbec4c39273451b83dec866bddf0f8fdd41 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 23 Jan 2017 22:21:16 +0100 Subject: [PATCH 108/746] .sinfo fixed. Shows 25 random emojis from the server. closes #991 --- 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 d1a3e76a..66ffa3c2 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 ({guild.Emojis.Count})**").WithValue(string.Join(" ", guild.Emojis.Take(30).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>")))); + embed.AddField(fb => fb.WithName($"**Custom Emojis ({guild.Emojis.Count})**").WithValue(string.Join(" ", guild.Emojis.Shuffle().Take(25).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>")))); } await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } From c34338458cbaff4c1b34cd610d425d02a5a189f8 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 24 Jan 2017 15:45:00 +0100 Subject: [PATCH 109/746] .adpl help updated. closes #999 --- src/NadekoBot/Resources/CommandStrings.Designer.cs | 2 +- src/NadekoBot/Resources/CommandStrings.resx | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 8a56ca9e..f37738f5 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -177,7 +177,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%. + /// Looks up a localized string similar to Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %time%,%shardid%,%shardcount%, %shardguilds%. /// public static string addplaying_desc { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 20d3b78e..95b16f7d 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -292,7 +292,7 @@ addplaying adpl - Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued% + Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %time%,%shardid%,%shardcount%, %shardguilds% `{0}adpl` @@ -1376,7 +1376,6 @@ `{0}plant` or `{0}plant 5` - gencurrency gc From c898027952dd5e5f384addceab930265d03b77d3 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 24 Jan 2017 18:30:21 +0100 Subject: [PATCH 110/746] img and rimg will use google images first. if it fails, then fallback to imgur closes #970 --- src/NadekoBot/Modules/Searches/Searches.cs | 117 +++++++++++------- .../Services/Impl/GoogleApiService.cs | 40 +++++- 2 files changed, 113 insertions(+), 44 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 34ef1074..ad160599 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -115,33 +115,50 @@ namespace NadekoBot.Modules.Searches if (string.IsNullOrWhiteSpace(terms)) return; - terms = WebUtility.UrlEncode(terms).Replace(' ', '+'); + try + { + var res = await NadekoBot.Google.GetImageAsync(terms).ConfigureAwait(false); + var embed = new EmbedBuilder() + .WithOkColor() + .WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50)) + .WithUrl("https://www.google.rs/search?q=" + terms + "&source=lnms&tbm=isch") + .WithIconUrl("http://i.imgur.com/G46fm8J.png")) + .WithDescription(res.Link) + .WithImageUrl(res.Link) + .WithTitle(Context.User.Mention); + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + catch + { + _log.Warn("Falling back to Imgur search."); + terms = WebUtility.UrlEncode(terms).Replace(' ', '+'); - var fullQueryLink = $"http://imgur.com/search?q={ terms }"; - var config = Configuration.Default.WithDefaultLoader(); - var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink); + var fullQueryLink = $"http://imgur.com/search?q={ terms }"; + var config = Configuration.Default.WithDefaultLoader(); + var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink); - var elems = document.QuerySelectorAll("a.image-list-link"); + var elems = document.QuerySelectorAll("a.image-list-link"); - if (!elems.Any()) - return; + if (!elems.Any()) + return; - var img = (elems.FirstOrDefault()?.Children?.FirstOrDefault() as IHtmlImageElement); + var img = (elems.FirstOrDefault()?.Children?.FirstOrDefault() as IHtmlImageElement); - if (img?.Source == null) - return; + if (img?.Source == null) + return; - var source = img.Source.Replace("b.", "."); + var source = img.Source.Replace("b.", "."); - var embed = new EmbedBuilder() - .WithOkColor() - .WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50)) - .WithUrl(fullQueryLink) - .WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?")) - .WithDescription(source) - .WithImageUrl(source) - .WithTitle(Context.User.Mention); - await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + var embed = new EmbedBuilder() + .WithOkColor() + .WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50)) + .WithUrl(fullQueryLink) + .WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?")) + .WithDescription(source) + .WithImageUrl(source) + .WithTitle(Context.User.Mention); + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -150,34 +167,50 @@ namespace NadekoBot.Modules.Searches terms = terms?.Trim(); if (string.IsNullOrWhiteSpace(terms)) return; + try + { + var res = await NadekoBot.Google.GetImageAsync(terms, new NadekoRandom().Next(0, 50)).ConfigureAwait(false); + var embed = new EmbedBuilder() + .WithOkColor() + .WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50)) + .WithUrl("https://www.google.rs/search?q=" + terms + "&source=lnms&tbm=isch") + .WithIconUrl("http://i.imgur.com/G46fm8J.png")) + .WithDescription(res.Link) + .WithImageUrl(res.Link) + .WithTitle(Context.User.Mention); + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + catch + { + _log.Warn("Falling back to Imgur"); + terms = WebUtility.UrlEncode(terms).Replace(' ', '+'); - terms = WebUtility.UrlEncode(terms).Replace(' ', '+'); + var fullQueryLink = $"http://imgur.com/search?q={ terms }"; + var config = Configuration.Default.WithDefaultLoader(); + var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink); - var fullQueryLink = $"http://imgur.com/search?q={ terms }"; - var config = Configuration.Default.WithDefaultLoader(); - var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink); + var elems = document.QuerySelectorAll("a.image-list-link").ToList(); - var elems = document.QuerySelectorAll("a.image-list-link").ToList(); + if (!elems.Any()) + return; - if (!elems.Any()) - return; + var img = (elems.ElementAtOrDefault(new NadekoRandom().Next(0, elems.Count))?.Children?.FirstOrDefault() as IHtmlImageElement); - var img = (elems.ElementAtOrDefault(new NadekoRandom().Next(0, elems.Count))?.Children?.FirstOrDefault() as IHtmlImageElement); + if (img?.Source == null) + return; - if (img?.Source == null) - return; + var source = img.Source.Replace("b.", "."); - var source = img.Source.Replace("b.", "."); - - var embed = new EmbedBuilder() - .WithOkColor() - .WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50)) - .WithUrl(fullQueryLink) - .WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?")) - .WithDescription(source) - .WithImageUrl(source) - .WithTitle(Context.User.Mention); - await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + var embed = new EmbedBuilder() + .WithOkColor() + .WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50)) + .WithUrl(fullQueryLink) + .WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?")) + .WithDescription(source) + .WithImageUrl(source) + .WithTitle(Context.User.Mention); + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -260,7 +293,7 @@ namespace NadekoBot.Modules.Searches .WithTitle(Context.User.Mention) .WithFooter(efb => efb.WithText(totalResults)); - var desc = await Task.WhenAll(results.Select(async res => + var desc = await Task.WhenAll(results.Select(async res => $"[{Format.Bold(res?.Title)}]({(await NadekoBot.Google.ShortenUrl(res?.Link))})\n{res?.Text}\n\n")) .ConfigureAwait(false); await Context.Channel.EmbedAsync(embed.WithDescription(String.Concat(desc))).ConfigureAwait(false); diff --git a/src/NadekoBot/Services/Impl/GoogleApiService.cs b/src/NadekoBot/Services/Impl/GoogleApiService.cs index 7da7ad7b..f2934ba6 100644 --- a/src/NadekoBot/Services/Impl/GoogleApiService.cs +++ b/src/NadekoBot/Services/Impl/GoogleApiService.cs @@ -8,13 +8,19 @@ using System.Text.RegularExpressions; using Google.Apis.Urlshortener.v1; using Google.Apis.Urlshortener.v1.Data; using NLog; +using Google.Apis.Customsearch.v1; +using Google.Apis.Customsearch.v1.Data; namespace NadekoBot.Services.Impl { public class GoogleApiService : IGoogleApiService { + const string search_engine_id = "018084019232060951019:hs5piey28-e"; + private YouTubeService yt; private UrlshortenerService sh; + private CustomsearchService cs; + private Logger _log { get; } public GoogleApiService() @@ -22,13 +28,14 @@ namespace NadekoBot.Services.Impl var bcs = new BaseClientService.Initializer { ApplicationName = "Nadeko Bot", - ApiKey = NadekoBot.Credentials.GoogleApiKey + ApiKey = NadekoBot.Credentials.GoogleApiKey, }; _log = LogManager.GetCurrentClassLogger(); yt = new YouTubeService(bcs); sh = new UrlshortenerService(bcs); + cs = new CustomsearchService(bcs); } public async Task> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1) { @@ -150,7 +157,7 @@ namespace NadekoBot.Services.Impl return toReturn; } //todo AsyncEnumerable - public async Task> GetVideoDurationsAsync(IEnumerable videoIds) + public async Task> GetVideoDurationsAsync(IEnumerable videoIds) { var videoIdsList = videoIds as List ?? videoIds.ToList(); @@ -179,5 +186,34 @@ namespace NadekoBot.Services.Impl return toReturn; } + + public struct ImageResult + { + public Result.ImageData Image { get; } + public string Link { get; } + + public ImageResult(Result.ImageData image, string link) + { + this.Image = image; + this.Link = link; + } + } + + public async Task GetImageAsync(string query, int start = 0) + { + if (string.IsNullOrWhiteSpace(query)) + throw new ArgumentNullException(nameof(query)); + + var req = cs.Cse.List(query); + req.Cx = search_engine_id; + req.Num = 1; + req.Fields = "items(image(contextLink,thumbnailLink),link)"; + req.SearchType = CseResource.ListRequest.SearchTypeEnum.Image; + req.Start = start; + + var search = await req.ExecuteAsync().ConfigureAwait(false); + + return new ImageResult(search.Items[0].Image, search.Items[0].Link); + } } } From 809192c732058b282f5f33ced0dbc21934e79bc1 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 24 Jan 2017 22:27:29 +0100 Subject: [PATCH 111/746] flower event fix --- src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs index 4dfa935f..5df56e36 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -66,7 +66,7 @@ namespace NadekoBot.Modules.Gambling { try { - if (r.Emoji.Name == "🌸" && r.User.IsSpecified && _flowerReactionAwardedUsers.Add(r.User.Value.Id)) + if (r.Emoji.Name == "🌸" && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _flowerReactionAwardedUsers.Add(r.User.Value.Id)) { try { await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, false).ConfigureAwait(false); } catch { } } From cde2931a51b2ba8df48f1e6af3c86bee208b7254 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 25 Jan 2017 03:06:41 +0100 Subject: [PATCH 112/746] added ~mal command --- .../Searches/Commands/AnimeSearchCommands.cs | 116 +++++++++++++++++- .../Resources/CommandStrings.Designer.cs | 27 ++++ src/NadekoBot/Resources/CommandStrings.resx | 9 ++ 3 files changed, 151 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs index ed6c058b..2aeb3c5b 100644 --- a/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs @@ -1,4 +1,7 @@ -using Discord; +using AngleSharp; +using AngleSharp.Dom.Html; +using AngleSharp.Extensions; +using Discord; using Discord.Commands; using NadekoBot.Attributes; using NadekoBot.Extensions; @@ -8,6 +11,7 @@ using Newtonsoft.Json.Linq; using NLog; using System; using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -52,6 +56,116 @@ namespace NadekoBot.Modules.Searches }, null, TimeSpan.FromSeconds(0), TimeSpan.FromMinutes(29)); } + [NadekoCommand, Usage, Description, Aliases] + [Priority(1)] + public async Task Mal([Remainder] string name) + { + if (string.IsNullOrWhiteSpace(name)) + return; + + var fullQueryLink = "https://myanimelist.net/profile/" + name; + + var config = Configuration.Default.WithDefaultLoader(); + var document = await BrowsingContext.New(config).OpenAsync(fullQueryLink); + + var imageElem = document.QuerySelector("body > div#myanimelist > div.wrapper > div#contentWrapper > div#content > div.content-container > div.container-left > div.user-profile > div.user-image > img"); + var imageUrl = ((IHtmlImageElement)imageElem)?.Source ?? "http://icecream.me/uploads/870b03f36b59cc16ebfe314ef2dde781.png"; + + var stats = document.QuerySelectorAll("body > div#myanimelist > div.wrapper > div#contentWrapper > div#content > div.content-container > div.container-right > div#statistics > div.user-statistics-stats > div.stats > div.clearfix > ul.stats-status > li > span").Select(x => x.InnerHtml).ToList(); + + var favorites = document.QuerySelectorAll("div.user-favorites > div.di-tc"); + + var favAnime = "No favorite anime yet"; + if (favorites[0].QuerySelector("p") == null) + favAnime = string.Join("\n", favorites[0].QuerySelectorAll("ul > li > div.di-tc.va-t > a") + .Shuffle() + .Take(3) + .Select(x => + { + var elem = (IHtmlAnchorElement)x; + return $"[{elem.InnerHtml}]({elem.Href})"; + })); + + //var favManga = "No favorite manga yet."; + //if (favorites[1].QuerySelector("p") == null) + // favManga = string.Join("\n", favorites[1].QuerySelectorAll("ul > li > div.di-tc.va-t > a") + // .Take(3) + // .Select(x => + // { + // var elem = (IHtmlAnchorElement)x; + // return $"[{elem.InnerHtml}]({elem.Href})"; + // })); + + var info = document.QuerySelectorAll("ul.user-status:nth-child(3) > li") + .Select(x => Tuple.Create(x.Children[0].InnerHtml, x.Children[1].InnerHtml)) + .ToList(); + + var daysAndMean = document.QuerySelectorAll("div.anime:nth-child(1) > div:nth-child(2) > div") + .Select(x => x.TextContent.Split(':').Select(y => y.Trim()).ToArray()) + .ToArray(); + + var embed = new EmbedBuilder() + .WithOkColor() + .WithTitle($"{name}'s MAL profile") + .AddField(efb => efb.WithName("💚 Watching").WithValue(stats[0]).WithIsInline(true)) + .AddField(efb => efb.WithName("💙 Completed").WithValue(stats[1]).WithIsInline(true)); + if (info.Count < 3) + embed.AddField(efb => efb.WithName("💛 On-Hold").WithValue(stats[2]).WithIsInline(true)); + embed + .AddField(efb => efb.WithName("💔 Dropped").WithValue(stats[3]).WithIsInline(true)) + .AddField(efb => efb.WithName("⚪ Plan to watch").WithValue(stats[4]).WithIsInline(true)) + .AddField(efb => efb.WithName("🕐 " + daysAndMean[0][0]).WithValue(daysAndMean[0][1]).WithIsInline(true)) + .AddField(efb => efb.WithName("📊 " + daysAndMean[1][0]).WithValue(daysAndMean[1][1]).WithIsInline(true)) + .AddField(efb => efb.WithName(MalInfoToEmoji(info[0].Item1) + " " + info[0].Item1).WithValue(info[0].Item2.TrimTo(20)).WithIsInline(true)) + .AddField(efb => efb.WithName(MalInfoToEmoji(info[1].Item1) + " " + info[1].Item1).WithValue(info[1].Item2.TrimTo(20)).WithIsInline(true)); + if (info.Count > 2) + embed.AddField(efb => efb.WithName(MalInfoToEmoji(info[2].Item1) + " " + info[2].Item1).WithValue(info[2].Item2.TrimTo(20)).WithIsInline(true)); + //if(info.Count > 3) + // embed.AddField(efb => efb.WithName(MalInfoToEmoji(info[3].Item1) + " " + info[3].Item1).WithValue(info[3].Item2).WithIsInline(true)) + embed + .WithDescription($@" +** https://myanimelist.net/animelist/{ name } ** + +**Top 3 Favorite Anime:** +{favAnime}" + +//**[Manga List](https://myanimelist.net/mangalist/{name})** +//💚`Reading:` {stats[5]} +//💙`Completed:` {stats[6]} +//💔`Dropped:` {stats[8]} +//⚪`Plan to read:` {stats[9]} + +//**Top 3 Favorite Manga:** +//{favManga}" + +) + .WithUrl(fullQueryLink) + .WithImageUrl(imageUrl); + + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + + private static string MalInfoToEmoji(string info) { + info = info.Trim().ToLowerInvariant(); + switch (info) + { + case "gender": + return "🚁"; + case "location": + return "🗺"; + case "last online": + return "👥"; + case "birthday": + return "📆"; + default: + return "❔"; + } + } + + [NadekoCommand, Usage, Description, Aliases] + [Priority(0)] + public Task Mal(IUser usr) => Mal(usr.Username); + [NadekoCommand, Usage, Description, Aliases] public async Task Anime([Remainder] string query) { diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index f37738f5..ae2ff2c6 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -4406,6 +4406,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to mal. + /// + public static string mal_cmd { + get { + return ResourceManager.GetString("mal_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows basic info from myanimelist profile.. + /// + public static string mal_desc { + get { + return ResourceManager.GetString("mal_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}mal straysocks`. + /// + public static string mal_usage { + get { + return ResourceManager.GetString("mal_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to manga mang mq. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 95b16f7d..a31288b1 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3024,4 +3024,13 @@ `{0}waifuinfo @MyCrush` or `{0}waifuinfo` + + mal + + + Shows basic info from myanimelist profile. + + + `{0}mal straysocks` + \ No newline at end of file From a4c190c3126376a479c808704f3386b140def945 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 25 Jan 2017 03:19:43 +0100 Subject: [PATCH 113/746] Fixed ~img and ~rimg, closes #1001 --- src/NadekoBot/Modules/Searches/Searches.cs | 4 +++- src/NadekoBot/Services/Impl/GoogleApiService.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index ad160599..27840678 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -115,6 +115,8 @@ namespace NadekoBot.Modules.Searches if (string.IsNullOrWhiteSpace(terms)) return; + terms = WebUtility.UrlEncode(terms).Replace(' ', '+'); + try { var res = await NadekoBot.Google.GetImageAsync(terms).ConfigureAwait(false); @@ -131,7 +133,6 @@ namespace NadekoBot.Modules.Searches catch { _log.Warn("Falling back to Imgur search."); - terms = WebUtility.UrlEncode(terms).Replace(' ', '+'); var fullQueryLink = $"http://imgur.com/search?q={ terms }"; var config = Configuration.Default.WithDefaultLoader(); @@ -167,6 +168,7 @@ namespace NadekoBot.Modules.Searches terms = terms?.Trim(); if (string.IsNullOrWhiteSpace(terms)) return; + terms = WebUtility.UrlEncode(terms).Replace(' ', '+'); try { var res = await NadekoBot.Google.GetImageAsync(terms, new NadekoRandom().Next(0, 50)).ConfigureAwait(false); diff --git a/src/NadekoBot/Services/Impl/GoogleApiService.cs b/src/NadekoBot/Services/Impl/GoogleApiService.cs index f2934ba6..187bf272 100644 --- a/src/NadekoBot/Services/Impl/GoogleApiService.cs +++ b/src/NadekoBot/Services/Impl/GoogleApiService.cs @@ -199,7 +199,7 @@ namespace NadekoBot.Services.Impl } } - public async Task GetImageAsync(string query, int start = 0) + public async Task GetImageAsync(string query, int start = 1) { if (string.IsNullOrWhiteSpace(query)) throw new ArgumentNullException(nameof(query)); From 15a3b99cbd1fdf4c4ef07c7baaf9ddf407cd3bb5 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 26 Jan 2017 07:57:52 +0100 Subject: [PATCH 114/746] Hangman fixed --- .../Modules/Games/Commands/Hangman/HangmanGame.cs | 14 +++++++------- .../Modules/Games/Commands/HangmanCommands.cs | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index 4dcb54e9..3d5f7ec6 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -189,13 +189,13 @@ namespace NadekoBot.Modules.Games.Commands.Hangman catch (Exception ex) { _log.Warn(ex); } } - public string GetHangman() => $@"\_\_\_\_\_\_\_\_\_ - | | - | | - {(Errors > 0 ? "😲" : " ")} | - {(Errors > 1 ? "/" : " ")} {(Errors > 2 ? "|" : " ")} {(Errors > 3 ? "\\" : " ")} | - {(Errors > 4 ? "/" : " ")} {(Errors > 5 ? "\\" : " ")} | - /-\"; + public string GetHangman() => $@". ┌─────┐ +.┃...............┋ +.┃...............┋ +.┃{(Errors > 0 ? ".............😲" : "")} +.┃{(Errors > 1 ? "............./" : "")} {(Errors > 2 ? "|" : "")} {(Errors > 3 ? "\\" : "")} +.┃{(Errors > 4 ? "............../" : "")} {(Errors > 5 ? "\\" : "")} +/-\"; public void Dispose() { diff --git a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs index 50596e4c..4d499301 100644 --- a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs @@ -61,7 +61,7 @@ namespace NadekoBot.Modules.Games return; } - await Context.Channel.SendConfirmAsync("Hangman game started", hm.ScrambledWord + "\n" + hm.GetHangman() + "\n" + hm.ScrambledWord); + await Context.Channel.SendConfirmAsync("Hangman game started", hm.ScrambledWord + "\n" + hm.GetHangman()); } } } From 5d5a67b4770db1ab0ef20908a9d724db2139a889 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 26 Jan 2017 08:02:57 +0100 Subject: [PATCH 115/746] .whpl fix on many users --- src/NadekoBot/Modules/Utility/Utility.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index dc5e56cd..304b2782 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -116,15 +116,18 @@ namespace NadekoBot.Modules.Utility var arr = (await (Context.Channel as IGuildChannel).Guild.GetUsersAsync()) .Where(u => u.Game?.Name?.ToUpperInvariant() == game) .Select(u => u.Username) + .Shuffle() + .Take(60) .ToList(); int i = 0; if (!arr.Any()) await Context.Channel.SendErrorAsync("Nobody is playing that game.").ConfigureAwait(false); - else + else { await Context.Channel.SendConfirmAsync("```css\n" + string.Join("\n", arr.GroupBy(item => (i++) / 2) .Select(ig => string.Concat(ig.Select(el => $"• {el,-27}")))) + "\n```") .ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] From f40dbc7bec33b9750f4dc8eaa7d4f383848b3c12 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 26 Jan 2017 08:08:40 +0100 Subject: [PATCH 116/746] Users can no longer submit multiple sentences in acrophobia --- src/NadekoBot/Modules/Games/Commands/Acropobia.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs index 2a7307bb..b379e473 100644 --- a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -69,6 +69,7 @@ namespace NadekoBot.Modules.Games private readonly ConcurrentDictionary submissions = new ConcurrentDictionary(); public IReadOnlyDictionary Submissions => submissions; + private readonly ConcurrentHashSet usersWhoSubmitted = new ConcurrentHashSet(); private readonly ConcurrentHashSet usersWhoVoted = new ConcurrentHashSet(); private int spamCount = 0; @@ -191,8 +192,7 @@ namespace NadekoBot.Modules.Games catch { } } //user didn't input something already - IGuildUser throwaway; - if (submissions.TryGetValue(input, out throwaway)) + if (!usersWhoSubmitted.Add(guildUser.Id)) return; var inputWords = input.Split(' '); //get all words From d09a5fd2e92ddd1eb7c1eeefbceaef11cb9090c9 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 26 Jan 2017 19:13:59 +0100 Subject: [PATCH 117/746] ~osu now links to new profile, closes #1005 --- src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs b/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs index f7f83361..a2760a1a 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs @@ -45,7 +45,7 @@ namespace NadekoBot.Modules.Searches MemoryStream ms = new MemoryStream(); res.CopyTo(ms); ms.Position = 0; - await Context.Channel.SendFileAsync(ms, $"{usr}.png", $"🎧 **Profile Link: **https://osu.ppy.sh/u/{Uri.EscapeDataString(usr)}\n`Image provided by https://lemmmy.pw/osusig`").ConfigureAwait(false); + await Context.Channel.SendFileAsync(ms, $"{usr}.png", $"🎧 **Profile Link:** \n`Image provided by https://lemmmy.pw/osusig`").ConfigureAwait(false); } catch (Exception ex) { From 927031dd60e990469997086f176e25f5d97f0beb Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 26 Jan 2017 19:19:57 +0100 Subject: [PATCH 118/746] Fixed accented 'a' in typing articles --- src/NadekoBot/data/typing_articles.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/data/typing_articles.json b/src/NadekoBot/data/typing_articles.json index 1a4581fe..c4317df8 100644 --- a/src/NadekoBot/data/typing_articles.json +++ b/src/NadekoBot/data/typing_articles.json @@ -237,7 +237,7 @@ }, { "Title":"Careers in Psychology: Opportunities in a Changing World", - "Text":"This text addresses the growing need among students and faculty for information about the careers available in psychology at the bachelor’s and graduate level." + "Text":"This text addresses the growing need among students and faculty for information about the careers available in psychology at the bacheloras and graduate level." }, { "Title":"Philosophy of Psychology", From 14b7aae0b026d3e1ad3d21dd5123b8a419d6391f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 26 Jan 2017 20:15:59 +0100 Subject: [PATCH 119/746] $raffle prettified --- src/NadekoBot/Modules/Gambling/Gambling.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 53ad4389..8db03d30 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -42,7 +42,7 @@ namespace NadekoBot.Modules.Gambling var members = role.Members().Where(u => u.Status != UserStatus.Offline && u.Status != UserStatus.Unknown); var membersArray = members as IUser[] ?? members.ToArray(); var usr = membersArray[new NadekoRandom().Next(0, membersArray.Length)]; - await Context.Channel.SendConfirmAsync("🎟 Raffled user", $"**{usr.Username}#{usr.Discriminator}** ID: `{usr.Id}`").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync("🎟 Raffled user", $"**{usr.Username}#{usr.Discriminator}**", footer: $"ID: {usr.Id}").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] From 41a75172354321d9142d1652bfb5694d54dfd15b Mon Sep 17 00:00:00 2001 From: The Oddball Date: Thu, 26 Jan 2017 14:11:28 -0700 Subject: [PATCH 120/746] Actually fixed typing articles. Bachelors isn't spelt with an a in it silly. --- src/NadekoBot/data/typing_articles.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/data/typing_articles.json b/src/NadekoBot/data/typing_articles.json index c4317df8..ab34341c 100644 --- a/src/NadekoBot/data/typing_articles.json +++ b/src/NadekoBot/data/typing_articles.json @@ -237,7 +237,7 @@ }, { "Title":"Careers in Psychology: Opportunities in a Changing World", - "Text":"This text addresses the growing need among students and faculty for information about the careers available in psychology at the bacheloras and graduate level." + "Text":"This text addresses the growing need among students and faculty for information about the careers available in psychology at the bachelors and graduate level." }, { "Title":"Philosophy of Psychology", From 484d8f3e9686b1d28a13c8780d38b9da7e649a36 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 26 Jan 2017 22:28:07 +0100 Subject: [PATCH 121/746] closes #1012, Fixed acrophobia not working if you type something other than the sentence --- src/NadekoBot/Modules/Games/Commands/Acropobia.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs index b379e473..ff0cc725 100644 --- a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -191,9 +191,6 @@ namespace NadekoBot.Modules.Games try { await channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); } catch { } } - //user didn't input something already - if (!usersWhoSubmitted.Add(guildUser.Id)) - return; var inputWords = input.Split(' '); //get all words if (inputWords.Length != startingLetters.Length) // number of words must be the same as the number of the starting letters @@ -207,9 +204,15 @@ namespace NadekoBot.Modules.Games return; } + + if (!usersWhoSubmitted.Add(guildUser.Id)) + return; //try adding it to the list of answers if (!submissions.TryAdd(input, guildUser)) + { + usersWhoSubmitted.TryRemove(guildUser.Id); return; + } // all good. valid input. answer recorded await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} submitted their sentence. ({submissions.Count} total)"); From 74fe68f54dfc69a6d9de15501406fce01ae6390c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 27 Jan 2017 06:31:50 +0100 Subject: [PATCH 122/746] Fixed .prune in combination with .delmsgoncmd --- src/NadekoBot/Modules/Administration/Administration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index cf431be1..45e99b8e 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -45,7 +45,7 @@ namespace NadekoBot.Modules.Administration var channel = msg.Channel as SocketTextChannel; if (channel == null) return; - if (DeleteMessagesOnCommand.Contains(channel.Guild.Id)) + if (DeleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune") await msg.DeleteAsync().ConfigureAwait(false); } catch (Exception ex) From f121cda212c2201c8333b8d65c65568a22eb9ba4 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 27 Jan 2017 21:57:47 +0100 Subject: [PATCH 123/746] Removed 'current' from overwatch field names --- .../Modules/Searches/Commands/OverwatchCommands.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs index 9a063715..e70381b2 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs @@ -60,9 +60,9 @@ namespace NadekoBot.Modules.Searches .WithThumbnailUrl(rankimg) .AddField(fb => fb.WithName("**Level**").WithValue($"{model.level}").WithIsInline(true)) .AddField(fb => fb.WithName("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Current Competitive Wins**").WithValue($"{model.Games.Competitive.wins}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Current Competitive Loses**").WithValue($"{model.Games.Competitive.lost}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Current Competitive Played**").WithValue($"{model.Games.Competitive.played}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Competitive Wins**").WithValue($"{model.Games.Competitive.wins}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Competitive Loses**").WithValue($"{model.Games.Competitive.lost}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Competitive Played**").WithValue($"{model.Games.Competitive.played}").WithIsInline(true)) .AddField(fb => fb.WithName("**Competitive Rank**").WithValue(rank).WithIsInline(true)) .AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"{model.Playtime.competitive}").WithIsInline(true)) .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true)) From c4ca121c02d2d96ea2d254cec2afc8268d721d37 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 27 Jan 2017 22:02:43 +0100 Subject: [PATCH 124/746] here and everyone no longer work in cross server text channel --- .../Modules/Utility/Commands/CrossServerTextChannel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs b/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs index decd705f..194ee455 100644 --- a/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs +++ b/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs @@ -50,7 +50,7 @@ namespace NadekoBot.Modules.Utility } private static string GetText(IGuild server, ITextChannel channel, IGuildUser user, IUserMessage message) => - $"**{server.Name} | {channel.Name}** `{user.Username}`: " + message.Content; + $"**{server.Name} | {channel.Name}** `{user.Username}`: " + message.Content.SanitizeMentions(); public static readonly ConcurrentDictionary> Subscribers = new ConcurrentDictionary>(); private static Logger _log { get; } From 24b8763ca84c34af36776a4d42425b2096981901 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 29 Jan 2017 00:38:09 +0100 Subject: [PATCH 125/746] Updated discord.net --- Discord.Net | 2 +- .../Administration/Commands/AutoAssignRoleCommands.cs | 4 ---- .../Modules/Administration/Commands/SelfCommands.cs | 6 ++---- .../Administration/Commands/VoicePlusTextCommands.cs | 8 ++++---- src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs | 6 ++---- src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs | 2 +- src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs | 8 ++++---- .../Searches/Commands/StreamNotificationCommands.cs | 2 +- src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs | 6 +++--- src/NadekoBot/Modules/Utility/Commands/Remind.cs | 4 +--- src/NadekoBot/NadekoBot.cs | 3 ++- 11 files changed, 21 insertions(+), 30 deletions(-) diff --git a/Discord.Net b/Discord.Net index 7c0cce6d..05e73771 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit 7c0cce6d35b04d883cf5ec2d775b051e4bc8739f +Subproject commit 05e7377142b8d8ccfabe0236dd8d2c40fb8d4bbf diff --git a/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs b/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs index e3cb8380..01c19fa8 100644 --- a/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs @@ -25,7 +25,6 @@ namespace NadekoBot.Modules.Administration static AutoAssignRoleCommands() { _log = LogManager.GetCurrentClassLogger(); - var sw = Stopwatch.StartNew(); AutoAssignedRoles = new ConcurrentDictionary(NadekoBot.AllGuildConfigs.Where(x => x.AutoAssignRoleId != 0) .ToDictionary(k => k.GuildId, v => v.AutoAssignRoleId)); @@ -46,9 +45,6 @@ namespace NadekoBot.Modules.Administration } catch (Exception ex) { _log.Warn(ex); } }; - - sw.Stop(); - _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index a087e6f2..13817a65 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -132,7 +132,7 @@ namespace NadekoBot.Modules.Administration if (ids[1].ToUpperInvariant().StartsWith("C:")) { var cid = ulong.Parse(ids[1].Substring(2)); - var ch = (await server.GetTextChannelsAsync()).Where(c => c.Id == cid).FirstOrDefault(); + var ch = server.TextChannels.Where(c => c.Id == cid).FirstOrDefault(); if (ch == null) { return; @@ -159,9 +159,7 @@ namespace NadekoBot.Modules.Administration [OwnerOnly] public async Task Announce([Remainder] string message) { - var channels = await Task.WhenAll(NadekoBot.Client.GetGuilds().Select(g => - g.GetDefaultChannelAsync() - )).ConfigureAwait(false); + var channels = NadekoBot.Client.GetGuilds().Select(g => g.DefaultChannel).ToArray(); if (channels == null) return; await Task.WhenAll(channels.Where(c => c != null).Select(c => c.SendConfirmAsync($"🆕 Message from {Context.User} `[Bot Owner]`:", message))) diff --git a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs index a52a2c60..1bd135d8 100644 --- a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs @@ -57,7 +57,7 @@ namespace NadekoBot.Modules.Administration { try { - await (await guild.GetOwnerAsync()).SendErrorAsync( + await guild.Owner.SendErrorAsync( "⚠️ I don't have **manage server** and/or **manage channels** permission," + $" so I cannot run `voice+text` on **{guild.Name}** server.").ConfigureAwait(false); } @@ -75,16 +75,16 @@ namespace NadekoBot.Modules.Administration var beforeVch = before.VoiceChannel; if (beforeVch != null) { - var textChannel = (await guild.GetTextChannelsAsync()).Where(t => t.Name == GetChannelName(beforeVch.Name).ToLowerInvariant()).FirstOrDefault(); + var textChannel = guild.TextChannels.Where(t => t.Name == GetChannelName(beforeVch.Name).ToLowerInvariant()).FirstOrDefault(); if (textChannel != null) await textChannel.AddPermissionOverwriteAsync(user, new OverwritePermissions(readMessages: PermValue.Deny, sendMessages: PermValue.Deny)).ConfigureAwait(false); } var afterVch = after.VoiceChannel; - if (afterVch != null && guild.AFKChannelId != afterVch.Id) + if (afterVch != null && guild.AFKChannel.Id != afterVch.Id) { - var textChannel = (await guild.GetTextChannelsAsync()) + ITextChannel textChannel = guild.TextChannels .Where(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant()) .FirstOrDefault(); if (textChannel == null) diff --git a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs index 26b18995..4fc33705 100644 --- a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs +++ b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs @@ -37,9 +37,7 @@ namespace NadekoBot.Modules.ClashOfClans .Select(cw => { cw.Channel = NadekoBot.Client.GetGuild(cw.GuildId) - ?.GetTextChannelAsync(cw.ChannelId) - .GetAwaiter() - .GetResult(); + .GetTextChannel(cw.ChannelId); return cw; }) .Where(cw => cw.Channel != null) @@ -322,7 +320,7 @@ namespace NadekoBot.Modules.ClashOfClans public static async Task CreateWar(string enemyClan, int size, ulong serverId, ulong channelId) { - var channel = await NadekoBot.Client.GetGuild(serverId)?.GetTextChannelAsync(channelId); + var channel = NadekoBot.Client.GetGuild(serverId)?.GetTextChannel(channelId); using (var uow = DbHandler.UnitOfWork()) { var cw = new ClashWar diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs index 5df56e36..598a19b0 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -59,7 +59,7 @@ namespace NadekoBot.Modules.Gambling catch { try { await msg.DeleteAsync().ConfigureAwait(false); } - catch { } + catch { return; } } } using (msg.OnReaction(async (r) => diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs index 08e9a9c8..2646ebd5 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs @@ -76,9 +76,9 @@ namespace NadekoBot.Modules.Games.Trivia questionMessage = await channel.EmbedAsync(questionEmbed).ConfigureAwait(false); } - catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound || - ex.StatusCode == System.Net.HttpStatusCode.Forbidden || - ex.StatusCode == System.Net.HttpStatusCode.BadRequest) + catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound || + ex.HttpCode == System.Net.HttpStatusCode.Forbidden || + ex.HttpCode == System.Net.HttpStatusCode.BadRequest) { return; } @@ -106,7 +106,7 @@ namespace NadekoBot.Modules.Games.Trivia await questionMessage.ModifyAsync(m => m.Embed = questionEmbed.WithFooter(efb => efb.WithText(CurrentQuestion.GetHint())).Build()) .ConfigureAwait(false); } - catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound || ex.StatusCode == System.Net.HttpStatusCode.Forbidden) + catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound || ex.HttpCode == System.Net.HttpStatusCode.Forbidden) { break; } diff --git a/src/NadekoBot/Modules/Searches/Commands/StreamNotificationCommands.cs b/src/NadekoBot/Modules/Searches/Commands/StreamNotificationCommands.cs index 36829953..3fc7a34b 100644 --- a/src/NadekoBot/Modules/Searches/Commands/StreamNotificationCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/StreamNotificationCommands.cs @@ -105,7 +105,7 @@ namespace NadekoBot.Modules.Searches var server = NadekoBot.Client.GetGuild(fs.GuildId); if (server == null) return; - var channel = await server.GetTextChannelAsync(fs.ChannelId); + var channel = server.GetTextChannel(fs.ChannelId); if (channel == null) return; try diff --git a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs index 619b71fa..b6efe2fc 100644 --- a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs @@ -40,7 +40,7 @@ namespace NadekoBot.Modules.Utility { _log = LogManager.GetCurrentClassLogger(); this.Repeater = repeater; - this.Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannelAsync(repeater.ChannelId).GetAwaiter().GetResult(); + this.Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannel(repeater.ChannelId); if (Channel == null) return; Task.Run(Run); @@ -69,12 +69,12 @@ namespace NadekoBot.Modules.Utility { oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false); } - catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.Forbidden) + catch (HttpException ex) when (ex.HttpCode == 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) + catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound) { _log.Warn("Channel not found. Repeater stopped. ChannelId : {0}", Channel?.Id); return; diff --git a/src/NadekoBot/Modules/Utility/Commands/Remind.cs b/src/NadekoBot/Modules/Utility/Commands/Remind.cs index 7d371c22..94521dd6 100644 --- a/src/NadekoBot/Modules/Utility/Commands/Remind.cs +++ b/src/NadekoBot/Modules/Utility/Commands/Remind.cs @@ -68,9 +68,7 @@ namespace NadekoBot.Modules.Utility } else { - var t = NadekoBot.Client.GetGuild(r.ServerId)?.GetTextChannelAsync(r.ChannelId).ConfigureAwait(false); - if (t != null) - ch = await t.Value; + ch = NadekoBot.Client.GetGuild(r.ServerId)?.GetTextChannel(r.ChannelId); } if (ch == null) return; diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 2e4d3daf..02c60720 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -75,7 +75,8 @@ namespace NadekoBot //initialize Services CommandService = new CommandService(new CommandServiceConfig() { - CaseSensitiveCommands = false + CaseSensitiveCommands = false, + DefaultRunMode = RunMode.Sync }); Google = new GoogleApiService(); CommandHandler = new CommandHandler(Client, CommandService); From 53c6f3ab0844b4832e3b9783f695006d5520ca8d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 29 Jan 2017 00:40:14 +0100 Subject: [PATCH 126/746] upped version --- 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 cdd6fd8f..380ca2bb 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.4"; + public const string BotVersion = "1.1.5"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From 9eb9e69edc244465a84fdd13ecd8a0d46104c506 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 29 Jan 2017 00:50:22 +0100 Subject: [PATCH 127/746] Fixed coc --- src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs index 4fc33705..67510d56 100644 --- a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs +++ b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs @@ -36,7 +36,7 @@ namespace NadekoBot.Modules.ClashOfClans .GetAllWars() .Select(cw => { - cw.Channel = NadekoBot.Client.GetGuild(cw.GuildId) + cw.Channel = NadekoBot.Client.GetGuild(cw.GuildId)? .GetTextChannel(cw.ChannelId); return cw; }) From 17338396a46f127e9ef27ace275d4386a3d85273 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 29 Jan 2017 01:25:17 +0100 Subject: [PATCH 128/746] fixed warning as error --- Discord.Net | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Discord.Net b/Discord.Net index 05e73771..4506fc5a 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit 05e7377142b8d8ccfabe0236dd8d2c40fb8d4bbf +Subproject commit 4506fc5a54fe31d826649dc413467c52a3cd7896 From d5c4d3f3d20f76bc0c4074e3c3a0fda1a744bf7b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 29 Jan 2017 04:30:21 +0100 Subject: [PATCH 129/746] Custom reaction bufixes and perf improvements --- .../CustomReactions/CustomReactions.cs | 99 ++++++++++++------- .../Modules/CustomReactions/Extensions.cs | 10 +- 2 files changed, 72 insertions(+), 37 deletions(-) diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index 8d95e5d4..1f1cca1d 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -10,14 +10,16 @@ using NadekoBot.Extensions; using NLog; using System.Diagnostics; using Discord.WebSocket; +using System; namespace NadekoBot.Modules.CustomReactions { [NadekoModule("CustomReactions", ".")] public class CustomReactions : DiscordModule { - public static ConcurrentHashSet GlobalReactions { get; } = new ConcurrentHashSet(); - public static ConcurrentDictionary> GuildReactions { get; } = new ConcurrentDictionary>(); + private static CustomReaction[] _globalReactions = new CustomReaction[] { }; + public static CustomReaction[] GlobalReactions => _globalReactions; + public static ConcurrentDictionary GuildReactions { get; } = new ConcurrentDictionary(); public static ConcurrentDictionary ReactionStats { get; } = new ConcurrentDictionary(); @@ -30,8 +32,8 @@ namespace NadekoBot.Modules.CustomReactions using (var uow = DbHandler.UnitOfWork()) { var items = uow.CustomReactions.GetAll(); - GuildReactions = new ConcurrentDictionary>(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => new ConcurrentHashSet(g))); - GlobalReactions = new ConcurrentHashSet(items.Where(g => g.GuildId == null || g.GuildId == 0)); + GuildReactions = new ConcurrentDictionary(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => g.ToArray())); + _globalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray(); } sw.Stop(); _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); @@ -46,32 +48,46 @@ namespace NadekoBot.Modules.CustomReactions return false; var content = umsg.Content.Trim().ToLowerInvariant(); - ConcurrentHashSet reactions; + CustomReaction[] reactions; GuildReactions.TryGetValue(channel.Guild.Id, out reactions); if (reactions != null && reactions.Any()) { - var reaction = reactions.Where(cr => + var rs = reactions.Where(cr => { + if (cr == null) + return false; + var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%"); var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant(); return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger); - }).Shuffle().FirstOrDefault(); - if (reaction != null) - { - if (reaction.Response != "-") - try { await channel.SendMessageAsync(reaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { } + }).ToArray(); - ReactionStats.AddOrUpdate(reaction.Trigger, 1, (k, old) => ++old); - return true; + if (rs.Length != 0) + { + var reaction = rs[new NadekoRandom().Next(0, rs.Length)]; + if (reaction != null) + { + if (reaction.Response != "-") + try { await channel.SendMessageAsync(reaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { } + + ReactionStats.AddOrUpdate(reaction.Trigger, 1, (k, old) => ++old); + return true; + } } } - var greaction = GlobalReactions.Where(cr => + + var grs = GlobalReactions.Where(cr => { + if (cr == null) + return false; var hasTarget = cr.Response.ToLowerInvariant().Contains("%target%"); var trigger = cr.TriggerWithContext(umsg).Trim().ToLowerInvariant(); return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger); - }).Shuffle().FirstOrDefault(); + }).ToArray(); + if (grs.Length == 0) + return false; + var greaction = grs[new NadekoRandom().Next(0, grs.Length)]; if (greaction != null) { @@ -114,12 +130,19 @@ namespace NadekoBot.Modules.CustomReactions if (channel == null) { - GlobalReactions.Add(cr); + Array.Resize(ref _globalReactions, _globalReactions.Length + 1); + _globalReactions[_globalReactions.Length - 1] = cr; } else { - var reactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet()); - reactions.Add(cr); + var reactions = GuildReactions.AddOrUpdate(Context.Guild.Id, + Array.Empty(), + (k, old) => + { + Array.Resize(ref old, old.Length + 1); + old[old.Length - 1] = cr; + return old; + }); } await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() @@ -136,17 +159,17 @@ namespace NadekoBot.Modules.CustomReactions { if (page < 1 || page > 1000) return; - ConcurrentHashSet customReactions; + CustomReaction[] customReactions; if (Context.Guild == null) - customReactions = GlobalReactions; + customReactions = GlobalReactions.Where(cr => cr != null).ToArray(); else - customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet()); + customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, Array.Empty()).Where(cr => cr != null).ToArray(); if (customReactions == null || !customReactions.Any()) await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false); else { - var lastPage = customReactions.Count / 20; + var lastPage = customReactions.Length / 20; await Context.Channel.SendPaginatedConfirmAsync(page, curPage => new EmbedBuilder().WithOkColor() .WithTitle("Custom reactions") @@ -167,11 +190,11 @@ namespace NadekoBot.Modules.CustomReactions [Priority(1)] public async Task ListCustReact(All x) { - ConcurrentHashSet customReactions; + CustomReaction[] customReactions; if (Context.Guild == null) - customReactions = GlobalReactions; + customReactions = GlobalReactions.Where(cr => cr != null).ToArray(); else - customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet()); + customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray(); if (customReactions == null || !customReactions.Any()) await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false); @@ -195,11 +218,11 @@ namespace NadekoBot.Modules.CustomReactions { if (page < 1 || page > 10000) return; - ConcurrentHashSet customReactions; + CustomReaction[] customReactions; if (Context.Guild == null) - customReactions = GlobalReactions; + customReactions = GlobalReactions.Where(cr => cr != null).ToArray(); else - customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet()); + customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray(); if (customReactions == null || !customReactions.Any()) await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false); @@ -225,13 +248,13 @@ namespace NadekoBot.Modules.CustomReactions [NadekoCommand, Usage, Description, Aliases] public async Task ShowCustReact(int id) { - ConcurrentHashSet customReactions; + CustomReaction[] customReactions; if (Context.Guild == null) customReactions = GlobalReactions; else - customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet()); + customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }); - var found = customReactions.FirstOrDefault(cr => cr.Id == id); + var found = customReactions.FirstOrDefault(cr => cr?.Id == id); if (found == null) await Context.Channel.SendErrorAsync("No custom reaction found with that id.").ConfigureAwait(false); @@ -265,13 +288,17 @@ namespace NadekoBot.Modules.CustomReactions if ((toDelete.GuildId == null || toDelete.GuildId == 0) && Context.Guild == null) { uow.CustomReactions.Remove(toDelete); - GlobalReactions.RemoveWhere(cr => cr.Id == toDelete.Id); + //todo i can dramatically improve performance of this, if Ids are ordered. + _globalReactions = GlobalReactions.Where(cr => cr?.Id != toDelete.Id).ToArray(); success = true; } else if ((toDelete.GuildId != null && toDelete.GuildId != 0) && Context.Guild.Id == toDelete.GuildId) { uow.CustomReactions.Remove(toDelete); - GuildReactions.GetOrAdd(Context.Guild.Id, new ConcurrentHashSet()).RemoveWhere(cr => cr.Id == toDelete.Id); + GuildReactions.AddOrUpdate(Context.Guild.Id, new CustomReaction[] { }, (key, old) => + { + return old.Where(cr => cr?.Id != toDelete.Id).ToArray(); + }); success = true; } if (success) @@ -312,8 +339,10 @@ namespace NadekoBot.Modules.CustomReactions { if (page < 1) return; - var ordered = ReactionStats.OrderByDescending(x => x.Value).ToList(); - var lastPage = ordered.Count / 9; + var ordered = ReactionStats.OrderByDescending(x => x.Value).ToArray(); + if (!ordered.Any()) + return; + var lastPage = ordered.Length / 9; await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) => ordered.Skip((curPage - 1) * 9) .Take(9) diff --git a/src/NadekoBot/Modules/CustomReactions/Extensions.cs b/src/NadekoBot/Modules/CustomReactions/Extensions.cs index a894ad2e..ff20fa89 100644 --- a/src/NadekoBot/Modules/CustomReactions/Extensions.cs +++ b/src/NadekoBot/Modules/CustomReactions/Extensions.cs @@ -1,9 +1,11 @@ using Discord; +using Discord.WebSocket; using NadekoBot.Extensions; using NadekoBot.Services; using NadekoBot.Services.Database.Models; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text.RegularExpressions; @@ -25,9 +27,13 @@ namespace NadekoBot.Modules.CustomReactions if(ch == null) return ""; - var usrs = (ch.Guild.GetUsersAsync().GetAwaiter().GetResult()); + var g = ch.Guild as SocketGuild; + if(g == null) + return ""; - return usrs.Skip(new NadekoRandom().Next(0,usrs.Count-1)).Shuffle().FirstOrDefault()?.Mention ?? ""; + var users = g.Users.ToArray(); + + return users[new NadekoRandom().Next(0, users.Length-1)].Mention; } } //{"%rng%", (ctx) => { return new NadekoRandom().Next(0,10).ToString(); } } }; From d4e78aa8eff973e8262cd7b3b12672622bb72668 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 29 Jan 2017 05:56:08 +0100 Subject: [PATCH 130/746] small change to how .ropl works --- .../Commands/PlayingRotateCommands.cs | 66 +++++++++---------- src/NadekoBot/Services/CommandHandler.cs | 1 + 2 files changed, 32 insertions(+), 35 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs index 3f70f908..81544f7e 100644 --- a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs @@ -10,6 +10,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Threading; using System.Threading.Tasks; namespace NadekoBot.Modules.Administration @@ -22,8 +23,8 @@ namespace NadekoBot.Modules.Administration private static Logger _log { get; } public static List RotatingStatusMessages { get; } public static bool RotatingStatuses { get; private set; } = false; - - //todo wtf is with this while(true) in constructor + private static Timer _t { get; } + static PlayingRotateCommands() { _log = LogManager.GetCurrentClassLogger(); @@ -31,48 +32,43 @@ namespace NadekoBot.Modules.Administration RotatingStatusMessages = NadekoBot.BotConfig.RotatingStatusMessages; RotatingStatuses = NadekoBot.BotConfig.RotatingStatuses; - var t = Task.Run(async () => + + + _t = new Timer(async (_) => { var index = 0; - do + try { - try + if (!RotatingStatuses) + return; + else { - if (!RotatingStatuses) - continue; - else - { - if (index >= RotatingStatusMessages.Count) - index = 0; + if (index >= RotatingStatusMessages.Count) + index = 0; - if (!RotatingStatusMessages.Any()) - continue; - var status = RotatingStatusMessages[index++].Status; - if (string.IsNullOrWhiteSpace(status)) - continue; - PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value())); - var shards = NadekoBot.Client.Shards; - for (int i = 0; i < shards.Count; i++) + if (!RotatingStatusMessages.Any()) + return; + var status = RotatingStatusMessages[index++].Status; + if (string.IsNullOrWhiteSpace(status)) + return; + PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value())); + var shards = NadekoBot.Client.Shards; + for (int i = 0; i < shards.Count; i++) + { + ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(shards.ElementAt(i)))); + try { await shards.ElementAt(i).SetGameAsync(status).ConfigureAwait(false); } + catch (Exception ex) { - ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(shards.ElementAt(i)))); - try { await shards.ElementAt(i).SetGameAsync(status).ConfigureAwait(false); } - catch (Exception ex) - { - _log.Warn(ex); - } + _log.Warn(ex); } } } - catch (Exception ex) - { - _log.Warn("Rotating playing status errored.\n" + ex); - } - finally - { - await Task.Delay(TimeSpan.FromMinutes(1)); - } - } while (true); - }); + } + catch (Exception ex) + { + _log.Warn("Rotating playing status errored.\n" + ex); + } + }, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); } public static Dictionary> PlayingPlaceholders { get; } = diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index f2aab51c..e8442334 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -222,6 +222,7 @@ namespace NadekoBot.Services return; // maybe this message is a custom reaction + // todo log custom reaction executions. return struct with info var crExecuted = await Task.Run(() => CustomReactions.TryExecuteCustomReaction(usrMsg)).ConfigureAwait(false); if (crExecuted) //if it was, don't execute the command return; From dbda89ca5d12d349cf16a8198f9743bebded6338 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 29 Jan 2017 05:56:55 +0100 Subject: [PATCH 131/746] cleanup --- src/NadekoBot/Modules/Music/Music.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index e90c910c..b7c41b55 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -711,14 +711,11 @@ namespace NadekoBot.Modules.Music await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } - - //todo only author or owner + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task DeletePlaylist([Remainder] int id) { - - bool success = false; MusicPlaylist pl = null; try @@ -747,7 +744,7 @@ namespace NadekoBot.Modules.Music } catch (Exception ex) { - Console.WriteLine(ex); + _log.Warn(ex); } } From 5b77e2eb90d014139b6ecffe25046e87f3c039ff Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 29 Jan 2017 13:12:07 +0100 Subject: [PATCH 132/746] Optimizations. bugfixes. 13:12:07.08 shows 00-24 instead of 0-12 --- .../Commands/PlayingRotateCommands.cs | 2 +- .../Commands/ServerGreetCommands.cs | 98 ++++++++++++++++--- src/NadekoBot/Services/CommandHandler.cs | 4 +- 3 files changed, 89 insertions(+), 15 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs index 81544f7e..7fff2dc6 100644 --- a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs @@ -88,7 +88,7 @@ namespace NadekoBot.Modules.Administration } }, { "%queued%", () => Music.Music.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()}, - { "%time%", () => DateTime.Now.ToString("hh:mm " + TimeZoneInfo.Local.StandardName.GetInitials()) }, + { "%time%", () => DateTime.Now.ToString("HH:mm " + TimeZoneInfo.Local.StandardName.GetInitials()) }, { "%shardcount%", () => NadekoBot.Client.Shards.Count.ToString() }, }; diff --git a/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs index 9fa0971c..9183b814 100644 --- a/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs @@ -4,9 +4,11 @@ using Discord.WebSocket; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; +using NadekoBot.Services.Database; using NadekoBot.Services.Database.Models; using NLog; using System; +using System.Collections.Concurrent; using System.Linq; using System.Threading.Tasks; @@ -17,24 +19,76 @@ namespace NadekoBot.Modules.Administration [Group] public class ServerGreetCommands : ModuleBase { + //make this to a field in the guildconfig table + class GreetSettings + { + public int AutoDeleteGreetMessagesTimer { get; set; } + public int AutoDeleteByeMessagesTimer { get; set; } + + public ulong GreetMessageChannelId { get; set; } + public ulong ByeMessageChannelId { get; set; } + + public bool SendDmGreetMessage { get; set; } + public string DmGreetMessageText { get; set; } + + public bool SendChannelGreetMessage { get; set; } + public string ChannelGreetMessageText { get; set; } + + public bool SendChannelByeMessage { get; set; } + public string ChannelByeMessageText { get; set; } + + public static GreetSettings Create(GuildConfig g) => new GreetSettings() + { + AutoDeleteByeMessagesTimer = g.AutoDeleteByeMessagesTimer, + AutoDeleteGreetMessagesTimer = g.AutoDeleteGreetMessagesTimer, + GreetMessageChannelId = g.GreetMessageChannelId, + ByeMessageChannelId = g.ByeMessageChannelId, + SendDmGreetMessage = g.SendDmGreetMessage, + DmGreetMessageText = g.DmGreetMessageText, + SendChannelGreetMessage = g.SendChannelGreetMessage, + ChannelGreetMessageText = g.ChannelGreetMessageText, + SendChannelByeMessage = g.SendChannelByeMessage, + ChannelByeMessageText = g.ChannelByeMessageText, + }; + } + private static Logger _log { get; } + private static ConcurrentDictionary GuildConfigsCache { get; } = new ConcurrentDictionary(); + static ServerGreetCommands() { NadekoBot.Client.UserJoined += UserJoined; NadekoBot.Client.UserLeft += UserLeft; _log = LogManager.GetCurrentClassLogger(); + + GuildConfigsCache = new ConcurrentDictionary(NadekoBot.AllGuildConfigs.ToDictionary(g => g.GuildId, (g) => GreetSettings.Create(g))); } + + private static GreetSettings GetOrAddSettingsForGuild(ulong guildId) + { + GreetSettings settings; + GuildConfigsCache.TryGetValue(guildId, out settings); + + if (settings != null) + return settings; + + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(guildId, set => set); + settings = GreetSettings.Create(gc); + } + + GuildConfigsCache.TryAdd(guildId, settings); + return settings; + } + //todo optimize ASAP private static async Task UserLeft(IGuildUser user) { try { - GuildConfig conf; - using (var uow = DbHandler.UnitOfWork()) - { - conf = uow.GuildConfigs.For(user.Guild.Id, set => set); - } + var conf = GetOrAddSettingsForGuild(user.GuildId); if (!conf.SendChannelByeMessage) return; var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.ByeMessageChannelId); @@ -62,11 +116,7 @@ namespace NadekoBot.Modules.Administration { try { - GuildConfig conf; - using (var uow = DbHandler.UnitOfWork()) - { - conf = uow.GuildConfigs.For(user.Guild.Id, set => set); - } + var conf = GetOrAddSettingsForGuild(user.GuildId); if (conf.SendChannelGreetMessage) { @@ -133,6 +183,9 @@ namespace NadekoBot.Modules.Administration var conf = uow.GuildConfigs.For(id, set => set); conf.AutoDeleteGreetMessagesTimer = timer; + var toAdd = GreetSettings.Create(conf); + GuildConfigsCache.AddOrUpdate(id, toAdd, (key, old) => toAdd); + await uow.CompleteAsync().ConfigureAwait(false); } } @@ -159,6 +212,9 @@ namespace NadekoBot.Modules.Administration enabled = conf.SendChannelGreetMessage = value ?? !conf.SendChannelGreetMessage; conf.GreetMessageChannelId = channelId; + var toAdd = GreetSettings.Create(conf); + GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); + await uow.CompleteAsync().ConfigureAwait(false); } return enabled; @@ -201,6 +257,9 @@ namespace NadekoBot.Modules.Administration conf.ChannelGreetMessageText = message; greetMsgEnabled = conf.SendChannelGreetMessage; + var toAdd = GreetSettings.Create(conf); + GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); + uow.Complete(); } return greetMsgEnabled; @@ -227,6 +286,9 @@ namespace NadekoBot.Modules.Administration var conf = uow.GuildConfigs.For(guildId, set => set); enabled = conf.SendDmGreetMessage = value ?? !conf.SendDmGreetMessage; + var toAdd = GreetSettings.Create(conf); + GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); + await uow.CompleteAsync().ConfigureAwait(false); } return enabled; @@ -269,6 +331,9 @@ namespace NadekoBot.Modules.Administration conf.DmGreetMessageText = message; greetMsgEnabled = conf.SendDmGreetMessage; + var toAdd = GreetSettings.Create(conf); + GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); + uow.Complete(); } return greetMsgEnabled; @@ -296,6 +361,9 @@ namespace NadekoBot.Modules.Administration enabled = conf.SendChannelByeMessage = value ?? !conf.SendChannelByeMessage; conf.ByeMessageChannelId = channelId; + var toAdd = GreetSettings.Create(conf); + GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); + await uow.CompleteAsync(); } return enabled; @@ -338,6 +406,9 @@ namespace NadekoBot.Modules.Administration conf.ChannelByeMessageText = message; byeMsgEnabled = conf.SendChannelByeMessage; + var toAdd = GreetSettings.Create(conf); + GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); + uow.Complete(); } return byeMsgEnabled; @@ -356,16 +427,19 @@ namespace NadekoBot.Modules.Administration await Context.Channel.SendConfirmAsync("ℹ️ Automatic deletion of bye messages has been **disabled**.").ConfigureAwait(false); } - private static async Task SetByeDel(ulong id, int timer) + private static async Task SetByeDel(ulong guildId, int timer) { if (timer < 0 || timer > 600) return; using (var uow = DbHandler.UnitOfWork()) { - var conf = uow.GuildConfigs.For(id, set => set); + var conf = uow.GuildConfigs.For(guildId, set => set); conf.AutoDeleteByeMessagesTimer = timer; + var toAdd = GreetSettings.Create(conf); + GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); + await uow.CompleteAsync().ConfigureAwait(false); } } diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index e8442334..09080f12 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -159,8 +159,8 @@ namespace NadekoBot.Services private async Task WordFiltered(IGuild guild, SocketUserMessage usrMsg) { - var filteredChannelWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id); - var filteredServerWords = Permissions.FilterCommands.FilteredWordsForServer(guild.Id); + var filteredChannelWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id) ?? new ConcurrentHashSet(); + var filteredServerWords = Permissions.FilterCommands.FilteredWordsForServer(guild.Id) ?? new ConcurrentHashSet(); var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' '); if (filteredChannelWords.Count != 0 || filteredServerWords.Count != 0) { From 0e9fa33591cd4138165141ff036930ad915f77c6 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 29 Jan 2017 13:34:11 +0100 Subject: [PATCH 133/746] small v+t fix --- .../Modules/Administration/Commands/VoicePlusTextCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs index 1bd135d8..9d92ff98 100644 --- a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs @@ -82,7 +82,7 @@ namespace NadekoBot.Modules.Administration sendMessages: PermValue.Deny)).ConfigureAwait(false); } var afterVch = after.VoiceChannel; - if (afterVch != null && guild.AFKChannel.Id != afterVch.Id) + if (afterVch != null && guild.AFKChannel?.Id != afterVch.Id) { ITextChannel textChannel = guild.TextChannels .Where(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant()) From cce8465ff3f8b1565f480ff40a821af0ab8b99c2 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 29 Jan 2017 22:54:27 +0100 Subject: [PATCH 134/746] a bit of cleanup --- src/NadekoBot/Modules/Games/Games.cs | 4 +-- src/NadekoBot/Modules/Music/Music.cs | 9 ++++++- src/NadekoBot/Modules/Searches/Searches.cs | 23 +++++++++------- .../Modules/Utility/Commands/QuoteCommands.cs | 27 ++++++++++++------- src/NadekoBot/Modules/Utility/Utility.cs | 22 ++++++++++----- .../Resources/CommandStrings.Designer.cs | 2 +- src/NadekoBot/Resources/CommandStrings.resx | 2 +- 7 files changed, 58 insertions(+), 31 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index 8dfd7d5a..6faf288c 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -13,7 +13,7 @@ namespace NadekoBot.Modules.Games [NadekoModule("Games", ">")] public partial class Games : DiscordModule { - private static IEnumerable _8BallResponses { get; } = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text); + private static string[] _8BallResponses { get; } = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text).ToArray(); [NadekoCommand, Usage, Description, Aliases] @@ -37,7 +37,7 @@ namespace NadekoBot.Modules.Games await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) .AddField(efb => efb.WithName("❓ Question").WithValue(question).WithIsInline(false)) - .AddField(efb => efb.WithName("🎱 8Ball").WithValue(_8BallResponses.Shuffle().FirstOrDefault()).WithIsInline(false))); + .AddField(efb => efb.WithName("🎱 8Ball").WithValue(_8BallResponses[new NadekoRandom().Next(0, _8BallResponses.Length)]).WithIsInline(false))); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index b7c41b55..b229bf84 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -833,7 +833,14 @@ namespace NadekoBot.Modules.Music if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.ProviderType == MusicType.Normal) { - await QueueSong(await queuer.Guild.GetCurrentUserAsync(), textCh, voiceCh, (await NadekoBot.Google.GetRelatedVideosAsync(song.SongInfo.Query, 4)).ToList().Shuffle().FirstOrDefault(), silent, musicType).ConfigureAwait(false); + var relatedVideos = (await NadekoBot.Google.GetRelatedVideosAsync(song.SongInfo.Query, 4)).ToList(); + if(relatedVideos.Count > 0) + await QueueSong(await queuer.Guild.GetCurrentUserAsync(), + textCh, + voiceCh, + relatedVideos[new NadekoRandom().Next(0, relatedVideos.Count)], + silent, + musicType).ConfigureAwait(false); } } catch { } diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 27840678..8abcfee8 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -320,10 +320,10 @@ namespace NadekoBot.Modules.Searches .ConfigureAwait(false); try { - var items = JArray.Parse(response).Shuffle().ToList(); - if (items == null) + var items = JArray.Parse(response).ToArray(); + if (items == null || items.Length == 0) throw new KeyNotFoundException("Cannot find a card by that name"); - var item = items[0]; + var item = items[new NadekoRandom().Next(0, items.Length)]; var storeUrl = await NadekoBot.Google.ShortenUrl(item["store_url"].ToString()); var cost = item["cost"].ToString(); var desc = item["text"].ToString(); @@ -379,13 +379,16 @@ namespace NadekoBot.Modules.Searches throw new KeyNotFoundException("Cannot find a card by that name"); foreach (var item in items.Where(item => item.HasValues && item["img"] != null).Take(4)) { - using (var sr = await http.GetStreamAsync(item["img"].ToString())) + await Task.Run(async () => { - var imgStream = new MemoryStream(); - await sr.CopyToAsync(imgStream); - imgStream.Position = 0; - images.Add(new ImageSharp.Image(imgStream)); - } + using (var sr = await http.GetStreamAsync(item["img"].ToString())) + { + var imgStream = new MemoryStream(); + await sr.CopyToAsync(imgStream); + imgStream.Position = 0; + images.Add(new ImageSharp.Image(imgStream)); + } + }).ConfigureAwait(false); } string msg = null; if (items.Count > 4) @@ -393,7 +396,7 @@ namespace NadekoBot.Modules.Searches msg = "⚠ Found over 4 images. Showing random 4."; } var ms = new MemoryStream(); - images.AsEnumerable().Merge().SaveAsPng(ms); + await Task.Run(() => images.AsEnumerable().Merge().SaveAsPng(ms)); ms.Position = 0; await Context.Channel.SendFileAsync(ms, arg + ".png", msg).ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index fd60a591..8add0707 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -93,24 +93,31 @@ namespace NadekoBot.Modules.Utility var isAdmin = ((IGuildUser)Context.Message.Author).GuildPermissions.Administrator; keyword = keyword.ToUpperInvariant(); + var sucess = false; string response; using (var uow = DbHandler.UnitOfWork()) { - var qs = uow.Quotes.GetAllQuotesByKeyword(Context.Guild.Id, keyword); + var qs = uow.Quotes.GetAllQuotesByKeyword(Context.Guild.Id, keyword)?.Where(elem => isAdmin || elem.AuthorId == Context.Message.Author.Id).ToArray(); if (qs == null || !qs.Any()) { - await Context.Channel.SendErrorAsync("No quotes found.").ConfigureAwait(false); - return; + sucess = false; + response = "No quotes found which you can remove."; } + else + { + var q = qs[new NadekoRandom().Next(0, qs.Length)]; - var q = qs.Shuffle().FirstOrDefault(elem => isAdmin || elem.AuthorId == Context.Message.Author.Id); - - uow.Quotes.Remove(q); - await uow.CompleteAsync().ConfigureAwait(false); - response = "🗑 **Deleted a random quote.**"; + uow.Quotes.Remove(q); + await uow.CompleteAsync().ConfigureAwait(false); + sucess = true; + response = "🗑 **Deleted a random quote.**"; + } } - await Context.Channel.SendConfirmAsync(response); + if(sucess) + await Context.Channel.SendConfirmAsync(response); + else + await Context.Channel.SendErrorAsync(response); } [NadekoCommand, Usage, Description, Aliases] @@ -126,7 +133,7 @@ namespace NadekoBot.Modules.Utility using (var uow = DbHandler.UnitOfWork()) { var quotes = uow.Quotes.GetAllQuotesByKeyword(Context.Guild.Id, keyword); - + //todo kwoth please don't be complete retard uow.Quotes.RemoveRange(quotes.ToArray());//wtf?! await uow.CompleteAsync(); diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 304b2782..1c1af1e0 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -15,6 +15,8 @@ using System.Threading; using ImageSharp; using System.Collections.Generic; using Newtonsoft.Json; +using Discord.WebSocket; +using NadekoBot.Services; namespace NadekoBot.Modules.Utility { @@ -113,21 +115,29 @@ namespace NadekoBot.Modules.Utility game = game.Trim().ToUpperInvariant(); if (string.IsNullOrWhiteSpace(game)) return; - var arr = (await (Context.Channel as IGuildChannel).Guild.GetUsersAsync()) + + var socketGuild = Context.Guild as SocketGuild; + if (socketGuild == null) { + _log.Warn("Can't cast guild to socket guild."); + return; + } + var rng = new NadekoRandom(); + var arr = await Task.Run(() => socketGuild.Users .Where(u => u.Game?.Name?.ToUpperInvariant() == game) .Select(u => u.Username) - .Shuffle() + .OrderBy(x => rng.Next()) .Take(60) - .ToList(); + .ToArray()).ConfigureAwait(false); int i = 0; - if (!arr.Any()) + if (arr.Length == 0) await Context.Channel.SendErrorAsync("Nobody is playing that game.").ConfigureAwait(false); - else { + else + { await Context.Channel.SendConfirmAsync("```css\n" + string.Join("\n", arr.GroupBy(item => (i++) / 2) .Select(ig => string.Concat(ig.Select(el => $"• {el,-27}")))) + "\n```") .ConfigureAwait(false); - } + } } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index ae2ff2c6..4388c9bd 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -8340,7 +8340,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}voice+text`. + /// Looks up a localized string similar to `{0}v+t`. /// public static string voiceplustext_usage { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index a31288b1..2dc50365 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -340,7 +340,7 @@ Creates a text channel for each voice channel only users in that voice channel can see.If you are server owner, keep in mind you will see them all the time regardless. - `{0}voice+text` + `{0}v+t` scsc From b75407ff9fc3d00dd81c19a62987595b41e14825 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 29 Jan 2017 22:55:32 +0100 Subject: [PATCH 135/746] Removed a warning during compilation --- Discord.Net | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Discord.Net b/Discord.Net index 4506fc5a..80384323 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit 4506fc5a54fe31d826649dc413467c52a3cd7896 +Subproject commit 80384323790471d254c7db5c237a49dc62624378 From 4205cf37a3dba1da2374a90b01bd1c5b2b9f6a2d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 29 Jan 2017 23:26:55 +0100 Subject: [PATCH 136/746] fixed the worst affinity title --- src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs index 3a365bf0..f5a2a454 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs @@ -506,7 +506,7 @@ namespace NadekoBot.Modules.Gambling title = AffinityTitles.Sloot; else if (count < 17) title = AffinityTitles.Depraved; - else if (count < 20) + else title = AffinityTitles.Harlot; return new WaifuProfileTitle(count, title.ToString().Replace('_', ' ')); From b4af05b12424c8ebb361bfbdbdd0076b24626036 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 30 Jan 2017 01:05:30 +0100 Subject: [PATCH 137/746] dlls --- src/NadekoBot/_libs/32/libsodium.dll | Bin 0 -> 492032 bytes src/NadekoBot/_libs/32/opus.dll | Bin 0 -> 284672 bytes src/NadekoBot/_libs/64/libsodium.dll | Bin 0 -> 399872 bytes src/NadekoBot/_libs/64/opus.dll | Bin 0 -> 261632 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/NadekoBot/_libs/32/libsodium.dll create mode 100644 src/NadekoBot/_libs/32/opus.dll create mode 100644 src/NadekoBot/_libs/64/libsodium.dll create mode 100644 src/NadekoBot/_libs/64/opus.dll diff --git a/src/NadekoBot/_libs/32/libsodium.dll b/src/NadekoBot/_libs/32/libsodium.dll new file mode 100644 index 0000000000000000000000000000000000000000..a9ab5078e7b8537c60a0f032e6e336b51a8f67e9 GIT binary patch literal 492032 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 literal 0 HcmV?d00001 diff --git a/src/NadekoBot/_libs/32/opus.dll b/src/NadekoBot/_libs/32/opus.dll new file mode 100644 index 0000000000000000000000000000000000000000..f867793e353dc54441bdc9dd3a955be77e44cd1c GIT binary patch literal 284672 zcmeEve|%KcweOtF2@D!MQAZnXDzP0~Qc{~}+Ga|qQ8E&3qVYoBr~7#R)DjsNNR|16Dm<-L5L zB3~&ep(^|@BJ2PBah2!gaAe8v=mYv5|M;>}b<|DALyhVd<5=P-Uvl-*ANYTO*M;;U%^h=g zJV7v+{8!{Ck6iszS+V{PDBpzl8*#1wbiE}-SKs^a!}Mi0y;}0A4(SE{)i{lIJbV0Be&@42V^~lA?ECuhI&Q+R4;P%{C`)cfiED}HjHL#_?h$Z-Mc-~3PYZlGrV|G)n;1a1!=&WNd=8q`Q+1f34i zDO6A5gC9B_;ep?6yw88{?_R(k|I8SpQgBB`UgWM$T(%O?-PPH6=N)JvU0>+&g!cq~ z`kZ5l|K4y!Yq$ijg9#;XK>voP7L8E(ux32sKwk+oHU4(+u=+B!A>v21KV7m3orEKS z1J7;7O>i_t3%!STs62}Xw*7IZgF6iFNWbgudpgn_;-sm@cz>0hz|2k z>Wfr;9(6kWIrQi4)Iw?KC)w{i=vN#?mtU~E9LyWAJ5{vMm8i*2m_z6onwxy}IlKxF zXrbLyIy;|+>(9izXUB>?Dj~C2=yBmWOSnDby}`q2!Bm>Gf+0&-@wglFBG$LY$Hyne z{~W=XKz`pcfIK3){MSE65T~MY6p7B@u<9LLrRh#|cmfaOz23n`j){CvqNdjAh^10( zbdNh~ith3vu~dR1-LFrjd7cZrR|xLbGz?=|<9ddJ^;JAH8vZXkXg2AM{(Av07hSj^ zs-O5Odb19n9Uo7wN;VY?PyxPCepqa4IG5qgX2Sf+>y%cVvnLP^hxg*!*Q`KJh;RWMlsLly8Hh%BuRr zmy!+mw@-POSR*^bO6?4MDR^25JV$S*4))L)?s@nLh9^~7nYi)Z$w?6~Y1lVRwxor> zkFkBap)2iqeX9MjAIs@}s`z2qtz{Cl?RNxz>gpZ)lbzNpcx!B-i6`mjaAquZrHw2^ z#vmyF<$9@SwqESXN|d2KUPu7*AV@77d6_!%UrG?V0B?ZT+$=n|)+C%Hao zzp}G&@*kd=kUROiYCD?|pg@zPRoiGV;Up0Dh4d0aBi-zO>Pvuc;`<%**7d+!MqzlAmN@Xf zsEQk_TzTW+NOdRr3-77^s*dK$-q%B~)Br#j8fIl=2J<3BkDuy4reFxFw`wTRH5{V% z42)de?z`%QDPCkOK!FpE7o zvc|r#!Bf>)+@Jb*e3z-#@)wzp)4bz>L;K_VIYgo78S%CpV#=H?cyjXYWkEP+$BK>xkzR^=ht5NJJ z(C4eb-(3B%47@8uNwHp3fRcRuu`F%7TCP9o2~pKGo)V+5SB&W7*a8~%~OL06m7!{ zytiMRMKj_^-&x~sMZ~q%POWtiK*?crL&JTisp(YEv^TC9_d@+L)Sb*@P<+K}cw98z zH*DO_A9wVP0#$O94&nEtS(WG#%d{FZ@dp#CKEqgX(KvH-Ag0Y9fK>(IaV=B;?A7Pb z1~);+>6nop*EBtpTs9YqR??UfhahgzYCaxvMVcpZ`R0jPgN+k(a( zwT2y-r47TEXu^qTVwRHV8#NXdIlXZsEd_X%s~PjKh{DW{Dt&k^HNHEJ+g;QokEYmD ziYpBzAGo6mKw#Ted=SsugAo-(hb|cTN4SRuriE(JlHK7WxFvy~j*bZyc@Z=93|1Pn znTO|<_|`wc57c$>9+QbA8jqTp>jn>)l1!q3_dp~m`{Ud_y1w!+XwL6hojsa8tri&V zC~^Qp9wQjw=~a4cchroJYun$nF7_E*saBkq3@(r7kWwi%MNo2{3sBQ1nj>B>PR{7Jykr(Ic}INnVC}m*JjiL` zT*4r%e!g&f694{Zhhr|4M>S(t3IN;v@*Ncw712|(Mh=Po?A_iI+J;}C+*o**)41Ui zj5n7k3{9yvGP(#E-$gTojEsnchDlU82~&|!g$7RO0!1_2gVE)EWW51c|Mv**p&1G> z(1}K$L!%-Fc1fHSlJ*yvO>XTN(Vh02h_(ePO!bu*fghsiGF%zY4R@XC2u4(M$Xs;B z+Z#Ae$d8xB;<#Sq0@1lpP>8FFYl%qn;IcCD$SH7#VzAkQ^y>41k7cH78~y?wgaxr# z-z7A`#Y_uMZA+Zc20J=dg?j8LHUvfmCZyZvtyf|;qE8}aSJbslF7N0T! zNkGvgD0W(Z!JB1`dcB-pj}|_FCaAx>j|6J{u644<;ra>v^Pf7;`>6jQdZfOK9F8k5 zewn(>8?gQa@PiFv(8=jzqL>hXuoysC3?M-N#I-~~>IER(EsYdRn}x5P&dkN1NrNXv zHOZGSv~DnK>xZX-e8k|&715`)?()XhTx-l%L{7a|d*sAy{w|J= z^crfB(yeq_-^3eWVL|w$|4srV*2M*+c8C>{mp%(l&I^KB=NJJcyVFqjW97$<%x@CN zH|+#l=rnvO;&|UM8p_Gun+=Htp_APuj#`gPB%x-d!Gup{5{~Y){z_wFwG{TjPG|^k z1`n^$0}jX+!V*9sM=w)Bksgp$t{zAS)U?*yTzD$bzqdpWWH>A6p-|hNf4lRcrNPm0 zZOf%v=xPif7*a!R>_#hD+Lm3~mb43k(KN5A8JFXAa6Cn8xDYpeOm+PU`eCtW;l3WURe<^A zqh9%7Pj&W4=lFF{v#+c@&E(xM4pByO)FC>ukM#o~lJZO6%suL5nc_rtr`Rjv(L=M8 zUSbV>qu!(1tzDv%bVIEqJ_qePCHKf4q|QWH<|MiKI=m+^?p&?jOA<{^5lUbon(}}o z#Ho0_r%_JMjX`Ija#CMFwRC&VtjA!|Dv)~4V%8cwx-S!2W1$icj%HNP#Pkb{;%Nzt z$#)bFId)%m^XQJX5|gN`e^i`8!`z?UNgDbl?ZAajenSXe&r8>Ls(BiHaDi;o1Ze%X6exzMISF#uFM!kqklM4w z?(A3+YTlT(p&R&M?ZzJf?Sd%~t0RX)@YHnCU421tXnORNGZ=9JWc@>!NiI0ochDMH z4WtF;fEeAF9nmU^ctj{lN0kDM2)Aj8?|uRvU?TzX`zc=&<|XIz&kbQ}8BEe>kfwL9 zLz!rZ`X)AqejQ|;%HepZ+OJ^M<8`j}IFNB!quE1?GlhIaz9&gIeYOfRdn#I^Ek@}i z4FRpY$0pEvj^C3{v_t5PnzMm!%26Vt3jrRGkuylmh1n|+CfV7kB;DHN!~ID0 zKG_w`3dJhAtU#CNqkU@|+zxh2#05p>1S7=!(}9ZQQ6dK%IFS-z=6Fz<(Mw#@##qDV zj<6Ha0kH`;ifZT!Nwq!4BtOJ*EJBTiXfTHwl>Cr5A>J%zo@nz!>r%+em%yhT;9*&Y z8%qrBVod2}X9QIJTRW^11T^Tb;qhwv9!$q0Oe6D^2O>lO!Kj)_NH4mgXWiiCSzxqT z=J(Ec&A^~Q&0foe<-$?EQIsO&4ce{dzbM)DI5m~gEG(pgGkJc0s zf6p7hW4d^K_&VD@4v+hPj0w7Eg0MqU%p>nw`{UYE5!566bqnCo^#28%{c)x%*r|Al zl^$AiS+F{D`r3~0cwpE}n3qqysQM7!6u~n?IFo4-<`tP4!5ukCpJZhxirnZ?cMuI6_jXoYZmRzlSAWejS-d%Vkw z40p@-4`5`pAiNr#%Nhxu!NY|ZbU6mH6e~#hkVOlOYbIUwm05aG4&%QE^%mz1K*0^z z@P!BAZf*O*yHmidv$8w-hm@WD2cv&W0ecJ>3!7j(f89Kyj7{iQtPFcQ;@yMMz=?Qj zI@qE~Kq*JdndX?*dILFq7b$Tg=W%#fy!%ZF`^9FZBk+qLDk*qRv++JheyJB_(dyB} zfg&z_K@O~I$#ZDU^D*}y@t1@@kn&hEm)5$#g|ggWSBg=%-ica<`nXU%=ug{z<5_L{ zrRMZ_6zyoOe~r&e!<@anRT(TFOf?AmH?x)&w>NN1TD)+Hp{coro69NOYrO?$aZuy;1F!D3ygzYGEQV zDmT>Yq6f&mP@rvJoJtguAxy0mEWyZcA+Rb(p?WloNdRZyeNNt<3H*quq~kasp}hTp z<4%&MXkhLd$oq@X7cs6Rt%McXt6Vs^7lwK1+XEt%%OcYkUIz&zMP zF0>bb0N}ZV

4ZAcmgQ-vDZJ!5QFKuuJvEu@rZoSvw5KqJN;5A13kQ3de9gKFyzl ziQ@Ad=R!{bP-H2MQzFK4jATi0M=33ab>0JrB4Cl|H6jQ2i0*LBqHEr`^*2adENhPS zWh`QHy^1|+yfFAsz5>2Gf`MifL5mj0Z0$rG!z2k>tHJgGGrH4SVPyi{mfQ1Rf~6*4 z(oz;>iPOQ(6k_L?LqQ4%wII6_qJ<0qU0n@?8#&RRz?W|DVz-%^CE+y%ZY#fU!wv0; zI6_SlT~?ad<$$c$*Q9#DUAzkC~CYJ$Waw zzFFoFks00*4!NOQrE9-C`qTO0f$DGNMJDj~fscs0iVic{e^5DIyOV^T;eKjlrvq~c zz~yU30D1FrZ)e~wz$gm?as<1SxqeSZ;CJK@M&nrs{oOj8x<3y70or#fzzRQsO7VL< zUM#t`p$$01p0NT{SgnA}S1OPjNyI>ErQQA*NH;rkN74H zjgx;-O?)!KL`-nY8V;I0@tL!++}1912ee;pubinqW$v;UYT(e`J^S}k3E;XHYh>Nb zV>6FH#PwMB$p><7yJ>OGR4_9pJ=l%ciahG6h#EMGJW_RR8 zv{s_FF_+fxHlT-EMA%Er)EtZyb4$ZC3H?}h;mT;JwO&sOWV-!MT9(BgPb0v+D7;5& zIF2`HCW`_t_(#BC{tU!Wwe4U7Yg3?5x2{3YGYuL<$uRZqvQ-gSsV?HURu2jwaR0hm4Lf+ zb{H3rK)rbx_LE}{)K#YvJvg0OfxE<5m~z8bdJ!E<369;m))m|_nhJg1tDZ zhw~z}V{5VGm~iraaP(ptgx13TH)Z&jcp`LIl(%Qj^)91CB^N(z{So4xnbtg-b40Z$ zJSfpl@?RAcMgk_obPYn?;B2bBl^@Fm~To-IpPJ+jL(RB6Rw6ipRkp>l+f?BZ2PVDOkF%3EvJa zbQ6?yM9M^2TvTm>g5I!{%+`utn9eQ|)?+G(A`us-MQr#cn0Z$SlYNK%2f^!HdPQ91 zd-}(4uO>JGIwnR*NFLOpqpG&$7v*s0Yg=mQBHn=zoDuU@4pm=+upKaF)2G{#4cWoG zCxBeTMpFLj6+=44d|I#Sj`?~C%A&7-sDB)@2#zaS!xLEVyhyOBThX3`iT@h+poIgN z4o3Y0ZA;mZUa>=r;+rwO>@|_*5m9k8an*aUCctt`-)3;0bltZVMu!W8N{+)c-4_w6 zM=y)(6>sUjO^J67Ln4>$6P@86{|(7Nqr{JM8vzTUyd8E*eO5yaXh?L@oB|k=xPLPy za~7KOF)Wk_AR7U?3aJdfO_R~po69M>N;5P-gjixNJOX^jMD?<*2&8hHv+T9J9)T6^ zLh!ZvW>K|KuZoDuh}aEtD_i$<>t%20Pc~D$Q)_+4P=BtB8EHS)D_(1q&gaXOoj)~&cC!>x-DFxKziJY33)GDH(juFZcNq@iJk1mS}g zo=(W;gHy#n53=+)0VkPn(g!3|PQuGnv5(j&6cWEjozZFI%H3oQSL}l}Hn*ZT&<~78 z8--}2YM&TE7PNF9Wjl55bdlB`h!~;?Qq= zLx{A2#6n-EMJ(%uVH)z#EwD5eJg5YZD_Ol-I10RGtZsM;^q~9VG;gU*y7WLVs4vlX zx6^Ub_nM-G-#}$C8j5J49ZU`)@S50*#SvY4<&NPSK|lb@rJ|yjKnRRgf!&EO!e$4> z1GK$;r!mMbMH!y~Rx)(5Q!&z}X<;AQidwTm7~r>YD{1#HQ(CbX!6eJRqIbBN^qM1Y{3u^Cl%K#^C?qU<=_p z>`TIT@ZZXPqC4<5;H6h?w9cc(KMUOVB7AElFjply^}AmWcj;ib6>ot6eJ+exjIx^l z@ZW*pG3y4bp1^ul?hyTY;I){K$;B!H@b`oF4w25|Dg!;04O!2kYZ148MGHghZYpJ2 z7oZgFosafxg=jkwo|F%qVN`qg3<@9oIc)}d4nfTP zJ1W9!Pzn_BrEA3}#E58HOj0lZ25tK^(U!~a$aG>?C|ZT40Ym-}sJ94(Qv$0($mGH|echWqEDqDHSMfjrX@NB|jC6hMOM z6=?$NRk2V{(JOLA#cO)SA`)H|@9PzAZ$-Lh+&=@DehNdT5Yl_P!NY7Srhz{;u2+U) z;nlbYwmM?rMYzL_LzLC&Wm$;ii}nI~8HHPJ-092GE7OHhiV_hn!C&1sTU0h0YO@G0 z;m7jqxCj^FR@>e+!H@JnBYgP`dc7i31a|0c48{{$Ydrd1in14O>9RV_2UGO6l7U?50j5>tL;nkr@0}-EpoRa)_mnYo z9j2yjPuE(T2%dAA$N>+sovpVp-WY^Nlqf*vCFRSU;}=q8T#ye4e=8 z!jq|N)Iv8v?`P;yLj<>0#(#;(hFU8Jsq>)q7OEry&l>I^LR&~_AP;Uwu&Q1WVLx8! zye`7`j21c{oe={t2zW-t^H2dY2>)O`>6LGZa1Iswo`v|#)P1G6xb-l>4tErjNi%%U z-~w(}kBe&fwk2-b2mh<@1-@~LAXQ@JR^?I zfvoO~4$o3LdBAdD^*sb`<^vhGO6Vznt@=4 zGHjxn>&%ucDj=7TL0E+GA-cK^1?hTODK2TcLBPPBOE-8<6s9h#Pb@(4!JHQA$qZ8) z$lsFSHN(_X@N`D?#c;&)ER5nS5|Dwuqr)jEYN2L$NZfM%gm+tvk%gEv(S$jnX>k+^ zozmzefC18Ni5(xK9mWBZS8PU?&Pze+2Ar)BxAo=`;1kl%s#t)d3+?84YJRGoArN4VfTel6gMYcJ-b1r#>afSsg^du#A zm|=?rPJI4OF#8r-N+efagFfNQorBTj$@nq#KV)XErxA3lJvN+Z_=-i<{}2NxA?DBtyXo1q6v<>Fwy87Wbi zrngbkhI)n0A`2f;ELt@J+o0L+J`Rk8P{Uvf&l$i3r8}9UP*;R6V-mS1+NS^-nE;YV zOEJK*8WgBHqY+aBh6dj)knA4xWj#m|c`|>CCC00Om;*^|+AT+QU-8o;XZ1E(tCuNg z?3`A6imuwNySxZyb~CYp0!q4tL4dO^gpM&OZz?n8bYs36w272x(MGtW`OaFmk>X|K z<4H1oDHHUTh4g;AdOhR7KS@F&s{@Pg)(zdM8#%G-NGL+X2>fDHEp;1^nkjRj< z2b0StF$Y*;v#rS`1J+DoViSBqGFORcc>{^(kN#I^V(o=G27SFzutc>wM(y}v(*%#o z#OR=jqYri%ox`Cxn3(Lnf0Xcf41=G_qp~oDIc>xyg=CX~xXmEXf}ii{wmF_^_z?HI!7njaanFf^SBb^;beF z%As8-rX@|?+5_X;sTAUFA7ooF;R<%RvMb`X?KBcc7ATn~plwKn-$0klu3b)y$C_ll zq1hk|;$ya)HK>m1Ft1k!d(0v=K0~e?N8{ioNyg%cL1FzwEK&7~Nv?5vWI*QufE10) z&%XqQV!M^$yCmMh*aux5fcJyg1ErFAFeqT{+uQ@3LxO;8D&q*Dg^24svJqQs4M=!0 zHpXvN&C6s#TrS1>uj#dOb^Cere0YC6EkqrQZxLkTFw>kK&9fFu+AY;w($335_*ksPe$ zBOcj*fWo9zan7o08}7$)>#P@wc0vIAms+P7`}d7-u9}h9f5HEn4_Eh*08}>3~Nq10LuS6}1sR>oGrvC#=prs_EEw z06zbW_;hm?(8^q(#w~7=I8%H9vgA=o3$H_C)<*m>qte8`8?%M4y2q@1()2xPhb8QH z4^F-#8uUFG?vWL=hWltxyyD~vcs#zFgg6w1_-ja29fTfX%kya9fRy2SmeC$UjvbocB*vSD=2#+IFaS(R3?=H& zD@);1ma?2l056kXf9bkI)|ga7$x#AH@v}ojBG^Z?YlMuN)tC@bo7Hy$!fcPlE+{4` zeF|Tu)k$`n?4fUzR2vx7#DK77@I_*n%&*xnfX+dBjS@%Er}*?qI6!y|MHs{6<_z2+ zKB3l*)qDrZXvJ&4SUXlU3+`}Apz_bG9UHnD58%j-z!y*0@&DSfNTuyC_YdPkSb6NI z@(<=kXnzEI+398?UffQzr6hn-#AGPUv{YY=Aml>N8a%ItKYam{=N!g<9+}i(hadkQVR8w7ynD(?Zwrp13Qn!e0!o7cUw`kq5>~ z4@?xu)1r^jHo~5RWU@emh6w|+jqfwSK6k{sxMmMZDFrY+-pS9IKR0)AgdP2+YmD*) zXT*4qpjIv|*w1bZ6l2YEyl=qih(QAq1%@i)_tEUV(36)S!UZf?E{)P^b_c+jqr}5|%;Ew}rr?aJ7T}^*e_t^TH-RHloF2Y-LO%vncA2}) z*9bZpE;=5NW^hY_Ov!yPI;O;g>?X3bN_20*G`+M^l9QG+Kt*;*GD32JM*8#C!oSb!!o9 zPvhq4NXuI_V`Q(6ZB{@AP&oSAdJEo7*}#ST-Wc+Gu|aaNz6yem>GGZ&WN~1~&^-u| z7m)5qA=NC5g0dzkO3&UDIL+WTE%ua18Z1Jcl}5fntA+22@ut*Xblg(P!Ae{Uj0Huw zu91r-U3+{L<0`YD~B7UQj=2+xKn1Ai7$*mPKvwneR4r2MJ%9#TF?*US? ztvtv?+g}d8oq@M3+Ni+@lug92iSHBQCNe>?I>MkGNK78WX06>usd5cAW>BJ4a7V^n zN;j7N9C<*Zz>j<(0N!D5b^xR2tPz=*0v7)y-UZKMgRd9(WllHM)@1Y_NkR}4Y1MvX zfoi~$WEB3!OblNzf!}5i2zZ|bn?QXb`3*(ISHb;Z_FzvO)HC9B7kWnn{Y1WKu=;C8 z@iWw#3wd)6XkN?JW3#s1dnA8-VDIG>&e zEd1{qc1eBM>=`^{9K zeDAQ!?2+vu{^UKoRv>L{*h#4hgCf&2pn3*RVdyd;?rj+YP~ByUg*>vqb1ubV z1j+sdRruqNX_9G7#waQtz9I?l)T4NV1^ynEutPySzuVhieVK_oq(`tH4cR-%LP`^} z=UN;_-p3}b!HHF5dbdI2?cLWCfbSYTOaaIK_<#ije2(!;#&>EDA0|faa|NrAk5QEt z^Syw{I`kqHi5y`l*yIwzYsv<(11>IX_gv&6b+Z`nL`xCXfLVorP`DR3!L@O}F!`lN zh9sa7xjO2aD8(aijUIqw8b0|OGxdj%*s%Ia{k9x$uNFE!A5nJ%1R953qQCz=Z`|*u z4E1Bx$KW#9iWbLtVJYFjSb`^Q3twKvBpf=t@xKW-qy4V%2l%V>e<0e9(ue{`lx(8A z+OBR?L_CjOU81a6`m4n8=m%g?{i5x8R6+n-fy0VsuC=z&^n{Utzj|3SUWvACsDmh= zV7Iw)OtfuAfiQ;f7f;4kToK8k@ay?70Q5kn)_zB(ev3PJe3s!qZ^*bq6>Sc*7aeof zR%M(98j80?(`)$bWqQzVsmKsbxu}qhfVE3B;B=pLC37hJHNT2ZQ} zIm2`lJc|g$7w4jaK?@TLkD^6h%nJ>q6s7%@?w=kxrI)#o6mwH9;z=Ck(waK5dtW9W z2fT*2M(NCkvR*j=(WFw}yzn-p4YkH_?}W$Hv9%FEM?!ma>os_S($U(X92Mamlhgmr z^%x8f1LFBQ8uuND)A+xkMCPn}9^Xh8V{~+yKysBm8(@hN0Vb4o@MydUHEZ>KI5b5M z6G-$nif4)6Z$vL}KZ|f750ECT7o~Z-v|GCLHfb6zqKZdh^Z-)}xRzYePX!f=zitN= z7bfi|mtK--)@;TA#ZlV!#M1}hpyPCD4L8HX3P$gK5h*wka5(0U_zTJc;etc<1}sWI zlR0U0-EXe?1`7xIO_JU@A8>CUY8)CsB3ts)p2?3T;DKt;mbibdp%eBPdRNyO?r)h9 zWpvVBL54Z^IniE+3XK9HXG(iMm)S`3k~J}0i9rbUd>dl5oe<3#3)9gMsD!Ye08MAAsopzsFB|cE|521Y$bUOz3d%qV{-zm%p20- zpJ<9eDTDXzO9%!mgkP0hjNGWGXoUJj0W5^GXu)uYa1bvk9BPPskd6k4oX}|(T1BHX zfEXy;hN_pnNo$|hR~J*P?m~o4YT8$#1&0<=DPqYS>3p7Ej9o%B$-rD1(@J;vWFRlN zIzvUsWRV|CKNKh?kSxLXPA#+?54Ed{esM9N(!?2G+yH&b*k(Ifejg{~FIpA~gbYm|#Z#OXqNLawUQcvKaG zwVl*v@WV66shfXB)Sdx@$v&0+2Daj&JZhz!_`PTS=mu)287Xo!wDjlHmn&2&H4bjp*9(GW`MI z%v8r_pj+x0Ae~;aT=ZrGV$svH^5WUB%4?WK{5lef?8QbViMScshLZCgj(F-yd?^1? zJ4Gw(rkD^PIS-z^tEdL(BGu1VBG7ZosZ&YUq;(+WR!Qa9ej?hVPbUOC7BzL*o)N9JC}Ia|IdF)xsypJ+pvPZ?RXj4zxa7_M#Wjb}*05#D%*oeF0g8nP!+LPM(+{ zsB+*N<>)T^DBd9uw-NkB2HuKWHW{H!Gy&xeyi=WRjMyAqGSoi-g%dx7&lmwupz>5F zexMnacj6UnkF?_wM8XX^Cdvj75dnKCo#=rY);aBi+FOfnbS4D7tPvbfDQi|F`58p5 zwOo-#R2wE}%R2%skCG8Z;RRKgbR~;JitC-r%>^s0wX|xOn1tn+saqQJZdA1v-~q7H85x8GFq5RtJkAUg&QU&mA5d7*84H5-op_Fg z>+zP*Odd6&Gp>_YnzrXkK8(bSOLVEXL^Lmpac#qe-{8jd)fup6&({|f6C-|eHuDDt z8?_l@X-;=$O9cJsoK-`y;~!D$$YQO8##NN5-|h|`on;iKAGDiq_%8QefT>aK8*^wZ z#CGR|S?xO~*XV0snNSN5@ePxTXOv$QJ)}kts-ib>!Q^X(BZ^Lcnd0xHW%7|V3lUJ2 zv4v1Agf?IV@iJZ8pnV-&xrJ6J7AAtGiCA+mGII#{tlwG!e5J!wT(D-zz{czu&pdPm zG2~#i$gSwcH4})69Yvq9n9S(0nEwhNvyCnPd4^y`j^Ih@2iGD<-pgrRTEo{MQLVp@ za)Li(SNUovYnPZsYxbwsFsI}dUUvlsjoAz^QplwyHa1YSe1B>kaXwBqM?(2}2Wsw{ z*@!aQP$oCOF=|X8MCk7bg%S}_3%GJL0!v7EcsfAqL!|xE=jB@$xu1$Cuj{j$r| z@?{!UgGu`>l0HdxlWd_AbI~M{$0TP!FUZn` zj_M)Glp1*}rvymuO`Mw*3gq|Ns(@4`mfG!Q;X5>9xAKf!M7@aEEK(z3;L#qAbe+=) zfL3XGJ8NIa>$H=W7>0F#v`o&?Sw85j947vb=nn0_f0FiUL50ui;N$~rnJQ)#tgeaZ zOz=G#cVj`)^_E2#67CQcAy!1rDas9DzEw;GSk$*;jBI*QF>L7hI%l&5Po-d|rxY2f zTY+8dVC$T=SQD}=q;e*Y%cJ#R z<`=H}3c9QW>sXw^v((DwFNW&qYnJmsOARH&G#L{}iz0WK!;J7K7Skw>ib11rkET-E@P($t9}IQel*-!bCY#S6}oneoVrW@-kl1?(hk{R`A2x!YPXMfio9 z>Ie@P6`M_sxFK%e4|+0No~2?=AAr>x>Lb3*c0L)^tRB!_1__%xS4LbaQi%kR;` zL-fSFS4B=CdLZPit7z6jy9l&NY)F@xO;|Go%ZlvPlhIU(14MR&kQKmmTE9#39gZ$v z^Au@BY)o<$>YKlkT;-aFz%Z&X4%^yiE1!H46NbKi2X^%%uM&o|&Iz(HmW<34!{ivC zMHQSXBdve7^}hneS=#z=2Iv=xzUY{WZ8xW!uoVTH-DFyaRgA_eI0~+A0zoEZj#NMy zTav2d5wj(M&a79FWha&DFKQcJ{1_!0@ka(WpurKJrtb*Hh|x;a2W&(xG+ke#*+Q!- zb$7Fc7M8tL?IiQeBiI*x0US{*wBs{LNtQ$*X&Xkr@wYsnz!9DESM+vT49S6zq6tJY z+^@o~dvPN>LE}+x)IZnUHSEMQoV%UzoOMafJ$O1Lu$M|6PnPf}@EJw}u(vTC@*47$ zkg;Y5rX;aoj?6*!H4;XTq1mX}L>P%JQy2i*3)=c)kTlr&MVP&NU|3ss*SBQ;iJ3Z^ zv0dWuU{qo;I>6@TlV&q@qJ_T>>7g^XmH=erV!lUwnb7POcqJxKK0FikwJogoXj@vy z!*yk6ov*pBg`8=_SD}nh4jvkQW!6G7=ON zrzcGYJel;23_H1t1cc<3P>@lM{Vbp2*OzwE%xKLfI1mdY2bD;s+5d&fzF6l3%T%-D zUPe>^N-xjQ>We{1dK)uKxV^rKCmd%84TXwPrKFfF$1ll)m~y3pqhG1MI5;|2 zmLN6Pp>3F-i?s@qt|)%L5`W`gBeX-NC9RZ91xVe2d+c?;AU<=^L@A>!C$5R3m=5$m zcrx+*gcj(UG8IxGr8LwRWr?Fk{x>P}y@opN(zch*#b#`EK85C(k>SvfG@06NsnG+f z=uT|QoB#`0YjH`07OmqVc!60r@S{*`aDSD+vJw!Fh2KI6U;vK; z8%0RXM}gFsN8;Ge8(z-OR4wV?TL}}8@Q8-3I+2-wZA#t%LdWn?#!=k=0jC~Tu{D2_%c&xFgE1rRw5UxrNE2I)uq$YPbGPung2KpJ>iBYD%jqMQBK-d^(n zZP16A&URU_o%+N+H$+-1>-?A2R5gQsa<8Ju`DEZFChaH;ATM&hq=hFVPG&LEUe-d- z;U$J-WEN~Ewz{m5S~6~hqv+Z%61bKS)>qX-cVu}sWlNekp4>&o6Dsb80KnjjzJ$*z zXz-iAj0PQuPQVA%FNZHPTI3XX?7ljjsDM3nb)ualEcg`yOfdy%8eY!L)HaafL1U7} zV*sfH3VfnGd%cB`OWI=U!&+zti~*fJ-QF-^m=?-{V3ldJg4bNXE6chHZ$K$hr=i1V zs;`pwdK<9|oo)CD`%&a`YH(-ZWDH^r|IX2LuDE;xJEaq;6UuiHks^+CM7jg~w_{GE z0pq>^rNPKT+~xE8G~DItY+~Rp#|AaUg=OLyMYsc*;51~-Wa(|>(ZwCI>}Jb5w-f~^ zgL=A1mLXM_H8nES+lfs8^HeDe1&%6w^BIgEha9mstKXy=nXl87U@6dfNt__0wO^m9 zKT66&Q10F^78YPbNIiD53?a~zLW)P%Wzd)X>54Fs@&3zBZOcHmDHA;$x2$p1`v8>d zTK8{Y1}3eJkCvl-)_QdQZbn5N8@Z3TMW7y&knI@$+@Zi`>F?94>dDOgJGnkv2))6q zjZl0EBKmTm*pZ@b$tYNaO|-jEDQSi!eKb;e2~fX0Mmbp;!)kZceAKe1%L`$oEwVdd z*=e}9L}v1jkrWIaDaQBNszWOQkY^DGpW+a3$e%6^)m*CtKVs{Tvuj6DjR%mftCUPlAnD zcp`;t`7n_f39Bglvy8CCw$GN3JKrWJy3Y~p$FQ0FO2Tt}bs_k&f-a=ZFE>P?=*Xp1 zBy(bu`VtV+SPT;mgHGHH|AACC5E{8_>kLfhWttKA5BX~ex1oF(C8=g=GvpEA_iphW zCu!492l9)2jd4yShi+jAd z5piQXSc8O~%tnG$f1poPHQJj|j+?2asEo#fmWthAtG%+l;zkwQtks{}7N*J({Z%f~ zA_;ylYtYysB{()t`2%Q=wpU=`?D)9eM1$Aa1U5>LPyh%kvEXS{Yj_n4FQhe$?Z}P8 zb9g;=!+81`>8G;8_`!+QiPGxu8Akp`O$C9U8%E6=cv_F7z!!akYTkgf0DKOC(?|+A zJTi!7Q?dhuCSvD3=5A7b>582uO{Bp-G7DYpm0b=062k`apn_fS_%g_=G}xx`|2U;T)3e5%6hwafr^eaECdxxtDLl}_*I9=0ANv1k#2;;GLSJ~ zo9)QHy?&IIm*#?*>FtCH=5);CLOD1(_F;GiuMdqc*&OLU0Hmq9xXDcHA|lkXpZA-2 zdvIoQrmOn%IJRZV0TL6~kRWW}Z2X|F8A7^QX`-GLUP7hU%X`MO4Ua;th8SncNHN)o zsD)OMI>B;5iYW64Hb>z=-x*|Xvj0No9A};5x|8@p=ka(Rr>Ww9-^5Y0336F1r1{w2 zlAl3-OCApuM`hU1vYi}j6S}d9>a>tjCq+G!uMYOazY+OVL&#Ny9c5jGuWjyXEgA&^KuEE~n_L0uO#7zZLX10j`f_0Bh6^r) z0HTv{C#&H=+<0_!77`~}L<)Bpu(4$;_=+uFQ_~^H*tASaKq5Zr)nlC+qM1E=GFt=| z!Nu=jRP6Ad4B$&$9Afm1vkLJ=s@i8EI^o?Ript*)?+)hcpmng<>uUJ7^tBx zN(vMr9}=r=EMFuau56~nN$g0L3g?7jW{3OxhhBow2x~IeDBOt~hgQ}tjbQI7?UqyG zn4xw+7i5Nn!>Af&BJ^k{h*vb~Y9l%3P9bP0zfs%^OK|JocRzwltNTM&veK~)^3$m3b(tE6aYrEp0ytN}U1 z^H?~ih{AQm23U;%NVN_B0pd2<28SAKvqC7&3=W!VF!J@es8>IofkA5+Tbx4LN+0r1VGe*iY9c6w3s&Zm_*_~Ovp0|l z@2`gDS0rTe3Au^3qOxAIjT&OQpccv(+aoVQWgMcU7553==Oftaw%HQQ>2e&0AjO5m zO)Zo_jDngdT1_J$iu7NJXS1dbJ(v+3G}T6q2{7ID&x1xu%CTDlQoZW8@UKtsNh-BF z;^G5yaT&^oA(Gq6)$KQ8XU^$r>|tF>$3M?;ctO-3J~(JPleHnW?kcYaiff z_r`r7I*$p$MkcLfqPGh4rZ-U(5h18c<1;^|X3u#`(}mEwp{AWgk;CuRn~1uN5@+Y4j9K1+-d@ zDg(TvQ$bVljJHoK>qFAgExnSlg(KJEy`ayC8 zte3{cS3iJl#4pp^_&n0VKq5Z^ zu?TWdk%2Ua9mo{n=N6ruu+@KX&QnZ6{G@Mr0iPotz%``H<6O94gXU9IXJjvso4?fR z%036*4Hgfxcd~C=@*a6&F_YO8YwoGVcI75^ASR=)jWZ?}L`W`QuWUv^ zuH5~HyBr;RY!M+gd@tZ>woyqL3G}rGTqTv+7W;EapT!#_OR&7=R0;CsBK*Mu7!pP5 zgD68n1My{Y=PiS42;mlf{{SSjimJ%9q=@ zXmxbX1K`EMsv&FMj)VeQv^FR~R$P_@BVc7i2?rLNI6L%61%9OZ7o)|e0x@5sA1EfO=h19f=MIpoJ$l#+49s~rK z?ihi1F*!6aTMqTVz@dNP#bizx@xvv#50nGv{xoCx0v{DPd!#YF(N(eXW>8X7i>cjatjsrjBITtNdqBjlU zFI!Nx(u}YToX)@@JxuT9Q3`tdR@~eCVXDPK9wVeX+93-3ya*oTVHRUXzEi{-Y5b(I zsxfF&m`GHOU4Mq};92Pk3`y(I%lXAxLj-konUBQW6d*|Zj&fXyJ2|t=hKFnqYmN3g z)YuKOy(rEPrS>S?%ZE1L;D$C@9%aPKDU{jAZYKH!rc>;O*aY2t{?Z_ZH)VO;=s(;y<*!?%xI1gtbNFOnMVyoHRs#FHK` zBVCL}15?5J1A2X_hCbyY+~5qcM$%}lzl~x#2q*mv?zY-?V%X!SK-&%f1J8E2lA}b( z`6GpET^Z_=n&ZP&=lZqdj#UZ_#^>?HR=PEhWRJp~cJcoBJmUIh>QYEut)UL@nI0aV1Y!{;Y*HTE@)|*}qA%QclE+>GIES$8! zf+_#67TC{wXtBuG`e_U7TcuM$`L8&ILb~gToVEjmGQ=RWD{w{=t3o(M`LQfx)#c)} zG>3G#pF2>mZNFCAetSy)2mJ@V$E&|(K4Ja0m9- z(9Sz zCH_KKy!b*V?PG=1WiHA;&!i@9M5*;7A{su~#Xebp_Gt5QYsl%vr&m%Xl`6@Q&U^G* zTIU9M?{=_18e-Cq{W+ZVgV`+w3P23YLr$tTV#;X-&iX-t>vLOOH zrHm5T>1$+K;$>Rm3o9vKV&hr#T0I@f!E}QG#b>S{wYI1L+Z3v^q%SErs_yHlzA!k7 z<56FQc1bppd4$ME?9(eYT7T>ZWY~M=Wx*+RCCPEnvjbjft-k03q&ckqaPmBmNk_=b zn4!Zui31$S>4S}Vm0M(NkH=$FxY1Uu}th7?$V5Hth)7~|wn zYS)f7O`hu|1C9G-YE{fAE_z*lLP1|vDMsa43&8|PrV;zoj>x1Ld32G4Z1uIWjQ!E- zx_uqyZg|u?<2!JK22L#+JPcoQ@+bA)C9uOdoi4BNpO#`Wd6AdWFgo$>iT?@y)$kxd zDNjd|agC|_yYORmon~<-cGzJbGX4)n_jSbIqr@Wgg5$DCwG5bO-IO6xiYKqW8hbD} zL1|cJzjid9gJaDHJFqtHpv?Q=Z0hmA5V_LfIOCL)eY~Lu-|_*BPs3+`MXkiKSdD3> z?|GaKkL8W?IU`yFv=v8u<})b4Y0H7;?L40@dCGu1S0JAD3MG2q{7FhO(fg&f_~p0n8|gVk-mAGJO`2GNo&7RpXjXID;wBjDvHZ9$_XrmzTHNtykf=I}-0Q zgO2^}IB-efy$^M^kPm+woJ1ZlPS0gMjxSI3DUG+$H3c<8i6EeP{&NAI)m2!R2S7veV+azsDM<@bs%&A*DWN;0Bkp(!uUuxJ<<~kG35G`Cw9*TeRc8Kmd9Osrk zm;r8Bx(TG!Pum_TasMI+exlcMj8$+n9U@Owm!A&ql24EombUIT_^rS^COi!|LhV#` zRJ>{Z7Sx~2SCh$VlJ>1TO!8=T1N4Bn!#e&~nq~=>id^4SjVxd}y8@1y0Uk1N`)dvi zN215Mnn89f=|T%%jUKJPU~h<>UqJh^8a5J>XT!?iO%Uut!4LO9C6v}0F&sK;+)m#q zrgZt`gg7t>Cz5zzR8WKfWf_2WFtU`{G2Jb}9dhQ`ECLtiw~J5)sbrfWQ*6OqB>f=a z=9gPPIygT5z}rg>!P=$WEbxcaUxXj~fB{^f;5WGN+|n8Byx98WD2<DNeIl5U9j zOcgF5!aZ$0ISz3W!byLcnYsi(lDav$J9{ZK`p>!)oF-NgerKsG%x3#!-mJAEPV9%p z0Dl*s=|VTw{iuv3;7uTwMTt>9*VNdu^_v4!L2d}9t*cBD>rTIoydmZt)=}Kz{8x6} zAkJ^~?x*LVuU>Js6On?udl~3j_&-n;VyKeIZdZI}gh-|bHv8alL__0XO}4)o7g7b| zyy1mTl(du2FjDT6*jy&T1Bb$Gfj}YeS{607>)k^X1k(+QvVeJLFS;KRz00Brjn3m< z);GFr?)53vX&7IJvTSbgZ7FL{>Ma~Y!mfti5u8WlB4j$^g*j(C2Ew^n&~4=T0DMFxEO*$m85lm( z0Y0Uqj0uOxH-3c|$&BVUu13kzli4ZBMy7mo8=_1wNUxNcP>?EP_97z$h+m>)QO7^Y zA*ooV>yw2)$!G*;gxq??HS0};t)!JuCMTE#p?fkK z8GxN8WwT5=mGmQ%POT@<05I$gm|7!<(mK#7evtLe9cY#f+Q}WVF=k1*-P3_=DvfRK zPUvQKTsO4@bf$%JCIT2xV0y5s_|fBm>Oy(k7UyPX_v+P9?LBBfYdvKY{>&(>hT(3< z|0PAoOYxf@5jdV<+I&Pin>l{5wk;XLOcMU7cq(~i?JyrFBoN_f>n}xYOJ-D)y!r|W zYSL>gV%p`a6^Wd~hvwtN&? z(~(X~77`ObSx9maM7sNKfV%PKF0|7|t~8`HoD8^(^6Oxw;^Y>eOQ~p#)jUrh;Gfly zKt)bZV}B+)b%^oHs4^LS@arL?V+qQX2r|Qrkb^R~;5Q9&v;oPt{|={yURkGeE`;21 z-~K#x-J`wgl-Z;t!?aiDEBr*efvFE8GsU}GyVX>p&;xGiv)yC}aJpZ_VI+ono)hOt zBHBJHuRFWjNXrntFthVIvOAm=jb08+2DZTM=V=#_EYpfUJNN=xi zvsT|gRw7$b6lA#%@RCEYqr($Z`8QILDw}0?gyDWzPTWY7S!?dwv{%p5Ui}wk#2ndc zWX^brzz-pAWL|{KKF%H-UK~?(f~?-cV0>HY$IoLu2sae~5>xB=6=#G%chOb)nLWc@ z;AFJL?-q>D${WibLwE$gN;WI+D1Oj0?qxxtg%lbZH)`Z(z*I$h-nZBO9Np0<|rulQg&#;5{d{~3bp%C3pxxcX2$)PV(ZHDt@_JnwL zH)C@<^rRxvGQfJ6?WV`SN-P-9ee_FUo@Qxc@$PkaByl92)K+ljOn2aqI3%P9x)Ip* z6ouOQ!^gyy%^~Z-DBrMxMFq5h-g2Q3za!GCw~&1dIf^MJJ=fQskt(dQ@LJ@JrL6v% z1P{FKs5E?`UK&)zd1US#QiG$|W)S?Dil1}TOV^=z_(SQ*mU)so=Yfkj&TGLh=CZJs ziHdsW6UhX{0DGO0KUD3y`V&cg5%K2u z_-E}Q!NC!N5dvzKwY!~~B<5oTwu1jaJ#b6+i<&r62#gP8TJv57`mr-vd;I%QX63Mw z`J+2I$#Wu&H2e}Iu5}fvLF{2vKCHC#Izt$QetL$-PFReiuO7k^xoNDLHP#Eg(7 z_%4Wnv}S3wzIzCE?z&RgDD(x{v(|NZfFA5?#!)Nyp(I*d#H6KT*}4f+369<;G0`Y? zU|$WP@6V=S7mr=;Ne}Qr6d8R>uP$!C{S<5Ps8@trQ7%W=gl?q-Wli zB29jhj&g5`+z(3`zSxEKX5 zk!hxdegR9Heu?4MCMj=tw4!Fw_G+d&ve#F+FF+GL3YN9!N^WPT(Y2|%gUS;m5tVC*7f72;>SS;oo? zw$BMu1_SB$3lTPg2V0&DgflP@scy% zIO~(K6nK$v_pA6!H&B{j0_nraD&_$@M3Nw8uC3dQrYU!kBsTn}fDF{iVxk;uB5Wj& z=l{zZt6xSl56!ga4c?1A>lq3+Ko{{2tHFovw zPaVSe;4op26)fV)dK*<)BttF4FI{~tjyn6@9(SJ|q|LUi3`uCd|~sxFX>NnYD2?705vh$V;0h&iO)cn@YJj zBqxuFHj^F(X7-;r?9+@`n<9%Aefc)D>oBhOUZ zP)c9!vN~{KQLy?jkd;-mydG=kNxYn9b%7;M?jxSGBCWqbzXStB2m2G~;AZ+3NCWlt z$V)hmh|s|Lg!1(;pU=ohx(LT5a3;s6a*?E?&o(CQyqI!gUQKUdm@*FvLBnsMyJS)^ zb9NoT80@ipiR7pj(5R|u+V&EW3ABb^$7fPT6Cl{!&8;vdW8wE>;nVTiz#j><_hY?w zSsB!Vokwl;vaB>y)5z(RnofVg=dC#ynLJ6&V53K#$4KXy71K$7^STkG&_Z`mJYwm* zSznLH(!5N%4dbU+=n%0Iu(XCB(EY`8Z*XZF zs6jE`v#b$2Xm;fA;Z|}K^EPvbe?<#x=g<3hexTof&>HT=-+6!Ff)A44i9b*ix6`?!B_iGW5x_U^%NV;q zUu$@SCOMnubRT{2Ri4wMcAp{`!F$U~OFVHNg`8`M%wgRnzPp+Z1N`n9y~HK-8r0TH z(u5x3n{=U*!mO9LgMLs?~ zBQu3ItF1qV>5BO-s~PW-`Ly%0cnVwaN`9JaJ&M;8p7WezT?=Y#mG`{9l>XPu zdzEfD&#Dhi6@{AKsx8N62xVf_%Ee#9$KoPGf1Lto$xZv@w;4yvCS19)tQuXs$cPnp zl+1yIvwTQ0@T$E_-V$+9(jI1uc$ZqnIdyB6-<)AC)y<`B{{;a)U@zdWP(1xDYOg4E zAC|g5Zkp|isnT<^Vs?8)krZyPz%C;{`MK(+EMI=G1_-v%X6jB6J1YrrigXhB7x^?O z+(c6JwvNGj*Lf-(Opo77BZJOZ%;)iZfXj&fXFXhGlG&}g!1^Xzxk+>1Esa zrls$s7-2bk8X|j~3Lt=gYeNw0ZyT{+jV5tRBCsHyGTqTDV+{e~cCHlijkKAO0f{)M zo^t-|Mha%)z1Hq-kMzlaNmj?YLpDM$Y$F-CYy!YWT=|ErN~G$-R!uTd+1!Xo04g7s zNT_Z6u(jcCGe_hABAXg=Hjy2T-TdgO+nV_T*(8V$QDKCF~`2 z>*E51Hmi23ZOcx5j?_}!kA*h3 zl*LriRP{CDRn#vDhB!JxN~O%{kyeRGDN34EJ0SAy1;)jcQqVllOftW2plb5$y+$@K zZ$|e2Su^sX%v2ncd7!uAH~4TRvr*RMLduTNU15@AcoQi%k^o91^IHH&7@IG-Mk1`4}`6C1#-cXVId-*PrT)DQI%c zM1V+AD{y*_YFR)@9zT_P#Fx4S;a^cho1%vQ1f1lLH-7_5uh}&le~8rb*M$*5!@7=h zxg^N5%jNI+VaHlR0DS#p11DdFkyjQ-^KZW0<54?dUFwfSGI~r3ul74 z)<|8)j|8SJfI)Foa{JqC%bNBwo;H5S_HSg*L&_2Ma|OS~*3I&ngg;bGTCf>*2dxE;6=QFUu%PU^D{qh+>aoPrhlaiR(TP}HlZkcPl}h$=6qE}C4X(V zzwtbE-K3t+#bqYA!Wt-Zjcfpq(o>(Tp&q_QVk|)E#WlTDJk!tjwy@02;aCcV}pF+=$4F?i2YblEmb*w zdD2{5m-3l;7>n=lr>4WMlA6?@t+?<8>&^oDMCdl0w0Si)IkFzx3TJ^0Gr^X0W?E#m zX#Bd&zY81%7M6{l0&x$vM92Uu)Uf?IX1DUk65nDqMG`I}cQ%YdhVHuKyn$FNs*W9D#Nl}iqCrANndpUnI>yvncVz*Co zcv*5b-J&P`Pk@P=R4d8|DV0Vs97;Vd1#&2jYb_QRP~MB*4L{-dbp9G^#oTOpY&FCa zysP<3Mdr-nv6V})Yx8G_U$^yc&27$>ZhI?0C+FUbH9Np>96sf- zYOy^oWFQmNt_CbuF814{x0~AqJ6v?(pd;6usIj{#f?GXz_>alo?E*wsUy946I|q^; zbMJie+?uZy_V)fZXOA@0`z8?#_XrZR%dJq;F5QLwp9dx4|H5=n{T@}eBt`=y^y4vR zWd1tAUrH?c52CNTo%2{$O#$cy*C2%!Hg7>Bw^El*?0~prq=p}6=~X>tQl)>{IF<7g zR&XX(EJCw8+Zr2NykJX&za+3$g#?5ou@-4rb;X@?ujGb$-kLK*nMKl8@C$@`M%Z;M zjjI)2zur?K^i6Q~B@b9LWrPK)RtU+ODY7`O zR^@!j3moYbwNRIIQz(dk072%8D_pDut+*PeCzoBi2$))c-O5s^n*J0zvyinMEdXE~ zDCi>eHwZuBLG)xgk0+i`jt-^PJ%S#=C_J9YX6ssWSWf*FwwD}F{5CthUAmy6@iZ8+ z4WcLSyC5qM-Y6(WIkwDiSP{)~VjQGr(GQ{>*)C|+9)*leO*B(2dljzmBH}6mWo3NK z@^@r&iLDAdzUp^0x4B84Zx&2*VXOR&A7E@!Q86q`K2IIE1qb79B@D<1gwf?M2G|L5 zk$Fo|dIXc_>rQegeJ2X<*m9{R0D9s#vsf|_ilwPZkV$eUL3KmvLV9Y1#gg4pAZBfl z=Ssy*+S0tEdX34Pmx`WHbzHD|RFFs>z!9|*yQbPhiH%$r?PJCmku28k((O*RV6afr zKhHwd8^&A3N%i3$GQQZ#mM}|{>aM%wx{EEE>*r+kmPxae!0R-#P_Tn@QWDvACQl{( zk9n>#>f+QX~!0}pe60VRT(<1;XzmxH0*;4dWxQ9p zs8My8+aD@uq#x(UefkA?dKLor%P^G&CSax?__ZlIC}6Ia;cQOKiq)FVU3#1ZGS0LWiL?2)t^jfl2^;nR3oF&-*~AqYP+rK0KP)O|E&L~^g^2OS{`hY`u}hF zUCO=)G-i|bL9)5n-xukh3<{jU_=p`?fU~g}!c^j*OnwlhudRH0A%l}W2F?ORNjLEv zL&bT0i~Oi06XJm)@5}w}hLv2agcGdG0tZvMH+TsrRAMw&V!wlXioE7ZX_LDQ@F$XN9mX?<3a`6_4mn|^{uY1XYL4aEn89~y(F+1~rx z@CR->ik?46N1;w{T6OEq>J_~w%?(A=xw0Wo4y!->8VSZZ!%W~F6@A&-BMrLAF~liN z`P+EJAm@K;Uue9>F8i^D=TuM%Mz(oT1sYZXk#M_ld%FbgAY(L9sgzGHThfwNqgcif zkK%^SaZ5R)y$5B(-K{5qxGiyhbFtdwr~$j%epDcv(MFR`zKZ0DV-#op1rx;4sV0z# z&a^PEKYYSi`%TP{?JBmP;HP&Kg$xO73TxeFMZhHYWIZ3t5vy}JW!V)3c9z7}c}p06so7LJ#wudrY@T|W z^G&ZPL9R*;m{#&wB8%Oso7L;>(pTgw?!9PYxC67yN9uR^?0${BTdrQb;Lg!el6CXD-(Q)-2AUE99Rx>Le&SPtX_Cr6vy@-oHNtpS2b(C={F zD!apCN9pVOIlCj%Zue>n$)98)z91#QHgS12I1c3{@zuWM>+R3EyVbu2-&S z;o#Ga1){xsUH{2P`6M%rCIrj)rD%)mz)ihK?ZLI28L4Z+yNMiBFDuYj9Wbk#Vv+U8 z)iQ)^xE0fF#6KmYZ83-4Lkk|l7k6c6y^P!iIAblJmDrNuQJn9M)lZ2FpbI}g?YikZ z@fVO$#?o40Vugw-kyVc!c?H2Z;6Yii)Xn17DO13yc@>&rEQ03#&apWoQ$-U8_qUBd zQ7$$}OtYnWek;A-a`|;nm6ur!E07MSdxy)3G{{}4oUdY|2TUolNdQn83UM5M8ezf_ zI=Ktlk>>!X=(t1~3T_i>@$zw|p+31UoC?jgI zXjCeSwLK`E9m1c-D-xiH3k8p_jTl=KF5%eanKSeAI>x~5E|)6$5<8KXpB5~p*x0#x zIWYM3f>?8iwA*fGkJ{(m02@|q9w8H^)rzaX+A}vIZ`fsuCA#^8tlH-=d8@#`rgAcr z6ZspY=dMG(Hmdbtv{kjjP8n(yieb&zk(JqC5f3XRXk!(}>)j(lgqw6d+;}$Ki}_f^ zq^lPAzSy!AaIjpsN4_b?;cs04MjAq^x(Qqg3e34Juxz0Rg&D5jf4-Y^0?kY<8={%1 zX=Izw`$kW_f#M6770cav=!E)owI&j$0nzpQa%8DC=sCK!8hgGf-7nw~y_0x{^788e zn?v<(lrhefip6MyPkJJDe;i_EzsWtdAgZ#;g8|F)x_mAbZQkSrEYqYuVAMQzS#0o z<3)B&-8?f!^&O?L<!g>!>%XT+P|ldGHM(* zYgY){FE4dy=^Uc@J>}-i>DJ6jM;-JsXU=wALWylSLO5^73+dLuM=t%1OjdZRQMAWwnzKpozaDAxlDgu0E(m%X|kJ!l$hemFZv6{ zj=bqL?5`H0P>vC;Cl7!YV{so0Ph8JsmQ|SZ z%Q%c;zmRqO4nRI4$2qp=32?;FCBi8zmzCfNED-9}7`7K>kKae*-i)D%lK@qX5vMYY|GP z6H-tGLSg#BZ}V*Go16!gt26&kWRjYyc3&o-`WTWotO_d*W7vPiLTg6Xx2qGD3@0o7 zD>019A~!>7QoLcyj5Vy#Ftf=-C}op_ zJH_0flCrzxDy3^yGFk!Qgz7&;_38V)=SmK6S&9Sz6eVgg&!pLC@P8r>rHZ-PEa*@= zJtRXyMs%I=*kbuAvcl6T zb?*#8hBe2(#gNh^s!SfFqs!R@<>Ky3-7l&VhY~)C9kE?alK{ItvVy-^=_f%RnHbU9 z0ENKl5hlQFwMo9mbMM)Es4%AUl4vFpFeHzu7OwUOQ+h~B5$8%KZQN`zVTxeZDvm(2!)mp3!` z|0(_6^+yd_2zXzf@>g)jrt7JyalY$b+H^IbFxEan<(@C9xKO!XsBYFR0<(jQt3JX< zmIMsDYQ`--!@h!BOgGps#bYcu(f?HWGB)K(y=x9jW#T|uKl{rGevJ4Yp3@hpvne6h zQs_ zujk2Y&ps>pz-M0~6Rh!s1WJ<*h-0FxUt$mOzF!l{d~e8r*M5Xsb5?%(YKndNWi^zu z49-H85DV1%axIdx^r&2aW_Wp?sijpssLa!PdE>KgwjR=PjAN>JKeW^+@ zf6T)w{$W77X0f;q1$u4$hT-G3|D)!yvGt&xhQ##~M0UmMj_BLzFG}%o_;56Ms+ySF zrkZ#lPLEH zgK*wNzsOwIKD^(q?8ZL)kZT@RTj>`oFLu(vI-p^%FBHxahjwJ zuvW68jrl;n4%cVmln>-B4dPT`R^;Kais1n}tLqD?hB$cE8!!75mj-_`?*FI;Ec7)U zWGH2Z$^;2WKzjgD$8UBS)ky+8hC8glhI@r}OaECy79U%dZ62`n&GIPRBg;RbATfpH zl&-V%wa=LQO1eb=NW62Smt=SFYPWq1|Li2(MNzX=V&)yAHJxyEK~_J<+n)NN3GKBs@-E&Q3!JrRpu1^DBijJ-x-C^d>~W` zgwbs1J;>{kcluhGqPR^j(adv$d&cl7m0lyMT^&6C%9qgf$ZCrgs$iiIus@T0n%i@E6GP4pq0m{ zE7^JEG8j%9t4EkwYo}Ca-_40hWf`%8KN6*wQ-Q6Knm&Il*Jdm6*EXtgNyi{*38DeNgZu$V4*8 z9y_haexGf`mx3AetDNtH#!gJi_OcsC=wZ2CHCdw@3AY

>D!+PEWdilG%ZClwP47 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

SIxr=y^IWcH&?s)J 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 z z_z&_YTE|ixj;6a8reQ8K!hX5>ckud{>(L6Vlc1?Id&$z>=|gQC!&+_ zF%*kD&F}GT{F&2+7UB_p)V1aFH`+E5Dh|#2)*ED=xt|}`$V%WDetdhRcs{%w;Do}kWqu-f1RCs?ydg)itlcESYwd z7pm1UZ)Q#mL?VUEVvgoQOw8hSZZQl+CV0lU?EiwFf*8x(Cd|xBpgF^E9cPa-rQjJ) zjJvagqO*gdOfZf*0pk5un$MCPTyHEjbj@K++N-fThEet56r4I3lc}2vQ#Tb|?bVIW zPhDReOXXllJ#Fd zYqIJQWQ}2OHQn4D4m*+Dog%il|5xkabYe{GBc0gdJxcJ)JR9>$u9)sseA2hhB60L- zjN-EbMzQaZ6=SQz1lXB$6_7g-n5+YkZ@<8RqsIU^6_?-y4#-b9k^S6`jJ?g`wqGt( z&OLgtt`$tjn=}q#;?$UXI2PHjyO7Dt4QX-zv3(itcj@mVRv!Jy}8i6smNt&-0Mq_=nO>8GKNGrBjLXR z`vc9f@?;Ar&l1pk%Z_DJn|h@KV{Z73ABBtQjrjJhSPmb=W622g@!-m?H6HxWxP|0` z(Cw;2{wa<>hcdY-+xR*%3h&&@f?_=*;y9Nnxs4kbvdIyorb11T-QC*hCGPFpQWZ_{8o;T{OO-X1 zAGf^`WO3`7LaDObFi3anZo`5uW61{n#VKuWh2>7lPi`Zib+&PHln_TtZBJBt%)6j6A5p5)2W0PZmO>N%T?ZZqx2qk$3s>TM+F_`0sccQH9j1>Y{IQykF^|2xZTU< zNwvQ)HPykdK_Z?Cg{y!tktzx!1&q4KK$S05iKTqB)+z649M^r(T0VwmS9{mUU2kWseAlfdbOyzrgsTM`t;)ao1(aTa zz1CgsUHs zb4>;G1`*t-uf-T7XD zz4;oPa_q76!`De>|(tVS_%aN|Vz>9)HnrGQYA#cc)vV{86uKzo+op5GGgDgBmCk{YyRJPQRaJqYt* zw`u8l=yrzz!n$>95KratL3~UI`HgH~g15Y)hF_(Z(1S*re;kAH4Je^$@vnmx&B*vo zVt(uCs+y;<;rSy<@TK_t{TmTgV77i-QUxcn>q;+i20muiKzyMQOIQxVcO*|vu-AM8 zYcAhO_Uil0N5Y$I0FHLrOruJw2kx6uJ=>I52}coSHGJC~EJ_~^;qcAcxhb!h-FRqZ zd9PjF+tp_*f4)MUiX-3jvTx8OBuR`FLa}VKn~QJ>#lG%5whh&ymuNEZUG0xuQ7s(| zISI{`a-Y%OBv}zk6FQE@4FCUPqTa!jo#kygy9X_>z@KwzsAVLtkR-OfrFp!85VZqD6`A&?XcqwAzviH3JiSq7$W8kijCx9#;_wc3^{DB>hQ5)d_jKfqtb-!n!Ov4wyN&-=5^nFPGH_xb+u zJP)rInRE8pKi67&t+m%)duWUZq>yqEA_KvtNxib$Mi?#1! zD7q+lXZ1g(Z&8Yo(|hF7T3ZXa^)?`LG274j0lukGj$40=^n%zGz*B*d9`stG!)1)@L1l zpX(;L4JWq$h3d}TPUlk)8U4kP*Qc>G@bVFpR#*LA$Czz&nI3C4s=Kl6)Hpzl)BM0x z0~-45$ct_Kh0-yvAo($`8$?`iRyS7(ZRP;OX6Y*^ZJoL_n8B@^Lf?FDG?R1r`}!DP zEm&%OeUH;I9U{{)H#<)K%)a%Eu7q#x9OB_Xbu4w|1hG8V;ptRw{q~pr`>UKzKuq0- zy@P(mXF3n}8J^Feu;KYZU^HBDkIre=^U12h5sLHLPP~8n>poBOhVYc<{1Axo-C9}v zulI-`VEim?{7kl)0lBwBhyg#V*zP^!8@k9zCJ32u5&6(`#bY?8jB}R#lwM9d+T)zyClyJRV*o5IPEYKwB|kUS`6wNTv*;w3tnArUhO^UbliyMX46un@lB}O zNaGg*9egMt4WAEvo3BP1pXF=7gZ?oC@?zA^b-!XveX;F**(=zVz<;L)1ukt1Nu5)9 z79Rg1zQ4@Ymqi^qpl=&g#l=LzpcfP3)3Wi3>=6w1hF@V_f-k|&PzJ@h_T%K^Gp6h* zh+nQ>h&?z##G#XWh)5h*4?sA9#M+6(^(B@aw)^lMWG9PEUMh;G>LWOu4B0_Qz1ZCc zD~`IW= zjj zlQ0OFfd+|CBO^}OtlnQju4OM_S!`Em6aW?i{6iFW(Zl^j$JYANzO50r@p%bA&K3f+ zoW5xkwO`+lps4I=!{b*p>8`I*w>PkTSN0@Sf!JC|O%5)mFdFSVp8Wy^Y<*+x>Eb7~ z=il;S_rnjjr|UjOANBpy3}IORwae!B^Bq}Q@ISD(Yfjw0IeRKp8(WK%r%UPBI`s{i zyS*n{$cKe1bSAUks#{+$%-}zoyD$5SrW<#SQR~McVH=P2=jvPq>wI?m_XOdxQ&hwD z{_NX8*ry*(3$HtsJ_V${&FPpzzjEyGbFgP)hvkN$g9b658?G)eZkYPM<8-`7Z!m1} zoZZ7C%uf?1cM#dH&=+^NQ_9$2ulOYVRVXkn`0uK3R}q3h1b#3#K28s0xdM<#;bAf$ z8I7BMmVQ|^r&zxf^&%%V?*v;&&CYxH)v=?j?pPkt7bTLJgVH;kj=%W)%ao~({nT&N zcDK6rVbK<*7V)pnBCB^pD0>)Z>4huA3!RQ1`4#yxa!RhEIetY)YcJ>JD!RZbqJ!t~ zFic(x3cVOqOleG*YA;!PY~>5mC`uu7E`c~XR^Pw{D~+R1#LK9HwZcL zE!j!Bv}D-6c2um8$Br!ClYN-i;NBrt9-nkNTDgmbbqH6I)Ss69fi7lQVcls@A5Rz& z1Z(zxtBCG^X#z=*$H%e{bIQ+eR^sv z1nPHCwt>nZ9R~O(so2Zbok02#K;iQiJdp`Y{#MA&e7OUkjtG@PT0DnJ_NgXj`g8%^4?j2K#}Ht)zo zwE4VktM|f}yeVce(P{T9X4ZPVkLI1&c zsKun>7F`A7-@g+8@kupwBoH@{kb}q3u+v>TWF21eWLJ=2AnWi!R$wVd;rD6l(=dMf zc|E#P9brETA@7kT*FK{ejyKbjohejxb2HIe7!urRAX~$5j?D8+HZ7VMrf17-C*YO) z4|dpfeMz*Im1BeBjqS%9K(unLe(uVs7C5`0o&t67V zR%h5U!E=e1V?{;Ww`jt&)BYO!%6vv?@U?~Pqk`=U^>?_t7Z7%45wus6Jse9GMvT@-d)EAGAgK`zOu#_LUIE;7ktGDQF;}fYf&nG7; zRP13%3AVkeT$Y^IxHz`Py+N#gQ>N`EVwQ!9iFe`y$S z%6sf(q4zV^%+o zpj+Zgb}U&xA7F9a}3~s+upyNPR|4s5ce<1UpxMEUF1*m|}kx z$JMd5>F%xUnP7&$E}ZZV)+k=oK)?@VRwk%d&Q<+@YAZ`r5WMM`%#{Wz-`igOv#3=D zED&?tyR)2<#H28`-!nK-ul=MemP#-^k9u z?r?&$Oyv+Kn}wI*PjbTq+JtE8Mu=v_(IVh)9I?OgI9QjzYf_eJ_&Ngl!7W^NQM_b! zvVG6Tb-l+%9ir5}+|V(eB`vAzYk!kZ`p024T^Q2aQE;oW8Ig|cKLlU?8}Hy&etlr2@~-lUlXrm(jeuWjAhC2`<#+ zY+&YB`wwA=up3(9$)rl-K+#Ho2N?TOtS)S^Uh`SEvA;G|n!uI%C&*7&{K+H}k~tsT zO&NH(f?|Y;m)O>f#0M8Y9>EXcWv{yiGivoRkYrYe>f?bt?xw zb8p2RF?=onusdFy`wZL5>@JsNyDH^com%Ii>ayg#asJIx)SuVBXF@6-d0n0z0yc4R zJR&e&;bTGm=~wtrm#YuokD|Z?n=C36>kHF4klZ_hUxk(_s}c6@imt>EYTK136SjqMwi5C(Yu_9LQ2rTOWh$yQ$Jm;ahrku4<9XN;*;F z4XBC9Y_5P?UGEW3-YLSC$vlm zKuieb!ks&KOn7W_uWHX5r;`T!f9<9fZ~G+Rfxjgn{Nv zz$HXYE6K>d8aRZ53RdMpT`Jt_axogCF1TEvH2hY@80()z$C5o&92`zG_8Js^cL=Kb zq~uQy=sq@r+=9H12AK66?lO2-D9cna0CwNpWOZJ0UXh{I#kEYrP``T;YN#3)rH<&3 z|BRbbM>J1pNLJ&j)DbQ6pUdZ&F=yo|P;kHCbIuq7EQ4zm!u? z)up5rSy~xsVM`lNn!=YQ=arKthqPpMlr;671i88;t0(hhC-I<<)=#NpoT*99o7&qE z{Tvw>2*R(!9B0v4uS7r`h6br+h>xUP&X0Z>AHN;Z4*l}ax$h=%LcUz4SALu9wmfakEM-MmM#q{w;JNLKWs|PLyCY5=yg^Hk!nTv8-G-%%gC>GMOy<}Of zUV)=U61a8kZxoXG%rB9dDxR|{@EW6z_FdulS&CXtxiSW)IZ+nZ7;}#5zOOMfpc$ZS z%P3BqFqYDR{8t56Ivsz*^aG@-*huS`psHXShGP$W^K3Zws+o=fjy>?rv*FmQF4ME& z*sErznr;Z+UiDN_wCIN<;oarBX;Oq^Dkf2Q_vRIoCLGfMX~MfVuaq?5n1)Cb-o1I_ zNfVlBkTk>lyeMfxI1PLACc8{pfkF)mqdN4COOEfmOMh06XSO()Lxksk81TDI3I=@};vXzQ!i|pI*no04Wqt zHjj(b{8S{+IjN?pyW*7`p`mUk^$SMDiSnvZPRHHAAWnp7`_QHEiTV&~DW+tTEPxxx zK!2N%&u^>GS87Z3a=B}Z;vsyIwE)?^Drh2BG>x~%OczUll*@ad%gCeSyB>7i(ocOK8D@(MQ$U-3VGOUkxpW> zSBy7^80=8&ERR6F-=%KUl|etwhBUdfd? z?JZ-E!z_NXw1;8V9?Yj4hwqi9dIX1O=~xxA+3IvILl-tY$&>str}IJ#s`R6YILRjs zV{`ePf)pW>7C9X&_4wcPuI$ILX22RcqD_nl_TzIir@rqaxRcAHrQuYOT@eB(aYt* zeK{eSDmFtxaVK#wyH2)j(+?BLS_DF|mUs6GuYr78?LV88N&C+xpZfjhGV#Iz|Jmfz z4*yy5X*JzR&MQ@pU8GVWiD^q5PueOyRYyp>*V3Y-t+ljqq;0V@384*^Ch660Pvtxf z@ILtdmDem4GrqdXbC5{zex^*ejqsv`hnyy=m(O+pdUyM z!CaC4+7RCBz{PH=p%U zvcy+7e14Ms3IGRRRmY-eh*x*c1)AA%rQ*9UaQWaCq&-uU4e*1%!}os?yJa%EaD1zr zN0$Q#+7NV6zgMuGh;iPX@^^Ittj<2IjV|Cf*`{0nl79&Ex3{g2zu{1?WLmOKY>~@iF|wF+`j%we zO}cc>DIeXvBThKIRG!=i&% z_#G5QXn-;#X)rR6SZ^tz-m=tM#LxQR#=7REsW2z#IphQ&=&Dox6bz<}=_D)V44Fg@ z;O5rJazUfS8pU~=hY&UTT%NgUhRDGGE=- zdUmCQ4H)EceDsS;S#Y@~U9x6st+$J8WtnismeOij-=`{ULMxT~MHB;O2Idp2H5kaO zz`x_7!ZJYxyuAbfT3XSQaiGWHw1rOjo{Ao~070YAnZ2{~@~|xR=B#PXl%cC)U?;xp zP9Y@5RlB%K;Rx|{7&BUw|{XNACB4iCA`MlGHo|Pc5QSeslvn9>I*Qb3L#ZI5Fr&;a1=9rMQxr+8Y?H9HMQmeIV)*S zFLT_+ztzac6{U%}RB9GBERfROT&b-qsKIRv|B**khANTo%DOlCdi)hL9fJUkxvNjH zHCBf}mQ|pMvdq3WnAkx%5c};}B5)bdwDiRQ?xOqor7)+-u6pw-^$VS$4%=+q$M}EY z0^aHeGQTL-dhkVC4-P$`hB9|dwz2)v%3!Ed#3*k_#BHC~P(q@9l{lDF&Mmr(5+_=Y zFl{KM(n#@rEJ2?N%qZA>FYV9#?Go@dd#Z~8tqzCU%Q&bn9C{tA(yHW!$HBLB>sAt3 zK&<31<5L#-j(uG+D&?Q`xhNY#N|_p;x5ICNU?VxGd*gg^9(metvNI;<>5GC4FKAx`u9s*6k5k23-ld z);?6){Ek~Gvw8t0x277-@pAN{J3L6FWsE?(C}|umAnq&t)rxqTPu%dTayoF7S;*wE zxO$q>0^Vh4S#Ij9^zY!gM5`MdjXiAyGDI=yY2G6(b_U%w&vff3j=K~#Geekb!34+* zJs)V!I^_p*BPYj1?95cZJlbl_U3$PNe{&juj)W(up1KWA`CkG19;dty))zk2TH>?S zUr+L*%8M1Qr$6MB?_d+dnY+`Ox52qcMm}9Tk;a%?H{c3b>=8URm0B;|tU_2u%!H@X zB}ahtW%+WumCrjJ_ZhwQlx8p20v%Y)Jr9j@{x%Ct7npAC2l;rbct65XvOs5=O%})w zx;83#Ao+Nu{XQ)bc@2*Vl3MNeQHi`|_J}l9F2ulj9T%QzECUWNS z_6mvD_3|H!D~kt}$b9Ew<^Kk$k)!HhfQ(h_guFLg#`MWd!RVH}DQMt?{u(iZcQQpN z3({T}`E4WTq-P0|^tRgD3Q3n`{uE{{_n=wcn~uwA6L>oSX}9nCSNPFC9s!K~TiC~0 zdOh{BealZ@`*YYb_0OiH(5Zv!MkPp~1@<102pWY*L>h+ChqkKhJs=J=3?q)V4Y!gE zeNQqN1FEt6U9p?U3BhmSAn%wQbrtyVs8T;ue-o*sI)(*N{Tvu#Rsq#XNo_Vz(`GD? zs_>6ip?&K2*P4=6NxK4@CrqWfUYw_@q*<(0<~qudQjR8~K})`s<*HvnW2#>HE*-AB zgrlG|ZubfErO>r6q)yG$#Ng0Fp_9`42atKo%pRUy9SHnj{W znMbr}WQ?bbwK4uCx=YlR`oAz?4LDWa}MR@hQF05uA{G~eX%X8hMx6wvD)|8;HfI^@4@&}-WUVQWP4 zK+TaZjfj~$cHTK5glnWwzy9WA=30l6K>@N+j(LdY;NMj%{wBGFWW{M&Fq!1~NVdYPlCr zh&cc$kb8R2h|kacD%CA8r&`r1BXFx&{>j<5FiISCpETRg!o|G|m0aW7Go#vv#yHm# zLlsDza(p#&HjRea?&9No_+@`Rj)%f1r|VX-ppT4Bq%Ovr?VpO=)OU;B)Q=)=>R(DZ zju;4g+h2yn<9VjmCGxZ>uWh#aV~u0;iA#+1K4#>-h&;6*5RPu&kuGj3|uWJXY;+Xc^0 z6`DFgz&t41r*HRPI#0j)1_OtoPz*Zq#o1Q4n(ZFajXA z>_`B)<9Qo~wL4A~jl2peBanB694sQnnSJ29@~W^TnhcVJ9!r`!oFoic5<~NIS*F~J zTg8!4@_;Dq$RERNcR0bJ)(8h~n2K3>a1PH$u!En2uAu=t$AAs!>ziQZ;$mQZ6f#EW zjB!M&#_KOb44``i{A`>@z%Oz%7>*`DSA9RCum(4bDSaEkQ`zviM1W-h0Xm)kj7pfj zDzFbSo-t0>BHkF!vHxg1qA92*ine9c2qmFU+t{KuHlfyL&k^0zsE?$L{~5(c6c&1i z$7TZ`8JxyFOe#m?6L*Fq@yTm9@!2`@Jx2q-7Ml@+E_S+pU{Bexnqrz-Bh&1=AoH6M zkXi~-nOWZ*&kSSm{}KfVu&!B?ZBhY&6*hj&fQZq(jen%i0?d&Z(d!Wd{QmiWrkP@pOv|SAEbEKt9rf5EWj*Lxyd04 z5dBd6#Coprw%4Y<#`)&{5NDd7O;sOuyI;=7jNo>^hJArk;V^Pr)Vkgo(P{f^Jy)Gv ze5Mgu=@%26kM|BH$0)v($02;(G(FJ#cIWPvc{PoFwH`;6rOMP)^a&ls#}YEc;i;s! zh>}QLTl+yavncz9%G#W_49&Yp-|T1BGSscy+5CWPiTF;HCMsWRIxbNVjwZM=wJ7^t zpalCq>ejiDL$Cmd7!c{^Maj0C*|aQZD?{d?D5h<}K`Yn!szQC?bzeb6m{PcepR30> z^Ect|G^PKlvzN7PqJ*=qpAZ87{&^JsMm*-juBxDP;asvKP_EkrsOd$~`d-UVppe1G ze1ECQ>A?p_5Ez?Z%bgH`w+l$%yz^s0Oq68^-N0}ZJQ3fDC)t8dDWx5KMA6qrJ?vsd z;ai;a;Mx-OzD-Vpb z-XB<;{DT+d{9zLzwkO$0J&^fiQ1gfDd+B+DQcxOKKCLWbPD2`-CceRQHzFv9f)Qfh zV^r*Ty)l7fKwF0@GfV!B;m-WDy5iK&{3O5N<2|SJuyb)==Bs|yb-f_v(me~Sozi{$ zxtK`SQ_g&ki0%NQ z{c02vEMYd)f3vF^1r){Pu4bWkex;JgYk)5))ZI zQ5l7N6ASFi#pTltZFUR%@|g-%*0|Ib1InB15-u?zU)PClN`ljMA*+gbvP(ToE7M6?Cft6~r^Z6hFaIMKa&x zRH)6Y{=LrEm_bw0&QJacVod&2z4EQj9nn^bc5Vxd%@L>TKUjq&e`-Bz?4h}M=lk9O zcL`k+bsOQ_iB!%%L|9*sFr?98zr8_Age7Tpqnag%m~5o@geqf02}(`GH}}%#OzCF@ zgdjL#s`MdBv8=Y?Va0k-byIT- z*;NRK{q-4@pKA`QnvXDB*=b6!SIeI_;tqdNmHL8=%Y-p3H}}yAj;WJrd4S>ue=-P` z)K&MGQ@+cbw=ZQZ$|ShvzA=id)1_;_Vs;T%&Yx`I3i2ijX{~+>t?5asgOtlhc`7L$ zb}@TeXXLvUTMZW-;x<=oyl}5yM(?5>*vVfAMtckNL<1M$1h$clBHh+18)i)-2P}y) z2Zfs#uWYO*%VfT|4k^Hfz$?Si^RbN!-ublt$3D&D{Da@F2nsb56H~O6^ zo39$>loJ~4QEZY@iQ?Qpz7@{8&1qlD9Ei0a3N?M%s*9gsa7_axt}SJp`pY=ur9nC} zGOSfdNf;wM!8KhnY20X?d6dva4F)a9K2|9$mJfY%oLX!fkLZf zg9(VNhdu)#$D<9MX)O<@x6D(=7ihciN=3qGKoK0iUyJ_M3{zPspfa18eEB<+8Dsu7 z%Us*BTHFN?&}YQK>rVOGz*N#@m;V*4+P5GzWAx?2XTyi!v++al;pk%fd)$Ke9!oJf zT!}&${(G*sUd-GlwD!QS2(=W4Z=ZRDVInt^xzcnH=Z5j@j8mfi%#COGwy17?C3<7d z#gApSYywtYl38MHoou&U+~4x8R7{%$C;W<>P-$*siJgW5A1QV4xRS7Lx&&@N*Yvb?63Gt)}%B=0q_R@of&|NVgDPr86t(X zPUyc+X6c-MByFg#U3!!L@wsk)_GMg1{Ivfp`|C_UXUL8g`Yb;CdyYaOQpM8|i=`hW zQ?$t0rZKz_i~%+Wa2tN%TP!0tS=UjQ=x?M;9dzdJ7UjXKQKjnH z_F_UyNpd>GkrWwEA{cf~fuEj1OAwpc5>&x--uYcRgJ0W-oA?B+GX-|g<}=jw9AMh+ zlt0hwPVjVdLDWEJ>5q_)#0K(~EH8+Ue4r!H;Ta_4=pTX)bf3XJ@Io4 zRx?DjY}3(r%IV`t9+{H1X*j8);1%KBBs27)okk>}D4ns3KuwX5NERuXXkK0*a?gQa zHD6BYol1j3@>o4M^#OT;&quO4^h~E_Ud5;EJy-RL*WW~^25Gp) z1W&k622VJ_@Pus-#3yf)cAC7=*MKIqNfk`~0W-P)Rd~neIAbC2pGV!kFljaiBPaZt zWaM}hR?@iL%o&Xh(I~P*y0RdB`VYtTre3Kh|dhE)^%Srxf!f+kI88ZuZlA>evzCy0v3R=;XOoF^vT zYZR8RX8kK#>#pb40pW@ZTxQTzB8f}19Aoh>oQo|ec{$q@sdK|_s^NNW5CB%#-mvrR*UIv@C`@Rr|29!R*Pf^ zs9zN@E?l(vryH)pv-?*;ZsfhyOghc zOr6AxTS9|Eq(PL`NY0)%Ej?H~>|YxxWxJ3=b$|jnN$Zl|X8TIy2kP#Q<{fU5qhRFo zmZ>2pavM{Ny4TL}+SK&${k)3mGk;sl*NECVCH3P&gh&Se{0ih(uh{wrUE?G|JBkEHXqQ#7x>*zJV$*vKqzI^#iI_gMT#*VzQ9An z<0RF+D+$1hO2C^+ewnMVVJ|I}oMBEe31P}L3tl)Hmby5VtTsruQkW{SfqFLAoABr1 zuxbK_qjAABayr*DEwvi*C(n#%JbBmjSD^LmfAN9(2wLegDibH-TyOxBC}LSUEp?r; zOJw+b%WE?}X96bRURMlruPcVR7Xl{WUI>_gdm&%~?sbLFy$~?sphpQ9c@C9}_=J`Z zq4SpkI-RaJ;n-P4J{d6`+7o8qxVKSz)xO!V{mljNU#2yGnYKBwbTref#MjMmO3+sL z$|MPu$k<){iW~uR11s!E;j{Lke(WRs20NtFAC^bbq%QGXY;@hppPEgD<+hz;-Q(Z) z>T(VCv{$HeW}RQR$oK|r`qEyS|H!|(Zr@0Tn8MOGWs~z0frENBX%`z^mzC=!(0d8j znD?<_dTGi1^1u2vnQYVD`WYE}HVq_#z@Mgyl~wp5o+X0?C7saH!Qi|;4DoN`Ii+0BsggSB|e+bgd8a*Y@C z9;i4{`U79v>PO}up^Rr~Oe}r|oBj9D2WQ<+WkwS+Cfjd);g6|?>Q3-~bE<0n=7Ax6 zCKv_4GrO64D})MeQ8;E{ejY#G6oav@6|XCt&M&s;Ib;I$g0}iN#l8+JvZPHCPn8lo z_C){N*yH^g)baMYj2p}K0-s3H&n7JmTr3J7FIR(g?J|*L8viA)SC<63>;uf6yzHl$ zx`7%zZCiGnB%~7wOzM%b7g+g*!n5qRzVJ)@I`adX$gJrXc}2!nlIlZR2ZuY;zFD|b zOCdT~UwE38j*LCUep!5WeTp@i$2Wa|mV^?aZUyp{4eNM-$=w%rYJ6nU=Jsng zj_lXOVMr^DIDH$M&EGPZqyj;uzN^b`dz|_5T${x8mo8Rk_g3n^{JQsJObXm0ODPPA z`x`kmjXm5!VM|0U;>Q88)6e39Y)m3dC2Zm4k2qcLQXsJR$j)HG-1lgM0aG`(o%44S z*|k(3mk3OYjHn@697pu9TmM7Fpn+?2%k-cg)OwH9gx-w-4XzJvS?JfVdlc9Ze=p%Z z!|l3^VQv&z9vNdWt3TEa?Uhd)7x&WMR$I7!`+Xj@gpUy5T9B>ZQWMJ7hTauRpk}^G zFTn0l*S%yVbfnE!Fx~QY5+j z9KVTb3f87B>*R#;j4#R+P>Vge0xq!M$5DQ95UR#~ou1Y z2>H!P&oV$TbOFLeueGkS52>!oB~4?I)4PF!eAn2!4+SmBcqJG@hiHuQ7??@O!GfK| zV36?mHmqY+@?O5^c|%rnkqtD{cf$WPzN=9`BhAH`+k>1RJ+R_z6e=2-%sdURkEZQr zg_OEDgu|xG8j=lEH-#09YEP1<_zI=5ooZOtvxJI=c?{28UYX*szKOs46!JuqyP@rU zVh5YwrJI_OvXKW~CQNwg?$m(Zpui%C?)pNPvZIfK~VKJD`$$-KMWMk5@3BzA*m%t!F!3bEsGs^hWSS9*4E} z5LtEJhi!bHYgK!DYC_MsDYjK82c1&S2)|XhhawKuV?706ggj|F1rVFZZO;C+C#Pe; z#$Fa*$QK{cE%5BT?S)}M+w^iI21lqSbRbqa&{XJ#4h;UASc3+t)kNuZ6lsPbWmZ!BDoeD2Aa1^X=Qlw}Fc-R^_XK0%FXAly z8GMBjGdPc(W=NCLx%TPhdU^|8u)pX;im?7b7>MqYA{~M#uiU&OV+1nDeX6jl8GZ;f zLzpQxtOyteOj;pmHdnsU@=ck!!=0D_09?4`bL{ZTi5Hfs_Z<936e?dLxRram_Uz!vh7k;=K&T^}28)6hM%;9`a{JA6Wie_9#`i8UC3bax4!p^&qJzoh&tVVG+RNU8B&PIynh>)z>lum7Qh zU#Cl3imBQ1;t5SVd~V>QlW2ToYX&E|l#3DKMQ%g}QjzeN3HEt$x}}+!A@X~My<--{ zMGylTdi^8XGB3{OFRtahL#Te{T9|=f(y*|Y$P64Z>9&QwrNEG6V#E(ueK zZ<2l;pbAz1b;KD1paMe4VO%m4VkX5&p_X&1Q?7~Hm8XUv3*Q^iyqV(utSp9E%Pzo% z!{nWW*?YDjx>(kV#pigX+)5^IqMgl8WkQ#r&LKXiek5MWd`?36i>3BA(W4s><9JCf zZDufsQS0AE$76f&Y^)lQu~FJ5WIGdmlC));_2)34d;#h;#DA4Wb98+2`L6eLuKoo< z{m*31sWjuR9AQmqij3_)1=}fh#N4cdhFYc)HkRhQUn&HkLHvE^VfoY0ok=wBcOf|R zu&4QD@inki730$N=7$2M-8wXUJ~c*%kTRQdE+$5_L+p-XztbvCTNyeAfLaRUzRmO`}*Bhf$C#q(f0FK zd&T3A9+2wr68Uq^Ek?;aKZ6r?8gSj#KisJi4LF z7#G9a5-Hy)1rjCxsoL9j673-6i~?ng4v0OES3Q9T*%X0;`>M?rAu7-+e6R^~O!yKQ-gL>_OC*zc*R4XKF$H z|7u?^S#{`e_5x;14))p2bm)ltfacYDn*-}u+neLy16pVBqbVbUUuyB)cn7tdllrPn zy2^2~EG6<#sfPU_iq8py#3WWu&o{BF6G$=6a*n$SMv zWI0DV4y;wASNQtJwHBvxpMRQa340IZ*+(=G^NLM%Ld|U6iVC(!y(a<^OGXf0PKx$L zw4BIH7;j?i%%jEF4{33@y?-Fj+BOJ2Liu{@_29p1eKU`14rHrvy~mFTcvoIs*3;ond8Ly2EE`xZ5XIx!dC1mFFldrxfJY zQ+|X!X;@llY6Yx&zLMK$C@v%keuMFDIkTQNu~;bvQRVsvIj!WuZj zS02_z%k*HoQ(6}5iD?u(aqKL3y35w$`noE*B1l6N@s#;KVw141WgwRCZ1LU6vRK{A zYx%J)&a|dgw>S#N6fNgTr{P$F!H;K~0ly~o&*61Y;Rt?M)O?Bf{IQBX9K_I4_7Pgq zF=s8o+Bb&xIwi>ezM{%^uYDp$T5ae9h15{9OYV^FUoHpBiMO+FPH)sE(7MYu+pMRq z_rhN6`W!`h``zEl?{bUOLxt!Y`+dq#Js_n=Jm8+;be#$p5Z~~}@rpR=3b8tv$|41X zS%mHW;%#cP@HEQXK|H>no0_}weKDN{`s3nNIDdCds=7!m4#~!LrHY&~iX!I|4TWBE z^@RE4%#F^`r!(Iz4JqbFoVhI*$z9uKA`6^oRR8n-uY+A*#%0 zD08j1mt$GBx0bLqGpb^_=H1DtG%T5!m6M#(-Oj~NI$dq#uSs3_ehtTFSqPEo^L&HuFz8M$L{wRnQW~&%9a9t9M0OcKKOHuPR?=#Wl#3wZHLzB!$*!8gr42cS?%aRGmt3K2M( zFa}uf4dgZMb9`Xk5xIFwgefSqYkLo2!VfdP0j(9bXl61H`dGK8`EeN#iRFRSdRkh; zKaq7zNz=!R@Oq_^9I;^*^!=-_dI(;aB>CE~FP@8T=9FZgQ0IQ$KFE?lgSmTjnVEfdmK5X^dsS_Sb2-~KG(sIk% zyiPM^Ix5ND**IYV)J_v1P&EfaA>L&>tS|B}^Wi&&;m+N1CBUUppgLT6LJ*NzIRJSH z3C)kh*gSDT@$@48RN14hlDeFmE=h=o#395AoEsj|CRm5Ph-v1L2(2Zh=4>5%1;H|3PDmTYXEsp2fvp~_fubX98KC5f zVdi^9huI{-2;Ljw+j{aDww{I=GMj4wL%w2|AyZ|*kf~1$8J$J4A}3M&+X1159+AZ3 zP(vS70Jd^oq+b)z`SfVa_AdNE^*mN6Jd-~E1s>?_+^x!VaG^7gRpdoI*~d|844+2S z!g69%k$##)pGQ%2_S@wBpOBONk|NW9w@M!`EfbJ(CM+6z#o=R>Pq}>^Mo8jj&6$tD z-%}3k{v*()bvVd53NNn=OQ|oJ1EB=bf@xSQeJg&@I3DTfqi$$_<|i~-`AcIJAi1G` z$@78-5~Kd{?5AKF;?{)|=|J{asa|p-dHwfn1^t>g|Ncc{r-B9SO|uRqhIj2o_PdK^ zCqf&SGfYWN*GV_OYTI}58`%!1he+jW%3ey$+o~;@Slf&56A97j_yxU_O=Th8_QzTsQuE3t6`XiTxWaerJVLFJ+4HYw`Bd|^5(DfRN1c3yZQ~xY`hy3tZC!Wl7 zHdfZ%ylPe|oMOV{RSsPH$wXtCm<4SssO}hBg?EQ5dwfPLVcNY!_JJZOW`3I8{YP`= zBi)zc_x~lo|4&>0-w6881$gv-D+?blOaZ*2M4P~JMpd7>si+xcwM z`B;FxmvTxo7ab&vS&89IfUJ`i{C17Ei7Of%@ykRbZrvd>M&1me$PcBCO(>$U$`GU| ztoWm02V5UwqfxzOMrk@!%DNS=T;F^HeKk9d-%bCDMhq$<8o_+x&x>sxz6&Gh#DC=( zm5E3a=Htsj40B4g(+een%RkxvlUYTbZ)BWuBEr4KD2burhk+HnoJ#=EZ43dr7-Rl4 z#}hr)d|pdLw{$x$LuJF}#V_Gk8~0w=dI(>#0XbI->+BWbdRCA}TrS3{N=XF~|0;4>g_4EsgjG{ee71 z=CdcqGRsMfZ<%yUE=08S@P9qKaqFAVjTp6Uj0o%8O?WiE5uD!BEJ$2$vu@#AFW2|> zm$gkYAi#9LOwdoZs7yCssg%_CQ%yg=S1;a9j91GSGxIUl} zq{0n?6dkHwqu52gD6jP!b0ZmiIKVRTny>jhEO;bd^W#|lSnfm!t)$(p9emXaB#*7b z1Y4W~dM7v^w?MmHtqmnLYYSA&OH-Pe`%g31^+)iQTN=X;pMi@U%9%fG6#i zRN=YADUTsuGpF5w*0Bkr=VmeJRuIBp{U9!*s z6)Y|qAFcLw*M?XPl`eBb_@AsQKA&`^oRg?{YiIt>H1>rpbiHk@{Sf^zZ;k#enf&2T z#DYA$Mt>Hc5R`H5Uv7m4M?Jq|F#q`-3v~_?KQs6X+c?d?*7EFL>ee!D4o67{-$1Yx zVwRv`*avzFmfpymNvy?03T$z#1xNn&9!QXN+%=2P&)JYXrY3d9vYHgZ>&Z0Zd}{KZ zc0-42DmaKXT`gj-W`33spz*&xM zCH&-O?$rBBY%51unC{0hhqYtqY9fzq9IXo%_SLj)(28$G4a{R#Y<0Qyo006z{2b@# z2lURcKzeyP)2~}Gh#p3(Xr9m^N@?9YD1yWe({ZAmV3E2nO}nXUqqTr$mlPRX^3!NK z+I*|iSXeDlR0BGyxzEZM8~5myv}n!oGK&9a2g-o40h>hK$i_V*t!^y}TJ>9E8J(7! zTpxdIi4WY~YF;4?u)6ZlwZ#lrO=ORS0l2AK${74=mjs$RVg4w%UQRwwN=qR6i`H(~ zK3bKz7_;Pj1A#cY`8g=FhzaGUIE*w^zqMtt)iLUl@9UgYQ(l;Ga+&LJD{&rPuT3}i zd+AbfkjD#+>0pErByMGu(B|(JnrL=s3M0egWl{DD%oMIM_F*fho?Hy$nbPlE|F6Zc z@_j7{`nf#1hiM|&re)dEi%TTNrm^vi;mo!Yvpy*RRUL$Mn?!LgnTFw3 zK9yR0c7z+Rmpm!c=L)>s#X4N6wl4WkblZCH69POP3=kCcX`Hr)Gtj)3E|?NL2Msl$gS_impVUz~YIZx$-bN{)A78Z{;I0<%Sh@ zecBGJAb<0-&i!+!G_tT@&inj7xKP(RXQ)_8vMOGE9NAI+82F#f0;j`F(~Z#2VvQVHVS1IWz&B~d;LMTze67^e zHL1x{7&@fF1>$}A@ygdULzyoeN*(b*S#_6W$hGsGhd)>AeUO`k2jvr$3g1l+^J*$K z%4Bvc{m^_5I+o4!aeobTxBu!JgO-9;`sgH8>fhr3M7gPCOfAf`zLlhyN`u{EF}9>S z0Fr@9br^JCOKkuiSpFSYH-VhKZ5_%92dCOkLE7m9yfF8`8R(DwZ>Bw7Y=6o}aL1jC z_q4wkCLY+aV#+iB?L7p>Iu@}yLn_?sQ8BBZ=R5VhmuSTP=Jx||E|0dt%!QKEFQYm! z$vIfP7E70=g5_k?KXDYcN#hJ;GM~jYEUhEj$`fX{9g=cm4{&XO{7L5MZQ>`W5d7BZ zW#;j`1o}4gHYb*x%zf_%YQ2FKozKQJqp*2$EhY6Q&}+4GNPDKA!{D8D)1(=tW~39L zEI+G5Z&eaMCA``+%`>Ko{jU-pn&oIw!c1cI!%Wo8z7<2U%HAbEpQeL_XV%d{-zb-l zQgc-yDE4|yW!563cgd@)OVjE_l^w9?=?yt^(URf&lQzbjdG9(G;oQVpC7lts7UgZ^ z@JxU{L8nUUjSevAkhP)|)NjBR0Bgcoz2O;Rl(u|EVttp8id{o)-CCO3ohLHK)#18& zDLl7<8y=@@y=rz)NssdNI8*jqHI1vf4<2B)HTJg7$d4>J4f%vhU$QFN3J5XjFUB)W zXdC7~*l%2*u^|knsl!s|I?I2Ebiy-jF?_HW^7~$gsU*ke<}6fq2Q@fdT?m*QrGmA^ zsqpbmM~ev7SEytFRL&62w;60i-Qd114)a{>+%O9!pfX%{%^AZbW6z>>C&3>+FEXax zN=f>}%cYOUzvrt(g>a=Kb6&0t@LJLqI~VYWzKJa$2Ux=9>@W#vTgE7XmC1mO2xCCW zF;2&mW3;~b9(X+f$KxL@dUUI%Ge_kA^R8D?bE3KY=?R~g^a8|pb z7yXC`aYMM_Wwvp{6(2;BY)(n322yN zbHy-+09ybFXc2S;a%vhO1$W_Q2QK8+qlYU~@zdD_c+0)DmUGS^Bq9}|iem$p>+^IW zOvmLbo{C#M+RV>(YmrsgD~wJTl#MZnEkKydjd0iu9Y;;^a424}1CQ|UN)XFnn@IVT zWwBI?gPW32_D}TrCv#^EIO8%S*8-RqR0cetcG{*i?a! zK=Lcv?q=&5bK^VB53_MsIoL8L!SRX(*>&KRZl8V<>u%5mH}$7|#_4!myF;lH_WzYh zXIDysss%o(fCh8=F3?v=SbgV)pOIA-(?!G5NYVDW<{Z7^Sxq}3(RPx3jL+eRrAJfL zRjI}7yVHk>^AM0V59(81Uh7v#IrDl_%$oEhNr^^A@1|xxMTZoirb;|@a;LU<@D*~p zw9y3b)izKW0BMD260$v%ug9$`ReHRUK`L1xy-tDJbI;4 z@conFtFEW{Ni>Z0S6uDEVuL4*Pu5Ljcy@9Q}pzU8WqJL^VsTQ3mr zU3{!l&aKI4+A(kc@O0~SI%guug_-zSJ}j4ff(bY$lpRC5^-tsTM>lw<0Ohi`_#<4~ zY8sz*8=K@0FynSvh7<(i%4uooGE5w?eK~b&@jX~p`AE#$vG|zEY>W%7xSF`y3q1eu znyVaY`mD2VOyyuKReao%Co3N%&*B#H9E{uN`ok4SSfU2cbYWeffMC&1eGAki zCv5mRY7@YFD!U5}5D6l6Y>jj(WTAgAzyY|pQnMFXjCUlQM3LY!ZCe6kHF@(gpMhUX z07*jWv&Lqwml~)B*as!h+dkClSTB{8f}XhdxOl;w3Cx% zwz1$~4q*i#V@)btAb{Ld8bQKC@^8vG(L&x zg6BW^Bi>{i3!av%-1UEDn%95?b zK-`H5+gR$Tvs*KPuA@f05 zJC_v4JWdYz{aJ>kK6^TH3=K<*X#g>^Y!7O1b50Ly{$6YyEG?(W>oGfxm5KAPbg|NZ z@&>jZ#KIUF$X;%w$9Yeh0VkTS@7{SYH}f4$aet54{)0WeqZSR;R4)|&(In_AQX?c- zd>v#c5-bf!Fd`BRec0M08`J}T-w^e{hYV4K4q$qZ7@};+svYd33{k^mcZB^3`co9$ zKjujA0;KW(0SW$H3LH&6IRjX(-R#~s0h7cM0w$X#G=m7vw~m}J{cY1d7JL$fpkoop zIaRp$Eln77itMQz*moQ8OEFVQ;k){f8r#5+^c9sc6_9f|__Y?kNxHM{j7W9{deITZ z){>6eI?*q7rHV2#qUj#p76pGH+i3M%!YoOZMR>t2HW<3p#dR;=LAk@bJuMD4dV{V(kP z)6(>veZ<@@o4Ty}sG99-bx9qy*PzSVH4NUZ%OQ1H+2j6BA_`mc8luN&=5mmr<&&&> z!Csrcf9D@Bvi!z_$gw1o>#F(Vii4rUm`!^H&(5;F{H5#c7UD{t^ASdVu1Joj>kYH9 z(2bvMwkgcIgQovHOc6Ri@kf;9_sr|~&4oOVN5et9KDN8jFId&$jbNe8rFS-bo&ARw z*y(oWZE-F_LAg}!uH#Q?!F8r4H9LGxDskfB!DEAXHyRIXVK#QmwQ&QmV2!N6{tB$Y z2?h4TOG)LNg1Mh;Zl*>I0=8u&>Tx=+LOz-`G_ax-}^SlCSXXc^V-@KQ=k)f7(4L*C?kRN+`JxD ztxe619fH#z=f z4w>KqOUMqO9=>gsH~!~8e5AG!;^s^nNyRtL@@D+27MSfDnIuEb4MBXwaYw00!}Axi zwVgzZatt0cdD;%3W9PL*xd3xl0c)yd`Obamitg1?dbka1*|}8C#4~+#*%(uda^%f@ zxvN{z*V($_zT$aYo8_N-L=R=Xj2r5HR;pV1-AG-j3lGE28d(jTVR{#!y`5xPHo2C< zW*6W%;hzz+!~GRKoX2sB)6PqcFH3lTNqC%@AlGQ0N1$)BeHj^(K<tYfolhD_Lg~AcFO9XFB0^mMfn{?egn-gSwoKpP*CD zw8xv%(23Wnu%+?J!+o7~Jm}xGKXQ}SR??E()VKP9bgUtEiF|f8txwLLQQ7BQFhpaW zlvg*M&UXdi3yZuV=boqW)Y@!P2*t(7V#J;t>%+fF|9s{+(EOG+G4Da>rr zfXvP6eYt_g^GAv-BLuE4}s%#^r4Y)%cqeI!2-NB+kQM?_8 z<@{9iQwi_48aFo+IUS3zZ^XXSCz$)Ij~^GC>yg*J8dDb`lE!FBB{X`o%bF%0fuY%x zz1gKyP=t0ddwlCxkPgY}>9f(>0z4;Dvx#n8eHY$raqrJMrs(~-jK2x*?s4k7_fUkN zxc3xz69BlJjM-A-^$va_S$$XXydvkG{!nkMa(`}neN$~Jn&{jo=kTfW_T;GHViwKG zTdXuU$+^jt2Bxdzs=2^n{oF%`xen=%I>OO$CHA`+{c-wEA6<;T=T6S zKA*CXOJWh5V2e{V1G?{HDBDD}IsP{SgB)RYJVoX4%KdCh_8O^%ob#VPnuPy5?S8pM zY8HeWW8KwPJx&zj5p&OIxX(ybN!ht*^vQYClLosQ@4a}^V3|nzP)r&WJGVJEcM7;p z=V6H55Y|-bJT$L0*?A4g?RzJ*{rHS5SWYGK-_dn_d8*4G)PoD%(6qNn670&j1p&==~p_CkG~!eR+u>BB9ZU**NQ&wjM;e2ZbW%>L^A z=FUCv4d=cA^62Tb9`6=W1{dMPR-Zs6r`H1d_M!0AWARE#73K|!timf2jlUJMdSLu# zbSzIK{9@*ndp>}d%%1$fI1-hxodkdW;>y$cOUBXqkh+@JG&7#OeJW2JJ87DRE?lnB zFz+m^hqu#5Rm?fRPe&8Cq2QJ!k}2_$%&*YD<4GIi11AUVe2;co9}-J~w;adZuCCk< zW5D@*|5?Twno2Ogjg2QS#HomjA73U5yN9Vxalh7wgr+>#sh&4ZwxlwG;7g@07hBXQ zZogHvTfaSHMos^eoLvOL_EG6q6Uk0Ze3SxLX95r#WB;1f8f}E1aM@oe>Q-<-j4gn8 zwe|)|`0;7FzxlaDs(R%E6N2&l;`eG%m}9+Ly)u!!(sepdGw^9!1lm8*_KS#{+j&0D;8 zlCz6tT`FT>oTcQr2OGSAfw)8#{SyQ5Se6^b4rk6Y=MF(34+(*thnv11;LTZnDWsD8 zaS`$hOJg4zXUk`FpJjkL3I`5Iv1Dl|<`IU+XTbfH~zRbcqGo~Rq* zENc33)<((MOqHTLf&9)pvZMy4AyJ-gr*ZBpH+V{jY%}c`xs4^HuAyr&Z-YqApWP}9k4VK!UguuzSVcPS+5BffVgvDt>ax__ zl3gk=Z4)b@jpT|^Bs7escC6wtVXVx&8@wPh8Zi&TkE&R%U<_D}eiwwly~y9lqU z&gr;`g&#AJSzvQ5lYiF-sLIu__<5XFeo^l8{>=3!EcZ{uHCKavxS^iRf?GboNu>IY z2Of5Op78LU9~{n}MZL(TUSmtNC>*K9UgJSQLHauuRga^*=&uCK}?LE zZ=(fudo9go&ZEsEhjA9~xna=f;bCYD%@#LC=TYf_2MJZ}$)90xYd;CgodGhYVl>)TkT>LUGA14A!|U6hS)QTMpsH$zK+fYi#pc!QbAt5jqTcFz z5BFC8;c&pUCa}b1I+|WIZ5#TKIK8A4K6{m$o8Lk`@yQi#4|+sE`kp-&5ckb??OAb9 zkrFc{ADoU)La;N>7jf^Jf+&;r;ZzTJ7mm+f&4l=WglHs}NL!VUG&v&8vft6HoJ|-q zAJ*Img%^^b&G>{ZCca6CyRm9zchXZsJ~+#q_n*+*u?P;oUOIj_dplSNSVd-#>mjn& zV_}O2`UV&~exuDR$Y@yX{PhmVC^hfiVfqQAhaWXr4S(}rp%Y(L zWdBTQ^s=f6z_F3GU;qzj8zkY~&OL~SGgsaJ0m_j-B@;)kTYjIcmtOcDZY23wUAF!0{8bG51$;0{;>o-pMar(l0Ov}>g z_=`?^7Vp-pP9zK-cCRX(8Ny|2gX^!~5OmSWnV+63We!gvw(-4p+S8-kcMXAt$(d7b zWYBY?lT!_mIfD=BJV^VSb!`XJmq1`tKh+Ktdfes7KBStR?kWz+Wx6-IuPM@YP;0>^ z?lBf2HGhG9O?74FI*`WNNL`t#PO;~PHtn)Igoh1<>0X_VaK}-u4~qPnHntrUu$wmy zK8WMV$0?4vzA>$^$vo(oPgTIPX)nqqSJEyNYJO}W4*A{u#PPUKU zCB@z)<6`X_Mtj#rV(qUCDVzZJyKJD}-y%MWRpfNmQx9r=%p3BaIX`vTL{o%*4grdS zX7KTWGGEF=Ntr+X?gQeitkGE!ZwCwCzUt{T%C^-0177uv>{zn<@N?S^|?Qc$RKNz*G zS>4aE$YmG{lHU)zjmMZ$2G=_Fs^eBe!odX&*lSQrH~j?&ZgU$;c?stq-X;4_*8~*-g!!?Dox`EYuiJ zkyA=v6-x|&*;f?_er>^!`O9y_6pFu)`RP{)1~$7Wd0w$C^}X4Xz5eb46ZXG>ZSmmf zip}1IGt>kP{N2tv9pmUVJWn0Y7V~WI9mzl3U-zi~YVZlZF@AsC0zxeW*wGK3gSBVV zqU7u-yA{;@M`8achy?&k{UooI`2?n5=hr96=3Q7$fi|9w;2*<9hx-#hvOf=WOJ?@| z`v;g+v*)O&{X3HXU*ohei{3`~U* zI>YuB(jTx@3LhkbOb$75Y`fq!ts)m(t0oano9on_MQ8ViFpGZo1A4xUUqQ0 zy`J`$7PKE+&_tgL+FvYaKTyzgPHg)wEUt!6*=P2@p(?u%7GiDj28R1{M^V$xkIEMI zv#p4&nL!&5Y_I*Mh^(lZ3**V|SJ-`Ul%I=MtsUi{dB5dcp3%7m!45Ro{^m8}2JET+ z#&)`liyKFm;R$vDpS_$r!Jew^d`0KI7f6OK($xf4!gFiA#}Y(bT1ibhje0M?4{5eI z9Y5vq0kMkovSj$P#Ai39I!7ht8{6!W(E2G-66 zur?fYJKsQ8kF_0q59m8LoX-muSGIiT#t+rP4aT#z&LSzwGNs0ISd`?~wD%R^Ayb)I z{90}2zNUieWut04cQ=i8E7(@9&C_*>l1aXF(g5L4_z!CdPxdUnFo=#X zX%OC4Gius*@>v}W8E=3vXG5(KYvZT(nD) zOUii92lj<7(RmwZ7_lyYJNMrK@-XNLFYE> zJI6?TEPXwM!DV~gd$Rr2vz?9?83(u1&uqne&beW`q3We7P?#T2oqwq5v-F+V&dPM( z?ELn(3iwhmllhKP$B9423kbTMWj`mSy5m{L`yPp21}zj}U(QOD*M!Hk*vvN2w0%(5 z>dFBQ0YW9& zCn=s-qY zvI()!w%FE#%!Sfu_8Djp@8ewWPb4d|gOGk3{hF4OfCU3upX_+QC3CibzWA`uN+IVF zmq;{;{U2aU$JO|rCjq?E`5fK)zqxz!_@;{Qe>mv^1zK)dDvK;ti?p&APZ7ZNB^+J+?1>m{WMxGT7$_z_nqo3sU*g6tw7pyGlgRAf^q)sp9ZW^U4g zetzHY@4x4H%8T54XE`%-=FFKhXU?24%fH4Sb1n5%HO`X7QQ?XpoH4oPol2$NEf0dH zgQ-9tfEx-Ss?g*MApo12d>Zx?Vg|<0B8d>2Grz$lf`(5ubge9jp>U}RBQT%_mT;#C zMKD@Cho@OwO6%c4AI3mUkEla%&w=B#Z^u;g6rab0A*UG*>moS>m=x>*gG$23LJV{j zAguDvQEtR=Xef}N5f9{G@J$sV>pcz*={PvJFhKBblIYizr8q80&foA2&hPvMPlyPT z;|zbfWK9?23qp8RV`-CzTM@V0i1QGnl*0WgR$xY8pNaV5N$|>>F5`Oc8@X# zXR9ydV^x@CG|K0^dIUr5#!)2|(n1@wZN_VlaDIw|!;u@xCGUZzmbPG$;4u;uh=nCmr%4W2d4Zez zgfjmSO75Qxhg{obR*adWOW?|=WEp9>)Rzjwv#0uur6+htv`dA*JD!mfmJ#B1b%J(YoB^5{gq;6~Cka5~&-?+Ukj z7XB&#kzt{nM>^v&ypjBAR0f6{wu=21KJ6NAdZB^FrMoqTvRe%?dQ#%b3^#A_UIINh z3z3lsNt;zHncB^8qLu}boL@{Id+zkiC>ab=)nLs zNL$j;&lOrN_NVp+NxSwNwEI&M{!oU7<-bhVmX9TbS(=zYEA$EpO`cHGTOk`)+ zMg8W5zJ^W<@;)O&pa0rf(8qa#kk>l{KSbZ&DR_y$lvP|+{15qxI7iMuV1bxo5it+X zXwPOpM=4I{h{q<{n9*kLviK`VIMcCDhMB5x7g_*N7{4*TSc?DL3+f9PH%zt(DF?ny zIdJCjv&xXO*f`CSn?nCe(=m2M5{~A9Nz)c~$SP99!11jQGwq_iMmgmGLQ@V@eOXUl zc1`nOGix7sX93D0`HkdV`#G4>s$wc8Mq11|D4NGRk8z~rwFSS>mQYt3AO~BT;1p`G zr7@RCNK)L5xvK=-;ImwnHX8tvRe6d>^QfWhS!fUw5Mr(NwPcy5x} z(WWb|kj=1pC=Dmk!2Pm%GZwwhI_cD|HVtUU%fPkiQGx80(xE=yP2Eh0ZlUjxo$L!Ehr_@})x z!_cUdOO|U&2`H>~jg3lo2jV?LkUSJ=s!l_VW%H2qZ;(=tl${HPhcx^C0?70fyMqWa zu-+gefu1yUrlV^@??*?$s-kxcF}e)A<;Fx}j)hraKFAUZwTJl6bl7`51VxHK=#n{C2{0rQ5q3~&vCEe3e=%qoVxGwrnF2q%7EJ3DJ<-&aLM9t)9ds*Nwn~Q z^#!dv(rDc=7H)xPc>?ZT@h|$FfkMBt6CLgoVto>c^_b`>KSUiYYmgZYoBm(*I|i3c zQw`N96h(~;wp+nr(13h|NdtT!)_&0EArDll^5>Rk=^UCE%`u6dpObkLWzza2np|Vx zbbl2!$vr599`d4$q%UgaEiYoU$?FREnA_9Pulh+e*!EB=quklEjRO+;9c2ZjgbGMr zgzHFSI?Ic~-Gf?^n#4V*HEBuQgZSnwc1h$xk?uj!wCyLKb`Of#FohyHkB9QmJ*X>f z___y)IdV{MeBg`EoSt#HLZS2(8U|MF*C}~yIki3m-zeVp0qRCN$T?OgL0`?v)n6QMQTlwykZT{#n->cGia)3URz{17v^4Z z05PI2pW}_R&+>}(cyq7VgI_9y%h6naMEb;lJ}j09t*_9BnP_#JW{{x|!N<7kvH}FmRvVEvM>C5h$1zPdz%OnR?AEq|}wOJ4* z%R05$cvWo{OY{q28Py{CO(Ob*k`gro5s%$nER<)G!wTF81)Ai@=I=xvlH+l_3mw`= zst)a4p+eg@6T|K0VuP)gC|q)kKtjmhRmZ3f%Y;VFy9j}I&cEq~>{3!Os%9xz?;Fxn zWwKuh$e$OZUKsI<%i$Vz%GvrHk~ zMafirKmaO5K$?7Q*TeXP5k|sM3-+cq6Ur^|1~I+6rWGUSzj83Tm$lB+ zqu92z=ijKEVF&-^xsB4$X+0ra<&{7?KT!!bDicE7&Jy$*3WjJ}O$d^m8xUY=q>P*@ zucbKW4eXg_DBFp~VMK3jYuH6npj>IVc^Rvw>W&8aq@m2$&=BXg`G|le2X|&mFN?5? zFYlKt2v2%4>7zZQCC7n=phZH@em|r17RC&)P-ws@sYWONXSMKHWBYYpE>B zg+8M2;no^Wwr>!+w#*l%Bv03gI)Bid$|rTqDZCkFg&3HM6P%c8L4b4Aw2qd<73?Kc zB|D8gz8Pw{Pp;(Jr<)f!UZCQND^EDFw6U9~p_$sgouFcYz7_D?$w~Mi`$VZ|F3PlR zCs1M?a0VsN%G6zs#Q}(om^+=uApa?}7{E zkEny-k0n5YU*-1}u_R;pW9eO}{`2nHo661bBrLx?P;qNk}IJN=m~trdMV=8!H1?*W!*gJZ0;V-j=ESS;VdaEb zmW#R;)G?i)uO%9hlXC=3$jS2*I}JKHdAj7-&WGJ}B70M&iz}rokEDi8LG_K$lh1Ia@wB z;)qpZWmQ%KW%hoQ$Z@*~hvK-V=tmrrgZ0K*ji(TL1ZSy1hAN~Ih{sMVA;65=kzZ$= z8y0?oU@TWn!MxuRzM#5GMV+t{t#Brx@)TkS6Tli1zTm^rNsc_-$vH$E-ekOE{@X_C zbgKAajCyI)Ep^cQT#0?Xsbnq$Uy0a6*L4B1@|xRxlVM^ft(uA$q2E!5oI-<}ip#}Q zN2HS^t*dbE+eQl%$+#b+JT-qLXY8w5v_py4wo;7!C#~a{fsZ(AD|Hn!+fYKoO2dN7XCZxd0jj?AX74)* zTx6Hhud8LVvg%0e?#gAdof4Ma3iJFZ(SGJc4WvEEVTatHjLhH`H_-0%1Yr_W;Z+NF z0?F9xr1e7zT}{WSlvffbGmLV`Dyye{)mA|nD-hHdAb@&8Ou+tk6e2lt!TO1ML{92f zQo$z4$uW}SCCJQzv8tm#yF!pia)wbJ91cy1oQ%E0jyG=!Dxe_`lU~Vj4;Z5eqUn{- zo7;pvO}U)hPRJm(8Y)b3e2+qGH3Zk4%omrEV-AKZj{MrUJJ4WMlX~5-jW*ug$$S|~ zS66l6G7##~S4S}hX;`@cX>_&3phrzoRvNKGZS4T3R@iqop#P%~eC1>~bpT*#2wH&~*IXnTnO!r< zgi&&=Lk9v)L{GrFJB8Psz!9y{PCMot5I8s6kH{@Ujmcz|Yw2d-t13a&(K-Ldko=ba zo_V|g)^P<;HPP80>=y-rFG7t_9z+|ih6DhR5;BgZZR|~Y1K`UhrlChA50I;qj_)VdHMATpX=7mjb<*V?vghGyk&zDOIc7 zu3gB}$(-qAmCFSO)iBrV8ILfr4BPf5D2S2`LXaS1QNc%nbkZ!mtHyWcS!gS4TXSx} zg8R$^Sp+fm!}x=UOMM3s7wU2vk4gbP3G+f20mq?v91@0q&zt0o8rsn2z8pi=c0hVA zM17D(8M$NxKLpsVuvJsl!0vJYL2?{N4aLfZI@6Jcl@U=3IR~O;UW)t`O8M4c`-}9B zQqdAH8>4&*vma!9TJDi>a}2K_>4tRt{WR)M1W48yN4pH33Mq`(2h7>2yn(KEZ9q8R zg5Tqae83Na;BSq|at;?%<^Cc#Wfvz+Tz>lfgqOU}NJe+^X=&4;p{|LmL+bRA=FFqm zKpd#7Sxtm!l%JyqK{O|vw*F*PI2S|NM-8|$t2->G3AnKfuN_s1>SKbBL)iEx9D%v6 z623}a$zfT40n$Y0%xDCXN*<+2!r0+!LobM5U6olfrJdaBQ&~$EbmW#CD0C6$uwUt@ zf^dzBJg1tdm!U*1lDLeK%@Qi}V*;f_apb#*a`}oTJ(3{tKCD~O#g|ra{HP>OrQNZ1 zCviw}e1+}>T+Z7#lLcr5U&lIJSxZ$D6HkA>@=_-~X&C=1bhf4n#6yCn;o#~20*v7{ z^FRkEg_Kc5+QNL?>oHH`=Ai*nPsBGWU4Uc|t@(f=VTyJWVi88DA;JjQY;fThHh45O zWBrMH3z}d=fubQi(?RKWjFfc-Smc3h3(sNh~eS1P*m#Y?57uvYJ+zxREFm3jN8dsiW6ZKxz4y;|rxgol*B_8oXwgYaXh>$)EUm zL#m^oa6?=r=NEc`4gVLpi_W&y=MgB-?`-CEF;oo1T{OFBHgenj+CUWt zgIvb`I9^yCB&`|&jWuQ~;_!GR;o)uh8wuCM5J*fO7q4bW1Uv%?&*`4vK~n= zfjejdrxs90MpF!lADGSgRIX0nnAss@6DfGkcfAcFNY22>rf=B6V5bjrdC_HVe+yy6 zK%A0Ou16zse@c5E4ze|F?47kW!9&)d3bBG{AHAA%9>a zaXH{D+JUifheWbTEIK%EUsLM+3^vbo`V%lOWYT!Y67G3Vr^sKsoqlDM%(<^O5-U;r zcIy2g$=MG{F>5AquH6kE^@ZW~{F^`u)*OLvEYAfsyhs43wA)p*8ZrVSd=MZ=9r4~; zw9LL_I!?%hCT#)Q(UEwK60eosbyq>jrL^>v9G_sCA|qW_)QQdLDOc#%cnnZlmJd|I zOF4n4jf46D3tP~MQCq1_W0K=6a=VJxV>}Sk8CH(@5VoAs>!oDLy$BJCO(=-L z-tSgVajmJeaw4LPqF6zy9CMsGqR4uZp7&3bA;e%3VPrnfcsBrj($2NqT144NGqgJ0 ziFpn--2+{@{VsUkE(QZE^FeXNr#hT*p}EW3h!h33?HETIAIpodEg9v53PxH*CsnYh z&jCF3fmz~n$MCd4#L(xReP0$Z`_GySG6jvG8h$Q!&4^{HByJp2ejtygP zL-?0sf4{lC01ymvxq^LAP&1wFAGe=#GsDdqY-ZlVe-GAZPr)70kWAPp*3j7{@+6Hi zI=%M=%Aze&h(*Wo_1zJ~GGRyO{|N$LSu>BMFD{k78-Tk*mr%-uGbK@7Inyi}B%g;K$A9bYMl} z)dBIcod%xQfRR+k9XCQtQBMYUzJhP)n}Trk8E?48(om4tKqEQr^yM-(@Kv=S{vvIL z9jOOeD9M@4b6f^H_66l%@Q%l)STM?5T=1R;E$r$^ePgSpMRUmlyu*Q`_sa|Qh`TS5 zO@HK7C1RpQRT}o*i*ploL&bZX^4Wb4t82@=2UJ;N+vxQ4bZFq4`!$C*FJiq*M~Y#7Y6LL2l6dIIb|OiBC(KVH+vT?|Aq}#PoAVd4&UZW=wPnXq17i=*-qq#tj`zJ z&;-QXym+(*Yic-t5Dsxk}ddLdVHOA^R};3meneK-tJmR%Z$+8Jm~x1|hgIOrl?>xtx$5;U4f zvfVmDtGTjU_uRx14@T6ot2d$z@;)t8pSL90ISPzS+69Z{GAPEnB2E^^l#kw$`6=46 znkY=)rP#-7L;3;env7cLM0cHnWmUQCj6n{C=ffONC8wa*A@EWw%r50^yi+z;2zH?) z+|{T!sr;k2h|S>ter*|!A|iyo0UOFOa_a>%t)sY0d=vag@!H5vlFmg+fI~t$k4BL2 z1=3R165_CFfK+t!17}#dI6sQ^n_YxII5&WAa&jvZ4e`??^QpkBc4^ReU`;y-M36}l zF+xnnDP@||At2FIPLNYwLvS%E?-DfcLxd7oIv_^2b|}U3#aVEPN@U~P`JQ)SWPzQ0 z?;{9N^&TLqK z*S}RKIoBgH1^Yz~H=%oFM;d%L8U#zuD7-;gYK$u*gY=?-$m%lO-tI#(0~S1D6#j*y z>Y0^!J;=b@m2>+s*TkklFx!3v{-GZMKW*0mK8>W!{or>`n^f4}MDC;#u30Y`3YrFE zOhE!RSlZ%jsVSJR^f25i1_Z$f7Jf^yPQRW4^$l8mp!5*$kin&HJ@H7Z<-heg&vK)(Q@40awf zxRQd6Qc5W~zIJp*f8iX57-vvZ8fWgS_H(shE{B1NW&Yw_2x(iaHBiXssEvPg^UaAm zxnAX2Sal3I4T249R{Vs?L$Q;JgbOEJC+uwkUPQv%bgi_u)N8;@Co%+9)4!+l)pQ}U zZTlRO87+!Vi?Edl!zb54c`A6=YqYY*5{{M-qEQ&=w5IZwK#K21qMi3a6r%9GV^t0k zC3-%0_*Ga!qZ4e!^jVlvscNKxvaCchHP3xqg zN9{F1P+j`>kxNh`nIizgRt8mB2#G?mfs>3Dgb`na_bzW7Py{Uw1;Mb)+7<(WT4XPe z!6w9aNTi|V^I7U0o+!{NET}b}@9j9exPc;*;XRwCJ_l`N>G)LX=s~YEL5MBilzQ8e z-d7=zi?QW>60*LrKPLkftCCqzhe{jcNf6=8dS=B`n&!@<>}beAnZ@k(reD#kh z0Oe#EN;FzjYgi@k4^m*k3x?3X-q9!E)YLcdsqOib5cfD{4YAEj`gN}i`C5FEZr%Gd zKJRSg5zK1ddoTcT>}MHjX@FpbwM1SkjAeMOFv z#*8p+2y7qTcg_3#&(!@2Ew}^AFd_{pkS`HvwR#lFh849pFu;FRbN zOV?-nW0L1rhxg3u!F>}&M&x{eq2!u)Z&3W1VoX{s+md`vQa41{W+7wY{RqCm&scv^ z(#7Fq4DR!1Xd&@<^*&)PSf`JKJwGk#Y&9Qaw2=XS0lvt9pT;nmlz+^>cW{@kX4(IZ z6N##WTya(}2bX5RL+|gQ*ma#{tJw}!nEL*4{ENkw7cW44-_hbT=u z^ntW$AbxE%dy&SP2Ty{kLs#&NeKZ5*Y@-;@v%~qJvKhcg|Nzp{q6W-G$1u$vckH;Kb>Im+-^awMn=>!<*{w|MT}$R(}%lGp7G z9ukBQz*|Me@U|Laev)$zh%*3_Frh@cmIVyhiiyGTB|pw_Hcl8hu>{F|RaP)oWOn3DvK zR*)D5CtXB0yKOb^aQJWYo}GkWKX49LJzEG<;zeKZxkY}~fo$0KGvL5w)f>gOnw_G4 zgx{4(yf^6Bz2uya(Hwx~$LF)8kK!oJL{n)$wua^zODe2mYChrl`u$tJ;k|jL?)C8* zfJyD*(Ng_rfo_f>R9{+g4RGaWDJ?qmJU%#n>yXLYYp?cMy6RekJy<%?289)5srv&x zDiyWGtC2=|_SffDhd`T)g-TYjY$t32;%W}D4txIE4WG!XX5rCEfFPG5gC8+Q#gL(V zQa~XJ&Q=qJ$OI6o9ay~aa}QYA;K&2KM|Fhc4Dpy0uC`lLMaeN0__p7|3wZ~SB~&9E z<WPW^EBg00XYh7OtEy;CGIBb={fM_>WsT}}TX^9n^=eKX2EL@k!+Rs~ z=XkrL{{HrJe!#2nEQcp^V)j#w0>fUK0BBD}-N*1BslErc0KznOEHVbe?(-h+P`sHk zae~~nmAKQkMD$kD4P0CA>K!jR_kwzGQm?cOhkSnuk@w-c3rhnxrXJp#79yZ!@0DLS@>Of8!ERDN> zAI8~gn&2rpyFzCB7oyMQ81G0$-c>-F)?PDBT0t5s*^mq9HGohz-fcBh0YM9nC-CY$ zeOEm7i5fo{QQmF%0S^*}TclSn$Nx(Iy2TY9=7onvAHOW#`#UP6YKBm90di(noa>C5 zlylJ#x&iNKBzD`Vcj*ruP5R4E`|_&?IpY=QX?YF2dO#30mK-i*wAGMJt*D*zKC0a! zgxV_uiS7p*@P;9x{&^fajpDr*a<}ULkgkTn?VV@x9x>tifS$PfnoQxK&mOb+ z6fLhWG(!UDkvr>45H2Gp^21kRyw_X-Cy5l@fv|6FD z=oDlDNU7+3yimo`1ZSho&AaAeJXtpDsn}Dpw2UWHTAdRG^=I6DHG2!3h|Cxy~ z?TldY?L-@(tyLRgF_Vs2OENMHKL!KFqP>{UaE_d6zq2T0G^9weY|jl>8w!|Nk|1V@x) zFP4=sLzLE*8*n)jZaR|J79f>p47H!XnsE}+AeSO3svnIRAU6J($AoAt$Fwma6OIUW z624zFX;XUgyBYjwk}C*N6LE+zIXv0bJBAK+gMKTlt*Y)1(0c%1SMS1C{0(D*8yT!k ztJ(w--9jR|f%a$QNIhEQ+In;06Q>T zqu0J9pkXPTu%Db-MANyRSmD#6r+gwm9gP_d`a6~r&&fCLx<}fl60PjEyBm5m_$1#% z7pg%}P`yfsc`NSwB;^v_4=O>6+c`lm1*F7)8`1n!9AaQ62|{&|ypO8!>bJUtv~ z;0fSle&eKqy>PBP75Jts^4_?Eh6GRkSqzzSll+6LYowqZS659{3%b$8fJ4z7m{imQ znE+=@xFO-9^=G6;LH|h9_>M&CaC=K-E*lB)@jlNCH^#ZVS1=d*UYw~rU+qap;E>Eq zICb8CN!ZfIj6fnSTU1@rH5`HRJclH-EBgTm#H_u9>Q#MxS0$f86tAQ);T!AE-X*9G z1`A@$QvY?8aBJ%h*XH97e4A4Bxa_ zT?7RVEzzXHH}GPVVIH^N!_SxD7~0Ey0Gp1X?Uo$RB3coWHST33KU1(p#MC?synvWD z;yy+aZq(p0VE8~0pfkaTN|4+Dl6+M-Z4T8HPU~~`5h-#R+&0pF zKD4#~6YKe|nrIKB%}>Aop8keE{eSLGuU;f7eudP<7s|*N%zNj%Cwp!9SNsjJ3QD0hw z)(U;qtKf9DS}t2Vs1mkX4fwg_ECC=Bgsf<#pUL%D7@gQUifr+vphA-}BMf#dFii~u z!*{|k5F0jm2?l!wNOf;R94&{lhiV!Z@sO)-U|iJo2mFV3H*0Ss95qS9uG73$19?og z!ekI$Dxtl%hK3Z`vsoX%{U(pVu&VR0$5{{TPjRh(YQZ! zE!5NhtTN;$TP+!-N{;t{KdERFhe>9rlH*~#XBFpvWUJ*GGv{c~n}7~Y2cXk*2H;}- z2HPDRIl##J1%ud+Sd$CBQ~aof{2_3QITH-^Dtv@@f6NsUpDKH{Q2{1t=oOlUJr~I= z1HSFF4QY1GKSI?e-(Ue;^GZNGLYZL-cRXfrB?2UGsf-h49dG*Ny(B3~Md|gb6OW3C zZWa|Gr|ufF_IJVbuphaXZ;pT+d9qN4ge4()b}9p2+EL&9Z$JiO^P}qPI{L8H3eBbi z1@ZMY;a>sG0YgS58npnqp=MIiey|5WX8utXTyEq*4?uo*Yf-RN^eR#(EUAwu>|KHT z085@qn8Lud^Kmbk!Psg^RcTpatL17;C;9a7-oTI0ci3u4n`h}~s}&mHiReXJE!X)u zv4!LFlFJTTEoq-62jh`KjrSx)!Z)tybF&g%ug~ElI)*B%%nX5d>7pxGhW@iLeg6R&$a_>lLx=&Ma0GG} zjeDy))R!(sA)KU(b^vPDk_-SrB=@@%*R=ZLL$nxhLTn)Tl*NmoCbCqWf!J^wpLOFA z{Xbn59-xoK85$uxm`GL}OTq&eDzE_OXVs_TzCJkOg!n)T4Y40kCqB^B4ikm$s`T&% zJ~@x0v|M^vg%?$NfY(}nh<#!=P%f7qQf2I&FGUKH61YwnPK5#zgoU^?&Cq8kqmURN zJYYS@rG~z$?@cs-qz0U5M^))qI~+7n3&=qOU;o1E0Az*RUFlF8jSnF!Y*l52Pl^fj zMpamN3**6mF}Qq^-<0rwH=nbOf%$xo=V5%t2}J#BA+)ERsezpQXwCl&0*w9yC*vaLH%u^O&uF z;j{H65Etg?2f@exr#YJA%jP35#n4{!T8X_6>Q9?b?9K#_aSHR z-*^|(fcv-kyvEZ9Y3{0_;P-SmKOXx=bSR{#F8~OEoN)IG7jaOL)XYm{%vOM=2IiXx zB(19x6c%y9`zD`n(9?XrA>X;G2*BrEzX*^*kf0tI2^j#oq%tJ?ClYWwOH5Z46YT>0 zn&yM}^guP1BWqnX2sK0GD|OR>Uesj2cM{U^{xrD;sMLaamrn{_E#d<3#r+^dcWHI9+Xu8dG-lgYnRAxtm08QqedRg-Eh`f{g%lAsfgC zIyoeFr;xx63{Dk%44a8?wz#&`qzrixY^|q~lEk^&kWXk%*sG+Jq$He|Q`ShUS^=2k zYz4@4GeuETd_pt?^EbMBGil{|Ks77Y4gT?_v@j$bU;1!r<{k`uX|pjnTzd=m!nF3* zA|b{TB6w&*rQbE?9_UAo=UxEHNXED&6(s{tXmKGFG%u#ezrh*#8oahvQr5(!MDu%f zV14hiOn`tzE4x@XC<)a=HHK_}p3s-xla6)5G69Z;|1e6a=R}>l_>0DUk=7{qX5#c% zFVM1q@;ATRGX=dl#|JWhRK$^tDZ zOM6y(eoY9>G@>GFHR1Ay5TS(?RskBJAmJbJm=e?}~ps&pGdsAVGXuKLAprSzT= z002qA($G!2>O5^M{2Tk_)4_-aJ>Yvfgo+Z>8V#5zymY5=O;;{?bAo?WlZ+$(?z~pY z@DTV^?k;V<2M%=O_v8LIK(#zVl7fje4QZrgfTn@61mpv0a|7-Yq7Xg_u6pvohGa~r z(8TaN{hEG;@4dWm=cT+aFlOlH32D=6N&+`iSV8BnGiC0ht6CVcxEzBE5o30lzoMl{ z;FOL)eNQ2v70p0fv@_w9%S(j*kNyjTp*lyLkmrBPF_JorT%V);Txc^E?CCU!u)N@cPe_dA9(Q(GQ+t}X_ z!U5#(gftj`#t`=n6y;8M68)eQ&@o{h4TDRG>@Z6U+_f2hCd**U9d-LJjkInzzvQbH z9$DztGI-R)X^Ib#g?wvDMRYY%iiArmaqaO1&bPCS{fz+A%8Ps3HPV*3XulgiW)nP; z^9r&->^3BPlm9C=mr7x>ymx?WVsKExsoW9p9hd4_9F$U+t+iJM8w$0>aANBmMevDv z2BY!uH{vf1k#>djPE}fNHesag)p}YzfIS)t;~s3aZbQPQ{4?HfFzAc7(-h;~k6)PD z=Eej`TSjGvWx?)HvH0k~5$JIpn)g*IV#zDv!63`ouW`x;#7w^QI9l?`!+C=nzrVzM2+(U~P_{9_Q8N48R z2BDWwN#So1Ot9V`+7B;@me%%~U`q>bp#%W2b^0`qg1w!(@M3=JV60uYpa)Ju!HGlY zlk|c{V^7}F9EL&`MgVvY;ZMH3e3lyAXBj;bu3OHTlwjh^K|ZLKc84LzdZ~UEPaBk2 zwM~_eiC;s^CFaj-P2b!HBi}+!BK{rtrUc^tIdm%R?ty=gA{M6VXQzt}INFiw6ER{L zu^3Z^q2yjvpR)XTf!7B|tAT5k($K4{HLk;*JrSo@Pv87+Ef;k%wc)qIM`M}B=tz9ThtDaG6N zP@!0HYLtlk7092ELpO3732lN;j90(>Vp3q+lW=-bOS6&`nW7|xnYHDngs-J#!AOn) z2(hy@u5UaAlJOJ+(dY@jP@YQAGB253vu0y^`FyZhzGMpS_R%v4l~W?!Vuj(!!y3te zB}2HOq$kx&3uQM}kVpa{Hnf0JE8YG)fNLKWb8MLJ8$gF&e}Kk_H^QLFnq&{1f>byi z2cNGh5D>3O7%mc8DB+X9I+y`fb00)|?>-v!9g}c7SCVDBS&3)~D6piZN}xViu4Awa z(RzJRb5S}L@-O(JzWWN1u85xs$bQ1}GsZm4_e!^Pq~Locet2uluDAK6%5?yz6F^Mp z-J+3ri2S4Po4WcWpgw31s+lA?;!!WM)N;h)1qsPL@k+H;0*LP$Zd4Y3$ya=DtMafew9}*g zL_FM~+mMI;Xb_=yL*Km)OVBKkLX;dQav2S{e6PYzzIqTtUQUY6{;Tleqt*9sKrx=1Jo zn+y*98Q)4ISlxFf#S|t;4=$PvD(#h{E$ED$NJY0KDd`)ql!AAmkk$s@iK_RF=qK7yMP}4|&;1M%2oJ5E2fW(Cf%BGMRKL1k}De+~m@QAcra8TWLADT?a;D zUicfhm{yv)lkki@WN^SW>Maa7zzJvk_UcHp5`K?m>Y^_8>M+Ui8zIRRu^^X&Z{}f2`hktsb zDF)xMpaW|xW#{XM_L!%X(5V!FJp~h3s!5JYr%w>W&opzvraZ7d67wT6*xQ2NR{P}L zmaZ6@&C%sgA*5J7N5x_s~Yn0A@6o2L*r|* zC!Ww)uT_0c^;JS2L?bbU@+(4iyF**xlZH4=lisHR(BC?7U+rD(n{Fz3_{|@>z0?I6 zAn_-el=hoD(>pn$4LGtT=|97iu$$Hx#CD`TmRNT5>qs(-$?n zf@ZL(^f~~q@?Q1nmM{6D#v+8$Mavbk&li8La!_395@5~l%I;-jPQjL(_T%qrS*$J8MQ39ZZ76U9Y$bBTdxI?EEYBY^PG^Os)$#~=aCWlVN zE0T75kn*OK;`L$iTIq|jQ0-h1S36-;MyO`-fqB`D%exjfTM=M$#cGgQ5J)(2rF@M5#szm%TA-wLt2U#I3(ivyR{fGfF z$ejV52>^k?@JqJ_xdfM4I9CU06d&&bf(|k+Udfb=i)=_*tPA5|D-gD5fetLBz>=p6 zMVR$03T%R4&$#*pV!8#+k8zT<6!Qc=;SRiN8OfrO-8d|!Lqupf8)=1 zdl5nS3Q(-6hUOEd)X04fnel{g+1Xtm{We+485adVzPt%Mf`|9l)z z{s7ty5r}&hATZR|c?!{H*i?ECQ50|DLPSx>4hrGrO;tn4y5lbW1qPwt`iF)iq9PdA4%F&eezJOH9@WNDh%t!c^EK-!#d8rpBF(zwt>l|2|pO zqqrhP(@05!7xW4(t_BN{TLpth!nHL?3VXxkL1FS3T5Kc1?PxMnyXx77_7m&ei>(oB zB(H+^5z%EvF6>~p$rbU7lgNC0xw`o9wnPfzY9L>XjVu~1z)~zXRU#}wZ!wFmVYYT4 zjDUsT;gy&pL#&5f5vj=Ri&|F(5K4PK?$B$H$#pR(&7|~s2QdNqQJVN*{j%400-&3k za4SzE%qnQ1mu7_tk<KU&{BLZUOmbQF9590$Fz{9NPQTRB#yF+{6 zm;QWFuk8XbNS_7tsf4yg1R8LUJ2V_`G(76SfuFh}+922$wTW__A^O95G|QGSWV|~4 znlgtc!u;5lkd}gtsoyAaaqA{QlJMgHkMm}lFNr} z<}zwq$M2)PDqcUV*I>hy6i%i^2}c(-G6rKwmry>xF^+Z{6OPXRfg_a6sa1SpeAJB$ zNE3mvfl1GEn`C`RXA9e@`wFZ1ur5D~`x=#QIeI`+w`u1L#5#JyN{O>vbXxU7Kds2maSlTk6LDjx`_!aP` z{5w2zW~fuZ8-NE+Tu0sw5B)uWI{h(pdZ`8a#x48M>5W@s2dV+-qe^3MBz2AkpMkr< zH%-|0fp!ua+WF^cum6bVhOBmNBVa5i6_fTvA!2rM!{5>Ic5 zFmr<6~f*Om(XusIApr+BnMEP6SIIV~5vZ!LiV82>WGlX)?w*G<~+Jc&q z^tHfx0$)J|HKQ%B6x1xVJTHG+g^Md8-L>D&D*{pO2OHM3+zuo#KY>5JKacoRM@l7! z?m!anW9non=F6}%v`X>o&*=V=(uP?1SC2D{PnCZ%=`emhATY1b+dX_9xu98oixW9A{%ErPKora%pRmD_kw*xNDd z)i9w=laz+w>er-Z5R$%wi2m*QSAID6-KkC*@M|40e95s~B*^`*38qm3BhI4yG7l9+ z^=?TD50jeRnd!zJtoxfFH6^+#DP}ce`!j0Bza%?t;SjK>!xUzex}TKnogfuamg~|A z9p#o{-JVm8>7~0HNn%eu-9U1@gG9J$dnLf5 zrQpaoDGpOvXl@e&80mcs3bYQanALK2*uST06mww3lBm* z9s$J94IqAQ0P%BG^(QV30f^lk6-&mWDSZyk1-hR(N6gtthC@`5mk<^hf1a6W^fhVh zO}FMgJJFezHRQRDb$8gHTUfzhpqygowv>^B$<}o7V2p*x|%t90FW{?18 z4f%+C@@VzVAF!#0YQ}OfC*V926F>?ILf$^F(Gw1)_R&xHk!`??53iH!q(K^Y z6+dJ5QOnBcvkcwS2Wny-hlFDz^6MoWM;ti%de$K#47cxd;~en5=0d=01! zH&8m?L3^m9a?!C~I^F7djM5Qv@e{0!*_Z+X1bY}6LNk#86aj+Grg%=UuaK%x5Nt7C ztKQ8j7N5(=Lq3NgJ@Y=;kK}xdn2=y7G9A7-MG8vq&T zitMK4H9+g|(P9G-^|+WupN0@%cT2=L3CP=TB0KFSp z?;E`hVwT31qsn8;9MqaCl4Cy9p40)Q#ODX%gYY>FP_m>kSG=Prmh%^m8LqGK-hdj@ zDeiTZ9OJ0JFjPEm(M*7Tf4Z;r5klFL89d?w-Xrq)J0T9pSYbjIx|4M@&pPUg{b#NB zeef~Lm7?Y%G~>Q8C|Tl<@iWW>W<8JWUb%1-YEScw|&WyijA-%koPD(g}O`p?938u7sIFOxp2PFmyXbGRgw1VVt|Y>64m z;dqXVSjY2q=TB)xBNf_90vZN$_oIu(Qhis6bY%-W;246ZBW@XpqTtpD<~2uo z6@)dIl2MJJjs>WrK1*|)k=LT28)n@MLh$(+&pw{PQCRfErovsiP@`5 zrIn}n=zEB_c_V;&8v^$?f7nS~;H4YMvv_&ad3j^5R6Ubb?CCGC5!xStVn*<$BDr6_ z;q6D1zvd>hmM@`MUZnQlA6WXO{YWP<=L4pQF|1uOEr>PN>g!@A|$+P4~PS?uYlK z`t7gZ-QWK3IcmBJ^?8UtiK^+(*Xj0uMEM=m_@?SJPYqwLJ}2GvT&R8*sn6%t=ez3j zOZC}7eZH)4S5C-{@ib6Rkme)Ib0C|J$F5Z;X6` z>S$D->FP5}eOlG$a`pMT`utFR(v9vp$PaZp|F3y@93yzxh`NR2bPidRr zf07!W^p1!x@IM=BG?eySu?UZTRy;G*=X(G5dm^0Hdi-yb_&%pT3qDc55x=4^tUq;2 z2ucspbbvXHgfc?$&!1U^fk)D(BA;fncwRx6Tv$k40C^Mf|G($uQ1;%LpW0hk7?ud8 z{XdpX`Oj6{nLiO>C_j;K@;{bM`Q3Nsk2@f~lhkL1`b1LxSD=0utIzd!#h3cO4+=OL z>eHV;TGLq5vOBC>4yolF7S96pxn6xH9TDN{)#nxU84XoP)`J_h(MLsm^w;8iAgA~^Q|0x`+ z4W35Alm2MTQ`&I+r*t&-DNj@Ur}S8u^Slvw670tKPcQ<1N&8doHTy;^8~@o8Z_doH zE^S}@;4#bV%{83AXbO<-OGnM zK$AUZ;gng~Q=_NMf6_X8+8m4K32Ro?wE5ANxpSiz%$_o97E)NI&7U)6mI@|w?)>@I zd6sEYqZe4_Pn$AZGk@As)@chY(R1cnqO)hun>CHVOq&{jyudQWGEFmk+U&XW7e@o& z+{`JK?74HIv!-OvLNZw0w!w*myxc{z$HcX06jGmveH#D2+ggp*r@5`E4N{-M^whkj z*Cb8SYf3}(nu1Gsmw_Anm70N*gTT?^dn00SV!kf_VP=7-a)v=01%}bO?25!^exfY#t%OD0C^8=nSEw+ zLebBC-%`47+dK5PJ(qv~{r9U^u3Wiy|IAq3;p>U-J-X8yH*r;Yi_?Rr_bH!0?1v?n zcm8OX^vb5{XZ~}q`Pmod-g>^xtE+!s^Zx^=d zo=2yAVrr9fCb@f;+Q0w)`^l;!bG?ID&DT9@kNx@eFt%>OPsiVQD`@gy+xT6xKY2KJ z%)QB9f4i#o6q;23&yRP1Sb_hAo@b=g|6@Fj!XS*y5RAG87^z_xf#DdPkvMkVTGI|X zyI4(6%zHyMQ|p8MKfjMp8=S)W#>d{@zGZV7(EM-C)bXQ+4l?xX)va@M+m^%+@V9Wz zlaG&18$8g^zfX_Yj;$nO4Vt_~^QKQ8H*%(3n`irY%`_hH;W=x$lW;j*4TgyuIucBY8?HsQ>nl=K9I;9re>scF{lcb6wX~w;5fxRO; zwCVx&tE)4!-dI+?K)^>V}4o4K0d#Qy>Kjt{k(B8TQL7=*17W%c47Y#_S&Re z*5~J3_UgE$Y-jmWw!C8=`+i;?+qfl<9sVPaJs6kImZ#^lFQ3k5&%cz<4t$!=TDtRD zyOa5B+0XgxyWjHJ=Iii`tsR3`0v60TKoqe;{V^p`%9Q(PW_$F zGHdc#znl4N67nAUJ)bGwe6|Mgyl3(LO+H(EFrR(CC!h7-p3kID@>!2}^VzE}=d;m8 z`D~&spKV%@&xTF|jM4ebGBBUr>Vvw)mHrQE`{c?nu|+W`r)Ol_S2>8kF`r#-<+lFE8ye9eoNVz zwoBQ#nq1cD+g!%BoV_#dy7G*AE7h}<{ zm#l2xCsy`|)yi%>YGqAoENsDc3+tI{VTMEtd+)CWY|6F;Y+lX+_D!D!Y}K{-?Ddc4 zv)~!?*_Sc%+2QY>VvoG|6#FCXDHhh~DYl?=9_zDc9vjwe9^3WPTvqtPT()8GTo&z{ z!>)cZhqawLhrJp#hb^p_%|2K-n?3sAY}VnMS!|Mh7Q5AR7Q6J_Os0EgCcDsQCaXF( zgAG<@u!enRu=d|)v*P91Y;yN(_RKfaS@YcK?B;#bS%UjXc53F6?6~wK>+x9@yO5s6 zZr_~7EH6!Crhe1dlG9UJ)2F90ZJViV`W}_<8 zS;UBR7Jp_GE6p6mwpNW~9Ttpamv4<=T?$694cG+M8MKD}z~|HiOxu=O1G=%^zb8SEaHQjZ@hY zr-}XO8^pFR9>f}5AIJ{O9LR!yNnx8Nq_CsMj4V6V$QJENW`FliW;fp-z-Dw9z|x;H zu#!*%doCx5UAV~D7ZVx#>!6w~;dn2$w|_4-_05Obim-=S zw>j}F{p+4g+qWls_|+a5^WE9~ncdk>d%Ll?*lz5G+?AzPbzw2)F0AmwhuHk^huE(( zKJM53sn12iQwb-p^hryN|`( zdmm$#XjXNgBkR|ovbUGDWphuqVF$akVWs)4 z*`Tjmv8fNXVyze7!=CsmiVbKV#kS6A$@cAP!Jdk2!9LAs&Q^Zh4E(7Xix?KkHoqpZ zTUAZjw+T&I`iclP=Xf}axi6e8oZW;?-`ben3~9_BOl!n$yd1`+o^QykJsPr3iyN>- z<)LgwlTa2kDun4@4QBWL62xBZ62!{qYuT!;8iw_lzT3*%`VU*x>aB17r7!AQqyOuR zYW-IIO?^ehpZd;2|InX3eobFB{;J-5?y^2~+VA>S-rw}gXI1IVm%aMAPkHp0uKlV% zwBWqH@gG0y-(T>P{)21h^o^eSLI2h7-|4T;Jgc{PPU{y;{Z@bAhm-oE@h9|O9zU)h zHS}x!X!lWlB|DWdq=_4h2rQ>+E<5z!y|PW;JAA7?D0ho~Sk)K$_TxX-&#nAaZ+PSr{qt{a(l3bo zNdI;2hx%=v5A?C4-q*+MdQbmu+`IbER==$uUi+p#H|q_3ufyx~iywVmKXTox`kf74 z(QlpolK!#dFX%1(p4azWzeeu}U9Ep=#{X=y@%fedq?%{+{T`R~$9JvJ zOZP9=U$#5+bIvc*KR3{(|9oh^{$(jwUwJr3KX8>*-)881eQNkz{n33h^&c*uuCE#} zO~35+6#bH|lk_JSOwhm4ZLI#QUq|UP)(zKB88cLWy6Is3j=h8QEpm6;yTP(LgG0eyPUX#F?m+UdV9Zlljlx<|kD za&!Hv*CqW;bGW{?CQSeKhEV+<=|TGP(A&C;lWyu3Y`LN{N*8tWvVPXp?l`OSH9w)7 zF#WKu&(2ESf@bBqzSFkrvP(YKwQKT`ZrbDT>0&pn*FCLySvO_)YTcDLR_em9IdyC7 zdAdpWKc#!UG*ibWjn>8eWzxO-LVsOBukN}Z4n^w@X1CB;LK^7$>#ipLJnux}pKonX z+FYz_9w4c|MkzWFYrJ83F9>MZv_4=(Y&px z)O_!c2s}lKIKyPn2MT&UD)4$31H(#5h&C}Xx!Bg)qw&DNsFIH;RuH*eN4|a}w zs7u#w-Fx(if4EogK94;5XhOgKi8?)Fh5^aOl!1c=#kRaJu4kVFUDAM*L8*hyL(@j2 zj~O>%;-rixrahTGbJm=B^R0^(FUid-h;7xmS7LJNu#saXOqwz^D|_bL1q&DF=Gp8k zl%i+XJpa-w>)v|z{SQC-%bYnsC(lvndUowg>)zS;@#kB2mbwpqed_;d z?@hpKy4t_td!3U>ghXP9F%dCOk;F`9F$Ezp)030rBsnrV8BkOV4WblnQB)&EJ=9S3 zAcmY&QHoNnnF?A}W7It5e7}3|eUg*lxxVka-uHjK?{z(!U)J7hyw|<%dkyzqd!0*H z|Gats@yl9`yA9H&O`ZGc7wb0f*!RPc6X&nre)zIR6aQi3CeK^8_S-!Ne?Ig3jk_=E zx^?b9TA!JnyLkEP^_#aB6dpc#_V+(;mpnE(c?OP5$zJ&7rh)?}&R@Ir&x@)p`^9H3 z{l@sq)d!|3tp}y#ezp6=^(PL^d&f*(xMs(pGk-jIU8T+7@e9@$ow;qY?J#Oup7GLC z8y`*1hNHJ^+Yg_-V%KkXZG5$JH=iuA?mBL1(O=fxQ&;`;(7JQ{Cwq#mdyHTG^E0c! z_qP;V1y9>?%c4mt+!iZW9+hYsyr7}SDe@P$|f-+%x8 z&Yj=n1~lUsd?D5etZ={oe*4EkEjR{Wh{YGj3~bIZ_(H5>M~)oXyLapSpcZlj`S1Sy z`*-cyG%v6@$KVUGjvP94XwRN49|g6jKy-zNiIC|8(TJ8%b&(@_&~|Dg)`(Gbiuws0 zt3$J4fS4fK(pqXLJ`?@v2kI`q6MDKzBgHSm8b8eUn36>kT0t%XpRiB?r2k(+LuYA_ z_)*lPkH|_)5#F?cJj8Ml4qXfoyF?1zp!dWXVNWyY1sOyO$|F~?P=vx9)Jbd>v2=+d z#W7Kr7Eu*3U38``)LeWihSG8BCH9GQx=k_Sq7XER9*|zR(Nc00vqew(H?!^`fBEskZ^$^>|IJ!oo#3^AzAJ7v@5uUV?YKo6U5bY*!u|Y)9 zISLntMJ<|7)?%vgp^el;tPq3g2nC7)kxGA&Mw}H@X(qj-bo3dksjgTgdXteli!DM& zmuaXtF6z-@^cXWl7urfKM4lK%KU1hE6d81fV#Ot)qW9?^8YkRo899kL!jE=PJF!lT zq2F-!*8x$3=E9^mNwlZ0$xSR31Lz?26#o{9be%?vUxh7Aqo0fq9Czbq|r@^66b^i&7xP7AzD#B)f0BMEBM&J365=CSBoN9=0h zd-1gxOQ&goI4GPc7v`<^g%_s~@g%wSqN0cNyXgN8H zToFLK$V;pj@6j0=C=Ll1oUpAHlSK#m7c~~2i$Qpa=r4APWcriFiqoPBO{eEHUNomK zsgC$q^rC&#QEU=1bde&&QQ=Ap$xdX8PPCbtiB%$!j!}r%D-3jtqQwPKopNB(%Mxuc z{xlGuihi`8x`}Nffr@E_I4K&^XH-pmD7w>k)LMKcM$#|TS9~uf(0z&*S1?-e8kMqn zU24o6wwKqV_T$g&<#p&^KfCYa^=G&DhVA2Zr^`Pd?&I}lt1Wr^c%A8^+p~|?msT!k z_VKzBWB)#0Pp)5YUC8UmJ@=gpdHp!X%e|1-jgR$h3wgbWIY%L{6ZaqNUC8Uh<2ND; zd0mLPOChfZ2RNh_@;Y#(P|J|E8tB}`yelKzhdA*l8Zc!nx^TK{xS~wo-yZ1Y< zD&%$D&QI19@_KIX%?*XTj>BB7urbzeV#>}!UbkULDdhDU=6r>`PW!$7Plb)JK0D%n zvXIwhi$|R)qyn4=qcU4*&2 z(HHBXpU&1d&cQkebA6*d)<0MS7X$2k=GNbqY-uGwW1Mq=QX5}*A3u_k=G00 zk&)L4;2Gi*uThQQr5|`|w(>)p8PRrr zXhS2~(hqHF*oe0FLz^4X_I{87BhT9*6Gq5}A7sP`S@DC+7$G};kRc;v$qzDR zglzdi#*C0PKggUBvgZdGG(r~rAd^POrXOU~$n$K-tP!&72N^a(mi-{pMxIYY#*L75 zKghfhvhN2SFhUpnpc6*uh97jq$n#|Aj1jui6FOvsF7<>?8KGM}p<_nqT2JVl5xUnC zI%tG0_JmFvp_@IRqekdz59q9syynBSn9a|7`I&W>!&!GZKI<;0XWixeSa&&p)?F@- zb(hO$-DP@McbPucU8a|Hm+5ES<@&Jha{X9$xxTEsTz}SG<_GI8^M`ep`Ng`+{A1l^ zezNW|e_3~#->kdLf7V@Y57u37AJ$!NFVtAJ$!#C)Qn-FVkbV z@2tBl|E#;L53IYaAFR8qFRZ()Kdif~PprGFU#z>VZ>+nL{y}$HA6a)pQ3AJUB1Tlk?^>xGXM{%Vrvw7N&`5V;Y%OrkQEyI&fXMPFy#xBiEJd z%ysAfi+RC3Vcsy0m{-g*<{k5pdC5Fw-ZGDw*UWR~J+}e31-A*e4Yv`u6}K6;9k(I3 zCATTJEw?eZHMcppJ<9;g0?P!;2FnP`3d;=34$BbB63Z0J7RwmR8p|BZ9?KxhBFiMp zCd(+xD$6X(F3T{>GRri}Hp@86I?FuEKI;JM0_z0p2I~mx3hNB(4(kx>66+M}7V8-6 z8tWYE9_t|MBI_jUChI8cD(fukE_qd3t2|4(%{s2cmvo=|03|=EZ{R*cDNpJ8a2s^)=k*DD+Ex5%)<-{iME%`z)pYQeVb>n!+DHg+kHLyQOJg&S(X6{jBaPiWhAaJnG`8~?uk;tv*w1qS zr9YA820TYl`WtEPz;g(tKk`@lCuy#MI!kj8@Iac2@SH^H-=w(;&smiIPnyd>ho!j< zcr49zc+R8rpVC~2=R`{XD$SLk!_wRdZ79v9(5BMdisx8Le=W_ucn+rY=l)9nF3r^- zGt%6R=Wxn+AkFP~j;D+l(%g^dfXa9x%?%-=(p-_}jLP^U%_X73(%cdoC*LI?VN99p?J64s(53 zhq?Z&!^{uXVdf9(F!PIbnEA&#%=}~>X8y7cGrw7fng6WA+#amM+&-+s++M81+C+}^Ci-2SY?EDx;1EFY}HEHA9XEI+KnEKjV%EMKg{EN`sCEPv8F3S~aX z^2s{P^2$2Q^2<8R^2|ES^36KT^3FQU^3OWV`oKEO`oTKP`ocQQ`olWR`oucS`o%iT z`o=oU`o}uV`p7!W`pG)X`pP=Y`YVC&*^k3G4#(v*oR;(8yf{zJo6F#`xJ)jaX<%BI zCZ>&PWLlYKrk(4+b>TX3-MEfiSFSVHoq52#V4g58*p22n{eB38*y84n{nH58**E6n{wN78*^K8n{(T<46rP)Ot5UQjIgY*%&_dR z46!V+OtEaSjIpe-%(3jT46-b;OtNgUjIyk<%(CpV46`h=OtWmWjI*q>%(LvX4zMn; zPOxsUj&av*X4zez?PO@&Yj$*u(be6EUVIpi+j?^EP zsvodBa1<HIIVX?Z3T@it>P!(V|L^v!_hp7o^V5vGw-jo81)D7&G2!#czkm}M< zSelMww?r%~QJ1JQrNiQM8@nrd!ou`#>;?#fCFuaU(P&tjex-Ia4i=?r*mDsC3({`v z6BrCj(Glzuh=L{Q9QjZxEJlA}zf^Bnh>TQ^hQSi_Gi=g2Sc)!V(@h2}LU*ut!w(jq z9aMt`z|wP&+-VFfLBCOZN`%GdI(Bpf!@{$NYQvJf0JfW^q=lvDJo!=@EIK!_*P{wBp0@q#xxd|n$y@5k_3y)AK2*- z0t?JuszVX5v>c^o6b(zv1?ouSVR8AJs!?B9SiZ+jk`b_^oTSzi4@=7x>PA_xsN5qf z3V;P=7rD?NSW0+<^?R_SoS_bs42#L1*dNvl7Lt9~MG*;0$T4b8F|d?eq)udjMdTKC zs`P^eWIy&;jD)4*7ivQZu!Iy-cbWi;$9;4!jnKlQ(7tWa!g{o46SSxX?dgpcO+ov$ zKnupA{W_xs)6rgTXtB{~uXbp$acCb;v``e<#|JHxiuP!U7SW+Sx}Zfez<+nNz!>nq zJz5|U{B8=4Yr$_{a6AqCZ3Pa;fxlhB;Y{$eF*rIF{PY4xlfb`b;9xZP*AW~X4}P@< z$Kt`SZs1rJ_~QW%y$Aku0Ed#nkLKV=4EWIr95JB&ZNPy9)W178FahQxUl>w@~!K#kg?9<@;uU(jD4HRuYuok6)5=&b{a zJA%#zptKw4a{+}NK$j~h>jZilf}-w~i9mXJf1laqJ$@>{{A_kB`}5ce7?17!s5PRO z?HR+V3jWI8Fu&!We=hG?Lxi_n*_M91w~WX=u-xzG0HVXdE?@(Y4=e{30v`b@fhE9V zV1e@dDcoGZ9EYEm0UVz87SKDdKGOoH2W1Cl2W0yJ0oh{)ju|v&;HW_vEz?^VTFk09 ztKOm-s~xu5e_Pe{JFnbMvpdb|nA7FM&a*nt>S+j#>NleQh~fQ428|Am?VjX4vBmpM zwXFwwM+}S{Jfi=we#3i@>N~dI*nY_^44#=DnI0e4SmeCeCEsDK{WjZuHidTIR;jbC zQ@Vd#P;{@Dej|I2?mK$m$YJ4Qg2o2Kb&v0n&?D1#a+};HAG&Fq4QShQ)Yu;SR*5ZB z+GaEx-z=@!lzOx3&vE&v=8EcHI<0cvQ0-g$J$6MlTdI6%Uu#?Ul-|So4~>i%9W5H%WAHwyS(1ITAQ49Roi91q}n{k+S~jM{f0zFj2RN|7u6>!Sl2hP&-l(+zEgd( zd^0=G?l8Cc7w(H1Y8ww|K{<*3*pTc`Y5V->B=0MXgZ%Jb#%9tusS;?4Wp&~2^gU5A zfb|#T3Lo4AK9f)w$GfZH+$XKoPTAvTJ7d_988`8^YNEDym{X!l6lzh@@FxZ2$QWNB7PHbW@jZIdavd zRnSPo-27d?+;FJt-A6m|lWz`Rsn@30D8uY8w;#V+t#-%oaWhtKKmLbf-8KQE(if~h z@Vkqv-;mgei`EyOsqN-HD1PG74M(rnYS=b#+>|974-_}*&|f=g!P?!w{OMBHH*{>q z$LoqN*7NY|ugzNY_5Sm98+QpEJ^tgh2d>oe@adz?T(t4P?=>5G2an2Jxc=bf+HPJ! zn#{#0!?m%`fQ+0~+YcAlY7jbn+?3BY>_1V)Lo1HS6IQ zT4yfbdibJ8>z)J08diLJ{LeZKJ87rne)Ziie>Q5?Wn|X$Rof2#RjVO(@T4yI>igg8 zdku*HaMgDQ&faX;zF*9grCSeOy4$!_&#*ou*n9H2Ya`#tnM>B~ zKKf@azFZX>1UrW{VF4PNcS;)Vn>dtC_zsA z7!%~_>EY>tE25XDuSZ5)Xh_J`xR4N!z@Z_Lo*DC(&D$_*&#rTGXFXqEFfSo4HY8-* zg@S?&kIwDcv*FR6Jr{H1SL`a7o3V4nvN^NP@7lFt&H0Th<~{n?u7V9~&Rw~Xd*OvFw=EceGR+7(?{k`q^=GC2@L+qrR+uKLg;G1W~ z8?}wBIMtm^nx=ey#5*qR%b01iNZOroXRKqCbhAIAZtu%{m*3YTC?D>r5Bj$5x(PQ& zruO#gHUl^7Qu=oFOE_gRy__7_IV5(Y$(;QQ%s6ZS{%57Q$KPE%+16>+sn^ihjG3S0 zZ~Ok_mHXA|w(Q(1B06o_f-g4iIeO`iBZRi+z%k=Kn6vEbg5y_9>}z>?`w!Bjd@%ou zP5X{tzFVVaQ=jewM2pTqqG0O;YnFDKmEGk=*2ruF7BRP28~Y2nzMZ4?qiqkR&CI_TfdR|iL;li z-G1QLYY%Lk8n^4we@x=!xhwxw@Z*`QRb3jj>52%GW-t5K?w>B)a&T$bu50fRu@h%~ zx^~Bp=l-ryr%Agm1ICP-oCA7~{eHK4jkX>A`;SaapS5)3-k&d*RB>w9qD$`)@e}4Q z-?;Di?{}SCJiWSx4cBMQTJm+lPZ#bu)M(hL_u%&uKA7{_njJ?j-*s%z-fxgLefokG z>$mSedF7s6^+s*|2ELa%?c*=E6rH$ozeb}DeuKs&PMEbQZ*$?XOSh}Lc(&~sHacli z?(%Pt|2+q1x3)dPMkh|rUA}S8vCDU=)o^RwF*G9HF!M9i|I*zWwVSl+HgIgp)Ojm5 z?ESg8#Lm&fJ2)aHedc1c$1lbAt2wm{>N`x6nmu>PS37^c`k+SLroR6D$HYyTwJ>js z@wdNR+&TnC#Abf@$?DB}4xhgMkF%R^$cXsN4{|^I>RYDIsbTw`VWY-PK!mNxuf(xd z6YrjVhiOwLOrO8y(1p8Kj~&^ybIYpbpU<9@5!ahJ!JOe2@~RbMTf*s%*u-E9i21hi(NZD zpOi2KAx25-T}P{)li+fJ#TWsTzyXT?1UY$J2&RUhK7U&1$oR2SQm%$-38^q z_3#Lq_1lwG^AZz>$HiWp`u^Ok_*sV8bM+g?d3&rmGymg)rIX@|Jfw2P$>e@}a-M%V zH!fv))^Obf9Y$tP&!CVdQETF2JxSI0>)g$8v5_iOY~sWTo(Emg0la?Xp!6Tb&E%Vx zzjT%Rk4HcBl5Sq!+!bld-9~B2?qSuXoBP{FH?roA&^wZc|5mw>+bV7Xl9UiP~v`cBpG3yJ5Du~^&geX ziA5jMLg`1WvHGcw*PTZmi z=6UUi*5FHB!-On}>Ao z(z#Q++B|Kvr2v>svIFSmDtlN#9$qf`H(?cBLhkr`yayJF?i+_v5h5I49_K@+H)aoQ zO~pld*--(A(Zb0VL!)%r$Ny7(*zrFavYR<%hQr9^R(078t|;UaYZamoo@`*sf9Q>;0>{#bvuTXw%UCg0_$I-Ib4Q?s&OWy}od*)!j7> zRrXgB)kl}m*&o(TO&KB=TlV+$i${O|wqwc6i7C-T`}FA0!o9AGW3{T~)8bPne?I!- z_dC}wNa*L=w0_O%_BK|kvc$N#a%AV%%W|irMvoX2>et1)P4gyh^<8T@J5_hEx3iHZ z)_b?E$eo}KZe7ow)=miT*}e&K!O5cI{iST|>>Z>b-ZD?i`>8(loEu z4Qn~F20y)&KQ6dc180XSTxCo0$*pT*-tptCQRb^x`{2}d6?}&D8>C6jUX-`#`0?Y# zCR4Ggcxu1yy|nXpn3KTWls>d?*qHQ1n~oPF3SaAT#>eU660@e}E?Th;%Yoxdig)Db zA_fiBPUKi}q~f9_6Ln)oj*ZL8$=gwceRZbd;vFk;vXT?x#-(P>M42-ykV_8=x6K;f zuVr<*^8FVdjqBRnxneNQ>^FZe#T!>60r(sPvdkXIjzi>{|3_SD&i% z>`ZnmTY7eNLwH?ldU@y22c4YN^y1#HUk+*FXiYEvI=Vi4M8~=|^y=QZf=`orw{W(i z*AK7$xGsBCSGQ_vDt+?zZ#zFp?%Sr0y^2gPO0FD2NVmpLHs}anKKkp_zZa+UZ&%lW z`^DGK?p;2xCVNbeCeC&|4SoImpFdA-Uz`%=Rlj!SJ-l`p^mS=ejVF4q9{=?Vm*2i_RepT^?C!<=UuBQ= zYw9A=SNh_?wd3C|N*(0W$kE24Kc7xVJJGG_b?EV~zV`Iu?DUq_^y=oOVXkU=U2=GO z7e^Jnesq4#d(H5(s;?hk+c&FseGu~c$zMmm)OV@FWIVfl`nwN@ws&E!ls>$?|I5tK zrVdPa>9boW(Jy(`mZqkqFG?=$`z$fo(}{~WmA-s<{RpV<+_0Lp^!)0{t<%i=*0t?< zOfp|H=x{gsYeqe^ZTJPqj;Y{CyqcgiySE1D|fBjw)JFL;4-~4_?U>zpp z<^5mtW7;}0Ctg0hvU_H~##OnMUOm3?(<*&eSBaw6Pj8?3ZdPO)7kTJIb07FJt(T|7 z9w;67xpmIi&h@LxgXZg3_b=~Xl^NE`xzci8WnHCu&H7E+bP60WDq+HGGvSI`+97zr zkg+j`sye&6dA2pR3mQ25y@Zq1Yq_`b2{OHxkersD^{ivB@DZB0N(q%muS{6Ha5A#{ zFD4V?jacrbZcp59xt(*{@3!7;j$5=_H#d8?bB*#EMK|(jbgALOhCvPQHCWQ1TZ41; z4fXBoudLUq-uAlP>h5*z;ku(vyE=Kbooatj>t@Y?HMhDrxuiHBuFS23(`+ik&?GD+hZ2fE|T5q$urS?#dQY{ugft*gJl+tyte}7f`)xei? zUhIEf`mEcttfxDkJbB#Z@svkJ5A7Zf`Df*WTP58}KDvMHUYC1|@0Q#Nzq9SO>+Ko0 zO8$=e`_#>THxK+3^4FmoVK>hF8T;pxKNkGa;*Ueu$6a^6UU)6-n&-9Oudccpb+yIS zC&h<~R~1hz9#QO9+@iR4v3;?s7^dj|d{wbgTUpx)m8}xZ(azSYDrQ90?5%C8RL3W~ z@GloPelQ7>s#H~~ehq)z;z5lE+fs8570XkhBSa$3NY1AGuY6~MG$WYa(soi#_(mB2 zO#(%hs$Q$quV1NOSy{cbe(}=gxsA2m({l1m$VH0H6f%)WqCx^Q{SpNrALbgSn@Lxh z)TO1R_z;Wn=x)?#0XJ{F%6Py|gpgm~39zzpyWb`_lfY z1K0d{H78dObCe1$uk~z^zdfmJob4T~B%^Z`D_gAn9Bjd{R$ERVIbjNb)jP(d6;7pJ zQS;XOhMhOr;2pp)({5P1vtJdto*Qu2bjcJ)Uz={?+HZ_DG;#P|a>@D{)h?eoNR z%XAIH^DUDaHvU+=|9ObL#8a_b^+)0I__G@$ogcPzvx#)K%x531f2~)=Psk*#>C{WR z3}3vvTK^;i2Zhy8-TLRxxRa(Qs*g(6j@@dStIoV{6Y+)Vn0m(jxZaC)3D3wDEr^f{$QGltG26QrmYCid}T|2{H>H-@|Fr<|<|e4(3bB zU%ssrAD#j2O!v8bc8yY`fR6)+-ajDSOMeuZoulSDaNU$^tG`)pz#FF7|JA=9oEi`v z&b*WK>rGlJ(wpXPGI{(j!b0RzqU7b?Sk5;9Zl-c?SuoB2HyJb#3|qP_9@+2Z2!mx{(Bh2mNSNw?2h;b=^?Y#(6P4h!Iu z+yPFNUA7yre>iexf6j|t&X3)9rSCKTKc~N$Er-9OejPx8MSWOir8={mDE$uZAu}aIpRAM4K*==dy4g#y17l+iIFrS_X_|Y2HXR45;5-#=ysmA! zE{0D`A$Rv-dP7F0HfeCC4ri&z2dKEmr5fCu#=1vO%Fv~|Yct%nWw|Icl&1?fq-G#5 zbIJ+&j0E?X)L5On*Tkk13Gs$1C&r|u>oQ|g-3_|3(^}GyG&LqQ$vsPFNay2Qn#Q)1 zss7LDqV*Z>>H7C|mhsJWwM&cDW@yb%gdGCu*fkJ?odFrJ`NU#}K~j0(JMT*TFDzV> zzh%um|JiF^UUD6A*MH@Z4==B%d&hs%ucJQy^5!l7g(Y9jSajfT|BHF8g8uyGrvGel zJH6)Wzxu7mR=Sd-ytst^57Df32MzFjKqk-z7RT z<^3+#{3j2d+GCgDs=wph=Sd^}UCix`%k0WeZ~JT8dGuM;T|1=^Zq%* z9{iotV_57q7vIbC_FfCRvt?;;a*sb|bT~EcQC5$v+_MFN3&-z$TV9raC1XZU`~2b+ z|5{g8-MW9dT0rXUiPQESYZQ>NV$6=28=M0ME^=S7eS=59<0Ib(noQjTRIzpH?>!a} z(C+WtMF&l-1EziQ&sp1;`+g%Azlths@9E$0e!s&XoEz%D)8|3T#%(kG7uT~oYnS+q zfAYZ@rhUer{VntvWSINSXVYYwO3bcFp)p(WH_GOW`_mNH98U6c1zf^ zZgx&U4e6ThFZ(+M43)06%CnvFd{B9o<~)d6?EkFl=1&_Ay(IZ(n@-629X?qk=d;xu zUw(u#n{Q;-Tu*cTDuZd;4+n~uwja#t&Q!I+ET8b5n2Z)=MZZ~DQ8vt#c@H23_b`ss7gX#fXdzAs4X6)0 zGyhi6Cm26Ap}$W+!vj%^iM&c6-N3>+@T;Yw;>$>X9`~@*Y=xiKcPOYH(iOnnjTt4} zlAW+6;2zuUC~6nV0#5Ej9+)K+6`_xWn+J_9G9n&7!^PGxiUPKtL)^2V2YD22L7GP@ z!p0<8h%(b)dns{6*&C340qD32IH_qXu+TwGC2BRD#Jif4Hh6|XE?k8$pt!r5ykN+o zI%^L4gw8N zQ9mK*qzQh11C0fRd#I@70P`L+0Peq|e7~Wk@$HduYB+qaf%nI$@3WU2BN+~9QZZEeNV*Mit-Ml zJnF8ZsDmmBKv*`Afw1tWg3^Li~|VrKsHdsK>Tc==py9y0?N4sx3!A4PEpaqV=8iLi}H@6 zp6yXiJJj12oh__y-7^s-o<+sJlOC4F*kt;F*_-ih6^_HpsId@;r(jf1}!gDeZ4Fmx0009eeT(CP#E=AzK7k*+e z>Kw|3f7DIX<0$;jL$-j0dl1$Kw1uJkez*rew+16`EU1g$L)imW6t0B}x{CI}5Ahe4 z!0!QQ0-}%yT|nMIz(uqJu=Nb&=~tA4Gz7WXYD8KAembMv1e6mG+Vn_^`vACIQ7?CZ zfV9b|JL(^R`w(ChFc#1PaX=D~_XE>=e&7sn6L=0dRKpHTzzYZhh5+vY~PCx^o8Q=?q0wVw&kPb`(J_P0ip8;!ueZXnpF7O!N7Q60k8%51-K7X z!Rv^ofIlz_m;x*S)&To}v%pip*~N-l0{*~gUPSKnZU=uGT>|AJHQB>25tlDT2@pOXbSiN!+{LoV_-9I2)GP90bFWZQ9B?Mhyy+V zmH-=oy}$|JPe5P~T{WN~-~|K#5kM3$1(*-41$F=zfO~)muyeJdxqQHM3OF^eB6q+W2m!_dS-^+DC%`&jCvXI~ z2s{Uz8lntf2rvWq1jqw+0SAFoKr!$HsL{xZ+5=%gGB6KV2NVLo0XKn{Ky^2?DbNEL z1!Mxbz*oRt;1uu>P`N{HfObG%U@R~ZSPJX}P6IE2nvFptFc63Z(t%uHHLwdf0o(=1 z19Ad12E2e^U<8m1%mr2h`+(Cx3EtRoJ1H9L7L~i6xjmd+W zkS8p=&8Ruv^tZ%*?bfi*w#E9dJzm6jz^-o}y#4Qp-PxV7xb6zub9Wf2dSX9-KLt=A z1yL}CP%jFl-q@?&7yHTkWAFO_>`xzrJ@SLGk39lA2Zmz5`*7?@9|`O8XzX|&i(Tm& ziXtsVQw+tDj^ZdDJJI#nHJ^x8XEJuzr(y^Ec&tU!u^P?9x^x0I4NSuK3X`$te=5Fv zn1+e}becgkX%@Z`$f4QzMq)0$Gnj{OE#~8Ug^#i4e-SOlmkFO@cmEQ6Ik61Z+~xQJ zVJ$^0Ne2m#twYP zunUvR-S{42FD8zKWTYbc9$ydqfG;x+;_HSV@rB0`d?j%dUm6_8*A^%6#lkQ68st}e zQE?hyC7i{V8RzkJ!$o}IaT#ApT%lsRimy1X<4cG?u@B-ed{OZ?zDl@_FEj4q>xTQ- z5%B=$b3DWu5sz_B$WxqE@f_!syu_IquW@bzCTo1&u22grVJ&QgEw-Ol!TCT{g@dRj zstZTqBx(p};Ua2^TB5e7BV0vYQ4gmKH4qI&BjG08MPuP1ng~zPR5ZicLoGy0(Ml-i z)VB3%7mL$pH8HxR42?FEjSmKc@|ctsL)xTx&G<|$PORm-%oOE5In6sPHQt*Lpx3}& zk)(w!gQQGib!_XAOi?Q@GXySDl8a7i@^wp>6Gh`oK%A09rzshONzU67-^aeQ- zz4<07CSGIEro>WAf-WWzWTs>oQj;|Ll(bBghx#VR#$;%swK0hkvvM_y2Y@FF&s*{o?6Xyb({WIB+qf?&1pvk4;UHQt`dH zMCqPeKuMpb&4@_=lk^#SZ4&2JmO4GbpifCO$1_ug^a?HVotYMhM3Oc}$2C{N%|7KR zGIU8vnmB_thLp4l3za8HR1&mWLkH5Qk2hracoX>N9hjU(m08SZE^A^k(=$?&l@bk_ zn2aQ{^p|se(?6NzH3p|FgSk?Cg=C9+Og)M-L*C`YtS{2p@@abRnqzU;yv!+*J<@erLrelmLo*Ln%BUkh$D}gb z+6d!uRPFoPz7Cm?0Max6>VKH-`ytwFDiPQs{w8BtuE9J?=u zL?w@M4<)(m5f(IL2y~n)tq%?f)ud%8Yzhkx)@Z@(N$L7@ussP!{VOTn3@B$Hr@{{h z;7yQDlV;GxYT~sR<|WGC8f2OB?NvZq1*fJ*YNIuweMe{pcTid-EHXSIMvHMrlOff5 za0g$dn8@(TbXydHK&D6&)HgChGq@vHS7}USCY8bDRrBji& zuu8s`6324x9Vn-k@5{;HXBO>&L7D+U?7k0c&KmD#yebty-=Gq;E+{jx+_YLfJO5SlnGYj0&Tprg_Hq%y^j zGRjQhPFBe%!c1qxV3aDATo$64V9=&7_Io`YEZ4;!z|~(?O1e_Dz}u zox%t)0m_*=p}eili$mzTPzxj{d%oEr8UCJk`q zezNLe{b*3e4aGyAqDc8GK46U=zxN^&r1)Xlf|(3@{7T+DmRF1@FCQ)QOV`JzR7hsf zKsz*XWqwH++VYN8&P}c&hHeeFa~Z!BZ;9qNd@Inc#8j4I5;=;O1v$zTqAYt%9%3Pp z!R1-YKIn`q#*wEi(imAOfJeBPR9#$pc?xNGDetxUF9%!}L^xR0QUm z(2w|cM$xD6^q!-bGp>+Bd9XBv!_Nib=YB8{W_0Lejt?1HkU5@UDl<7BB`B5c z8|ew!Gz{bBsZAMsI?LPnZ4urT`X3TjPJ(d@>QdPk zqG;)7(8=>N3vvyq{2NXh9uyVDgRqo)y%|#$!*XUwiY={bqOsE_(L7<28L4oc$4@!5 zoIpvCr3sCcqa44IXL;!c9$z2_SdLXJ!7`vcbAv8E6SEAA`P{Q%50W$hTPPnkNy#Ix zTyEK;v;gsbtEWa0j`FzZZ(=an9HKGLHOqro6D#MEX3%GGH3EmcQGhw9FET@h?@Gz5 zqyH41ndYtOqYUBYw3suOL(LPKvNH6s*bb(wp)44#ORo?RlZtgid9X5JO--8wqlh%= zDw7B~=uO`Q=tFs=1h$Sz22p8Ru1tv1D|ss;bY*Xaf0ezJ2CD3>!77L6U2=`(Pn)8)-*~OFQqD^kwz-^)t4`96%x2yxd}MOa^+Ei zrB&IuRP@sC2$Pj{a0fHn<%-F^7Ib7LYhd3*Z>onWO&ZBECZS)I8$}w&%Zs)QNs$Nn z^1#d#J*?NsJ{IICUcPU7b$rvS)0V4 z*ng=oBpaT_SE zhvK$STrb7#qPPKy+fQ+aDDDWwjZ)lkikqRhA1Lk|#a*np%N2Kx;%-)4bAA8YZgPA5 z-_~w96rxMQVl&tP8vzVv5tw*zSNsL_;@=mo?2X@9fN3B&6Vtzx3~XDMeyg<4n|^&` z@k3s+VqTGl7X6L^7DYy*vuqdAFSz)DgOjp(%J1g8Ihxni!)?W1gdy;5asB zMkMKUX%wf9)ESatanI118BNLR$fR_zU>Gm+XC!bHTy`_CG5n| zXz(T`d#g}#r?0} z|M?sU43CuBIYe=tl;1(e0cUS*|NrxA^j`}9KXG888hi0@<=N#q<+V>P9tv-0I@hH&>Tn3!YuR zQ@(qCi+r#AKKbGKBl4s26Y|sYC+5$|UzoovKQDiM{?`0m`9=AM^NaIKuwl>cE0h_4 Z{iASPr4n%yE Date: Mon, 30 Jan 2017 06:47:49 +0530 Subject: [PATCH 138/746] added libs to support 32bit windows --- scripts/Latest.bat | 44 ++++++++++++++++++++++++++++++++++++++------ scripts/Stable.bat | 44 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 76 insertions(+), 12 deletions(-) diff --git a/scripts/Latest.bat b/scripts/Latest.bat index 8d59ec86..9af911a7 100644 --- a/scripts/Latest.bat +++ b/scripts/Latest.bat @@ -1,5 +1,5 @@ @ECHO off -TITLE Downloading NadekoBot, please wait +TITLE Downloading Latest Build of NadekoBot... ::Setting convenient to read variables which don't delete the windows temp folder SET root=%~dp0 CD /D %root% @@ -24,30 +24,43 @@ ECHO Downloading Nadeko... ECHO. git clone -b dev --recursive --depth 1 --progress https://github.com/Kwoth/NadekoBot.git >nul IF %ERRORLEVEL% EQU 128 (GOTO :giterror) -TITLE Installing NadekoBot, please wait +TITLE Installing NadekoBot, please wait... ECHO. -ECHO Installing... +ECHO Installing Discord.Net(1/4)... ::Building Nadeko CD /D %build1% dotnet restore >nul 2>&1 +ECHO Installing Discord.Net(2/4)... CD /D %build2% dotnet restore >nul 2>&1 +ECHO Installing Discord.Net(3/4)... CD /D %build3% dotnet restore >nul 2>&1 +ECHO Installing Discord.Net(4/4)... CD /D %build4% dotnet restore >nul 2>&1 +ECHO. +ECHO Discord.Net installation completed successfully... +ECHO. +ECHO Installing NadekoBot... CD /D %build5% dotnet restore >nul 2>&1 dotnet build --configuration Release >nul 2>&1 +ECHO. +ECHO NadekoBot installation completed successfully... ::Attempts to backup old files if they currently exist in the same folder as the batch file IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) :freshinstall ::Moves the NadekoBot folder to keep things tidy + ECHO. + ECHO Moving files, Please wait... ROBOCOPY "%root%NadekoInstall_Temp" "%rootdir%" /E /MOVE >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) - GOTO :end + IF EXIST "%PROGRAMFILES(X86)%" (GOTO 64BIT) ELSE (GOTO 32BIT) :backupinstall - TITLE Backing up old files + TITLE Backing up old files... + ECHO. + ECHO Moving and Backing up old files... ::Recursively copies all files and folders from NadekoBot to NadekoBot_Old ROBOCOPY "%root%NadekoBot" "%root%NadekoBot_Old" /MIR >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) @@ -70,7 +83,7 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) RMDIR "%root%NadekoBot\" /S /Q >nul 2>&1 ROBOCOPY "%root%NadekoInstall_Temp" "%rootdir%" /E /MOVE >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) - GOTO :end + IF EXIST "%PROGRAMFILES(X86)%" (GOTO 64BIT) ELSE (GOTO 32BIT) :dotnet ::Terminates the batch script if it can't run dotnet --version TITLE Error! @@ -102,6 +115,25 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) PAUSE >nul 2>&1 CD /D "%root%" GOTO :EOF +:64BIT +ECHO. +ECHO Your System Architecture is 64bit... +GOTO end +:32BIT +ECHO. +ECHO Your System Architecture is 32bit... +timeout /t 5 +ECHO. +ECHO Downloading libsodium.dll and libopus.dll... +SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll" +bitsadmin.exe /transfer "Downloading libsodium.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll "%FILENAME%" +ECHO libsodium.dll downloaded. +ECHO. +timeout /t 5 +SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll" +bitsadmin.exe /transfer "Downloading libopus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%" +ECHO libopus.dll downloaded. +GOTO end :end ::Normal execution of end of script TITLE Installation complete! diff --git a/scripts/Stable.bat b/scripts/Stable.bat index a2016889..827326b3 100644 --- a/scripts/Stable.bat +++ b/scripts/Stable.bat @@ -1,5 +1,5 @@ @ECHO off -TITLE Downloading NadekoBot, please wait +TITLE Downloading Stable Build of NadekoBot... ::Setting convenient to read variables which don't delete the windows temp folder SET root=%~dp0 CD /D %root% @@ -24,30 +24,43 @@ ECHO Downloading Nadeko... ECHO. git clone -b master --recursive --depth 1 --progress https://github.com/Kwoth/NadekoBot.git >nul IF %ERRORLEVEL% EQU 128 (GOTO :giterror) -TITLE Installing NadekoBot, please wait +TITLE Installing NadekoBot, please wait... ECHO. -ECHO Installing... +ECHO Installing Discord.Net(1/4)... ::Building Nadeko CD /D %build1% dotnet restore >nul 2>&1 +ECHO Installing Discord.Net(2/4)... CD /D %build2% dotnet restore >nul 2>&1 +ECHO Installing Discord.Net(3/4)... CD /D %build3% dotnet restore >nul 2>&1 +ECHO Installing Discord.Net(4/4)... CD /D %build4% dotnet restore >nul 2>&1 +ECHO. +ECHO Discord.Net installation completed successfully... +ECHO. +ECHO Installing NadekoBot... CD /D %build5% dotnet restore >nul 2>&1 dotnet build --configuration Release >nul 2>&1 +ECHO. +ECHO NadekoBot installation completed successfully... ::Attempts to backup old files if they currently exist in the same folder as the batch file IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) :freshinstall ::Moves the NadekoBot folder to keep things tidy + ECHO. + ECHO Moving files, Please wait... ROBOCOPY "%root%NadekoInstall_Temp" "%rootdir%" /E /MOVE >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) - GOTO :end + IF EXIST "%PROGRAMFILES(X86)%" (GOTO 64BIT) ELSE (GOTO 32BIT) :backupinstall - TITLE Backing up old files + TITLE Backing up old files... + ECHO. + ECHO Moving and Backing up old files... ::Recursively copies all files and folders from NadekoBot to NadekoBot_Old ROBOCOPY "%root%NadekoBot" "%root%NadekoBot_Old" /MIR >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) @@ -70,7 +83,7 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) RMDIR "%root%NadekoBot\" /S /Q >nul 2>&1 ROBOCOPY "%root%NadekoInstall_Temp" "%rootdir%" /E /MOVE >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) - GOTO :end + IF EXIST "%PROGRAMFILES(X86)%" (GOTO 64BIT) ELSE (GOTO 32BIT) :dotnet ::Terminates the batch script if it can't run dotnet --version TITLE Error! @@ -102,6 +115,25 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) PAUSE >nul 2>&1 CD /D "%root%" GOTO :EOF +:64BIT +ECHO. +ECHO Your System Architecture is 64bit... +GOTO end +:32BIT +ECHO. +ECHO Your System Architecture is 32bit... +timeout /t 5 +ECHO. +ECHO Downloading libsodium.dll and libopus.dll... +SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll" +bitsadmin.exe /transfer "Downloading libsodium.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll "%FILENAME%" +ECHO libsodium.dll downloaded. +ECHO. +timeout /t 5 +SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll" +bitsadmin.exe /transfer "Downloading libopus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%" +ECHO libopus.dll downloaded. +GOTO end :end ::Normal execution of end of script TITLE Installation complete! From 69cf15f07b3ac8d078217feb3b9e2c3a343c3aa7 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 30 Jan 2017 02:58:36 +0100 Subject: [PATCH 139/746] uinfo now works with users without avatar. $give and $award messages are arguably nicer --- src/NadekoBot/Modules/Gambling/Gambling.cs | 4 ++-- src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 8db03d30..ceaa4300 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -74,7 +74,7 @@ namespace NadekoBot.Modules.Gambling return; } await CurrencyHandler.AddCurrencyAsync(receiver, $"Gift from {Context.User.Username} ({Context.User.Id}).", amount, true).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully sent {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} to {receiver}!").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} gifted {amount}{CurrencySign} to {Format.Bold(receiver.ToString())}!").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -94,7 +94,7 @@ namespace NadekoBot.Modules.Gambling await CurrencyHandler.AddCurrencyAsync(usrId, $"Awarded by bot owner. ({Context.User.Username}/{Context.User.Id})", amount).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} awarded {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} to <@{usrId}>!").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} awarded {amount}{CurrencySign} to <@{usrId}>!").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 66ffa3c2..b2594d3a 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -97,8 +97,10 @@ 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.RealAvatarUrl()) .WithColor(NadekoBot.OkColor); + + if (user.AvatarId != null) + embed.WithThumbnailUrl(user.RealAvatarUrl()); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } } From 81a4d553bec569332f5ef7dd823e73aa2391aef5 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 30 Jan 2017 05:40:19 +0100 Subject: [PATCH 140/746] !!smch added. Set music output's text channel. --- .../Modules/Music/Classes/MusicControls.cs | 5 +- src/NadekoBot/Modules/Music/Music.cs | 54 ++++++++++++------- .../Resources/CommandStrings.Designer.cs | 27 ++++++++++ src/NadekoBot/Resources/CommandStrings.resx | 9 ++++ 4 files changed, 75 insertions(+), 20 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index 6d101975..e11b680e 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -71,6 +71,7 @@ namespace NadekoBot.Modules.Music.Classes public event Action OnPauseChanged = delegate { }; public IVoiceChannel PlaybackVoiceChannel { get; private set; } + public ITextChannel OutputTextChannel { get; set; } private bool Destroyed { get; set; } = false; public bool RepeatSong { get; private set; } = false; @@ -84,10 +85,12 @@ namespace NadekoBot.Modules.Music.Classes public event Action SongRemoved = delegate { }; - public MusicPlayer(IVoiceChannel startingVoiceChannel, float? defaultVolume) + public MusicPlayer(IVoiceChannel startingVoiceChannel, ITextChannel outputChannel, float? defaultVolume) { if (startingVoiceChannel == null) throw new ArgumentNullException(nameof(startingVoiceChannel)); + + OutputTextChannel = outputChannel; Volume = defaultVolume ?? 1.0f; PlaybackVoiceChannel = startingVoiceChannel; diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index b229bf84..5ad9918c 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -797,6 +797,23 @@ namespace NadekoBot.Modules.Music await Context.Channel.SendConfirmAsync("✅ Autoplay enabled.").ConfigureAwait(false); } + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + public async Task SetMusicChannel() + { + MusicPlayer musicPlayer; + if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) + { + await Context.Channel.SendErrorAsync("Music must be playing before you set an ouput channel.").ConfigureAwait(false); + return; + } + + musicPlayer.OutputTextChannel = (ITextChannel)Context.Channel; + + await Context.Channel.SendConfirmAsync("I will now output playing, finished, paused and removed songs in this channel.").ConfigureAwait(false); + } + public static async Task QueueSong(IGuildUser queuer, ITextChannel textCh, IVoiceChannel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal) { if (voiceCh == null || voiceCh.Guild != textCh.Guild) @@ -815,7 +832,7 @@ namespace NadekoBot.Modules.Music { vol = uow.GuildConfigs.For(textCh.Guild.Id, set => set).DefaultMusicVolume; } - var mp = new MusicPlayer(voiceCh, vol); + var mp = new MusicPlayer(voiceCh, textCh, vol); IUserMessage playingMessage = null; IUserMessage lastFinishedMessage = null; mp.OnCompleted += async (s, song) => @@ -825,7 +842,7 @@ namespace NadekoBot.Modules.Music if (lastFinishedMessage != null) lastFinishedMessage.DeleteAfter(0); - lastFinishedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor() + lastFinishedMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithAuthor(eab => eab.WithName("Finished Song").WithMusicIcon()) .WithDescription(song.PrettyName) .WithFooter(ef => ef.WithText(song.PrettyInfo))) @@ -857,7 +874,7 @@ namespace NadekoBot.Modules.Music if (playingMessage != null) playingMessage.DeleteAfter(0); - playingMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor() + playingMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithAuthor(eab => eab.WithName("Playing Song").WithMusicIcon()) .WithDescription(song.PrettyName) .WithFooter(ef => ef.WithText(song.PrettyInfo))) @@ -866,22 +883,21 @@ namespace NadekoBot.Modules.Music catch { } }; mp.OnPauseChanged += async (paused) => - { - try - { - IUserMessage msg; - if (paused) - msg = await textCh.SendConfirmAsync("🎵 Music playback **paused**.").ConfigureAwait(false); - else - msg = await textCh.SendConfirmAsync("🎵 Music playback **resumed**.").ConfigureAwait(false); - - if (msg != null) - msg.DeleteAfter(10); - } - catch { } - }; - + { + try + { + IUserMessage msg; + if (paused) + msg = await mp.OutputTextChannel.SendConfirmAsync("🎵 Music playback **paused**.").ConfigureAwait(false); + else + msg = await mp.OutputTextChannel.SendConfirmAsync("🎵 Music playback **resumed**.").ConfigureAwait(false); + if (msg != null) + msg.DeleteAfter(10); + } + catch { } + }; + mp.SongRemoved += async (song, index) => { try @@ -892,7 +908,7 @@ namespace NadekoBot.Modules.Music .WithFooter(ef => ef.WithText(song.PrettyInfo)) .WithErrorColor(); - await textCh.EmbedAsync(embed).ConfigureAwait(false); + await mp.OutputTextChannel.EmbedAsync(embed).ConfigureAwait(false); } catch { } diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 4388c9bd..e89ba368 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -6782,6 +6782,33 @@ namespace NadekoBot.Resources { } } + ///

+ /// Looks up a localized string similar to setmusicchannel smch. + /// + public static string setmusicchannel_cmd { + get { + return ResourceManager.GetString("setmusicchannel_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in.. + /// + public static string setmusicchannel_desc { + get { + return ResourceManager.GetString("setmusicchannel_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}smch`. + /// + public static string setmusicchannel_usage { + get { + return ResourceManager.GetString("setmusicchannel_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to setmuterole. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 2dc50365..7ee5714b 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3033,4 +3033,13 @@ `{0}mal straysocks` + + setmusicchannel smch + + + Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in. + + + `{0}smch` + \ No newline at end of file From fab46bc3f237437849ca0d28d24bcf687f0032b4 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 30 Jan 2017 06:26:47 +0100 Subject: [PATCH 141/746] sneakygamestatus event added --- .../Gambling/Commands/CurrencyEvents.cs | 78 ++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs index 598a19b0..ad6e7023 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -9,6 +9,8 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Discord.WebSocket; +using NadekoBot.Services.Database; namespace NadekoBot.Modules.Gambling { @@ -19,15 +21,27 @@ namespace NadekoBot.Modules.Gambling { public enum CurrencyEvent { - FlowerReaction + FlowerReaction, + SneakyGameStatus } //flower reaction event public static readonly ConcurrentHashSet _flowerReactionAwardedUsers = new ConcurrentHashSet(); + + private static readonly char[] _sneakyGameStatusChars = Enumerable.Range(48, 10) + .Concat(Enumerable.Range(65, 26)) + .Concat(Enumerable.Range(97, 26)) + .Select(x => (char)x) + .ToArray(); + + public static readonly ConcurrentHashSet _sneakyGameAwardedUsers = new ConcurrentHashSet(); + + private static string _secretCode = String.Empty; + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [OwnerOnly] - public async Task StartEvent(CurrencyEvent e) + public async Task StartEvent(CurrencyEvent e, int arg = -1) { var channel = (ITextChannel)Context.Channel; try @@ -38,6 +52,9 @@ namespace NadekoBot.Modules.Gambling case CurrencyEvent.FlowerReaction: await FlowerReactionEvent(Context).ConfigureAwait(false); break; + case CurrencyEvent.SneakyGameStatus: + await SneakyGameStatusEvent(Context, arg).ConfigureAwait(false); + break; default: break; } @@ -45,6 +62,63 @@ namespace NadekoBot.Modules.Gambling catch { } } + public static async Task SneakyGameStatusEvent(CommandContext Context, int? arg) + { + int num; + if (arg == null || arg < 5) + num = 60; + else + num = arg.Value; + + if (_secretCode != String.Empty) + return; + var rng = new NadekoRandom(); + + for (int i = 0; i < 5; i++) + { + _secretCode += _sneakyGameStatusChars[rng.Next(0, _sneakyGameStatusChars.Length)]; + } + + await NadekoBot.Client.SetGameAsync($"type {_secretCode} for " + NadekoBot.BotConfig.CurrencyPluralName) + .ConfigureAwait(false); + try + { + await Context.Channel.SendConfirmAsync($"SneakyGameStatus event started", + $"Users must type a secret code to get 100 currency.\n" + + $"Lasts {num} seconds. Don't tell anyone. Shhh.") + .ConfigureAwait(false); + } + catch { } + + + NadekoBot.Client.MessageReceived += SneakyGameMessageReceivedEventHandler; + await Task.Delay(num * 1000); + NadekoBot.Client.MessageReceived -= SneakyGameMessageReceivedEventHandler; + + _sneakyGameAwardedUsers.Clear(); + _secretCode = String.Empty; + + await NadekoBot.Client.SetGameAsync($"SneakyGame event ended.") + .ConfigureAwait(false); + } + + private static Task SneakyGameMessageReceivedEventHandler(SocketMessage arg) + { + if (arg.Content == _secretCode && + _sneakyGameAwardedUsers.Add(arg.Author.Id)) + { + var _ = Task.Run(async () => + { + await CurrencyHandler.AddCurrencyAsync(arg.Author, "Sneaky Game Event", 100, false) + .ConfigureAwait(false); + + try { await arg.DeleteAsync(new RequestOptions() { RetryMode = RetryMode.AlwaysFail }).ConfigureAwait(false); } + catch { } + }); + } + + return Task.Delay(0); + } public static async Task FlowerReactionEvent(CommandContext Context) { From 28566023c2661995dea6f83d0c68b52a601a177a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 31 Jan 2017 20:11:42 +0100 Subject: [PATCH 142/746] Fixed music errors? --- NuGet.Config | 1 + src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs | 3 +-- src/NadekoBot/Modules/Music/Classes/SongHandler.cs | 2 +- src/NadekoBot/project.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NuGet.Config b/NuGet.Config index d40268d3..e482807c 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -2,5 +2,6 @@ + diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs index ad6e7023..927f8a72 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -26,6 +26,7 @@ namespace NadekoBot.Modules.Gambling } //flower reaction event public static readonly ConcurrentHashSet _flowerReactionAwardedUsers = new ConcurrentHashSet(); + public static readonly ConcurrentHashSet _sneakyGameAwardedUsers = new ConcurrentHashSet(); private static readonly char[] _sneakyGameStatusChars = Enumerable.Range(48, 10) @@ -34,8 +35,6 @@ namespace NadekoBot.Modules.Gambling .Select(x => (char)x) .ToArray(); - public static readonly ConcurrentHashSet _sneakyGameAwardedUsers = new ConcurrentHashSet(); - private static string _secretCode = String.Empty; [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Music/Classes/SongHandler.cs b/src/NadekoBot/Modules/Music/Classes/SongHandler.cs index 7892e278..f296d2cb 100644 --- a/src/NadekoBot/Modules/Music/Classes/SongHandler.cs +++ b/src/NadekoBot/Modules/Music/Classes/SongHandler.cs @@ -97,7 +97,7 @@ namespace NadekoBot.Modules.Music.Classes { Title = video.Title.Substring(0, video.Title.Length - 10), // removing trailing "- You Tube" Provider = "YouTube", - Uri = video.Uri, + Uri = await video.GetUriAsync().ConfigureAwait(false), Query = link, ProviderType = musicType, }); diff --git a/src/NadekoBot/project.json b/src/NadekoBot/project.json index 17dc48f1..a88058ea 100644 --- a/src/NadekoBot/project.json +++ b/src/NadekoBot/project.json @@ -18,7 +18,7 @@ }, "dependencies": { "AngleSharp": "0.9.9", - "VideoLibrary": "1.3.4", + "libvideo": "1.0.0", "CoreCLR-NCalc": "2.1.2", "Google.Apis.Urlshortener.v1": "1.19.0.138", "Google.Apis.YouTube.v3": "1.20.0.701", From 3c4cdb3e60ad99f23bb6dc7f30657bb48c14e7fa Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 31 Jan 2017 20:22:12 +0100 Subject: [PATCH 143/746] 1.1.5a --- 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 380ca2bb..ab72769d 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.5"; + public const string BotVersion = "1.1.5a"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From a5b40ae608980485bf1f97ca7df8cd95d04414bd Mon Sep 17 00:00:00 2001 From: samvaio Date: Wed, 1 Feb 2017 03:08:31 +0530 Subject: [PATCH 144/746] changed libopus names to opus (minor) --- scripts/Latest.bat | 6 +++--- scripts/Stable.bat | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/Latest.bat b/scripts/Latest.bat index 9af911a7..a4f9e15b 100644 --- a/scripts/Latest.bat +++ b/scripts/Latest.bat @@ -124,15 +124,15 @@ ECHO. ECHO Your System Architecture is 32bit... timeout /t 5 ECHO. -ECHO Downloading libsodium.dll and libopus.dll... +ECHO Downloading libsodium.dll and opus.dll... SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll" bitsadmin.exe /transfer "Downloading libsodium.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll "%FILENAME%" ECHO libsodium.dll downloaded. ECHO. timeout /t 5 SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll" -bitsadmin.exe /transfer "Downloading libopus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%" -ECHO libopus.dll downloaded. +bitsadmin.exe /transfer "Downloading opus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%" +ECHO opus.dll downloaded. GOTO end :end ::Normal execution of end of script diff --git a/scripts/Stable.bat b/scripts/Stable.bat index 827326b3..f55fc958 100644 --- a/scripts/Stable.bat +++ b/scripts/Stable.bat @@ -124,15 +124,15 @@ ECHO. ECHO Your System Architecture is 32bit... timeout /t 5 ECHO. -ECHO Downloading libsodium.dll and libopus.dll... +ECHO Downloading libsodium.dll and opus.dll... SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll" bitsadmin.exe /transfer "Downloading libsodium.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll "%FILENAME%" ECHO libsodium.dll downloaded. ECHO. timeout /t 5 SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll" -bitsadmin.exe /transfer "Downloading libopus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%" -ECHO libopus.dll downloaded. +bitsadmin.exe /transfer "Downloading opus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%" +ECHO opus.dll downloaded. GOTO end :end ::Normal execution of end of script From 630c71de6303230d75ad53ac8c6b93760b285696 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 1 Feb 2017 17:50:14 +0100 Subject: [PATCH 145/746] Download users back? --- Discord.Net | 2 +- src/NadekoBot/NadekoBot.cs | 3 +- src/NadekoBot/ShardedDiscordClient.cs | 199 -------------------------- 3 files changed, 3 insertions(+), 201 deletions(-) delete mode 100644 src/NadekoBot/ShardedDiscordClient.cs diff --git a/Discord.Net b/Discord.Net index 80384323..b57d5d73 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit 80384323790471d254c7db5c237a49dc62624378 +Subproject commit b57d5d738921021f6e366ab6b4eb13cd0501959d diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 02c60720..a6842797 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -67,7 +67,8 @@ namespace NadekoBot MessageCacheSize = 10, LogLevel = LogSeverity.Warning, TotalShards = Credentials.TotalShards, - ConnectionTimeout = int.MaxValue + ConnectionTimeout = int.MaxValue, + AlwaysDownloadUsers = true, }); #if GLOBAL_NADEKO Client.Log += Client_Log; diff --git a/src/NadekoBot/ShardedDiscordClient.cs b/src/NadekoBot/ShardedDiscordClient.cs deleted file mode 100644 index daa5276e..00000000 --- a/src/NadekoBot/ShardedDiscordClient.cs +++ /dev/null @@ -1,199 +0,0 @@ -using Discord; -using Discord.WebSocket; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using NLog; -using System.Diagnostics; - -namespace NadekoBot -{ - public class ShardedDiscordClient - { - private DiscordSocketConfig discordSocketConfig; - private Logger _log { get; } - - public event Action UserJoined = delegate { }; - public event Action MessageReceived = delegate { }; - public event Action UserLeft = delegate { }; - public event Action UserUpdated = delegate { }; - public event Action GuildUserUpdated = delegate { }; - public event Action, SocketMessage> MessageUpdated = delegate { }; - public event Action> MessageDeleted = delegate { }; - public event Action UserBanned = delegate { }; - public event Action UserUnbanned = delegate { }; - public event Action, SocketUser, SocketPresence, SocketPresence> UserPresenceUpdated = delegate { }; - public event Action UserVoiceStateUpdated = delegate { }; - public event Action ChannelCreated = delegate { }; - public event Action ChannelDestroyed = delegate { }; - public event Action ChannelUpdated = delegate { }; - public event Action, SocketReaction> ReactionAdded = delegate { }; - public event Action, SocketReaction> ReactionRemoved = delegate { }; - public event Action> ReactionsCleared = delegate { }; - - public event Action JoinedGuild = delegate { }; - public event Action LeftGuild = delegate { }; - - public event Action Disconnected = delegate { }; - public event Action Connected = delegate { }; - - private uint _connectedCount = 0; - private uint _downloadedCount = 0; - - private int _guildCount = 0; - - private IReadOnlyList Clients { get; } - - public ShardedDiscordClient(DiscordSocketConfig discordSocketConfig) - { - _log = LogManager.GetCurrentClassLogger(); - this.discordSocketConfig = discordSocketConfig; - - var clientList = new List(); - for (int i = 0; i < discordSocketConfig.TotalShards; i++) - { - discordSocketConfig.ShardId = i; - var client = new DiscordSocketClient(discordSocketConfig); - clientList.Add(client); - client.UserJoined += arg1 => { UserJoined(arg1); return Task.CompletedTask; }; - client.MessageReceived += arg1 => - { - if (arg1.Author == null || arg1.Author.IsBot) - return Task.CompletedTask; - MessageReceived(arg1); - return Task.CompletedTask; - }; - client.UserLeft += arg1 => { UserLeft(arg1); return Task.CompletedTask; }; - client.UserUpdated += (arg1, gu2) => { UserUpdated(arg1, gu2); return Task.CompletedTask; }; - client.GuildMemberUpdated += (arg1, arg2) => { GuildUserUpdated(arg1, arg2); return Task.CompletedTask; }; - client.MessageUpdated += (arg1, m2) => { MessageUpdated(arg1, m2); return Task.CompletedTask; }; - client.MessageDeleted += (arg1, arg2) => { MessageDeleted(arg1, arg2); return Task.CompletedTask; }; - client.UserBanned += (arg1, arg2) => { UserBanned(arg1, arg2); return Task.CompletedTask; }; - client.UserUnbanned += (arg1, arg2) => { UserUnbanned(arg1, arg2); return Task.CompletedTask; }; - client.UserPresenceUpdated += (arg1, arg2, arg3, arg4) => { UserPresenceUpdated(arg1, arg2, arg3, arg4); return Task.CompletedTask; }; - client.UserVoiceStateUpdated += (arg1, arg2, arg3) => { UserVoiceStateUpdated(arg1, arg2, arg3); return Task.CompletedTask; }; - client.ChannelCreated += arg => { ChannelCreated(arg); return Task.CompletedTask; }; - client.ChannelDestroyed += arg => { ChannelDestroyed(arg); return Task.CompletedTask; }; - client.ChannelUpdated += (arg1, arg2) => { ChannelUpdated(arg1, arg2); return Task.CompletedTask; }; - client.JoinedGuild += (arg1) => { JoinedGuild(arg1); ++_guildCount; return Task.CompletedTask; }; - client.LeftGuild += (arg1) => { LeftGuild(arg1); --_guildCount; return Task.CompletedTask; }; - client.ReactionAdded += (arg1, arg2, arg3) => { ReactionAdded(arg1, arg2, arg3); return Task.CompletedTask; }; - client.ReactionRemoved += (arg1, arg2, arg3) => { ReactionRemoved(arg1, arg2, arg3); return Task.CompletedTask; }; - client.ReactionsCleared += (arg1, arg2) => { ReactionsCleared(arg1, arg2); return Task.CompletedTask; }; - - _log.Info($"Shard #{i} initialized."); -#if GLOBAL_NADEKO - client.Log += Client_Log; -#endif - var j = i; - client.Disconnected += (ex) => - { - _log.Error("Shard #{0} disconnected", j); - _log.Error(ex, ex?.Message ?? "No error"); - return Task.CompletedTask; - }; - } - - Clients = clientList.AsReadOnly(); - } - - private Task Client_Log(LogMessage arg) - { - _log.Warn(arg.Message); - _log.Error(arg.Exception); - return Task.CompletedTask; - } - - public DiscordSocketClient MainClient => - Clients[0]; - - public SocketSelfUser CurrentUser => - Clients[0].CurrentUser; - - public IEnumerable GetGuilds() => - Clients.SelectMany(c => c.Guilds); - - public int GetGuildsCount() => - _guildCount; - - public SocketGuild GetGuild(ulong id) - { - foreach (var c in Clients) - { - var g = c.GetGuild(id); - if (g != null) - return g; - } - return null; - } - - public Task GetDMChannelAsync(ulong channelId) => - Clients[0].GetDMChannelAsync(channelId); - - internal async Task LoginAsync(TokenType tokenType, string token) - { - foreach (var c in Clients) - { - await c.LoginAsync(tokenType, token).ConfigureAwait(false); - _log.Info($"Shard #{c.ShardId} logged in."); - } - } - - internal async Task ConnectAsync() - { - - foreach (var c in Clients) - { - try - { - var sw = Stopwatch.StartNew(); - await c.ConnectAsync().ConfigureAwait(false); - sw.Stop(); - _log.Info($"Shard #{c.ShardId} connected after {sw.Elapsed.TotalSeconds:F2}s ({++_connectedCount}/{Clients.Count})"); - _guildCount += c.Guilds.Count; - } - catch - { - _log.Error($"Shard #{c.ShardId} FAILED CONNECTING."); - try { await c.ConnectAsync().ConfigureAwait(false); } - catch (Exception ex2) - { - _log.Error($"Shard #{c.ShardId} FAILED CONNECTING TWICE."); - _log.Error(ex2); - } - } - } - Connected(); - } - - internal Task DownloadAllUsersAsync() => - Task.WhenAll(Clients.Select(async c => - { - var sw = Stopwatch.StartNew(); - await c.DownloadAllUsersAsync().ConfigureAwait(false); - sw.Stop(); - _log.Info($"Shard #{c.ShardId} downloaded {c.Guilds.Sum(g => g.Users.Count)} users after {sw.Elapsed.TotalSeconds:F2}s ({++_downloadedCount}/{Clients.Count})."); - })); - - public Task SetGame(string game) => Task.WhenAll(Clients.Select(ms => ms.SetGameAsync(game))); - - - public Task SetStream(string name, string url) => Task.WhenAll(Clients.Select(ms => ms.SetGameAsync(name, url, StreamType.Twitch))); - - //public Task SetStatus(SettableUserStatus status) => Task.WhenAll(Clients.Select(ms => ms.SetStatusAsync(SettableUserStatusToUserStatus(status)))); - } - - public enum SettableUserStatus - { - Online = 1, - On = 1, - Invisible = 2, - Invis = 2, - Idle = 3, - Afk = 3, - Dnd = 4, - DoNotDisturb = 4, - Busy = 4, - } -} \ No newline at end of file From 0a280f9b5b73126690ee5d6f24620a911ed7b642 Mon Sep 17 00:00:00 2001 From: samvaio Date: Thu, 2 Feb 2017 03:52:16 +0530 Subject: [PATCH 146/746] linux guide updated --- docs/guides/Linux Guide.md | 289 +++++++++++++++++++++++-------------- 1 file changed, 178 insertions(+), 111 deletions(-) diff --git a/docs/guides/Linux Guide.md b/docs/guides/Linux Guide.md index 5fee13a3..b14351bc 100644 --- a/docs/guides/Linux Guide.md +++ b/docs/guides/Linux Guide.md @@ -8,11 +8,11 @@ Assuming you have followed the link above to setup an account and Droplet with 6 **Go through this whole guide before setting up Nadeko** -#### Prerequisites +####Prerequisites - Download [PuTTY](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html) -- Download [CyberDuck](https://cyberduck.io) or [WinSCP](https://winscp.net/eng/download.php) +- Download [WinSCP](https://winscp.net/eng/download.php) *(optional)* -#### Follow these steps +####Starting up - **Open PuTTY.exe** that you downloaded before, and paste or enter your `IP address` and then click **Open**. If you entered your Droplets IP address correctly, it should show **login as:** in a newly opened window. @@ -24,7 +24,162 @@ If you entered your Droplets IP address correctly, it should show **login as:** **NOTE:** Copy the commands, and just paste them using **mouse single right-click.** -####Installing Git +####Creating and Inviting bot + +- Read here how to [create a DiscordBot application](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#creating-discordbot-application) +- [Visual Invite Guide](http://discord.kongslien.net/guide.html) **(Note: Client ID is your Bot ID)** +- Copy your `Client ID` from your [applications page](https://discordapp.com/developers/applications/me). +- Replace the **12345678** in this link: +`https://discordapp.com/oauth2/authorize?client_id=`12345678`&scope=bot&permissions=66186303` + with your `Client ID` +- The link should now look like this: +`https://discordapp.com/oauth2/authorize?client_id=`**YOUR_CLENT_ID_HERE**`&scope=bot&permissions=66186303` +- Go to the newly created link and pick the server we created, and click `Authorize` +- The bot should have been added to your server. + +####Getting NadekoBot +#####Part I +Use the following command to get and run `linuxAIO.sh` +(Remember **Do Not** rename the file **linuxAIO.sh**) + +`cd ~ && wget -N https://github.com/Kwoth/NadekoBot-BashScript/raw/master/linuxAIO.sh && bash linuxAIO.sh` + +You should see these following options after using the above command: + +``` +1. Download Dev Build (Latest) +2. Download Stable Build +3. Run Nadeko (Normally) +4. Run Nadeko with Auto Restart (Run Nadeko normally before using this.) +5. Auto-Install Prerequisites (for Ubuntu and Debian) +6. Set up credentials.json (if you have downloaded the bot already) +7. To exit +``` +#####Part II +**If** you are running NadekoBot for the first time on your system and never had any *prerequisites* installed, Press `5` and press `enter` key, then `y` when you see the following: +``` +Welcome to NadekoBot Auto Prerequisites Installer. +Would you like to continue? +``` +That will install all the prerequisites your system need to run NadekoBot. + +If you prefer to install them [manually](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#installing-manually-optional), click on the link. *(Optional)* + +Once *prerequisites* finish installing. +#####Part III +Choose either +`1` to get the **most updated build of NadekoBot** +or +`2` to get the **previously stable build of NadekoBot** +and then press `enter` key. + +Once Installation is completed you should see the options again. + +Next, check out: +#####Part IV +If you prefer to do this step [manually](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#setting-up-sftp), and skip other parts click on the link. *(Optional)* + +- [1. Setting up credentials.json](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#setting-up-credentialsjson) +- [2. To Get the Google API](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-nadekobot-for-music) +- [3. JSON Explanations for other APIs](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/) + +You will need the following for the next step: +![botimg](https://cdn.discordapp.com/attachments/251504306010849280/276455844223123457/Capture.PNG) + +- **Bot's Client ID** and **Bot's ID** (both are same) [(*required)](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-credentialsjson-file) +- **Bot's Token** (not client secret) [(*required)](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-credentialsjson-file) +- Your **Discord userID** [(*required)](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-credentialsjson-file) +- **Google Api Key** [(optional)](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-nadekobot-for-music) +- **LoL Api Key** [(optional)](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/) +- **Mashape Key** [(optional)](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/) +- **Osu Api Key** [(optional)](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/) +- **Sound Cloud Client Id** [(optional)](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/) + +Once you have acquired them, press `6` to **Set up credentials.json** + +You will be asked to enter the required informations, just follow the on-screen instructions and enter whats asked. +*i.e* If you are asked **Bot's Token**, then just copy and paste the `token` and press `enter` key. + +If you want to skip any optional informations, just press `enter` key without typing/pasting anything. +Once done, +#####Part V +You should see the options again within the **tmux session** named *nadako*. +Next, press `3` to **Run Nadeko (Normally)** +Check in your discord server if your new bot is working properly. +#####Part VI +If the bot is working properly in your server, type `.die` to shut down the bot. +You should be back to the options again, +from the options choose `4` to **Run Nadeko with Auto Restart.** + +It will show you more options: +``` +1. Run Auto Restart normally without Updating. +2. Auto Restart and Update with Dev Build (latest) +3. Auto Restart and Update with Stable Build +4. Exit +``` +Choose anything you like and once the bot's back online again in your server, close the **PuTTY**. +Done, You now have your own **NadekoBot**. + + +[To **Restart** your **NadekoBot** anytime later.](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#restarting-nadeko) + +####Running NadekoBot + +**Create a new Session:** + +- `tmux new -s nadeko` + +The above command will create a new session named **nadeko** *(you can replace “nadeko” with anything you prefer and remember its your session name)* so you can run the bot in background without having to keep the PuTTY running. + +**Next, we need to run `linuxAIO.sh` in order to get the latest running scripts with patches:** + +- `cd ~ && bash linuxAIO.sh` + +From the options, + +Choose `3` To Run the bot normally. +**NOTE:** With option `3` (Running Normally), if you use `.die` [command](http://nadekobot.readthedocs.io/en/latest/Commands%20List/#administration) in discord. The bot will shut down and will stay offline until you manually run it again. (best if you want to check the bot.) + +Choose `4` To Run the bot with Auto Restart. +**NOTE:** With option `4` (Running with Auto Restart), bot will auto run if you use `.die` [command](http://nadekobot.readthedocs.io/en/latest/Commands%20List/#administration) making the command `.die` to function as restart. + +See how that happens: + +![img9](https://cdn.discordapp.com/attachments/251504306010849280/251506312893038592/die_explaination.gif) + +**Remember** that, while running with Auto Restart, you will need to [close the tmux session](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#restarting-nadeko) to stop the bot completely. + +**Now check your Discord, the bot should be online** + +Next to **move the bot to background** and to do that, press **CTRL+B+D** (this will detach the nadeko session using TMUX), and you can finally close PuTTY now. + +####Restarting Nadeko + +**Restarting Nadeko with the Server:** + +Open **PuTTY** and login as you have before, type `reboot` and hit Enter. + +**Restarting Manually:** + +- Kill your previous session, check with `tmux ls` +- `tmux kill-session -t nadeko` (don't forget to replace "nadeko" to what ever you named your bot's session) +- [Run the bot again.](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#running-nadekobot) + +####Updating Nadeko + +- Connect to the terminal through PuTTY. +- `tmux kill-session -t nadeko` (don't forget to replace **nadeko** in the command with the name of your bot's session) +- Make sure the bot is **not** running. +- `tmux new -s nadeko` (**nadeko** is the name of the session) +- `cd ~ && bash linuxAIO.sh` +- Choose either `1` or `2` to update the bot with **latest build** or **stable build** respectively. +- Choose either `3` or `4` to run the bot again with **normally** or **auto restart** respectively. +- Done. You can close PuTTY now. + +####Installing Manually (Optional) + +#####Installing Git ![img1](https://cdn.discordapp.com/attachments/251504306010849280/251504416019054592/git.gif) @@ -38,14 +193,14 @@ CentOS: **NOTE:** If the command is not being initiated, hit **Enter** -####Installing .NET Core SDK +#####Installing .NET Core SDK ![img2](https://cdn.discordapp.com/attachments/251504306010849280/251504746987388938/dotnet.gif) Go to [this link](https://www.microsoft.com/net/core#ubuntu) (for Ubuntu) or to [this link](https://www.microsoft.com/net/core#linuxcentos) (for CentOS) provided by microsoft for instructions on how to get the most up to date version of the dotnet core sdk! Make sure that you're on the correct page for your distribution of linux as the guides are different for the various distributions -We'll go over the steps here for Ubuntu 16.04 anyway (these will **only** work on Ubuntu 16.04), accurate as of 25/11/2016 +We'll go over the steps here for Ubuntu 16.04 anyway (these will **only** work on Ubuntu 16.04), accurate as of 3/2/2017 ``` sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ xenial main" > /etc/apt/sources.list.d/dotnetdev.list' @@ -55,7 +210,7 @@ sudo apt-get update && sudo apt-get install dotnet-dev-1.0.0-preview2.1-003177 - **NOTE:** .NET CORE SDK only supports 64-bit Linux Operating Systems (Raspberry Pis are not supported because of this) -####Installing Opus Voice Codec and libsodium +#####Installing Opus Voice Codec and libsodium ![img3](https://cdn.discordapp.com/attachments/251504306010849280/251505294654308353/libopus.gif) @@ -67,7 +222,7 @@ CentOS: `yum -y install opus opus-devel` -####Installing FFMPEG +#####Installing FFMPEG ![img4](https://cdn.discordapp.com/attachments/251504306010849280/251505443111829505/ffmpeg.gif) @@ -101,7 +256,7 @@ echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sou sudo apt-get update && sudo apt-get install ffmpeg -y ``` -####Installing TMUX +#####Installing TMUX ![img5](https://cdn.discordapp.com/attachments/251504306010849280/251505519758409728/tmux.gif) @@ -113,33 +268,7 @@ Centos: `yum -y install tmux` -####Getting NadekoBot - -Use the following command to get and run `linuxAIO.sh`: -(Remember **DO NOT** rename the file `linuxAIO.sh`) - -`cd ~ && wget -N https://github.com/Kwoth/NadekoBot-BashScript/raw/master/linuxAIO.sh && bash linuxAIO.sh` - -Follow the on screen instructions: - -1. To Get the latest build. (most recent updates) -2. To Get the stable build. - -Choose either `1` or `2` then press `enter` key. -Once Installation is completed you should see the options again. -Next, choose `5` to exit. - -####Creating and Inviting bot - -- Read here how to [create a DiscordBot application](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#creating-discordbot-application) -- [Visual Invite Guide](http://discord.kongslien.net/guide.html) *NOTE: Client ID is your Bot ID* -- Copy your `Client ID` from your [applications page](https://discordapp.com/developers/applications/me). -- Replace the `12345678` in this link `https://discordapp.com/oauth2/authorize?client_id=12345678&scope=bot&permissions=66186303` with your `Client ID`. -- The link should now look like this: `https://discordapp.com/oauth2/authorize?client_id=**YOUR_CLENT_ID_HERE**&scope=bot&permissions=66186303`. -- Go to the newly created link and pick the server we created, and click `Authorize`. -- The bot should have been added to your server. - -####Guide for Advance Users +####Guide for Advance Users (Optional) **Skip this step if you are a Regular User or New to Linux.** @@ -158,23 +287,23 @@ Next, choose `5` to exit. ####Setting up SFTP -- Open **CyberDuck** -- Click on **Open Connection** (top-left corner), a new window should appear. -- You should see **FTP (File Transfer Protocol)** in drop-down. -- Change it to **SFTP (SSH File Transfer Protocol)** -- Now, in **Server:** paste or type in your `Digital Ocean Droplets IP address`, leave `Port: 22` (no need to change it) +- Open **WinSCP** +- Click on **New Site** (top-left corner). +- On the right-hand side, you should see **File Protocol** above a drop-down selection menu. +- Select **SFTP** *(SSH File Transfer Protocol)* if its not already selected. +- Now, in **Host name:** paste or type in your `Digital Ocean Droplets IP address` and leave `Port: 22` (no need to change it). - In **Username:** type `root` - In **Password:** type `the new root password (you changed at the start)` -- Click on **Connect** -- It should show you the NadekoBot folder which was created by git earlier +- Click on **Login**, it should connect. +- It should show you the NadekoBot folder which was created by git earlier on the right-hand side window. - Open that folder, then open the `src` folder, followed by another `NadekoBot` folder and you should see `credentials.json` there. ####Setting up credentials.json - Copy the `credentials.json` to desktop - EDIT it as it is guided here: [Setting up credentials.json](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-credentialsjson-file) -- Paste/put it back in the folder once done. `(Using CyberDuck/WinSCP)` -- **If** you already have Nadeko 1.0 setup and have `credentials.json` and `NadekoBot.db`, you can just copy and paste the `credentials.json` to `NadekoBot/src/NadekoBot` and `NadekoBot.db` to `NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data` using CyberDuck. +- Paste/put it back in the folder once done. `(Using WinSCP)` +- **If** you already have Nadeko 1.0 setup and have `credentials.json` and `NadekoBot.db`, you can just copy and paste the `credentials.json` to `NadekoBot/src/NadekoBot` and `NadekoBot.db` to `NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data` using WinSCP. - **If** you have Nadeko 0.9x follow the [Upgrading Guide](http://nadekobot.readthedocs.io/en/latest/guides/Upgrading%20Guide/) ####Setting up Music @@ -183,80 +312,18 @@ To set up Nadeko for music and Google API Keys, follow [Setting up NadekoBot for Once done, go back to **PuTTY** -####Running NadekoBot +####Some more Info -**Create a new Session:** - -- `tmux new -s nadeko` - -The above command will create a new session named **nadeko** *(you can replace “nadeko” with anything you prefer and remember its your session name)* so you can run the bot in background without having to keep the PuTTY running. - -**Next, we need to run `linuxAIO.sh` in order to get the latest running scripts with patches:** - -- `cd ~ && bash linuxAIO.sh` - -From the options, - -Choose `3` To Run the bot normally. -**NOTE:** With option `3` (Running Normally), if you use `.die` [command](http://nadekobot.readthedocs.io/en/latest/Commands%20List/#administration) in discord. The bot will shut down and will stay offline until you manually run it again. (best if you want to check the bot.) - -Choose `4` To Run the bot with Auto Restart. -**NOTE:** With option `4` (Running with Auto Restart), bot will auto run if you use `.die` [command](http://nadekobot.readthedocs.io/en/latest/Commands%20List/#administration) making the command `.die` to function as restart. - -See how that happens: - -![img9](https://cdn.discordapp.com/attachments/251504306010849280/251506312893038592/die_explaination.gif) - -**Remember** that, while running with Auto Restart, you will need to [close the tmux session](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#restarting-nadeko) to stop the bot completely. - -**Now check your Discord, the bot should be online** - -Next to **move the bot to background** and to do that, press **CTRL+B+D** (this will detach the nadeko session using TMUX), and you can finally close PuTTY now. - -####Some more Info (just in case) - -**Info about tmux:** +#####Info about tmux - If you want to **see the sessions** after logging back again, type `tmux ls`, and that will give you the list of sessions running. - If you want to **switch to/ see that session**, type `tmux a -t nadeko` (**nadeko** is the name of the session we created before so, replace **“nadeko”** with the session name you created.) - If you want to **kill** NadekoBot **session**, type `tmux kill-session -t nadeko` -**If you are running Ubuntu 16.10, and having trouble installing .NET Core:** - -- Go to [Download Page for libicu55_55.1-7_amd64.deb](http://packages.ubuntu.com/en/xenial/amd64/libicu55/download) -- Copy the link with a download option closest to you -- `wget ` *e.g.* `wget http://mirrors.kernel.org/ubuntu/pool/main/i/icu/libicu55_55.1-7_amd64.deb` (make sure it is downloaded) -- Install with: `dpkg –i libicu55_55.1-7_amd64.deb` -- Now go back and install the .NET Core - -####Restarting Nadeko - -**Restarting Nadeko with the Server:** - -Open **PuTTY** and login as you have before, type `reboot` and hit Enter. - -**Restarting Manually:** - -- Kill your previous session, check with `tmux ls` -- `tmux kill-session -t nadeko` (don't forget to replace "nadeko" to what ever you named your bot's session) -- [Run the bot again.](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#running-nadekobot) - -####Updating Nadeko - -- Connect to the terminal through PuTTY. -- `tmux kill-session -t nadeko` (don't forget to replace **nadeko** in the command with the name of your bot's session) -- Make sure the bot is **not** running. -- `tmux new -s nadeko` (**nadeko** is the name of the session) -- `cd ~ && bash linuxAIO.sh` -- Choose either `1` or `2` to update the bot with **latest build** or **stable build** respectively. -- Choose either `3` or `4` to run the bot again with **normally** or **auto restart** respectively. -- Done. You can close PuTTY now. - -####Alternative way to Install +#####Alternative way to Install If the [Nadeko installer](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#getting-nadekobot) shows any kind error, check if you have the `linuxAIO.sh` file and make sure its not renamed or if you want to manually install the bot. Use the following command(s): - ![img6](https://cdn.discordapp.com/attachments/251504306010849280/251505587089571850/getting_nadeko.gif) `cd ~ && curl -L https://github.com/Kwoth/NadekoBot-BashScript/raw/master/nadeko_installer.sh | sh` @@ -264,7 +331,7 @@ If the [Nadeko installer](http://nadekobot.readthedocs.io/en/latest/guides/Linux **OR** ``` -cd ~ && git clone -b 1.0 --recursive --depth 1 https://github.com/Kwoth/NadekoBot.git +cd ~ && git clone -b dev --recursive --depth 1 https://github.com/Kwoth/NadekoBot.git cd ~/NadekoBot/discord.net/src/Discord.Net && dotnet restore && cd ../Discord.Net.Commands && dotnet restore && cd ../../../src/NadekoBot/ && dotnet restore && dotnet build --configuration Release ``` From a9ab99a29bd38105362df914ad3861f72c83ae54 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 2 Feb 2017 03:21:02 +0100 Subject: [PATCH 147/746] Compile error --- .../Modules/Administration/Commands/SelfCommands.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index 13817a65..a56ee402 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -184,6 +184,14 @@ namespace NadekoBot.Modules.Administration return UserStatus.Online; } + + public enum SettableUserStatus + { + Online, + Invisible, + Idle, + Dnd + } } } } From 258b90e48278ac68de8e51dd54644f4027292b4d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 2 Feb 2017 03:21:32 +0100 Subject: [PATCH 148/746] upped version --- 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 ab72769d..d8995c59 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.5a"; + public const string BotVersion = "1.1.6"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From aef7302513030c6e09eee663d9029597284294d8 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 2 Feb 2017 04:55:51 +0100 Subject: [PATCH 149/746] log for public bot --- Discord.Net | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Discord.Net b/Discord.Net index b57d5d73..979eecab 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit b57d5d738921021f6e366ab6b4eb13cd0501959d +Subproject commit 979eecabfe0654db0be27cba71ecb398848f2c0c From e7fcac3c8fd9374c13644387f365e54a3d0b92de Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 2 Feb 2017 04:58:39 +0100 Subject: [PATCH 150/746] gelbooru and danbooru back on public bot --- src/NadekoBot/Modules/NSFW/NSFW.cs | 43 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index 266ffa68..cd87454a 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -140,24 +140,6 @@ namespace NadekoBot.Modules.NSFW } } - - [NadekoCommand, Usage, Description, Aliases] - public async Task Danbooru([Remainder] string tag = null) - { - tag = tag?.Trim() ?? ""; - - var url = await GetDanbooruImageLink(tag).ConfigureAwait(false); - - if (url == null) - await Context.Channel.SendErrorAsync(Context.User.Mention + " No results.").ConfigureAwait(false); - else - await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithDescription(Context.User.Mention + " " + tag) - .WithImageUrl(url) - .WithFooter(efb => efb.WithText("Danbooru"))) - .ConfigureAwait(false); - } - [NadekoCommand, Usage, Description, Aliases] public Task Yandere([Remainder] string tag = null) => Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Yandere); @@ -166,10 +148,6 @@ namespace NadekoBot.Modules.NSFW public Task Konachan([Remainder] string tag = null) => Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Konachan); - [NadekoCommand, Usage, Description, Aliases] - public Task Gelbooru([Remainder] string tag = null) - => Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Gelbooru); - [NadekoCommand, Usage, Description, Aliases] public Task Rule34([Remainder] string tag = null) => Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Rule34); @@ -191,6 +169,27 @@ namespace NadekoBot.Modules.NSFW .ConfigureAwait(false); } #endif + [NadekoCommand, Usage, Description, Aliases] + public async Task Danbooru([Remainder] string tag = null) + { + tag = tag?.Trim() ?? ""; + + var url = await GetDanbooruImageLink(tag).ConfigureAwait(false); + + if (url == null) + await Context.Channel.SendErrorAsync(Context.User.Mention + " No results.").ConfigureAwait(false); + else + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithDescription(Context.User.Mention + " " + tag) + .WithImageUrl(url) + .WithFooter(efb => efb.WithText("Danbooru"))) + .ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + public Task Gelbooru([Remainder] string tag = null) + => Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Gelbooru); + [NadekoCommand, Usage, Description, Aliases] public async Task Cp() { From 3488eb8152ea136f7d9bc5141f98b8e21f6f7517 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 2 Feb 2017 05:02:37 +0100 Subject: [PATCH 151/746] compile error --- src/NadekoBot/Modules/NSFW/NSFW.cs | 43 +++++++++++++++--------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index cd87454a..9698379a 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -186,6 +186,28 @@ namespace NadekoBot.Modules.NSFW .ConfigureAwait(false); } + public static Task GetDanbooruImageLink(string tag) => Task.Run(async () => + { + try + { + using (var http = new HttpClient()) + { + http.AddFakeHeaders(); + var data = await http.GetStreamAsync("https://danbooru.donmai.us/posts.xml?limit=100&tags=" + tag).ConfigureAwait(false); + var doc = new XmlDocument(); + doc.Load(data); + var nodes = doc.GetElementsByTagName("file-url"); + + var node = nodes[new NadekoRandom().Next(0, nodes.Count)]; + return "https://danbooru.donmai.us" + node.InnerText; + } + } + catch + { + return null; + } + }); + [NadekoCommand, Usage, Description, Aliases] public Task Gelbooru([Remainder] string tag = null) => Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Gelbooru); @@ -232,27 +254,6 @@ namespace NadekoBot.Modules.NSFW } } #if !GLOBAL_NADEKO - public static Task GetDanbooruImageLink(string tag) => Task.Run(async () => - { - try - { - using (var http = new HttpClient()) - { - http.AddFakeHeaders(); - var data = await http.GetStreamAsync("https://danbooru.donmai.us/posts.xml?limit=100&tags=" + tag).ConfigureAwait(false); - var doc = new XmlDocument(); - doc.Load(data); - var nodes = doc.GetElementsByTagName("file-url"); - - var node = nodes[new NadekoRandom().Next(0, nodes.Count)]; - return "https://danbooru.donmai.us" + node.InnerText; - } - } - catch - { - return null; - } - }); public static Task GetE621ImageLink(string tag) => Task.Run(async () => From a0e23b4c2cf0a0552eed78447d729eaaabd11c7a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 2 Feb 2017 05:08:28 +0100 Subject: [PATCH 152/746] Fixed public bot connection logging --- Discord.Net | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Discord.Net b/Discord.Net index 979eecab..0fd1e70a 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit 979eecabfe0654db0be27cba71ecb398848f2c0c +Subproject commit 0fd1e70a22612ff9fa697dace96f22780080b01f From dfbabea8b904ec980f9277e57dcc8096123170ea Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 2 Feb 2017 14:16:28 +0100 Subject: [PATCH 153/746] performance improvements? --- .../Modules/Administration/Administration.cs | 28 ++-- src/NadekoBot/Services/CommandHandler.cs | 137 +++++++++--------- 2 files changed, 87 insertions(+), 78 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 45e99b8e..cf92fb4b 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -38,20 +38,24 @@ namespace NadekoBot.Modules.Administration } - private static async Task DelMsgOnCmd_Handler(SocketUserMessage msg, CommandInfo cmd) + private static Task DelMsgOnCmd_Handler(SocketUserMessage msg, CommandInfo cmd) { - try + var _ = Task.Run(async () => { - var channel = msg.Channel as SocketTextChannel; - if (channel == null) - return; - if (DeleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune") - await msg.DeleteAsync().ConfigureAwait(false); - } - catch (Exception ex) - { - _log.Warn(ex, "Delmsgoncmd errored..."); - } + try + { + var channel = msg.Channel as SocketTextChannel; + if (channel == null) + return; + if (DeleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune") + await msg.DeleteAsync().ConfigureAwait(false); + } + catch (Exception ex) + { + _log.Warn(ex, "Delmsgoncmd errored..."); + } + }); + return Task.CompletedTask; } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 09080f12..8cc68001 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -105,9 +105,8 @@ namespace NadekoBot.Services BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id); const float oneThousandth = 1.0f / 1000; - private async Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int ticks) + private Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int ticks) { - await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false); _log.Info("Command Executed after {4}s\n\t" + "User: {0}\n\t" + "Server: {1}\n\t" + @@ -118,6 +117,7 @@ namespace NadekoBot.Services (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2} usrMsg.Content, // {3} ticks * oneThousandth); + return Task.CompletedTask; } private void LogErroredExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int ticks) @@ -184,93 +184,98 @@ namespace NadekoBot.Services return false; } - private async Task MessageReceivedHandler(SocketMessage msg) + private Task MessageReceivedHandler(SocketMessage msg) { - try + var _ = Task.Run(async () => { - if (msg.Author.IsBot || !NadekoBot.Ready) //no bots, wait until bot connected and initialized - return; + try + { + if (msg.Author.IsBot || !NadekoBot.Ready) //no bots, wait until bot connected and initialized + return; - var execTime = Environment.TickCount; + var execTime = Environment.TickCount; - var usrMsg = msg as SocketUserMessage; - if (usrMsg == null) //has to be an user message, not system/other messages. - return; + var usrMsg = msg as SocketUserMessage; + 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); + // 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; + var channel = msg.Channel as SocketTextChannel; + var guild = channel?.Guild; - if (guild != null && guild.OwnerId != msg.Author.Id) - { - if (await InviteFiltered(guild, usrMsg).ConfigureAwait(false)) + if (guild != null && guild.OwnerId != msg.Author.Id) + { + if (await InviteFiltered(guild, usrMsg).ConfigureAwait(false)) + return; + + if (await WordFiltered(guild, usrMsg).ConfigureAwait(false)) + return; + } + + if (IsBlacklisted(guild, usrMsg)) return; - if (await WordFiltered(guild, usrMsg).ConfigureAwait(false)) + var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false); + if (cleverBotRan) return; - } - if (IsBlacklisted(guild, usrMsg)) - return; + // maybe this message is a custom reaction + // todo log custom reaction executions. return struct with info + var crExecuted = await Task.Run(() => CustomReactions.TryExecuteCustomReaction(usrMsg)).ConfigureAwait(false); + if (crExecuted) //if it was, don't execute the command + return; - var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false); - if (cleverBotRan) - return; + string messageContent = usrMsg.Content; - // maybe this message is a custom reaction - // todo log custom reaction executions. return struct with info - var crExecuted = await Task.Run(() => CustomReactions.TryExecuteCustomReaction(usrMsg)).ConfigureAwait(false); - if (crExecuted) //if it was, don't execute the command - return; + // execute the command and measure the time it took + var exec = await Task.Run(() => ExecuteCommand(new CommandContext(_client, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best)).ConfigureAwait(false); + execTime = Environment.TickCount - execTime; - string messageContent = usrMsg.Content; - - // execute the command and measure the time it took - 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) - { - await LogSuccessfulExecution(usrMsg, exec, channel, execTime).ConfigureAwait(false); - } - else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand) - { - LogErroredExecution(usrMsg, exec, channel, execTime); - if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception) + if (exec.Result.IsSuccess) { - if (exec.PermissionCache != null && exec.PermissionCache.Verbose) - try { await msg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { } + await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false); + await LogSuccessfulExecution(usrMsg, exec, channel, execTime).ConfigureAwait(false); + } + else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand) + { + LogErroredExecution(usrMsg, exec, channel, execTime); + if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception) + { + if (exec.PermissionCache != null && exec.PermissionCache.Verbose) + try { await msg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { } + } + } + else + { + if (msg.Channel is IPrivateChannel) + { + // rofl, gotta do this to prevent dm help message being sent to + // users who are voting on private polls (sending a number in a DM) + int vote; + if (int.TryParse(msg.Content, out vote)) return; + + await msg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false); + + await DMForwardCommands.HandleDMForwarding(msg, ownerChannels).ConfigureAwait(false); + } } } - else + catch (Exception ex) { - if (msg.Channel is IPrivateChannel) + _log.Warn("Error in CommandHandler"); + _log.Warn(ex); + if (ex.InnerException != null) { - // rofl, gotta do this to prevent dm help message being sent to - // users who are voting on private polls (sending a number in a DM) - int vote; - if (int.TryParse(msg.Content, out vote)) return; - - await msg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false); - - await DMForwardCommands.HandleDMForwarding(msg, ownerChannels).ConfigureAwait(false); + _log.Warn("Inner Exception of the error in CommandHandler"); + _log.Warn(ex.InnerException); } } - } - catch (Exception ex) - { - _log.Warn("Error in CommandHandler"); - _log.Warn(ex); - if (ex.InnerException != null) - { - _log.Warn("Inner Exception of the error in CommandHandler"); - _log.Warn(ex.InnerException); - } - } + }); + return Task.CompletedTask; } public Task ExecuteCommandAsync(CommandContext context, int argPos, IDependencyMap dependencyMap = null, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception) From 0728486f3e68a49aee68c0a7ed93bdd5ffe31a6d Mon Sep 17 00:00:00 2001 From: samvaio Date: Thu, 2 Feb 2017 21:57:46 +0530 Subject: [PATCH 154/746] fixed typo :/ --- docs/guides/Linux Guide.md | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/docs/guides/Linux Guide.md b/docs/guides/Linux Guide.md index b14351bc..8a6cab9f 100644 --- a/docs/guides/Linux Guide.md +++ b/docs/guides/Linux Guide.md @@ -56,7 +56,7 @@ You should see these following options after using the above command: 7. To exit ``` #####Part II -**If** you are running NadekoBot for the first time on your system and never had any *prerequisites* installed, Press `5` and press `enter` key, then `y` when you see the following: +**If** you are running NadekoBot for the first time on your system and never had any *prerequisites* installed, Press `5` and `enter` key, then `y` when you see the following: ``` Welcome to NadekoBot Auto Prerequisites Installer. Would you like to continue? @@ -97,18 +97,19 @@ You will need the following for the next step: Once you have acquired them, press `6` to **Set up credentials.json** -You will be asked to enter the required informations, just follow the on-screen instructions and enter whats asked. -*i.e* If you are asked **Bot's Token**, then just copy and paste the `token` and press `enter` key. +You will be asked to enter the required informations, just follow the on-screen instructions and enter the required information. +*i.e* If you are asked **Bot's Token**, then just copy and paste or type the **Bot's Token** and press `enter` key. -If you want to skip any optional informations, just press `enter` key without typing/pasting anything. +(If you want to skip any optional infos, just press `enter` key without typing/pasting anything.) Once done, #####Part V -You should see the options again within the **tmux session** named *nadako*. +You should see the options again within the **`tmux` session** named `nadeko` *(remember this one)* Next, press `3` to **Run Nadeko (Normally)** Check in your discord server if your new bot is working properly. #####Part VI -If the bot is working properly in your server, type `.die` to shut down the bot. -You should be back to the options again, +If your bot is working properly in your server, type `.die` to shut down the bot. + +You should be back to the options screen again on **PuTTY**, from the options choose `4` to **Run Nadeko with Auto Restart.** It will show you more options: @@ -118,11 +119,12 @@ It will show you more options: 3. Auto Restart and Update with Stable Build 4. Exit ``` -Choose anything you like and once the bot's back online again in your server, close the **PuTTY**. -Done, You now have your own **NadekoBot**. +Choose anything you like and once the bot's back online again in your server, close the **PuTTY**. + +**Done**, You now have your own **NadekoBot**. -[To **Restart** your **NadekoBot** anytime later.](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#restarting-nadeko) +[Check this when you need to **restart** your **NadekoBot** anytime later along with tmux session.](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#restarting-nadeko) ####Running NadekoBot @@ -156,6 +158,11 @@ Next to **move the bot to background** and to do that, press **CTRL+B+D** (this ####Restarting Nadeko +**Restarting NadekoBot:** + +**If** you have chosen option `4` to **Run Nadeko with Auto Restart** from Nadeko's `linuxAIO.sh` *[(you got it from this step)](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#getting-nadekobot)* +You can simply type `.die` in the server you have your NadekoBot to make her restart. + **Restarting Nadeko with the Server:** Open **PuTTY** and login as you have before, type `reboot` and hit Enter. @@ -168,14 +175,14 @@ Open **PuTTY** and login as you have before, type `reboot` and hit Enter. ####Updating Nadeko -- Connect to the terminal through PuTTY. +- Connect to the terminal through **PuTTY**. - `tmux kill-session -t nadeko` (don't forget to replace **nadeko** in the command with the name of your bot's session) - Make sure the bot is **not** running. - `tmux new -s nadeko` (**nadeko** is the name of the session) - `cd ~ && bash linuxAIO.sh` - Choose either `1` or `2` to update the bot with **latest build** or **stable build** respectively. - Choose either `3` or `4` to run the bot again with **normally** or **auto restart** respectively. -- Done. You can close PuTTY now. +- Done. You can close **PuTTY** now. ####Installing Manually (Optional) From e3b6c8dffb8c003287f135f752c5d242c773068b Mon Sep 17 00:00:00 2001 From: samvaio Date: Thu, 2 Feb 2017 22:15:06 +0530 Subject: [PATCH 155/746] added lil more info --- docs/guides/Linux Guide.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guides/Linux Guide.md b/docs/guides/Linux Guide.md index 8a6cab9f..8e01383e 100644 --- a/docs/guides/Linux Guide.md +++ b/docs/guides/Linux Guide.md @@ -55,7 +55,7 @@ You should see these following options after using the above command: 6. Set up credentials.json (if you have downloaded the bot already) 7. To exit ``` -#####Part II +#####Part II (Optional) **If** you are running NadekoBot for the first time on your system and never had any *prerequisites* installed, Press `5` and `enter` key, then `y` when you see the following: ``` Welcome to NadekoBot Auto Prerequisites Installer. @@ -76,8 +76,8 @@ and then press `enter` key. Once Installation is completed you should see the options again. Next, check out: -#####Part IV -If you prefer to do this step [manually](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#setting-up-sftp), and skip other parts click on the link. *(Optional)* +#####Part IV (Optional) +If you prefer to skip this step and want to do it [manually](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#setting-up-sftp) or already have the `credentials.json` file, click on the link. *(Optional)* - [1. Setting up credentials.json](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#setting-up-credentialsjson) - [2. To Get the Google API](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-nadekobot-for-music) From 9791b5b9e367311ad719671b78da1380ed27755b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 2 Feb 2017 21:00:38 +0100 Subject: [PATCH 156/746] v+t slower but much better and reliable. Need to check ratelimits before speeding it up. --- .../Commands/ProtectionCommands.cs | 109 ++++++----- .../Commands/VoicePlusTextCommands.cs | 182 ++++++++++++------ src/NadekoBot/NadekoBot.cs | 2 +- 3 files changed, 185 insertions(+), 108 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs index e37f4850..3e3b217a 100644 --- a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs @@ -105,74 +105,85 @@ namespace NadekoBot.Modules.Administration antiSpamGuilds.TryAdd(gc.GuildId, new AntiSpamStats() { AntiSpamSettings = spam }); } - NadekoBot.Client.MessageReceived += async (imsg) => + NadekoBot.Client.MessageReceived += (imsg) => { + var msg = imsg as IUserMessage; + if (msg == null || msg.Author.IsBot) + return Task.CompletedTask; - try + var channel = msg.Channel as ITextChannel; + if (channel == null) + return Task.CompletedTask; + var _ = Task.Run(async () => { - var msg = imsg as IUserMessage; - if (msg == null || msg.Author.IsBot) - return; - - var channel = msg.Channel as ITextChannel; - if (channel == null) - return; - AntiSpamStats spamSettings; - if (!antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings) || - spamSettings.AntiSpamSettings.IgnoredChannels.Contains(new AntiSpamIgnore() - { - ChannelId = channel.Id - })) - return; - - var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, new UserSpamStats(msg.Content), - (id, old) => { old.ApplyNextMessage(msg.Content); return old; }); - - if (stats.Count >= spamSettings.AntiSpamSettings.MessageThreshold) + try { - if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats)) + AntiSpamStats spamSettings; + if (!antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings) || + spamSettings.AntiSpamSettings.IgnoredChannels.Contains(new AntiSpamIgnore() + { + ChannelId = channel.Id + })) + return; + + var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, new UserSpamStats(msg.Content), + (id, old) => + { + old.ApplyNextMessage(msg.Content); return old; + }); + + if (stats.Count >= spamSettings.AntiSpamSettings.MessageThreshold) { - await PunishUsers(spamSettings.AntiSpamSettings.Action, ProtectionType.Spamming, (IGuildUser)msg.Author) - .ConfigureAwait(false); + if (spamSettings.UserStats.TryRemove(msg.Author.Id, out stats)) + { + await PunishUsers(spamSettings.AntiSpamSettings.Action, ProtectionType.Spamming, (IGuildUser)msg.Author) + .ConfigureAwait(false); + } } } - } - catch { } + catch { } + }); + return Task.CompletedTask; }; - NadekoBot.Client.UserJoined += async (usr) => + NadekoBot.Client.UserJoined += (usr) => { - try + if (usr.IsBot) + return Task.CompletedTask; + AntiRaidStats settings; + if (!antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings)) + return Task.CompletedTask; + if (!settings.RaidUsers.Add(usr)) + return Task.CompletedTask; + + var _ = Task.Run(async () => { - if (usr.IsBot) - return; - AntiRaidStats settings; - if (!antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings)) - return; - if (!settings.RaidUsers.Add(usr)) - return; - - ++settings.UsersCount; - - if (settings.UsersCount >= settings.AntiRaidSettings.UserThreshold) + try { - var users = settings.RaidUsers.ToArray(); - settings.RaidUsers.Clear(); + ++settings.UsersCount; + + if (settings.UsersCount >= settings.AntiRaidSettings.UserThreshold) + { + var users = settings.RaidUsers.ToArray(); + settings.RaidUsers.Clear(); + + await PunishUsers(settings.AntiRaidSettings.Action, ProtectionType.Raiding, users).ConfigureAwait(false); + } + await Task.Delay(1000 * settings.AntiRaidSettings.Seconds).ConfigureAwait(false); + + settings.RaidUsers.TryRemove(usr); + --settings.UsersCount; - await PunishUsers(settings.AntiRaidSettings.Action, ProtectionType.Raiding, users).ConfigureAwait(false); } - await Task.Delay(1000 * settings.AntiRaidSettings.Seconds).ConfigureAwait(false); - - settings.RaidUsers.TryRemove(usr); - --settings.UsersCount; - - } - catch { } + catch { } + }); + return Task.CompletedTask; }; } private static async Task PunishUsers(PunishmentAction action, ProtectionType pt, params IGuildUser[] gus) { + _log.Warn($"[{pt}] - Punishing [{gus.Length}] users with [{action}] in {gus[0].Guild.Name} guild"); foreach (var gu in gus) { switch (action) diff --git a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs index 9d92ff98..3b68f36f 100644 --- a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs @@ -7,9 +7,11 @@ using NadekoBot.Services; using NLog; using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; namespace NadekoBot.Modules.Administration @@ -22,6 +24,8 @@ namespace NadekoBot.Modules.Administration private static Regex channelNameRegex = new Regex(@"[^a-zA-Z0-9 -]", RegexOptions.Compiled); private static ConcurrentHashSet voicePlusTextCache { get; } + + private static ConcurrentDictionary guildLockObjects = new ConcurrentDictionary(); static VoicePlusTextCommands() { var _log = LogManager.GetCurrentClassLogger(); @@ -36,78 +40,119 @@ namespace NadekoBot.Modules.Administration _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); } - private static async Task UserUpdatedEventHandler(SocketUser iuser, SocketVoiceState before, SocketVoiceState after) + private static Task UserUpdatedEventHandler(SocketUser iuser, SocketVoiceState before, SocketVoiceState after) { var user = (iuser as SocketGuildUser); var guild = user?.Guild; if (guild == null) - return; + return Task.CompletedTask; - try + var botUserPerms = guild.CurrentUser.GuildPermissions; + + if (before.VoiceChannel == after.VoiceChannel) + return Task.CompletedTask; + + if (!voicePlusTextCache.Contains(guild.Id)) + return Task.CompletedTask; + + var _ = Task.Run(async () => { - var botUserPerms = guild.CurrentUser.GuildPermissions; - - if (before.VoiceChannel == after.VoiceChannel) return; - - if (!voicePlusTextCache.Contains(guild.Id)) - return; - - if (!botUserPerms.ManageChannels || !botUserPerms.ManageRoles) + try { + + if (!botUserPerms.ManageChannels || !botUserPerms.ManageRoles) + { + try + { + await guild.Owner.SendErrorAsync( + "⚠️ I don't have **manage server** and/or **manage channels** permission," + + $" so I cannot run `voice+text` on **{guild.Name}** server.").ConfigureAwait(false); + } + catch { } + using (var uow = DbHandler.UnitOfWork()) + { + uow.GuildConfigs.For(guild.Id, set => set).VoicePlusTextEnabled = false; + voicePlusTextCache.TryRemove(guild.Id); + await uow.CompleteAsync().ConfigureAwait(false); + } + return; + } + + var semaphore = guildLockObjects.GetOrAdd(guild.Id, (key) => new SemaphoreSlim(1, 1)); + try { - await guild.Owner.SendErrorAsync( - "⚠️ I don't have **manage server** and/or **manage channels** permission," + - $" so I cannot run `voice+text` on **{guild.Name}** server.").ConfigureAwait(false); - } - catch { } - using (var uow = DbHandler.UnitOfWork()) - { - uow.GuildConfigs.For(guild.Id, set => set).VoicePlusTextEnabled = false; - voicePlusTextCache.TryRemove(guild.Id); - await uow.CompleteAsync().ConfigureAwait(false); - } - return; - } + await semaphore.WaitAsync().ConfigureAwait(false); + var beforeVch = before.VoiceChannel; + if (beforeVch != null) + { + var beforeRoleName = GetRoleName(beforeVch); + var beforeRole = guild.Roles.FirstOrDefault(x => x.Name == beforeRoleName); + if (beforeRole != null) + try + { + _log.Warn("Removing role " + beforeRoleName + " from user " + user.Username); + await user.RemoveRolesAsync(beforeRole).ConfigureAwait(false); + await Task.Delay(200).ConfigureAwait(false); + } + catch (Exception ex) + { + _log.Warn(ex); + } + } + var afterVch = after.VoiceChannel; + if (afterVch != null && guild.AFKChannel?.Id != afterVch.Id) + { + var roleName = GetRoleName(afterVch); + IRole roleToAdd = guild.Roles.FirstOrDefault(x => x.Name == roleName); + if (roleToAdd == null) + roleToAdd = await guild.CreateRoleAsync(roleName).ConfigureAwait(false); - var beforeVch = before.VoiceChannel; - if (beforeVch != null) - { - var textChannel = guild.TextChannels.Where(t => t.Name == GetChannelName(beforeVch.Name).ToLowerInvariant()).FirstOrDefault(); - if (textChannel != null) - await textChannel.AddPermissionOverwriteAsync(user, - new OverwritePermissions(readMessages: PermValue.Deny, - sendMessages: PermValue.Deny)).ConfigureAwait(false); - } - var afterVch = after.VoiceChannel; - if (afterVch != null && guild.AFKChannel?.Id != afterVch.Id) - { - ITextChannel textChannel = guild.TextChannels - .Where(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant()) - .FirstOrDefault(); - if (textChannel == null) - { - textChannel = (await guild.CreateTextChannelAsync(GetChannelName(afterVch.Name).ToLowerInvariant()).ConfigureAwait(false)); - await textChannel.AddPermissionOverwriteAsync(guild.EveryoneRole, - new OverwritePermissions(readMessages: PermValue.Deny, - sendMessages: PermValue.Deny)).ConfigureAwait(false); + ITextChannel textChannel = guild.TextChannels + .Where(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant()) + .FirstOrDefault(); + if (textChannel == null) + { + var created = (await guild.CreateTextChannelAsync(GetChannelName(afterVch.Name).ToLowerInvariant()).ConfigureAwait(false)); + + try { await guild.CurrentUser.AddRolesAsync(roleToAdd).ConfigureAwait(false); } catch { } + await Task.Delay(50).ConfigureAwait(false); + await created.AddPermissionOverwriteAsync(roleToAdd, new OverwritePermissions( + readMessages: PermValue.Allow, + sendMessages: PermValue.Allow)) + .ConfigureAwait(false); + await Task.Delay(50).ConfigureAwait(false); + await created.AddPermissionOverwriteAsync(guild.EveryoneRole, new OverwritePermissions( + readMessages: PermValue.Deny, + sendMessages: PermValue.Deny)) + .ConfigureAwait(false); + await Task.Delay(50).ConfigureAwait(false); + } + _log.Warn("Adding role " + roleToAdd.Name + " to user " + user.Username); + await user.AddRolesAsync(roleToAdd).ConfigureAwait(false); + } + } + finally + { + semaphore.Release(); } - await textChannel.AddPermissionOverwriteAsync(user, - new OverwritePermissions(readMessages: PermValue.Allow, - sendMessages: PermValue.Allow)).ConfigureAwait(false); } - } - catch (Exception ex) - { - Console.WriteLine(ex); - } + catch (Exception ex) + { + _log.Warn(ex); + } + }); + return Task.CompletedTask; } private static string GetChannelName(string voiceName) => channelNameRegex.Replace(voiceName, "").Trim().Replace(" ", "-").TrimTo(90, true) + "-voice"; + private static string GetRoleName(IVoiceChannel ch) => + "nvoice-" + ch.Id; + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageRoles)] @@ -127,7 +172,7 @@ namespace NadekoBot.Modules.Administration { try { - await Context.Channel.SendErrorAsync("⚠️ You are enabling this feature and **I do not have ADMINISTRATOR permissions**. " + + await Context.Channel.SendErrorAsync("⚠️ You are enabling/disabling this feature and **I do not have ADMINISTRATOR permissions**. " + "`This may cause some issues, and you will have to clean up text channels yourself afterwards.`"); } catch { } @@ -147,6 +192,13 @@ namespace NadekoBot.Modules.Administration foreach (var textChannel in (await guild.GetTextChannelsAsync().ConfigureAwait(false)).Where(c => c.Name.EndsWith("-voice"))) { try { await textChannel.DeleteAsync().ConfigureAwait(false); } catch { } + await Task.Delay(500).ConfigureAwait(false); + } + + foreach (var role in guild.Roles.Where(c => c.Name.StartsWith("nvoice-"))) + { + try { await role.DeleteAsync().ConfigureAwait(false); } catch { } + await Task.Delay(500).ConfigureAwait(false); } await Context.Channel.SendConfirmAsync("ℹ️ Successfuly **removed** voice + text feature.").ConfigureAwait(false); return; @@ -163,7 +215,9 @@ namespace NadekoBot.Modules.Administration [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageChannels)] + [RequireBotPermission(GuildPermission.ManageChannels)] [RequireUserPermission(GuildPermission.ManageRoles)] + //[RequireBotPermission(GuildPermission.ManageRoles)] public async Task CleanVPlusT() { var guild = Context.Guild; @@ -174,15 +228,27 @@ namespace NadekoBot.Modules.Administration return; } - var allTxtChannels = (await guild.GetTextChannelsAsync()).Where(c => c.Name.EndsWith("-voice")); - var validTxtChannelNames = (await guild.GetVoiceChannelsAsync()).Select(c => GetChannelName(c.Name).ToLowerInvariant()); + var textChannels = await guild.GetTextChannelsAsync().ConfigureAwait(false); + var voiceChannels = await guild.GetVoiceChannelsAsync().ConfigureAwait(false); - var invalidTxtChannels = allTxtChannels.Where(c => !validTxtChannelNames.Contains(c.Name)); + var boundTextChannels = textChannels.Where(c => c.Name.EndsWith("-voice")); + var validTxtChannelNames = new HashSet(voiceChannels.Select(c => GetChannelName(c.Name).ToLowerInvariant())); + var invalidTxtChannels = boundTextChannels.Where(c => !validTxtChannelNames.Contains(c.Name)); foreach (var c in invalidTxtChannels) { try { await c.DeleteAsync().ConfigureAwait(false); } catch { } - await Task.Delay(500); + await Task.Delay(500).ConfigureAwait(false); + } + + var boundRoles = guild.Roles.Where(r => r.Name.StartsWith("nvoice-")); + var validRoleNames = new HashSet(voiceChannels.Select(c => GetRoleName(c).ToLowerInvariant())); + var invalidRoles = boundRoles.Where(r => !validRoleNames.Contains(r.Name)); + + foreach (var r in invalidRoles) + { + try { await r.DeleteAsync().ConfigureAwait(false); } catch { } + await Task.Delay(500).ConfigureAwait(false); } await Context.Channel.SendConfirmAsync("Cleaned v+t.").ConfigureAwait(false); diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index a6842797..ba411cea 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -113,7 +113,7 @@ namespace NadekoBot await CommandHandler.StartHandling().ConfigureAwait(false); - await CommandService.AddModulesAsync(this.GetType().GetTypeInfo().Assembly).ConfigureAwait(false); + var _ = await Task.Run(() => CommandService.AddModulesAsync(this.GetType().GetTypeInfo().Assembly)).ConfigureAwait(false); #if !GLOBAL_NADEKO await CommandService.AddModuleAsync().ConfigureAwait(false); #endif From 4a3d66e712505aaf2417459d992e33dfb7b0b1ca Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 2 Feb 2017 21:59:01 +0100 Subject: [PATCH 157/746] Images service. Preloads images bot uses. Holds heads and tails images only for now. --- .../Gambling/Commands/FlipCoinCommand.cs | 30 +++++++----- src/NadekoBot/NadekoBot.cs | 5 ++ src/NadekoBot/Services/IImagesService.cs | 17 +++++++ src/NadekoBot/Services/Impl/ImagesService.cs | 46 +++++++++++++++++++ 4 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 src/NadekoBot/Services/IImagesService.cs create mode 100644 src/NadekoBot/Services/Impl/ImagesService.cs diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs index 85092dc7..74e201c0 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs @@ -16,32 +16,38 @@ namespace NadekoBot.Modules.Gambling [Group] public class FlipCoinCommands : ModuleBase { + private readonly IImagesService _images; + private static NadekoRandom rng { get; } = new NadekoRandom(); - private const string headsPath = "data/images/coins/heads.png"; - private const string tailsPath = "data/images/coins/tails.png"; - + + public FlipCoinCommands() + { + //todo DI in the future, can't atm + this._images = NadekoBot.Images; + } + [NadekoCommand, Usage, Description, Aliases] public async Task Flip(int count = 1) { if (count == 1) { if (rng.Next(0, 2) == 1) - await Context.Channel.SendFileAsync(File.Open(headsPath, FileMode.OpenOrCreate), "heads.jpg", $"{Context.User.Mention} flipped " + Format.Code("Heads") + ".").ConfigureAwait(false); + await Context.Channel.SendFileAsync(_images.Heads, "heads.jpg", $"{Context.User.Mention} flipped " + Format.Code("Heads") + ".").ConfigureAwait(false); else - await Context.Channel.SendFileAsync(File.Open(tailsPath, FileMode.OpenOrCreate), "tails.jpg", $"{Context.User.Mention} flipped " + Format.Code("Tails") + ".").ConfigureAwait(false); + await Context.Channel.SendFileAsync(_images.Tails, "tails.jpg", $"{Context.User.Mention} flipped " + Format.Code("Tails") + ".").ConfigureAwait(false); return; } if (count > 10 || count < 1) { - await Context.Channel.SendErrorAsync("`Invalid number specified. You can flip 1 to 10 coins.`"); + await Context.Channel.SendErrorAsync("`Invalid number specified. You can flip 1 to 10 coins.`").ConfigureAwait(false); return; } var imgs = new Image[count]; for (var i = 0; i < count; i++) { imgs[i] = rng.Next(0, 10) < 5 ? - new Image(File.OpenRead(headsPath)) : - new Image(File.OpenRead(tailsPath)); + new Image(_images.Heads) : + new Image(_images.Tails); } await Context.Channel.SendFileAsync(imgs.Merge().ToStream(), $"{count} coins.png").ConfigureAwait(false); } @@ -70,15 +76,15 @@ namespace NadekoBot.Modules.Gambling var isHeads = guessStr == "HEADS" || guessStr == "H"; bool result = false; - string imgPathToSend; + Stream imageToSend; if (rng.Next(0, 2) == 1) { - imgPathToSend = headsPath; + imageToSend = _images.Heads; result = true; } else { - imgPathToSend = tailsPath; + imageToSend = _images.Tails; } string str; @@ -93,7 +99,7 @@ namespace NadekoBot.Modules.Gambling str = $"{Context.User.Mention}`Better luck next time.`"; } - await Context.Channel.SendFileAsync(File.Open(imgPathToSend, FileMode.OpenOrCreate), new FileInfo(imgPathToSend).Name, str).ConfigureAwait(false); + await Context.Channel.SendFileAsync(imageToSend, "result.png", str).ConfigureAwait(false); } } } diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index ba411cea..a32abc73 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -33,6 +33,7 @@ namespace NadekoBot public static GoogleApiService Google { get; private set; } public static StatsService Stats { get; private set; } + public static IImagesService Images { get; private set; } public static ConcurrentDictionary ModulePrefixes { get; private set; } public static bool Ready { get; private set; } @@ -68,8 +69,11 @@ namespace NadekoBot LogLevel = LogSeverity.Warning, TotalShards = Credentials.TotalShards, ConnectionTimeout = int.MaxValue, +#if !GLOBAL_NADEKO AlwaysDownloadUsers = true, +#endif }); + #if GLOBAL_NADEKO Client.Log += Client_Log; #endif @@ -82,6 +86,7 @@ namespace NadekoBot Google = new GoogleApiService(); CommandHandler = new CommandHandler(Client, CommandService); Stats = new StatsService(Client, CommandHandler); + Images = await ImagesService.Create().ConfigureAwait(false); ////setup DI //var depMap = new DependencyMap(); diff --git a/src/NadekoBot/Services/IImagesService.cs b/src/NadekoBot/Services/IImagesService.cs new file mode 100644 index 00000000..b00b4a4a --- /dev/null +++ b/src/NadekoBot/Services/IImagesService.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services +{ + public interface IImagesService + { + Stream Heads { get; } + Stream Tails { get; } + + Task Reload(); + } +} diff --git a/src/NadekoBot/Services/Impl/ImagesService.cs b/src/NadekoBot/Services/Impl/ImagesService.cs new file mode 100644 index 00000000..e57636c1 --- /dev/null +++ b/src/NadekoBot/Services/Impl/ImagesService.cs @@ -0,0 +1,46 @@ +using NLog; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Impl +{ + public class ImagesService : IImagesService + { + private readonly Logger _log; + + private const string headsPath = "data/images/coins/heads.png"; + private const string tailsPath = "data/images/coins/tails.png"; + + private byte[] heads; + public Stream Heads => new MemoryStream(heads, false); + + private byte[] tails; + public Stream Tails => new MemoryStream(tails, false); + + private ImagesService() + { + _log = LogManager.GetCurrentClassLogger(); + } + + public static async Task Create() + { + var srvc = new ImagesService(); + await srvc.Reload().ConfigureAwait(false); + return srvc; + } + + public Task Reload() => Task.Run(() => + { + _log.Info("Loading images..."); + var sw = Stopwatch.StartNew(); + heads = File.ReadAllBytes(headsPath); + tails = File.ReadAllBytes(tailsPath); + _log.Info($"Images loaded after {sw.Elapsed.TotalSeconds:F2}s!"); + }); + } +} \ No newline at end of file From 22f7443f0b1fe3b2b447afec7fd9641339556594 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 2 Feb 2017 22:05:53 +0100 Subject: [PATCH 158/746] punishments and v+t info is info now, not warning --- .../Modules/Administration/Commands/ProtectionCommands.cs | 2 +- .../Modules/Administration/Commands/VoicePlusTextCommands.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs index 3e3b217a..7639a4dc 100644 --- a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs @@ -183,7 +183,7 @@ namespace NadekoBot.Modules.Administration private static async Task PunishUsers(PunishmentAction action, ProtectionType pt, params IGuildUser[] gus) { - _log.Warn($"[{pt}] - Punishing [{gus.Length}] users with [{action}] in {gus[0].Guild.Name} guild"); + _log.Info($"[{pt}] - Punishing [{gus.Length}] users with [{action}] in {gus[0].Guild.Name} guild"); foreach (var gu in gus) { switch (action) diff --git a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs index 3b68f36f..d0c905bb 100644 --- a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs @@ -93,7 +93,7 @@ namespace NadekoBot.Modules.Administration if (beforeRole != null) try { - _log.Warn("Removing role " + beforeRoleName + " from user " + user.Username); + _log.Info("Removing role " + beforeRoleName + " from user " + user.Username); await user.RemoveRolesAsync(beforeRole).ConfigureAwait(false); await Task.Delay(200).ConfigureAwait(false); } From a728e6f670d6556768918918d1e887fc84faaee2 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 3 Feb 2017 00:22:29 +0100 Subject: [PATCH 159/746] Currency images are preloaded now too.(>plant/>gc) --- .../Games/Commands/PlantAndPickCommands.cs | 16 +++++----- src/NadekoBot/Services/IImagesService.cs | 3 ++ src/NadekoBot/Services/Impl/ImagesService.cs | 29 +++++++++++++++--- src/NadekoBot/data/currency_images/img2.jpg | Bin 230256 -> 33845 bytes 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 6b5da1b1..0fe72678 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 file = GetRandomCurrencyImage(); var sent = await channel.SendFileAsync( - File.Open(file, FileMode.OpenOrCreate), - new FileInfo(file).Name, + file.Item2, + file.Item1, $"❗ {firstPart} Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`") .ConfigureAwait(false); @@ -159,7 +159,7 @@ namespace NadekoBot.Modules.Games return; } - var file = GetRandomCurrencyImagePath(); + var file = GetRandomCurrencyImage(); IUserMessage msg; var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.BotConfig.CurrencyName[0]); @@ -170,7 +170,7 @@ namespace NadekoBot.Modules.Games } else { - msg = await Context.Channel.SendFileAsync(File.Open(file, FileMode.OpenOrCreate), new FileInfo(file).Name, msgToSend).ConfigureAwait(false); + msg = await Context.Channel.SendFileAsync(file.Item2, file.Item1, msgToSend).ConfigureAwait(false); } var msgs = new IUserMessage[amount]; @@ -220,10 +220,12 @@ namespace NadekoBot.Modules.Games } } - private static string GetRandomCurrencyImagePath() + private static Tuple GetRandomCurrencyImage() { var rng = new NadekoRandom(); - return Directory.GetFiles("data/currency_images").OrderBy(s => rng.Next()).FirstOrDefault(); + var images = NadekoBot.Images.CurrencyImages; + + return images[rng.Next(0, images.Count)]; } int GetRandomNumber() diff --git a/src/NadekoBot/Services/IImagesService.cs b/src/NadekoBot/Services/IImagesService.cs index b00b4a4a..192ee842 100644 --- a/src/NadekoBot/Services/IImagesService.cs +++ b/src/NadekoBot/Services/IImagesService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.IO; using System.Linq; using System.Text; @@ -12,6 +13,8 @@ namespace NadekoBot.Services Stream Heads { get; } Stream Tails { get; } + IImmutableList> CurrencyImages { get; } + Task Reload(); } } diff --git a/src/NadekoBot/Services/Impl/ImagesService.cs b/src/NadekoBot/Services/Impl/ImagesService.cs index e57636c1..f63e2eb5 100644 --- a/src/NadekoBot/Services/Impl/ImagesService.cs +++ b/src/NadekoBot/Services/Impl/ImagesService.cs @@ -1,6 +1,8 @@ using NLog; using System; using System.Collections.Generic; +using System.Collections.Immutable; +using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; @@ -16,11 +18,18 @@ namespace NadekoBot.Services.Impl private const string headsPath = "data/images/coins/heads.png"; private const string tailsPath = "data/images/coins/tails.png"; + private const string currencyImagesPath = "data/currency_images"; + private byte[] heads; public Stream Heads => new MemoryStream(heads, false); private byte[] tails; public Stream Tails => new MemoryStream(tails, false); + //todo tuple + private IReadOnlyDictionary currencyImages; + public IImmutableList> CurrencyImages => + currencyImages.Select(x => new Tuple(x.Key, (Stream)new MemoryStream(x.Value, false))) + .ToImmutableArray(); private ImagesService() { @@ -36,11 +45,21 @@ namespace NadekoBot.Services.Impl public Task Reload() => Task.Run(() => { - _log.Info("Loading images..."); - var sw = Stopwatch.StartNew(); - heads = File.ReadAllBytes(headsPath); - tails = File.ReadAllBytes(tailsPath); - _log.Info($"Images loaded after {sw.Elapsed.TotalSeconds:F2}s!"); + try + { + _log.Info("Loading images..."); + var sw = Stopwatch.StartNew(); + heads = File.ReadAllBytes(headsPath); + tails = File.ReadAllBytes(tailsPath); + + currencyImages = Directory.GetFiles(currencyImagesPath).ToDictionary(x => Path.GetFileName(x), x => File.ReadAllBytes(x)); + _log.Info($"Images loaded after {sw.Elapsed.TotalSeconds:F2}s!"); + } + catch (Exception ex) + { + _log.Error(ex); + throw; + } }); } } \ No newline at end of file diff --git a/src/NadekoBot/data/currency_images/img2.jpg b/src/NadekoBot/data/currency_images/img2.jpg index 5697f8bbf5319a59a7b0494ba2c57fd942a87426..cb22be2c9270022ae11c4d95b17b4bac0c16a219 100644 GIT binary patch delta 29564 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 C$!b&p delta 227522 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 Date: Fri, 3 Feb 2017 09:54:22 +0100 Subject: [PATCH 160/746] .reloadimages owner-only command added. --- .../Administration/Commands/SelfCommands.cs | 18 ++++ .../Games/Commands/PlantAndPickCommands.cs | 98 ++++++++++--------- .../Resources/CommandStrings.Designer.cs | 27 +++++ src/NadekoBot/Resources/CommandStrings.resx | 9 ++ 4 files changed, 107 insertions(+), 45 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index a56ee402..b2af48ab 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -3,6 +3,7 @@ using Discord.Commands; using NadekoBot.Attributes; using NadekoBot.Extensions; using System; +using System.Diagnostics; using System.IO; using System.Linq; using System.Net.Http; @@ -168,6 +169,23 @@ namespace NadekoBot.Modules.Administration await Context.Channel.SendConfirmAsync("🆗").ConfigureAwait(false); } + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task ReloadImages() + { + var channel = (ITextChannel)Context.Channel; + + var msg = await Context.Channel.SendMessageAsync("Reloading Images...").ConfigureAwait(false); + var sw = Stopwatch.StartNew(); + await NadekoBot.Images.Reload().ConfigureAwait(false); + sw.Stop(); + await msg.ModifyAsync(x => + { + x.Content = "✅ Images reloaded."; + }).ConfigureAwait(false); + } + private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus) { switch (sus) diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 0fe72678..ab40b511 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -51,62 +51,70 @@ namespace NadekoBot.Modules.Games .SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId))); } - private static async Task PotentialFlowerGeneration(SocketMessage imsg) + private static Task PotentialFlowerGeneration(SocketMessage imsg) { - try + var msg = imsg as SocketUserMessage; + if (msg == null || msg.IsAuthor() || msg.Author.IsBot) + return Task.CompletedTask; + + var channel = imsg.Channel as ITextChannel; + if (channel == null) + return Task.CompletedTask; + + if (!generationChannels.Contains(channel.Id)) + return Task.CompletedTask; + + var _ = Task.Run(async () => { - var msg = imsg as SocketUserMessage; - if (msg == null || msg.IsAuthor() || msg.Author.IsBot) - return; - - var channel = imsg.Channel as ITextChannel; - if (channel == null) - return; - - if (!generationChannels.Contains(channel.Id)) - return; - - var lastGeneration = lastGenerations.GetOrAdd(channel.Id, DateTime.MinValue); - var rng = new NadekoRandom(); - - if (DateTime.Now - TimeSpan.FromSeconds(NadekoBot.BotConfig.CurrencyGenerationCooldown) < lastGeneration) //recently generated in this channel, don't generate again - return; - - var num = rng.Next(1, 101) + NadekoBot.BotConfig.CurrencyGenerationChance * 100; - - if (num > 100) + try { - lastGenerations.AddOrUpdate(channel.Id, DateTime.Now, (id, old) => DateTime.Now); + var lastGeneration = lastGenerations.GetOrAdd(channel.Id, DateTime.MinValue); + var rng = new NadekoRandom(); - var dropAmount = NadekoBot.BotConfig.CurrencyDropAmount; + //todo i'm stupid :rofl: wtg kwoth. real async programming :100: :ok_hand: :100: :100: :thumbsup: + if (DateTime.Now - TimeSpan.FromSeconds(NadekoBot.BotConfig.CurrencyGenerationCooldown) < lastGeneration) //recently generated in this channel, don't generate again + return; - if (dropAmount > 0) + var num = rng.Next(1, 101) + NadekoBot.BotConfig.CurrencyGenerationChance * 100; + + if (num > 100) { - var msgs = new IUserMessage[dropAmount]; + lastGenerations.AddOrUpdate(channel.Id, DateTime.Now, (id, old) => DateTime.Now); - string firstPart; - if (dropAmount == 1) + var dropAmount = NadekoBot.BotConfig.CurrencyDropAmount; + + if (dropAmount > 0) { - firstPart = $"A random { NadekoBot.BotConfig.CurrencyName } appeared!"; - } - else - { - firstPart = $"{dropAmount} random { NadekoBot.BotConfig.CurrencyPluralName } appeared!"; - } - var file = GetRandomCurrencyImage(); - var sent = await channel.SendFileAsync( - file.Item2, - file.Item1, - $"❗ {firstPart} Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`") - .ConfigureAwait(false); + var msgs = new IUserMessage[dropAmount]; - msgs[0] = sent; + string firstPart; + if (dropAmount == 1) + { + firstPart = $"A random { NadekoBot.BotConfig.CurrencyName } appeared!"; + } + else + { + firstPart = $"{dropAmount} random { NadekoBot.BotConfig.CurrencyPluralName } appeared!"; + } + var file = GetRandomCurrencyImage(); + var sent = await channel.SendFileAsync( + file.Item2, + file.Item1, + $"❗ {firstPart} Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`") + .ConfigureAwait(false); - plantedFlowers.AddOrUpdate(channel.Id, msgs.ToList(), (id, old) => { old.AddRange(msgs); return old; }); + msgs[0] = sent; + + plantedFlowers.AddOrUpdate(channel.Id, msgs.ToList(), (id, old) => { old.AddRange(msgs); return old; }); + } } } - } - catch { } + catch (Exception ex) + { + _log.Warn(ex); + } + }); + return Task.CompletedTask; } [NadekoCommand, Usage, Description, Aliases] @@ -162,7 +170,7 @@ namespace NadekoBot.Modules.Games var file = GetRandomCurrencyImage(); IUserMessage msg; var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.BotConfig.CurrencyName[0]); - + var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(amount == 1 ? (vowelFirst ? "an" : "a") : amount.ToString())} {(amount > 1 ? NadekoBot.BotConfig.CurrencyPluralName : NadekoBot.BotConfig.CurrencyName)}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick"; if (file == null) { diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index e89ba368..634991da 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -5621,6 +5621,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to reloadimages. + /// + public static string reloadimages_cmd { + get { + return ResourceManager.GetString("reloadimages_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reloads images bot is using. Safe to use even when bot is being used heavily.. + /// + public static string reloadimages_desc { + get { + return ResourceManager.GetString("reloadimages_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}reloadimages`. + /// + public static string reloadimages_usage { + get { + return ResourceManager.GetString("reloadimages_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to remind. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 7ee5714b..9b0b01be 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3042,4 +3042,13 @@ `{0}smch` + + reloadimages + + + Reloads images bot is using. Safe to use even when bot is being used heavily. + + + `{0}reloadimages` + \ No newline at end of file From 0b9c52fc63533841d697baf8e2e67b9d7f6e07dd Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 3 Feb 2017 09:56:27 +0100 Subject: [PATCH 161/746] commandlist update --- docs/Commands List.md | 301 +++++++++++++++++++++--------------------- 1 file changed, 152 insertions(+), 149 deletions(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index ed71757c..d73852f3 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -18,56 +18,6 @@ You can support the project on patreon: or paypa ### Administration Command and aliases | Description | Usage ----------------|--------------|------- -`.voice+text` `.v+t` | Creates a text channel for each voice channel only users in that voice channel can see.If you are server owner, keep in mind you will see them all the time regardless. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.voice+text` -`.cleanvplust` `.cv+t` | Deletes all text channels ending in `-voice` for which voicechannels are not found. Use at your own risk. **Requires ManageChannels server permission.** **Requires ManageRoles server permission.** | `.cleanv+t` -`.greetdel` `.grdel` | Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.greetdel 0` or `.greetdel 30` -`.greet` | Toggles anouncements on the current channel when someone joins the server. **Requires ManageServer server permission.** | `.greet` -`.greetmsg` | Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. **Requires ManageServer server permission.** | `.greetmsg Welcome, %user%.` -`.greetdm` | Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). **Requires ManageServer server permission.** | `.greetdm` -`.greetdmmsg` | Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message. **Requires ManageServer server permission.** | `.greetdmmsg Welcome to the server, %user%`. -`.bye` | Toggles anouncements on the current channel when someone leaves the server. **Requires ManageServer server permission.** | `.bye` -`.byemsg` | Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message. **Requires ManageServer server permission.** | `.byemsg %user% has left.` -`.byedel` | Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.byedel 0` or `.byedel 30` -`.leave` | Makes Nadeko leave the server. Either name or id required. **Bot Owner only.** | `.leave 123123123331` -`.die` | Shuts the bot down. **Bot Owner only.** | `.die` -`.setname` `.newnm` | Gives the bot a new name. **Bot Owner only.** | `.newnm BotName` -`.setstatus` | Sets the bot's status. (Online/Idle/Dnd/Invisible) **Bot Owner only.** | `.setstatus Idle` -`.setavatar` `.setav` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner only.** | `.setav http://i.imgur.com/xTG3a1I.jpg` -`.setgame` | Sets the bots game. **Bot Owner only.** | `.setgame with snakes` -`.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot Owner only.** | `.setstream TWITCHLINK Hello` -`.send` | Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prepend channel id with `c:` and user id with `u:`. **Bot Owner only.** | `.send serverid|c:channelid message` or `.send serverid|u:userid message` -`.announce` | Sends a message to all servers' general channel bot is connected to. **Bot Owner only.** | `.announce Useless spam` -`.adsarm` | Toggles the automatic deletion of confirmations for .iam and .iamn commands. **Requires ManageMessages server permission.** | `.adsarm` -`.asar` | Adds a role to the list of self-assignable roles. **Requires ManageRoles server permission.** | `.asar Gamer` -`.rsar` | Removes a specified role from the list of self-assignable roles. **Requires ManageRoles server permission.** | `.rsar` -`.lsar` | Lists all self-assignable roles. | `.lsar` -`.togglexclsar` `.tesar` | Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) **Requires ManageRoles server permission.** | `.tesar` -`.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | `.iam Gamer` -`.iamnot` `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | `.iamn Gamer` -`.slowmode` | Toggles slowmode. Disable by specifying no parameters. To enable, specify a number of messages each user can send, and an interval in seconds. For example 1 message every 5 seconds. **Requires ManageMessages server permission.** | `.slowmode 1 5` or `.slowmode` -`.antiraid` | Sets an anti-raid protection on the server. First argument is number of people which will trigger the protection. Second one is a time interval in which that number of people needs to join in order to trigger the protection, and third argument is punishment for those people (Kick, Ban, Mute) **Requires Administrator server permission.** | `.antiraid 5 20 Kick` -`.antispam` | Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. **Requires Administrator server permission.** | `.antispam 3 Mute` or `.antispam 4 Kick` or `.antispam 6 Ban` -`.antispamignore` | Toggles whether antispam ignores current channel. Antispam must be enabled. | `.antispamignore` -`.antilist` `.antilst` | Shows currently enabled protection features. | `.antilist` -`.rotateplaying` `.ropl` | Toggles rotation of playing status of the dynamic strings you previously specified. **Bot Owner only.** | `.ropl` -`.addplaying` `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued% **Bot Owner only.** | `.adpl` -`.listplaying` `.lipl` | Lists all playing statuses with their corresponding number. **Bot Owner only.** | `.lipl` -`.removeplaying` `.rmpl` `.repl` | Removes a playing string on a given number. **Bot Owner only.** | `.rmpl` -`.setmuterole` | Sets a name of the role which will be assigned to people who should be muted. Default is nadeko-mute. **Requires ManageRoles server permission.** | `.setmuterole Silenced` -`.mute` | Mutes a mentioned user both from speaking and chatting. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.mute @Someone` -`.unmute` | Unmutes a mentioned user previously muted with `.mute` command. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.unmute @Someone` -`.chatmute` | Prevents a mentioned user from chatting in text channels. **Requires ManageRoles server permission.** | `.chatmute @Someone` -`.chatunmute` | Removes a mute role previously set on a mentioned user with `.chatmute` which prevented him from chatting in text channels. **Requires ManageRoles server permission.** | `.chatunmute @Someone` -`.voicemute` | Prevents a mentioned user from speaking in voice channels. **Requires MuteMembers server permission.** | `.voicemute @Someone` -`.voiceunmute` | Gives a previously voice-muted user a permission to speak. **Requires MuteMembers server permission.** | `.voiceunmute @Someguy` -`.migratedata` | Migrate data from old bot configuration **Bot Owner only.** | `.migratedata` -`.logserver` | Enables or Disables ALL log events. If enabled, all log events will log to this channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logserver enable` or `.logserver disable` -`.logignore` | Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logignore` -`.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot Owner only.** | `.logevents` -`.log` | Toggles logging event. Disables it if it's active anywhere on the server. Enables if it's not active. Use `.logevents` to see a list of all events you can subscribe to. **Requires Administrator server permission.** **Bot Owner only.** | `.log userpresence` or `.log userbanned` -`.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot Owner only.** | `.fwmsgs` -`.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json **Bot Owner only.** | `.fwtoall` -`.autoassignrole` `.aar` | Automaticaly assigns a specified role to every user who joins the server. **Requires ManageRoles server permission.** | `.aar` to disable, `.aar Role Name` to enable `.resetperms` | Resets BOT's permissions module on this server to the default value. **Requires Administrator server permission.** | `.resetperms` `.delmsgoncmd` | Toggles the automatic deletion of user's successful command message to prevent chat flood. **Requires Administrator server permission.** | `.delmsgoncmd` `.setrole` `.sr` | Sets a role for a given user. **Requires ManageRoles server permission.** | `.sr @User Guest` @@ -91,6 +41,57 @@ Command and aliases | Description | Usage `.mentionrole` `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. **Requires MentionEveryone server permission.** | `.menro RoleName` `.donators` | List of lovely people who donated to keep this project alive. | `.donators` `.donadd` | Add a donator to the database. **Bot Owner only.** | `.donadd Donate Amount` +`.autoassignrole` `.aar` | Automaticaly assigns a specified role to every user who joins the server. **Requires ManageRoles server permission.** | `.aar` to disable, `.aar Role Name` to enable +`.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot Owner only.** | `.fwmsgs` +`.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json **Bot Owner only.** | `.fwtoall` +`.logserver` | Enables or Disables ALL log events. If enabled, all log events will log to this channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logserver enable` or `.logserver disable` +`.logignore` | Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logignore` +`.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot Owner only.** | `.logevents` +`.log` | Toggles logging event. Disables it if it's active anywhere on the server. Enables if it's not active. Use `.logevents` to see a list of all events you can subscribe to. **Requires Administrator server permission.** **Bot Owner only.** | `.log userpresence` or `.log userbanned` +`.migratedata` | Migrate data from old bot configuration **Bot Owner only.** | `.migratedata` +`.setmuterole` | Sets a name of the role which will be assigned to people who should be muted. Default is nadeko-mute. **Requires ManageRoles server permission.** | `.setmuterole Silenced` +`.mute` | Mutes a mentioned user both from speaking and chatting. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.mute @Someone` +`.unmute` | Unmutes a mentioned user previously muted with `.mute` command. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.unmute @Someone` +`.chatmute` | Prevents a mentioned user from chatting in text channels. **Requires ManageRoles server permission.** | `.chatmute @Someone` +`.chatunmute` | Removes a mute role previously set on a mentioned user with `.chatmute` which prevented him from chatting in text channels. **Requires ManageRoles server permission.** | `.chatunmute @Someone` +`.voicemute` | Prevents a mentioned user from speaking in voice channels. **Requires MuteMembers server permission.** | `.voicemute @Someone` +`.voiceunmute` | Gives a previously voice-muted user a permission to speak. **Requires MuteMembers server permission.** | `.voiceunmute @Someguy` +`.rotateplaying` `.ropl` | Toggles rotation of playing status of the dynamic strings you previously specified. **Bot Owner only.** | `.ropl` +`.addplaying` `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %time%,%shardid%,%shardcount%, %shardguilds% **Bot Owner only.** | `.adpl` +`.listplaying` `.lipl` | Lists all playing statuses with their corresponding number. **Bot Owner only.** | `.lipl` +`.removeplaying` `.rmpl` `.repl` | Removes a playing string on a given number. **Bot Owner only.** | `.rmpl` +`.antiraid` | Sets an anti-raid protection on the server. First argument is number of people which will trigger the protection. Second one is a time interval in which that number of people needs to join in order to trigger the protection, and third argument is punishment for those people (Kick, Ban, Mute) **Requires Administrator server permission.** | `.antiraid 5 20 Kick` +`.antispam` | Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. **Requires Administrator server permission.** | `.antispam 3 Mute` or `.antispam 4 Kick` or `.antispam 6 Ban` +`.antispamignore` | Toggles whether antispam ignores current channel. Antispam must be enabled. | `.antispamignore` +`.antilist` `.antilst` | Shows currently enabled protection features. | `.antilist` +`.slowmode` | Toggles slowmode. Disable by specifying no parameters. To enable, specify a number of messages each user can send, and an interval in seconds. For example 1 message every 5 seconds. **Requires ManageMessages server permission.** | `.slowmode 1 5` or `.slowmode` +`.adsarm` | Toggles the automatic deletion of confirmations for .iam and .iamn commands. **Requires ManageMessages server permission.** | `.adsarm` +`.asar` | Adds a role to the list of self-assignable roles. **Requires ManageRoles server permission.** | `.asar Gamer` +`.rsar` | Removes a specified role from the list of self-assignable roles. **Requires ManageRoles server permission.** | `.rsar` +`.lsar` | Lists all self-assignable roles. | `.lsar` +`.togglexclsar` `.tesar` | Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) **Requires ManageRoles server permission.** | `.tesar` +`.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | `.iam Gamer` +`.iamnot` `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | `.iamn Gamer` +`.leave` | Makes Nadeko leave the server. Either name or id required. **Bot Owner only.** | `.leave 123123123331` +`.die` | Shuts the bot down. **Bot Owner only.** | `.die` +`.setname` `.newnm` | Gives the bot a new name. **Bot Owner only.** | `.newnm BotName` +`.setstatus` | Sets the bot's status. (Online/Idle/Dnd/Invisible) **Bot Owner only.** | `.setstatus Idle` +`.setavatar` `.setav` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner only.** | `.setav http://i.imgur.com/xTG3a1I.jpg` +`.setgame` | Sets the bots game. **Bot Owner only.** | `.setgame with snakes` +`.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot Owner only.** | `.setstream TWITCHLINK Hello` +`.send` | Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prepend channel id with `c:` and user id with `u:`. **Bot Owner only.** | `.send serverid|c:channelid message` or `.send serverid|u:userid message` +`.announce` | Sends a message to all servers' general channel bot is connected to. **Bot Owner only.** | `.announce Useless spam` +`.reloadimages` | Reloads images bot is using. Safe to use even when bot is being used heavily. **Bot Owner only.** | `.reloadimages` +`.greetdel` `.grdel` | Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.greetdel 0` or `.greetdel 30` +`.greet` | Toggles anouncements on the current channel when someone joins the server. **Requires ManageServer server permission.** | `.greet` +`.greetmsg` | Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. **Requires ManageServer server permission.** | `.greetmsg Welcome, %user%.` +`.greetdm` | Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). **Requires ManageServer server permission.** | `.greetdm` +`.greetdmmsg` | Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message. **Requires ManageServer server permission.** | `.greetdmmsg Welcome to the server, %user%`. +`.bye` | Toggles anouncements on the current channel when someone leaves the server. **Requires ManageServer server permission.** | `.bye` +`.byemsg` | Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message. **Requires ManageServer server permission.** | `.byemsg %user% has left.` +`.byedel` | Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.byedel 0` or `.byedel 30` +`.voice+text` `.v+t` | Creates a text channel for each voice channel only users in that voice channel can see.If you are server owner, keep in mind you will see them all the time regardless. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.v+t` +`.cleanvplust` `.cv+t` | Deletes all text channels ending in `-voice` for which voicechannels are not found. Use at your own risk. **Requires ManageChannels server permission.** **Requires ManageRoles server permission.** | `.cleanv+t` ###### [Back to TOC](#table-of-contents) @@ -125,24 +126,6 @@ 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` -`$shuffle` `$sh` | Reshuffles all cards back into the deck. | `$sh` -`$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` `$cash` `$$$` | Check how much currency a person has. (Defaults to yourself) | `$$$` or `$$$ @SomeGuy` `$give` | Give someone a certain amount of currency. | `$give 1 "@SomeGuy"` @@ -150,36 +133,54 @@ Command and aliases | Description | Usage `$take` | Takes a certain amount of currency from someone. **Bot Owner only.** | `$take 1 "@someguy"` `$betroll` `$br` | Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x3 and 100 x10. | `$br 5` `$leaderboard` `$lb` | Displays bot currency leaderboard. | `$lb` +`$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` +`$startevent` | Starts one of the events seen on public nadeko. **Bot Owner only.** | `$startevent flowerreaction` +`$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` +`$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` +`$shuffle` `$sh` | Reshuffles all cards back into the deck. | `$sh` +`$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.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. | `$bf 5 heads` or `$bf 3 t` +`$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` +`$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` ###### [Back to TOC](#table-of-contents) ### Games Command and aliases | Description | Usage ----------------|--------------|------- -`>trivia` `>t` | Starts a game of trivia. You can add nohint to prevent hints.First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. | `>t` or `>t 5 nohint` -`>tl` | Shows a current trivia leaderboard. | `>tl` -`>tq` | Quits current trivia after current question. | `>tq` -`>typestart` | Starts a typing contest. | `>typestart` -`>typestop` | Stops a typing contest on the current channel. | `>typestop` -`>typeadd` | Adds a new article to the typing contest. **Bot Owner only.** | `>typeadd wordswords` -`>typelist` | Lists added typing articles with their IDs. 15 per page. | `>typelist` or `>typelist 3` -`>typedel` | Deletes a typing article given the ID. **Bot Owner only.** | `>typedel 3` -`>poll` | Creates a poll which requires users to send the number of the voting option to the bot. **Requires ManageMessages server permission.** | `>poll Question?;Answer1;Answ 2;A_3` -`>publicpoll` `>ppoll` | Creates a public poll which requires users to type a number of the voting option in the channel command is ran in. **Requires ManageMessages server permission.** | `>ppoll Question?;Answer1;Answ 2;A_3` -`>pollstats` | Shows the poll results without stopping the poll on this server. **Requires ManageMessages server permission.** | `>pollstats` -`>pollend` | Stops active poll on this server and prints the results in this channel. **Requires ManageMessages server permission.** | `>pollend` -`>pick` | Picks the currency planted in this channel. 60 seconds cooldown. | `>pick` -`>plant` | Spend a unit of currency to plant it in this channel. (If bot is restarted or crashes, the currency will be lost) | `>plant` -`>gencurrency` `>gc` | Toggles currency generation on this channel. Every posted message will have chance to spawn currency. Chance is specified by the Bot Owner. (default is 2%) **Requires ManageMessages server permission.** | `>gc` -`>hangmanlist` | Shows a list of hangman term types. | `> hangmanlist` -`>hangman` | Starts a game of hangman in the channel. Use `>hangmanlist` to see a list of available term types. Defaults to 'all'. | `>hangman` or `>hangman movies` -`>cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. **Requires ManageMessages server permission.** | `>cleverbot` -`>acrophobia` `>acro` | Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60) | `>acro` or `>acro 30` `>choose` | Chooses a thing from a list of things | `>choose Get up;Sleep;Sleep more` `>8ball` | Ask the 8ball a yes/no question. | `>8ball should I do something` `>rps` | Play a game of rocket paperclip scissors with Nadeko. | `>rps scissors` `>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows` `>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | `>leet 3 Hello` +`>acrophobia` `>acro` | Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60) | `>acro` or `>acro 30` +`>cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. **Requires ManageMessages server permission.** | `>cleverbot` +`>hangmanlist` | Shows a list of hangman term types. | `> hangmanlist` +`>hangman` | Starts a game of hangman in the channel. Use `>hangmanlist` to see a list of available term types. Defaults to 'all'. | `>hangman` or `>hangman movies` +`>pick` | Picks the currency planted in this channel. 60 seconds cooldown. | `>pick` +`>plant` | Spend an amount of currency to plant it in this channel. Default is 1. (If bot is restarted or crashes, the currency will be lost) | `>plant` or `>plant 5` +`>gencurrency` `>gc` | Toggles currency generation on this channel. Every posted message will have chance to spawn currency. Chance is specified by the Bot Owner. (default is 2%) **Requires ManageMessages server permission.** | `>gc` +`>poll` | Creates a poll which requires users to send the number of the voting option to the bot. **Requires ManageMessages server permission.** | `>poll Question?;Answer1;Answ 2;A_3` +`>publicpoll` `>ppoll` | Creates a public poll which requires users to type a number of the voting option in the channel command is ran in. **Requires ManageMessages server permission.** | `>ppoll Question?;Answer1;Answ 2;A_3` +`>pollstats` | Shows the poll results without stopping the poll on this server. **Requires ManageMessages server permission.** | `>pollstats` +`>pollend` | Stops active poll on this server and prints the results in this channel. **Requires ManageMessages server permission.** | `>pollend` +`>typestart` | Starts a typing contest. | `>typestart` +`>typestop` | Stops a typing contest on the current channel. | `>typestop` +`>typeadd` | Adds a new article to the typing contest. **Bot Owner only.** | `>typeadd wordswords` +`>typelist` | Lists added typing articles with their IDs. 15 per page. | `>typelist` or `>typelist 3` +`>typedel` | Deletes a typing article given the ID. **Bot Owner only.** | `>typedel 3` +`>trivia` `>t` | Starts a game of trivia. You can add nohint to prevent hints.First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. | `>t` or `>t 5 nohint` +`>tl` | Shows a current trivia leaderboard. | `>tl` +`>tq` | Quits current trivia after current question. | `>tq` ###### [Back to TOC](#table-of-contents) @@ -227,6 +228,7 @@ Command and aliases | Description | Usage `!!deleteplaylist` `!!delpls` | Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!!delpls animu-5` `!!goto` | Goes to a specific time in seconds in a song. | `!!goto 30` `!!autoplay` `!!ap` | Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty) | `!!ap` +`!!setmusicchannel` `!!smch` | Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in. **Requires ManageMessages server permission.** | `!!smch` ###### [Back to TOC](#table-of-contents) @@ -236,12 +238,12 @@ 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. **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` `~konachan` | Shows a random hentai image from konachan with a given tag. Tag is optional but preferred. | `~konachan yuri` -`~gelbooru` | Shows a random hentai image from gelbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~gelbooru yuri+kissing` `~rule34` | Shows a random image from rule34.xx with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~rule34 yuri+kissing` `~e621` | Shows a random hentai image from e621.net with a given tag. Tag is optional but preferred. Use spaces for multiple tags. | `~e621 yuri kissing` +`~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` +`~gelbooru` | Shows a random hentai image from gelbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~gelbooru yuri+kissing` `~cp` | We all know where this will lead you to. | `~cp` `~boobs` | Real adult content. | `~boobs` `~butts` `~ass` `~butt` | Real adult content. | `~butts` or `~ass` @@ -251,18 +253,6 @@ Command and aliases | Description | Usage ### Permissions Command and aliases | Description | Usage ----------------|--------------|------- -`;srvrfilterinv` `;sfi` | Toggles automatic deleting of invites posted in the server. Does not affect Bot Owner. | `;sfi` -`;chnlfilterinv` `;cfi` | Toggles automatic deleting of invites posted in the channel. Does not negate the ;srvrfilterinv enabled setting. Does not affect Bot Owner. | `;cfi` -`;srvrfilterwords` `;sfw` | Toggles automatic deleting of messages containing forbidden words on the server. Does not affect Bot Owner. | `;sfw` -`;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` -`;cbl` | Either [add]s or [rem]oves a channel specified by an ID from a blacklist. **Bot Owner only.** | `;cbl rem 12312312312` -`;sbl` | Either [add]s or [rem]oves a server specified by a Name or ID from a blacklist. **Bot Owner only.** | `;sbl add 12312321312` or `;sbl rem SomeTrashServer` `;verbose` `;v` | Sets whether to show when a command/module is blocked. | `;verbose true` `;permrole` `;pr` | Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'. | `;pr role` `;listperms` `;lp` | Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions. | `;lp` or `;lp 3` @@ -280,6 +270,18 @@ Command and aliases | Description | Usage `;allrolemdls` `;arm` | Enable or disable all modules for a specific role. | `;arm [enable/disable] MyRole` `;allusrmdls` `;aum` | Enable or disable all modules for a specific user. | `;aum enable @someone` `;allsrvrmdls` `;asm` | Enable or disable all modules for your server. | `;asm [enable/disable]` +`;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` +`;cbl` | Either [add]s or [rem]oves a channel specified by an ID from a blacklist. **Bot Owner only.** | `;cbl rem 12312312312` +`;sbl` | Either [add]s or [rem]oves a server specified by a Name or ID from a blacklist. **Bot Owner only.** | `;sbl add 12312321312` or `;sbl rem SomeTrashServer` +`;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` +`;cmdcosts` | Shows a list of command costs. Paginated with 9 command per page. | `;cmdcosts` or `;cmdcosts 2` +`;srvrfilterinv` `;sfi` | Toggles automatic deleting of invites posted in the server. Does not affect Bot Owner. | `;sfi` +`;chnlfilterinv` `;cfi` | Toggles automatic deleting of invites posted in the channel. Does not negate the ;srvrfilterinv enabled setting. Does not affect Bot Owner. | `;cfi` +`;srvrfilterwords` `;sfw` | Toggles automatic deleting of messages containing forbidden words on the server. Does not affect Bot Owner. | `;sfw` +`;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` ###### [Back to TOC](#table-of-contents) @@ -297,32 +299,6 @@ Command and aliases | Description | Usage ### Searches Command and aliases | Description | Usage ----------------|--------------|------- -`~xkcd` | Shows a XKCD comic. No arguments will retrieve random one. Number argument will retrieve a specific comic, and "latest" will get the latest one. | `~xkcd` or `~xkcd 1400` or `~xkcd latest` -`~translate` `~trans` | Translates from>to text. From the given language to the destination language. | `~trans en>fr Hello` -`~autotrans` `~at` | Starts automatic translation of all messages by users who set their `~atl` in this channel. You can set "del" argument to automatically delete all translated user messages. **Requires Administrator server permission.** **Bot Owner only.** | `~at` or `~at del` -`~autotranslang` `~atl` | `~atl en>fr` | Sets your source and target language to be used with `~at`. Specify no arguments to remove previously set value. -`~translangs` | Lists the valid languages for translation. | `~translangs` -`~hitbox` `~hb` | Notifies this channel when a certain user starts streaming. **Requires ManageMessages server permission.** | `~hitbox SomeStreamer` -`~twitch` `~tw` | Notifies this channel when a certain user starts streaming. **Requires ManageMessages server permission.** | `~twitch SomeStreamer` -`~beam` `~bm` | Notifies this channel when a certain user starts streaming. **Requires ManageMessages server permission.** | `~beam SomeStreamer` -`~liststreams` `~ls` | Lists all streams you are following on this server. | `~ls` -`~removestream` `~rms` | Removes notifications of a certain streamer from a certain platform on this channel. **Requires ManageMessages server permission.** | `~rms Twitch SomeGuy` or `~rms Beam SomeOtherGuy` -`~checkstream` `~cs` | Checks if a user is online on a certain streaming platform. | `~cs twitch MyFavStreamer` -`~pokemon` `~poke` | Searches for a pokemon. | `~poke Sylveon` -`~pokemonability` `~pokeab` | Searches for a pokemon ability. | `~pokeab overgrow` -`~placelist` | Shows the list of available tags for the `~place` command. | `~placelist` -`~place` | Shows a placeholder image of a given tag. Use `~placelist` to see all available tags. You can specify the width and height of the image as the last two optional arguments. | `~place Cage` or `~place steven 500 400` -`~overwatch` `~ow` | Show's basic stats on a player (competitive rank, playtime, level etc) Region codes are: `eu` `us` `cn` `kr` | `~ow us Battletag#1337` or `~overwatch eu Battletag#2016` -`~osu` | Shows osu stats for a player. | `~osu Name` or `~osu Name taiko` -`~osub` | Shows information about an osu beatmap. | `~osub https://osu.ppy.sh/s/127712` -`~osu5` | Displays a user's top 5 plays. | `~osu5 Name` -`~yomama` `~ym` | Shows a random joke from | `~ym` -`~randjoke` `~rj` | Shows a random joke from | `~rj` -`~chucknorris` `~cn` | Shows a random chucknorris joke from | `~cn` -`~wowjoke` | Get one of Kwoth's penultimate WoW jokes. | `~wowjoke` -`~magicitem` `~mi` | Shows a random magicitem from | `~mi` -`~anime` `~ani` `~aq` | Queries anilist for an anime and shows the first result. | `~ani aquarion evol` -`~manga` `~mang` `~mq` | Queries anilist for a manga and shows the first result. | `~mq Shingeki no kyojin` `~weather` `~we` | Shows weather data for a specified city. You can also specify a country after a comma. | `~we Moscow, RU` `~youtube` `~yt` | Searches youtubes and shows the first result | `~yt query` `~imdb` `~omdb` | Queries omdb for movies or series, show first result. | `~imdb Batman vs Superman` @@ -353,34 +329,40 @@ Command and aliases | Description | Usage `~lolban` | Shows top banned champions ordered by ban rate. | `~lolban` `~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/ | `~memelist` `~memegen` | Generates a meme from memelist with top and bottom text. | `~memegen biw "gets iced coffee" "in the winter"` +`~mal` | Shows basic info from myanimelist profile. | `~mal straysocks` +`~anime` `~ani` `~aq` | Queries anilist for an anime and shows the first result. | `~ani aquarion evol` +`~manga` `~mang` `~mq` | Queries anilist for a manga and shows the first result. | `~mq Shingeki no kyojin` +`~yomama` `~ym` | Shows a random joke from | `~ym` +`~randjoke` `~rj` | Shows a random joke from | `~rj` +`~chucknorris` `~cn` | Shows a random chucknorris joke from | `~cn` +`~wowjoke` | Get one of Kwoth's penultimate WoW jokes. | `~wowjoke` +`~magicitem` `~mi` | Shows a random magicitem from | `~mi` +`~osu` | Shows osu stats for a player. | `~osu Name` or `~osu Name taiko` +`~osub` | Shows information about an osu beatmap. | `~osub https://osu.ppy.sh/s/127712` +`~osu5` | Displays a user's top 5 plays. | `~osu5 Name` +`~overwatch` `~ow` | Show's basic stats on a player (competitive rank, playtime, level etc) Region codes are: `eu` `us` `cn` `kr` | `~ow us Battletag#1337` or `~overwatch eu Battletag#2016` +`~placelist` | Shows the list of available tags for the `~place` command. | `~placelist` +`~place` | Shows a placeholder image of a given tag. Use `~placelist` to see all available tags. You can specify the width and height of the image as the last two optional arguments. | `~place Cage` or `~place steven 500 400` +`~pokemon` `~poke` | Searches for a pokemon. | `~poke Sylveon` +`~pokemonability` `~pokeab` | Searches for a pokemon ability. | `~pokeab overgrow` +`~hitbox` `~hb` | Notifies this channel when a certain user starts streaming. **Requires ManageMessages server permission.** | `~hitbox SomeStreamer` +`~twitch` `~tw` | Notifies this channel when a certain user starts streaming. **Requires ManageMessages server permission.** | `~twitch SomeStreamer` +`~beam` `~bm` | Notifies this channel when a certain user starts streaming. **Requires ManageMessages server permission.** | `~beam SomeStreamer` +`~liststreams` `~ls` | Lists all streams you are following on this server. | `~ls` +`~removestream` `~rms` | Removes notifications of a certain streamer from a certain platform on this channel. **Requires ManageMessages server permission.** | `~rms Twitch SomeGuy` or `~rms Beam SomeOtherGuy` +`~checkstream` `~cs` | Checks if a user is online on a certain streaming platform. | `~cs twitch MyFavStreamer` +`~translate` `~trans` | Translates from>to text. From the given language to the destination language. | `~trans en>fr Hello` +`~autotrans` `~at` | Starts automatic translation of all messages by users who set their `~atl` in this channel. You can set "del" argument to automatically delete all translated user messages. **Requires Administrator server permission.** **Bot Owner only.** | `~at` or `~at del` +`~autotranslang` `~atl` | `~atl en>fr` | Sets your source and target language to be used with `~at`. Specify no arguments to remove previously set value. +`~translangs` | Lists the valid languages for translation. | `~translangs` +`~xkcd` | Shows a XKCD comic. No arguments will retrieve random one. Number argument will retrieve a specific comic, and "latest" will get the latest one. | `~xkcd` or `~xkcd 1400` or `~xkcd latest` ###### [Back to TOC](#table-of-contents) ### Utility Command and aliases | Description | Usage ----------------|--------------|------- -`.convertlist` | List of the convertible dimensions and currencies. | `.convertlist` -`.convert` | Convert quantities. Use `.convertlist` to see supported dimensions and currencies. | `.convert m km 1000` -`.remind` | Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message. | `.remind me 1d5h Do something` or `.remind #general 1m Start now!` -`.remindtemplate` | Sets message for when the remind is triggered. Available placeholders are %user% - user who ran the command, %message% - Message specified in the remind, %target% - target channel of the remind. **Bot Owner only.** | `.remindtemplate %user%, do %message%!` -`.listquotes` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page. -`...` | Shows a random quote with a specified name. | `... abc` -`..` | Adds a new quote with the specified name and message. | `.. sayhi Hi` -`.deletequote` `.delq` | Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. | `.delq abc` -`.delallq` `.daq` | Deletes all quotes on a specified keyword. **Requires Administrator server permission.** | `.delallq kek` -`.repeatinvoke` `.repinv` | Immediately shows the repeat message on a certain index and restarts its timer. **Requires ManageMessages server permission.** | `.repinv 1` -`.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2` -`.repeat` | Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` -`.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist` -`.serverinfo` `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | `.sinfo Some Server` -`.channelinfo` `.cinfo` | Shows info about the channel. If no channel is supplied, it defaults to current one. | `.cinfo #some-channel` -`.userinfo` `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | `.uinfo @SomeUser` -`.scsc` | Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. **Bot Owner only.** | `.scsc` -`.jcsc` | Joins current channel to an instance of cross server channel using the token. **Requires ManageServer server permission.** | `.jcsc TokenHere` -`.lcsc` | Leaves Cross server channel instance from this channel. **Requires ManageServer server permission.** | `.lcsc` -`.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1` -`.calcops` | Shows all available operations in .calc command | `.calcops` -`.rotaterolecolor` `.rrc` | Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. **Bot Owner only.** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole` +`.rotaterolecolor` `.rrc` | Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. **Requires ManageRoles server permission.** **Bot Owner only.** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole` `.togethertube` `.totube` | Creates a new room on and shows the link in the chat. | `.totube` `.whosplaying` `.whpl` | Shows a list of users who are playing the specified game. | `.whpl Overwatch` `.inrole` | Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission. | `.inrole Role` @@ -396,3 +378,24 @@ Command and aliases | Description | Usage `.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot Owner only.** | `.listservers 3` `.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner only.** | `.savechat 150` `.activity` | Checks for spammers. **Bot Owner only.** | `.activity` +`.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1` +`.calcops` | Shows all available operations in .calc command | `.calcops` +`.scsc` | Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. **Bot Owner only.** | `.scsc` +`.jcsc` | Joins current channel to an instance of cross server channel using the token. **Requires ManageServer server permission.** | `.jcsc TokenHere` +`.lcsc` | Leaves Cross server channel instance from this channel. **Requires ManageServer server permission.** | `.lcsc` +`.serverinfo` `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | `.sinfo Some Server` +`.channelinfo` `.cinfo` | Shows info about the channel. If no channel is supplied, it defaults to current one. | `.cinfo #some-channel` +`.userinfo` `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | `.uinfo @SomeUser` +`.repeatinvoke` `.repinv` | Immediately shows the repeat message on a certain index and restarts its timer. **Requires ManageMessages server permission.** | `.repinv 1` +`.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2` +`.repeat` | Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` +`.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist` +`.listquotes` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page. +`...` | Shows a random quote with a specified name. | `... abc` +`..` | Adds a new quote with the specified name and message. | `.. sayhi Hi` +`.deletequote` `.delq` | Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. | `.delq abc` +`.delallq` `.daq` | Deletes all quotes on a specified keyword. **Requires Administrator server permission.** | `.delallq kek` +`.remind` | Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message. | `.remind me 1d5h Do something` or `.remind #general 1m Start now!` +`.remindtemplate` | Sets message for when the remind is triggered. Available placeholders are %user% - user who ran the command, %message% - Message specified in the remind, %target% - target channel of the remind. **Bot Owner only.** | `.remindtemplate %user%, do %message%!` +`.convertlist` | List of the convertible dimensions and currencies. | `.convertlist` +`.convert` | Convert quantities. Use `.convertlist` to see supported dimensions and currencies. | `.convert m km 1000` From 9d5c977b485fc76f2c4b030c210bfc95219556b4 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 3 Feb 2017 09:59:18 +0100 Subject: [PATCH 162/746] .reloadimages can be ran in DM now --- src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index b2af48ab..e787b83a 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -170,12 +170,9 @@ namespace NadekoBot.Modules.Administration } [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] [OwnerOnly] public async Task ReloadImages() { - var channel = (ITextChannel)Context.Channel; - var msg = await Context.Channel.SendMessageAsync("Reloading Images...").ConfigureAwait(false); var sw = Stopwatch.StartNew(); await NadekoBot.Images.Reload().ConfigureAwait(false); From 8791bc55f508523f04406801db8fa47051b0988f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 3 Feb 2017 10:01:29 +0100 Subject: [PATCH 163/746] Just a bit better formatting. --- .../Modules/Administration/Commands/SelfCommands.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index e787b83a..137fa10c 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -173,14 +173,10 @@ namespace NadekoBot.Modules.Administration [OwnerOnly] public async Task ReloadImages() { - var msg = await Context.Channel.SendMessageAsync("Reloading Images...").ConfigureAwait(false); var sw = Stopwatch.StartNew(); await NadekoBot.Images.Reload().ConfigureAwait(false); sw.Stop(); - await msg.ModifyAsync(x => - { - x.Content = "✅ Images reloaded."; - }).ConfigureAwait(false); + await Context.Channel.SendConfirmAsync("Images Reloaded").ConfigureAwait(false); } private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus) From f850d62c89d9051ad5342d0928c2e4bc4f23cc1c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 3 Feb 2017 11:36:58 +0100 Subject: [PATCH 164/746] sneaky game will say a number of rewarded users at the end --- .../Modules/Gambling/Commands/CurrencyEvents.cs | 4 +++- .../Games/Commands/PlantAndPickCommands.cs | 2 +- src/NadekoBot/Services/IImagesService.cs | 3 ++- src/NadekoBot/Services/Impl/ImagesService.cs | 17 ++++++++++++----- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs index 927f8a72..bea309af 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -78,6 +78,7 @@ namespace NadekoBot.Modules.Gambling _secretCode += _sneakyGameStatusChars[rng.Next(0, _sneakyGameStatusChars.Length)]; } + var game = NadekoBot.Client.Game?.Name; await NadekoBot.Client.SetGameAsync($"type {_secretCode} for " + NadekoBot.BotConfig.CurrencyPluralName) .ConfigureAwait(false); try @@ -94,10 +95,11 @@ namespace NadekoBot.Modules.Gambling await Task.Delay(num * 1000); NadekoBot.Client.MessageReceived -= SneakyGameMessageReceivedEventHandler; + var cnt = _sneakyGameAwardedUsers.Count; _sneakyGameAwardedUsers.Clear(); _secretCode = String.Empty; - await NadekoBot.Client.SetGameAsync($"SneakyGame event ended.") + await NadekoBot.Client.SetGameAsync($"SneakyGame event ended. {cnt} users received a reward.") .ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index ab40b511..0ae16be6 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -231,7 +231,7 @@ namespace NadekoBot.Modules.Games private static Tuple GetRandomCurrencyImage() { var rng = new NadekoRandom(); - var images = NadekoBot.Images.CurrencyImages; + var images = NadekoBot.Images.Currency; return images[rng.Next(0, images.Count)]; } diff --git a/src/NadekoBot/Services/IImagesService.cs b/src/NadekoBot/Services/IImagesService.cs index 192ee842..7d98cd06 100644 --- a/src/NadekoBot/Services/IImagesService.cs +++ b/src/NadekoBot/Services/IImagesService.cs @@ -13,7 +13,8 @@ namespace NadekoBot.Services Stream Heads { get; } Stream Tails { get; } - IImmutableList> CurrencyImages { get; } + IImmutableList> Currency { get; } + IImmutableList> Dice { get; } Task Reload(); } diff --git a/src/NadekoBot/Services/Impl/ImagesService.cs b/src/NadekoBot/Services/Impl/ImagesService.cs index f63e2eb5..80898dc1 100644 --- a/src/NadekoBot/Services/Impl/ImagesService.cs +++ b/src/NadekoBot/Services/Impl/ImagesService.cs @@ -19,16 +19,22 @@ namespace NadekoBot.Services.Impl private const string tailsPath = "data/images/coins/tails.png"; private const string currencyImagesPath = "data/currency_images"; + private const string diceImagesPath = "data/images/dice"; private byte[] heads; public Stream Heads => new MemoryStream(heads, false); private byte[] tails; public Stream Tails => new MemoryStream(tails, false); - //todo tuple - private IReadOnlyDictionary currencyImages; - public IImmutableList> CurrencyImages => - currencyImages.Select(x => new Tuple(x.Key, (Stream)new MemoryStream(x.Value, false))) + //todo C#7 + private IReadOnlyDictionary currency; + public IImmutableList> Currency => + currency.Select(x => new Tuple(x.Key, new MemoryStream(x.Value, false))) + .ToImmutableArray(); + + private IReadOnlyDictionary dice; + public IImmutableList> Dice => + dice.Select(x => new Tuple(x.Key, new MemoryStream(x.Value, false))) .ToImmutableArray(); private ImagesService() @@ -52,7 +58,8 @@ namespace NadekoBot.Services.Impl heads = File.ReadAllBytes(headsPath); tails = File.ReadAllBytes(tailsPath); - currencyImages = Directory.GetFiles(currencyImagesPath).ToDictionary(x => Path.GetFileName(x), x => File.ReadAllBytes(x)); + currency = Directory.GetFiles(currencyImagesPath).ToDictionary(x => Path.GetFileName(x), x => File.ReadAllBytes(x)); + dice = Directory.GetFiles(diceImagesPath).ToDictionary(x => Path.GetFileName(x), x => File.ReadAllBytes(x)); _log.Info($"Images loaded after {sw.Elapsed.TotalSeconds:F2}s!"); } catch (Exception ex) From 5fba2de3a6da273ec5cadbe073e06ae0675c6b8d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 4 Feb 2017 06:44:27 +0100 Subject: [PATCH 165/746] Don't download users. --- 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 a32abc73..49d0d5c4 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -70,7 +70,7 @@ namespace NadekoBot TotalShards = Credentials.TotalShards, ConnectionTimeout = int.MaxValue, #if !GLOBAL_NADEKO - AlwaysDownloadUsers = true, + //AlwaysDownloadUsers = true, #endif }); From d39e544567c9bc5d3c85fff121d6310a4af9e597 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 4 Feb 2017 09:34:51 +0100 Subject: [PATCH 166/746] Images service almost done. Slots images moved to /data/images/slots currency_images renamed to currency and moved to data/images/ --- .../DataStructures/DisposableImutableList.cs | 82 ++++++++++++++++++ .../Administration/Commands/SelfCommands.cs | 6 +- .../Gambling/Commands/DiceRollCommand.cs | 42 ++++----- .../Gambling/Commands/FlipCoinCommand.cs | 38 +++++--- .../Modules/Gambling/Commands/Slots.cs | 60 +++---------- .../Games/Commands/PlantAndPickCommands.cs | 33 +++---- src/NadekoBot/Services/IImagesService.cs | 17 ++-- src/NadekoBot/Services/Impl/ImagesService.cs | 71 ++++++++++----- src/NadekoBot/_Extensions/Extensions.cs | 5 +- .../currency}/img1.jpg | Bin .../currency}/img2.jpg | Bin .../currency}/img3.jpg | Bin .../data/{ => images}/slots/background.png | Bin .../data/{ => images}/slots/emojis/0.png | Bin .../data/{ => images}/slots/emojis/1.png | Bin .../data/{ => images}/slots/emojis/2.png | Bin .../data/{ => images}/slots/emojis/3.png | Bin .../data/{ => images}/slots/emojis/4.png | Bin .../data/{ => images}/slots/emojis/5.png | Bin .../{slots => images/slots/numbers}/0.png | Bin .../{slots => images/slots/numbers}/1.png | Bin .../{slots => images/slots/numbers}/2.png | Bin .../{slots => images/slots/numbers}/3.png | Bin .../{slots => images/slots/numbers}/4.png | Bin .../{slots => images/slots/numbers}/5.png | Bin .../{slots => images/slots/numbers}/6.png | Bin .../{slots => images/slots/numbers}/7.png | Bin .../{slots => images/slots/numbers}/8.png | Bin .../{slots => images/slots/numbers}/9.png | Bin 29 files changed, 228 insertions(+), 126 deletions(-) create mode 100644 src/NadekoBot/DataStructures/DisposableImutableList.cs rename src/NadekoBot/data/{currency_images => images/currency}/img1.jpg (100%) rename src/NadekoBot/data/{currency_images => images/currency}/img2.jpg (100%) rename src/NadekoBot/data/{currency_images => images/currency}/img3.jpg (100%) rename src/NadekoBot/data/{ => images}/slots/background.png (100%) rename src/NadekoBot/data/{ => images}/slots/emojis/0.png (100%) rename src/NadekoBot/data/{ => images}/slots/emojis/1.png (100%) rename src/NadekoBot/data/{ => images}/slots/emojis/2.png (100%) rename src/NadekoBot/data/{ => images}/slots/emojis/3.png (100%) rename src/NadekoBot/data/{ => images}/slots/emojis/4.png (100%) rename src/NadekoBot/data/{ => images}/slots/emojis/5.png (100%) rename src/NadekoBot/data/{slots => images/slots/numbers}/0.png (100%) rename src/NadekoBot/data/{slots => images/slots/numbers}/1.png (100%) rename src/NadekoBot/data/{slots => images/slots/numbers}/2.png (100%) rename src/NadekoBot/data/{slots => images/slots/numbers}/3.png (100%) rename src/NadekoBot/data/{slots => images/slots/numbers}/4.png (100%) rename src/NadekoBot/data/{slots => images/slots/numbers}/5.png (100%) rename src/NadekoBot/data/{slots => images/slots/numbers}/6.png (100%) rename src/NadekoBot/data/{slots => images/slots/numbers}/7.png (100%) rename src/NadekoBot/data/{slots => images/slots/numbers}/8.png (100%) rename src/NadekoBot/data/{slots => images/slots/numbers}/9.png (100%) diff --git a/src/NadekoBot/DataStructures/DisposableImutableList.cs b/src/NadekoBot/DataStructures/DisposableImutableList.cs new file mode 100644 index 00000000..71bda6de --- /dev/null +++ b/src/NadekoBot/DataStructures/DisposableImutableList.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.DataStructures +{ + + public static class DisposableReadOnlyListExtensions + { + public static IDisposableReadOnlyList AsDisposable(this IReadOnlyList arr) where T : IDisposable + => new DisposableReadOnlyList(arr); + + public static IDisposableReadOnlyList> AsDisposable(this IReadOnlyList> arr) where TValue : IDisposable + => new DisposableReadOnlyList(arr); + } + + public interface IDisposableReadOnlyList : IReadOnlyList, IDisposable + { + } + + public class DisposableReadOnlyList : IDisposableReadOnlyList + where T : IDisposable + { + private readonly IReadOnlyList _arr; + + public int Count => _arr.Count; + + public T this[int index] => _arr[index]; + + public DisposableReadOnlyList(IReadOnlyList arr) + { + this._arr = arr; + } + + public IEnumerator GetEnumerator() + => _arr.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + => _arr.GetEnumerator(); + + public void Dispose() + { + foreach (var item in _arr) + { + item.Dispose(); + } + } + } + + public class DisposableReadOnlyList : IDisposableReadOnlyList> + where U : IDisposable + { + private readonly IReadOnlyList> _arr; + + public int Count => _arr.Count; + + KeyValuePair IReadOnlyList>.this[int index] => _arr[index]; + + public DisposableReadOnlyList(IReadOnlyList> arr) + { + this._arr = arr; + } + + public IEnumerator> GetEnumerator() => + _arr.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => + _arr.GetEnumerator(); + + public void Dispose() + { + foreach (var item in _arr) + { + item.Value.Dispose(); + } + } + } +} diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index 137fa10c..80356f73 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -173,10 +173,8 @@ namespace NadekoBot.Modules.Administration [OwnerOnly] public async Task ReloadImages() { - var sw = Stopwatch.StartNew(); - await NadekoBot.Images.Reload().ConfigureAwait(false); - sw.Stop(); - await Context.Channel.SendConfirmAsync("Images Reloaded").ConfigureAwait(false); + var time = await NadekoBot.Images.Reload().ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"Images loaded after {time.TotalSeconds:F3}s!").ConfigureAwait(false); } private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus) diff --git a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs index 01283c83..4616aa91 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs @@ -34,15 +34,11 @@ namespace NadekoBot.Modules.Gambling var num2 = gen % 10; var imageStream = await Task.Run(() => { - try - { - var ms = new MemoryStream(); - new[] { GetDice(num1), GetDice(num2) }.Merge().SaveAsPng(ms); - ms.Position = 0; - return ms; - } - catch { return new MemoryStream(); } - }); + var ms = new MemoryStream(); + new[] { GetDice(num1), GetDice(num2) }.Merge().SaveAsPng(ms); + ms.Position = 0; + return ms; + }).ConfigureAwait(false); await Context.Channel.SendFileAsync(imageStream, "dice.png", $"{Context.User.Mention} rolled " + Format.Code(gen.ToString())).ConfigureAwait(false); } @@ -82,7 +78,7 @@ namespace NadekoBot.Modules.Gambling await InternallDndRoll(arg, false).ConfigureAwait(false); } - private async Task InternalRoll( int num, bool ordered) + private async Task InternalRoll(int num, bool ordered) { if (num < 1 || num > 30) { @@ -209,20 +205,24 @@ namespace NadekoBot.Modules.Gambling private Image GetDice(int num) { - const string pathToImage = "data/images/dice"; - if (num != 10) + if (num < 0 || num > 10) + throw new ArgumentOutOfRangeException(nameof(num)); + + if (num == 10) { - using (var stream = File.OpenRead(Path.Combine(pathToImage, $"{num}.png"))) - return new Image(stream); + var images = NadekoBot.Images.Dice; + using (var imgOneStream = images[1].Value.ToStream()) + using (var imgZeroStream = images[0].Value.ToStream()) + { + Image imgOne = new Image(imgOneStream); + Image imgZero = new Image(imgZeroStream); + + return new[] { imgOne, imgZero }.Merge(); + } } - - using (var one = File.OpenRead(Path.Combine(pathToImage, "1.png"))) - using (var zero = File.OpenRead(Path.Combine(pathToImage, "0.png"))) + using (var die = NadekoBot.Images.Dice[num].Value.ToStream()) { - Image imgOne = new Image(one); - Image imgZero = new Image(zero); - - return new[] { imgOne, imgZero }.Merge(); + return new Image(die); } } } diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs index 74e201c0..6ccfe786 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs @@ -5,6 +5,7 @@ using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; using System; +using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Image = ImageSharp.Image; @@ -32,9 +33,19 @@ namespace NadekoBot.Modules.Gambling if (count == 1) { if (rng.Next(0, 2) == 1) - await Context.Channel.SendFileAsync(_images.Heads, "heads.jpg", $"{Context.User.Mention} flipped " + Format.Code("Heads") + ".").ConfigureAwait(false); + { + using (var heads = _images.Heads.ToStream()) + { + await Context.Channel.SendFileAsync(heads, "heads.jpg", $"{Context.User.Mention} flipped " + Format.Code("Heads") + ".").ConfigureAwait(false); + } + } else - await Context.Channel.SendFileAsync(_images.Tails, "tails.jpg", $"{Context.User.Mention} flipped " + Format.Code("Tails") + ".").ConfigureAwait(false); + { + using (var tails = _images.Tails.ToStream()) + { + await Context.Channel.SendFileAsync(tails, "tails.jpg", $"{Context.User.Mention} flipped " + Format.Code("Tails") + ".").ConfigureAwait(false); + } + } return; } if (count > 10 || count < 1) @@ -43,13 +54,17 @@ namespace NadekoBot.Modules.Gambling return; } var imgs = new Image[count]; - for (var i = 0; i < count; i++) + using (var heads = _images.Heads.ToStream()) + using(var tails = _images.Tails.ToStream()) { - imgs[i] = rng.Next(0, 10) < 5 ? - new Image(_images.Heads) : - new Image(_images.Tails); + for (var i = 0; i < count; i++) + { + imgs[i] = rng.Next(0, 10) < 5 ? + new Image(heads) : + new Image(tails); + } + await Context.Channel.SendFileAsync(imgs.Merge().ToStream(), $"{count} coins.png").ConfigureAwait(false); } - await Context.Channel.SendFileAsync(imgs.Merge().ToStream(), $"{count} coins.png").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -74,9 +89,10 @@ namespace NadekoBot.Modules.Gambling //heads = true //tails = false + //todo this seems stinky, no time to look at it right now var isHeads = guessStr == "HEADS" || guessStr == "H"; bool result = false; - Stream imageToSend; + IEnumerable imageToSend; if (rng.Next(0, 2) == 1) { imageToSend = _images.Heads; @@ -98,8 +114,10 @@ namespace NadekoBot.Modules.Gambling { str = $"{Context.User.Mention}`Better luck next time.`"; } - - await Context.Channel.SendFileAsync(imageToSend, "result.png", str).ConfigureAwait(false); + using (var toSend = imageToSend.ToStream()) + { + await Context.Channel.SendFileAsync(toSend, "result.png", str).ConfigureAwait(false); + } } } } diff --git a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs index e1671a6d..445d6c48 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs @@ -21,52 +21,19 @@ namespace NadekoBot.Modules.Gambling 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 + private readonly IImagesService _images; + + public Slots() + { + this._images = NadekoBot.Images; + } + public class SlotMachine { public const int MaxValue = 5; @@ -154,7 +121,7 @@ namespace NadekoBot.Modules.Gambling var sb = new StringBuilder(); const int bet = 1; int payout = 0; - foreach (var key in dict.Keys.OrderByDescending(x=>x)) + 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]; @@ -164,6 +131,7 @@ namespace NadekoBot.Modules.Gambling } static HashSet runningUsers = new HashSet(); + [NadekoCommand, Usage, Description, Aliases] public async Task Slot(int amount = 0) { @@ -189,7 +157,7 @@ namespace NadekoBot.Modules.Gambling return; } Interlocked.Add(ref totalBet, amount); - using (var bgFileStream = new MemoryStream(backgroundBuffer)) + using (var bgFileStream = NadekoBot.Images.SlotBackground.ToStream()) { var bgImage = new ImageSharp.Image(bgFileStream); @@ -199,7 +167,7 @@ namespace NadekoBot.Modules.Gambling { for (int i = 0; i < 3; i++) { - using (var file = new MemoryStream(emojiBuffer[numbers[i]])) + using (var file = _images.SlotEmojis[numbers[i]].ToStream()) { var randomImage = new ImageSharp.Image(file); using (var toAdd = randomImage.Lock()) @@ -226,7 +194,7 @@ namespace NadekoBot.Modules.Gambling do { var digit = printWon % 10; - using (var fs = new MemoryStream(numbersBuffer[digit])) + using (var fs = NadekoBot.Images.SlotNumbers[digit].ToStream()) { var img = new ImageSharp.Image(fs); using (var pixels = img.Lock()) @@ -251,7 +219,7 @@ namespace NadekoBot.Modules.Gambling do { var digit = printAmount % 10; - using (var fs = new MemoryStream(numbersBuffer[digit])) + using (var fs = _images.SlotNumbers[digit].ToStream()) { var img = new ImageSharp.Image(fs); using (var pixels = img.Lock()) @@ -301,4 +269,4 @@ namespace NadekoBot.Modules.Gambling } } } -} +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 0ae16be6..1c8671f8 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -10,6 +10,7 @@ using NLog; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.IO; using System.Linq; @@ -97,13 +98,16 @@ namespace NadekoBot.Modules.Games firstPart = $"{dropAmount} random { NadekoBot.BotConfig.CurrencyPluralName } appeared!"; } var file = GetRandomCurrencyImage(); - var sent = await channel.SendFileAsync( - file.Item2, - file.Item1, - $"❗ {firstPart} Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`") - .ConfigureAwait(false); + using (var fileStream = file.Value.ToStream()) + { + var sent = await channel.SendFileAsync( + fileStream, + file.Key, + $"❗ {firstPart} Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`") + .ConfigureAwait(false); - msgs[0] = sent; + msgs[0] = sent; + } plantedFlowers.AddOrUpdate(channel.Id, msgs.ToList(), (id, old) => { old.AddRange(msgs); return old; }); } @@ -167,18 +171,15 @@ namespace NadekoBot.Modules.Games return; } - var file = GetRandomCurrencyImage(); - IUserMessage msg; + var imgData = GetRandomCurrencyImage(); var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.BotConfig.CurrencyName[0]); var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(amount == 1 ? (vowelFirst ? "an" : "a") : amount.ToString())} {(amount > 1 ? NadekoBot.BotConfig.CurrencyPluralName : NadekoBot.BotConfig.CurrencyName)}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick"; - if (file == null) + + IUserMessage msg; + using (var toSend = imgData.Value.ToStream()) { - msg = await Context.Channel.SendConfirmAsync(NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); - } - else - { - msg = await Context.Channel.SendFileAsync(file.Item2, file.Item1, msgToSend).ConfigureAwait(false); + msg = await Context.Channel.SendFileAsync(toSend, imgData.Key, msgToSend).ConfigureAwait(false); } var msgs = new IUserMessage[amount]; @@ -228,12 +229,12 @@ namespace NadekoBot.Modules.Games } } - private static Tuple GetRandomCurrencyImage() + private static KeyValuePair> GetRandomCurrencyImage() { var rng = new NadekoRandom(); var images = NadekoBot.Images.Currency; - return images[rng.Next(0, images.Count)]; + return images[rng.Next(0, images.Length)]; } int GetRandomNumber() diff --git a/src/NadekoBot/Services/IImagesService.cs b/src/NadekoBot/Services/IImagesService.cs index 7d98cd06..81e21907 100644 --- a/src/NadekoBot/Services/IImagesService.cs +++ b/src/NadekoBot/Services/IImagesService.cs @@ -1,4 +1,5 @@ -using System; +using NadekoBot.DataStructures; +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; @@ -10,12 +11,16 @@ namespace NadekoBot.Services { public interface IImagesService { - Stream Heads { get; } - Stream Tails { get; } + ImmutableArray Heads { get; } + ImmutableArray Tails { get; } - IImmutableList> Currency { get; } - IImmutableList> Dice { get; } + ImmutableArray>> Currency { get; } + ImmutableArray>> Dice { get; } - Task Reload(); + ImmutableArray SlotBackground { get; } + ImmutableArray> SlotEmojis { get; } + ImmutableArray> SlotNumbers { get; } + + Task Reload(); } } diff --git a/src/NadekoBot/Services/Impl/ImagesService.cs b/src/NadekoBot/Services/Impl/ImagesService.cs index 80898dc1..02bcb1cd 100644 --- a/src/NadekoBot/Services/Impl/ImagesService.cs +++ b/src/NadekoBot/Services/Impl/ImagesService.cs @@ -1,4 +1,5 @@ -using NLog; +using NadekoBot.DataStructures; +using NLog; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -15,27 +16,30 @@ namespace NadekoBot.Services.Impl { private readonly Logger _log; - private const string headsPath = "data/images/coins/heads.png"; - private const string tailsPath = "data/images/coins/tails.png"; + private const string basePath = "data/images/"; - private const string currencyImagesPath = "data/currency_images"; - private const string diceImagesPath = "data/images/dice"; + private const string headsPath = basePath + "coins/heads.png"; + private const string tailsPath = basePath + "coins/tails.png"; - private byte[] heads; - public Stream Heads => new MemoryStream(heads, false); + private const string currencyImagesPath = basePath + "currency"; + private const string diceImagesPath = basePath + "dice"; + + private const string slotBackgroundPath = basePath + "slots/background.png"; + private const string slotNumbersPath = basePath + "slots/numbers/"; + private const string slotEmojisPath = basePath + "slots/emojis/"; + + + public ImmutableArray Heads { get; private set; } + public ImmutableArray Tails { get; private set; } - private byte[] tails; - public Stream Tails => new MemoryStream(tails, false); //todo C#7 - private IReadOnlyDictionary currency; - public IImmutableList> Currency => - currency.Select(x => new Tuple(x.Key, new MemoryStream(x.Value, false))) - .ToImmutableArray(); + public ImmutableArray>> Currency { get; private set; } - private IReadOnlyDictionary dice; - public IImmutableList> Dice => - dice.Select(x => new Tuple(x.Key, new MemoryStream(x.Value, false))) - .ToImmutableArray(); + public ImmutableArray>> Dice { get; private set; } + + public ImmutableArray SlotBackground { get; private set; } + public ImmutableArray> SlotNumbers { get; private set; } + public ImmutableArray> SlotEmojis { get; private set; } private ImagesService() { @@ -49,18 +53,41 @@ namespace NadekoBot.Services.Impl return srvc; } - public Task Reload() => Task.Run(() => + public Task Reload() => Task.Run(() => { try { _log.Info("Loading images..."); var sw = Stopwatch.StartNew(); - heads = File.ReadAllBytes(headsPath); - tails = File.ReadAllBytes(tailsPath); + Heads = File.ReadAllBytes(headsPath).ToImmutableArray(); + Tails = File.ReadAllBytes(tailsPath).ToImmutableArray(); - currency = Directory.GetFiles(currencyImagesPath).ToDictionary(x => Path.GetFileName(x), x => File.ReadAllBytes(x)); - dice = Directory.GetFiles(diceImagesPath).ToDictionary(x => Path.GetFileName(x), x => File.ReadAllBytes(x)); + Currency = Directory.GetFiles(currencyImagesPath) + .Select(x => new KeyValuePair>( + Path.GetFileName(x), + File.ReadAllBytes(x).ToImmutableArray())) + .ToImmutableArray(); + + Dice = Directory.GetFiles(diceImagesPath) + .OrderBy(x => int.Parse(Path.GetFileNameWithoutExtension(x))) + .Select(x => new KeyValuePair>(x, + File.ReadAllBytes(x).ToImmutableArray())) + .ToImmutableArray(); + + SlotBackground = File.ReadAllBytes(slotBackgroundPath).ToImmutableArray(); + + SlotNumbers = Directory.GetFiles(slotNumbersPath) + .OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f))) + .Select(x => File.ReadAllBytes(x).ToImmutableArray()) + .ToImmutableArray(); + + SlotEmojis = Directory.GetFiles(slotEmojisPath) + .Select(x => File.ReadAllBytes(x).ToImmutableArray()) + .ToImmutableArray(); + + sw.Stop(); _log.Info($"Images loaded after {sw.Elapsed.TotalSeconds:F2}s!"); + return sw.Elapsed; } catch (Exception ex) { diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index 56479a6f..4c32a542 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -20,7 +20,10 @@ namespace NadekoBot.Extensions { private const string arrow_left = "⬅"; private const string arrow_right = "➡"; - + + public static Stream ToStream(this IEnumerable bytes, bool canWrite = false) + => new MemoryStream(bytes as byte[] ?? bytes.ToArray(), canWrite); + /// /// danny kamisama /// diff --git a/src/NadekoBot/data/currency_images/img1.jpg b/src/NadekoBot/data/images/currency/img1.jpg similarity index 100% rename from src/NadekoBot/data/currency_images/img1.jpg rename to src/NadekoBot/data/images/currency/img1.jpg diff --git a/src/NadekoBot/data/currency_images/img2.jpg b/src/NadekoBot/data/images/currency/img2.jpg similarity index 100% rename from src/NadekoBot/data/currency_images/img2.jpg rename to src/NadekoBot/data/images/currency/img2.jpg diff --git a/src/NadekoBot/data/currency_images/img3.jpg b/src/NadekoBot/data/images/currency/img3.jpg similarity index 100% rename from src/NadekoBot/data/currency_images/img3.jpg rename to src/NadekoBot/data/images/currency/img3.jpg diff --git a/src/NadekoBot/data/slots/background.png b/src/NadekoBot/data/images/slots/background.png similarity index 100% rename from src/NadekoBot/data/slots/background.png rename to src/NadekoBot/data/images/slots/background.png diff --git a/src/NadekoBot/data/slots/emojis/0.png b/src/NadekoBot/data/images/slots/emojis/0.png similarity index 100% rename from src/NadekoBot/data/slots/emojis/0.png rename to src/NadekoBot/data/images/slots/emojis/0.png diff --git a/src/NadekoBot/data/slots/emojis/1.png b/src/NadekoBot/data/images/slots/emojis/1.png similarity index 100% rename from src/NadekoBot/data/slots/emojis/1.png rename to src/NadekoBot/data/images/slots/emojis/1.png diff --git a/src/NadekoBot/data/slots/emojis/2.png b/src/NadekoBot/data/images/slots/emojis/2.png similarity index 100% rename from src/NadekoBot/data/slots/emojis/2.png rename to src/NadekoBot/data/images/slots/emojis/2.png diff --git a/src/NadekoBot/data/slots/emojis/3.png b/src/NadekoBot/data/images/slots/emojis/3.png similarity index 100% rename from src/NadekoBot/data/slots/emojis/3.png rename to src/NadekoBot/data/images/slots/emojis/3.png diff --git a/src/NadekoBot/data/slots/emojis/4.png b/src/NadekoBot/data/images/slots/emojis/4.png similarity index 100% rename from src/NadekoBot/data/slots/emojis/4.png rename to src/NadekoBot/data/images/slots/emojis/4.png diff --git a/src/NadekoBot/data/slots/emojis/5.png b/src/NadekoBot/data/images/slots/emojis/5.png similarity index 100% rename from src/NadekoBot/data/slots/emojis/5.png rename to src/NadekoBot/data/images/slots/emojis/5.png diff --git a/src/NadekoBot/data/slots/0.png b/src/NadekoBot/data/images/slots/numbers/0.png similarity index 100% rename from src/NadekoBot/data/slots/0.png rename to src/NadekoBot/data/images/slots/numbers/0.png diff --git a/src/NadekoBot/data/slots/1.png b/src/NadekoBot/data/images/slots/numbers/1.png similarity index 100% rename from src/NadekoBot/data/slots/1.png rename to src/NadekoBot/data/images/slots/numbers/1.png diff --git a/src/NadekoBot/data/slots/2.png b/src/NadekoBot/data/images/slots/numbers/2.png similarity index 100% rename from src/NadekoBot/data/slots/2.png rename to src/NadekoBot/data/images/slots/numbers/2.png diff --git a/src/NadekoBot/data/slots/3.png b/src/NadekoBot/data/images/slots/numbers/3.png similarity index 100% rename from src/NadekoBot/data/slots/3.png rename to src/NadekoBot/data/images/slots/numbers/3.png diff --git a/src/NadekoBot/data/slots/4.png b/src/NadekoBot/data/images/slots/numbers/4.png similarity index 100% rename from src/NadekoBot/data/slots/4.png rename to src/NadekoBot/data/images/slots/numbers/4.png diff --git a/src/NadekoBot/data/slots/5.png b/src/NadekoBot/data/images/slots/numbers/5.png similarity index 100% rename from src/NadekoBot/data/slots/5.png rename to src/NadekoBot/data/images/slots/numbers/5.png diff --git a/src/NadekoBot/data/slots/6.png b/src/NadekoBot/data/images/slots/numbers/6.png similarity index 100% rename from src/NadekoBot/data/slots/6.png rename to src/NadekoBot/data/images/slots/numbers/6.png diff --git a/src/NadekoBot/data/slots/7.png b/src/NadekoBot/data/images/slots/numbers/7.png similarity index 100% rename from src/NadekoBot/data/slots/7.png rename to src/NadekoBot/data/images/slots/numbers/7.png diff --git a/src/NadekoBot/data/slots/8.png b/src/NadekoBot/data/images/slots/numbers/8.png similarity index 100% rename from src/NadekoBot/data/slots/8.png rename to src/NadekoBot/data/images/slots/numbers/8.png diff --git a/src/NadekoBot/data/slots/9.png b/src/NadekoBot/data/images/slots/numbers/9.png similarity index 100% rename from src/NadekoBot/data/slots/9.png rename to src/NadekoBot/data/images/slots/numbers/9.png From cfb874475f28fb706338a6e6c215ef44543e3396 Mon Sep 17 00:00:00 2001 From: samvaio Date: Sat, 4 Feb 2017 14:19:35 +0530 Subject: [PATCH 167/746] changed a lil --- docs/guides/Linux Guide.md | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/docs/guides/Linux Guide.md b/docs/guides/Linux Guide.md index 8e01383e..1ba7e0c0 100644 --- a/docs/guides/Linux Guide.md +++ b/docs/guides/Linux Guide.md @@ -103,26 +103,12 @@ You will be asked to enter the required informations, just follow the on-screen (If you want to skip any optional infos, just press `enter` key without typing/pasting anything.) Once done, #####Part V -You should see the options again within the **`tmux` session** named `nadeko` *(remember this one)* +You should see the options again. Next, press `3` to **Run Nadeko (Normally)** Check in your discord server if your new bot is working properly. #####Part VI -If your bot is working properly in your server, type `.die` to shut down the bot. - -You should be back to the options screen again on **PuTTY**, -from the options choose `4` to **Run Nadeko with Auto Restart.** - -It will show you more options: -``` -1. Run Auto Restart normally without Updating. -2. Auto Restart and Update with Dev Build (latest) -3. Auto Restart and Update with Stable Build -4. Exit -``` -Choose anything you like and once the bot's back online again in your server, close the **PuTTY**. - -**Done**, You now have your own **NadekoBot**. - +If your bot is working properly in your server, type `.die` to **shut down the bot**, then press `7` to **exit**. +Next, [Run your bot again with **tmux**.](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#running-nadekobot) [Check this when you need to **restart** your **NadekoBot** anytime later along with tmux session.](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#restarting-nadeko) @@ -138,12 +124,19 @@ The above command will create a new session named **nadeko** *(you can replace - `cd ~ && bash linuxAIO.sh` -From the options, +**From the options,** -Choose `3` To Run the bot normally. +Choose `3` to **Run NadekoBot normally.** **NOTE:** With option `3` (Running Normally), if you use `.die` [command](http://nadekobot.readthedocs.io/en/latest/Commands%20List/#administration) in discord. The bot will shut down and will stay offline until you manually run it again. (best if you want to check the bot.) -Choose `4` To Run the bot with Auto Restart. +Choose `4` to **Run NadekoBot with Auto Restart.** +It will show you more options: +``` +1. Run Auto Restart normally without Updating. +2. Auto Restart and Update with Dev Build (latest) +3. Auto Restart and Update with Stable Build +4. Exit +``` **NOTE:** With option `4` (Running with Auto Restart), bot will auto run if you use `.die` [command](http://nadekobot.readthedocs.io/en/latest/Commands%20List/#administration) making the command `.die` to function as restart. See how that happens: @@ -154,7 +147,7 @@ See how that happens: **Now check your Discord, the bot should be online** -Next to **move the bot to background** and to do that, press **CTRL+B+D** (this will detach the nadeko session using TMUX), and you can finally close PuTTY now. +Next to **move the bot to background** and to do that, press **CTRL+B+D** (that will detach the nadeko session using TMUX) and you can finally close **PuTTY** if you want. ####Restarting Nadeko From 1fe9f596fdcc3c64af47a1394f41662f405397ef Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 4 Feb 2017 18:19:03 +0100 Subject: [PATCH 168/746] .shardstats added --- src/NadekoBot/Modules/Utility/Utility.cs | 35 ++++++++++++++++--- .../Resources/CommandStrings.Designer.cs | 27 ++++++++++++++ src/NadekoBot/Resources/CommandStrings.resx | 9 +++++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 1c1af1e0..ddb34011 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -279,11 +279,41 @@ namespace NadekoBot.Modules.Utility await Context.Channel.SendConfirmAsync($"{Context.User.Mention} https://discord.gg/{invite.Code}"); } + [NadekoCommand, Usage, Description, Aliases] + public async Task ShardStats(int page = 1) + { + page -= 1; + if (page < 0) + return; + + var shards = NadekoBot.Client.Shards.Skip(page * 25).Take(25); + + var info = string.Join("\n", + shards.Select(x => $"Shard **#{x.ShardId.ToString()}** is in {Format.Bold(x.ConnectionState.ToString())} state with {Format.Bold(x.Guilds.Count.ToString())} servers")); + + if (string.IsNullOrWhiteSpace(info)) + info = "No shard stats on this page."; + + await Context.Channel.EmbedAsync(new EmbedBuilder() + .WithOkColor() + .WithTitle("Shard Stats - page " + (page + 1)) + .WithDescription(info)) + .ConfigureAwait(false); + } + [NadekoCommand, Usage, Description, Aliases] public async Task Stats() { var stats = NadekoBot.Stats; + var shardId = Context.Guild != null + ? NadekoBot.Client.GetShardIdFor(Context.Guild.Id) + : 0; + var footer = $"Shard {shardId} | {NadekoBot.Client.Shards.Count} total shards"; +#if !GLOBAL_NADEKO + footer += $" | Playing {Music.Music.MusicPlayers.Where(mp => mp.Value.CurrentSong != null).Count()} songs, {Music.Music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count)} queued."; +#endif + await Context.Channel.EmbedAsync( new EmbedBuilder().WithOkColor() .WithAuthor(eab => eab.WithName($"NadekoBot v{StatsService.BotVersion}") @@ -298,10 +328,7 @@ namespace NadekoBot.Modules.Utility .AddField(efb => efb.WithName(Format.Bold("Owner ID(s)")).WithValue(string.Join("\n", NadekoBot.Credentials.OwnerIds)).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Uptime")).WithValue(stats.GetUptimeString("\n")).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Presence")).WithValue($"{NadekoBot.Client.GetGuildCount()} Servers\n{stats.TextChannels} Text Channels\n{stats.VoiceChannels} Voice Channels").WithIsInline(true)) -#if !GLOBAL_NADEKO - .WithFooter(efb => efb.WithText($"Playing {Music.Music.MusicPlayers.Where(mp => mp.Value.CurrentSong != null).Count()} songs, {Music.Music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count)} queued.")) -#endif - ); + .WithFooter(efb => efb.WithText(footer))); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 634991da..0a7ff768 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -7025,6 +7025,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to shardstats. + /// + public static string shardstats_cmd { + get { + return ResourceManager.GetString("shardstats_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stats for shards. Paginated with 25 shards per page.. + /// + public static string shardstats_desc { + get { + return ResourceManager.GetString("shardstats_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}shardstats` or `{0}shardstats 2`. + /// + public static string shardstats_usage { + get { + return ResourceManager.GetString("shardstats_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to shorten. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 9b0b01be..d6074104 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3051,4 +3051,13 @@ `{0}reloadimages` + + shardstats + + + Stats for shards. Paginated with 25 shards per page. + + + `{0}shardstats` or `{0}shardstats 2` + \ No newline at end of file From 58f23ff40b72fcfb97e674d17e2e38a7518ea2a8 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 4 Feb 2017 18:45:07 +0100 Subject: [PATCH 169/746] .connectshard added --- .../Administration/Commands/SelfCommands.cs | 23 ++++++++++++++++ .../Resources/CommandStrings.Designer.cs | 27 +++++++++++++++++++ src/NadekoBot/Resources/CommandStrings.resx | 9 +++++++ 3 files changed, 59 insertions(+) diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index 80356f73..fb316beb 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -16,6 +16,29 @@ namespace NadekoBot.Modules.Administration [Group] class SelfCommands : ModuleBase { + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task ConnectShard(int shardid) + { + var shard = NadekoBot.Client.GetShard(shardid); + + if (shard == null) + { + await Context.Channel.SendErrorAsync("No shard by that id found.").ConfigureAwait(false); + return; + } + try + { + await Context.Channel.SendConfirmAsync($"Shard **#{shardid}** reconnecting.").ConfigureAwait(false); + await shard.ConnectAsync().ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"Shard **#{shardid}** reconnected.").ConfigureAwait(false); + } + catch (Exception ex) + { + _log.Warn(ex); + } + } + [NadekoCommand, Usage, Description, Aliases] [OwnerOnly] public async Task Leave([Remainder] string guildStr) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 0a7ff768..2be25567 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -1868,6 +1868,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to connectshard. + /// + public static string connectshard_cmd { + get { + return ResourceManager.GetString("connectshard_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors.. + /// + public static string connectshard_desc { + get { + return ResourceManager.GetString("connectshard_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}connectshard 2`. + /// + public static string connectshard_usage { + get { + return ResourceManager.GetString("connectshard_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to convert. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index d6074104..a0cd8924 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3060,4 +3060,13 @@ `{0}shardstats` or `{0}shardstats 2` + + connectshard + + + Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. + + + `{0}connectshard 2` + \ No newline at end of file From 1e5b7df47f5e29dfd5dff6b9aa3f8976b5de5a7b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 5 Feb 2017 06:36:07 +0100 Subject: [PATCH 170/746] `.shardid guildid` added, .ropl fixed --- Discord.Net | 2 +- .../Commands/PlayingRotateCommands.cs | 19 ++++++++++++------- src/NadekoBot/Modules/Utility/Utility.cs | 8 ++++++++ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Discord.Net b/Discord.Net index 0fd1e70a..9ce5c475 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit 0fd1e70a22612ff9fa697dace96f22780080b01f +Subproject commit 9ce5c4757efc6cb6bb8959e851abcdcbe03217be diff --git a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs index 7fff2dc6..371a6d6b 100644 --- a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs @@ -24,7 +24,12 @@ namespace NadekoBot.Modules.Administration public static List RotatingStatusMessages { get; } public static bool RotatingStatuses { get; private set; } = false; private static Timer _t { get; } - + + private class TimerState + { + public int Index { get; set; } = 0; + } + static PlayingRotateCommands() { _log = LogManager.GetCurrentClassLogger(); @@ -34,21 +39,21 @@ namespace NadekoBot.Modules.Administration - _t = new Timer(async (_) => + _t = new Timer(async (objState) => { - var index = 0; try { + var state = (TimerState)objState; if (!RotatingStatuses) return; else { - if (index >= RotatingStatusMessages.Count) - index = 0; + if (state.Index >= RotatingStatusMessages.Count) + state.Index = 0; if (!RotatingStatusMessages.Any()) return; - var status = RotatingStatusMessages[index++].Status; + var status = RotatingStatusMessages[state.Index++].Status; if (string.IsNullOrWhiteSpace(status)) return; PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value())); @@ -68,7 +73,7 @@ namespace NadekoBot.Modules.Administration { _log.Warn("Rotating playing status errored.\n" + ex); } - }, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); + }, new TimerState(), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); } public static Dictionary> PlayingPlaceholders { get; } = diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index ddb34011..01f91b67 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -301,6 +301,14 @@ namespace NadekoBot.Modules.Utility .ConfigureAwait(false); } + [NadekoCommand, Usage, Description, Aliases] + public async Task ShardId(ulong guildid) + { + var shardId = NadekoBot.Client.GetShardIdFor(guildid); + + await Context.Channel.SendConfirmAsync($"ShardId for **{guildid}** with {NadekoBot.Client.Shards.Count} total shards", shardId.ToString()).ConfigureAwait(false); + } + [NadekoCommand, Usage, Description, Aliases] public async Task Stats() { From 22eb42ff8f7ff43fee4b96962b6468a1bc08bacb Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 5 Feb 2017 07:52:39 +0100 Subject: [PATCH 171/746] !!smq can now be used on it's own and act like !!smq 0 (reset max queue) --- 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 5ad9918c..c6746996 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -556,7 +556,7 @@ namespace NadekoBot.Modules.Music [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task SetMaxQueue(uint size) + public async Task SetMaxQueue(uint size = 0) { MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) From 871237af4e2e8fbd23460128f8e3f06ca941784f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 5 Feb 2017 09:09:18 +0100 Subject: [PATCH 172/746] $slot cooldown reduced to 2 seconds. .v+t roles now have no permissions --- .../Modules/Administration/Commands/VoicePlusTextCommands.cs | 2 +- src/NadekoBot/Modules/Gambling/Commands/Slots.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs index d0c905bb..392b4e88 100644 --- a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs @@ -108,7 +108,7 @@ namespace NadekoBot.Modules.Administration var roleName = GetRoleName(afterVch); IRole roleToAdd = guild.Roles.FirstOrDefault(x => x.Name == roleName); if (roleToAdd == null) - roleToAdd = await guild.CreateRoleAsync(roleName).ConfigureAwait(false); + roleToAdd = await guild.CreateRoleAsync(roleName, GuildPermissions.None).ConfigureAwait(false); ITextChannel textChannel = guild.TextChannels .Where(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant()) diff --git a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs index 445d6c48..989d3789 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs @@ -262,7 +262,7 @@ namespace NadekoBot.Modules.Gambling { var t = Task.Run(async () => { - await Task.Delay(3000); + await Task.Delay(2000); runningUsers.Remove(Context.User.Id); }); } From 7e79dd416320a2cf20966daa6186841f0adbc308 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 5 Feb 2017 10:06:36 +0100 Subject: [PATCH 173/746] $waifuinfo will update target user's username and discrimnator in case they changed --- .../Modules/Gambling/Commands/WaifuClaimCommands.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs index f5a2a454..f04ebda8 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs @@ -403,6 +403,7 @@ namespace NadekoBot.Modules.Gambling x.UpdateType == WaifuUpdateType.Claimed && x.New == null); if (w == null) + { uow.Waifus.Add(w = new WaifuInfo() { Affinity = null, @@ -410,6 +411,10 @@ namespace NadekoBot.Modules.Gambling Price = 1, Waifu = uow.DiscordUsers.GetOrCreate(target), }); + } + + w.Waifu.Username = target.Username; + w.Waifu.Discriminator = target.Discriminator; await uow.CompleteAsync().ConfigureAwait(false); } From 3388005edbf0705a83d612f7908344ae04f243a9 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 5 Feb 2017 19:15:05 +0100 Subject: [PATCH 174/746] just a bit better console output --- .../Resources/CommandStrings.Designer.cs | 27 +++++++++++++++++ src/NadekoBot/Resources/CommandStrings.resx | 9 ++++++ src/NadekoBot/Services/CommandHandler.cs | 29 ++++++++++++++----- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 2be25567..6c880516 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -7052,6 +7052,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to shardid. + /// + public static string shardid_cmd { + get { + return ResourceManager.GetString("shardid_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows which shard is a certain guild on, by guildid.. + /// + public static string shardid_desc { + get { + return ResourceManager.GetString("shardid_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}shardid 117523346618318850`. + /// + public static string shardid_usage { + get { + return ResourceManager.GetString("shardid_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to shardstats. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index a0cd8924..0f03e989 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3069,4 +3069,13 @@ `{0}connectshard 2` + + shardid + + + Shows which shard is a certain guild on, by guildid. + + + `{0}shardid 117523346618318850` + \ No newline at end of file diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 8cc68001..ac0a5b80 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -105,9 +105,9 @@ namespace NadekoBot.Services BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id); const float oneThousandth = 1.0f / 1000; - private Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int ticks) + private Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int exec1, int exec2, int exec3, int total) { - _log.Info("Command Executed after {4}s\n\t" + + _log.Info("Command Executed after {4}/{5}/{6}/{7}s\n\t" + "User: {0}\n\t" + "Server: {1}\n\t" + "Channel: {2}\n\t" + @@ -116,13 +116,17 @@ namespace NadekoBot.Services (channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1} (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2} usrMsg.Content, // {3} - ticks * oneThousandth); + exec1 * oneThousandth, // {4} + exec2 * oneThousandth, // {5} + exec3 * oneThousandth, // {6} + total * oneThousandth // {7} + ); return Task.CompletedTask; } - private void LogErroredExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int ticks) + private void LogErroredExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int exec1, int exec2, int exec3, int total) { - _log.Warn("Command Errored after {5}s\n\t" + + _log.Warn("Command Errored after {5}/{6}/{7}/{8}s\n\t" + "User: {0}\n\t" + "Server: {1}\n\t" + "Channel: {2}\n\t" + @@ -133,7 +137,10 @@ namespace NadekoBot.Services (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2} usrMsg.Content,// {3} exec.Result.ErrorReason, // {4} - ticks * oneThousandth // {5} + exec1 * oneThousandth, // {5} + exec2 * oneThousandth, // {6} + exec3 * oneThousandth, // {7} + total * oneThousandth // {8} ); } @@ -219,16 +226,22 @@ namespace NadekoBot.Services if (IsBlacklisted(guild, usrMsg)) return; + var exec1 = Environment.TickCount - execTime; + var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false); if (cleverBotRan) return; + var exec2 = Environment.TickCount - execTime; + // maybe this message is a custom reaction // todo log custom reaction executions. return struct with info var crExecuted = await Task.Run(() => CustomReactions.TryExecuteCustomReaction(usrMsg)).ConfigureAwait(false); if (crExecuted) //if it was, don't execute the command return; + var exec3 = Environment.TickCount - execTime; + string messageContent = usrMsg.Content; // execute the command and measure the time it took @@ -238,11 +251,11 @@ namespace NadekoBot.Services if (exec.Result.IsSuccess) { await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false); - await LogSuccessfulExecution(usrMsg, exec, channel, execTime).ConfigureAwait(false); + await LogSuccessfulExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime).ConfigureAwait(false); } else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand) { - LogErroredExecution(usrMsg, exec, channel, execTime); + LogErroredExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime); if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception) { if (exec.PermissionCache != null && exec.PermissionCache.Verbose) From fbd32a679728fef0752393214654da80713be65a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 5 Feb 2017 19:47:36 +0100 Subject: [PATCH 175/746] disabled %rnduser% completely due to performance issues --- .../Modules/CustomReactions/Extensions.cs | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/NadekoBot/Modules/CustomReactions/Extensions.cs b/src/NadekoBot/Modules/CustomReactions/Extensions.cs index ff20fa89..a0b91962 100644 --- a/src/NadekoBot/Modules/CustomReactions/Extensions.cs +++ b/src/NadekoBot/Modules/CustomReactions/Extensions.cs @@ -23,17 +23,24 @@ namespace NadekoBot.Modules.CustomReactions {"%mention%", (ctx) => { return $"<@{NadekoBot.Client.CurrentUser.Id}>"; } }, {"%user%", (ctx) => { return ctx.Author.Mention; } }, {"%rnduser%", (ctx) => { - var ch = ctx.Channel as ITextChannel; - if(ch == null) - return ""; + //var ch = ctx.Channel as ITextChannel; + //if(ch == null) + // return ""; - var g = ch.Guild as SocketGuild; - if(g == null) - return ""; + //var g = ch.Guild as SocketGuild; + //if(g == null) + // return ""; + //try { + // var usr = g.Users.Skip(new NadekoRandom().Next(0, g.Users.Count)).FirstOrDefault(); + // return usr.Mention; + //} + //catch { + return "[%rnduser% is temp. disabled]"; + //} - var users = g.Users.ToArray(); + //var users = g.Users.ToArray(); - return users[new NadekoRandom().Next(0, users.Length-1)].Mention; + //return users[new NadekoRandom().Next(0, users.Length-1)].Mention; } } //{"%rng%", (ctx) => { return new NadekoRandom().Next(0,10).ToString(); } } }; From ad3dd61d26ca95e3a366192c746ecf261ae591d0 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 6 Feb 2017 07:53:27 +0100 Subject: [PATCH 176/746] rule34, e621 back on public bot --- src/NadekoBot/Modules/NSFW/NSFW.cs | 12 +++---- src/NadekoBot/Modules/Utility/Utility.cs | 43 ++++++++++++++++++++---- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index 9698379a..fe81fa49 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -147,11 +147,7 @@ namespace NadekoBot.Modules.NSFW [NadekoCommand, Usage, Description, Aliases] public Task Konachan([Remainder] string tag = null) => Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Konachan); - - [NadekoCommand, Usage, Description, Aliases] - public Task Rule34([Remainder] string tag = null) - => Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Rule34); - +#endif [NadekoCommand, Usage, Description, Aliases] public async Task E621([Remainder] string tag = null) { @@ -168,7 +164,11 @@ namespace NadekoBot.Modules.NSFW .WithFooter(efb => efb.WithText("e621"))) .ConfigureAwait(false); } -#endif + + [NadekoCommand, Usage, Description, Aliases] + public Task Rule34([Remainder] string tag = null) + => Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Rule34); + [NadekoCommand, Usage, Description, Aliases] public async Task Danbooru([Remainder] string tag = null) { diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 01f91b67..035acf74 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -25,6 +25,36 @@ namespace NadekoBot.Modules.Utility { private static ConcurrentDictionary rotatingRoleColors = new ConcurrentDictionary(); + //[NadekoCommand, Usage, Description, Aliases] + //[RequireContext(ContextType.Guild)] + //public async Task Midorina([Remainder] string arg) + //{ + // var channel = (ITextChannel)Context.Channel; + + // var roleNames = arg?.Split(';'); + + // if (roleNames == null || roleNames.Length == 0) + // return; + + // var j = 0; + // var roles = roleNames.Select(x => Context.Guild.Roles.FirstOrDefault(r => String.Compare(r.Name, x) == 0)) + // .Where(x => x != null) + // .Select(x => $"`{++j}.` {x.Name}") + // .Take(10) + // .ToArray(); + + // string[] reactions = { "one", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:", ":ten:" }; + + // var msg = await Context.Channel.SendConfirmAsync("Pick a Role", + // string.Join("\n", roles)).ConfigureAwait(false); + + // for (int i = 0; i < roles.Length; i++) + // { + // await msg.AddReactionAsync(reactions[i]).ConfigureAwait(false); + // await Task.Delay(1000).ConfigureAwait(false); + // } + //} + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageRoles)] @@ -317,10 +347,6 @@ namespace NadekoBot.Modules.Utility var shardId = Context.Guild != null ? NadekoBot.Client.GetShardIdFor(Context.Guild.Id) : 0; - var footer = $"Shard {shardId} | {NadekoBot.Client.Shards.Count} total shards"; -#if !GLOBAL_NADEKO - footer += $" | Playing {Music.Music.MusicPlayers.Where(mp => mp.Value.CurrentSong != null).Count()} songs, {Music.Music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count)} queued."; -#endif await Context.Channel.EmbedAsync( new EmbedBuilder().WithOkColor() @@ -328,15 +354,18 @@ namespace NadekoBot.Modules.Utility .WithUrl("http://nadekobot.readthedocs.io/en/latest/") .WithIconUrl("https://cdn.discordapp.com/avatars/116275390695079945/b21045e778ef21c96d175400e779f0fb.jpg")) .AddField(efb => efb.WithName(Format.Bold("Author")).WithValue(stats.Author).WithIsInline(true)) - .AddField(efb => efb.WithName(Format.Bold("Library")).WithValue(stats.Library).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Bot ID")).WithValue(NadekoBot.Client.CurrentUser.Id.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName(Format.Bold("Shard")).WithValue($"#{shardId}, {NadekoBot.Client.Shards.Count} total").WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Commands Ran")).WithValue(stats.CommandsRan.ToString()).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Messages")).WithValue($"{stats.MessageCounter} ({stats.MessagesPerSecond:F2}/sec)").WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Memory")).WithValue($"{stats.Heap} MB").WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Owner ID(s)")).WithValue(string.Join("\n", NadekoBot.Credentials.OwnerIds)).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Uptime")).WithValue(stats.GetUptimeString("\n")).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Presence")).WithValue($"{NadekoBot.Client.GetGuildCount()} Servers\n{stats.TextChannels} Text Channels\n{stats.VoiceChannels} Voice Channels").WithIsInline(true)) - .WithFooter(efb => efb.WithText(footer))); +#if !GLOBAL_NADEKO + .WithFooter(efb => efb.WithText($"Playing {Music.Music.MusicPlayers.Where(mp => mp.Value.CurrentSong != null).Count()} songs, {Music.Music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count)} queued.")) +#endif + ); } [NadekoCommand, Usage, Description, Aliases] @@ -393,4 +422,4 @@ namespace NadekoBot.Modules.Utility await JsonConvert.SerializeObject(grouping, Formatting.Indented).ToStream().ConfigureAwait(false), title, title).ConfigureAwait(false); } } -} +} \ No newline at end of file From b73b670f6f5950af645655e1d8282296dc683cac Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 6 Feb 2017 08:35:45 +0100 Subject: [PATCH 177/746] .shardstats improved --- src/NadekoBot/Modules/Utility/Utility.cs | 33 +++++++++++++++--------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 035acf74..7f002e1f 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -312,23 +312,32 @@ namespace NadekoBot.Modules.Utility [NadekoCommand, Usage, Description, Aliases] public async Task ShardStats(int page = 1) { - page -= 1; - if (page < 0) + if (page < 1) return; - var shards = NadekoBot.Client.Shards.Skip(page * 25).Take(25); + var status = string.Join(", ", NadekoBot.Client.Shards.GroupBy(x => x.ConnectionState) + .Select(x => $"{x.Count()} shards {x.Key}") + .ToArray()); - var info = string.Join("\n", - shards.Select(x => $"Shard **#{x.ShardId.ToString()}** is in {Format.Bold(x.ConnectionState.ToString())} state with {Format.Bold(x.Guilds.Count.ToString())} servers")); + var allShardStrings = NadekoBot.Client.Shards + .Select(x => $"Shard **#{x.ShardId.ToString()}** is in {Format.Bold(x.ConnectionState.ToString())} state with {Format.Bold(x.Guilds.Count.ToString())} servers") + .ToArray(); - if (string.IsNullOrWhiteSpace(info)) - info = "No shard stats on this page."; - await Context.Channel.EmbedAsync(new EmbedBuilder() - .WithOkColor() - .WithTitle("Shard Stats - page " + (page + 1)) - .WithDescription(info)) - .ConfigureAwait(false); + + await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) => { + + var str = string.Join("\n", allShardStrings.Skip(25 * (curPage - 1)).Take(25)); + + if (string.IsNullOrWhiteSpace(str)) + str = "No shards on this page."; + + return new EmbedBuilder() + .WithAuthor(a => a.WithName("Shard Stats")) + .WithTitle(status) + .WithOkColor() + .WithDescription(str); + }, allShardStrings.Length / 25); } [NadekoCommand, Usage, Description, Aliases] From ba8e906c970a00e9b9f102be407cf77c300a928f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 6 Feb 2017 09:35:49 +0100 Subject: [PATCH 178/746] gave up on command, commented out, will continue in the future maybe --- .../Gambling/Commands/CurrencyEvents.cs | 2 +- src/NadekoBot/Modules/Utility/Utility.cs | 62 ++++++++++++++++--- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs index bea309af..cfc1d789 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -125,7 +125,7 @@ namespace NadekoBot.Modules.Gambling { var msg = await Context.Channel.SendConfirmAsync("Flower reaction event started!", "Add 🌸 reaction to this message to get 100" + NadekoBot.BotConfig.CurrencySign, - footer: "This event is active for 24 hours.") + footer: "This event is active for up to 24 hours.") .ConfigureAwait(false); try { await msg.AddReactionAsync("🌸").ConfigureAwait(false); } catch diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 7f002e1f..d5826f1b 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -37,22 +37,68 @@ namespace NadekoBot.Modules.Utility // return; // var j = 0; - // var roles = roleNames.Select(x => Context.Guild.Roles.FirstOrDefault(r => String.Compare(r.Name, x) == 0)) + // var roles = roleNames.Select(x => Context.Guild.Roles.FirstOrDefault(r => String.Compare(r.Name, x, StringComparison.OrdinalIgnoreCase) == 0)) // .Where(x => x != null) - // .Select(x => $"`{++j}.` {x.Name}") // .Take(10) // .ToArray(); - // string[] reactions = { "one", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:", ":ten:" }; + // var rnd = new NadekoRandom(); + // var reactions = new[] { "🎬", "🐧", "🌍", "🌺", "🚀", "☀", "🌲", "🍒", "🐾", "🏀" } + // .OrderBy(x => rnd.Next()) + // .ToArray(); + // var roleStrings = roles + // .Select(x => $"{reactions[j++]} -> {x.Name}"); + // var msg = await Context.Channel.SendConfirmAsync("Pick a Role", - // string.Join("\n", roles)).ConfigureAwait(false); + // string.Join("\n", roleStrings)).ConfigureAwait(false); // for (int i = 0; i < roles.Length; i++) // { - // await msg.AddReactionAsync(reactions[i]).ConfigureAwait(false); + // try { await msg.AddReactionAsync(reactions[i]).ConfigureAwait(false); } + // catch (Exception ex) { _log.Warn(ex); } // await Task.Delay(1000).ConfigureAwait(false); // } + + // msg.OnReaction((r) => Task.Run(async () => + // { + // try + // { + // var usr = r.User.GetValueOrDefault() as IGuildUser; + + // if (usr == null) + // return; + + // var index = Array.IndexOf(reactions, r.Emoji.Name); + // if (index == -1) + // return; + + // await usr.RemoveRolesAsync(roles[index]); + // } + // catch (Exception ex) + // { + // _log.Warn(ex); + // } + // }), (r) => Task.Run(async () => + // { + // try + // { + // var usr = r.User.GetValueOrDefault() as IGuildUser; + + // if (usr == null) + // return; + + // var index = Array.IndexOf(reactions, r.Emoji.Name); + // if (index == -1) + // return; + + // await usr.RemoveRolesAsync(roles[index]); + // } + // catch (Exception ex) + // { + // _log.Warn(ex); + // } + // })); //} [NadekoCommand, Usage, Description, Aliases] @@ -147,7 +193,8 @@ namespace NadekoBot.Modules.Utility return; var socketGuild = Context.Guild as SocketGuild; - if (socketGuild == null) { + if (socketGuild == null) + { _log.Warn("Can't cast guild to socket guild."); return; } @@ -325,7 +372,8 @@ namespace NadekoBot.Modules.Utility - await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) => { + await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) => + { var str = string.Join("\n", allShardStrings.Skip(25 * (curPage - 1)).Take(25)); From 04ea4790170967c49a58409caa59167212202991 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 6 Feb 2017 12:57:38 +0100 Subject: [PATCH 179/746] flowerreaction event under the hood improvements --- .../Gambling/Commands/CurrencyEvents.cs | 105 ++++++++++++++---- 1 file changed, 83 insertions(+), 22 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs index cfc1d789..5647b3e4 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -11,6 +11,8 @@ using System.Text; using System.Threading.Tasks; using Discord.WebSocket; using NadekoBot.Services.Database; +using System.Threading; +using NLog; namespace NadekoBot.Modules.Gambling { @@ -25,7 +27,6 @@ namespace NadekoBot.Modules.Gambling SneakyGameStatus } //flower reaction event - public static readonly ConcurrentHashSet _flowerReactionAwardedUsers = new ConcurrentHashSet(); public static readonly ConcurrentHashSet _sneakyGameAwardedUsers = new ConcurrentHashSet(); @@ -45,7 +46,6 @@ namespace NadekoBot.Modules.Gambling var channel = (ITextChannel)Context.Channel; try { - switch (e) { case CurrencyEvent.FlowerReaction: @@ -121,38 +121,99 @@ namespace NadekoBot.Modules.Gambling return Task.Delay(0); } - public static async Task FlowerReactionEvent(CommandContext Context) + public static Task FlowerReactionEvent(CommandContext Context) => + new FlowerReactionEvent().Start(Context); + } + } + + public abstract class CurrencyEvent + { + public abstract Task Start(CommandContext channel); + } + + public class FlowerReactionEvent : CurrencyEvent + { + public readonly ConcurrentHashSet _flowerReactionAwardedUsers = new ConcurrentHashSet(); + private readonly Logger _log; + + private IUserMessage msg { get; set; } = null; + + private CancellationTokenSource source { get; } + private CancellationToken cancelToken { get; } + + public FlowerReactionEvent() + { + _log = LogManager.GetCurrentClassLogger(); + source = new CancellationTokenSource(); + cancelToken = source.Token; + } + + private async Task End() + { + if(msg != null) + await msg.DeleteAsync().ConfigureAwait(false); + + if(!source.IsCancellationRequested) + source.Cancel(); + + NadekoBot.Client.MessageDeleted -= MessageDeletedEventHandler; + } + + private Task MessageDeletedEventHandler(ulong id, Optional _) { + if (msg?.Id == id) { - var msg = await Context.Channel.SendConfirmAsync("Flower reaction event started!", + _log.Warn("Stopping flower reaction event because message is deleted."); + Task.Run(() => End()); + } + + return Task.CompletedTask; + } + + public override async Task Start(CommandContext context) + { + msg = await context.Channel.SendConfirmAsync("Flower reaction event started!", "Add 🌸 reaction to this message to get 100" + NadekoBot.BotConfig.CurrencySign, footer: "This event is active for up to 24 hours.") .ConfigureAwait(false); + + NadekoBot.Client.MessageDeleted += MessageDeletedEventHandler; + + try { await msg.AddReactionAsync("🌸").ConfigureAwait(false); } + catch + { try { await msg.AddReactionAsync("🌸").ConfigureAwait(false); } catch { - try { await msg.AddReactionAsync("🌸").ConfigureAwait(false); } - catch + try { await msg.DeleteAsync().ConfigureAwait(false); } + catch { return; } + } + } + using (msg.OnReaction(async (r) => + { + try + { + if (r.Emoji.Name == "🌸" && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _flowerReactionAwardedUsers.Add(r.User.Value.Id)) { - try { await msg.DeleteAsync().ConfigureAwait(false); } - catch { return; } + try { await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, false).ConfigureAwait(false); } catch { } } } - using (msg.OnReaction(async (r) => - { - try - { - if (r.Emoji.Name == "🌸" && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _flowerReactionAwardedUsers.Add(r.User.Value.Id)) - { - try { await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, false).ConfigureAwait(false); } catch { } - } - } - catch { } - })) + catch { } + })) + { + try { - await Task.Delay(TimeSpan.FromHours(24)).ConfigureAwait(false); - try { await msg.DeleteAsync().ConfigureAwait(false); } catch { } - _flowerReactionAwardedUsers.Clear(); + await Task.Delay(TimeSpan.FromHours(24), cancelToken).ConfigureAwait(false); } + catch (OperationCanceledException) + { + + } + if (cancelToken.IsCancellationRequested) + return; + + _log.Warn("Stopping flower reaction event because it expired."); + await End(); + } } } From 4429687bd567a1c0631333d7a7cd6bb4635cbf35 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 6 Feb 2017 13:00:39 +0100 Subject: [PATCH 180/746] public nadeko fix --- src/NadekoBot/Modules/NSFW/NSFW.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index fe81fa49..bd213773 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -253,8 +253,6 @@ namespace NadekoBot.Modules.NSFW await Context.Channel.SendErrorAsync(ex.Message).ConfigureAwait(false); } } -#if !GLOBAL_NADEKO - public static Task GetE621ImageLink(string tag) => Task.Run(async () => { @@ -278,6 +276,10 @@ namespace NadekoBot.Modules.NSFW } }); + public static Task GetRule34ImageLink(string tag) => + Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Rule34); + +#if !GLOBAL_NADEKO public static Task GetYandereImageLink(string tag) => Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Yandere); @@ -286,9 +288,6 @@ namespace NadekoBot.Modules.NSFW public static Task GetGelbooruImageLink(string tag) => Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Gelbooru); - - public static Task GetRule34ImageLink(string tag) => - Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Rule34); #endif } } \ No newline at end of file From 91efe4db48817a553ed4a902d7bf1ffa5287cce3 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 6 Feb 2017 20:09:47 +0100 Subject: [PATCH 181/746] .greetmsg, .greetdmmsg, .acr and .byemsg now accept json which will cause the output to be a discord embed. You can create a proper json using http://nadekobot.xyz/embedbuilder/ --- src/NadekoBot/DataStructures/CREmbed.cs | 91 +++++++++++ .../Commands/ServerGreetCommands.cs | 151 ++++++++++++------ .../CustomReactions/CustomReactions.cs | 34 +++- 3 files changed, 229 insertions(+), 47 deletions(-) create mode 100644 src/NadekoBot/DataStructures/CREmbed.cs diff --git a/src/NadekoBot/DataStructures/CREmbed.cs b/src/NadekoBot/DataStructures/CREmbed.cs new file mode 100644 index 00000000..88e81630 --- /dev/null +++ b/src/NadekoBot/DataStructures/CREmbed.cs @@ -0,0 +1,91 @@ +using Discord; +using Newtonsoft.Json; +using NLog; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.DataStructures +{ + public class CREmbed + { + private static readonly Logger _log; + public string PlainText { get; set; } + public string Title { get; set; } + public string Description { get; set; } + public CREmbedFooter Footer { get; set; } + public string Thumbnail { get; set; } + public string Image { get; set; } + public CREmbedField[] Fields { get; set; } + public uint Color { get; set; } = 7458112; + + static CREmbed() + { + _log = LogManager.GetCurrentClassLogger(); + } + + public bool IsValid => + !string.IsNullOrWhiteSpace(Title) || + !string.IsNullOrWhiteSpace(Description) || + !string.IsNullOrWhiteSpace(Thumbnail) || + !string.IsNullOrWhiteSpace(Image) || + (Footer != null && (!string.IsNullOrWhiteSpace(Footer.Text) || !string.IsNullOrWhiteSpace(Footer.IconUrl))) || + (Fields != null && Fields.Length > 0); + + public EmbedBuilder ToEmbed() + { + var embed = new EmbedBuilder() + .WithTitle(Title) + .WithDescription(Description) + .WithColor(new Discord.Color(Color)); + if (Footer != null) + embed.WithFooter(efb => efb.WithIconUrl(Footer.IconUrl).WithText(Footer.Text)); + embed.WithThumbnailUrl(Thumbnail) + .WithImageUrl(Image); + + if (Fields != null) + foreach (var f in Fields) + { + embed.AddField(efb => efb.WithName(f.Name).WithValue(f.Value).WithIsInline(f.Inline)); + } + + return embed; + } + + public static bool TryParse(string input, out CREmbed embed) + { + embed = null; + if (string.IsNullOrWhiteSpace(input)) + return false; + + try + { + var crembed = JsonConvert.DeserializeObject(input); + + if (!crembed.IsValid) + return false; + + embed = crembed; + return true; + } + catch (Exception ex) + { + return false; + } + } + } + + public class CREmbedField + { + public string Name { get; set; } + public string Value { get; set; } + public bool Inline { get; set; } + } + + public class CREmbedFooter { + public string Text { get; set; } + public string IconUrl { get; set; } + } +} diff --git a/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs index 9183b814..6c1be19e 100644 --- a/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs @@ -2,6 +2,7 @@ using Discord.Commands; using Discord.WebSocket; using NadekoBot.Attributes; +using NadekoBot.DataStructures; using NadekoBot.Extensions; using NadekoBot.Services; using NadekoBot.Services.Database; @@ -83,77 +84,137 @@ namespace NadekoBot.Modules.Administration return settings; } - //todo optimize ASAP - private static async Task UserLeft(IGuildUser user) + private static Task UserLeft(IGuildUser user) { - try + var _ = Task.Run(async () => { - var conf = GetOrAddSettingsForGuild(user.GuildId); - - if (!conf.SendChannelByeMessage) return; - var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.ByeMessageChannelId); - - if (channel == null) //maybe warn the server owner that the channel is missing - return; - - var msg = conf.ChannelByeMessageText.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name); - if (string.IsNullOrWhiteSpace(msg)) - return; try { - var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false); - if (conf.AutoDeleteByeMessagesTimer > 0) + var conf = GetOrAddSettingsForGuild(user.GuildId); + + if (!conf.SendChannelByeMessage) return; + var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.ByeMessageChannelId); + + if (channel == null) //maybe warn the server owner that the channel is missing + return; + CREmbed embedData; + if (CREmbed.TryParse(conf.ChannelByeMessageText, out embedData)) { - toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer); + embedData.PlainText = embedData.PlainText?.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name); + embedData.Description = embedData.Description?.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name); + embedData.Title = embedData.Title?.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name); + try + { + var toDelete = await channel.EmbedAsync(embedData.ToEmbed(), embedData.PlainText ?? "").ConfigureAwait(false); + if (conf.AutoDeleteByeMessagesTimer > 0) + { + toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer); + } + } + catch (Exception ex) { _log.Warn(ex); } + } + else + { + var msg = conf.ChannelByeMessageText.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name); + if (string.IsNullOrWhiteSpace(msg)) + return; + try + { + var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false); + if (conf.AutoDeleteByeMessagesTimer > 0) + { + toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer); + } + } + catch (Exception ex) { _log.Warn(ex); } } } - catch (Exception ex) { _log.Warn(ex); } - } - catch { } + catch { } + }); + return Task.CompletedTask; } - private static async Task UserJoined(IGuildUser user) + private static Task UserJoined(IGuildUser user) { - try + var _ = Task.Run(async () => { - var conf = GetOrAddSettingsForGuild(user.GuildId); - - if (conf.SendChannelGreetMessage) + try { - var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.GreetMessageChannelId); - if (channel != null) //maybe warn the server owner that the channel is missing + var conf = GetOrAddSettingsForGuild(user.GuildId); + + if (conf.SendChannelGreetMessage) { - var msg = conf.ChannelGreetMessageText.Replace("%user%", user.Mention).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name); - if (!string.IsNullOrWhiteSpace(msg)) + var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.GreetMessageChannelId); + if (channel != null) //maybe warn the server owner that the channel is missing { - try + + CREmbed embedData; + if (CREmbed.TryParse(conf.ChannelGreetMessageText, out embedData)) { - var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false); - if (conf.AutoDeleteGreetMessagesTimer > 0) + embedData.PlainText = embedData.PlainText?.Replace("%user%", user.Mention).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name); + embedData.Description = embedData.Description?.Replace("%user%", user.Mention).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name); + embedData.Title = embedData.Title?.Replace("%user%", user.ToString()).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name); + try { - toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer); + var toDelete = await channel.EmbedAsync(embedData.ToEmbed(), embedData.PlainText ?? "").ConfigureAwait(false); + if (conf.AutoDeleteGreetMessagesTimer > 0) + { + toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer); + } + } + catch (Exception ex) { _log.Warn(ex); } + } + else + { + var msg = conf.ChannelGreetMessageText.Replace("%user%", user.Mention).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name); + if (!string.IsNullOrWhiteSpace(msg)) + { + try + { + var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false); + if (conf.AutoDeleteGreetMessagesTimer > 0) + { + toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer); + } + } + catch (Exception ex) { _log.Warn(ex); } } } - catch (Exception ex) { _log.Warn(ex); } } } - } - if (conf.SendDmGreetMessage) - { - var channel = await user.CreateDMChannelAsync(); - - if (channel != null) + if (conf.SendDmGreetMessage) { - var msg = conf.DmGreetMessageText.Replace("%user%", user.Username).Replace("%server%", user.Guild.Name); - if (!string.IsNullOrWhiteSpace(msg)) + var channel = await user.CreateDMChannelAsync(); + + if (channel != null) { - await channel.SendConfirmAsync(msg).ConfigureAwait(false); + CREmbed embedData; + if (CREmbed.TryParse(conf.ChannelGreetMessageText, out embedData)) + { + embedData.PlainText = embedData.PlainText?.Replace("%user%", user.ToString()).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name); + embedData.Description = embedData.Description?.Replace("%user%", user.ToString()).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name); + embedData.Title = embedData.Title?.Replace("%user%", user.ToString()).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name); + try + { + await channel.EmbedAsync(embedData.ToEmbed(), embedData.PlainText ?? "").ConfigureAwait(false); + } + catch (Exception ex) { _log.Warn(ex); } + } + else + { + var msg = conf.DmGreetMessageText.Replace("%user%", user.ToString()).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name); + if (!string.IsNullOrWhiteSpace(msg)) + { + await channel.SendConfirmAsync(msg).ConfigureAwait(false); + } + } } } } - } - catch { } + catch { } + }); + return Task.CompletedTask; } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index 1f1cca1d..8f76f0a8 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -11,6 +11,8 @@ using NLog; using System.Diagnostics; using Discord.WebSocket; using System; +using Newtonsoft.Json; +using NadekoBot.DataStructures; namespace NadekoBot.Modules.CustomReactions { @@ -69,7 +71,22 @@ namespace NadekoBot.Modules.CustomReactions if (reaction != null) { if (reaction.Response != "-") - try { await channel.SendMessageAsync(reaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { } + { + CREmbed crembed; + if (CREmbed.TryParse(reaction.Response, out crembed)) + { + try { await channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "").ConfigureAwait(false); } + catch (Exception ex) + { + _log.Warn("Sending CREmbed failed"); + _log.Warn(ex); + } + } + else + { + try { await channel.SendMessageAsync(reaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { } + } + } ReactionStats.AddOrUpdate(reaction.Trigger, 1, (k, old) => ++old); return true; @@ -91,7 +108,20 @@ namespace NadekoBot.Modules.CustomReactions if (greaction != null) { - try { await channel.SendMessageAsync(greaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { } + CREmbed crembed; + if (CREmbed.TryParse(greaction.Response, out crembed)) + { + try { await channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "").ConfigureAwait(false); } + catch (Exception ex) + { + _log.Warn("Sending CREmbed failed"); + _log.Warn(ex); + } + } + else + { + try { await channel.SendMessageAsync(greaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { } + } ReactionStats.AddOrUpdate(greaction.Trigger, 1, (k, old) => ++old); return true; } From e36ef3f5096d4c0308f97ef3ef8cef1db40b32f2 Mon Sep 17 00:00:00 2001 From: samvaio Date: Wed, 8 Feb 2017 20:01:22 +0530 Subject: [PATCH 182/746] Updated with addition of CentOS --- docs/guides/Linux Guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/Linux Guide.md b/docs/guides/Linux Guide.md index 1ba7e0c0..1997407b 100644 --- a/docs/guides/Linux Guide.md +++ b/docs/guides/Linux Guide.md @@ -51,12 +51,12 @@ You should see these following options after using the above command: 2. Download Stable Build 3. Run Nadeko (Normally) 4. Run Nadeko with Auto Restart (Run Nadeko normally before using this.) -5. Auto-Install Prerequisites (for Ubuntu and Debian) +5. Auto-Install Prerequisites (for Ubuntu, Debian and CentOS) 6. Set up credentials.json (if you have downloaded the bot already) 7. To exit ``` #####Part II (Optional) -**If** you are running NadekoBot for the first time on your system and never had any *prerequisites* installed, Press `5` and `enter` key, then `y` when you see the following: +**If** you are running NadekoBot for the first time on your system and never had any *prerequisites* installed and have Ubuntu, Debian or CentOS, Press `5` and `enter` key, then `y` when you see the following: ``` Welcome to NadekoBot Auto Prerequisites Installer. Would you like to continue? From a8124cf1f240831fd77365e5c70f1803bd6ea910 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 8 Feb 2017 21:44:32 +0100 Subject: [PATCH 183/746] started work on ttt --- .../Modules/Games/Commands/TicTacToe.cs | 127 ++++++++++++++++++ src/NadekoBot/Modules/Games/Games.cs | 1 - .../Resources/CommandStrings.Designer.cs | 8 +- src/NadekoBot/Resources/CommandStrings.resx | 8 +- 4 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 src/NadekoBot/Modules/Games/Commands/TicTacToe.cs diff --git a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs new file mode 100644 index 00000000..54afcab9 --- /dev/null +++ b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs @@ -0,0 +1,127 @@ +using Discord; +using Discord.Commands; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NLog; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Games +{ + public partial class Games + { + [Group] + public class TicTacToeCommands : ModuleBase + { + //channelId/game + private static readonly ConcurrentDictionary _openGames = new ConcurrentDictionary(); + private readonly Logger _log; + + public TicTacToeCommands() + { + _log = LogManager.GetCurrentClassLogger(); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task Ttt(IGuildUser secondUser) + { + var channel = (ITextChannel)Context.Channel; + + + TicTacToe game; + if (_openGames.TryRemove(channel.Id, out game)) // joining open game + { + if (!game.Join((IGuildUser)Context.User)) + { + await Context.Channel.SendErrorAsync("You can't play against yourself. Game stopped.").ConfigureAwait(false); + return; + } + var _ = Task.Run(() => game.Start()); + _log.Warn($"User {Context.User} joined a TicTacToe game."); + return; + } + game = new TicTacToe(channel, (IGuildUser)Context.User); + if (_openGames.TryAdd(Context.Channel.Id, game)) + { + _log.Warn($"User {Context.User} created a TicTacToe game."); + await Context.Channel.SendConfirmAsync("Tic Tac Toe game created. Waiting for another user.").ConfigureAwait(false); + } + } + } + + public class TicTacToe + { + + private readonly ITextChannel _channel; + private readonly Logger _log; + private readonly IGuildUser[] _users; + private readonly int?[,] _state; + + public TicTacToe(ITextChannel channel, IGuildUser firstUser) + { + _channel = channel; + _users = new IGuildUser[2] { firstUser, null }; + _state = new int?[3, 3] { + { null, null, null }, + { null, 1, 1 }, + { 0, null, 0 }, + }; + + _log = LogManager.GetCurrentClassLogger(); + } + + public string GetState() + { + var sb = new StringBuilder(); + for (int i = 0; i < _state.GetLength(0); i++) + { + for (int j = 0; j < _state.GetLength(1); j++) + { + sb.Append(GetIcon(_state[i, j])); + if (j < _state.GetLength(1) - 1) + sb.Append("┃"); + } + if (i < _state.GetLength(0) - 1) + sb.AppendLine("\n──────────"); + } + + return sb.ToString(); + } + + public EmbedBuilder GetEmbed() => + new EmbedBuilder() + .WithOkColor() + .WithDescription(GetState()) + .WithAuthor(eab => eab.WithName("Tic Tac Toe")) + .WithTitle($"{_users[0]} vs {_users[1]}"); + + private static string GetIcon(int? val) + { + switch (val) + { + case 0: + return "❌"; + case 1: + return "⭕"; + default: + return "⬛"; + } + } + + public Task Start() + { + return Task.CompletedTask; + } + + public void Join(IGuildUser user) + { + + } + } + } +} diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index 6faf288c..b4107acd 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -15,7 +15,6 @@ namespace NadekoBot.Modules.Games { private static string[] _8BallResponses { get; } = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text).ToArray(); - [NadekoCommand, Usage, Description, Aliases] public async Task Choose([Remainder] string list = null) { diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 6c880516..fef3709d 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -906,7 +906,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x3 and 100 x10.. + /// Looks up a localized string similar to Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10.. /// public static string betroll_desc { get { @@ -1041,7 +1041,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message.. + /// Looks up a localized string similar to Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded.. /// public static string byemsg_desc { get { @@ -3066,7 +3066,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message.. + /// Looks up a localized string similar to Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded.. /// public static string greetdmmsg_desc { get { @@ -3093,7 +3093,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message.. + /// Looks up a localized string similar to Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded.. /// public static string greetmsg_desc { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 0f03e989..fb6d8b15 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -184,7 +184,7 @@ greetmsg - Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. + Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. `{0}greetmsg Welcome, %user%.` @@ -202,7 +202,7 @@ byemsg - Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message. + Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. `{0}byemsg %user% has left.` @@ -1273,7 +1273,7 @@ betroll br - Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x3 and 100 x10. + Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10. `{0}br 5` @@ -2311,7 +2311,7 @@ `{0}greetdmmsg Welcome to the server, %user%`. - Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message. + Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. Check how much currency a person has. (Defaults to yourself) From 959f1726c9490bbbcfa48b565f399b0bddccbda3 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 9 Feb 2017 03:09:06 +0100 Subject: [PATCH 184/746] >tictactoe finished, sanity said it seems good to her. Unfortunately it isn't centered and can't be. --- .../Modules/Games/Commands/TicTacToe.cs | 254 ++++++++++++++++-- .../Resources/CommandStrings.Designer.cs | 27 ++ src/NadekoBot/Resources/CommandStrings.resx | 9 + 3 files changed, 263 insertions(+), 27 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs index 54afcab9..ef20bfb0 100644 --- a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs +++ b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs @@ -8,17 +8,19 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; namespace NadekoBot.Modules.Games { public partial class Games { + //todo timeout [Group] public class TicTacToeCommands : ModuleBase { //channelId/game - private static readonly ConcurrentDictionary _openGames = new ConcurrentDictionary(); + private static readonly Dictionary _games = new Dictionary(); private readonly Logger _log; public TicTacToeCommands() @@ -26,41 +28,69 @@ namespace NadekoBot.Modules.Games _log = LogManager.GetCurrentClassLogger(); } + private readonly SemaphoreSlim sem = new SemaphoreSlim(1, 1); + private readonly object tttLockObj = new object(); + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task Ttt(IGuildUser secondUser) + public async Task TicTacToe() { var channel = (ITextChannel)Context.Channel; - - TicTacToe game; - if (_openGames.TryRemove(channel.Id, out game)) // joining open game + await sem.WaitAsync(1000); + try { - if (!game.Join((IGuildUser)Context.User)) + TicTacToe game; + if (_games.TryGetValue(channel.Id, out game)) { - await Context.Channel.SendErrorAsync("You can't play against yourself. Game stopped.").ConfigureAwait(false); + var _ = Task.Run(async () => + { + await game.Start((IGuildUser)Context.User); + }); return; } - var _ = Task.Run(() => game.Start()); - _log.Warn($"User {Context.User} joined a TicTacToe game."); - return; + game = new TicTacToe(channel, (IGuildUser)Context.User); + _games.Add(channel.Id, game); + await Context.Channel.SendConfirmAsync($"{Context.User.Mention} Created a TicTacToe game.").ConfigureAwait(false); + + game.OnEnded += (g) => + { + _games.Remove(channel.Id); + }; } - game = new TicTacToe(channel, (IGuildUser)Context.User); - if (_openGames.TryAdd(Context.Channel.Id, game)) + finally { - _log.Warn($"User {Context.User} created a TicTacToe game."); - await Context.Channel.SendConfirmAsync("Tic Tac Toe game created. Waiting for another user.").ConfigureAwait(false); + sem.Release(); } } } public class TicTacToe { + enum Phase + { + Starting, + Started, + Ended + } private readonly ITextChannel _channel; private readonly Logger _log; private readonly IGuildUser[] _users; private readonly int?[,] _state; + private Phase _phase; + private readonly Func _playMove; + int curUserIndex = 0; + private readonly SemaphoreSlim moveLock; + + private IGuildUser _winner = null; + + private readonly string[] numbers = { ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:" }; + + public Action OnEnded; + + private IUserMessage previousMessage = null; + private Timer timeoutTimer; public TicTacToe(ITextChannel channel, IGuildUser firstUser) { @@ -68,11 +98,44 @@ namespace NadekoBot.Modules.Games _users = new IGuildUser[2] { firstUser, null }; _state = new int?[3, 3] { { null, null, null }, - { null, 1, 1 }, - { 0, null, 0 }, + { null, null, null }, + { null, null, null }, }; _log = LogManager.GetCurrentClassLogger(); + _log.Warn($"User {firstUser} created a TicTacToe game."); + _phase = Phase.Starting; + moveLock = new SemaphoreSlim(1, 1); + + timeoutTimer = new Timer(async (_) => + { + await moveLock.WaitAsync(); + try + { + if (_phase == Phase.Ended) + return; + + _phase = Phase.Ended; + if (_users[1] != null) + { + _winner = _users[curUserIndex ^= 1]; + var del = previousMessage?.DeleteAsync(); + try + { + await _channel.EmbedAsync(GetEmbed("Time Expired!")).ConfigureAwait(false); + await del.ConfigureAwait(false); + } + catch { } + } + + OnEnded?.Invoke(this); + } + catch { } + finally + { + moveLock.Release(); + } + }, null, 15000, Timeout.Infinite); } public string GetState() @@ -82,7 +145,7 @@ namespace NadekoBot.Modules.Games { for (int j = 0; j < _state.GetLength(1); j++) { - sb.Append(GetIcon(_state[i, j])); + sb.Append(_state[i, j] == null ? numbers[i * 3 + j] : GetIcon(_state[i, j])); if (j < _state.GetLength(1) - 1) sb.Append("┃"); } @@ -93,12 +156,28 @@ namespace NadekoBot.Modules.Games return sb.ToString(); } - public EmbedBuilder GetEmbed() => - new EmbedBuilder() + public EmbedBuilder GetEmbed(string title = null) + { + var embed = new EmbedBuilder() .WithOkColor() - .WithDescription(GetState()) - .WithAuthor(eab => eab.WithName("Tic Tac Toe")) - .WithTitle($"{_users[0]} vs {_users[1]}"); + .WithDescription(Environment.NewLine + GetState()) + .WithAuthor(eab => eab.WithName($"{_users[0]} vs {_users[1]}")); + + if (!string.IsNullOrWhiteSpace(title)) + embed.WithTitle(title); + + if (_winner == null) + { + if (_phase == Phase.Ended) + embed.WithFooter(efb => efb.WithText($"No moves left!")); + else + embed.WithFooter(efb => efb.WithText($"{_users[curUserIndex]}'s move")); + } + else + embed.WithFooter(efb => efb.WithText($"{_winner} Won!")); + + return embed; + } private static string GetIcon(int? val) { @@ -108,20 +187,141 @@ namespace NadekoBot.Modules.Games return "❌"; case 1: return "⭕"; + case 2: + return "❎"; + case 3: + return "🅾"; default: return "⬛"; } } - public Task Start() + public async Task Start(IGuildUser user) { - return Task.CompletedTask; + if (_phase == Phase.Started || _phase == Phase.Ended) + { + await _channel.SendErrorAsync(user.Mention + " TicTacToe Game is already running in this channel.").ConfigureAwait(false); + return; + } + else if (_users[0] == user) + { + await _channel.SendErrorAsync(user.Mention + " You can't play against yourself.").ConfigureAwait(false); + return; + } + + _users[1] = user; + _log.Warn($"User {user} joined a TicTacToe game."); + + _phase = Phase.Started; + + NadekoBot.Client.MessageReceived += Client_MessageReceived; + + previousMessage = await _channel.EmbedAsync(GetEmbed("Game Started")).ConfigureAwait(false); } - public void Join(IGuildUser user) + private bool IsDraw() { - + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + if (_state[i, j] == null) + return false; + } + } + return true; + } + + private Task Client_MessageReceived(Discord.WebSocket.SocketMessage msg) + { + var _ = Task.Run(async () => + { + await moveLock.WaitAsync().ConfigureAwait(false); + try + { + var curUser = _users[curUserIndex]; + if (_phase == Phase.Ended || msg.Author?.Id != curUser.Id) + return; + + int index; + if (int.TryParse(msg.Content, out index) && + --index >= 0 && + index <= 9 && + _state[index / 3, index % 3] == null) + { + _state[index / 3, index % 3] = curUserIndex; + + // i'm lazy + if (_state[index / 3, 0] == _state[index / 3, 1] && _state[index / 3, 1] == _state[index / 3, 2]) + { + _state[index / 3, 0] = curUserIndex + 2; + _state[index / 3, 1] = curUserIndex + 2; + _state[index / 3, 2] = curUserIndex + 2; + + _phase = Phase.Ended; + } + else if (_state[0, index % 3] == _state[1, index % 3] && _state[1, index % 3] == _state[2, index % 3]) + { + _state[0, index % 3] = curUserIndex + 2; + _state[1, index % 3] = curUserIndex + 2; + _state[2, index % 3] = curUserIndex + 2; + + _phase = Phase.Ended; + } + else if (curUserIndex == _state[0, 0] && _state[0, 0] == _state[1, 1] && _state[1, 1] == _state[2, 2]) + { + _state[0, 0] = curUserIndex + 2; + _state[1, 1] = curUserIndex + 2; + _state[2, 2] = curUserIndex + 2; + + _phase = Phase.Ended; + } + else if (curUserIndex == _state[0, 2] && _state[0, 2] == _state[1, 1] && _state[1, 1] == _state[2, 0]) + { + _state[0, 2] = curUserIndex + 2; + _state[1, 1] = curUserIndex + 2; + _state[2, 0] = curUserIndex + 2; + + _phase = Phase.Ended; + } + string reason = ""; + + if (_phase == Phase.Ended) // if user won, stop receiving moves + { + reason = "Matched three!"; + _winner = _users[curUserIndex]; + NadekoBot.Client.MessageReceived -= Client_MessageReceived; + OnEnded?.Invoke(this); + } + else if (IsDraw()) + { + reason = "A draw!"; + _phase = Phase.Ended; + NadekoBot.Client.MessageReceived -= Client_MessageReceived; + OnEnded?.Invoke(this); + } + + var sendstate = Task.Run(async () => + { + var del1 = msg.DeleteAsync(); + var del2 = previousMessage?.DeleteAsync(); + try { previousMessage = await _channel.EmbedAsync(GetEmbed(reason)); } catch { } + try { await del1; } catch { } + try { await del2; } catch { } + }); + curUserIndex ^= 1; + + timeoutTimer.Change(15000, Timeout.Infinite); + } + } + finally + { + moveLock.Release(); + } + }); + + return Task.CompletedTask; } } } -} +} \ No newline at end of file diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index fef3709d..04745557 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -7727,6 +7727,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to tictactoe ttt. + /// + public static string tictactoe_cmd { + get { + return ResourceManager.GetString("tictactoe_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. 15 seconds per move.. + /// + public static string tictactoe_desc { + get { + return ResourceManager.GetString("tictactoe_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to >ttt. + /// + public static string tictactoe_usage { + get { + return ResourceManager.GetString("tictactoe_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to tl. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index fb6d8b15..fae1afda 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3078,4 +3078,13 @@ `{0}shardid 117523346618318850` + + tictactoe ttt + + + Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. 15 seconds per move. + + + >ttt + \ No newline at end of file From c6351ea958f5f493c8d148b737083ae179efb9da Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 9 Feb 2017 17:09:11 +0100 Subject: [PATCH 185/746] Updated invite links --- docs/Frequently Asked Questions.md | 2 +- docs/index.md | 2 +- src/NadekoBot/Services/Database/Models/BotConfig.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/Frequently Asked Questions.md b/docs/Frequently Asked Questions.md index 32d7a6e9..09eaafd7 100644 --- a/docs/Frequently Asked Questions.md +++ b/docs/Frequently Asked Questions.md @@ -19,7 +19,7 @@ ###Question 5: I have an issue/bug/suggestion, where do I put it so it gets noticed? ----------- -**Answer:** First, check [issues](https://github.com/Kwoth/NadekoBot/issues "GitHub NadekoBot Issues"), then check the `#suggestions` channel in the Nadeko [help server](https://discord.gg/0ehQwTK2RBjAxzEY). +**Answer:** First, check [issues](https://github.com/Kwoth/NadekoBot/issues "GitHub NadekoBot Issues"), then check the `#suggestions` channel in the Nadeko [help server](https://discord.gg/nadekobot). If your problem or suggestion is not there, feel free to request/notify us about it either in the Issues section of GitHub for issues or in the `#suggestions` channel on the Nadeko help server for suggestions. diff --git a/docs/index.md b/docs/index.md index c2dbfa0a..50909579 100644 --- a/docs/index.md +++ b/docs/index.md @@ -33,7 +33,7 @@ If you want to contribute, be sure to PR on the **[dev][dev]** branch. - [Donate](Donate.md) [img]: https://cdn.discordapp.com/attachments/202743183774318593/210580315381563392/discord.png -[NadekoBot Server]: https://discord.gg/0ehQwTK2RBjAxzEY +[NadekoBot Server]: https://discord.gg/nadekobot [GitHub]: https://github.com/Kwoth/NadekoBot [Issues]: https://github.com/Kwoth/NadekoBot/issues [dev]: https://github.com/Kwoth/NadekoBot/tree/dev diff --git a/src/NadekoBot/Services/Database/Models/BotConfig.cs b/src/NadekoBot/Services/Database/Models/BotConfig.cs index d96d4cc8..6b35e5f2 100644 --- a/src/NadekoBot/Services/Database/Models/BotConfig.cs +++ b/src/NadekoBot/Services/Database/Models/BotConfig.cs @@ -54,7 +54,7 @@ For a specific command help, use `{1}h CommandName` (for example {1}h !!q) -Nadeko Support Server: https://discord.gg/0ehQwTK2RBjAxzEY"; +Nadeko Support Server: https://discord.gg/nadekobot"; public int MigrationVersion { get; set; } From 971308d0a29484f3a17712daf66941bcd9301509 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Thu, 9 Feb 2017 17:10:39 +0100 Subject: [PATCH 186/746] new discord invite link to readme.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c0df0727..7a7cd1f4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ![img](https://ci.appveyor.com/api/projects/status/gmu6b3ltc80hr3k9?svg=true) -[![Discord](https://discordapp.com/api/guilds/117523346618318850/widget.png)](https://discord.gg/0ehQwTK2RBjAxzEY) +[![Discord](https://discordapp.com/api/guilds/117523346618318850/widget.png)](https://discord.gg/nadekobot) [![Documentation Status](https://readthedocs.org/projects/nadekobot/badge/?version=latest)](http://nadekobot.readthedocs.io/en/latest/?badge=latest) # NadekoBot [![nadeko1](https://cdn.discordapp.com/attachments/155726317222887425/252095170676391936/A1.jpg)](https://discordapp.com/oauth2/authorize?client_id=170254782546575360&scope=bot&permissions=66186303) From d032a7c46483f5987fb57ab83df54906cd903910 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Thu, 9 Feb 2017 17:11:39 +0100 Subject: [PATCH 187/746] Missed another invite --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7a7cd1f4..bb66aa4f 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,6 @@ `Follow me on twitter for updates. | Join my Discord server if you need help. | Read the Docs for hosting guides.` -[![twitter](https://cdn.discordapp.com/attachments/155726317222887425/252192520094613504/twiter_banner.JPG)](https://twitter.com/TheNadekoBot) [![discord](https://cdn.discordapp.com/attachments/155726317222887425/252192415673221122/discord_banner.JPG)](https://discord.gg/0ehQwTK2RBjAxzEY) [![Wiki](https://cdn.discordapp.com/attachments/155726317222887425/252192472849973250/read_the_docs_banner.JPG)](http://nadekobot.readthedocs.io/en/latest/) +[![twitter](https://cdn.discordapp.com/attachments/155726317222887425/252192520094613504/twiter_banner.JPG)](https://twitter.com/TheNadekoBot) [![discord](https://cdn.discordapp.com/attachments/155726317222887425/252192415673221122/discord_banner.JPG)](https://discord.gg/nadekobot) [![Wiki](https://cdn.discordapp.com/attachments/155726317222887425/252192472849973250/read_the_docs_banner.JPG)](http://nadekobot.readthedocs.io/en/latest/) From 27d4f79be053d42b261cca01c50c1b9f5be99a79 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 9 Feb 2017 20:27:52 +0100 Subject: [PATCH 188/746] Fixed ~mal command for mal supporters --- src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs index 2aeb3c5b..c1d2eef9 100644 --- a/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs @@ -96,7 +96,7 @@ namespace NadekoBot.Modules.Searches // return $"[{elem.InnerHtml}]({elem.Href})"; // })); - var info = document.QuerySelectorAll("ul.user-status:nth-child(3) > li") + var info = document.QuerySelectorAll("ul.user-status:nth-child(3) > li.clearfix") .Select(x => Tuple.Create(x.Children[0].InnerHtml, x.Children[1].InnerHtml)) .ToList(); From a88f0569350ef7394238360b5c21b50f421981ba Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 9 Feb 2017 20:56:27 +0100 Subject: [PATCH 189/746] Fixed spaces in hangman/trivia hints --- .../Modules/Games/Commands/Hangman/HangmanGame.cs | 9 ++++----- .../Modules/Games/Commands/Trivia/TriviaQuestion.cs | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index 3d5f7ec6..a025eb0d 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -63,14 +63,13 @@ namespace NadekoBot.Modules.Games.Commands.Hangman public uint MaxErrors { get; } = 6; public uint MessagesSinceLastPost { get; private set; } = 0; public string ScrambledWord => "`" + String.Concat(Term.Word.Select(c => - { - if (!(char.IsLetter(c) || char.IsDigit(c))) + { + if (c == ' ') + return " \u2000"; + if (!(char.IsLetter(c) || char.IsDigit(c))) return $" {c}"; c = char.ToUpperInvariant(c); - - if (c == ' ') - return " "; return Guesses.Contains(c) ? $" {c}" : " _"; })) + "`"; diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestion.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestion.cs index 83ac895a..d9c908a8 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestion.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestion.cs @@ -98,7 +98,7 @@ namespace NadekoBot.Modules.Games.Trivia if (letters[i] != ' ') letters[i] = '_'; } - return string.Join(" \x200B", new string(letters).Replace(" ", " \x200B").AsEnumerable()); + return string.Join(" ", new string(letters).Replace(" ", " \u2000").AsEnumerable()); } } } From 51e45d17a0ed0d0cf4c52608cf19fd3d1ca12612 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 9 Feb 2017 21:08:02 +0100 Subject: [PATCH 190/746] fixed message updated and message title in logs --- src/NadekoBot/Modules/Administration/Commands/LogCommand.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index db339d4f..4219ff98 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -653,7 +653,7 @@ namespace NadekoBot.Modules.Administration return; var embed = new EmbedBuilder() .WithOkColor() - .WithTitle($"🗑 Message Deleted in {((ITextChannel)msg.Channel).Mention}") + .WithTitle($"🗑 Message Deleted in #{((ITextChannel)msg.Channel).Name}") .WithDescription($"{msg.Author}") .AddField(efb => efb.WithName("Content").WithValue(msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) .AddField(efb => efb.WithName("Id").WithValue(msg.Id.ToString()).WithIsInline(false)) @@ -697,7 +697,7 @@ namespace NadekoBot.Modules.Administration var embed = new EmbedBuilder() .WithOkColor() - .WithTitle($"📝 Message Updated in {((ITextChannel)after.Channel).Mention}") + .WithTitle($"📝 Message Updated in #{((ITextChannel)after.Channel).Name}") .WithDescription(after.Author.ToString()) .AddField(efb => efb.WithName("Old Message").WithValue(before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) .AddField(efb => efb.WithName("New Message").WithValue(after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) From 9c00d36f40c98f3c81238cdcb61163187e8d5f03 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 9 Feb 2017 21:11:33 +0100 Subject: [PATCH 191/746] .repinv should now reset the repeater --- src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs index b6efe2fc..1167cab7 100644 --- a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs @@ -141,6 +141,7 @@ namespace NadekoBot.Modules.Utility } var repeater = repList[index].Repeater; + repList[index].Reset(); await Context.Channel.SendMessageAsync("🔄 " + repeater.Message).ConfigureAwait(false); } From 84bec3e19c59a7a065ae23d852e08c3bf6bcc5f3 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 10 Feb 2017 11:16:30 +0100 Subject: [PATCH 192/746] Fixed warnings --- src/NadekoBot/DataStructures/CREmbed.cs | 2 +- src/NadekoBot/Modules/Games/Commands/TicTacToe.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/NadekoBot/DataStructures/CREmbed.cs b/src/NadekoBot/DataStructures/CREmbed.cs index 88e81630..cb67503b 100644 --- a/src/NadekoBot/DataStructures/CREmbed.cs +++ b/src/NadekoBot/DataStructures/CREmbed.cs @@ -70,7 +70,7 @@ namespace NadekoBot.DataStructures embed = crembed; return true; } - catch (Exception ex) + catch { return false; } diff --git a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs index ef20bfb0..1a254e28 100644 --- a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs +++ b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs @@ -79,7 +79,6 @@ namespace NadekoBot.Modules.Games private readonly IGuildUser[] _users; private readonly int?[,] _state; private Phase _phase; - private readonly Func _playMove; int curUserIndex = 0; private readonly SemaphoreSlim moveLock; From 494cf9447ee5e60f8018eb1da447a29a40b801b7 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 10 Feb 2017 13:03:15 +0100 Subject: [PATCH 193/746] Currency emoji issue fixed? --- src/NadekoBot/Services/Impl/ImagesService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NadekoBot/Services/Impl/ImagesService.cs b/src/NadekoBot/Services/Impl/ImagesService.cs index 02bcb1cd..77ee9f26 100644 --- a/src/NadekoBot/Services/Impl/ImagesService.cs +++ b/src/NadekoBot/Services/Impl/ImagesService.cs @@ -82,6 +82,7 @@ namespace NadekoBot.Services.Impl .ToImmutableArray(); SlotEmojis = Directory.GetFiles(slotEmojisPath) + .OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f))) .Select(x => File.ReadAllBytes(x).ToImmutableArray()) .ToImmutableArray(); From 145109cd72298987c907619a957e71c80934079a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 10 Feb 2017 14:46:48 +0100 Subject: [PATCH 194/746] small change to ffmpeg params --- src/NadekoBot/Modules/Music/Classes/SongBuffer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs b/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs index 9fd23294..738d07ec 100644 --- a/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs +++ b/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs @@ -56,7 +56,7 @@ namespace NadekoBot.Modules.Music.Classes p = Process.Start(new ProcessStartInfo { FileName = "ffmpeg", - Arguments = $"-ss {SkipTo} -i {SongInfo.Uri} -f s16le -ar 48000 -ac 2 pipe:1 -loglevel quiet", + Arguments = $"-ss {SkipTo} -i {SongInfo.Uri} -f s16le -ar 48000 -vn -ac 2 pipe:1 -loglevel quiet", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = false, From 567c6f87bf25177b67546250dbfdc7fcd5a397e8 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 10 Feb 2017 15:26:06 +0100 Subject: [PATCH 195/746] SoundcloudClientId is no longer mandatory in order to play soundcloud songs. (thanks to samvaio <3) --- src/NadekoBot/Services/Impl/BotCredentials.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/Impl/BotCredentials.cs b/src/NadekoBot/Services/Impl/BotCredentials.cs index fdd0a1fa..47906e8c 100644 --- a/src/NadekoBot/Services/Impl/BotCredentials.cs +++ b/src/NadekoBot/Services/Impl/BotCredentials.cs @@ -25,7 +25,17 @@ namespace NadekoBot.Services.Impl public string LoLApiKey { get; } public string OsuApiKey { get; } - public string SoundCloudClientId { get; } + private string _soundcloudClientId; + public string SoundCloudClientId { + get { + return string.IsNullOrWhiteSpace(_soundcloudClientId) + ? "d0bd7768e3a1a2d15430f0dccb871117" + : _soundcloudClientId; + } + set { + _soundcloudClientId = value; + } + } public DBConfig Db { get; } public int TotalShards { get; } From f91bb2897984b664f8da56b1c6786ecd416fa84b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 11 Feb 2017 10:17:59 +0100 Subject: [PATCH 196/746] kwothy plz fix --- src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 1c8671f8..1cf43a30 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -167,7 +167,7 @@ namespace NadekoBot.Modules.Games var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {NadekoBot.BotConfig.CurrencyName}", amount, false).ConfigureAwait(false); if (!removed) { - await Context.Channel.SendErrorAsync($"You don't have any {NadekoBot.BotConfig.CurrencyPluralName}.").ConfigureAwait(false); + await Context.Channel.SendErrorAsync($"You don't have enough {NadekoBot.BotConfig.CurrencyPluralName}.").ConfigureAwait(false); return; } From 46e74f64f0cc5c628e6fc22de16615d619dacc26 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 11 Feb 2017 15:21:09 +0100 Subject: [PATCH 197/746] small waifu fix --- src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs index f04ebda8..1d1f414f 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs @@ -110,7 +110,7 @@ namespace NadekoBot.Modules.Gambling result = WaifuClaimResult.Success; } } - else if (isAffinity && amount >= w.Price * 0.88f) + else if (isAffinity && amount > w.Price * 0.88f) { if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User.Id, "Claimed Waifu", amount, uow).ConfigureAwait(false)) { From 4d2d27d48ff0fb664ddfbc946591c94d417c5345 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 11 Feb 2017 15:21:53 +0100 Subject: [PATCH 198/746] small uinfo fix --- src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs index b2594d3a..8131bf16 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -94,9 +94,9 @@ namespace NadekoBot.Modules.Utility embed.AddField(fb => fb.WithName("**Nickname**").WithValue(user.Nickname).WithIsInline(true)); } 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 Server**").WithValue($"{user.JoinedAt?.ToString("dd.MM.yyyy HH:mm") ?? "unavail."}").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)) + .AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count - 1})** - {string.Join("\n", user.GetRoles().Take(10).Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true)) .WithColor(NadekoBot.OkColor); if (user.AvatarId != null) From 12eb216a4bd1079affb0cad1360ebb07d8352dfd Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 11 Feb 2017 16:26:04 +0100 Subject: [PATCH 199/746] all nsfw commands except ~hentaibomb and ~autohentai will work on public bot again --- src/NadekoBot/Modules/NSFW/NSFW.cs | 130 ++++++++++++++--------------- 1 file changed, 64 insertions(+), 66 deletions(-) diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index bd213773..131d1501 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -19,7 +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(); @@ -66,79 +66,79 @@ namespace NadekoBot.Modules.NSFW public Task Hentai([Remainder] string tag = null) => InternalHentai(Context.Channel, tag, false); - [NadekoCommand, Usage, Description, Aliases] - [RequireUserPermission(ChannelPermission.ManageMessages)] - public async Task AutoHentai(int interval = 0, string tags = null) - { - Timer t; + //[NadekoCommand, Usage, Description, Aliases] + //[RequireUserPermission(ChannelPermission.ManageMessages)] + //public async Task AutoHentai(int interval = 0, string tags = null) + //{ + // Timer t; - if (interval == 0) - { - if (AutoHentaiTimers.TryRemove(Context.Channel.Id, out t)) - { - t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer - await Context.Channel.SendConfirmAsync("Autohentai stopped.").ConfigureAwait(false); - } - return; - } + // if (interval == 0) + // { + // if (AutoHentaiTimers.TryRemove(Context.Channel.Id, out t)) + // { + // t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer + // await Context.Channel.SendConfirmAsync("Autohentai stopped.").ConfigureAwait(false); + // } + // return; + // } - if (interval < 20) - return; + // if (interval < 20) + // return; - var tagsArr = tags?.Split('|'); + // var tagsArr = tags?.Split('|'); - t = new Timer(async (state) => - { - try - { - if (tagsArr == null || tagsArr.Length == 0) - await InternalHentai(Context.Channel, null, true).ConfigureAwait(false); - else - await InternalHentai(Context.Channel, tagsArr[new NadekoRandom().Next(0, tagsArr.Length)], true).ConfigureAwait(false); - } - catch { } - }, null, interval * 1000, interval * 1000); + // t = new Timer(async (state) => + // { + // try + // { + // if (tagsArr == null || tagsArr.Length == 0) + // await InternalHentai(Context.Channel, null, true).ConfigureAwait(false); + // else + // await InternalHentai(Context.Channel, tagsArr[new NadekoRandom().Next(0, tagsArr.Length)], true).ConfigureAwait(false); + // } + // catch { } + // }, null, interval * 1000, interval * 1000); - AutoHentaiTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) => - { - old.Change(Timeout.Infinite, Timeout.Infinite); - return t; - }); + // AutoHentaiTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) => + // { + // old.Change(Timeout.Infinite, Timeout.Infinite); + // return t; + // }); - await Context.Channel.SendConfirmAsync($"Autohentai started. Reposting every {interval}s with one of the following tags:\n{string.Join(", ", tagsArr)}") - .ConfigureAwait(false); - } + // await Context.Channel.SendConfirmAsync($"Autohentai started. Reposting every {interval}s with one of the following tags:\n{string.Join(", ", tagsArr)}") + // .ConfigureAwait(false); + //} - [NadekoCommand, Usage, Description, Aliases] - public async Task HentaiBomb([Remainder] string tag = null) - { - if (!_hentaiBombBlacklist.Add(Context.User.Id)) - return; - try - { - tag = tag?.Trim() ?? ""; - tag = "rating%3Aexplicit+" + tag; + //[NadekoCommand, Usage, Description, Aliases] + //public async Task HentaiBomb([Remainder] string tag = null) + //{ + // if (!_hentaiBombBlacklist.Add(Context.User.Id)) + // return; + // try + // { + // tag = tag?.Trim() ?? ""; + // tag = "rating%3Aexplicit+" + tag; - var links = await Task.WhenAll(GetGelbooruImageLink(tag), - GetDanbooruImageLink(tag), - GetKonachanImageLink(tag), - GetYandereImageLink(tag)).ConfigureAwait(false); + // var links = await Task.WhenAll(GetGelbooruImageLink(tag), + // GetDanbooruImageLink(tag), + // GetKonachanImageLink(tag), + // GetYandereImageLink(tag)).ConfigureAwait(false); - var linksEnum = links?.Where(l => l != null); - if (links == null || !linksEnum.Any()) - { - await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false); - return; - } + // var linksEnum = links?.Where(l => l != null); + // if (links == null || !linksEnum.Any()) + // { + // await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false); + // return; + // } - await Context.Channel.SendMessageAsync(String.Join("\n\n", linksEnum)).ConfigureAwait(false); - } - finally { - await Task.Delay(5000).ConfigureAwait(false); - _hentaiBombBlacklist.TryRemove(Context.User.Id); - } - } + // await Context.Channel.SendMessageAsync(String.Join("\n\n", linksEnum)).ConfigureAwait(false); + // } + // finally { + // await Task.Delay(5000).ConfigureAwait(false); + // _hentaiBombBlacklist.TryRemove(Context.User.Id); + // } + //} [NadekoCommand, Usage, Description, Aliases] public Task Yandere([Remainder] string tag = null) @@ -147,7 +147,7 @@ namespace NadekoBot.Modules.NSFW [NadekoCommand, Usage, Description, Aliases] public Task Konachan([Remainder] string tag = null) => Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Konachan); -#endif + [NadekoCommand, Usage, Description, Aliases] public async Task E621([Remainder] string tag = null) { @@ -279,7 +279,6 @@ namespace NadekoBot.Modules.NSFW public static Task GetRule34ImageLink(string tag) => Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Rule34); -#if !GLOBAL_NADEKO public static Task GetYandereImageLink(string tag) => Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Yandere); @@ -288,6 +287,5 @@ namespace NadekoBot.Modules.NSFW public static Task GetGelbooruImageLink(string tag) => Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Gelbooru); -#endif } } \ No newline at end of file From c32546d633e55b3f524f9c1bcf65aa4fd1373f6a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 11 Feb 2017 22:29:25 +0100 Subject: [PATCH 200/746] timezone parsing done, just needs actual db field and usage --- .../Modules/Administration/Administration.cs | 40 ++++++++++++++ .../Resources/CommandStrings.Designer.cs | 54 +++++++++++++++++++ src/NadekoBot/Resources/CommandStrings.resx | 18 +++++++ 3 files changed, 112 insertions(+) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index cf92fb4b..b86f80e9 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -552,5 +552,45 @@ namespace NadekoBot.Modules.Administration await Context.Channel.SendConfirmAsync($"Successfuly added a new donator. Total donated amount from this user: {don.Amount} 👑").ConfigureAwait(false); } + + //[NadekoCommand, Usage, Description, Aliases] + //[RequireContext(ContextType.Guild)] + //public async Task Timezones(int page = 1) + //{ + // page -= 1; + + // if (page < 0 || page > 20) + // return; + + // var timezones = TimeZoneInfo.GetSystemTimeZones(); + // var timezonesPerPage = 20; + + // await Context.Channel.SendPaginatedConfirmAsync(page + 1, (curPage) => new EmbedBuilder() + // .WithOkColor() + // .WithTitle("Available Timezones") + // .WithDescription(string.Join("\n", timezones.Skip((curPage - 1) * timezonesPerPage).Take(timezonesPerPage).Select(x => $"`{x.Id,-25}` UTC{x.BaseUtcOffset:hhmm}"))), + // timezones.Count / timezonesPerPage); + //} + + //[NadekoCommand, Usage, Description, Aliases] + //[RequireContext(ContextType.Guild)] + //public async Task Timezone([Remainder] string id) + //{ + // TimeZoneInfo tz; + // try + // { + // tz = TimeZoneInfo.FindSystemTimeZoneById(id); + // if (tz != null) + // await Context.Channel.SendConfirmAsync(tz.ToString()).ConfigureAwait(false); + // } + // catch (Exception ex) + // { + // tz = null; + // _log.Warn(ex); + // } + + // if (tz == null) + // await Context.Channel.SendErrorAsync("Timezone not found. You should specify one of the timezones listed in the 'timezones' command.").ConfigureAwait(false); + //} } } \ No newline at end of file diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 04745557..11fa3692 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -7754,6 +7754,60 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to timezone. + /// + public static string timezone_cmd { + get { + return ResourceManager.GetString("timezone_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sets this guilds timezone. This affects bot's time output in this server (logs, etc..). + /// + public static string timezone_desc { + get { + return ResourceManager.GetString("timezone_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}timezone`. + /// + public static string timezone_usage { + get { + return ResourceManager.GetString("timezone_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to timezones. + /// + public static string timezones_cmd { + get { + return ResourceManager.GetString("timezones_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List of all timezones available on the system to be used with `{0}timezone`.. + /// + public static string timezones_desc { + get { + return ResourceManager.GetString("timezones_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}timezones`. + /// + public static string timezones_usage { + get { + return ResourceManager.GetString("timezones_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to tl. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index fae1afda..cca4cf5c 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3087,4 +3087,22 @@ >ttt + + timezones + + + List of all timezones available on the system to be used with `{0}timezone`. + + + `{0}timezones` + + + timezone + + + Sets this guilds timezone. This affects bot's time output in this server (logs, etc..) + + + `{0}timezone` + \ No newline at end of file From 3e3c5e75c58acf643df33705369918f58f762234 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 12 Feb 2017 00:27:52 +0100 Subject: [PATCH 201/746] ttt fix, thx aurora --- .../Modules/Games/Commands/TicTacToe.cs | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs index 1a254e28..4879793b 100644 --- a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs +++ b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs @@ -105,36 +105,6 @@ namespace NadekoBot.Modules.Games _log.Warn($"User {firstUser} created a TicTacToe game."); _phase = Phase.Starting; moveLock = new SemaphoreSlim(1, 1); - - timeoutTimer = new Timer(async (_) => - { - await moveLock.WaitAsync(); - try - { - if (_phase == Phase.Ended) - return; - - _phase = Phase.Ended; - if (_users[1] != null) - { - _winner = _users[curUserIndex ^= 1]; - var del = previousMessage?.DeleteAsync(); - try - { - await _channel.EmbedAsync(GetEmbed("Time Expired!")).ConfigureAwait(false); - await del.ConfigureAwait(false); - } - catch { } - } - - OnEnded?.Invoke(this); - } - catch { } - finally - { - moveLock.Release(); - } - }, null, 15000, Timeout.Infinite); } public string GetState() @@ -213,8 +183,39 @@ namespace NadekoBot.Modules.Games _phase = Phase.Started; + timeoutTimer = new Timer(async (_) => + { + await moveLock.WaitAsync(); + try + { + if (_phase == Phase.Ended) + return; + + _phase = Phase.Ended; + if (_users[1] != null) + { + _winner = _users[curUserIndex ^= 1]; + var del = previousMessage?.DeleteAsync(); + try + { + await _channel.EmbedAsync(GetEmbed("Time Expired!")).ConfigureAwait(false); + await del.ConfigureAwait(false); + } + catch { } + } + + OnEnded?.Invoke(this); + } + catch { } + finally + { + moveLock.Release(); + } + }, null, 15000, Timeout.Infinite); + NadekoBot.Client.MessageReceived += Client_MessageReceived; + previousMessage = await _channel.EmbedAsync(GetEmbed("Game Started")).ConfigureAwait(false); } From 85a00f61239d0a7d25ac1eee1a889b0621de202b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 12 Feb 2017 00:33:13 +0100 Subject: [PATCH 202/746] accidentaly disabled autohentai and hentaibomb on self hosteds too. --- src/NadekoBot/Modules/NSFW/NSFW.cs | 129 +++++++++++++++-------------- 1 file changed, 65 insertions(+), 64 deletions(-) diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index 131d1501..735d29f4 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -65,81 +65,82 @@ namespace NadekoBot.Modules.NSFW [NadekoCommand, Usage, Description, Aliases] public Task Hentai([Remainder] string tag = null) => InternalHentai(Context.Channel, tag, false); +#if !GLOBAL_NADEKO + [NadekoCommand, Usage, Description, Aliases] + [RequireUserPermission(ChannelPermission.ManageMessages)] + public async Task AutoHentai(int interval = 0, string tags = null) + { + Timer t; - //[NadekoCommand, Usage, Description, Aliases] - //[RequireUserPermission(ChannelPermission.ManageMessages)] - //public async Task AutoHentai(int interval = 0, string tags = null) - //{ - // Timer t; + if (interval == 0) + { + if (AutoHentaiTimers.TryRemove(Context.Channel.Id, out t)) + { + t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer + await Context.Channel.SendConfirmAsync("Autohentai stopped.").ConfigureAwait(false); + } + return; + } - // if (interval == 0) - // { - // if (AutoHentaiTimers.TryRemove(Context.Channel.Id, out t)) - // { - // t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer - // await Context.Channel.SendConfirmAsync("Autohentai stopped.").ConfigureAwait(false); - // } - // return; - // } + if (interval < 20) + return; - // if (interval < 20) - // return; + var tagsArr = tags?.Split('|'); - // var tagsArr = tags?.Split('|'); + t = new Timer(async (state) => + { + try + { + if (tagsArr == null || tagsArr.Length == 0) + await InternalHentai(Context.Channel, null, true).ConfigureAwait(false); + else + await InternalHentai(Context.Channel, tagsArr[new NadekoRandom().Next(0, tagsArr.Length)], true).ConfigureAwait(false); + } + catch { } + }, null, interval * 1000, interval * 1000); - // t = new Timer(async (state) => - // { - // try - // { - // if (tagsArr == null || tagsArr.Length == 0) - // await InternalHentai(Context.Channel, null, true).ConfigureAwait(false); - // else - // await InternalHentai(Context.Channel, tagsArr[new NadekoRandom().Next(0, tagsArr.Length)], true).ConfigureAwait(false); - // } - // catch { } - // }, null, interval * 1000, interval * 1000); + AutoHentaiTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) => + { + old.Change(Timeout.Infinite, Timeout.Infinite); + return t; + }); - // AutoHentaiTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) => - // { - // old.Change(Timeout.Infinite, Timeout.Infinite); - // return t; - // }); - - // await Context.Channel.SendConfirmAsync($"Autohentai started. Reposting every {interval}s with one of the following tags:\n{string.Join(", ", tagsArr)}") - // .ConfigureAwait(false); - //} + await Context.Channel.SendConfirmAsync($"Autohentai started. Reposting every {interval}s with one of the following tags:\n{string.Join(", ", tagsArr)}") + .ConfigureAwait(false); + } - //[NadekoCommand, Usage, Description, Aliases] - //public async Task HentaiBomb([Remainder] string tag = null) - //{ - // if (!_hentaiBombBlacklist.Add(Context.User.Id)) - // return; - // try - // { - // tag = tag?.Trim() ?? ""; - // tag = "rating%3Aexplicit+" + tag; + [NadekoCommand, Usage, Description, Aliases] + public async Task HentaiBomb([Remainder] string tag = null) + { + if (!_hentaiBombBlacklist.Add(Context.User.Id)) + return; + try + { + tag = tag?.Trim() ?? ""; + tag = "rating%3Aexplicit+" + tag; - // var links = await Task.WhenAll(GetGelbooruImageLink(tag), - // GetDanbooruImageLink(tag), - // GetKonachanImageLink(tag), - // GetYandereImageLink(tag)).ConfigureAwait(false); + var links = await Task.WhenAll(GetGelbooruImageLink(tag), + GetDanbooruImageLink(tag), + GetKonachanImageLink(tag), + GetYandereImageLink(tag)).ConfigureAwait(false); - // var linksEnum = links?.Where(l => l != null); - // if (links == null || !linksEnum.Any()) - // { - // await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false); - // return; - // } - - // await Context.Channel.SendMessageAsync(String.Join("\n\n", linksEnum)).ConfigureAwait(false); - // } - // finally { - // await Task.Delay(5000).ConfigureAwait(false); - // _hentaiBombBlacklist.TryRemove(Context.User.Id); - // } - //} + var linksEnum = links?.Where(l => l != null); + if (links == null || !linksEnum.Any()) + { + await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false); + return; + } + await Context.Channel.SendMessageAsync(String.Join("\n\n", linksEnum)).ConfigureAwait(false); + } + finally + { + await Task.Delay(5000).ConfigureAwait(false); + _hentaiBombBlacklist.TryRemove(Context.User.Id); + } + } +#endif [NadekoCommand, Usage, Description, Aliases] public Task Yandere([Remainder] string tag = null) => Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Yandere); From fb837235a7424842038f97242b84ecc7c413146d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 10:28:49 +0100 Subject: [PATCH 203/746] a bit faster OwnerOnly checking --- src/NadekoBot/Services/IBotCredentials.cs | 4 +++- src/NadekoBot/Services/Impl/BotCredentials.cs | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Services/IBotCredentials.cs b/src/NadekoBot/Services/IBotCredentials.cs index 88bc5986..a03c6db3 100644 --- a/src/NadekoBot/Services/IBotCredentials.cs +++ b/src/NadekoBot/Services/IBotCredentials.cs @@ -1,4 +1,6 @@ using Discord; +using System.Collections.Generic; +using System.Collections.Immutable; namespace NadekoBot.Services { @@ -9,7 +11,7 @@ namespace NadekoBot.Services string Token { get; } string GoogleApiKey { get; } - ulong[] OwnerIds { get; } + ImmutableHashSet OwnerIds { get; } string MashapeKey { get; } string LoLApiKey { get; } diff --git a/src/NadekoBot/Services/Impl/BotCredentials.cs b/src/NadekoBot/Services/Impl/BotCredentials.cs index 47906e8c..56851762 100644 --- a/src/NadekoBot/Services/Impl/BotCredentials.cs +++ b/src/NadekoBot/Services/Impl/BotCredentials.cs @@ -5,6 +5,8 @@ using Discord; using System.Linq; using NLog; using Microsoft.Extensions.Configuration; +using System.Collections.Generic; +using System.Collections.Immutable; namespace NadekoBot.Services.Impl { @@ -21,7 +23,7 @@ namespace NadekoBot.Services.Impl public string Token { get; } - public ulong[] OwnerIds { get; } + public ImmutableHashSet OwnerIds { get; } public string LoLApiKey { get; } public string OsuApiKey { get; } @@ -61,7 +63,7 @@ namespace NadekoBot.Services.Impl Token = data[nameof(Token)]; if (string.IsNullOrWhiteSpace(Token)) throw new ArgumentNullException(nameof(Token), "Token is missing from credentials.json or Environment varibles."); - OwnerIds = data.GetSection("OwnerIds").GetChildren().Select(c => ulong.Parse(c.Value)).ToArray(); + OwnerIds = data.GetSection("OwnerIds").GetChildren().Select(c => ulong.Parse(c.Value)).ToImmutableHashSet(); LoLApiKey = data[nameof(LoLApiKey)]; GoogleApiKey = data[nameof(GoogleApiKey)]; MashapeKey = data[nameof(MashapeKey)]; From 34c69243200c90a1b3c2a8aa30a996e280cbb831 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 10:29:34 +0100 Subject: [PATCH 204/746] Localization in the works --- src/NadekoBot/Services/Impl/Localization.cs | 110 +++++++++++++------- 1 file changed, 74 insertions(+), 36 deletions(-) diff --git a/src/NadekoBot/Services/Impl/Localization.cs b/src/NadekoBot/Services/Impl/Localization.cs index 5ec6e71d..26de5990 100644 --- a/src/NadekoBot/Services/Impl/Localization.cs +++ b/src/NadekoBot/Services/Impl/Localization.cs @@ -1,45 +1,83 @@ -namespace NadekoBot.Services +using Discord; +using Discord.Commands; +using NadekoBot.Extensions; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using System; +using NadekoBot.Services.Database; + +namespace NadekoBot.Services { public class Localization { - public string this[string key] => LoadCommandString(key); + public ConcurrentDictionary GuildCultureInfos { get; } - public static string LoadCommandString(string key) + private Localization() { } + public Localization(IDictionary cultureInfoNames) { - string toReturn = Resources.CommandStrings.ResourceManager.GetString(key); - return string.IsNullOrWhiteSpace(toReturn) ? key : toReturn; + GuildCultureInfos = new ConcurrentDictionary(cultureInfoNames.ToDictionary(x => x.Key, x => + { + CultureInfo cultureInfo = null; + try + { + cultureInfo = new CultureInfo(x.Value); + } + catch + { + } + return cultureInfo; + }).Where(x => x.Value != null)); } - //private static string GetCommandString(string key) - //{ - // return key; - //var resx = new List(); - //var fs = new StreamReader(File.OpenRead("./Strings.resx")); - //Console.WriteLine(fs.ReadToEnd()); - //using (var reader = new ResourceReader(fs.BaseStream)) - //{ - // List existing = new List(); - // foreach (DictionaryEntry item in reader) - // { - // existing.Add(item); - // } - // var existingResource = resx.Where(r => r.Key.ToString() == key).FirstOrDefault(); - // if (existingResource.Key == null) - // { - // resx.Add(new DictionaryEntry() { Key = key, Value = key }); - // } - // else - // return existingResource.Value.ToString(); - //} - //using (var writer = new ResourceWriter(new FileStream("./Strings.resx", FileMode.OpenOrCreate))) - //{ - // resx.ForEach(r => - // { - // writer.AddResource(r.Key.ToString(), r.Value.ToString()); - // }); - // writer.Generate(); - //} - //return key; - //} + public void SetGuildCulture(IGuild guild, CultureInfo ci) => + SetGuildCulture(guild.Id, ci); + + public void SetGuildCulture(ulong guildId, CultureInfo ci) + { + if (ci == DefaultCultureInfo) + { + RemoveGuildCulture(guildId); + return; + } + + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(guildId, set => set); + gc.Locale = ci.Name; + uow.Complete(); + } + } + + public void RemoveGuildCulture(IGuild guild) => + RemoveGuildCulture(guild.Id); + + public void RemoveGuildCulture(ulong guildId) { + + CultureInfo throwaway; + if (GuildCultureInfos.TryRemove(guildId, out throwaway)) + { + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(guildId, set => set); + gc.Locale = null; + uow.Complete(); + } + } + } + + public CultureInfo GetCultureInfo(IGuild guild) => + GetCultureInfo(guild.Id); + + public CultureInfo DefaultCultureInfo { get; } = CultureInfo.CurrentCulture; + + public CultureInfo GetCultureInfo(ulong guildId) + { + CultureInfo info = null; + GuildCultureInfos.TryGetValue(guildId, out info); + return info ?? DefaultCultureInfo; + } } } From 3f420f78f21a2059402bde5b98d4ad1bbef4f37b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 10:29:57 +0100 Subject: [PATCH 205/746] More localization, DiscordModule renamed to NadekoModule --- .../Modules/Administration/Administration.cs | 2 +- .../Commands/LocalizationCommands.cs | 67 ++++++++++++++++++ .../Modules/ClashOfClans/ClashOfClans.cs | 2 +- .../CustomReactions/CustomReactions.cs | 2 +- src/NadekoBot/Modules/DiscordModule.cs | 69 ++++++++++++++++--- src/NadekoBot/Modules/Gambling/Gambling.cs | 2 +- src/NadekoBot/Modules/Games/Games.cs | 2 +- src/NadekoBot/Modules/Help/Help.cs | 2 +- src/NadekoBot/Modules/Music/Music.cs | 2 +- src/NadekoBot/Modules/NSFW/NSFW.cs | 2 +- .../Modules/Permissions/Permissions.cs | 2 +- src/NadekoBot/Modules/Pokemon/Pokemon.cs | 4 +- src/NadekoBot/Modules/Searches/Searches.cs | 2 +- src/NadekoBot/Modules/Utility/Utility.cs | 2 +- src/NadekoBot/NadekoBot.cs | 8 ++- .../Services/Database/Models/GuildConfig.cs | 2 + 16 files changed, 147 insertions(+), 25 deletions(-) create mode 100644 src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index b86f80e9..76b96ec4 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -20,7 +20,7 @@ using NLog; namespace NadekoBot.Modules.Administration { [NadekoModule("Administration", ".")] - public partial class Administration : DiscordModule + public partial class Administration : NadekoModule { private static ConcurrentDictionary GuildMuteRoles { get; } = new ConcurrentDictionary(); diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs new file mode 100644 index 00000000..b06d5dce --- /dev/null +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -0,0 +1,67 @@ +using Discord; +using Discord.Commands; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Administration.Commands +{ + public partial class Administration + { + [Group] + public class LocalizationCommands : ModuleBase + { + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.Administrator)] + public async Task SetLocale([Remainder] string name) + { + CultureInfo ci = null; + try + { + if(name.Trim().ToLowerInvariant() == "default") + { + NadekoBot.Localization.RemoveGuildCulture(Context.Guild); + } + ci = new CultureInfo(name); + NadekoBot.Localization.SetGuildCulture(Context.Guild, ci); + + await Context.Channel.SendConfirmAsync($"Your guild's locale is now {ci}.").ConfigureAwait(false); + } + catch(Exception) { + + //_log.warn(ex); + await Context.Channel.SendConfirmAsync($"Failed setting locale. Revisit this command's help.").ConfigureAwait(false); + } + } + + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task SetDefaulLocale(string name) + { + CultureInfo ci = null; + try + { + if (name.Trim().ToLowerInvariant() == "default") + { + NadekoBot.Localization.RemoveGuildCulture(Context.Guild); + } + ci = new CultureInfo(name); + NadekoBot.Localization.SetGuildCulture(Context.Guild, ci); + + await Context.Channel.SendConfirmAsync($"Your guild's locale is now {ci}.").ConfigureAwait(false); + } + catch (Exception) + { + //_log.warn(ex); + await Context.Channel.SendConfirmAsync($"Failed setting locale. Revisit this command's help.").ConfigureAwait(false); + } + } + } + } +} diff --git a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs index 67510d56..83e6d00b 100644 --- a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs +++ b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs @@ -17,7 +17,7 @@ using NLog; namespace NadekoBot.Modules.ClashOfClans { [NadekoModule("ClashOfClans", ",")] - public class ClashOfClans : DiscordModule + public class ClashOfClans : NadekoModule { public static ConcurrentDictionary> ClashWars { get; set; } = new ConcurrentDictionary>(); diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index 8f76f0a8..a5129c2b 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -17,7 +17,7 @@ using NadekoBot.DataStructures; namespace NadekoBot.Modules.CustomReactions { [NadekoModule("CustomReactions", ".")] - public class CustomReactions : DiscordModule + public class CustomReactions : NadekoModule { private static CustomReaction[] _globalReactions = new CustomReaction[] { }; public static CustomReaction[] GlobalReactions => _globalReactions; diff --git a/src/NadekoBot/Modules/DiscordModule.cs b/src/NadekoBot/Modules/DiscordModule.cs index 711431d5..cc609a58 100644 --- a/src/NadekoBot/Modules/DiscordModule.cs +++ b/src/NadekoBot/Modules/DiscordModule.cs @@ -1,22 +1,69 @@ -using Discord.Commands; +using Discord; +using Discord.Commands; +using NadekoBot.Extensions; using NLog; +using System; +using System.Collections.Concurrent; +using System.Globalization; +using System.Threading.Tasks; namespace NadekoBot.Modules { - public abstract class DiscordModule : ModuleBase + public abstract class NadekoModule : ModuleBase { - protected Logger _log { get; } - protected string _prefix { get; } + protected readonly Logger _log; + public readonly string _prefix; + public readonly CultureInfo cultureInfo; - public DiscordModule() + public NadekoModule(bool isTopLevelModule = true) { - string prefix; - if (NadekoBot.ModulePrefixes.TryGetValue(this.GetType().Name, out prefix)) - _prefix = prefix; - else - _prefix = "?missing_prefix?"; - + //if it's top level module + var typeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name; + if (!NadekoBot.ModulePrefixes.TryGetValue(typeName, out _prefix)) + _prefix = "?err?"; _log = LogManager.GetCurrentClassLogger(); + + cultureInfo = (Context.Guild == null + ? CultureInfo.CurrentCulture + : NadekoBot.Localization.GetCultureInfo(Context.Guild)); + } + } + + public abstract class NadekoSubmodule : NadekoModule + { + public NadekoSubmodule() : base(false) + { + + } + } + + + public static class ModuleBaseExtensions + { + public static Task ConfirmLocalized(this NadekoModule module, string titleKey, string textKey, string url = null, string footer = null) + { + var title = NadekoBot.ResponsesResourceManager.GetString(titleKey, module.cultureInfo); + var text = NadekoBot.ResponsesResourceManager.GetString(textKey, module.cultureInfo); + return module.Context.Channel.SendConfirmAsync(title, text, url, footer); + } + + public static Task ConfirmLocalized(this NadekoModule module, string textKey) + { + var text = NadekoBot.ResponsesResourceManager.GetString(textKey, module.cultureInfo); + return module.Context.Channel.SendConfirmAsync(textKey); + } + + public static Task ErrorLocalized(this NadekoModule module, string titleKey, string textKey, string url = null, string footer = null) + { + var title = NadekoBot.ResponsesResourceManager.GetString(titleKey, module.cultureInfo); + var text = NadekoBot.ResponsesResourceManager.GetString(textKey, module.cultureInfo); + return module.Context.Channel.SendErrorAsync(title, text, url, footer); + } + + public static Task ErrorLocalized(this NadekoModule module, string textKey) + { + var text = NadekoBot.ResponsesResourceManager.GetString(textKey, module.cultureInfo); + return module.Context.Channel.SendErrorAsync(textKey); } } } diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index ceaa4300..555f55cb 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -12,7 +12,7 @@ using System.Collections.Generic; namespace NadekoBot.Modules.Gambling { [NadekoModule("Gambling", "$")] - public partial class Gambling : DiscordModule + public partial class Gambling : NadekoModule { public static string CurrencyName { get; set; } public static string CurrencyPluralName { get; set; } diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index b4107acd..e0dbb2c3 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -11,7 +11,7 @@ using NadekoBot.Extensions; namespace NadekoBot.Modules.Games { [NadekoModule("Games", ">")] - public partial class Games : DiscordModule + public partial class Games : NadekoModule { private static string[] _8BallResponses { get; } = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text).ToArray(); diff --git a/src/NadekoBot/Modules/Help/Help.cs b/src/NadekoBot/Modules/Help/Help.cs index 4a561ca6..a15501b0 100644 --- a/src/NadekoBot/Modules/Help/Help.cs +++ b/src/NadekoBot/Modules/Help/Help.cs @@ -13,7 +13,7 @@ using System.Collections.Generic; namespace NadekoBot.Modules.Help { [NadekoModule("Help", "-")] - public partial class Help : DiscordModule + public partial class Help : NadekoModule { private static string helpString { get; } = NadekoBot.BotConfig.HelpString; public static string HelpString => String.Format(helpString, NadekoBot.Credentials.ClientId, NadekoBot.ModulePrefixes[typeof(Help).Name]); diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index c6746996..bae06919 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -21,7 +21,7 @@ namespace NadekoBot.Modules.Music { [NadekoModule("Music", "!!")] [DontAutoLoad] - public partial class Music : DiscordModule + public partial class Music : NadekoModule { public static ConcurrentDictionary MusicPlayers { get; } = new ConcurrentDictionary(); diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index 735d29f4..c2e42d58 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -17,7 +17,7 @@ using System.Collections.Concurrent; namespace NadekoBot.Modules.NSFW { [NadekoModule("NSFW", "~")] - public class NSFW : DiscordModule + public class NSFW : NadekoModule { private static ConcurrentDictionary AutoHentaiTimers { get; } = new ConcurrentDictionary(); diff --git a/src/NadekoBot/Modules/Permissions/Permissions.cs b/src/NadekoBot/Modules/Permissions/Permissions.cs index 33d8a27e..407ca2a2 100644 --- a/src/NadekoBot/Modules/Permissions/Permissions.cs +++ b/src/NadekoBot/Modules/Permissions/Permissions.cs @@ -15,7 +15,7 @@ using NLog; namespace NadekoBot.Modules.Permissions { [NadekoModule("Permissions", ";")] - public partial class Permissions : DiscordModule + public partial class Permissions : NadekoModule { public class PermissionCache { diff --git a/src/NadekoBot/Modules/Pokemon/Pokemon.cs b/src/NadekoBot/Modules/Pokemon/Pokemon.cs index 2ce50745..3ece509f 100644 --- a/src/NadekoBot/Modules/Pokemon/Pokemon.cs +++ b/src/NadekoBot/Modules/Pokemon/Pokemon.cs @@ -16,7 +16,7 @@ using System.Collections.Concurrent; namespace NadekoBot.Modules.Pokemon { [NadekoModule("Pokemon", ">")] - public partial class Pokemon : DiscordModule + public partial class Pokemon : NadekoModule { private static List PokemonTypes = new List(); private static ConcurrentDictionary Stats = new ConcurrentDictionary(); @@ -105,7 +105,7 @@ namespace NadekoBot.Modules.Pokemon if (targetUser == null) { - await Context.Channel.SendMessageAsync("No such person.").ConfigureAwait(false); + await ReplyLocalized("no user found").ConfigureAwait(false); return; } else if (targetUser == user) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 8abcfee8..d612299c 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -28,7 +28,7 @@ using System.Xml.Linq; namespace NadekoBot.Modules.Searches { [NadekoModule("Searches", "~")] - public partial class Searches : DiscordModule + public partial class Searches : NadekoModule { [NadekoCommand, Usage, Description, Aliases] public async Task Weather([Remainder] string query) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index d5826f1b..1705d934 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -21,7 +21,7 @@ using NadekoBot.Services; namespace NadekoBot.Modules.Utility { [NadekoModule("Utility", ".")] - public partial class Utility : DiscordModule + public partial class Utility : NadekoModule { private static ConcurrentDictionary rotatingRoleColors = new ConcurrentDictionary(); diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 49d0d5c4..65f1e02b 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -16,6 +16,8 @@ using NadekoBot.TypeReaders; using System.Collections.Concurrent; using NadekoBot.Modules.Music; using NadekoBot.Services.Database.Models; +using System.Resources; +using NadekoBot.Resources; namespace NadekoBot { @@ -29,7 +31,10 @@ namespace NadekoBot public static CommandService CommandService { get; private set; } public static CommandHandler CommandHandler { get; private set; } public static DiscordShardedClient Client { get; private set; } - public static BotCredentials Credentials { get; private set; } + public static BotCredentials Credentials { get; } + + public static Localization Localization { get; private set; } + public static ResourceManager ResponsesResourceManager { get; } = new ResourceManager(typeof(ResponseStrings)); public static GoogleApiService Google { get; private set; } public static StatsService Stats { get; private set; } @@ -79,6 +84,7 @@ namespace NadekoBot #endif //initialize Services + Localization = new Localization(NadekoBot.AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale)); CommandService = new CommandService(new CommandServiceConfig() { CaseSensitiveCommands = false, DefaultRunMode = RunMode.Sync diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs index 7931e8c9..9b0209e9 100644 --- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs +++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs @@ -64,6 +64,8 @@ namespace NadekoBot.Services.Database.Models public AntiRaidSetting AntiRaidSetting { get; set; } public AntiSpamSetting AntiSpamSetting { get; set; } + public string Locale { get; set; } + //public List ProtectionIgnoredChannels { get; set; } = new List(); } From db79177f0cbc8c2bae097cdffb3e150f48284e1a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 10:50:58 +0100 Subject: [PATCH 206/746] Setting locales done? Needs testing --- .../Commands/LocalizationCommands.cs | 8 +-- .../Resources/CommandStrings.Designer.cs | 54 +++++++++++++++++++ src/NadekoBot/Resources/CommandStrings.resx | 18 +++++++ src/NadekoBot/Services/Impl/Localization.cs | 13 ++++- 4 files changed, 87 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index b06d5dce..a7e39fc6 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -19,7 +19,7 @@ namespace NadekoBot.Modules.Administration.Commands [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.Administrator)] - public async Task SetLocale([Remainder] string name) + public async Task SetLocale([Remainder] string name = null) { CultureInfo ci = null; try @@ -42,17 +42,17 @@ namespace NadekoBot.Modules.Administration.Commands [NadekoCommand, Usage, Description, Aliases] [OwnerOnly] - public async Task SetDefaulLocale(string name) + public async Task SetDefaultLocale(string name) { CultureInfo ci = null; try { if (name.Trim().ToLowerInvariant() == "default") { - NadekoBot.Localization.RemoveGuildCulture(Context.Guild); + NadekoBot.Localization.ResetDefaultCulture(); } ci = new CultureInfo(name); - NadekoBot.Localization.SetGuildCulture(Context.Guild, ci); + NadekoBot.Localization.SetDefaultCulture(ci); await Context.Channel.SendConfirmAsync($"Your guild's locale is now {ci}.").ConfigureAwait(false); } diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 11fa3692..3659c523 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -6755,6 +6755,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to setdefaultlocale sdl. + /// + public static string setdefaultlocale_cmd { + get { + return ResourceManager.GetString("setdefaultlocale_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sets the bot's default locale. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture.. + /// + public static string setdefaultlocale_desc { + get { + return ResourceManager.GetString("setdefaultlocale_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}sdl en-US` or `{0}sdl default`. + /// + public static string setdefaultlocale_usage { + get { + return ResourceManager.GetString("setdefaultlocale_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to setgame. /// @@ -6782,6 +6809,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to setlocale sl. + /// + public static string setlocale_cmd { + get { + return ResourceManager.GetString("setlocale_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sets this server's response locale (language). If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name.. + /// + public static string setlocale_desc { + get { + return ResourceManager.GetString("setlocale_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{}sl de-DE ` or `{0}sl default`. + /// + public static string setlocale_usage { + get { + return ResourceManager.GetString("setlocale_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to setmaxplaytime smp. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index cca4cf5c..0c1566d0 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3105,4 +3105,22 @@ `{0}timezone` + + setdefaultlocale sdl + + + Sets the bot's default locale. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. + + + `{0}sdl en-US` or `{0}sdl default` + + + setlocale sl + + + Sets this server's response locale (language). If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. + + + `{}sl de-DE ` or `{0}sl default` + \ No newline at end of file diff --git a/src/NadekoBot/Services/Impl/Localization.cs b/src/NadekoBot/Services/Impl/Localization.cs index 26de5990..7a29c233 100644 --- a/src/NadekoBot/Services/Impl/Localization.cs +++ b/src/NadekoBot/Services/Impl/Localization.cs @@ -14,6 +14,7 @@ namespace NadekoBot.Services public class Localization { public ConcurrentDictionary GuildCultureInfos { get; } + public CultureInfo DefaultCultureInfo { get; private set; } = CultureInfo.CurrentCulture; private Localization() { } public Localization(IDictionary cultureInfoNames) @@ -68,11 +69,19 @@ namespace NadekoBot.Services } } + internal void SetDefaultCulture(CultureInfo ci) + { + DefaultCultureInfo = ci; + } + + public void ResetDefaultCulture() + { + DefaultCultureInfo = CultureInfo.CurrentCulture; + } + public CultureInfo GetCultureInfo(IGuild guild) => GetCultureInfo(guild.Id); - public CultureInfo DefaultCultureInfo { get; } = CultureInfo.CurrentCulture; - public CultureInfo GetCultureInfo(ulong guildId) { CultureInfo info = null; From a1e25f5149161497b5a2f0f5d2286a759fc5a1eb Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 11:12:13 +0100 Subject: [PATCH 207/746] Cleanup, now compiles! :O --- .../{DiscordModule.cs => NadekoModule.cs} | 57 +++++++++---------- .../Modules/NadekoModuleExtensions.cs | 15 +++++ src/NadekoBot/Modules/Pokemon/Pokemon.cs | 6 +- .../Resources/ResponseStrings.Designer.cs | 18 ++++++ src/NadekoBot/Resources/ResponseStrings.resx | 6 ++ src/NadekoBot/Services/CommandHandler.cs | 2 +- src/NadekoBot/Services/Impl/Localization.cs | 6 ++ 7 files changed, 76 insertions(+), 34 deletions(-) rename src/NadekoBot/Modules/{DiscordModule.cs => NadekoModule.cs} (59%) create mode 100644 src/NadekoBot/Modules/NadekoModuleExtensions.cs diff --git a/src/NadekoBot/Modules/DiscordModule.cs b/src/NadekoBot/Modules/NadekoModule.cs similarity index 59% rename from src/NadekoBot/Modules/DiscordModule.cs rename to src/NadekoBot/Modules/NadekoModule.cs index cc609a58..b5541b78 100644 --- a/src/NadekoBot/Modules/DiscordModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -27,43 +27,38 @@ namespace NadekoBot.Modules ? CultureInfo.CurrentCulture : NadekoBot.Localization.GetCultureInfo(Context.Guild)); } + + public Task ConfirmLocalized(string titleKey, string textKey, string url = null, string footer = null) + { + var title = NadekoBot.ResponsesResourceManager.GetString(titleKey, cultureInfo); + var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo); + return Context.Channel.SendConfirmAsync(title, text, url, footer); + } + + public Task ConfirmLocalized(string textKey) + { + var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo); + return Context.Channel.SendConfirmAsync(textKey); + } + + public Task ErrorLocalized(string titleKey, string textKey, string url = null, string footer = null) + { + var title = NadekoBot.ResponsesResourceManager.GetString(titleKey, cultureInfo); + var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo); + return Context.Channel.SendErrorAsync(title, text, url, footer); + } + + public Task ErrorLocalized(string textKey) + { + var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo); + return Context.Channel.SendErrorAsync(textKey); + } } public abstract class NadekoSubmodule : NadekoModule { public NadekoSubmodule() : base(false) { - - } - } - - - public static class ModuleBaseExtensions - { - public static Task ConfirmLocalized(this NadekoModule module, string titleKey, string textKey, string url = null, string footer = null) - { - var title = NadekoBot.ResponsesResourceManager.GetString(titleKey, module.cultureInfo); - var text = NadekoBot.ResponsesResourceManager.GetString(textKey, module.cultureInfo); - return module.Context.Channel.SendConfirmAsync(title, text, url, footer); - } - - public static Task ConfirmLocalized(this NadekoModule module, string textKey) - { - var text = NadekoBot.ResponsesResourceManager.GetString(textKey, module.cultureInfo); - return module.Context.Channel.SendConfirmAsync(textKey); - } - - public static Task ErrorLocalized(this NadekoModule module, string titleKey, string textKey, string url = null, string footer = null) - { - var title = NadekoBot.ResponsesResourceManager.GetString(titleKey, module.cultureInfo); - var text = NadekoBot.ResponsesResourceManager.GetString(textKey, module.cultureInfo); - return module.Context.Channel.SendErrorAsync(title, text, url, footer); - } - - public static Task ErrorLocalized(this NadekoModule module, string textKey) - { - var text = NadekoBot.ResponsesResourceManager.GetString(textKey, module.cultureInfo); - return module.Context.Channel.SendErrorAsync(textKey); } } } diff --git a/src/NadekoBot/Modules/NadekoModuleExtensions.cs b/src/NadekoBot/Modules/NadekoModuleExtensions.cs new file mode 100644 index 00000000..09625409 --- /dev/null +++ b/src/NadekoBot/Modules/NadekoModuleExtensions.cs @@ -0,0 +1,15 @@ +using Discord; +using NadekoBot.Extensions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules +{ + public static class NadekoModuleExtensions + { + + } +} diff --git a/src/NadekoBot/Modules/Pokemon/Pokemon.cs b/src/NadekoBot/Modules/Pokemon/Pokemon.cs index 3ece509f..19515ad1 100644 --- a/src/NadekoBot/Modules/Pokemon/Pokemon.cs +++ b/src/NadekoBot/Modules/Pokemon/Pokemon.cs @@ -12,6 +12,8 @@ using System; using Newtonsoft.Json; using System.IO; using System.Collections.Concurrent; +using NadekoBot.Modules; +using NadekoBot.Resources; namespace NadekoBot.Modules.Pokemon { @@ -105,12 +107,12 @@ namespace NadekoBot.Modules.Pokemon if (targetUser == null) { - await ReplyLocalized("no user found").ConfigureAwait(false); + await ErrorLocalized(nameof(ResponseStrings.Culture)).ConfigureAwait(false); return; } else if (targetUser == user) { - await Context.Channel.SendMessageAsync("You can't attack yourself.").ConfigureAwait(false); + await ErrorLocalized("You can't attack yourself.").ConfigureAwait(false); return; } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 72395491..5b93ef8c 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -58,5 +58,23 @@ namespace NadekoBot.Resources { resourceCulture = value; } } + + /// + /// Looks up a localized string similar to You can't attack yourself.. + /// + public static string cant_attack_yourself { + get { + return ResourceManager.GetString("cant_attack_yourself", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User not found.. + /// + public static string no_user_found { + get { + return ResourceManager.GetString("no_user_found", resourceCulture); + } + } } } diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 1af7de15..e740045d 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -117,4 +117,10 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + You can't attack yourself. + + + User not found. + \ No newline at end of file diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index ac0a5b80..ce17de09 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -73,7 +73,7 @@ namespace NadekoBot.Services if (!ownerChannels.Any()) _log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file."); else - _log.Info($"Created {ownerChannels.Count} out of {NadekoBot.Credentials.OwnerIds.Length} owner message channels."); + _log.Info($"Created {ownerChannels.Count} out of {NadekoBot.Credentials.OwnerIds.Count} owner message channels."); _client.MessageReceived += MessageReceivedHandler; } diff --git a/src/NadekoBot/Services/Impl/Localization.cs b/src/NadekoBot/Services/Impl/Localization.cs index 7a29c233..dc64dd3e 100644 --- a/src/NadekoBot/Services/Impl/Localization.cs +++ b/src/NadekoBot/Services/Impl/Localization.cs @@ -88,5 +88,11 @@ namespace NadekoBot.Services GuildCultureInfos.TryGetValue(guildId, out info); return info ?? DefaultCultureInfo; } + + public static string LoadCommandString(string key) + { + string toReturn = Resources.CommandStrings.ResourceManager.GetString(key); + return string.IsNullOrWhiteSpace(toReturn) ? key : toReturn; + } } } From eb17f0b5b77f4e18f9ea13825e89b94b34f0cf92 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 13:24:11 +0100 Subject: [PATCH 208/746] pokemon mostly localized, only strings which are constructed are left. --- src/NadekoBot/Modules/NadekoModule.cs | 38 +++- src/NadekoBot/Modules/Pokemon/Pokemon.cs | 67 +++---- .../Resources/ResponseStrings.Designer.cs | 188 +++++++++++++++++- src/NadekoBot/Resources/ResponseStrings.resx | 65 +++++- 4 files changed, 305 insertions(+), 53 deletions(-) diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index b5541b78..5ce45fb4 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -28,30 +28,48 @@ namespace NadekoBot.Modules : NadekoBot.Localization.GetCultureInfo(Context.Guild)); } - public Task ConfirmLocalized(string titleKey, string textKey, string url = null, string footer = null) + //public Task ReplyConfirmLocalized(string titleKey, string textKey, string url = null, string footer = null) + //{ + // var title = NadekoBot.ResponsesResourceManager.GetString(titleKey, cultureInfo); + // var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo); + // return Context.Channel.SendConfirmAsync(title, text, url, footer); + //} + + //public Task ReplyConfirmLocalized(string textKey) + //{ + // var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo); + // return Context.Channel.SendConfirmAsync(Context.User.Mention + " " + textKey); + //} + + //public Task ReplyErrorLocalized(string titleKey, string textKey, string url = null, string footer = null) + //{ + // var title = NadekoBot.ResponsesResourceManager.GetString(titleKey, cultureInfo); + // var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo); + // return Context.Channel.SendErrorAsync(title, text, url, footer); + //} + + public Task ErrorLocalized(string textKey, params object[] replacements) { - var title = NadekoBot.ResponsesResourceManager.GetString(titleKey, cultureInfo); var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo); - return Context.Channel.SendConfirmAsync(title, text, url, footer); + return Context.Channel.SendErrorAsync(string.Format(text, replacements)); } - public Task ConfirmLocalized(string textKey) + public Task ReplyErrorLocalized(string textKey, params object[] replacements) { var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo); - return Context.Channel.SendConfirmAsync(textKey); + return Context.Channel.SendErrorAsync(Context.User.Mention + " " +string.Format(text, replacements)); } - public Task ErrorLocalized(string titleKey, string textKey, string url = null, string footer = null) + public Task ConfirmLocalized(string textKey, params object[] replacements) { - var title = NadekoBot.ResponsesResourceManager.GetString(titleKey, cultureInfo); var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo); - return Context.Channel.SendErrorAsync(title, text, url, footer); + return Context.Channel.SendConfirmAsync(string.Format(text, replacements)); } - public Task ErrorLocalized(string textKey) + public Task ReplyConfirmLocalized(string textKey, params object[] replacements) { var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo); - return Context.Channel.SendErrorAsync(textKey); + return Context.Channel.SendConfirmAsync(Context.User.Mention + " " + string.Format(text, replacements)); } } diff --git a/src/NadekoBot/Modules/Pokemon/Pokemon.cs b/src/NadekoBot/Modules/Pokemon/Pokemon.cs index 19515ad1..997f3570 100644 --- a/src/NadekoBot/Modules/Pokemon/Pokemon.cs +++ b/src/NadekoBot/Modules/Pokemon/Pokemon.cs @@ -107,12 +107,12 @@ namespace NadekoBot.Modules.Pokemon if (targetUser == null) { - await ErrorLocalized(nameof(ResponseStrings.Culture)).ConfigureAwait(false); + await ReplyErrorLocalized("user_not_found").ConfigureAwait(false); return; } - else if (targetUser == user) + if (targetUser == user) { - await ErrorLocalized("You can't attack yourself.").ConfigureAwait(false); + await ReplyErrorLocalized("cant_attack_yourself").ConfigureAwait(false); return; } @@ -126,17 +126,17 @@ namespace NadekoBot.Modules.Pokemon //User not able if HP < 0, has made more than 4 attacks if (userStats.Hp < 0) { - await Context.Channel.SendMessageAsync($"{user.Mention} has fainted and was not able to move!").ConfigureAwait(false); + await ReplyErrorLocalized("you_fainted").ConfigureAwait(false); return; } if (userStats.MovesMade >= 5) { - await Context.Channel.SendMessageAsync($"{user.Mention} has used too many moves in a row and was not able to move!").ConfigureAwait(false); + await ReplyErrorLocalized("too_many_moves").ConfigureAwait(false); return; } if (userStats.LastAttacked.Contains(targetUser.Id)) { - await Context.Channel.SendMessageAsync($"{user.Mention} can't attack again without retaliation!").ConfigureAwait(false); + await ReplyErrorLocalized("cant_attack_again").ConfigureAwait(false); return; } //get target stats @@ -146,7 +146,7 @@ namespace NadekoBot.Modules.Pokemon //If target's HP is below 0, no use attacking if (targetStats.Hp <= 0) { - await Context.Channel.SendMessageAsync($"{targetUser.Mention} has already fainted!").ConfigureAwait(false); + await ReplyErrorLocalized("too_many_moves", targetUser).ConfigureAwait(false); return; } @@ -156,7 +156,7 @@ namespace NadekoBot.Modules.Pokemon var enabledMoves = userType.Moves; if (!enabledMoves.Contains(move.ToLowerInvariant())) { - await Context.Channel.SendMessageAsync($"{user.Mention} is not able to use **{move}**. Type {NadekoBot.ModulePrefixes[typeof(Pokemon).Name]}ml to see moves").ConfigureAwait(false); + await ReplyErrorLocalized("invalid_move", move, _prefix).ConfigureAwait(false); return; } @@ -172,7 +172,7 @@ namespace NadekoBot.Modules.Pokemon //Damage type if (damage < 40) { - response += "\nIt's not effective.."; + response += "\nIt's not effective."; } else if (damage > 60) { @@ -235,7 +235,7 @@ namespace NadekoBot.Modules.Pokemon IGuildUser user = (IGuildUser)Context.User; if (targetUser == null) { - await Context.Channel.SendMessageAsync("No such person.").ConfigureAwait(false); + await ReplyErrorLocalized("user_not_found").ConfigureAwait(false); return; } @@ -244,7 +244,7 @@ namespace NadekoBot.Modules.Pokemon var targetStats = Stats[targetUser.Id]; if (targetStats.Hp == targetStats.MaxHp) { - await Context.Channel.SendMessageAsync($"{targetUser.Mention} already has full HP!").ConfigureAwait(false); + await ReplyErrorLocalized("already_full", targetUser).ConfigureAwait(false); return; } //Payment~ @@ -253,11 +253,11 @@ namespace NadekoBot.Modules.Pokemon var target = (targetUser.Id == user.Id) ? "yourself" : targetUser.Mention; if (amount > 0) { - if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"Poke-Heal {target}", amount, true).ConfigureAwait(false)) - { - try { await Context.Channel.SendMessageAsync($"{user.Mention} You don't have enough {NadekoBot.BotConfig.CurrencyName}s.").ConfigureAwait(false); } catch { } - return; - } + if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"Poke-Heal {target}", amount, true).ConfigureAwait(false)) + { + await ReplyErrorLocalized("no_currency", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); + return; + } } //healing @@ -268,20 +268,18 @@ namespace NadekoBot.Modules.Pokemon Stats[targetUser.Id].Hp = (targetStats.MaxHp / 2); if (target == "yourself") { - await Context.Channel.SendMessageAsync($"You revived yourself with one {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); + await ReplyErrorLocalized("revive_yourself", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); + return; } - else - { - await Context.Channel.SendMessageAsync($"{user.Mention} revived {targetUser.Mention} with one {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); - } - return; + + await ReplyErrorLocalized("revive_other", targetUser, NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); } - await Context.Channel.SendMessageAsync($"{user.Mention} healed {targetUser.Mention} with one {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); + await ReplyErrorLocalized("healed", targetUser, NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); return; } else { - await Context.Channel.SendMessageAsync($"{targetUser.Mention} already has full HP!").ConfigureAwait(false); + await ErrorLocalized("already_full", targetUser); } } @@ -290,15 +288,9 @@ namespace NadekoBot.Modules.Pokemon [RequireContext(ContextType.Guild)] public async Task Type(IGuildUser targetUser = null) { - IGuildUser user = (IGuildUser)Context.User; - - if (targetUser == null) - { - return; - } - + targetUser = targetUser ?? (IGuildUser)Context.User; var pType = GetPokeType(targetUser.Id); - await Context.Channel.SendMessageAsync($"Type of {targetUser.Mention} is **{pType.Name.ToLowerInvariant()}**{pType.Icon}").ConfigureAwait(false); + await ReplyConfirmLocalized("type_of_user", targetUser.Mention, pType.Name.ToLowerInvariant() + pType.Icon).ConfigureAwait(false); } @@ -320,7 +312,7 @@ namespace NadekoBot.Modules.Pokemon } if (targetType == GetPokeType(user.Id)) { - await Context.Channel.SendMessageAsync($"Your type is already {targetType.Name.ToLowerInvariant()}{targetType.Icon}").ConfigureAwait(false); + await ReplyErrorLocalized("already_that_type", targetType.Name.ToLowerInvariant() + targetType.Icon).ConfigureAwait(false); return; } @@ -328,9 +320,9 @@ namespace NadekoBot.Modules.Pokemon var amount = 1; if (amount > 0) { - if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"{user.Mention} change type to {typeTargeted}", amount, true).ConfigureAwait(false)) + if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"{user} change type to {typeTargeted}", amount, true).ConfigureAwait(false)) { - try { await Context.Channel.SendMessageAsync($"{user.Mention} You don't have enough {NadekoBot.BotConfig.CurrencyName}s.").ConfigureAwait(false); } catch { } + await ReplyErrorLocalized("no_currency", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); return; } } @@ -363,9 +355,10 @@ namespace NadekoBot.Modules.Pokemon } //Now for the response - await Context.Channel.SendMessageAsync($"Set type of {user.Mention} to {typeTargeted}{targetType.Icon} for a {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); + await ReplyConfirmLocalized("settype_success", + typeTargeted + targetType.Icon, + NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); } - } } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 5b93ef8c..aab0ef1f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -59,21 +59,201 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to {0} has already fainted.. + /// + public static string pokemon_already_fainted { + get { + return ResourceManager.GetString("pokemon_already_fainted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {1} already has full HP.. + /// + public static string pokemon_already_full { + get { + return ResourceManager.GetString("pokemon_already_full", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Your type is already {0}. + /// + public static string pokemon_already_that_type { + get { + return ResourceManager.GetString("pokemon_already_that_type", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to used **{0}**{1} on {2}{3} for **{4}** damage.. + /// + public static string pokemon_attack { + get { + return ResourceManager.GetString("pokemon_attack", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You can't attack again without retaliation!. + /// + public static string pokemon_cant_attack_again { + get { + return ResourceManager.GetString("pokemon_cant_attack_again", resourceCulture); + } + } + /// /// Looks up a localized string similar to You can't attack yourself.. /// - public static string cant_attack_yourself { + public static string pokemon_cant_attack_yourself { get { - return ResourceManager.GetString("cant_attack_yourself", resourceCulture); + return ResourceManager.GetString("pokemon_cant_attack_yourself", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has fainted!. + /// + public static string pokemon_fainted { + get { + return ResourceManager.GetString("pokemon_fainted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has {1} HP remaining.. + /// + public static string pokemon_hp_remaining { + get { + return ResourceManager.GetString("pokemon_hp_remaining", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You are not able to use **{0}**. Type {1}ml to see a list of moves you can use.. + /// + public static string pokemon_invalid_move { + get { + return ResourceManager.GetString("pokemon_invalid_move", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It's not effective.. + /// + public static string pokemon_its_not_effective { + get { + return ResourceManager.GetString("pokemon_its_not_effective", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It's somewhat effective.. + /// + public static string pokemon_its_somewhat_effective { + get { + return ResourceManager.GetString("pokemon_its_somewhat_effective", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It's super effective!. + /// + public static string pokemon_its_super_effective { + get { + return ResourceManager.GetString("pokemon_its_super_effective", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Moves for {0} type. + /// + public static string pokemon_moves { + get { + return ResourceManager.GetString("pokemon_moves", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You don't have enough {0}. + /// + public static string pokemon_no_currency { + get { + return ResourceManager.GetString("pokemon_no_currency", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to revived {0} with one {1}. + /// + public static string pokemon_revive_other { + get { + return ResourceManager.GetString("pokemon_revive_other", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You revived yourself with one {0}. + /// + public static string pokemon_revive_yourself { + get { + return ResourceManager.GetString("pokemon_revive_yourself", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Your type has been changed to {0} for a {1}. + /// + public static string pokemon_settype_success { + get { + return ResourceManager.GetString("pokemon_settype_success", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You used too many moves in a row, so you can't move!. + /// + public static string pokemon_too_many_moves { + get { + return ResourceManager.GetString("pokemon_too_many_moves", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type of {0} is **{1}**. + /// + public static string pokemon_type_of_user { + get { + return ResourceManager.GetString("pokemon_type_of_user", resourceCulture); } } /// /// Looks up a localized string similar to User not found.. /// - public static string no_user_found { + public static string pokemon_user_not_found { get { - return ResourceManager.GetString("no_user_found", resourceCulture); + return ResourceManager.GetString("pokemon_user_not_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You fainted, so you are not able to move!. + /// + public static string pokemon_you_fainted { + get { + return ResourceManager.GetString("pokemon_you_fainted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to healed {0} with one {1}. + /// + public static string pokmeon_healed { + get { + return ResourceManager.GetString("pokmeon_healed", resourceCulture); } } } diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index e740045d..69503270 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -117,10 +117,71 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + + {0} has already fainted. + + + {1} already has full HP. + + + Your type is already {0} + + + used **{0}**{1} on {2}{3} for **{4}** damage. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + You can't attack again without retaliation! + + You can't attack yourself. - + + {0} has fainted! + + + {0} has {1} HP remaining. + + + You are not able to use **{0}**. Type {1}ml to see a list of moves you can use. + + + It's not effective. + + + It's somewhat effective. + + + It's super effective! + + + Moves for {0} type + + + You don't have enough {0} + + + revived {0} with one {1} + + + You revived yourself with one {0} + + + Your type has been changed to {0} for a {1} + + + You used too many moves in a row, so you can't move! + + + Type of {0} is **{1}** + + User not found. + + You fainted, so you are not able to move! + + + healed {0} with one {1} + \ No newline at end of file From 5571f74c5227340b68c33c5c75d82d0b10721dd4 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 13:44:21 +0100 Subject: [PATCH 209/746] Fixes, everything localized? --- src/NadekoBot/Modules/NadekoModule.cs | 26 +++++++-- src/NadekoBot/Modules/Pokemon/Pokemon.cs | 32 +++++------ .../Resources/ResponseStrings.Designer.cs | 56 +++++++++---------- src/NadekoBot/Resources/ResponseStrings.resx | 20 +++---- 4 files changed, 73 insertions(+), 61 deletions(-) diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index 5ce45fb4..9c574cde 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -14,12 +14,16 @@ namespace NadekoBot.Modules protected readonly Logger _log; public readonly string _prefix; public readonly CultureInfo cultureInfo; + public readonly string ModuleTypeName; + public readonly string LowerModuleTypeName; public NadekoModule(bool isTopLevelModule = true) { //if it's top level module - var typeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name; - if (!NadekoBot.ModulePrefixes.TryGetValue(typeName, out _prefix)) + ModuleTypeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name; + LowerModuleTypeName = ModuleTypeName.ToLowerInvariant(); + + if (!NadekoBot.ModulePrefixes.TryGetValue(ModuleTypeName, out _prefix)) _prefix = "?err?"; _log = LogManager.GetCurrentClassLogger(); @@ -48,27 +52,37 @@ namespace NadekoBot.Modules // return Context.Channel.SendErrorAsync(title, text, url, footer); //} + protected string GetText(string key) + { + return NadekoBot.ResponsesResourceManager.GetString(LowerModuleTypeName + "_" + key, cultureInfo); + } + + protected string GetText(string key, params object[] replacements) + { + return string.Format(GetText(key), replacements); + } + public Task ErrorLocalized(string textKey, params object[] replacements) { - var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo); + var text = GetText(textKey); return Context.Channel.SendErrorAsync(string.Format(text, replacements)); } public Task ReplyErrorLocalized(string textKey, params object[] replacements) { - var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo); + var text = GetText(textKey); return Context.Channel.SendErrorAsync(Context.User.Mention + " " +string.Format(text, replacements)); } public Task ConfirmLocalized(string textKey, params object[] replacements) { - var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo); + var text = GetText(textKey); return Context.Channel.SendConfirmAsync(string.Format(text, replacements)); } public Task ReplyConfirmLocalized(string textKey, params object[] replacements) { - var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo); + var text = GetText(textKey); return Context.Channel.SendConfirmAsync(Context.User.Mention + " " + string.Format(text, replacements)); } } diff --git a/src/NadekoBot/Modules/Pokemon/Pokemon.cs b/src/NadekoBot/Modules/Pokemon/Pokemon.cs index 997f3570..dab998ff 100644 --- a/src/NadekoBot/Modules/Pokemon/Pokemon.cs +++ b/src/NadekoBot/Modules/Pokemon/Pokemon.cs @@ -166,32 +166,32 @@ namespace NadekoBot.Modules.Pokemon int damage = GetDamage(userType, targetType); //apply damage to target targetStats.Hp -= damage; - - var response = $"{user.Mention} used **{move}**{userType.Icon} on {targetUser.Mention}{targetType.Icon} for **{damage}** damage"; + + var response = GetText("attack", move, userType.Icon, targetUser.Mention, targetType.Icon, damage); //Damage type if (damage < 40) { - response += "\nIt's not effective."; + response += "\n" + GetText("not_effective"); } else if (damage > 60) { - response += "\nIt's super effective!"; + response += "\n" + GetText("super_effective"); } else { - response += "\nIt's somewhat effective"; + response += "\n" + GetText("somewhat_effective"); } //check fainted if (targetStats.Hp <= 0) { - response += $"\n**{targetUser.Mention}** has fainted!"; + response += $"\n" + GetText("fainted", targetUser); } else { - response += $"\n**{targetUser.Mention}** has {targetStats.Hp} HP remaining"; + response += $"\n" + GetText("hp_remaining", targetUser, targetStats.Hp); } //update other stats @@ -208,7 +208,7 @@ namespace NadekoBot.Modules.Pokemon Stats[user.Id] = userStats; Stats[targetUser.Id] = targetStats; - await Context.Channel.SendMessageAsync(response).ConfigureAwait(false); + await Context.Channel.SendConfirmAsync(Context.User.Mention + " " + response).ConfigureAwait(false); } @@ -220,12 +220,10 @@ namespace NadekoBot.Modules.Pokemon var userType = GetPokeType(user.Id); var movesList = userType.Moves; - var str = $"**Moves for `{userType.Name}` type.**"; - foreach (string m in movesList) - { - str += $"\n{userType.Icon}{m}"; - } - await Context.Channel.SendMessageAsync(str).ConfigureAwait(false); + var embed = new EmbedBuilder().WithOkColor() + .WithTitle(GetText("moves", userType)) + .WithDescription(string.Join("\n", movesList.Select(m => userType.Icon + " " + m))); + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -268,13 +266,13 @@ namespace NadekoBot.Modules.Pokemon Stats[targetUser.Id].Hp = (targetStats.MaxHp / 2); if (target == "yourself") { - await ReplyErrorLocalized("revive_yourself", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); + await ReplyConfirmLocalized("revive_yourself", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); return; } - await ReplyErrorLocalized("revive_other", targetUser, NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); + await ReplyConfirmLocalized("revive_other", targetUser, NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); } - await ReplyErrorLocalized("healed", targetUser, NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); + await ReplyConfirmLocalized("healed", targetUser, NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); return; } else diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index aab0ef1f..1e0c5ff4 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -141,34 +141,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to It's not effective.. - /// - public static string pokemon_its_not_effective { - get { - return ResourceManager.GetString("pokemon_its_not_effective", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to It's somewhat effective.. - /// - public static string pokemon_its_somewhat_effective { - get { - return ResourceManager.GetString("pokemon_its_somewhat_effective", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to It's super effective!. - /// - public static string pokemon_its_super_effective { - get { - return ResourceManager.GetString("pokemon_its_super_effective", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Moves for {0} type. + /// Looks up a localized string similar to Movelist for "{0}" type. /// public static string pokemon_moves { get { @@ -185,6 +158,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to It's not effective.. + /// + public static string pokemon_not_effective { + get { + return ResourceManager.GetString("pokemon_not_effective", resourceCulture); + } + } + /// /// Looks up a localized string similar to revived {0} with one {1}. /// @@ -212,6 +194,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to It's somewhat effective.. + /// + public static string pokemon_somewhat_effective { + get { + return ResourceManager.GetString("pokemon_somewhat_effective", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It's super effective!. + /// + public static string pokemon_super_effective { + get { + return ResourceManager.GetString("pokemon_super_effective", resourceCulture); + } + } + /// /// Looks up a localized string similar to You used too many moves in a row, so you can't move!. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 69503270..1a349d0f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -145,17 +145,11 @@ You are not able to use **{0}**. Type {1}ml to see a list of moves you can use. - - It's not effective. - - - It's somewhat effective. - - - It's super effective! - - Moves for {0} type + Movelist for "{0}" type + + + It's not effective. You don't have enough {0} @@ -169,6 +163,12 @@ Your type has been changed to {0} for a {1} + + It's somewhat effective. + + + It's super effective! + You used too many moves in a row, so you can't move! From fe4f9aad1e9e683a70a2857e1ad3d4e750cc0f02 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 13:56:06 +0100 Subject: [PATCH 210/746] woops, forgot migrations, added timezone and locale to guildconfig --- ...5444_guild-timezone-and-locale.Designer.cs | 1093 +++++++++++++++++ ...0170213125444_guild-timezone-and-locale.cs | 34 + .../NadekoSqliteContextModelSnapshot.cs | 4 + .../Services/Database/Models/GuildConfig.cs | 3 +- 4 files changed, 1133 insertions(+), 1 deletion(-) create mode 100644 src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.cs diff --git a/src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.Designer.cs b/src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.Designer.cs new file mode 100644 index 00000000..670a7e40 --- /dev/null +++ b/src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.Designer.cs @@ -0,0 +1,1093 @@ +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("20170213125444_guild-timezone-and-locale")] + partial class guildtimezoneandlocale + { + 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("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + 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/20170213125444_guild-timezone-and-locale.cs b/src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.cs new file mode 100644 index 00000000..c49b1fff --- /dev/null +++ b/src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class guildtimezoneandlocale : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Locale", + table: "GuildConfigs", + nullable: true, + defaultValue: null); + + migrationBuilder.AddColumn( + name: "TimeZoneId", + table: "GuildConfigs", + defaultValue: null); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Locale", + table: "GuildConfigs"); + + migrationBuilder.DropColumn( + name: "TimeZoneId", + table: "GuildConfigs"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index dd9bb84d..36fc1624 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -469,6 +469,8 @@ namespace NadekoBot.Migrations b.Property("GuildId"); + b.Property("Locale"); + b.Property("LogSettingId"); b.Property("MuteRoleName"); @@ -483,6 +485,8 @@ namespace NadekoBot.Migrations b.Property("SendDmGreetMessage"); + b.Property("TimeZoneId"); + b.Property("VerbosePermissions"); b.Property("VoicePlusTextEnabled"); diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs index 9b0209e9..9bf945cd 100644 --- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs +++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs @@ -64,7 +64,8 @@ namespace NadekoBot.Services.Database.Models public AntiRaidSetting AntiRaidSetting { get; set; } public AntiSpamSetting AntiSpamSetting { get; set; } - public string Locale { get; set; } + public string Locale { get; set; } = null; + public string TimeZoneId { get; set; } = null; //public List ProtectionIgnoredChannels { get; set; } = new List(); } From dadb7f0166f45d899ee6840b0ee83270c21e2487 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 13:58:08 +0100 Subject: [PATCH 211/746] fixed migration --- .../Migrations/20170213125444_guild-timezone-and-locale.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.cs b/src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.cs index c49b1fff..6aab0a04 100644 --- a/src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.cs +++ b/src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.cs @@ -17,6 +17,7 @@ namespace NadekoBot.Migrations migrationBuilder.AddColumn( name: "TimeZoneId", table: "GuildConfigs", + nullable: true, defaultValue: null); } From 1da9c0ae5a662943eeccf7830c0da947862a3189 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 14:23:29 +0100 Subject: [PATCH 212/746] fixes --- .../Administration/Commands/LocalizationCommands.cs | 2 +- src/NadekoBot/Modules/NadekoModule.cs | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index a7e39fc6..7f555b89 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -9,7 +9,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace NadekoBot.Modules.Administration.Commands +namespace NadekoBot.Modules.Administration { public partial class Administration { diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index 9c574cde..d0aa8433 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -12,8 +12,8 @@ namespace NadekoBot.Modules public abstract class NadekoModule : ModuleBase { protected readonly Logger _log; + protected CultureInfo _cultureInfo { get; private set; } public readonly string _prefix; - public readonly CultureInfo cultureInfo; public readonly string ModuleTypeName; public readonly string LowerModuleTypeName; @@ -26,8 +26,11 @@ namespace NadekoBot.Modules if (!NadekoBot.ModulePrefixes.TryGetValue(ModuleTypeName, out _prefix)) _prefix = "?err?"; _log = LogManager.GetCurrentClassLogger(); + } - cultureInfo = (Context.Guild == null + protected override void BeforeExecute() + { + _cultureInfo = (Context.Guild == null ? CultureInfo.CurrentCulture : NadekoBot.Localization.GetCultureInfo(Context.Guild)); } @@ -54,7 +57,7 @@ namespace NadekoBot.Modules protected string GetText(string key) { - return NadekoBot.ResponsesResourceManager.GetString(LowerModuleTypeName + "_" + key, cultureInfo); + return NadekoBot.ResponsesResourceManager.GetString(LowerModuleTypeName + "_" + key, _cultureInfo); } protected string GetText(string key, params object[] replacements) From 995b05e1f7acaa8b3a8afa0ccf0cc09a4530a909 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 15:03:39 +0100 Subject: [PATCH 213/746] a lot of fixes and improvements to pokemon localization --- src/NadekoBot/Modules/NadekoModule.cs | 4 +-- src/NadekoBot/Modules/Pokemon/Pokemon.cs | 32 +++++++++---------- src/NadekoBot/Modules/Pokemon/PokemonType.cs | 3 ++ .../Resources/ResponseStrings.Designer.cs | 28 ++++++++-------- src/NadekoBot/Resources/ResponseStrings.resx | 14 ++++---- 5 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index d0aa8433..89e685f3 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -74,7 +74,7 @@ namespace NadekoBot.Modules public Task ReplyErrorLocalized(string textKey, params object[] replacements) { var text = GetText(textKey); - return Context.Channel.SendErrorAsync(Context.User.Mention + " " +string.Format(text, replacements)); + return Context.Channel.SendErrorAsync(Context.User.Mention + " " + string.Format(text, replacements)); } public Task ConfirmLocalized(string textKey, params object[] replacements) @@ -96,4 +96,4 @@ namespace NadekoBot.Modules { } } -} +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Pokemon/Pokemon.cs b/src/NadekoBot/Modules/Pokemon/Pokemon.cs index dab998ff..a95a6d5f 100644 --- a/src/NadekoBot/Modules/Pokemon/Pokemon.cs +++ b/src/NadekoBot/Modules/Pokemon/Pokemon.cs @@ -77,9 +77,7 @@ namespace NadekoBot.Modules.Pokemon return PokemonTypes[remainder]; } - - - + private PokemonType StringToPokemonType(string v) { var str = v?.ToUpperInvariant(); @@ -93,8 +91,7 @@ namespace NadekoBot.Modules.Pokemon } return null; } - - + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task Attack(string move, IGuildUser targetUser = null) @@ -156,7 +153,7 @@ namespace NadekoBot.Modules.Pokemon var enabledMoves = userType.Moves; if (!enabledMoves.Contains(move.ToLowerInvariant())) { - await ReplyErrorLocalized("invalid_move", move, _prefix).ConfigureAwait(false); + await ReplyErrorLocalized("invalid_move", Format.Bold(move), _prefix).ConfigureAwait(false); return; } @@ -167,7 +164,7 @@ namespace NadekoBot.Modules.Pokemon //apply damage to target targetStats.Hp -= damage; - var response = GetText("attack", move, userType.Icon, targetUser.Mention, targetType.Icon, damage); + var response = GetText("attack", Format.Bold(move), userType.Icon, Format.Bold(targetUser.ToString()), targetType.Icon, Format.Bold(damage.ToString())); //Damage type if (damage < 40) @@ -187,11 +184,11 @@ namespace NadekoBot.Modules.Pokemon if (targetStats.Hp <= 0) { - response += $"\n" + GetText("fainted", targetUser); + response += $"\n" + GetText("fainted", Format.Bold(targetUser.ToString())); } else { - response += $"\n" + GetText("hp_remaining", targetUser, targetStats.Hp); + response += $"\n" + GetText("hp_remaining", Format.Bold(targetUser.ToString()), targetStats.Hp); } //update other stats @@ -232,7 +229,8 @@ namespace NadekoBot.Modules.Pokemon { IGuildUser user = (IGuildUser)Context.User; - if (targetUser == null) { + if (targetUser == null) + { await ReplyErrorLocalized("user_not_found").ConfigureAwait(false); return; } @@ -242,7 +240,7 @@ namespace NadekoBot.Modules.Pokemon var targetStats = Stats[targetUser.Id]; if (targetStats.Hp == targetStats.MaxHp) { - await ReplyErrorLocalized("already_full", targetUser).ConfigureAwait(false); + await ReplyErrorLocalized("already_full", Format.Bold(targetUser.ToString())).ConfigureAwait(false); return; } //Payment~ @@ -270,14 +268,14 @@ namespace NadekoBot.Modules.Pokemon return; } - await ReplyConfirmLocalized("revive_other", targetUser, NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); + await ReplyConfirmLocalized("revive_other", Format.Bold(targetUser.ToString()), NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); } - await ReplyConfirmLocalized("healed", targetUser, NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); + await ReplyConfirmLocalized("healed", Format.Bold(targetUser.ToString()), NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); return; } else { - await ErrorLocalized("already_full", targetUser); + await ErrorLocalized("already_full", Format.Bold(targetUser.ToString())); } } @@ -288,7 +286,7 @@ namespace NadekoBot.Modules.Pokemon { targetUser = targetUser ?? (IGuildUser)Context.User; var pType = GetPokeType(targetUser.Id); - await ReplyConfirmLocalized("type_of_user", targetUser.Mention, pType.Name.ToLowerInvariant() + pType.Icon).ConfigureAwait(false); + await ReplyConfirmLocalized("type_of_user", Format.Bold(targetUser.ToString()), pType).ConfigureAwait(false); } @@ -310,7 +308,7 @@ namespace NadekoBot.Modules.Pokemon } if (targetType == GetPokeType(user.Id)) { - await ReplyErrorLocalized("already_that_type", targetType.Name.ToLowerInvariant() + targetType.Icon).ConfigureAwait(false); + await ReplyErrorLocalized("already_that_type", targetType).ConfigureAwait(false); return; } @@ -354,7 +352,7 @@ namespace NadekoBot.Modules.Pokemon //Now for the response await ReplyConfirmLocalized("settype_success", - typeTargeted + targetType.Icon, + targetType, NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); } } diff --git a/src/NadekoBot/Modules/Pokemon/PokemonType.cs b/src/NadekoBot/Modules/Pokemon/PokemonType.cs index b73dec6b..20d47df0 100644 --- a/src/NadekoBot/Modules/Pokemon/PokemonType.cs +++ b/src/NadekoBot/Modules/Pokemon/PokemonType.cs @@ -15,6 +15,9 @@ namespace NadekoBot.Modules.Pokemon public List Multipliers { get; set; } public string Icon { get; set; } public string[] Moves { get; set; } + + public override string ToString() => + Icon + "**" + Name.ToLowerInvariant() + "**" + Icon; } public class PokemonMultiplier { diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 1e0c5ff4..337d3b62 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -69,7 +69,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to {1} already has full HP.. + /// Looks up a localized string similar to {0} already has full HP.. /// public static string pokemon_already_full { get { @@ -87,7 +87,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to used **{0}**{1} on {2}{3} for **{4}** damage.. + /// Looks up a localized string similar to used {0}{1} on {2}{3} for {4} damage.. /// public static string pokemon_attack { get { @@ -122,6 +122,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to healed {0} with one {1}. + /// + public static string pokemon_healed { + get { + return ResourceManager.GetString("pokemon_healed", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} has {1} HP remaining.. /// @@ -132,7 +141,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to You are not able to use **{0}**. Type {1}ml to see a list of moves you can use.. + /// Looks up a localized string similar to You can't use {0}. Type `{1}ml` to see a list of moves you can use.. /// public static string pokemon_invalid_move { get { @@ -141,7 +150,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Movelist for "{0}" type. + /// Looks up a localized string similar to Movelist for {0} type. /// public static string pokemon_moves { get { @@ -222,7 +231,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Type of {0} is **{1}**. + /// Looks up a localized string similar to Type of {0} is {1}. /// public static string pokemon_type_of_user { get { @@ -247,14 +256,5 @@ namespace NadekoBot.Resources { return ResourceManager.GetString("pokemon_you_fainted", resourceCulture); } } - - /// - /// Looks up a localized string similar to healed {0} with one {1}. - /// - public static string pokmeon_healed { - get { - return ResourceManager.GetString("pokmeon_healed", resourceCulture); - } - } } } diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 1a349d0f..00fc702f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -121,13 +121,13 @@ {0} has already fainted. - {1} already has full HP. + {0} already has full HP. Your type is already {0} - used **{0}**{1} on {2}{3} for **{4}** damage. + used {0}{1} on {2}{3} for {4} damage. Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. @@ -139,6 +139,9 @@ {0} has fainted! + + healed {0} with one {1} + {0} has {1} HP remaining. @@ -146,7 +149,7 @@ You are not able to use **{0}**. Type {1}ml to see a list of moves you can use. - Movelist for "{0}" type + Movelist for {0} type It's not effective. @@ -173,7 +176,7 @@ You used too many moves in a row, so you can't move! - Type of {0} is **{1}** + Type of {0} is {1} User not found. @@ -181,7 +184,4 @@ You fainted, so you are not able to move! - - healed {0} with one {1} - \ No newline at end of file From 8d496563dcda2b65fe78eba6f07587f3891f8133 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 15:04:27 +0100 Subject: [PATCH 214/746] woops, unsaved change --- src/NadekoBot/Resources/ResponseStrings.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 00fc702f..63ef2430 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -146,7 +146,7 @@ {0} has {1} HP remaining. - You are not able to use **{0}**. Type {1}ml to see a list of moves you can use. + You can't use {0}. Type `{1}ml` to see a list of moves you can use. Movelist for {0} type From 34e0399c7e0d28bb59b5d1ce413790b04c13cae4 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 15:29:02 +0100 Subject: [PATCH 215/746] sneaky little bugs :3 --- .../Commands/LocalizationCommands.cs | 22 +- src/NadekoBot/Modules/Help/Help.cs | 2 +- src/NadekoBot/Modules/NadekoModule.cs | 4 +- .../Resources/CommandStrings.Designer.cs | 2 +- src/NadekoBot/Resources/CommandStrings.resx | 2 +- .../ResponseStrings-sr-SP.Designer.cs | 260 ++++++++++++++++++ .../Resources/ResponseStrings-sr-SP.resx | 187 +++++++++++++ src/NadekoBot/Services/Impl/Localization.cs | 2 +- 8 files changed, 469 insertions(+), 12 deletions(-) create mode 100644 src/NadekoBot/Resources/ResponseStrings-sr-SP.Designer.cs create mode 100644 src/NadekoBot/Resources/ResponseStrings-sr-SP.resx diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 7f555b89..2db38bc7 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -24,14 +24,18 @@ namespace NadekoBot.Modules.Administration CultureInfo ci = null; try { - if(name.Trim().ToLowerInvariant() == "default") + if (name.Trim().ToLowerInvariant() == "default") { NadekoBot.Localization.RemoveGuildCulture(Context.Guild); + ci = NadekoBot.Localization.DefaultCultureInfo; + } + else + { + ci = new CultureInfo(name); + NadekoBot.Localization.SetGuildCulture(Context.Guild, ci); } - ci = new CultureInfo(name); - NadekoBot.Localization.SetGuildCulture(Context.Guild, ci); - await Context.Channel.SendConfirmAsync($"Your guild's locale is now {ci}.").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"Your guild's locale is now {Format.Bold(ci.ToString())} - {Format.Bold(ci.NativeName)}.").ConfigureAwait(false); } catch(Exception) { @@ -50,11 +54,15 @@ namespace NadekoBot.Modules.Administration if (name.Trim().ToLowerInvariant() == "default") { NadekoBot.Localization.ResetDefaultCulture(); + ci = NadekoBot.Localization.DefaultCultureInfo; + } + else + { + ci = new CultureInfo(name); + NadekoBot.Localization.SetDefaultCulture(ci); } - ci = new CultureInfo(name); - NadekoBot.Localization.SetDefaultCulture(ci); - await Context.Channel.SendConfirmAsync($"Your guild's locale is now {ci}.").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"Bot's default locale is now {Format.Bold(ci.ToString())} - {Format.Bold(ci.NativeName)}.").ConfigureAwait(false); } catch (Exception) { diff --git a/src/NadekoBot/Modules/Help/Help.cs b/src/NadekoBot/Modules/Help/Help.cs index a15501b0..c447db40 100644 --- a/src/NadekoBot/Modules/Help/Help.cs +++ b/src/NadekoBot/Modules/Help/Help.cs @@ -82,7 +82,7 @@ namespace NadekoBot.Modules.Help var alias = com.Aliases.Skip(1).FirstOrDefault(); if (alias != null) str += $" **/ `{alias}`**"; - var embed = new EmbedBuilder() + var embed = new EmbedBuilder() .AddField(fb => fb.WithName(str).WithValue($"{ string.Format(com.Summary, com.Module.Aliases.First())} { GetCommandRequirements(com)}").WithIsInline(true)) .AddField(fb => fb.WithName("**Usage**").WithValue($"{string.Format(com.Remarks, com.Module.Aliases.First())}").WithIsInline(false)) .WithColor(NadekoBot.OkColor); diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index 89e685f3..24a21954 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -31,8 +31,10 @@ namespace NadekoBot.Modules protected override void BeforeExecute() { _cultureInfo = (Context.Guild == null - ? CultureInfo.CurrentCulture + ? NadekoBot.Localization.DefaultCultureInfo : NadekoBot.Localization.GetCultureInfo(Context.Guild)); + + _log.Warn("Culture info is {0}", _cultureInfo); } //public Task ReplyConfirmLocalized(string titleKey, string textKey, string url = null, string footer = null) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 3659c523..3c6d7404 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -6828,7 +6828,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{}sl de-DE ` or `{0}sl default`. + /// Looks up a localized string similar to `{0}sl de-DE ` or `{0}sl default`. /// public static string setlocale_usage { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 0c1566d0..577a1b72 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3121,6 +3121,6 @@ Sets this server's response locale (language). If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. - `{}sl de-DE ` or `{0}sl default` + `{0}sl de-DE ` or `{0}sl default` \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings-sr-SP.Designer.cs b/src/NadekoBot/Resources/ResponseStrings-sr-SP.Designer.cs new file mode 100644 index 00000000..4d43d571 --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings-sr-SP.Designer.cs @@ -0,0 +1,260 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace NadekoBot.Resources { + using System; + using System.Reflection; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class ResponseStrings_sr_SP { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + internal ResponseStrings_sr_SP() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NadekoBot.Resources.ResponseStrings-sr-SP", typeof(ResponseStrings_sr_SP).GetTypeInfo().Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to {0} has already fainted.. + /// + public static string pokemon_already_fainted { + get { + return ResourceManager.GetString("pokemon_already_fainted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} already has full HP.. + /// + public static string pokemon_already_full { + get { + return ResourceManager.GetString("pokemon_already_full", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Your type is already {0}. + /// + public static string pokemon_already_that_type { + get { + return ResourceManager.GetString("pokemon_already_that_type", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to used {0}{1} on {2}{3} for {4} damage.. + /// + public static string pokemon_attack { + get { + return ResourceManager.GetString("pokemon_attack", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You can't attack again without retaliation!. + /// + public static string pokemon_cant_attack_again { + get { + return ResourceManager.GetString("pokemon_cant_attack_again", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You can't attack yourself.. + /// + public static string pokemon_cant_attack_yourself { + get { + return ResourceManager.GetString("pokemon_cant_attack_yourself", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has fainted!. + /// + public static string pokemon_fainted { + get { + return ResourceManager.GetString("pokemon_fainted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to healed {0} with one {1}. + /// + public static string pokemon_healed { + get { + return ResourceManager.GetString("pokemon_healed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has {1} HP remaining.. + /// + public static string pokemon_hp_remaining { + get { + return ResourceManager.GetString("pokemon_hp_remaining", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You can't use {0}. Type `{1}ml` to see a list of moves you can use.. + /// + public static string pokemon_invalid_move { + get { + return ResourceManager.GetString("pokemon_invalid_move", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Movelist for {0} type. + /// + public static string pokemon_moves { + get { + return ResourceManager.GetString("pokemon_moves", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You don't have enough {0}. + /// + public static string pokemon_no_currency { + get { + return ResourceManager.GetString("pokemon_no_currency", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It's not effective.. + /// + public static string pokemon_not_effective { + get { + return ResourceManager.GetString("pokemon_not_effective", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to revived {0} with one {1}. + /// + public static string pokemon_revive_other { + get { + return ResourceManager.GetString("pokemon_revive_other", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You revived yourself with one {0}. + /// + public static string pokemon_revive_yourself { + get { + return ResourceManager.GetString("pokemon_revive_yourself", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Your type has been changed to {0} for a {1}. + /// + public static string pokemon_settype_success { + get { + return ResourceManager.GetString("pokemon_settype_success", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It's somewhat effective.. + /// + public static string pokemon_somewhat_effective { + get { + return ResourceManager.GetString("pokemon_somewhat_effective", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It's super effective!. + /// + public static string pokemon_super_effective { + get { + return ResourceManager.GetString("pokemon_super_effective", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You used too many moves in a row, so you can't move!. + /// + public static string pokemon_too_many_moves { + get { + return ResourceManager.GetString("pokemon_too_many_moves", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type of {0} is {1}. + /// + public static string pokemon_type_of_user { + get { + return ResourceManager.GetString("pokemon_type_of_user", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User not found.. + /// + public static string pokemon_user_not_found { + get { + return ResourceManager.GetString("pokemon_user_not_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You fainted, so you are not able to move!. + /// + public static string pokemon_you_fainted { + get { + return ResourceManager.GetString("pokemon_you_fainted", resourceCulture); + } + } + } +} diff --git a/src/NadekoBot/Resources/ResponseStrings-sr-SP.resx b/src/NadekoBot/Resources/ResponseStrings-sr-SP.resx new file mode 100644 index 00000000..63ef2430 --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings-sr-SP.resx @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + {0} has already fainted. + + + {0} already has full HP. + + + Your type is already {0} + + + used {0}{1} on {2}{3} for {4} damage. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + You can't attack again without retaliation! + + + You can't attack yourself. + + + {0} has fainted! + + + healed {0} with one {1} + + + {0} has {1} HP remaining. + + + You can't use {0}. Type `{1}ml` to see a list of moves you can use. + + + Movelist for {0} type + + + It's not effective. + + + You don't have enough {0} + + + revived {0} with one {1} + + + You revived yourself with one {0} + + + Your type has been changed to {0} for a {1} + + + It's somewhat effective. + + + It's super effective! + + + You used too many moves in a row, so you can't move! + + + Type of {0} is {1} + + + User not found. + + + You fainted, so you are not able to move! + + \ No newline at end of file diff --git a/src/NadekoBot/Services/Impl/Localization.cs b/src/NadekoBot/Services/Impl/Localization.cs index dc64dd3e..73891d4a 100644 --- a/src/NadekoBot/Services/Impl/Localization.cs +++ b/src/NadekoBot/Services/Impl/Localization.cs @@ -69,7 +69,7 @@ namespace NadekoBot.Services } } - internal void SetDefaultCulture(CultureInfo ci) + public void SetDefaultCulture(CultureInfo ci) { DefaultCultureInfo = ci; } From 63dc5f0c46b90d9930aac5c163cb8cb1417f1d87 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 16:42:41 +0100 Subject: [PATCH 216/746] Pokemon completely translated to serbian cyrillic, it's so funny xD :rofl: --- .../Commands/LocalizationCommands.cs | 21 +++++++-- .../Resources/CommandStrings.Designer.cs | 28 ++++++------ src/NadekoBot/Resources/CommandStrings.resx | 16 +++---- ...=> ResponseStrings.sr-cyrl-rs.Designer.cs} | 0 ...P.resx => ResponseStrings.sr-cyrl-rs.resx} | 44 +++++++++---------- 5 files changed, 62 insertions(+), 47 deletions(-) rename src/NadekoBot/Resources/{ResponseStrings-sr-SP.Designer.cs => ResponseStrings.sr-cyrl-rs.Designer.cs} (100%) rename src/NadekoBot/Resources/{ResponseStrings-sr-SP.resx => ResponseStrings.sr-cyrl-rs.resx} (82%) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 2db38bc7..7247c29d 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -4,6 +4,7 @@ using NadekoBot.Attributes; using NadekoBot.Extensions; using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Globalization; using System.Linq; using System.Text; @@ -16,10 +17,16 @@ namespace NadekoBot.Modules.Administration [Group] public class LocalizationCommands : ModuleBase { + private ImmutableDictionary SupportedLocales { get; } = new Dictionary() + { + {"en-US", "English, United States" }, + {"sr-cyrl-rs", "Serbian, Cyrillic" } + }.ToImmutableDictionary(); + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.Administrator)] - public async Task SetLocale([Remainder] string name = null) + public async Task SetLanguage([Remainder] string name = null) { CultureInfo ci = null; try @@ -35,7 +42,7 @@ namespace NadekoBot.Modules.Administration NadekoBot.Localization.SetGuildCulture(Context.Guild, ci); } - await Context.Channel.SendConfirmAsync($"Your guild's locale is now {Format.Bold(ci.ToString())} - {Format.Bold(ci.NativeName)}.").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"Your server's locale is now {Format.Bold(ci.ToString())} - {Format.Bold(ci.NativeName)}.").ConfigureAwait(false); } catch(Exception) { @@ -46,7 +53,7 @@ namespace NadekoBot.Modules.Administration [NadekoCommand, Usage, Description, Aliases] [OwnerOnly] - public async Task SetDefaultLocale(string name) + public async Task SetDefaultLanguage(string name) { CultureInfo ci = null; try @@ -70,6 +77,14 @@ namespace NadekoBot.Modules.Administration await Context.Channel.SendConfirmAsync($"Failed setting locale. Revisit this command's help.").ConfigureAwait(false); } } + + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task ListLanguages(string name) + { + await Context.Channel.SendConfirmAsync("List Of Languages", + string.Join("\n", SupportedLocales.Select(x => $"{Format.Code(x.Key)} => {x.Value}"))); + } } } } diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 3c6d7404..11519c80 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -6758,27 +6758,27 @@ namespace NadekoBot.Resources { /// /// Looks up a localized string similar to setdefaultlocale sdl. /// - public static string setdefaultlocale_cmd { + public static string setdefaultlanguage_cmd { get { - return ResourceManager.GetString("setdefaultlocale_cmd", resourceCulture); + return ResourceManager.GetString("setdefaultlanguage_cmd", resourceCulture); } } /// - /// Looks up a localized string similar to Sets the bot's default locale. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture.. + /// Looks up a localized string similar to Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture.. /// - public static string setdefaultlocale_desc { + public static string setdefaultlanguage_desc { get { - return ResourceManager.GetString("setdefaultlocale_desc", resourceCulture); + return ResourceManager.GetString("setdefaultlanguage_desc", resourceCulture); } } /// /// Looks up a localized string similar to `{0}sdl en-US` or `{0}sdl default`. /// - public static string setdefaultlocale_usage { + public static string setdefaultlanguage_usage { get { - return ResourceManager.GetString("setdefaultlocale_usage", resourceCulture); + return ResourceManager.GetString("setdefaultlanguage_usage", resourceCulture); } } @@ -6812,27 +6812,27 @@ namespace NadekoBot.Resources { /// /// Looks up a localized string similar to setlocale sl. /// - public static string setlocale_cmd { + public static string setlanguage_cmd { get { - return ResourceManager.GetString("setlocale_cmd", resourceCulture); + return ResourceManager.GetString("setlanguage_cmd", resourceCulture); } } /// - /// Looks up a localized string similar to Sets this server's response locale (language). If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name.. + /// Looks up a localized string similar to Sets this server's response language) If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name.. /// - public static string setlocale_desc { + public static string setlanguage_desc { get { - return ResourceManager.GetString("setlocale_desc", resourceCulture); + return ResourceManager.GetString("setlanguage_desc", resourceCulture); } } /// /// Looks up a localized string similar to `{0}sl de-DE ` or `{0}sl default`. /// - public static string setlocale_usage { + public static string setlanguage_usage { get { - return ResourceManager.GetString("setlocale_usage", resourceCulture); + return ResourceManager.GetString("setlanguage_usage", resourceCulture); } } diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 577a1b72..23fb8072 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3105,22 +3105,22 @@ `{0}timezone` - + setdefaultlocale sdl - - Sets the bot's default locale. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. + + Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. - + `{0}sdl en-US` or `{0}sdl default` - + setlocale sl - - Sets this server's response locale (language). If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. + + Sets this server's response language) If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. - + `{0}sl de-DE ` or `{0}sl default` \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings-sr-SP.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.Designer.cs similarity index 100% rename from src/NadekoBot/Resources/ResponseStrings-sr-SP.Designer.cs rename to src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.Designer.cs diff --git a/src/NadekoBot/Resources/ResponseStrings-sr-SP.resx b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx similarity index 82% rename from src/NadekoBot/Resources/ResponseStrings-sr-SP.resx rename to src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx index 63ef2430..218a7645 100644 --- a/src/NadekoBot/Resources/ResponseStrings-sr-SP.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx @@ -118,70 +118,70 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - {0} has already fainted. + {0} је већ онесвешћен. - {0} already has full HP. + {0} је већ потпуно здрав. - Your type is already {0} + Твој тип већ јесте {0} - used {0}{1} on {2}{3} for {4} damage. + је искористио {0}{1} на {2}{3} и нанео {4} штете. Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. - You can't attack again without retaliation! + Не можеш напасти пре узвратног ударца. - You can't attack yourself. + Не можеш напасти себе. - {0} has fainted! + {0} се онесвестио. - healed {0} with one {1} + је излечио {0} са једним {1} - {0} has {1} HP remaining. + {0} има {1} преосталог здравља. - You can't use {0}. Type `{1}ml` to see a list of moves you can use. + Не можеш искористити {0}. Укуцај `{1}ml` да би видео листу удараца које можеш користити. - Movelist for {0} type + Листа покрета за {0} тип - It's not effective. + Није ефективно. - You don't have enough {0} + Немаш довољно {0} - revived {0} with one {1} + је оживео {0} са једним {1} - You revived yourself with one {0} + Оживео си себе са једним {0} - Your type has been changed to {0} for a {1} + Твој тип је промењен на {0} за један {1} - It's somewhat effective. + Има неког ефекта! - It's super effective! + Супер ефективно! - You used too many moves in a row, so you can't move! + Користио си превише напада узастопно, не можеш да се крећеш! - Type of {0} is {1} + {0}-ов тип је {1} - User not found. + Корисник није нађен. - You fainted, so you are not able to move! + Онесвешћен си, не можеш да се крећеш. \ No newline at end of file From 66f046a77c0f14238f485353244d3296c7e84bef Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 16:57:10 +0100 Subject: [PATCH 217/746] .langli, .langset, .langsetd added which: list all languages for which translation exists atm, set server's language, set default bot language (this is used if not server language is set, default) respectively --- .../Commands/LocalizationCommands.cs | 137 +++++++++++++++++- .../Resources/CommandStrings.Designer.cs | 135 ++++++++++------- src/NadekoBot/Resources/CommandStrings.resx | 31 ++-- 3 files changed, 235 insertions(+), 68 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 7247c29d..55b03213 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -26,7 +26,7 @@ namespace NadekoBot.Modules.Administration [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.Administrator)] - public async Task SetLanguage([Remainder] string name = null) + public async Task LanguageSet([Remainder] string name = null) { CultureInfo ci = null; try @@ -53,7 +53,7 @@ namespace NadekoBot.Modules.Administration [NadekoCommand, Usage, Description, Aliases] [OwnerOnly] - public async Task SetDefaultLanguage(string name) + public async Task LanguageSetDefault(string name) { CultureInfo ci = null; try @@ -80,7 +80,7 @@ namespace NadekoBot.Modules.Administration [NadekoCommand, Usage, Description, Aliases] [OwnerOnly] - public async Task ListLanguages(string name) + public async Task LanguagesList(string name) { await Context.Channel.SendConfirmAsync("List Of Languages", string.Join("\n", SupportedLocales.Select(x => $"{Format.Code(x.Key)} => {x.Value}"))); @@ -88,3 +88,134 @@ namespace NadekoBot.Modules.Administration } } } +/* list of language codes for reference. + * taken from https://github.com/dotnet/coreclr/blob/ee5862c6a257e60e263537d975ab6c513179d47f/src/mscorlib/src/System/Globalization/CultureData.cs#L192 + { "029", "en-029" }, + { "AE", "ar-AE" }, + { "AF", "prs-AF" }, + { "AL", "sq-AL" }, + { "AM", "hy-AM" }, + { "AR", "es-AR" }, + { "AT", "de-AT" }, + { "AU", "en-AU" }, + { "AZ", "az-Cyrl-AZ" }, + { "BA", "bs-Latn-BA" }, + { "BD", "bn-BD" }, + { "BE", "nl-BE" }, + { "BG", "bg-BG" }, + { "BH", "ar-BH" }, + { "BN", "ms-BN" }, + { "BO", "es-BO" }, + { "BR", "pt-BR" }, + { "BY", "be-BY" }, + { "BZ", "en-BZ" }, + { "CA", "en-CA" }, + { "CH", "it-CH" }, + { "CL", "es-CL" }, + { "CN", "zh-CN" }, + { "CO", "es-CO" }, + { "CR", "es-CR" }, + { "CS", "sr-Cyrl-CS" }, + { "CZ", "cs-CZ" }, + { "DE", "de-DE" }, + { "DK", "da-DK" }, + { "DO", "es-DO" }, + { "DZ", "ar-DZ" }, + { "EC", "es-EC" }, + { "EE", "et-EE" }, + { "EG", "ar-EG" }, + { "ES", "es-ES" }, + { "ET", "am-ET" }, + { "FI", "fi-FI" }, + { "FO", "fo-FO" }, + { "FR", "fr-FR" }, + { "GB", "en-GB" }, + { "GE", "ka-GE" }, + { "GL", "kl-GL" }, + { "GR", "el-GR" }, + { "GT", "es-GT" }, + { "HK", "zh-HK" }, + { "HN", "es-HN" }, + { "HR", "hr-HR" }, + { "HU", "hu-HU" }, + { "ID", "id-ID" }, + { "IE", "en-IE" }, + { "IL", "he-IL" }, + { "IN", "hi-IN" }, + { "IQ", "ar-IQ" }, + { "IR", "fa-IR" }, + { "IS", "is-IS" }, + { "IT", "it-IT" }, + { "IV", "" }, + { "JM", "en-JM" }, + { "JO", "ar-JO" }, + { "JP", "ja-JP" }, + { "KE", "sw-KE" }, + { "KG", "ky-KG" }, + { "KH", "km-KH" }, + { "KR", "ko-KR" }, + { "KW", "ar-KW" }, + { "KZ", "kk-KZ" }, + { "LA", "lo-LA" }, + { "LB", "ar-LB" }, + { "LI", "de-LI" }, + { "LK", "si-LK" }, + { "LT", "lt-LT" }, + { "LU", "lb-LU" }, + { "LV", "lv-LV" }, + { "LY", "ar-LY" }, + { "MA", "ar-MA" }, + { "MC", "fr-MC" }, + { "ME", "sr-Latn-ME" }, + { "MK", "mk-MK" }, + { "MN", "mn-MN" }, + { "MO", "zh-MO" }, + { "MT", "mt-MT" }, + { "MV", "dv-MV" }, + { "MX", "es-MX" }, + { "MY", "ms-MY" }, + { "NG", "ig-NG" }, + { "NI", "es-NI" }, + { "NL", "nl-NL" }, + { "NO", "nn-NO" }, + { "NP", "ne-NP" }, + { "NZ", "en-NZ" }, + { "OM", "ar-OM" }, + { "PA", "es-PA" }, + { "PE", "es-PE" }, + { "PH", "en-PH" }, + { "PK", "ur-PK" }, + { "PL", "pl-PL" }, + { "PR", "es-PR" }, + { "PT", "pt-PT" }, + { "PY", "es-PY" }, + { "QA", "ar-QA" }, + { "RO", "ro-RO" }, + { "RS", "sr-Latn-RS" }, + { "RU", "ru-RU" }, + { "RW", "rw-RW" }, + { "SA", "ar-SA" }, + { "SE", "sv-SE" }, + { "SG", "zh-SG" }, + { "SI", "sl-SI" }, + { "SK", "sk-SK" }, + { "SN", "wo-SN" }, + { "SV", "es-SV" }, + { "SY", "ar-SY" }, + { "TH", "th-TH" }, + { "TJ", "tg-Cyrl-TJ" }, + { "TM", "tk-TM" }, + { "TN", "ar-TN" }, + { "TR", "tr-TR" }, + { "TT", "en-TT" }, + { "TW", "zh-TW" }, + { "UA", "uk-UA" }, + { "US", "en-US" }, + { "UY", "es-UY" }, + { "UZ", "uz-Cyrl-UZ" }, + { "VE", "es-VE" }, + { "VN", "vi-VN" }, + { "YE", "ar-YE" }, + { "ZA", "af-ZA" }, + { "ZW", "en-ZW" } + */ diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 11519c80..5526e556 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -3677,6 +3677,87 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to languageset langset. + /// + public static string languageset_cmd { + get { + return ResourceManager.GetString("languageset_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name.. + /// + public static string languageset_desc { + get { + return ResourceManager.GetString("languageset_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}langset de-DE ` or `{0}langset default`. + /// + public static string languageset_usage { + get { + return ResourceManager.GetString("languageset_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to langsetdefault langsetd. + /// + public static string languagesetdefault_cmd { + get { + return ResourceManager.GetString("languagesetdefault_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture.. + /// + public static string languagesetdefault_desc { + get { + return ResourceManager.GetString("languagesetdefault_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}langsetd en-US` or `{0}langsetd default`. + /// + public static string languagesetdefault_usage { + get { + return ResourceManager.GetString("languagesetdefault_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to languageslist langli. + /// + public static string languageslist_cmd { + get { + return ResourceManager.GetString("languageslist_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List of languages for which translation (or part of it) exist atm.. + /// + public static string languageslist_desc { + get { + return ResourceManager.GetString("languageslist_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}langli`. + /// + public static string languageslist_usage { + get { + return ResourceManager.GetString("languageslist_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to lcsc. /// @@ -6755,33 +6836,6 @@ namespace NadekoBot.Resources { } } - /// - /// Looks up a localized string similar to setdefaultlocale sdl. - /// - public static string setdefaultlanguage_cmd { - get { - return ResourceManager.GetString("setdefaultlanguage_cmd", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture.. - /// - public static string setdefaultlanguage_desc { - get { - return ResourceManager.GetString("setdefaultlanguage_desc", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to `{0}sdl en-US` or `{0}sdl default`. - /// - public static string setdefaultlanguage_usage { - get { - return ResourceManager.GetString("setdefaultlanguage_usage", resourceCulture); - } - } - /// /// Looks up a localized string similar to setgame. /// @@ -6809,33 +6863,6 @@ namespace NadekoBot.Resources { } } - /// - /// Looks up a localized string similar to setlocale sl. - /// - public static string setlanguage_cmd { - get { - return ResourceManager.GetString("setlanguage_cmd", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sets this server's response language) If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name.. - /// - public static string setlanguage_desc { - get { - return ResourceManager.GetString("setlanguage_desc", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to `{0}sl de-DE ` or `{0}sl default`. - /// - public static string setlanguage_usage { - get { - return ResourceManager.GetString("setlanguage_usage", resourceCulture); - } - } - /// /// Looks up a localized string similar to setmaxplaytime smp. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 23fb8072..fab8d243 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3105,22 +3105,31 @@ `{0}timezone` - - setdefaultlocale sdl + + langsetdefault langsetd - + Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. - - `{0}sdl en-US` or `{0}sdl default` + + `{0}langsetd en-US` or `{0}langsetd default` - - setlocale sl + + languageset langset - - Sets this server's response language) If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. + + Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. - - `{0}sl de-DE ` or `{0}sl default` + + `{0}langset de-DE ` or `{0}langset default` + + + languageslist langli + + + List of languages for which translation (or part of it) exist atm. + + + `{0}langli` \ No newline at end of file From de4b1fdbf5a211505c9b62e36891d50df6691504 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 17:16:31 +0100 Subject: [PATCH 218/746] In case response key is missing, use the string from ResponseStrings.resx --- src/NadekoBot/Modules/NadekoModule.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index 24a21954..9311dac5 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -57,9 +57,20 @@ namespace NadekoBot.Modules // return Context.Channel.SendErrorAsync(title, text, url, footer); //} + /// + /// Used as failsafe in case response key doesn't exist in the selected or default language. + /// + private readonly CultureInfo usCultureInfo = new CultureInfo("en-US"); protected string GetText(string key) { - return NadekoBot.ResponsesResourceManager.GetString(LowerModuleTypeName + "_" + key, _cultureInfo); + var text = NadekoBot.ResponsesResourceManager.GetString(LowerModuleTypeName + "_" + key, _cultureInfo); + + if (string.IsNullOrWhiteSpace(text)) + { + _log.Warn(LowerModuleTypeName + "_" + key + " key is missing from " + _cultureInfo + " response strings. PLEASE REPORT THIS."); + return NadekoBot.ResponsesResourceManager.GetString(LowerModuleTypeName + "_" + key, usCultureInfo); + } + return text; } protected string GetText(string key, params object[] replacements) From 08c96385ea97f3f81285417df8711b39488a6cfc Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 17:45:29 +0100 Subject: [PATCH 219/746] redid migration in order to add botconfig.locale, added some improvements --- ...350_guild-timezone-and-locale.Designer.cs} | 4 ++- ...170213164350_guild-timezone-and-locale.cs} | 10 +++++++ .../NadekoSqliteContextModelSnapshot.cs | 2 ++ src/NadekoBot/NadekoBot.cs | 2 +- .../Services/Database/Models/BotConfig.cs | 1 + src/NadekoBot/Services/Impl/Localization.cs | 26 ++++++++++++++++--- 6 files changed, 39 insertions(+), 6 deletions(-) rename src/NadekoBot/Migrations/{20170213125444_guild-timezone-and-locale.Designer.cs => 20170213164350_guild-timezone-and-locale.Designer.cs} (99%) rename src/NadekoBot/Migrations/{20170213125444_guild-timezone-and-locale.cs => 20170213164350_guild-timezone-and-locale.cs} (77%) diff --git a/src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.Designer.cs b/src/NadekoBot/Migrations/20170213164350_guild-timezone-and-locale.Designer.cs similarity index 99% rename from src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.Designer.cs rename to src/NadekoBot/Migrations/20170213164350_guild-timezone-and-locale.Designer.cs index 670a7e40..1dc832d9 100644 --- a/src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.Designer.cs +++ b/src/NadekoBot/Migrations/20170213164350_guild-timezone-and-locale.Designer.cs @@ -10,7 +10,7 @@ using NadekoBot.Modules.Music.Classes; namespace NadekoBot.Migrations { [DbContext(typeof(NadekoContext))] - [Migration("20170213125444_guild-timezone-and-locale")] + [Migration("20170213164350_guild-timezone-and-locale")] partial class guildtimezoneandlocale { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -129,6 +129,8 @@ namespace NadekoBot.Migrations b.Property("HelpString"); + b.Property("Locale"); + b.Property("MigrationVersion"); b.Property("MinimumBetAmount"); diff --git a/src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.cs b/src/NadekoBot/Migrations/20170213164350_guild-timezone-and-locale.cs similarity index 77% rename from src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.cs rename to src/NadekoBot/Migrations/20170213164350_guild-timezone-and-locale.cs index 6aab0a04..757d9150 100644 --- a/src/NadekoBot/Migrations/20170213125444_guild-timezone-and-locale.cs +++ b/src/NadekoBot/Migrations/20170213164350_guild-timezone-and-locale.cs @@ -19,6 +19,12 @@ namespace NadekoBot.Migrations table: "GuildConfigs", nullable: true, defaultValue: null); + + migrationBuilder.AddColumn( + name: "Locale", + table: "BotConfig", + nullable: true, + defaultValue: null); } protected override void Down(MigrationBuilder migrationBuilder) @@ -30,6 +36,10 @@ namespace NadekoBot.Migrations migrationBuilder.DropColumn( name: "TimeZoneId", table: "GuildConfigs"); + + migrationBuilder.DropColumn( + name: "Locale", + table: "BotConfig"); } } } diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 36fc1624..5a03594c 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -128,6 +128,8 @@ namespace NadekoBot.Migrations b.Property("HelpString"); + b.Property("Locale"); + b.Property("MigrationVersion"); b.Property("MinimumBetAmount"); diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 65f1e02b..5df52a6e 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -84,7 +84,7 @@ namespace NadekoBot #endif //initialize Services - Localization = new Localization(NadekoBot.AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale)); + Localization = new Localization(NadekoBot.BotConfig.Locale, NadekoBot.AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale)); CommandService = new CommandService(new CommandServiceConfig() { CaseSensitiveCommands = false, DefaultRunMode = RunMode.Sync diff --git a/src/NadekoBot/Services/Database/Models/BotConfig.cs b/src/NadekoBot/Services/Database/Models/BotConfig.cs index 6b35e5f2..8ff90e8a 100644 --- a/src/NadekoBot/Services/Database/Models/BotConfig.cs +++ b/src/NadekoBot/Services/Database/Models/BotConfig.cs @@ -60,6 +60,7 @@ Nadeko Support Server: https://discord.gg/nadekobot"; public string OkColor { get; set; } = "71cd40"; public string ErrorColor { get; set; } = "ee281f"; + public string Locale { get; set; } = null; } public class PlayingStatus :DbEntity diff --git a/src/NadekoBot/Services/Impl/Localization.cs b/src/NadekoBot/Services/Impl/Localization.cs index 73891d4a..df703381 100644 --- a/src/NadekoBot/Services/Impl/Localization.cs +++ b/src/NadekoBot/Services/Impl/Localization.cs @@ -8,17 +8,35 @@ using System.Linq; using System.Threading.Tasks; using System; using NadekoBot.Services.Database; +using NLog; namespace NadekoBot.Services { public class Localization { + private readonly Logger _log; + public ConcurrentDictionary GuildCultureInfos { get; } public CultureInfo DefaultCultureInfo { get; private set; } = CultureInfo.CurrentCulture; private Localization() { } - public Localization(IDictionary cultureInfoNames) + public Localization(string defaultCulture, IDictionary cultureInfoNames) { + _log = LogManager.GetCurrentClassLogger(); + if (string.IsNullOrWhiteSpace(defaultCulture)) + DefaultCultureInfo = new CultureInfo("en-US"); + else + { + try + { + DefaultCultureInfo = new CultureInfo(defaultCulture); + } + catch + { + _log.Warn("Unable to load default bot's locale/language. Using en-US."); + DefaultCultureInfo = new CultureInfo("en-US"); + } + } GuildCultureInfos = new ConcurrentDictionary(cultureInfoNames.ToDictionary(x => x.Key, x => { CultureInfo cultureInfo = null; @@ -26,9 +44,7 @@ namespace NadekoBot.Services { cultureInfo = new CultureInfo(x.Value); } - catch - { - } + catch { } return cultureInfo; }).Where(x => x.Value != null)); } @@ -50,6 +66,8 @@ namespace NadekoBot.Services gc.Locale = ci.Name; uow.Complete(); } + + GuildCultureInfos.AddOrUpdate(guildId, ci, (id, old) => ci); } public void RemoveGuildCulture(IGuild guild) => From 8ed7a4c5d87c19b979b4c275217d1b93b46f85bb Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 17:56:06 +0100 Subject: [PATCH 220/746] .langset and .langsetd can now be used with no arguments to show the currently set language --- .../Commands/LocalizationCommands.cs | 15 ++++++++++++++- .../Resources/CommandStrings.Designer.cs | 4 ++-- src/NadekoBot/Resources/CommandStrings.resx | 4 ++-- src/NadekoBot/Services/Impl/Localization.cs | 12 ++++++++---- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 55b03213..daea20a0 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -28,6 +28,13 @@ namespace NadekoBot.Modules.Administration [RequireUserPermission(GuildPermission.Administrator)] public async Task LanguageSet([Remainder] string name = null) { + if (string.IsNullOrWhiteSpace(name)) + { + var cul = NadekoBot.Localization.GetCultureInfo(Context.Guild); + await Context.Channel.SendConfirmAsync("This server's language is set to " + cul + " - " + cul.NativeName).ConfigureAwait(false); + return; + } + CultureInfo ci = null; try { @@ -53,8 +60,14 @@ namespace NadekoBot.Modules.Administration [NadekoCommand, Usage, Description, Aliases] [OwnerOnly] - public async Task LanguageSetDefault(string name) + public async Task LanguageSetDefault([Remainder]string name = null) { + if (string.IsNullOrWhiteSpace(name)) + { + var cul = NadekoBot.Localization.GetCultureInfo(Context.Guild); + await Context.Channel.SendConfirmAsync("Bot's language is set to " + cul + " - " + cul.NativeName).ConfigureAwait(false); + return; + } CultureInfo ci = null; try { diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 5526e556..487e5ec8 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -3687,7 +3687,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name.. + /// Looks up a localized string similar to Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language.. /// public static string languageset_desc { get { @@ -3714,7 +3714,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture.. + /// Looks up a localized string similar to Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language.. /// public static string languagesetdefault_desc { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index fab8d243..4ba617cd 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3109,7 +3109,7 @@ langsetdefault langsetd - Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. + Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. `{0}langsetd en-US` or `{0}langsetd default` @@ -3118,7 +3118,7 @@ languageset langset - Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. + Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. `{0}langset de-DE ` or `{0}langset default` diff --git a/src/NadekoBot/Services/Impl/Localization.cs b/src/NadekoBot/Services/Impl/Localization.cs index df703381..e4906712 100644 --- a/src/NadekoBot/Services/Impl/Localization.cs +++ b/src/NadekoBot/Services/Impl/Localization.cs @@ -89,13 +89,17 @@ namespace NadekoBot.Services public void SetDefaultCulture(CultureInfo ci) { + using (var uow = DbHandler.UnitOfWork()) + { + var bc = uow.BotConfig.GetOrCreate(); + bc.Locale = ci.Name; + uow.Complete(); + } DefaultCultureInfo = ci; } - public void ResetDefaultCulture() - { - DefaultCultureInfo = CultureInfo.CurrentCulture; - } + public void ResetDefaultCulture() => + SetDefaultCulture(CultureInfo.CurrentCulture); public CultureInfo GetCultureInfo(IGuild guild) => GetCultureInfo(guild.Id); From b3a4fec1411395ba15f5de1fe8adc4942fa55b40 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 18:08:14 +0100 Subject: [PATCH 221/746] .langset and .langsetd no longer need perms to run without args (to check current language) --- .../Commands/LocalizationCommands.cs | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index daea20a0..684eebf9 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -25,16 +25,17 @@ namespace NadekoBot.Modules.Administration [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.Administrator)] - public async Task LanguageSet([Remainder] string name = null) + public async Task LanguageSet() { - if (string.IsNullOrWhiteSpace(name)) - { - var cul = NadekoBot.Localization.GetCultureInfo(Context.Guild); - await Context.Channel.SendConfirmAsync("This server's language is set to " + cul + " - " + cul.NativeName).ConfigureAwait(false); - return; - } + var cul = NadekoBot.Localization.GetCultureInfo(Context.Guild); + await Context.Channel.SendConfirmAsync("This server's language is set to " + Format.Bold(cul.ToString()) + " - " + Format.Bold(cul.NativeName)).ConfigureAwait(false); + } + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.Administrator)] + public async Task LanguageSet(string name) + { CultureInfo ci = null; try { @@ -59,15 +60,17 @@ namespace NadekoBot.Modules.Administration } [NadekoCommand, Usage, Description, Aliases] - [OwnerOnly] - public async Task LanguageSetDefault([Remainder]string name = null) + public async Task LanguageSetDefault() + { + var cul = NadekoBot.Localization.DefaultCultureInfo; + await Context.Channel.SendConfirmAsync("Bot's language is set to " + cul + " - " + cul.NativeName).ConfigureAwait(false); + return; + } + + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task LanguageSetDefault(string name) { - if (string.IsNullOrWhiteSpace(name)) - { - var cul = NadekoBot.Localization.GetCultureInfo(Context.Guild); - await Context.Channel.SendConfirmAsync("Bot's language is set to " + cul + " - " + cul.NativeName).ConfigureAwait(false); - return; - } CultureInfo ci = null; try { From 838e014f7335287055ce4c103fae6f98181fbea1 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 18:11:03 +0100 Subject: [PATCH 222/746] cleverbot fixed --- src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs b/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs index d5df8dfe..e183c249 100644 --- a/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs +++ b/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs @@ -30,9 +30,9 @@ namespace Services.CleverBotApi public static ChatterBot Create(ChatterBotType type, object arg) { #if GLOBAL_NADEKO - var url = "http://www.cleverbot.com/webservicemin?uc=3210&botapi=nadekobot"; + var url = "http://www.cleverbot.com/webservicemin?uc=777&botapi=nadekobot"; #else - var url = "http://www.cleverbot.com/webservicemin?uc=3210&botapi=chatterbotapi"; + var url = "http://www.cleverbot.com/webservicemin?uc=777&botapi=chatterbotapi"; #endif switch (type) From 53b6a77fc25f249c8d6c648824006567ee46991b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 18:26:58 +0100 Subject: [PATCH 223/746] pick no longer has cooldown on public bot --- .../Games/Commands/PlantAndPickCommands.cs | 32 ++++++------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 1cf43a30..234da7c2 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -129,32 +129,18 @@ namespace NadekoBot.Modules.Games if (!(await channel.Guild.GetCurrentUserAsync()).GetPermissions(channel).ManageMessages) return; -#if GLOBAL_NADEKO - if (!usersRecentlyPicked.Add(Context.User.Id)) + + List msgs; + + try { await Context.Message.DeleteAsync().ConfigureAwait(false); } catch { } + if (!plantedFlowers.TryRemove(channel.Id, out msgs)) return; -#endif - try - { - List msgs; + await Task.WhenAll(msgs.Where(m => m != null).Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false); - try { await Context.Message.DeleteAsync().ConfigureAwait(false); } catch { } - if (!plantedFlowers.TryRemove(channel.Id, out msgs)) - return; - - await Task.WhenAll(msgs.Where(m => m != null).Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false); - - await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, $"Picked {NadekoBot.BotConfig.CurrencyPluralName}", msgs.Count, false).ConfigureAwait(false); - var msg = await channel.SendConfirmAsync($"**{Context.User}** picked {msgs.Count}{NadekoBot.BotConfig.CurrencySign}!").ConfigureAwait(false); - msg.DeleteAfter(10); - } - finally - { -#if GLOBAL_NADEKO - await Task.Delay(60000); - usersRecentlyPicked.TryRemove(Context.User.Id); -#endif - } + await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, $"Picked {NadekoBot.BotConfig.CurrencyPluralName}", msgs.Count, false).ConfigureAwait(false); + var msg = await channel.SendConfirmAsync($"**{Context.User}** picked {msgs.Count}{NadekoBot.BotConfig.CurrencySign}!").ConfigureAwait(false); + msg.DeleteAfter(10); } [NadekoCommand, Usage, Description, Aliases] From 023df131217b609c0a3e70d7426eebb76ba3054f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 21:29:06 +0100 Subject: [PATCH 224/746] Clash of clans completely localizable, fixes, improvements :ok: :100: --- .../Modules/ClashOfClans/ClashOfClans.cs | 51 +++-- .../Modules/ClashOfClans/Extensions.cs | 33 ++- .../Games/Commands/PlantAndPickCommands.cs | 11 - src/NadekoBot/Modules/NadekoModule.cs | 33 +-- src/NadekoBot/Modules/Pokemon/Pokemon.cs | 2 +- .../Resources/ResponseStrings.Designer.cs | 207 ++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 69 ++++++ .../Resources/ResponseStrings.sr-cyrl-rs.resx | 69 ++++++ src/NadekoBot/Services/Impl/Localization.cs | 8 +- 9 files changed, 419 insertions(+), 64 deletions(-) diff --git a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs index 83e6d00b..1ed31a6e 100644 --- a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs +++ b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs @@ -73,7 +73,11 @@ namespace NadekoBot.Modules.ClashOfClans try { SaveWar(war); - await war.Channel.SendErrorAsync($"❗🔰**Claim from @{Bases[i].CallUser} for a war against {war.ShortPrint()} has expired.**").ConfigureAwait(false); + await war.Channel.SendErrorAsync(GetTextStatic("claim_expired", + NadekoBot.Localization.GetCultureInfo(war.Channel.GuildId), + typeof(ClashOfClans).Name.ToLowerInvariant(), + Format.Bold(Bases[i].CallUser), + war.ShortPrint())); } catch { } } @@ -92,7 +96,7 @@ namespace NadekoBot.Modules.ClashOfClans if (size < 10 || size > 50 || size % 5 != 0) { - await Context.Channel.SendErrorAsync("🔰 Not a Valid war size").ConfigureAwait(false); + await ReplyErrorLocalized("invalid_size").ConfigureAwait(false); return; } List wars; @@ -107,7 +111,7 @@ namespace NadekoBot.Modules.ClashOfClans var cw = await CreateWar(enemyClan, size, Context.Guild.Id, Context.Channel.Id); wars.Add(cw); - await Context.Channel.SendConfirmAsync($"❗🔰**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**").ConfigureAwait(false); + await ReplyErrorLocalized("war_created", cw.ShortPrint()).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -120,18 +124,18 @@ namespace NadekoBot.Modules.ClashOfClans var warsInfo = GetWarInfo(Context.Guild, num); if (warsInfo == null) { - await Context.Channel.SendErrorAsync("🔰 **That war does not exist.**").ConfigureAwait(false); + await ReplyErrorLocalized("war_not_exist").ConfigureAwait(false); return; } var war = warsInfo.Item1[warsInfo.Item2]; try { war.Start(); - await Context.Channel.SendConfirmAsync($"🔰**STARTED WAR AGAINST {war.ShortPrint()}**").ConfigureAwait(false); + await ReplyConfirmLocalized("war_started", war.ShortPrint()).ConfigureAwait(false); } catch { - await Context.Channel.SendErrorAsync($"🔰**WAR AGAINST {war.ShortPrint()} HAS ALREADY STARTED**").ConfigureAwait(false); + await ReplyErrorLocalized("war_already_started", war.ShortPrint()).ConfigureAwait(false); } SaveWar(war); } @@ -149,22 +153,20 @@ namespace NadekoBot.Modules.ClashOfClans ClashWars.TryGetValue(Context.Guild.Id, out wars); if (wars == null || wars.Count == 0) { - await Context.Channel.SendErrorAsync("🔰 **No active wars.**").ConfigureAwait(false); + await ReplyErrorLocalized("no_active_wars").ConfigureAwait(false); return; } var sb = new StringBuilder(); - sb.AppendLine("🔰 **LIST OF ACTIVE WARS**"); sb.AppendLine("**-------------------------**"); for (var i = 0; i < wars.Count; i++) { - sb.AppendLine($"**#{i + 1}.** `Enemy:` **{wars[i].EnemyClan}**"); - sb.AppendLine($"\t\t`Size:` **{wars[i].Size} v {wars[i].Size}**"); + sb.AppendLine($"**#{i + 1}.** `{GetText("enemy")}:` **{wars[i].EnemyClan}**"); + sb.AppendLine($"\t\t`{GetText("size")}:` **{wars[i].Size} v {wars[i].Size}**"); sb.AppendLine("**-------------------------**"); } - await Context.Channel.SendConfirmAsync(sb.ToString()).ConfigureAwait(false); + await Context.Channel.SendConfirmAsync(GetText("list_active_wars"), sb.ToString()).ConfigureAwait(false); return; - } var num = 0; int.TryParse(number, out num); @@ -172,10 +174,11 @@ namespace NadekoBot.Modules.ClashOfClans var warsInfo = GetWarInfo(Context.Guild, num); if (warsInfo == null) { - await Context.Channel.SendErrorAsync("🔰 **That war does not exist.**").ConfigureAwait(false); + await ReplyErrorLocalized("war_not_exist").ConfigureAwait(false); return; } - await Context.Channel.SendConfirmAsync(warsInfo.Item1[warsInfo.Item2].ToPrettyString()).ConfigureAwait(false); + var war = warsInfo.Item1[warsInfo.Item2]; + await Context.Channel.SendConfirmAsync(war.Localize("info_about_war", $"`{war.EnemyClan}` ({war.Size} v {war.Size})"), war.ToPrettyString()).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -185,7 +188,7 @@ namespace NadekoBot.Modules.ClashOfClans var warsInfo = GetWarInfo(Context.Guild, number); if (warsInfo == null || warsInfo.Item1.Count == 0) { - await Context.Channel.SendErrorAsync("🔰 **That war does not exist.**").ConfigureAwait(false); + await ReplyErrorLocalized("war_not_exist").ConfigureAwait(false); return; } var usr = @@ -197,11 +200,11 @@ namespace NadekoBot.Modules.ClashOfClans var war = warsInfo.Item1[warsInfo.Item2]; war.Call(usr, baseNumber - 1); SaveWar(war); - await Context.Channel.SendConfirmAsync($"🔰**{usr}** claimed a base #{baseNumber} for a war against {war.ShortPrint()}").ConfigureAwait(false); + await ConfirmLocalized("claimed_base", Format.Bold(usr.ToString()), baseNumber, war.ShortPrint()).ConfigureAwait(false); } catch (Exception ex) { - await Context.Channel.SendErrorAsync($"🔰 {ex.Message}").ConfigureAwait(false); + await Context.Channel.SendErrorAsync(ex.Message).ConfigureAwait(false); } } @@ -233,13 +236,13 @@ namespace NadekoBot.Modules.ClashOfClans var warsInfo = GetWarInfo(Context.Guild, number); if (warsInfo == null) { - await Context.Channel.SendErrorAsync("🔰 That war does not exist.").ConfigureAwait(false); + await ReplyErrorLocalized("war_not_exist").ConfigureAwait(false); return; } var war = warsInfo.Item1[warsInfo.Item2]; war.End(); SaveWar(war); - await Context.Channel.SendConfirmAsync($"❗🔰**War against {warsInfo.Item1[warsInfo.Item2].ShortPrint()} ended.**").ConfigureAwait(false); + await ReplyConfirmLocalized("war_ended", warsInfo.Item1[warsInfo.Item2].ShortPrint()).ConfigureAwait(false); var size = warsInfo.Item1[warsInfo.Item2].Size; warsInfo.Item1.RemoveAt(warsInfo.Item2); @@ -252,7 +255,7 @@ namespace NadekoBot.Modules.ClashOfClans var warsInfo = GetWarInfo(Context.Guild, number); if (warsInfo == null || warsInfo.Item1.Count == 0) { - await Context.Channel.SendErrorAsync("🔰 **That war does not exist.**").ConfigureAwait(false); + await ReplyErrorLocalized("war_not_exist").ConfigureAwait(false); return; } var usr = @@ -264,11 +267,11 @@ namespace NadekoBot.Modules.ClashOfClans var war = warsInfo.Item1[warsInfo.Item2]; var baseNumber = war.Uncall(usr); SaveWar(war); - await Context.Channel.SendConfirmAsync($"🔰 @{usr} has **UNCLAIMED** a base #{baseNumber + 1} from a war against {war.ShortPrint()}").ConfigureAwait(false); + await ReplyConfirmLocalized("base_unclaimed", usr, baseNumber + 1, war.ShortPrint()).ConfigureAwait(false); } catch (Exception ex) { - await Context.Channel.SendErrorAsync($"🔰 {ex.Message}").ConfigureAwait(false); + await Context.Channel.SendErrorAsync(ex.Message).ConfigureAwait(false); } } @@ -277,7 +280,7 @@ namespace NadekoBot.Modules.ClashOfClans var warInfo = GetWarInfo(Context.Guild, number); if (warInfo == null || warInfo.Item1.Count == 0) { - await Context.Channel.SendErrorAsync("🔰 **That war does not exist.**").ConfigureAwait(false); + await ReplyErrorLocalized("war_not_exist").ConfigureAwait(false); return; } var war = warInfo.Item1[warInfo.Item2]; @@ -292,7 +295,7 @@ namespace NadekoBot.Modules.ClashOfClans { war.FinishClaim(baseNumber, stars); } - await Context.Channel.SendConfirmAsync($"❗🔰{Context.User.Mention} **DESTROYED** a base #{baseNumber + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false); + await ReplyConfirmLocalized("base_destroyed", baseNumber +1, war.ShortPrint()).ConfigureAwait(false); } catch (Exception ex) { diff --git a/src/NadekoBot/Modules/ClashOfClans/Extensions.cs b/src/NadekoBot/Modules/ClashOfClans/Extensions.cs index de12bcab..032d3bcd 100644 --- a/src/NadekoBot/Modules/ClashOfClans/Extensions.cs +++ b/src/NadekoBot/Modules/ClashOfClans/Extensions.cs @@ -27,13 +27,13 @@ namespace NadekoBot.Modules.ClashOfClans public static void Call(this ClashWar cw, string u, int baseNumber) { if (baseNumber < 0 || baseNumber >= cw.Bases.Count) - throw new ArgumentException("Invalid base number"); + throw new ArgumentException(cw.Localize("invalid_base_number")); if (cw.Bases[baseNumber].CallUser != null && cw.Bases[baseNumber].Stars == 3) - throw new ArgumentException("That base is already destroyed."); + throw new ArgumentException(cw.Localize("base_already_claimed")); for (var i = 0; i < cw.Bases.Count; i++) { if (cw.Bases[i]?.BaseDestroyed == false && cw.Bases[i]?.CallUser == u) - throw new ArgumentException($"@{u} You already claimed base #{i + 1}. You can't claim a new one."); + throw new ArgumentException(cw.Localize("claimed_other", u, i + 1)); } var cc = cw.Bases[baseNumber]; @@ -45,7 +45,7 @@ namespace NadekoBot.Modules.ClashOfClans public static void Start(this ClashWar cw) { if (cw.WarState == StateOfWar.Started) - throw new InvalidOperationException("War already started"); + throw new InvalidOperationException("war_already_started"); //if (Started) // throw new InvalidOperationException(); //Started = true; @@ -66,7 +66,7 @@ namespace NadekoBot.Modules.ClashOfClans cw.Bases[i].CallUser = null; return i; } - throw new InvalidOperationException("You are not participating in that war."); + throw new InvalidOperationException(cw.Localize("not_partic")); } public static string ShortPrint(this ClashWar cw) => @@ -75,8 +75,7 @@ namespace NadekoBot.Modules.ClashOfClans public static string ToPrettyString(this ClashWar cw) { var sb = new StringBuilder(); - - sb.AppendLine($"🔰**WAR AGAINST `{cw.EnemyClan}` ({cw.Size} v {cw.Size}) INFO:**"); + if (cw.WarState == StateOfWar.Created) sb.AppendLine("`not started`"); var twoHours = new TimeSpan(2, 0, 0); @@ -84,7 +83,7 @@ namespace NadekoBot.Modules.ClashOfClans { if (cw.Bases[i].CallUser == null) { - sb.AppendLine($"`{i + 1}.` ❌*unclaimed*"); + sb.AppendLine($"`{i + 1}.` ❌*{cw.Localize("not_claimed")}*"); } else { @@ -120,7 +119,7 @@ namespace NadekoBot.Modules.ClashOfClans cw.Bases[i].Stars = stars; return i; } - throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base."); + throw new InvalidOperationException(cw.Localize("not_partic_or_destroyed", user)); } public static void FinishClaim(this ClashWar cw, int index, int stars = 3) @@ -128,10 +127,22 @@ namespace NadekoBot.Modules.ClashOfClans if (index < 0 || index > cw.Bases.Count) throw new ArgumentOutOfRangeException(nameof(index)); var toFinish = cw.Bases[index]; - if (toFinish.BaseDestroyed != false) throw new InvalidOperationException("That base is already destroyed."); - if (toFinish.CallUser == null) throw new InvalidOperationException("That base is unclaimed."); + if (toFinish.BaseDestroyed != false) throw new InvalidOperationException(cw.Localize("base_already_destroyed")); + if (toFinish.CallUser == null) throw new InvalidOperationException(cw.Localize("base_already_unclaimed")); toFinish.BaseDestroyed = true; toFinish.Stars = stars; } + + public static string Localize(this ClashWar cw, string key) + { + return NadekoModule.GetTextStatic(key, + NadekoBot.Localization.GetCultureInfo(cw.Channel?.GuildId), + typeof(ClashOfClans).Name.ToLowerInvariant()); + } + + public static string Localize(this ClashWar cw, string key, params object[] replacements) + { + return string.Format(cw.Localize(key), replacements); + } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 234da7c2..f664a7f2 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -222,17 +222,6 @@ namespace NadekoBot.Modules.Games return images[rng.Next(0, images.Length)]; } - - int GetRandomNumber() - { - using (var rg = RandomNumberGenerator.Create()) - { - byte[] rno = new byte[4]; - rg.GetBytes(rno); - int randomvalue = BitConverter.ToInt32(rno, 0); - return randomvalue; - } - } } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index 9311dac5..7ef213db 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -13,7 +13,7 @@ namespace NadekoBot.Modules { protected readonly Logger _log; protected CultureInfo _cultureInfo { get; private set; } - public readonly string _prefix; + public readonly string Prefix; public readonly string ModuleTypeName; public readonly string LowerModuleTypeName; @@ -23,16 +23,14 @@ namespace NadekoBot.Modules ModuleTypeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name; LowerModuleTypeName = ModuleTypeName.ToLowerInvariant(); - if (!NadekoBot.ModulePrefixes.TryGetValue(ModuleTypeName, out _prefix)) - _prefix = "?err?"; + if (!NadekoBot.ModulePrefixes.TryGetValue(ModuleTypeName, out Prefix)) + Prefix = "?err?"; _log = LogManager.GetCurrentClassLogger(); } protected override void BeforeExecute() { - _cultureInfo = (Context.Guild == null - ? NadekoBot.Localization.DefaultCultureInfo - : NadekoBot.Localization.GetCultureInfo(Context.Guild)); + _cultureInfo = NadekoBot.Localization.GetCultureInfo(Context.Guild?.Id); _log.Warn("Culture info is {0}", _cultureInfo); } @@ -60,24 +58,31 @@ namespace NadekoBot.Modules /// /// Used as failsafe in case response key doesn't exist in the selected or default language. /// - private readonly CultureInfo usCultureInfo = new CultureInfo("en-US"); - protected string GetText(string key) + private static readonly CultureInfo usCultureInfo = new CultureInfo("en-US"); + + public static string GetTextStatic(string key, CultureInfo _cultureInfo, string lowerModuleTypeName) { - var text = NadekoBot.ResponsesResourceManager.GetString(LowerModuleTypeName + "_" + key, _cultureInfo); + var text = NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, _cultureInfo); if (string.IsNullOrWhiteSpace(text)) { - _log.Warn(LowerModuleTypeName + "_" + key + " key is missing from " + _cultureInfo + " response strings. PLEASE REPORT THIS."); - return NadekoBot.ResponsesResourceManager.GetString(LowerModuleTypeName + "_" + key, usCultureInfo); + LogManager.GetCurrentClassLogger().Warn(lowerModuleTypeName + "_" + key + " key is missing from " + _cultureInfo + " response strings. PLEASE REPORT THIS."); + return NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} found!"; } - return text; + return text ?? $"Error: key {lowerModuleTypeName + "_" + key} not found."; } - protected string GetText(string key, params object[] replacements) + public static string GetTextStatic(string key, CultureInfo _cultureInfo, string lowerModuleTypeName, params object[] replacements) { - return string.Format(GetText(key), replacements); + return string.Format(GetTextStatic(key, _cultureInfo, lowerModuleTypeName), replacements); } + protected string GetText(string key) => + GetTextStatic(key, _cultureInfo, LowerModuleTypeName); + + protected string GetText(string key, params object[] replacements) => + GetText(key, _cultureInfo, LowerModuleTypeName, replacements); + public Task ErrorLocalized(string textKey, params object[] replacements) { var text = GetText(textKey); diff --git a/src/NadekoBot/Modules/Pokemon/Pokemon.cs b/src/NadekoBot/Modules/Pokemon/Pokemon.cs index a95a6d5f..e2679147 100644 --- a/src/NadekoBot/Modules/Pokemon/Pokemon.cs +++ b/src/NadekoBot/Modules/Pokemon/Pokemon.cs @@ -153,7 +153,7 @@ namespace NadekoBot.Modules.Pokemon var enabledMoves = userType.Moves; if (!enabledMoves.Contains(move.ToLowerInvariant())) { - await ReplyErrorLocalized("invalid_move", Format.Bold(move), _prefix).ConfigureAwait(false); + await ReplyErrorLocalized("invalid_move", Format.Bold(move), Prefix).ConfigureAwait(false); return; } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 337d3b62..3b58fbab 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -59,6 +59,213 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to That base is already claimed or destroyed.. + /// + public static string clashofclans_base_already_claimed { + get { + return ResourceManager.GetString("clashofclans_base_already_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to That base is already destroyed.. + /// + public static string clashofclans_base_already_destroyed { + get { + return ResourceManager.GetString("clashofclans_base_already_destroyed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to That base is not claimed.. + /// + public static string clashofclans_base_already_unclaimed { + get { + return ResourceManager.GetString("clashofclans_base_already_unclaimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to **DESTROYED** base #{0} in a war against {1}. + /// + public static string clashofclans_base_destroyed { + get { + return ResourceManager.GetString("clashofclans_base_destroyed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has **UNCLAIMED** base #{1} in a war against {2}. + /// + public static string clashofclans_base_unclaimed { + get { + return ResourceManager.GetString("clashofclans_base_unclaimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Claim from @{0} for a war against {1} has expired.. + /// + public static string clashofclans_claim_expired { + get { + return ResourceManager.GetString("clashofclans_claim_expired", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} claimed a base #{1} in a war against {2}. + /// + public static string clashofclans_claimed_base { + get { + return ResourceManager.GetString("clashofclans_claimed_base", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to @{0} You already claimed base #{1}. You can't claim a new one.. + /// + public static string clashofclans_claimed_other { + get { + return ResourceManager.GetString("clashofclans_claimed_other", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enemy. + /// + public static string clashofclans_enemy { + get { + return ResourceManager.GetString("clashofclans_enemy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Info about war against {0}. + /// + public static string clashofclans_info_about_war { + get { + return ResourceManager.GetString("clashofclans_info_about_war", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid base number.. + /// + public static string clashofclans_invalid_base_number { + get { + return ResourceManager.GetString("clashofclans_invalid_base_number", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not a Valid war size.. + /// + public static string clashofclans_invalid_size { + get { + return ResourceManager.GetString("clashofclans_invalid_size", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List Of Active Wars. + /// + public static string clashofclans_list_active_wars { + get { + return ResourceManager.GetString("clashofclans_list_active_wars", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No active wars.. + /// + public static string clashofclans_no_active_wars { + get { + return ResourceManager.GetString("clashofclans_no_active_wars", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to not claimed. + /// + public static string clashofclans_not_claimed { + get { + return ResourceManager.GetString("clashofclans_not_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You are not participating in that war.. + /// + public static string clashofclans_not_partic { + get { + return ResourceManager.GetString("clashofclans_not_partic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to @{0} You are either not participating in that war, or that base is already destroyed.. + /// + public static string clashofclans_not_partic_or_destroyed { + get { + return ResourceManager.GetString("clashofclans_not_partic_or_destroyed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Size. + /// + public static string clashofclans_size { + get { + return ResourceManager.GetString("clashofclans_size", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to War against {0} has already started.. + /// + public static string clashofclans_war_already_started { + get { + return ResourceManager.GetString("clashofclans_war_already_started", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to War against {0} created.. + /// + public static string clashofclans_war_created { + get { + return ResourceManager.GetString("clashofclans_war_created", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to War against {0} ended.. + /// + public static string clashofclans_war_ended { + get { + return ResourceManager.GetString("clashofclans_war_ended", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to That war does not exist.. + /// + public static string clashofclans_war_not_exist { + get { + return ResourceManager.GetString("clashofclans_war_not_exist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to War against {0} started!. + /// + public static string clashofclans_war_started { + get { + return ResourceManager.GetString("clashofclans_war_started", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} has already fainted.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 63ef2430..155460f7 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -117,6 +117,75 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + That base is already claimed or destroyed. + + + That base is already destroyed. + + + That base is not claimed. + + + **DESTROYED** base #{0} in a war against {1} + + + {0} has **UNCLAIMED** base #{1} in a war against {2} + + + {0} claimed a base #{1} in a war against {2} + + + @{0} You already claimed base #{1}. You can't claim a new one. + + + Claim from @{0} for a war against {1} has expired. + + + Enemy + + + Info about war against {0} + + + Invalid base number. + + + Not a Valid war size. + + + List Of Active Wars + + + not claimed + + + You are not participating in that war. + + + @{0} You are either not participating in that war, or you have already destroyed a base. + + + No active wars. + + + Size + + + War against {0} is already started. + + + War against {0} created. + + + War against {0} ended. + + + That war does not exist. + + + War against {0} started! + {0} has already fainted. diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx index 218a7645..43a96f10 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx @@ -184,4 +184,73 @@ Онесвешћен си, не можеш да се крећеш. + + Та база је већ под захетвом или је уништена. + + + Та база је већ под захтевом. + + + Та база није под захтевом. + + + {0} је **ПОНИШТИО ЗАХТЕВ** за базу #{1} у рату против {2} + + + {0} захтева базу #{1} у рату против {2} + + + @{0} Ти већ захтеваш базу #{1}. Не можеш захтевати још једну. + + + Захтев од @{0} за рат против {1} је истекао. + + + Противник + + + Подаци о рату против {0} + + + Број базе није валидан. + + + Величина рата није валидна. + + + Листа Ратова У Току + + + нема захтева + + + Ти не учествујеш у том рату. + + + @{0} Ти или не учествујеш у рату или је та база већ уништена. + + + Нема ратова у току. + + + Величина + + + Рат против {0} је већ почео. + + + Рат против {0} је направљен. + + + Рат против {0} је завршен. + + + Тај рат не постоји. + + + Рат против {0} је започет! + + + је **УНИШТИО** базу #{0} у рату против {1} + \ No newline at end of file diff --git a/src/NadekoBot/Services/Impl/Localization.cs b/src/NadekoBot/Services/Impl/Localization.cs index e4906712..e9d792ca 100644 --- a/src/NadekoBot/Services/Impl/Localization.cs +++ b/src/NadekoBot/Services/Impl/Localization.cs @@ -102,12 +102,14 @@ namespace NadekoBot.Services SetDefaultCulture(CultureInfo.CurrentCulture); public CultureInfo GetCultureInfo(IGuild guild) => - GetCultureInfo(guild.Id); + GetCultureInfo(guild?.Id); - public CultureInfo GetCultureInfo(ulong guildId) + public CultureInfo GetCultureInfo(ulong? guildId) { + if (guildId == null) + return DefaultCultureInfo; CultureInfo info = null; - GuildCultureInfos.TryGetValue(guildId, out info); + GuildCultureInfos.TryGetValue(guildId.Value, out info); return info ?? DefaultCultureInfo; } From ff193e4549b768ba6a7d2bf3114ec35aa8bac3e0 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 22:11:36 +0100 Subject: [PATCH 225/746] custom reactions fully localizable, found several bugs too. --- .../CustomReactions/CustomReactions.cs | 132 ++++++++++-------- .../Resources/ResponseStrings.Designer.cs | 117 ++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 43 +++++- .../Database/Models/CustomReaction.cs | 1 - 4 files changed, 233 insertions(+), 60 deletions(-) diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index a5129c2b..295d7e37 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -139,7 +139,7 @@ namespace NadekoBot.Modules.CustomReactions if ((channel == null && !NadekoBot.Credentials.IsOwner(Context.User)) || (channel != null && !((IGuildUser)Context.User).GuildPermissions.Administrator)) { - try { await Context.Channel.SendErrorAsync("Insufficient permissions. Requires Bot ownership for global custom reactions, and Administrator for guild custom reactions."); } catch { } + await ReplyErrorLocalized("insuff_perms").ConfigureAwait(false); return; } @@ -166,7 +166,7 @@ namespace NadekoBot.Modules.CustomReactions else { var reactions = GuildReactions.AddOrUpdate(Context.Guild.Id, - Array.Empty(), + new CustomReaction[] { cr }, (k, old) => { Array.Resize(ref old, old.Length + 1); @@ -176,10 +176,10 @@ namespace NadekoBot.Modules.CustomReactions } await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithTitle("New Custom Reaction") + .WithTitle(GetText("new_cust_react")) .WithDescription($"#{cr.Id}") - .AddField(efb => efb.WithName("Trigger").WithValue(key)) - .AddField(efb => efb.WithName("Response").WithValue(message)) + .AddField(efb => efb.WithName(GetText("trigger")).WithValue(key)) + .AddField(efb => efb.WithName(GetText("response")).WithValue(message)) ).ConfigureAwait(false); } @@ -196,19 +196,20 @@ namespace NadekoBot.Modules.CustomReactions customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, Array.Empty()).Where(cr => cr != null).ToArray(); if (customReactions == null || !customReactions.Any()) - await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false); - else { - var lastPage = customReactions.Length / 20; - await Context.Channel.SendPaginatedConfirmAsync(page, curPage => - new EmbedBuilder().WithOkColor() - .WithTitle("Custom reactions") - .WithDescription(string.Join("\n", customReactions.OrderBy(cr => cr.Trigger) - .Skip((curPage - 1) * 20) - .Take(20) - .Select(cr => $"`#{cr.Id}` `Trigger:` {cr.Trigger}"))), lastPage) - .ConfigureAwait(false); + await ReplyErrorLocalized("no_found").ConfigureAwait(false); + return; } + + var lastPage = customReactions.Length / 20; + await Context.Channel.SendPaginatedConfirmAsync(page, curPage => + new EmbedBuilder().WithOkColor() + .WithTitle(GetText("name")) + .WithDescription(string.Join("\n", customReactions.OrderBy(cr => cr.Trigger) + .Skip((curPage - 1) * 20) + .Take(20) + .Select(cr => $"`#{cr.Id}` `{GetText("trigger")}:` {cr.Trigger}"))), lastPage) + .ConfigureAwait(false); } public enum All @@ -227,20 +228,22 @@ namespace NadekoBot.Modules.CustomReactions customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray(); if (customReactions == null || !customReactions.Any()) - await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false); - else { - var txtStream = await customReactions.GroupBy(cr => cr.Trigger) - .OrderBy(cr => cr.Key) - .Select(cr => new { Trigger = cr.Key, Responses = cr.Select(y => new { id = y.Id, text = y.Response }).ToList() }) - .ToJson() - .ToStream() - .ConfigureAwait(false); - if (Context.Guild == null) // its a private one, just send back - await Context.Channel.SendFileAsync(txtStream, "customreactions.txt", "List of all custom reactions").ConfigureAwait(false); - else - await ((IGuildUser)Context.User).SendFileAsync(txtStream, "customreactions.txt", "List of all custom reactions").ConfigureAwait(false); + await ReplyErrorLocalized("no_found").ConfigureAwait(false); + return; } + + var txtStream = await customReactions.GroupBy(cr => cr.Trigger) + .OrderBy(cr => cr.Key) + .Select(cr => new { Trigger = cr.Key, Responses = cr.Select(y => new { id = y.Id, text = y.Response }).ToList() }) + .ToJson() + .ToStream() + .ConfigureAwait(false); + + if (Context.Guild == null) // its a private one, just send back + await Context.Channel.SendFileAsync(txtStream, "customreactions.txt", GetText("list_all")).ConfigureAwait(false); + else + await ((IGuildUser)Context.User).SendFileAsync(txtStream, "customreactions.txt", GetText("list_all")).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -255,7 +258,9 @@ namespace NadekoBot.Modules.CustomReactions customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray(); if (customReactions == null || !customReactions.Any()) - await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false); + { + await ReplyErrorLocalized("no_found").ConfigureAwait(false); + } else { var ordered = customReactions @@ -266,7 +271,7 @@ namespace NadekoBot.Modules.CustomReactions var lastPage = ordered.Count / 20; await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) => new EmbedBuilder().WithOkColor() - .WithTitle($"Custom Reactions (grouped)") + .WithTitle(GetText("name")) .WithDescription(string.Join("\r\n", ordered .Skip((curPage - 1) * 20) .Take(20) @@ -287,13 +292,16 @@ namespace NadekoBot.Modules.CustomReactions var found = customReactions.FirstOrDefault(cr => cr?.Id == id); if (found == null) - await Context.Channel.SendErrorAsync("No custom reaction found with that id.").ConfigureAwait(false); + { + await ReplyErrorLocalized("no_found_id").ConfigureAwait(false); + return; + } else { await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithDescription($"#{id}") - .AddField(efb => efb.WithName("Trigger").WithValue(found.Trigger)) - .AddField(efb => efb.WithName("Response").WithValue(found.Response + "\n```css\n" + found.Response + "```")) + .AddField(efb => efb.WithName(GetText("trigger")).WithValue(found.Trigger)) + .AddField(efb => efb.WithName(GetText("response")).WithValue(found.Response + "\n```css\n" + found.Response + "```")) ).ConfigureAwait(false); } } @@ -303,7 +311,7 @@ namespace NadekoBot.Modules.CustomReactions { if ((Context.Guild == null && !NadekoBot.Credentials.IsOwner(Context.User)) || (Context.Guild != null && !((IGuildUser)Context.User).GuildPermissions.Administrator)) { - try { await Context.Channel.SendErrorAsync("Insufficient permissions. Requires Bot ownership for global custom reactions, and Administrator for guild custom reactions."); } catch { } + await ReplyErrorLocalized("insuff_perms").ConfigureAwait(false); return; } @@ -313,32 +321,42 @@ namespace NadekoBot.Modules.CustomReactions { toDelete = uow.CustomReactions.Get(id); if (toDelete == null) //not found - return; - - if ((toDelete.GuildId == null || toDelete.GuildId == 0) && Context.Guild == null) + success = false; + else { - uow.CustomReactions.Remove(toDelete); - //todo i can dramatically improve performance of this, if Ids are ordered. - _globalReactions = GlobalReactions.Where(cr => cr?.Id != toDelete.Id).ToArray(); - success = true; - } - else if ((toDelete.GuildId != null && toDelete.GuildId != 0) && Context.Guild.Id == toDelete.GuildId) - { - uow.CustomReactions.Remove(toDelete); - GuildReactions.AddOrUpdate(Context.Guild.Id, new CustomReaction[] { }, (key, old) => + if ((toDelete.GuildId == null || toDelete.GuildId == 0) && Context.Guild == null) { - return old.Where(cr => cr?.Id != toDelete.Id).ToArray(); - }); - success = true; + uow.CustomReactions.Remove(toDelete); + //todo i can dramatically improve performance of this, if Ids are ordered. + _globalReactions = GlobalReactions.Where(cr => cr?.Id != toDelete.Id).ToArray(); + success = true; + } + else if ((toDelete.GuildId != null && toDelete.GuildId != 0) && Context.Guild.Id == toDelete.GuildId) + { + uow.CustomReactions.Remove(toDelete); + GuildReactions.AddOrUpdate(Context.Guild.Id, new CustomReaction[] { }, (key, old) => + { + return old.Where(cr => cr?.Id != toDelete.Id).ToArray(); + }); + success = true; + } + if (success) + await uow.CompleteAsync().ConfigureAwait(false); } - if (success) - await uow.CompleteAsync().ConfigureAwait(false); } if (success) - await Context.Channel.SendConfirmAsync("Deleted custom reaction", toDelete.ToString()).ConfigureAwait(false); + { + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle(GetText("deleted")) + .WithDescription("#" + toDelete.Id) + .AddField(efb => efb.WithName(GetText("trigger")).WithValue(toDelete.Trigger)) + .AddField(efb => efb.WithName(GetText("response")).WithValue(toDelete.Response))); + } else - await Context.Channel.SendErrorAsync("Failed to find that custom reaction.").ConfigureAwait(false); + { + await ReplyErrorLocalized("no_found_id").ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -348,18 +366,18 @@ namespace NadekoBot.Modules.CustomReactions if (string.IsNullOrWhiteSpace(trigger)) { ClearStats(); - await Context.Channel.SendConfirmAsync($"Custom reaction stats cleared.").ConfigureAwait(false); + await ReplyConfirmLocalized("all_stats_cleared").ConfigureAwait(false); } else { uint throwaway; if (ReactionStats.TryRemove(trigger, out throwaway)) { - await Context.Channel.SendConfirmAsync($"Stats cleared for `{trigger}` custom reaction.").ConfigureAwait(false); + await ReplyErrorLocalized("stats_cleared", Format.Bold(trigger)).ConfigureAwait(false); } else { - await Context.Channel.SendErrorAsync("No stats for that trigger found, no action taken.").ConfigureAwait(false); + await ReplyErrorLocalized("stats_not_found").ConfigureAwait(false); } } } @@ -376,7 +394,7 @@ namespace NadekoBot.Modules.CustomReactions await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) => ordered.Skip((curPage - 1) * 9) .Take(9) - .Aggregate(new EmbedBuilder().WithOkColor().WithTitle($"Custom Reaction Stats"), + .Aggregate(new EmbedBuilder().WithOkColor().WithTitle(GetText("stats")), (agg, cur) => agg.AddField(efb => efb.WithName(cur.Key).WithValue(cur.Value.ToString()).WithIsInline(true))), lastPage) .ConfigureAwait(false); } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 3b58fbab..76d825ad 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -266,6 +266,123 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to All custom reaction stats cleared.. + /// + public static string customreactions_all_stats_cleared { + get { + return ResourceManager.GetString("customreactions_all_stats_cleared", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Custom Reaction deleted. + /// + public static string customreactions_deleted { + get { + return ResourceManager.GetString("customreactions_deleted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Insufficient permissions. Requires Bot ownership for global custom reactions, and Administrator for guild custom reactions.. + /// + public static string customreactions_insuff_perms { + get { + return ResourceManager.GetString("customreactions_insuff_perms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List of all custom reactions. + /// + public static string customreactions_list_all { + get { + return ResourceManager.GetString("customreactions_list_all", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Custom Reactions. + /// + public static string customreactions_name { + get { + return ResourceManager.GetString("customreactions_name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New Custom Reaction. + /// + public static string customreactions_new_cust_react { + get { + return ResourceManager.GetString("customreactions_new_cust_react", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No custom reactions found.. + /// + public static string customreactions_no_found { + get { + return ResourceManager.GetString("customreactions_no_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No custom reaction found with that id.. + /// + public static string customreactions_no_found_id { + get { + return ResourceManager.GetString("customreactions_no_found_id", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Response. + /// + public static string customreactions_response { + get { + return ResourceManager.GetString("customreactions_response", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Custom Reaction Stats. + /// + public static string customreactions_stats { + get { + return ResourceManager.GetString("customreactions_stats", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stats cleared for {0} custom reaction.. + /// + public static string customreactions_stats_cleared { + get { + return ResourceManager.GetString("customreactions_stats_cleared", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No stats for that trigger found, no action taken.. + /// + public static string customreactions_stats_not_found { + get { + return ResourceManager.GetString("customreactions_stats_not_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trigger. + /// + public static string customreactions_trigger { + get { + return ResourceManager.GetString("customreactions_trigger", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} has already fainted.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 155460f7..cd6857ab 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -163,7 +163,7 @@ You are not participating in that war. - @{0} You are either not participating in that war, or you have already destroyed a base. + @{0} You are either not participating in that war, or that base is already destroyed. No active wars. @@ -172,7 +172,7 @@ Size - War against {0} is already started. + War against {0} has already started. War against {0} created. @@ -186,6 +186,45 @@ War against {0} started! + + All custom reaction stats cleared. + + + Custom Reaction deleted + + + Insufficient permissions. Requires Bot ownership for global custom reactions, and Administrator for guild custom reactions. + + + List of all custom reactions + + + Custom Reactions + + + New Custom Reaction + + + No custom reactions found. + + + No custom reaction found with that id. + + + Response + + + Custom Reaction Stats + + + Stats cleared for {0} custom reaction. + + + No stats for that trigger found, no action taken. + + + Trigger + {0} has already fainted. diff --git a/src/NadekoBot/Services/Database/Models/CustomReaction.cs b/src/NadekoBot/Services/Database/Models/CustomReaction.cs index 9ae3ab3b..394e5084 100644 --- a/src/NadekoBot/Services/Database/Models/CustomReaction.cs +++ b/src/NadekoBot/Services/Database/Models/CustomReaction.cs @@ -12,7 +12,6 @@ namespace NadekoBot.Services.Database.Models public string Trigger { get; set; } public bool IsRegex { get; set; } public bool OwnerOnly { get; set; } - public override string ToString() => $"`#{Id}` `Trigger:` {Trigger}\n `Response:` {Response}"; } public class ReactionResponse : DbEntity From 813a9b7839fd0211038e0eb902df5564a1913b4f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 22:21:18 +0100 Subject: [PATCH 226/746] custom reaction module translated --- .../Resources/ResponseStrings.Designer.cs | 2 +- src/NadekoBot/Resources/ResponseStrings.resx | 2 +- .../Resources/ResponseStrings.sr-cyrl-rs.resx | 39 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 76d825ad..342b3967 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -285,7 +285,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Insufficient permissions. Requires Bot ownership for global custom reactions, and Administrator for guild custom reactions.. + /// Looks up a localized string similar to Insufficient permissions. Requires Bot ownership for global custom reactions, and Administrator for server custom reactions.. /// public static string customreactions_insuff_perms { get { diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index cd6857ab..a6728d5f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -193,7 +193,7 @@ Custom Reaction deleted - Insufficient permissions. Requires Bot ownership for global custom reactions, and Administrator for guild custom reactions. + Insufficient permissions. Requires Bot ownership for global custom reactions, and Administrator for server custom reactions. List of all custom reactions diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx index 43a96f10..e3d4d417 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx @@ -253,4 +253,43 @@ је **УНИШТИО** базу #{0} у рату против {1} + + Сва статистика Реакција по Избору је обрисана. + + + Реакција по Избору обрисана + + + Немате дозволу. Потребно је поседовати бота за глобалне Реакције по Избору, а Администратор за серверске Реакције по Избору. + + + Листа свих реакција по избору + + + Реакције по Избору + + + Нова Реакција по Избору + + + Реакција по избору није нађена. + + + Није нађена реакција са тим идентификатором. + + + Одговор + + + Статистика Реакција по Избору + + + Статистика је обрисана за {0} реакцију по избору. + + + Није нађена статистика за тај окидач. Нема промене. + + + Окидач + \ No newline at end of file From e6af53d6473bd269ea8f3010ea0249252c5f02e9 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 13 Feb 2017 23:21:25 +0100 Subject: [PATCH 227/746] nsfw translated. whole 5 strings out of which 3 are the same. :) --- src/NadekoBot/Modules/NSFW/NSFW.cs | 53 ++++++++++--------- .../Resources/ResponseStrings.Designer.cs | 37 +++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 13 +++++ .../Resources/ResponseStrings.sr-cyrl-rs.resx | 13 +++++ 4 files changed, 90 insertions(+), 26 deletions(-) diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index c2e42d58..5538e8d6 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -20,8 +20,8 @@ namespace NadekoBot.Modules.NSFW public class NSFW : NadekoModule { - private static ConcurrentDictionary AutoHentaiTimers { get; } = new ConcurrentDictionary(); - private static ConcurrentHashSet _hentaiBombBlacklist { get; } = new ConcurrentHashSet(); + private static readonly ConcurrentDictionary AutoHentaiTimers = new ConcurrentDictionary(); + private static readonly ConcurrentHashSet HentaiBombBlacklist = new ConcurrentHashSet(); private async Task InternalHentai(IMessageChannel channel, string tag, bool noError) { @@ -30,7 +30,7 @@ namespace NadekoBot.Modules.NSFW tag = "rating%3Aexplicit+" + tag; var rng = new NadekoRandom(); - Task provider = Task.FromResult(""); + var provider = Task.FromResult(""); switch (rng.Next(0, 4)) { case 0: @@ -45,20 +45,18 @@ namespace NadekoBot.Modules.NSFW case 3: provider = GetYandereImageLink(tag); break; - default: - break; } var link = await provider.ConfigureAwait(false); if (string.IsNullOrWhiteSpace(link)) { if (!noError) - await channel.SendErrorAsync("No results found.").ConfigureAwait(false); + await ReplyErrorLocalized("not_found").ConfigureAwait(false); return; } await channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithImageUrl(link) - .WithDescription("Tag: " + tag)) + .WithDescription($"{GetText("tag")}: " + tag)) .ConfigureAwait(false); } @@ -74,11 +72,10 @@ namespace NadekoBot.Modules.NSFW if (interval == 0) { - if (AutoHentaiTimers.TryRemove(Context.Channel.Id, out t)) - { - t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer - await Context.Channel.SendConfirmAsync("Autohentai stopped.").ConfigureAwait(false); - } + if (!AutoHentaiTimers.TryRemove(Context.Channel.Id, out t)) return; + + t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer + await ReplyConfirmLocalized("autohentai_stopped").ConfigureAwait(false); return; } @@ -96,7 +93,10 @@ namespace NadekoBot.Modules.NSFW else await InternalHentai(Context.Channel, tagsArr[new NadekoRandom().Next(0, tagsArr.Length)], true).ConfigureAwait(false); } - catch { } + catch + { + // ignored + } }, null, interval * 1000, interval * 1000); AutoHentaiTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) => @@ -105,15 +105,16 @@ namespace NadekoBot.Modules.NSFW return t; }); - await Context.Channel.SendConfirmAsync($"Autohentai started. Reposting every {interval}s with one of the following tags:\n{string.Join(", ", tagsArr)}") - .ConfigureAwait(false); + await ReplyConfirmLocalized("autohentai_started", + interval, + string.Join(", ", tagsArr)).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] public async Task HentaiBomb([Remainder] string tag = null) { - if (!_hentaiBombBlacklist.Add(Context.User.Id)) + if (!HentaiBombBlacklist.Add(Context.User.Id)) return; try { @@ -125,19 +126,19 @@ namespace NadekoBot.Modules.NSFW GetKonachanImageLink(tag), GetYandereImageLink(tag)).ConfigureAwait(false); - var linksEnum = links?.Where(l => l != null); + var linksEnum = links?.Where(l => l != null).ToArray(); if (links == null || !linksEnum.Any()) { - await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false); + await ReplyErrorLocalized("not_found").ConfigureAwait(false); return; } - await Context.Channel.SendMessageAsync(String.Join("\n\n", linksEnum)).ConfigureAwait(false); + await Context.Channel.SendMessageAsync(string.Join("\n\n", linksEnum)).ConfigureAwait(false); } finally { await Task.Delay(5000).ConfigureAwait(false); - _hentaiBombBlacklist.TryRemove(Context.User.Id); + HentaiBombBlacklist.TryRemove(Context.User.Id); } } #endif @@ -157,7 +158,7 @@ namespace NadekoBot.Modules.NSFW var url = await GetE621ImageLink(tag).ConfigureAwait(false); if (url == null) - await Context.Channel.SendErrorAsync(Context.User.Mention + " No results."); + await ReplyErrorLocalized("not_found").ConfigureAwait(false); else await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithDescription(Context.User.Mention + " " + tag) @@ -178,7 +179,7 @@ namespace NadekoBot.Modules.NSFW var url = await GetDanbooruImageLink(tag).ConfigureAwait(false); if (url == null) - await Context.Channel.SendErrorAsync(Context.User.Mention + " No results.").ConfigureAwait(false); + await ReplyErrorLocalized("not_found").ConfigureAwait(false); else await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithDescription(Context.User.Mention + " " + tag) @@ -227,9 +228,9 @@ 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, 10330) }").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); + await Context.Channel.SendMessageAsync($"http://media.oboobs.ru/{obj["preview"]}").ConfigureAwait(false); } catch (Exception ex) { @@ -245,9 +246,9 @@ 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, 4335) }").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); + await Context.Channel.SendMessageAsync($"http://media.obutts.ru/{obj["preview"]}").ConfigureAwait(false); } catch (Exception ex) { diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 342b3967..23b6abda 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -383,6 +383,43 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Autohentai started. Reposting every {0}s with one of the following tags: + ///{1}. + /// + public static string nsfw_autohentai_started { + get { + return ResourceManager.GetString("nsfw_autohentai_started", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Autohentai stopped.. + /// + public static string nsfw_autohentai_stopped { + get { + return ResourceManager.GetString("nsfw_autohentai_stopped", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No results found.. + /// + public static string nsfw_not_found { + get { + return ResourceManager.GetString("nsfw_not_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tag. + /// + public static string nsfw_tag { + get { + return ResourceManager.GetString("nsfw_tag", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} has already fainted.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index a6728d5f..80ada81e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -225,6 +225,12 @@ Trigger + + Autohentai stopped. + + + No results found. + {0} has already fainted. @@ -292,4 +298,11 @@ You fainted, so you are not able to move! + + Autohentai started. Reposting every {0}s with one of the following tags: +{1} + + + Tag + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx index e3d4d417..5b59766c 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx @@ -292,4 +292,17 @@ Окидач + + Аутохентаи започет. Постоваћу сваких {0} сек. користећи један од следећих тагова: +{1} + + + АутоХентаи заустављен. + + + Нема резултата. + + + Таг + \ No newline at end of file From e68608770f7944d550b103d96a745917258ae110 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 00:19:59 +0100 Subject: [PATCH 228/746] help fully localized, hgit might not work properly though, needs testing --- src/NadekoBot/Modules/Help/Help.cs | 86 +++++---- src/NadekoBot/Modules/NadekoModule.cs | 6 +- .../Resources/ResponseStrings.Designer.cs | 168 ++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 60 +++++++ 4 files changed, 271 insertions(+), 49 deletions(-) diff --git a/src/NadekoBot/Modules/Help/Help.cs b/src/NadekoBot/Modules/Help/Help.cs index c447db40..c22a9789 100644 --- a/src/NadekoBot/Modules/Help/Help.cs +++ b/src/NadekoBot/Modules/Help/Help.cs @@ -13,19 +13,26 @@ using System.Collections.Generic; namespace NadekoBot.Modules.Help { [NadekoModule("Help", "-")] - public partial class Help : NadekoModule + public class Help : NadekoModule { private static string helpString { get; } = NadekoBot.BotConfig.HelpString; public static string HelpString => String.Format(helpString, NadekoBot.Credentials.ClientId, NadekoBot.ModulePrefixes[typeof(Help).Name]); public static string DMHelpString { get; } = NadekoBot.BotConfig.DMHelpString; + public const string PatreonUrl = "https://patreon.com/nadekobot"; + public const string PaypalUrl = "https://paypal.me/Kwoth"; + [NadekoCommand, Usage, Description, Aliases] public async Task Modules() { - - var embed = new EmbedBuilder().WithOkColor().WithFooter(efb => efb.WithText($" ℹ️ Type `-cmds ModuleName` to get a list of commands in that module. eg `-cmds games`")) - .WithTitle("📜 List Of Modules").WithDescription("\n• " + string.Join("\n• ", NadekoBot.CommandService.Modules.GroupBy(m => m.GetTopLevelModule()).Select(m => m.Key.Name).OrderBy(s => s))); + var embed = new EmbedBuilder().WithOkColor() + .WithFooter(efb => efb.WithText("ℹ️" + GetText("modules_footer", Prefix))) + .WithTitle(GetText("list_of_modules")) + .WithDescription(string.Join("\n", + NadekoBot.CommandService.Modules.GroupBy(m => m.GetTopLevelModule()) + .Select(m => "• " + m.Key.Name) + .OrderBy(s => s))); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } @@ -45,18 +52,13 @@ namespace NadekoBot.Modules.Help var cmdsArray = cmds as CommandInfo[] ?? cmds.ToArray(); if (!cmdsArray.Any()) { - await channel.SendErrorAsync("That module does not exist.").ConfigureAwait(false); + await ReplyErrorLocalized("module_not_found").ConfigureAwait(false); return; } - if (module != "customreactions" && module != "conversations") - { - await channel.SendTableAsync("📃 **List Of Commands:**\n", cmdsArray, el => $"{el.Aliases.First(),-15} {"["+el.Aliases.Skip(1).FirstOrDefault()+"]",-8}").ConfigureAwait(false); - } - else - { - await channel.SendMessageAsync("📃 **List Of Commands:**\n• " + string.Join("\n• ", cmdsArray.Select(c => $"{c.Aliases.First()}"))); - } - await channel.SendConfirmAsync($"ℹ️ **Type** `\"{NadekoBot.ModulePrefixes[typeof(Help).Name]}h CommandName\"` **to see the help for that specified command.** ***e.g.*** `-h >8ball`").ConfigureAwait(false); + + await channel.SendTableAsync($"📃 **{GetText("list_of_commands")}**\n", cmdsArray, el => $"{el.Aliases.First(),-15} {"["+el.Aliases.Skip(1).FirstOrDefault()+"]",-8}").ConfigureAwait(false); + + await ConfirmLocalized("commands_instr", Prefix).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -75,32 +77,33 @@ namespace NadekoBot.Modules.Help if (com == null) { - await channel.SendErrorAsync("I can't find that command. Please check the **command** and **command prefix** before trying again."); + await ReplyErrorLocalized("command_not_found").ConfigureAwait(false); return; } - var str = $"**`{com.Aliases.First()}`**"; + var str = string.Format("**`{0}`**", com.Aliases.First()); var alias = com.Aliases.Skip(1).FirstOrDefault(); if (alias != null) - str += $" **/ `{alias}`**"; + str += string.Format(" **/ `{0}`**", alias); var embed = new EmbedBuilder() - .AddField(fb => fb.WithName(str).WithValue($"{ string.Format(com.Summary, com.Module.Aliases.First())} { GetCommandRequirements(com)}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Usage**").WithValue($"{string.Format(com.Remarks, com.Module.Aliases.First())}").WithIsInline(false)) + .AddField(fb => fb.WithName(str).WithValue($"{string.Format(com.Summary, com.Module.Aliases.First())} {GetCommandRequirements(com)}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("usage")).WithValue(string.Format(com.Remarks, com.Module.Aliases.First())).WithIsInline(false)) .WithColor(NadekoBot.OkColor); await channel.EmbedAsync(embed).ConfigureAwait(false); } private string GetCommandRequirements(CommandInfo cmd) => - String.Join(" ", cmd.Preconditions + string.Join(" ", cmd.Preconditions .Where(ca => ca is OwnerOnlyAttribute || ca is RequireUserPermissionAttribute) .Select(ca => { if (ca is OwnerOnlyAttribute) - return "**Bot Owner only.**"; + return Format.Bold(GetText("bot_owner_only")); var cau = (RequireUserPermissionAttribute)ca; if (cau.GuildPermission != null) - return $"**Requires {cau.GuildPermission} server permission.**".Replace("Guild", "Server"); - else - return $"**Requires {cau.ChannelPermission} channel permission.**".Replace("Guild", "Server"); + return Format.Bold(GetText("server_permission", cau.GuildPermission)) + .Replace("Guild", "Server"); + return Format.Bold(GetText("channel_permission", cau.ChannelPermission)) + .Replace("Guild", "Server"); })); [NadekoCommand, Usage, Description, Aliases] @@ -109,14 +112,14 @@ namespace NadekoBot.Modules.Help public async Task Hgit() { var helpstr = new StringBuilder(); - helpstr.AppendLine("You can support the project on patreon: or paypal: \n"); - helpstr.AppendLine("##Table Of Contents"); + helpstr.AppendLine(GetText("cmdlist_donate", PatreonUrl, PaypalUrl) + "\n"); + helpstr.AppendLine("##"+ GetText("table_of_contents")); helpstr.AppendLine(string.Join("\n", NadekoBot.CommandService.Modules.Where(m => m.GetTopLevelModule().Name.ToLowerInvariant() != "help") .Select(m => m.GetTopLevelModule().Name) .Distinct() .OrderBy(m => m) .Prepend("Help") - .Select(m => $"- [{m}](#{m.ToLowerInvariant()})"))); + .Select(m => string.Format("- [{0}](#{1})", m, m.ToLowerInvariant())))); helpstr.AppendLine(); string lastModule = null; foreach (var com in NadekoBot.CommandService.Commands.OrderBy(com => com.Module.GetTopLevelModule().Name).GroupBy(c => c.Aliases.First()).Select(g => g.First())) @@ -127,44 +130,35 @@ namespace NadekoBot.Modules.Help if (lastModule != null) { helpstr.AppendLine(); - helpstr.AppendLine("###### [Back to TOC](#table-of-contents)"); + helpstr.AppendLine($"###### [{GetText("back_to_toc")}](#{GetText("table_of_contents").ToLowerInvariant().Replace(' ', '-')})"); } helpstr.AppendLine(); helpstr.AppendLine("### " + module.Name + " "); - helpstr.AppendLine("Command and aliases | Description | Usage"); + helpstr.AppendLine($"{GetText("cmd_and_alias")} | {GetText("desc")} | {GetText("usage")}"); helpstr.AppendLine("----------------|--------------|-------"); lastModule = module.Name; } - helpstr.AppendLine($"{string.Join(" ", com.Aliases.Select(a => "`" + a + "`"))} | {string.Format(com.Summary, com.Module.GetPrefix())} {GetCommandRequirements(com)} | {string.Format(com.Remarks, com.Module.GetPrefix())}"); + helpstr.AppendLine($"{string.Join(" ", com.Aliases.Select(a => "`" + a + "`"))} |" + + $" {string.Format(com.Summary, com.Module.GetPrefix())} {GetCommandRequirements(com)} |" + + $" {string.Format(com.Remarks, com.Module.GetPrefix())}"); } helpstr = helpstr.Replace(NadekoBot.Client.CurrentUser.Username , "@BotName"); File.WriteAllText("../../docs/Commands List.md", helpstr.ToString()); - await Context.Channel.SendConfirmAsync("Commandlist Regenerated").ConfigureAwait(false); + await ReplyConfirmLocalized("commandlist_regen").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] public async Task Guide() { - var channel = (ITextChannel)Context.Channel; - - await channel.SendConfirmAsync( -@"**LIST OF COMMANDS**: -**Hosting Guides and docs can be found here**: ").ConfigureAwait(false); + await ConfirmLocalized("guide", + "http://nadekobot.readthedocs.io/en/latest/Commands%20List/", + "http://nadekobot.readthedocs.io/en/latest/").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] public async Task Donate() { - var channel = (ITextChannel)Context.Channel; - - await channel.SendConfirmAsync( -$@"You can support the NadekoBot project on patreon. or -Paypal -Don't forget to leave your discord name or id in the message. - -**Thank you** ♥️").ConfigureAwait(false); + await ReplyConfirmLocalized("donate", PatreonUrl, PaypalUrl).ConfigureAwait(false); } } diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index 7ef213db..7f75e891 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -17,7 +17,7 @@ namespace NadekoBot.Modules public readonly string ModuleTypeName; public readonly string LowerModuleTypeName; - public NadekoModule(bool isTopLevelModule = true) + protected NadekoModule(bool isTopLevelModule = true) { //if it's top level module ModuleTypeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name; @@ -81,7 +81,7 @@ namespace NadekoBot.Modules GetTextStatic(key, _cultureInfo, LowerModuleTypeName); protected string GetText(string key, params object[] replacements) => - GetText(key, _cultureInfo, LowerModuleTypeName, replacements); + GetTextStatic(key, _cultureInfo, LowerModuleTypeName, replacements); public Task ErrorLocalized(string textKey, params object[] replacements) { @@ -110,7 +110,7 @@ namespace NadekoBot.Modules public abstract class NadekoSubmodule : NadekoModule { - public NadekoSubmodule() : base(false) + protected NadekoSubmodule() : base(false) { } } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 23b6abda..975e2331 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -383,6 +383,174 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Back to ToC. + /// + public static string help_back_to_toc { + get { + return ResourceManager.GetString("help_back_to_toc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bot Owner Only. + /// + public static string help_bot_owner_only { + get { + return ResourceManager.GetString("help_bot_owner_only", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Requires {0} channel permission.. + /// + public static string help_channel_permission { + get { + return ResourceManager.GetString("help_channel_permission", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Command and aliases. + /// + public static string help_cmd_and_alias { + get { + return ResourceManager.GetString("help_cmd_and_alias", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You can support the project on patreon: <{0}> or paypal: <{1}>. + /// + public static string help_cmdlist_donate { + get { + return ResourceManager.GetString("help_cmdlist_donate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I can't find that command. Please verify that the command exists before trying again.. + /// + public static string help_command_not_found { + get { + return ResourceManager.GetString("help_command_not_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Commandlist Regenerated.. + /// + public static string help_commandlist_regen { + get { + return ResourceManager.GetString("help_commandlist_regen", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type `{0}h CommandName` to see the help for that specified command. e.g. `{0}h >8ball`. + /// + public static string help_commands_instr { + get { + return ResourceManager.GetString("help_commands_instr", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Description. + /// + public static string help_desc { + get { + return ResourceManager.GetString("help_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You can support the NadekoBot project on + ///Patreon <{0}> or + ///Paypal <{1}> + ///Don't forget to leave your discord name or id in the message. + /// + ///**Thank you** ♥️. + /// + public static string help_donate { + get { + return ResourceManager.GetString("help_donate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to **List of Commands**: <{0}> + ///**Hosting Guides and docs can be found here**: <{1}>. + /// + public static string help_guide { + get { + return ResourceManager.GetString("help_guide", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List Of Commands. + /// + public static string help_list_of_commands { + get { + return ResourceManager.GetString("help_list_of_commands", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List Of Modules. + /// + public static string help_list_of_modules { + get { + return ResourceManager.GetString("help_list_of_modules", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to That module does not exist.. + /// + public static string help_module_not_found { + get { + return ResourceManager.GetString("help_module_not_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type `{0}cmds ModuleName` to get a list of commands in that module. eg `{0}cmds games`. + /// + public static string help_modules_footer { + get { + return ResourceManager.GetString("help_modules_footer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Requires {0} server permission.. + /// + public static string help_server_permission { + get { + return ResourceManager.GetString("help_server_permission", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Table Of Contents. + /// + public static string help_table_of_contents { + get { + return ResourceManager.GetString("help_table_of_contents", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Usage. + /// + public static string help_usage { + get { + return ResourceManager.GetString("help_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to Autohentai started. Reposting every {0}s with one of the following tags: ///{1}. diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 80ada81e..5285f3b6 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -298,6 +298,66 @@ You fainted, so you are not able to move! + + Back to ToC + + + Bot Owner Only + + + Requires {0} channel permission. + + + You can support the project on patreon: <{0}> or paypal: <{1}> + + + Command and aliases + + + Commandlist Regenerated. + + + Type `{0}h CommandName` to see the help for that specified command. e.g. `{0}h >8ball` + + + I can't find that command. Please verify that the command exists before trying again. + + + Description + + + You can support the NadekoBot project on +Patreon <{0}> or +Paypal <{1}> +Don't forget to leave your discord name or id in the message. + +**Thank you** ♥️ + + + **List of Commands**: <{0}> +**Hosting Guides and docs can be found here**: <{1}> + + + List Of Commands + + + List Of Modules + + + Type `{0}cmds ModuleName` to get a list of commands in that module. eg `{0}cmds games` + + + That module does not exist. + + + Requires {0} server permission. + + + Table Of Contents + + + Usage + Autohentai started. Reposting every {0}s with one of the following tags: {1} From d49af3389e242f11aa52dd8f4c6d409e61664829 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 00:27:45 +0100 Subject: [PATCH 229/746] translated help xd --- .../Resources/ResponseStrings.sr-cyrl-rs.resx | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx index 5b59766c..86b7aa87 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx @@ -292,6 +292,66 @@ Окидач + + Назад на Садржај + + + Само Власник Бота + + + Захтева {0} дозволу на каналу. + + + Можете подржати пројекат на Пејтриону: <{0}> или Пејпалу: <{1}> + + + Команде и псеудоними + + + Листа команди је обновљена. + + + Укуцај `{0}h ИмеКоманде` да видиш помоћ за ту команду. нпр. `{0}h >8ball` + + + Не могу да нађем ту команду. Проверите да ли команда постоји, па покушајте поново. + + + Опис + + + Можете подржати НадекоБот пројекат на +Пејтриону <{0}> или +Пејпалу <{1}> +Не заборавите да оставите своје корисничко име или ИД. + +**Хвала** ♥️ + + + **List of Commands**: <{0}> +**Hosting Guides and docs can be found here**: <{1}> + + + Листа Команди + + + Листа Модула + + + Укуцај `{0}cmds ИмеМодула` да видиш листу свих команди у том модулу. нпр `{0}cmds games` + + + Тај модул не постоји. + + + Захтева {0} дозволу на серверу. + + + Садржај + + + Упутство + Аутохентаи започет. Постоваћу сваких {0} сек. користећи један од следећих тагова: {1} From 91a0ee31af034ed2ac74ed26c3d21fe4c2b0ad96 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Mon, 13 Feb 2017 22:30:16 -0500 Subject: [PATCH 230/746] Add quote search by keyword and text command Quote search by keyword and text --- .../Modules/Utility/Commands/QuoteCommands.cs | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index 8add0707..b136b7aa 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -58,6 +58,27 @@ namespace NadekoBot.Modules.Utility await Context.Channel.SendMessageAsync("📣 " + quote.Text.SanitizeMentions()); } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task SearchQuote(string keyword, [Remainder] string text) + { + if (string.IsNullOrWhiteSpace(keyword) || string.IsNullOrWhiteSpace(text)) + return; + + keyword = keyword.ToUpperInvariant(); + + Quote keywordquote; + using (var uow = DbHandler.UnitOfWork()) + { + keywordquote = await uow.Quotes.SearchQuoteKeywordTextAsync(Context.Guild.Id, keyword, text).ConfigureAwait(false); + } + + if (keywordquote == null) + return; + + await Context.Channel.SendMessageAsync("💬 " + keyword + ": " + keywordquote.Text.SanitizeMentions()); + } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] @@ -143,4 +164,4 @@ namespace NadekoBot.Modules.Utility } } } -} \ No newline at end of file +} From 283fc2c21663a00345f9e95981b67265789cceea Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Mon, 13 Feb 2017 22:31:20 -0500 Subject: [PATCH 231/746] Update IQuoteRepository.cs --- src/NadekoBot/Services/Database/Repositories/IQuoteRepository.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NadekoBot/Services/Database/Repositories/IQuoteRepository.cs b/src/NadekoBot/Services/Database/Repositories/IQuoteRepository.cs index e3ca6ec1..080783ab 100644 --- a/src/NadekoBot/Services/Database/Repositories/IQuoteRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/IQuoteRepository.cs @@ -8,6 +8,7 @@ namespace NadekoBot.Services.Database.Repositories { IEnumerable GetAllQuotesByKeyword(ulong guildId, string keyword); Task GetRandomQuoteByKeywordAsync(ulong guildId, string keyword); + Task SearchQuoteKeywordTextAsync(ulong guildId, string keyword, string text); IEnumerable GetGroup(ulong guildId, int skip, int take); } } From 921f3a6d6c9cbf76e43d0c77a5cf1ad8869fc561 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Mon, 13 Feb 2017 22:32:16 -0500 Subject: [PATCH 232/746] Update QuoteRepository.cs Add quote search by keyword and text --- .../Services/Database/Repositories/Impl/QuoteRepository.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs index 22c6e5c9..d96a98c9 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs @@ -23,5 +23,11 @@ namespace NadekoBot.Services.Database.Repositories.Impl var rng = new NadekoRandom(); return _set.Where(q => q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rng.Next()).FirstOrDefaultAsync(); } + public Task SearchQuoteKeywordTextAsync(ulong guildId, string keyword, string text) + { + + var rngk = new NadekoRandom(); + return _set.Where(q => q.Text.Contains(text) && q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); + } } } From 7a03c277cf6cd60fae86fc049025b08d20e2a2a9 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Mon, 13 Feb 2017 22:32:39 -0500 Subject: [PATCH 233/746] Add quote search by keyword and text Add quote search by keyword and text --- .../Services/Database/Repositories/Impl/QuoteRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs index d96a98c9..6f9cfc20 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs @@ -28,6 +28,6 @@ namespace NadekoBot.Services.Database.Repositories.Impl var rngk = new NadekoRandom(); return _set.Where(q => q.Text.Contains(text) && q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); - } + } } } From 9d84dfbe90e89be4609268906d2f5c62957284c4 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Mon, 13 Feb 2017 22:38:08 -0500 Subject: [PATCH 234/746] Update CommandStrings.Designer.cs --- .../Resources/CommandStrings.Designer.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 11fa3692..73ea4744 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -2381,6 +2381,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to qsearch ..... + /// + public static string searchquote_cmd { + get { + return ResourceManager.GetString("searchquote_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Searches a quote for a given keyword and any string portion of a quote matching that keyword.. + /// + public static string searchquote_desc { + get { + return ResourceManager.GetString("searchquote_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}qsearch keyword text`. + /// + public static string searchquote_usage { + get { + return ResourceManager.GetString("searchquote_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to delmsgoncmd. /// From 599463e9123fa393eb37157559aa94813786f5d8 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Mon, 13 Feb 2017 22:39:39 -0500 Subject: [PATCH 235/746] Add searchquote command Add searchquote command --- src/NadekoBot/Resources/CommandStrings.resx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index cca4cf5c..97ffe02e 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -1143,6 +1143,15 @@ `{0}.. abc` + + qsearch .... + + + Searches a quote for a given keyword and any string portion of a quote matching that keyword. + + + `{0}qsearch keyword text` + deletequote delq @@ -3105,4 +3114,4 @@ `{0}timezone` - \ No newline at end of file + From 90d31fc266f0e459b7c17f504066ecfc0c9f8ad0 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Mon, 13 Feb 2017 22:42:10 -0500 Subject: [PATCH 236/746] Add quote search command by keyword and text Add quote search command by keyword and text --- src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index b136b7aa..87285de0 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -60,7 +60,7 @@ namespace NadekoBot.Modules.Utility } [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] + [RequireContext(ContextType.Guild)] public async Task SearchQuote(string keyword, [Remainder] string text) { if (string.IsNullOrWhiteSpace(keyword) || string.IsNullOrWhiteSpace(text)) From 9b773f4ea45d58ee4d33bb14d40ed6920e91d971 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Mon, 13 Feb 2017 22:51:57 -0500 Subject: [PATCH 237/746] Update CommandStrings.resx --- src/NadekoBot/Resources/CommandStrings.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 97ffe02e..208ab0cc 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -1144,7 +1144,7 @@ `{0}.. abc` - qsearch .... + qsearch ... Searches a quote for a given keyword and any string portion of a quote matching that keyword. From c4e228f2766d17369402f95ac8a6c055cea47d72 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Mon, 13 Feb 2017 23:43:35 -0500 Subject: [PATCH 238/746] Update QuoteCommands.cs --- src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index 87285de0..bf26a667 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -59,12 +59,12 @@ namespace NadekoBot.Modules.Utility await Context.Channel.SendMessageAsync("📣 " + quote.Text.SanitizeMentions()); } - [NadekoCommand, Usage, Description, Aliases] + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task SearchQuote(string keyword, [Remainder] string text) - { - if (string.IsNullOrWhiteSpace(keyword) || string.IsNullOrWhiteSpace(text)) - return; + { + if (string.IsNullOrWhiteSpace(keyword) || string.IsNullOrWhiteSpace(text)) + return; keyword = keyword.ToUpperInvariant(); From f0679854024f23b3460bb2c21ff418430a0f9545 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Mon, 13 Feb 2017 23:44:09 -0500 Subject: [PATCH 239/746] Update CommandStrings.Designer.cs --- src/NadekoBot/Resources/CommandStrings.Designer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 73ea4744..8788c2e3 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -2382,7 +2382,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to qsearch ..... + /// Looks up a localized string similar to qsearch .... /// public static string searchquote_cmd { get { From 672bb565e8891d29ad1a213860e5f1c8f32a9ba7 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Mon, 13 Feb 2017 23:44:50 -0500 Subject: [PATCH 240/746] Update QuoteRepository.cs --- .../Services/Database/Repositories/Impl/QuoteRepository.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs index 6f9cfc20..898f0efd 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs @@ -24,9 +24,8 @@ namespace NadekoBot.Services.Database.Repositories.Impl return _set.Where(q => q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rng.Next()).FirstOrDefaultAsync(); } public Task SearchQuoteKeywordTextAsync(ulong guildId, string keyword, string text) - { - - var rngk = new NadekoRandom(); + { + var rngk = new NadekoRandom(); return _set.Where(q => q.Text.Contains(text) && q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); } } From db49096246e17aab7b52a411a18736573dc5ca4c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 14:30:21 +0100 Subject: [PATCH 241/746] quite a bit of cleanup --- .../Commands/DMForwardCommands.cs | 4 +- .../Administration/Commands/LogCommand.cs | 29 ++++++----- .../Administration/Commands/Migration.cs | 20 ++++---- .../Administration/Commands/MuteCommands.cs | 2 - .../Commands/ProtectionCommands.cs | 2 - .../Commands/RatelimitCommand.cs | 24 ++++------ .../Commands/ServerGreetCommands.cs | 19 +++++--- .../Commands/VoicePlusTextCommands.cs | 6 +-- .../Modules/ClashOfClans/ClashOfClans.cs | 5 -- .../CustomReactions/CustomReactions.cs | 2 +- .../Modules/Gambling/Commands/AnimalRacing.cs | 22 ++++----- .../Gambling/Commands/CurrencyEvents.cs | 48 ++++++++++--------- .../Modules/Gambling/Commands/Slots.cs | 2 +- .../Gambling/Commands/WaifuClaimCommands.cs | 2 - src/NadekoBot/Modules/Gambling/Gambling.cs | 1 - .../Games/Commands/CleverBotCommands.cs | 20 +++----- .../Modules/Games/Commands/HangmanCommands.cs | 3 +- .../Games/Commands/PlantAndPickCommands.cs | 7 +-- .../Modules/Games/Commands/TicTacToe.cs | 2 +- src/NadekoBot/Modules/Games/Games.cs | 1 - src/NadekoBot/Modules/Music/Music.cs | 33 +++++++------ .../Permissions/Commands/CmdCdsCommands.cs | 28 +++++------ .../Permissions/Commands/FilterCommands.cs | 20 ++++---- .../Searches/Commands/AnimeSearchCommands.cs | 2 +- .../Searches/Commands/OverwatchCommands.cs | 2 +- .../Searches/Commands/PlaceCommands.cs | 3 +- .../Commands/StreamNotificationCommands.cs | 14 ++++-- src/NadekoBot/Modules/Searches/Searches.cs | 8 ++-- .../Modules/Utility/Commands/InfoCommands.cs | 10 ++-- .../Utility/Commands/MessageRepeater.cs | 2 +- .../Modules/Utility/Commands/Remind.cs | 6 +-- src/NadekoBot/Modules/Utility/Utility.cs | 1 - .../Services/Database/NadekoContext.cs | 4 +- src/NadekoBot/Services/Impl/StatsService.cs | 11 +++-- src/NadekoBot/Services/NadekoRandom.cs | 1 - 35 files changed, 174 insertions(+), 192 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs b/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs index fd954a4b..fe4a328b 100644 --- a/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs @@ -74,8 +74,8 @@ namespace NadekoBot.Modules.Administration var title = $"DM from [{msg.Author}]({msg.Author.Id})"; if (ForwardDMsToAllOwners) { - var msgs = await Task.WhenAll(ownerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id) - .Select(ch => ch.SendConfirmAsync(title, msg.Content))).ConfigureAwait(false); + await Task.WhenAll(ownerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id) + .Select(ch => ch.SendConfirmAsync(title, msg.Content))).ConfigureAwait(false); } else { diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index 4219ff98..c5183692 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -35,19 +35,15 @@ namespace NadekoBot.Modules.Administration private static ConcurrentDictionary> PresenceUpdates { get; } = new ConcurrentDictionary>(); private static Timer timerReference { get; } - private IGoogleApiService _google { get; } static LogCommands() { _client = NadekoBot.Client; _log = LogManager.GetCurrentClassLogger(); var sw = Stopwatch.StartNew(); - - using (var uow = DbHandler.UnitOfWork()) - { - GuildLogSettings = new ConcurrentDictionary(NadekoBot.AllGuildConfigs - .ToDictionary(g => g.GuildId, g => g.LogSetting)); - } + + GuildLogSettings = new ConcurrentDictionary(NadekoBot.AllGuildConfigs + .ToDictionary(g => g.GuildId, g => g.LogSetting)); timerReference = new Timer(async (state) => { @@ -59,7 +55,11 @@ namespace NadekoBot.Modules.Administration { List messages; if (PresenceUpdates.TryRemove(key, out messages)) - try { await key.SendConfirmAsync("Presence Updates", string.Join(Environment.NewLine, messages)); } catch { } + try { await key.SendConfirmAsync("Presence Updates", string.Join(Environment.NewLine, messages)); } + catch + { + // ignored + } })); } catch (Exception ex) @@ -159,7 +159,9 @@ namespace NadekoBot.Modules.Administration //} } catch - { } + { + // ignored + } } private static async Task _client_UserVoiceStateUpdated_TTS(SocketUser iusr, SocketVoiceState before, SocketVoiceState after) @@ -188,7 +190,7 @@ namespace NadekoBot.Modules.Administration var str = ""; if (beforeVch?.Guild == afterVch?.Guild) { - str = $"{usr.Username} moved from {beforeVch.Name} to {afterVch.Name}"; + str = $"{usr.Username} moved from {beforeVch?.Name} to {afterVch?.Name}"; } else if (beforeVch == null) { @@ -201,7 +203,10 @@ namespace NadekoBot.Modules.Administration var toDelete = await logChannel.SendMessageAsync(str, true).ConfigureAwait(false); toDelete.DeleteAfter(5); } - catch { } + catch + { + // ignored + } } private static async void MuteCommands_UserMuted(IGuildUser usr, MuteCommands.MuteType muteType) @@ -216,7 +221,7 @@ namespace NadekoBot.Modules.Administration ITextChannel logChannel; if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserMuted)) == null) return; - string mutes = ""; + var mutes = ""; switch (muteType) { case MuteCommands.MuteType.Voice: diff --git a/src/NadekoBot/Modules/Administration/Commands/Migration.cs b/src/NadekoBot/Modules/Administration/Commands/Migration.cs index 3a917698..883e5d4b 100644 --- a/src/NadekoBot/Modules/Administration/Commands/Migration.cs +++ b/src/NadekoBot/Modules/Administration/Commands/Migration.cs @@ -103,11 +103,8 @@ namespace NadekoBot.Modules.Administration var greetChannel = (ulong)(long)reader["GreetChannelId"]; var greetMsg = (string)reader["GreetText"]; var bye = (long)reader["Bye"] == 1; - var byeDM = (long)reader["ByePM"] == 1; var byeChannel = (ulong)(long)reader["ByeChannelId"]; var byeMsg = (string)reader["ByeText"]; - var grdel = false; - var byedel = grdel; var gc = uow.GuildConfigs.For(gid, set => set); if (greetDM) @@ -121,7 +118,6 @@ namespace NadekoBot.Modules.Administration gc.ByeMessageChannelId = byeChannel; gc.ChannelByeMessageText = byeMsg; - gc.AutoDeleteGreetMessagesTimer = gc.AutoDeleteByeMessagesTimer = grdel ? 30 : 0; _log.Info(++i); } } @@ -129,12 +125,12 @@ namespace NadekoBot.Modules.Administration _log.Warn("Greet/bye messages won't be migrated"); } var com2 = db.CreateCommand(); - com.CommandText = "SELECT * FROM CurrencyState GROUP BY UserId"; + com2.CommandText = "SELECT * FROM CurrencyState GROUP BY UserId"; i = 0; try { - var reader2 = com.ExecuteReader(); + var reader2 = com2.ExecuteReader(); while (reader2.Read()) { _log.Info(++i); @@ -203,7 +199,6 @@ namespace NadekoBot.Modules.Administration guildConfig.ExclusiveSelfAssignedRoles = data.ExclusiveSelfAssignedRoles; guildConfig.GenerateCurrencyChannelIds = new HashSet(data.GenerateCurrencyChannels.Select(gc => new GCChannelId() { ChannelId = gc.Key })); selfAssRoles.AddRange(data.ListOfSelfAssignableRoles.Select(r => new SelfAssignedRole() { GuildId = guildConfig.GuildId, RoleId = r }).ToArray()); - var logSetting = guildConfig.LogSetting; guildConfig.LogSetting.IgnoredChannels = new HashSet(data.LogserverIgnoreChannels.Select(id => new IgnoredLogChannel() { ChannelId = id })); guildConfig.LogSetting.LogUserPresenceId = data.LogPresenceChannel; @@ -249,7 +244,7 @@ namespace NadekoBot.Modules.Administration private void MigratePermissions0_9(IUnitOfWork uow) { - var PermissionsDict = new ConcurrentDictionary(); + var permissionsDict = new ConcurrentDictionary(); if (!Directory.Exists("data/permissions/")) { _log.Warn("No data from permissions will be migrated."); @@ -263,12 +258,15 @@ namespace NadekoBot.Modules.Administration if (string.IsNullOrWhiteSpace(strippedFileName)) continue; var id = ulong.Parse(strippedFileName); var data = JsonConvert.DeserializeObject(File.ReadAllText(file)); - PermissionsDict.TryAdd(id, data); + permissionsDict.TryAdd(id, data); + } + catch + { + // ignored } - catch { } } var i = 0; - PermissionsDict + permissionsDict .Select(p => new { data = p.Value, gconfig = uow.GuildConfigs.For(p.Key) }) .AsParallel() .ForAll(perms => diff --git a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs index f37a26ec..89ef6ec6 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs @@ -36,8 +36,6 @@ namespace NadekoBot.Modules.Administration static MuteCommands() { - var _log = LogManager.GetCurrentClassLogger(); - var configs = NadekoBot.AllGuildConfigs; GuildMuteRoles = new ConcurrentDictionary(configs .Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName)) diff --git a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs index 7639a4dc..ff671a98 100644 --- a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs @@ -402,8 +402,6 @@ namespace NadekoBot.Modules.Administration [RequireContext(ContextType.Guild)] public async Task AntiList() { - var channel = (ITextChannel)Context.Channel; - AntiSpamStats spam; antiSpamGuilds.TryGetValue(Context.Guild.Id, out spam); diff --git a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs index ccff187d..8ed81849 100644 --- a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs @@ -37,26 +37,22 @@ namespace NadekoBot.Modules.Administration public bool CheckUserRatelimit(ulong id) { - RatelimitedUser usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id }); + var usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id }); if (usr.MessageCount == MaxMessages) { return true; } - else + usr.MessageCount++; + var _ = Task.Run(async () => { - usr.MessageCount++; - var t = Task.Run(async () => + try { - try - { - await Task.Delay(PerSeconds * 1000, cancelSource.Token); - } - catch (OperationCanceledException) { } - usr.MessageCount--; - }); - return false; - } - + await Task.Delay(PerSeconds * 1000, cancelSource.Token); + } + catch (OperationCanceledException) { } + usr.MessageCount--; + }); + return false; } } diff --git a/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs index 6c1be19e..7c58fbfd 100644 --- a/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs @@ -18,10 +18,10 @@ namespace NadekoBot.Modules.Administration public partial class Administration { [Group] - public class ServerGreetCommands : ModuleBase + public class ServerGreetCommands : NadekoSubmodule { //make this to a field in the guildconfig table - class GreetSettings + private class GreetSettings { public int AutoDeleteGreetMessagesTimer { get; set; } public int AutoDeleteByeMessagesTimer { get; set; } @@ -129,7 +129,10 @@ namespace NadekoBot.Modules.Administration catch (Exception ex) { _log.Warn(ex); } } } - catch { } + catch + { + // ignored + } }); return Task.CompletedTask; } @@ -212,7 +215,10 @@ namespace NadekoBot.Modules.Administration } } } - catch { } + catch + { + // ignored + } }); return Task.CompletedTask; } @@ -222,7 +228,6 @@ namespace NadekoBot.Modules.Administration [RequireUserPermission(GuildPermission.ManageGuild)] public async Task GreetDel(int timer = 30) { - var channel = (ITextChannel)Context.Channel; if (timer < 0 || timer > 600) return; @@ -375,7 +380,7 @@ namespace NadekoBot.Modules.Administration await Context.Channel.SendConfirmAsync("🆗 New DM greet message **set**.").ConfigureAwait(false); if (!sendGreetEnabled) - await Context.Channel.SendConfirmAsync($"ℹ️ Enable DM greet messsages by typing `{NadekoBot.ModulePrefixes[typeof(Administration).Name]}greetdm`").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"ℹ️ Enable DM greet messsages by typing `{Prefix}greetdm`").ConfigureAwait(false); } public static bool SetGreetDmMessage(ulong guildId, ref string message) @@ -450,7 +455,7 @@ namespace NadekoBot.Modules.Administration await Context.Channel.SendConfirmAsync("🆗 New bye message **set**.").ConfigureAwait(false); if (!sendByeEnabled) - await Context.Channel.SendConfirmAsync($"ℹ️ Enable bye messsages by typing `{NadekoBot.ModulePrefixes[typeof(Administration).Name]}bye`").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"ℹ️ Enable bye messsages by typing `{Prefix}bye`").ConfigureAwait(false); } public static bool SetByeMessage(ulong guildId, ref string message) diff --git a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs index 392b4e88..dba5bb3a 100644 --- a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs @@ -30,10 +30,8 @@ namespace NadekoBot.Modules.Administration { var _log = LogManager.GetCurrentClassLogger(); var sw = Stopwatch.StartNew(); - using (var uow = DbHandler.UnitOfWork()) - { - voicePlusTextCache = new ConcurrentHashSet(NadekoBot.AllGuildConfigs.Where(g => g.VoicePlusTextEnabled).Select(g => g.GuildId)); - } + + voicePlusTextCache = new ConcurrentHashSet(NadekoBot.AllGuildConfigs.Where(g => g.VoicePlusTextEnabled).Select(g => g.GuildId)); NadekoBot.Client.UserVoiceStateUpdated += UserUpdatedEventHandler; sw.Stop(); diff --git a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs index 1ed31a6e..37f07efa 100644 --- a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs +++ b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs @@ -23,12 +23,8 @@ namespace NadekoBot.Modules.ClashOfClans private static Timer checkWarTimer { get; } - private static new readonly Logger _log; - static ClashOfClans() { - _log = LogManager.GetCurrentClassLogger(); - var sw = Stopwatch.StartNew(); using (var uow = DbHandler.UnitOfWork()) { ClashWars = new ConcurrentDictionary>( @@ -244,7 +240,6 @@ namespace NadekoBot.Modules.ClashOfClans SaveWar(war); await ReplyConfirmLocalized("war_ended", warsInfo.Item1[warsInfo.Item2].ShortPrint()).ConfigureAwait(false); - var size = warsInfo.Item1[warsInfo.Item2].Size; warsInfo.Item1.RemoveAt(warsInfo.Item2); } diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index 295d7e37..ebeb4922 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -165,7 +165,7 @@ namespace NadekoBot.Modules.CustomReactions } else { - var reactions = GuildReactions.AddOrUpdate(Context.Guild.Id, + GuildReactions.AddOrUpdate(Context.Guild.Id, new CustomReaction[] { cr }, (k, old) => { diff --git a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs index f2b6404c..78de87e6 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs @@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Gambling public partial class Gambling { [Group] - public class AnimalRacing : ModuleBase + public class AnimalRacing : NadekoSubmodule { public static ConcurrentDictionary AnimalRaces { get; } = new ConcurrentDictionary(); @@ -25,7 +25,7 @@ namespace NadekoBot.Modules.Gambling [RequireContext(ContextType.Guild)] public async Task Race() { - var ar = new AnimalRace(Context.Guild.Id, (ITextChannel)Context.Channel); + var ar = new AnimalRace(Context.Guild.Id, (ITextChannel)Context.Channel, Prefix); if (ar.Fail) await Context.Channel.SendErrorAsync("🏁 `Failed starting a race. Another race is probably running.`").ConfigureAwait(false); @@ -59,13 +59,16 @@ namespace NadekoBot.Modules.Gambling public List participants = new List(); private ulong serverId; private int messagesSinceGameStarted = 0; + private readonly string _prefix; + private Logger _log { get; } public ITextChannel raceChannel { get; set; } public bool Started { get; private set; } = false; - public AnimalRace(ulong serverId, ITextChannel ch) + public AnimalRace(ulong serverId, ITextChannel ch, string prefix) { + this._prefix = prefix; this._log = LogManager.GetCurrentClassLogger(); this.serverId = serverId; this.raceChannel = ch; @@ -74,11 +77,8 @@ namespace NadekoBot.Modules.Gambling Fail = true; return; } - - using (var uow = DbHandler.UnitOfWork()) - { - animals = new ConcurrentQueue(NadekoBot.BotConfig.RaceAnimals.Select(ra => ra.Icon).Shuffle()); - } + + animals = new ConcurrentQueue(NadekoBot.BotConfig.RaceAnimals.Select(ra => ra.Icon).Shuffle()); var cancelSource = new CancellationTokenSource(); @@ -91,7 +91,7 @@ namespace NadekoBot.Modules.Gambling try { await raceChannel.SendConfirmAsync("Animal Race", $"Starting in 20 seconds or when the room is full.", - footer: $"Type {NadekoBot.ModulePrefixes[typeof(Gambling).Name]}jr to join the race."); + footer: $"Type {_prefix}jr to join the race."); } catch (Exception ex) { @@ -280,9 +280,7 @@ namespace NadekoBot.Modules.Gambling public override bool Equals(object obj) { var p = obj as Participant; - return p == null ? - false : - p.User == User; + return p != null && p.User == User; } public override string ToString() diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs index 5647b3e4..02c8803e 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -43,22 +43,15 @@ namespace NadekoBot.Modules.Gambling [OwnerOnly] public async Task StartEvent(CurrencyEvent e, int arg = -1) { - var channel = (ITextChannel)Context.Channel; - try + switch (e) { - switch (e) - { - case CurrencyEvent.FlowerReaction: - await FlowerReactionEvent(Context).ConfigureAwait(false); - break; - case CurrencyEvent.SneakyGameStatus: - await SneakyGameStatusEvent(Context, arg).ConfigureAwait(false); - break; - default: - break; - } + case CurrencyEvent.FlowerReaction: + await FlowerReactionEvent(Context).ConfigureAwait(false); + break; + case CurrencyEvent.SneakyGameStatus: + await SneakyGameStatusEvent(Context, arg).ConfigureAwait(false); + break; } - catch { } } public static async Task SneakyGameStatusEvent(CommandContext Context, int? arg) @@ -77,8 +70,7 @@ namespace NadekoBot.Modules.Gambling { _secretCode += _sneakyGameStatusChars[rng.Next(0, _sneakyGameStatusChars.Length)]; } - - var game = NadekoBot.Client.Game?.Name; + await NadekoBot.Client.SetGameAsync($"type {_secretCode} for " + NadekoBot.BotConfig.CurrencyPluralName) .ConfigureAwait(false); try @@ -88,7 +80,10 @@ namespace NadekoBot.Modules.Gambling $"Lasts {num} seconds. Don't tell anyone. Shhh.") .ConfigureAwait(false); } - catch { } + catch + { + // ignored + } NadekoBot.Client.MessageReceived += SneakyGameMessageReceivedEventHandler; @@ -114,15 +109,18 @@ namespace NadekoBot.Modules.Gambling .ConfigureAwait(false); try { await arg.DeleteAsync(new RequestOptions() { RetryMode = RetryMode.AlwaysFail }).ConfigureAwait(false); } - catch { } + catch + { + // ignored + } }); } return Task.Delay(0); } - public static Task FlowerReactionEvent(CommandContext Context) => - new FlowerReactionEvent().Start(Context); + public static Task FlowerReactionEvent(CommandContext context) => + new FlowerReactionEvent().Start(context); } } @@ -163,7 +161,7 @@ namespace NadekoBot.Modules.Gambling if (msg?.Id == id) { _log.Warn("Stopping flower reaction event because message is deleted."); - Task.Run(() => End()); + var __ = Task.Run(End); } return Task.CompletedTask; @@ -194,10 +192,14 @@ namespace NadekoBot.Modules.Gambling { if (r.Emoji.Name == "🌸" && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _flowerReactionAwardedUsers.Add(r.User.Value.Id)) { - try { await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, false).ConfigureAwait(false); } catch { } + await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, false) + .ConfigureAwait(false); } } - catch { } + catch + { + // ignored + } })) { try diff --git a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs index 989d3789..bd977e9b 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs @@ -260,7 +260,7 @@ namespace NadekoBot.Modules.Gambling } finally { - var t = Task.Run(async () => + var _ = Task.Run(async () => { await Task.Delay(2000); runningUsers.Remove(Context.User.Id); diff --git a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs index 1d1f414f..1426bebd 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs @@ -197,8 +197,6 @@ namespace NadekoBot.Modules.Gambling [RequireContext(ContextType.Guild)] public async Task Divorce([Remainder]IUser target) { - var channel = (ITextChannel)Context.Channel; - if (target.Id == Context.User.Id) return; diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 555f55cb..6bcf5654 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -103,7 +103,6 @@ namespace NadekoBot.Modules.Gambling [Priority(0)] public async Task Award(int amount, [Remainder] IRole role) { - var channel = (ITextChannel)Context.Channel; var users = (await Context.Guild.GetUsersAsync()) .Where(u => u.GetRoles().Contains(role)) .ToList(); diff --git a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs index b6544256..0541a4ae 100644 --- a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs @@ -21,12 +21,6 @@ namespace NadekoBot.Modules.Games { private static Logger _log { get; } - class CleverAnswer - { - public string Status { get; set; } - public string Response { get; set; } - } - public static ConcurrentDictionary> CleverbotGuilds { get; } = new ConcurrentDictionary>(); static CleverBotCommands() @@ -34,14 +28,12 @@ namespace NadekoBot.Modules.Games _log = LogManager.GetCurrentClassLogger(); var sw = Stopwatch.StartNew(); - using (var uow = DbHandler.UnitOfWork()) - { - var bot = ChatterBotFactory.Create(ChatterBotType.CLEVERBOT); - CleverbotGuilds = new ConcurrentDictionary>( - NadekoBot.AllGuildConfigs - .Where(gc => gc.CleverbotEnabled) - .ToDictionary(gc => gc.GuildId, gc => new Lazy(() => bot.CreateSession(), true))); - } + + var bot = ChatterBotFactory.Create(ChatterBotType.CLEVERBOT); + CleverbotGuilds = new ConcurrentDictionary>( + NadekoBot.AllGuildConfigs + .Where(gc => gc.CleverbotEnabled) + .ToDictionary(gc => gc.GuildId, gc => new Lazy(() => bot.CreateSession(), true))); sw.Stop(); _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); diff --git a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs index 4d499301..83637a62 100644 --- a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs @@ -23,7 +23,8 @@ namespace NadekoBot.Modules.Games static HangmanCommands() { _log = LogManager.GetCurrentClassLogger(); - typesStr = $"`List of \"{NadekoBot.ModulePrefixes[typeof(Games).Name]}hangman\" term types:`\n" + String.Join(", ", HangmanTermPool.data.Keys); + typesStr = + string.Format("`List of \"{0}hangman\" term types:`\n", NadekoBot.ModulePrefixes[typeof(Games).Name]) + String.Join(", ", HangmanTermPool.data.Keys); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index f664a7f2..43cbf52f 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -29,7 +29,7 @@ namespace NadekoBot.Modules.Games /// https://discord.gg/0TYNJfCU4De7YIk8 /// [Group] - public class PlantPickCommands : ModuleBase + public class PlantPickCommands : NadekoSubmodule { private static ConcurrentHashSet generationChannels { get; } = new ConcurrentHashSet(); //channelid/message @@ -103,7 +103,8 @@ namespace NadekoBot.Modules.Games var sent = await channel.SendFileAsync( fileStream, file.Key, - $"❗ {firstPart} Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`") + string.Format("❗ {0} Pick it up by typing `{1}pick`", firstPart, + NadekoBot.ModulePrefixes[typeof(Games).Name])) .ConfigureAwait(false); msgs[0] = sent; @@ -160,7 +161,7 @@ namespace NadekoBot.Modules.Games var imgData = GetRandomCurrencyImage(); var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.BotConfig.CurrencyName[0]); - var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(amount == 1 ? (vowelFirst ? "an" : "a") : amount.ToString())} {(amount > 1 ? NadekoBot.BotConfig.CurrencyPluralName : NadekoBot.BotConfig.CurrencyName)}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick"; + var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(amount == 1 ? (vowelFirst ? "an" : "a") : amount.ToString())} {(amount > 1 ? NadekoBot.BotConfig.CurrencyPluralName : NadekoBot.BotConfig.CurrencyName)}. Pick it using {Prefix}pick"; IUserMessage msg; using (var toSend = imgData.Value.ToStream()) diff --git a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs index 4879793b..de36fe3b 100644 --- a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs +++ b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs @@ -307,7 +307,7 @@ namespace NadekoBot.Modules.Games var del2 = previousMessage?.DeleteAsync(); try { previousMessage = await _channel.EmbedAsync(GetEmbed(reason)); } catch { } try { await del1; } catch { } - try { await del2; } catch { } + try { if (del2 != null) await del2; } catch { } }); curUserIndex ^= 1; diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index e0dbb2c3..b10869b8 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -32,7 +32,6 @@ namespace NadekoBot.Modules.Games { if (string.IsNullOrWhiteSpace(question)) return; - var rng = new NadekoRandom(); await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) .AddField(efb => efb.WithName("❓ Question").WithValue(question).WithIsInline(false)) diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index bae06919..fa7012fd 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -415,27 +415,26 @@ namespace NadekoBot.Modules.Music var arg = directory; if (string.IsNullOrWhiteSpace(arg)) return; - try + var dir = new DirectoryInfo(arg); + var fileEnum = dir.GetFiles("*", SearchOption.AllDirectories) + .Where(x => !x.Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System)); + var gusr = (IGuildUser)Context.User; + foreach (var file in fileEnum) { - var dir = new DirectoryInfo(arg); - var fileEnum = dir.GetFiles("*", SearchOption.AllDirectories) - .Where(x => !x.Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System)); - var gusr = (IGuildUser)Context.User; - foreach (var file in fileEnum) + try { - try - { - await QueueSong(((IGuildUser)Context.User), (ITextChannel)Context.Channel, ((IGuildUser)Context.User).VoiceChannel, file.FullName, true, MusicType.Local).ConfigureAwait(false); - } - catch (PlaylistFullException) - { - break; - } - catch { } + await QueueSong(gusr, (ITextChannel)Context.Channel, gusr.VoiceChannel, file.FullName, true, MusicType.Local).ConfigureAwait(false); + } + catch (PlaylistFullException) + { + break; + } + catch + { + // ignored } - await Context.Channel.SendConfirmAsync("🎵 Directory queue complete.").ConfigureAwait(false); } - catch { } + await Context.Channel.SendConfirmAsync("🎵 Directory queue complete.").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs b/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs index fbb41acd..80b8067b 100644 --- a/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs +++ b/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs @@ -101,23 +101,23 @@ namespace NadekoBot.Modules.Permissions { return true; } - else + activeCdsForGuild.Add(new ActiveCooldown() { - activeCdsForGuild.Add(new ActiveCooldown() + UserId = user.Id, + Command = cmd.Aliases.First().ToLowerInvariant(), + }); + var _ = Task.Run(async () => + { + try { - UserId = user.Id, - Command = cmd.Aliases.First().ToLowerInvariant(), - }); - var t = Task.Run(async () => + await Task.Delay(cdRule.Seconds * 1000); + activeCdsForGuild.RemoveWhere(ac => ac.Command == cmd.Aliases.First().ToLowerInvariant() && ac.UserId == user.Id); + } + catch { - try - { - await Task.Delay(cdRule.Seconds * 1000); - activeCdsForGuild.RemoveWhere(ac => ac.Command == cmd.Aliases.First().ToLowerInvariant() && ac.UserId == user.Id); - } - catch { } - }); - } + // ignored + } + }); } return false; } diff --git a/src/NadekoBot/Modules/Permissions/Commands/FilterCommands.cs b/src/NadekoBot/Modules/Permissions/Commands/FilterCommands.cs index 2d0376e1..2576ac78 100644 --- a/src/NadekoBot/Modules/Permissions/Commands/FilterCommands.cs +++ b/src/NadekoBot/Modules/Permissions/Commands/FilterCommands.cs @@ -42,23 +42,19 @@ namespace NadekoBot.Modules.Permissions static FilterCommands() { - using (var uow = DbHandler.UnitOfWork()) - { - var guildConfigs = NadekoBot.AllGuildConfigs; + var guildConfigs = NadekoBot.AllGuildConfigs; - InviteFilteringServers = new ConcurrentHashSet(guildConfigs.Where(gc => gc.FilterInvites).Select(gc => gc.GuildId)); - InviteFilteringChannels = new ConcurrentHashSet(guildConfigs.SelectMany(gc => gc.FilterInvitesChannelIds.Select(fci => fci.ChannelId))); + InviteFilteringServers = new ConcurrentHashSet(guildConfigs.Where(gc => gc.FilterInvites).Select(gc => gc.GuildId)); + InviteFilteringChannels = new ConcurrentHashSet(guildConfigs.SelectMany(gc => gc.FilterInvitesChannelIds.Select(fci => fci.ChannelId))); - var dict = guildConfigs.ToDictionary(gc => gc.GuildId, gc => new ConcurrentHashSet(gc.FilteredWords.Select(fw => fw.Word))); + var dict = guildConfigs.ToDictionary(gc => gc.GuildId, gc => new ConcurrentHashSet(gc.FilteredWords.Select(fw => fw.Word))); - ServerFilteredWords = new ConcurrentDictionary>(dict); + ServerFilteredWords = new ConcurrentDictionary>(dict); - var serverFiltering = guildConfigs.Where(gc => gc.FilterWords); - WordFilteringServers = new ConcurrentHashSet(serverFiltering.Select(gc => gc.GuildId)); + var serverFiltering = guildConfigs.Where(gc => gc.FilterWords); + WordFilteringServers = new ConcurrentHashSet(serverFiltering.Select(gc => gc.GuildId)); - WordFilteringChannels = new ConcurrentHashSet(guildConfigs.SelectMany(gc => gc.FilterWordsChannelIds.Select(fwci => fwci.ChannelId))); - - } + WordFilteringChannels = new ConcurrentHashSet(guildConfigs.SelectMany(gc => gc.FilterWordsChannelIds.Select(fwci => fwci.ChannelId))); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs index c1d2eef9..bf05f0ac 100644 --- a/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs @@ -230,7 +230,7 @@ namespace NadekoBot.Modules.Searches var link = "http://anilist.co/api/anime/search/" + Uri.EscapeUriString(query); using (var http = new HttpClient()) { - var res = await http.GetStringAsync("http://anilist.co/api/anime/search/" + Uri.EscapeUriString(query) + $"?access_token={anilistToken}").ConfigureAwait(false); + var res = await http.GetStringAsync(link + $"?access_token={anilistToken}").ConfigureAwait(false); var smallObj = JArray.Parse(res)[0]; var aniData = await http.GetStringAsync("http://anilist.co/api/anime/" + smallObj["id"] + $"?access_token={anilistToken}").ConfigureAwait(false); diff --git a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs index e70381b2..77e88289 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs @@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Searches var rankimg = $"{model.Competitive.rank_img}"; var rank = $"{model.Competitive.rank}"; - var competitiveplay = $"{model.Games.Competitive.played}"; + //var competitiveplay = $"{model.Games.Competitive.played}"; if (string.IsNullOrWhiteSpace(rank)) { var embed = new EmbedBuilder() diff --git a/src/NadekoBot/Modules/Searches/Commands/PlaceCommands.cs b/src/NadekoBot/Modules/Searches/Commands/PlaceCommands.cs index af8a1fb3..bd22733b 100644 --- a/src/NadekoBot/Modules/Searches/Commands/PlaceCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/PlaceCommands.cs @@ -12,7 +12,8 @@ namespace NadekoBot.Modules.Searches [Group] public class PlaceCommands : ModuleBase { - private static string typesStr { get; } = $"`List of \"{NadekoBot.ModulePrefixes[typeof(Searches).Name]}place\" tags:`\n" + String.Join(", ", Enum.GetNames(typeof(PlaceType))); + private static string typesStr { get; } = + string.Format("`List of \"{0}place\" tags:`\n", NadekoBot.ModulePrefixes[typeof(Searches).Name]) + String.Join(", ", Enum.GetNames(typeof(PlaceType))); public enum PlaceType { diff --git a/src/NadekoBot/Modules/Searches/Commands/StreamNotificationCommands.cs b/src/NadekoBot/Modules/Searches/Commands/StreamNotificationCommands.cs index 3fc7a34b..86411634 100644 --- a/src/NadekoBot/Modules/Searches/Commands/StreamNotificationCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/StreamNotificationCommands.cs @@ -103,19 +103,23 @@ namespace NadekoBot.Modules.Searches oldStatus.IsLive != newStatus.IsLive) { var server = NadekoBot.Client.GetGuild(fs.GuildId); - if (server == null) - return; - var channel = server.GetTextChannel(fs.ChannelId); + var channel = server?.GetTextChannel(fs.ChannelId); if (channel == null) return; try { var msg = await channel.EmbedAsync(fs.GetEmbed(newStatus)).ConfigureAwait(false); } - catch { } + catch + { + // ignored + } } } - catch { } + catch + { + // ignored + } })); FirstPass = false; diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index d612299c..b250e57f 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -499,12 +499,12 @@ namespace NadekoBot.Modules.Searches var data = JsonConvert.DeserializeObject(res); - var sense = data.Results.Where(x => x.Senses != null && x.Senses[0].Definition != null).FirstOrDefault()?.Senses[0]; + var sense = data.Results.FirstOrDefault(x => x.Senses?[0].Definition != null)?.Senses[0]; if (sense?.Definition == null) return; - string definition = sense.Definition.ToString(); + var definition = sense.Definition.ToString(); if (!(sense.Definition is string)) definition = ((JArray)JToken.Parse(sense.Definition.ToString())).First.ToString(); @@ -536,7 +536,7 @@ namespace NadekoBot.Modules.Searches } await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); - string res = ""; + var res = ""; using (var http = new HttpClient()) { http.DefaultRequestHeaders.Clear(); @@ -548,7 +548,7 @@ namespace NadekoBot.Modules.Searches { var items = JObject.Parse(res); var item = items["defs"]["def"]; - var hashtag = item["hashtag"].ToString(); + //var hashtag = item["hashtag"].ToString(); var link = item["uri"].ToString(); var desc = item["text"].ToString(); await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() diff --git a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs index 8131bf16..0eedba24 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -32,7 +32,6 @@ namespace NadekoBot.Modules.Utility var voicechn = (await guild.GetVoiceChannelsAsync()).Count(); 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)) @@ -45,13 +44,13 @@ namespace NadekoBot.Modules.Utility .AddField(fb => fb.WithName("**Members**").WithValue(users.Count.ToString()).WithIsInline(true)) .AddField(fb => fb.WithName("**Text Channels**").WithValue(textchn.ToString()).WithIsInline(true)) .AddField(fb => fb.WithName("**Voice Channels**").WithValue(voicechn.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt: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) + if (guild.Emojis.Any()) { embed.AddField(fb => fb.WithName($"**Custom Emojis ({guild.Emojis.Count})**").WithValue(string.Join(" ", guild.Emojis.Shuffle().Take(25).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>")))); } @@ -71,7 +70,7 @@ namespace NadekoBot.Modules.Utility .WithTitle(ch.Name) .WithDescription(ch.Topic?.SanitizeMentions()) .AddField(fb => fb.WithName("**ID**").WithValue(ch.Id.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt:dd.MM.yyyy HH:mm}").WithIsInline(true)) .AddField(fb => fb.WithName("**Users**").WithValue(usercount.ToString()).WithIsInline(true)) .WithColor(NadekoBot.OkColor); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); @@ -81,7 +80,6 @@ namespace NadekoBot.Modules.Utility [RequireContext(ContextType.Guild)] public async Task UserInfo(IGuildUser usr = null) { - var channel = (ITextChannel)Context.Channel; var user = usr ?? Context.User as IGuildUser; if (user == null) @@ -95,7 +93,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") ?? "unavail."}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Joined Discord**").WithValue($"{user.CreatedAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true)) + .AddField(fb => fb.WithName("**Joined Discord**").WithValue($"{user.CreatedAt:dd.MM.yyyy HH:mm}").WithIsInline(true)) .AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count - 1})** - {string.Join("\n", user.GetRoles().Take(10).Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true)) .WithColor(NadekoBot.OkColor); diff --git a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs index 1167cab7..e767bbcf 100644 --- a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs @@ -91,7 +91,7 @@ namespace NadekoBot.Modules.Utility public void Reset() { source.Cancel(); - var t = Task.Run(Run); + var _ = Task.Run(Run); } public void Stop() diff --git a/src/NadekoBot/Modules/Utility/Commands/Remind.cs b/src/NadekoBot/Modules/Utility/Commands/Remind.cs index 94521dd6..10d43352 100644 --- a/src/NadekoBot/Modules/Utility/Commands/Remind.cs +++ b/src/NadekoBot/Modules/Utility/Commands/Remind.cs @@ -45,15 +45,15 @@ namespace NadekoBot.Modules.Utility foreach (var r in reminders) { - try { var t = StartReminder(r); } catch (Exception ex) { _log.Warn(ex); } + Task.Run(() => StartReminder(r)); } } private static async Task StartReminder(Reminder r) { var now = DateTime.Now; - var twoMins = new TimeSpan(0, 2, 0); - TimeSpan time = r.When - now; + + var time = r.When - now; if (time.TotalMilliseconds > int.MaxValue) return; diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 1705d934..d627d956 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -468,7 +468,6 @@ namespace NadekoBot.Modules.Utility [OwnerOnly] public async Task SaveChat(int cnt) { - var sb = new StringBuilder(); var msgs = new List(cnt); await Context.Channel.GetMessagesAsync(cnt).ForEachAsync(dled => msgs.AddRange(dled)).ConfigureAwait(false); diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index 102c6703..4efb6150 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -132,7 +132,7 @@ namespace NadekoBot.Services.Database { #region QUOTES - var quoteEntity = modelBuilder.Entity(); + //var quoteEntity = modelBuilder.Entity(); #endregion @@ -166,7 +166,7 @@ namespace NadekoBot.Services.Database #endregion #region BotConfig - var botConfigEntity = modelBuilder.Entity(); + //var botConfigEntity = modelBuilder.Entity(); //botConfigEntity // .HasMany(c => c.ModulePrefixes) // .WithOne(mp => mp.BotConfig) diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index d8995c59..7c6d2201 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -96,18 +96,21 @@ namespace NadekoBot.Services.Impl content.Headers.Clear(); content.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); - var res = await http.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false); + await http.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false); } }; } - catch { } + catch + { + // ignored + } }, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1)); } public void Initialize() { - var guilds = this.client.GetGuilds(); - _textChannels = guilds.Sum(g => g.Channels.Where(cx => cx is ITextChannel).Count()); + var guilds = this.client.GetGuilds().ToArray(); + _textChannels = guilds.Sum(g => g.Channels.Count(cx => cx is ITextChannel)); _voiceChannels = guilds.Sum(g => g.Channels.Count) - _textChannels; } diff --git a/src/NadekoBot/Services/NadekoRandom.cs b/src/NadekoBot/Services/NadekoRandom.cs index 0d42c065..f1af50c1 100644 --- a/src/NadekoBot/Services/NadekoRandom.cs +++ b/src/NadekoBot/Services/NadekoRandom.cs @@ -41,7 +41,6 @@ namespace NadekoBot.Services return minValue; var bytes = new byte[sizeof(int)]; rng.GetBytes(bytes); - var num = BitConverter.ToInt32(bytes, 0); var sign = Math.Sign(BitConverter.ToInt32(bytes, 0)); return (sign * BitConverter.ToInt32(bytes, 0)) % (maxValue - minValue) + minValue; } From b6d93c3105fe47314ed2a3197ed8d4ff8865ee23 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 14:49:21 +0100 Subject: [PATCH 242/746] Bot connecting speed improved by exactly 5 seconds. --- .../Modules/Administration/Commands/ServerGreetCommands.cs | 2 +- .../Modules/Games/Commands/PlantAndPickCommands.cs | 7 +------ src/NadekoBot/NadekoBot.cs | 6 +++++- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs index 7c58fbfd..b3f79c83 100644 --- a/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs @@ -53,7 +53,7 @@ namespace NadekoBot.Modules.Administration }; } - private static Logger _log { get; } + private new static Logger _log { get; } private static ConcurrentDictionary GuildConfigsCache { get; } = new ConcurrentDictionary(); diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 43cbf52f..ba98f5f1 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -37,13 +37,8 @@ namespace NadekoBot.Modules.Games //channelId/last generation private static ConcurrentDictionary lastGenerations { get; } = new ConcurrentDictionary(); - private static ConcurrentHashSet usersRecentlyPicked { get; } = new ConcurrentHashSet(); - - private static Logger _log { get; } - static PlantPickCommands() { - _log = LogManager.GetCurrentClassLogger(); #if !GLOBAL_NADEKO NadekoBot.Client.MessageReceived += PotentialFlowerGeneration; @@ -116,7 +111,7 @@ namespace NadekoBot.Modules.Games } catch (Exception ex) { - _log.Warn(ex); + LogManager.GetCurrentClassLogger().Warn(ex); } }); return Task.CompletedTask; diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 5df52a6e..21752102 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -14,6 +14,7 @@ using System.Collections.Generic; using NadekoBot.Modules.Permissions; using NadekoBot.TypeReaders; using System.Collections.Concurrent; +using System.Diagnostics; using NadekoBot.Modules.Music; using NadekoBot.Services.Database.Models; using System.Resources; @@ -108,13 +109,16 @@ namespace NadekoBot CommandService.AddTypeReader(new ModuleTypeReader()); CommandService.AddTypeReader(new GuildTypeReader()); + + var sw = Stopwatch.StartNew(); //connect await Client.LoginAsync(TokenType.Bot, Credentials.Token).ConfigureAwait(false); await Client.ConnectAsync().ConfigureAwait(false); //await Client.DownloadAllUsersAsync().ConfigureAwait(false); Stats.Initialize(); - _log.Info("Connected"); + sw.Stop(); + _log.Info("Connected in " + sw.Elapsed.TotalSeconds.ToString("F2")); //load commands and prefixes From e5d85dd81867bea149b12dcb839b8e038a43fc2a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 15:41:23 +0100 Subject: [PATCH 243/746] All administration submodules now inherit NadekoSubmodule, and woops, forgot to commit discord.net connection change --- Discord.Net | 2 +- .../Commands/AutoAssignRoleCommands.cs | 2 +- .../Commands/DMForwardCommands.cs | 5 +--- .../Commands/LocalizationCommands.cs | 2 +- .../Administration/Commands/LogCommand.cs | 2 +- .../Administration/Commands/Migration.cs | 2 +- .../Administration/Commands/MuteCommands.cs | 7 ++--- .../Commands/PlayingRotateCommands.cs | 2 +- .../Commands/ProtectionCommands.cs | 30 +++++++++---------- .../Commands/RatelimitCommand.cs | 2 +- .../Commands/SelfAssignedRolesCommand.cs | 2 +- .../Administration/Commands/SelfCommands.cs | 2 +- .../Commands/VoicePlusTextCommands.cs | 28 ++++++++--------- 13 files changed, 42 insertions(+), 46 deletions(-) diff --git a/Discord.Net b/Discord.Net index 9ce5c475..d2229228 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit 9ce5c4757efc6cb6bb8959e851abcdcbe03217be +Subproject commit d2229228b92117899d65cd549a1f2853057b255b diff --git a/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs b/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs index 01c19fa8..3ebddf9d 100644 --- a/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs @@ -16,7 +16,7 @@ namespace NadekoBot.Modules.Administration public partial class Administration { [Group] - public class AutoAssignRoleCommands : ModuleBase + public class AutoAssignRoleCommands : NadekoSubmodule { private static Logger _log { get; } //guildid/roleid diff --git a/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs b/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs index fe4a328b..9a9c4129 100644 --- a/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs @@ -15,16 +15,13 @@ namespace NadekoBot.Modules.Administration public partial class Administration { [Group] - public class DMForwardCommands : ModuleBase + public class DMForwardCommands : NadekoSubmodule { private static bool ForwardDMs { get; set; } private static bool ForwardDMsToAllOwners { get; set; } - - private static readonly Logger _log; static DMForwardCommands() { - _log = LogManager.GetCurrentClassLogger(); using (var uow = DbHandler.UnitOfWork()) { diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 684eebf9..70fcd6c6 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -15,7 +15,7 @@ namespace NadekoBot.Modules.Administration public partial class Administration { [Group] - public class LocalizationCommands : ModuleBase + public class LocalizationCommands : NadekoSubmodule { private ImmutableDictionary SupportedLocales { get; } = new Dictionary() { diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index c5183692..8c63191d 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -21,7 +21,7 @@ namespace NadekoBot.Modules.Administration public partial class Administration { [Group] - public class LogCommands : ModuleBase + public class LogCommands : NadekoSubmodule { private const string clockEmojiUrl = "https://cdn.discordapp.com/attachments/155726317222887425/258309524966866945/clock.png"; diff --git a/src/NadekoBot/Modules/Administration/Commands/Migration.cs b/src/NadekoBot/Modules/Administration/Commands/Migration.cs index 883e5d4b..42798128 100644 --- a/src/NadekoBot/Modules/Administration/Commands/Migration.cs +++ b/src/NadekoBot/Modules/Administration/Commands/Migration.cs @@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Administration public partial class Administration { [Group] - public class Migration : ModuleBase + public class Migration : NadekoSubmodule { private const int CURRENT_VERSION = 1; diff --git a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs index 89ef6ec6..362e4960 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs @@ -18,7 +18,7 @@ namespace NadekoBot.Modules.Administration public partial class Administration { [Group] - public class MuteCommands : ModuleBase + public class MuteCommands : NadekoSubmodule { private static ConcurrentDictionary GuildMuteRoles { get; } = new ConcurrentDictionary(); @@ -58,12 +58,11 @@ namespace NadekoBot.Modules.Administration if (muted == null || !muted.Contains(usr.Id)) return; - else - await MuteUser(usr).ConfigureAwait(false); + await MuteUser(usr).ConfigureAwait(false); } catch (Exception ex) { - _log.Warn(ex); + LogManager.GetCurrentClassLogger().Warn(ex); } } diff --git a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs index 371a6d6b..5b06c944 100644 --- a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs @@ -18,7 +18,7 @@ namespace NadekoBot.Modules.Administration public partial class Administration { [Group] - public class PlayingRotateCommands : ModuleBase + public class PlayingRotateCommands : NadekoSubmodule { private static Logger _log { get; } public static List RotatingStatusMessages { get; } diff --git a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs index ff671a98..ed85c42d 100644 --- a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs @@ -76,12 +76,12 @@ namespace NadekoBot.Modules.Administration } [Group] - public class ProtectionCommands : ModuleBase + public class ProtectionCommands : NadekoSubmodule { - private static ConcurrentDictionary antiRaidGuilds = + private static readonly ConcurrentDictionary _antiRaidGuilds = new ConcurrentDictionary(); // guildId | (userId|messages) - private static ConcurrentDictionary antiSpamGuilds = + private static readonly ConcurrentDictionary _antiSpamGuilds = new ConcurrentDictionary(); private static Logger _log { get; } @@ -98,11 +98,11 @@ namespace NadekoBot.Modules.Administration if (raid != null) { var raidStats = new AntiRaidStats() { AntiRaidSettings = raid }; - antiRaidGuilds.TryAdd(gc.GuildId, raidStats); + _antiRaidGuilds.TryAdd(gc.GuildId, raidStats); } if (spam != null) - antiSpamGuilds.TryAdd(gc.GuildId, new AntiSpamStats() { AntiSpamSettings = spam }); + _antiSpamGuilds.TryAdd(gc.GuildId, new AntiSpamStats() { AntiSpamSettings = spam }); } NadekoBot.Client.MessageReceived += (imsg) => @@ -119,7 +119,7 @@ namespace NadekoBot.Modules.Administration try { AntiSpamStats spamSettings; - if (!antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings) || + if (!_antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings) || spamSettings.AntiSpamSettings.IgnoredChannels.Contains(new AntiSpamIgnore() { ChannelId = channel.Id @@ -151,7 +151,7 @@ namespace NadekoBot.Modules.Administration if (usr.IsBot) return Task.CompletedTask; AntiRaidStats settings; - if (!antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings)) + if (!_antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings)) return Task.CompletedTask; if (!settings.RaidUsers.Add(usr)) return Task.CompletedTask; @@ -245,7 +245,7 @@ namespace NadekoBot.Modules.Administration } AntiRaidStats throwaway; - if (antiRaidGuilds.TryRemove(Context.Guild.Id, out throwaway)) + if (_antiRaidGuilds.TryRemove(Context.Guild.Id, out throwaway)) { using (var uow = DbHandler.UnitOfWork()) { @@ -281,7 +281,7 @@ namespace NadekoBot.Modules.Administration } }; - antiRaidGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats); + _antiRaidGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats); using (var uow = DbHandler.UnitOfWork()) { @@ -304,7 +304,7 @@ namespace NadekoBot.Modules.Administration return; AntiSpamStats throwaway; - if (antiSpamGuilds.TryRemove(Context.Guild.Id, out throwaway)) + if (_antiSpamGuilds.TryRemove(Context.Guild.Id, out throwaway)) { using (var uow = DbHandler.UnitOfWork()) { @@ -340,7 +340,7 @@ namespace NadekoBot.Modules.Administration } }; - antiSpamGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats); + _antiSpamGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats); using (var uow = DbHandler.UnitOfWork()) { @@ -376,7 +376,7 @@ namespace NadekoBot.Modules.Administration if (spam.IgnoredChannels.Add(obj)) { AntiSpamStats temp; - if (antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp)) + if (_antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp)) temp.AntiSpamSettings.IgnoredChannels.Add(obj); added = true; } @@ -384,7 +384,7 @@ namespace NadekoBot.Modules.Administration { spam.IgnoredChannels.Remove(obj); AntiSpamStats temp; - if (antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp)) + if (_antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp)) temp.AntiSpamSettings.IgnoredChannels.Remove(obj); added = false; } @@ -403,10 +403,10 @@ namespace NadekoBot.Modules.Administration public async Task AntiList() { AntiSpamStats spam; - antiSpamGuilds.TryGetValue(Context.Guild.Id, out spam); + _antiSpamGuilds.TryGetValue(Context.Guild.Id, out spam); AntiRaidStats raid; - antiRaidGuilds.TryGetValue(Context.Guild.Id, out raid); + _antiRaidGuilds.TryGetValue(Context.Guild.Id, out raid); if (spam == null && raid == null) { diff --git a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs index 8ed81849..5ece6c1d 100644 --- a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs @@ -13,7 +13,7 @@ namespace NadekoBot.Modules.Administration public partial class Administration { [Group] - public class RatelimitCommand : ModuleBase + public class RatelimitCommand : NadekoSubmodule { public static ConcurrentDictionary RatelimitingChannels = new ConcurrentDictionary(); private static Logger _log { get; } diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs b/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs index 1775e85e..73327f87 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs @@ -16,7 +16,7 @@ namespace NadekoBot.Modules.Administration public partial class Administration { [Group] - public class SelfAssignedRolesCommands : ModuleBase + public class SelfAssignedRolesCommands : NadekoSubmodule { [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index fb316beb..3361eff4 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -14,7 +14,7 @@ namespace NadekoBot.Modules.Administration public partial class Administration { [Group] - class SelfCommands : ModuleBase + public class SelfCommands : NadekoSubmodule { [NadekoCommand, Usage, Description, Aliases] [OwnerOnly] diff --git a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs index dba5bb3a..2a4c3152 100644 --- a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs @@ -19,19 +19,20 @@ namespace NadekoBot.Modules.Administration public partial class Administration { [Group] - public class VoicePlusTextCommands : ModuleBase + public class VoicePlusTextCommands : NadekoSubmodule { - private static Regex channelNameRegex = new Regex(@"[^a-zA-Z0-9 -]", RegexOptions.Compiled); + private new static readonly Logger _log; - private static ConcurrentHashSet voicePlusTextCache { get; } + private static readonly Regex _channelNameRegex = new Regex(@"[^a-zA-Z0-9 -]", RegexOptions.Compiled); - private static ConcurrentDictionary guildLockObjects = new ConcurrentDictionary(); + private static readonly ConcurrentHashSet _voicePlusTextCache; + private static readonly ConcurrentDictionary _guildLockObjects = new ConcurrentDictionary(); static VoicePlusTextCommands() { - var _log = LogManager.GetCurrentClassLogger(); + _log = LogManager.GetCurrentClassLogger(); var sw = Stopwatch.StartNew(); - voicePlusTextCache = new ConcurrentHashSet(NadekoBot.AllGuildConfigs.Where(g => g.VoicePlusTextEnabled).Select(g => g.GuildId)); + _voicePlusTextCache = new ConcurrentHashSet(NadekoBot.AllGuildConfigs.Where(g => g.VoicePlusTextEnabled).Select(g => g.GuildId)); NadekoBot.Client.UserVoiceStateUpdated += UserUpdatedEventHandler; sw.Stop(); @@ -51,7 +52,7 @@ namespace NadekoBot.Modules.Administration if (before.VoiceChannel == after.VoiceChannel) return Task.CompletedTask; - if (!voicePlusTextCache.Contains(guild.Id)) + if (!_voicePlusTextCache.Contains(guild.Id)) return Task.CompletedTask; var _ = Task.Run(async () => @@ -71,13 +72,13 @@ namespace NadekoBot.Modules.Administration using (var uow = DbHandler.UnitOfWork()) { uow.GuildConfigs.For(guild.Id, set => set).VoicePlusTextEnabled = false; - voicePlusTextCache.TryRemove(guild.Id); + _voicePlusTextCache.TryRemove(guild.Id); await uow.CompleteAsync().ConfigureAwait(false); } return; } - var semaphore = guildLockObjects.GetOrAdd(guild.Id, (key) => new SemaphoreSlim(1, 1)); + var semaphore = _guildLockObjects.GetOrAdd(guild.Id, (key) => new SemaphoreSlim(1, 1)); try { @@ -109,8 +110,7 @@ namespace NadekoBot.Modules.Administration roleToAdd = await guild.CreateRoleAsync(roleName, GuildPermissions.None).ConfigureAwait(false); ITextChannel textChannel = guild.TextChannels - .Where(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant()) - .FirstOrDefault(); + .FirstOrDefault(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant()); if (textChannel == null) { var created = (await guild.CreateTextChannelAsync(GetChannelName(afterVch.Name).ToLowerInvariant()).ConfigureAwait(false)); @@ -146,7 +146,7 @@ namespace NadekoBot.Modules.Administration } private static string GetChannelName(string voiceName) => - channelNameRegex.Replace(voiceName, "").Trim().Replace(" ", "-").TrimTo(90, true) + "-voice"; + _channelNameRegex.Replace(voiceName, "").Trim().Replace(" ", "-").TrimTo(90, true) + "-voice"; private static string GetRoleName(IVoiceChannel ch) => "nvoice-" + ch.Id; @@ -186,7 +186,7 @@ namespace NadekoBot.Modules.Administration } if (!isEnabled) { - voicePlusTextCache.TryRemove(guild.Id); + _voicePlusTextCache.TryRemove(guild.Id); foreach (var textChannel in (await guild.GetTextChannelsAsync().ConfigureAwait(false)).Where(c => c.Name.EndsWith("-voice"))) { try { await textChannel.DeleteAsync().ConfigureAwait(false); } catch { } @@ -201,7 +201,7 @@ namespace NadekoBot.Modules.Administration await Context.Channel.SendConfirmAsync("ℹ️ Successfuly **removed** voice + text feature.").ConfigureAwait(false); return; } - voicePlusTextCache.Add(guild.Id); + _voicePlusTextCache.Add(guild.Id); await Context.Channel.SendConfirmAsync("🆗 Successfuly **enabled** voice + text feature.").ConfigureAwait(false); } From f9c989692616ad1911f8a002b65fd53b2f18d1c2 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 15:53:51 +0100 Subject: [PATCH 244/746] clean MuteCommands.cs --- .../Modules/Administration/Administration.cs | 16 ++++------ .../Administration/Commands/MuteCommands.cs | 29 +++++++++---------- src/NadekoBot/NadekoBot.cs | 5 ++-- src/NadekoBot/NadekoBot.xproj.DotSettings | 2 ++ 4 files changed, 24 insertions(+), 28 deletions(-) create mode 100644 src/NadekoBot/NadekoBot.xproj.DotSettings diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 76b96ec4..21dceacc 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -22,9 +22,6 @@ namespace NadekoBot.Modules.Administration [NadekoModule("Administration", ".")] public partial class Administration : NadekoModule { - - private static ConcurrentDictionary GuildMuteRoles { get; } = new ConcurrentDictionary(); - private static ConcurrentHashSet DeleteMessagesOnCommand { get; } = new ConcurrentHashSet(); private new static Logger _log { get; } @@ -206,7 +203,7 @@ namespace NadekoBot.Modules.Administration return; } var roleName = args[0].ToUpperInvariant(); - var role = Context.Guild.Roles.Where(r => r.Name.ToUpperInvariant() == roleName).FirstOrDefault(); + var role = Context.Guild.Roles.FirstOrDefault(r => r.Name.ToUpperInvariant() == roleName); if (role == null) { @@ -513,7 +510,7 @@ namespace NadekoBot.Modules.Administration await Context.Channel.SendMessageAsync(send).ConfigureAwait(false); } - IGuild nadekoSupportServer; + IGuild _nadekoSupportServer; [NadekoCommand, Usage, Description, Aliases] public async Task Donators() { @@ -525,16 +522,13 @@ namespace NadekoBot.Modules.Administration } await Context.Channel.SendConfirmAsync("Thanks to the people listed below for making this project happen!", string.Join("⭐", donatorsOrdered.Select(d => d.Name))).ConfigureAwait(false); - nadekoSupportServer = nadekoSupportServer ?? NadekoBot.Client.GetGuild(117523346618318850); + _nadekoSupportServer = _nadekoSupportServer ?? NadekoBot.Client.GetGuild(117523346618318850); - if (nadekoSupportServer == null) - return; - - var patreonRole = nadekoSupportServer.GetRole(236667642088259585); + var patreonRole = _nadekoSupportServer?.GetRole(236667642088259585); if (patreonRole == null) return; - var usrs = (await nadekoSupportServer.GetUsersAsync()).Where(u => u.RoleIds.Contains(236667642088259585u)); + var usrs = (await _nadekoSupportServer.GetUsersAsync()).Where(u => u.RoleIds.Contains(236667642088259585u)); await Context.Channel.SendConfirmAsync("Patreon supporters", string.Join("⭐", usrs.Select(d => d.Username))).ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs index 362e4960..8dac31eb 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs @@ -8,8 +8,6 @@ using NadekoBot.Services.Database.Models; using NLog; using System; using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Threading.Tasks; @@ -20,9 +18,8 @@ namespace NadekoBot.Modules.Administration [Group] public class MuteCommands : NadekoSubmodule { - private static ConcurrentDictionary GuildMuteRoles { get; } = new ConcurrentDictionary(); - - private static ConcurrentDictionary> MutedUsers { get; } = new ConcurrentDictionary>(); + private static ConcurrentDictionary guildMuteRoles { get; } + private static ConcurrentDictionary> mutedUsers { get; } public static event Action UserMuted = delegate { }; public static event Action UserUnmuted = delegate { }; @@ -37,11 +34,11 @@ namespace NadekoBot.Modules.Administration static MuteCommands() { var configs = NadekoBot.AllGuildConfigs; - GuildMuteRoles = new ConcurrentDictionary(configs + guildMuteRoles = new ConcurrentDictionary(configs .Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName)) .ToDictionary(c => c.GuildId, c => c.MuteRoleName)); - MutedUsers = new ConcurrentDictionary>(configs.ToDictionary( + mutedUsers = new ConcurrentDictionary>(configs.ToDictionary( k => k.GuildId, v => new ConcurrentHashSet(v.MutedUsers.Select(m => m.UserId)) )); @@ -54,7 +51,7 @@ namespace NadekoBot.Modules.Administration try { ConcurrentHashSet muted; - MutedUsers.TryGetValue(usr.Guild.Id, out muted); + mutedUsers.TryGetValue(usr.Guild.Id, out muted); if (muted == null || !muted.Contains(usr.Id)) return; @@ -79,7 +76,7 @@ namespace NadekoBot.Modules.Administration UserId = usr.Id }); ConcurrentHashSet muted; - if (MutedUsers.TryGetValue(usr.Guild.Id, out muted)) + if (mutedUsers.TryGetValue(usr.Guild.Id, out muted)) muted.Add(usr.Id); await uow.CompleteAsync().ConfigureAwait(false); @@ -99,18 +96,18 @@ namespace NadekoBot.Modules.Administration UserId = usr.Id }); ConcurrentHashSet muted; - if (MutedUsers.TryGetValue(usr.Guild.Id, out muted)) + if (mutedUsers.TryGetValue(usr.Guild.Id, out muted)) muted.TryRemove(usr.Id); await uow.CompleteAsync().ConfigureAwait(false); } UserUnmuted(usr, MuteType.All); } - public static async Task GetMuteRole(IGuild guild) + public static async TaskGetMuteRole(IGuild guild) { const string defaultMuteRoleName = "nadeko-mute"; - var muteRoleName = GuildMuteRoles.GetOrAdd(guild.Id, defaultMuteRoleName); + var muteRoleName = guildMuteRoles.GetOrAdd(guild.Id, defaultMuteRoleName); var muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName); if (muteRole == null) @@ -132,7 +129,10 @@ namespace NadekoBot.Modules.Administration await toOverwrite.AddPermissionOverwriteAsync(muteRole, new OverwritePermissions(sendMessages: PermValue.Deny, attachFiles: PermValue.Deny)) .ConfigureAwait(false); } - catch { } + catch + { + // ignored + } await Task.Delay(200).ConfigureAwait(false); } } @@ -145,7 +145,6 @@ namespace NadekoBot.Modules.Administration [Priority(1)] public async Task SetMuteRole([Remainder] string name) { - //var channel = (ITextChannel)Context.Channel; name = name.Trim(); if (string.IsNullOrWhiteSpace(name)) return; @@ -154,7 +153,7 @@ namespace NadekoBot.Modules.Administration { var config = uow.GuildConfigs.For(Context.Guild.Id, set => set); config.MuteRoleName = name; - GuildMuteRoles.AddOrUpdate(Context.Guild.Id, name, (id, old) => name); + guildMuteRoles.AddOrUpdate(Context.Guild.Id, name, (id, old) => name); await uow.CompleteAsync().ConfigureAwait(false); } await Context.Channel.SendConfirmAsync("☑️ **New mute role set.**").ConfigureAwait(false); diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 21752102..40d71602 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -14,6 +14,7 @@ using System.Collections.Generic; using NadekoBot.Modules.Permissions; using NadekoBot.TypeReaders; using System.Collections.Concurrent; +using System.Collections.Immutable; using System.Diagnostics; using NadekoBot.Modules.Music; using NadekoBot.Services.Database.Models; @@ -44,7 +45,7 @@ namespace NadekoBot public static ConcurrentDictionary ModulePrefixes { get; private set; } public static bool Ready { get; private set; } - public static IEnumerable AllGuildConfigs { get; } + public static ImmutableArray AllGuildConfigs { get; } public static BotConfig BotConfig { get; } static NadekoBot() @@ -54,7 +55,7 @@ namespace NadekoBot using (var uow = DbHandler.UnitOfWork()) { - AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(); + AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs().ToImmutableArray(); 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/NadekoBot.xproj.DotSettings b/src/NadekoBot/NadekoBot.xproj.DotSettings new file mode 100644 index 00000000..ae4d5dac --- /dev/null +++ b/src/NadekoBot/NadekoBot.xproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file From 8c27082c14017eff04a6b07274eb42943cb40d58 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 16:36:02 +0100 Subject: [PATCH 245/746] localized mute commands --- .../Administration/Commands/MuteCommands.cs | 28 ++++---- .../Resources/ResponseStrings.Designer.cs | 72 +++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 24 +++++++ 3 files changed, 110 insertions(+), 14 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs index 8dac31eb..5f67b3dd 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs @@ -156,7 +156,7 @@ namespace NadekoBot.Modules.Administration guildMuteRoles.AddOrUpdate(Context.Guild.Id, name, (id, old) => name); await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync("☑️ **New mute role set.**").ConfigureAwait(false); + await ReplyConfirmLocalized("mute_role_set").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -174,12 +174,12 @@ namespace NadekoBot.Modules.Administration { try { - await MuteUser(user).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"🔇 **{user}** has been **muted** from text and voice chat.").ConfigureAwait(false); + await MuteUser(user).ConfigureAwait(false); + await ReplyConfirmLocalized("user_muted", Format.Bold(user.ToString())).ConfigureAwait(false); } catch { - await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false); + await ReplyErrorLocalized("mute_error").ConfigureAwait(false); } } @@ -192,11 +192,11 @@ namespace NadekoBot.Modules.Administration try { await UnmuteUser(user).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"🔉 **{user}** has been **unmuted** from text and voice chat.").ConfigureAwait(false); + await ReplyConfirmLocalized("user_unmuted", Format.Bold(user.ToString())).ConfigureAwait(false); } catch { - await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false); + await ReplyErrorLocalized("mute_error").ConfigureAwait(false); } } @@ -209,11 +209,11 @@ namespace NadekoBot.Modules.Administration { await user.AddRolesAsync(await GetMuteRole(Context.Guild).ConfigureAwait(false)).ConfigureAwait(false); UserMuted(user, MuteType.Chat); - await Context.Channel.SendConfirmAsync($"✏️🚫 **{user}** has been **muted** from chatting.").ConfigureAwait(false); + await ReplyConfirmLocalized("user_chat_mute", Format.Bold(user.ToString())).ConfigureAwait(false); } catch { - await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false); + await ReplyErrorLocalized("mute_error").ConfigureAwait(false); } } @@ -226,11 +226,11 @@ namespace NadekoBot.Modules.Administration { await user.RemoveRolesAsync(await GetMuteRole(Context.Guild).ConfigureAwait(false)).ConfigureAwait(false); UserUnmuted(user, MuteType.Chat); - await Context.Channel.SendConfirmAsync($"✏️✅ **{user}** has been **unmuted** from chatting.").ConfigureAwait(false); + await ReplyConfirmLocalized("user_chat_unmute", Format.Bold(user.ToString())).ConfigureAwait(false); } catch { - await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false); + await ReplyErrorLocalized("mute_error").ConfigureAwait(false); } } @@ -243,11 +243,11 @@ namespace NadekoBot.Modules.Administration { await user.ModifyAsync(usr => usr.Mute = true).ConfigureAwait(false); UserMuted(user, MuteType.Voice); - await Context.Channel.SendConfirmAsync($"🎙🚫 **{user}** has been **voice muted**.").ConfigureAwait(false); + await ReplyConfirmLocalized("user_voice_mute", Format.Bold(user.ToString())).ConfigureAwait(false); } catch { - await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false); + await ReplyErrorLocalized("mute_error").ConfigureAwait(false); } } @@ -260,11 +260,11 @@ namespace NadekoBot.Modules.Administration { await user.ModifyAsync(usr => usr.Mute = false).ConfigureAwait(false); UserUnmuted(user, MuteType.Voice); - await Context.Channel.SendConfirmAsync($"🎙✅ **{user}** has been **voice unmuted**.").ConfigureAwait(false); + await ReplyConfirmLocalized("user_voice_unmute", Format.Bold(user.ToString())).ConfigureAwait(false); } catch { - await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false); + await ReplyErrorLocalized("mute_error").ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 975e2331..493016ee 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -59,6 +59,78 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to I don't have the permission necessary for that most likely.. + /// + public static string administration_mute_error { + get { + return ResourceManager.GetString("administration_mute_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New mute role set.. + /// + public static string administration_mute_role_set { + get { + return ResourceManager.GetString("administration_mute_role_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has been **muted** from chatting.. + /// + public static string administration_user_chat_mute { + get { + return ResourceManager.GetString("administration_user_chat_mute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has been **unmuted** from chatting.. + /// + public static string administration_user_chat_unmute { + get { + return ResourceManager.GetString("administration_user_chat_unmute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has been **muted** from text and voice chat.. + /// + public static string administration_user_muted { + get { + return ResourceManager.GetString("administration_user_muted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has been **unmuted** from text and voice chat.. + /// + public static string administration_user_unmuted { + get { + return ResourceManager.GetString("administration_user_unmuted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has been **voice muted**.. + /// + public static string administration_user_voice_mute { + get { + return ResourceManager.GetString("administration_user_voice_mute", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has been **voice unmuted**.. + /// + public static string administration_user_voice_unmute { + get { + return ResourceManager.GetString("administration_user_voice_unmute", resourceCulture); + } + } + /// /// Looks up a localized string similar to That base is already claimed or destroyed.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 5285f3b6..480a91f0 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -298,6 +298,30 @@ You fainted, so you are not able to move! + + I don't have the permission necessary for that most likely. + + + New mute role set. + + + {0} has been **muted** from chatting. + + + {0} has been **unmuted** from chatting. + + + {0} has been **muted** from text and voice chat. + + + {0} has been **unmuted** from text and voice chat. + + + {0} has been **voice muted**. + + + {0} has been **voice unmuted**. + Back to ToC From 45fb8b925d6d9d695af1421d11e7330d4294bd41 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 16:55:59 +0100 Subject: [PATCH 246/746] .aar cleaned up, localized --- .../Commands/AutoAssignRoleCommands.cs | 27 ++++++++----------- .../Resources/ResponseStrings.Designer.cs | 18 +++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 6 +++++ 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs b/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs index 3ebddf9d..98a8844f 100644 --- a/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs @@ -1,13 +1,10 @@ using Discord; using Discord.Commands; using NadekoBot.Attributes; -using NadekoBot.Extensions; using NadekoBot.Services; -using NadekoBot.Services.Database.Models; using NLog; using System; using System.Collections.Concurrent; -using System.Diagnostics; using System.Linq; using System.Threading.Tasks; @@ -18,22 +15,21 @@ namespace NadekoBot.Modules.Administration [Group] public class AutoAssignRoleCommands : NadekoSubmodule { - private static Logger _log { get; } //guildid/roleid - private static ConcurrentDictionary AutoAssignedRoles { get; } + private static ConcurrentDictionary autoAssignedRoles { get; } static AutoAssignRoleCommands() { - _log = LogManager.GetCurrentClassLogger(); + var log = LogManager.GetCurrentClassLogger(); - AutoAssignedRoles = new ConcurrentDictionary(NadekoBot.AllGuildConfigs.Where(x => x.AutoAssignRoleId != 0) + autoAssignedRoles = new ConcurrentDictionary(NadekoBot.AllGuildConfigs.Where(x => x.AutoAssignRoleId != 0) .ToDictionary(k => k.GuildId, v => v.AutoAssignRoleId)); NadekoBot.Client.UserJoined += async (user) => { try { - ulong roleId = 0; - AutoAssignedRoles.TryGetValue(user.Guild.Id, out roleId); + ulong roleId; + autoAssignedRoles.TryGetValue(user.Guild.Id, out roleId); if (roleId == 0) return; @@ -43,7 +39,7 @@ namespace NadekoBot.Modules.Administration if (role != null) await user.AddRolesAsync(role).ConfigureAwait(false); } - catch (Exception ex) { _log.Warn(ex); } + catch (Exception ex) { log.Warn(ex); } }; } @@ -52,20 +48,19 @@ namespace NadekoBot.Modules.Administration [RequireUserPermission(GuildPermission.ManageRoles)] public async Task AutoAssignRole([Remainder] IRole role = null) { - GuildConfig conf; using (var uow = DbHandler.UnitOfWork()) { - conf = uow.GuildConfigs.For(Context.Guild.Id, set => set); + var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set); if (role == null) { conf.AutoAssignRoleId = 0; ulong throwaway; - AutoAssignedRoles.TryRemove(Context.Guild.Id, out throwaway); + autoAssignedRoles.TryRemove(Context.Guild.Id, out throwaway); } else { conf.AutoAssignRoleId = role.Id; - AutoAssignedRoles.AddOrUpdate(Context.Guild.Id, role.Id, (key, val) => role.Id); + autoAssignedRoles.AddOrUpdate(Context.Guild.Id, role.Id, (key, val) => role.Id); } await uow.CompleteAsync().ConfigureAwait(false); @@ -73,11 +68,11 @@ namespace NadekoBot.Modules.Administration if (role == null) { - await Context.Channel.SendConfirmAsync("🆗 **Auto assign role** on user join is now **disabled**.").ConfigureAwait(false); + await ReplyConfirmLocalized("aar_disabled").ConfigureAwait(false); return; } - await Context.Channel.SendConfirmAsync("✅ **Auto assign role** on user join is now **enabled**.").ConfigureAwait(false); + await ReplyConfirmLocalized("aar_enabled").ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 493016ee..7d27eaf2 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -59,6 +59,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to **Auto assign role** on user join is now **disabled**.. + /// + public static string administration_aar_disabled { + get { + return ResourceManager.GetString("administration_aar_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to **Auto assign role** on user join is now **enabled**.. + /// + public static string administration_aar_enabled { + get { + return ResourceManager.GetString("administration_aar_enabled", resourceCulture); + } + } + /// /// Looks up a localized string similar to I don't have the permission necessary for that most likely.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 480a91f0..7eeb75f1 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -298,6 +298,12 @@ You fainted, so you are not able to move! + + **Auto assign role** on user join is now **disabled**. + + + **Auto assign role** on user join is now **enabled**. + I don't have the permission necessary for that most likely. From a89ca8d1859282577978fcaffbee3dbebba289a4 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 17:15:53 +0100 Subject: [PATCH 247/746] dm foward commands cleaned up and localized --- .../Commands/DMForwardCommands.cs | 51 +++++++++++-------- .../Resources/ResponseStrings.Designer.cs | 45 ++++++++++++++++ src/NadekoBot/Services/CommandHandler.cs | 2 +- 3 files changed, 76 insertions(+), 22 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs b/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs index 9a9c4129..ef6d1231 100644 --- a/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs @@ -4,10 +4,9 @@ using Discord.WebSocket; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; -using NLog; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; +using System.Threading; using System.Threading.Tasks; namespace NadekoBot.Modules.Administration @@ -15,19 +14,21 @@ namespace NadekoBot.Modules.Administration public partial class Administration { [Group] - public class DMForwardCommands : NadekoSubmodule + public class DmForwardCommands : NadekoSubmodule { - private static bool ForwardDMs { get; set; } - private static bool ForwardDMsToAllOwners { get; set; } + private static volatile bool _forwardDMs; + private static volatile bool _forwardDMsToAllOwners; + + private static readonly object _locker = new object(); - static DMForwardCommands() + static DmForwardCommands() { using (var uow = DbHandler.UnitOfWork()) { var config = uow.BotConfig.GetOrCreate(); - ForwardDMs = config.ForwardMessages; - ForwardDMsToAllOwners = config.ForwardToAllOwners; + _forwardDMs = config.ForwardMessages; + _forwardDMsToAllOwners = config.ForwardToAllOwners; } } @@ -38,13 +39,14 @@ namespace NadekoBot.Modules.Administration using (var uow = DbHandler.UnitOfWork()) { var config = uow.BotConfig.GetOrCreate(); - ForwardDMs = config.ForwardMessages = !config.ForwardMessages; + lock(_locker) + _forwardDMs = config.ForwardMessages = !config.ForwardMessages; uow.Complete(); } - if (ForwardDMs) - await Context.Channel.SendConfirmAsync("✅ **I will forward DMs from now on.**").ConfigureAwait(false); + if (_forwardDMs) + await ReplyConfirmLocalized("fwdm_start").ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync("🆗 **I will stop forwarding DMs from now on.**").ConfigureAwait(false); + await ReplyConfirmLocalized("fwdm_stop").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -54,22 +56,25 @@ namespace NadekoBot.Modules.Administration using (var uow = DbHandler.UnitOfWork()) { var config = uow.BotConfig.GetOrCreate(); - ForwardDMsToAllOwners = config.ForwardToAllOwners = !config.ForwardToAllOwners; + lock(_locker) + _forwardDMsToAllOwners = config.ForwardToAllOwners = !config.ForwardToAllOwners; uow.Complete(); } - if (ForwardDMsToAllOwners) - await Context.Channel.SendConfirmAsync("ℹ️ **I will forward DMs to all owners.**").ConfigureAwait(false); + if (_forwardDMsToAllOwners) + await ReplyConfirmLocalized("fwall_start").ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync("ℹ️ **I will forward DMs only to the first owner.**").ConfigureAwait(false); + await ReplyConfirmLocalized("fwall_stop").ConfigureAwait(false); } - public static async Task HandleDMForwarding(SocketMessage msg, List ownerChannels) + public static async Task HandleDmForwarding(SocketMessage msg, List ownerChannels) { - if (ForwardDMs && ownerChannels.Any()) + if (_forwardDMs && ownerChannels.Any()) { - var title = $"DM from [{msg.Author}]({msg.Author.Id})"; - if (ForwardDMsToAllOwners) + var title = + GetTextStatic("dm_from", NadekoBot.Localization.DefaultCultureInfo, + typeof(Administration).Name.ToLowerInvariant()) + $" [{msg.Author}]({msg.Author.Id})"; + if (_forwardDMsToAllOwners) { await Task.WhenAll(ownerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id) .Select(ch => ch.SendConfirmAsync(title, msg.Content))).ConfigureAwait(false); @@ -78,7 +83,11 @@ namespace NadekoBot.Modules.Administration { var firstOwnerChannel = ownerChannels.First(); if (firstOwnerChannel.Recipient.Id != msg.Author.Id) - try { await firstOwnerChannel.SendConfirmAsync(title, msg.Content).ConfigureAwait(false); } catch { } + try { await firstOwnerChannel.SendConfirmAsync(title, msg.Content).ConfigureAwait(false); } + catch + { + // ignored + } } } } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 7d27eaf2..c2109c7d 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -77,6 +77,51 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to DM from. + /// + public static string administration_dm_from { + get { + return ResourceManager.GetString("administration_dm_from", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I will forward DMs to all owners.. + /// + public static string administration_fwall_start { + get { + return ResourceManager.GetString("administration_fwall_start", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I will forward DMs only to the first owner.. + /// + public static string administration_fwall_stop { + get { + return ResourceManager.GetString("administration_fwall_stop", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I will forward DMs from now on.. + /// + public static string administration_fwdm_start { + get { + return ResourceManager.GetString("administration_fwdm_start", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I will stop forwarding DMs from now on.. + /// + public static string administration_fwdm_stop { + get { + return ResourceManager.GetString("administration_fwdm_stop", resourceCulture); + } + } + /// /// Looks up a localized string similar to I don't have the permission necessary for that most likely.. /// diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index ce17de09..4dcfd461 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -273,7 +273,7 @@ namespace NadekoBot.Services await msg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false); - await DMForwardCommands.HandleDMForwarding(msg, ownerChannels).ConfigureAwait(false); + await DmForwardCommands.HandleDmForwarding(msg, ownerChannels).ConfigureAwait(false); } } } From 64d43fed748d47be09dfe066e64c0c2be8959db6 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 17:22:57 +0100 Subject: [PATCH 248/746] moved dmfoward commands to selfcommands --- .../Commands/DMForwardCommands.cs | 96 ------------------- .../Administration/Commands/SelfCommands.cs | 86 ++++++++++++++++- src/NadekoBot/Services/CommandHandler.cs | 2 +- 3 files changed, 83 insertions(+), 101 deletions(-) delete mode 100644 src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs diff --git a/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs b/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs deleted file mode 100644 index ef6d1231..00000000 --- a/src/NadekoBot/Modules/Administration/Commands/DMForwardCommands.cs +++ /dev/null @@ -1,96 +0,0 @@ -using Discord; -using Discord.Commands; -using Discord.WebSocket; -using NadekoBot.Attributes; -using NadekoBot.Extensions; -using NadekoBot.Services; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace NadekoBot.Modules.Administration -{ - public partial class Administration - { - [Group] - public class DmForwardCommands : NadekoSubmodule - { - private static volatile bool _forwardDMs; - private static volatile bool _forwardDMsToAllOwners; - - private static readonly object _locker = new object(); - - static DmForwardCommands() - { - - using (var uow = DbHandler.UnitOfWork()) - { - var config = uow.BotConfig.GetOrCreate(); - _forwardDMs = config.ForwardMessages; - _forwardDMsToAllOwners = config.ForwardToAllOwners; - } - } - - [NadekoCommand, Usage, Description, Aliases] - [OwnerOnly] - public async Task ForwardMessages() - { - using (var uow = DbHandler.UnitOfWork()) - { - var config = uow.BotConfig.GetOrCreate(); - lock(_locker) - _forwardDMs = config.ForwardMessages = !config.ForwardMessages; - uow.Complete(); - } - if (_forwardDMs) - await ReplyConfirmLocalized("fwdm_start").ConfigureAwait(false); - else - await ReplyConfirmLocalized("fwdm_stop").ConfigureAwait(false); - } - - [NadekoCommand, Usage, Description, Aliases] - [OwnerOnly] - public async Task ForwardToAll() - { - using (var uow = DbHandler.UnitOfWork()) - { - var config = uow.BotConfig.GetOrCreate(); - lock(_locker) - _forwardDMsToAllOwners = config.ForwardToAllOwners = !config.ForwardToAllOwners; - uow.Complete(); - } - if (_forwardDMsToAllOwners) - await ReplyConfirmLocalized("fwall_start").ConfigureAwait(false); - else - await ReplyConfirmLocalized("fwall_stop").ConfigureAwait(false); - - } - - public static async Task HandleDmForwarding(SocketMessage msg, List ownerChannels) - { - if (_forwardDMs && ownerChannels.Any()) - { - var title = - GetTextStatic("dm_from", NadekoBot.Localization.DefaultCultureInfo, - typeof(Administration).Name.ToLowerInvariant()) + $" [{msg.Author}]({msg.Author.Id})"; - if (_forwardDMsToAllOwners) - { - await Task.WhenAll(ownerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id) - .Select(ch => ch.SendConfirmAsync(title, msg.Content))).ConfigureAwait(false); - } - else - { - var firstOwnerChannel = ownerChannels.First(); - if (firstOwnerChannel.Recipient.Id != msg.Author.Id) - try { await firstOwnerChannel.SendConfirmAsync(title, msg.Content).ConfigureAwait(false); } - catch - { - // ignored - } - } - } - } - } - } -} diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index 3361eff4..b67f5d3e 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -3,11 +3,13 @@ using Discord.Commands; using NadekoBot.Attributes; using NadekoBot.Extensions; using System; -using System.Diagnostics; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Threading.Tasks; +using Discord.WebSocket; +using NadekoBot.Services; namespace NadekoBot.Modules.Administration { @@ -16,6 +18,82 @@ namespace NadekoBot.Modules.Administration [Group] public class SelfCommands : NadekoSubmodule { + private static volatile bool _forwardDMs; + private static volatile bool _forwardDMsToAllOwners; + + private static readonly object _locker = new object(); + + static SelfCommands() + { + using (var uow = DbHandler.UnitOfWork()) + { + var config = uow.BotConfig.GetOrCreate(); + _forwardDMs = config.ForwardMessages; + _forwardDMsToAllOwners = config.ForwardToAllOwners; + } + } + + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task ForwardMessages() + { + using (var uow = DbHandler.UnitOfWork()) + { + var config = uow.BotConfig.GetOrCreate(); + lock (_locker) + _forwardDMs = config.ForwardMessages = !config.ForwardMessages; + uow.Complete(); + } + if (_forwardDMs) + await ReplyConfirmLocalized("fwdm_start").ConfigureAwait(false); + else + await ReplyConfirmLocalized("fwdm_stop").ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task ForwardToAll() + { + using (var uow = DbHandler.UnitOfWork()) + { + var config = uow.BotConfig.GetOrCreate(); + lock (_locker) + _forwardDMsToAllOwners = config.ForwardToAllOwners = !config.ForwardToAllOwners; + uow.Complete(); + } + if (_forwardDMsToAllOwners) + await ReplyConfirmLocalized("fwall_start").ConfigureAwait(false); + else + await ReplyConfirmLocalized("fwall_stop").ConfigureAwait(false); + + } + + public static async Task HandleDmForwarding(SocketMessage msg, List ownerChannels) + { + if (_forwardDMs && ownerChannels.Any()) + { + var title = + GetTextStatic("dm_from", NadekoBot.Localization.DefaultCultureInfo, + typeof(Administration).Name.ToLowerInvariant()) + $" [{msg.Author}]({msg.Author.Id})"; + if (_forwardDMsToAllOwners) + { + await Task.WhenAll(ownerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id) + .Select(ch => ch.SendConfirmAsync(title, msg.Content))).ConfigureAwait(false); + } + else + { + var firstOwnerChannel = ownerChannels.First(); + if (firstOwnerChannel.Recipient.Id != msg.Author.Id) + try { await firstOwnerChannel.SendConfirmAsync(title, msg.Content).ConfigureAwait(false); } + catch + { + // ignored + } + } + } + } + + [NadekoCommand, Usage, Description, Aliases] [OwnerOnly] public async Task ConnectShard(int shardid) @@ -148,7 +226,7 @@ namespace NadekoBot.Modules.Administration if (ids.Length != 2) return; var sid = ulong.Parse(ids[0]); - var server = NadekoBot.Client.GetGuilds().Where(s => s.Id == sid).FirstOrDefault(); + var server = NadekoBot.Client.GetGuilds().FirstOrDefault(s => s.Id == sid); if (server == null) return; @@ -156,7 +234,7 @@ namespace NadekoBot.Modules.Administration if (ids[1].ToUpperInvariant().StartsWith("C:")) { var cid = ulong.Parse(ids[1].Substring(2)); - var ch = server.TextChannels.Where(c => c.Id == cid).FirstOrDefault(); + var ch = server.TextChannels.FirstOrDefault(c => c.Id == cid); if (ch == null) { return; @@ -166,7 +244,7 @@ namespace NadekoBot.Modules.Administration else if (ids[1].ToUpperInvariant().StartsWith("U:")) { var uid = ulong.Parse(ids[1].Substring(2)); - var user = server.Users.Where(u => u.Id == uid).FirstOrDefault(); + var user = server.Users.FirstOrDefault(u => u.Id == uid); if (user == null) { return; diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 4dcfd461..a944a21e 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -273,7 +273,7 @@ namespace NadekoBot.Services await msg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false); - await DmForwardCommands.HandleDmForwarding(msg, ownerChannels).ConfigureAwait(false); + await SelfCommands.HandleDmForwarding(msg, ownerChannels).ConfigureAwait(false); } } } From 97d32a46b6726452993756e806c98001acc28eed Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 17:49:15 +0100 Subject: [PATCH 249/746] localization commands localized :OOOO localiception! --- .../Commands/LocalizationCommands.cs | 35 ++++++------ .../Resources/ResponseStrings.Designer.cs | 55 +++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 34 ++++++++++++ 3 files changed, 105 insertions(+), 19 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 70fcd6c6..3b3467f6 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Globalization; using System.Linq; -using System.Text; using System.Threading.Tasks; namespace NadekoBot.Modules.Administration @@ -17,7 +16,7 @@ namespace NadekoBot.Modules.Administration [Group] public class LocalizationCommands : NadekoSubmodule { - private ImmutableDictionary SupportedLocales { get; } = new Dictionary() + private ImmutableDictionary supportedLocales { get; } = new Dictionary() { {"en-US", "English, United States" }, {"sr-cyrl-rs", "Serbian, Cyrillic" } @@ -28,7 +27,8 @@ namespace NadekoBot.Modules.Administration public async Task LanguageSet() { var cul = NadekoBot.Localization.GetCultureInfo(Context.Guild); - await Context.Channel.SendConfirmAsync("This server's language is set to " + Format.Bold(cul.ToString()) + " - " + Format.Bold(cul.NativeName)).ConfigureAwait(false); + await ReplyConfirmLocalized("lang_set_show", Format.Bold(cul.ToString()), Format.Bold(cul.NativeName)) + .ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -36,9 +36,9 @@ namespace NadekoBot.Modules.Administration [RequireUserPermission(GuildPermission.Administrator)] public async Task LanguageSet(string name) { - CultureInfo ci = null; try { + CultureInfo ci; if (name.Trim().ToLowerInvariant() == "default") { NadekoBot.Localization.RemoveGuildCulture(Context.Guild); @@ -50,12 +50,11 @@ namespace NadekoBot.Modules.Administration NadekoBot.Localization.SetGuildCulture(Context.Guild, ci); } - await Context.Channel.SendConfirmAsync($"Your server's locale is now {Format.Bold(ci.ToString())} - {Format.Bold(ci.NativeName)}.").ConfigureAwait(false); + await ReplyConfirmLocalized("lang_set", Format.Bold(ci.ToString()), Format.Bold(ci.NativeName)).ConfigureAwait(false); } - catch(Exception) { - - //_log.warn(ex); - await Context.Channel.SendConfirmAsync($"Failed setting locale. Revisit this command's help.").ConfigureAwait(false); + catch(Exception) + { + await ReplyErrorLocalized("lang_set_fail").ConfigureAwait(false); } } @@ -63,17 +62,16 @@ namespace NadekoBot.Modules.Administration public async Task LanguageSetDefault() { var cul = NadekoBot.Localization.DefaultCultureInfo; - await Context.Channel.SendConfirmAsync("Bot's language is set to " + cul + " - " + cul.NativeName).ConfigureAwait(false); - return; + await ReplyConfirmLocalized("lang_set_bot_show", cul, cul.NativeName).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [OwnerOnly] public async Task LanguageSetDefault(string name) { - CultureInfo ci = null; try { + CultureInfo ci; if (name.Trim().ToLowerInvariant() == "default") { NadekoBot.Localization.ResetDefaultCulture(); @@ -84,22 +82,21 @@ namespace NadekoBot.Modules.Administration ci = new CultureInfo(name); NadekoBot.Localization.SetDefaultCulture(ci); } - - await Context.Channel.SendConfirmAsync($"Bot's default locale is now {Format.Bold(ci.ToString())} - {Format.Bold(ci.NativeName)}.").ConfigureAwait(false); + await ReplyConfirmLocalized("lang_set_bot", Format.Bold(ci.ToString()), Format.Bold(ci.NativeName)).ConfigureAwait(false); } catch (Exception) { - //_log.warn(ex); - await Context.Channel.SendConfirmAsync($"Failed setting locale. Revisit this command's help.").ConfigureAwait(false); + await ReplyErrorLocalized("lang_set_fail").ConfigureAwait(false); } } [NadekoCommand, Usage, Description, Aliases] [OwnerOnly] - public async Task LanguagesList(string name) + public async Task LanguagesList() { - await Context.Channel.SendConfirmAsync("List Of Languages", - string.Join("\n", SupportedLocales.Select(x => $"{Format.Code(x.Key)} => {x.Value}"))); + await ReplyConfirmLocalized("lang_list", + string.Join("\n", supportedLocales.Select(x => $"{Format.Code(x.Key)} => {x.Value}"))) + .ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index c2109c7d..48733a24 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -122,6 +122,61 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to List Of Languages + ///{0}. + /// + public static string administration_lang_list { + get { + return ResourceManager.GetString("administration_lang_list", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Your server's locale is now {0} - {1}. + /// + public static string administration_lang_set { + get { + return ResourceManager.GetString("administration_lang_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bot's default locale is now {0} - {1}. + /// + public static string administration_lang_set_bot { + get { + return ResourceManager.GetString("administration_lang_set_bot", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bot's language is set to {0} - {0}. + /// + public static string administration_lang_set_bot_show { + get { + return ResourceManager.GetString("administration_lang_set_bot_show", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed setting locale. Revisit this command's help.. + /// + public static string administration_lang_set_fail { + get { + return ResourceManager.GetString("administration_lang_set_fail", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This server's language is set to {0} - {0}. + /// + public static string administration_lang_set_show { + get { + return ResourceManager.GetString("administration_lang_set_show", resourceCulture); + } + } + /// /// Looks up a localized string similar to I don't have the permission necessary for that most likely.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 7eeb75f1..ff566d6c 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -304,6 +304,40 @@ **Auto assign role** on user join is now **enabled**. + + DM from + + + I will forward DMs to all owners. + + + I will forward DMs only to the first owner. + + + I will forward DMs from now on. + + + I will stop forwarding DMs from now on. + + + List Of Languages +{0} + + + Your server's locale is now {0} - {1} + + + Bot's default locale is now {0} - {1} + + + Bot's language is set to {0} - {0} + + + Failed setting locale. Revisit this command's help. + + + This server's language is set to {0} - {0} + I don't have the permission necessary for that most likely. From be8ca3b45dff51d621eaabc8b5afde40087cfeb7 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 19:06:02 +0100 Subject: [PATCH 250/746] logging localized >.< --- .../Administration/Commands/LogCommand.cs | 267 +++++++---- src/NadekoBot/Modules/NadekoModule.cs | 18 +- .../Resources/ResponseStrings.Designer.cs | 450 ++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 155 ++++++ 4 files changed, 776 insertions(+), 114 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index 8c63191d..3ad8c084 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -1,7 +1,6 @@ using Discord; using Discord.Commands; using Discord.WebSocket; -using Microsoft.EntityFrameworkCore; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Modules.Permissions; @@ -23,39 +22,37 @@ namespace NadekoBot.Modules.Administration [Group] public class LogCommands : NadekoSubmodule { - private const string clockEmojiUrl = "https://cdn.discordapp.com/attachments/155726317222887425/258309524966866945/clock.png"; - - private static DiscordShardedClient _client { get; } - private static Logger _log { get; } + private static DiscordShardedClient client { get; } + private new static Logger _log { get; } private static string prettyCurrentTime => $"【{DateTime.Now:HH:mm:ss}】"; private static string currentTime => $"{DateTime.Now:HH:mm:ss}"; public static ConcurrentDictionary GuildLogSettings { get; } - private static ConcurrentDictionary> PresenceUpdates { get; } = new ConcurrentDictionary>(); - private static Timer timerReference { get; } + private static ConcurrentDictionary> presenceUpdates { get; } = new ConcurrentDictionary>(); + private static readonly Timer _timerReference; static LogCommands() { - _client = NadekoBot.Client; + client = NadekoBot.Client; _log = LogManager.GetCurrentClassLogger(); var sw = Stopwatch.StartNew(); GuildLogSettings = new ConcurrentDictionary(NadekoBot.AllGuildConfigs .ToDictionary(g => g.GuildId, g => g.LogSetting)); - timerReference = new Timer(async (state) => + _timerReference = new Timer(async (state) => { try { - var keys = PresenceUpdates.Keys.ToList(); + var keys = presenceUpdates.Keys.ToList(); await Task.WhenAll(keys.Select(async key => { List messages; - if (PresenceUpdates.TryRemove(key, out messages)) - try { await key.SendConfirmAsync("Presence Updates", string.Join(Environment.NewLine, messages)); } + if (presenceUpdates.TryRemove(key, out messages)) + try { await key.SendConfirmAsync(key.Guild.GetLogText("presence_updates"), string.Join(Environment.NewLine, messages)); } catch { // ignored @@ -72,23 +69,22 @@ namespace NadekoBot.Modules.Administration _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); //_client.MessageReceived += _client_MessageReceived; - _client.MessageUpdated += _client_MessageUpdated; - _client.MessageDeleted += _client_MessageDeleted; - _client.UserBanned += _client_UserBanned; - _client.UserUnbanned += _client_UserUnbanned; - _client.UserJoined += _client_UserJoined; - _client.UserLeft += _client_UserLeft; - _client.UserPresenceUpdated += _client_UserPresenceUpdated; - _client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated; - _client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS; - _client.GuildMemberUpdated += _client_GuildUserUpdated; + client.MessageUpdated += _client_MessageUpdated; + client.MessageDeleted += _client_MessageDeleted; + client.UserBanned += _client_UserBanned; + client.UserUnbanned += _client_UserUnbanned; + client.UserJoined += _client_UserJoined; + client.UserLeft += _client_UserLeft; + client.UserPresenceUpdated += _client_UserPresenceUpdated; + client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated; + client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS; + client.GuildMemberUpdated += _client_GuildUserUpdated; #if !GLOBAL_NADEKO - _client.UserUpdated += _client_UserUpdated; + client.UserUpdated += _client_UserUpdated; #endif - - _client.ChannelCreated += _client_ChannelCreated; - _client.ChannelDestroyed += _client_ChannelDestroyed; - _client.ChannelUpdated += _client_ChannelUpdated; + client.ChannelCreated += _client_ChannelCreated; + client.ChannelDestroyed += _client_ChannelDestroyed; + client.ChannelUpdated += _client_ChannelUpdated; MuteCommands.UserMuted += MuteCommands_UserMuted; MuteCommands.UserUnmuted += MuteCommands_UserUnmuted; @@ -119,7 +115,7 @@ namespace NadekoBot.Modules.Administration if (before.Username != after.Username) { - embed.WithTitle("👥 Username Changed") + embed.WithTitle("👥 " + g.GetLogText("username_changed")) .WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}") .AddField(fb => fb.WithName("Old Name").WithValue($"{before.Username}").WithIsInline(true)) .AddField(fb => fb.WithName("New Name").WithValue($"{after.Username}").WithIsInline(true)) @@ -128,7 +124,7 @@ namespace NadekoBot.Modules.Administration } else if (before.AvatarUrl != after.AvatarUrl) { - embed.WithTitle("👥 Avatar Changed") + embed.WithTitle("👥" + g.GetLogText("avatar_changed")) .WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}") .WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}") .WithThumbnailUrl(before.AvatarUrl) @@ -190,15 +186,15 @@ namespace NadekoBot.Modules.Administration var str = ""; if (beforeVch?.Guild == afterVch?.Guild) { - str = $"{usr.Username} moved from {beforeVch?.Name} to {afterVch?.Name}"; + str = logChannel.Guild.GetLogText("moved", usr.Username, beforeVch?.Name, afterVch?.Name); } else if (beforeVch == null) { - str = $"{usr.Username} has joined {afterVch.Name}"; + str = logChannel.Guild.GetLogText("joined", usr.Username, afterVch.Name); } else if (afterVch == null) { - str = $"{usr.Username} has left {beforeVch.Name}"; + str = logChannel.Guild.GetLogText("left", usr.Username, beforeVch.Name); } var toDelete = await logChannel.SendMessageAsync(str, true).ConfigureAwait(false); toDelete.DeleteAfter(5); @@ -222,27 +218,31 @@ namespace NadekoBot.Modules.Administration if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserMuted)) == null) return; var mutes = ""; + var mutedLocalized = logChannel.Guild.GetLogText("muted_sn"); switch (muteType) { case MuteCommands.MuteType.Voice: - mutes = "voice chat"; + mutes = "🔇 " + logChannel.Guild.GetLogText("xmuted_voice", mutedLocalized); break; case MuteCommands.MuteType.Chat: - mutes = "text chat"; + mutes = "🔇 " + logChannel.Guild.GetLogText("xmuted_text", mutedLocalized); break; case MuteCommands.MuteType.All: - mutes = "text and voice chat"; + mutes = "🔇 " + logChannel.Guild.GetLogText("xmuted_text_and_voice", mutedLocalized); break; } - var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName("🔇 User Muted from " + mutes)) + var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName(mutes)) .WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}") .WithFooter(fb => fb.WithText(currentTime)) .WithOkColor(); await logChannel.EmbedAsync(embed).ConfigureAwait(false); } - catch { } + catch + { + // ignored + } } private static async void MuteCommands_UserUnmuted(IGuildUser usr, MuteCommands.MuteType muteType) @@ -258,28 +258,32 @@ namespace NadekoBot.Modules.Administration if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserMuted)) == null) return; - string mutes = ""; + var mutes = ""; + var unmutedLocalized = logChannel.Guild.GetLogText("unmuted_sn"); switch (muteType) { case MuteCommands.MuteType.Voice: - mutes = "voice chat"; + mutes = "🔊 " + logChannel.Guild.GetLogText("xmuted_voice", unmutedLocalized); break; case MuteCommands.MuteType.Chat: - mutes = "text chat"; + mutes = "🔊 " + logChannel.Guild.GetLogText("xmuted_text", unmutedLocalized); break; case MuteCommands.MuteType.All: - mutes = "text and voice chat"; + mutes = "🔊 " + logChannel.Guild.GetLogText("xmuted_text_and_voice", unmutedLocalized); break; } - var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName("🔊 User Unmuted from " + mutes)) + var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName(mutes)) .WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}") .WithFooter(fb => fb.WithText($"{currentTime}")) .WithOkColor(); await logChannel.EmbedAsync(embed).ConfigureAwait(false); } - catch { } + catch + { + // ignored + } } public static async Task TriggeredAntiProtection(IGuildUser[] users, PunishmentAction action, ProtectionType protection) @@ -298,28 +302,31 @@ namespace NadekoBot.Modules.Administration return; var punishment = ""; - if (action == PunishmentAction.Mute) + switch (action) { - punishment = "🔇 MUTED"; - } - else if (action == PunishmentAction.Kick) - { - punishment = "☣ SOFT-BANNED (KICKED)"; - } - else if (action == PunishmentAction.Ban) - { - punishment = "⛔️ BANNED"; + case PunishmentAction.Mute: + punishment = "🔇 " + logChannel.Guild.GetLogText("muted_pl").ToUpperInvariant(); + break; + case PunishmentAction.Kick: + punishment = "☣ " + logChannel.Guild.GetLogText("soft_banned_pl").ToUpperInvariant(); + break; + case PunishmentAction.Ban: + punishment = "⛔️ " + logChannel.Guild.GetLogText("banned_pl").ToUpperInvariant(); + break; } var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName($"🛡 Anti-{protection}")) - .WithTitle($"Users " + punishment) - .WithDescription(String.Join("\n", users.Select(u => u.ToString()))) + .WithTitle(logChannel.Guild.GetLogText("users") + " " + punishment) + .WithDescription(string.Join("\n", users.Select(u => u.ToString()))) .WithFooter(fb => fb.WithText($"{currentTime}")) .WithOkColor(); await logChannel.EmbedAsync(embed).ConfigureAwait(false); } - catch { } + catch + { + // ignored + } } private static async Task _client_GuildUserUpdated(SocketGuildUser before, SocketGuildUser after) @@ -338,23 +345,23 @@ namespace NadekoBot.Modules.Administration .WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}"); if (before.Nickname != after.Nickname) { - embed.WithAuthor(eab => eab.WithName("👥 Nickname Changed")) + embed.WithAuthor(eab => eab.WithName("👥 " + logChannel.Guild.GetLogText("nick_change"))) - .AddField(efb => efb.WithName("Old Nickname").WithValue($"{before.Nickname}#{before.Discriminator}")) - .AddField(efb => efb.WithName("New Nickname").WithValue($"{after.Nickname}#{after.Discriminator}")); + .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("old_nick")).WithValue($"{before.Nickname}#{before.Discriminator}")) + .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("new_nick")).WithValue($"{after.Nickname}#{after.Discriminator}")); } else if (!before.RoleIds.SequenceEqual(after.RoleIds)) { if (before.RoleIds.Count < after.RoleIds.Count) { var diffRoles = after.RoleIds.Where(r => !before.RoleIds.Contains(r)).Select(r => before.Guild.GetRole(r).Name); - embed.WithAuthor(eab => eab.WithName("⚔ User's Role Added")) + embed.WithAuthor(eab => eab.WithName("⚔ " + logChannel.Guild.GetLogText("user_role_add"))) .WithDescription(string.Join(", ", diffRoles).SanitizeMentions()); } else if (before.RoleIds.Count > after.RoleIds.Count) { var diffRoles = before.RoleIds.Where(r => !after.RoleIds.Contains(r)).Select(r => before.Guild.GetRole(r).Name); - embed.WithAuthor(eab => eab.WithName("⚔ User's Role Removed")) + embed.WithAuthor(eab => eab.WithName("⚔ " + logChannel.Guild.GetLogText("user_role_rem"))) .WithDescription(string.Join(", ", diffRoles).SanitizeMentions()); } } @@ -362,7 +369,10 @@ namespace NadekoBot.Modules.Administration return; await logChannel.EmbedAsync(embed).ConfigureAwait(false); } - catch { } + catch + { + // ignored + } } private static async Task _client_ChannelUpdated(IChannel cbefore, IChannel cafter) @@ -391,23 +401,26 @@ namespace NadekoBot.Modules.Administration if (before.Name != after.Name) { - embed.WithTitle("ℹ️ Channel Name Changed") + embed.WithTitle("ℹ️ " + logChannel.Guild.GetLogText("ch_name_change")) .WithDescription($"{after} | {after.Id}") - .AddField(efb => efb.WithName("Old Name").WithValue(before.Name)); + .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("ch_old_name")).WithValue(before.Name)); } else if (beforeTextChannel?.Topic != afterTextChannel?.Topic) { - embed.WithTitle("ℹ️ Channel Topic Changed") + embed.WithTitle("ℹ️ " + logChannel.Guild.GetLogText("ch_topic_change")) .WithDescription($"{after} | {after.Id}") - .AddField(efb => efb.WithName("Old Topic").WithValue(beforeTextChannel.Topic)) - .AddField(efb => efb.WithName("New Topic").WithValue(afterTextChannel.Topic)); + .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("old_topic")).WithValue(beforeTextChannel?.Topic ?? "-")) + .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("new_topic")).WithValue(afterTextChannel?.Topic ?? "-")); } else return; await logChannel.EmbedAsync(embed).ConfigureAwait(false); } - catch { } + catch + { + // ignored + } } private static async Task _client_ChannelDestroyed(IChannel ich) @@ -427,14 +440,23 @@ namespace NadekoBot.Modules.Administration ITextChannel logChannel; if ((logChannel = await TryGetLogChannel(ch.Guild, logSetting, LogType.ChannelDestroyed)) == null) return; - + string title; + if (ch is IVoiceChannel) + { + title = logChannel.Guild.GetLogText("voice_chan_destroyed"); + } + else + title = logChannel.Guild.GetLogText("text_chan_destroyed"); await logChannel.EmbedAsync(new EmbedBuilder() .WithOkColor() - .WithTitle("🆕 " + (ch is IVoiceChannel ? "Voice" : "Text") + " Channel Destroyed") + .WithTitle("🆕 " + title) .WithDescription($"{ch.Name} | {ch.Id}") .WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false); } - catch { } + catch + { + // ignored + } } private static async Task _client_ChannelCreated(IChannel ich) @@ -453,10 +475,16 @@ namespace NadekoBot.Modules.Administration ITextChannel logChannel; if ((logChannel = await TryGetLogChannel(ch.Guild, logSetting, LogType.ChannelCreated)) == null) return; - + string title; + if (ch is IVoiceChannel) + { + title = logChannel.Guild.GetLogText("voice_chan_created"); + } + else + title = logChannel.Guild.GetLogText("text_chan_created"); await logChannel.EmbedAsync(new EmbedBuilder() .WithOkColor() - .WithTitle("🆕 " + (ch is IVoiceChannel ? "Voice" : "Text") + " Channel Created") + .WithTitle("🆕 " + title) .WithDescription($"{ch.Name} | {ch.Id}") .WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false); } @@ -489,20 +517,29 @@ namespace NadekoBot.Modules.Administration string str = null; if (beforeVch?.Guild == afterVch?.Guild) { - str = $"🎙`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__ moved from **{beforeVch.Name}** to **{afterVch.Name}** voice channel."; + str = "🎙" + Format.Code(prettyCurrentTime) + logChannel.Guild.GetLogText("user_vmoved", + "👤" + Format.Bold(usr.Username + "#" + usr.Discriminator), + Format.Bold(beforeVch?.Name ?? ""), Format.Bold(afterVch?.Name ?? "")); } else if (beforeVch == null) { - str = $"🎙`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__ has joined **{afterVch.Name}** voice channel."; + str = "🎙" + Format.Code(prettyCurrentTime) + logChannel.Guild.GetLogText("user_vjoined", + "👤" + Format.Bold(usr.Username + "#" + usr.Discriminator), + Format.Bold(afterVch.Name ?? "")); } else if (afterVch == null) { - str = $"🎙`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__ has left **{beforeVch.Name}** voice channel."; + str = "🎙" + Format.Code(prettyCurrentTime) + logChannel.Guild.GetLogText("user_vleft", + "👤" + Format.Code(prettyCurrentTime), "👤" + Format.Bold(usr.Username + "#" + usr.Discriminator), + Format.Bold(beforeVch.Name ?? "")); } if (str != null) - PresenceUpdates.AddOrUpdate(logChannel, new List() { str }, (id, list) => { list.Add(str); return list; }); + presenceUpdates.AddOrUpdate(logChannel, new List() { str }, (id, list) => { list.Add(str); return list; }); + } + catch + { + // ignored } - catch { } } private static async Task _client_UserPresenceUpdated(Optional optGuild, SocketUser usr, SocketPresence before, SocketPresence after) @@ -525,7 +562,10 @@ namespace NadekoBot.Modules.Administration return; string str = ""; if (before.Status != after.Status) - str = $"🎭`{prettyCurrentTime}`👤__**{usr.Username}**__ is now **{after.Status}**."; + str = "🎭" + Format.Code(prettyCurrentTime) + + logChannel.Guild.GetLogText("user_status_change", + "👤" + Format.Bold(usr.Username), + Format.Bold(after.Status.ToString())); //if (before.Game?.Name != after.Game?.Name) //{ @@ -534,9 +574,12 @@ namespace NadekoBot.Modules.Administration // str += $"👾`{prettyCurrentTime}`👤__**{usr.Username}**__ is now playing **{after.Game?.Name}**."; //} - PresenceUpdates.AddOrUpdate(logChannel, new List() { str }, (id, list) => { list.Add(str); return list; }); + presenceUpdates.AddOrUpdate(logChannel, new List() { str }, (id, list) => { list.Add(str); return list; }); + } + catch + { + // ignored } - catch { } } private static async Task _client_UserLeft(IGuildUser usr) @@ -554,13 +597,16 @@ namespace NadekoBot.Modules.Administration await logChannel.EmbedAsync(new EmbedBuilder() .WithOkColor() - .WithTitle("❌ User Left") + .WithTitle("❌ " + logChannel.Guild.GetLogText("user_left")) .WithThumbnailUrl(usr.AvatarUrl) .WithDescription(usr.ToString()) .AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString())) .WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false); } - catch { } + catch + { + // ignored + } } private static async Task _client_UserJoined(IGuildUser usr) @@ -578,7 +624,7 @@ namespace NadekoBot.Modules.Administration await logChannel.EmbedAsync(new EmbedBuilder() .WithOkColor() - .WithTitle("✅ User Joined") + .WithTitle("✅ " + logChannel.Guild.GetLogText("user_joined")) .WithThumbnailUrl(usr.AvatarUrl) .WithDescription($"{usr}") .AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString())) @@ -602,7 +648,7 @@ namespace NadekoBot.Modules.Administration await logChannel.EmbedAsync(new EmbedBuilder() .WithOkColor() - .WithTitle("♻️ User Unbanned") + .WithTitle("♻️ " + logChannel.Guild.GetLogText("user_unbanned")) .WithThumbnailUrl(usr.AvatarUrl) .WithDescription(usr.ToString()) .AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString())) @@ -625,7 +671,7 @@ namespace NadekoBot.Modules.Administration return; await logChannel.EmbedAsync(new EmbedBuilder() .WithOkColor() - .WithTitle("🚫 User Banned") + .WithTitle("🚫 " + logChannel.Guild.GetLogText("user_banned")) .WithThumbnailUrl(usr.AvatarUrl) .WithDescription(usr.ToString()) .AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString())) @@ -658,17 +704,20 @@ namespace NadekoBot.Modules.Administration return; var embed = new EmbedBuilder() .WithOkColor() - .WithTitle($"🗑 Message Deleted in #{((ITextChannel)msg.Channel).Name}") + .WithTitle("🗑 " + logChannel.Guild.GetLogText("msg_del", ((ITextChannel)msg.Channel).Name)) .WithDescription($"{msg.Author}") - .AddField(efb => efb.WithName("Content").WithValue(msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) + .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("content")).WithValue(msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) .AddField(efb => efb.WithName("Id").WithValue(msg.Id.ToString()).WithIsInline(false)) .WithFooter(efb => efb.WithText(currentTime)); if (msg.Attachments.Any()) - embed.AddField(efb => efb.WithName("Attachments").WithValue(string.Join(", ", msg.Attachments.Select(a => a.ProxyUrl))).WithIsInline(false)); + embed.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("attachments")).WithValue(string.Join(", ", msg.Attachments.Select(a => a.ProxyUrl))).WithIsInline(false)); await logChannel.EmbedAsync(embed).ConfigureAwait(false); } - catch { } + catch + { + // ignored + } } private static async Task _client_MessageUpdated(Optional optmsg, SocketMessage imsg2) @@ -702,16 +751,19 @@ namespace NadekoBot.Modules.Administration var embed = new EmbedBuilder() .WithOkColor() - .WithTitle($"📝 Message Updated in #{((ITextChannel)after.Channel).Name}") + .WithTitle("📝 " + logChannel.Guild.GetLogText("msg_update", ((ITextChannel)after.Channel).Name)) .WithDescription(after.Author.ToString()) - .AddField(efb => efb.WithName("Old Message").WithValue(before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) - .AddField(efb => efb.WithName("New Message").WithValue(after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) + .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("old_msg")).WithValue(before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) + .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("new_msg")).WithValue(after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) .AddField(efb => efb.WithName("Id").WithValue(after.Id.ToString()).WithIsInline(false)) .WithFooter(efb => efb.WithText(currentTime)); await logChannel.EmbedAsync(embed).ConfigureAwait(false); } - catch { } + catch + { + // ignored + } } public enum LogType @@ -783,8 +835,6 @@ namespace NadekoBot.Modules.Administration case LogType.UserMuted: id = logSetting.UserMutedId; break; - default: - break; } if (!id.HasValue) @@ -855,8 +905,6 @@ namespace NadekoBot.Modules.Administration case LogType.VoicePresenceTTS: newLogSetting.LogVoicePresenceTTSId = null; break; - default: - break; } GuildLogSettings.AddOrUpdate(guildId, newLogSetting, (gid, old) => newLogSetting); uow.Complete(); @@ -900,9 +948,9 @@ namespace NadekoBot.Modules.Administration await uow.CompleteAsync().ConfigureAwait(false); } if (action.Value) - await channel.SendConfirmAsync("Logging all events in this channel.").ConfigureAwait(false); + await ReplyConfirmLocalized("log_all").ConfigureAwait(false); else - await channel.SendConfirmAsync("Logging disabled.").ConfigureAwait(false); + await ReplyConfirmLocalized("log_disabled").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -929,9 +977,9 @@ namespace NadekoBot.Modules.Administration } if (removed == 0) - await channel.SendConfirmAsync($"Logging will IGNORE **{channel.Mention} ({channel.Id})**").ConfigureAwait(false); + await ReplyConfirmLocalized("log_ignore", Format.Bold(channel.Mention + "(" + channel.Id + ")")).ConfigureAwait(false); else - await channel.SendConfirmAsync($"Logging will NOT IGNORE **{channel.Mention} ({channel.Id})**").ConfigureAwait(false); + await ReplyConfirmLocalized("log_not_ignore", Format.Bold(channel.Mention + "(" + channel.Id + ")")).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -940,7 +988,7 @@ namespace NadekoBot.Modules.Administration [OwnerOnly] public async Task LogEvents() { - await Context.Channel.SendConfirmAsync("Log events you can subscribe to:", String.Join(", ", Enum.GetNames(typeof(LogType)).Cast())); + await ReplyConfirmLocalized("log_events", string.Join(", ", Enum.GetNames(typeof(LogType)).Cast())).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -1008,10 +1056,19 @@ namespace NadekoBot.Modules.Administration } if (channelId != null) - await channel.SendConfirmAsync($"Logging **{type}** event in this channel.").ConfigureAwait(false); + await ReplyConfirmLocalized("log", Format.Bold(type.ToString())).ConfigureAwait(false); else - await channel.SendConfirmAsync($"Stopped logging **{type}** event.").ConfigureAwait(false); + await ReplyConfirmLocalized("log_stop", Format.Bold(type.ToString())).ConfigureAwait(false); } } } + + public static class GuildExtensions + { + public static string GetLogText(this IGuild guild, string key, params object[] replacements) + => NadekoModule.GetTextStatic(key, + NadekoBot.Localization.GetCultureInfo(guild), + typeof(Administration).Name.ToLowerInvariant(), + replacements); + } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index 7f75e891..9bb524ec 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -12,7 +12,7 @@ namespace NadekoBot.Modules public abstract class NadekoModule : ModuleBase { protected readonly Logger _log; - protected CultureInfo _cultureInfo { get; private set; } + protected CultureInfo _cultureInfo; public readonly string Prefix; public readonly string ModuleTypeName; public readonly string LowerModuleTypeName; @@ -58,23 +58,23 @@ namespace NadekoBot.Modules /// /// Used as failsafe in case response key doesn't exist in the selected or default language. /// - private static readonly CultureInfo usCultureInfo = new CultureInfo("en-US"); + private static readonly CultureInfo _usCultureInfo = new CultureInfo("en-US"); - public static string GetTextStatic(string key, CultureInfo _cultureInfo, string lowerModuleTypeName) + public static string GetTextStatic(string key, CultureInfo cultureInfo, string lowerModuleTypeName) { - var text = NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, _cultureInfo); + var text = NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, cultureInfo); if (string.IsNullOrWhiteSpace(text)) { - LogManager.GetCurrentClassLogger().Warn(lowerModuleTypeName + "_" + key + " key is missing from " + _cultureInfo + " response strings. PLEASE REPORT THIS."); - return NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} found!"; + LogManager.GetCurrentClassLogger().Warn(lowerModuleTypeName + "_" + key + " key is missing from " + cultureInfo + " response strings. PLEASE REPORT THIS."); + return NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, _usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} found!"; } - return text ?? $"Error: key {lowerModuleTypeName + "_" + key} not found."; + return text; } - public static string GetTextStatic(string key, CultureInfo _cultureInfo, string lowerModuleTypeName, params object[] replacements) + public static string GetTextStatic(string key, CultureInfo cultureInfo, string lowerModuleTypeName, params object[] replacements) { - return string.Format(GetTextStatic(key, _cultureInfo, lowerModuleTypeName), replacements); + return string.Format(GetTextStatic(key, cultureInfo, lowerModuleTypeName), replacements); } protected string GetText(string key) => diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 48733a24..66ebbe34 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -77,6 +77,69 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Attachments. + /// + public static string administration_attachments { + get { + return ResourceManager.GetString("administration_attachments", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Avatar Changed. + /// + public static string administration_avatar_changed { + get { + return ResourceManager.GetString("administration_avatar_changed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to banned. + /// + public static string administration_banned_pl { + get { + return ResourceManager.GetString("administration_banned_pl", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Channel Name Changed. + /// + public static string administration_ch_name_change { + get { + return ResourceManager.GetString("administration_ch_name_change", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Old Name. + /// + public static string administration_ch_old_name { + get { + return ResourceManager.GetString("administration_ch_old_name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Channel Topic Changed. + /// + public static string administration_ch_topic_change { + get { + return ResourceManager.GetString("administration_ch_topic_change", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Content. + /// + public static string administration_content { + get { + return ResourceManager.GetString("administration_content", resourceCulture); + } + } + /// /// Looks up a localized string similar to DM from. /// @@ -122,6 +185,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to {0} has joined {1}. + /// + public static string administration_joined { + get { + return ResourceManager.GetString("administration_joined", resourceCulture); + } + } + /// /// Looks up a localized string similar to List Of Languages ///{0}. @@ -177,6 +249,105 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to {0} has left {1}. + /// + public static string administration_left { + get { + return ResourceManager.GetString("administration_left", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logging {0} event in this channel.. + /// + public static string administration_log { + get { + return ResourceManager.GetString("administration_log", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logging all events in this channel.. + /// + public static string administration_log_all { + get { + return ResourceManager.GetString("administration_log_all", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logging disabled.. + /// + public static string administration_log_disabled { + get { + return ResourceManager.GetString("administration_log_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Log events you can subscribe to:. + /// + public static string administration_log_events { + get { + return ResourceManager.GetString("administration_log_events", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logging will ignore {0}. + /// + public static string administration_log_ignore { + get { + return ResourceManager.GetString("administration_log_ignore", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Logging will not ignore {0}. + /// + public static string administration_log_not_ignore { + get { + return ResourceManager.GetString("administration_log_not_ignore", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stopped logging {0} event.. + /// + public static string administration_log_stop { + get { + return ResourceManager.GetString("administration_log_stop", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} moved from {1} to {2}. + /// + public static string administration_moved { + get { + return ResourceManager.GetString("administration_moved", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Message Deleted in #{0}. + /// + public static string administration_msg_del { + get { + return ResourceManager.GetString("administration_msg_del", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Message Updated in #{0}. + /// + public static string administration_msg_update { + get { + return ResourceManager.GetString("administration_msg_update", resourceCulture); + } + } + /// /// Looks up a localized string similar to I don't have the permission necessary for that most likely.. /// @@ -195,6 +366,132 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Muted. + /// + public static string administration_muted_pl { + get { + return ResourceManager.GetString("administration_muted_pl", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Muted. + /// + public static string administration_muted_sn { + get { + return ResourceManager.GetString("administration_muted_sn", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New Message. + /// + public static string administration_new_msg { + get { + return ResourceManager.GetString("administration_new_msg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New Nickname. + /// + public static string administration_new_nick { + get { + return ResourceManager.GetString("administration_new_nick", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New Topic. + /// + public static string administration_new_topic { + get { + return ResourceManager.GetString("administration_new_topic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nickname Changed. + /// + public static string administration_nick_change { + get { + return ResourceManager.GetString("administration_nick_change", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Old Message. + /// + public static string administration_old_msg { + get { + return ResourceManager.GetString("administration_old_msg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Old Nickname. + /// + public static string administration_old_nick { + get { + return ResourceManager.GetString("administration_old_nick", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Old Topic. + /// + public static string administration_old_topic { + get { + return ResourceManager.GetString("administration_old_topic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to soft-banned (kicked). + /// + public static string administration_soft_banned_pl { + get { + return ResourceManager.GetString("administration_soft_banned_pl", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Text Channel Destroyed . + /// + public static string administration_text_chan_created { + get { + return ResourceManager.GetString("administration_text_chan_created", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Text Channel Destroyed . + /// + public static string administration_text_chan_destroyed { + get { + return ResourceManager.GetString("administration_text_chan_destroyed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unmuted. + /// + public static string administration_unmuted_sn { + get { + return ResourceManager.GetString("administration_unmuted_sn", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User Banned. + /// + public static string administration_user_banned { + get { + return ResourceManager.GetString("administration_user_banned", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} has been **muted** from chatting.. /// @@ -213,6 +510,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to User Joined. + /// + public static string administration_user_joined { + get { + return ResourceManager.GetString("administration_user_joined", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User Left. + /// + public static string administration_user_left { + get { + return ResourceManager.GetString("administration_user_left", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} has been **muted** from text and voice chat.. /// @@ -222,6 +537,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to User's Role Added. + /// + public static string administration_user_role_add { + get { + return ResourceManager.GetString("administration_user_role_add", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User's Role Removed. + /// + public static string administration_user_role_rem { + get { + return ResourceManager.GetString("administration_user_role_rem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} is now {1}. + /// + public static string administration_user_status_change { + get { + return ResourceManager.GetString("administration_user_status_change", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} has been **unmuted** from text and voice chat.. /// @@ -231,6 +573,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to {0} has joined {1} voice channel.. + /// + public static string administration_user_vjoined { + get { + return ResourceManager.GetString("administration_user_vjoined", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has left {1} voice channel.. + /// + public static string administration_user_vleft { + get { + return ResourceManager.GetString("administration_user_vleft", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} moved from {1} to {2} voice channel.. + /// + public static string administration_user_vmoved { + get { + return ResourceManager.GetString("administration_user_vmoved", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} has been **voice muted**.. /// @@ -249,6 +618,87 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Username Changed. + /// + public static string administration_username_changed { + get { + return ResourceManager.GetString("administration_username_changed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Users. + /// + public static string administration_users { + get { + return ResourceManager.GetString("administration_users", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Voice Channel Destroyed. + /// + public static string administration_voice_chan_created { + get { + return ResourceManager.GetString("administration_voice_chan_created", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Voice Channel Destroyed. + /// + public static string administration_voice_chan_destroyed { + get { + return ResourceManager.GetString("administration_voice_chan_destroyed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User {0} from text chat. + /// + public static string administration_xmuted_text { + get { + return ResourceManager.GetString("administration_xmuted_text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User {0} from text and voice chat. + /// + public static string administration_xmuted_text_and_voice { + get { + return ResourceManager.GetString("administration_xmuted_text_and_voice", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User {0} from voice chat. + /// + public static string administration_xmuted_voice { + get { + return ResourceManager.GetString("administration_xmuted_voice", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User Unbanned. + /// + public static string administraton_user_unbanned { + get { + return ResourceManager.GetString("administraton_user_unbanned", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Presence Updates. + /// + public static string adminsitration_presence_updates { + get { + return ResourceManager.GetString("adminsitration_presence_updates", resourceCulture); + } + } + /// /// Looks up a localized string similar to That base is already claimed or destroyed.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index ff566d6c..1fdaa035 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -304,6 +304,28 @@ **Auto assign role** on user join is now **enabled**. + + Attachments + + + Avatar Changed + + + banned + PLURAL + + + Channel Name Changed + + + Old Name + + + Channel Topic Changed + + + Content + DM from @@ -319,6 +341,9 @@ I will stop forwarding DMs from now on. + + {0} has joined {1} + List Of Languages {0} @@ -338,30 +363,160 @@ This server's language is set to {0} - {0} + + {0} has left {1} + + + Logging {0} event in this channel. + + + Logging all events in this channel. + + + Logging disabled. + + + Log events you can subscribe to: + + + Logging will ignore {0} + + + Logging will not ignore {0} + + + Stopped logging {0} event. + + + {0} moved from {1} to {2} + + + Message Deleted in #{0} + + + Message Updated in #{0} + + + Muted + PLURAL (users have been muted) + + + Muted + singular "User muted." + I don't have the permission necessary for that most likely. New mute role set. + + New Message + + + New Nickname + + + New Topic + + + Nickname Changed + + + Old Message + + + Old Nickname + + + Old Topic + + + soft-banned (kicked) + PLURAL + + + Text Channel Destroyed + + + Text Channel Destroyed + + + Unmuted + singular + + + Username Changed + + + Users + + + User Banned + {0} has been **muted** from chatting. {0} has been **unmuted** from chatting. + + User Joined + + + User Left + {0} has been **muted** from text and voice chat. + + User's Role Added + + + User's Role Removed + + + {0} is now {1} + {0} has been **unmuted** from text and voice chat. + + {0} has joined {1} voice channel. + + + {0} has left {1} voice channel. + + + {0} moved from {1} to {2} voice channel. + {0} has been **voice muted**. {0} has been **voice unmuted**. + + Voice Channel Destroyed + + + Voice Channel Destroyed + + + User {0} from text chat + + + User {0} from text and voice chat + + + User {0} from voice chat + + + User Unbanned + + + Presence Updates + Back to ToC From b24e68c24cb48bad0e7dfb94effdefe93025660e Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 19:08:27 +0100 Subject: [PATCH 251/746] migration localized, only 2 responses, won't localize console output --- .../Administration/Commands/Migration.cs | 4 ++-- .../Resources/ResponseStrings.Designer.cs | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/Migration.cs b/src/NadekoBot/Modules/Administration/Commands/Migration.cs index 42798128..8ee6f652 100644 --- a/src/NadekoBot/Modules/Administration/Commands/Migration.cs +++ b/src/NadekoBot/Modules/Administration/Commands/Migration.cs @@ -51,12 +51,12 @@ namespace NadekoBot.Modules.Administration break; } } - await Context.Channel.SendMessageAsync("🆙 **Migration done.**").ConfigureAwait(false); + await ReplyConfirmLocalized("migration_done").ConfigureAwait(false); } catch (Exception ex) { _log.Error(ex); - await Context.Channel.SendMessageAsync("⚠️ **Error while migrating, check `logs` for more informations.**").ConfigureAwait(false); + await ReplyErrorLocalized("migration_error").ConfigureAwait(false); } } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 66ebbe34..c4cdc664 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -690,6 +690,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Migration done!. + /// + public static string adminsitration_migration_done { + get { + return ResourceManager.GetString("adminsitration_migration_done", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error while migrating, check bot's console for more information.. + /// + public static string adminsitration_migration_error { + get { + return ResourceManager.GetString("adminsitration_migration_error", resourceCulture); + } + } + /// /// Looks up a localized string similar to Presence Updates. /// From b890506de6c46d29bdca333922a5092b98304a63 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 19:54:02 +0100 Subject: [PATCH 252/746] localized playing rotate commands --- .../Commands/PlayingRotateCommands.cs | 76 +++++++++---------- .../Resources/ResponseStrings.Designer.cs | 55 ++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 25 ++++++ 3 files changed, 118 insertions(+), 38 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs index 5b06c944..c398de5f 100644 --- a/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/PlayingRotateCommands.cs @@ -1,5 +1,4 @@ -using Discord; -using Discord.Commands; +using Discord.Commands; using Discord.WebSocket; using NadekoBot.Attributes; using NadekoBot.Extensions; @@ -8,7 +7,6 @@ using NadekoBot.Services.Database.Models; using NLog; using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -20,14 +18,15 @@ namespace NadekoBot.Modules.Administration [Group] public class PlayingRotateCommands : NadekoSubmodule { - private static Logger _log { get; } public static List RotatingStatusMessages { get; } - public static bool RotatingStatuses { get; private set; } = false; - private static Timer _t { get; } + public static volatile bool RotatingStatuses; + private readonly object _locker = new object(); + private new static Logger _log { get; } + private static readonly Timer _t; private class TimerState { - public int Index { get; set; } = 0; + public int Index { get; set; } } static PlayingRotateCommands() @@ -37,8 +36,6 @@ namespace NadekoBot.Modules.Administration RotatingStatusMessages = NadekoBot.BotConfig.RotatingStatusMessages; RotatingStatuses = NadekoBot.BotConfig.RotatingStatuses; - - _t = new Timer(async (objState) => { try @@ -46,26 +43,24 @@ namespace NadekoBot.Modules.Administration var state = (TimerState)objState; if (!RotatingStatuses) return; - else - { - if (state.Index >= RotatingStatusMessages.Count) - state.Index = 0; + if (state.Index >= RotatingStatusMessages.Count) + state.Index = 0; - if (!RotatingStatusMessages.Any()) - return; - var status = RotatingStatusMessages[state.Index++].Status; - if (string.IsNullOrWhiteSpace(status)) - return; - PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value())); - var shards = NadekoBot.Client.Shards; - for (int i = 0; i < shards.Count; i++) + if (!RotatingStatusMessages.Any()) + return; + var status = RotatingStatusMessages[state.Index++].Status; + if (string.IsNullOrWhiteSpace(status)) + return; + PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value())); + var shards = NadekoBot.Client.Shards; + for (int i = 0; i < shards.Count; i++) + { + var curShard = shards.ElementAt(i); + ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(curShard))); + try { await shards.ElementAt(i).SetGameAsync(status).ConfigureAwait(false); } + catch (Exception ex) { - ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(shards.ElementAt(i)))); - try { await shards.ElementAt(i).SetGameAsync(status).ConfigureAwait(false); } - catch (Exception ex) - { - _log.Warn(ex); - } + _log.Warn(ex); } } } @@ -107,17 +102,20 @@ namespace NadekoBot.Modules.Administration [OwnerOnly] public async Task RotatePlaying() { - using (var uow = DbHandler.UnitOfWork()) + lock (_locker) { - var config = uow.BotConfig.GetOrCreate(); + using (var uow = DbHandler.UnitOfWork()) + { + var config = uow.BotConfig.GetOrCreate(); - RotatingStatuses = config.RotatingStatuses = !config.RotatingStatuses; - await uow.CompleteAsync(); + RotatingStatuses = config.RotatingStatuses = !config.RotatingStatuses; + uow.Complete(); + } } if (RotatingStatuses) - await Context.Channel.SendConfirmAsync("🆗 **Rotating playing status enabled.**").ConfigureAwait(false); + await ReplyConfirmLocalized("ropl_enabled").ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync("ℹ️ **Rotating playing status disabled.**").ConfigureAwait(false); + await ReplyConfirmLocalized("ropl_disabled").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -133,7 +131,7 @@ namespace NadekoBot.Modules.Administration await uow.CompleteAsync(); } - await Context.Channel.SendConfirmAsync("✅ **Added.**").ConfigureAwait(false); + await ReplyConfirmLocalized("ropl_added").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -141,11 +139,13 @@ namespace NadekoBot.Modules.Administration public async Task ListPlaying() { if (!RotatingStatusMessages.Any()) - await Context.Channel.SendErrorAsync("❎ **No rotating playing statuses set.**"); + await ReplyErrorLocalized("ropl_not_set").ConfigureAwait(false); else { var i = 1; - await Context.Channel.SendConfirmAsync($"ℹ️ {Context.User.Mention} `Here is a list of rotating statuses:`\n\n\t" + string.Join("\n\t", RotatingStatusMessages.Select(rs => $"`{i++}.` {rs.Status}"))); + await ReplyConfirmLocalized("ropl_list", + string.Join("\n\t", RotatingStatusMessages.Select(rs => $"`{i++}.` {rs.Status}"))) + .ConfigureAwait(false); } } @@ -156,7 +156,7 @@ namespace NadekoBot.Modules.Administration { index -= 1; - string msg = ""; + string msg; using (var uow = DbHandler.UnitOfWork()) { var config = uow.BotConfig.GetOrCreate(); @@ -168,7 +168,7 @@ namespace NadekoBot.Modules.Administration RotatingStatusMessages.RemoveAt(index); await uow.CompleteAsync(); } - await Context.Channel.SendConfirmAsync($"🗑 **Removed the the playing message:** {msg}").ConfigureAwait(false); + await ReplyConfirmLocalized("reprm", msg).ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index c4cdc664..042557ed 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -447,6 +447,61 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Removed the playing message: {0}. + /// + public static string administration_reprm { + get { + return ResourceManager.GetString("administration_reprm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Added.. + /// + public static string administration_ropl_added { + get { + return ResourceManager.GetString("administration_ropl_added", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Rotating playing status disabled.. + /// + public static string administration_ropl_disabled { + get { + return ResourceManager.GetString("administration_ropl_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Rotating playing status enabled.. + /// + public static string administration_ropl_enabled { + get { + return ResourceManager.GetString("administration_ropl_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Here is a list of rotating statuses: + ///{0}. + /// + public static string administration_ropl_list { + get { + return ResourceManager.GetString("administration_ropl_list", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No rotating playing statuses set.. + /// + public static string administration_ropl_not_set { + get { + return ResourceManager.GetString("administration_ropl_not_set", resourceCulture); + } + } + /// /// Looks up a localized string similar to soft-banned (kicked). /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 1fdaa035..0f7e0cae 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -431,6 +431,25 @@ Old Topic + + Removed the playing message: {0} + + + Added. + + + Rotating playing status disabled. + + + Rotating playing status enabled. + + + Here is a list of rotating statuses: +{0} + + + No rotating playing statuses set. + soft-banned (kicked) PLURAL @@ -514,6 +533,12 @@ User Unbanned + + Migration done! + + + Error while migrating, check bot's console for more information. + Presence Updates From 9edbd8535a827420f717133963ffdbdf52b153de Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 20:26:48 +0100 Subject: [PATCH 253/746] protection commands localized --- .../Commands/ProtectionCommands.cs | 76 ++++++------- .../Resources/ResponseStrings.Designer.cs | 100 ++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 34 ++++++ 3 files changed, 172 insertions(+), 38 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs index ed85c42d..0cc02896 100644 --- a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs @@ -4,12 +4,10 @@ using Microsoft.EntityFrameworkCore; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; -using NadekoBot.Services.Database; using NadekoBot.Services.Database.Models; using NLog; using System; using System.Collections.Concurrent; -using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Threading.Tasks; @@ -26,12 +24,8 @@ namespace NadekoBot.Modules.Administration public class AntiRaidStats { public AntiRaidSetting AntiRaidSettings { get; set; } - public int UsersCount { get; set; } = 0; + public int UsersCount { get; set; } public ConcurrentHashSet RaidUsers { get; set; } = new ConcurrentHashSet(); - - public override string ToString() => - $"If **{AntiRaidSettings.UserThreshold}** or more users join within **{AntiRaidSettings.Seconds}** seconds," + - $" I will **{AntiRaidSettings.Action}** them."; } public class AntiSpamStats @@ -39,16 +33,6 @@ namespace NadekoBot.Modules.Administration public AntiSpamSetting AntiSpamSettings { get; set; } public ConcurrentDictionary UserStats { get; set; } = new ConcurrentDictionary(); - - public override string ToString() - { - var ignoredString = string.Join(", ", AntiSpamSettings.IgnoredChannels.Select(c => $"<#{c.ChannelId}>")); - - if (string.IsNullOrWhiteSpace(ignoredString)) - ignoredString = "none"; - return $"If a user posts **{AntiSpamSettings.MessageThreshold}** same messages in a row, I will **{AntiSpamSettings.Action}** them." - + $"\n\t__IgnoredChannels__: {ignoredString}"; - } } public class UserSpamStats @@ -84,7 +68,7 @@ namespace NadekoBot.Modules.Administration private static readonly ConcurrentDictionary _antiSpamGuilds = new ConcurrentDictionary(); - private static Logger _log { get; } + private new static readonly Logger _log; static ProtectionCommands() { @@ -141,7 +125,10 @@ namespace NadekoBot.Modules.Administration } } } - catch { } + catch + { + // ignored + } }); return Task.CompletedTask; }; @@ -175,7 +162,10 @@ namespace NadekoBot.Modules.Administration --settings.UsersCount; } - catch { } + catch + { + // ignored + } }); return Task.CompletedTask; }; @@ -219,13 +209,27 @@ namespace NadekoBot.Modules.Administration } catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); } break; - default: - break; } } await LogCommands.TriggeredAntiProtection(gus, action, pt).ConfigureAwait(false); } + private string GetAntiSpamString(AntiSpamStats stats) + { + var ignoredString = string.Join(", ", stats.AntiSpamSettings.IgnoredChannels.Select(c => $"<#{c.ChannelId}>")); + + if (string.IsNullOrWhiteSpace(ignoredString)) + ignoredString = "none"; + return GetText("spam_stats", + Format.Bold(stats.AntiSpamSettings.MessageThreshold.ToString()), + Format.Bold(stats.AntiSpamSettings.Action.ToString()), + ignoredString); + } + + private string GetAntiRaidString(AntiRaidStats stats) => GetText("raid_stats", + Format.Bold(stats.AntiRaidSettings.UserThreshold.ToString()), + Format.Bold(stats.AntiRaidSettings.Seconds.ToString()), + Format.Bold(stats.AntiRaidSettings.Action.ToString())); [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] @@ -234,13 +238,13 @@ namespace NadekoBot.Modules.Administration { if (userThreshold < 2 || userThreshold > 30) { - await Context.Channel.SendErrorAsync("❗️User threshold must be between **2** and **30**.").ConfigureAwait(false); + await ReplyErrorLocalized("raid_cnt", 2, 30).ConfigureAwait(false); return; } if (seconds < 2 || seconds > 300) { - await Context.Channel.SendErrorAsync("❗️Time must be between **2** and **300** seconds.").ConfigureAwait(false); + await ReplyErrorLocalized("raid_time", 2, 300).ConfigureAwait(false); return; } @@ -254,7 +258,7 @@ namespace NadekoBot.Modules.Administration gc.AntiRaidSetting = null; await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync("**Anti-Raid** feature has been **disabled** on this server.").ConfigureAwait(false); + await ReplyConfirmLocalized("prot_disable", "Anti-Raid").ConfigureAwait(false); return; } @@ -264,10 +268,8 @@ namespace NadekoBot.Modules.Administration } catch (Exception ex) { - await Context.Channel.SendConfirmAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" + - "or create 'nadeko-mute' role with disabled SendMessages and try again.") - .ConfigureAwait(false); _log.Warn(ex); + await ReplyErrorLocalized("prot_error").ConfigureAwait(false); return; } @@ -291,7 +293,7 @@ namespace NadekoBot.Modules.Administration await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync("Anti-Raid Enabled", $"{Context.User.Mention} {stats.ToString()}") + await Context.Channel.SendConfirmAsync(GetText("prot_enable", "Anti-Raid"), $"{Context.User.Mention} {GetAntiRaidString(stats)}") .ConfigureAwait(false); } @@ -314,7 +316,7 @@ namespace NadekoBot.Modules.Administration gc.AntiSpamSetting = null; await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync("**Anti-Spam** has been **disabled** on this server.").ConfigureAwait(false); + await ReplyConfirmLocalized("prot_disable", "Anti-Spam").ConfigureAwait(false); return; } @@ -324,10 +326,8 @@ namespace NadekoBot.Modules.Administration } catch (Exception ex) { - await Context.Channel.SendErrorAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" + - "or create 'nadeko-mute' role with disabled SendMessages and try again.") - .ConfigureAwait(false); _log.Warn(ex); + await ReplyErrorLocalized("prot_error").ConfigureAwait(false); return; } @@ -350,7 +350,7 @@ namespace NadekoBot.Modules.Administration await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync("Anti-Spam Enabled", $"{Context.User.Mention} {stats.ToString()}").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync(GetText("prot_enable", "Anti-Spam"), $"{Context.User.Mention} {GetAntiSpamString(stats)}").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -392,9 +392,9 @@ namespace NadekoBot.Modules.Administration await uow.CompleteAsync().ConfigureAwait(false); } if (added) - await Context.Channel.SendConfirmAsync("Anti-Spam will ignore this channel.").ConfigureAwait(false); + await ReplyConfirmLocalized("spam_ignore", "Anti-Spam").ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync("Anti-Spam will no longer ignore this channel.").ConfigureAwait(false); + await ReplyConfirmLocalized("spam_not_ignore", "Anti-Spam").ConfigureAwait(false); } @@ -410,12 +410,12 @@ namespace NadekoBot.Modules.Administration if (spam == null && raid == null) { - await Context.Channel.SendConfirmAsync("No protections enabled."); + await ReplyConfirmLocalized("prot_none").ConfigureAwait(false); return; } var embed = new EmbedBuilder().WithOkColor() - .WithTitle("Protections Enabled"); + .WithTitle(GetText("prot_active")); if (spam != null) embed.AddField(efb => efb.WithName("Anti-Spam") diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 042557ed..ee7d0001 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -447,6 +447,78 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Active Protections. + /// + public static string administration_prot_active { + get { + return ResourceManager.GetString("administration_prot_active", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has been **disabled** on this server.. + /// + public static string administration_prot_disable { + get { + return ResourceManager.GetString("administration_prot_disable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} Enabled. + /// + public static string administration_prot_enable { + get { + return ResourceManager.GetString("administration_prot_enable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error. I need ManageRoles permission. + /// + public static string administration_prot_error { + get { + return ResourceManager.GetString("administration_prot_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No protections enabled.. + /// + public static string administration_prot_none { + get { + return ResourceManager.GetString("administration_prot_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User threshold must be between {0} and {1}.. + /// + public static string administration_raid_cnt { + get { + return ResourceManager.GetString("administration_raid_cnt", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If {0} or more users join within {1} seconds, I will {2} them.. + /// + public static string administration_raid_stats { + get { + return ResourceManager.GetString("administration_raid_stats", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Time must be between {0} and {1} seconds.. + /// + public static string administration_raid_time { + get { + return ResourceManager.GetString("administration_raid_time", resourceCulture); + } + } + /// /// Looks up a localized string similar to Removed the playing message: {0}. /// @@ -511,6 +583,34 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to {0} will ignore this channel.. + /// + public static string administration_spam_ignore { + get { + return ResourceManager.GetString("administration_spam_ignore", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} will no longer ignore this channel.. + /// + public static string administration_spam_not_ignore { + get { + return ResourceManager.GetString("administration_spam_not_ignore", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If a user posts {0} same messages in a row, I will {1} them. + /// __IgnoredChannels__: {2}. + /// + public static string administration_spam_stats { + get { + return ResourceManager.GetString("administration_spam_stats", resourceCulture); + } + } + /// /// Looks up a localized string similar to Text Channel Destroyed . /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 0f7e0cae..45a93e60 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -431,6 +431,30 @@ Old Topic + + Active Protections + + + {0} has been **disabled** on this server. + + + {0} Enabled + + + Error. I need ManageRoles permission + + + No protections enabled. + + + User threshold must be between {0} and {1}. + + + If {0} or more users join within {1} seconds, I will {2} them. + + + Time must be between {0} and {1} seconds. + Removed the playing message: {0} @@ -454,6 +478,16 @@ soft-banned (kicked) PLURAL + + {0} will ignore this channel. + + + {0} will no longer ignore this channel. + + + If a user posts {0} same messages in a row, I will {1} them. + __IgnoredChannels__: {2} + Text Channel Destroyed From bfc10ab3e25a5f794fd505d0f7a36a0d6288aaa6 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 20:28:43 +0100 Subject: [PATCH 254/746] output fix --- .../Modules/Administration/Commands/ProtectionCommands.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs index 0cc02896..8e2bd691 100644 --- a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs @@ -419,12 +419,12 @@ namespace NadekoBot.Modules.Administration if (spam != null) embed.AddField(efb => efb.WithName("Anti-Spam") - .WithValue(spam.ToString()) + .WithValue(GetAntiSpamString(spam)) .WithIsInline(true)); if (raid != null) embed.AddField(efb => efb.WithName("Anti-Raid") - .WithValue(raid.ToString()) + .WithValue(GetAntiRaidString(raid)) .WithIsInline(true)); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); From 6ab8f26cd7e17e80a6f30e30dd521fbd2d9abbae Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 20:35:10 +0100 Subject: [PATCH 255/746] slowmode can now be localized --- .../Commands/RatelimitCommand.cs | 15 ++++---- .../Resources/ResponseStrings.Designer.cs | 36 +++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 12 +++++++ 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs index 5ece6c1d..2a4e111f 100644 --- a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs @@ -16,7 +16,7 @@ namespace NadekoBot.Modules.Administration public class RatelimitCommand : NadekoSubmodule { public static ConcurrentDictionary RatelimitingChannels = new ConcurrentDictionary(); - private static Logger _log { get; } + private new static readonly Logger _log; public class Ratelimiter { @@ -65,9 +65,7 @@ namespace NadekoBot.Modules.Administration try { var usrMsg = umsg as IUserMessage; - if (usrMsg == null) - return; - var channel = usrMsg.Channel as ITextChannel; + var channel = usrMsg?.Channel as ITextChannel; if (channel == null || usrMsg.IsAuthor()) return; @@ -91,8 +89,7 @@ namespace NadekoBot.Modules.Administration if (RatelimitingChannels.TryRemove(Context.Channel.Id, out throwaway)) { throwaway.cancelSource.Cancel(); - await Context.Channel.SendConfirmAsync("ℹ️ Slow mode disabled.").ConfigureAwait(false); - return; + await ReplyConfirmLocalized("slowmode_disabled").ConfigureAwait(false); } } @@ -105,7 +102,7 @@ namespace NadekoBot.Modules.Administration if (msg < 1 || perSec < 1 || msg > 100 || perSec > 3600) { - await Context.Channel.SendErrorAsync("⚠️ Invalid parameters."); + await ReplyErrorLocalized("invalid_params").ConfigureAwait(false); return; } var toAdd = new Ratelimiter() @@ -116,8 +113,8 @@ namespace NadekoBot.Modules.Administration }; if(RatelimitingChannels.TryAdd(Context.Channel.Id, toAdd)) { - await Context.Channel.SendConfirmAsync("Slow mode initiated", - $"Users can't send more than `{toAdd.MaxMessages} message(s)` every `{toAdd.PerSeconds} second(s)`.") + await Context.Channel.SendConfirmAsync(GetText("slowmode_init"), + GetText("slowmode_desc", Format.Bold(toAdd.MaxMessages.ToString()), Format.Bold(toAdd.PerSeconds.ToString()))) .ConfigureAwait(false); } } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index ee7d0001..5ed8eb66 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -185,6 +185,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Invalid parameters.. + /// + public static string administration_invalid_params { + get { + return ResourceManager.GetString("administration_invalid_params", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} has joined {1}. /// @@ -574,6 +583,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Users can't send more than {0} messages every {1} seconds.. + /// + public static string administration_slowmode_desc { + get { + return ResourceManager.GetString("administration_slowmode_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Slow mode disabled.. + /// + public static string administration_slowmode_disabled { + get { + return ResourceManager.GetString("administration_slowmode_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Slow mode initiated. + /// + public static string administration_slowmode_init { + get { + return ResourceManager.GetString("administration_slowmode_init", resourceCulture); + } + } + /// /// Looks up a localized string similar to soft-banned (kicked). /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 45a93e60..6bb626c3 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -341,6 +341,9 @@ I will stop forwarding DMs from now on. + + Invalid parameters. + {0} has joined {1} @@ -474,6 +477,15 @@ No rotating playing statuses set. + + Users can't send more than {0} messages every {1} seconds. + + + Slow mode disabled. + + + Slow mode initiated + soft-banned (kicked) PLURAL From fd81b2de26aa05bfcb29f03dc69684c98975a173 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 21:47:46 +0100 Subject: [PATCH 256/746] self assigned role commands can now be localized :3 --- .../Commands/SelfAssignedRolesCommand.cs | 62 +++++---- .../Resources/ResponseStrings.Designer.cs | 126 ++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 43 ++++++ 3 files changed, 199 insertions(+), 32 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs b/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs index 73327f87..7fd35dfc 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs @@ -44,25 +44,30 @@ namespace NadekoBot.Modules.Administration IEnumerable roles; string msg; + var error = false; using (var uow = DbHandler.UnitOfWork()) { roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id); if (roles.Any(s => s.RoleId == role.Id && s.GuildId == role.Guild.Id)) { - await Context.Channel.SendMessageAsync($"💢 Role **{role.Name}** is already in the list.").ConfigureAwait(false); - return; + msg = GetText("role_in_list", Format.Bold(role.Name)); + error = true; } else { - uow.SelfAssignedRoles.Add(new SelfAssignedRole { + uow.SelfAssignedRoles.Add(new SelfAssignedRole + { RoleId = role.Id, GuildId = role.Guild.Id }); await uow.CompleteAsync(); - msg = $"🆗 Role **{role.Name}** added to the list."; + msg = GetText("role_added", Format.Bold(role.Name)); } } - await Context.Channel.SendConfirmAsync(msg.ToString()).ConfigureAwait(false); + if (error) + await Context.Channel.SendErrorAsync(msg).ConfigureAwait(false); + else + await Context.Channel.SendConfirmAsync(msg).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -70,8 +75,6 @@ namespace NadekoBot.Modules.Administration [RequireUserPermission(GuildPermission.ManageRoles)] public async Task Rsar([Remainder] IRole role) { - //var channel = (ITextChannel)Context.Channel; - bool success; using (var uow = DbHandler.UnitOfWork()) { @@ -80,18 +83,16 @@ namespace NadekoBot.Modules.Administration } if (!success) { - await Context.Channel.SendErrorAsync("❎ That role is not self-assignable.").ConfigureAwait(false); + await ReplyErrorLocalized("self_assign_not").ConfigureAwait(false); return; } - await Context.Channel.SendConfirmAsync($"🗑 **{role.Name}** has been removed from the list of self-assignable roles.").ConfigureAwait(false); + await ReplyConfirmLocalized("self_assign_rem", Format.Bold(role.Name)).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task Lsar() { - //var channel = (ITextChannel)Context.Channel; - var toRemove = new ConcurrentHashSet(); var removeMsg = new StringBuilder(); var msg = new StringBuilder(); @@ -116,11 +117,11 @@ namespace NadekoBot.Modules.Administration } foreach (var role in toRemove) { - removeMsg.AppendLine($"`{role.RoleId} not found. Cleaned up.`"); + removeMsg.AppendLine(GetText("role_clean", role.RoleId)); } await uow.CompleteAsync(); } - await Context.Channel.SendConfirmAsync($"ℹ️ There are `{roleCnt}` self assignable roles:", msg.ToString() + "\n\n" + removeMsg.ToString()).ConfigureAwait(false); + await Context.Channel.SendConfirmAsync(GetText("self_assign_list", roleCnt), msg + "\n\n" + removeMsg).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -128,8 +129,6 @@ namespace NadekoBot.Modules.Administration [RequireUserPermission(GuildPermission.ManageRoles)] public async Task Tesar() { - //var channel = (ITextChannel)Context.Channel; - bool areExclusive; using (var uow = DbHandler.UnitOfWork()) { @@ -138,15 +137,16 @@ namespace NadekoBot.Modules.Administration areExclusive = config.ExclusiveSelfAssignedRoles = !config.ExclusiveSelfAssignedRoles; await uow.CompleteAsync(); } - string exl = areExclusive ? "**exclusive**." : "**not exclusive**."; - await Context.Channel.SendConfirmAsync("ℹ️ Self assigned roles are now " + exl); + if(areExclusive) + await ReplyConfirmLocalized("self_assign_excl").ConfigureAwait(false); + else + await ReplyConfirmLocalized("self_assign_no_excl").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task Iam([Remainder] IRole role) { - //var channel = (ITextChannel)Context.Channel; var guildUser = (IGuildUser)Context.User; GuildConfig conf; @@ -156,25 +156,24 @@ namespace NadekoBot.Modules.Administration conf = uow.GuildConfigs.For(Context.Guild.Id, set => set); roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id); } - SelfAssignedRole roleModel; - if ((roleModel = roles.FirstOrDefault(r=>r.RoleId == role.Id)) == null) + if (roles.FirstOrDefault(r=>r.RoleId == role.Id) == null) { - await Context.Channel.SendErrorAsync("That role is not self-assignable.").ConfigureAwait(false); + await ReplyErrorLocalized("self_assign_not").ConfigureAwait(false); return; } if (guildUser.RoleIds.Contains(role.Id)) { - await Context.Channel.SendErrorAsync($"You already have **{role.Name}** role.").ConfigureAwait(false); + await ReplyErrorLocalized("self_assign_already", Format.Bold(role.Name)).ConfigureAwait(false); return; } if (conf.ExclusiveSelfAssignedRoles) { - var sameRoleId = guildUser.RoleIds.Where(r => roles.Select(sar => sar.RoleId).Contains(r)).FirstOrDefault(); + var sameRoleId = guildUser.RoleIds.FirstOrDefault(r => roles.Select(sar => sar.RoleId).Contains(r)); var sameRole = Context.Guild.GetRole(sameRoleId); if (sameRoleId != default(ulong)) { - await Context.Channel.SendErrorAsync($"You already have **{sameRole?.Name}** `exclusive self-assigned` role.").ConfigureAwait(false); + await ReplyErrorLocalized("self_assign_already_excl", Format.Bold(sameRole?.Name)).ConfigureAwait(false); return; } } @@ -184,11 +183,11 @@ namespace NadekoBot.Modules.Administration } catch (Exception ex) { - await Context.Channel.SendErrorAsync($"⚠️ I am unable to add that role to you. `I can't add roles to owners or other roles higher than my role in the role hierarchy.`").ConfigureAwait(false); + await ReplyErrorLocalized("self_assign_perms").ConfigureAwait(false); Console.WriteLine(ex); return; } - var msg = await Context.Channel.SendConfirmAsync($"🆗 You now have **{role.Name}** role.").ConfigureAwait(false); + var msg = await ReplyConfirmLocalized("self_assign_success",Format.Bold(role.Name)).ConfigureAwait(false); if (conf.AutoDeleteSelfAssignedRoleMessages) { @@ -210,15 +209,14 @@ namespace NadekoBot.Modules.Administration autoDeleteSelfAssignedRoleMessages = uow.GuildConfigs.For(Context.Guild.Id, set => set).AutoDeleteSelfAssignedRoleMessages; roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id); } - SelfAssignedRole roleModel; - if ((roleModel = roles.FirstOrDefault(r => r.RoleId == role.Id)) == null) + if (roles.FirstOrDefault(r => r.RoleId == role.Id) == null) { - await Context.Channel.SendErrorAsync("💢 That role is not self-assignable.").ConfigureAwait(false); + await ReplyErrorLocalized("self_assign_not").ConfigureAwait(false); return; } if (!guildUser.RoleIds.Contains(role.Id)) { - await Context.Channel.SendErrorAsync($"❎ You don't have **{role.Name}** role.").ConfigureAwait(false); + await ReplyErrorLocalized("self_assign_not_have",Format.Bold(role.Name)).ConfigureAwait(false); return; } try @@ -227,10 +225,10 @@ namespace NadekoBot.Modules.Administration } catch (Exception) { - await Context.Channel.SendErrorAsync($"⚠️ I am unable to add that role to you. `I can't remove roles to owners or other roles higher than my role in the role hierarchy.`").ConfigureAwait(false); + await ReplyErrorLocalized("self_assign_perms").ConfigureAwait(false); return; } - var msg = await Context.Channel.SendConfirmAsync($"🆗 You no longer have **{role.Name}** role.").ConfigureAwait(false); + var msg = await ReplyConfirmLocalized("self_assign_remove", Format.Bold(role.Name)).ConfigureAwait(false); if (autoDeleteSelfAssignedRoleMessages) { diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 5ed8eb66..5afd534e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -59,6 +59,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to You already have {0} role.. + /// + public static string administartion_self_assign_already { + get { + return ResourceManager.GetString("administartion_self_assign_already", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You no longer have {0} role.. + /// + public static string administartion_self_assign_remove { + get { + return ResourceManager.GetString("administartion_self_assign_remove", resourceCulture); + } + } + /// /// Looks up a localized string similar to **Auto assign role** on user join is now **disabled**.. /// @@ -537,6 +555,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Role {0} as been added to the list.. + /// + public static string administration_role_added { + get { + return ResourceManager.GetString("administration_role_added", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} not found.Cleaned up.. + /// + public static string administration_role_clean { + get { + return ResourceManager.GetString("administration_role_clean", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Role {0} is already in the list.. + /// + public static string administration_role_in_list { + get { + return ResourceManager.GetString("administration_role_in_list", resourceCulture); + } + } + /// /// Looks up a localized string similar to Added.. /// @@ -583,6 +628,87 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to You already have {0} exclusive self-assigned role.. + /// + public static string administration_self_assign_already_excl { + get { + return ResourceManager.GetString("administration_self_assign_already_excl", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Self assigned roles are now exclusive!. + /// + public static string administration_self_assign_excl { + get { + return ResourceManager.GetString("administration_self_assign_excl", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to There are {0} self assignable roles. + /// + public static string administration_self_assign_list { + get { + return ResourceManager.GetString("administration_self_assign_list", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Self assigned roles are now not exclusive!. + /// + public static string administration_self_assign_no_excl { + get { + return ResourceManager.GetString("administration_self_assign_no_excl", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to That role is not self-assignable.. + /// + public static string administration_self_assign_not { + get { + return ResourceManager.GetString("administration_self_assign_not", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You don't have {0} role.. + /// + public static string administration_self_assign_not_have { + get { + return ResourceManager.GetString("administration_self_assign_not_have", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I am unable to add that role to you. `I can't add roles to owners or other roles higher than my role in the role hierarchy.`. + /// + public static string administration_self_assign_perms { + get { + return ResourceManager.GetString("administration_self_assign_perms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has been removed from the list of self-assignable roles.. + /// + public static string administration_self_assign_rem { + get { + return ResourceManager.GetString("administration_self_assign_rem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You now have {0} role.. + /// + public static string administration_self_assign_sucess { + get { + return ResourceManager.GetString("administration_self_assign_sucess", resourceCulture); + } + } + /// /// Looks up a localized string similar to Users can't send more than {0} messages every {1} seconds.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 6bb626c3..1d1aaaca 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -298,6 +298,12 @@ You fainted, so you are not able to move! + + You already have {0} role. + + + You no longer have {0} role. + **Auto assign role** on user join is now **disabled**. @@ -461,6 +467,15 @@ Removed the playing message: {0} + + Role {0} is added to the list. + + + {0} not found.Cleaned up. + + + Role {0} is already in the list. + Added. @@ -477,6 +492,34 @@ No rotating playing statuses set. + + You already have {0} exclusive self-assigned role. + + + Self assigned roles are now exclusive! + + + There are {0} self assignable roles: +{1} + + + That role is not self-assignable. + + + You don't have {0} role. + + + Self assigned roles are now not exclusive! + + + I am unable to add that role to you. `I can't add roles to owners or other roles higher than my role in the role hierarchy.` + + + {0} has been removed from the list of self-assignable roles. + + + You now have {0} role. + Users can't send more than {0} messages every {1} seconds. From fdc41caed159e12aae9cdcaa8023b8655daee40e Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 22:07:28 +0100 Subject: [PATCH 257/746] self commands done too --- .../Administration/Commands/SelfCommands.cs | 41 ++-- .../Resources/ResponseStrings.Designer.cs | 180 ++++++++++++++++-- src/NadekoBot/Resources/ResponseStrings.resx | 67 ++++++- 3 files changed, 244 insertions(+), 44 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index b67f5d3e..0dfb3d0a 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -102,14 +102,14 @@ namespace NadekoBot.Modules.Administration if (shard == null) { - await Context.Channel.SendErrorAsync("No shard by that id found.").ConfigureAwait(false); + await ReplyErrorLocalized("no_shard_id").ConfigureAwait(false); return; } try { - await Context.Channel.SendConfirmAsync($"Shard **#{shardid}** reconnecting.").ConfigureAwait(false); + await ReplyConfirmLocalized("shard_reconnecting", Format.Bold("#" + shardid)).ConfigureAwait(false); await shard.ConnectAsync().ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"Shard **#{shardid}** reconnected.").ConfigureAwait(false); + await ReplyConfirmLocalized("shard_reconnected", Format.Bold("#" + shardid)).ConfigureAwait(false); } catch (Exception ex) { @@ -127,18 +127,18 @@ namespace NadekoBot.Modules.Administration if (server == null) { - await Context.Channel.SendErrorAsync("⚠️ Cannot find that server").ConfigureAwait(false); + await ReplyErrorLocalized("no_server").ConfigureAwait(false); return; } if (server.OwnerId != NadekoBot.Client.CurrentUser.Id) { await server.LeaveAsync().ConfigureAwait(false); - await Context.Channel.SendConfirmAsync("✅ Left server " + server.Name).ConfigureAwait(false); + await ReplyConfirmLocalized("left_server", Format.Bold(server.Name)).ConfigureAwait(false); } else { await server.DeleteAsync().ConfigureAwait(false); - await Context.Channel.SendConfirmAsync("Deleted server " + server.Name).ConfigureAwait(false); + await ReplyConfirmLocalized("deleted_server",Format.Bold(server.Name)).ConfigureAwait(false); } } @@ -147,7 +147,14 @@ namespace NadekoBot.Modules.Administration [OwnerOnly] public async Task Die() { - try { await Context.Channel.SendConfirmAsync("ℹ️ **Shutting down.**").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } + try + { + await ReplyConfirmLocalized("shutting_down").ConfigureAwait(false); + } + catch + { + // ignored + } await Task.Delay(2000).ConfigureAwait(false); Environment.Exit(0); } @@ -161,7 +168,7 @@ namespace NadekoBot.Modules.Administration await NadekoBot.Client.CurrentUser.ModifyAsync(u => u.Username = newName).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"Bot name changed to **{newName}**").ConfigureAwait(false); + await ReplyConfirmLocalized("bot_name", Format.Bold(newName)).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -170,7 +177,7 @@ namespace NadekoBot.Modules.Administration { await NadekoBot.Client.SetStatusAsync(SettableUserStatusToUserStatus(status)).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"Bot status changed to **{status}**").ConfigureAwait(false); + await ReplyConfirmLocalized("bot_status", Format.Bold(status.ToString())).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -192,7 +199,7 @@ namespace NadekoBot.Modules.Administration } } - await Context.Channel.SendConfirmAsync("🆒 **New avatar set.**").ConfigureAwait(false); + await ReplyConfirmLocalized("set_avatar").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -201,7 +208,7 @@ namespace NadekoBot.Modules.Administration { await NadekoBot.Client.SetGameAsync(game).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync("👾 **New game set.**").ConfigureAwait(false); + await ReplyConfirmLocalized("set_game").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -212,7 +219,7 @@ namespace NadekoBot.Modules.Administration await NadekoBot.Client.SetGameAsync(name, url, StreamType.Twitch).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync("ℹ️ **New stream set.**").ConfigureAwait(false); + await ReplyConfirmLocalized("set_stream").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -253,8 +260,10 @@ namespace NadekoBot.Modules.Administration } else { - await Context.Channel.SendErrorAsync("⚠️ Invalid format.").ConfigureAwait(false); + await ReplyErrorLocalized("invalid_format").ConfigureAwait(false); + return; } + await ReplyConfirmLocalized("message_sent").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -264,10 +273,10 @@ namespace NadekoBot.Modules.Administration var channels = NadekoBot.Client.GetGuilds().Select(g => g.DefaultChannel).ToArray(); if (channels == null) return; - await Task.WhenAll(channels.Where(c => c != null).Select(c => c.SendConfirmAsync($"🆕 Message from {Context.User} `[Bot Owner]`:", message))) + await Task.WhenAll(channels.Where(c => c != null).Select(c => c.SendConfirmAsync(GetText("message_from_bo", Context.User.ToString()), message))) .ConfigureAwait(false); - await Context.Channel.SendConfirmAsync("🆗").ConfigureAwait(false); + await ReplyConfirmLocalized("message_sent").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -275,7 +284,7 @@ namespace NadekoBot.Modules.Administration public async Task ReloadImages() { var time = await NadekoBot.Images.Reload().ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"Images loaded after {time.TotalSeconds:F3}s!").ConfigureAwait(false); + await ReplyConfirmLocalized("images_loaded", time.TotalSeconds.ToString("F3")).ConfigureAwait(false); } private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus) diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 5afd534e..74cc34e8 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -59,24 +59,6 @@ namespace NadekoBot.Resources { } } - /// - /// Looks up a localized string similar to You already have {0} role.. - /// - public static string administartion_self_assign_already { - get { - return ResourceManager.GetString("administartion_self_assign_already", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You no longer have {0} role.. - /// - public static string administartion_self_assign_remove { - get { - return ResourceManager.GetString("administartion_self_assign_remove", resourceCulture); - } - } - /// /// Looks up a localized string similar to **Auto assign role** on user join is now **disabled**.. /// @@ -122,6 +104,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Bot name changed to {0}. + /// + public static string administration_bot_name { + get { + return ResourceManager.GetString("administration_bot_name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bot status changed to {0}. + /// + public static string administration_bot_status { + get { + return ResourceManager.GetString("administration_bot_status", resourceCulture); + } + } + /// /// Looks up a localized string similar to Channel Name Changed. /// @@ -158,6 +158,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Deleted server {0}. + /// + public static string administration_deleted_server { + get { + return ResourceManager.GetString("administration_deleted_server", resourceCulture); + } + } + /// /// Looks up a localized string similar to DM from. /// @@ -203,6 +212,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Images loaded after {0} seconds!. + /// + public static string administration_images_loaded { + get { + return ResourceManager.GetString("administration_images_loaded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid input format.. + /// + public static string administration_invalid_format { + get { + return ResourceManager.GetString("administration_invalid_format", resourceCulture); + } + } + /// /// Looks up a localized string similar to Invalid parameters.. /// @@ -285,6 +312,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Left server {0}. + /// + public static string administration_left_server { + get { + return ResourceManager.GetString("administration_left_server", resourceCulture); + } + } + /// /// Looks up a localized string similar to Logging {0} event in this channel.. /// @@ -348,6 +384,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Message from {0} `[Bot Owner]`:. + /// + public static string administration_message_from_bo { + get { + return ResourceManager.GetString("administration_message_from_bo", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Message sent.. + /// + public static string administration_message_sent { + get { + return ResourceManager.GetString("administration_message_sent", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} moved from {1} to {2}. /// @@ -447,6 +501,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Can't find that server. + /// + public static string administration_no_server { + get { + return ResourceManager.GetString("administration_no_server", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No shard with that ID found.. + /// + public static string administration_no_shard_id { + get { + return ResourceManager.GetString("administration_no_shard_id", resourceCulture); + } + } + /// /// Looks up a localized string similar to Old Message. /// @@ -628,6 +700,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to You already have {0} role.. + /// + public static string administration_self_assign_already { + get { + return ResourceManager.GetString("administration_self_assign_already", resourceCulture); + } + } + /// /// Looks up a localized string similar to You already have {0} exclusive self-assigned role.. /// @@ -700,6 +781,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to You no longer have {0} role.. + /// + public static string administration_self_assign_remove { + get { + return ResourceManager.GetString("administration_self_assign_remove", resourceCulture); + } + } + /// /// Looks up a localized string similar to You now have {0} role.. /// @@ -709,6 +799,60 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to New avatar set!. + /// + public static string administration_set_avatar { + get { + return ResourceManager.GetString("administration_set_avatar", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New game set!. + /// + public static string administration_set_game { + get { + return ResourceManager.GetString("administration_set_game", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New stream set!. + /// + public static string administration_set_stream { + get { + return ResourceManager.GetString("administration_set_stream", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shard {0} reconnected.. + /// + public static string administration_shard_reconnected { + get { + return ResourceManager.GetString("administration_shard_reconnected", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shard {0} reconnecting.. + /// + public static string administration_shard_reconnecting { + get { + return ResourceManager.GetString("administration_shard_reconnecting", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shutting down. + /// + public static string administration_shutting_down { + get { + return ResourceManager.GetString("administration_shutting_down", resourceCulture); + } + } + /// /// Looks up a localized string similar to Users can't send more than {0} messages every {1} seconds.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 1d1aaaca..382b6c14 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -298,12 +298,6 @@ You fainted, so you are not able to move! - - You already have {0} role. - - - You no longer have {0} role. - **Auto assign role** on user join is now **disabled**. @@ -320,6 +314,12 @@ banned PLURAL + + Bot name changed to {0} + + + Bot status changed to {0} + Channel Name Changed @@ -332,6 +332,9 @@ Content + + Deleted server {0} + DM from @@ -347,6 +350,12 @@ I will stop forwarding DMs from now on. + + Images loaded after {0} seconds! + + + Invalid input format. + Invalid parameters. @@ -375,6 +384,9 @@ {0} has left {1} + + Left server {0} + Logging {0} event in this channel. @@ -396,6 +408,12 @@ Stopped logging {0} event. + + Message from {0} `[Bot Owner]`: + + + Message sent. + {0} moved from {1} to {2} @@ -431,6 +449,12 @@ Nickname Changed + + Can't find that server + + + No shard with that ID found. + Old Message @@ -468,7 +492,7 @@ Removed the playing message: {0} - Role {0} is added to the list. + Role {0} as been added to the list. {0} not found.Cleaned up. @@ -492,6 +516,9 @@ No rotating playing statuses set. + + You already have {0} role. + You already have {0} exclusive self-assigned role. @@ -499,8 +526,7 @@ Self assigned roles are now exclusive! - There are {0} self assignable roles: -{1} + There are {0} self assignable roles That role is not self-assignable. @@ -517,9 +543,30 @@ {0} has been removed from the list of self-assignable roles. - + + You no longer have {0} role. + + You now have {0} role. + + New avatar set! + + + New game set! + + + New stream set! + + + Shard {0} reconnected. + + + Shard {0} reconnecting. + + + Shutting down + Users can't send more than {0} messages every {1} seconds. From 431f328bb464bf5a11c45058ac9c9350b1d540e6 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 22:33:54 +0100 Subject: [PATCH 258/746] greet commands done and EVEN tested!1!! --- .../Commands/ServerGreetCommands.cs | 64 ++++--- .../Resources/ResponseStrings.Designer.cs | 171 ++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 57 ++++++ 3 files changed, 259 insertions(+), 33 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs index b3f79c83..b64df312 100644 --- a/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/ServerGreetCommands.cs @@ -1,11 +1,9 @@ using Discord; using Discord.Commands; -using Discord.WebSocket; using NadekoBot.Attributes; using NadekoBot.DataStructures; using NadekoBot.Extensions; using NadekoBot.Services; -using NadekoBot.Services.Database; using NadekoBot.Services.Database.Models; using NLog; using System; @@ -55,7 +53,7 @@ namespace NadekoBot.Modules.Administration private new static Logger _log { get; } - private static ConcurrentDictionary GuildConfigsCache { get; } = new ConcurrentDictionary(); + private static ConcurrentDictionary guildConfigsCache { get; } static ServerGreetCommands() { @@ -63,13 +61,13 @@ namespace NadekoBot.Modules.Administration NadekoBot.Client.UserLeft += UserLeft; _log = LogManager.GetCurrentClassLogger(); - GuildConfigsCache = new ConcurrentDictionary(NadekoBot.AllGuildConfigs.ToDictionary(g => g.GuildId, (g) => GreetSettings.Create(g))); + guildConfigsCache = new ConcurrentDictionary(NadekoBot.AllGuildConfigs.ToDictionary(g => g.GuildId, GreetSettings.Create)); } private static GreetSettings GetOrAddSettingsForGuild(ulong guildId) { GreetSettings settings; - GuildConfigsCache.TryGetValue(guildId, out settings); + guildConfigsCache.TryGetValue(guildId, out settings); if (settings != null) return settings; @@ -80,7 +78,7 @@ namespace NadekoBot.Modules.Administration settings = GreetSettings.Create(gc); } - GuildConfigsCache.TryAdd(guildId, settings); + guildConfigsCache.TryAdd(guildId, settings); return settings; } @@ -234,9 +232,9 @@ namespace NadekoBot.Modules.Administration await ServerGreetCommands.SetGreetDel(Context.Guild.Id, timer).ConfigureAwait(false); if (timer > 0) - await Context.Channel.SendConfirmAsync($"🆗 Greet messages **will be deleted** after `{timer} seconds`.").ConfigureAwait(false); + await ReplyConfirmLocalized("greetdel_on", timer).ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync("ℹ️ Automatic deletion of greet messages has been **disabled**.").ConfigureAwait(false); + await ReplyConfirmLocalized("greetdel_off").ConfigureAwait(false); } private static async Task SetGreetDel(ulong id, int timer) @@ -250,7 +248,7 @@ namespace NadekoBot.Modules.Administration conf.AutoDeleteGreetMessagesTimer = timer; var toAdd = GreetSettings.Create(conf); - GuildConfigsCache.AddOrUpdate(id, toAdd, (key, old) => toAdd); + guildConfigsCache.AddOrUpdate(id, toAdd, (key, old) => toAdd); await uow.CompleteAsync().ConfigureAwait(false); } @@ -264,9 +262,9 @@ namespace NadekoBot.Modules.Administration var enabled = await ServerGreetCommands.SetGreet(Context.Guild.Id, Context.Channel.Id).ConfigureAwait(false); if (enabled) - await Context.Channel.SendConfirmAsync("✅ Greeting messages **enabled** on this channel.").ConfigureAwait(false); + await ReplyConfirmLocalized("greet_on").ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync("ℹ️ Greeting messages **disabled**.").ConfigureAwait(false); + await ReplyConfirmLocalized("greet_off").ConfigureAwait(false); } private static async Task SetGreet(ulong guildId, ulong channelId, bool? value = null) @@ -279,7 +277,7 @@ namespace NadekoBot.Modules.Administration conf.GreetMessageChannelId = channelId; var toAdd = GreetSettings.Create(conf); - GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); + guildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); await uow.CompleteAsync().ConfigureAwait(false); } @@ -298,15 +296,15 @@ namespace NadekoBot.Modules.Administration { channelGreetMessageText = uow.GuildConfigs.For(Context.Guild.Id, set => set).ChannelGreetMessageText; } - await Context.Channel.SendConfirmAsync("Current greet message: ", channelGreetMessageText?.SanitizeMentions()); + await ReplyConfirmLocalized("greetmsg_cur", channelGreetMessageText?.SanitizeMentions()).ConfigureAwait(false); return; } var sendGreetEnabled = ServerGreetCommands.SetGreetMessage(Context.Guild.Id, ref text); - await Context.Channel.SendConfirmAsync("🆗 New greet message **set**.").ConfigureAwait(false); + await ReplyConfirmLocalized("greetmsg_new").ConfigureAwait(false); if (!sendGreetEnabled) - await Context.Channel.SendConfirmAsync("ℹ️ Enable greet messsages by typing `.greet`").ConfigureAwait(false); + await ReplyConfirmLocalized("greetmsg_enable", $"`{Prefix}greet`").ConfigureAwait(false); } public static bool SetGreetMessage(ulong guildId, ref string message) @@ -324,7 +322,7 @@ namespace NadekoBot.Modules.Administration greetMsgEnabled = conf.SendChannelGreetMessage; var toAdd = GreetSettings.Create(conf); - GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); + guildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); uow.Complete(); } @@ -339,9 +337,9 @@ namespace NadekoBot.Modules.Administration var enabled = await ServerGreetCommands.SetGreetDm(Context.Guild.Id).ConfigureAwait(false); if (enabled) - await Context.Channel.SendConfirmAsync("🆗 DM Greet announcements **enabled**.").ConfigureAwait(false); + await ReplyConfirmLocalized("greetdm_on").ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync("ℹ️ Greet announcements **disabled**.").ConfigureAwait(false); + await ReplyConfirmLocalized("greetdm_off").ConfigureAwait(false); } private static async Task SetGreetDm(ulong guildId, bool? value = null) @@ -353,7 +351,7 @@ namespace NadekoBot.Modules.Administration enabled = conf.SendDmGreetMessage = value ?? !conf.SendDmGreetMessage; var toAdd = GreetSettings.Create(conf); - GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); + guildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); await uow.CompleteAsync().ConfigureAwait(false); } @@ -372,15 +370,15 @@ namespace NadekoBot.Modules.Administration { config = uow.GuildConfigs.For(Context.Guild.Id); } - await Context.Channel.SendConfirmAsync("ℹ️ Current **DM greet** message: `" + config.DmGreetMessageText?.SanitizeMentions() + "`"); + await ReplyConfirmLocalized("greetdmmsg_cur", config.DmGreetMessageText?.SanitizeMentions()).ConfigureAwait(false); return; } var sendGreetEnabled = ServerGreetCommands.SetGreetDmMessage(Context.Guild.Id, ref text); - await Context.Channel.SendConfirmAsync("🆗 New DM greet message **set**.").ConfigureAwait(false); + await ReplyConfirmLocalized("greetdmmsg_new").ConfigureAwait(false); if (!sendGreetEnabled) - await Context.Channel.SendConfirmAsync($"ℹ️ Enable DM greet messsages by typing `{Prefix}greetdm`").ConfigureAwait(false); + await ReplyConfirmLocalized("greetdmmsg_enable", $"`{Prefix}greetdm`").ConfigureAwait(false); } public static bool SetGreetDmMessage(ulong guildId, ref string message) @@ -398,7 +396,7 @@ namespace NadekoBot.Modules.Administration greetMsgEnabled = conf.SendDmGreetMessage; var toAdd = GreetSettings.Create(conf); - GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); + guildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); uow.Complete(); } @@ -413,9 +411,9 @@ namespace NadekoBot.Modules.Administration var enabled = await ServerGreetCommands.SetBye(Context.Guild.Id, Context.Channel.Id).ConfigureAwait(false); if (enabled) - await Context.Channel.SendConfirmAsync("✅ Bye announcements **enabled** on this channel.").ConfigureAwait(false); + await ReplyConfirmLocalized("bye_on").ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync("ℹ️ Bye announcements **disabled**.").ConfigureAwait(false); + await ReplyConfirmLocalized("bye_off").ConfigureAwait(false); } private static async Task SetBye(ulong guildId, ulong channelId, bool? value = null) @@ -428,7 +426,7 @@ namespace NadekoBot.Modules.Administration conf.ByeMessageChannelId = channelId; var toAdd = GreetSettings.Create(conf); - GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); + guildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); await uow.CompleteAsync(); } @@ -447,15 +445,15 @@ namespace NadekoBot.Modules.Administration { byeMessageText = uow.GuildConfigs.For(Context.Guild.Id, set => set).ChannelByeMessageText; } - await Context.Channel.SendConfirmAsync("ℹ️ Current **bye** message: `" + byeMessageText?.SanitizeMentions() + "`"); + await ReplyConfirmLocalized("byemsg_cur", byeMessageText?.SanitizeMentions()).ConfigureAwait(false); return; } var sendByeEnabled = ServerGreetCommands.SetByeMessage(Context.Guild.Id, ref text); - await Context.Channel.SendConfirmAsync("🆗 New bye message **set**.").ConfigureAwait(false); + await ReplyConfirmLocalized("byemsg_new").ConfigureAwait(false); if (!sendByeEnabled) - await Context.Channel.SendConfirmAsync($"ℹ️ Enable bye messsages by typing `{Prefix}bye`").ConfigureAwait(false); + await ReplyConfirmLocalized("byemsg_enable", $"`{Prefix}bye`").ConfigureAwait(false); } public static bool SetByeMessage(ulong guildId, ref string message) @@ -473,7 +471,7 @@ namespace NadekoBot.Modules.Administration byeMsgEnabled = conf.SendChannelByeMessage; var toAdd = GreetSettings.Create(conf); - GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); + guildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); uow.Complete(); } @@ -488,9 +486,9 @@ namespace NadekoBot.Modules.Administration await ServerGreetCommands.SetByeDel(Context.Guild.Id, timer).ConfigureAwait(false); if (timer > 0) - await Context.Channel.SendConfirmAsync($"🆗 Bye messages **will be deleted** after `{timer} seconds`.").ConfigureAwait(false); + await ReplyConfirmLocalized("byedel_on", timer).ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync("ℹ️ Automatic deletion of bye messages has been **disabled**.").ConfigureAwait(false); + await ReplyConfirmLocalized("byedel_off").ConfigureAwait(false); } private static async Task SetByeDel(ulong guildId, int timer) @@ -504,7 +502,7 @@ namespace NadekoBot.Modules.Administration conf.AutoDeleteByeMessagesTimer = timer; var toAdd = GreetSettings.Create(conf); - GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); + guildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd); await uow.CompleteAsync().ConfigureAwait(false); } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 74cc34e8..2d55b084 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -122,6 +122,69 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Bye announcements disabled.. + /// + public static string administration_bye_off { + get { + return ResourceManager.GetString("administration_bye_off", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bye announcements enabled on this channel.. + /// + public static string administration_bye_on { + get { + return ResourceManager.GetString("administration_bye_on", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatic deletion of bye messages has been disabled.. + /// + public static string administration_byedel_off { + get { + return ResourceManager.GetString("administration_byedel_off", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bye messages will be deleted after {0} seconds.. + /// + public static string administration_byedel_on { + get { + return ResourceManager.GetString("administration_byedel_on", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Current bye message: {0}. + /// + public static string administration_byemsg_cur { + get { + return ResourceManager.GetString("administration_byemsg_cur", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enable bye messages by typing {0}. + /// + public static string administration_byemsg_enable { + get { + return ResourceManager.GetString("administration_byemsg_enable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New bye message set.. + /// + public static string administration_byemsg_new { + get { + return ResourceManager.GetString("administration_byemsg_new", resourceCulture); + } + } + /// /// Looks up a localized string similar to Channel Name Changed. /// @@ -212,6 +275,114 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Greet announcements disabled.. + /// + public static string administration_greet_off { + get { + return ResourceManager.GetString("administration_greet_off", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Greet announcements enabled on this channel.. + /// + public static string administration_greet_on { + get { + return ResourceManager.GetString("administration_greet_on", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Automatic deletion of greet messages has been disabled.. + /// + public static string administration_greetdel_off { + get { + return ResourceManager.GetString("administration_greetdel_off", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Greet messages will be deleted after {0} seconds.. + /// + public static string administration_greetdel_on { + get { + return ResourceManager.GetString("administration_greetdel_on", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DM greet announcements disabled.. + /// + public static string administration_greetdm_off { + get { + return ResourceManager.GetString("administration_greetdm_off", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to DM greet announcements enabled.. + /// + public static string administration_greetdm_on { + get { + return ResourceManager.GetString("administration_greetdm_on", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Current DM greet message: {0}. + /// + public static string administration_greetdmmsg_cur { + get { + return ResourceManager.GetString("administration_greetdmmsg_cur", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enable DM greet messages by typing {0}. + /// + public static string administration_greetdmmsg_enable { + get { + return ResourceManager.GetString("administration_greetdmmsg_enable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New DM greet message set.. + /// + public static string administration_greetdmmsg_new { + get { + return ResourceManager.GetString("administration_greetdmmsg_new", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Current greet message: {0}. + /// + public static string administration_greetmsg_cur { + get { + return ResourceManager.GetString("administration_greetmsg_cur", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enable greet messages by typing {0}. + /// + public static string administration_greetmsg_enable { + get { + return ResourceManager.GetString("administration_greetmsg_enable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New greet message set.. + /// + public static string administration_greetmsg_new { + get { + return ResourceManager.GetString("administration_greetmsg_new", resourceCulture); + } + } + /// /// Looks up a localized string similar to Images loaded after {0} seconds!. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 382b6c14..84b45ae4 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -320,6 +320,27 @@ Bot status changed to {0} + + Automatic deletion of bye messages has been disabled. + + + Bye messages will be deleted after {0} seconds. + + + Current bye message: {0} + + + Enable bye messages by typing {0} + + + New bye message set. + + + Bye announcements disabled. + + + Bye announcements enabled on this channel. + Channel Name Changed @@ -350,6 +371,42 @@ I will stop forwarding DMs from now on. + + Automatic deletion of greet messages has been disabled. + + + Greet messages will be deleted after {0} seconds. + + + Current DM greet message: {0} + + + Enable DM greet messages by typing {0} + + + New DM greet message set. + + + DM greet announcements disabled. + + + DM greet announcements enabled. + + + Current greet message: {0} + + + Enable greet messages by typing {0} + + + New greet message set. + + + Greet announcements disabled. + + + Greet announcements enabled on this channel. + Images loaded after {0} seconds! From 0d0938f613aa25e6f953fc25d8ac30ada6ea8cec Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Feb 2017 22:48:53 +0100 Subject: [PATCH 259/746] .v+t localizable. (only) main file left --- .../Commands/VoicePlusTextCommands.cs | 36 ++++++----- .../Resources/ResponseStrings.Designer.cs | 63 +++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 21 +++++++ 3 files changed, 105 insertions(+), 15 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs index 2a4c3152..7302b09d 100644 --- a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs @@ -65,10 +65,15 @@ namespace NadekoBot.Modules.Administration try { await guild.Owner.SendErrorAsync( - "⚠️ I don't have **manage server** and/or **manage channels** permission," + - $" so I cannot run `voice+text` on **{guild.Name}** server.").ConfigureAwait(false); + GetTextStatic("vt_exit", + NadekoBot.Localization.GetCultureInfo(guild), + typeof(Administration).Name.ToLowerInvariant(), + Format.Bold(guild.Name))).ConfigureAwait(false); + } + catch + { + // ignored } - catch { } using (var uow = DbHandler.UnitOfWork()) { uow.GuildConfigs.For(guild.Id, set => set).VoicePlusTextEnabled = false; @@ -105,9 +110,8 @@ namespace NadekoBot.Modules.Administration if (afterVch != null && guild.AFKChannel?.Id != afterVch.Id) { var roleName = GetRoleName(afterVch); - IRole roleToAdd = guild.Roles.FirstOrDefault(x => x.Name == roleName); - if (roleToAdd == null) - roleToAdd = await guild.CreateRoleAsync(roleName, GuildPermissions.None).ConfigureAwait(false); + var roleToAdd = guild.Roles.FirstOrDefault(x => x.Name == roleName) ?? + (IRole) await guild.CreateRoleAsync(roleName, GuildPermissions.None).ConfigureAwait(false); ITextChannel textChannel = guild.TextChannels .FirstOrDefault(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant()); @@ -115,7 +119,7 @@ namespace NadekoBot.Modules.Administration { var created = (await guild.CreateTextChannelAsync(GetChannelName(afterVch.Name).ToLowerInvariant()).ConfigureAwait(false)); - try { await guild.CurrentUser.AddRolesAsync(roleToAdd).ConfigureAwait(false); } catch { } + try { await guild.CurrentUser.AddRolesAsync(roleToAdd).ConfigureAwait(false); } catch {/*ignored*/} await Task.Delay(50).ConfigureAwait(false); await created.AddPermissionOverwriteAsync(roleToAdd, new OverwritePermissions( readMessages: PermValue.Allow, @@ -162,7 +166,7 @@ namespace NadekoBot.Modules.Administration var botUser = await guild.GetCurrentUserAsync().ConfigureAwait(false); if (!botUser.GuildPermissions.ManageRoles || !botUser.GuildPermissions.ManageChannels) { - await Context.Channel.SendErrorAsync("I require atleast **manage roles** and **manage channels permissions** to enable this feature. `(preffered Administration permission)`"); + await ReplyErrorLocalized("vt_no_perms").ConfigureAwait(false); return; } @@ -170,10 +174,12 @@ namespace NadekoBot.Modules.Administration { try { - await Context.Channel.SendErrorAsync("⚠️ You are enabling/disabling this feature and **I do not have ADMINISTRATOR permissions**. " + - "`This may cause some issues, and you will have to clean up text channels yourself afterwards.`"); + await ReplyErrorLocalized("vt_no_admin").ConfigureAwait(false); + } + catch + { + // ignored } - catch { } } try { @@ -198,11 +204,11 @@ namespace NadekoBot.Modules.Administration try { await role.DeleteAsync().ConfigureAwait(false); } catch { } await Task.Delay(500).ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync("ℹ️ Successfuly **removed** voice + text feature.").ConfigureAwait(false); + await ReplyConfirmLocalized("vt_disabled").ConfigureAwait(false); return; } _voicePlusTextCache.Add(guild.Id); - await Context.Channel.SendConfirmAsync("🆗 Successfuly **enabled** voice + text feature.").ConfigureAwait(false); + await ReplyConfirmLocalized("vt_enabled").ConfigureAwait(false); } catch (Exception ex) @@ -222,7 +228,7 @@ namespace NadekoBot.Modules.Administration var botUser = await guild.GetCurrentUserAsync().ConfigureAwait(false); if (!botUser.GuildPermissions.Administrator) { - await Context.Channel.SendErrorAsync("I need **Administrator permission** to do that.").ConfigureAwait(false); + await ReplyErrorLocalized("need_admin").ConfigureAwait(false); return; } @@ -249,7 +255,7 @@ namespace NadekoBot.Modules.Administration await Task.Delay(500).ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync("Cleaned v+t.").ConfigureAwait(false); + await ReplyConfirmLocalized("cleaned_up").ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 2d55b084..bb9992f1 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -212,6 +212,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Cleaned up.. + /// + public static string administration_cleaned_up { + get { + return ResourceManager.GetString("administration_cleaned_up", resourceCulture); + } + } + /// /// Looks up a localized string similar to Content. /// @@ -636,6 +645,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to I need **Administration** permission to do that.. + /// + public static string administration_need_admin { + get { + return ResourceManager.GetString("administration_need_admin", resourceCulture); + } + } + /// /// Looks up a localized string similar to New Message. /// @@ -1286,6 +1304,51 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Disabled voice + text feature.. + /// + public static string administration_vt_disabled { + get { + return ResourceManager.GetString("administration_vt_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enabled voice + text feature.. + /// + public static string administration_vt_enabled { + get { + return ResourceManager.GetString("administration_vt_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I don't have **manage roles** and/or **manage channels** permission, so I cannot run `voice+text` on {0} server.. + /// + public static string administration_vt_exit { + get { + return ResourceManager.GetString("administration_vt_exit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You are enabling/disabling this feature and **I do not have ADMINISTRATOR permissions**. This may cause some issues, and you will have to clean up text channels yourself afterwards.. + /// + public static string administration_vt_no_admin { + get { + return ResourceManager.GetString("administration_vt_no_admin", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I require atleast **manage roles** and **manage channels** permissions to enable this feature. (preffered Administration permission). + /// + public static string administration_vt_perms { + get { + return ResourceManager.GetString("administration_vt_perms", resourceCulture); + } + } + /// /// Looks up a localized string similar to User {0} from text chat. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 84b45ae4..f044bf3a 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -350,6 +350,9 @@ Channel Topic Changed + + Cleaned up. + Content @@ -494,6 +497,9 @@ New mute role set. + + I need **Administration** permission to do that. + New Message @@ -714,6 +720,21 @@ Voice Channel Destroyed + + Disabled voice + text feature. + + + Enabled voice + text feature. + + + I don't have **manage roles** and/or **manage channels** permission, so I cannot run `voice+text` on {0} server. + + + You are enabling/disabling this feature and **I do not have ADMINISTRATOR permissions**. This may cause some issues, and you will have to clean up text channels yourself afterwards. + + + I require atleast **manage roles** and **manage channels** permissions to enable this feature. (preffered Administration permission) + User {0} from text chat From d0100f0c9f7258214dfc769b5dac3846094a6907 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 15 Feb 2017 00:38:02 +0100 Subject: [PATCH 260/746] Administration module fully translatable!!! Partially tested though, report any missing keys. --- .../Modules/Administration/Administration.cs | 216 ++++++----- .../Administration/Commands/Migration.cs | 2 +- .../Resources/ResponseStrings.Designer.cs | 336 ++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 114 ++++++ 4 files changed, 552 insertions(+), 116 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 21dceacc..97b872b9 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -1,18 +1,14 @@ using Discord; using Discord.Commands; using NadekoBot.Extensions; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading.Tasks; using NadekoBot.Services; using NadekoBot.Attributes; using Discord.WebSocket; using NadekoBot.Services.Database.Models; -using System.Net.Http; -using System.IO; using static NadekoBot.Modules.Permissions.Permissions; using System.Collections.Concurrent; using NLog; @@ -22,7 +18,7 @@ namespace NadekoBot.Modules.Administration [NadekoModule("Administration", ".")] public partial class Administration : NadekoModule { - private static ConcurrentHashSet DeleteMessagesOnCommand { get; } = new ConcurrentHashSet(); + private static ConcurrentHashSet deleteMessagesOnCommand { get; } private new static Logger _log { get; } @@ -31,7 +27,7 @@ namespace NadekoBot.Modules.Administration _log = LogManager.GetCurrentClassLogger(); NadekoBot.CommandHandler.CommandExecuted += DelMsgOnCmd_Handler; - DeleteMessagesOnCommand = new ConcurrentHashSet(NadekoBot.AllGuildConfigs.Where(g => g.DeleteMessageOnCommand).Select(g => g.GuildId)); + deleteMessagesOnCommand = new ConcurrentHashSet(NadekoBot.AllGuildConfigs.Where(g => g.DeleteMessageOnCommand).Select(g => g.GuildId)); } @@ -44,7 +40,7 @@ namespace NadekoBot.Modules.Administration var channel = msg.Channel as SocketTextChannel; if (channel == null) return; - if (DeleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune") + if (deleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune") await msg.DeleteAsync().ConfigureAwait(false); } catch (Exception ex) @@ -71,17 +67,17 @@ namespace NadekoBot.Modules.Administration PermRole = config.PermissionRole, Verbose = config.VerbosePermissions, }; - Permissions.Permissions.Cache.AddOrUpdate(channel.Guild.Id, + Cache.AddOrUpdate(channel.Guild.Id, toAdd, (id, old) => toAdd); await uow.CompleteAsync(); } - - await channel.SendConfirmAsync($"{Context.Message.Author.Mention} 🆗 **Permissions for this server are reset.**"); + await ReplyConfirmLocalized("perms_reset").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.Administrator)] + [RequireBotPermission(GuildPermission.ManageMessages)] public async Task Delmsgoncmd() { bool enabled; @@ -94,29 +90,31 @@ namespace NadekoBot.Modules.Administration } if (enabled) { - DeleteMessagesOnCommand.Add(Context.Guild.Id); - await Context.Channel.SendConfirmAsync("✅ **Now automatically deleting successful command invokations.**").ConfigureAwait(false); + deleteMessagesOnCommand.Add(Context.Guild.Id); + await ReplyConfirmLocalized("delmsg_on").ConfigureAwait(false); } else { - DeleteMessagesOnCommand.TryRemove(Context.Guild.Id); - await Context.Channel.SendConfirmAsync("❗**Stopped automatic deletion of successful command invokations.**").ConfigureAwait(false); + deleteMessagesOnCommand.TryRemove(Context.Guild.Id); + await ReplyConfirmLocalized("delmsg_off").ConfigureAwait(false); } } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageRoles)] + [RequireBotPermission(GuildPermission.ManageRoles)] public async Task Setrole(IGuildUser usr, [Remainder] IRole role) { try { await usr.AddRolesAsync(role).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"ℹ️ Successfully added role **{role.Name}** to user **{usr.Username}**").ConfigureAwait(false); + await ReplyConfirmLocalized("setrole", Format.Bold(role.Name), Format.Bold(usr.ToString())) + .ConfigureAwait(false); } catch (Exception ex) { - await Context.Channel.SendErrorAsync("⚠️ Failed to add role. **Bot has insufficient permissions.**\n").ConfigureAwait(false); + await ReplyErrorLocalized("setrole_err").ConfigureAwait(false); Console.WriteLine(ex.ToString()); } } @@ -124,82 +122,81 @@ namespace NadekoBot.Modules.Administration [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageRoles)] + [RequireBotPermission(GuildPermission.ManageRoles)] public async Task Removerole(IGuildUser usr, [Remainder] IRole role) { try { await usr.RemoveRolesAsync(role).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"ℹ️ Successfully removed role **{role.Name}** from user **{usr.Username}**").ConfigureAwait(false); + await ReplyConfirmLocalized("remrole", Format.Bold(role.Name), Format.Bold(usr.ToString())).ConfigureAwait(false); } catch { - await Context.Channel.SendErrorAsync("⚠️ Failed to remove role. Most likely reason: **Insufficient permissions.**").ConfigureAwait(false); + await ReplyErrorLocalized("remrole_err").ConfigureAwait(false); } } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageRoles)] + [RequireBotPermission(GuildPermission.ManageRoles)] public async Task RenameRole(IRole roleToEdit, string newname) { try { if (roleToEdit.Position > (await Context.Guild.GetCurrentUserAsync().ConfigureAwait(false)).GetRoles().Max(r => r.Position)) { - await Context.Channel.SendErrorAsync("🚫 You can't edit roles higher than your highest role.").ConfigureAwait(false); + await ReplyErrorLocalized("renrole_perms").ConfigureAwait(false); return; } await roleToEdit.ModifyAsync(g => g.Name = newname).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync("✅ Role renamed.").ConfigureAwait(false); + await ReplyConfirmLocalized("renrole").ConfigureAwait(false); } catch (Exception) { - await Context.Channel.SendErrorAsync("⚠️ Failed to rename role. Probably **insufficient permissions.**").ConfigureAwait(false); + await ReplyErrorLocalized("renrole_err").ConfigureAwait(false); } } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageRoles)] + [RequireBotPermission(GuildPermission.ManageRoles)] public async Task RemoveAllRoles([Remainder] IGuildUser user) { try { await user.RemoveRolesAsync(user.GetRoles()).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"🗑 Successfully removed **all** roles from user **{user.Username}**").ConfigureAwait(false); + await ReplyConfirmLocalized("rar", Format.Bold(user.ToString())).ConfigureAwait(false); } catch { - await Context.Channel.SendErrorAsync("⚠️ Failed to remove roles. Most likely reason: **Insufficient permissions.**").ConfigureAwait(false); + await ReplyErrorLocalized("rar_err").ConfigureAwait(false); } } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageRoles)] + [RequireBotPermission(GuildPermission.ManageRoles)] public async Task CreateRole([Remainder] string roleName = null) { if (string.IsNullOrWhiteSpace(roleName)) return; - try - { - var r = await Context.Guild.CreateRoleAsync(roleName).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"✅ Successfully created role **{r.Name}**.").ConfigureAwait(false); - } - catch (Exception) - { - await Context.Channel.SendErrorAsync("⚠️ Unspecified error.").ConfigureAwait(false); - } + + var r = await Context.Guild.CreateRoleAsync(roleName).ConfigureAwait(false); + await ReplyConfirmLocalized("cr", Format.Bold(r.Name)).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageRoles)] + [RequireBotPermission(GuildPermission.ManageRoles)] public async Task RoleColor(params string[] args) { - if (args.Count() != 2 && args.Count() != 4) + if (args.Length != 2 && args.Length != 4) { - await Context.Channel.SendErrorAsync("❌ The parameters specified are **invalid.**").ConfigureAwait(false); + await ReplyErrorLocalized("rc_params").ConfigureAwait(false); return; } var roleName = args[0].ToUpperInvariant(); @@ -207,7 +204,7 @@ namespace NadekoBot.Modules.Administration if (role == null) { - await Context.Channel.SendErrorAsync("🚫 That role **does not exist.**").ConfigureAwait(false); + await ReplyErrorLocalized("rc_not_exist").ConfigureAwait(false); return; } try @@ -220,64 +217,54 @@ namespace NadekoBot.Modules.Administration var blue = Convert.ToByte(rgb ? int.Parse(args[3]) : Convert.ToInt32(arg1.Substring(4, 2), 16)); await role.ModifyAsync(r => r.Color = new Color(red, green, blue)).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"☑️ Role **{role.Name}'s** color has been changed.").ConfigureAwait(false); + await ReplyConfirmLocalized("rc", Format.Bold(role.Name)).ConfigureAwait(false); } catch (Exception) { - await Context.Channel.SendErrorAsync("⚠️ Error occured, most likely **invalid parameters** or **insufficient permissions.**").ConfigureAwait(false); + await ReplyErrorLocalized("rc_perms").ConfigureAwait(false); } } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.BanMembers)] + [RequireBotPermission(GuildPermission.BanMembers)] public async Task Ban(IGuildUser user, [Remainder] string msg = null) { - if (string.IsNullOrWhiteSpace(msg)) - { - msg = "❗️No reason provided."; - } if (Context.User.Id != user.Guild.OwnerId && (user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max())) { - await Context.Channel.SendErrorAsync("⚠️ You can't use this command on users with a role higher or equal to yours in the role hierarchy.").ConfigureAwait(false); + await ReplyErrorLocalized("hierarchy").ConfigureAwait(false); return; } if (!string.IsNullOrWhiteSpace(msg)) { try { - await (await user.CreateDMChannelAsync()).SendErrorAsync($"⛔️ **You have been BANNED from `{Context.Guild.Name}` server.**\n" + - $"⚖ *Reason:* {msg}").ConfigureAwait(false); + await user.SendErrorAsync(GetText("bandm", Format.Bold(Context.Guild.Name), msg)); await Task.Delay(2000).ConfigureAwait(false); } catch { } } - try - { - await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync("⛔️ **Banned** user **" + user.Username + "** ID: `" + user.Id + "`").ConfigureAwait(false); - } - catch - { - await Context.Channel.SendErrorAsync("⚠️ **Error.** Most likely I don't have sufficient permissions.").ConfigureAwait(false); - } + await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false); + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle("⛔️ " + GetText("banned_user")) + .AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) + .ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.KickMembers)] [RequireUserPermission(GuildPermission.ManageMessages)] + [RequireBotPermission(GuildPermission.BanMembers)] public async Task Softban(IGuildUser user, [Remainder] string msg = null) { - if (string.IsNullOrWhiteSpace(msg)) - { - msg = "❗️No reason provided."; - } if (Context.User.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max()) { - await Context.Channel.SendErrorAsync("⚠️ You can't use this command on users with a role higher or equal to yours in the role hierarchy."); + await ReplyErrorLocalized("hierarchy").ConfigureAwait(false); return; } @@ -285,161 +272,159 @@ namespace NadekoBot.Modules.Administration { try { - await user.SendErrorAsync($"☣ **You have been SOFT-BANNED from `{Context.Guild.Name}` server.**\n" + - $"⚖ *Reason:* {msg}").ConfigureAwait(false); + await user.SendErrorAsync(GetText("sbdm", Format.Bold(Context.Guild.Name), msg)); await Task.Delay(2000).ConfigureAwait(false); } catch { } } - try - { - await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false); - try { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); } - catch { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); } - - await Context.Channel.SendConfirmAsync("☣ **Soft-Banned** user **" + user.Username + "** ID: `" + user.Id + "`").ConfigureAwait(false); - } - catch - { - await Context.Channel.SendErrorAsync("⚠️ Error. Most likely I don't have sufficient permissions.").ConfigureAwait(false); - } + await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false); + try { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); } + catch { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); } + + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle("☣ " + GetText("sb_user")) + .AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) + .ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.KickMembers)] + [RequireBotPermission(GuildPermission.KickMembers)] public async Task Kick(IGuildUser user, [Remainder] string msg = null) { - if (user == null) - { - await Context.Channel.SendErrorAsync("❗️User not found.").ConfigureAwait(false); - return; - } - if (Context.Message.Author.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max()) { - await Context.Channel.SendErrorAsync("⚠️ You can't use this command on users with a role higher or equal to yours in the role hierarchy."); + await ReplyErrorLocalized("hierarchy").ConfigureAwait(false); return; } if (!string.IsNullOrWhiteSpace(msg)) { try { - await user.SendErrorAsync($"‼️**You have been KICKED from `{Context.Guild.Name}` server.**\n" + - $"⚖ *Reason:* {msg}").ConfigureAwait(false); + await user.SendErrorAsync(GetText("kickdm", Format.Bold(Context.Guild.Name), msg)); await Task.Delay(2000).ConfigureAwait(false); } catch { } } - try - { - await user.KickAsync().ConfigureAwait(false); - await Context.Channel.SendConfirmAsync("‼️**Kicked** user **" + user.Username + "** ID: `" + user.Id + "`").ConfigureAwait(false); - } - catch - { - await Context.Channel.SendErrorAsync("⚠️ Error. Most likely I don't have sufficient permissions.").ConfigureAwait(false); - } + + await user.KickAsync().ConfigureAwait(false); + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle(GetText("kicked_user")) + .AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) + .ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.DeafenMembers)] + [RequireBotPermission(GuildPermission.DeafenMembers)] public async Task Deafen(params IGuildUser[] users) { if (!users.Any()) return; - try + foreach (var u in users) { - foreach (var u in users) + try { await u.ModifyAsync(usr => usr.Deaf = true).ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync("🔇 **Deafen** successful.").ConfigureAwait(false); - } - catch - { - await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false); + catch + { + // ignored + } } + await ReplyConfirmLocalized("deafen").ConfigureAwait(false); } + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.DeafenMembers)] + [RequireBotPermission(GuildPermission.DeafenMembers)] public async Task UnDeafen(params IGuildUser[] users) { if (!users.Any()) return; - try + + foreach (var u in users) { - foreach (var u in users) + try { await u.ModifyAsync(usr => usr.Deaf = false).ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync("🔊 **Undeafen** successful.").ConfigureAwait(false); - } - catch - { - await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false); + catch + { + // ignored + } } + await ReplyConfirmLocalized("undeafen").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageChannels)] + [RequireBotPermission(GuildPermission.ManageChannels)] public async Task DelVoiChanl([Remainder] IVoiceChannel voiceChannel) { await voiceChannel.DeleteAsync().ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"🗑 Removed voice channel **{voiceChannel.Name}** successfully.").ConfigureAwait(false); + await ReplyConfirmLocalized("delvoich", Format.Bold(voiceChannel.Name)).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageChannels)] + [RequireBotPermission(GuildPermission.ManageChannels)] public async Task CreatVoiChanl([Remainder] string channelName) { var ch = await Context.Guild.CreateVoiceChannelAsync(channelName).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"✅ Created voice channel **{ch.Name}**. ID: `{ch.Id}`").ConfigureAwait(false); + await ReplyConfirmLocalized("createvoich",Format.Bold(ch.Name)).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageChannels)] + [RequireBotPermission(GuildPermission.ManageChannels)] public async Task DelTxtChanl([Remainder] ITextChannel toDelete) { await toDelete.DeleteAsync().ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"🗑 Removed text channel **{toDelete.Name}**. ID: `{toDelete.Id}`").ConfigureAwait(false); + await ReplyConfirmLocalized("deltextchan", Format.Bold(toDelete.Name)).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageChannels)] + [RequireBotPermission(GuildPermission.ManageChannels)] public async Task CreaTxtChanl([Remainder] string channelName) { var txtCh = await Context.Guild.CreateTextChannelAsync(channelName).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"✅ Added text channel **{txtCh.Name}**. ID: `{txtCh.Id}`").ConfigureAwait(false); + await ReplyConfirmLocalized("createtextchan", Format.Bold(txtCh.Name)).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageChannels)] + [RequireBotPermission(GuildPermission.ManageChannels)] public async Task SetTopic([Remainder] string topic = null) { var channel = (ITextChannel)Context.Channel; topic = topic ?? ""; await channel.ModifyAsync(c => c.Topic = topic); - await channel.SendConfirmAsync("🆗 **New channel topic set.**").ConfigureAwait(false); + await ReplyConfirmLocalized("set_topic").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageChannels)] + [RequireBotPermission(GuildPermission.ManageChannels)] public async Task SetChanlName([Remainder] string name) { var channel = (ITextChannel)Context.Channel; await channel.ModifyAsync(c => c.Name = name).ConfigureAwait(false); - await channel.SendConfirmAsync("🆗 **New channel name set.**").ConfigureAwait(false); + await ReplyConfirmLocalized("set_channel_name").ConfigureAwait(false); } @@ -459,6 +444,7 @@ namespace NadekoBot.Modules.Administration [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(ChannelPermission.ManageMessages)] + [RequireBotPermission(GuildPermission.ManageMessages)] public async Task Prune(int count) { if (count < 1) @@ -474,6 +460,7 @@ namespace NadekoBot.Modules.Administration [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(ChannelPermission.ManageMessages)] + [RequireBotPermission(GuildPermission.ManageMessages)] public async Task Prune(IGuildUser user, int count = 100) { if (count < 1) @@ -492,7 +479,7 @@ namespace NadekoBot.Modules.Administration [RequireUserPermission(GuildPermission.MentionEveryone)] public async Task MentionRole(params IRole[] roles) { - string send = $"❕{Context.User.Mention} has invoked a mention on the following roles ❕"; + string send = "❕" +GetText("menrole",Context.User.Mention); foreach (var role in roles) { send += $"\n**{role.Name}**\n"; @@ -510,7 +497,7 @@ namespace NadekoBot.Modules.Administration await Context.Channel.SendMessageAsync(send).ConfigureAwait(false); } - IGuild _nadekoSupportServer; + private IGuild _nadekoSupportServer; [NadekoCommand, Usage, Description, Aliases] public async Task Donators() { @@ -520,7 +507,7 @@ namespace NadekoBot.Modules.Administration { donatorsOrdered = uow.Donators.GetDonatorsOrdered(); } - await Context.Channel.SendConfirmAsync("Thanks to the people listed below for making this project happen!", string.Join("⭐", donatorsOrdered.Select(d => d.Name))).ConfigureAwait(false); + await Context.Channel.SendConfirmAsync(GetText("donators"), string.Join("⭐", donatorsOrdered.Select(d => d.Name))).ConfigureAwait(false); _nadekoSupportServer = _nadekoSupportServer ?? NadekoBot.Client.GetGuild(117523346618318850); @@ -543,8 +530,7 @@ namespace NadekoBot.Modules.Administration don = uow.Donators.AddOrUpdateDonator(donator.Id, donator.Username, amount); await uow.CompleteAsync(); } - - await Context.Channel.SendConfirmAsync($"Successfuly added a new donator. Total donated amount from this user: {don.Amount} 👑").ConfigureAwait(false); + await ReplyConfirmLocalized("donadd", don.Amount).ConfigureAwait(false); } //[NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Administration/Commands/Migration.cs b/src/NadekoBot/Modules/Administration/Commands/Migration.cs index 8ee6f652..802e5ae9 100644 --- a/src/NadekoBot/Modules/Administration/Commands/Migration.cs +++ b/src/NadekoBot/Modules/Administration/Commands/Migration.cs @@ -24,7 +24,7 @@ namespace NadekoBot.Modules.Administration { private const int CURRENT_VERSION = 1; - private static Logger _log { get; } + private new static readonly Logger _log; static Migration() { diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index bb9992f1..d8db88cd 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -95,6 +95,16 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to You have been banned from {0} server. + ///Reason: {1}. + /// + public static string administration_bandm { + get { + return ResourceManager.GetString("administration_bandm", resourceCulture); + } + } + /// /// Looks up a localized string similar to banned. /// @@ -104,6 +114,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to User Banned. + /// + public static string administration_banned_user { + get { + return ResourceManager.GetString("administration_banned_user", resourceCulture); + } + } + /// /// Looks up a localized string similar to Bot name changed to {0}. /// @@ -230,6 +249,42 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Sucessfully created role {0}. + /// + public static string administration_cr { + get { + return ResourceManager.GetString("administration_cr", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Text channel {0} created.. + /// + public static string administration_createtextchan { + get { + return ResourceManager.GetString("administration_createtextchan", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Voice channel {0} created.. + /// + public static string administration_createvoich { + get { + return ResourceManager.GetString("administration_createvoich", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Deafen successful.. + /// + public static string administration_deafen { + get { + return ResourceManager.GetString("administration_deafen", resourceCulture); + } + } + /// /// Looks up a localized string similar to Deleted server {0}. /// @@ -239,6 +294,42 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Stopped automatic deletion of successful command invokations.. + /// + public static string administration_delmsg_off { + get { + return ResourceManager.GetString("administration_delmsg_off", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Now automatically deleting sucessful command invokations.. + /// + public static string administration_delmsg_on { + get { + return ResourceManager.GetString("administration_delmsg_on", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Text channel {0} deleted.. + /// + public static string administration_deltextchan { + get { + return ResourceManager.GetString("administration_deltextchan", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Voice channel {0} deleted.. + /// + public static string administration_delvoich { + get { + return ResourceManager.GetString("administration_delvoich", resourceCulture); + } + } + /// /// Looks up a localized string similar to DM from. /// @@ -248,6 +339,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Sucessfully added a new donator.Total donated amount from this user: {0} 👑. + /// + public static string administration_donadd { + get { + return ResourceManager.GetString("administration_donadd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Thanks to the people listed below for making this project hjappen!. + /// + public static string administration_donators { + get { + return ResourceManager.GetString("administration_donators", resourceCulture); + } + } + /// /// Looks up a localized string similar to I will forward DMs to all owners.. /// @@ -392,6 +501,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to You can't use this command on users with a role higher or equal to yours in the role hierarchy.. + /// + public static string administration_hierarchy { + get { + return ResourceManager.GetString("administration_hierarchy", resourceCulture); + } + } + /// /// Looks up a localized string similar to Images loaded after {0} seconds!. /// @@ -428,6 +546,25 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to You have been kicked from {0} server. + ///Reason: {1}. + /// + public static string administration_kickdm { + get { + return ResourceManager.GetString("administration_kickdm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User Kicked. + /// + public static string administration_kicked_user { + get { + return ResourceManager.GetString("administration_kicked_user", resourceCulture); + } + } + /// /// Looks up a localized string similar to List Of Languages ///{0}. @@ -564,6 +701,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to {0} has invoked a mention on the following roles. + /// + public static string administration_menrole { + get { + return ResourceManager.GetString("administration_menrole", resourceCulture); + } + } + /// /// Looks up a localized string similar to Message from {0} `[Bot Owner]`:. /// @@ -735,6 +881,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Error. Most likely I don't have sufficient permissions.. + /// + public static string administration_perms { + get { + return ResourceManager.GetString("administration_perms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Permissions for this server are reset.. + /// + public static string administration_perms_reset { + get { + return ResourceManager.GetString("administration_perms_reset", resourceCulture); + } + } + /// /// Looks up a localized string similar to Active Protections. /// @@ -807,6 +971,105 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Successfully removed all roles from user {0}. + /// + public static string administration_rar { + get { + return ResourceManager.GetString("administration_rar", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to remove roles. I have insufficient permissions.. + /// + public static string administration_rar_err { + get { + return ResourceManager.GetString("administration_rar_err", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Color of {0} role has been changed.. + /// + public static string administration_rc { + get { + return ResourceManager.GetString("administration_rc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to That role does not exist.. + /// + public static string administration_rc_not_exist { + get { + return ResourceManager.GetString("administration_rc_not_exist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The parameters specified are invalid.. + /// + public static string administration_rc_params { + get { + return ResourceManager.GetString("administration_rc_params", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error occured due to invalid color or insufficient permissions.. + /// + public static string administration_rc_perms { + get { + return ResourceManager.GetString("administration_rc_perms", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Successfully removed role {0} from user {1}. + /// + public static string administration_remrole { + get { + return ResourceManager.GetString("administration_remrole", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to remove role. I have insufficient permissions.. + /// + public static string administration_remrole_err { + get { + return ResourceManager.GetString("administration_remrole_err", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Role renamed.. + /// + public static string administration_renrole { + get { + return ResourceManager.GetString("administration_renrole", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to rename role. I have insufficient permissions.. + /// + public static string administration_renrole_err { + get { + return ResourceManager.GetString("administration_renrole_err", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You can't edit roles higher than your highest role.. + /// + public static string administration_renrole_perms { + get { + return ResourceManager.GetString("administration_renrole_perms", resourceCulture); + } + } + /// /// Looks up a localized string similar to Removed the playing message: {0}. /// @@ -997,6 +1260,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to New channel name set.. + /// + public static string administration_set_channel_name { + get { + return ResourceManager.GetString("administration_set_channel_name", resourceCulture); + } + } + /// /// Looks up a localized string similar to New game set!. /// @@ -1015,6 +1287,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to New channel topic set.. + /// + public static string administration_set_topic { + get { + return ResourceManager.GetString("administration_set_topic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sucessfully added role {0} to user {1}. + /// + public static string administration_setrole { + get { + return ResourceManager.GetString("administration_setrole", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to add role. I have insufficient permissions.. + /// + public static string administration_setrole_err { + get { + return ResourceManager.GetString("administration_setrole_err", resourceCulture); + } + } + /// /// Looks up a localized string similar to Shard {0} reconnected.. /// @@ -1124,6 +1423,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Undeafen successful.. + /// + public static string administration_undeafen { + get { + return ResourceManager.GetString("administration_undeafen", resourceCulture); + } + } + /// /// Looks up a localized string similar to Unmuted. /// @@ -1268,6 +1576,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Username. + /// + public static string administration_username { + get { + return ResourceManager.GetString("administration_username", resourceCulture); + } + } + /// /// Looks up a localized string similar to Username Changed. /// @@ -1376,6 +1693,16 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to You have been soft-banned from {0} server. + ///Reason: {1}. + /// + public static string administraton_sbdm { + get { + return ResourceManager.GetString("administraton_sbdm", resourceCulture); + } + } + /// /// Looks up a localized string similar to User Unbanned. /// @@ -1412,6 +1739,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to User Soft-Banned. + /// + public static string adminsitration_sb_user { + get { + return ResourceManager.GetString("adminsitration_sb_user", resourceCulture); + } + } + /// /// Looks up a localized string similar to That base is already claimed or destroyed.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index f044bf3a..7fabfa84 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -310,10 +310,17 @@ Avatar Changed + + You have been banned from {0} server. +Reason: {1} + banned PLURAL + + User Banned + Bot name changed to {0} @@ -356,12 +363,42 @@ Content + + Sucessfully created role {0} + + + Text channel {0} created. + + + Voice channel {0} created. + + + Deafen successful. + Deleted server {0} + + Stopped automatic deletion of successful command invokations. + + + Now automatically deleting sucessful command invokations. + + + Text channel {0} deleted. + + + Voice channel {0} deleted. + DM from + + Sucessfully added a new donator.Total donated amount from this user: {0} 👑 + + + Thanks to the people listed below for making this project hjappen! + I will forward DMs to all owners. @@ -410,6 +447,9 @@ Greet announcements enabled on this channel. + + You can't use this command on users with a role higher or equal to yours in the role hierarchy. + Images loaded after {0} seconds! @@ -422,6 +462,13 @@ {0} has joined {1} + + You have been kicked from {0} server. +Reason: {1} + + + User Kicked + List Of Languages {0} @@ -468,6 +515,9 @@ Stopped logging {0} event. + + {0} has invoked a mention on the following roles + Message from {0} `[Bot Owner]`: @@ -527,6 +577,12 @@ Old Topic + + Error. Most likely I don't have sufficient permissions. + + + Permissions for this server are reset. + Active Protections @@ -551,6 +607,39 @@ Time must be between {0} and {1} seconds. + + Successfully removed all roles from user {0} + + + Failed to remove roles. I have insufficient permissions. + + + Color of {0} role has been changed. + + + That role does not exist. + + + The parameters specified are invalid. + + + Error occured due to invalid color or insufficient permissions. + + + Successfully removed role {0} from user {1} + + + Failed to remove role. I have insufficient permissions. + + + Role renamed. + + + Failed to rename role. I have insufficient permissions. + + + You can't edit roles higher than your highest role. + Removed the playing message: {0} @@ -612,15 +701,27 @@ You now have {0} role. + + Sucessfully added role {0} to user {1} + + + Failed to add role. I have insufficient permissions. + New avatar set! + + New channel name set. + New game set! New stream set! + + New channel topic set. + Shard {0} reconnected. @@ -659,10 +760,16 @@ Text Channel Destroyed + + Undeafen successful. + Unmuted singular + + Username + Username Changed @@ -744,6 +851,10 @@ User {0} from voice chat + + You have been soft-banned from {0} server. +Reason: {1} + User Unbanned @@ -756,6 +867,9 @@ Presence Updates + + User Soft-Banned + Back to ToC From 8983c9c37e4590732e2ef091396bcc0ef4c7bdaf Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 15 Feb 2017 00:59:10 +0100 Subject: [PATCH 261/746] small cleanup --- .../Modules/Administration/Administration.cs | 14 ++-- .../Gambling/Commands/WaifuClaimCommands.cs | 2 +- src/NadekoBot/Modules/Pokemon/Pokemon.cs | 67 ++++++++----------- 3 files changed, 40 insertions(+), 43 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 97b872b9..eb07ef1f 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Administration { private static ConcurrentHashSet deleteMessagesOnCommand { get; } - private new static Logger _log { get; } + private new static readonly Logger _log; static Administration() { @@ -209,7 +209,7 @@ namespace NadekoBot.Modules.Administration } try { - var rgb = args.Count() == 4; + var rgb = args.Length == 4; var arg1 = args[1].Replace("#", ""); var red = Convert.ToByte(rgb ? int.Parse(arg1) : Convert.ToInt32(arg1.Substring(0, 2), 16)); @@ -244,7 +244,10 @@ namespace NadekoBot.Modules.Administration await Task.Delay(2000).ConfigureAwait(false); } - catch { } + catch + { + // ignored + } } await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false); @@ -275,7 +278,10 @@ namespace NadekoBot.Modules.Administration await user.SendErrorAsync(GetText("sbdm", Format.Bold(Context.Guild.Name), msg)); await Task.Delay(2000).ConfigureAwait(false); } - catch { } + catch + { + // ignored + } } await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false); diff --git a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs index 1426bebd..8c6cfcd5 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs @@ -421,7 +421,7 @@ namespace NadekoBot.Modules.Gambling var embed = new EmbedBuilder() .WithOkColor() - .WithTitle("Waifu " + w.Waifu.ToString() + " - \"the " + claimInfo.Title + "\"") + .WithTitle("Waifu " + w.Waifu + " - \"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)) diff --git a/src/NadekoBot/Modules/Pokemon/Pokemon.cs b/src/NadekoBot/Modules/Pokemon/Pokemon.cs index e2679147..08d3976f 100644 --- a/src/NadekoBot/Modules/Pokemon/Pokemon.cs +++ b/src/NadekoBot/Modules/Pokemon/Pokemon.cs @@ -12,27 +12,25 @@ using System; using Newtonsoft.Json; using System.IO; using System.Collections.Concurrent; -using NadekoBot.Modules; -using NadekoBot.Resources; namespace NadekoBot.Modules.Pokemon { [NadekoModule("Pokemon", ">")] - public partial class Pokemon : NadekoModule + public class Pokemon : NadekoModule { - private static List PokemonTypes = new List(); - private static ConcurrentDictionary Stats = new ConcurrentDictionary(); + private static readonly List _pokemonTypes = new List(); + private static readonly ConcurrentDictionary _stats = new ConcurrentDictionary(); public const string PokemonTypesFile = "data/pokemon_types.json"; - private static new Logger _log { get; } + private new static Logger _log { get; } static Pokemon() { _log = LogManager.GetCurrentClassLogger(); if (File.Exists(PokemonTypesFile)) { - PokemonTypes = JsonConvert.DeserializeObject>(File.ReadAllText(PokemonTypesFile)); + _pokemonTypes = JsonConvert.DeserializeObject>(File.ReadAllText(PokemonTypesFile)); } else { @@ -44,21 +42,18 @@ namespace NadekoBot.Modules.Pokemon private int GetDamage(PokemonType usertype, PokemonType targetType) { var rng = new Random(); - int damage = rng.Next(40, 60); - foreach (PokemonMultiplier Multiplier in usertype.Multipliers) + var damage = rng.Next(40, 60); + foreach (var multiplierObj in usertype.Multipliers) { - if (Multiplier.Type == targetType.Name) - { - var multiplier = Multiplier.Multiplication; - damage = (int)(damage * multiplier); - } + if (multiplierObj.Type != targetType.Name) continue; + damage = (int)(damage * multiplierObj.Multiplication); } return damage; } - private PokemonType GetPokeType(ulong id) + private static PokemonType GetPokeType(ulong id) { Dictionary setTypes; @@ -71,18 +66,18 @@ namespace NadekoBot.Modules.Pokemon { return StringToPokemonType(setTypes[id]); } - int count = PokemonTypes.Count; + var count = _pokemonTypes.Count; - int remainder = Math.Abs((int)(id % (ulong)count)); + var remainder = Math.Abs((int)(id % (ulong)count)); - return PokemonTypes[remainder]; + return _pokemonTypes[remainder]; } - private PokemonType StringToPokemonType(string v) + private static PokemonType StringToPokemonType(string v) { var str = v?.ToUpperInvariant(); - var list = PokemonTypes; - foreach (PokemonType p in list) + var list = _pokemonTypes; + foreach (var p in list) { if (str == p.Name) { @@ -116,8 +111,7 @@ namespace NadekoBot.Modules.Pokemon // Checking stats first, then move //Set up the userstats - PokeStats userStats; - userStats = Stats.GetOrAdd(user.Id, new PokeStats()); + var userStats = _stats.GetOrAdd(user.Id, new PokeStats()); //Check if able to move //User not able if HP < 0, has made more than 4 attacks @@ -137,8 +131,7 @@ namespace NadekoBot.Modules.Pokemon return; } //get target stats - PokeStats targetStats; - targetStats = Stats.GetOrAdd(targetUser.Id, new PokeStats()); + var targetStats = _stats.GetOrAdd(targetUser.Id, new PokeStats()); //If target's HP is below 0, no use attacking if (targetStats.Hp <= 0) @@ -184,11 +177,11 @@ namespace NadekoBot.Modules.Pokemon if (targetStats.Hp <= 0) { - response += $"\n" + GetText("fainted", Format.Bold(targetUser.ToString())); + response += "\n" + GetText("fainted", Format.Bold(targetUser.ToString())); } else { - response += $"\n" + GetText("hp_remaining", Format.Bold(targetUser.ToString()), targetStats.Hp); + response += "\n" + GetText("hp_remaining", Format.Bold(targetUser.ToString()), targetStats.Hp); } //update other stats @@ -202,8 +195,8 @@ namespace NadekoBot.Modules.Pokemon //update dictionary //This can stay the same right? - Stats[user.Id] = userStats; - Stats[targetUser.Id] = targetStats; + _stats[user.Id] = userStats; + _stats[targetUser.Id] = targetStats; await Context.Channel.SendConfirmAsync(Context.User.Mention + " " + response).ConfigureAwait(false); } @@ -235,9 +228,9 @@ namespace NadekoBot.Modules.Pokemon return; } - if (Stats.ContainsKey(targetUser.Id)) + if (_stats.ContainsKey(targetUser.Id)) { - var targetStats = Stats[targetUser.Id]; + var targetStats = _stats[targetUser.Id]; if (targetStats.Hp == targetStats.MaxHp) { await ReplyErrorLocalized("already_full", Format.Bold(targetUser.ToString())).ConfigureAwait(false); @@ -261,7 +254,7 @@ namespace NadekoBot.Modules.Pokemon if (targetStats.Hp < 0) { //Could heal only for half HP? - Stats[targetUser.Id].Hp = (targetStats.MaxHp / 2); + _stats[targetUser.Id].Hp = (targetStats.MaxHp / 2); if (target == "yourself") { await ReplyConfirmLocalized("revive_yourself", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); @@ -271,7 +264,6 @@ namespace NadekoBot.Modules.Pokemon await ReplyConfirmLocalized("revive_other", Format.Bold(targetUser.ToString()), NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); } await ReplyConfirmLocalized("healed", Format.Bold(targetUser.ToString()), NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); - return; } else { @@ -299,7 +291,7 @@ namespace NadekoBot.Modules.Pokemon var targetType = StringToPokemonType(typeTargeted); if (targetType == null) { - await Context.Channel.EmbedAsync(PokemonTypes.Aggregate(new EmbedBuilder().WithDescription("List of the available types:"), + await Context.Channel.EmbedAsync(_pokemonTypes.Aggregate(new EmbedBuilder().WithDescription("List of the available types:"), (eb, pt) => eb.AddField(efb => efb.WithName(pt.Name) .WithValue(pt.Icon) .WithIsInline(true))) @@ -324,12 +316,11 @@ namespace NadekoBot.Modules.Pokemon } //Actually changing the type here - Dictionary setTypes; using (var uow = DbHandler.UnitOfWork()) { - var pokeUsers = uow.PokeGame.GetAll(); - setTypes = pokeUsers.ToDictionary(x => x.UserId, y => y.type); + var pokeUsers = uow.PokeGame.GetAll().ToArray(); + var setTypes = pokeUsers.ToDictionary(x => x.UserId, y => y.type); var pt = new UserPokeTypes { UserId = user.Id, @@ -343,7 +334,7 @@ namespace NadekoBot.Modules.Pokemon else { //update user in db - var pokeUserCmd = pokeUsers.Where(p => p.UserId == user.Id).FirstOrDefault(); + var pokeUserCmd = pokeUsers.FirstOrDefault(p => p.UserId == user.Id); pokeUserCmd.type = targetType.Name; uow.PokeGame.Update(pokeUserCmd); } From 45f69bac585ea7694fed06c2c8f9c002b6d12fd1 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 15 Feb 2017 11:03:40 +0100 Subject: [PATCH 262/746] Cleanup, bugfixes, Slots, flip, gambling commands localizable. --- .../Gambling/Commands/CurrencyEvents.cs | 2 +- .../Gambling/Commands/DiceRollCommand.cs | 2 +- .../Modules/Gambling/Commands/DrawCommand.cs | 2 +- .../Gambling/Commands/FlipCoinCommand.cs | 25 +- .../Modules/Gambling/Commands/Slots.cs | 64 ++--- .../Gambling/Commands/WaifuClaimCommands.cs | 2 +- src/NadekoBot/Modules/Gambling/Gambling.cs | 105 ++++---- src/NadekoBot/Modules/NadekoModule.cs | 34 ++- src/NadekoBot/NadekoBot.xproj.DotSettings | 3 +- .../Resources/ResponseStrings.Designer.cs | 234 ++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 81 ++++++ 11 files changed, 439 insertions(+), 115 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs index 02c8803e..4681d91b 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -19,7 +19,7 @@ namespace NadekoBot.Modules.Gambling public partial class Gambling { [Group] - public class CurrencyEvents : ModuleBase + public class CurrencyEvents : NadekoSubmodule { public enum CurrencyEvent { diff --git a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs index 4616aa91..4bda25a4 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs @@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Gambling public partial class Gambling { [Group] - public class DriceRollCommands : ModuleBase + public class DriceRollCommands : NadekoSubmodule { private Regex dndRegex { get; } = new Regex(@"^(?\d+)d(?\d+)(?:\+(?\d+))?(?:\-(?\d+))?$", RegexOptions.Compiled); private Regex fudgeRegex { get; } = new Regex(@"^(?\d+)d(?:F|f)$", RegexOptions.Compiled); diff --git a/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs index adbe4913..b9ae375b 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs @@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Gambling public partial class Gambling { [Group] - public class DrawCommands : ModuleBase + public class DrawCommands : NadekoSubmodule { private static readonly ConcurrentDictionary AllDecks = new ConcurrentDictionary(); diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs index 6ccfe786..973bc90e 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs @@ -1,12 +1,10 @@ using Discord; using Discord.Commands; -using ImageSharp; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; using System; using System.Collections.Generic; -using System.IO; using System.Threading.Tasks; using Image = ImageSharp.Image; @@ -15,7 +13,7 @@ namespace NadekoBot.Modules.Gambling public partial class Gambling { [Group] - public class FlipCoinCommands : ModuleBase + public class FlipCoinCommands : NadekoSubmodule { private readonly IImagesService _images; @@ -24,7 +22,7 @@ namespace NadekoBot.Modules.Gambling public FlipCoinCommands() { //todo DI in the future, can't atm - this._images = NadekoBot.Images; + _images = NadekoBot.Images; } [NadekoCommand, Usage, Description, Aliases] @@ -36,21 +34,21 @@ namespace NadekoBot.Modules.Gambling { using (var heads = _images.Heads.ToStream()) { - await Context.Channel.SendFileAsync(heads, "heads.jpg", $"{Context.User.Mention} flipped " + Format.Code("Heads") + ".").ConfigureAwait(false); + await Context.Channel.SendFileAsync(heads, "heads.jpg", Context.User.Mention + " " + GetText("flipped", Format.Bold(GetText("heads"))) + ".").ConfigureAwait(false); } } else { using (var tails = _images.Tails.ToStream()) { - await Context.Channel.SendFileAsync(tails, "tails.jpg", $"{Context.User.Mention} flipped " + Format.Code("Tails") + ".").ConfigureAwait(false); + await Context.Channel.SendFileAsync(tails, "tails.jpg", Context.User.Mention + " " + GetText("flipped", Format.Bold(GetText("tails"))) + ".").ConfigureAwait(false); } } return; } if (count > 10 || count < 1) { - await Context.Channel.SendErrorAsync("`Invalid number specified. You can flip 1 to 10 coins.`").ConfigureAwait(false); + await ReplyErrorLocalized("flip_invalid", 10).ConfigureAwait(false); return; } var imgs = new Image[count]; @@ -76,14 +74,13 @@ namespace NadekoBot.Modules.Gambling if (amount < NadekoBot.BotConfig.MinimumBetAmount) { - await Context.Channel.SendErrorAsync($"You can't bet less than {NadekoBot.BotConfig.MinimumBetAmount}{CurrencySign}.") - .ConfigureAwait(false); + await ReplyErrorLocalized("min_bet_limit", NadekoBot.BotConfig.MinimumBetAmount + CurrencySign).ConfigureAwait(false); return; } var removed = await CurrencyHandler.RemoveCurrencyAsync(Context.User, "Betflip Gamble", amount, false).ConfigureAwait(false); if (!removed) { - await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {CurrencyPluralName}.").ConfigureAwait(false); + await ReplyErrorLocalized("not_enough", CurrencyPluralName).ConfigureAwait(false); return; } //heads = true @@ -91,7 +88,7 @@ namespace NadekoBot.Modules.Gambling //todo this seems stinky, no time to look at it right now var isHeads = guessStr == "HEADS" || guessStr == "H"; - bool result = false; + var result = false; IEnumerable imageToSend; if (rng.Next(0, 2) == 1) { @@ -107,12 +104,12 @@ namespace NadekoBot.Modules.Gambling if (isHeads == result) { var toWin = (int)Math.Round(amount * NadekoBot.BotConfig.BetflipMultiplier); - str = $"{Context.User.Mention}`You guessed it!` You won {toWin}{CurrencySign}"; - await CurrencyHandler.AddCurrencyAsync(Context.User, "Betflip Gamble", toWin, false).ConfigureAwait(false); + str = Context.User.Mention + " " + GetText("flip_guess", toWin + CurrencySign); + await CurrencyHandler.AddCurrencyAsync(Context.User, GetText("betflip_gamble"), toWin, false).ConfigureAwait(false); } else { - str = $"{Context.User.Mention}`Better luck next time.`"; + str = Context.User.Mention + " " + GetText("better_luck"); } using (var toSend = imageToSend.ToStream()) { diff --git a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs index bd977e9b..c298a9b4 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs @@ -5,7 +5,6 @@ using NadekoBot.Extensions; using NadekoBot.Services; using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Text; using System.Threading; @@ -16,12 +15,12 @@ namespace NadekoBot.Modules.Gambling public partial class Gambling { [Group] - public class Slots : ModuleBase + public class Slots : NadekoSubmodule { - private static int totalBet = 0; - private static int totalPaidOut = 0; + private static int _totalBet; + private static int _totalPaidOut; - const int alphaCutOut = byte.MaxValue / 3; + private const int _alphaCutOut = byte.MaxValue / 3; //here is a payout chart //https://lh6.googleusercontent.com/-i1hjAJy_kN4/UswKxmhrbPI/AAAAAAAAB1U/82wq_4ZZc-Y/DE6B0895-6FC1-48BE-AC4F-14D1B91AB75B.jpg @@ -31,14 +30,14 @@ namespace NadekoBot.Modules.Gambling public Slots() { - this._images = NadekoBot.Images; + _images = NadekoBot.Images; } public class SlotMachine { public const int MaxValue = 5; - static readonly List> winningCombos = new List>() + static readonly List> _winningCombos = new List>() { //three flowers (arr) => arr.All(a=>a==MaxValue) ? 30 : 0, @@ -53,14 +52,14 @@ namespace NadekoBot.Modules.Gambling public static SlotResult Pull() { var numbers = new int[3]; - for (int i = 0; i < numbers.Length; i++) + for (var 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++) + var multi = 0; + foreach (var t in _winningCombos) { - multi = winningCombos[i](numbers); + multi = t(numbers); if (multi != 0) break; } @@ -74,8 +73,8 @@ namespace NadekoBot.Modules.Gambling public int Multiplier { get; } public SlotResult(int[] nums, int multi) { - this.Numbers = nums; - this.Multiplier = multi; + Numbers = nums; + Multiplier = multi; } } } @@ -85,8 +84,8 @@ namespace NadekoBot.Modules.Gambling public async Task SlotStats() { //i remembered to not be a moron - var paid = totalPaidOut; - var bet = totalBet; + var paid = _totalPaidOut; + var bet = _totalBet; if (bet <= 0) bet = 1; @@ -130,33 +129,34 @@ namespace NadekoBot.Modules.Gambling footer: $"Total Bet: {tests * bet} | Payout: {payout * bet} | {payout * 1.0f / tests * 100}%"); } - static HashSet runningUsers = new HashSet(); + private static readonly HashSet _runningUsers = new HashSet(); [NadekoCommand, Usage, Description, Aliases] public async Task Slot(int amount = 0) { - if (!runningUsers.Add(Context.User.Id)) + 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); + await ReplyErrorLocalized("min_bet_limit", 1 + CurrencySign).ConfigureAwait(false); return; } if (amount > 999) { - await Context.Channel.SendErrorAsync($"You can't bet more than 999{NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); + GetText("slot_maxbet", 999 + CurrencySign); + await ReplyErrorLocalized("max_bet_limit", 999 + CurrencySign).ConfigureAwait(false); return; } if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User, "Slot Machine", amount, false)) { - await Context.Channel.SendErrorAsync($"You don't have enough {NadekoBot.BotConfig.CurrencySign}.").ConfigureAwait(false); + await ReplyErrorLocalized("not_enough", CurrencySign).ConfigureAwait(false); return; } - Interlocked.Add(ref totalBet, amount); + Interlocked.Add(ref _totalBet, amount); using (var bgFileStream = NadekoBot.Images.SlotBackground.ToStream()) { var bgImage = new ImageSharp.Image(bgFileStream); @@ -179,7 +179,7 @@ namespace NadekoBot.Modules.Gambling var x = 95 + 142 * i + j; int y = 330 + k; var toSet = toAdd[j, k]; - if (toSet.A < alphaCutOut) + if (toSet.A < _alphaCutOut) continue; bgPixels[x, y] = toAdd[j, k]; } @@ -203,7 +203,7 @@ namespace NadekoBot.Modules.Gambling { for (int j = 0; j < pixels.Height; j++) { - if (pixels[i, j].A < alphaCutOut) + if (pixels[i, j].A < _alphaCutOut) continue; var x = 230 - n * 16 + i; bgPixels[x, 462 + j] = pixels[i, j]; @@ -228,7 +228,7 @@ namespace NadekoBot.Modules.Gambling { for (int j = 0; j < pixels.Height; j++) { - if (pixels[i, j].A < alphaCutOut) + if (pixels[i, j].A < _alphaCutOut) continue; var x = 395 - n * 16 + i; bgPixels[x, 462 + j] = pixels[i, j]; @@ -240,22 +240,22 @@ namespace NadekoBot.Modules.Gambling } while ((printAmount /= 10) != 0); } - var msg = "Better luck next time ^_^"; + var msg = GetText("better_luck"); 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); + Interlocked.Add(ref _totalPaidOut, amount * result.Multiplier); if (result.Multiplier == 1) - msg = $"A single {NadekoBot.BotConfig.CurrencySign}, x1 - Try again!"; + msg = GetText("slot_single", CurrencySign, 1); else if (result.Multiplier == 4) - msg = $"Good job! Two {NadekoBot.BotConfig.CurrencySign} - bet x4"; + msg = GetText("slot_two", CurrencySign, 4); else if (result.Multiplier == 10) - msg = "Wow! Lucky! Three of a kind! x10"; + msg = GetText("slot_three", 10); else if (result.Multiplier == 30) - msg = "WOAAHHHHHH!!! Congratulations!!! x30"; + msg = GetText("slot_jackpot", 30); } - await Context.Channel.SendFileAsync(bgImage.ToStream(), "result.png", Context.User.Mention + " " + msg + $"\n`Bet:`{amount} `Won:` {amount * result.Multiplier}{NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); + await Context.Channel.SendFileAsync(bgImage.ToStream(), "result.png", Context.User.Mention + " " + msg + $"\n`{GetText("slot_bet")}:`{amount} `{GetText("slot_won")}:` {amount * result.Multiplier}{NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false); } } finally @@ -263,7 +263,7 @@ namespace NadekoBot.Modules.Gambling var _ = Task.Run(async () => { await Task.Delay(2000); - runningUsers.Remove(Context.User.Id); + _runningUsers.Remove(Context.User.Id); }); } } diff --git a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs index 8c6cfcd5..6ff7695d 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs @@ -47,7 +47,7 @@ namespace NadekoBot.Modules.Gambling } [Group] - public class WaifuClaimCommands : ModuleBase + public class WaifuClaimCommands : NadekoSubmodule { private static ConcurrentDictionary _divorceCooldowns { get; } = new ConcurrentDictionary(); private static ConcurrentDictionary _affinityCooldowns { get; } = new ConcurrentDictionary(); diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 6bcf5654..6650bee5 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -1,9 +1,9 @@ -using Discord; +using System; +using Discord; using Discord.Commands; using NadekoBot.Attributes; using NadekoBot.Extensions; using System.Linq; -using System.Text; using System.Threading.Tasks; using NadekoBot.Services; using NadekoBot.Services.Database.Models; @@ -42,7 +42,7 @@ namespace NadekoBot.Modules.Gambling var members = role.Members().Where(u => u.Status != UserStatus.Offline && u.Status != UserStatus.Unknown); var membersArray = members as IUser[] ?? members.ToArray(); var usr = membersArray[new NadekoRandom().Next(0, membersArray.Length)]; - await Context.Channel.SendConfirmAsync("🎟 Raffled user", $"**{usr.Username}#{usr.Discriminator}**", footer: $"ID: {usr.Id}").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync("🎟 "+ GetText("raffled_user"), $"**{usr.Username}#{usr.Discriminator}**", footer: $"ID: {usr.Id}").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -50,15 +50,14 @@ namespace NadekoBot.Modules.Gambling public async Task Cash([Remainder] IUser user = null) { user = user ?? Context.User; - - await Context.Channel.SendConfirmAsync($"{user.Username} has {GetCurrency(user.Id)} {CurrencySign}").ConfigureAwait(false); + await ReplyConfirmLocalized("has", Format.Bold(user.ToString()), $"{GetCurrency(user.Id)} {CurrencySign}").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [Priority(1)] public async Task Cash(ulong userId) { - await Context.Channel.SendConfirmAsync($"`{userId}` has {GetCurrency(userId)} {CurrencySign}").ConfigureAwait(false); + await ReplyConfirmLocalized("has", Format.Code(userId.ToString()), $"{GetCurrency(userId)} {CurrencySign}").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -70,11 +69,12 @@ namespace NadekoBot.Modules.Gambling var success = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Gift to {receiver.Username} ({receiver.Id}).", amount, false).ConfigureAwait(false); if (!success) { - await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {CurrencyPluralName}.").ConfigureAwait(false); + await ReplyErrorLocalized("not_enough", CurrencyPluralName).ConfigureAwait(false); return; } await CurrencyHandler.AddCurrencyAsync(receiver, $"Gift from {Context.User.Username} ({Context.User.Id}).", amount, true).ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} gifted {amount}{CurrencySign} to {Format.Bold(receiver.ToString())}!").ConfigureAwait(false); + await ReplyConfirmLocalized("gifted", amount + CurrencySign, Format.Bold(receiver.ToString())) + .ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -93,8 +93,7 @@ namespace NadekoBot.Modules.Gambling return; await CurrencyHandler.AddCurrencyAsync(usrId, $"Awarded by bot owner. ({Context.User.Username}/{Context.User.Id})", amount).ConfigureAwait(false); - - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} awarded {amount}{CurrencySign} to <@{usrId}>!").ConfigureAwait(false); + await ReplyConfirmLocalized("awarded", amount + CurrencySign, $"<@{usrId}>").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -111,9 +110,10 @@ namespace NadekoBot.Modules.Gambling amount))) .ConfigureAwait(false); - await Context.Channel.SendConfirmAsync($"Awarded `{amount}` {CurrencyPluralName} to `{users.Count}` users from `{role.Name}` role.") - .ConfigureAwait(false); - + await ReplyConfirmLocalized("mass_award", + amount + CurrencySign, + Format.Bold(users.Count.ToString()), + Format.Bold(role.Name)).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -125,9 +125,9 @@ namespace NadekoBot.Modules.Gambling return; if (await CurrencyHandler.RemoveCurrencyAsync(user, $"Taken by bot owner.({Context.User.Username}/{Context.User.Id})", amount, true).ConfigureAwait(false)) - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully took {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from {user}!").ConfigureAwait(false); + await ReplyConfirmLocalized("take", amount+CurrencySign, Format.Bold(user.ToString())).ConfigureAwait(false); else - await Context.Channel.SendErrorAsync($"{Context.User.Mention} was unable to take {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from {user} because the user doesn't have that much {CurrencyPluralName}!").ConfigureAwait(false); + await ReplyErrorLocalized("take_fail", amount + CurrencySign, Format.Bold(user.ToString()), CurrencyPluralName).ConfigureAwait(false); } @@ -139,9 +139,9 @@ namespace NadekoBot.Modules.Gambling return; if (await CurrencyHandler.RemoveCurrencyAsync(usrId, $"Taken by bot owner.({Context.User.Username}/{Context.User.Id})", amount).ConfigureAwait(false)) - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully took {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from <@{usrId}>!").ConfigureAwait(false); + await ReplyConfirmLocalized("take", amount + CurrencySign, $"<@{usrId}>").ConfigureAwait(false); else - 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); + await ReplyErrorLocalized("take_fail", amount + CurrencySign, Format.Code(usrId.ToString()), CurrencyPluralName).ConfigureAwait(false); } //[NadekoCommand, Usage, Description, Aliases] @@ -205,49 +205,48 @@ namespace NadekoBot.Modules.Gambling if (amount < 1) return; - long userFlowers; - using (var uow = DbHandler.UnitOfWork()) + if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User, "Betroll Gamble", amount, false).ConfigureAwait(false)) { - userFlowers = uow.Currency.GetOrCreate(Context.User.Id).Amount; - } - - if (userFlowers < amount) - { - await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {CurrencyPluralName}. You only have {userFlowers}{CurrencySign}.").ConfigureAwait(false); + await ReplyErrorLocalized("not_enough", CurrencyPluralName).ConfigureAwait(false); return; } - await CurrencyHandler.RemoveCurrencyAsync(Context.User, "Betroll Gamble", amount, false).ConfigureAwait(false); - - var rng = new NadekoRandom().Next(0, 101); - var str = $"{Context.User.Mention} `You rolled {rng}.` "; - if (rng < 67) + var rnd = new NadekoRandom().Next(0, 101); + var str = Context.User.Mention + Format.Code(GetText("roll", rnd)); + if (rnd < 67) { - str += "Better luck next time."; - } - else if (rng < 91) - { - str += $"Congratulations! You won {amount * NadekoBot.BotConfig.Betroll67Multiplier}{CurrencySign} for rolling above 66"; - await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", (int)(amount * NadekoBot.BotConfig.Betroll67Multiplier), false).ConfigureAwait(false); - } - else if (rng < 100) - { - str += $"Congratulations! You won {amount * NadekoBot.BotConfig.Betroll91Multiplier}{CurrencySign} for rolling above 90."; - await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", (int)(amount * NadekoBot.BotConfig.Betroll91Multiplier), false).ConfigureAwait(false); + str += GetText("better_luck"); } else { - str += $"👑 Congratulations! You won {amount * NadekoBot.BotConfig.Betroll100Multiplier}{CurrencySign} for rolling **100**. 👑"; - await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", (int)(amount * NadekoBot.BotConfig.Betroll100Multiplier), false).ConfigureAwait(false); + if (rnd < 91) + { + str += GetText("br_win", (amount * NadekoBot.BotConfig.Betroll67Multiplier) + CurrencySign, 66); + await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", + (int) (amount * NadekoBot.BotConfig.Betroll67Multiplier), false).ConfigureAwait(false); + } + else if (rnd < 100) + { + str += GetText("br_win", (amount * NadekoBot.BotConfig.Betroll91Multiplier) + CurrencySign, 90); + await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", + (int) (amount * NadekoBot.BotConfig.Betroll91Multiplier), false).ConfigureAwait(false); + } + else + { + str += GetText("br_win", (amount * NadekoBot.BotConfig.Betroll100Multiplier) + CurrencySign, 100) + " 👑"; + await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", + (int) (amount * NadekoBot.BotConfig.Betroll100Multiplier), false).ConfigureAwait(false); + } } - + Console.WriteLine("started sending"); await Context.Channel.SendConfirmAsync(str).ConfigureAwait(false); + Console.WriteLine("done sending"); } [NadekoCommand, Usage, Description, Aliases] public async Task Leaderboard() { - var richest = new List(); + List richest; using (var uow = DbHandler.UnitOfWork()) { richest = uow.Currency.GetTopRichest(9).ToList(); @@ -255,22 +254,22 @@ namespace NadekoBot.Modules.Gambling if (!richest.Any()) return; - var embed = new EmbedBuilder() .WithOkColor() - .WithTitle(NadekoBot.BotConfig.CurrencySign + " Leaderboard"); + .WithTitle(NadekoBot.BotConfig.CurrencySign + " " + GetText("leaderboard")); for (var i = 0; i < richest.Count; i++) { var x = richest[i]; var usr = await Context.Guild.GetUserAsync(x.UserId).ConfigureAwait(false); - var usrStr = ""; - if (usr == null) - usrStr = x.UserId.ToString(); - else - usrStr = usr.Username?.TrimTo(20, true); + var usrStr = usr == null + ? x.UserId.ToString() + : usr.Username?.TrimTo(20, true); - embed.AddField(efb => efb.WithName("#" + (i + 1) + " " + usrStr).WithValue(x.Amount.ToString() + " " + NadekoBot.BotConfig.CurrencySign).WithIsInline(true)); + var j = i; + embed.AddField(efb => efb.WithName("#" + (j + 1) + " " + usrStr) + .WithValue(x.Amount.ToString() + " " + NadekoBot.BotConfig.CurrencySign) + .WithIsInline(true)); } await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index 9bb524ec..4c8d17d3 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -67,14 +67,26 @@ namespace NadekoBot.Modules if (string.IsNullOrWhiteSpace(text)) { LogManager.GetCurrentClassLogger().Warn(lowerModuleTypeName + "_" + key + " key is missing from " + cultureInfo + " response strings. PLEASE REPORT THIS."); - return NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, _usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} found!"; + text = NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, _usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} not found!"; + if (string.IsNullOrWhiteSpace(text)) + return "I cant tell if you command is executed, because there was an error printing out the response. Key '" + + lowerModuleTypeName + "_" + key + "' " + "is missing from resources. Please report this."; } return text; } - public static string GetTextStatic(string key, CultureInfo cultureInfo, string lowerModuleTypeName, params object[] replacements) + public static string GetTextStatic(string key, CultureInfo cultureInfo, string lowerModuleTypeName, + params object[] replacements) { - return string.Format(GetTextStatic(key, cultureInfo, lowerModuleTypeName), replacements); + try + { + return string.Format(GetTextStatic(key, cultureInfo, lowerModuleTypeName), replacements); + } + catch (FormatException) + { + return "I cant tell if you command is executed, because there was an error printing out the response. Key '" + + lowerModuleTypeName + "_" + key + "' " + "is not properly formatted. Please report this."; + } } protected string GetText(string key) => @@ -85,26 +97,26 @@ namespace NadekoBot.Modules public Task ErrorLocalized(string textKey, params object[] replacements) { - var text = GetText(textKey); - return Context.Channel.SendErrorAsync(string.Format(text, replacements)); + var text = GetText(textKey, replacements); + return Context.Channel.SendErrorAsync(text); } public Task ReplyErrorLocalized(string textKey, params object[] replacements) { - var text = GetText(textKey); - return Context.Channel.SendErrorAsync(Context.User.Mention + " " + string.Format(text, replacements)); + var text = GetText(textKey, replacements); + return Context.Channel.SendErrorAsync(Context.User.Mention + " " + text); } public Task ConfirmLocalized(string textKey, params object[] replacements) { - var text = GetText(textKey); - return Context.Channel.SendConfirmAsync(string.Format(text, replacements)); + var text = GetText(textKey, replacements); + return Context.Channel.SendConfirmAsync(text); } public Task ReplyConfirmLocalized(string textKey, params object[] replacements) { - var text = GetText(textKey); - return Context.Channel.SendConfirmAsync(Context.User.Mention + " " + string.Format(text, replacements)); + var text = GetText(textKey, replacements); + return Context.Channel.SendConfirmAsync(Context.User.Mention + " " + text); } } diff --git a/src/NadekoBot/NadekoBot.xproj.DotSettings b/src/NadekoBot/NadekoBot.xproj.DotSettings index ae4d5dac..3a1cb1b5 100644 --- a/src/NadekoBot/NadekoBot.xproj.DotSettings +++ b/src/NadekoBot/NadekoBot.xproj.DotSettings @@ -1,2 +1,3 @@  - True \ No newline at end of file + True + True \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index d8db88cd..95a0be9a 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2072,6 +2072,240 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to has awarded {0} to {1}. + /// + public static string gambling_awarded { + get { + return ResourceManager.GetString("gambling_awarded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Betflip Gamble. + /// + public static string gambling_betflip_gamble { + get { + return ResourceManager.GetString("gambling_betflip_gamble", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Better luck next time ^_^. + /// + public static string gambling_better_luck { + get { + return ResourceManager.GetString("gambling_better_luck", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Congratulations! You won {0} for rolling above {1}. + /// + public static string gambling_br_win { + get { + return ResourceManager.GetString("gambling_br_win", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You guessed it! You won {0}. + /// + public static string gambling_flip_guess { + get { + return ResourceManager.GetString("gambling_flip_guess", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid number specified. You can flip 1 to {0} coins.. + /// + public static string gambling_flip_invalid { + get { + return ResourceManager.GetString("gambling_flip_invalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to flipped {0}.. + /// + public static string gambling_flipped { + get { + return ResourceManager.GetString("gambling_flipped", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to has gifted {0} to {1}. + /// + public static string gambling_gifted { + get { + return ResourceManager.GetString("gambling_gifted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has {1}. + /// + public static string gambling_has { + get { + return ResourceManager.GetString("gambling_has", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Heads. + /// + public static string gambling_heads { + get { + return ResourceManager.GetString("gambling_heads", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Leaderboard. + /// + public static string gambling_leaderboard { + get { + return ResourceManager.GetString("gambling_leaderboard", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Awarded {0} to {1} users from {2} role.. + /// + public static string gambling_mass_award { + get { + return ResourceManager.GetString("gambling_mass_award", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You can't bet more than {0}. + /// + public static string gambling_max_bet_limit { + get { + return ResourceManager.GetString("gambling_max_bet_limit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You can't bet less than {0}. + /// + public static string gambling_min_bet_limit { + get { + return ResourceManager.GetString("gambling_min_bet_limit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You don't have enough {0}. + /// + public static string gambling_not_enough { + get { + return ResourceManager.GetString("gambling_not_enough", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Raffled User. + /// + public static string gambling_raffled_user { + get { + return ResourceManager.GetString("gambling_raffled_user", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You rolled {0}.. + /// + public static string gambling_roll { + get { + return ResourceManager.GetString("gambling_roll", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bet. + /// + public static string gambling_slot_bet { + get { + return ResourceManager.GetString("gambling_slot_bet", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WOAAHHHHHH!!! Congratulations!!! x{0}. + /// + public static string gambling_slot_jackpot { + get { + return ResourceManager.GetString("gambling_slot_jackpot", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A single {0}, x{1}. + /// + public static string gambling_slot_single { + get { + return ResourceManager.GetString("gambling_slot_single", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wow! Lucky! Three of a kind! x{0}. + /// + public static string gambling_slot_three { + get { + return ResourceManager.GetString("gambling_slot_three", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Good job! Two {0} - bet x{1}. + /// + public static string gambling_slot_two { + get { + return ResourceManager.GetString("gambling_slot_two", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Won. + /// + public static string gambling_slot_won { + get { + return ResourceManager.GetString("gambling_slot_won", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tails. + /// + public static string gambling_tails { + get { + return ResourceManager.GetString("gambling_tails", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to successfully took {0} from {1}. + /// + public static string gambling_take { + get { + return ResourceManager.GetString("gambling_take", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to was unable to take {0} from{1} because the user doesn't have that much {2}!. + /// + public static string gambling_take_fail { + get { + return ResourceManager.GetString("gambling_take_fail", resourceCulture); + } + } + /// /// Looks up a localized string similar to Back to ToC. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 7fabfa84..6fee14d7 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -870,6 +870,87 @@ Reason: {1} User Soft-Banned + + has awarded {0} to {1} + + + Betflip Gamble + + + Better luck next time ^_^ + + + Congratulations! You won {0} for rolling above {1} + + + flipped {0}. + User flipped tails. + + + You guessed it! You won {0} + + + Invalid number specified. You can flip 1 to {0} coins. + + + has gifted {0} to {1} + X has gifted 15 flowers to Y + + + {0} has {1} + X has Y flowers + + + Heads + + + Leaderboard + + + Awarded {0} to {1} users from {2} role. + + + You can't bet more than {0} + + + You can't bet less than {0} + + + You don't have enough {0} + + + Raffled User + + + You rolled {0}. + + + Bet + + + WOAAHHHHHH!!! Congratulations!!! x{0} + + + A single {0}, x{1} + + + Wow! Lucky! Three of a kind! x{0} + + + Good job! Two {0} - bet x{1} + + + Won + + + Tails + + + successfully took {0} from {1} + + + was unable to take {0} from{1} because the user doesn't have that much {2}! + Back to ToC From 5ed0ee4ef8a78e5b5b5bc1e86afa4327b7c304e4 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 15 Feb 2017 11:17:55 +0100 Subject: [PATCH 263/746] Draw commands done --- .../Modules/Gambling/Commands/DrawCommand.cs | 23 +++++++++++-------- .../Resources/ResponseStrings.Designer.cs | 18 +++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 6 +++++ 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs index b9ae375b..7471f7d0 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs @@ -4,8 +4,6 @@ using ImageSharp; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Modules.Gambling.Models; -using NLog; -using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; @@ -19,15 +17,15 @@ namespace NadekoBot.Modules.Gambling [Group] public class DrawCommands : NadekoSubmodule { - private static readonly ConcurrentDictionary AllDecks = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary _allDecks = new ConcurrentDictionary(); - private const string cardsPath = "data/images/cards"; + private const string _cardsPath = "data/images/cards"; [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task Draw(int num = 1) { - var cards = AllDecks.GetOrAdd(Context.Guild, (s) => new Cards()); + var cards = _allDecks.GetOrAdd(Context.Guild, (s) => new Cards()); var images = new List(); var cardObjects = new List(); if (num > 5) num = 5; @@ -35,12 +33,19 @@ namespace NadekoBot.Modules.Gambling { if (cards.CardPool.Count == 0 && i != 0) { - try { await Context.Channel.SendErrorAsync("No more cards in a deck.").ConfigureAwait(false); } catch { } + try + { + await ReplyErrorLocalized("no_more_cards").ConfigureAwait(false); + } + catch + { + // ignored + } break; } var currentCard = cards.DrawACard(); cardObjects.Add(currentCard); - using (var stream = File.OpenRead(Path.Combine(cardsPath, currentCard.ToString().ToLowerInvariant()+ ".jpg").Replace(' ','_'))) + using (var stream = File.OpenRead(Path.Combine(_cardsPath, currentCard.ToString().ToLowerInvariant()+ ".jpg").Replace(' ','_'))) images.Add(new Image(stream)); } MemoryStream bitmapStream = new MemoryStream(); @@ -59,7 +64,7 @@ namespace NadekoBot.Modules.Gambling { //var channel = (ITextChannel)Context.Channel; - AllDecks.AddOrUpdate(Context.Guild, + _allDecks.AddOrUpdate(Context.Guild, (g) => new Cards(), (g, c) => { @@ -67,7 +72,7 @@ namespace NadekoBot.Modules.Gambling return c; }); - await Context.Channel.SendConfirmAsync("Deck reshuffled.").ConfigureAwait(false); + await ReplyConfirmLocalized("deck_reshuffled").ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 95a0be9a..7dda445c 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2108,6 +2108,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Deck reshuffled.. + /// + public static string gambling_deck_reshuffled { + get { + return ResourceManager.GetString("gambling_deck_reshuffled", resourceCulture); + } + } + /// /// Looks up a localized string similar to You guessed it! You won {0}. /// @@ -2198,6 +2207,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to No more cards in the deck.. + /// + public static string gambling_no_more_cards { + get { + return ResourceManager.GetString("gambling_no_more_cards", resourceCulture); + } + } + /// /// Looks up a localized string similar to You don't have enough {0}. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 6fee14d7..eb8b565a 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -882,6 +882,9 @@ Reason: {1} Congratulations! You won {0} for rolling above {1} + + Deck reshuffled. + flipped {0}. User flipped tails. @@ -918,6 +921,9 @@ Reason: {1} You don't have enough {0} + + No more cards in the deck. + Raffled User From 1804b81b8a8a55a7842ddb430d08841a2c18f7bf Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 15 Feb 2017 11:41:32 +0100 Subject: [PATCH 264/746] currency events localizable :ok: --- .../Gambling/Commands/CurrencyEvents.cs | 51 ++++++++--------- .../Resources/ResponseStrings.Designer.cs | 55 +++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 19 +++++++ 3 files changed, 100 insertions(+), 25 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs index 4681d91b..814fb747 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -5,12 +5,9 @@ using NadekoBot.Extensions; using NadekoBot.Services; using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading.Tasks; using Discord.WebSocket; -using NadekoBot.Services.Database; using System.Threading; using NLog; @@ -27,7 +24,7 @@ namespace NadekoBot.Modules.Gambling SneakyGameStatus } //flower reaction event - public static readonly ConcurrentHashSet _sneakyGameAwardedUsers = new ConcurrentHashSet(); + private static readonly ConcurrentHashSet _sneakyGameAwardedUsers = new ConcurrentHashSet(); private static readonly char[] _sneakyGameStatusChars = Enumerable.Range(48, 10) @@ -36,7 +33,7 @@ namespace NadekoBot.Modules.Gambling .Select(x => (char)x) .ToArray(); - private static string _secretCode = String.Empty; + private static string _secretCode = string.Empty; [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] @@ -54,7 +51,7 @@ namespace NadekoBot.Modules.Gambling } } - public static async Task SneakyGameStatusEvent(CommandContext Context, int? arg) + public async Task SneakyGameStatusEvent(CommandContext context, int? arg) { int num; if (arg == null || arg < 5) @@ -62,11 +59,11 @@ namespace NadekoBot.Modules.Gambling else num = arg.Value; - if (_secretCode != String.Empty) + if (_secretCode != string.Empty) return; var rng = new NadekoRandom(); - for (int i = 0; i < 5; i++) + for (var i = 0; i < 5; i++) { _secretCode += _sneakyGameStatusChars[rng.Next(0, _sneakyGameStatusChars.Length)]; } @@ -75,10 +72,9 @@ namespace NadekoBot.Modules.Gambling .ConfigureAwait(false); try { - await Context.Channel.SendConfirmAsync($"SneakyGameStatus event started", - $"Users must type a secret code to get 100 currency.\n" + - $"Lasts {num} seconds. Don't tell anyone. Shhh.") - .ConfigureAwait(false); + var title = GetText("sneakygamestatus_title"); + var desc = GetText("sneakygamestatus_desc", Format.Bold(100.ToString()) + CurrencySign, Format.Bold(num.ToString())); + await context.Channel.SendConfirmAsync(title, desc).ConfigureAwait(false); } catch { @@ -92,9 +88,9 @@ namespace NadekoBot.Modules.Gambling var cnt = _sneakyGameAwardedUsers.Count; _sneakyGameAwardedUsers.Clear(); - _secretCode = String.Empty; + _secretCode = string.Empty; - await NadekoBot.Client.SetGameAsync($"SneakyGame event ended. {cnt} users received a reward.") + await NadekoBot.Client.SetGameAsync(GetText("sneakygamestatus_end", cnt)) .ConfigureAwait(false); } @@ -119,22 +115,31 @@ namespace NadekoBot.Modules.Gambling return Task.Delay(0); } - public static Task FlowerReactionEvent(CommandContext context) => - new FlowerReactionEvent().Start(context); + public async Task FlowerReactionEvent(CommandContext context) + { + var title = GetText("flowerreaction_title"); + var desc = GetText("flowerreaction_desc", "🌸", Format.Bold(100.ToString()) + CurrencySign); + var footer = GetText("flowerreaction_footer", 24); + var msg = await context.Channel.SendConfirmAsync(title, + desc, footer: footer) + .ConfigureAwait(false); + + await new FlowerReactionEvent().Start(msg, context); + } } } public abstract class CurrencyEvent { - public abstract Task Start(CommandContext channel); + public abstract Task Start(IUserMessage msg, CommandContext channel); } public class FlowerReactionEvent : CurrencyEvent { - public readonly ConcurrentHashSet _flowerReactionAwardedUsers = new ConcurrentHashSet(); + private readonly ConcurrentHashSet _flowerReactionAwardedUsers = new ConcurrentHashSet(); private readonly Logger _log; - private IUserMessage msg { get; set; } = null; + private IUserMessage msg { get; set; } private CancellationTokenSource source { get; } private CancellationToken cancelToken { get; } @@ -167,13 +172,9 @@ namespace NadekoBot.Modules.Gambling return Task.CompletedTask; } - public override async Task Start(CommandContext context) + public override async Task Start(IUserMessage umsg, CommandContext context) { - msg = await context.Channel.SendConfirmAsync("Flower reaction event started!", - "Add 🌸 reaction to this message to get 100" + NadekoBot.BotConfig.CurrencySign, - footer: "This event is active for up to 24 hours.") - .ConfigureAwait(false); - + msg = umsg; NadekoBot.Client.MessageDeleted += MessageDeletedEventHandler; try { await msg.AddReactionAsync("🌸").ConfigureAwait(false); } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 7dda445c..30c80001 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2144,6 +2144,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Add {0} reaction to this message to get {1} . + /// + public static string gambling_flowerreaction_desc { + get { + return ResourceManager.GetString("gambling_flowerreaction_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This event is active for up to {0} hours.. + /// + public static string gambling_flowerreaction_footer { + get { + return ResourceManager.GetString("gambling_flowerreaction_footer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Flower reaction event started!. + /// + public static string gambling_flowerreaction_title { + get { + return ResourceManager.GetString("gambling_flowerreaction_title", resourceCulture); + } + } + /// /// Looks up a localized string similar to has gifted {0} to {1}. /// @@ -2297,6 +2324,34 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Users must type a secret code to get {0}. + ///Lasts {1} seconds. Don't tell anyone. Shhh.. + /// + public static string gambling_sneakygamestatus_desc { + get { + return ResourceManager.GetString("gambling_sneakygamestatus_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SneakyGame event ended. {0} users received the reward.. + /// + public static string gambling_sneakygamestatus_end { + get { + return ResourceManager.GetString("gambling_sneakygamestatus_end", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SneakyGameStatus event started. + /// + public static string gambling_sneakygamestatus_title { + get { + return ResourceManager.GetString("gambling_sneakygamestatus_title", resourceCulture); + } + } + /// /// Looks up a localized string similar to Tails. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index eb8b565a..c4228d5c 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -895,6 +895,15 @@ Reason: {1} Invalid number specified. You can flip 1 to {0} coins. + + Add {0} reaction to this message to get {1} + + + This event is active for up to {0} hours. + + + Flower reaction event started! + has gifted {0} to {1} X has gifted 15 flowers to Y @@ -948,6 +957,16 @@ Reason: {1} Won + + Users must type a secret code to get {0}. +Lasts {1} seconds. Don't tell anyone. Shhh. + + + SneakyGame event ended. {0} users received the reward. + + + SneakyGameStatus event started + Tails From da79daa92402b6db4229cc0cea1040ec92a4ae42 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 15 Feb 2017 11:46:58 +0100 Subject: [PATCH 265/746] closes #1057 mention role can now mention up to 50 peopl --- src/NadekoBot/Modules/Administration/Administration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index eb07ef1f..20760373 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -489,7 +489,7 @@ namespace NadekoBot.Modules.Administration foreach (var role in roles) { send += $"\n**{role.Name}**\n"; - send += string.Join(", ", (await Context.Guild.GetUsersAsync()).Where(u => u.GetRoles().Contains(role)).Distinct().Select(u => u.Mention)); + send += string.Join(", ", (await Context.Guild.GetUsersAsync()).Where(u => u.GetRoles().Contains(role)).Take(50).Select(u => u.Mention)); } while (send.Length > 2000) From 2edbbed583c79a13fefb888c2a824520aaa228c4 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 15 Feb 2017 12:09:10 +0100 Subject: [PATCH 266/746] song not found fix --- src/NadekoBot/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/project.json b/src/NadekoBot/project.json index a88058ea..88ebdd52 100644 --- a/src/NadekoBot/project.json +++ b/src/NadekoBot/project.json @@ -18,7 +18,7 @@ }, "dependencies": { "AngleSharp": "0.9.9", - "libvideo": "1.0.0", + "libvideo": "1.0.1", "CoreCLR-NCalc": "2.1.2", "Google.Apis.Urlshortener.v1": "1.19.0.138", "Google.Apis.YouTube.v3": "1.20.0.701", From d2484fa42b481ab788a7fcf1d22b34f1f1f5b478 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 15 Feb 2017 12:17:06 +0100 Subject: [PATCH 267/746] 1.1.8-alpha --- 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 7c6d2201..40823b1b 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.6"; + public const string BotVersion = "1.1.8-alpha"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From b5db72fa1a131f06cd8ae603933785b7421b6989 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Wed, 15 Feb 2017 06:18:58 -0500 Subject: [PATCH 268/746] matches latest dev --- src/NadekoBot/Resources/CommandStrings.resx | 28 +++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 208ab0cc..951a745c 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3114,4 +3114,32 @@ `{0}timezone` + + langsetdefault langsetd + + + Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. + + + `{0}langsetd en-US` or `{0}langsetd default` + + + languageset langset + + + Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. + + + `{0}langset de-DE ` or `{0}langset default` + + + languageslist langli + + + List of languages for which translation (or part of it) exist atm. + + + `{0}langli` + + From 0ae08ec556d04b5c9229ee745babe0dbd5ad5d44 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Wed, 15 Feb 2017 06:20:19 -0500 Subject: [PATCH 269/746] Update --- src/NadekoBot/Resources/CommandStrings.resx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 951a745c..27d7b10b 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3142,4 +3142,3 @@ `{0}langli` - From a5f0cf8abfdd8b8d13b2908b0ab7dbfe1154983e Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 15 Feb 2017 12:24:12 +0100 Subject: [PATCH 270/746] ~yoda usage fix --- src/NadekoBot/Resources/CommandStrings.Designer.cs | 2 +- src/NadekoBot/Resources/CommandStrings.resx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 487e5ec8..a95f8db1 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -9042,7 +9042,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to {0}yodify I was once an adventurer like you` or `{0}yoda my feelings hurt`. + /// Looks up a localized string similar to `{0}yoda my feelings hurt`. /// public static string yodify_usage { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 4ba617cd..664b0713 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2689,7 +2689,7 @@ Translates your normal sentences into Yoda styled sentences! - {0}yodify I was once an adventurer like you` or `{0}yoda my feelings hurt` + `{0}yoda my feelings hurt` attack From 641f26242c62aa699d1fa646c726ae54ebbbbc83 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Wed, 15 Feb 2017 06:24:23 -0500 Subject: [PATCH 271/746] revert --- src/NadekoBot/Resources/CommandStrings.resx | 27 --------------------- 1 file changed, 27 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 27d7b10b..208ab0cc 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3114,31 +3114,4 @@ `{0}timezone` - - langsetdefault langsetd - - - Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. - - - `{0}langsetd en-US` or `{0}langsetd default` - - - languageset langset - - - Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. - - - `{0}langset de-DE ` or `{0}langset default` - - - languageslist langli - - - List of languages for which translation (or part of it) exist atm. - - - `{0}langli` - From 317edc2d9475f1875377840d1c7835b33cb6b53a Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Wed, 15 Feb 2017 06:56:53 -0500 Subject: [PATCH 272/746] Revert "revert" This reverts commit 641f26242c62aa699d1fa646c726ae54ebbbbc83. --- src/NadekoBot/Resources/CommandStrings.resx | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 208ab0cc..27d7b10b 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3114,4 +3114,31 @@ `{0}timezone` + + langsetdefault langsetd + + + Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. + + + `{0}langsetd en-US` or `{0}langsetd default` + + + languageset langset + + + Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. + + + `{0}langset de-DE ` or `{0}langset default` + + + languageslist langli + + + List of languages for which translation (or part of it) exist atm. + + + `{0}langli` + From 73ec3e43a1208d85e53403c462c165b828d981b2 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Wed, 15 Feb 2017 06:57:06 -0500 Subject: [PATCH 273/746] Revert "Update" This reverts commit 0ae08ec556d04b5c9229ee745babe0dbd5ad5d44. --- src/NadekoBot/Resources/CommandStrings.resx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 27d7b10b..951a745c 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3142,3 +3142,4 @@ `{0}langli` + From 56a8914423f25f24a58453a0eaa26c42d9778445 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Wed, 15 Feb 2017 06:57:10 -0500 Subject: [PATCH 274/746] Revert "matches latest dev" This reverts commit b5db72fa1a131f06cd8ae603933785b7421b6989. --- src/NadekoBot/Resources/CommandStrings.resx | 28 --------------------- 1 file changed, 28 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 951a745c..208ab0cc 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3114,32 +3114,4 @@ `{0}timezone` - - langsetdefault langsetd - - - Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. - - - `{0}langsetd en-US` or `{0}langsetd default` - - - languageset langset - - - Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. - - - `{0}langset de-DE ` or `{0}langset default` - - - languageslist langli - - - List of languages for which translation (or part of it) exist atm. - - - `{0}langli` - - From 2a3eaa316a1efc90b1d8c10577385907bcf7115d Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Wed, 15 Feb 2017 06:57:16 -0500 Subject: [PATCH 275/746] Revert "revert" This reverts commit 641f26242c62aa699d1fa646c726ae54ebbbbc83. --- src/NadekoBot/Resources/CommandStrings.resx | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 208ab0cc..27d7b10b 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3114,4 +3114,31 @@ `{0}timezone` + + langsetdefault langsetd + + + Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. + + + `{0}langsetd en-US` or `{0}langsetd default` + + + languageset langset + + + Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. + + + `{0}langset de-DE ` or `{0}langset default` + + + languageslist langli + + + List of languages for which translation (or part of it) exist atm. + + + `{0}langli` + From d704e77124a9539377a5b7b784c603bf6ddb5be3 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Wed, 15 Feb 2017 07:04:26 -0500 Subject: [PATCH 276/746] Update CommandStrings.resx --- src/NadekoBot/Resources/CommandStrings.resx | 27 --------------------- 1 file changed, 27 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 27d7b10b..208ab0cc 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3114,31 +3114,4 @@ `{0}timezone` - - langsetdefault langsetd - - - Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. - - - `{0}langsetd en-US` or `{0}langsetd default` - - - languageset langset - - - Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. - - - `{0}langset de-DE ` or `{0}langset default` - - - languageslist langli - - - List of languages for which translation (or part of it) exist atm. - - - `{0}langli` - From 77f0a3b4ee17caa276b4723f73fdc5c71181f5a6 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Wed, 15 Feb 2017 07:16:23 -0500 Subject: [PATCH 277/746] Update CommandStrings.resx --- src/NadekoBot/Resources/CommandStrings.resx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 6b03349f..69aa41c4 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3114,9 +3114,6 @@ `{0}timezone` -<<<<<<< HEAD - -======= langsetdefault langsetd @@ -3145,4 +3142,3 @@ `{0}langli` ->>>>>>> Kwoth/dev From 615502fc073f1ce3937e7f5eb4db1228bd08f0f3 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 15 Feb 2017 15:08:00 +0100 Subject: [PATCH 278/746] fixed 5 administration response strings --- src/NadekoBot/Resources/ResponseStrings.resx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index c4228d5c..2f82096e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -851,23 +851,23 @@ Reason: {1} User {0} from voice chat - + You have been soft-banned from {0} server. Reason: {1} - + User Unbanned - + Migration done! Error while migrating, check bot's console for more information. - + Presence Updates - + User Soft-Banned From fa20d8cc954661e4c24ab4f7de742d25f67b1249 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 16 Feb 2017 10:57:15 +0100 Subject: [PATCH 279/746] fixed self_assign_success key, thanks chf --- .../Resources/ResponseStrings.Designer.cs | 96 +++++++++---------- src/NadekoBot/Resources/ResponseStrings.resx | 2 +- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 30c80001..78867fa4 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -728,6 +728,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Migration done!. + /// + public static string administration_migration_done { + get { + return ResourceManager.GetString("administration_migration_done", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} moved from {1} to {2}. /// @@ -899,6 +908,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Presence Updates. + /// + public static string administration_presence_updates { + get { + return ResourceManager.GetString("administration_presence_updates", resourceCulture); + } + } + /// /// Looks up a localized string similar to Active Protections. /// @@ -1152,6 +1170,25 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to User Soft-Banned. + /// + public static string administration_sb_user { + get { + return ResourceManager.GetString("administration_sb_user", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You have been soft-banned from {0} server. + ///Reason: {1}. + /// + public static string administration_sbdm { + get { + return ResourceManager.GetString("administration_sbdm", resourceCulture); + } + } + /// /// Looks up a localized string similar to You already have {0} role.. /// @@ -1245,9 +1282,9 @@ namespace NadekoBot.Resources { /// /// Looks up a localized string similar to You now have {0} role.. /// - public static string administration_self_assign_sucess { + public static string administration_self_assign_success { get { - return ResourceManager.GetString("administration_self_assign_sucess", resourceCulture); + return ResourceManager.GetString("administration_self_assign_success", resourceCulture); } } @@ -1522,6 +1559,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to User Unbanned. + /// + public static string administration_user_unbanned { + get { + return ResourceManager.GetString("administration_user_unbanned", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} has been **unmuted** from text and voice chat.. /// @@ -1693,34 +1739,6 @@ namespace NadekoBot.Resources { } } - /// - /// Looks up a localized string similar to You have been soft-banned from {0} server. - ///Reason: {1}. - /// - public static string administraton_sbdm { - get { - return ResourceManager.GetString("administraton_sbdm", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User Unbanned. - /// - public static string administraton_user_unbanned { - get { - return ResourceManager.GetString("administraton_user_unbanned", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Migration done!. - /// - public static string adminsitration_migration_done { - get { - return ResourceManager.GetString("adminsitration_migration_done", resourceCulture); - } - } - /// /// Looks up a localized string similar to Error while migrating, check bot's console for more information.. /// @@ -1730,24 +1748,6 @@ namespace NadekoBot.Resources { } } - /// - /// Looks up a localized string similar to Presence Updates. - /// - public static string adminsitration_presence_updates { - get { - return ResourceManager.GetString("adminsitration_presence_updates", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User Soft-Banned. - /// - public static string adminsitration_sb_user { - get { - return ResourceManager.GetString("adminsitration_sb_user", resourceCulture); - } - } - /// /// Looks up a localized string similar to That base is already claimed or destroyed.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 2f82096e..1afc5b8b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -698,7 +698,7 @@ Reason: {1} You no longer have {0} role. - + You now have {0} role. From d8a04ed78b8f98b19e0a0ebb28ddb35376d20478 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 16 Feb 2017 16:34:14 +0100 Subject: [PATCH 280/746] a few speedtyping fixes, some music experimentation --- .../Games/Commands/SpeedTypingCommands.cs | 20 ++++++++--------- .../Modules/Music/Classes/MusicControls.cs | 22 +++++++++---------- src/NadekoBot/NadekoBot.xproj.DotSettings | 3 ++- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs index 47724820..96866f0e 100644 --- a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs @@ -116,7 +116,7 @@ namespace NadekoBot.Modules.Games if (msg == null) return; - if (this.Channel == null || this.Channel.Id != this.Channel.Id) return; + if (this.Channel == null || this.Channel.Id != msg.Channel.Id) return; var guess = msg.Content; @@ -127,10 +127,10 @@ namespace NadekoBot.Modules.Games var wpm = CurrentSentence.Length / WORD_VALUE / sw.Elapsed.Seconds * 60; finishedUserIds.Add(msg.Author.Id); await this.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithTitle((string)$"{msg.Author} finished the race!") + .WithTitle($"{msg.Author} finished the race!") .AddField(efb => efb.WithName("Place").WithValue($"#{finishedUserIds.Count}").WithIsInline(true)) - .AddField(efb => efb.WithName("WPM").WithValue($"{wpm:F2} *[{sw.Elapsed.Seconds.ToString()}sec]*").WithIsInline(true)) - .AddField(efb => efb.WithName((string)"Errors").WithValue((string)distance.ToString()).WithIsInline((bool)true))) + .AddField(efb => efb.WithName("WPM").WithValue($"{wpm:F2} *[{sw.Elapsed.TotalSeconds:F2}sec]*").WithIsInline(true)) + .AddField(efb => efb.WithName("Errors").WithValue(distance.ToString()).WithIsInline(true))) .ConfigureAwait(false); if (finishedUserIds.Count % 4 == 0) { @@ -150,11 +150,11 @@ namespace NadekoBot.Modules.Games { public static List TypingArticles { get; } = new List(); - const string typingArticlesPath = "data/typing_articles.json"; + private const string _typingArticlesPath = "data/typing_articles.json"; static SpeedTypingCommands() { - try { TypingArticles = JsonConvert.DeserializeObject>(File.ReadAllText(typingArticlesPath)); } catch { } + try { TypingArticles = JsonConvert.DeserializeObject>(File.ReadAllText(_typingArticlesPath)); } catch { } } public static ConcurrentDictionary RunningContests = new ConcurrentDictionary(); @@ -207,7 +207,7 @@ namespace NadekoBot.Modules.Games Text = text.SanitizeMentions(), }); - File.WriteAllText(typingArticlesPath, JsonConvert.SerializeObject(TypingArticles)); + File.WriteAllText(_typingArticlesPath, JsonConvert.SerializeObject(TypingArticles)); await channel.SendConfirmAsync("Added new article for typing game.").ConfigureAwait(false); } @@ -221,7 +221,7 @@ namespace NadekoBot.Modules.Games if (page < 1) return; - var articles = TypingArticles.Skip((page - 1) * 15).Take(15); + var articles = TypingArticles.Skip((page - 1) * 15).Take(15).ToArray(); if (!articles.Any()) { @@ -229,7 +229,7 @@ namespace NadekoBot.Modules.Games return; } var i = (page - 1) * 15; - await channel.SendConfirmAsync("List of articles for Type Race", String.Join("\n", articles.Select(a => $"`#{++i}` - {a.Text.TrimTo(50)}"))) + await channel.SendConfirmAsync("List of articles for Type Race", string.Join("\n", articles.Select(a => $"`#{++i}` - {a.Text.TrimTo(50)}"))) .ConfigureAwait(false); } @@ -247,7 +247,7 @@ namespace NadekoBot.Modules.Games var removed = TypingArticles[index]; TypingArticles.RemoveAt(index); - File.WriteAllText(typingArticlesPath, JsonConvert.SerializeObject(TypingArticles)); + File.WriteAllText(_typingArticlesPath, JsonConvert.SerializeObject(TypingArticles)); await channel.SendConfirmAsync($"`Removed typing article:` #{index + 1} - {removed.Text.TrimTo(50)}") .ConfigureAwait(false); diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index e11b680e..a1b0d0a9 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -67,7 +67,7 @@ namespace NadekoBot.Modules.Music.Classes public float Volume { get; private set; } public event Action OnCompleted = delegate { }; - public event Action OnStarted = delegate { }; + public event Action OnStarted = delegate { }; public event Action OnPauseChanged = delegate { }; public IVoiceChannel PlaybackVoiceChannel { get; private set; } @@ -130,13 +130,9 @@ namespace NadekoBot.Modules.Music.Classes { try { - if (audioClient?.ConnectionState != ConnectionState.Connected) - { - if (audioClient != null) - try { await audioClient.DisconnectAsync().ConfigureAwait(false); } catch { } - audioClient = await PlaybackVoiceChannel.ConnectAsync().ConfigureAwait(false); - continue; - } + if (audioClient != null) + try { await audioClient.DisconnectAsync().ConfigureAwait(false); } catch { } + audioClient = await PlaybackVoiceChannel.ConnectAsync().ConfigureAwait(false); CurrentSong = GetNextSong(); @@ -313,11 +309,15 @@ namespace NadekoBot.Modules.Music.Classes { var curSong = CurrentSong; var toUpdate = playlist.Where(s => s.SongInfo.ProviderType == MusicType.Normal && - s.TotalTime == TimeSpan.Zero); + s.TotalTime == TimeSpan.Zero) + .ToArray(); if (curSong != null) - toUpdate = toUpdate.Append(curSong); + { + Array.Resize(ref toUpdate, toUpdate.Length + 1); + toUpdate[toUpdate.Length - 1] = curSong; + } var ids = toUpdate.Select(s => s.SongInfo.Query.Substring(s.SongInfo.Query.LastIndexOf("?v=") + 3)) - .Distinct(); + .Distinct(); var durations = await NadekoBot.Google.GetVideoDurationsAsync(ids); diff --git a/src/NadekoBot/NadekoBot.xproj.DotSettings b/src/NadekoBot/NadekoBot.xproj.DotSettings index 3a1cb1b5..65ccbd58 100644 --- a/src/NadekoBot/NadekoBot.xproj.DotSettings +++ b/src/NadekoBot/NadekoBot.xproj.DotSettings @@ -1,3 +1,4 @@  True - True \ No newline at end of file + True + True \ No newline at end of file From e648ff7d48120ddd3e325018b842c0b70c3df6b9 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 16 Feb 2017 16:37:15 +0100 Subject: [PATCH 281/746] I didn't save /facepalm --- src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs index 96866f0e..fc5a67a2 100644 --- a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs @@ -124,12 +124,13 @@ namespace NadekoBot.Modules.Games var decision = Judge(distance, guess.Length); if (decision && !finishedUserIds.Contains(msg.Author.Id)) { - var wpm = CurrentSentence.Length / WORD_VALUE / sw.Elapsed.Seconds * 60; + var elapsed = sw.Elapsed; + var wpm = CurrentSentence.Length / WORD_VALUE / elapsed.TotalSeconds * 60; finishedUserIds.Add(msg.Author.Id); await this.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithTitle($"{msg.Author} finished the race!") .AddField(efb => efb.WithName("Place").WithValue($"#{finishedUserIds.Count}").WithIsInline(true)) - .AddField(efb => efb.WithName("WPM").WithValue($"{wpm:F2} *[{sw.Elapsed.TotalSeconds:F2}sec]*").WithIsInline(true)) + .AddField(efb => efb.WithName("WPM").WithValue($"{wpm:F1} *[{elapsed.TotalSeconds:F2}sec]*").WithIsInline(true)) .AddField(efb => efb.WithName("Errors").WithValue(distance.ToString()).WithIsInline(true))) .ConfigureAwait(false); if (finishedUserIds.Count % 4 == 0) From 8eb2b980d1657c593f8408211b4c41ed2c0b9c1d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 16 Feb 2017 17:47:37 +0100 Subject: [PATCH 282/746] Fixed random disconnects and reconnects --- src/NadekoBot/Modules/Music/Classes/MusicControls.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index a1b0d0a9..fe7fe953 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -130,15 +130,15 @@ namespace NadekoBot.Modules.Music.Classes { try { - if (audioClient != null) - try { await audioClient.DisconnectAsync().ConfigureAwait(false); } catch { } - audioClient = await PlaybackVoiceChannel.ConnectAsync().ConfigureAwait(false); - CurrentSong = GetNextSong(); if (CurrentSong == null) continue; + if (audioClient != null) + try { await audioClient.DisconnectAsync().ConfigureAwait(false); } catch { } + audioClient = await PlaybackVoiceChannel.ConnectAsync().ConfigureAwait(false); + var index = playlist.IndexOf(CurrentSong); if (index != -1) RemoveSongAt(index, true); From 108a9fb1560da923d1b6e97c521618ca4cab23ad Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 16 Feb 2017 18:13:24 +0100 Subject: [PATCH 283/746] Fixes to music. Thanks to samvaio --- .../Modules/Music/Classes/MusicControls.cs | 85 +++++++++++-------- src/NadekoBot/Modules/Music/Music.cs | 11 +-- 2 files changed, 52 insertions(+), 44 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index fe7fe953..92ca19ae 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -7,6 +7,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using NLog; + namespace NadekoBot.Modules.Music.Classes { @@ -46,17 +48,19 @@ namespace NadekoBot.Modules.Music.Classes // this should be written better public TimeSpan TotalPlaytime => - playlist.Any(s => s.TotalTime == TimeSpan.MaxValue) ? + _playlist.Any(s => s.TotalTime == TimeSpan.MaxValue) ? TimeSpan.MaxValue : - new TimeSpan(playlist.Sum(s => s.TotalTime.Ticks)); + new TimeSpan(_playlist.Sum(s => s.TotalTime.Ticks)); /// /// Users who recently got their music wish /// private ConcurrentHashSet recentlyPlayedUsers { get; } = new ConcurrentHashSet(); - private readonly List playlist = new List(); - public IReadOnlyCollection Playlist => playlist; + private readonly List _playlist = new List(); + private readonly Logger _log; + + public IReadOnlyCollection Playlist => _playlist; public Song CurrentSong { get; private set; } public CancellationTokenSource SongCancelSource { get; private set; } @@ -73,7 +77,7 @@ namespace NadekoBot.Modules.Music.Classes public IVoiceChannel PlaybackVoiceChannel { get; private set; } public ITextChannel OutputTextChannel { get; set; } - private bool Destroyed { get; set; } = false; + private bool destroyed { get; set; } = false; public bool RepeatSong { get; private set; } = false; public bool RepeatPlaylist { get; private set; } = false; public bool Autoplay { get; set; } = false; @@ -90,6 +94,8 @@ namespace NadekoBot.Modules.Music.Classes if (startingVoiceChannel == null) throw new ArgumentNullException(nameof(startingVoiceChannel)); + _log = LogManager.GetCurrentClassLogger(); + OutputTextChannel = outputChannel; Volume = defaultVolume ?? 1.0f; @@ -101,7 +107,7 @@ namespace NadekoBot.Modules.Music.Classes { try { - while (!Destroyed) + while (!destroyed) { try { @@ -119,14 +125,14 @@ namespace NadekoBot.Modules.Music.Classes } catch (Exception ex) { - Console.WriteLine("Action queue crashed"); - Console.WriteLine(ex); + _log.Warn("Action queue crashed"); + _log.Warn(ex); } }).ConfigureAwait(false); - var t = new Thread(new ThreadStart(async () => + var t = new Thread(async () => { - while (!Destroyed) + while (!destroyed) { try { @@ -139,7 +145,7 @@ namespace NadekoBot.Modules.Music.Classes try { await audioClient.DisconnectAsync().ConfigureAwait(false); } catch { } audioClient = await PlaybackVoiceChannel.ConnectAsync().ConfigureAwait(false); - var index = playlist.IndexOf(CurrentSong); + var index = _playlist.IndexOf(CurrentSong); if (index != -1) RemoveSongAt(index, true); @@ -148,11 +154,14 @@ namespace NadekoBot.Modules.Music.Classes { await CurrentSong.Play(audioClient, cancelToken); } - catch(OperationCanceledException) + catch (OperationCanceledException) + { + } + finally { OnCompleted(this, CurrentSong); } - + if (RepeatPlaylist) AddSong(CurrentSong, CurrentSong.QueuerName); @@ -163,8 +172,8 @@ namespace NadekoBot.Modules.Music.Classes } catch (Exception ex) { - Console.WriteLine("Music thread almost crashed."); - Console.WriteLine(ex); + _log.Warn("Music thread almost crashed."); + _log.Warn(ex); await Task.Delay(3000).ConfigureAwait(false); } finally @@ -179,7 +188,7 @@ namespace NadekoBot.Modules.Music.Classes await Task.Delay(300).ConfigureAwait(false); } } - })); + }); t.Start(); } @@ -199,7 +208,8 @@ namespace NadekoBot.Modules.Music.Classes { RepeatPlaylist = false; RepeatSong = false; - playlist.Clear(); + Autoplay = false; + _playlist.Clear(); if (!SongCancelSource.IsCancellationRequested) SongCancelSource.Cancel(); }); @@ -222,10 +232,10 @@ namespace NadekoBot.Modules.Music.Classes { if (!FairPlay) { - return playlist.FirstOrDefault(); + return _playlist.FirstOrDefault(); } - var song = playlist.FirstOrDefault(c => !recentlyPlayedUsers.Contains(c.QueuerName)) - ?? playlist.FirstOrDefault(); + var song = _playlist.FirstOrDefault(c => !recentlyPlayedUsers.Contains(c.QueuerName)) + ?? _playlist.FirstOrDefault(); if (song == null) return null; @@ -243,9 +253,9 @@ namespace NadekoBot.Modules.Music.Classes { actionQueue.Enqueue(() => { - var oldPlaylist = playlist.ToArray(); - playlist.Clear(); - playlist.AddRange(oldPlaylist.Shuffle()); + var oldPlaylist = _playlist.ToArray(); + _playlist.Clear(); + _playlist.AddRange(oldPlaylist.Shuffle()); }); } @@ -258,7 +268,7 @@ namespace NadekoBot.Modules.Music.Classes { s.MusicPlayer = this; s.QueuerName = username.TrimTo(10); - playlist.Add(s); + _playlist.Add(s); }); } @@ -268,7 +278,7 @@ namespace NadekoBot.Modules.Music.Classes throw new ArgumentNullException(nameof(s)); actionQueue.Enqueue(() => { - playlist.Insert(index, s); + _playlist.Insert(index, s); }); } @@ -278,7 +288,7 @@ namespace NadekoBot.Modules.Music.Classes throw new ArgumentNullException(nameof(s)); actionQueue.Enqueue(() => { - playlist.Remove(s); + _playlist.Remove(s); }); } @@ -286,10 +296,10 @@ namespace NadekoBot.Modules.Music.Classes { actionQueue.Enqueue(() => { - if (index < 0 || index >= playlist.Count) + if (index < 0 || index >= _playlist.Count) return; - var song = playlist.ElementAtOrDefault(index); - if (playlist.Remove(song) && !silent) + var song = _playlist.ElementAtOrDefault(index); + if (_playlist.Remove(song) && !silent) { SongRemoved(song, index); } @@ -301,14 +311,14 @@ namespace NadekoBot.Modules.Music.Classes { actionQueue.Enqueue(() => { - playlist.Clear(); + _playlist.Clear(); }); } public async Task UpdateSongDurationsAsync() { var curSong = CurrentSong; - var toUpdate = playlist.Where(s => s.SongInfo.ProviderType == MusicType.Normal && + var toUpdate = _playlist.Where(s => s.SongInfo.ProviderType == MusicType.Normal && s.TotalTime == TimeSpan.Zero) .ToArray(); if (curSong != null) @@ -341,8 +351,9 @@ namespace NadekoBot.Modules.Music.Classes { RepeatPlaylist = false; RepeatSong = false; - Destroyed = true; - playlist.Clear(); + Autoplay = false; + destroyed = true; + _playlist.Clear(); try { await audioClient.DisconnectAsync(); } catch { } if (!SongCancelSource.IsCancellationRequested) @@ -358,17 +369,17 @@ namespace NadekoBot.Modules.Music.Classes // audioClient = await voiceChannel.ConnectAsync().ConfigureAwait(false); //} - public bool ToggleRepeatSong() => this.RepeatSong = !this.RepeatSong; + public bool ToggleRepeatSong() => RepeatSong = !RepeatSong; - public bool ToggleRepeatPlaylist() => this.RepeatPlaylist = !this.RepeatPlaylist; + public bool ToggleRepeatPlaylist() => RepeatPlaylist = !RepeatPlaylist; - public bool ToggleAutoplay() => this.Autoplay = !this.Autoplay; + public bool ToggleAutoplay() => Autoplay = !Autoplay; public void ThrowIfQueueFull() { if (MaxQueueSize == 0) return; - if (playlist.Count >= MaxQueueSize) + if (_playlist.Count >= MaxQueueSize) throw new PlaylistFullException(); } } diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index fa7012fd..15d8e82e 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -838,8 +838,7 @@ namespace NadekoBot.Modules.Music { try { - if (lastFinishedMessage != null) - lastFinishedMessage.DeleteAfter(0); + lastFinishedMessage?.DeleteAfter(0); lastFinishedMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithAuthor(eab => eab.WithName("Finished Song").WithMusicIcon()) @@ -855,7 +854,7 @@ namespace NadekoBot.Modules.Music textCh, voiceCh, relatedVideos[new NadekoRandom().Next(0, relatedVideos.Count)], - silent, + true, musicType).ConfigureAwait(false); } } @@ -870,8 +869,7 @@ namespace NadekoBot.Modules.Music return; try { - if (playingMessage != null) - playingMessage.DeleteAfter(0); + playingMessage?.DeleteAfter(0); playingMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithAuthor(eab => eab.WithName("Playing Song").WithMusicIcon()) @@ -891,8 +889,7 @@ namespace NadekoBot.Modules.Music else msg = await mp.OutputTextChannel.SendConfirmAsync("🎵 Music playback **resumed**.").ConfigureAwait(false); - if (msg != null) - msg.DeleteAfter(10); + msg?.DeleteAfter(10); } catch { } }; From ad2dd3a565f715337840943e2f7ceebc914af91c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 16 Feb 2017 19:44:39 +0100 Subject: [PATCH 284/746] reduced the delay on .ban, .softban, and .kick to 1 second, from 2 --- src/NadekoBot/Modules/Administration/Administration.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 20760373..ab618ac5 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -241,7 +241,7 @@ namespace NadekoBot.Modules.Administration try { await user.SendErrorAsync(GetText("bandm", Format.Bold(Context.Guild.Name), msg)); - await Task.Delay(2000).ConfigureAwait(false); + await Task.Delay(1000).ConfigureAwait(false); } catch @@ -276,7 +276,7 @@ namespace NadekoBot.Modules.Administration try { await user.SendErrorAsync(GetText("sbdm", Format.Bold(Context.Guild.Name), msg)); - await Task.Delay(2000).ConfigureAwait(false); + await Task.Delay(1000).ConfigureAwait(false); } catch { @@ -311,7 +311,7 @@ namespace NadekoBot.Modules.Administration try { await user.SendErrorAsync(GetText("kickdm", Format.Bold(Context.Guild.Name), msg)); - await Task.Delay(2000).ConfigureAwait(false); + await Task.Delay(1000).ConfigureAwait(false); } catch { } } From 7ce0702c786c2a8acf6d6a2ccb6d1916f13eb5a1 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 16 Feb 2017 19:48:51 +0100 Subject: [PATCH 285/746] banning, kicking and softbanning no longer have the delay at all. --- src/NadekoBot/Modules/Administration/Administration.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index ab618ac5..40d7776f 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -241,8 +241,6 @@ namespace NadekoBot.Modules.Administration try { await user.SendErrorAsync(GetText("bandm", Format.Bold(Context.Guild.Name), msg)); - await Task.Delay(1000).ConfigureAwait(false); - } catch { @@ -276,7 +274,6 @@ namespace NadekoBot.Modules.Administration try { await user.SendErrorAsync(GetText("sbdm", Format.Bold(Context.Guild.Name), msg)); - await Task.Delay(1000).ConfigureAwait(false); } catch { @@ -311,7 +308,6 @@ namespace NadekoBot.Modules.Administration try { await user.SendErrorAsync(GetText("kickdm", Format.Bold(Context.Guild.Name), msg)); - await Task.Delay(1000).ConfigureAwait(false); } catch { } } From b9673d5918839fdb1e9e2f2b064549e6c378bda9 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 16 Feb 2017 20:32:42 +0100 Subject: [PATCH 286/746] no idea what i did, locale won't be pink anymore though, thx aurora --- src/NadekoBot/Modules/Music/Music.cs | 17 ++++++++++++----- src/NadekoBot/Modules/NadekoModule.cs | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 15d8e82e..256a1c43 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -840,11 +840,18 @@ namespace NadekoBot.Modules.Music { lastFinishedMessage?.DeleteAfter(0); - lastFinishedMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithAuthor(eab => eab.WithName("Finished Song").WithMusicIcon()) - .WithDescription(song.PrettyName) - .WithFooter(ef => ef.WithText(song.PrettyInfo))) - .ConfigureAwait(false); + try + { + lastFinishedMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithAuthor(eab => eab.WithName("Finished Song").WithMusicIcon()) + .WithDescription(song.PrettyName) + .WithFooter(ef => ef.WithText(song.PrettyInfo))) + .ConfigureAwait(false); + } + catch + { + // ignored + } if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.ProviderType == MusicType.Normal) { diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index 4c8d17d3..d76a483c 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -32,7 +32,7 @@ namespace NadekoBot.Modules { _cultureInfo = NadekoBot.Localization.GetCultureInfo(Context.Guild?.Id); - _log.Warn("Culture info is {0}", _cultureInfo); + _log.Info("Culture info is {0}", _cultureInfo); } //public Task ReplyConfirmLocalized(string titleKey, string textKey, string url = null, string footer = null) From 9f9548b33ba2ce9920200a7bfd1a28873afe6e67 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 16 Feb 2017 21:49:30 +0100 Subject: [PATCH 287/746] stats should work properly now --- src/NadekoBot/Services/IStatsService.cs | 1 - src/NadekoBot/Services/Impl/StatsService.cs | 117 ++++++++++++-------- 2 files changed, 72 insertions(+), 46 deletions(-) diff --git a/src/NadekoBot/Services/IStatsService.cs b/src/NadekoBot/Services/IStatsService.cs index b1cb948f..5634790d 100644 --- a/src/NadekoBot/Services/IStatsService.cs +++ b/src/NadekoBot/Services/IStatsService.cs @@ -5,6 +5,5 @@ namespace NadekoBot.Services public interface IStatsService { Task Print(); - Task Reset(); } } diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index 40823b1b..f7f39985 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -3,6 +3,7 @@ using Discord.WebSocket; using NadekoBot.Extensions; using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Net.Http; using System.Threading; @@ -12,75 +13,108 @@ namespace NadekoBot.Services.Impl { public class StatsService : IStatsService { - private DiscordShardedClient client; - private DateTime started; + private readonly DiscordShardedClient _client; + private DateTime _started; public const string BotVersion = "1.1.8-alpha"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; - public int MessageCounter { get; private set; } = 0; - public int CommandsRan { get; private set; } = 0; public string Heap => - Math.Round((double)GC.GetTotalMemory(false) / 1.MiB(), 2).ToString(); + Math.Round((double)GC.GetTotalMemory(false) / 1.MiB(), 2).ToString(CultureInfo.InvariantCulture); public double MessagesPerSecond => MessageCounter / GetUptime().TotalSeconds; - private int _textChannels = 0; - public int TextChannels => _textChannels; - private int _voiceChannels = 0; - public int VoiceChannels => _voiceChannels; - Timer carbonitexTimer { get; } + private long _textChannels; + public long TextChannels => Interlocked.Read(ref _textChannels); + private long _voiceChannels; + public long VoiceChannels => Interlocked.Read(ref _voiceChannels); + private long _messageCounter; + public long MessageCounter => Interlocked.Read(ref _messageCounter); + private long _commandsRan; + public long CommandsRan => Interlocked.Read(ref _commandsRan); + + private Timer carbonitexTimer { get; } public StatsService(DiscordShardedClient client, CommandHandler cmdHandler) { - this.client = client; + _client = client; - Reset(); - this.client.MessageReceived += _ => Task.FromResult(MessageCounter++); - cmdHandler.CommandExecuted += (_, e) => Task.FromResult(CommandsRan++); + _started = DateTime.Now; + _client.MessageReceived += _ => Task.FromResult(Interlocked.Increment(ref _messageCounter)); + cmdHandler.CommandExecuted += (_, e) => Task.FromResult(Interlocked.Increment(ref _commandsRan)); - this.client.ChannelCreated += (c) => + _client.ChannelCreated += (c) => { if (c is ITextChannel) - ++_textChannels; + Interlocked.Increment(ref _textChannels); else if (c is IVoiceChannel) - ++_voiceChannels; + Interlocked.Increment(ref _voiceChannels); return Task.CompletedTask; }; - this.client.ChannelDestroyed += (c) => + _client.ChannelDestroyed += (c) => { if (c is ITextChannel) - --_textChannels; + Interlocked.Decrement(ref _textChannels); else if (c is IVoiceChannel) - --_voiceChannels; + Interlocked.Decrement(ref _voiceChannels); return Task.CompletedTask; }; - this.client.JoinedGuild += (g) => + _client.GuildAvailable += (g) => { - var tc = g.Channels.Where(cx => cx is ITextChannel).Count(); - var vc = g.Channels.Count - tc; - _textChannels += tc; - _voiceChannels += vc; - + var _ = Task.Run(() => + { + var tc = g.Channels.Count(cx => cx is ITextChannel); + var vc = g.Channels.Count - tc; + Interlocked.Add(ref _textChannels, tc); + Interlocked.Add(ref _voiceChannels, vc); + }); return Task.CompletedTask; }; - this.client.LeftGuild += (g) => + _client.JoinedGuild += (g) => { - var tc = g.Channels.Where(cx => cx is ITextChannel).Count(); - var vc = g.Channels.Count - tc; - _textChannels -= tc; - _voiceChannels -= vc; + var _ = Task.Run(() => + { + var tc = g.Channels.Count(cx => cx is ITextChannel); + var vc = g.Channels.Count - tc; + Interlocked.Add(ref _textChannels, tc); + Interlocked.Add(ref _voiceChannels, vc); + }); + return Task.CompletedTask; + }; + + _client.GuildUnavailable += (g) => + { + var _ = Task.Run(() => + { + var tc = g.Channels.Count(cx => cx is ITextChannel); + var vc = g.Channels.Count - tc; + Interlocked.Add(ref _textChannels, -tc); + Interlocked.Add(ref _voiceChannels, -vc); + }); return Task.CompletedTask; }; - this.carbonitexTimer = new Timer(async (state) => + _client.LeftGuild += (g) => + { + var _ = Task.Run(() => + { + var tc = g.Channels.Count(cx => cx is ITextChannel); + var vc = g.Channels.Count - tc; + Interlocked.Add(ref _textChannels, -tc); + Interlocked.Add(ref _voiceChannels, -vc); + }); + + return Task.CompletedTask; + }; + + carbonitexTimer = new Timer(async (state) => { if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.CarbonKey)) return; @@ -90,7 +124,7 @@ namespace NadekoBot.Services.Impl { using (var content = new FormUrlEncodedContent( new Dictionary { - { "servercount", this.client.GetGuildCount().ToString() }, + { "servercount", _client.GetGuildCount().ToString() }, { "key", NadekoBot.Credentials.CarbonKey }})) { content.Headers.Clear(); @@ -98,7 +132,7 @@ namespace NadekoBot.Services.Impl await http.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false); } - }; + } } catch { @@ -109,34 +143,27 @@ namespace NadekoBot.Services.Impl public void Initialize() { - var guilds = this.client.GetGuilds().ToArray(); + var guilds = _client.GetGuilds().ToArray(); _textChannels = guilds.Sum(g => g.Channels.Count(cx => cx is ITextChannel)); _voiceChannels = guilds.Sum(g => g.Channels.Count) - _textChannels; } public Task Print() { - var curUser = client.CurrentUser; + var curUser = _client.CurrentUser; return Task.FromResult($@" Author: [{Author}] | Library: [{Library}] Bot Version: [{BotVersion}] Bot ID: {curUser.Id} Owner ID(s): {string.Join(", ", NadekoBot.Credentials.OwnerIds)} Uptime: {GetUptimeString()} -Servers: {client.GetGuildCount()} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels} +Servers: {_client.GetGuildCount()} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels} Commands Ran this session: {CommandsRan} Messages: {MessageCounter} [{MessagesPerSecond:F2}/sec] Heap: [{Heap} MB]"); } - public Task Reset() - { - MessageCounter = 0; - started = DateTime.Now; - return Task.CompletedTask; - } - public TimeSpan GetUptime() => - DateTime.Now - started; + DateTime.Now - _started; public string GetUptimeString(string separator = ", ") { From d104d86df5fdf5135e64ce2f3016acebe059407c Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Thu, 16 Feb 2017 23:55:36 +0100 Subject: [PATCH 288/746] updated front page, thanks to rjt --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bb66aa4f..62289d80 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ ![img](https://ci.appveyor.com/api/projects/status/gmu6b3ltc80hr3k9?svg=true) [![Discord](https://discordapp.com/api/guilds/117523346618318850/widget.png)](https://discord.gg/nadekobot) [![Documentation Status](https://readthedocs.org/projects/nadekobot/badge/?version=latest)](http://nadekobot.readthedocs.io/en/latest/?badge=latest) -# NadekoBot -[![nadeko1](https://cdn.discordapp.com/attachments/155726317222887425/252095170676391936/A1.jpg)](https://discordapp.com/oauth2/authorize?client_id=170254782546575360&scope=bot&permissions=66186303) -[![nadeko2](https://cdn.discordapp.com/attachments/155726317222887425/252095207514832896/A2.jpg)](http://nadekobot.readthedocs.io/en/latest/Commands%20List/) +![nadeko0](https://cdn.discordapp.com/attachments/266240393639755778/281920716809699328/part1.png) +[![nadeko1](https://cdn.discordapp.com/attachments/266240393639755778/281920134967328768/part2.png)](https://discordapp.com/oauth2/authorize?client_id=170254782546575360&scope=bot&permissions=66186303) +[![nadeko2](https://cdn.discordapp.com/attachments/266240393639755778/281920161311883264/part3.png)](http://nadekobot.readthedocs.io/en/latest/Commands%20List/) ##For Update, Help and Guidlines `Follow me on twitter for updates. | Join my Discord server if you need help. | Read the Docs for hosting guides.` -[![twitter](https://cdn.discordapp.com/attachments/155726317222887425/252192520094613504/twiter_banner.JPG)](https://twitter.com/TheNadekoBot) [![discord](https://cdn.discordapp.com/attachments/155726317222887425/252192415673221122/discord_banner.JPG)](https://discord.gg/nadekobot) [![Wiki](https://cdn.discordapp.com/attachments/155726317222887425/252192472849973250/read_the_docs_banner.JPG)](http://nadekobot.readthedocs.io/en/latest/) +[![twitter](https://cdn.discordapp.com/attachments/155726317222887425/252192520094613504/twiter_banner.JPG)](https://twitter.com/TheNadekoBot) [![discord](https://cdn.discordapp.com/attachments/266240393639755778/281920766490968064/discord.png)](https://discord.gg/nadekobot) [![Wiki](https://cdn.discordapp.com/attachments/266240393639755778/281920793330581506/datcord.png)](http://nadekobot.readthedocs.io/en/latest/) From 28563c1f0bf5b787d3803f36eaf1e249d5da974b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 17 Feb 2017 11:38:06 +0100 Subject: [PATCH 289/746] fixed !!ms on local songs --- src/NadekoBot/Modules/Music/Classes/Song.cs | 4 ++-- src/NadekoBot/Modules/Music/Music.cs | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/Song.cs b/src/NadekoBot/Modules/Music/Classes/Song.cs index 04e49a70..31c92d10 100644 --- a/src/NadekoBot/Modules/Music/Classes/Song.cs +++ b/src/NadekoBot/Modules/Music/Classes/Song.cs @@ -47,7 +47,7 @@ namespace NadekoBot.Modules.Music.Classes public string PrettyFullTime => PrettyCurrentTime + " / " + PrettyTotalTime; - public string PrettyName => $"**[{SongInfo.Title.TrimTo(65)}]({songUrl})**"; + public string PrettyName => $"**[{SongInfo.Title.TrimTo(65)}]({SongUrl})**"; public string PrettyInfo => $"{MusicPlayer.PrettyVolume} | {PrettyTotalTime} | {PrettyProvider} | {QueuerName}"; @@ -104,7 +104,7 @@ namespace NadekoBot.Modules.Music.Classes } } - private string songUrl { + public string SongUrl { get { switch (SongInfo.ProviderType) { diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 256a1c43..231bcc65 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -512,12 +512,13 @@ namespace NadekoBot.Modules.Music [RequireContext(ContextType.Guild)] public async Task MoveSong([Remainder] string fromto) { + if (string.IsNullOrWhiteSpace(fromto)) + return; MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) - { return; - } + fromto = fromto?.Trim(); var fromtoArr = fromto.Split('>'); @@ -541,7 +542,7 @@ namespace NadekoBot.Modules.Music var embed = new EmbedBuilder() .WithTitle($"{s.SongInfo.Title.TrimTo(70)}") - .WithUrl($"{s.SongInfo.Query}") + .WithUrl(s.SongUrl) .WithAuthor(eab => eab.WithName("Song Moved").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) .AddField(fb => fb.WithName("**From Position**").WithValue($"#{n1}").WithIsInline(true)) .AddField(fb => fb.WithName("**To Position**").WithValue($"#{n2}").WithIsInline(true)) From cf686a20c3afec14dee48162c19f74476ac02121 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 17 Feb 2017 12:05:05 +0100 Subject: [PATCH 290/746] owner channel bugs fixed, you can now see files sent to the bot --- .../Administration/Commands/SelfCommands.cs | 29 +++++++++++--- src/NadekoBot/Services/CommandHandler.cs | 39 +++++++++++++------ 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index 0dfb3d0a..89d23094 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -72,23 +72,42 @@ namespace NadekoBot.Modules.Administration { if (_forwardDMs && ownerChannels.Any()) { - var title = - GetTextStatic("dm_from", NadekoBot.Localization.DefaultCultureInfo, - typeof(Administration).Name.ToLowerInvariant()) + $" [{msg.Author}]({msg.Author.Id})"; + var title = GetTextStatic("dm_from", + NadekoBot.Localization.DefaultCultureInfo, + typeof(Administration).Name.ToLowerInvariant()) + + $" [{msg.Author}]({msg.Author.Id})"; + + var attachamentsTxt = GetTextStatic("attachments", + NadekoBot.Localization.DefaultCultureInfo, + typeof(Administration).Name.ToLowerInvariant()); + + var toSend = msg.Content; + + if (msg.Attachments.Count > 0) + { + toSend += $"\n\n{Format.Code(attachamentsTxt)}:\n" + + string.Join("\n", msg.Attachments.Select(a => a.ProxyUrl)); + } + if (_forwardDMsToAllOwners) { await Task.WhenAll(ownerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id) - .Select(ch => ch.SendConfirmAsync(title, msg.Content))).ConfigureAwait(false); + .Select(ch => ch.SendConfirmAsync(title, toSend))).ConfigureAwait(false); } else { var firstOwnerChannel = ownerChannels.First(); if (firstOwnerChannel.Recipient.Id != msg.Author.Id) - try { await firstOwnerChannel.SendConfirmAsync(title, msg.Content).ConfigureAwait(false); } + { + try + { + await firstOwnerChannel.SendConfirmAsync(title, toSend).ConfigureAwait(false); + } catch { // ignored } + } } } } diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index a944a21e..2b827191 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -40,7 +40,7 @@ namespace NadekoBot.Services private readonly CommandService _commandService; private readonly Logger _log; - private List ownerChannels { get; set; } + private List ownerChannels { get; set; } = new List(); public event Func CommandExecuted = delegate { return Task.CompletedTask; }; @@ -61,21 +61,36 @@ namespace NadekoBot.Services UsersOnShortCooldown.Clear(); }, null, GlobalCommandsCooldown, GlobalCommandsCooldown); } - public async Task StartHandling() + public Task StartHandling() { - ownerChannels = (await Task.WhenAll(_client.GetGuilds().SelectMany(g => g.Users) - .Where(u => NadekoBot.Credentials.OwnerIds.Contains(u.Id)) - .Distinct(new IGuildUserComparer()) - .Select(async u => { try { return await u.CreateDMChannelAsync(); } catch { return null; } }))) - .Where(ch => ch != null) - .ToList(); + var _ = Task.Run(async () => + { + await Task.Delay(5000).ConfigureAwait(false); + ownerChannels = (await Task.WhenAll(_client.GetGuilds().SelectMany(g => g.Users) + .Where(u => NadekoBot.Credentials.OwnerIds.Contains(u.Id)) + .Distinct(new IGuildUserComparer()) + .Select(async u => + { + try + { + return await u.CreateDMChannelAsync(); + } + catch + { + return null; + } + }))) + .Where(ch => ch != null) + .ToList(); - if (!ownerChannels.Any()) - _log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file."); - else - _log.Info($"Created {ownerChannels.Count} out of {NadekoBot.Credentials.OwnerIds.Count} owner message channels."); + if (!ownerChannels.Any()) + _log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file."); + else + _log.Info($"Created {ownerChannels.Count} out of {NadekoBot.Credentials.OwnerIds.Count} owner message channels."); + }); _client.MessageReceived += MessageReceivedHandler; + return Task.CompletedTask; } private async Task TryRunCleverbot(SocketUserMessage usrMsg, IGuild guild) From b588da43e59e2aa043877c3f5fb039eacdb30892 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 17 Feb 2017 13:11:24 +0100 Subject: [PATCH 291/746] !!ap bug fixed --- .../Modules/Music/Classes/SongHandler.cs | 13 +++++--- src/NadekoBot/Modules/Music/Music.cs | 33 ++++++++++++------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/SongHandler.cs b/src/NadekoBot/Modules/Music/Classes/SongHandler.cs index f296d2cb..e374279f 100644 --- a/src/NadekoBot/Modules/Music/Classes/SongHandler.cs +++ b/src/NadekoBot/Modules/Music/Classes/SongHandler.cs @@ -6,12 +6,14 @@ using System.Net.Http; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using NLog; using VideoLibrary; namespace NadekoBot.Modules.Music.Classes { public static class SongHandler { + private static readonly Logger _log = LogManager.GetCurrentClassLogger(); public static async Task ResolveSong(string query, MusicType musicType = MusicType.Normal) { if (string.IsNullOrWhiteSpace(query)) @@ -106,7 +108,8 @@ namespace NadekoBot.Modules.Music.Classes } catch (Exception ex) { - Console.WriteLine($"Failed resolving the link.{ex.Message}"); + _log.Warn($"Failed resolving the link.{ex.Message}"); + _log.Warn(ex); return null; } } @@ -137,7 +140,7 @@ namespace NadekoBot.Modules.Music.Classes } catch { - Console.WriteLine($"Failed reading .pls:\n{file}"); + _log.Warn($"Failed reading .pls:\n{file}"); return null; } } @@ -156,7 +159,7 @@ namespace NadekoBot.Modules.Music.Classes } catch { - Console.WriteLine($"Failed reading .m3u:\n{file}"); + _log.Warn($"Failed reading .m3u:\n{file}"); return null; } @@ -172,7 +175,7 @@ namespace NadekoBot.Modules.Music.Classes } catch { - Console.WriteLine($"Failed reading .asx:\n{file}"); + _log.Warn($"Failed reading .asx:\n{file}"); return null; } } @@ -192,7 +195,7 @@ namespace NadekoBot.Modules.Music.Classes } catch { - Console.WriteLine($"Failed reading .xspf:\n{file}"); + _log.Warn($"Failed reading .xspf:\n{file}"); return null; } } diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 231bcc65..4fbc8701 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -14,7 +14,6 @@ using System.Net.Http; using Newtonsoft.Json.Linq; using System.Collections.Generic; using NadekoBot.Services.Database.Models; -using System.Text.RegularExpressions; using System.Threading; namespace NadekoBot.Modules.Music @@ -78,7 +77,10 @@ namespace NadekoBot.Modules.Music } } - catch { } + catch + { + // ignored + } return Task.CompletedTask; } @@ -215,9 +217,8 @@ namespace NadekoBot.Modules.Music .Skip(startAt) .Take(itemsPerPage) .Select(v => $"`{++number}.` {v.PrettyFullName}")); - - if (currentSong != null) - desc = $"`🔊` {currentSong.PrettyFullName}\n\n" + desc; + + desc = $"`🔊` {currentSong.PrettyFullName}\n\n" + desc; if (musicPlayer.RepeatSong) desc = "🔂 Repeating Current Song\n\n" + desc; @@ -862,8 +863,7 @@ namespace NadekoBot.Modules.Music textCh, voiceCh, relatedVideos[new NadekoRandom().Next(0, relatedVideos.Count)], - true, - musicType).ConfigureAwait(false); + true).ConfigureAwait(false); } } catch { } @@ -871,7 +871,11 @@ namespace NadekoBot.Modules.Music mp.OnStarted += async (player, song) => { - try { await mp.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { } + try { await mp.UpdateSongDurationsAsync().ConfigureAwait(false); } + catch + { + // ignored + } var sender = player as MusicPlayer; if (sender == null) return; @@ -915,7 +919,10 @@ namespace NadekoBot.Modules.Music await mp.OutputTextChannel.EmbedAsync(embed).ConfigureAwait(false); } - catch { } + catch + { + // ignored + } }; return mp; }); @@ -946,10 +953,12 @@ namespace NadekoBot.Modules.Music .WithThumbnailUrl(resolvedSong.Thumbnail) .WithFooter(ef => ef.WithText(resolvedSong.PrettyProvider))) .ConfigureAwait(false); - if (queuedMessage != null) - queuedMessage.DeleteAfter(10); + queuedMessage?.DeleteAfter(10); } - catch { } // if queued message sending fails, don't attempt to delete it + catch + { + // ignored + } // if queued message sending fails, don't attempt to delete it } } } From 40989604e94e5f56e091f3cc42ad40916716f710 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 17 Feb 2017 13:57:01 +0100 Subject: [PATCH 292/746] fixed current time on repeating songs --- src/NadekoBot/Modules/Music/Classes/Song.cs | 95 +++++++++------------ 1 file changed, 42 insertions(+), 53 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/Song.cs b/src/NadekoBot/Modules/Music/Classes/Song.cs index 31c92d10..8a69ec6f 100644 --- a/src/NadekoBot/Modules/Music/Classes/Song.cs +++ b/src/NadekoBot/Modules/Music/Classes/Song.cs @@ -5,12 +5,9 @@ using System; using System.Diagnostics; using System.Diagnostics.Contracts; using System.IO; -using System.Linq; -using System.Net.Http; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -using VideoLibrary; using System.Net; namespace NadekoBot.Modules.Music.Classes @@ -32,13 +29,13 @@ namespace NadekoBot.Modules.Music.Classes public string QueuerName { get; set; } public TimeSpan TotalTime { get; set; } = TimeSpan.Zero; - public TimeSpan CurrentTime => TimeSpan.FromSeconds(bytesSent / frameBytes / (1000 / milliseconds)); + public TimeSpan CurrentTime => TimeSpan.FromSeconds(bytesSent / (float)_frameBytes / (1000 / (float)_milliseconds)); - const int milliseconds = 20; - const int samplesPerFrame = (48000 / 1000) * milliseconds; - const int frameBytes = 3840; //16-bit, 2 channels + private const int _milliseconds = 20; + private const int _samplesPerFrame = (48000 / 1000) * _milliseconds; + private const int _frameBytes = 3840; //16-bit, 2 channels - private ulong bytesSent { get; set; } = 0; + private ulong bytesSent { get; set; } //pwetty @@ -65,22 +62,19 @@ namespace NadekoBot.Modules.Music.Classes } } - private string PrettyTotalTime { - get { + public string PrettyTotalTime { + get + { if (TotalTime == TimeSpan.Zero) return "(?)"; - else if (TotalTime == TimeSpan.MaxValue) + if (TotalTime == TimeSpan.MaxValue) return "∞"; - else - { - var time = TotalTime.ToString(@"mm\:ss"); - var hrs = (int)TotalTime.TotalHours; + var time = TotalTime.ToString(@"mm\:ss"); + var hrs = (int)TotalTime.TotalHours; - if (hrs > 0) - return hrs + ":" + time; - else - return time; - } + if (hrs > 0) + return hrs + ":" + time; + return time; } } @@ -89,13 +83,13 @@ namespace NadekoBot.Modules.Music.Classes switch (SongInfo.ProviderType) { case MusicType.Radio: - return $"https://cdn.discordapp.com/attachments/155726317222887425/261850925063340032/1482522097_radio.png"; //test links + return "https://cdn.discordapp.com/attachments/155726317222887425/261850925063340032/1482522097_radio.png"; //test links case MusicType.Normal: //todo have videoid in songinfo from the start var videoId = Regex.Match(SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+"); return $"https://img.youtube.com/vi/{ videoId }/0.jpg"; case MusicType.Local: - return $"https://cdn.discordapp.com/attachments/155726317222887425/261850914783100928/1482522077_music.png"; //test links + return "https://cdn.discordapp.com/attachments/155726317222887425/261850914783100928/1482522077_music.png"; //test links case MusicType.Soundcloud: return SongInfo.AlbumArt; default: @@ -122,36 +116,32 @@ namespace NadekoBot.Modules.Music.Classes } } - private int skipTo = 0; - public int SkipTo { - get { return skipTo; } - set { - skipTo = value; - bytesSent = (ulong)skipTo * 3840 * 50; - } - } + public int SkipTo { get; set; } private readonly Logger _log; public Song(SongInfo songInfo) { - this.SongInfo = songInfo; - this._log = LogManager.GetCurrentClassLogger(); + SongInfo = songInfo; + _log = LogManager.GetCurrentClassLogger(); } public Song Clone() { - var s = new Song(SongInfo); - s.MusicPlayer = MusicPlayer; - s.QueuerName = QueuerName; + var s = new Song(SongInfo) + { + MusicPlayer = MusicPlayer, + QueuerName = QueuerName + }; return s; } public async Task Play(IAudioClient voiceClient, CancellationToken cancelToken) { + bytesSent = (ulong) SkipTo * 3840 * 50; var filename = Path.Combine(Music.MusicDataPath, DateTime.Now.UnixTimestamp().ToString()); - SongBuffer inStream = new SongBuffer(MusicPlayer, filename, SongInfo, skipTo, frameBytes * 100); + var inStream = new SongBuffer(MusicPlayer, filename, SongInfo, SkipTo, _frameBytes * 100); var bufferTask = inStream.BufferSong(cancelToken).ConfigureAwait(false); try @@ -200,22 +190,22 @@ namespace NadekoBot.Modules.Music.Classes var outStream = voiceClient.CreatePCMStream(960); - int nextTime = Environment.TickCount + milliseconds; + int nextTime = Environment.TickCount + _milliseconds; - byte[] buffer = new byte[frameBytes]; + byte[] buffer = new byte[_frameBytes]; while (!cancelToken.IsCancellationRequested && //song canceled for whatever reason !(MusicPlayer.MaxPlaytimeSeconds != 0 && CurrentTime.TotalSeconds >= MusicPlayer.MaxPlaytimeSeconds)) // or exceedded max playtime { //Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------"); var read = await inStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); //await inStream.CopyToAsync(voiceClient.OutputStream); - if (read < frameBytes) + if (read < _frameBytes) _log.Debug("read {0}", read); unchecked { bytesSent += (ulong)read; } - if (read < frameBytes) + if (read < _frameBytes) { if (read == 0) { @@ -231,12 +221,12 @@ namespace NadekoBot.Modules.Music.Classes _log.Warn("Slow connection has disrupted music, waiting a bit for buffer"); await Task.Delay(1000, cancelToken).ConfigureAwait(false); - nextTime = Environment.TickCount + milliseconds; + nextTime = Environment.TickCount + _milliseconds; } else { await Task.Delay(100, cancelToken).ConfigureAwait(false); - nextTime = Environment.TickCount + milliseconds; + nextTime = Environment.TickCount + _milliseconds; } } else @@ -245,16 +235,16 @@ namespace NadekoBot.Modules.Music.Classes else attempt = 0; - while (this.MusicPlayer.Paused) + while (MusicPlayer.Paused) { await Task.Delay(200, cancelToken).ConfigureAwait(false); - nextTime = Environment.TickCount + milliseconds; + nextTime = Environment.TickCount + _milliseconds; } buffer = AdjustVolume(buffer, MusicPlayer.Volume); - if (read != frameBytes) continue; - nextTime = unchecked(nextTime + milliseconds); + if (read != _frameBytes) continue; + nextTime = unchecked(nextTime + _milliseconds); int delayMillis = unchecked(nextTime - Environment.TickCount); if (delayMillis > 0) await Task.Delay(delayMillis, cancelToken).ConfigureAwait(false); @@ -264,8 +254,7 @@ namespace NadekoBot.Modules.Music.Classes finally { await bufferTask; - if (inStream != null) - inStream.Dispose(); + inStream.Dispose(); } } @@ -279,7 +268,7 @@ namespace NadekoBot.Modules.Music.Classes } //aidiakapi ftw - public unsafe static byte[] AdjustVolume(byte[] audioSamples, float volume) + public static unsafe byte[] AdjustVolume(byte[] audioSamples, float volume) { Contract.Requires(audioSamples != null); Contract.Requires(audioSamples.Length % 2 == 0); @@ -289,15 +278,15 @@ namespace NadekoBot.Modules.Music.Classes if (Math.Abs(volume - 1f) < 0.0001f) return audioSamples; // 16-bit precision for the multiplication - int volumeFixed = (int)Math.Round(volume * 65536d); + var volumeFixed = (int)Math.Round(volume * 65536d); - int count = audioSamples.Length / 2; + var count = audioSamples.Length / 2; fixed (byte* srcBytes = audioSamples) { - short* src = (short*)srcBytes; + var src = (short*)srcBytes; - for (int i = count; i != 0; i--, src++) + for (var i = count; i != 0; i--, src++) *src = (short)(((*src) * volumeFixed) >> 16); } From 33bc565571c8f4521a329e9f4228c4c6b274d9f1 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 17 Feb 2017 14:26:32 +0100 Subject: [PATCH 293/746] fixed rare randomcat bug --- src/NadekoBot/Modules/Searches/Searches.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index b250e57f..75d82871 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -94,7 +94,7 @@ namespace NadekoBot.Modules.Searches using (var http = new HttpClient()) { var res = JObject.Parse(await http.GetStringAsync("http://www.random.cat/meow").ConfigureAwait(false)); - await Context.Channel.SendMessageAsync(res["file"].ToString()).ConfigureAwait(false); + await Context.Channel.SendMessageAsync(Uri.EscapeUriString(res["file"].ToString())).ConfigureAwait(false); } } From 9f69532d7b72f7132a7d99b0e83caf07dd16fb9f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 17 Feb 2017 14:43:32 +0100 Subject: [PATCH 294/746] ~g fix --- src/NadekoBot/Modules/Music/Classes/MusicControls.cs | 8 ++++---- src/NadekoBot/Modules/Searches/Searches.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index 92ca19ae..bf07a508 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -77,10 +77,10 @@ namespace NadekoBot.Modules.Music.Classes public IVoiceChannel PlaybackVoiceChannel { get; private set; } public ITextChannel OutputTextChannel { get; set; } - private bool destroyed { get; set; } = false; - public bool RepeatSong { get; private set; } = false; - public bool RepeatPlaylist { get; private set; } = false; - public bool Autoplay { get; set; } = false; + private bool destroyed { get; set; } + public bool RepeatSong { get; private set; } + public bool RepeatPlaylist { get; private set; } + public bool Autoplay { get; set; } public uint MaxQueueSize { get; set; } = 0; private ConcurrentQueue actionQueue { get; } = new ConcurrentQueue(); diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 75d82871..670980ea 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -273,7 +273,7 @@ namespace NadekoBot.Modules.Searches var results = elems.Select(elem => { - var aTag = (elem.Children.FirstOrDefault().Children.FirstOrDefault() as IHtmlAnchorElement); //

-> + var aTag = (elem.Children.FirstOrDefault()?.Children.FirstOrDefault() as IHtmlAnchorElement); //

-> var href = aTag?.Href; var name = aTag?.TextContent; if (href == null || name == null) @@ -292,7 +292,7 @@ namespace NadekoBot.Modules.Searches .WithAuthor(eab => eab.WithName("Search For: " + terms.TrimTo(50)) .WithUrl(fullQueryLink) .WithIconUrl("http://i.imgur.com/G46fm8J.png")) - .WithTitle(Context.User.Mention) + .WithTitle(Context.User.ToString()) .WithFooter(efb => efb.WithText(totalResults)); var desc = await Task.WhenAll(results.Select(async res => From eeb9ff93703a03b261a63eb144c260b7462ead65 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 17 Feb 2017 14:53:13 +0100 Subject: [PATCH 295/746] $$$ is smarter, $startevent flowerreaction X - x is number of flowers to award --- .../Modules/Gambling/Commands/CurrencyEvents.cs | 17 ++++++++++------- src/NadekoBot/Modules/Gambling/Gambling.cs | 6 ++++-- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs index 814fb747..d3f04c53 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -43,7 +43,7 @@ namespace NadekoBot.Modules.Gambling switch (e) { case CurrencyEvent.FlowerReaction: - await FlowerReactionEvent(Context).ConfigureAwait(false); + await FlowerReactionEvent(Context, arg).ConfigureAwait(false); break; case CurrencyEvent.SneakyGameStatus: await SneakyGameStatusEvent(Context, arg).ConfigureAwait(false); @@ -115,23 +115,26 @@ namespace NadekoBot.Modules.Gambling return Task.Delay(0); } - public async Task FlowerReactionEvent(CommandContext context) + public async Task FlowerReactionEvent(CommandContext context, int amount) { + if (amount <= 0) + amount = 100; + var title = GetText("flowerreaction_title"); - var desc = GetText("flowerreaction_desc", "🌸", Format.Bold(100.ToString()) + CurrencySign); + var desc = GetText("flowerreaction_desc", "🌸", Format.Bold(amount.ToString()) + CurrencySign); var footer = GetText("flowerreaction_footer", 24); var msg = await context.Channel.SendConfirmAsync(title, desc, footer: footer) .ConfigureAwait(false); - await new FlowerReactionEvent().Start(msg, context); + await new FlowerReactionEvent().Start(msg, context, amount); } } } public abstract class CurrencyEvent { - public abstract Task Start(IUserMessage msg, CommandContext channel); + public abstract Task Start(IUserMessage msg, CommandContext channel, int amount); } public class FlowerReactionEvent : CurrencyEvent @@ -172,7 +175,7 @@ namespace NadekoBot.Modules.Gambling return Task.CompletedTask; } - public override async Task Start(IUserMessage umsg, CommandContext context) + public override async Task Start(IUserMessage umsg, CommandContext context, int amount) { msg = umsg; NadekoBot.Client.MessageDeleted += MessageDeletedEventHandler; @@ -193,7 +196,7 @@ namespace NadekoBot.Modules.Gambling { if (r.Emoji.Name == "🌸" && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _flowerReactionAwardedUsers.Add(r.User.Value.Id)) { - await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, false) + await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", amount, false) .ConfigureAwait(false); } } diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 6650bee5..acceab4e 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -49,8 +49,10 @@ namespace NadekoBot.Modules.Gambling [Priority(0)] public async Task Cash([Remainder] IUser user = null) { - user = user ?? Context.User; - await ReplyConfirmLocalized("has", Format.Bold(user.ToString()), $"{GetCurrency(user.Id)} {CurrencySign}").ConfigureAwait(false); + if(user == null) + await ConfirmLocalized("has", Format.Bold(Context.User.ToString()), $"{GetCurrency(Context.User.Id)} {CurrencySign}").ConfigureAwait(false); + else + await ReplyConfirmLocalized("has", Format.Bold(user.ToString()), $"{GetCurrency(user.Id)} {CurrencySign}").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] From d5987f33317598db77304803d6c58d2b2f1bb3b0 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 17 Feb 2017 15:06:44 +0100 Subject: [PATCH 296/746] ../... now support embeds too --- .../Modules/Utility/Commands/QuoteCommands.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index 8add0707..193acf42 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -8,13 +8,14 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using NadekoBot.DataStructures; namespace NadekoBot.Modules.Utility { public partial class Utility { [Group] - public class QuoteCommands : ModuleBase + public class QuoteCommands : NadekoSubmodule { [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] @@ -56,6 +57,17 @@ namespace NadekoBot.Modules.Utility if (quote == null) return; + CREmbed crembed; + if (CREmbed.TryParse(quote.Text, out crembed)) + { + try { await Context.Channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "").ConfigureAwait(false); } + catch (Exception ex) + { + _log.Warn("Sending CREmbed failed"); + _log.Warn(ex); + } + return; + } await Context.Channel.SendMessageAsync("📣 " + quote.Text.SanitizeMentions()); } From ffdfd0e84e05f77a5a9cabac2ef5fac91896ec15 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 17 Feb 2017 15:20:28 +0100 Subject: [PATCH 297/746] word and invite filtering work on edited messages too, now --- src/NadekoBot/Services/CommandHandler.cs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 2b827191..c563586c 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -90,6 +90,27 @@ namespace NadekoBot.Services }); _client.MessageReceived += MessageReceivedHandler; + _client.MessageUpdated += (oldmsg, newMsg) => + { + var ignore = Task.Run(async () => + { + try + { + var usrMsg = newMsg as SocketUserMessage; + var guild = (usrMsg?.Channel as ITextChannel)?.Guild; + + if (guild != null && !await InviteFiltered(guild, usrMsg).ConfigureAwait(false)) + await WordFiltered(guild, usrMsg).ConfigureAwait(false); + + } + catch (Exception ex) + { + _log.Warn(ex); + } + return Task.CompletedTask; + }); + return Task.CompletedTask; + }; return Task.CompletedTask; } From 407df07b52281fc5585a463af41375307e5a23be Mon Sep 17 00:00:00 2001 From: samvaio Date: Fri, 17 Feb 2017 21:38:34 +0530 Subject: [PATCH 298/746] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 62289d80..955a8e80 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ![img](https://ci.appveyor.com/api/projects/status/gmu6b3ltc80hr3k9?svg=true) [![Discord](https://discordapp.com/api/guilds/117523346618318850/widget.png)](https://discord.gg/nadekobot) [![Documentation Status](https://readthedocs.org/projects/nadekobot/badge/?version=latest)](http://nadekobot.readthedocs.io/en/latest/?badge=latest) -![nadeko0](https://cdn.discordapp.com/attachments/266240393639755778/281920716809699328/part1.png) +[![nadeko0](https://cdn.discordapp.com/attachments/266240393639755778/281920716809699328/part1.png)](http://nadekobot.xyz) [![nadeko1](https://cdn.discordapp.com/attachments/266240393639755778/281920134967328768/part2.png)](https://discordapp.com/oauth2/authorize?client_id=170254782546575360&scope=bot&permissions=66186303) [![nadeko2](https://cdn.discordapp.com/attachments/266240393639755778/281920161311883264/part3.png)](http://nadekobot.readthedocs.io/en/latest/Commands%20List/) From 9ca376c4fd52f6f35b4be40732b8defdeadfa439 Mon Sep 17 00:00:00 2001 From: Manuel de la Fuente Date: Fri, 17 Feb 2017 14:58:40 -0600 Subject: [PATCH 299/746] Fixed a typo and put the bottom links in a table to look better --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 955a8e80..1a4b64db 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,8 @@ [![nadeko1](https://cdn.discordapp.com/attachments/266240393639755778/281920134967328768/part2.png)](https://discordapp.com/oauth2/authorize?client_id=170254782546575360&scope=bot&permissions=66186303) [![nadeko2](https://cdn.discordapp.com/attachments/266240393639755778/281920161311883264/part3.png)](http://nadekobot.readthedocs.io/en/latest/Commands%20List/) -##For Update, Help and Guidlines - -`Follow me on twitter for updates. | Join my Discord server if you need help. | Read the Docs for hosting guides.` - -[![twitter](https://cdn.discordapp.com/attachments/155726317222887425/252192520094613504/twiter_banner.JPG)](https://twitter.com/TheNadekoBot) [![discord](https://cdn.discordapp.com/attachments/266240393639755778/281920766490968064/discord.png)](https://discord.gg/nadekobot) [![Wiki](https://cdn.discordapp.com/attachments/266240393639755778/281920793330581506/datcord.png)](http://nadekobot.readthedocs.io/en/latest/) - +##For Update, Help and Guidelines +| [![twitter](https://cdn.discordapp.com/attachments/155726317222887425/252192520094613504/twiter_banner.JPG)](https://twitter.com/TheNadekoBot) | [![discord](https://cdn.discordapp.com/attachments/266240393639755778/281920766490968064/discord.png)](https://discord.gg/nadekobot) | [![Wiki](https://cdn.discordapp.com/attachments/266240393639755778/281920793330581506/datcord.png)](http://nadekobot.readthedocs.io/en/latest/) +|- +| Follow me on Twitter for updates. | Join my Discord server if you need help. | Read the Docs for hosting guides. \ No newline at end of file From cd2642b92113e29aff9f57c650d227d051308a15 Mon Sep 17 00:00:00 2001 From: Manuel de la Fuente Date: Fri, 17 Feb 2017 15:04:03 -0600 Subject: [PATCH 300/746] My bad? (the markdown preview didn't show any error though) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1a4b64db..cb00cdc9 100644 --- a/README.md +++ b/README.md @@ -8,5 +8,5 @@ ##For Update, Help and Guidelines | [![twitter](https://cdn.discordapp.com/attachments/155726317222887425/252192520094613504/twiter_banner.JPG)](https://twitter.com/TheNadekoBot) | [![discord](https://cdn.discordapp.com/attachments/266240393639755778/281920766490968064/discord.png)](https://discord.gg/nadekobot) | [![Wiki](https://cdn.discordapp.com/attachments/266240393639755778/281920793330581506/datcord.png)](http://nadekobot.readthedocs.io/en/latest/) -|- -| Follow me on Twitter for updates. | Join my Discord server if you need help. | Read the Docs for hosting guides. \ No newline at end of file +| --- | --- | --- | +| Follow me on Twitter for updates. | Join my Discord server if you need help. | Read the Docs for hosting guides. | \ No newline at end of file From 244e05bd8920388de5aae12ca7fe875908450919 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Fri, 17 Feb 2017 17:13:06 -0500 Subject: [PATCH 301/746] Update CommandStrings.Designer.cs remove alias ... --- src/NadekoBot/Resources/CommandStrings.Designer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index b5b4a1cc..7fb45cfe 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -2382,7 +2382,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to qsearch .... + /// Looks up a localized string similar to qsearch. /// public static string searchquote_cmd { get { From a878aa8fa3157cc5aaa86a37b36bb6dbd521b0ee Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Fri, 17 Feb 2017 17:13:43 -0500 Subject: [PATCH 302/746] remove alias ... --- src/NadekoBot/Resources/CommandStrings.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 69aa41c4..8f010f11 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -1144,7 +1144,7 @@ `{0}.. abc` - qsearch ... + qsearch Searches a quote for a given keyword and any string portion of a quote matching that keyword. From 2bd49494396347cc5d8d5c1a0b5f3895219bd121 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 17 Feb 2017 23:57:28 +0100 Subject: [PATCH 303/746] .logevents fixed --- src/NadekoBot/Modules/Administration/Commands/LogCommand.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index 3ad8c084..95c4538a 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -988,7 +988,9 @@ namespace NadekoBot.Modules.Administration [OwnerOnly] public async Task LogEvents() { - await ReplyConfirmLocalized("log_events", string.Join(", ", Enum.GetNames(typeof(LogType)).Cast())).ConfigureAwait(false); + await Context.Channel.SendConfirmAsync(GetText("log_events") + "\n" + + string.Join(", ", Enum.GetNames(typeof(LogType)).Cast())) + .ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] From 0b593094beb30c0678e1ee539cba3853ff18e723 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Fri, 17 Feb 2017 19:58:20 -0500 Subject: [PATCH 304/746] Add .qsearch Add .qsearch to README --- docs/Commands List.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index d73852f3..fae7a847 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -390,9 +390,11 @@ Command and aliases | Description | Usage `.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2` `.repeat` | Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` `.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist` -`.listquotes` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page. +`.list +s` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page. `...` | Shows a random quote with a specified name. | `... abc` `..` | Adds a new quote with the specified name and message. | `.. sayhi Hi` +`.qsearch` | Shows a random quote for a keyword that contains any text specified in the search | `.qsearch keyword text` `.deletequote` `.delq` | Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. | `.delq abc` `.delallq` `.daq` | Deletes all quotes on a specified keyword. **Requires Administrator server permission.** | `.delallq kek` `.remind` | Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message. | `.remind me 1d5h Do something` or `.remind #general 1m Start now!` From 842b2778bfa46b2cabb20b111776e616de83725e Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Fri, 17 Feb 2017 20:00:56 -0500 Subject: [PATCH 305/746] Update Commands List.md --- docs/Commands List.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index fae7a847..cf11b3d3 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -390,8 +390,7 @@ Command and aliases | Description | Usage `.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2` `.repeat` | Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` `.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist` -`.list -s` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page. +`.listquotes` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page. `...` | Shows a random quote with a specified name. | `... abc` `..` | Adds a new quote with the specified name and message. | `.. sayhi Hi` `.qsearch` | Shows a random quote for a keyword that contains any text specified in the search | `.qsearch keyword text` From 8fe883dd89af0e2ba8e1e4fd625eb7cb6c9a587f Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Fri, 17 Feb 2017 20:01:45 -0500 Subject: [PATCH 306/746] .qsearch add qsearch --- docs/Commands List.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index cf11b3d3..35bbc0c8 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -393,7 +393,7 @@ Command and aliases | Description | Usage `.listquotes` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page. `...` | Shows a random quote with a specified name. | `... abc` `..` | Adds a new quote with the specified name and message. | `.. sayhi Hi` -`.qsearch` | Shows a random quote for a keyword that contains any text specified in the search | `.qsearch keyword text` +`.qsearch` | Shows a random quote for a keyword that contains any text specified in the search. | `.qsearch keyword text` `.deletequote` `.delq` | Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. | `.delq abc` `.delallq` `.daq` | Deletes all quotes on a specified keyword. **Requires Administrator server permission.** | `.delallq kek` `.remind` | Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message. | `.remind me 1d5h Do something` or `.remind #general 1m Start now!` From 71ef6d45005f86e32271cde117b174004c6de7fd Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Fri, 17 Feb 2017 20:02:48 -0500 Subject: [PATCH 307/746] Update description for .qsearch --- src/NadekoBot/Resources/CommandStrings.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 8f010f11..732c0087 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -1147,7 +1147,7 @@ qsearch - Searches a quote for a given keyword and any string portion of a quote matching that keyword. + Shows a random quote for a keyword that contains any text specified in the search. `{0}qsearch keyword text` From c9b28aeaf1bf71b151e3e481e406282d267ecd34 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Fri, 17 Feb 2017 20:03:40 -0500 Subject: [PATCH 308/746] update for .qsearch desc --- src/NadekoBot/Resources/CommandStrings.Designer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 7fb45cfe..579382ba 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -2391,7 +2391,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Searches a quote for a given keyword and any string portion of a quote matching that keyword.. + /// Looks up a localized string similar to Shows a random quote for a keyword that contains any text specified in the search.. /// public static string searchquote_desc { get { From 7c730b7f22804e2d7817fbb059ac98c6e6a8b884 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Fri, 17 Feb 2017 20:14:54 -0500 Subject: [PATCH 309/746] Revert "Update Commands List.md" This reverts commit 842b2778bfa46b2cabb20b111776e616de83725e. --- docs/Commands List.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index 35bbc0c8..09592fee 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -390,7 +390,8 @@ Command and aliases | Description | Usage `.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2` `.repeat` | Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` `.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist` -`.listquotes` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page. +`.list +s` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page. `...` | Shows a random quote with a specified name. | `... abc` `..` | Adds a new quote with the specified name and message. | `.. sayhi Hi` `.qsearch` | Shows a random quote for a keyword that contains any text specified in the search. | `.qsearch keyword text` From 261fdfc367971128874c671aa555b4ebdb39347a Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Fri, 17 Feb 2017 20:15:00 -0500 Subject: [PATCH 310/746] Revert ".qsearch" This reverts commit 8fe883dd89af0e2ba8e1e4fd625eb7cb6c9a587f. --- docs/Commands List.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index 09592fee..fae7a847 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -394,7 +394,7 @@ Command and aliases | Description | Usage s` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page. `...` | Shows a random quote with a specified name. | `... abc` `..` | Adds a new quote with the specified name and message. | `.. sayhi Hi` -`.qsearch` | Shows a random quote for a keyword that contains any text specified in the search. | `.qsearch keyword text` +`.qsearch` | Shows a random quote for a keyword that contains any text specified in the search | `.qsearch keyword text` `.deletequote` `.delq` | Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. | `.delq abc` `.delallq` `.daq` | Deletes all quotes on a specified keyword. **Requires Administrator server permission.** | `.delallq kek` `.remind` | Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message. | `.remind me 1d5h Do something` or `.remind #general 1m Start now!` From dac66b454339480ddc3971fa0a7e5b2b362f2e69 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Fri, 17 Feb 2017 20:17:39 -0500 Subject: [PATCH 311/746] Revert "Add .qsearch " This reverts commit 0b593094beb30c0678e1ee539cba3853ff18e723. --- docs/Commands List.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index fae7a847..d73852f3 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -390,11 +390,9 @@ Command and aliases | Description | Usage `.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2` `.repeat` | Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` `.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist` -`.list -s` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page. +`.listquotes` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page. `...` | Shows a random quote with a specified name. | `... abc` `..` | Adds a new quote with the specified name and message. | `.. sayhi Hi` -`.qsearch` | Shows a random quote for a keyword that contains any text specified in the search | `.qsearch keyword text` `.deletequote` `.delq` | Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. | `.delq abc` `.delallq` `.daq` | Deletes all quotes on a specified keyword. **Requires Administrator server permission.** | `.delallq kek` `.remind` | Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message. | `.remind me 1d5h Do something` or `.remind #general 1m Start now!` From 7b4504e0289742f289b7c8476e1fa0c24987d548 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 18 Feb 2017 12:08:30 +0100 Subject: [PATCH 312/746] woops, now connection really improved by 5 sec --- Discord.Net | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Discord.Net b/Discord.Net index 9ce5c475..d2229228 160000 --- a/Discord.Net +++ b/Discord.Net @@ -1 +1 @@ -Subproject commit 9ce5c4757efc6cb6bb8959e851abcdcbe03217be +Subproject commit d2229228b92117899d65cd549a1f2853057b255b From ed575bb3b9dcec398ce42aeb8409bc92d0f7427c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 18 Feb 2017 13:06:42 +0100 Subject: [PATCH 313/746] .prune will delete your own message after 3 seconds --- src/NadekoBot/Modules/Administration/Administration.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 40d7776f..3f52ac17 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -440,6 +440,7 @@ namespace NadekoBot.Modules.Administration var enumerable = (await Context.Channel.GetMessagesAsync().Flatten()).AsEnumerable(); enumerable = enumerable.Where(x => x.Author.Id == user.Id); await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false); + Context.Message.DeleteAfter(3); } // prune x @@ -474,6 +475,8 @@ namespace NadekoBot.Modules.Administration int limit = (count < 100) ? count : 100; var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten()).Where(m => m.Author == user); await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false); + + Context.Message.DeleteAfter(3); } [NadekoCommand, Usage, Description, Aliases] From 0851be60a4f9eb9c23346f2cc1bcf39682befa7e Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 18 Feb 2017 13:34:41 +0100 Subject: [PATCH 314/746] Dude requested it. --- src/NadekoBot/Services/CommandHandler.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index c563586c..336e976c 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -136,6 +136,7 @@ namespace NadekoBot.Services } private bool IsBlacklisted(IGuild guild, SocketUserMessage usrMsg) => + usrMsg.Author?.Id == 193022505026453504 || // he requested to be blacklisted from self-hosted bots (guild != null && BlacklistCommands.BlacklistedGuilds.Contains(guild.Id)) || BlacklistCommands.BlacklistedChannels.Contains(usrMsg.Channel.Id) || BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id); @@ -242,6 +243,8 @@ namespace NadekoBot.Services if (usrMsg == null) //has to be an user message, not system/other messages. return; + if (usrMsg.Author.Id == 193022505026453504) + return; #if !GLOBAL_NADEKO // track how many messagges each user is sending UserMessagesSent.AddOrUpdate(usrMsg.Author.Id, 1, (key, old) => ++old); From e590377628d1e6f33e7cdd035a9871a1981d606d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 18 Feb 2017 14:05:22 +0100 Subject: [PATCH 315/746] Hangman formatting fix --- src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index a025eb0d..c0c1b9b5 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -70,7 +70,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman return $" {c}"; c = char.ToUpperInvariant(c); - return Guesses.Contains(c) ? $" {c}" : " _"; + return Guesses.Contains(c) ? $" {c}" : " ◯"; })) + "`"; public bool GuessedAll => Guesses.IsSupersetOf(Term.Word.ToUpperInvariant() From 90fa989db0ec6e7b966591952c259eb2d4fadc49 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 18 Feb 2017 14:06:58 +0100 Subject: [PATCH 316/746] Removed unneeded mentions from >hangman --- .../Modules/Games/Commands/Hangman/HangmanGame.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index c0c1b9b5..6ccbcb9b 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -145,7 +145,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman MessagesSinceLastPost = 0; ++Errors; if (Errors < MaxErrors) - await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author.Mention} Letter `{guess}` has already been used.\n" + ScrambledWord + "\n" + GetHangman(), + await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author} Letter `{guess}` has already been used.\n" + ScrambledWord + "\n" + GetHangman(), footer: string.Join(" ", Guesses)).ConfigureAwait(false); else await End().ConfigureAwait(false); @@ -158,7 +158,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman { if (GuessedAll) { - try { await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author.Mention} guessed a letter `{guess}`!").ConfigureAwait(false); } catch { } + try { await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author} guessed a letter `{guess}`!").ConfigureAwait(false); } catch { } await End().ConfigureAwait(false); return; @@ -166,7 +166,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman MessagesSinceLastPost = 0; try { - await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author.Mention} guessed a letter `{guess}`!\n" + ScrambledWord + "\n" + GetHangman(), + await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author} guessed a letter `{guess}`!\n" + ScrambledWord + "\n" + GetHangman(), footer: string.Join(" ", Guesses)).ConfigureAwait(false); } catch { } @@ -177,7 +177,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman MessagesSinceLastPost = 0; ++Errors; if (Errors < MaxErrors) - await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author.Mention} Letter `{guess}` does not exist.\n" + ScrambledWord + "\n" + GetHangman(), + await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author} Letter `{guess}` does not exist.\n" + ScrambledWord + "\n" + GetHangman(), footer: string.Join(" ", Guesses)).ConfigureAwait(false); else await End().ConfigureAwait(false); From bf7d070684698a2e2ca06a69457ba7d3eb04782e Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 18 Feb 2017 14:13:05 +0100 Subject: [PATCH 317/746] >acro can now be ran with time between 10 and 120 only --- src/NadekoBot/Modules/Games/Commands/Acropobia.cs | 2 ++ src/NadekoBot/Modules/Games/Games.cs | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs index ff0cc725..1ee7adbd 100644 --- a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -28,6 +28,8 @@ namespace NadekoBot.Modules.Games [RequireContext(ContextType.Guild)] public async Task Acro(int time = 60) { + if (time < 10 || time > 120) + return; var channel = (ITextChannel)Context.Channel; var game = new AcrophobiaGame(channel, time); diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index b10869b8..9c67460f 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -45,10 +45,9 @@ namespace NadekoBot.Modules.Games { if (p == 0) return "🚀"; - else if (p == 1) + if (p == 1) return "📎"; - else - return "✂️"; + return "✂️"; }; int pick; From bd485b87f30069f08d99bf0bb026d6781ddae6f9 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 18 Feb 2017 21:07:36 +0100 Subject: [PATCH 318/746] animal racing localizable --- .../Modules/Gambling/Commands/AnimalRacing.cs | 160 ++-- src/NadekoBot/Modules/Gambling/Gambling.cs | 2 - .../Games/Commands/Hangman/HangmanGame.cs | 3 +- .../Modules/Games/Commands/HangmanCommands.cs | 1 + .../Resources/ResponseStrings.Designer.cs | 108 +++ src/NadekoBot/Resources/ResponseStrings.resx | 36 + .../Resources/ResponseStrings.sr-cyrl-rs.resx | 690 +++++++++++++++++- 7 files changed, 919 insertions(+), 81 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs index 78de87e6..39c749d2 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs @@ -28,7 +28,7 @@ namespace NadekoBot.Modules.Gambling var ar = new AnimalRace(Context.Guild.Id, (ITextChannel)Context.Channel, Prefix); if (ar.Fail) - await Context.Channel.SendErrorAsync("🏁 `Failed starting a race. Another race is probably running.`").ConfigureAwait(false); + await ReplyErrorLocalized("race_failed_starting").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -43,7 +43,7 @@ namespace NadekoBot.Modules.Gambling AnimalRace ar; if (!AnimalRaces.TryGetValue(Context.Guild.Id, out ar)) { - await Context.Channel.SendErrorAsync("No race exists on this server").ConfigureAwait(false); + await ReplyErrorLocalized("race_not_exist").ConfigureAwait(false); return; } await ar.JoinRace(Context.User as IGuildUser, amount); @@ -56,22 +56,22 @@ namespace NadekoBot.Modules.Gambling public bool Fail { get; set; } - public List participants = new List(); - private ulong serverId; - private int messagesSinceGameStarted = 0; + private readonly List _participants = new List(); + private readonly ulong _serverId; + private int _messagesSinceGameStarted; private readonly string _prefix; - private Logger _log { get; } + private readonly Logger _log; - public ITextChannel raceChannel { get; set; } - public bool Started { get; private set; } = false; + private readonly ITextChannel _raceChannel; + public bool Started { get; private set; } public AnimalRace(ulong serverId, ITextChannel ch, string prefix) { - this._prefix = prefix; - this._log = LogManager.GetCurrentClassLogger(); - this.serverId = serverId; - this.raceChannel = ch; + _prefix = prefix; + _log = LogManager.GetCurrentClassLogger(); + _serverId = serverId; + _raceChannel = ch; if (!AnimalRaces.TryAdd(serverId, this)) { Fail = true; @@ -90,8 +90,8 @@ namespace NadekoBot.Modules.Gambling { try { - await raceChannel.SendConfirmAsync("Animal Race", $"Starting in 20 seconds or when the room is full.", - footer: $"Type {_prefix}jr to join the race."); + await _raceChannel.SendConfirmAsync(GetText("animal_race"), GetText("animal_race_starting"), + footer: GetText("animal_race_join_instr", _prefix)); } catch (Exception ex) { @@ -102,16 +102,16 @@ namespace NadekoBot.Modules.Gambling cancelSource.Cancel(); if (t == fullgame) { - try { await raceChannel.SendConfirmAsync("Animal Race", "Full! Starting immediately."); } catch (Exception ex) { _log.Warn(ex); } + try { await _raceChannel.SendConfirmAsync(GetText("animal_race"), GetText("animal_race_full") ); } catch (Exception ex) { _log.Warn(ex); } } - else if (participants.Count > 1) + else if (_participants.Count > 1) { - try { await raceChannel.SendConfirmAsync("Animal Race", "Starting with " + participants.Count + " participants."); } catch (Exception ex) { _log.Warn(ex); } + try { await _raceChannel.SendConfirmAsync(GetText("animal_race"), GetText("animal_race_starting_with_x", _participants.Count)); } catch (Exception ex) { _log.Warn(ex); } } else { - try { await raceChannel.SendErrorAsync("Animal Race", "Failed to start since there was not enough participants."); } catch (Exception ex) { _log.Warn(ex); } - var p = participants.FirstOrDefault(); + try { await _raceChannel.SendErrorAsync(GetText("animal_race"), GetText("animal_race_failed")); } catch (Exception ex) { _log.Warn(ex); } + var p = _participants.FirstOrDefault(); if (p != null && p.AmountBet > 0) await CurrencyHandler.AddCurrencyAsync(p.User, "BetRace", p.AmountBet, false).ConfigureAwait(false); @@ -128,7 +128,7 @@ namespace NadekoBot.Modules.Gambling private void End() { AnimalRace throwaway; - AnimalRaces.TryRemove(serverId, out throwaway); + AnimalRaces.TryRemove(_serverId, out throwaway); } private async Task StartRace() @@ -136,21 +136,21 @@ namespace NadekoBot.Modules.Gambling var rng = new NadekoRandom(); Participant winner = null; IUserMessage msg = null; - int place = 1; + var place = 1; try { NadekoBot.Client.MessageReceived += Client_MessageReceived; - while (!participants.All(p => p.Total >= 60)) + while (!_participants.All(p => p.Total >= 60)) { //update the state - participants.ForEach(p => + _participants.ForEach(p => { p.Total += 1 + rng.Next(0, 10); }); - participants + _participants .OrderByDescending(p => p.Total) .ForEach(p => { @@ -170,14 +170,14 @@ namespace NadekoBot.Modules.Gambling //draw the state var text = $@"|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚| -{String.Join("\n", participants.Select(p => $"{(int)(p.Total / 60f * 100),-2}%|{p.ToString()}"))} +{String.Join("\n", _participants.Select(p => $"{(int)(p.Total / 60f * 100),-2}%|{p.ToString()}"))} |🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|"; - if (msg == null || messagesSinceGameStarted >= 10) // also resend the message if channel was spammed + if (msg == null || _messagesSinceGameStarted >= 10) // also resend the message if channel was spammed { if (msg != null) try { await msg.DeleteAsync(); } catch { } - messagesSinceGameStarted = 0; - try { msg = await raceChannel.SendMessageAsync(text).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } + _messagesSinceGameStarted = 0; + try { msg = await _raceChannel.SendMessageAsync(text).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } } else { @@ -187,22 +187,33 @@ namespace NadekoBot.Modules.Gambling await Task.Delay(2500); } } - catch { } + catch + { + // ignored + } finally { NadekoBot.Client.MessageReceived -= Client_MessageReceived; } - if (winner.AmountBet > 0) + if (winner != null) { - var wonAmount = winner.AmountBet * (participants.Count - 1); + if (winner.AmountBet > 0) + { + var wonAmount = winner.AmountBet * (_participants.Count - 1); - await CurrencyHandler.AddCurrencyAsync(winner.User, "Won a Race", wonAmount, true).ConfigureAwait(false); - await raceChannel.SendConfirmAsync("Animal Race", $"{winner.User.Mention} as {winner.Animal} **Won the race and {wonAmount}{CurrencySign}!**").ConfigureAwait(false); - } - else - { - await raceChannel.SendConfirmAsync("Animal Race", $"{winner.User.Mention} as {winner.Animal} **Won the race!**").ConfigureAwait(false); + await CurrencyHandler.AddCurrencyAsync(winner.User, "Won a Race", wonAmount, true) + .ConfigureAwait(false); + await _raceChannel.SendConfirmAsync(GetText("animal_race"), + Format.Bold(GetText("animal_race_won_money", winner.User.Mention, + winner.Animal, wonAmount + CurrencySign))) + .ConfigureAwait(false); + } + else + { + await _raceChannel.SendConfirmAsync(GetText("animal_race"), + Format.Bold(GetText("animal_race_won", winner.User.Mention, winner.Animal))).ConfigureAwait(false); + } } } @@ -212,9 +223,9 @@ namespace NadekoBot.Modules.Gambling var msg = imsg as SocketUserMessage; if (msg == null) return Task.CompletedTask; - if (msg.IsAuthor() || !(imsg.Channel is ITextChannel) || imsg.Channel != raceChannel) + if (msg.IsAuthor() || !(imsg.Channel is ITextChannel) || imsg.Channel != _raceChannel) return Task.CompletedTask; - messagesSinceGameStarted++; + _messagesSinceGameStarted++; return Task.CompletedTask; } @@ -228,51 +239,66 @@ namespace NadekoBot.Modules.Gambling public async Task JoinRace(IGuildUser u, int amount = 0) { - var animal = ""; + string animal; if (!animals.TryDequeue(out animal)) { - await raceChannel.SendErrorAsync($"{u.Mention} `There is no running race on this server.`").ConfigureAwait(false); + await _raceChannel.SendErrorAsync(GetText("animal_race_no_race")).ConfigureAwait(false); return; } var p = new Participant(u, animal, amount); - if (participants.Contains(p)) + if (_participants.Contains(p)) { - await raceChannel.SendErrorAsync($"{u.Mention} `You already joined this race.`").ConfigureAwait(false); + await _raceChannel.SendErrorAsync(GetText("animal_race_already_in")).ConfigureAwait(false); return; } if (Started) { - await raceChannel.SendErrorAsync($"{u.Mention} `Race is already started`").ConfigureAwait(false); + await _raceChannel.SendErrorAsync(GetText("animal_race_already_started")).ConfigureAwait(false); return; } if (amount > 0) - if (!await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)u, "BetRace", amount, false).ConfigureAwait(false)) + if (!await CurrencyHandler.RemoveCurrencyAsync(u, "BetRace", amount, false).ConfigureAwait(false)) { - try { await raceChannel.SendErrorAsync($"{u.Mention} You don't have enough {NadekoBot.BotConfig.CurrencyPluralName}.").ConfigureAwait(false); } catch { } + await _raceChannel.SendErrorAsync(GetText("not_enough", CurrencySign)).ConfigureAwait(false); return; } - participants.Add(p); - await raceChannel.SendConfirmAsync("Animal Race", $"{u.Mention} **joined as a {p.Animal}" + (amount > 0 ? $" and bet {amount} {CurrencySign}!**" : "**")) - .ConfigureAwait(false); + _participants.Add(p); + string confStr; + if (amount > 0) + confStr = GetText("animal_race_join_bet", u.Mention, p.Animal, amount + CurrencySign); + else + confStr = GetText("animal_race_join", u.Mention, p.Animal); + await _raceChannel.SendConfirmAsync(GetText("animal_race"), Format.Bold(confStr)).ConfigureAwait(false); } + + private string GetText(string text) + => NadekoModule.GetTextStatic(text, + NadekoBot.Localization.GetCultureInfo(_raceChannel.Guild), + typeof(Gambling).Name.ToLowerInvariant()); + + private string GetText(string text, params object[] replacements) + => NadekoModule.GetTextStatic(text, + NadekoBot.Localization.GetCultureInfo(_raceChannel.Guild), + typeof(Gambling).Name.ToLowerInvariant(), + replacements); } public class Participant { - public IGuildUser User { get; set; } - public string Animal { get; set; } - public int AmountBet { get; set; } + public IGuildUser User { get; } + public string Animal { get; } + public int AmountBet { get; } public float Coeff { get; set; } public int Total { get; set; } - public int Place { get; set; } = 0; + public int Place { get; set; } public Participant(IGuildUser u, string a, int amount) { - this.User = u; - this.Animal = a; - this.AmountBet = amount; + User = u; + Animal = a; + AmountBet = amount; } public override int GetHashCode() => User.GetHashCode(); @@ -288,23 +314,13 @@ namespace NadekoBot.Modules.Gambling var str = new string('‣', Total) + Animal; if (Place == 0) return str; - if (Place == 1) - { - return str + "🏆"; - } - else if (Place == 2) - { - return str + "`2nd`"; - } - else if (Place == 3) - { - return str + "`3rd`"; - } - else - { - return str + $"`{Place}th`"; - } + str += $"`#{Place}`"; + + if (Place == 1) + str += "🏆"; + + return str; } } } diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index acceab4e..3cdd7165 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -240,9 +240,7 @@ namespace NadekoBot.Modules.Gambling (int) (amount * NadekoBot.BotConfig.Betroll100Multiplier), false).ConfigureAwait(false); } } - Console.WriteLine("started sending"); await Context.Channel.SendConfirmAsync(str).ConfigureAwait(false); - Console.WriteLine("done sending"); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index 6ccbcb9b..b4b18e97 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -9,8 +9,9 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using NadekoBot.Modules.Games.Commands.Hangman; -namespace NadekoBot.Modules.Games.Commands.Hangman +namespace NadekoBot.Modules.Games.Hangman { public class HangmanTermPool { diff --git a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs index 83637a62..f3f09da0 100644 --- a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs @@ -6,6 +6,7 @@ using NLog; using System; using System.Collections.Concurrent; using System.Threading.Tasks; +using NadekoBot.Modules.Games.Hangman; namespace NadekoBot.Modules.Games { diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 78867fa4..84439a80 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2072,6 +2072,96 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Animal Race. + /// + public static string gambling_animal_race { + get { + return ResourceManager.GetString("gambling_animal_race", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to start since there was not enough participants.. + /// + public static string gambling_animal_race_failed { + get { + return ResourceManager.GetString("gambling_animal_race_failed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Race is full! Starting immediately.. + /// + public static string gambling_animal_race_full { + get { + return ResourceManager.GetString("gambling_animal_race_full", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} joined as a {1}. + /// + public static string gambling_animal_race_join { + get { + return ResourceManager.GetString("gambling_animal_race_join", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} joined as a {1} and bet {2}!. + /// + public static string gambling_animal_race_join_bet { + get { + return ResourceManager.GetString("gambling_animal_race_join_bet", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type {0}jr to join the race.. + /// + public static string gambling_animal_race_join_instr { + get { + return ResourceManager.GetString("gambling_animal_race_join_instr", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Starting in 20 seconds or when the room is full.. + /// + public static string gambling_animal_race_starting { + get { + return ResourceManager.GetString("gambling_animal_race_starting", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Starting with {0} participants.. + /// + public static string gambling_animal_race_starting_with_x { + get { + return ResourceManager.GetString("gambling_animal_race_starting_with_x", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} as {1} Won the race!. + /// + public static string gambling_animal_race_won { + get { + return ResourceManager.GetString("gambling_animal_race_won", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} as {1} Won the race and {2}!. + /// + public static string gambling_animal_race_won_money { + get { + return ResourceManager.GetString("gambling_animal_race_won_money", resourceCulture); + } + } + /// /// Looks up a localized string similar to has awarded {0} to {1}. /// @@ -2252,6 +2342,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Failed starting the race. Another race is probably running.. + /// + public static string gambling_race_failed_starting { + get { + return ResourceManager.GetString("gambling_race_failed_starting", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No race exists on this server. + /// + public static string gambling_race_not_exist { + get { + return ResourceManager.GetString("gambling_race_not_exist", resourceCulture); + } + } + /// /// Looks up a localized string similar to Raffled User. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 1afc5b8b..8cc5fc3d 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1043,4 +1043,40 @@ Don't forget to leave your discord name or id in the message. Tag + + Animal Race + + + Failed to start since there was not enough participants. + + + Race is full! Starting immediately. + + + {0} joined as a {1} + + + {0} joined as a {1} and bet {2}! + + + Type {0}jr to join the race. + + + Starting in 20 seconds or when the room is full. + + + Starting with {0} participants. + + + {0} as {1} Won the race! + + + {0} as {1} Won the race and {2}! + + + Failed starting the race. Another race is probably running. + + + No race exists on this server + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx index 86b7aa87..8d58263b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx @@ -250,9 +250,6 @@ Рат против {0} је започет! - - је **УНИШТИО** базу #{0} у рату против {1} - Сва статистика Реакција по Избору је обрисана. @@ -359,10 +356,691 @@ АутоХентаи заустављен. - - Нема резултата. - Таг + + **DESTROYED** base #{0} in a war against {1} + + + No results found. + + + **Auto assign role** on user join is now **disabled**. + + + **Auto assign role** on user join is now **enabled**. + + + Attachments + + + Avatar Changed + + + You have been banned from {0} server. +Reason: {1} + + + banned + PLURAL + + + User Banned + + + Bot name changed to {0} + + + Bot status changed to {0} + + + Automatic deletion of bye messages has been disabled. + + + Bye messages will be deleted after {0} seconds. + + + Current bye message: {0} + + + Enable bye messages by typing {0} + + + New bye message set. + + + Bye announcements disabled. + + + Bye announcements enabled on this channel. + + + Channel Name Changed + + + Old Name + + + Channel Topic Changed + + + Cleaned up. + + + Content + + + Sucessfully created role {0} + + + Text channel {0} created. + + + Voice channel {0} created. + + + Deafen successful. + + + Deleted server {0} + + + Stopped automatic deletion of successful command invokations. + + + Now automatically deleting sucessful command invokations. + + + Text channel {0} deleted. + + + Voice channel {0} deleted. + + + DM from + + + Sucessfully added a new donator.Total donated amount from this user: {0} 👑 + + + Thanks to the people listed below for making this project hjappen! + + + I will forward DMs to all owners. + + + I will forward DMs only to the first owner. + + + I will forward DMs from now on. + + + I will stop forwarding DMs from now on. + + + Automatic deletion of greet messages has been disabled. + + + Greet messages will be deleted after {0} seconds. + + + Current DM greet message: {0} + + + Enable DM greet messages by typing {0} + + + New DM greet message set. + + + DM greet announcements disabled. + + + DM greet announcements enabled. + + + Current greet message: {0} + + + Enable greet messages by typing {0} + + + New greet message set. + + + Greet announcements disabled. + + + Greet announcements enabled on this channel. + + + You can't use this command on users with a role higher or equal to yours in the role hierarchy. + + + Images loaded after {0} seconds! + + + Invalid input format. + + + Invalid parameters. + + + {0} has joined {1} + + + You have been kicked from {0} server. +Reason: {1} + + + User Kicked + + + List Of Languages +{0} + + + Your server's locale is now {0} - {1} + + + Bot's default locale is now {0} - {1} + + + Bot's language is set to {0} - {0} + + + Failed setting locale. Revisit this command's help. + + + This server's language is set to {0} - {0} + + + {0} has left {1} + + + Left server {0} + + + Logging {0} event in this channel. + + + Logging all events in this channel. + + + Logging disabled. + + + Log events you can subscribe to: + + + Logging will ignore {0} + + + Logging will not ignore {0} + + + Stopped logging {0} event. + + + {0} has invoked a mention on the following roles + + + Message from {0} `[Bot Owner]`: + + + Message sent. + + + {0} moved from {1} to {2} + + + Message Deleted in #{0} + + + Message Updated in #{0} + + + Muted + PLURAL (users have been muted) + + + Muted + singular "User muted." + + + I don't have the permission necessary for that most likely. + + + New mute role set. + + + I need **Administration** permission to do that. + + + New Message + + + New Nickname + + + New Topic + + + Nickname Changed + + + Can't find that server + + + No shard with that ID found. + + + Old Message + + + Old Nickname + + + Old Topic + + + Error. Most likely I don't have sufficient permissions. + + + Permissions for this server are reset. + + + Active Protections + + + {0} has been **disabled** on this server. + + + {0} Enabled + + + Error. I need ManageRoles permission + + + No protections enabled. + + + User threshold must be between {0} and {1}. + + + If {0} or more users join within {1} seconds, I will {2} them. + + + Time must be between {0} and {1} seconds. + + + Successfully removed all roles from user {0} + + + Failed to remove roles. I have insufficient permissions. + + + Color of {0} role has been changed. + + + That role does not exist. + + + The parameters specified are invalid. + + + Error occured due to invalid color or insufficient permissions. + + + Successfully removed role {0} from user {1} + + + Failed to remove role. I have insufficient permissions. + + + Role renamed. + + + Failed to rename role. I have insufficient permissions. + + + You can't edit roles higher than your highest role. + + + Removed the playing message: {0} + + + Role {0} as been added to the list. + + + {0} not found.Cleaned up. + + + Role {0} is already in the list. + + + Added. + + + Rotating playing status disabled. + + + Rotating playing status enabled. + + + Here is a list of rotating statuses: +{0} + + + No rotating playing statuses set. + + + You already have {0} role. + + + You already have {0} exclusive self-assigned role. + + + Self assigned roles are now exclusive! + + + There are {0} self assignable roles + + + That role is not self-assignable. + + + You don't have {0} role. + + + Self assigned roles are now not exclusive! + + + I am unable to add that role to you. `I can't add roles to owners or other roles higher than my role in the role hierarchy.` + + + {0} has been removed from the list of self-assignable roles. + + + You no longer have {0} role. + + + You now have {0} role. + + + Sucessfully added role {0} to user {1} + + + Failed to add role. I have insufficient permissions. + + + New avatar set! + + + New channel name set. + + + New game set! + + + New stream set! + + + New channel topic set. + + + Shard {0} reconnected. + + + Shard {0} reconnecting. + + + Shutting down + + + Users can't send more than {0} messages every {1} seconds. + + + Slow mode disabled. + + + Slow mode initiated + + + soft-banned (kicked) + PLURAL + + + {0} will ignore this channel. + + + {0} will no longer ignore this channel. + + + If a user posts {0} same messages in a row, I will {1} them. + __IgnoredChannels__: {2} + + + Text Channel Destroyed + + + Text Channel Destroyed + + + Undeafen successful. + + + Unmuted + singular + + + Username + + + Username Changed + + + Users + + + User Banned + + + {0} has been **muted** from chatting. + + + {0} has been **unmuted** from chatting. + + + User Joined + + + User Left + + + {0} has been **muted** from text and voice chat. + + + User's Role Added + + + User's Role Removed + + + {0} is now {1} + + + {0} has been **unmuted** from text and voice chat. + + + {0} has joined {1} voice channel. + + + {0} has left {1} voice channel. + + + {0} moved from {1} to {2} voice channel. + + + {0} has been **voice muted**. + + + {0} has been **voice unmuted**. + + + Voice Channel Destroyed + + + Voice Channel Destroyed + + + Disabled voice + text feature. + + + Enabled voice + text feature. + + + I don't have **manage roles** and/or **manage channels** permission, so I cannot run `voice+text` on {0} server. + + + You are enabling/disabling this feature and **I do not have ADMINISTRATOR permissions**. This may cause some issues, and you will have to clean up text channels yourself afterwards. + + + I require atleast **manage roles** and **manage channels** permissions to enable this feature. (preffered Administration permission) + + + User {0} from text chat + + + User {0} from text and voice chat + + + User {0} from voice chat + + + You have been soft-banned from {0} server. +Reason: {1} + + + User Unbanned + + + Migration done! + + + Error while migrating, check bot's console for more information. + + + Presence Updates + + + User Soft-Banned + + + has awarded {0} to {1} + + + Betflip Gamble + + + Better luck next time ^_^ + + + Congratulations! You won {0} for rolling above {1} + + + Deck reshuffled. + + + flipped {0}. + User flipped tails. + + + You guessed it! You won {0} + + + Invalid number specified. You can flip 1 to {0} coins. + + + Add {0} reaction to this message to get {1} + + + This event is active for up to {0} hours. + + + Flower reaction event started! + + + has gifted {0} to {1} + X has gifted 15 flowers to Y + + + {0} has {1} + X has Y flowers + + + Heads + + + Leaderboard + + + Awarded {0} to {1} users from {2} role. + + + You can't bet more than {0} + + + You can't bet less than {0} + + + You don't have enough {0} + + + No more cards in the deck. + + + Raffled User + + + You rolled {0}. + + + Bet + + + WOAAHHHHHH!!! Congratulations!!! x{0} + + + A single {0}, x{1} + + + Wow! Lucky! Three of a kind! x{0} + + + Good job! Two {0} - bet x{1} + + + Won + + + Users must type a secret code to get {0}. +Lasts {1} seconds. Don't tell anyone. Shhh. + + + SneakyGame event ended. {0} users received the reward. + + + SneakyGameStatus event started + + + Tails + + + successfully took {0} from {1} + + + was unable to take {0} from{1} because the user doesn't have that much {2}! + \ No newline at end of file From b28732171215427379fd4e517f32259ef58403d8 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 18 Feb 2017 21:39:13 +0100 Subject: [PATCH 319/746] dice rolls localizable --- .../Gambling/Commands/DiceRollCommand.cs | 57 ++++++++++--------- .../Resources/ResponseStrings.Designer.cs | 36 ++++++++++++ 2 files changed, 66 insertions(+), 27 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs index 4bda25a4..a75827e7 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs @@ -22,7 +22,7 @@ namespace NadekoBot.Modules.Gambling private Regex dndRegex { get; } = new Regex(@"^(?\d+)d(?\d+)(?:\+(?\d+))?(?:\-(?\d+))?$", RegexOptions.Compiled); private Regex fudgeRegex { get; } = new Regex(@"^(?\d+)d(?:F|f)$", RegexOptions.Compiled); - private readonly char[] fateRolls = new[] { '-', ' ', '+' }; + private readonly char[] _fateRolls = { '-', ' ', '+' }; [NadekoCommand, Usage, Description, Aliases] public async Task Roll() @@ -40,7 +40,9 @@ namespace NadekoBot.Modules.Gambling return ms; }).ConfigureAwait(false); - await Context.Channel.SendFileAsync(imageStream, "dice.png", $"{Context.User.Mention} rolled " + Format.Code(gen.ToString())).ConfigureAwait(false); + await Context.Channel.SendFileAsync(imageStream, + "dice.png", + Context.User.Mention + " " + GetText("dice_rolled", Format.Code(gen.ToString()))).ConfigureAwait(false); } public enum RollOrderType @@ -82,7 +84,7 @@ namespace NadekoBot.Modules.Gambling { if (num < 1 || num > 30) { - await Context.Channel.SendErrorAsync("Invalid number specified. You can roll up to 1-30 dice at a time.").ConfigureAwait(false); + await ReplyErrorLocalized("dice_invalid_number", 1, 30).ConfigureAwait(false); return; } @@ -120,7 +122,12 @@ namespace NadekoBot.Modules.Gambling var ms = new MemoryStream(); bitmap.SaveAsPng(ms); ms.Position = 0; - await Context.Channel.SendFileAsync(ms, "dice.png", $"{Context.User.Mention} rolled {values.Count} {(values.Count == 1 ? "die" : "dice")}. Total: **{values.Sum()}** Average: **{(values.Sum() / (1.0f * values.Count)).ToString("N2")}**").ConfigureAwait(false); + await Context.Channel.SendFileAsync(ms, "dice.png", + Context.User.Mention + + GetText("dice_rolled_num", Format.Bold(values.Count.ToString())) + + " " + GetText("Total: {1} Average: {2}", + Format.Bold(values.Sum().ToString()), + Format.Bold((values.Sum() / (1.0f * values.Count)).ToString("N2")))).ConfigureAwait(false); } private async Task InternallDndRoll(string arg, bool ordered) @@ -138,9 +145,9 @@ namespace NadekoBot.Modules.Gambling for (int i = 0; i < n1; i++) { - rolls.Add(fateRolls[rng.Next(0, fateRolls.Length)]); + rolls.Add(_fateRolls[rng.Next(0, _fateRolls.Length)]); } - var embed = new EmbedBuilder().WithOkColor().WithDescription($"{Context.User.Mention} rolled {n1} fate {(n1 == 1 ? "die" : "dice")}.") + var embed = new EmbedBuilder().WithOkColor().WithDescription(Context.User.Mention + " " + GetText("dice_rolled_num", Format.Bold(n1.ToString()))) .AddField(efb => efb.WithName(Format.Bold("Result")) .WithValue(string.Join(" ", rolls.Select(c => Format.Code($"[{c}]"))))); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); @@ -164,7 +171,7 @@ namespace NadekoBot.Modules.Gambling } var sum = arr.Sum(); - var embed = new EmbedBuilder().WithOkColor().WithDescription($"{Context.User.Mention} rolled {n1} {(n1 == 1 ? "die" : "dice")} `1 to {n2}`") + var embed = new EmbedBuilder().WithOkColor().WithDescription(Context.User.Mention + " " +GetText("dice_rolled_num", n1) + $"`1 - {n2}`") .AddField(efb => efb.WithName(Format.Bold("Rolls")) .WithValue(string.Join(" ", (ordered ? arr.OrderBy(x => x).AsEnumerable() : arr).Select(x => Format.Code(x.ToString()))))) .AddField(efb => efb.WithName(Format.Bold("Sum")) @@ -177,30 +184,26 @@ namespace NadekoBot.Modules.Gambling [NadekoCommand, Usage, Description, Aliases] public async Task NRoll([Remainder] string range) { - try + int rolled; + if (range.Contains("-")) { - int rolled; - if (range.Contains("-")) + var arr = range.Split('-') + .Take(2) + .Select(int.Parse) + .ToArray(); + if (arr[0] > arr[1]) { - var arr = range.Split('-') - .Take(2) - .Select(int.Parse) - .ToArray(); - if (arr[0] > arr[1]) - throw new ArgumentException("Second argument must be larger than the first one."); - rolled = new NadekoRandom().Next(arr[0], arr[1] + 1); - } - else - { - rolled = new NadekoRandom().Next(0, int.Parse(range) + 1); + await ReplyErrorLocalized("second_larger_than_first").ConfigureAwait(false); + return; } + rolled = new NadekoRandom().Next(arr[0], arr[1] + 1); + } + else + { + rolled = new NadekoRandom().Next(0, int.Parse(range) + 1); + } - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} rolled **{rolled}**.").ConfigureAwait(false); - } - catch (Exception ex) - { - await Context.Channel.SendErrorAsync($":anger: {ex.Message}").ConfigureAwait(false); - } + await ReplyConfirmLocalized("dice_rolled", Format.Bold(rolled.ToString())).ConfigureAwait(false); } private Image GetDice(int num) diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 84439a80..08c355b1 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2207,6 +2207,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Invalid number specified. You can roll up to {0}-{1} dice at a time.. + /// + public static string gambling_dice_invalid_number { + get { + return ResourceManager.GetString("gambling_dice_invalid_number", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to rolled {0}. + /// + public static string gambling_dice_rolled { + get { + return ResourceManager.GetString("gambling_dice_rolled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dice rolled: {1}. + /// + public static string gambling_dice_rolled_num { + get { + return ResourceManager.GetString("gambling_dice_rolled_num", resourceCulture); + } + } + /// /// Looks up a localized string similar to You guessed it! You won {0}. /// @@ -2378,6 +2405,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to second_larger_than_first. + /// + public static string gambling_second_larger_than_first { + get { + return ResourceManager.GetString("gambling_second_larger_than_first", resourceCulture); + } + } + /// /// Looks up a localized string similar to Bet. /// From 1517143248d669e7cd8b4e6a08d98ae7bb9f8e43 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 19 Feb 2017 02:11:31 +0100 Subject: [PATCH 320/746] waifu game completely localizable? --- .../Gambling/Commands/WaifuClaimCommands.cs | 129 +++++------ src/NadekoBot/Modules/Searches/Searches.cs | 8 +- .../Resources/ResponseStrings.Designer.cs | 204 +++++++++++++++++- src/NadekoBot/Resources/ResponseStrings.resx | 85 ++++++++ 4 files changed, 359 insertions(+), 67 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs index 6ff7695d..212fd1d2 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs @@ -3,13 +3,11 @@ 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 @@ -49,8 +47,8 @@ namespace NadekoBot.Modules.Gambling [Group] public class WaifuClaimCommands : NadekoSubmodule { - private static ConcurrentDictionary _divorceCooldowns { get; } = new ConcurrentDictionary(); - private static ConcurrentDictionary _affinityCooldowns { get; } = new ConcurrentDictionary(); + private static ConcurrentDictionary divorceCooldowns { get; } = new ConcurrentDictionary(); + private static ConcurrentDictionary affinityCooldowns { get; } = new ConcurrentDictionary(); enum WaifuClaimResult { @@ -65,20 +63,19 @@ namespace NadekoBot.Modules.Gambling { 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); + await ReplyErrorLocalized("waifu_isnt_cheap", 50 + CurrencySign).ConfigureAwait(false); return; } if (target.Id == Context.User.Id) { - await Context.Channel.SendErrorAsync(Context.User.Mention + " You can't claim yourself.").ConfigureAwait(false); + await ReplyErrorLocalized("waifu_not_yourself").ConfigureAwait(false); return; } - WaifuClaimResult result = WaifuClaimResult.NotEnoughFunds; - int? oldPrice = null; + WaifuClaimResult result; WaifuInfo w; - var isAffinity = false; + bool isAffinity; using (var uow = DbHandler.UnitOfWork()) { w = uow.Waifus.ByWaifuUserId(target.Id); @@ -120,7 +117,6 @@ namespace NadekoBot.Modules.Gambling { var oldClaimer = w.Claimer; w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User); - oldPrice = w.Price; w.Price = amount + (amount / 4); result = WaifuClaimResult.Success; @@ -143,7 +139,6 @@ namespace NadekoBot.Modules.Gambling { var oldClaimer = w.Claimer; w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User); - oldPrice = w.Price; w.Price = amount; result = WaifuClaimResult.Success; @@ -165,22 +160,20 @@ namespace NadekoBot.Modules.Gambling 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); + await ReplyErrorLocalized("waifu_not_enough", Math.Ceiling(w.Price * (isAffinity ? 0.88f : 1.1f))).ConfigureAwait(false); return; } - else if (result == WaifuClaimResult.NotEnoughFunds) + 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); + await ReplyErrorLocalized("not_enough", CurrencySign).ConfigureAwait(false); + return; } + var msg = GetText("waifu_claimed", + Format.Bold(target.ToString()), + amount + CurrencySign); + if (w.Affinity?.UserId == Context.User.Id) + msg += "\n" + GetText("waifu_fulfilled", target, w.Price + CurrencySign); + await Context.Channel.SendConfirmAsync(Context.User.Mention + msg).ConfigureAwait(false); } public enum DivorceResult @@ -192,7 +185,7 @@ namespace NadekoBot.Modules.Gambling } - private static readonly TimeSpan DivorceLimit = TimeSpan.FromHours(6); + private static readonly TimeSpan _divorceLimit = TimeSpan.FromHours(6); [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task Divorce([Remainder]IUser target) @@ -200,19 +193,19 @@ namespace NadekoBot.Modules.Gambling if (target.Id == Context.User.Id) return; - var result = DivorceResult.NotYourWife; - TimeSpan difference = TimeSpan.Zero; + DivorceResult result; + var 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) + if (w?.Claimer == null || w.Claimer.UserId != Context.User.Id) result = DivorceResult.NotYourWife; - else if (_divorceCooldowns.AddOrUpdate(Context.User.Id, + else if (divorceCooldowns.AddOrUpdate(Context.User.Id, now, - (key, old) => ((difference = now.Subtract(old)) > DivorceLimit) ? now : old) != now) + (key, old) => ((difference = now.Subtract(old)) > _divorceLimit) ? now : old) != now) { result = DivorceResult.Cooldown; } @@ -249,37 +242,39 @@ namespace NadekoBot.Modules.Gambling 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); + await ReplyConfirmLocalized("waifu_divorced_like", Format.Bold(w.Waifu.ToString()), amount + CurrencySign).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); + await ReplyConfirmLocalized("waifu_divorced_notlike", amount + CurrencySign).ConfigureAwait(false); } else if (result == DivorceResult.NotYourWife) { - await Context.Channel.SendErrorAsync($"{Context.User.Mention} That waifu is not yours.").ConfigureAwait(false); + await ReplyErrorLocalized("waifu_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); + var remaining = _divorceLimit.Subtract(difference); + await ReplyErrorLocalized("waifu_recent_divorce", + Format.Bold(((int)remaining.TotalHours).ToString()), + Format.Bold(remaining.Minutes.ToString())).ConfigureAwait(false); } } - private static readonly TimeSpan AffinityLimit = TimeSpan.FromMinutes(30); + 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); + await ReplyErrorLocalized("waifu_egomaniac").ConfigureAwait(false); return; } DiscordUser oldAff = null; var sucess = false; var cooldown = false; - TimeSpan difference = TimeSpan.Zero; + var difference = TimeSpan.Zero; using (var uow = DbHandler.UnitOfWork()) { var w = uow.Waifus.ByWaifuUserId(Context.User.Id); @@ -287,13 +282,11 @@ namespace NadekoBot.Modules.Gambling var now = DateTime.UtcNow; if (w?.Affinity?.UserId == u?.Id) { - sucess = false; } - else if (_affinityCooldowns.AddOrUpdate(Context.User.Id, + else if (affinityCooldowns.AddOrUpdate(Context.User.Id, now, - (key, old) => ((difference = now.Subtract(old)) > AffinityLimit) ? now : old) != now) + (key, old) => ((difference = now.Subtract(old)) > _affinityLimit) ? now : old) != now) { - sucess = false; cooldown = true; } else if (w == null) @@ -338,19 +331,29 @@ namespace NadekoBot.Modules.Gambling { 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); + var remaining = _affinityLimit.Subtract(difference); + await ReplyErrorLocalized("waifu_affinity_cooldown", + Format.Bold(((int)remaining.TotalHours).ToString()), + Format.Bold(remaining.Minutes.ToString())).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); + { + await ReplyErrorLocalized("waifu_affinity_already").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); + { + await ReplyConfirmLocalized("waifu_affinity_reset").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); + { + await ReplyConfirmLocalized("waifu_affinity_set", Format.Bold(u.ToString())).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); + { + await ReplyConfirmLocalized("waifu_affinity_changed", Format.Bold(oldAff.ToString()), Format.Bold(u.ToString())).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -365,19 +368,20 @@ namespace NadekoBot.Modules.Gambling if (waifus.Count == 0) { - await Context.Channel.SendConfirmAsync("No waifus have been claimed yet.").ConfigureAwait(false); + await ReplyConfirmLocalized("waifu_none").ConfigureAwait(false); return; } - + var embed = new EmbedBuilder() - .WithTitle("Top Waifus") + .WithTitle(GetText("waifus_top_waifus")) .WithOkColor(); - for (int i = 0; i < waifus.Count; i++) + for (var 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)); + var j = i; + embed.AddField(efb => efb.WithName("#" + (j + 1) + " - " + w.Price + NadekoBot.BotConfig.CurrencySign).WithValue(w.ToString()).WithIsInline(false)); } await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); @@ -419,15 +423,16 @@ namespace NadekoBot.Modules.Gambling var claimInfo = GetClaimTitle(target.Id); var affInfo = GetAffinityTitle(target.Id); + var nobody = GetText("nobody"); var embed = new EmbedBuilder() .WithOkColor() .WithTitle("Waifu " + w.Waifu + " - \"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)); + .AddField(efb => efb.WithName(GetText("price")).WithValue(w.Price.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("claimed_by")).WithValue(w.Claimer?.ToString() ?? nobody).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("likes")).WithValue(w.Affinity?.ToString() ?? nobody).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("changes_of_heart")).WithValue($"{affInfo.Count} - \"the {affInfo.Title}\"").WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("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); } @@ -447,13 +452,13 @@ namespace NadekoBot.Modules.Gambling private static WaifuProfileTitle GetClaimTitle(ulong userId) { - int count = 0; + int count; using (var uow = DbHandler.UnitOfWork()) { count = uow.Waifus.ByClaimerUserId(userId).Count; } - ClaimTitles title = ClaimTitles.Lonely; + ClaimTitles title; if (count == 0) title = ClaimTitles.Lonely; else if (count == 1) @@ -484,13 +489,13 @@ namespace NadekoBot.Modules.Gambling private static WaifuProfileTitle GetAffinityTitle(ulong userId) { - int count = 0; + int count; using (var uow = DbHandler.UnitOfWork()) { count = uow._context.WaifuUpdates.Count(w => w.User.UserId == userId && w.UpdateType == WaifuUpdateType.AffinityChanged); } - AffinityTitles title = AffinityTitles.Pure; + AffinityTitles title; if (count < 1) title = AffinityTitles.Pure; else if (count < 2) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 670980ea..28a00413 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -127,7 +127,7 @@ namespace NadekoBot.Modules.Searches .WithIconUrl("http://i.imgur.com/G46fm8J.png")) .WithDescription(res.Link) .WithImageUrl(res.Link) - .WithTitle(Context.User.Mention); + .WithTitle(Context.User.ToString()); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } catch @@ -157,7 +157,7 @@ namespace NadekoBot.Modules.Searches .WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?")) .WithDescription(source) .WithImageUrl(source) - .WithTitle(Context.User.Mention); + .WithTitle(Context.User.ToString()); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } } @@ -179,7 +179,7 @@ namespace NadekoBot.Modules.Searches .WithIconUrl("http://i.imgur.com/G46fm8J.png")) .WithDescription(res.Link) .WithImageUrl(res.Link) - .WithTitle(Context.User.Mention); + .WithTitle(Context.User.ToString()); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } catch @@ -210,7 +210,7 @@ namespace NadekoBot.Modules.Searches .WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?")) .WithDescription(source) .WithImageUrl(source) - .WithTitle(Context.User.Mention); + .WithTitle(Context.User.ToString()); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 08c355b1..afe8652d 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2198,6 +2198,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Changes Of Heart. + /// + public static string gambling_changes_of_heart { + get { + return ResourceManager.GetString("gambling_changes_of_heart", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Claimed By. + /// + public static string gambling_claimed_by { + get { + return ResourceManager.GetString("gambling_claimed_by", resourceCulture); + } + } + /// /// Looks up a localized string similar to Deck reshuffled.. /// @@ -2234,6 +2252,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Divorces. + /// + public static string gambling_divorces { + get { + return ResourceManager.GetString("gambling_divorces", resourceCulture); + } + } + /// /// Looks up a localized string similar to You guessed it! You won {0}. /// @@ -2324,6 +2351,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Likes. + /// + public static string gambling_likes { + get { + return ResourceManager.GetString("gambling_likes", resourceCulture); + } + } + /// /// Looks up a localized string similar to Awarded {0} to {1} users from {2} role.. /// @@ -2369,6 +2405,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Price. + /// + public static string gambling_price { + get { + return ResourceManager.GetString("gambling_price", resourceCulture); + } + } + /// /// Looks up a localized string similar to Failed starting the race. Another race is probably running.. /// @@ -2406,7 +2451,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to second_larger_than_first. + /// Looks up a localized string similar to Second number must be larger than the first one.. /// public static string gambling_second_larger_than_first { get { @@ -2523,6 +2568,163 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to your affinity is already set to that waifu or you're trying to remove your affinity while not having one.. + /// + public static string gambling_waifu_affinity_already { + get { + return ResourceManager.GetString("gambling_waifu_affinity_already", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to changed their affinity from {0} to {1}. + /// + ///*This is morally questionable.*🤔. + /// + public static string gambling_waifu_affinity_changed { + get { + return ResourceManager.GetString("gambling_waifu_affinity_changed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You must wait {0} hours and {1} minutes in order to change your affinity again.. + /// + public static string gambling_waifu_affinity_cooldown { + get { + return ResourceManager.GetString("gambling_waifu_affinity_cooldown", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Your affinity is reset. You no longer have a person you like.. + /// + public static string gambling_waifu_affinity_reset { + get { + return ResourceManager.GetString("gambling_waifu_affinity_reset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to wants to be {0}'s waifu. Aww <3. + /// + public static string gambling_waifu_affinity_set { + get { + return ResourceManager.GetString("gambling_waifu_affinity_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to claimed {0} as their waifu for {1}!. + /// + public static string gambling_waifu_claimed { + get { + return ResourceManager.GetString("gambling_waifu_claimed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You have divorced a waifu who likes you. You heartless monster. + ///{0} received {1} as a compensation.. + /// + public static string gambling_waifu_divorced_like { + get { + return ResourceManager.GetString("gambling_waifu_divorced_like", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You have divorced a waifu who doesn't like you. You received {0} back.. + /// + public static string gambling_waifu_divorced_not_like { + get { + return ResourceManager.GetString("gambling_waifu_divorced_not_like", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to you can't set affinity to yourself, you egomaniac.. + /// + public static string gambling_waifu_egomaniac { + get { + return ResourceManager.GetString("gambling_waifu_egomaniac", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 🎉 Their love is fulfilled! 🎉 + ///{0}'s new value is {1}!. + /// + public static string gambling_waifu_fulfilled { + get { + return ResourceManager.GetString("gambling_waifu_fulfilled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No waifu is that cheap. You must pay at least {0} to get a waifu, even if their actual value is lower.. + /// + public static string gambling_waifu_isnt_cheap { + get { + return ResourceManager.GetString("gambling_waifu_isnt_cheap", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You must pay {0} or more to claim that waifu!. + /// + public static string gambling_waifu_not_enough { + get { + return ResourceManager.GetString("gambling_waifu_not_enough", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to That waifu is not yours.. + /// + public static string gambling_waifu_not_yours { + get { + return ResourceManager.GetString("gambling_waifu_not_yours", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You can't claim yourself.. + /// + public static string gambling_waifu_not_yourself { + get { + return ResourceManager.GetString("gambling_waifu_not_yourself", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You divorced recently. You must wait {0} hours and {1} minutes to divorce again.. + /// + public static string gambling_waifu_recent_divorce { + get { + return ResourceManager.GetString("gambling_waifu_recent_divorce", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No waifus have been claimed yet.. + /// + public static string gambling_waifus_none { + get { + return ResourceManager.GetString("gambling_waifus_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Top Waifus. + /// + public static string gambling_waifus_top_waifus { + get { + return ResourceManager.GetString("gambling_waifus_top_waifus", resourceCulture); + } + } + /// /// Looks up a localized string similar to Back to ToC. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 8cc5fc3d..4db9ff76 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1073,10 +1073,95 @@ Don't forget to leave your discord name or id in the message. {0} as {1} Won the race and {2}! + + Invalid number specified. You can roll up to {0}-{1} dice at a time. + + + rolled {0} + Someone rolled 35 + + + Dice rolled: {1} + Dice Rolled: 5 + Failed starting the race. Another race is probably running. No race exists on this server + + Second number must be larger than the first one. + + + Changes Of Heart + + + Claimed By + + + Divorces + + + Likes + + + Price + + + No waifus have been claimed yet. + + + Top Waifus + + + your affinity is already set to that waifu or you're trying to remove your affinity while not having one. + + + changed their affinity from {0} to {1}. + +*This is morally questionable.*🤔 + Make sure to get the formatting right, and leave the thinking emoji + + + You must wait {0} hours and {1} minutes in order to change your affinity again. + + + Your affinity is reset. You no longer have a person you like. + + + wants to be {0}'s waifu. Aww <3 + + + claimed {0} as their waifu for {1}! + + + You have divorced a waifu who likes you. You heartless monster. +{0} received {1} as a compensation. + + + You have divorced a waifu who doesn't like you. You received {0} back. + + + you can't set affinity to yourself, you egomaniac. + + + 🎉 Their love is fulfilled! 🎉 +{0}'s new value is {1}! + + + No waifu is that cheap. You must pay at least {0} to get a waifu, even if their actual value is lower. + + + You must pay {0} or more to claim that waifu! + + + That waifu is not yours. + + + You can't claim yourself. + + + You divorced recently. You must wait {0} hours and {1} minutes to divorce again. + \ No newline at end of file From 81675781b42a8d3b9a25f8f456995b1291077881 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 19 Feb 2017 02:12:14 +0100 Subject: [PATCH 321/746] forgot nobody key --- src/NadekoBot/Resources/ResponseStrings.Designer.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index afe8652d..6e3c725a 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2396,6 +2396,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Nobody. + /// + public static string gambling_nobody { + get { + return ResourceManager.GetString("gambling_nobody", resourceCulture); + } + } + /// /// Looks up a localized string similar to You don't have enough {0}. /// From 8b703294f163eac6c6d5c2cf21a4ff0ea3cc6c15 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 19 Feb 2017 15:18:40 +0100 Subject: [PATCH 322/746] acrophobia localizable --- .../Modules/Games/Commands/Acropobia.cs | 162 ++++++++++-------- .../Games/Commands/CleverBotCommands.cs | 2 +- .../Modules/Games/Commands/HangmanCommands.cs | 2 +- .../Modules/Games/Commands/PollCommands.cs | 2 +- .../Games/Commands/SpeedTypingCommands.cs | 2 +- .../Modules/Games/Commands/TicTacToe.cs | 2 +- .../Modules/Games/Commands/TriviaCommands.cs | 2 +- src/NadekoBot/Modules/Games/Games.cs | 31 ++-- .../Resources/ResponseStrings.Designer.cs | 153 +++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 18 ++ 10 files changed, 282 insertions(+), 94 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs index 1ee7adbd..088b95d7 100644 --- a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -19,7 +19,7 @@ namespace NadekoBot.Modules.Games public partial class Games { [Group] - public class Acropobia : ModuleBase + public class Acropobia : NadekoSubmodule { //channelId, game public static ConcurrentDictionary AcrophobiaGames { get; } = new ConcurrentDictionary(); @@ -47,7 +47,7 @@ namespace NadekoBot.Modules.Games } else { - await channel.SendErrorAsync("Acrophobia game is already running in this channel.").ConfigureAwait(false); + await ReplyErrorLocalized("acro_running").ConfigureAwait(false); } } } @@ -61,44 +61,44 @@ namespace NadekoBot.Modules.Games public class AcrophobiaGame { - private readonly ITextChannel channel; - private readonly int time; - private readonly NadekoRandom rng; - private readonly ImmutableArray startingLetters; - private readonly CancellationTokenSource source; + private readonly ITextChannel _channel; + private readonly int _time; + private readonly NadekoRandom _rng; + private readonly ImmutableArray _startingLetters; + private readonly CancellationTokenSource _source; private AcroPhase phase { get; set; } = AcroPhase.Submitting; - private readonly ConcurrentDictionary submissions = new ConcurrentDictionary(); - public IReadOnlyDictionary Submissions => submissions; + private readonly ConcurrentDictionary _submissions = new ConcurrentDictionary(); + public IReadOnlyDictionary Submissions => _submissions; - private readonly ConcurrentHashSet usersWhoSubmitted = new ConcurrentHashSet(); - private readonly ConcurrentHashSet usersWhoVoted = new ConcurrentHashSet(); + private readonly ConcurrentHashSet _usersWhoSubmitted = new ConcurrentHashSet(); + private readonly ConcurrentHashSet _usersWhoVoted = new ConcurrentHashSet(); - private int spamCount = 0; + private int _spamCount; //text, votes - private readonly ConcurrentDictionary votes = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _votes = new ConcurrentDictionary(); private readonly Logger _log; public AcrophobiaGame(ITextChannel channel, int time) { - this._log = LogManager.GetCurrentClassLogger(); + _log = LogManager.GetCurrentClassLogger(); - this.channel = channel; - this.time = time; - this.source = new CancellationTokenSource(); + _channel = channel; + _time = time; + _source = new CancellationTokenSource(); - this.rng = new NadekoRandom(); - var wordCount = rng.Next(3, 6); + _rng = new NadekoRandom(); + var wordCount = _rng.Next(3, 6); var lettersArr = new char[wordCount]; for (int i = 0; i < wordCount; i++) { - var randChar = (char)rng.Next(65, 91); - lettersArr[i] = randChar == 'X' ? (char)rng.Next(65, 88) : randChar; + var randChar = (char)_rng.Next(65, 91); + lettersArr[i] = randChar == 'X' ? (char)_rng.Next(65, 88) : randChar; } - startingLetters = lettersArr.ToImmutableArray(); + _startingLetters = lettersArr.ToImmutableArray(); } private EmbedBuilder GetEmbed() @@ -106,19 +106,19 @@ namespace NadekoBot.Modules.Games var i = 0; return phase == AcroPhase.Submitting - ? new EmbedBuilder().WithOkColor() - .WithTitle("Acrophobia") - .WithDescription($"Game started. Create a sentence with the following acronym: **{string.Join(".", startingLetters)}.**\n") - .WithFooter(efb => efb.WithText("You have " + this.time + " seconds to make a submission.")) + ? new EmbedBuilder().WithOkColor() + .WithTitle(GetText("acrophobia")) + .WithDescription(GetText("acro_started", Format.Bold(string.Join(".", _startingLetters)))) + .WithFooter(efb => efb.WithText(GetText("acro_started_footer", _time))) - : new EmbedBuilder() - .WithOkColor() - .WithTitle("Acrophobia - Submissions Closed") - .WithDescription($@"Acronym was **{string.Join(".", startingLetters)}.** --- -{this.submissions.Aggregate("", (agg, cur) => agg + $"`{++i}.` **{cur.Key.ToLowerInvariant().ToTitleCase()}**\n")} ---") - .WithFooter(efb => efb.WithText("Vote by typing a number of the submission")); + : new EmbedBuilder() + .WithOkColor() + .WithTitle(GetText("acrophobia") + " - " + GetText("submissions_closed")) + .WithDescription(GetText("acro_nym_was", Format.Bold(string.Join(".", _startingLetters)) + "\n" + +$@"-- +{_submissions.Aggregate("",(agg, cur) => agg + $"`{++i}.` **{cur.Key.ToLowerInvariant().ToTitleCase()}**\n")} +--")) + .WithFooter(efb => efb.WithText(GetText("acro_vote"))); } public async Task Run() @@ -127,10 +127,10 @@ namespace NadekoBot.Modules.Games var embed = GetEmbed(); //SUBMISSIONS PHASE - await channel.EmbedAsync(embed).ConfigureAwait(false); + await _channel.EmbedAsync(embed).ConfigureAwait(false); try { - await Task.Delay(time * 1000, source.Token).ConfigureAwait(false); + await Task.Delay(_time * 1000, _source.Token).ConfigureAwait(false); phase = AcroPhase.Idle; } catch (OperationCanceledException) @@ -139,30 +139,32 @@ namespace NadekoBot.Modules.Games } //var i = 0; - if (submissions.Count == 0) + if (_submissions.Count == 0) { - await channel.SendErrorAsync("Acrophobia", "Game ended with no submissions."); + await _channel.SendErrorAsync(GetText("acrophobia"), GetText("acro_ended_no_sub")); return; } - else if (submissions.Count == 1) + if (_submissions.Count == 1) { - await channel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithDescription($"{submissions.First().Value.Mention} is the winner for being the only user who made a submission!") - .WithFooter(efb => efb.WithText(submissions.First().Key.ToLowerInvariant().ToTitleCase()))) - .ConfigureAwait(false); + await _channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithDescription( + GetText("acro_winner_only", + Format.Bold(_submissions.First().Value.ToString()))) + .WithFooter(efb => efb.WithText(_submissions.First().Key.ToLowerInvariant().ToTitleCase()))) + .ConfigureAwait(false); return; } var submissionClosedEmbed = GetEmbed(); - await channel.EmbedAsync(submissionClosedEmbed).ConfigureAwait(false); + await _channel.EmbedAsync(submissionClosedEmbed).ConfigureAwait(false); //VOTING PHASE - this.phase = AcroPhase.Voting; + phase = AcroPhase.Voting; try { //30 secondds for voting - await Task.Delay(30000, source.Token).ConfigureAwait(false); - this.phase = AcroPhase.Idle; + await Task.Delay(30000, _source.Token).ConfigureAwait(false); + phase = AcroPhase.Idle; } catch (OperationCanceledException) { @@ -176,10 +178,10 @@ namespace NadekoBot.Modules.Games try { var msg = arg as SocketUserMessage; - if (msg == null || msg.Author.IsBot || msg.Channel.Id != channel.Id) + if (msg == null || msg.Author.IsBot || msg.Channel.Id != _channel.Id) return; - ++spamCount; + ++_spamCount; var guildUser = (IGuildUser)msg.Author; @@ -187,37 +189,39 @@ namespace NadekoBot.Modules.Games if (phase == AcroPhase.Submitting) { - if (spamCount > 10) + if (_spamCount > 10) { - spamCount = 0; - try { await channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); } + _spamCount = 0; + try { await _channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); } catch { } } var inputWords = input.Split(' '); //get all words - if (inputWords.Length != startingLetters.Length) // number of words must be the same as the number of the starting letters + if (inputWords.Length != _startingLetters.Length) // number of words must be the same as the number of the starting letters return; - for (int i = 0; i < startingLetters.Length; i++) + for (int i = 0; i < _startingLetters.Length; i++) { - var letter = startingLetters[i]; + var letter = _startingLetters[i]; if (!inputWords[i].StartsWith(letter.ToString())) // all first letters must match return; } - if (!usersWhoSubmitted.Add(guildUser.Id)) + if (!_usersWhoSubmitted.Add(guildUser.Id)) return; //try adding it to the list of answers - if (!submissions.TryAdd(input, guildUser)) + if (!_submissions.TryAdd(input, guildUser)) { - usersWhoSubmitted.TryRemove(guildUser.Id); + _usersWhoSubmitted.TryRemove(guildUser.Id); return; } // all good. valid input. answer recorded - await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} submitted their sentence. ({submissions.Count} total)"); + await _channel.SendConfirmAsync(GetText("acrophobia"), + GetText("acro_submit", guildUser.Mention, + _submissions.Count)); try { await msg.DeleteAsync(); @@ -229,10 +233,10 @@ namespace NadekoBot.Modules.Games } else if (phase == AcroPhase.Voting) { - if (spamCount > 10) + if (_spamCount > 10) { - spamCount = 0; - try { await channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); } + _spamCount = 0; + try { await _channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); } catch { } } @@ -248,17 +252,17 @@ namespace NadekoBot.Modules.Games //} int num; - if (int.TryParse(input, out num) && num > 0 && num <= submissions.Count) + if (int.TryParse(input, out num) && num > 0 && num <= _submissions.Count) { - var kvp = submissions.Skip(num - 1).First(); + var kvp = _submissions.Skip(num - 1).First(); usr = kvp.Value; //can't vote for yourself, can't vote multiple times - if (usr.Id == guildUser.Id || !usersWhoVoted.Add(guildUser.Id)) + if (usr.Id == guildUser.Id || !_usersWhoVoted.Add(guildUser.Id)) return; - votes.AddOrUpdate(kvp.Key, 1, (key, old) => ++old); - await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} cast their vote!").ConfigureAwait(false); + _votes.AddOrUpdate(kvp.Key, 1, (key, old) => ++old); + await _channel.SendConfirmAsync(GetText("acrophobia"), + GetText("vote_cast", Format.Bold(guildUser.ToString()))).ConfigureAwait(false); await msg.DeleteAsync().ConfigureAwait(false); - return; } } @@ -271,27 +275,33 @@ namespace NadekoBot.Modules.Games public async Task End() { - if (!votes.Any()) + if (!_votes.Any()) { - await channel.SendErrorAsync("Acrophobia", "No votes cast. Game ended with no winner.").ConfigureAwait(false); + await _channel.SendErrorAsync(GetText("acrophobia"), GetText("no_votes_cast")).ConfigureAwait(false); return; } - var table = votes.OrderByDescending(v => v.Value); + var table = _votes.OrderByDescending(v => v.Value); var winner = table.First(); var embed = new EmbedBuilder().WithOkColor() - .WithTitle("Acrophobia") - .WithDescription($"Winner is {submissions[winner.Key].Mention} with {winner.Value} points.\n") + .WithTitle(GetText("acrophobia")) + .WithDescription(GetText("winner", Format.Bold(_submissions[winner.Key].ToString()), + Format.Bold(winner.Value.ToString()))) .WithFooter(efb => efb.WithText(winner.Key.ToLowerInvariant().ToTitleCase())); - await channel.EmbedAsync(embed).ConfigureAwait(false); + await _channel.EmbedAsync(embed).ConfigureAwait(false); } public void EnsureStopped() { NadekoBot.Client.MessageReceived -= PotentialAcro; - if (!source.IsCancellationRequested) - source.Cancel(); + if (!_source.IsCancellationRequested) + _source.Cancel(); } + + private string GetText(string key, params object[] replacements) + => NadekoModule.GetTextStatic(key, + NadekoBot.Localization.GetCultureInfo(_channel.Guild), + typeof(Games).Name.ToLowerInvariant()); } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs index 0541a4ae..1f33bc2a 100644 --- a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs @@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Games public partial class Games { [Group] - public class CleverBotCommands : ModuleBase + public class CleverBotCommands : NadekoSubmodule { private static Logger _log { get; } diff --git a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs index f3f09da0..0fb8e2f3 100644 --- a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs @@ -13,7 +13,7 @@ namespace NadekoBot.Modules.Games public partial class Games { [Group] - public class HangmanCommands : ModuleBase + public class HangmanCommands : NadekoSubmodule { private static Logger _log { get; } diff --git a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs index 3088546c..1434ee9e 100644 --- a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs @@ -16,7 +16,7 @@ namespace NadekoBot.Modules.Games public partial class Games { [Group] - public class PollCommands : ModuleBase + public class PollCommands : NadekoSubmodule { public static ConcurrentDictionary ActivePolls = new ConcurrentDictionary(); diff --git a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs index fc5a67a2..7dec0992 100644 --- a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs @@ -147,7 +147,7 @@ namespace NadekoBot.Modules.Games } [Group] - public class SpeedTypingCommands : ModuleBase + public class SpeedTypingCommands : NadekoSubmodule { public static List TypingArticles { get; } = new List(); diff --git a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs index de36fe3b..2e115fd2 100644 --- a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs +++ b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs @@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Games { //todo timeout [Group] - public class TicTacToeCommands : ModuleBase + public class TicTacToeCommands : NadekoSubmodule { //channelId/game private static readonly Dictionary _games = new Dictionary(); diff --git a/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs b/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs index 6f43ff83..be7d135c 100644 --- a/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs @@ -14,7 +14,7 @@ namespace NadekoBot.Modules.Games public partial class Games { [Group] - public class TriviaCommands : ModuleBase + public class TriviaCommands : NadekoSubmodule { public static ConcurrentDictionary RunningTrivias { get; } = new ConcurrentDictionary(); diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index 9c67460f..b6b9130b 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -6,6 +6,7 @@ using NadekoBot.Attributes; using System; using System.Linq; using System.Collections.Generic; +using System.Collections.Immutable; using NadekoBot.Extensions; namespace NadekoBot.Modules.Games @@ -13,7 +14,7 @@ namespace NadekoBot.Modules.Games [NadekoModule("Games", ">")] public partial class Games : NadekoModule { - private static string[] _8BallResponses { get; } = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text).ToArray(); + private static readonly ImmutableArray _8BallResponses = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text).ToImmutableArray(); [NadekoCommand, Usage, Description, Aliases] public async Task Choose([Remainder] string list = null) @@ -34,8 +35,8 @@ namespace NadekoBot.Modules.Games return; await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) - .AddField(efb => efb.WithName("❓ Question").WithValue(question).WithIsInline(false)) - .AddField(efb => efb.WithName("🎱 8Ball").WithValue(_8BallResponses[new NadekoRandom().Next(0, _8BallResponses.Length)]).WithIsInline(false))); + .AddField(efb => efb.WithName("❓ " + GetText("question") ).WithValue(question).WithIsInline(false)) + .AddField(efb => efb.WithName("🎱 " + GetText("8ball")).WithValue(_8BallResponses[new NadekoRandom().Next(0, _8BallResponses.Length)]).WithIsInline(false))); } [NadekoCommand, Usage, Description, Aliases] @@ -43,11 +44,15 @@ namespace NadekoBot.Modules.Games { Func GetRPSPick = (p) => { - if (p == 0) - return "🚀"; - if (p == 1) - return "📎"; - return "✂️"; + switch (p) + { + case 0: + return "🚀"; + case 1: + return "📎"; + default: + return "✂️"; + } }; int pick; @@ -71,15 +76,17 @@ namespace NadekoBot.Modules.Games return; } var nadekoPick = new NadekoRandom().Next(0, 3); - var msg = ""; + string msg; if (pick == nadekoPick) - msg = $"It's a draw! Both picked {GetRPSPick(pick)}"; + msg = GetText("rps_draw", GetRPSPick(pick)); else if ((pick == 0 && nadekoPick == 1) || (pick == 1 && nadekoPick == 2) || (pick == 2 && nadekoPick == 0)) - msg = $"{NadekoBot.Client.CurrentUser.Mention} won! {GetRPSPick(nadekoPick)} beats {GetRPSPick(pick)}"; + msg = GetText("rps_win", NadekoBot.Client.CurrentUser.Mention, + GetRPSPick(nadekoPick), GetRPSPick(pick)); else - msg = $"{Context.User.Mention} won! {GetRPSPick(pick)} beats {GetRPSPick(nadekoPick)}"; + msg = GetText("rps_win", Context.User.Mention, GetRPSPick(pick), + GetRPSPick(nadekoPick)); await Context.Channel.SendConfirmAsync(msg).ConfigureAwait(false); } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 6e3c725a..e2d01a97 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2734,6 +2734,159 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to 8ball. + /// + public static string games_8ball { + get { + return ResourceManager.GetString("games_8ball", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game ended with no submissions.. + /// + public static string games_acro_ended_no_sub { + get { + return ResourceManager.GetString("games_acro_ended_no_sub", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No votes cast. Game ended with no winner.. + /// + public static string games_acro_no_votes_cast { + get { + return ResourceManager.GetString("games_acro_no_votes_cast", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Acronym was {0}.. + /// + public static string games_acro_nym_was { + get { + return ResourceManager.GetString("games_acro_nym_was", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Acrophobia game is already running in this channel.. + /// + public static string games_acro_running { + get { + return ResourceManager.GetString("games_acro_running", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game started. Create a sentence with the following acronym: {0}.. + /// + public static string games_acro_started { + get { + return ResourceManager.GetString("games_acro_started", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You have {0} seconds to make a submission.. + /// + public static string games_acro_started_footer { + get { + return ResourceManager.GetString("games_acro_started_footer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} submitted their sentence. ({1} total). + /// + public static string games_acro_submit { + get { + return ResourceManager.GetString("games_acro_submit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Vote by typing a number of the submission. + /// + public static string games_acro_vote { + get { + return ResourceManager.GetString("games_acro_vote", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} cast their vote!. + /// + public static string games_acro_vote_cast { + get { + return ResourceManager.GetString("games_acro_vote_cast", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Winner is {0} with {1} points.. + /// + public static string games_acro_winner { + get { + return ResourceManager.GetString("games_acro_winner", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} is the winner for being the only user who made a submission!. + /// + public static string games_acro_winner_only { + get { + return ResourceManager.GetString("games_acro_winner_only", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Acrophobia. + /// + public static string games_acrophobia { + get { + return ResourceManager.GetString("games_acrophobia", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Question. + /// + public static string games_question { + get { + return ResourceManager.GetString("games_question", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to It's a draw! Both picked {0}. + /// + public static string games_rps_draw { + get { + return ResourceManager.GetString("games_rps_draw", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} won! {1} beats {2}. + /// + public static string games_rps_win { + get { + return ResourceManager.GetString("games_rps_win", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Submissions Closed. + /// + public static string games_submissions_closed { + get { + return ResourceManager.GetString("games_submissions_closed", resourceCulture); + } + } + /// /// Looks up a localized string similar to Back to ToC. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 4db9ff76..90024cd2 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1105,6 +1105,9 @@ Don't forget to leave your discord name or id in the message. Likes + + Nobody + Price @@ -1164,4 +1167,19 @@ Don't forget to leave your discord name or id in the message. You divorced recently. You must wait {0} hours and {1} minutes to divorce again. + + 8ball + + + Acrophobia game is already running in this channel. + + + Question + + + It's a draw! Both picked {0} + + + {0} won! {1} beats {2} + \ No newline at end of file From 06cafa1296a39385d07ef69deab3c46267e77004 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 20 Feb 2017 23:46:34 +0100 Subject: [PATCH 323/746] more localization, fixes, etc, no idea exactly what, rategirl is commented out until i fix the last bug --- ...dekoModule.cs => NadekoModuleAttribute.cs} | 0 src/NadekoBot/DataStructures/AsyncLazy.cs | 23 +++ .../Modules/Administration/Administration.cs | 2 +- .../Administration/Commands/LogCommand.cs | 2 +- .../Modules/ClashOfClans/ClashOfClans.cs | 2 +- .../Modules/ClashOfClans/Extensions.cs | 2 +- .../CustomReactions/CustomReactions.cs | 2 +- .../Modules/Gambling/Commands/AnimalRacing.cs | 4 +- .../Gambling/Commands/DiceRollCommand.cs | 5 +- .../Modules/Gambling/Commands/DrawCommand.cs | 2 +- .../Gambling/Commands/FlipCoinCommand.cs | 19 +- .../Modules/Gambling/Commands/Slots.cs | 105 ++++------- src/NadekoBot/Modules/Gambling/Gambling.cs | 2 +- .../Modules/Games/Commands/Acropobia.cs | 2 +- src/NadekoBot/Modules/Games/Games.cs | 166 +++++++++++++++++- src/NadekoBot/Modules/Help/Help.cs | 2 +- src/NadekoBot/Modules/Music/Music.cs | 2 +- src/NadekoBot/Modules/NSFW/NSFW.cs | 2 +- src/NadekoBot/Modules/NadekoModule.cs | 6 +- .../Modules/Permissions/Permissions.cs | 2 +- src/NadekoBot/Modules/Pokemon/Pokemon.cs | 2 +- src/NadekoBot/Modules/Searches/Searches.cs | 15 +- src/NadekoBot/Modules/Utility/Utility.cs | 7 +- src/NadekoBot/NadekoBot.cs | 3 + .../Resources/CommandStrings.Designer.cs | 81 ++++++--- src/NadekoBot/Resources/CommandStrings.resx | 13 +- src/NadekoBot/Resources/ResponseStrings.resx | 36 ++++ src/NadekoBot/Services/IImagesService.cs | 2 + src/NadekoBot/Services/Impl/ImagesService.cs | 6 + src/NadekoBot/_Extensions/Extensions.cs | 27 ++- src/NadekoBot/data/images/wifematrix.png | Bin 0 -> 34050 bytes src/NadekoBot/project.json | 7 +- 32 files changed, 393 insertions(+), 158 deletions(-) rename src/NadekoBot/Attributes/{NadekoModule.cs => NadekoModuleAttribute.cs} (100%) create mode 100644 src/NadekoBot/DataStructures/AsyncLazy.cs create mode 100644 src/NadekoBot/data/images/wifematrix.png diff --git a/src/NadekoBot/Attributes/NadekoModule.cs b/src/NadekoBot/Attributes/NadekoModuleAttribute.cs similarity index 100% rename from src/NadekoBot/Attributes/NadekoModule.cs rename to src/NadekoBot/Attributes/NadekoModuleAttribute.cs diff --git a/src/NadekoBot/DataStructures/AsyncLazy.cs b/src/NadekoBot/DataStructures/AsyncLazy.cs new file mode 100644 index 00000000..40800755 --- /dev/null +++ b/src/NadekoBot/DataStructures/AsyncLazy.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.DataStructures +{ + public class AsyncLazy : Lazy> + { + public AsyncLazy(Func valueFactory) : + base(() => Task.Factory.StartNew(valueFactory)) + { } + + public AsyncLazy(Func> taskFactory) : + base(() => Task.Factory.StartNew(taskFactory).Unwrap()) + { } + + public TaskAwaiter GetAwaiter() { return Value.GetAwaiter(); } + } + +} diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 3f52ac17..405485dd 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -16,7 +16,7 @@ using NLog; namespace NadekoBot.Modules.Administration { [NadekoModule("Administration", ".")] - public partial class Administration : NadekoModule + public partial class Administration : NadekoTopLevelModule { private static ConcurrentHashSet deleteMessagesOnCommand { get; } diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index 95c4538a..88d512e7 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -1068,7 +1068,7 @@ namespace NadekoBot.Modules.Administration public static class GuildExtensions { public static string GetLogText(this IGuild guild, string key, params object[] replacements) - => NadekoModule.GetTextStatic(key, + => NadekoTopLevelModule.GetTextStatic(key, NadekoBot.Localization.GetCultureInfo(guild), typeof(Administration).Name.ToLowerInvariant(), replacements); diff --git a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs index 37f07efa..043a12b2 100644 --- a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs +++ b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs @@ -17,7 +17,7 @@ using NLog; namespace NadekoBot.Modules.ClashOfClans { [NadekoModule("ClashOfClans", ",")] - public class ClashOfClans : NadekoModule + public class ClashOfClans : NadekoTopLevelModule { public static ConcurrentDictionary> ClashWars { get; set; } = new ConcurrentDictionary>(); diff --git a/src/NadekoBot/Modules/ClashOfClans/Extensions.cs b/src/NadekoBot/Modules/ClashOfClans/Extensions.cs index 032d3bcd..5756d3db 100644 --- a/src/NadekoBot/Modules/ClashOfClans/Extensions.cs +++ b/src/NadekoBot/Modules/ClashOfClans/Extensions.cs @@ -135,7 +135,7 @@ namespace NadekoBot.Modules.ClashOfClans public static string Localize(this ClashWar cw, string key) { - return NadekoModule.GetTextStatic(key, + return NadekoTopLevelModule.GetTextStatic(key, NadekoBot.Localization.GetCultureInfo(cw.Channel?.GuildId), typeof(ClashOfClans).Name.ToLowerInvariant()); } diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index ebeb4922..efd3717e 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -17,7 +17,7 @@ using NadekoBot.DataStructures; namespace NadekoBot.Modules.CustomReactions { [NadekoModule("CustomReactions", ".")] - public class CustomReactions : NadekoModule + public class CustomReactions : NadekoTopLevelModule { private static CustomReaction[] _globalReactions = new CustomReaction[] { }; public static CustomReaction[] GlobalReactions => _globalReactions; diff --git a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs index 39c749d2..040e657e 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs @@ -272,12 +272,12 @@ namespace NadekoBot.Modules.Gambling } private string GetText(string text) - => NadekoModule.GetTextStatic(text, + => NadekoTopLevelModule.GetTextStatic(text, NadekoBot.Localization.GetCultureInfo(_raceChannel.Guild), typeof(Gambling).Name.ToLowerInvariant()); private string GetText(string text, params object[] replacements) - => NadekoModule.GetTextStatic(text, + => NadekoTopLevelModule.GetTextStatic(text, NadekoBot.Localization.GetCultureInfo(_raceChannel.Guild), typeof(Gambling).Name.ToLowerInvariant(), replacements); diff --git a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs index a75827e7..721b5b4e 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs @@ -10,6 +10,7 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; +using ImageSharp.Formats; using Image = ImageSharp.Image; namespace NadekoBot.Modules.Gambling @@ -35,7 +36,7 @@ namespace NadekoBot.Modules.Gambling var imageStream = await Task.Run(() => { var ms = new MemoryStream(); - new[] { GetDice(num1), GetDice(num2) }.Merge().SaveAsPng(ms); + new[] { GetDice(num1), GetDice(num2) }.Merge().Save(ms); ms.Position = 0; return ms; }).ConfigureAwait(false); @@ -120,7 +121,7 @@ namespace NadekoBot.Modules.Gambling var bitmap = dice.Merge(); var ms = new MemoryStream(); - bitmap.SaveAsPng(ms); + bitmap.Save(ms); ms.Position = 0; await Context.Channel.SendFileAsync(ms, "dice.png", Context.User.Mention + diff --git a/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs index 7471f7d0..b7a68ece 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/DrawCommand.cs @@ -49,7 +49,7 @@ namespace NadekoBot.Modules.Gambling images.Add(new Image(stream)); } MemoryStream bitmapStream = new MemoryStream(); - images.Merge().SaveAsPng(bitmapStream); + images.Merge().Save(bitmapStream); bitmapStream.Position = 0; var toSend = $"{Context.User.Mention}"; if (cardObjects.Count == 5) diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs index 973bc90e..40b8a735 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs @@ -52,17 +52,22 @@ namespace NadekoBot.Modules.Gambling return; } var imgs = new Image[count]; - using (var heads = _images.Heads.ToStream()) - using(var tails = _images.Tails.ToStream()) + for (var i = 0; i < count; i++) { - for (var i = 0; i < count; i++) + using (var heads = _images.Heads.ToStream()) + using (var tails = _images.Tails.ToStream()) { - imgs[i] = rng.Next(0, 10) < 5 ? - new Image(heads) : - new Image(tails); + if (rng.Next(0, 10) < 5) + { + imgs[i] = new Image(heads); + } + else + { + imgs[i] = new Image(tails); + } } - await Context.Channel.SendFileAsync(imgs.Merge().ToStream(), $"{count} coins.png").ConfigureAwait(false); } + await Context.Channel.SendFileAsync(imgs.Merge().ToStream(), $"{count} coins.png").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs index c298a9b4..ea20b4b1 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs @@ -1,5 +1,6 @@ using Discord; using Discord.Commands; +using ImageSharp; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; @@ -163,83 +164,43 @@ namespace NadekoBot.Modules.Gambling var result = SlotMachine.Pull(); int[] numbers = result.Numbers; - using (var bgPixels = bgImage.Lock()) + + for (int i = 0; i < 3; i++) { - for (int i = 0; i < 3; i++) + using (var file = _images.SlotEmojis[numbers[i]].ToStream()) + using (var randomImage = new ImageSharp.Image(file)) { - using (var file = _images.SlotEmojis[numbers[i]].ToStream()) - { - 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]; - } - } - } - } + bgImage.DrawImage(randomImage, 100, default(Size), new Point(95 + 142 * i, 330)); } - - var won = amount * result.Multiplier; - var printWon = won; - var n = 0; - do - { - var digit = printWon % 10; - using (var fs = NadekoBot.Images.SlotNumbers[digit].ToStream()) - { - 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 = _images.SlotNumbers[digit].ToStream()) - { - 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 won = amount * result.Multiplier; + var printWon = won; + var n = 0; + do + { + var digit = printWon % 10; + using (var fs = NadekoBot.Images.SlotNumbers[digit].ToStream()) + using (var img = new ImageSharp.Image(fs)) + { + bgImage.DrawImage(img, 100, default(Size), new Point(230 - n * 16, 462)); + } + n++; + } while ((printWon /= 10) != 0); + + var printAmount = amount; + n = 0; + do + { + var digit = printAmount % 10; + using (var fs = _images.SlotNumbers[digit].ToStream()) + using (var img = new ImageSharp.Image(fs)) + { + bgImage.DrawImage(img, 100, default(Size), new Point(395 - n * 16, 462)); + } + n++; + } while ((printAmount /= 10) != 0); + var msg = GetText("better_luck"); if (result.Multiplier != 0) { diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 3cdd7165..0db8e198 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -12,7 +12,7 @@ using System.Collections.Generic; namespace NadekoBot.Modules.Gambling { [NadekoModule("Gambling", "$")] - public partial class Gambling : NadekoModule + public partial class Gambling : NadekoTopLevelModule { public static string CurrencyName { get; set; } public static string CurrencyPluralName { get; set; } diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs index 088b95d7..aa11f1c6 100644 --- a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -299,7 +299,7 @@ $@"-- } private string GetText(string key, params object[] replacements) - => NadekoModule.GetTextStatic(key, + => NadekoTopLevelModule.GetTextStatic(key, NadekoBot.Localization.GetCultureInfo(_channel.Guild), typeof(Games).Name.ToLowerInvariant()); } diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index b6b9130b..88a663df 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -4,18 +4,33 @@ using NadekoBot.Services; using System.Threading.Tasks; using NadekoBot.Attributes; using System; +using System.Collections.Concurrent; using System.Linq; using System.Collections.Generic; using System.Collections.Immutable; +using System.IO; +using System.Threading; using NadekoBot.Extensions; +using System.Net.Http; +using ImageSharp; +using NadekoBot.DataStructures; +using NLog; +using ImageSharp.Drawing.Pens; +using SixLabors.Shapes; namespace NadekoBot.Modules.Games { [NadekoModule("Games", ">")] - public partial class Games : NadekoModule + public partial class Games : NadekoTopLevelModule { private static readonly ImmutableArray _8BallResponses = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text).ToImmutableArray(); + private static readonly Timer _t = new Timer((_) => + { + _girlRatings.Clear(); + + }, null, TimeSpan.FromDays(1), TimeSpan.FromDays(1)); + [NadekoCommand, Usage, Description, Aliases] public async Task Choose([Remainder] string list = null) { @@ -91,6 +106,155 @@ namespace NadekoBot.Modules.Games await Context.Channel.SendConfirmAsync(msg).ConfigureAwait(false); } + private static readonly ConcurrentDictionary _girlRatings = new ConcurrentDictionary(); + + public class GirlRating + { + private static Logger _log = LogManager.GetCurrentClassLogger(); + + public double Crazy { get; } + public double Hot { get; } + public int Roll { get; } + public string Advice { get; } + public AsyncLazy Url { get; } + + public GirlRating(double crazy, double hot, int roll, string advice) + { + Crazy = crazy; + Hot = hot; + Roll = roll; + Advice = advice; // convenient to have it here, even though atm there are only few different ones. + + Url = new AsyncLazy(async () => + { + try + { + using (var ms = new MemoryStream(NadekoBot.Images.WifeMatrix.ToArray(), false)) + using (var img = new ImageSharp.Image(ms)) + { + var clr = new ImageSharp.Color(0x0000ff); + const int minx = 35; + const int miny = 385; + const int length = 345; + + var pointx = (int)(minx + length * (Hot / 10)); + var pointy = (int)(miny - length * ((Crazy - 4) / 6)); + + var p = new Pen(ImageSharp.Color.Red, 5); + + img.Draw(p, new SixLabors.Shapes.Ellipse(200, 200, 5, 5)); + + string url; + using (var http = new HttpClient()) + using (var imgStream = new MemoryStream()) + { + img.Save(imgStream); + var byteContent = new ByteArrayContent(imgStream.ToArray()); + http.AddFakeHeaders(); + + var reponse = await http.PutAsync("https://transfer.sh/img.png", byteContent); + url = await reponse.Content.ReadAsStringAsync(); + } + return url; + } + } + catch (Exception ex) + { + _log.Warn(ex); + return null; + } + }); + } + } + + //[NadekoCommand, Usage, Description, Aliases] + //[RequireContext(ContextType.Guild)] + //public async Task RateGirl(IGuildUser usr) + //{ + // var gr = _girlRatings.GetOrAdd(usr.Id, GetGirl); + // var img = await gr.Url; + // await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + // .WithTitle("Girl Rating For " + usr) + // .AddField(efb => efb.WithName("Hot").WithValue(gr.Hot.ToString("F2")).WithIsInline(true)) + // .AddField(efb => efb.WithName("Crazy").WithValue(gr.Crazy.ToString("F2")).WithIsInline(true)) + // .AddField(efb => efb.WithName("Advice").WithValue(gr.Advice).WithIsInline(false)) + // .WithImageUrl(img)).ConfigureAwait(false); + //} + + private double NextDouble(double x, double y) + { + var rng = new Random(); + return rng.NextDouble() * (y - x) + x; + } + + private GirlRating GetGirl(ulong uid) + { + var rng = new NadekoRandom(); + + var roll = rng.Next(1, 1001); + + double hot; + double crazy; + string advice; + if (roll < 500) + { + hot = NextDouble(0, 5); + crazy = NextDouble(4, 10); + advice = + "This is your NO-GO ZONE. We do not hang around, and date, and marry women who are atleast, in our mind, a 5. " + + "So, this is your no-go zone. You don't go here. You just rule this out. Life is better this way, that's the way it is."; + } + else if (roll < 750) + { + hot = NextDouble(5, 8); + crazy = NextDouble(4, .6 * hot + 4); + advice = "Above a 5, and to about an 8, and below the crazy line - this is your FUN ZONE. You can " + + "hang around here, and meet these girls and spend time with them. Keep in mind, while you're " + + "in the fun zone, you want to move OUT of the fun zone to a more permanent location. " + + "These girls are most of the time not crazy."; + } + else if (roll < 900) + { + hot = NextDouble(5, 10); + crazy = NextDouble(.61 * hot + 4, 10); + advice = "Above the crazy line - it's the DANGER ZONE. This is redheads, strippers, anyone named Tiffany, " + + "hairdressers... This is where your car gets keyed, you get bunny in the pot, your tires get slashed, " + + "and you wind up in jail."; + } + else if (roll < 951) + { + hot = NextDouble(8, 10); + crazy = NextDouble(4, 10); + advice = "Below the crazy line, above an 8 hot, but still about 7 crazy. This is your DATE ZONE. " + + "You can stay in the date zone indefinitely. These are the girls you introduce to your friends and your family. " + + "They're good looking, and they're reasonably not crazy most of the time. You can stay here indefinitely."; + } + else if (roll < 990) + { + hot = NextDouble(8, 10); + crazy = NextDouble(5, 7); + advice = "Above an 8 hot, and between about 7 and a 5 crazy - this is WIFE ZONE. You you meet this girl, you should consider long-term " + + "relationship. Rare."; + } + else if (roll < 999) + { + hot = NextDouble(8, 10); + crazy = NextDouble(2, 3.99d); + advice = "You've met a girl she's above 8 hot, and not crazy at all (below 4)... totally cool?" + + " You should be careful. That's a dude. It's a tranny."; + } + else + { + hot = NextDouble(8, 10); + crazy = NextDouble(4, 5); + advice = "Below 5 crazy, and above 8 hot, this is the UNICORN ZONE, these things don't exist." + + "If you find a unicorn, please capture it safely, keep it alive, we'd like to study it, " + + "and maybe look at how to replicate that."; + } + + return new GirlRating(crazy, hot, roll, advice); + } + [NadekoCommand, Usage, Description, Aliases] public async Task Linux(string guhnoo, string loonix) { diff --git a/src/NadekoBot/Modules/Help/Help.cs b/src/NadekoBot/Modules/Help/Help.cs index c22a9789..d6ceb1bd 100644 --- a/src/NadekoBot/Modules/Help/Help.cs +++ b/src/NadekoBot/Modules/Help/Help.cs @@ -13,7 +13,7 @@ using System.Collections.Generic; namespace NadekoBot.Modules.Help { [NadekoModule("Help", "-")] - public class Help : NadekoModule + public class Help : NadekoTopLevelModule { private static string helpString { get; } = NadekoBot.BotConfig.HelpString; public static string HelpString => String.Format(helpString, NadekoBot.Credentials.ClientId, NadekoBot.ModulePrefixes[typeof(Help).Name]); diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 4fbc8701..a7b46269 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Music { [NadekoModule("Music", "!!")] [DontAutoLoad] - public partial class Music : NadekoModule + public partial class Music : NadekoTopLevelModule { public static ConcurrentDictionary MusicPlayers { get; } = new ConcurrentDictionary(); diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index 5538e8d6..53a3f3bb 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -17,7 +17,7 @@ using System.Collections.Concurrent; namespace NadekoBot.Modules.NSFW { [NadekoModule("NSFW", "~")] - public class NSFW : NadekoModule + public class NSFW : NadekoTopLevelModule { private static readonly ConcurrentDictionary AutoHentaiTimers = new ConcurrentDictionary(); diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index d76a483c..ea4a0049 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; namespace NadekoBot.Modules { - public abstract class NadekoModule : ModuleBase + public abstract class NadekoTopLevelModule : ModuleBase { protected readonly Logger _log; protected CultureInfo _cultureInfo; @@ -17,7 +17,7 @@ namespace NadekoBot.Modules public readonly string ModuleTypeName; public readonly string LowerModuleTypeName; - protected NadekoModule(bool isTopLevelModule = true) + protected NadekoTopLevelModule(bool isTopLevelModule = true) { //if it's top level module ModuleTypeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name; @@ -120,7 +120,7 @@ namespace NadekoBot.Modules } } - public abstract class NadekoSubmodule : NadekoModule + public abstract class NadekoSubmodule : NadekoTopLevelModule { protected NadekoSubmodule() : base(false) { diff --git a/src/NadekoBot/Modules/Permissions/Permissions.cs b/src/NadekoBot/Modules/Permissions/Permissions.cs index 407ca2a2..3e8ecd13 100644 --- a/src/NadekoBot/Modules/Permissions/Permissions.cs +++ b/src/NadekoBot/Modules/Permissions/Permissions.cs @@ -15,7 +15,7 @@ using NLog; namespace NadekoBot.Modules.Permissions { [NadekoModule("Permissions", ";")] - public partial class Permissions : NadekoModule + public partial class Permissions : NadekoTopLevelModule { public class PermissionCache { diff --git a/src/NadekoBot/Modules/Pokemon/Pokemon.cs b/src/NadekoBot/Modules/Pokemon/Pokemon.cs index 08d3976f..c81091c7 100644 --- a/src/NadekoBot/Modules/Pokemon/Pokemon.cs +++ b/src/NadekoBot/Modules/Pokemon/Pokemon.cs @@ -16,7 +16,7 @@ using System.Collections.Concurrent; namespace NadekoBot.Modules.Pokemon { [NadekoModule("Pokemon", ">")] - public class Pokemon : NadekoModule + public class Pokemon : NadekoTopLevelModule { private static readonly List _pokemonTypes = new List(); private static readonly ConcurrentDictionary _stats = new ConcurrentDictionary(); diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 28a00413..ef47301c 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -1,5 +1,4 @@ using Discord; -using Discord.Commands; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; @@ -8,27 +7,25 @@ using System.Text; using System.Net.Http; using NadekoBot.Services; using System.Threading.Tasks; -using NadekoBot.Attributes; -using System.Text.RegularExpressions; using System.Net; using NadekoBot.Modules.Searches.Models; using System.Collections.Generic; -using ImageSharp; using NadekoBot.Extensions; using System.IO; using NadekoBot.Modules.Searches.Commands.OMDB; using NadekoBot.Modules.Searches.Commands.Models; -using AngleSharp.Parser.Html; using AngleSharp; using AngleSharp.Dom.Html; using AngleSharp.Dom; using System.Xml; -using System.Xml.Linq; +using Configuration = AngleSharp.Configuration; +using NadekoBot.Attributes; +using Discord.Commands; namespace NadekoBot.Modules.Searches { [NadekoModule("Searches", "~")] - public partial class Searches : NadekoModule + public partial class Searches : NadekoTopLevelModule { [NadekoCommand, Usage, Description, Aliases] public async Task Weather([Remainder] string query) @@ -396,7 +393,7 @@ namespace NadekoBot.Modules.Searches msg = "⚠ Found over 4 images. Showing random 4."; } var ms = new MemoryStream(); - await Task.Run(() => images.AsEnumerable().Merge().SaveAsPng(ms)); + await Task.Run(() => images.AsEnumerable().Merge().Save(ms)); ms.Position = 0; await Context.Channel.SendFileAsync(ms, arg + ".png", msg).ConfigureAwait(false); } @@ -625,7 +622,7 @@ namespace NadekoBot.Modules.Searches return; var img = new ImageSharp.Image(50, 50); - img.BackgroundColor(new ImageSharp.Color(color)); + //img.FillPolygon(new ImageSharp, new ImageSharp.Color(color)); await Context.Channel.SendFileAsync(img.ToStream(), $"{color}.png").ConfigureAwait(false); ; } diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index d627d956..8d3a95c4 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Threading.Tasks; using System.Text; using NadekoBot.Extensions; -using System.Text.RegularExpressions; using System.Reflection; using NadekoBot.Services.Impl; using System.Net.Http; @@ -21,7 +20,7 @@ using NadekoBot.Services; namespace NadekoBot.Modules.Utility { [NadekoModule("Utility", ".")] - public partial class Utility : NadekoModule + public partial class Utility : NadekoTopLevelModule { private static ConcurrentDictionary rotatingRoleColors = new ConcurrentDictionary(); @@ -122,10 +121,10 @@ namespace NadekoBot.Modules.Utility } return; } - + var hexColors = hexes.Select(hex => { - try { return (ImageSharp.Color?)new ImageSharp.Color(hex.Replace("#", "")); } catch { return null; } + try { return (ImageSharp.Color?)ImageSharp.Color.FromHex(hex.Replace("#", "")); } catch { return null; } }) .Where(c => c != null) .Select(c => c.Value) diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 40d71602..7da895d6 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -60,6 +60,9 @@ namespace NadekoBot OkColor = new Color(Convert.ToUInt32(BotConfig.OkColor, 16)); ErrorColor = new Color(Convert.ToUInt32(BotConfig.ErrorColor, 16)); } + + //ImageSharp.Configuration.Default.AddImageFormat(new ImageSharp.Formats.PngFormat()); + //ImageSharp.Configuration.Default.AddImageFormat(new ImageSharp.Formats.JpegFormat()); } public async Task RunAsync(params string[] args) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 579382ba..e6390b66 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -2381,33 +2381,6 @@ namespace NadekoBot.Resources { } } - /// - /// Looks up a localized string similar to qsearch. - /// - public static string searchquote_cmd { - get { - return ResourceManager.GetString("searchquote_cmd", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Shows a random quote for a keyword that contains any text specified in the search.. - /// - public static string searchquote_desc { - get { - return ResourceManager.GetString("searchquote_desc", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to `{0}qsearch keyword text`. - /// - public static string searchquote_usage { - get { - return ResourceManager.GetString("searchquote_usage", resourceCulture); - } - } - /// /// Looks up a localized string similar to delmsgoncmd. /// @@ -5756,6 +5729,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to rategirl. + /// + public static string rategirl_cmd { + get { + return ResourceManager.GetString("rategirl_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use the universal hot-crazy wife zone matrix to determine the girl's worth. It is everything young men need to know about women. At any moment in time, any woman you have previously located on this chart can vanish from that location and appear anywhere else on the chart.. + /// + public static string rategirl_desc { + get { + return ResourceManager.GetString("rategirl_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}rategirl @SomeGurl`. + /// + public static string rategirl_usage { + get { + return ResourceManager.GetString("rategirl_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to reloadimages. /// @@ -6701,6 +6701,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to qsearch. + /// + public static string searchquote_cmd { + get { + return ResourceManager.GetString("searchquote_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows a random quote for a keyword that contains any text specified in the search.. + /// + public static string searchquote_desc { + get { + return ResourceManager.GetString("searchquote_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}qsearch keyword text`. + /// + public static string searchquote_usage { + get { + return ResourceManager.GetString("searchquote_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to send. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 732c0087..c661db7d 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -1151,7 +1151,7 @@ `{0}qsearch keyword text` - + deletequote delq @@ -3141,4 +3141,13 @@ `{0}langli` - + + rategirl + + + Use the universal hot-crazy wife zone matrix to determine the girl's worth. It is everything young men need to know about women. At any moment in time, any woman you have previously located on this chart can vanish from that location and appear anywhere else on the chart. + + + `{0}rategirl @SomeGurl` + + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 90024cd2..c1eb0a5d 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1170,9 +1170,42 @@ Don't forget to leave your discord name or id in the message. 8ball + + Acrophobia + + + Game ended with no submissions. + + + No votes cast. Game ended with no winner. + + + Acronym was {0}. + Acrophobia game is already running in this channel. + + Game started. Create a sentence with the following acronym: {0}. + + + You have {0} seconds to make a submission. + + + {0} submitted their sentence. ({1} total) + + + Vote by typing a number of the submission + + + {0} cast their vote! + + + Winner is {0} with {1} points. + + + {0} is the winner for being the only user who made a submission! + Question @@ -1182,4 +1215,7 @@ Don't forget to leave your discord name or id in the message. {0} won! {1} beats {2} + + Submissions Closed + \ No newline at end of file diff --git a/src/NadekoBot/Services/IImagesService.cs b/src/NadekoBot/Services/IImagesService.cs index 81e21907..e3b25458 100644 --- a/src/NadekoBot/Services/IImagesService.cs +++ b/src/NadekoBot/Services/IImagesService.cs @@ -21,6 +21,8 @@ namespace NadekoBot.Services ImmutableArray> SlotEmojis { get; } ImmutableArray> SlotNumbers { get; } + ImmutableArray WifeMatrix { get; } + Task Reload(); } } diff --git a/src/NadekoBot/Services/Impl/ImagesService.cs b/src/NadekoBot/Services/Impl/ImagesService.cs index 77ee9f26..567d63f2 100644 --- a/src/NadekoBot/Services/Impl/ImagesService.cs +++ b/src/NadekoBot/Services/Impl/ImagesService.cs @@ -28,6 +28,8 @@ namespace NadekoBot.Services.Impl private const string slotNumbersPath = basePath + "slots/numbers/"; private const string slotEmojisPath = basePath + "slots/emojis/"; + private const string _wifeMatrixPath = basePath + "wifematrix.png"; + public ImmutableArray Heads { get; private set; } public ImmutableArray Tails { get; private set; } @@ -41,6 +43,8 @@ namespace NadekoBot.Services.Impl public ImmutableArray> SlotNumbers { get; private set; } public ImmutableArray> SlotEmojis { get; private set; } + public ImmutableArray WifeMatrix { get; private set; } + private ImagesService() { _log = LogManager.GetCurrentClassLogger(); @@ -86,6 +90,8 @@ namespace NadekoBot.Services.Impl .Select(x => File.ReadAllBytes(x).ToImmutableArray()) .ToImmutableArray(); + WifeMatrix = File.ReadAllBytes(_wifeMatrixPath).ToImmutableArray(); + sw.Stop(); _log.Info($"Images loaded after {sw.Elapsed.TotalSeconds:F2}s!"); return sw.Elapsed; diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index 4c32a542..8dbdf02b 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -22,7 +22,11 @@ namespace NadekoBot.Extensions private const string arrow_right = "➡"; public static Stream ToStream(this IEnumerable bytes, bool canWrite = false) - => new MemoryStream(bytes as byte[] ?? bytes.ToArray(), canWrite); + { + var ms = new MemoryStream(bytes as byte[] ?? bytes.ToArray(), canWrite); + ms.Seek(0, SeekOrigin.Begin); + return ms; + } /// /// danny kamisama @@ -398,22 +402,15 @@ namespace NadekoBot.Extensions public static ImageSharp.Image Merge(this IEnumerable images) { - var imgList = images.ToList(); + var imgs = images.ToArray(); - var canvas = new ImageSharp.Image(imgList.Sum(img => img.Width), imgList.Max(img => img.Height)); + var canvas = new ImageSharp.Image(imgs.Sum(img => img.Width), imgs.Max(img => img.Height)); - var canvasPixels = canvas.Lock(); - int offsetX = 0; - foreach (var img in imgList.Select(img => img.Lock())) + var xOffset = 0; + for (int i = 0; i < imgs.Length; i++) { - for (int i = 0; i < img.Width; i++) - { - for (int j = 0; j < img.Height; j++) - { - canvasPixels[i + offsetX, j] = img[i, j]; - } - } - offsetX += img.Width; + canvas.DrawImage(imgs[i], 100, default(Size), new Point(xOffset, 0)); + xOffset += imgs[i].Bounds.Width; } return canvas; @@ -422,7 +419,7 @@ namespace NadekoBot.Extensions public static Stream ToStream(this ImageSharp.Image img) { var imageStream = new MemoryStream(); - img.SaveAsPng(imageStream); + img.Save(imageStream); imageStream.Position = 0; return imageStream; } diff --git a/src/NadekoBot/data/images/wifematrix.png b/src/NadekoBot/data/images/wifematrix.png new file mode 100644 index 0000000000000000000000000000000000000000..6e0b8db9b6f25e0175b76a163f7ce20929a78fba GIT binary patch literal 34050 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 literal 0 HcmV?d00001 diff --git a/src/NadekoBot/project.json b/src/NadekoBot/project.json index 88ebdd52..d6b8ad6c 100644 --- a/src/NadekoBot/project.json +++ b/src/NadekoBot/project.json @@ -23,7 +23,12 @@ "Google.Apis.Urlshortener.v1": "1.19.0.138", "Google.Apis.YouTube.v3": "1.20.0.701", "Google.Apis.Customsearch.v1": "1.20.0.466", - "ImageSharp": "1.0.0-alpha-000079", + "ImageSharp": "1.0.0-alpha2-00090", + "ImageSharp.Processing": "1.0.0-alpha2-00078", + "ImageSharp.Formats.Png": "1.0.0-alpha2-00086", + "ImageSharp.Drawing": "1.0.0-alpha2-00090", + "ImageSharp.Drawing.Paths": "1.0.0-alpha2-00040", + //"ImageSharp.Formats.Jpeg": "1.0.0-alpha2-00090", "Microsoft.EntityFrameworkCore": "1.1.0", "Microsoft.EntityFrameworkCore.Design": "1.1.0", "Microsoft.EntityFrameworkCore.Sqlite": "1.1.0", From ed656f503bb9b0211c033298e2494c11e322030a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Feb 2017 01:00:53 +0100 Subject: [PATCH 324/746] ~clr fixed --- src/NadekoBot/Modules/Searches/Searches.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index ef47301c..096a171c 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -21,6 +21,7 @@ using System.Xml; using Configuration = AngleSharp.Configuration; using NadekoBot.Attributes; using Discord.Commands; +using ImageSharp.Processing.Processors; namespace NadekoBot.Modules.Searches { @@ -622,7 +623,7 @@ namespace NadekoBot.Modules.Searches return; var img = new ImageSharp.Image(50, 50); - //img.FillPolygon(new ImageSharp, new ImageSharp.Color(color)); + img.ApplyProcessor(new BackgroundColorProcessor(ImageSharp.Color.FromHex(color)), img.Bounds); await Context.Channel.SendFileAsync(img.ToStream(), $"{color}.png").ConfigureAwait(false); ; } From cfc00b5df6864636cc9f806f3328ed0b145a62ba Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Feb 2017 03:04:22 +0100 Subject: [PATCH 325/746] Fixed $roll X response, $waifuinfo now shows up to 40 random wives, not all --- .../Modules/Gambling/Commands/DiceRollCommand.cs | 4 ++-- .../Modules/Gambling/Commands/WaifuClaimCommands.cs | 4 +++- src/NadekoBot/Resources/ResponseStrings.Designer.cs | 11 ++++++++++- src/NadekoBot/Resources/ResponseStrings.resx | 5 ++++- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs index 721b5b4e..8a0323b9 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs @@ -124,9 +124,9 @@ namespace NadekoBot.Modules.Gambling bitmap.Save(ms); ms.Position = 0; await Context.Channel.SendFileAsync(ms, "dice.png", - Context.User.Mention + + Context.User.Mention + " " + GetText("dice_rolled_num", Format.Bold(values.Count.ToString())) + - " " + GetText("Total: {1} Average: {2}", + " " + GetText("total_average", Format.Bold(values.Sum().ToString()), Format.Bold((values.Sum() / (1.0f * values.Count)).ToString("N2")))).ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs index 212fd1d2..6847dcfc 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs @@ -423,6 +423,8 @@ namespace NadekoBot.Modules.Gambling var claimInfo = GetClaimTitle(target.Id); var affInfo = GetAffinityTitle(target.Id); + var rng = new NadekoRandom(); + var nobody = GetText("nobody"); var embed = new EmbedBuilder() .WithOkColor() @@ -432,7 +434,7 @@ namespace NadekoBot.Modules.Gambling .AddField(efb => efb.WithName(GetText("likes")).WithValue(w.Affinity?.ToString() ?? nobody).WithIsInline(true)) .AddField(efb => efb.WithName(GetText("changes_of_heart")).WithValue($"{affInfo.Count} - \"the {affInfo.Title}\"").WithIsInline(true)) .AddField(efb => efb.WithName(GetText("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)); + .AddField(efb => efb.WithName($"Waifus ({claims.Count})").WithValue(claims.Count == 0 ? nobody : string.Join("\n", claims.OrderBy(x => rng.Next()).Take(40).Select(x => x.Waifu))).WithIsInline(true)); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index e2d01a97..57744c5b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2244,7 +2244,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Dice rolled: {1}. + /// Looks up a localized string similar to Dice rolled: {0}. /// public static string gambling_dice_rolled_num { get { @@ -2577,6 +2577,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Total: {0} Average: {1}. + /// + public static string gambling_total_average { + get { + return ResourceManager.GetString("gambling_total_average", resourceCulture); + } + } + /// /// Looks up a localized string similar to your affinity is already set to that waifu or you're trying to remove your affinity while not having one.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index c1eb0a5d..5e1f21f7 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1081,7 +1081,7 @@ Don't forget to leave your discord name or id in the message. Someone rolled 35 - Dice rolled: {1} + Dice rolled: {0} Dice Rolled: 5 @@ -1218,4 +1218,7 @@ Don't forget to leave your discord name or id in the message. Submissions Closed + + Total: {0} Average: {1} + \ No newline at end of file From 43ad7120f56564c6023e07af90168ffa930fac11 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Feb 2017 03:06:13 +0100 Subject: [PATCH 326/746] $divorce response string fixed --- src/NadekoBot/Resources/ResponseStrings.Designer.cs | 4 ++-- src/NadekoBot/Resources/ResponseStrings.resx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 57744c5b..dbf21639 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2655,9 +2655,9 @@ namespace NadekoBot.Resources { /// /// Looks up a localized string similar to You have divorced a waifu who doesn't like you. You received {0} back.. /// - public static string gambling_waifu_divorced_not_like { + public static string gambling_waifu_divorced_notlike { get { - return ResourceManager.GetString("gambling_waifu_divorced_not_like", resourceCulture); + return ResourceManager.GetString("gambling_waifu_divorced_notlike", resourceCulture); } } diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 5e1f21f7..86ecb97b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1142,7 +1142,7 @@ Don't forget to leave your discord name or id in the message. You have divorced a waifu who likes you. You heartless monster. {0} received {1} as a compensation. - + You have divorced a waifu who doesn't like you. You received {0} back. From 14c0b44f03a68bc0861e4ba31f3f69cc97659977 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Feb 2017 03:27:30 +0100 Subject: [PATCH 327/746] fixed message deleted and message updated with image uploads or embeds --- .../Modules/Administration/Commands/LogCommand.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index 88d512e7..b6b4967b 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -705,8 +705,8 @@ namespace NadekoBot.Modules.Administration var embed = new EmbedBuilder() .WithOkColor() .WithTitle("🗑 " + logChannel.Guild.GetLogText("msg_del", ((ITextChannel)msg.Channel).Name)) - .WithDescription($"{msg.Author}") - .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("content")).WithValue(msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) + .WithDescription(msg.Author.ToString()) + .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("content")).WithValue(string.IsNullOrWhiteSpace(msg.Content) ? "-" : msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) .AddField(efb => efb.WithName("Id").WithValue(msg.Id.ToString()).WithIsInline(false)) .WithFooter(efb => efb.WithText(currentTime)); if (msg.Attachments.Any()) @@ -714,8 +714,9 @@ namespace NadekoBot.Modules.Administration await logChannel.EmbedAsync(embed).ConfigureAwait(false); } - catch + catch (Exception ex) { + _log.Warn(ex); // ignored } } @@ -753,8 +754,8 @@ namespace NadekoBot.Modules.Administration .WithOkColor() .WithTitle("📝 " + logChannel.Guild.GetLogText("msg_update", ((ITextChannel)after.Channel).Name)) .WithDescription(after.Author.ToString()) - .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("old_msg")).WithValue(before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) - .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("new_msg")).WithValue(after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) + .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("old_msg")).WithValue(string.IsNullOrWhiteSpace(before.Content) ? "-" : before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) + .AddField(efb => efb.WithName(logChannel.Guild.GetLogText("new_msg")).WithValue(string.IsNullOrWhiteSpace(after.Content) ? "-" : after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false)) .AddField(efb => efb.WithName("Id").WithValue(after.Id.ToString()).WithIsInline(false)) .WithFooter(efb => efb.WithText(currentTime)); From 0af1a711e2ce7750ac1946dc96809a9e78b945aa Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Feb 2017 03:50:24 +0100 Subject: [PATCH 328/746] normal links in log attachment list --- src/NadekoBot/Modules/Administration/Commands/LogCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index b6b4967b..039e8f74 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -710,7 +710,7 @@ namespace NadekoBot.Modules.Administration .AddField(efb => efb.WithName("Id").WithValue(msg.Id.ToString()).WithIsInline(false)) .WithFooter(efb => efb.WithText(currentTime)); if (msg.Attachments.Any()) - embed.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("attachments")).WithValue(string.Join(", ", msg.Attachments.Select(a => a.ProxyUrl))).WithIsInline(false)); + embed.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("attachments")).WithValue(string.Join(", ", msg.Attachments.Select(a => a.Url))).WithIsInline(false)); await logChannel.EmbedAsync(embed).ConfigureAwait(false); } From 126d5d61d77349088118abb72355a67714a6bbe4 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Feb 2017 14:05:51 +0100 Subject: [PATCH 329/746] Fixed acrophobia responses --- src/NadekoBot/Modules/Games/Commands/Acropobia.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs index aa11f1c6..fc2b6f8c 100644 --- a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -301,7 +301,8 @@ $@"-- private string GetText(string key, params object[] replacements) => NadekoTopLevelModule.GetTextStatic(key, NadekoBot.Localization.GetCultureInfo(_channel.Guild), - typeof(Games).Name.ToLowerInvariant()); + typeof(Games).Name.ToLowerInvariant(), + replacements); } } } \ No newline at end of file From 4e51918c0830b979a6a48040c79beee9a747c010 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Feb 2017 15:28:59 +0100 Subject: [PATCH 330/746] Fixed .donators string --- src/NadekoBot/Resources/ResponseStrings.Designer.cs | 2 +- src/NadekoBot/Resources/ResponseStrings.resx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index dbf21639..d49f4610 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -349,7 +349,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Thanks to the people listed below for making this project hjappen!. + /// Looks up a localized string similar to Thanks to the people listed below for making this project happen!. /// public static string administration_donators { get { diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 86ecb97b..7cf55c8f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -397,7 +397,7 @@ Reason: {1} Sucessfully added a new donator.Total donated amount from this user: {0} 👑 - Thanks to the people listed below for making this project hjappen! + Thanks to the people listed below for making this project happen! I will forward DMs to all owners. From 23e8a082d3a7b5758409b4f1acaab3b7ee9181f1 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Feb 2017 18:46:17 +0100 Subject: [PATCH 331/746] Fixed some keys, a bit more localization --- .../Modules/Games/Commands/Acropobia.cs | 2 +- .../Modules/Games/Commands/HangmanCommands.cs | 20 +++++-------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs index fc2b6f8c..c65c24e6 100644 --- a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -261,7 +261,7 @@ $@"-- return; _votes.AddOrUpdate(kvp.Key, 1, (key, old) => ++old); await _channel.SendConfirmAsync(GetText("acrophobia"), - GetText("vote_cast", Format.Bold(guildUser.ToString()))).ConfigureAwait(false); + GetText("acro_vote_cast", Format.Bold(guildUser.ToString()))).ConfigureAwait(false); await msg.DeleteAsync().ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs index 0fb8e2f3..9726eb65 100644 --- a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Concurrent; using System.Threading.Tasks; using NadekoBot.Modules.Games.Hangman; +using Discord; namespace NadekoBot.Modules.Games { @@ -15,23 +16,12 @@ namespace NadekoBot.Modules.Games [Group] public class HangmanCommands : NadekoSubmodule { - private static Logger _log { get; } - //channelId, game public static ConcurrentDictionary HangmanGames { get; } = new ConcurrentDictionary(); - private static string typesStr { get; } = ""; - - static HangmanCommands() - { - _log = LogManager.GetCurrentClassLogger(); - typesStr = - string.Format("`List of \"{0}hangman\" term types:`\n", NadekoBot.ModulePrefixes[typeof(Games).Name]) + String.Join(", ", HangmanTermPool.data.Keys); - } - [NadekoCommand, Usage, Description, Aliases] public async Task Hangmanlist() { - await Context.Channel.SendConfirmAsync(typesStr); + await Context.Channel.SendConfirmAsync(Format.Code(GetText("hangman_types", Prefix)) + "\n" + String.Join(", ", HangmanTermPool.data.Keys)); } [NadekoCommand, Usage, Description, Aliases] @@ -41,7 +31,7 @@ namespace NadekoBot.Modules.Games if (!HangmanGames.TryAdd(Context.Channel.Id, hm)) { - await Context.Channel.SendErrorAsync("Hangman game already running on this channel.").ConfigureAwait(false); + await ReplyErrorLocalized("hangman_running").ConfigureAwait(false); return; } @@ -56,14 +46,14 @@ namespace NadekoBot.Modules.Games } catch (Exception ex) { - try { await Context.Channel.SendErrorAsync($"Starting errored: {ex.Message}").ConfigureAwait(false); } catch { } + try { await Context.Channel.SendErrorAsync(GetText("hangman_start_errored") + " " + ex.Message).ConfigureAwait(false); } catch { } HangmanGame throwaway; HangmanGames.TryRemove(Context.Channel.Id, out throwaway); throwaway.Dispose(); return; } - await Context.Channel.SendConfirmAsync("Hangman game started", hm.ScrambledWord + "\n" + hm.GetHangman()); + await Context.Channel.SendConfirmAsync(GetText("hangman_game_started"), hm.ScrambledWord + "\n" + hm.GetHangman()); } } } From a5adce9b6fe7d30af515d488c393f8cfa9766462 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Feb 2017 18:46:37 +0100 Subject: [PATCH 332/746] woopps --- .../Resources/ResponseStrings.Designer.cs | 54 +++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 18 +++++++ 2 files changed, 72 insertions(+) diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index d49f4610..da3aab5b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2860,6 +2860,60 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Currency generation has been disabled on this channel.. + /// + public static string games_curgen_disabled { + get { + return ResourceManager.GetString("games_curgen_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Currency generation has been enabled on this channel.. + /// + public static string games_curgen_enabled { + get { + return ResourceManager.GetString("games_curgen_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hangman game started. + /// + public static string games_hangman_game_started { + get { + return ResourceManager.GetString("games_hangman_game_started", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hangman game already running on this channel.. + /// + public static string games_hangman_running { + get { + return ResourceManager.GetString("games_hangman_running", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Starting hangman errored.. + /// + public static string games_hangman_start_errored { + get { + return ResourceManager.GetString("games_hangman_start_errored", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List of "{0}hangman" term types:. + /// + public static string games_hangman_types { + get { + return ResourceManager.GetString("games_hangman_types", resourceCulture); + } + } + /// /// Looks up a localized string similar to Question. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 7cf55c8f..6fa196c1 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1221,4 +1221,22 @@ Don't forget to leave your discord name or id in the message. Total: {0} Average: {1} + + Currency generation has been disabled on this channel. + + + Currency generation has been enabled on this channel. + + + Hangman game started + + + Hangman game already running on this channel. + + + Starting hangman errored. + + + List of "{0}hangman" term types: + \ No newline at end of file From 895d24c75504b677c373d4e5d84a46848c8497b6 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Feb 2017 20:42:04 +0100 Subject: [PATCH 333/746] .sinfo more reliable? --- 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 0eedba24..fefd0a01 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -52,7 +52,7 @@ namespace NadekoBot.Modules.Utility .WithColor(NadekoBot.OkColor); if (guild.Emojis.Any()) { - embed.AddField(fb => fb.WithName($"**Custom Emojis ({guild.Emojis.Count})**").WithValue(string.Join(" ", guild.Emojis.Shuffle().Take(25).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>")))); + embed.AddField(fb => fb.WithName($"**Custom Emojis ({guild.Emojis.Count})**").WithValue(string.Join(" ", guild.Emojis.Shuffle().Take(20).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>")))); } await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } From fff6cb40242b0a13c6eabf9a27888389215424c8 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 22 Feb 2017 11:40:51 +0100 Subject: [PATCH 334/746] fixed a string, closes #1075 --- src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs index 6847dcfc..7f3e4b03 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs @@ -368,7 +368,7 @@ namespace NadekoBot.Modules.Gambling if (waifus.Count == 0) { - await ReplyConfirmLocalized("waifu_none").ConfigureAwait(false); + await ReplyConfirmLocalized("waifus_none").ConfigureAwait(false); return; } From 8ae3d0c5e58738c0947c4f2b4841209d4547c9a2 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 22 Feb 2017 15:20:49 +0100 Subject: [PATCH 335/746] closes #1079 --- src/NadekoBot/Modules/Games/Commands/PollCommands.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs index 1434ee9e..a17e9d26 100644 --- a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs @@ -48,8 +48,6 @@ namespace NadekoBot.Modules.Games { var channel = (ITextChannel)Context.Channel; - if (!(Context.User as IGuildUser).GuildPermissions.ManageChannels) - return; if (string.IsNullOrWhiteSpace(arg) || !arg.Contains(";")) return; var data = arg.Split(';'); From ec9c556f06e1e95700840ee7d18ff8065c9182c2 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 22 Feb 2017 16:11:06 +0100 Subject: [PATCH 336/746] closes #1080 --- src/NadekoBot/Modules/Games/Commands/Acropobia.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs index c65c24e6..bcfc279d 100644 --- a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -284,7 +284,7 @@ $@"-- var winner = table.First(); var embed = new EmbedBuilder().WithOkColor() .WithTitle(GetText("acrophobia")) - .WithDescription(GetText("winner", Format.Bold(_submissions[winner.Key].ToString()), + .WithDescription(GetText("acro_winner", Format.Bold(_submissions[winner.Key].ToString()), Format.Bold(winner.Value.ToString()))) .WithFooter(efb => efb.WithText(winner.Key.ToLowerInvariant().ToTitleCase())); From 5cdb41b65f333e9233a36febb2841ed263babe6d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 22 Feb 2017 18:16:05 +0100 Subject: [PATCH 337/746] A lot more localization, cleanup, inole improved and dateadded is not a field in all database models --- .../20170222162505_dateadded.Designer.cs | 1171 +++++++++++++++++ .../Migrations/20170222162505_dateadded.cs | 357 +++++ .../NadekoSqliteContextModelSnapshot.cs | 76 ++ .../Modules/Games/Commands/Acropobia.cs | 5 +- .../Games/Commands/CleverBotCommands.cs | 2 +- .../Games/Commands/PlantAndPickCommands.cs | 4 +- .../Modules/Games/Commands/TicTacToe.cs | 9 - src/NadekoBot/Modules/Games/Games.cs | 33 +- src/NadekoBot/Modules/Utility/Utility.cs | 119 +- .../Resources/CommandStrings.Designer.cs | 4 +- src/NadekoBot/Resources/CommandStrings.resx | 4 +- .../Resources/ResponseStrings.Designer.cs | 301 +++++ src/NadekoBot/Resources/ResponseStrings.resx | 104 ++ .../Services/Database/Models/DbEntity.cs | 2 +- 14 files changed, 2101 insertions(+), 90 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170222162505_dateadded.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170222162505_dateadded.cs diff --git a/src/NadekoBot/Migrations/20170222162505_dateadded.Designer.cs b/src/NadekoBot/Migrations/20170222162505_dateadded.Designer.cs new file mode 100644 index 00000000..89102dc7 --- /dev/null +++ b/src/NadekoBot/Migrations/20170222162505_dateadded.Designer.cs @@ -0,0 +1,1171 @@ +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("20170222162505_dateadded")] + partial class dateadded + { + 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("DateAdded"); + + 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.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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/20170222162505_dateadded.cs b/src/NadekoBot/Migrations/20170222162505_dateadded.cs new file mode 100644 index 00000000..5f96eca8 --- /dev/null +++ b/src/NadekoBot/Migrations/20170222162505_dateadded.cs @@ -0,0 +1,357 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class dateadded : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "DateAdded", + table: "WaifuUpdates", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "WaifuInfo", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "PokeGame", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "SelfAssignableRoles", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "Reminders", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "RaceAnimals", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "Quotes", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "PlaylistSong", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "PlayingStatus", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "Permission", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "MutedUserId", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "MusicPlaylists", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "ModulePrefixes", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "LogSettings", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "IgnoredVoicePresenceCHannels", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "IgnoredLogChannels", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "GuildRepeater", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "GuildConfigs", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "GCChannelId", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "FollowedStream", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "FilteredWord", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "FilterChannelId", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "EightBallResponses", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "Donators", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "DiscordUser", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "CustomReactions", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "CurrencyTransactions", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "Currency", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "ConversionUnits", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "CommandPrice", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "CommandCooldown", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "ClashOfClans", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "ClashCallers", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "BotConfig", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "BlacklistItem", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "AntiSpamSetting", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "AntiSpamIgnore", + nullable: true); + + migrationBuilder.AddColumn( + name: "DateAdded", + table: "AntiRaidSetting", + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "DateAdded", + table: "WaifuUpdates"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "WaifuInfo"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "PokeGame"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "SelfAssignableRoles"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "Reminders"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "RaceAnimals"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "Quotes"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "PlaylistSong"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "PlayingStatus"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "Permission"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "MutedUserId"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "MusicPlaylists"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "ModulePrefixes"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "LogSettings"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "IgnoredVoicePresenceCHannels"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "IgnoredLogChannels"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "GuildRepeater"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "GuildConfigs"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "GCChannelId"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "FollowedStream"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "FilteredWord"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "FilterChannelId"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "EightBallResponses"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "Donators"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "DiscordUser"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "CustomReactions"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "CurrencyTransactions"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "Currency"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "ConversionUnits"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "CommandPrice"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "CommandCooldown"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "ClashOfClans"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "ClashCallers"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "BotConfig"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "BlacklistItem"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "AntiSpamSetting"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "AntiSpamIgnore"); + + migrationBuilder.DropColumn( + name: "DateAdded", + table: "AntiRaidSetting"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 5a03594c..981d53cf 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -24,6 +24,8 @@ namespace NadekoBot.Migrations b.Property("Action"); + b.Property("DateAdded"); + b.Property("GuildConfigId"); b.Property("Seconds"); @@ -47,6 +49,8 @@ namespace NadekoBot.Migrations b.Property("ChannelId"); + b.Property("DateAdded"); + b.HasKey("Id"); b.HasIndex("AntiSpamSettingId"); @@ -61,6 +65,8 @@ namespace NadekoBot.Migrations b.Property("Action"); + b.Property("DateAdded"); + b.Property("GuildConfigId"); b.Property("MessageThreshold"); @@ -80,6 +86,8 @@ namespace NadekoBot.Migrations b.Property("BotConfigId"); + b.Property("DateAdded"); + b.Property("ItemId"); b.Property("Type"); @@ -120,6 +128,8 @@ namespace NadekoBot.Migrations b.Property("DMHelpString"); + b.Property("DateAdded"); + b.Property("ErrorColor"); b.Property("ForwardMessages"); @@ -158,6 +168,8 @@ namespace NadekoBot.Migrations b.Property("ClashWarId"); + b.Property("DateAdded"); + b.Property("SequenceNumber"); b.Property("Stars"); @@ -178,6 +190,8 @@ namespace NadekoBot.Migrations b.Property("ChannelId"); + b.Property("DateAdded"); + b.Property("EnemyClan"); b.Property("GuildId"); @@ -200,6 +214,8 @@ namespace NadekoBot.Migrations b.Property("CommandName"); + b.Property("DateAdded"); + b.Property("GuildConfigId"); b.Property("Seconds"); @@ -220,6 +236,8 @@ namespace NadekoBot.Migrations b.Property("CommandName"); + b.Property("DateAdded"); + b.Property("Price"); b.HasKey("Id"); @@ -237,6 +255,8 @@ namespace NadekoBot.Migrations b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("DateAdded"); + b.Property("InternalTrigger"); b.Property("Modifier"); @@ -255,6 +275,8 @@ namespace NadekoBot.Migrations b.Property("Amount"); + b.Property("DateAdded"); + b.Property("UserId"); b.HasKey("Id"); @@ -272,6 +294,8 @@ namespace NadekoBot.Migrations b.Property("Amount"); + b.Property("DateAdded"); + b.Property("Reason"); b.Property("UserId"); @@ -286,6 +310,8 @@ namespace NadekoBot.Migrations b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("DateAdded"); + b.Property("GuildId"); b.Property("IsRegex"); @@ -308,6 +334,8 @@ namespace NadekoBot.Migrations b.Property("AvatarId"); + b.Property("DateAdded"); + b.Property("Discriminator"); b.Property("UserId"); @@ -328,6 +356,8 @@ namespace NadekoBot.Migrations b.Property("Amount"); + b.Property("DateAdded"); + b.Property("Name"); b.Property("UserId"); @@ -347,6 +377,8 @@ namespace NadekoBot.Migrations b.Property("BotConfigId"); + b.Property("DateAdded"); + b.Property("Text"); b.HasKey("Id"); @@ -363,6 +395,8 @@ namespace NadekoBot.Migrations b.Property("ChannelId"); + b.Property("DateAdded"); + b.Property("GuildConfigId"); b.Property("GuildConfigId1"); @@ -381,6 +415,8 @@ namespace NadekoBot.Migrations b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("DateAdded"); + b.Property("GuildConfigId"); b.Property("Word"); @@ -399,6 +435,8 @@ namespace NadekoBot.Migrations b.Property("ChannelId"); + b.Property("DateAdded"); + b.Property("GuildConfigId"); b.Property("GuildId"); @@ -421,6 +459,8 @@ namespace NadekoBot.Migrations b.Property("ChannelId"); + b.Property("DateAdded"); + b.Property("GuildConfigId"); b.HasKey("Id"); @@ -455,6 +495,8 @@ namespace NadekoBot.Migrations b.Property("CleverbotEnabled"); + b.Property("DateAdded"); + b.Property("DefaultMusicVolume"); b.Property("DeleteMessageOnCommand"); @@ -512,6 +554,8 @@ namespace NadekoBot.Migrations b.Property("ChannelId"); + b.Property("DateAdded"); + b.Property("GuildConfigId"); b.Property("GuildId"); @@ -534,6 +578,8 @@ namespace NadekoBot.Migrations b.Property("ChannelId"); + b.Property("DateAdded"); + b.Property("LogSettingId"); b.HasKey("Id"); @@ -550,6 +596,8 @@ namespace NadekoBot.Migrations b.Property("ChannelId"); + b.Property("DateAdded"); + b.Property("LogSettingId"); b.HasKey("Id"); @@ -578,6 +626,8 @@ namespace NadekoBot.Migrations b.Property("ChannelUpdatedId"); + b.Property("DateAdded"); + b.Property("IsLogging"); b.Property("LogOtherId"); @@ -638,6 +688,8 @@ namespace NadekoBot.Migrations b.Property("BotConfigId"); + b.Property("DateAdded"); + b.Property("ModuleName"); b.Property("Prefix"); @@ -658,6 +710,8 @@ namespace NadekoBot.Migrations b.Property("AuthorId"); + b.Property("DateAdded"); + b.Property("Name"); b.HasKey("Id"); @@ -670,6 +724,8 @@ namespace NadekoBot.Migrations b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("DateAdded"); + b.Property("GuildConfigId"); b.Property("UserId"); @@ -686,6 +742,8 @@ namespace NadekoBot.Migrations b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("DateAdded"); + b.Property("NextId"); b.Property("PrimaryTarget"); @@ -713,6 +771,8 @@ namespace NadekoBot.Migrations b.Property("BotConfigId"); + b.Property("DateAdded"); + b.Property("Status"); b.HasKey("Id"); @@ -727,6 +787,8 @@ namespace NadekoBot.Migrations b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("DateAdded"); + b.Property("MusicPlaylistId"); b.Property("Provider"); @@ -756,6 +818,8 @@ namespace NadekoBot.Migrations b.Property("AuthorName") .IsRequired(); + b.Property("DateAdded"); + b.Property("GuildId"); b.Property("Keyword") @@ -776,6 +840,8 @@ namespace NadekoBot.Migrations b.Property("BotConfigId"); + b.Property("DateAdded"); + b.Property("Icon"); b.Property("Name"); @@ -794,6 +860,8 @@ namespace NadekoBot.Migrations b.Property("ChannelId"); + b.Property("DateAdded"); + b.Property("IsPrivate"); b.Property("Message"); @@ -814,6 +882,8 @@ namespace NadekoBot.Migrations b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("DateAdded"); + b.Property("GuildId"); b.Property("RoleId"); @@ -831,6 +901,8 @@ namespace NadekoBot.Migrations b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("DateAdded"); + b.Property("UserId"); b.Property("type"); @@ -852,6 +924,8 @@ namespace NadekoBot.Migrations b.Property("ClaimerId"); + b.Property("DateAdded"); + b.Property("Price"); b.Property("WaifuId"); @@ -873,6 +947,8 @@ namespace NadekoBot.Migrations b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("DateAdded"); + b.Property("NewId"); b.Property("OldId"); diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs index bcfc279d..ddaf3e98 100644 --- a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -240,7 +240,6 @@ $@"-- catch { } } - IGuildUser usr; //if (submissions.TryGetValue(input, out usr) && usr.Id != guildUser.Id) //{ // if (!usersWhoVoted.Add(guildUser.Id)) @@ -255,7 +254,7 @@ $@"-- if (int.TryParse(input, out num) && num > 0 && num <= _submissions.Count) { var kvp = _submissions.Skip(num - 1).First(); - usr = kvp.Value; + var usr = kvp.Value; //can't vote for yourself, can't vote multiple times if (usr.Id == guildUser.Id || !_usersWhoVoted.Add(guildUser.Id)) return; @@ -299,7 +298,7 @@ $@"-- } private string GetText(string key, params object[] replacements) - => NadekoTopLevelModule.GetTextStatic(key, + => GetTextStatic(key, NadekoBot.Localization.GetCultureInfo(_channel.Guild), typeof(Games).Name.ToLowerInvariant(), replacements); diff --git a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs index 1f33bc2a..47aad031 100644 --- a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs @@ -19,7 +19,7 @@ namespace NadekoBot.Modules.Games [Group] public class CleverBotCommands : NadekoSubmodule { - private static Logger _log { get; } + private static new Logger _log { get; } public static ConcurrentDictionary> CleverbotGuilds { get; } = new ConcurrentDictionary>(); diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index ba98f5f1..423964cb 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -203,11 +203,11 @@ namespace NadekoBot.Modules.Games } if (enabled) { - await channel.SendConfirmAsync("Currency generation enabled on this channel.").ConfigureAwait(false); + await ReplyConfirmLocalized("curgen_enabled").ConfigureAwait(false); } else { - await channel.SendConfirmAsync("Currency generation disabled on this channel.").ConfigureAwait(false); + await ReplyConfirmLocalized("curgen_disabled").ConfigureAwait(false); } } diff --git a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs index 2e115fd2..e1000af2 100644 --- a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs +++ b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs @@ -4,9 +4,7 @@ using NadekoBot.Attributes; using NadekoBot.Extensions; using NLog; using System; -using System.Collections.Concurrent; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -21,15 +19,8 @@ namespace NadekoBot.Modules.Games { //channelId/game private static readonly Dictionary _games = new Dictionary(); - private readonly Logger _log; - - public TicTacToeCommands() - { - _log = LogManager.GetCurrentClassLogger(); - } private readonly SemaphoreSlim sem = new SemaphoreSlim(1, 1); - private readonly object tttLockObj = new object(); [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index 88a663df..2249c1b2 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -141,8 +141,11 @@ namespace NadekoBot.Modules.Games var pointy = (int)(miny - length * ((Crazy - 4) / 6)); var p = new Pen(ImageSharp.Color.Red, 5); - - img.Draw(p, new SixLabors.Shapes.Ellipse(200, 200, 5, 5)); + //using (var pointMs = File.ReadAllBytes("data/images/point.png").ToStream()) + //using (var pointIMg = new ImageSharp.Image(pointMs)) + //{ + // img.DrawImage(pointIMg, 100, new ImageSharp.Size(100, 100), new Point(pointx, pointy)); + //} string url; using (var http = new HttpClient()) @@ -167,19 +170,19 @@ namespace NadekoBot.Modules.Games } } - //[NadekoCommand, Usage, Description, Aliases] - //[RequireContext(ContextType.Guild)] - //public async Task RateGirl(IGuildUser usr) - //{ - // var gr = _girlRatings.GetOrAdd(usr.Id, GetGirl); - // var img = await gr.Url; - // await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() - // .WithTitle("Girl Rating For " + usr) - // .AddField(efb => efb.WithName("Hot").WithValue(gr.Hot.ToString("F2")).WithIsInline(true)) - // .AddField(efb => efb.WithName("Crazy").WithValue(gr.Crazy.ToString("F2")).WithIsInline(true)) - // .AddField(efb => efb.WithName("Advice").WithValue(gr.Advice).WithIsInline(false)) - // .WithImageUrl(img)).ConfigureAwait(false); - //} + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task RateGirl(IGuildUser usr) + { + var gr = _girlRatings.GetOrAdd(usr.Id, GetGirl); + var img = await gr.Url; + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle("Girl Rating For " + usr) + .AddField(efb => efb.WithName("Hot").WithValue(gr.Hot.ToString("F2")).WithIsInline(true)) + .AddField(efb => efb.WithName("Crazy").WithValue(gr.Crazy.ToString("F2")).WithIsInline(true)) + .AddField(efb => efb.WithName("Advice").WithValue(gr.Advice).WithIsInline(false)) + .WithImageUrl(img)).ConfigureAwait(false); + } private double NextDouble(double x, double y) { diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 8d3a95c4..f69aef7d 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -117,7 +117,7 @@ namespace NadekoBot.Modules.Utility if (rotatingRoleColors.TryRemove(role.Id, out t)) { t.Change(Timeout.Infinite, Timeout.Infinite); - await channel.SendConfirmAsync($"Stopped rotating colors for the **{role.Name}** role").ConfigureAwait(false); + await ReplyConfirmLocalized("rrc_stop", Format.Bold(role.Name)).ConfigureAwait(false); } return; } @@ -132,7 +132,7 @@ namespace NadekoBot.Modules.Utility if (!hexColors.Any()) { - await channel.SendMessageAsync("No colors are in the correct format. Use `#00ff00` for example.").ConfigureAwait(false); + await ReplyErrorLocalized("rrc_no_colors").ConfigureAwait(false); return; } @@ -162,8 +162,7 @@ namespace NadekoBot.Modules.Utility old.Change(Timeout.Infinite, Timeout.Infinite); return t; }); - - await channel.SendFileAsync(images, "magicalgirl.jpg", $"Rotating **{role.Name}** role's color.").ConfigureAwait(false); + await channel.SendFileAsync(images, "magicalgirl.jpg", GetText("rrc_start", Format.Bold(role.Name))).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -180,14 +179,14 @@ namespace NadekoBot.Modules.Utility .WithAuthor(eab => eab.WithIconUrl("https://togethertube.com/assets/img/favicons/favicon-32x32.png") .WithName("Together Tube") .WithUrl("https://togethertube.com/")) - .WithDescription($"{Context.User.Mention} Here is your room link:\n{target}")); + .WithDescription(Context.User.Mention + " " + GetText("togtub_room_link") + "\n" + target)); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task WhosPlaying([Remainder] string game = null) + public async Task WhosPlaying([Remainder] string game) { - game = game.Trim().ToUpperInvariant(); + game = game?.Trim().ToUpperInvariant(); if (string.IsNullOrWhiteSpace(game)) return; @@ -207,7 +206,7 @@ namespace NadekoBot.Modules.Utility int i = 0; if (arr.Length == 0) - await Context.Channel.SendErrorAsync("Nobody is playing that game.").ConfigureAwait(false); + await ReplyErrorLocalized("nobody_playing_game").ConfigureAwait(false); else { await Context.Channel.SendConfirmAsync("```css\n" + string.Join("\n", arr.GroupBy(item => (i++) / 2) @@ -218,26 +217,24 @@ namespace NadekoBot.Modules.Utility [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task InRole([Remainder] string roles) + public async Task InRole(params IRole[] roles) { - if (string.IsNullOrWhiteSpace(roles)) + if (roles.Length == 0) return; - var arg = roles.Split(',').Select(r => r.Trim().ToUpperInvariant()); - string send = "ℹ️ **Here is a list of users in those roles:**"; - foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str) && str != "@EVERYONE" && str != "EVERYONE")) + var send = "ℹ️ " + Format.Bold(GetText("inrole_list")); + var usrs = (await Context.Guild.GetUsersAsync()).ToArray(); + foreach (var role in roles.Where(r => r.Id != Context.Guild.Id)) { - var role = Context.Guild.Roles.Where(r => r.Name.ToUpperInvariant() == roleStr).FirstOrDefault(); - if (role == null) continue; send += $"```css\n[{role.Name}]\n"; - send += string.Join(", ", (await Context.Guild.GetUsersAsync()).Where(u => u.RoleIds.Contains(role.Id)).Select(u => u.ToString())); - send += $"\n```"; + send += string.Join(", ", usrs.Where(u => u.RoleIds.Contains(role.Id)).Select(u => u.ToString())); + send += "\n```"; } - var usr = Context.User as IGuildUser; + var usr = (IGuildUser)Context.User; while (send.Length > 2000) { if (!usr.GetPermissions((ITextChannel)Context.Channel).ManageMessages) { - await Context.Channel.SendErrorAsync($"⚠️ {usr.Mention} **you are not allowed to use this command on roles with a lot of users in them to prevent abuse.**").ConfigureAwait(false); + await ReplyErrorLocalized("inrole_not_allowed").ConfigureAwait(false); return; } var curstr = send.Substring(0, 2000); @@ -254,15 +251,13 @@ namespace NadekoBot.Modules.Utility public async Task CheckMyPerms() { - StringBuilder builder = new StringBuilder("```http\n"); - var user = Context.User as IGuildUser; + StringBuilder builder = new StringBuilder(); + var user = (IGuildUser) Context.User; var perms = user.GetPermissions((ITextChannel)Context.Channel); foreach (var p in perms.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any())) { - builder.AppendLine($"{p.Name} : {p.GetValue(perms, null).ToString()}"); + builder.AppendLine($"{p.Name} : {p.GetValue(perms, null)}"); } - - builder.Append("```"); await Context.Channel.SendConfirmAsync(builder.ToString()); } @@ -271,20 +266,23 @@ namespace NadekoBot.Modules.Utility public async Task UserId(IGuildUser target = null) { var usr = target ?? Context.User; - await Context.Channel.SendConfirmAsync($"🆔 of the user **{ usr.Username }** is `{ usr.Id }`").ConfigureAwait(false); + await ReplyConfirmLocalized("userid", "🆔", Format.Bold(usr.ToString()), + Format.Code(usr.Id.ToString())).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] public async Task ChannelId() { - await Context.Channel.SendConfirmAsync($"🆔 of this channel is `{Context.Channel.Id}`").ConfigureAwait(false); + await ReplyConfirmLocalized("channelidd", "🆔", Format.Code(Context.Channel.Id.ToString())) + .ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task ServerId() { - await Context.Channel.SendConfirmAsync($"🆔 of this server is `{Context.Guild.Id}`").ConfigureAwait(false); + await ReplyConfirmLocalized("serverid", "🆔", Format.Code(Context.Guild.Id.ToString())) + .ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -294,33 +292,36 @@ namespace NadekoBot.Modules.Utility var channel = (ITextChannel)Context.Channel; var guild = channel.Guild; - const int RolesPerPage = 20; + const int rolesPerPage = 20; if (page < 1 || page > 100) return; if (target != null) { - var roles = target.GetRoles().Except(new[] { guild.EveryoneRole }).OrderBy(r => -r.Position).Skip((page - 1) * RolesPerPage).Take(RolesPerPage); + var roles = target.GetRoles().Except(new[] { guild.EveryoneRole }).OrderBy(r => -r.Position).Skip((page - 1) * rolesPerPage).Take(rolesPerPage).ToArray(); if (!roles.Any()) { - await channel.SendErrorAsync("No roles on this page.").ConfigureAwait(false); + await ReplyErrorLocalized("no_roles_on_page").ConfigureAwait(false); } else { - await channel.SendConfirmAsync($"⚔ **Page #{page} of roles for {target.Username}**", $"```css\n• " + string.Join("\n• ", roles).SanitizeMentions() + "\n```").ConfigureAwait(false); + + await channel.SendConfirmAsync(GetText("roles_page", page, Format.Bold(target.ToString())), + "\n• " + string.Join("\n• ", (IEnumerable)roles).SanitizeMentions()).ConfigureAwait(false); } } else { - var roles = guild.Roles.Except(new[] { guild.EveryoneRole }).OrderBy(r => -r.Position).Skip((page - 1) * RolesPerPage).Take(RolesPerPage); + var roles = guild.Roles.Except(new[] { guild.EveryoneRole }).OrderBy(r => -r.Position).Skip((page - 1) * rolesPerPage).Take(rolesPerPage).ToArray(); if (!roles.Any()) { - await channel.SendErrorAsync("No roles on this page.").ConfigureAwait(false); + await ReplyErrorLocalized("no_roles_on_page").ConfigureAwait(false); } else { - await channel.SendConfirmAsync($"⚔ **Page #{page} of all roles on this server:**", $"```css\n• " + string.Join("\n• ", roles).SanitizeMentions() + "\n```").ConfigureAwait(false); + await channel.SendConfirmAsync(GetText("roles_all_page", page), + "\n• " + string.Join("\n• ", (IEnumerable)roles).SanitizeMentions()).ConfigureAwait(false); } } } @@ -339,9 +340,9 @@ namespace NadekoBot.Modules.Utility var topic = channel.Topic; if (string.IsNullOrWhiteSpace(topic)) - await Context.Channel.SendErrorAsync("No topic set.").ConfigureAwait(false); + await ReplyErrorLocalized("no_topic_set").ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync("Channel topic", topic).ConfigureAwait(false); + await Context.Channel.SendConfirmAsync(GetText("channel_topic"), topic).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -362,11 +363,13 @@ namespace NadekoBot.Modules.Utility return; var status = string.Join(", ", NadekoBot.Client.Shards.GroupBy(x => x.ConnectionState) - .Select(x => $"{x.Count()} shards {x.Key}") + .Select(x => $"{x.Count()} {x.Key}") .ToArray()); var allShardStrings = NadekoBot.Client.Shards - .Select(x => $"Shard **#{x.ShardId.ToString()}** is in {Format.Bold(x.ConnectionState.ToString())} state with {Format.Bold(x.Guilds.Count.ToString())} servers") + .Select(x => + GetText("shard_stats_txt", x.ShardId.ToString(), + Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.Count.ToString()))) .ToArray(); @@ -377,10 +380,10 @@ namespace NadekoBot.Modules.Utility var str = string.Join("\n", allShardStrings.Skip(25 * (curPage - 1)).Take(25)); if (string.IsNullOrWhiteSpace(str)) - str = "No shards on this page."; + str = GetText("no_shards_on_page"); return new EmbedBuilder() - .WithAuthor(a => a.WithName("Shard Stats")) + .WithAuthor(a => a.WithName(GetText("shard_stats"))) .WithTitle(status) .WithOkColor() .WithDescription(str); @@ -392,7 +395,7 @@ namespace NadekoBot.Modules.Utility { var shardId = NadekoBot.Client.GetShardIdFor(guildid); - await Context.Channel.SendConfirmAsync($"ShardId for **{guildid}** with {NadekoBot.Client.Shards.Count} total shards", shardId.ToString()).ConfigureAwait(false); + await Context.Channel.SendConfirmAsync(shardId.ToString()).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -409,17 +412,21 @@ namespace NadekoBot.Modules.Utility .WithAuthor(eab => eab.WithName($"NadekoBot v{StatsService.BotVersion}") .WithUrl("http://nadekobot.readthedocs.io/en/latest/") .WithIconUrl("https://cdn.discordapp.com/avatars/116275390695079945/b21045e778ef21c96d175400e779f0fb.jpg")) - .AddField(efb => efb.WithName(Format.Bold("Author")).WithValue(stats.Author).WithIsInline(true)) - .AddField(efb => efb.WithName(Format.Bold("Bot ID")).WithValue(NadekoBot.Client.CurrentUser.Id.ToString()).WithIsInline(true)) - .AddField(efb => efb.WithName(Format.Bold("Shard")).WithValue($"#{shardId}, {NadekoBot.Client.Shards.Count} total").WithIsInline(true)) - .AddField(efb => efb.WithName(Format.Bold("Commands Ran")).WithValue(stats.CommandsRan.ToString()).WithIsInline(true)) - .AddField(efb => efb.WithName(Format.Bold("Messages")).WithValue($"{stats.MessageCounter} ({stats.MessagesPerSecond:F2}/sec)").WithIsInline(true)) - .AddField(efb => efb.WithName(Format.Bold("Memory")).WithValue($"{stats.Heap} MB").WithIsInline(true)) - .AddField(efb => efb.WithName(Format.Bold("Owner ID(s)")).WithValue(string.Join("\n", NadekoBot.Credentials.OwnerIds)).WithIsInline(true)) - .AddField(efb => efb.WithName(Format.Bold("Uptime")).WithValue(stats.GetUptimeString("\n")).WithIsInline(true)) - .AddField(efb => efb.WithName(Format.Bold("Presence")).WithValue($"{NadekoBot.Client.GetGuildCount()} Servers\n{stats.TextChannels} Text Channels\n{stats.VoiceChannels} Voice Channels").WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("author")).WithValue(stats.Author).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("botid")).WithValue(NadekoBot.Client.CurrentUser.Id.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("shard")).WithValue($"#{shardId} / {NadekoBot.Client.Shards.Count}").WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("commands_ran")).WithValue(stats.CommandsRan.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("messages")).WithValue($"{stats.MessageCounter} ({stats.MessagesPerSecond:F2}/sec)").WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("memory")).WithValue($"{stats.Heap} MB").WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("owner_ids")).WithValue(string.Join("\n", NadekoBot.Credentials.OwnerIds)).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("uptime")).WithValue(stats.GetUptimeString("\n")).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("presence")).WithValue( + GetText("presence_txt", + NadekoBot.Client.GetGuildCount(), stats.TextChannels, stats.VoiceChannels)).WithIsInline(true)) #if !GLOBAL_NADEKO - .WithFooter(efb => efb.WithText($"Playing {Music.Music.MusicPlayers.Where(mp => mp.Value.CurrentSong != null).Count()} songs, {Music.Music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count)} queued.")) + .WithFooter(efb => efb.WithText(GetText("stats_songs", + Music.Music.MusicPlayers.Count(mp => mp.Value.CurrentSong != null), + Music.Music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count)))) #endif ); } @@ -429,10 +436,10 @@ namespace NadekoBot.Modules.Utility { var tags = Context.Message.Tags.Where(t => t.Type == TagType.Emoji).Select(t => (Emoji)t.Value); - var result = string.Join("\n", tags.Select(m => $"**Name:** {m} **Link:** {m.Url}")); + var result = string.Join("\n", tags.Select(m => GetText("showemojis", m, m.Url))); if (string.IsNullOrWhiteSpace(result)) - await Context.Channel.SendErrorAsync("No special emojis found."); + await ReplyErrorLocalized("emojis_none").ConfigureAwait(false); else await Context.Channel.SendMessageAsync(result).ConfigureAwait(false); } @@ -450,13 +457,15 @@ namespace NadekoBot.Modules.Utility if (!guilds.Any()) { - await Context.Channel.SendErrorAsync("No servers found on that page.").ConfigureAwait(false); + await ReplyErrorLocalized("listservers_none").ConfigureAwait(false); return; } await Context.Channel.EmbedAsync(guilds.Aggregate(new EmbedBuilder().WithOkColor(), (embed, g) => embed.AddField(efb => efb.WithName(g.Name) - .WithValue($"```css\nID: {g.Id}\nMembers: {g.Users.Count}\nOwnerID: {g.OwnerId} ```") + .WithValue( + GetText("listservers", g.Id, g.Users.Count, + g.OwnerId)) .WithIsInline(false)))) .ConfigureAwait(false); } diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index e6390b66..52100d6c 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -3552,7 +3552,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission.. + /// Looks up a localized string similar to Lists every person from the provided role or roles, separated with space, on this server. You can use role IDs, role names (in quotes if it has multiple words), or role mention If the list is too long for 1 message, you must have Manage Messages permission.. /// public static string inrole_desc { get { @@ -3561,7 +3561,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}inrole Role`. + /// Looks up a localized string similar to `{0}inrole Role` or `{0}inrole Role1 "Role 2" @role3`. /// public static string inrole_usage { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index c661db7d..703fcf20 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -841,10 +841,10 @@ inrole - Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission. + Lists every person from the provided role or roles, separated with space, on this server. You can use role IDs, role names (in quotes if it has multiple words), or role mention If the list is too long for 1 message, you must have Manage Messages permission. - `{0}inrole Role` + `{0}inrole Role` or `{0}inrole Role1 "Role 2" @role3` checkmyperms diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index da3aab5b..d6423df6 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -3352,5 +3352,306 @@ namespace NadekoBot.Resources { return ResourceManager.GetString("pokemon_you_fainted", resourceCulture); } } + + /// + /// Looks up a localized string similar to Author. + /// + public static string utility_author { + get { + return ResourceManager.GetString("utility_author", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bot ID. + /// + public static string utility_botid { + get { + return ResourceManager.GetString("utility_botid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Channel Topic. + /// + public static string utility_channel_topic { + get { + return ResourceManager.GetString("utility_channel_topic", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} of this channel is {1}. + /// + public static string utility_channelid { + get { + return ResourceManager.GetString("utility_channelid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Commands Ran. + /// + public static string utility_commands_ran { + get { + return ResourceManager.GetString("utility_commands_ran", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Here is a list of users in those roles:. + /// + public static string utility_inrole_list { + get { + return ResourceManager.GetString("utility_inrole_list", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to you are not allowed to use this command on roles with a lot of users in them to prevent abuse.. + /// + public static string utility_inrole_not_allowed { + get { + return ResourceManager.GetString("utility_inrole_not_allowed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ID: {0} + ///Members: {1} + ///OwnerID: {2}. + /// + public static string utility_listservers { + get { + return ResourceManager.GetString("utility_listservers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No servers found on that page.. + /// + public static string utility_listservers_none { + get { + return ResourceManager.GetString("utility_listservers_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Memory. + /// + public static string utility_memory { + get { + return ResourceManager.GetString("utility_memory", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Messages. + /// + public static string utility_messages { + get { + return ResourceManager.GetString("utility_messages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No roles on this page.. + /// + public static string utility_no_roles_on_page { + get { + return ResourceManager.GetString("utility_no_roles_on_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No shards on this page.. + /// + public static string utility_no_shards_on_page { + get { + return ResourceManager.GetString("utility_no_shards_on_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No topic set.. + /// + public static string utility_no_topic_set { + get { + return ResourceManager.GetString("utility_no_topic_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nobody is playing that game.. + /// + public static string utility_nobody_playing_game { + get { + return ResourceManager.GetString("utility_nobody_playing_game", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Owner IDs. + /// + public static string utility_owner_ids { + get { + return ResourceManager.GetString("utility_owner_ids", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Presence. + /// + public static string utility_presence { + get { + return ResourceManager.GetString("utility_presence", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} Servers + ///{1} Text Channels + ///{2} Voice Channels. + /// + public static string utility_presence_txt { + get { + return ResourceManager.GetString("utility_presence_txt", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Page #{0} of all roles on this server:. + /// + public static string utility_roles_all_page { + get { + return ResourceManager.GetString("utility_roles_all_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Page #{0} of roels for {1}. + /// + public static string utility_roles_page { + get { + return ResourceManager.GetString("utility_roles_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No colors are in the correct format. Use `#00ff00` for example.. + /// + public static string utility_rrc_no_colors { + get { + return ResourceManager.GetString("utility_rrc_no_colors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Started rotating {0} role's color.. + /// + public static string utility_rrc_start { + get { + return ResourceManager.GetString("utility_rrc_start", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stopped rotating colors for the {0} role. + /// + public static string utility_rrc_stop { + get { + return ResourceManager.GetString("utility_rrc_stop", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} of this server is {1}. + /// + public static string utility_serverid { + get { + return ResourceManager.GetString("utility_serverid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shard. + /// + public static string utility_shard { + get { + return ResourceManager.GetString("utility_shard", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shard Stats. + /// + public static string utility_shard_stats { + get { + return ResourceManager.GetString("utility_shard_stats", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shard **#{0}** is in {1} state with {2} servers. + /// + public static string utility_shard_stats_txt { + get { + return ResourceManager.GetString("utility_shard_stats_txt", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to **Name:** {0} **Link:** {1}. + /// + public static string utility_showemojis { + get { + return ResourceManager.GetString("utility_showemojis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No special emojis found.. + /// + public static string utility_showemojis_none { + get { + return ResourceManager.GetString("utility_showemojis_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Playing {0} songs, {1} queued.. + /// + public static string utility_stats_songs { + get { + return ResourceManager.GetString("utility_stats_songs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Here is your room link:. + /// + public static string utility_togtub_room_link { + get { + return ResourceManager.GetString("utility_togtub_room_link", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Uptime. + /// + public static string utility_uptime { + get { + return ResourceManager.GetString("utility_uptime", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} of the user {1} is {2}. + /// + public static string utility_userid { + get { + return ResourceManager.GetString("utility_userid", resourceCulture); + } + } } } diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 6fa196c1..95396e70 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1239,4 +1239,108 @@ Don't forget to leave your discord name or id in the message. List of "{0}hangman" term types: + + Author + + + Bot ID + + + {0} of this channel is {1} + + + Channel Topic + + + Commands Ran + + + Here is a list of users in those roles: + + + you are not allowed to use this command on roles with a lot of users in them to prevent abuse. + + + ID: {0} +Members: {1} +OwnerID: {2} + + + No servers found on that page. + + + Memory + + + Messages + + + Nobody is playing that game. + + + No roles on this page. + + + No shards on this page. + + + No topic set. + + + Owner IDs + + + Presence + + + {0} Servers +{1} Text Channels +{2} Voice Channels + + + Page #{0} of all roles on this server: + + + Page #{0} of roels for {1} + + + No colors are in the correct format. Use `#00ff00` for example. + + + Started rotating {0} role's color. + + + Stopped rotating colors for the {0} role + + + {0} of this server is {1} + + + Shard + + + Shard Stats + + + Shard **#{0}** is in {1} state with {2} servers + + + **Name:** {0} **Link:** {1} + + + No special emojis found. + + + Playing {0} songs, {1} queued. + + + Here is your room link: + + + Uptime + + + {0} of the user {1} is {2} + Id of the user kwoth#1234 is 123123123123 + \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/Models/DbEntity.cs b/src/NadekoBot/Services/Database/Models/DbEntity.cs index 5c7dda6b..e727851c 100644 --- a/src/NadekoBot/Services/Database/Models/DbEntity.cs +++ b/src/NadekoBot/Services/Database/Models/DbEntity.cs @@ -7,6 +7,6 @@ namespace NadekoBot.Services.Database.Models { [Key] public int Id { get; set; } - public DateTime DateAdded { get; } = DateTime.UtcNow; + public DateTime? DateAdded { get; set; } = DateTime.UtcNow; } } From 53140940d7c61ea6b7f6d008a3b2637615ac4566 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 23 Feb 2017 03:06:37 +0100 Subject: [PATCH 338/746] A lot more localization, utility module done. --- .../Modules/Utility/Commands/CalcCommand.cs | 35 +- .../Commands/CrossServerTextChannel.cs | 47 +- .../Modules/Utility/Commands/InfoCommands.cs | 55 ++- .../Utility/Commands/MessageRepeater.cs | 93 ++-- .../Modules/Utility/Commands/QuoteCommands.cs | 19 +- .../Modules/Utility/Commands/Remind.cs | 59 +-- .../Utility/Commands/UnitConversion.cs | 21 +- src/NadekoBot/NadekoBot.xproj.DotSettings | 3 +- .../Resources/ResponseStrings.Designer.cs | 450 ++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 153 ++++++ 10 files changed, 787 insertions(+), 148 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs b/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs index b4327c85..8eccc500 100644 --- a/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs +++ b/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs @@ -12,7 +12,7 @@ namespace NadekoBot.Modules.Utility public partial class Utility { [Group] - public class CalcCommands : ModuleBase + public class CalcCommands : NadekoSubmodule { [NadekoCommand, Usage, Description, Aliases] public async Task Calculate([Remainder] string expression) @@ -21,9 +21,9 @@ namespace NadekoBot.Modules.Utility expr.EvaluateParameter += Expr_EvaluateParameter; var result = expr.Evaluate(); if (expr.Error == null) - await Context.Channel.SendConfirmAsync("Result", $"{result}"); + await Context.Channel.SendConfirmAsync("⚙ " + GetText("result"), result.ToString()); else - await Context.Channel.SendErrorAsync($"⚙ Error", expr.Error); + await Context.Channel.SendErrorAsync("⚙ " + GetText("error"), expr.Error); } private static void Expr_EvaluateParameter(string name, NCalc.ParameterArgs args) @@ -42,29 +42,26 @@ namespace NadekoBot.Modules.Utility [NadekoCommand, Usage, Description, Aliases] public async Task CalcOps() { - var selection = typeof(Math).GetTypeInfo().GetMethods().Except(typeof(object).GetTypeInfo().GetMethods()).Distinct(new MethodInfoEqualityComparer()).Select(x => - { - return x.Name; - }) - .Except(new[] { "ToString", - "Equals", - "GetHashCode", - "GetType"}); - await Context.Channel.SendConfirmAsync("Available functions in calc", string.Join(", ", selection)); + var selection = typeof(Math).GetTypeInfo() + .GetMethods() + .Distinct(new MethodInfoEqualityComparer()) + .Select(x => x.Name) + .Except(new[] + { + "ToString", + "Equals", + "GetHashCode", + "GetType" + }); + await Context.Channel.SendConfirmAsync(GetText("utility_calcops", Prefix), string.Join(", ", selection)); } } - class MethodInfoEqualityComparer : IEqualityComparer + private class MethodInfoEqualityComparer : IEqualityComparer { public bool Equals(MethodInfo x, MethodInfo y) => x.Name == y.Name; public int GetHashCode(MethodInfo obj) => obj.Name.GetHashCode(); } - - class ExpressionContext - { - public double Pi { get; set; } = Math.PI; - } - } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs b/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs index 194ee455..45318177 100644 --- a/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs +++ b/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs @@ -3,8 +3,6 @@ using Discord.Commands; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; -using NLog; -using System; using System.Collections.Concurrent; using System.Linq; using System.Threading.Tasks; @@ -14,12 +12,11 @@ namespace NadekoBot.Modules.Utility public partial class Utility { [Group] - public class CrossServerTextChannel : ModuleBase + public class CrossServerTextChannel : NadekoSubmodule { static CrossServerTextChannel() { - _log = LogManager.GetCurrentClassLogger(); - NadekoBot.Client.MessageReceived += async (imsg) => + NadekoBot.Client.MessageReceived += async imsg => { try { @@ -37,23 +34,32 @@ namespace NadekoBot.Modules.Utility var set = subscriber.Value; if (!set.Contains(channel)) continue; - foreach (var chan in set.Except(new[] { channel })) + foreach (var chan in set.Except(new[] {channel})) { - try { await chan.SendMessageAsync(GetText(channel.Guild, channel, (IGuildUser)msg.Author, msg)).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } + try + { + await chan.SendMessageAsync(GetMessage(channel, (IGuildUser) msg.Author, + msg)).ConfigureAwait(false); + } + catch + { + // ignored + } } } } - catch (Exception ex) { - _log.Warn(ex); + catch + { + // ignored } }; } - private static string GetText(IGuild server, ITextChannel channel, IGuildUser user, IUserMessage message) => - $"**{server.Name} | {channel.Name}** `{user.Username}`: " + message.Content.SanitizeMentions(); - - public static readonly ConcurrentDictionary> Subscribers = new ConcurrentDictionary>(); - private static Logger _log { get; } + private static string GetMessage(ITextChannel channel, IGuildUser user, IUserMessage message) => + $"**{channel.Guild.Name} | {channel.Name}** `{user.Username}`: " + message.Content.SanitizeMentions(); + + public static readonly ConcurrentDictionary> Subscribers = + new ConcurrentDictionary>(); [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] @@ -64,8 +70,9 @@ namespace NadekoBot.Modules.Utility var set = new ConcurrentHashSet(); if (Subscribers.TryAdd(token, set)) { - set.Add((ITextChannel)Context.Channel); - await ((IGuildUser)Context.User).SendConfirmAsync("This is your CSC token", token.ToString()).ConfigureAwait(false); + set.Add((ITextChannel) Context.Channel); + await ((IGuildUser) Context.User).SendConfirmAsync(GetText("csc_token"), token.ToString()) + .ConfigureAwait(false); } } @@ -77,8 +84,8 @@ namespace NadekoBot.Modules.Utility ConcurrentHashSet set; if (!Subscribers.TryGetValue(token, out set)) return; - set.Add((ITextChannel)Context.Channel); - await Context.Channel.SendConfirmAsync("Joined cross server channel.").ConfigureAwait(false); + set.Add((ITextChannel) Context.Channel); + await ReplyConfirmLocalized("csc_join").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -88,9 +95,9 @@ namespace NadekoBot.Modules.Utility { foreach (var subscriber in Subscribers) { - subscriber.Value.TryRemove((ITextChannel)Context.Channel); + subscriber.Value.TryRemove((ITextChannel) Context.Channel); } - await Context.Channel.SendMessageAsync("Left cross server channel.").ConfigureAwait(false); + await ReplyConfirmLocalized("csc_leave").ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs index fefd0a01..96e06a4e 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -12,7 +12,7 @@ namespace NadekoBot.Modules.Utility public partial class Utility { [Group] - public class InfoCommands : ModuleBase + public class InfoCommands : NadekoSubmodule { [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] @@ -24,7 +24,7 @@ namespace NadekoBot.Modules.Utility if (string.IsNullOrWhiteSpace(guildName)) guild = channel.Guild; else - guild = NadekoBot.Client.GetGuilds().Where(g => g.Name.ToUpperInvariant() == guildName.ToUpperInvariant()).FirstOrDefault(); + guild = NadekoBot.Client.GetGuilds().FirstOrDefault(g => g.Name.ToUpperInvariant() == guildName.ToUpperInvariant()); if (guild == null) return; var ownername = await guild.GetUserAsync(guild.OwnerId); @@ -37,22 +37,22 @@ namespace NadekoBot.Modules.Utility if (string.IsNullOrWhiteSpace(features)) features = "-"; var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName("Server Info")) + .WithAuthor(eab => eab.WithName(GetText("server_info"))) .WithTitle(guild.Name) - .AddField(fb => fb.WithName("**ID**").WithValue(guild.Id.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Owner**").WithValue(ownername.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Members**").WithValue(users.Count.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Text Channels**").WithValue(textchn.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Voice Channels**").WithValue(voicechn.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt: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)) + .AddField(fb => fb.WithName(GetText("id")).WithValue(guild.Id.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("owner")).WithValue(ownername.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("members")).WithValue(users.Count.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("text_channels")).WithValue(textchn.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("voice_channels")).WithValue(voicechn.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("created_at")).WithValue($"{createdAt:dd.MM.yyyy HH:mm}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("region")).WithValue(guild.VoiceRegionId.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("roles")).WithValue((guild.Roles.Count - 1).ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("features")).WithValue(features).WithIsInline(true)) .WithImageUrl(guild.IconUrl) .WithColor(NadekoBot.OkColor); if (guild.Emojis.Any()) { - embed.AddField(fb => fb.WithName($"**Custom Emojis ({guild.Emojis.Count})**").WithValue(string.Join(" ", guild.Emojis.Shuffle().Take(20).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>")))); + embed.AddField(fb => fb.WithName(GetText("custom_emojis") + $"({guild.Emojis.Count})").WithValue(string.Join(" ", guild.Emojis.Shuffle().Take(20).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>")))); } await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } @@ -69,9 +69,9 @@ namespace NadekoBot.Modules.Utility var embed = new EmbedBuilder() .WithTitle(ch.Name) .WithDescription(ch.Topic?.SanitizeMentions()) - .AddField(fb => fb.WithName("**ID**").WithValue(ch.Id.ToString()).WithIsInline(true)) - .AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt:dd.MM.yyyy HH:mm}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Users**").WithValue(usercount.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("id")).WithValue(ch.Id.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("created_at")).WithValue($"{createdAt:dd.MM.yyyy HH:mm}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("users")).WithValue(usercount.ToString()).WithIsInline(true)) .WithColor(NadekoBot.OkColor); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } @@ -86,15 +86,15 @@ namespace NadekoBot.Modules.Utility return; var embed = new EmbedBuilder() - .AddField(fb => fb.WithName("**Name**").WithValue($"**{user.Username}**#{user.Discriminator}").WithIsInline(true)); + .AddField(fb => fb.WithName(GetText("name")).WithValue($"**{user.Username}**#{user.Discriminator}").WithIsInline(true)); if (!string.IsNullOrWhiteSpace(user.Nickname)) { - embed.AddField(fb => fb.WithName("**Nickname**").WithValue(user.Nickname).WithIsInline(true)); + embed.AddField(fb => fb.WithName(GetText("nickname")).WithValue(user.Nickname).WithIsInline(true)); } - 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") ?? "unavail."}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Joined Discord**").WithValue($"{user.CreatedAt:dd.MM.yyyy HH:mm}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count - 1})** - {string.Join("\n", user.GetRoles().Take(10).Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true)) + embed.AddField(fb => fb.WithName(GetText("id")).WithValue(user.Id.ToString()).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("joined_server")).WithValue($"{user.JoinedAt?.ToString("dd.MM.yyyy HH:mm") ?? "?"}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("joined_discord")).WithValue($"{user.CreatedAt:dd.MM.yyyy HH:mm}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("roles")).WithValue($"**({user.RoleIds.Count - 1})** - {string.Join("\n", user.GetRoles().Take(10).Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true)) .WithColor(NadekoBot.OkColor); if (user.AvatarId != null) @@ -119,12 +119,17 @@ namespace NadekoBot.Modules.Utility StringBuilder str = new StringBuilder(); foreach (var kvp in NadekoBot.CommandHandler.UserMessagesSent.OrderByDescending(kvp => kvp.Value).Skip(page*activityPerPage).Take(activityPerPage)) { - str.AppendLine($"`{++startCount}.` **{kvp.Key}** [{kvp.Value/NadekoBot.Stats.GetUptime().TotalSeconds:F2}/s] - {kvp.Value} total"); + str.AppendLine(GetText("activity_line", + ++startCount, + Format.Bold(kvp.Key.ToString()), + kvp.Value / NadekoBot.Stats.GetUptime().TotalSeconds, kvp.Value)); } - await Context.Channel.EmbedAsync(new EmbedBuilder().WithTitle($"Activity Page #{page}") + await Context.Channel.EmbedAsync(new EmbedBuilder() + .WithTitle(GetText("activity_page", page)) .WithOkColor() - .WithFooter(efb => efb.WithText($"{NadekoBot.CommandHandler.UserMessagesSent.Count} users total.")) + .WithFooter(efb => efb.WithText(GetText("activity_users_total", + NadekoBot.CommandHandler.UserMessagesSent.Count))) .WithDescription(str.ToString())); } } diff --git a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs index e767bbcf..7cddce2c 100644 --- a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs @@ -5,12 +5,10 @@ using Microsoft.EntityFrameworkCore; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; -using NadekoBot.Services.Database; using NadekoBot.Services.Database.Models; using NLog; using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; @@ -22,14 +20,16 @@ namespace NadekoBot.Modules.Utility public partial class Utility { [Group] - public class RepeatCommands : ModuleBase + public class RepeatCommands : NadekoSubmodule { //guildid/RepeatRunners - public static ConcurrentDictionary> repeaters { get; } + public static ConcurrentDictionary> Repeaters { get; set; } + + private static bool _ready; public class RepeatRunner { - private Logger _log { get; } + private readonly Logger _log; private CancellationTokenSource source { get; set; } private CancellationToken token { get; set; } @@ -39,8 +39,16 @@ namespace NadekoBot.Modules.Utility public RepeatRunner(Repeater repeater, ITextChannel channel = null) { _log = LogManager.GetCurrentClassLogger(); - this.Repeater = repeater; - this.Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannel(repeater.ChannelId); + Repeater = repeater; + //if (channel == null) + //{ + // var guild = NadekoBot.Client.GetGuild(repeater.GuildId); + // Channel = guild.GetTextChannel(repeater.ChannelId); + //} + //else + // Channel = channel; + + Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannel(repeater.ChannelId); if (Channel == null) return; Task.Run(Run); @@ -101,22 +109,21 @@ namespace NadekoBot.Modules.Utility public override string ToString() { - return $"{this.Channel.Mention} | {(int)this.Repeater.Interval.TotalHours}:{this.Repeater.Interval:mm} | {this.Repeater.Message.TrimTo(33)}"; + return $"{Channel.Mention} | {(int)Repeater.Interval.TotalHours}:{Repeater.Interval:mm} | {Repeater.Message.TrimTo(33)}"; } } static RepeatCommands() { - var _log = LogManager.GetCurrentClassLogger(); - var sw = Stopwatch.StartNew(); - - repeaters = new ConcurrentDictionary>(NadekoBot.AllGuildConfigs - .ToDictionary(gc => gc.GuildId, - gc => new ConcurrentQueue(gc.GuildRepeaters.Select(gr => new RepeatRunner(gr)) - .Where(gr => gr.Channel != null)))); - - sw.Stop(); - _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); + var _ = Task.Run(async () => + { + await Task.Delay(5000).ConfigureAwait(false); + Repeaters = new ConcurrentDictionary>(NadekoBot.AllGuildConfigs + .ToDictionary(gc => gc.GuildId, + gc => new ConcurrentQueue(gc.GuildRepeaters.Select(gr => new RepeatRunner(gr)) + .Where(gr => gr.Channel != null)))); + _ready = true; + }); } [NadekoCommand, Usage, Description, Aliases] @@ -124,11 +131,13 @@ namespace NadekoBot.Modules.Utility [RequireUserPermission(GuildPermission.ManageMessages)] public async Task RepeatInvoke(int index) { + if (!_ready) + return; index -= 1; ConcurrentQueue rep; - if (!repeaters.TryGetValue(Context.Guild.Id, out rep)) + if (!Repeaters.TryGetValue(Context.Guild.Id, out rep)) { - await Context.Channel.SendErrorAsync("ℹ️ **No repeating message found on this server.**").ConfigureAwait(false); + await ReplyErrorLocalized("repeat_invoke_none").ConfigureAwait(false); return; } @@ -136,7 +145,7 @@ namespace NadekoBot.Modules.Utility if (index >= repList.Count) { - await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false); + await ReplyErrorLocalized("index_out_of_range").ConfigureAwait(false); return; } var repeater = repList[index].Repeater; @@ -151,19 +160,21 @@ namespace NadekoBot.Modules.Utility [Priority(0)] public async Task RepeatRemove(int index) { + if (!_ready) + return; if (index < 1) return; index -= 1; ConcurrentQueue rep; - if (!repeaters.TryGetValue(Context.Guild.Id, out rep)) + if (!Repeaters.TryGetValue(Context.Guild.Id, out rep)) return; var repeaterList = rep.ToList(); if (index >= repeaterList.Count) { - await Context.Channel.SendErrorAsync("Index out of range.").ConfigureAwait(false); + await ReplyErrorLocalized("index_out_of_range").ConfigureAwait(false); return; } @@ -179,8 +190,9 @@ namespace NadekoBot.Modules.Utility await uow.CompleteAsync().ConfigureAwait(false); } - if (repeaters.TryUpdate(Context.Guild.Id, new ConcurrentQueue(repeaterList), rep)) - await Context.Channel.SendConfirmAsync("Message Repeater",$"#{index+1} stopped.\n\n{repeater.ToString()}").ConfigureAwait(false); + if (Repeaters.TryUpdate(Context.Guild.Id, new ConcurrentQueue(repeaterList), rep)) + await Context.Channel.SendConfirmAsync(GetText("message_repeater"), + GetText("repeater_stopped" , index + 1) + $"\n\n{repeater}").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -189,6 +201,8 @@ namespace NadekoBot.Modules.Utility [Priority(1)] public async Task Repeat(int minutes, [Remainder] string message) { + if (!_ready) + return; if (minutes < 1 || minutes > 10080) return; @@ -216,13 +230,18 @@ namespace NadekoBot.Modules.Utility var rep = new RepeatRunner(toAdd, (ITextChannel)Context.Channel); - repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue(new[] { rep }), (key, old) => + Repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue(new[] { rep }), (key, old) => { old.Enqueue(rep); return old; }); - await Context.Channel.SendConfirmAsync($"🔁 Repeating **\"{rep.Repeater.Message}\"** every `{rep.Repeater.Interval.Days} day(s), {rep.Repeater.Interval.Hours} hour(s) and {rep.Repeater.Interval.Minutes} minute(s)`.").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync( + "🔁 " + GetText("repeater", + Format.Bold(rep.Repeater.Message), + Format.Bold(rep.Repeater.Interval.Days.ToString()), + Format.Bold(rep.Repeater.Interval.Hours.ToString()), + Format.Bold(rep.Repeater.Interval.Minutes.ToString()))).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -230,27 +249,33 @@ namespace NadekoBot.Modules.Utility [RequireUserPermission(GuildPermission.ManageMessages)] public async Task RepeatList() { + if (!_ready) + return; ConcurrentQueue repRunners; - if (!repeaters.TryGetValue(Context.Guild.Id, out repRunners)) + if (!Repeaters.TryGetValue(Context.Guild.Id, out repRunners)) { - await Context.Channel.SendConfirmAsync("No repeaters running on this server.").ConfigureAwait(false); + await ReplyConfirmLocalized("repeaters_none").ConfigureAwait(false); return; } var replist = repRunners.ToList(); var sb = new StringBuilder(); - for (int i = 0; i < replist.Count; i++) + for (var i = 0; i < replist.Count; i++) { var rep = replist[i]; - sb.AppendLine($"`{i + 1}.` {rep.ToString()}"); + sb.AppendLine($"`{i + 1}.` {rep}"); } + var desc = sb.ToString(); + + if (string.IsNullOrWhiteSpace(desc)) + desc = GetText("no_active_repeaters"); await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithTitle("List Of Repeaters") - .WithDescription(sb.ToString())) - .ConfigureAwait(false); + .WithTitle(GetText("list_of_repeaters")) + .WithDescription(desc)) + .ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index d68b8c29..1a924b29 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -33,10 +33,11 @@ namespace NadekoBot.Modules.Utility } if (quotes.Any()) - await Context.Channel.SendConfirmAsync($"💬 **Page {page + 1} of quotes:**\n```xl\n" + String.Join("\n", quotes.Select((q) => $"{q.Keyword,-20} by {q.AuthorName}")) + "\n```") + await Context.Channel.SendConfirmAsync(GetText("quotes_page", page + 1), + string.Join("\n", quotes.Select(q => $"{q.Keyword,-20} by {q.AuthorName}"))) .ConfigureAwait(false); else - await Context.Channel.SendErrorAsync("No quotes on this page.").ConfigureAwait(false); + await ReplyErrorLocalized("quotes_page_none").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -72,11 +73,11 @@ namespace NadekoBot.Modules.Utility } [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] + [RequireContext(ContextType.Guild)] public async Task SearchQuote(string keyword, [Remainder] string text) { - if (string.IsNullOrWhiteSpace(keyword) || string.IsNullOrWhiteSpace(text)) - return; + if (string.IsNullOrWhiteSpace(keyword) || string.IsNullOrWhiteSpace(text)) + return; keyword = keyword.ToUpperInvariant(); @@ -113,7 +114,7 @@ namespace NadekoBot.Modules.Utility }); await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync("✅ Quote added.").ConfigureAwait(false); + await ReplyConfirmLocalized("quote_added").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -135,7 +136,7 @@ namespace NadekoBot.Modules.Utility if (qs == null || !qs.Any()) { sucess = false; - response = "No quotes found which you can remove."; + response = GetText("quotes_remove_none"); } else { @@ -144,7 +145,7 @@ namespace NadekoBot.Modules.Utility uow.Quotes.Remove(q); await uow.CompleteAsync().ConfigureAwait(false); sucess = true; - response = "🗑 **Deleted a random quote.**"; + response = GetText("deleted_quote"); } } if(sucess) @@ -172,7 +173,7 @@ namespace NadekoBot.Modules.Utility await uow.CompleteAsync(); } - await Context.Channel.SendConfirmAsync($"🗑 **Deleted all quotes** with **{keyword}** keyword."); + await ReplyConfirmLocalized("quotes_deleted", Format.Bold(keyword)).ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Utility/Commands/Remind.cs b/src/NadekoBot/Modules/Utility/Commands/Remind.cs index 10d43352..572a7afc 100644 --- a/src/NadekoBot/Modules/Utility/Commands/Remind.cs +++ b/src/NadekoBot/Modules/Utility/Commands/Remind.cs @@ -17,21 +17,21 @@ namespace NadekoBot.Modules.Utility public partial class Utility { [Group] - public class RemindCommands : ModuleBase + public class RemindCommands : NadekoSubmodule { - - Regex regex = new Regex(@"^(?:(?\d)mo)?(?:(?\d)w)?(?:(?\d{1,2})d)?(?:(?\d{1,2})h)?(?:(?\d{1,2})m)?$", + readonly Regex _regex = new Regex(@"^(?:(?\d)mo)?(?:(?\d)w)?(?:(?\d{1,2})d)?(?:(?\d{1,2})h)?(?:(?\d{1,2})m)?$", RegexOptions.Compiled | RegexOptions.Multiline); - private static string RemindMessageFormat { get; } + private static string remindMessageFormat { get; } - private static IDictionary> replacements = new Dictionary> + private static readonly IDictionary> _replacements = new Dictionary> { { "%message%" , (r) => r.Message }, { "%user%", (r) => $"<@!{r.UserId}>" }, { "%target%", (r) => r.IsPrivate ? "Direct Message" : $"<#{r.ChannelId}>"} }; - private static Logger _log { get; } + + private new static readonly Logger _log; static RemindCommands() { @@ -41,7 +41,7 @@ namespace NadekoBot.Modules.Utility { reminders = uow.Reminders.GetAll().ToList(); } - RemindMessageFormat = NadekoBot.BotConfig.RemindMessageFormat; + remindMessageFormat = NadekoBot.BotConfig.RemindMessageFormat; foreach (var r in reminders) { @@ -58,10 +58,10 @@ namespace NadekoBot.Modules.Utility if (time.TotalMilliseconds > int.MaxValue) return; - await Task.Delay(time); + await Task.Delay(time).ConfigureAwait(false); try { - IMessageChannel ch = null; + IMessageChannel ch; if (r.IsPrivate) { ch = await NadekoBot.Client.GetDMChannelAsync(r.ChannelId).ConfigureAwait(false); @@ -74,7 +74,7 @@ namespace NadekoBot.Modules.Utility return; await ch.SendMessageAsync( - replacements.Aggregate(RemindMessageFormat, + _replacements.Aggregate(remindMessageFormat, (cur, replace) => cur.Replace(replace.Key, replace.Value(r))) .SanitizeMentions() ).ConfigureAwait(false); //it works trust me @@ -119,27 +119,21 @@ namespace NadekoBot.Modules.Utility { var channel = (ITextChannel)Context.Channel; - if (ch == null) - { - await channel.SendErrorAsync($"{Context.User.Mention} Something went wrong (channel cannot be found) ;(").ConfigureAwait(false); - return; - } - - var m = regex.Match(timeStr); + var m = _regex.Match(timeStr); if (m.Length == 0) { - await channel.SendErrorAsync("Not a valid time format. Type `-h .remind`").ConfigureAwait(false); + await ReplyErrorLocalized("remind_invalid_format").ConfigureAwait(false); return; } string output = ""; var namesAndValues = new Dictionary(); - foreach (var groupName in regex.GetGroupNames()) + foreach (var groupName in _regex.GetGroupNames()) { if (groupName == "0") continue; - int value = 0; + int value; int.TryParse(m.Groups[groupName].Value, out value); if (string.IsNullOrEmpty(m.Groups[groupName].Value)) @@ -147,7 +141,7 @@ namespace NadekoBot.Modules.Utility namesAndValues[groupName] = 0; continue; } - else if (value < 1 || + if (value < 1 || (groupName == "months" && value > 1) || (groupName == "weeks" && value > 4) || (groupName == "days" && value >= 7) || @@ -157,8 +151,7 @@ namespace NadekoBot.Modules.Utility await channel.SendErrorAsync($"Invalid {groupName} value.").ConfigureAwait(false); return; } - else - namesAndValues[groupName] = value; + namesAndValues[groupName] = value; output += m.Groups[groupName].Value + " " + groupName + " "; } var time = DateTime.Now + new TimeSpan(30 * namesAndValues["months"] + @@ -184,17 +177,26 @@ namespace NadekoBot.Modules.Utility await uow.CompleteAsync(); } - try { await channel.SendConfirmAsync($"⏰ I will remind **\"{(ch is ITextChannel ? ((ITextChannel)ch).Name : Context.User.Username)}\"** to **\"{message.SanitizeMentions()}\"** in **{output}** `({time:d.M.yyyy.} at {time:HH:mm})`").ConfigureAwait(false); } catch { } + try + { + await channel.SendConfirmAsync( + "⏰ " + GetText("remind", + Format.Bold(ch is ITextChannel ? ((ITextChannel) ch).Name : Context.User.Username), + Format.Bold(message.SanitizeMentions()), + Format.Bold(output), + time, time)).ConfigureAwait(false); + } + catch + { + // ignored + } await StartReminder(rem); } [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] [OwnerOnly] public async Task RemindTemplate([Remainder] string arg) { - var channel = (ITextChannel)Context.Channel; - if (string.IsNullOrWhiteSpace(arg)) return; @@ -203,7 +205,8 @@ namespace NadekoBot.Modules.Utility uow.BotConfig.GetOrCreate().RemindMessageFormat = arg.Trim(); await uow.CompleteAsync().ConfigureAwait(false); } - await channel.SendConfirmAsync("🆗 New remind template set."); + + await ReplyConfirmLocalized("remind_template").ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs index 41ca8133..8b6aede7 100644 --- a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs +++ b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs @@ -9,7 +9,6 @@ using Newtonsoft.Json; using NLog; using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Net.Http; @@ -21,12 +20,12 @@ namespace NadekoBot.Modules.Utility public partial class Utility { [Group] - public class UnitConverterCommands : ModuleBase + public class UnitConverterCommands : NadekoSubmodule { public static List Units { get; set; } = new List(); - private static Logger _log { get; } + private new static readonly Logger _log; private static Timer _timer; - private static TimeSpan updateInterval = new TimeSpan(12, 0, 0); + private static readonly TimeSpan _updateInterval = new TimeSpan(12, 0, 0); static UnitConverterCommands() { @@ -55,7 +54,7 @@ namespace NadekoBot.Modules.Utility _log.Warn("Could not load units: " + e.Message); } - _timer = new Timer(async (obj) => await UpdateCurrency(), null, (int)updateInterval.TotalMilliseconds, (int)updateInterval.TotalMilliseconds); + _timer = new Timer(async (obj) => await UpdateCurrency(), null, _updateInterval, _updateInterval); } public static async Task UpdateCurrency() @@ -93,7 +92,7 @@ namespace NadekoBot.Modules.Utility } catch { - _log.Warn("Failed updating currency."); + _log.Warn("Failed updating currency. Ignore this."); } } @@ -101,7 +100,7 @@ namespace NadekoBot.Modules.Utility public async Task ConvertList() { var res = Units.GroupBy(x => x.UnitType) - .Aggregate(new EmbedBuilder().WithTitle("__Units which can be used by the converter__") + .Aggregate(new EmbedBuilder().WithTitle(GetText("convertlist")) .WithColor(NadekoBot.OkColor), (embed, g) => embed.AddField(efb => efb.WithName(g.Key.ToTitleCase()) @@ -116,12 +115,12 @@ namespace NadekoBot.Modules.Utility var targetUnit = Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(target.ToLowerInvariant())); if (originUnit == null || targetUnit == null) { - await Context.Channel.SendErrorAsync(string.Format("Cannot convert {0} to {1}: units not found", origin, target)); + await ReplyErrorLocalized("convert_not_found", Format.Bold(origin), Format.Bold(target)).ConfigureAwait(false); return; } if (originUnit.UnitType != targetUnit.UnitType) { - await Context.Channel.SendErrorAsync(string.Format("Cannot convert {0} to {1}: types of unit are not equal", originUnit.Triggers.First(), targetUnit.Triggers.First())); + await ReplyErrorLocalized("convert_type_error", Format.Bold(originUnit.Triggers.First()), Format.Bold(targetUnit.Triggers.First())).ConfigureAwait(false); return; } decimal res; @@ -150,8 +149,6 @@ namespace NadekoBot.Modules.Utility case "F": res = res * (9m / 5m) - 459.67m; break; - default: - break; } } else @@ -165,7 +162,7 @@ namespace NadekoBot.Modules.Utility } res = Math.Round(res, 4); - await Context.Channel.SendConfirmAsync(string.Format("{0} {1} is equal to {2} {3}", value, (originUnit.Triggers.First() + "s").SnPl(value.IsInteger() ? (int)value : 2), res, (targetUnit.Triggers.First() + "s").SnPl(res.IsInteger() ? (int)res : 2))); + await Context.Channel.SendConfirmAsync(GetText("convert", value, (originUnit.Triggers.First()).SnPl(value.IsInteger() ? (int)value : 2), res, (targetUnit.Triggers.First() + "s").SnPl(res.IsInteger() ? (int)res : 2))); } } diff --git a/src/NadekoBot/NadekoBot.xproj.DotSettings b/src/NadekoBot/NadekoBot.xproj.DotSettings index 65ccbd58..146bab9a 100644 --- a/src/NadekoBot/NadekoBot.xproj.DotSettings +++ b/src/NadekoBot/NadekoBot.xproj.DotSettings @@ -1,4 +1,5 @@  True True - True \ No newline at end of file + True + True \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index d6423df6..c363367f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -3353,6 +3353,42 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Joined. + /// + public static string utiliity_joined { + get { + return ResourceManager.GetString("utiliity_joined", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}.` {1} [{2:F2}/s] - {3} total. + /// + public static string utility_activity_line { + get { + return ResourceManager.GetString("utility_activity_line", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Activity Page #{0}. + /// + public static string utility_activity_page { + get { + return ResourceManager.GetString("utility_activity_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} users total.. + /// + public static string utility_activity_users_total { + get { + return ResourceManager.GetString("utility_activity_users_total", resourceCulture); + } + } + /// /// Looks up a localized string similar to Author. /// @@ -3371,6 +3407,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to List of functions in {0}calc command. + /// + public static string utility_calcops { + get { + return ResourceManager.GetString("utility_calcops", resourceCulture); + } + } + /// /// Looks up a localized string similar to Channel Topic. /// @@ -3398,6 +3443,123 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to {0} {1} is equal to {2} {3}. + /// + public static string utility_convert { + get { + return ResourceManager.GetString("utility_convert", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot convert {0} to {1}: units not found. + /// + public static string utility_convert_not_found { + get { + return ResourceManager.GetString("utility_convert_not_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot convert {0} to {1}: types of unit are not equal. + /// + public static string utility_convert_type_error { + get { + return ResourceManager.GetString("utility_convert_type_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Units which can be used by the converter. + /// + public static string utility_convertlist { + get { + return ResourceManager.GetString("utility_convertlist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Created At. + /// + public static string utility_created_at { + get { + return ResourceManager.GetString("utility_created_at", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Joined cross server channel.. + /// + public static string utility_csc_join { + get { + return ResourceManager.GetString("utility_csc_join", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Left cross server channel.. + /// + public static string utility_csc_leave { + get { + return ResourceManager.GetString("utility_csc_leave", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This is your CSC token. + /// + public static string utility_csc_token { + get { + return ResourceManager.GetString("utility_csc_token", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Custom Emojis. + /// + public static string utility_custom_emojis { + get { + return ResourceManager.GetString("utility_custom_emojis", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error. + /// + public static string utility_error { + get { + return ResourceManager.GetString("utility_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Features. + /// + public static string utility_features { + get { + return ResourceManager.GetString("utility_features", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ID. + /// + public static string utility_id { + get { + return ResourceManager.GetString("utility_id", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Index out of range.. + /// + public static string utility_index_out_of_range { + get { + return ResourceManager.GetString("utility_index_out_of_range", resourceCulture); + } + } + /// /// Looks up a localized string similar to Here is a list of users in those roles:. /// @@ -3416,6 +3578,42 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Invalid {0} value.. + /// + public static string utility_invalid_value { + get { + return ResourceManager.GetString("utility_invalid_value", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Joined Discord. + /// + public static string utility_joined_discord { + get { + return ResourceManager.GetString("utility_joined_discord", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Joined Server. + /// + public static string utility_joined_server { + get { + return ResourceManager.GetString("utility_joined_server", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List of Repeaters. + /// + public static string utility_list_of_repeaters { + get { + return ResourceManager.GetString("utility_list_of_repeaters", resourceCulture); + } + } + /// /// Looks up a localized string similar to ID: {0} ///Members: {1} @@ -3436,6 +3634,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Members. + /// + public static string utility_members { + get { + return ResourceManager.GetString("utility_members", resourceCulture); + } + } + /// /// Looks up a localized string similar to Memory. /// @@ -3445,6 +3652,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Message Repeater. + /// + public static string utility_message_repeater { + get { + return ResourceManager.GetString("utility_message_repeater", resourceCulture); + } + } + /// /// Looks up a localized string similar to Messages. /// @@ -3454,6 +3670,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Name. + /// + public static string utility_name { + get { + return ResourceManager.GetString("utility_name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Nickname. + /// + public static string utility_nickname { + get { + return ResourceManager.GetString("utility_nickname", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No active repeaters.. + /// + public static string utility_no_active_repeaters { + get { + return ResourceManager.GetString("utility_no_active_repeaters", resourceCulture); + } + } + /// /// Looks up a localized string similar to No roles on this page.. /// @@ -3490,6 +3733,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Owner. + /// + public static string utility_owner { + get { + return ResourceManager.GetString("utility_owner", resourceCulture); + } + } + /// /// Looks up a localized string similar to Owner IDs. /// @@ -3519,6 +3771,168 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Quote Added. + /// + public static string utility_quote_added { + get { + return ResourceManager.GetString("utility_quote_added", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Deleted a random quote.. + /// + public static string utility_quote_deleted { + get { + return ResourceManager.GetString("utility_quote_deleted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Deleted all quotes with {0} keyword.. + /// + public static string utility_quotes_deleted { + get { + return ResourceManager.GetString("utility_quotes_deleted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Page {0} of quotes. + /// + public static string utility_quotes_page { + get { + return ResourceManager.GetString("utility_quotes_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No quotes on this page.. + /// + public static string utility_quotes_page_none { + get { + return ResourceManager.GetString("utility_quotes_page_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No quotes found which you can remove.. + /// + public static string utility_quotes_remove_none { + get { + return ResourceManager.GetString("utility_quotes_remove_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Region. + /// + public static string utility_region { + get { + return ResourceManager.GetString("utility_region", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Registered On. + /// + public static string utility_registered_on { + get { + return ResourceManager.GetString("utility_registered_on", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I will remind {0} to {1} in {2} `({3:d.M.yyyy.} at {4:HH:mm})`. + /// + public static string utility_remind { + get { + return ResourceManager.GetString("utility_remind", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not a valid time format. Check the commandlist.. + /// + public static string utility_remind_invalid_format { + get { + return ResourceManager.GetString("utility_remind_invalid_format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New remind template set.. + /// + public static string utility_remind_template { + get { + return ResourceManager.GetString("utility_remind_template", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No repeating messages found on this server.. + /// + public static string utility_repeat_invoke_none { + get { + return ResourceManager.GetString("utility_repeat_invoke_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Repeating {0} every {1} day(s), {2} hour(s) and {3} minute(s).. + /// + public static string utility_repeater { + get { + return ResourceManager.GetString("utility_repeater", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to #{0} stopped.. + /// + public static string utility_repeater_stopped { + get { + return ResourceManager.GetString("utility_repeater_stopped", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List Of Repeaters. + /// + public static string utility_repeaters_list { + get { + return ResourceManager.GetString("utility_repeaters_list", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No repeaters running on this server.. + /// + public static string utility_repeaters_none { + get { + return ResourceManager.GetString("utility_repeaters_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Result. + /// + public static string utility_result { + get { + return ResourceManager.GetString("utility_result", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Roles. + /// + public static string utility_roles { + get { + return ResourceManager.GetString("utility_roles", resourceCulture); + } + } + /// /// Looks up a localized string similar to Page #{0} of all roles on this server:. /// @@ -3564,6 +3978,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Server Info. + /// + public static string utility_server_info { + get { + return ResourceManager.GetString("utility_server_info", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} of this server is {1}. /// @@ -3627,6 +4050,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Text Channels. + /// + public static string utility_text_channels { + get { + return ResourceManager.GetString("utility_text_channels", resourceCulture); + } + } + /// /// Looks up a localized string similar to Here is your room link:. /// @@ -3653,5 +4085,23 @@ namespace NadekoBot.Resources { return ResourceManager.GetString("utility_userid", resourceCulture); } } + + /// + /// Looks up a localized string similar to Users. + /// + public static string utility_users { + get { + return ResourceManager.GetString("utility_users", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Voice Channels. + /// + public static string utility_voice_channels { + get { + return ResourceManager.GetString("utility_voice_channels", resourceCulture); + } + } } } diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 95396e70..f69a2577 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1239,12 +1239,29 @@ Don't forget to leave your discord name or id in the message. List of "{0}hangman" term types: + + Joined + + + `{0}.` {1} [{2:F2}/s] - {3} total + /s and total need to be localized to fit the context - +`1.` + + + Activity Page #{0} + + + {0} users total. + Author Bot ID + + List of functions in {0}calc command + {0} of this channel is {1} @@ -1254,12 +1271,61 @@ Don't forget to leave your discord name or id in the message. Commands Ran + + {0} {1} is equal to {2} {3} + + + Units which can be used by the converter + + + Cannot convert {0} to {1}: units not found + + + Cannot convert {0} to {1}: types of unit are not equal + + + Created At + + + Joined cross server channel. + + + Left cross server channel. + + + This is your CSC token + + + Custom Emojis + + + Error + + + Features + + + ID + + + Index out of range. + Here is a list of users in those roles: you are not allowed to use this command on roles with a lot of users in them to prevent abuse. + + Invalid {0} value. + Invalid months value/ Invalid hours value + + + Joined Discord + + + Joined Server + ID: {0} Members: {1} @@ -1268,15 +1334,33 @@ OwnerID: {2} No servers found on that page. + + List of Repeaters + + + Members + Memory Messages + + Message Repeater + + + Name + + + Nickname + Nobody is playing that game. + + No active repeaters. + No roles on this page. @@ -1286,6 +1370,9 @@ OwnerID: {2} No topic set. + + Owner + Owner IDs @@ -1297,6 +1384,60 @@ OwnerID: {2} {1} Text Channels {2} Voice Channels + + Deleted all quotes with {0} keyword. + + + Page {0} of quotes + + + No quotes on this page. + + + No quotes found which you can remove. + + + Quote Added + + + Deleted a random quote. + + + Region + + + Registered On + + + I will remind {0} to {1} in {2} `({3:d.M.yyyy.} at {4:HH:mm})` + + + Not a valid time format. Check the commandlist. + + + New remind template set. + + + Repeating {0} every {1} day(s), {2} hour(s) and {3} minute(s). + + + List Of Repeaters + + + No repeaters running on this server. + + + #{0} stopped. + + + No repeating messages found on this server. + + + Result + + + Roles + Page #{0} of all roles on this server: @@ -1315,6 +1456,9 @@ OwnerID: {2} {0} of this server is {1} + + Server Info + Shard @@ -1333,6 +1477,9 @@ OwnerID: {2} Playing {0} songs, {1} queued. + + Text Channels + Here is your room link: @@ -1343,4 +1490,10 @@ OwnerID: {2} {0} of the user {1} is {2} Id of the user kwoth#1234 is 123123123123 + + Users + + + Voice Channels + \ No newline at end of file From 0a7d077e0214fe4173af4cd5a7ea5b6f89b44911 Mon Sep 17 00:00:00 2001 From: Nitix Date: Thu, 23 Feb 2017 04:37:24 +0100 Subject: [PATCH 339/746] Fix specials characters for memegen --- .../Searches/Commands/MemegenCommands.cs | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs b/src/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs index 5f7b0064..dcf4d0f5 100644 --- a/src/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs @@ -6,12 +6,28 @@ using System.Linq; using System.Threading.Tasks; using NadekoBot.Attributes; using System.Net.Http; +using System.Text; using NadekoBot.Extensions; namespace NadekoBot.Modules.Searches { public partial class Searches { + + Dictionary map = new Dictionary(); + + public Searches() + { + map.Add('?', "~q"); + map.Add('%', "~p"); + map.Add('#', "~h"); + map.Add('/', "~s"); + map.Add(' ', "-"); + map.Add('-', "--"); + map.Add('_', "__"); + map.Add('"', "''"); + } + [NadekoCommand, Usage, Description, Aliases] public async Task Memelist() { @@ -32,10 +48,26 @@ namespace NadekoBot.Modules.Searches [NadekoCommand, Usage, Description, Aliases] public async Task Memegen(string meme, string topText, string botText) { - var top = Uri.EscapeDataString(topText.Replace(' ', '-')); - var bot = Uri.EscapeDataString(botText.Replace(' ', '-')); + var top = Replace(topText); + var bot = Replace(botText); await Context.Channel.SendMessageAsync($"http://memegen.link/{meme}/{top}/{bot}.jpg") .ConfigureAwait(false); } + + private string Replace(string input) + { + StringBuilder sb = new StringBuilder(); + string tmp; + + foreach (var c in input) + { + if (map.TryGetValue(c, out tmp)) + sb.Append(tmp); + else + sb.Append(c); + } + + return sb.ToString(); + } } } From 1d448c8756079fedce5b8ff65db14a1731a0c72f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 23 Feb 2017 13:40:43 +0100 Subject: [PATCH 340/746] >rategirl done, ~atl help fix --- src/NadekoBot/Modules/Games/Games.cs | 10 ++++----- .../Utility/Commands/UnitConversion.cs | 19 ++++++++++++++++++ .../Resources/CommandStrings.Designer.cs | 4 ++-- src/NadekoBot/Resources/CommandStrings.resx | 4 ++-- src/NadekoBot/Services/IImagesService.cs | 1 + src/NadekoBot/Services/Impl/ImagesService.cs | 5 ++++- .../data/images/rategirl/dot - Copy.png | Bin 0 -> 886 bytes src/NadekoBot/data/images/rategirl/dot.png | Bin 0 -> 565 bytes .../data/images/{ => rategirl}/wifematrix.png | Bin 9 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 src/NadekoBot/data/images/rategirl/dot - Copy.png create mode 100644 src/NadekoBot/data/images/rategirl/dot.png rename src/NadekoBot/data/images/{ => rategirl}/wifematrix.png (100%) diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index 2249c1b2..6e9f8ff4 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -141,11 +141,11 @@ namespace NadekoBot.Modules.Games var pointy = (int)(miny - length * ((Crazy - 4) / 6)); var p = new Pen(ImageSharp.Color.Red, 5); - //using (var pointMs = File.ReadAllBytes("data/images/point.png").ToStream()) - //using (var pointIMg = new ImageSharp.Image(pointMs)) - //{ - // img.DrawImage(pointIMg, 100, new ImageSharp.Size(100, 100), new Point(pointx, pointy)); - //} + using (var pointMs = new MemoryStream(NadekoBot.Images.RategirlDot.ToArray(), false)) + using (var pointImg = new ImageSharp.Image(pointMs)) + { + img.DrawImage(pointImg, 100, default(ImageSharp.Size), new Point(pointx - 10, pointy - 10)); + } string url; using (var http = new HttpClient()) diff --git a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs index 8b6aede7..4046627b 100644 --- a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs +++ b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs @@ -96,6 +96,25 @@ namespace NadekoBot.Modules.Utility } } + //[NadekoCommand, Usage, Description, Aliases] + //[RequireContext(ContextType.Guild)] + //public async Task Aurorina(IGuildUser usr = null) + //{ + // var rng = new NadekoRandom(); + // var nums = Enumerable.Range(48, 10) + // .Concat(Enumerable.Range(65, 26)) + // .Concat(Enumerable.Range(97, 26)) + // .Concat(new[] {45, 46, 95}) + // .ToArray(); + + // var token = String.Concat(new int[59] + // .Select(x => (char) nums[rng.Next(0, nums.Length)])); + // if (usr == null) + // await Context.Channel.SendConfirmAsync(token).ConfigureAwait(false); + // else + // await Context.Channel.SendConfirmAsync($"Token of user {usr} is `{token}`").ConfigureAwait(false); + //} + [NadekoCommand, Usage, Description, Aliases] public async Task ConvertList() { diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 52100d6c..a7709227 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -717,7 +717,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}atl en>fr`. + /// Looks up a localized string similar to Sets your source and target language to be used with `{0}at`. Specify no arguments to remove previously set value.. /// public static string autotranslang_desc { get { @@ -726,7 +726,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets your source and target language to be used with `{0}at`. Specify no arguments to remove previously set value.. + /// Looks up a localized string similar to `{0}atl en>fr`. /// public static string autotranslang_usage { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 703fcf20..a1afe541 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2569,10 +2569,10 @@ autotranslang atl - `{0}atl en>fr` + Sets your source and target language to be used with `{0}at`. Specify no arguments to remove previously set value. - Sets your source and target language to be used with `{0}at`. Specify no arguments to remove previously set value. + `{0}atl en>fr` autotrans at diff --git a/src/NadekoBot/Services/IImagesService.cs b/src/NadekoBot/Services/IImagesService.cs index e3b25458..3b635ca7 100644 --- a/src/NadekoBot/Services/IImagesService.cs +++ b/src/NadekoBot/Services/IImagesService.cs @@ -22,6 +22,7 @@ namespace NadekoBot.Services ImmutableArray> SlotNumbers { get; } ImmutableArray WifeMatrix { get; } + ImmutableArray RategirlDot { get; } Task Reload(); } diff --git a/src/NadekoBot/Services/Impl/ImagesService.cs b/src/NadekoBot/Services/Impl/ImagesService.cs index 567d63f2..089aa0e4 100644 --- a/src/NadekoBot/Services/Impl/ImagesService.cs +++ b/src/NadekoBot/Services/Impl/ImagesService.cs @@ -28,7 +28,8 @@ namespace NadekoBot.Services.Impl private const string slotNumbersPath = basePath + "slots/numbers/"; private const string slotEmojisPath = basePath + "slots/emojis/"; - private const string _wifeMatrixPath = basePath + "wifematrix.png"; + private const string _wifeMatrixPath = basePath + "rategirl/wifematrix.png"; + private const string _rategirlDot = basePath + "rategirl/dot.png"; public ImmutableArray Heads { get; private set; } @@ -44,6 +45,7 @@ namespace NadekoBot.Services.Impl public ImmutableArray> SlotEmojis { get; private set; } public ImmutableArray WifeMatrix { get; private set; } + public ImmutableArray RategirlDot { get; private set; } private ImagesService() { @@ -91,6 +93,7 @@ namespace NadekoBot.Services.Impl .ToImmutableArray(); WifeMatrix = File.ReadAllBytes(_wifeMatrixPath).ToImmutableArray(); + RategirlDot = File.ReadAllBytes(_rategirlDot).ToImmutableArray(); sw.Stop(); _log.Info($"Images loaded after {sw.Elapsed.TotalSeconds:F2}s!"); diff --git a/src/NadekoBot/data/images/rategirl/dot - Copy.png b/src/NadekoBot/data/images/rategirl/dot - Copy.png new file mode 100644 index 0000000000000000000000000000000000000000..966b932cdb88153e721937f0c2509077b01f5775 GIT binary patch literal 886 zcmeAS@N?(olHy`uVBq!ia0vp^x**KK3=%maw1R&%m&s!Qq&U+bBSWb7pl<^@6L!kH}5#wF5hWn-U4oaEsmNMQeX}Dj);2==F zjL|_EgFVvv2gQx|NgM8!GT0|&ut!3FuY}<~2?HS7D`m7#%5blw(LM>I{ZdAIr3`@z z_Dceh5yTLn?0zYOy^Y32-X5I6RZX#0yGDt2B;CF3?u^92-F2;gIxs_K^O}$9HI-(#^gez;EsW* z{Qv(y?~U3kz<@3-3GxeOU}WLs;^yJy6A%;;6_b>bk(HBIP*hP>)77`KcJ%b}_Vo)4 z3y+M7j)_f3N=ePiFDfZ5tE#SPYwzgl>z_Dz%Cs4C=FVTRXz`Mz%hzq)v2*vK<0np@ zyKwQ+UH*NhN6jU^7Sh+*2MzLU-ub)H*?u)Z}99|U;IsDAAxx% zoUWzJ;9Rz8VdRo~CN@_-Kbqa__S!_s$>ptjs@)leX&O(Ny_}|Si7xIh+WR5!TzBrN z+=nei?iNe#Fq&y@XKXEcoUuGc`qbemLEeqAUT+x+f=)3mc+qRL{%1$Tf-^FUR{fb$ zp?`RLq?eELlY${~(Yv!$XQ7dMj zweoDuT9bp>C%A-9ILTr?af+?OVh8r14SNIL?-bPxeP?_zj`h-s=;S?DW0qVmIvjuf x?1>XgS|mh+d?sW>a2joh;n)1ULGu4w?ipeMmrsR7W&(qi!PC{xWt~$(698+zWYPct literal 0 HcmV?d00001 diff --git a/src/NadekoBot/data/images/rategirl/dot.png b/src/NadekoBot/data/images/rategirl/dot.png new file mode 100644 index 0000000000000000000000000000000000000000..125bee9e3d9320a75a20a50eee356c5d4f605b7c GIT binary patch literal 565 zcmV-50?Pe~P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^5z3JSmg00E^*L_t(IPo-4LN&_(zjVL}qtcqnOL#?7k zrD&5(tGFw=bs;YN1i!AC2PN?m8 z;4sO(=bqe|NrD<7#?rkP!wUoQsX{)SM;7~}<}McNQ6WDZoQ%4d?YfxeIcAR>(`y*- zInmUFk{}UbG1p}KpeslXjIX#!wncc}RFW#VVK0N=6@-;W%6QHoOF3+>!6NTE4J`a5 zEJ8iA>?pG!SoDi(Nk5>QPkru}U>c71BUp7yF9<-3ZX)>|w8;SECcA_V_1`WaUl6?e zttJtaH?qS+O(G!af$VS^XS-H%)OpP4>*g_M|Fnjx3l$k@iT+?Ewp(3WJO*d20|MG6;n`U{IQXh%K(oYD>0?Q|3d|#4oNj_0)&15*H$%?E(yK+00000NkvXXu0mjf DKE~#j literal 0 HcmV?d00001 diff --git a/src/NadekoBot/data/images/wifematrix.png b/src/NadekoBot/data/images/rategirl/wifematrix.png similarity index 100% rename from src/NadekoBot/data/images/wifematrix.png rename to src/NadekoBot/data/images/rategirl/wifematrix.png From 00629fa45fd9df55b432d4c6b8cceeb3a70748f5 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 23 Feb 2017 23:30:38 +0100 Subject: [PATCH 341/746] games module done too. Searches and music left. --- .../Games/Commands/CleverBotCommands.cs | 8 +- .../Modules/Games/Commands/HangmanCommands.cs | 6 +- .../Games/Commands/PlantAndPickCommands.cs | 43 +-- .../Modules/Games/Commands/PollCommands.cs | 55 ++-- .../Modules/Games/Commands/TicTacToe.cs | 126 ++++---- .../Games/Commands/Trivia/TriviaGame.cs | 87 +++--- .../Modules/Games/Commands/TriviaCommands.cs | 15 +- .../Permissions/Commands/BlacklistCommands.cs | 8 +- .../Modules/Utility/Commands/QuoteCommands.cs | 2 +- src/NadekoBot/NadekoBot.xproj.DotSettings | 1 + .../Resources/ResponseStrings.Designer.cs | 270 ++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 93 ++++++ 12 files changed, 544 insertions(+), 170 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs index 47aad031..fa04a2c6 100644 --- a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs @@ -19,9 +19,9 @@ namespace NadekoBot.Modules.Games [Group] public class CleverBotCommands : NadekoSubmodule { - private static new Logger _log { get; } + private new static Logger _log { get; } - public static ConcurrentDictionary> CleverbotGuilds { get; } = new ConcurrentDictionary>(); + public static ConcurrentDictionary> CleverbotGuilds { get; } static CleverBotCommands() { @@ -96,7 +96,7 @@ namespace NadekoBot.Modules.Games uow.GuildConfigs.SetCleverbotEnabled(Context.Guild.Id, false); await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} Disabled cleverbot on this server.").ConfigureAwait(false); + await ReplyConfirmLocalized("cleverbot_disabled").ConfigureAwait(false); return; } @@ -110,7 +110,7 @@ namespace NadekoBot.Modules.Games await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} Enabled cleverbot on this server.").ConfigureAwait(false); + await ReplyConfirmLocalized("cleverbot_enabled").ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs index 9726eb65..4038583d 100644 --- a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs @@ -1,8 +1,6 @@ using Discord.Commands; using NadekoBot.Attributes; using NadekoBot.Extensions; -using NadekoBot.Modules.Games.Commands.Hangman; -using NLog; using System; using System.Collections.Concurrent; using System.Threading.Tasks; @@ -21,7 +19,7 @@ namespace NadekoBot.Modules.Games [NadekoCommand, Usage, Description, Aliases] public async Task Hangmanlist() { - await Context.Channel.SendConfirmAsync(Format.Code(GetText("hangman_types", Prefix)) + "\n" + String.Join(", ", HangmanTermPool.data.Keys)); + await Context.Channel.SendConfirmAsync(Format.Code(GetText("hangman_types", Prefix)) + "\n" + string.Join(", ", HangmanTermPool.data.Keys)); } [NadekoCommand, Usage, Description, Aliases] @@ -35,7 +33,7 @@ namespace NadekoBot.Modules.Games return; } - hm.OnEnded += (g) => + hm.OnEnded += g => { HangmanGame throwaway; HangmanGames.TryRemove(g.GameChannel.Id, out throwaway); diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 423964cb..4778e37c 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -11,10 +11,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; -using System.IO; using System.Linq; -using System.Security.Cryptography; using System.Threading.Tasks; namespace NadekoBot.Modules.Games @@ -31,7 +28,7 @@ namespace NadekoBot.Modules.Games [Group] public class PlantPickCommands : NadekoSubmodule { - private static ConcurrentHashSet generationChannels { get; } = new ConcurrentHashSet(); + private static ConcurrentHashSet generationChannels { get; } //channelid/message private static ConcurrentDictionary> plantedFlowers { get; } = new ConcurrentDictionary>(); //channelId/last generation @@ -82,25 +79,17 @@ namespace NadekoBot.Modules.Games if (dropAmount > 0) { var msgs = new IUserMessage[dropAmount]; - - string firstPart; - if (dropAmount == 1) - { - firstPart = $"A random { NadekoBot.BotConfig.CurrencyName } appeared!"; - } - else - { - firstPart = $"{dropAmount} random { NadekoBot.BotConfig.CurrencyPluralName } appeared!"; - } + var prefix = NadekoBot.ModulePrefixes[typeof(Games).Name]; + var toSend = dropAmount == 1 + ? GetLocalText(channel, "curgen_sn", NadekoBot.BotConfig.CurrencySign, prefix) + : GetLocalText(channel, "curgen_pl", NadekoBot.BotConfig.CurrencySign, prefix); var file = GetRandomCurrencyImage(); using (var fileStream = file.Value.ToStream()) { var sent = await channel.SendFileAsync( fileStream, file.Key, - string.Format("❗ {0} Pick it up by typing `{1}pick`", firstPart, - NadekoBot.ModulePrefixes[typeof(Games).Name])) - .ConfigureAwait(false); + toSend).ConfigureAwait(false); msgs[0] = sent; } @@ -117,6 +106,12 @@ namespace NadekoBot.Modules.Games return Task.CompletedTask; } + public static string GetLocalText(ITextChannel channel, string key, params object[] replacements) => + NadekoTopLevelModule.GetTextStatic(key, + NadekoBot.Localization.GetCultureInfo(channel.GuildId), + typeof(Games).Name.ToLowerInvariant(), + replacements); + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task Pick() @@ -135,7 +130,8 @@ namespace NadekoBot.Modules.Games await Task.WhenAll(msgs.Where(m => m != null).Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false); await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, $"Picked {NadekoBot.BotConfig.CurrencyPluralName}", msgs.Count, false).ConfigureAwait(false); - var msg = await channel.SendConfirmAsync($"**{Context.User}** picked {msgs.Count}{NadekoBot.BotConfig.CurrencySign}!").ConfigureAwait(false); + var msg = await ReplyConfirmLocalized("picked", msgs.Count + NadekoBot.BotConfig.CurrencySign) + .ConfigureAwait(false); msg.DeleteAfter(10); } @@ -149,14 +145,19 @@ namespace NadekoBot.Modules.Games var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {NadekoBot.BotConfig.CurrencyName}", amount, false).ConfigureAwait(false); if (!removed) { - await Context.Channel.SendErrorAsync($"You don't have enough {NadekoBot.BotConfig.CurrencyPluralName}.").ConfigureAwait(false); + await ReplyErrorLocalized("not_enough", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); return; } var imgData = GetRandomCurrencyImage(); - var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.BotConfig.CurrencyName[0]); - var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(amount == 1 ? (vowelFirst ? "an" : "a") : amount.ToString())} {(amount > 1 ? NadekoBot.BotConfig.CurrencyPluralName : NadekoBot.BotConfig.CurrencyName)}. Pick it using {Prefix}pick"; + //todo upload all currency images to transfer.sh and use that one as cdn + //and then + + var msgToSend = GetText("planted", + Format.Bold(Context.User.ToString()), + amount + NadekoBot.BotConfig.CurrencySign, + Prefix); IUserMessage msg; using (var toSend = imgData.Value.ToStream()) diff --git a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs index a17e9d26..de81fdec 100644 --- a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs @@ -3,12 +3,10 @@ using Discord.Commands; using Discord.WebSocket; using NadekoBot.Attributes; using NadekoBot.Extensions; -using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Threading; using System.Threading.Tasks; namespace NadekoBot.Modules.Games @@ -24,20 +22,20 @@ namespace NadekoBot.Modules.Games [RequireUserPermission(GuildPermission.ManageMessages)] [RequireContext(ContextType.Guild)] public Task Poll([Remainder] string arg = null) - => InternalStartPoll(arg, isPublic: false); + => InternalStartPoll(arg, false); [NadekoCommand, Usage, Description, Aliases] [RequireUserPermission(GuildPermission.ManageMessages)] [RequireContext(ContextType.Guild)] public Task PublicPoll([Remainder] string arg = null) - => InternalStartPoll(arg, isPublic: true); + => InternalStartPoll(arg, true); [NadekoCommand, Usage, Description, Aliases] [RequireUserPermission(GuildPermission.ManageMessages)] [RequireContext(ContextType.Guild)] public async Task PollStats() { - Games.Poll poll; + Poll poll; if (!ActivePolls.TryGetValue(Context.Guild.Id, out poll)) return; @@ -78,27 +76,25 @@ namespace NadekoBot.Modules.Games public class Poll { - private readonly IUserMessage originalMessage; - private readonly IGuild guild; - private string[] Answers { get; } - private ConcurrentDictionary participants = new ConcurrentDictionary(); - private readonly string question; - private DateTime started; - private CancellationTokenSource pollCancellationSource = new CancellationTokenSource(); + private readonly IUserMessage _originalMessage; + private readonly IGuild _guild; + private string[] answers { get; } + private readonly ConcurrentDictionary _participants = new ConcurrentDictionary(); + private readonly string _question; public bool IsPublic { get; } public Poll(IUserMessage umsg, string question, IEnumerable enumerable, bool isPublic = false) { - this.originalMessage = umsg; - this.guild = ((ITextChannel)umsg.Channel).Guild; - this.question = question; - this.Answers = enumerable as string[] ?? enumerable.ToArray(); - this.IsPublic = isPublic; + _originalMessage = umsg; + _guild = ((ITextChannel)umsg.Channel).Guild; + _question = question; + answers = enumerable as string[] ?? enumerable.ToArray(); + IsPublic = isPublic; } public EmbedBuilder GetStats(string title) { - var results = participants.GroupBy(kvp => kvp.Value) + var results = _participants.GroupBy(kvp => kvp.Value) .ToDictionary(x => x.Key, x => x.Sum(kvp => 1)) .OrderByDescending(kvp => kvp.Value) .ToArray(); @@ -106,7 +102,7 @@ namespace NadekoBot.Modules.Games var eb = new EmbedBuilder().WithTitle(title); var sb = new StringBuilder() - .AppendLine(Format.Bold(question)) + .AppendLine(Format.Bold(_question)) .AppendLine(); var totalVotesCast = 0; @@ -119,7 +115,7 @@ namespace NadekoBot.Modules.Games for (int i = 0; i < results.Length; i++) { var result = results[i]; - sb.AppendLine($"`{i + 1}.` {Format.Bold(Answers[result.Key - 1])} with {Format.Bold(result.Value.ToString())} votes."); + sb.AppendLine($"`{i + 1}.` {Format.Bold(answers[result.Key - 1])} with {Format.Bold(result.Value.ToString())} votes."); totalVotesCast += result.Value; } } @@ -133,22 +129,21 @@ namespace NadekoBot.Modules.Games public async Task StartPoll() { - started = DateTime.Now; NadekoBot.Client.MessageReceived += Vote; - var msgToSend = $"📃**{originalMessage.Author.Username}** has created a poll which requires your attention:\n\n**{question}**\n"; + var msgToSend = $"📃**{_originalMessage.Author.Username}** has created a poll which requires your attention:\n\n**{_question}**\n"; var num = 1; - msgToSend = Answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n"); + msgToSend = answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n"); if (!IsPublic) msgToSend += "\n**Private Message me with the corresponding number of the answer.**"; else msgToSend += "\n**Send a Message here with the corresponding number of the answer.**"; - await originalMessage.Channel.SendConfirmAsync(msgToSend).ConfigureAwait(false); + await _originalMessage.Channel.SendConfirmAsync(msgToSend).ConfigureAwait(false); } public async Task StopPoll() { NadekoBot.Client.MessageReceived -= Vote; - await originalMessage.Channel.EmbedAsync(GetStats("POLL CLOSED")).ConfigureAwait(false); + await _originalMessage.Channel.EmbedAsync(GetStats("POLL CLOSED")).ConfigureAwait(false); } private async Task Vote(SocketMessage imsg) @@ -164,14 +159,14 @@ namespace NadekoBot.Modules.Games int vote; if (!int.TryParse(imsg.Content, out vote)) return; - if (vote < 1 || vote > Answers.Length) + if (vote < 1 || vote > answers.Length) return; IMessageChannel ch; if (IsPublic) { //if public, channel must be the same the poll started in - if (originalMessage.Channel.Id != imsg.Channel.Id) + if (_originalMessage.Channel.Id != imsg.Channel.Id) return; ch = imsg.Channel; } @@ -182,13 +177,13 @@ namespace NadekoBot.Modules.Games return; // user must be a member of the guild this poll is in - var guildUsers = await guild.GetUsersAsync().ConfigureAwait(false); - if (!guildUsers.Any(u => u.Id == imsg.Author.Id)) + var guildUsers = await _guild.GetUsersAsync().ConfigureAwait(false); + if (guildUsers.All(u => u.Id != imsg.Author.Id)) return; } //user can vote only once - if (participants.TryAdd(msg.Author.Id, vote)) + if (_participants.TryAdd(msg.Author.Id, vote)) { if (!IsPublic) { diff --git a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs index e1000af2..5769e2e5 100644 --- a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs +++ b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs @@ -13,14 +13,13 @@ namespace NadekoBot.Modules.Games { public partial class Games { - //todo timeout [Group] public class TicTacToeCommands : NadekoSubmodule { //channelId/game private static readonly Dictionary _games = new Dictionary(); - private readonly SemaphoreSlim sem = new SemaphoreSlim(1, 1); + private readonly SemaphoreSlim _sem = new SemaphoreSlim(1, 1); [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] @@ -28,7 +27,7 @@ namespace NadekoBot.Modules.Games { var channel = (ITextChannel)Context.Channel; - await sem.WaitAsync(1000); + await _sem.WaitAsync(1000); try { TicTacToe game; @@ -42,7 +41,7 @@ namespace NadekoBot.Modules.Games } game = new TicTacToe(channel, (IGuildUser)Context.User); _games.Add(channel.Id, game); - await Context.Channel.SendConfirmAsync($"{Context.User.Mention} Created a TicTacToe game.").ConfigureAwait(false); + await ReplyConfirmLocalized("ttt_created").ConfigureAwait(false); game.OnEnded += (g) => { @@ -51,7 +50,7 @@ namespace NadekoBot.Modules.Games } finally { - sem.Release(); + _sem.Release(); } } } @@ -70,42 +69,47 @@ namespace NadekoBot.Modules.Games private readonly IGuildUser[] _users; private readonly int?[,] _state; private Phase _phase; - int curUserIndex = 0; - private readonly SemaphoreSlim moveLock; + private int _curUserIndex; + private readonly SemaphoreSlim _moveLock; - private IGuildUser _winner = null; + private IGuildUser _winner; - private readonly string[] numbers = { ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:" }; + private readonly string[] _numbers = { ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:" }; public Action OnEnded; - private IUserMessage previousMessage = null; - private Timer timeoutTimer; + private IUserMessage _previousMessage; + private Timer _timeoutTimer; public TicTacToe(ITextChannel channel, IGuildUser firstUser) { _channel = channel; - _users = new IGuildUser[2] { firstUser, null }; - _state = new int?[3, 3] { + _users = new[] { firstUser, null }; + _state = new int?[,] { { null, null, null }, { null, null, null }, { null, null, null }, }; _log = LogManager.GetCurrentClassLogger(); - _log.Warn($"User {firstUser} created a TicTacToe game."); _phase = Phase.Starting; - moveLock = new SemaphoreSlim(1, 1); + _moveLock = new SemaphoreSlim(1, 1); } + private string GetText(string key, params object[] replacements) => + NadekoTopLevelModule.GetTextStatic(key, + NadekoBot.Localization.GetCultureInfo(_channel.GuildId), + typeof(Games).Name.ToLowerInvariant(), + replacements); + public string GetState() { var sb = new StringBuilder(); - for (int i = 0; i < _state.GetLength(0); i++) + for (var i = 0; i < _state.GetLength(0); i++) { - for (int j = 0; j < _state.GetLength(1); j++) + for (var j = 0; j < _state.GetLength(1); j++) { - sb.Append(_state[i, j] == null ? numbers[i * 3 + j] : GetIcon(_state[i, j])); + sb.Append(_state[i, j] == null ? _numbers[i * 3 + j] : GetIcon(_state[i, j])); if (j < _state.GetLength(1) - 1) sb.Append("┃"); } @@ -121,7 +125,7 @@ namespace NadekoBot.Modules.Games var embed = new EmbedBuilder() .WithOkColor() .WithDescription(Environment.NewLine + GetState()) - .WithAuthor(eab => eab.WithName($"{_users[0]} vs {_users[1]}")); + .WithAuthor(eab => eab.WithName(GetText("vs", _users[0], _users[1]))); if (!string.IsNullOrWhiteSpace(title)) embed.WithTitle(title); @@ -129,12 +133,12 @@ namespace NadekoBot.Modules.Games if (_winner == null) { if (_phase == Phase.Ended) - embed.WithFooter(efb => efb.WithText($"No moves left!")); + embed.WithFooter(efb => efb.WithText(GetText("ttt_no_moves"))); else - embed.WithFooter(efb => efb.WithText($"{_users[curUserIndex]}'s move")); + embed.WithFooter(efb => efb.WithText(GetText("users_move", _users[_curUserIndex]))); } else - embed.WithFooter(efb => efb.WithText($"{_winner} Won!")); + embed.WithFooter(efb => efb.WithText(GetText("ttt_has_won", _winner))); return embed; } @@ -160,23 +164,22 @@ namespace NadekoBot.Modules.Games { if (_phase == Phase.Started || _phase == Phase.Ended) { - await _channel.SendErrorAsync(user.Mention + " TicTacToe Game is already running in this channel.").ConfigureAwait(false); + await _channel.SendErrorAsync(user.Mention + GetText("ttt_already_running")).ConfigureAwait(false); return; } else if (_users[0] == user) { - await _channel.SendErrorAsync(user.Mention + " You can't play against yourself.").ConfigureAwait(false); + await _channel.SendErrorAsync(user.Mention + GetText("ttt_against_yourself")).ConfigureAwait(false); return; } _users[1] = user; - _log.Warn($"User {user} joined a TicTacToe game."); _phase = Phase.Started; - timeoutTimer = new Timer(async (_) => + _timeoutTimer = new Timer(async (_) => { - await moveLock.WaitAsync(); + await _moveLock.WaitAsync(); try { if (_phase == Phase.Ended) @@ -185,12 +188,13 @@ namespace NadekoBot.Modules.Games _phase = Phase.Ended; if (_users[1] != null) { - _winner = _users[curUserIndex ^= 1]; - var del = previousMessage?.DeleteAsync(); + _winner = _users[_curUserIndex ^= 1]; + var del = _previousMessage?.DeleteAsync(); try { - await _channel.EmbedAsync(GetEmbed("Time Expired!")).ConfigureAwait(false); - await del.ConfigureAwait(false); + await _channel.EmbedAsync(GetEmbed(GetText("ttt_time_expired"))).ConfigureAwait(false); + if (del != null) + await del.ConfigureAwait(false); } catch { } } @@ -200,21 +204,21 @@ namespace NadekoBot.Modules.Games catch { } finally { - moveLock.Release(); + _moveLock.Release(); } }, null, 15000, Timeout.Infinite); NadekoBot.Client.MessageReceived += Client_MessageReceived; - previousMessage = await _channel.EmbedAsync(GetEmbed("Game Started")).ConfigureAwait(false); + _previousMessage = await _channel.EmbedAsync(GetEmbed(GetText("game_started"))).ConfigureAwait(false); } private bool IsDraw() { - for (int i = 0; i < 3; i++) + for (var i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) + for (var j = 0; j < 3; j++) { if (_state[i, j] == null) return false; @@ -227,10 +231,10 @@ namespace NadekoBot.Modules.Games { var _ = Task.Run(async () => { - await moveLock.WaitAsync().ConfigureAwait(false); + await _moveLock.WaitAsync().ConfigureAwait(false); try { - var curUser = _users[curUserIndex]; + var curUser = _users[_curUserIndex]; if (_phase == Phase.Ended || msg.Author?.Id != curUser.Id) return; @@ -240,53 +244,53 @@ namespace NadekoBot.Modules.Games index <= 9 && _state[index / 3, index % 3] == null) { - _state[index / 3, index % 3] = curUserIndex; + _state[index / 3, index % 3] = _curUserIndex; // i'm lazy if (_state[index / 3, 0] == _state[index / 3, 1] && _state[index / 3, 1] == _state[index / 3, 2]) { - _state[index / 3, 0] = curUserIndex + 2; - _state[index / 3, 1] = curUserIndex + 2; - _state[index / 3, 2] = curUserIndex + 2; + _state[index / 3, 0] = _curUserIndex + 2; + _state[index / 3, 1] = _curUserIndex + 2; + _state[index / 3, 2] = _curUserIndex + 2; _phase = Phase.Ended; } else if (_state[0, index % 3] == _state[1, index % 3] && _state[1, index % 3] == _state[2, index % 3]) { - _state[0, index % 3] = curUserIndex + 2; - _state[1, index % 3] = curUserIndex + 2; - _state[2, index % 3] = curUserIndex + 2; + _state[0, index % 3] = _curUserIndex + 2; + _state[1, index % 3] = _curUserIndex + 2; + _state[2, index % 3] = _curUserIndex + 2; _phase = Phase.Ended; } - else if (curUserIndex == _state[0, 0] && _state[0, 0] == _state[1, 1] && _state[1, 1] == _state[2, 2]) + else if (_curUserIndex == _state[0, 0] && _state[0, 0] == _state[1, 1] && _state[1, 1] == _state[2, 2]) { - _state[0, 0] = curUserIndex + 2; - _state[1, 1] = curUserIndex + 2; - _state[2, 2] = curUserIndex + 2; + _state[0, 0] = _curUserIndex + 2; + _state[1, 1] = _curUserIndex + 2; + _state[2, 2] = _curUserIndex + 2; _phase = Phase.Ended; } - else if (curUserIndex == _state[0, 2] && _state[0, 2] == _state[1, 1] && _state[1, 1] == _state[2, 0]) + else if (_curUserIndex == _state[0, 2] && _state[0, 2] == _state[1, 1] && _state[1, 1] == _state[2, 0]) { - _state[0, 2] = curUserIndex + 2; - _state[1, 1] = curUserIndex + 2; - _state[2, 0] = curUserIndex + 2; + _state[0, 2] = _curUserIndex + 2; + _state[1, 1] = _curUserIndex + 2; + _state[2, 0] = _curUserIndex + 2; _phase = Phase.Ended; } - string reason = ""; + var reason = ""; if (_phase == Phase.Ended) // if user won, stop receiving moves { - reason = "Matched three!"; - _winner = _users[curUserIndex]; + reason = GetText("ttt_matched_three"); + _winner = _users[_curUserIndex]; NadekoBot.Client.MessageReceived -= Client_MessageReceived; OnEnded?.Invoke(this); } else if (IsDraw()) { - reason = "A draw!"; + reason = GetText("ttt_a_draw"); _phase = Phase.Ended; NadekoBot.Client.MessageReceived -= Client_MessageReceived; OnEnded?.Invoke(this); @@ -295,19 +299,19 @@ namespace NadekoBot.Modules.Games var sendstate = Task.Run(async () => { var del1 = msg.DeleteAsync(); - var del2 = previousMessage?.DeleteAsync(); - try { previousMessage = await _channel.EmbedAsync(GetEmbed(reason)); } catch { } + var del2 = _previousMessage?.DeleteAsync(); + try { _previousMessage = await _channel.EmbedAsync(GetEmbed(reason)); } catch { } try { await del1; } catch { } try { if (del2 != null) await del2; } catch { } }); - curUserIndex ^= 1; + _curUserIndex ^= 1; - timeoutTimer.Change(15000, Timeout.Infinite); + _timeoutTimer.Change(15000, Timeout.Infinite); } } finally { - moveLock.Release(); + _moveLock.Release(); } }); diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs index 2646ebd5..0862290f 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs @@ -17,36 +17,42 @@ namespace NadekoBot.Modules.Games.Trivia public class TriviaGame { private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1, 1); - private Logger _log { get; } + private readonly Logger _log; - public IGuild guild { get; } - public ITextChannel channel { get; } + public IGuild Guild { get; } + public ITextChannel Channel { get; } - private int QuestionDurationMiliseconds { get; } = 30000; - private int HintTimeoutMiliseconds { get; } = 6000; - public bool ShowHints { get; } = true; + private int questionDurationMiliseconds { get; } = 30000; + private int hintTimeoutMiliseconds { get; } = 6000; + public bool ShowHints { get; } private CancellationTokenSource triviaCancelSource { get; set; } public TriviaQuestion CurrentQuestion { get; private set; } - public HashSet oldQuestions { get; } = new HashSet(); + public HashSet OldQuestions { get; } = new HashSet(); public ConcurrentDictionary Users { get; } = new ConcurrentDictionary(); - public bool GameActive { get; private set; } = false; + public bool GameActive { get; private set; } public bool ShouldStopGame { get; private set; } - public int WinRequirement { get; } = 10; + public int WinRequirement { get; } public TriviaGame(IGuild guild, ITextChannel channel, bool showHints, int winReq) { - this._log = LogManager.GetCurrentClassLogger(); + _log = LogManager.GetCurrentClassLogger(); - this.ShowHints = showHints; - this.guild = guild; - this.channel = channel; - this.WinRequirement = winReq; + ShowHints = showHints; + Guild = guild; + Channel = channel; + WinRequirement = winReq; } + private string GetText(string key, params object[] replacements) => + NadekoTopLevelModule.GetTextStatic(key, + NadekoBot.Localization.GetCultureInfo(Channel.GuildId), + typeof(Games).Name.ToLowerInvariant(), + replacements); + public async Task StartGame() { while (!ShouldStopGame) @@ -55,26 +61,24 @@ namespace NadekoBot.Modules.Games.Trivia triviaCancelSource = new CancellationTokenSource(); // load question - CurrentQuestion = TriviaQuestionPool.Instance.GetRandomQuestion(oldQuestions); - if (CurrentQuestion == null || - string.IsNullOrWhiteSpace(CurrentQuestion.Answer) || - string.IsNullOrWhiteSpace(CurrentQuestion.Question)) + CurrentQuestion = TriviaQuestionPool.Instance.GetRandomQuestion(OldQuestions); + if (string.IsNullOrWhiteSpace(CurrentQuestion?.Answer) || string.IsNullOrWhiteSpace(CurrentQuestion.Question)) { - await channel.SendErrorAsync("Trivia Game", "Failed loading a question.").ConfigureAwait(false); + await Channel.SendErrorAsync(GetText("trivia_game"), GetText("failed_loading_question")).ConfigureAwait(false); return; } - oldQuestions.Add(CurrentQuestion); //add it to exclusion list so it doesn't show up again + OldQuestions.Add(CurrentQuestion); //add it to exclusion list so it doesn't show up again EmbedBuilder questionEmbed; IUserMessage questionMessage; try { questionEmbed = new EmbedBuilder().WithOkColor() - .WithTitle("Trivia Game") - .AddField(eab => eab.WithName("Category").WithValue(CurrentQuestion.Category)) - .AddField(eab => eab.WithName("Question").WithValue(CurrentQuestion.Question)); + .WithTitle(GetText("trivia_game")) + .AddField(eab => eab.WithName(GetText("category")).WithValue(CurrentQuestion.Category)) + .AddField(eab => eab.WithName(GetText("question")).WithValue(CurrentQuestion.Question)); - questionMessage = await channel.EmbedAsync(questionEmbed).ConfigureAwait(false); + questionMessage = await Channel.EmbedAsync(questionEmbed).ConfigureAwait(false); } catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound || ex.HttpCode == System.Net.HttpStatusCode.Forbidden || @@ -99,7 +103,7 @@ namespace NadekoBot.Modules.Games.Trivia try { //hint - await Task.Delay(HintTimeoutMiliseconds, triviaCancelSource.Token).ConfigureAwait(false); + await Task.Delay(hintTimeoutMiliseconds, triviaCancelSource.Token).ConfigureAwait(false); if (ShowHints) try { @@ -113,7 +117,7 @@ namespace NadekoBot.Modules.Games.Trivia catch (Exception ex) { _log.Warn(ex); } //timeout - await Task.Delay(QuestionDurationMiliseconds - HintTimeoutMiliseconds, triviaCancelSource.Token).ConfigureAwait(false); + await Task.Delay(questionDurationMiliseconds - hintTimeoutMiliseconds, triviaCancelSource.Token).ConfigureAwait(false); } catch (TaskCanceledException) { } //means someone guessed the answer @@ -124,7 +128,7 @@ namespace NadekoBot.Modules.Games.Trivia NadekoBot.Client.MessageReceived -= PotentialGuess; } if (!triviaCancelSource.IsCancellationRequested) - try { await channel.SendErrorAsync("Trivia Game", $"**Time's up!** The correct answer was **{CurrentQuestion.Answer}**").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } + try { await Channel.SendErrorAsync(GetText("trivia_game"), GetText("trivia_times_up", Format.Bold(CurrentQuestion.Answer))).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } await Task.Delay(2000).ConfigureAwait(false); } } @@ -133,7 +137,7 @@ namespace NadekoBot.Modules.Games.Trivia { ShouldStopGame = true; - await channel.EmbedAsync(new EmbedBuilder().WithOkColor() + await Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithAuthor(eab => eab.WithName("Trivia Game Ended")) .WithTitle("Final Results") .WithDescription(GetLeaderboard())).ConfigureAwait(false); @@ -144,7 +148,7 @@ namespace NadekoBot.Modules.Games.Trivia var old = ShouldStopGame; ShouldStopGame = true; if (!old) - try { await channel.SendConfirmAsync("Trivia Game", "Stopping after this question.").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } + try { await Channel.SendConfirmAsync(GetText("trivia_game"), GetText("trivia_stopping")).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } } private async Task PotentialGuess(SocketMessage imsg) @@ -155,11 +159,9 @@ namespace NadekoBot.Modules.Games.Trivia return; var umsg = imsg as SocketUserMessage; - if (umsg == null) - return; - var textChannel = umsg.Channel as ITextChannel; - if (textChannel == null || textChannel.Guild != guild) + var textChannel = umsg?.Channel as ITextChannel; + if (textChannel == null || textChannel.Guild != Guild) return; var guildUser = (IGuildUser)umsg.Author; @@ -182,13 +184,24 @@ namespace NadekoBot.Modules.Games.Trivia if (Users[guildUser] == WinRequirement) { ShouldStopGame = true; - try { await channel.SendConfirmAsync("Trivia Game", $"{guildUser.Mention} guessed it and WON the game! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false); } catch { } + try + { + await Channel.SendConfirmAsync(GetText("trivia_game"), + GetText("trivia_win", + guildUser.Mention, + Format.Bold(CurrentQuestion.Answer))).ConfigureAwait(false); + } + catch + { + // ignored + } var reward = NadekoBot.BotConfig.TriviaCurrencyReward; if (reward > 0) await CurrencyHandler.AddCurrencyAsync(guildUser, "Won trivia", reward, true).ConfigureAwait(false); return; } - await channel.SendConfirmAsync("Trivia Game", $"{guildUser.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false); + await Channel.SendConfirmAsync(GetText("trivia_game"), + GetText("guess", guildUser.Mention, Format.Bold(CurrentQuestion.Answer))).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } @@ -197,13 +210,13 @@ namespace NadekoBot.Modules.Games.Trivia public string GetLeaderboard() { if (Users.Count == 0) - return "No results."; + return GetText("no_results"); var sb = new StringBuilder(); foreach (var kvp in Users.OrderByDescending(kvp => kvp.Value)) { - sb.AppendLine($"**{kvp.Key.Username}** has {kvp.Value} points".ToString().SnPl(kvp.Value)); + sb.AppendLine(GetText("trivia_points", Format.Bold(kvp.Key.ToString()), kvp.Value).SnPl(kvp.Value)); } return sb.ToString(); diff --git a/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs b/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs index be7d135c..60dc4216 100644 --- a/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs @@ -3,9 +3,7 @@ using Discord.Commands; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Modules.Games.Trivia; -using System; using System.Collections.Concurrent; -using System.Linq; using System.Threading.Tasks; @@ -31,7 +29,7 @@ namespace NadekoBot.Modules.Games var showHints = !additionalArgs.Contains("nohint"); - TriviaGame trivia = new TriviaGame(channel.Guild, channel, showHints, winReq); + var trivia = new TriviaGame(channel.Guild, channel, showHints, winReq); if (RunningTrivias.TryAdd(channel.Guild.Id, trivia)) { try @@ -45,8 +43,9 @@ namespace NadekoBot.Modules.Games } return; } - else - await Context.Channel.SendErrorAsync("Trivia game is already running on this server.\n" + trivia.CurrentQuestion).ConfigureAwait(false); + + await Context.Channel.SendErrorAsync(GetText("trivia_already_running") + "\n" + trivia.CurrentQuestion) + .ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -58,11 +57,11 @@ namespace NadekoBot.Modules.Games TriviaGame trivia; if (RunningTrivias.TryGetValue(channel.Guild.Id, out trivia)) { - await channel.SendConfirmAsync("Leaderboard", trivia.GetLeaderboard()).ConfigureAwait(false); + await channel.SendConfirmAsync(GetText("leaderboard"), trivia.GetLeaderboard()).ConfigureAwait(false); return; } - await channel.SendErrorAsync("No trivia is running on this server.").ConfigureAwait(false); + await ReplyErrorLocalized("trivia_none").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -78,7 +77,7 @@ namespace NadekoBot.Modules.Games return; } - await channel.SendErrorAsync("No trivia is running on this server.").ConfigureAwait(false); + await ReplyErrorLocalized("trivia_none").ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs b/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs index e02dc895..6c3a2888 100644 --- a/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs +++ b/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs @@ -23,9 +23,9 @@ namespace NadekoBot.Modules.Permissions [Group] public class BlacklistCommands : ModuleBase { - public static ConcurrentHashSet BlacklistedUsers { get; set; } = new ConcurrentHashSet(); - public static ConcurrentHashSet BlacklistedGuilds { get; set; } = new ConcurrentHashSet(); - public static ConcurrentHashSet BlacklistedChannels { get; set; } = new ConcurrentHashSet(); + public static ConcurrentHashSet BlacklistedUsers { get; set; } + public static ConcurrentHashSet BlacklistedGuilds { get; set; } + public static ConcurrentHashSet BlacklistedChannels { get; set; } static BlacklistCommands() { @@ -115,7 +115,7 @@ namespace NadekoBot.Modules.Permissions } break; case BlacklistType.Channel: - var item = Games.Games.TriviaCommands.RunningTrivias.FirstOrDefault(kvp => kvp.Value.channel.Id == id); + var item = Games.Games.TriviaCommands.RunningTrivias.FirstOrDefault(kvp => kvp.Value.Channel.Id == id); Games.Games.TriviaCommands.RunningTrivias.TryRemove(item.Key, out tg); if (tg != null) { diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index 1a924b29..5a7fc983 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -145,7 +145,7 @@ namespace NadekoBot.Modules.Utility uow.Quotes.Remove(q); await uow.CompleteAsync().ConfigureAwait(false); sucess = true; - response = GetText("deleted_quote"); + response = GetText("quote_deleted"); } } if(sucess) diff --git a/src/NadekoBot/NadekoBot.xproj.DotSettings b/src/NadekoBot/NadekoBot.xproj.DotSettings index 146bab9a..e418daea 100644 --- a/src/NadekoBot/NadekoBot.xproj.DotSettings +++ b/src/NadekoBot/NadekoBot.xproj.DotSettings @@ -2,4 +2,5 @@ True True True + True True \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index c363367f..b93554ab 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2860,6 +2860,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Category. + /// + public static string games_category { + get { + return ResourceManager.GetString("games_category", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disabled cleverbot on this server.. + /// + public static string games_cleverbot_disabled { + get { + return ResourceManager.GetString("games_cleverbot_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enabled cleverbot on this server.. + /// + public static string games_cleverbot_enabled { + get { + return ResourceManager.GetString("games_cleverbot_enabled", resourceCulture); + } + } + /// /// Looks up a localized string similar to Currency generation has been disabled on this channel.. /// @@ -2878,6 +2905,42 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to {0} random {1} appeared! Pick them up by typing `{2}pick`. + /// + public static string games_curgen_pl { + get { + return ResourceManager.GetString("games_curgen_pl", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A random {0} appeared! Pick it up by typing `{1}pick`. + /// + public static string games_curgen_sn { + get { + return ResourceManager.GetString("games_curgen_sn", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed loading a question.. + /// + public static string games_failed_loading_question { + get { + return ResourceManager.GetString("games_failed_loading_question", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Game Started. + /// + public static string games_game_started { + get { + return ResourceManager.GetString("games_game_started", resourceCulture); + } + } + /// /// Looks up a localized string similar to Hangman game started. /// @@ -2914,6 +2977,51 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Leaderboard. + /// + public static string games_leaderboard { + get { + return ResourceManager.GetString("games_leaderboard", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No results. + /// + public static string games_no_results { + get { + return ResourceManager.GetString("games_no_results", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You don't have enough {0}. + /// + public static string games_not_enough { + get { + return ResourceManager.GetString("games_not_enough", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to picked {0}. + /// + public static string games_picked { + get { + return ResourceManager.GetString("games_picked", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} planted {1}. + /// + public static string games_planted { + get { + return ResourceManager.GetString("games_planted", resourceCulture); + } + } + /// /// Looks up a localized string similar to Question. /// @@ -2950,6 +3058,168 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Trivia game is already running on this server.. + /// + public static string games_trivia_already_running { + get { + return ResourceManager.GetString("games_trivia_already_running", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trivia Game. + /// + public static string games_trivia_game { + get { + return ResourceManager.GetString("games_trivia_game", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} guessed it! The answer was: {1}. + /// + public static string games_trivia_guess { + get { + return ResourceManager.GetString("games_trivia_guess", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No trivia is running on this server.. + /// + public static string games_trivia_none { + get { + return ResourceManager.GetString("games_trivia_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has {1} points. + /// + public static string games_trivia_points { + get { + return ResourceManager.GetString("games_trivia_points", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stopping after this question.. + /// + public static string games_trivia_stopping { + get { + return ResourceManager.GetString("games_trivia_stopping", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Time's up! The correct answer was {0}. + /// + public static string games_trivia_times_up { + get { + return ResourceManager.GetString("games_trivia_times_up", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} guessed it and WON the game! The answer was: {1}. + /// + public static string games_trivia_win { + get { + return ResourceManager.GetString("games_trivia_win", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A draw!. + /// + public static string games_ttt_a_draw { + get { + return ResourceManager.GetString("games_ttt_a_draw", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You can't play against yourself.. + /// + public static string games_ttt_against_yourself { + get { + return ResourceManager.GetString("games_ttt_against_yourself", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to TicTacToe Game is already running in this channel.. + /// + public static string games_ttt_already_running { + get { + return ResourceManager.GetString("games_ttt_already_running", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to has created a game of TicTacToe.. + /// + public static string games_ttt_created { + get { + return ResourceManager.GetString("games_ttt_created", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} has Won!. + /// + public static string games_ttt_has_won { + get { + return ResourceManager.GetString("games_ttt_has_won", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Matched Three. + /// + public static string games_ttt_matched_three { + get { + return ResourceManager.GetString("games_ttt_matched_three", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No moves left!. + /// + public static string games_ttt_no_moves { + get { + return ResourceManager.GetString("games_ttt_no_moves", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Time Expired!. + /// + public static string games_ttt_time_expired { + get { + return ResourceManager.GetString("games_ttt_time_expired", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}'s move. + /// + public static string games_ttt_users_move { + get { + return ResourceManager.GetString("games_ttt_users_move", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} vs {1}. + /// + public static string games_vs { + get { + return ResourceManager.GetString("games_vs", resourceCulture); + } + } + /// /// Looks up a localized string similar to Back to ToC. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index f69a2577..f8208dca 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1221,12 +1221,34 @@ Don't forget to leave your discord name or id in the message. Total: {0} Average: {1} + + Category + + + Disabled cleverbot on this server. + + + Enabled cleverbot on this server. + Currency generation has been disabled on this channel. Currency generation has been enabled on this channel. + + {0} random {1} appeared! Pick them up by typing `{2}pick` + plural + + + A random {0} appeared! Pick it up by typing `{1}pick` + + + Failed loading a question. + + + Game Started + Hangman game started @@ -1239,6 +1261,77 @@ Don't forget to leave your discord name or id in the message. List of "{0}hangman" term types: + + Leaderboard + + + You don't have enough {0} + + + No results + + + picked {0} + Kwoth picked 5* + + + {0} planted {1} + Kwoth planted 5* + + + Trivia game is already running on this server. + + + Trivia Game + + + {0} guessed it! The answer was: {1} + + + No trivia is running on this server. + + + {0} has {1} points + + + Stopping after this question. + + + Time's up! The correct answer was {0} + + + {0} guessed it and WON the game! The answer was: {1} + + + You can't play against yourself. + + + TicTacToe Game is already running in this channel. + + + A draw! + + + has created a game of TicTacToe. + + + {0} has Won! + + + Matched Three + + + No moves left! + + + Time Expired! + + + {0}'s move + + + {0} vs {1} + Joined From 2ef3006ac0980797d5918852e5904c2215dc4816 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 24 Feb 2017 10:53:42 +0100 Subject: [PATCH 342/746] permissions done. now really 2 modules left, unless i forgot another one to make myself feel better --- .../Permissions/Commands/BlacklistCommands.cs | 8 +- .../Permissions/Commands/CmdCdsCommands.cs | 27 +- .../Commands/CommandCostCommands.cs | 44 +- .../Permissions/Commands/FilterCommands.cs | 39 +- .../Modules/Permissions/Permissions.cs | 278 ++++++++--- .../Resources/ResponseStrings.Designer.cs | 450 ++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 153 ++++++ 7 files changed, 876 insertions(+), 123 deletions(-) diff --git a/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs b/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs index 6c3a2888..4278d5a4 100644 --- a/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs +++ b/src/NadekoBot/Modules/Permissions/Commands/BlacklistCommands.cs @@ -21,7 +21,7 @@ namespace NadekoBot.Modules.Permissions } [Group] - public class BlacklistCommands : ModuleBase + public class BlacklistCommands : NadekoSubmodule { public static ConcurrentHashSet BlacklistedUsers { get; set; } public static ConcurrentHashSet BlacklistedGuilds { get; set; } @@ -124,16 +124,14 @@ namespace NadekoBot.Modules.Permissions break; case BlacklistType.User: break; - default: - break; } } if(action == AddRemove.Add) - await Context.Channel.SendConfirmAsync($"Blacklisted a `{type}` with id `{id}`").ConfigureAwait(false); + await ReplyConfirmLocalized("blacklisted", Format.Code(type.ToString()), Format.Code(id.ToString())).ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync($"Unblacklisted a `{type}` with id `{id}`").ConfigureAwait(false); + await ReplyConfirmLocalized("unblacklisted", Format.Code(type.ToString()), Format.Code(id.ToString())).ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs b/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs index 80b8067b..cfccebde 100644 --- a/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs +++ b/src/NadekoBot/Modules/Permissions/Commands/CmdCdsCommands.cs @@ -21,15 +21,15 @@ namespace NadekoBot.Modules.Permissions } [Group] - public class CmdCdsCommands : ModuleBase + public class CmdCdsCommands : NadekoSubmodule { - public static ConcurrentDictionary> commandCooldowns { get; } + public static ConcurrentDictionary> CommandCooldowns { get; } private static ConcurrentDictionary> activeCooldowns { get; } = new ConcurrentDictionary>(); static CmdCdsCommands() { var configs = NadekoBot.AllGuildConfigs; - commandCooldowns = new ConcurrentDictionary>(configs.ToDictionary(k => k.GuildId, v => new ConcurrentHashSet(v.CommandCooldowns))); + CommandCooldowns = new ConcurrentDictionary>(configs.ToDictionary(k => k.GuildId, v => new ConcurrentHashSet(v.CommandCooldowns))); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] @@ -38,14 +38,14 @@ namespace NadekoBot.Modules.Permissions var channel = (ITextChannel)Context.Channel; if (secs < 0 || secs > 3600) { - await channel.SendErrorAsync("Invalid second parameter. (Must be a number between 0 and 3600)").ConfigureAwait(false); + await ReplyErrorLocalized("invalid_second_param_between", 0, 3600).ConfigureAwait(false); return; } using (var uow = DbHandler.UnitOfWork()) { var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.CommandCooldowns)); - var localSet = commandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet()); + var localSet = CommandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet()); config.CommandCooldowns.RemoveWhere(cc => cc.CommandName == command.Aliases.First().ToLowerInvariant()); localSet.RemoveWhere(cc => cc.CommandName == command.Aliases.First().ToLowerInvariant()); @@ -65,13 +65,14 @@ namespace NadekoBot.Modules.Permissions { var activeCds = activeCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet()); activeCds.RemoveWhere(ac => ac.Command == command.Aliases.First().ToLowerInvariant()); - await channel.SendConfirmAsync($"🚮 Command **{command.Aliases.First()}** has no coooldown now and all existing cooldowns have been cleared.") - .ConfigureAwait(false); + await ReplyConfirmLocalized("cmdcd_cleared", + Format.Bold(command.Aliases.First())).ConfigureAwait(false); } else { - await channel.SendConfirmAsync($"✅ Command **{command.Aliases.First()}** now has a **{secs} {"seconds".SnPl(secs)}** cooldown.") - .ConfigureAwait(false); + await ReplyConfirmLocalized("cmdcd_add", + Format.Bold(command.Aliases.First()), + Format.Bold(secs.ToString())).ConfigureAwait(false); } } @@ -80,19 +81,19 @@ namespace NadekoBot.Modules.Permissions public async Task AllCmdCooldowns() { var channel = (ITextChannel)Context.Channel; - var localSet = commandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet()); + var localSet = CommandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet()); if (!localSet.Any()) - await channel.SendConfirmAsync("ℹ️ `No command cooldowns set.`").ConfigureAwait(false); + await ReplyConfirmLocalized("cmdcd_none").ConfigureAwait(false); else - await channel.SendTableAsync("", localSet.Select(c => c.CommandName + ": " + c.Seconds + " secs"), s => $"{s,-30}", 2).ConfigureAwait(false); + await channel.SendTableAsync("", localSet.Select(c => c.CommandName + ": " + c.Seconds + GetText("sec")), s => $"{s,-30}", 2).ConfigureAwait(false); } public static bool HasCooldown(CommandInfo cmd, IGuild guild, IUser user) { if (guild == null) return false; - var cmdcds = CmdCdsCommands.commandCooldowns.GetOrAdd(guild.Id, new ConcurrentHashSet()); + var cmdcds = CmdCdsCommands.CommandCooldowns.GetOrAdd(guild.Id, new ConcurrentHashSet()); CommandCooldown cdRule; if ((cdRule = cmdcds.FirstOrDefault(cc => cc.CommandName == cmd.Aliases.First().ToLowerInvariant())) != null) { diff --git a/src/NadekoBot/Modules/Permissions/Commands/CommandCostCommands.cs b/src/NadekoBot/Modules/Permissions/Commands/CommandCostCommands.cs index e0ef1a29..91b8a7d2 100644 --- a/src/NadekoBot/Modules/Permissions/Commands/CommandCostCommands.cs +++ b/src/NadekoBot/Modules/Permissions/Commands/CommandCostCommands.cs @@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Permissions public partial class Permissions { [Group] - public class CommandCostCommands : ModuleBase + public class CommandCostCommands : NadekoSubmodule { private static readonly ConcurrentDictionary _commandCosts = new ConcurrentDictionary(); public static IReadOnlyDictionary CommandCosts => _commandCosts; @@ -29,29 +29,29 @@ namespace NadekoBot.Modules.Permissions // x => x.Cost)); } - [NadekoCommand, Usage, Description, Aliases] - public async Task CmdCosts(int page = 1) - { - var prices = _commandCosts.ToList(); + //[NadekoCommand, Usage, Description, Aliases] + //public async Task CmdCosts(int page = 1) + //{ + // var prices = _commandCosts.ToList(); - if (!prices.Any()) - { - await Context.Channel.SendConfirmAsync("No costs set.").ConfigureAwait(false); - return; - } + // if (!prices.Any()) + // { + // await Context.Channel.SendConfirmAsync(GetText("no_costs")).ConfigureAwait(false); + // return; + // } - await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) => { - var embed = new EmbedBuilder().WithOkColor() - .WithTitle("Command Costs"); - var current = prices.Skip((curPage - 1) * 9) - .Take(9); - foreach (var price in current) - { - embed.AddField(efb => efb.WithName(price.Key).WithValue(price.Value.ToString()).WithIsInline(true)); - } - return embed; - }, prices.Count / 9).ConfigureAwait(false); - } + // await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) => { + // var embed = new EmbedBuilder().WithOkColor() + // .WithTitle(GetText("command_costs")); + // var current = prices.Skip((curPage - 1) * 9) + // .Take(9); + // foreach (var price in current) + // { + // embed.AddField(efb => efb.WithName(price.Key).WithValue(price.Value.ToString()).WithIsInline(true)); + // } + // return embed; + // }, prices.Count / 9).ConfigureAwait(false); + //} //[NadekoCommand, Usage, Description, Aliases] //public async Task CommandCost(int cost, CommandInfo cmd) diff --git a/src/NadekoBot/Modules/Permissions/Commands/FilterCommands.cs b/src/NadekoBot/Modules/Permissions/Commands/FilterCommands.cs index 2576ac78..9eea8a50 100644 --- a/src/NadekoBot/Modules/Permissions/Commands/FilterCommands.cs +++ b/src/NadekoBot/Modules/Permissions/Commands/FilterCommands.cs @@ -13,13 +13,13 @@ namespace NadekoBot.Modules.Permissions public partial class Permissions { [Group] - public class FilterCommands : ModuleBase + public class FilterCommands : NadekoSubmodule { public static ConcurrentHashSet InviteFilteringChannels { get; } public static ConcurrentHashSet InviteFilteringServers { get; } //serverid, filteredwords - private static ConcurrentDictionary> ServerFilteredWords { get; } + private static ConcurrentDictionary> serverFilteredWords { get; } public static ConcurrentHashSet WordFilteringChannels { get; } public static ConcurrentHashSet WordFilteringServers { get; } @@ -28,7 +28,7 @@ namespace NadekoBot.Modules.Permissions { ConcurrentHashSet words = new ConcurrentHashSet(); if(WordFilteringChannels.Contains(channelId)) - ServerFilteredWords.TryGetValue(guildId, out words); + serverFilteredWords.TryGetValue(guildId, out words); return words; } @@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Permissions { var words = new ConcurrentHashSet(); if(WordFilteringServers.Contains(guildId)) - ServerFilteredWords.TryGetValue(guildId, out words); + serverFilteredWords.TryGetValue(guildId, out words); return words; } @@ -49,7 +49,7 @@ namespace NadekoBot.Modules.Permissions var dict = guildConfigs.ToDictionary(gc => gc.GuildId, gc => new ConcurrentHashSet(gc.FilteredWords.Select(fw => fw.Word))); - ServerFilteredWords = new ConcurrentDictionary>(dict); + serverFilteredWords = new ConcurrentDictionary>(dict); var serverFiltering = guildConfigs.Where(gc => gc.FilterWords); WordFilteringServers = new ConcurrentHashSet(serverFiltering.Select(gc => gc.GuildId)); @@ -74,12 +74,12 @@ namespace NadekoBot.Modules.Permissions if (enabled) { InviteFilteringServers.Add(channel.Guild.Id); - await channel.SendConfirmAsync("Invite filtering enabled on this server.").ConfigureAwait(false); + await ReplyConfirmLocalized("invite_filter_server_on").ConfigureAwait(false); } else { InviteFilteringServers.TryRemove(channel.Guild.Id); - await channel.SendConfirmAsync("Invite filtering disabled on this server.").ConfigureAwait(false); + await ReplyConfirmLocalized("invite_filter_server_off").ConfigureAwait(false); } } @@ -107,12 +107,11 @@ namespace NadekoBot.Modules.Permissions if (removed == 0) { InviteFilteringChannels.Add(channel.Id); - await channel.SendConfirmAsync("Invite filtering enabled on this channel.").ConfigureAwait(false); + await ReplyConfirmLocalized("invite_filter_channel_on").ConfigureAwait(false); } else { - InviteFilteringChannels.TryRemove(channel.Id); - await channel.SendConfirmAsync("Invite filtering disabled on this channel.").ConfigureAwait(false); + await ReplyConfirmLocalized("invite_filter_channel_off").ConfigureAwait(false); } } @@ -133,12 +132,12 @@ namespace NadekoBot.Modules.Permissions if (enabled) { WordFilteringServers.Add(channel.Guild.Id); - await channel.SendConfirmAsync("Word filtering enabled on this server.").ConfigureAwait(false); + await ReplyConfirmLocalized("word_filter_server_on").ConfigureAwait(false); } else { WordFilteringServers.TryRemove(channel.Guild.Id); - await channel.SendConfirmAsync("Word filtering disabled on this server.").ConfigureAwait(false); + await ReplyConfirmLocalized("word_filter_server_off").ConfigureAwait(false); } } @@ -166,12 +165,12 @@ namespace NadekoBot.Modules.Permissions if (removed == 0) { WordFilteringChannels.Add(channel.Id); - await channel.SendConfirmAsync("Word filtering enabled on this channel.").ConfigureAwait(false); + await ReplyConfirmLocalized("word_filter_channel_on").ConfigureAwait(false); } else { WordFilteringChannels.TryRemove(channel.Id); - await channel.SendConfirmAsync("Word filtering disabled on this channel.").ConfigureAwait(false); + await ReplyConfirmLocalized("word_filter_channel_off").ConfigureAwait(false); } } @@ -199,19 +198,17 @@ namespace NadekoBot.Modules.Permissions await uow.CompleteAsync().ConfigureAwait(false); } - var filteredWords = ServerFilteredWords.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet()); + var filteredWords = serverFilteredWords.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet()); if (removed == 0) { filteredWords.Add(word); - await channel.SendConfirmAsync($"Word `{word}` successfully added to the list of filtered words.") - .ConfigureAwait(false); + await ReplyConfirmLocalized("filter_word_add", Format.Code(word)).ConfigureAwait(false); } else { filteredWords.TryRemove(word); - await channel.SendConfirmAsync($"Word `{word}` removed from the list of filtered words.") - .ConfigureAwait(false); + await ReplyConfirmLocalized("filter_word_remove", Format.Code(word)).ConfigureAwait(false); } } @@ -222,9 +219,9 @@ namespace NadekoBot.Modules.Permissions var channel = (ITextChannel)Context.Channel; ConcurrentHashSet filteredWords; - ServerFilteredWords.TryGetValue(channel.Guild.Id, out filteredWords); + serverFilteredWords.TryGetValue(channel.Guild.Id, out filteredWords); - await channel.SendConfirmAsync($"List of filtered words", string.Join("\n", filteredWords)) + await channel.SendConfirmAsync(GetText("filter_word_list"), string.Join("\n", filteredWords)) .ConfigureAwait(false); } } diff --git a/src/NadekoBot/Modules/Permissions/Permissions.cs b/src/NadekoBot/Modules/Permissions/Permissions.cs index 3e8ecd13..04d1352d 100644 --- a/src/NadekoBot/Modules/Permissions/Permissions.cs +++ b/src/NadekoBot/Modules/Permissions/Permissions.cs @@ -29,7 +29,7 @@ namespace NadekoBot.Modules.Permissions static Permissions() { - var _log = LogManager.GetCurrentClassLogger(); + var log = LogManager.GetCurrentClassLogger(); var sw = Stopwatch.StartNew(); using (var uow = DbHandler.UnitOfWork()) @@ -46,7 +46,7 @@ namespace NadekoBot.Modules.Permissions } sw.Stop(); - _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); + log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); } [NadekoCommand, Usage, Description, Aliases] @@ -65,8 +65,14 @@ namespace NadekoBot.Modules.Permissions }, (id, old) => { old.Verbose = config.VerbosePermissions; return old; }); await uow.CompleteAsync().ConfigureAwait(false); } - - await Context.Channel.SendConfirmAsync("ℹ️ I will " + (action.Value ? "now" : "no longer") + " show permission warnings.").ConfigureAwait(false); + if (action.Value) + { + await ReplyConfirmLocalized("verbose_true").ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("verbose_false").ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -81,22 +87,20 @@ namespace NadekoBot.Modules.Permissions var config = uow.GuildConfigs.For(Context.Guild.Id, set => set); if (role == null) { - await Context.Channel.SendConfirmAsync($"ℹ️ Current permission role is **{config.PermissionRole}**.").ConfigureAwait(false); + await ReplyConfirmLocalized("permrole", Format.Bold(config.PermissionRole)).ConfigureAwait(false); return; } - else { - config.PermissionRole = role.Name.Trim(); - Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache() - { - PermRole = config.PermissionRole, - RootPermission = Permission.GetDefaultRoot(), - Verbose = config.VerbosePermissions - }, (id, old) => { old.PermRole = role.Name.Trim(); return old; }); - await uow.CompleteAsync().ConfigureAwait(false); - } + config.PermissionRole = role.Name.Trim(); + Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache() + { + PermRole = config.PermissionRole, + RootPermission = Permission.GetDefaultRoot(), + Verbose = config.VerbosePermissions + }, (id, old) => { old.PermRole = role.Name.Trim(); return old; }); + await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"Users now require **{role.Name}** role in order to edit permissions.").ConfigureAwait(false); + await ReplyConfirmLocalized("permrole_changed", Format.Bold(role.Name)).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -105,12 +109,18 @@ namespace NadekoBot.Modules.Permissions { if (page < 1 || page > 4) return; - string toSend = ""; + string toSend; using (var uow = DbHandler.UnitOfWork()) { var perms = uow.GuildConfigs.PermissionsFor(Context.Guild.Id).RootPermission; var i = 1 + 20 * (page - 1); - toSend = Format.Code($"📄 Permissions page {page}") + "\n\n" + String.Join("\n", perms.AsEnumerable().Skip((page - 1) * 20).Take(20).Select(p => $"`{(i++)}.` {(p.Next == null ? Format.Bold(p.GetCommand((SocketGuild)Context.Guild) + " [uneditable]") : (p.GetCommand((SocketGuild)Context.Guild)))}")); + toSend = Format.Bold(GetText("page", page)) + "\n\n" + string.Join("\n", + perms.AsEnumerable() + .Skip((page - 1) * 20) + .Take(20) + .Select( + p => + $"`{(i++)}.` {(p.Next == null ? Format.Bold(p.GetCommand((SocketGuild) Context.Guild) + $" [{GetText("uneditable")}]") : (p.GetCommand((SocketGuild) Context.Guild)))}")); } await Context.Channel.SendMessageAsync(toSend).ConfigureAwait(false); @@ -132,7 +142,7 @@ namespace NadekoBot.Modules.Permissions { return; } - else if (index == 0) + if (index == 0) { p = perms; config.RootPermission = perms.Next; @@ -155,12 +165,13 @@ namespace NadekoBot.Modules.Permissions uow2._context.Remove(p); uow2._context.SaveChanges(); } - - await Context.Channel.SendConfirmAsync($"✅ {Context.User.Mention} removed permission **{p.GetCommand((SocketGuild)Context.Guild)}** from position #{index + 1}.").ConfigureAwait(false); + await ReplyConfirmLocalized("removed", + index+1, + Format.Code(p.GetCommand((SocketGuild)Context.Guild))).ConfigureAwait(false); } - catch (ArgumentOutOfRangeException) + catch (IndexOutOfRangeException) { - await Context.Channel.SendErrorAsync("❗️`No command on that index found.`").ConfigureAwait(false); + await ReplyErrorLocalized("perm_out_of_range").ConfigureAwait(false); } } @@ -180,7 +191,6 @@ namespace NadekoBot.Modules.Permissions { var config = uow.GuildConfigs.PermissionsFor(Context.Guild.Id); var perms = config.RootPermission; - var root = perms; var index = 0; var fromFound = false; var toFound = false; @@ -207,13 +217,13 @@ namespace NadekoBot.Modules.Permissions { if (!fromFound) { - await Context.Channel.SendErrorAsync($"Can't find permission at index `#{++from}`").ConfigureAwait(false); + await ReplyErrorLocalized("not_found", ++from).ConfigureAwait(false); return; } if (!toFound) { - await Context.Channel.SendErrorAsync($"Can't find permission at index `#{++to}`").ConfigureAwait(false); + await ReplyErrorLocalized("not_found", ++to).ConfigureAwait(false); return; } } @@ -230,7 +240,6 @@ namespace NadekoBot.Modules.Permissions next.Previous = pre; if (from == 0) { - root = next; } await uow.CompleteAsync().ConfigureAwait(false); //Inserting @@ -263,14 +272,18 @@ namespace NadekoBot.Modules.Permissions }, (id, old) => { old.RootPermission = config.RootPermission; return old; }); await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"`Moved permission:` \"{fromPerm.GetCommand((SocketGuild)Context.Guild)}\" `from #{++from} to #{++to}.`").ConfigureAwait(false); + await ReplyConfirmLocalized("moved_permission", + Format.Code(fromPerm.GetCommand((SocketGuild) Context.Guild)), + ++from, + ++to) + .ConfigureAwait(false); return; } catch (Exception e) when (e is ArgumentOutOfRangeException || e is IndexOutOfRangeException) { } } - await Context.Channel.SendErrorAsync("`Invalid index(es) specified.`").ConfigureAwait(false); + await ReplyErrorLocalized("perm_out_of_range").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -297,7 +310,19 @@ namespace NadekoBot.Modules.Permissions await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{command.Aliases.First()}` command on this server.").ConfigureAwait(false); + + if (action.Value) + { + await ReplyConfirmLocalized("sx_enable", + Format.Code(command.Aliases.First()), + GetText("of_command")).ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("sx_disable", + Format.Code(command.Aliases.First()), + GetText("of_command")).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -323,7 +348,19 @@ namespace NadekoBot.Modules.Permissions }, (id, old) => { old.RootPermission = config.RootPermission; return old; }); await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of **`{module.Name}`** module on this server.").ConfigureAwait(false); + + if (action.Value) + { + await ReplyConfirmLocalized("sx_enable", + Format.Code(module.Name), + GetText("of_module")).ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("sx_disable", + Format.Code(module.Name), + GetText("of_module")).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -349,7 +386,21 @@ namespace NadekoBot.Modules.Permissions }, (id, old) => { old.RootPermission = config.RootPermission; return old; }); await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{command.Aliases.First()}` command for `{user}` user.").ConfigureAwait(false); + + if (action.Value) + { + await ReplyConfirmLocalized("ux_enable", + Format.Code(command.Aliases.First()), + GetText("of_command"), + Format.Code(user.ToString())).ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("ux_disable", + Format.Code(command.Aliases.First()), + GetText("of_command"), + Format.Code(user.ToString())).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -375,7 +426,21 @@ namespace NadekoBot.Modules.Permissions }, (id, old) => { old.RootPermission = config.RootPermission; return old; }); await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{module.Name}` module for `{user}` user.").ConfigureAwait(false); + + if (action.Value) + { + await ReplyConfirmLocalized("ux_enable", + Format.Code(module.Name), + GetText("of_module"), + Format.Code(user.ToString())).ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("ux_disable", + Format.Code(module.Name), + GetText("of_module"), + Format.Code(user.ToString())).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -404,7 +469,21 @@ namespace NadekoBot.Modules.Permissions }, (id, old) => { old.RootPermission = config.RootPermission; return old; }); await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{command.Aliases.First()}` command for `{role}` role.").ConfigureAwait(false); + + if (action.Value) + { + await ReplyConfirmLocalized("rx_enable", + Format.Code(command.Aliases.First()), + GetText("of_command"), + Format.Code(role.Name)).ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("rx_disable", + Format.Code(command.Aliases.First()), + GetText("of_command"), + Format.Code(role.Name)).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -433,39 +512,62 @@ namespace NadekoBot.Modules.Permissions }, (id, old) => { old.RootPermission = config.RootPermission; return old; }); await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{module.Name}` module for `{role}` role.").ConfigureAwait(false); + + + if (action.Value) + { + await ReplyConfirmLocalized("rx_enable", + Format.Code(module.Name), + GetText("of_module"), + Format.Code(role.Name)).ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("rx_disable", + Format.Code(module.Name), + GetText("of_module"), + Format.Code(role.Name)).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task ChnlCmd(CommandInfo command, PermissionAction action, [Remainder] ITextChannel chnl) { - try + using (var uow = DbHandler.UnitOfWork()) { - using (var uow = DbHandler.UnitOfWork()) + var newPerm = new Permission { - var newPerm = new Permission - { - PrimaryTarget = PrimaryPermissionType.Channel, - PrimaryTargetId = chnl.Id, - SecondaryTarget = SecondaryPermissionType.Command, - SecondaryTargetName = command.Aliases.First().ToLowerInvariant(), - State = action.Value, - }; - var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm); - Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache() - { - PermRole = config.PermissionRole, - RootPermission = config.RootPermission, - Verbose = config.VerbosePermissions - }, (id, old) => { old.RootPermission = config.RootPermission; return old; }); - await uow.CompleteAsync().ConfigureAwait(false); - } + PrimaryTarget = PrimaryPermissionType.Channel, + PrimaryTargetId = chnl.Id, + SecondaryTarget = SecondaryPermissionType.Command, + SecondaryTargetName = command.Aliases.First().ToLowerInvariant(), + State = action.Value, + }; + var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm); + Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache() + { + PermRole = config.PermissionRole, + RootPermission = config.RootPermission, + Verbose = config.VerbosePermissions + }, (id, old) => { old.RootPermission = config.RootPermission; return old; }); + await uow.CompleteAsync().ConfigureAwait(false); } - catch (Exception ex) { - _log.Error(ex); + + if (action.Value) + { + await ReplyConfirmLocalized("cx_enable", + Format.Code(command.Aliases.First()), + GetText("of_command"), + Format.Code(chnl.Name)).ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("cx_disable", + Format.Code(command.Aliases.First()), + GetText("of_command"), + Format.Code(chnl.Name)).ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{command.Aliases.First()}` command for `{chnl}` channel.").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -491,7 +593,21 @@ namespace NadekoBot.Modules.Permissions }, (id, old) => { old.RootPermission = config.RootPermission; return old; }); await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{module.Name}` module for `{chnl}` channel.").ConfigureAwait(false); + + if (action.Value) + { + await ReplyConfirmLocalized("cx_enable", + Format.Code(module.Name), + GetText("of_module"), + Format.Code(chnl.Name)).ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("cx_disable", + Format.Code(module.Name), + GetText("of_module"), + Format.Code(chnl.Name)).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -517,7 +633,17 @@ namespace NadekoBot.Modules.Permissions }, (id, old) => { old.RootPermission = config.RootPermission; return old; }); await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `ALL MODULES` for `{chnl}` channel.").ConfigureAwait(false); + + if (action.Value) + { + await ReplyConfirmLocalized("acm_enable", + Format.Code(chnl.Name)).ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("acm_disable", + Format.Code(chnl.Name)).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -546,7 +672,17 @@ namespace NadekoBot.Modules.Permissions }, (id, old) => { old.RootPermission = config.RootPermission; return old; }); await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `ALL MODULES` for `{role}` role.").ConfigureAwait(false); + + if (action.Value) + { + await ReplyConfirmLocalized("arm_enable", + Format.Code(role.Name)).ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("arm_disable", + Format.Code(role.Name)).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -572,7 +708,17 @@ namespace NadekoBot.Modules.Permissions }, (id, old) => { old.RootPermission = config.RootPermission; return old; }); await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `ALL MODULES` for `{user}` user.").ConfigureAwait(false); + + if (action.Value) + { + await ReplyConfirmLocalized("aum_enable", + Format.Code(user.ToString())).ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("aum_disable", + Format.Code(user.ToString())).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -609,7 +755,15 @@ namespace NadekoBot.Modules.Permissions }, (id, old) => { old.RootPermission = config.RootPermission; return old; }); await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `ALL MODULES` on this server.").ConfigureAwait(false); + + if (action.Value) + { + await ReplyConfirmLocalized("asm_enable").ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("asm_disable").ConfigureAwait(false); + } } } } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index b93554ab..f0c48b9d 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -3425,6 +3425,456 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Disabled usage of ALL MODULES on {0} channel.. + /// + public static string permissions_acm_disable { + get { + return ResourceManager.GetString("permissions_acm_disable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enabled usage of ALL MODULES on {0} channel.. + /// + public static string permissions_acm_enable { + get { + return ResourceManager.GetString("permissions_acm_enable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Allowed. + /// + public static string permissions_allowed { + get { + return ResourceManager.GetString("permissions_allowed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disabled usage of ALL MODULES for {0} role.. + /// + public static string permissions_arm_disable { + get { + return ResourceManager.GetString("permissions_arm_disable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enabled usage of ALL MODULES for {0} role.. + /// + public static string permissions_arm_enable { + get { + return ResourceManager.GetString("permissions_arm_enable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disabled usage of ALL MODULES on this server.. + /// + public static string permissions_asm_disable { + get { + return ResourceManager.GetString("permissions_asm_disable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enabled usage of ALL MODULES on this server.. + /// + public static string permissions_asm_enable { + get { + return ResourceManager.GetString("permissions_asm_enable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disabled usage of ALL MODULES for {0} user.. + /// + public static string permissions_aum_disable { + get { + return ResourceManager.GetString("permissions_aum_disable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enabled usage of ALL MODULES for {0} user.. + /// + public static string permissions_aum_enable { + get { + return ResourceManager.GetString("permissions_aum_enable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Blacklisted {0} with ID {1}. + /// + public static string permissions_blacklisted { + get { + return ResourceManager.GetString("permissions_blacklisted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Command {0} now has a {1}s cooldown.. + /// + public static string permissions_cmdcd_add { + get { + return ResourceManager.GetString("permissions_cmdcd_add", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Command {0} has no coooldown now and all existing cooldowns have been cleared.. + /// + public static string permissions_cmdcd_cleared { + get { + return ResourceManager.GetString("permissions_cmdcd_cleared", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No command cooldowns set.. + /// + public static string permissions_cmdcd_none { + get { + return ResourceManager.GetString("permissions_cmdcd_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Command Costs. + /// + public static string permissions_command_costs { + get { + return ResourceManager.GetString("permissions_command_costs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disabled usage of {0} {1} on {2} channel.. + /// + public static string permissions_cx_disable { + get { + return ResourceManager.GetString("permissions_cx_disable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enabled usage of {0} {1} on {2} channel.. + /// + public static string permissions_cx_enable { + get { + return ResourceManager.GetString("permissions_cx_enable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Denied. + /// + public static string permissions_denied { + get { + return ResourceManager.GetString("permissions_denied", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Added word {0} to the list of filtered words.. + /// + public static string permissions_filter_word_add { + get { + return ResourceManager.GetString("permissions_filter_word_add", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List Of Filtered Words. + /// + public static string permissions_filter_word_list { + get { + return ResourceManager.GetString("permissions_filter_word_list", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removed word {0} from the list of filtered words.. + /// + public static string permissions_filter_word_remove { + get { + return ResourceManager.GetString("permissions_filter_word_remove", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid second parameter.(Must be a number between {0} and {1}). + /// + public static string permissions_invalid_second_param_between { + get { + return ResourceManager.GetString("permissions_invalid_second_param_between", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invite filtering disabled on this channel.. + /// + public static string permissions_invite_filter_channel_off { + get { + return ResourceManager.GetString("permissions_invite_filter_channel_off", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invite filtering enabled on this channel.. + /// + public static string permissions_invite_filter_channel_on { + get { + return ResourceManager.GetString("permissions_invite_filter_channel_on", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invite filtering disabled on this server.. + /// + public static string permissions_invite_filter_server_off { + get { + return ResourceManager.GetString("permissions_invite_filter_server_off", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invite filtering enabled on this server.. + /// + public static string permissions_invite_filter_server_on { + get { + return ResourceManager.GetString("permissions_invite_filter_server_on", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Moved permission {0} from #{1} to #{2}. + /// + public static string permissions_moved_permission { + get { + return ResourceManager.GetString("permissions_moved_permission", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No costs set.. + /// + public static string permissions_no_costs { + get { + return ResourceManager.GetString("permissions_no_costs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Can't find permission at index #{0}. + /// + public static string permissions_not_found { + get { + return ResourceManager.GetString("permissions_not_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to command. + /// + public static string permissions_of_command { + get { + return ResourceManager.GetString("permissions_of_command", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to module. + /// + public static string permissions_of_module { + get { + return ResourceManager.GetString("permissions_of_module", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Permissions page {0}. + /// + public static string permissions_page { + get { + return ResourceManager.GetString("permissions_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No permission found on that index.. + /// + public static string permissions_perm_out_of_range { + get { + return ResourceManager.GetString("permissions_perm_out_of_range", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Current permissions role is {0}.. + /// + public static string permissions_permrole { + get { + return ResourceManager.GetString("permissions_permrole", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Users now require {0} role in order to edit permissions.. + /// + public static string permissions_permrole_changed { + get { + return ResourceManager.GetString("permissions_permrole_changed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to removed permission #{0} - {1}. + /// + public static string permissions_removed { + get { + return ResourceManager.GetString("permissions_removed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disabled usage of {0} {1} for {2} role.. + /// + public static string permissions_rx_disable { + get { + return ResourceManager.GetString("permissions_rx_disable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enabled usage of {0} {1} for {2} role.. + /// + public static string permissions_rx_enable { + get { + return ResourceManager.GetString("permissions_rx_enable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to sec.. + /// + public static string permissions_sec { + get { + return ResourceManager.GetString("permissions_sec", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disabled usage of {0} {1} on this server.. + /// + public static string permissions_sx_disable { + get { + return ResourceManager.GetString("permissions_sx_disable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enabled usage of {0} {1} on this server.. + /// + public static string permissions_sx_enable { + get { + return ResourceManager.GetString("permissions_sx_enable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unblacklisted {0} with ID {1}. + /// + public static string permissions_unblacklisted { + get { + return ResourceManager.GetString("permissions_unblacklisted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to uneditable. + /// + public static string permissions_uneditable { + get { + return ResourceManager.GetString("permissions_uneditable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Disabled usage of {0} {1} for {2} user.. + /// + public static string permissions_ux_disable { + get { + return ResourceManager.GetString("permissions_ux_disable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enabled usage of {0} {1} for {2} user.. + /// + public static string permissions_ux_enable { + get { + return ResourceManager.GetString("permissions_ux_enable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I will no longer show permission warnings.. + /// + public static string permissions_verbose_false { + get { + return ResourceManager.GetString("permissions_verbose_false", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I will now show permission warnings.. + /// + public static string permissions_verbose_true { + get { + return ResourceManager.GetString("permissions_verbose_true", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word filtering disabled on this channel.. + /// + public static string permissions_word_filter_channel_off { + get { + return ResourceManager.GetString("permissions_word_filter_channel_off", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word filtering enabled on this channel.. + /// + public static string permissions_word_filter_channel_on { + get { + return ResourceManager.GetString("permissions_word_filter_channel_on", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word filtering disabled on this server.. + /// + public static string permissions_word_filter_server_off { + get { + return ResourceManager.GetString("permissions_word_filter_server_off", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Word filtering enabled on this server.. + /// + public static string permissions_word_filter_server_on { + get { + return ResourceManager.GetString("permissions_word_filter_server_on", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} has already fainted.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index f8208dca..d365b08c 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1332,6 +1332,159 @@ Don't forget to leave your discord name or id in the message. {0} vs {1} + + Disabled usage of ALL MODULES on {0} channel. + + + Enabled usage of ALL MODULES on {0} channel. + + + Allowed + + + Disabled usage of ALL MODULES for {0} role. + + + Enabled usage of ALL MODULES for {0} role. + + + Disabled usage of ALL MODULES on this server. + + + Enabled usage of ALL MODULES on this server. + + + Disabled usage of ALL MODULES for {0} user. + + + Enabled usage of ALL MODULES for {0} user. + + + Blacklisted {0} with ID {1} + + + Command {0} now has a {1}s cooldown. + + + Command {0} has no coooldown now and all existing cooldowns have been cleared. + + + No command cooldowns set. + + + Command Costs + + + Disabled usage of {0} {1} on {2} channel. + + + Enabled usage of {0} {1} on {2} channel. + + + Denied + + + Added word {0} to the list of filtered words. + + + List Of Filtered Words + + + Removed word {0} from the list of filtered words. + + + Invalid second parameter.(Must be a number between {0} and {1}) + + + Invite filtering disabled on this channel. + + + Invite filtering enabled on this channel. + + + Invite filtering disabled on this server. + + + Invite filtering enabled on this server. + + + Moved permission {0} from #{1} to #{2} + + + Can't find permission at index #{0} + + + No costs set. + + + command + Gen (of command) + + + module + Gen. (of module) + + + Permissions page {0} + + + Current permissions role is {0}. + + + Users now require {0} role in order to edit permissions. + + + No permission found on that index. + + + removed permission #{0} - {1} + + + Disabled usage of {0} {1} for {2} role. + + + Enabled usage of {0} {1} for {2} role. + + + sec. + Short of seconds. + + + Disabled usage of {0} {1} on this server. + + + Enabled usage of {0} {1} on this server. + + + Unblacklisted {0} with ID {1} + + + uneditable + + + Disabled usage of {0} {1} for {2} user. + + + Enabled usage of {0} {1} for {2} user. + + + I will no longer show permission warnings. + + + I will now show permission warnings. + + + Word filtering disabled on this channel. + + + Word filtering enabled on this channel. + + + Word filtering disabled on this server. + + + Word filtering enabled on this server. + Joined From 1bfa8becb37e89798740eaa871abc647d3369360 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 24 Feb 2017 17:10:44 +0100 Subject: [PATCH 343/746] searches localizable o.o --- src/NadekoBot/Modules/NSFW/NSFW.cs | 39 +- .../Searches/Commands/AnimeSearchCommands.cs | 48 +- .../Searches/Commands/GoogleTranslator.cs | 10 +- .../Modules/Searches/Commands/JokeCommands.cs | 9 +- .../Modules/Searches/Commands/LoLCommands.cs | 15 +- .../Searches/Commands/MemegenCommands.cs | 104 ++- .../Modules/Searches/Commands/OsuCommands.cs | 70 +- .../Searches/Commands/OverwatchCommands.cs | 45 +- .../Searches/Commands/PlaceCommands.cs | 10 +- .../Commands/PokemonSearchCommands.cs | 18 +- .../Commands/StreamNotificationCommands.cs | 97 +- .../Modules/Searches/Commands/Translator.cs | 46 +- .../Modules/Searches/Commands/XkcdCommands.cs | 19 +- src/NadekoBot/Modules/Searches/Searches.cs | 314 +++---- src/NadekoBot/NadekoBot.xproj.DotSettings | 1 + .../Resources/ResponseStrings.Designer.cs | 846 ++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 283 ++++++ 17 files changed, 1542 insertions(+), 432 deletions(-) diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index 53a3f3bb..6e72aefc 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -7,8 +7,6 @@ using System.Linq; using System.Threading.Tasks; using NadekoBot.Services; using System.Net.Http; -using System.Text.RegularExpressions; -using System.Xml.Linq; using NadekoBot.Extensions; using System.Xml; using System.Threading; @@ -20,8 +18,8 @@ namespace NadekoBot.Modules.NSFW public class NSFW : NadekoTopLevelModule { - private static readonly ConcurrentDictionary AutoHentaiTimers = new ConcurrentDictionary(); - private static readonly ConcurrentHashSet HentaiBombBlacklist = new ConcurrentHashSet(); + private static readonly ConcurrentDictionary _autoHentaiTimers = new ConcurrentDictionary(); + private static readonly ConcurrentHashSet _hentaiBombBlacklist = new ConcurrentHashSet(); private async Task InternalHentai(IMessageChannel channel, string tag, bool noError) { @@ -72,7 +70,7 @@ namespace NadekoBot.Modules.NSFW if (interval == 0) { - if (!AutoHentaiTimers.TryRemove(Context.Channel.Id, out t)) return; + if (!_autoHentaiTimers.TryRemove(Context.Channel.Id, out t)) return; t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer await ReplyConfirmLocalized("autohentai_stopped").ConfigureAwait(false); @@ -99,7 +97,7 @@ namespace NadekoBot.Modules.NSFW } }, null, interval * 1000, interval * 1000); - AutoHentaiTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) => + _autoHentaiTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) => { old.Change(Timeout.Infinite, Timeout.Infinite); return t; @@ -114,7 +112,7 @@ namespace NadekoBot.Modules.NSFW [NadekoCommand, Usage, Description, Aliases] public async Task HentaiBomb([Remainder] string tag = null) { - if (!HentaiBombBlacklist.Add(Context.User.Id)) + if (!_hentaiBombBlacklist.Add(Context.User.Id)) return; try { @@ -138,17 +136,17 @@ namespace NadekoBot.Modules.NSFW finally { await Task.Delay(5000).ConfigureAwait(false); - HentaiBombBlacklist.TryRemove(Context.User.Id); + _hentaiBombBlacklist.TryRemove(Context.User.Id); } } #endif [NadekoCommand, Usage, Description, Aliases] public Task Yandere([Remainder] string tag = null) - => Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Yandere); + => InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Yandere); [NadekoCommand, Usage, Description, Aliases] public Task Konachan([Remainder] string tag = null) - => Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Konachan); + => InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Konachan); [NadekoCommand, Usage, Description, Aliases] public async Task E621([Remainder] string tag = null) @@ -169,7 +167,7 @@ namespace NadekoBot.Modules.NSFW [NadekoCommand, Usage, Description, Aliases] public Task Rule34([Remainder] string tag = null) - => Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Rule34); + => InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Rule34); [NadekoCommand, Usage, Description, Aliases] public async Task Danbooru([Remainder] string tag = null) @@ -212,7 +210,7 @@ namespace NadekoBot.Modules.NSFW [NadekoCommand, Usage, Description, Aliases] public Task Gelbooru([Remainder] string tag = null) - => Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Gelbooru); + => InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Gelbooru); [NadekoCommand, Usage, Description, Aliases] public async Task Cp() @@ -289,5 +287,22 @@ namespace NadekoBot.Modules.NSFW public static Task GetGelbooruImageLink(string tag) => Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Gelbooru); + + public async Task InternalDapiCommand(IUserMessage umsg, string tag, Searches.Searches.DapiSearchType type) + { + var channel = umsg.Channel; + + tag = tag?.Trim() ?? ""; + + var url = await Searches.Searches.InternalDapiSearch(tag, type).ConfigureAwait(false); + + if (url == null) + await channel.SendErrorAsync(umsg.Author.Mention + " " + GetText("no_results")); + else + await channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithDescription(umsg.Author.Mention + " " + tag) + .WithImageUrl(url) + .WithFooter(efb => efb.WithText(type.ToString()))).ConfigureAwait(false); + } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs index bf05f0ac..9fdf07f0 100644 --- a/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs @@ -1,6 +1,5 @@ using AngleSharp; using AngleSharp.Dom.Html; -using AngleSharp.Extensions; using Discord; using Discord.Commands; using NadekoBot.Attributes; @@ -8,7 +7,6 @@ using NadekoBot.Extensions; using NadekoBot.Modules.Searches.Models; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using NLog; using System; using System.Collections.Generic; using System.Linq; @@ -21,15 +19,13 @@ namespace NadekoBot.Modules.Searches public partial class Searches { [Group] - public class AnimeSearchCommands : ModuleBase + public class AnimeSearchCommands : NadekoSubmodule { - private static Timer anilistTokenRefresher { get; } - private static Logger _log { get; } + private static readonly Timer anilistTokenRefresher; private static string anilistToken { get; set; } static AnimeSearchCommands() { - _log = LogManager.GetCurrentClassLogger(); anilistTokenRefresher = new Timer(async (state) => { try @@ -49,9 +45,9 @@ namespace NadekoBot.Modules.Searches anilistToken = JObject.Parse(stringContent)["access_token"].ToString(); } } - catch (Exception ex) + catch { - _log.Error(ex); + // ignored } }, null, TimeSpan.FromSeconds(0), TimeSpan.FromMinutes(29)); } @@ -75,7 +71,7 @@ namespace NadekoBot.Modules.Searches var favorites = document.QuerySelectorAll("div.user-favorites > div.di-tc"); - var favAnime = "No favorite anime yet"; + var favAnime = GetText("anime_no_fav"); if (favorites[0].QuerySelector("p") == null) favAnime = string.Join("\n", favorites[0].QuerySelectorAll("ul > li > div.di-tc.va-t > a") .Shuffle() @@ -106,14 +102,14 @@ namespace NadekoBot.Modules.Searches var embed = new EmbedBuilder() .WithOkColor() - .WithTitle($"{name}'s MAL profile") - .AddField(efb => efb.WithName("💚 Watching").WithValue(stats[0]).WithIsInline(true)) - .AddField(efb => efb.WithName("💙 Completed").WithValue(stats[1]).WithIsInline(true)); + .WithTitle(GetText("mal_profile", name)) + .AddField(efb => efb.WithName("💚 " + GetText("watching")).WithValue(stats[0]).WithIsInline(true)) + .AddField(efb => efb.WithName("💙 " + GetText("completed")).WithValue(stats[1]).WithIsInline(true)); if (info.Count < 3) - embed.AddField(efb => efb.WithName("💛 On-Hold").WithValue(stats[2]).WithIsInline(true)); + embed.AddField(efb => efb.WithName("💛 " + GetText("on_hold")).WithValue(stats[2]).WithIsInline(true)); embed - .AddField(efb => efb.WithName("💔 Dropped").WithValue(stats[3]).WithIsInline(true)) - .AddField(efb => efb.WithName("⚪ Plan to watch").WithValue(stats[4]).WithIsInline(true)) + .AddField(efb => efb.WithName("💔 " + GetText("dropped")).WithValue(stats[3]).WithIsInline(true)) + .AddField(efb => efb.WithName("⚪ " + GetText("plan_to_watch")).WithValue(stats[4]).WithIsInline(true)) .AddField(efb => efb.WithName("🕐 " + daysAndMean[0][0]).WithValue(daysAndMean[0][1]).WithIsInline(true)) .AddField(efb => efb.WithName("📊 " + daysAndMean[1][0]).WithValue(daysAndMean[1][1]).WithIsInline(true)) .AddField(efb => efb.WithName(MalInfoToEmoji(info[0].Item1) + " " + info[0].Item1).WithValue(info[0].Item2.TrimTo(20)).WithIsInline(true)) @@ -126,7 +122,7 @@ namespace NadekoBot.Modules.Searches .WithDescription($@" ** https://myanimelist.net/animelist/{ name } ** -**Top 3 Favorite Anime:** +**{GetText("top_3_fav_anime")}** {favAnime}" //**[Manga List](https://myanimelist.net/mangalist/{name})** @@ -176,7 +172,7 @@ namespace NadekoBot.Modules.Searches if (animeData == null) { - await Context.Channel.SendErrorAsync("Failed finding that animu.").ConfigureAwait(false); + await ReplyErrorLocalized("failed_finding_anime").ConfigureAwait(false); return; } @@ -185,10 +181,10 @@ namespace NadekoBot.Modules.Searches .WithTitle(animeData.title_english) .WithUrl(animeData.Link) .WithImageUrl(animeData.image_url_lge) - .AddField(efb => efb.WithName("Episodes").WithValue(animeData.total_episodes.ToString()).WithIsInline(true)) - .AddField(efb => efb.WithName("Status").WithValue(animeData.AiringStatus.ToString()).WithIsInline(true)) - .AddField(efb => efb.WithName("Genres").WithValue(String.Join(", ", animeData.Genres)).WithIsInline(true)) - .WithFooter(efb => efb.WithText("Score: " + animeData.average_score + " / 100")); + .AddField(efb => efb.WithName(GetText("episodes")).WithValue(animeData.total_episodes.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("status")).WithValue(animeData.AiringStatus.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("genres")).WithValue(String.Join(",\n", animeData.Genres)).WithIsInline(true)) + .WithFooter(efb => efb.WithText(GetText("score") + " " + animeData.average_score + " / 100")); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } @@ -203,7 +199,7 @@ namespace NadekoBot.Modules.Searches if (mangaData == null) { - await Context.Channel.SendErrorAsync("Failed finding that mango.").ConfigureAwait(false); + await ReplyErrorLocalized("failed_finding_manga").ConfigureAwait(false); return; } @@ -212,10 +208,10 @@ namespace NadekoBot.Modules.Searches .WithTitle(mangaData.title_english) .WithUrl(mangaData.Link) .WithImageUrl(mangaData.image_url_lge) - .AddField(efb => efb.WithName("Episodes").WithValue(mangaData.total_chapters.ToString()).WithIsInline(true)) - .AddField(efb => efb.WithName("Status").WithValue(mangaData.publishing_status.ToString()).WithIsInline(true)) - .AddField(efb => efb.WithName("Genres").WithValue(String.Join(", ", mangaData.Genres)).WithIsInline(true)) - .WithFooter(efb => efb.WithText("Score: " + mangaData.average_score + " / 100")); + .AddField(efb => efb.WithName(GetText("chapters")).WithValue(mangaData.total_chapters.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("status")).WithValue(mangaData.publishing_status.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("genres")).WithValue(String.Join(",\n", mangaData.Genres)).WithIsInline(true)) + .WithFooter(efb => efb.WithText(GetText("score") + " " + mangaData.average_score + " / 100")); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Searches/Commands/GoogleTranslator.cs b/src/NadekoBot/Modules/Searches/Commands/GoogleTranslator.cs index be415465..5604fdd1 100644 --- a/src/NadekoBot/Modules/Searches/Commands/GoogleTranslator.cs +++ b/src/NadekoBot/Modules/Searches/Commands/GoogleTranslator.cs @@ -13,7 +13,7 @@ namespace NadekoBot.Modules.Searches public static GoogleTranslator Instance = _instance ?? (_instance = new GoogleTranslator()); public IEnumerable Languages => _languageDictionary.Keys.OrderBy(x => x); - private Dictionary _languageDictionary; + private readonly Dictionary _languageDictionary; static GoogleTranslator() { } private GoogleTranslator() { @@ -153,13 +153,13 @@ namespace NadekoBot.Modules.Searches public async Task Translate(string sourceText, string sourceLanguage, string targetLanguage) { - string text = string.Empty; + string text; - string url = string.Format("https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}", + var url = string.Format("https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}", ConvertToLanguageCode(sourceLanguage), ConvertToLanguageCode(targetLanguage), WebUtility.UrlEncode(sourceText)); - using (HttpClient http = new HttpClient()) + using (var http = new HttpClient()) { http.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"); text = await http.GetStringAsync(url).ConfigureAwait(false); @@ -170,7 +170,7 @@ namespace NadekoBot.Modules.Searches private string ConvertToLanguageCode(string language) { - string mode = string.Empty; + string mode; _languageDictionary.TryGetValue(language, out mode); return mode; } diff --git a/src/NadekoBot/Modules/Searches/Commands/JokeCommands.cs b/src/NadekoBot/Modules/Searches/Commands/JokeCommands.cs index 1d5f3c99..a867aeb8 100644 --- a/src/NadekoBot/Modules/Searches/Commands/JokeCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/JokeCommands.cs @@ -7,7 +7,6 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NLog; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Net.Http; @@ -18,11 +17,11 @@ namespace NadekoBot.Modules.Searches public partial class Searches { [Group] - public class JokeCommands : ModuleBase + public class JokeCommands : NadekoSubmodule { private static List wowJokes { get; } = new List(); private static List magicItems { get; } = new List(); - private static Logger _log { get; } + private new static readonly Logger _log; static JokeCommands() { @@ -78,7 +77,7 @@ namespace NadekoBot.Modules.Searches { if (!wowJokes.Any()) { - await Context.Channel.SendErrorAsync("Jokes not loaded.").ConfigureAwait(false); + await ReplyErrorLocalized("jokes_not_loaded").ConfigureAwait(false); return; } var joke = wowJokes[new NadekoRandom().Next(0, wowJokes.Count)]; @@ -90,7 +89,7 @@ namespace NadekoBot.Modules.Searches { if (!wowJokes.Any()) { - await Context.Channel.SendErrorAsync("MagicItems not loaded.").ConfigureAwait(false); + await ReplyErrorLocalized("magicitems_not_loaded").ConfigureAwait(false); return; } var item = magicItems[new NadekoRandom().Next(0, magicItems.Count)]; diff --git a/src/NadekoBot/Modules/Searches/Commands/LoLCommands.cs b/src/NadekoBot/Modules/Searches/Commands/LoLCommands.cs index 308ccbd2..83fe18a8 100644 --- a/src/NadekoBot/Modules/Searches/Commands/LoLCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/LoLCommands.cs @@ -33,7 +33,7 @@ namespace NadekoBot.Modules.Searches [NadekoCommand, Usage, Description, Aliases] public async Task Lolban() { - var showCount = 8; + const int showCount = 8; //http://api.champion.gg/stats/champs/mostBanned?api_key=YOUR_API_TOKEN&page=1&limit=2 try { @@ -44,19 +44,20 @@ namespace NadekoBot.Modules.Searches $"limit={showCount}") .ConfigureAwait(false))["data"] as JArray; var dataList = data.Distinct(new ChampionNameComparer()).Take(showCount).ToList(); - var eb = new EmbedBuilder().WithOkColor().WithTitle(Format.Underline($"{dataList.Count} most banned champions")); - for (var i = 0; i < dataList.Count; i++) + var eb = new EmbedBuilder().WithOkColor().WithTitle(Format.Underline(GetText("x_most_banned_champs",dataList.Count))); + foreach (var champ in dataList) { - var champ = dataList[i]; - eb.AddField(efb => efb.WithName(champ["name"].ToString()).WithValue(champ["general"]["banRate"] + "%").WithIsInline(true)); + var champ1 = champ; + eb.AddField(efb => efb.WithName(champ1["name"].ToString()).WithValue(champ1["general"]["banRate"] + "%").WithIsInline(true)); } await Context.Channel.EmbedAsync(eb, Format.Italics(trashTalk[new NadekoRandom().Next(0, trashTalk.Length)])).ConfigureAwait(false); } } - catch (Exception) + catch (Exception ex) { - await Context.Channel.SendMessageAsync("Something went wrong.").ConfigureAwait(false); + _log.Warn(ex); + await ReplyErrorLocalized("something_went_wrong").ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs b/src/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs index dcf4d0f5..0b12d343 100644 --- a/src/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/MemegenCommands.cs @@ -1,73 +1,79 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.IO; using System.Linq; using System.Threading.Tasks; using NadekoBot.Attributes; using System.Net.Http; using System.Text; +using Discord.Commands; using NadekoBot.Extensions; namespace NadekoBot.Modules.Searches { public partial class Searches { - - Dictionary map = new Dictionary(); - - public Searches() + [Group] + public class MemegenCommands : NadekoSubmodule { - map.Add('?', "~q"); - map.Add('%', "~p"); - map.Add('#', "~h"); - map.Add('/', "~s"); - map.Add(' ', "-"); - map.Add('-', "--"); - map.Add('_', "__"); - map.Add('"', "''"); - } - - [NadekoCommand, Usage, Description, Aliases] - public async Task Memelist() - { - HttpClientHandler handler = new HttpClientHandler(); - - handler.AllowAutoRedirect = false; - - using (var http = new HttpClient(handler)) + private static readonly ImmutableDictionary _map = new Dictionary() { - var rawJson = await http.GetStringAsync("https://memegen.link/api/templates/").ConfigureAwait(false); - var data = JsonConvert.DeserializeObject>(rawJson) - .Select(kvp => Path.GetFileName(kvp.Value)); + {'?', "~q"}, + {'%', "~p"}, + {'#', "~h"}, + {'/', "~s"}, + {' ', "-"}, + {'-', "--"}, + {'_', "__"}, + {'"', "''"} - await Context.Channel.SendTableAsync(data, x => $"{x,-17}", 3).ConfigureAwait(false); - } - } + }.ToImmutableDictionary(); - [NadekoCommand, Usage, Description, Aliases] - public async Task Memegen(string meme, string topText, string botText) - { - var top = Replace(topText); - var bot = Replace(botText); - await Context.Channel.SendMessageAsync($"http://memegen.link/{meme}/{top}/{bot}.jpg") - .ConfigureAwait(false); - } - - private string Replace(string input) - { - StringBuilder sb = new StringBuilder(); - string tmp; - - foreach (var c in input) + [NadekoCommand, Usage, Description, Aliases] + public async Task Memelist() { - if (map.TryGetValue(c, out tmp)) - sb.Append(tmp); - else - sb.Append(c); + var handler = new HttpClientHandler + { + AllowAutoRedirect = false + }; + + + using (var http = new HttpClient(handler)) + { + var rawJson = await http.GetStringAsync("https://memegen.link/api/templates/").ConfigureAwait(false); + var data = JsonConvert.DeserializeObject>(rawJson) + .Select(kvp => Path.GetFileName(kvp.Value)); + + await Context.Channel.SendTableAsync(data, x => $"{x,-17}", 3).ConfigureAwait(false); + } } - return sb.ToString(); + [NadekoCommand, Usage, Description, Aliases] + public async Task Memegen(string meme, string topText, string botText) + { + var top = Replace(topText); + var bot = Replace(botText); + await Context.Channel.SendMessageAsync($"http://memegen.link/{meme}/{top}/{bot}.jpg") + .ConfigureAwait(false); + } + + private static string Replace(string input) + { + var sb = new StringBuilder(); + + foreach (var c in input) + { + string tmp; + if (_map.TryGetValue(c, out tmp)) + sb.Append(tmp); + else + sb.Append(c); + } + + return sb.ToString(); + } } } -} +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs b/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs index a2760a1a..0a764fab 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs @@ -3,7 +3,6 @@ using Discord.Commands; using NadekoBot.Attributes; using NadekoBot.Extensions; using Newtonsoft.Json.Linq; -using NLog; using System; using System.Globalization; using System.IO; @@ -16,21 +15,15 @@ namespace NadekoBot.Modules.Searches public partial class Searches { [Group] - public class OsuCommands : ModuleBase + public class OsuCommands : NadekoSubmodule { - private static Logger _log { get; } - - static OsuCommands() - { - _log = LogManager.GetCurrentClassLogger(); - } [NadekoCommand, Usage, Description, Aliases] public async Task Osu(string usr, [Remainder] string mode = null) { if (string.IsNullOrWhiteSpace(usr)) return; - using (HttpClient http = new HttpClient()) + using (var http = new HttpClient()) { try { @@ -42,15 +35,15 @@ namespace NadekoBot.Modules.Searches http.AddFakeHeaders(); var res = await http.GetStreamAsync(new Uri($"http://lemmmy.pw/osusig/sig.php?uname={ usr }&flagshadow&xpbar&xpbarhex&pp=2&mode={m}")).ConfigureAwait(false); - MemoryStream ms = new MemoryStream(); + var ms = new MemoryStream(); res.CopyTo(ms); ms.Position = 0; - await Context.Channel.SendFileAsync(ms, $"{usr}.png", $"🎧 **Profile Link:** \n`Image provided by https://lemmmy.pw/osusig`").ConfigureAwait(false); + await Context.Channel.SendFileAsync(ms, $"{usr}.png", $"🎧 **{GetText("profile_link")}** \n`Image provided by https://lemmmy.pw/osusig`").ConfigureAwait(false); } catch (Exception ex) { - await Context.Channel.SendErrorAsync("Failed retrieving osu signature.").ConfigureAwait(false); - _log.Warn(ex, "Osu command failed"); + await ReplyErrorLocalized("osu_failed").ConfigureAwait(false); + _log.Warn(ex); } } } @@ -60,7 +53,7 @@ namespace NadekoBot.Modules.Searches { if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.OsuApiKey)) { - await Context.Channel.SendErrorAsync("An osu! API key is required.").ConfigureAwait(false); + await ReplyErrorLocalized("osu_api_key").ConfigureAwait(false); return; } @@ -75,8 +68,8 @@ namespace NadekoBot.Modules.Searches var reqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Credentials.OsuApiKey}&{mapId}"; var obj = JArray.Parse(await http.GetStringAsync(reqString).ConfigureAwait(false))[0]; var sb = new System.Text.StringBuilder(); - var starRating = Math.Round(Double.Parse($"{obj["difficultyrating"]}", CultureInfo.InvariantCulture), 2); - var time = TimeSpan.FromSeconds(Double.Parse($"{obj["total_length"]}")).ToString(@"mm\:ss"); + var starRating = Math.Round(double.Parse($"{obj["difficultyrating"]}", CultureInfo.InvariantCulture), 2); + var time = TimeSpan.FromSeconds(double.Parse($"{obj["total_length"]}")).ToString(@"mm\:ss"); sb.AppendLine($"{obj["artist"]} - {obj["title"]}, mapped by {obj["creator"]}. https://osu.ppy.sh/s/{obj["beatmapset_id"]}"); sb.AppendLine($"{starRating} stars, {obj["bpm"]} BPM | AR{obj["diff_approach"]}, CS{obj["diff_size"]}, OD{obj["diff_overall"]} | Length: {time}"); await Context.Channel.SendMessageAsync(sb.ToString()).ConfigureAwait(false); @@ -84,8 +77,8 @@ namespace NadekoBot.Modules.Searches } catch (Exception ex) { - await Context.Channel.SendErrorAsync("Something went wrong."); - _log.Warn(ex, "Osub command failed"); + await ReplyErrorLocalized("something_went_wrong").ConfigureAwait(false); + _log.Warn(ex); } } @@ -121,54 +114,53 @@ namespace NadekoBot.Modules.Searches { var mapReqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Credentials.OsuApiKey}&b={item["beatmap_id"]}"; var map = JArray.Parse(await http.GetStringAsync(mapReqString).ConfigureAwait(false))[0]; - var pp = Math.Round(Double.Parse($"{item["pp"]}", CultureInfo.InvariantCulture), 2); + var pp = Math.Round(double.Parse($"{item["pp"]}", CultureInfo.InvariantCulture), 2); var acc = CalculateAcc(item, m); - var mods = ResolveMods(Int32.Parse($"{item["enabled_mods"]}")); - if (mods != "+") - sb.AppendLine($"{pp + "pp",-7} | {acc + "%",-7} | {map["artist"] + "-" + map["title"] + " (" + map["version"] + ")",-40} | **{mods,-10}** | /b/{item["beatmap_id"]}"); - else - sb.AppendLine($"{pp + "pp",-7} | {acc + "%",-7} | {map["artist"] + "-" + map["title"] + " (" + map["version"] + ")",-40} | /b/{item["beatmap_id"]}"); + var mods = ResolveMods(int.Parse($"{item["enabled_mods"]}")); + sb.AppendLine(mods != "+" + ? $"{pp + "pp",-7} | {acc + "%",-7} | {map["artist"] + "-" + map["title"] + " (" + map["version"] + ")",-40} | **{mods,-10}** | /b/{item["beatmap_id"]}" + : $"{pp + "pp",-7} | {acc + "%",-7} | {map["artist"] + "-" + map["title"] + " (" + map["version"] + ")",-40} | /b/{item["beatmap_id"]}"); } sb.Append("```"); await channel.SendMessageAsync(sb.ToString()).ConfigureAwait(false); } catch (Exception ex) { - await channel.SendErrorAsync("Something went wrong."); - _log.Warn(ex, "Osu5 command failed"); + await ReplyErrorLocalized("something_went_wrong").ConfigureAwait(false); + _log.Warn(ex); } } } //https://osu.ppy.sh/wiki/Accuracy - private static Double CalculateAcc(JToken play, int mode) + private static double CalculateAcc(JToken play, int mode) { if (mode == 0) { - var hitPoints = Double.Parse($"{play["count50"]}") * 50 + Double.Parse($"{play["count100"]}") * 100 + Double.Parse($"{play["count300"]}") * 300; - var totalHits = Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countmiss"]}"); + var hitPoints = double.Parse($"{play["count50"]}") * 50 + double.Parse($"{play["count100"]}") * 100 + double.Parse($"{play["count300"]}") * 300; + var totalHits = double.Parse($"{play["count50"]}") + double.Parse($"{play["count100"]}") + double.Parse($"{play["count300"]}") + double.Parse($"{play["countmiss"]}"); totalHits *= 300; return Math.Round(hitPoints / totalHits * 100, 2); } else if (mode == 1) { - var hitPoints = Double.Parse($"{play["countmiss"]}") * 0 + Double.Parse($"{play["count100"]}") * 0.5 + Double.Parse($"{play["count300"]}") * 1; - var totalHits = Double.Parse($"{play["countmiss"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}"); + var hitPoints = double.Parse($"{play["countmiss"]}") * 0 + double.Parse($"{play["count100"]}") * 0.5 + double.Parse($"{play["count300"]}") * 1; + var totalHits = double.Parse($"{play["countmiss"]}") + double.Parse($"{play["count100"]}") + double.Parse($"{play["count300"]}"); hitPoints *= 300; totalHits *= 300; return Math.Round(hitPoints / totalHits * 100, 2); } else if (mode == 2) { - var fruitsCaught = Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}"); - var totalFruits = Double.Parse($"{play["countmiss"]}") + Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countkatu"]}"); + var fruitsCaught = double.Parse($"{play["count50"]}") + double.Parse($"{play["count100"]}") + double.Parse($"{play["count300"]}"); + var totalFruits = double.Parse($"{play["countmiss"]}") + double.Parse($"{play["count50"]}") + double.Parse($"{play["count100"]}") + double.Parse($"{play["count300"]}") + double.Parse($"{play["countkatu"]}"); return Math.Round(fruitsCaught / totalFruits * 100, 2); } else { - var hitPoints = Double.Parse($"{play["count50"]}") * 50 + Double.Parse($"{play["count100"]}") * 100 + Double.Parse($"{play["countkatu"]}") * 200 + (Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countgeki"]}")) * 300; - var totalHits = Double.Parse($"{play["countmiss"]}") + Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["countkatu"]}") + Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countgeki"]}"); + var hitPoints = double.Parse($"{play["count50"]}") * 50 + double.Parse($"{play["count100"]}") * 100 + double.Parse($"{play["countkatu"]}") * 200 + (double.Parse($"{play["count300"]}") + double.Parse($"{play["countgeki"]}")) * 300; + var totalHits = double.Parse($"{play["countmiss"]}") + double.Parse($"{play["count50"]}") + double.Parse($"{play["count100"]}") + double.Parse($"{play["countkatu"]}") + double.Parse($"{play["count300"]}") + double.Parse($"{play["countgeki"]}"); totalHits *= 300; return Math.Round(hitPoints / totalHits * 100, 2); } @@ -176,10 +168,10 @@ namespace NadekoBot.Modules.Searches private static string ResolveMap(string mapLink) { - Match s = new Regex(@"osu.ppy.sh\/s\/", RegexOptions.IgnoreCase).Match(mapLink); - Match b = new Regex(@"osu.ppy.sh\/b\/", RegexOptions.IgnoreCase).Match(mapLink); - Match p = new Regex(@"osu.ppy.sh\/p\/", RegexOptions.IgnoreCase).Match(mapLink); - Match m = new Regex(@"&m=", RegexOptions.IgnoreCase).Match(mapLink); + var s = new Regex(@"osu.ppy.sh\/s\/", RegexOptions.IgnoreCase).Match(mapLink); + var b = new Regex(@"osu.ppy.sh\/b\/", RegexOptions.IgnoreCase).Match(mapLink); + var p = new Regex(@"osu.ppy.sh\/p\/", RegexOptions.IgnoreCase).Match(mapLink); + var m = new Regex(@"&m=", RegexOptions.IgnoreCase).Match(mapLink); if (s.Success) { var mapId = mapLink.Substring(mapLink.IndexOf("/s/") + 3); diff --git a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs index 77e88289..65574849 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs @@ -4,7 +4,6 @@ using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Modules.Searches.Models; using Newtonsoft.Json; -using NLog; using System.Net.Http; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -14,13 +13,8 @@ namespace NadekoBot.Modules.Searches public partial class Searches { [Group] - public class OverwatchCommands : ModuleBase + public class OverwatchCommands : NadekoSubmodule { - private readonly Logger _log; - public OverwatchCommands() - { - _log = LogManager.GetCurrentClassLogger(); - } [NadekoCommand, Usage, Description, Aliases] public async Task Overwatch(string region, [Remainder] string query = null) { @@ -34,9 +28,9 @@ namespace NadekoBot.Modules.Searches await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); var model = await GetProfile(region, battletag); - var rankimg = $"{model.Competitive.rank_img}"; - var rank = $"{model.Competitive.rank}"; - //var competitiveplay = $"{model.Games.Competitive.played}"; + var rankimg = model.Competitive.rank_img; + var rank = model.Competitive.rank; + if (string.IsNullOrWhiteSpace(rank)) { var embed = new EmbedBuilder() @@ -44,10 +38,10 @@ namespace NadekoBot.Modules.Searches .WithUrl($"https://www.overbuff.com/players/pc/{battletag}") .WithIconUrl($"{model.avatar}")) .WithThumbnailUrl("https://cdn.discordapp.com/attachments/155726317222887425/255653487512256512/YZ4w2ey.png") - .AddField(fb => fb.WithName("**Level**").WithValue($"{model.level}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Competitive Rank**").WithValue("0").WithIsInline(true)) - .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("level")).WithValue($"{model.level}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("quick_wins")).WithValue($"{model.Games.Quick.wins}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("compet_rank")).WithValue("0").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("quick_playtime")).WithValue($"{model.Playtime.quick}").WithIsInline(true)) .WithOkColor(); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } @@ -58,22 +52,21 @@ namespace NadekoBot.Modules.Searches .WithUrl($"https://www.overbuff.com/players/pc/{battletag}") .WithIconUrl($"{model.avatar}")) .WithThumbnailUrl(rankimg) - .AddField(fb => fb.WithName("**Level**").WithValue($"{model.level}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Quick Wins**").WithValue($"{model.Games.Quick.wins}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Competitive Wins**").WithValue($"{model.Games.Competitive.wins}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Competitive Loses**").WithValue($"{model.Games.Competitive.lost}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Competitive Played**").WithValue($"{model.Games.Competitive.played}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Competitive Rank**").WithValue(rank).WithIsInline(true)) - .AddField(fb => fb.WithName("**Competitive Playtime**").WithValue($"{model.Playtime.competitive}").WithIsInline(true)) - .AddField(fb => fb.WithName("**Quick Playtime**").WithValue($"{model.Playtime.quick}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("level")).WithValue($"{model.level}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("quick_wins")).WithValue($"{model.Games.Quick.wins}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("compet_wins")).WithValue($"{model.Games.Competitive.wins}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("compet_losses")).WithValue($"{model.Games.Competitive.lost}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("compet_played")).WithValue($"{model.Games.Competitive.played}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("compet_rank")).WithValue(rank).WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("compet_played")).WithValue($"{model.Playtime.competitive}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("quick_playtime")).WithValue($"{model.Playtime.quick}").WithIsInline(true)) .WithColor(NadekoBot.OkColor); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); - return; } } catch { - await Context.Channel.SendErrorAsync("Found no user! Please check the **Region** and **BattleTag** before trying again."); + await ReplyErrorLocalized("ow_user_not_found").ConfigureAwait(false); } } public async Task GetProfile(string region, string battletag) @@ -82,8 +75,8 @@ namespace NadekoBot.Modules.Searches { using (var http = new HttpClient()) { - var Url = await http.GetStringAsync($"https://api.lootbox.eu/pc/{region.ToLower()}/{battletag}/profile"); - var model = JsonConvert.DeserializeObject(Url); + var url = await http.GetStringAsync($"https://api.lootbox.eu/pc/{region.ToLower()}/{battletag}/profile"); + var model = JsonConvert.DeserializeObject(url); return model.data; } } diff --git a/src/NadekoBot/Modules/Searches/Commands/PlaceCommands.cs b/src/NadekoBot/Modules/Searches/Commands/PlaceCommands.cs index bd22733b..b44eb97d 100644 --- a/src/NadekoBot/Modules/Searches/Commands/PlaceCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/PlaceCommands.cs @@ -10,10 +10,9 @@ namespace NadekoBot.Modules.Searches public partial class Searches { [Group] - public class PlaceCommands : ModuleBase + public class PlaceCommands : NadekoSubmodule { - private static string typesStr { get; } = - string.Format("`List of \"{0}place\" tags:`\n", NadekoBot.ModulePrefixes[typeof(Searches).Name]) + String.Join(", ", Enum.GetNames(typeof(PlaceType))); + private static string typesStr { get; } = string.Join(", ", Enum.GetNames(typeof(PlaceType))); public enum PlaceType { @@ -30,14 +29,15 @@ namespace NadekoBot.Modules.Searches [NadekoCommand, Usage, Description, Aliases] public async Task Placelist() { - await Context.Channel.SendConfirmAsync(typesStr) + await Context.Channel.SendConfirmAsync(GetText("list_of_place_tags", NadekoBot.ModulePrefixes[typeof(Searches).Name]), + typesStr) .ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] public async Task Place(PlaceType placeType, uint width = 0, uint height = 0) { - string url = ""; + var url = ""; switch (placeType) { case PlaceType.Cage: diff --git a/src/NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs index 5f37c3d8..b04769fa 100644 --- a/src/NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs @@ -6,7 +6,6 @@ using NadekoBot.Modules.Searches.Models; using Newtonsoft.Json; using NLog; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -16,7 +15,7 @@ namespace NadekoBot.Modules.Searches public partial class Searches { [Group] - public class PokemonSearchCommands : ModuleBase + public class PokemonSearchCommands : NadekoSubmodule { private static Dictionary pokemons { get; } = new Dictionary(); private static Dictionary pokemonAbilities { get; } = new Dictionary(); @@ -24,7 +23,7 @@ namespace NadekoBot.Modules.Searches public const string PokemonAbilitiesFile = "data/pokemon/pokemon_abilities7.json"; public const string PokemonListFile = "data/pokemon/pokemon_list7.json"; - private static Logger _log { get; } + private new static readonly Logger _log; static PokemonSearchCommands() { @@ -57,14 +56,13 @@ namespace NadekoBot.Modules.Searches await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithTitle(kvp.Key.ToTitleCase()) .WithDescription(p.BaseStats.ToString()) - .AddField(efb => efb.WithName("Types").WithValue(string.Join(",\n", p.Types)).WithIsInline(true)) - .AddField(efb => efb.WithName("Height/Weight").WithValue($"{p.HeightM}m/{p.WeightKg}kg").WithIsInline(true)) - .AddField(efb => efb.WithName("Abilitities").WithValue(string.Join(",\n", p.Abilities.Select(a => a.Value))).WithIsInline(true)) - ); + .AddField(efb => efb.WithName(GetText("types")).WithValue(string.Join(",\n", p.Types)).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("height_weight")).WithValue(GetText("height_weight_val", p.HeightM, p.WeightKg)).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("abilities")).WithValue(string.Join(",\n", p.Abilities.Select(a => a.Value))).WithIsInline(true))); return; } } - await Context.Channel.SendErrorAsync("No pokemon found."); + await ReplyErrorLocalized("pokemon_none").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -80,12 +78,12 @@ namespace NadekoBot.Modules.Searches await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithTitle(kvp.Value.Name) .WithDescription(kvp.Value.Desc) - .AddField(efb => efb.WithName("Rating").WithValue(kvp.Value.Rating.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("rating")).WithValue(kvp.Value.Rating.ToString(_cultureInfo)).WithIsInline(true)) ).ConfigureAwait(false); return; } } - await Context.Channel.SendErrorAsync("No ability found."); + await ReplyErrorLocalized("pokemon_ability_none").ConfigureAwait(false); } } } diff --git a/src/NadekoBot/Modules/Searches/Commands/StreamNotificationCommands.cs b/src/NadekoBot/Modules/Searches/Commands/StreamNotificationCommands.cs index 86411634..d122e47a 100644 --- a/src/NadekoBot/Modules/Searches/Commands/StreamNotificationCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/StreamNotificationCommands.cs @@ -12,9 +12,7 @@ using System.Net.Http; using NadekoBot.Attributes; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; -using NLog; using NadekoBot.Extensions; -using System.Diagnostics; namespace NadekoBot.Modules.Searches { @@ -65,23 +63,19 @@ namespace NadekoBot.Modules.Searches } [Group] - public class StreamNotificationCommands : ModuleBase + public class StreamNotificationCommands : NadekoSubmodule { - private static Timer checkTimer { get; } - private static ConcurrentDictionary oldCachedStatuses = new ConcurrentDictionary(); - private static ConcurrentDictionary cachedStatuses = new ConcurrentDictionary(); - private static Logger _log { get; } + private static readonly Timer _checkTimer; + private static readonly ConcurrentDictionary _cachedStatuses = new ConcurrentDictionary(); - private static bool FirstPass { get; set; } = true; + private static bool firstPass { get; set; } = true; static StreamNotificationCommands() { - _log = LogManager.GetCurrentClassLogger(); - - checkTimer = new Timer(async (state) => + _checkTimer = new Timer(async (state) => { - oldCachedStatuses = new ConcurrentDictionary(cachedStatuses); - cachedStatuses.Clear(); + var oldCachedStatuses = new ConcurrentDictionary(_cachedStatuses); + _cachedStatuses.Clear(); IEnumerable streams; using (var uow = DbHandler.UnitOfWork()) { @@ -93,7 +87,7 @@ namespace NadekoBot.Modules.Searches try { var newStatus = await GetStreamStatus(fs).ConfigureAwait(false); - if (FirstPass) + if (firstPass) { return; } @@ -108,7 +102,7 @@ namespace NadekoBot.Modules.Searches return; try { - var msg = await channel.EmbedAsync(fs.GetEmbed(newStatus)).ConfigureAwait(false); + await channel.EmbedAsync(fs.GetEmbed(newStatus, channel.Guild.Id)).ConfigureAwait(false); } catch { @@ -122,7 +116,7 @@ namespace NadekoBot.Modules.Searches } })); - FirstPass = false; + firstPass = false; }, null, TimeSpan.Zero, TimeSpan.FromSeconds(60)); } @@ -134,7 +128,7 @@ namespace NadekoBot.Modules.Searches { case FollowedStream.FollowedStreamType.Hitbox: var hitboxUrl = $"https://api.hitbox.tv/media/status/{stream.Username.ToLowerInvariant()}"; - if (checkCache && cachedStatuses.TryGetValue(hitboxUrl, out result)) + if (checkCache && _cachedStatuses.TryGetValue(hitboxUrl, out result)) return result; using (var http = new HttpClient()) { @@ -149,11 +143,11 @@ namespace NadekoBot.Modules.Searches ApiLink = hitboxUrl, Views = hbData.Views }; - cachedStatuses.AddOrUpdate(hitboxUrl, result, (key, old) => result); + _cachedStatuses.AddOrUpdate(hitboxUrl, result, (key, old) => result); return result; case FollowedStream.FollowedStreamType.Twitch: var twitchUrl = $"https://api.twitch.tv/kraken/streams/{Uri.EscapeUriString(stream.Username.ToLowerInvariant())}?client_id=67w6z9i09xv2uoojdm9l0wsyph4hxo6"; - if (checkCache && cachedStatuses.TryGetValue(twitchUrl, out result)) + if (checkCache && _cachedStatuses.TryGetValue(twitchUrl, out result)) return result; using (var http = new HttpClient()) { @@ -170,11 +164,11 @@ namespace NadekoBot.Modules.Searches ApiLink = twitchUrl, Views = twData.Stream?.Viewers.ToString() ?? "0" }; - cachedStatuses.AddOrUpdate(twitchUrl, result, (key, old) => result); + _cachedStatuses.AddOrUpdate(twitchUrl, result, (key, old) => result); return result; case FollowedStream.FollowedStreamType.Beam: var beamUrl = $"https://beam.pro/api/v1/channels/{stream.Username.ToLowerInvariant()}"; - if (checkCache && cachedStatuses.TryGetValue(beamUrl, out result)) + if (checkCache && _cachedStatuses.TryGetValue(beamUrl, out result)) return result; using (var http = new HttpClient()) { @@ -190,7 +184,7 @@ namespace NadekoBot.Modules.Searches ApiLink = beamUrl, Views = bmData.ViewersCurrent.ToString() }; - cachedStatuses.AddOrUpdate(beamUrl, result, (key, old) => result); + _cachedStatuses.AddOrUpdate(beamUrl, result, (key, old) => result); return result; default: break; @@ -234,17 +228,21 @@ namespace NadekoBot.Modules.Searches if (!streams.Any()) { - await Context.Channel.SendConfirmAsync("You are not following any streams on this server.").ConfigureAwait(false); + await ReplyErrorLocalized("streams_none").ConfigureAwait(false); return; } var text = string.Join("\n", await Task.WhenAll(streams.Select(async snc => { var ch = await Context.Guild.GetTextChannelAsync(snc.ChannelId); - return $"`{snc.Username}`'s stream on **{(ch)?.Name}** channel. 【`{snc.Type.ToString()}`】"; + return string.Format("{0}'s stream on {1} channel. 【{2}】", + Format.Code(snc.Username), + Format.Bold(ch?.Name ?? "deleted-channel"), + Format.Code(snc.Type.ToString())); }))); - - await Context.Channel.SendConfirmAsync($"You are following **{streams.Count()}** streams on this server.\n\n" + text).ConfigureAwait(false); + + await Context.Channel.SendConfirmAsync(GetText("streams_following", streams.Count()) + "\n\n" + text) + .ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -271,10 +269,13 @@ namespace NadekoBot.Modules.Searches } if (!removed) { - await Context.Channel.SendErrorAsync("No such stream.").ConfigureAwait(false); + await ReplyErrorLocalized("stream_no").ConfigureAwait(false); return; } - await Context.Channel.SendConfirmAsync($"Removed `{username}`'s stream ({type}) from notifications.").ConfigureAwait(false); + + await ReplyConfirmLocalized("stream_removed", + Format.Code(username), + type).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -293,20 +294,24 @@ namespace NadekoBot.Modules.Searches })); if (streamStatus.IsLive) { - await Context.Channel.SendConfirmAsync($"Streamer {username} is online with {streamStatus.Views} viewers."); + await ReplyConfirmLocalized("streamer_online", + username, + streamStatus.Views) + .ConfigureAwait(false); } else { - await Context.Channel.SendConfirmAsync($"Streamer {username} is offline."); + await ReplyConfirmLocalized("streamer_offline", + username).ConfigureAwait(false); } } catch { - await Context.Channel.SendErrorAsync("No channel found."); + await ReplyErrorLocalized("no_channel_found").ConfigureAwait(false); } } - private static async Task TrackStream(ITextChannel channel, string username, FollowedStream.FollowedStreamType type) + private async Task TrackStream(ITextChannel channel, string username, FollowedStream.FollowedStreamType type) { username = username.ToLowerInvariant().Trim(); var fs = new FollowedStream @@ -324,7 +329,7 @@ namespace NadekoBot.Modules.Searches } catch { - await channel.SendErrorAsync("Stream probably doesn't exist.").ConfigureAwait(false); + await ReplyErrorLocalized("stream_not_exist").ConfigureAwait(false); return; } @@ -335,24 +340,24 @@ namespace NadekoBot.Modules.Searches .Add(fs); await uow.CompleteAsync().ConfigureAwait(false); } - await channel.EmbedAsync(fs.GetEmbed(status), $"🆗 I will notify this channel when status changes.").ConfigureAwait(false); + await channel.EmbedAsync(fs.GetEmbed(status, Context.Guild.Id), GetText("stream_tracked")).ConfigureAwait(false); } } } public static class FollowedStreamExtensions { - public static EmbedBuilder GetEmbed(this FollowedStream fs, Searches.StreamStatus status) + public static EmbedBuilder GetEmbed(this FollowedStream fs, Searches.StreamStatus status, ulong guildId) { var embed = new EmbedBuilder().WithTitle(fs.Username) .WithUrl(fs.GetLink()) - .AddField(efb => efb.WithName("Status") + .AddField(efb => efb.WithName(fs.GetText("status")) .WithValue(status.IsLive ? "Online" : "Offline") .WithIsInline(true)) - .AddField(efb => efb.WithName("Viewers") + .AddField(efb => efb.WithName(fs.GetText("viewers")) .WithValue(status.IsLive ? status.Views : "-") .WithIsInline(true)) - .AddField(efb => efb.WithName("Platform") + .AddField(efb => efb.WithName(fs.GetText("platform")) .WithValue(fs.Type.ToString()) .WithIsInline(true)) .WithColor(status.IsLive ? NadekoBot.OkColor : NadekoBot.ErrorColor); @@ -360,15 +365,21 @@ namespace NadekoBot.Modules.Searches return embed; } - public static string GetLink(this FollowedStream fs) { + public static string GetText(this FollowedStream fs, string key, params object[] replacements) => + NadekoTopLevelModule.GetTextStatic(key, + NadekoBot.Localization.GetCultureInfo(fs.GuildId), + typeof(Searches).Name.ToLowerInvariant(), + replacements); + + public static string GetLink(this FollowedStream fs) + { if (fs.Type == FollowedStream.FollowedStreamType.Hitbox) return $"http://www.hitbox.tv/{fs.Username}/"; - else if (fs.Type == FollowedStream.FollowedStreamType.Twitch) + if (fs.Type == FollowedStream.FollowedStreamType.Twitch) return $"http://www.twitch.tv/{fs.Username}/"; - else if (fs.Type == FollowedStream.FollowedStreamType.Beam) + if (fs.Type == FollowedStream.FollowedStreamType.Beam) return $"https://beam.pro/{fs.Username}/"; - else - return "??"; + return "??"; } } } diff --git a/src/NadekoBot/Modules/Searches/Commands/Translator.cs b/src/NadekoBot/Modules/Searches/Commands/Translator.cs index 3ee67e6c..9ed33ce5 100644 --- a/src/NadekoBot/Modules/Searches/Commands/Translator.cs +++ b/src/NadekoBot/Modules/Searches/Commands/Translator.cs @@ -19,10 +19,10 @@ namespace NadekoBot.Modules.Searches } [Group] - public class TranslateCommands : ModuleBase + public class TranslateCommands : NadekoSubmodule { - private static ConcurrentDictionary TranslatedChannels { get; } = new ConcurrentDictionary(); - private static ConcurrentDictionary UserLanguages { get; } = new ConcurrentDictionary(); + private static ConcurrentDictionary translatedChannels { get; } = new ConcurrentDictionary(); + private static ConcurrentDictionary userLanguages { get; } = new ConcurrentDictionary(); static TranslateCommands() { @@ -35,7 +35,7 @@ namespace NadekoBot.Modules.Searches return; bool autoDelete; - if (!TranslatedChannels.TryGetValue(umsg.Channel.Id, out autoDelete)) + if (!translatedChannels.TryGetValue(umsg.Channel.Id, out autoDelete)) return; var key = new UserChannelPair() { @@ -44,10 +44,10 @@ namespace NadekoBot.Modules.Searches }; string langs; - if (!UserLanguages.TryGetValue(key, out langs)) + if (!userLanguages.TryGetValue(key, out langs)) return; - var text = await TranslateInternal(langs, umsg.Resolve(TagHandling.Ignore), true) + var text = await TranslateInternal(langs, umsg.Resolve(TagHandling.Ignore)) .ConfigureAwait(false); if (autoDelete) try { await umsg.DeleteAsync().ConfigureAwait(false); } catch { } @@ -64,21 +64,21 @@ namespace NadekoBot.Modules.Searches { await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); var translation = await TranslateInternal(langs, text); - await Context.Channel.SendConfirmAsync("Translation " + langs, translation).ConfigureAwait(false); + await Context.Channel.SendConfirmAsync(GetText("translation") + " " + langs, translation).ConfigureAwait(false); } catch { - await Context.Channel.SendErrorAsync("Bad input format, or something went wrong...").ConfigureAwait(false); + await ReplyErrorLocalized("bad_input_format").ConfigureAwait(false); } } - private static async Task TranslateInternal(string langs, [Remainder] string text = null, bool silent = false) + private static async Task TranslateInternal(string langs, [Remainder] string text = null) { var langarr = langs.ToLowerInvariant().Split('>'); if (langarr.Length != 2) throw new ArgumentException(); - string from = langarr[0]; - string to = langarr[1]; + var from = langarr[0]; + var to = langarr[1]; text = text?.Trim(); if (string.IsNullOrWhiteSpace(text)) throw new ArgumentException(); @@ -101,20 +101,20 @@ namespace NadekoBot.Modules.Searches if (autoDelete == AutoDeleteAutoTranslate.Del) { - TranslatedChannels.AddOrUpdate(channel.Id, true, (key, val) => true); - try { await channel.SendConfirmAsync("Started automatic translation of messages on this channel. User messages will be auto-deleted.").ConfigureAwait(false); } catch { } + translatedChannels.AddOrUpdate(channel.Id, true, (key, val) => true); + await ReplyConfirmLocalized("atl_ad_started").ConfigureAwait(false); return; } bool throwaway; - if (TranslatedChannels.TryRemove(channel.Id, out throwaway)) + if (translatedChannels.TryRemove(channel.Id, out throwaway)) { - try { await channel.SendConfirmAsync("Stopped automatic translation of messages on this channel.").ConfigureAwait(false); } catch { } + await ReplyConfirmLocalized("atl_stopped").ConfigureAwait(false); return; } - else if (TranslatedChannels.TryAdd(channel.Id, autoDelete == AutoDeleteAutoTranslate.Del)) + if (translatedChannels.TryAdd(channel.Id, autoDelete == AutoDeleteAutoTranslate.Del)) { - try { await channel.SendConfirmAsync("Started automatic translation of messages on this channel.").ConfigureAwait(false); } catch { } + await ReplyConfirmLocalized("atl_started").ConfigureAwait(false); } } @@ -130,8 +130,8 @@ namespace NadekoBot.Modules.Searches if (string.IsNullOrWhiteSpace(langs)) { - if (UserLanguages.TryRemove(ucp, out langs)) - await Context.Channel.SendConfirmAsync($"{Context.User.Mention}'s auto-translate language has been removed.").ConfigureAwait(false); + if (userLanguages.TryRemove(ucp, out langs)) + await ReplyConfirmLocalized("atl_removed").ConfigureAwait(false); return; } @@ -143,20 +143,20 @@ namespace NadekoBot.Modules.Searches if (!GoogleTranslator.Instance.Languages.Contains(from) || !GoogleTranslator.Instance.Languages.Contains(to)) { - try { await Context.Channel.SendErrorAsync("Invalid source and/or target language.").ConfigureAwait(false); } catch { } + await ReplyErrorLocalized("invalid_lang").ConfigureAwait(false); return; } - UserLanguages.AddOrUpdate(ucp, langs, (key, val) => langs); + userLanguages.AddOrUpdate(ucp, langs, (key, val) => langs); - await Context.Channel.SendConfirmAsync($"Your auto-translate language has been set to {from}>{to}").ConfigureAwait(false); + await ReplyConfirmLocalized("atl_set", from, to).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task Translangs() { - await Context.Channel.SendTableAsync(GoogleTranslator.Instance.Languages, str => $"{str,-15}", columns: 3); + await Context.Channel.SendTableAsync(GoogleTranslator.Instance.Languages, str => $"{str,-15}", 3); } } diff --git a/src/NadekoBot/Modules/Searches/Commands/XkcdCommands.cs b/src/NadekoBot/Modules/Searches/Commands/XkcdCommands.cs index a8de4c7e..b747f2bd 100644 --- a/src/NadekoBot/Modules/Searches/Commands/XkcdCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/XkcdCommands.cs @@ -12,9 +12,9 @@ namespace NadekoBot.Modules.Searches public partial class Searches { [Group] - public class XkcdCommands : ModuleBase + public class XkcdCommands : NadekoSubmodule { - private const string xkcdUrl = "https://xkcd.com"; + private const string _xkcdUrl = "https://xkcd.com"; [NadekoCommand, Usage, Description, Aliases] [Priority(1)] @@ -24,9 +24,9 @@ namespace NadekoBot.Modules.Searches { using (var http = new HttpClient()) { - var res = await http.GetStringAsync($"{xkcdUrl}/info.0.json").ConfigureAwait(false); + var res = await http.GetStringAsync($"{_xkcdUrl}/info.0.json").ConfigureAwait(false); var comic = JsonConvert.DeserializeObject(res); - var sent = await Context.Channel.SendMessageAsync($"{Context.User.Mention} " + comic.ToString()) + var sent = await Context.Channel.SendMessageAsync($"{Context.User.Mention} " + comic) .ConfigureAwait(false); await Task.Delay(10000).ConfigureAwait(false); @@ -47,14 +47,14 @@ namespace NadekoBot.Modules.Searches using (var http = new HttpClient()) { - var res = await http.GetStringAsync($"{xkcdUrl}/{num}/info.0.json").ConfigureAwait(false); + var res = await http.GetStringAsync($"{_xkcdUrl}/{num}/info.0.json").ConfigureAwait(false); var comic = JsonConvert.DeserializeObject(res); var embed = new EmbedBuilder().WithColor(NadekoBot.OkColor) .WithImageUrl(comic.ImageLink) - .WithAuthor(eab => eab.WithName(comic.Title).WithUrl($"{xkcdUrl}/{num}").WithIconUrl("http://xkcd.com/s/919f27.ico")) - .AddField(efb => efb.WithName("Comic#").WithValue(comic.Num.ToString()).WithIsInline(true)) - .AddField(efb => efb.WithName("Date").WithValue($"{comic.Month}/{comic.Year}").WithIsInline(true)); + .WithAuthor(eab => eab.WithName(comic.Title).WithUrl($"{_xkcdUrl}/{num}").WithIconUrl("http://xkcd.com/s/919f27.ico")) + .AddField(efb => efb.WithName(GetText("comic_number")).WithValue(comic.Num.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("date")).WithValue($"{comic.Month}/{comic.Year}").WithIsInline(true)); var sent = await Context.Channel.EmbedAsync(embed) .ConfigureAwait(false); @@ -75,9 +75,6 @@ namespace NadekoBot.Modules.Searches [JsonProperty("img")] public string ImageLink { get; set; } public string Alt { get; set; } - - public override string ToString() - => $"`Comic:` #{Num} `Title:` {Title} `Date:` {Month}/{Year}\n{ImageLink}"; } } } diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 096a171c..28fb15bb 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -41,15 +41,15 @@ namespace NadekoBot.Modules.Searches var data = JsonConvert.DeserializeObject(response); var embed = new EmbedBuilder() - .AddField(fb => fb.WithName("🌍 **Location**").WithValue(data.name + ", " + data.sys.country).WithIsInline(true)) - .AddField(fb => fb.WithName("📏 **Lat,Long**").WithValue($"{data.coord.lat}, {data.coord.lon}").WithIsInline(true)) - .AddField(fb => fb.WithName("☁ **Condition**").WithValue(String.Join(", ", data.weather.Select(w => w.main))).WithIsInline(true)) - .AddField(fb => fb.WithName("😓 **Humidity**").WithValue($"{data.main.humidity}%").WithIsInline(true)) - .AddField(fb => fb.WithName("💨 **Wind Speed**").WithValue(data.wind.speed + " km/h").WithIsInline(true)) - .AddField(fb => fb.WithName("🌡 **Temperature**").WithValue(data.main.temp + "°C").WithIsInline(true)) - .AddField(fb => fb.WithName("🔆 **Min - Max**").WithValue($"{data.main.temp_min}°C - {data.main.temp_max}°C").WithIsInline(true)) - .AddField(fb => fb.WithName("🌄 **Sunrise (utc)**").WithValue($"{data.sys.sunrise.ToUnixTimestamp():HH:mm}").WithIsInline(true)) - .AddField(fb => fb.WithName("🌇 **Sunset (utc)**").WithValue($"{data.sys.sunset.ToUnixTimestamp():HH:mm}").WithIsInline(true)) + .AddField(fb => fb.WithName("🌍 " + GetText("location")).WithValue(data.name + ", " + data.sys.country).WithIsInline(true)) + .AddField(fb => fb.WithName("📏 " + GetText("latlong")).WithValue($"{data.coord.lat}, {data.coord.lon}").WithIsInline(true)) + .AddField(fb => fb.WithName("☁ " + GetText("condition")).WithValue(string.Join(", ", data.weather.Select(w => w.main))).WithIsInline(true)) + .AddField(fb => fb.WithName("😓 " + GetText("humidity")).WithValue($"{data.main.humidity}%").WithIsInline(true)) + .AddField(fb => fb.WithName("💨 " + GetText("wind_speed")).WithValue(data.wind.speed + " km/h").WithIsInline(true)) + .AddField(fb => fb.WithName("🌡 " + GetText("temperature")).WithValue(data.main.temp + "°C").WithIsInline(true)) + .AddField(fb => fb.WithName("🔆 " + GetText("min_max")).WithValue($"{data.main.temp_min}°C - {data.main.temp_max}°C").WithIsInline(true)) + .AddField(fb => fb.WithName("🌄 " + GetText("sunrise")).WithValue($"{data.sys.sunrise.ToUnixTimestamp():HH:mm}").WithIsInline(true)) + .AddField(fb => fb.WithName("🌇 " + GetText("sunset")).WithValue($"{data.sys.sunset.ToUnixTimestamp():HH:mm}").WithIsInline(true)) .WithOkColor() .WithFooter(efb => efb.WithText("Powered by http://openweathermap.org")); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); @@ -58,17 +58,15 @@ namespace NadekoBot.Modules.Searches [NadekoCommand, Usage, Description, Aliases] public async Task Youtube([Remainder] string query = null) { - if (!(await ValidateQuery(Context.Channel, query).ConfigureAwait(false))) return; + if (!await ValidateQuery(Context.Channel, query).ConfigureAwait(false)) return; var result = (await NadekoBot.Google.GetVideosByKeywordsAsync(query, 1)).FirstOrDefault(); if (string.IsNullOrWhiteSpace(result)) { - await Context.Channel.SendErrorAsync("No results found for that query.").ConfigureAwait(false); + await ReplyErrorLocalized("no_results").ConfigureAwait(false); return; } await Context.Channel.SendMessageAsync(result).ConfigureAwait(false); - - //await Context.Channel.EmbedAsync(new Discord.API.Embed() { Video = new Discord.API.EmbedVideo() { Url = result.Replace("watch?v=", "embed/") }, Color = NadekoBot.OkColor }).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -80,7 +78,7 @@ namespace NadekoBot.Modules.Searches var movie = await OmdbProvider.FindMovie(query); if (movie == null) { - await Context.Channel.SendErrorAsync("Failed to find that movie.").ConfigureAwait(false); + await ReplyErrorLocalized("imdb_fail").ConfigureAwait(false); return; } await Context.Channel.EmbedAsync(movie.GetEmbed()).ConfigureAwait(false); @@ -120,7 +118,7 @@ namespace NadekoBot.Modules.Searches var res = await NadekoBot.Google.GetImageAsync(terms).ConfigureAwait(false); var embed = new EmbedBuilder() .WithOkColor() - .WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50)) + .WithAuthor(eab => eab.WithName(GetText("image_search_for") + " " + terms.TrimTo(50)) .WithUrl("https://www.google.rs/search?q=" + terms + "&source=lnms&tbm=isch") .WithIconUrl("http://i.imgur.com/G46fm8J.png")) .WithDescription(res.Link) @@ -172,7 +170,7 @@ namespace NadekoBot.Modules.Searches var res = await NadekoBot.Google.GetImageAsync(terms, new NadekoRandom().Next(0, 50)).ConfigureAwait(false); var embed = new EmbedBuilder() .WithOkColor() - .WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50)) + .WithAuthor(eab => eab.WithName(GetText("image_search_for") + " " + terms.TrimTo(50)) .WithUrl("https://www.google.rs/search?q=" + terms + "&source=lnms&tbm=isch") .WithIconUrl("http://i.imgur.com/G46fm8J.png")) .WithDescription(res.Link) @@ -203,7 +201,7 @@ namespace NadekoBot.Modules.Searches var embed = new EmbedBuilder() .WithOkColor() - .WithAuthor(eab => eab.WithName("Image Search For: " + terms.TrimTo(50)) + .WithAuthor(eab => eab.WithName(GetText("image_search_for") + " " + terms.TrimTo(50)) .WithUrl(fullQueryLink) .WithIconUrl("http://s.imgur.com/images/logo-1200-630.jpg?")) .WithDescription(source) @@ -233,13 +231,14 @@ namespace NadekoBot.Modules.Searches if (shortened == arg) { - await Context.Channel.SendErrorAsync("Failed to shorten that url.").ConfigureAwait(false); + await ReplyErrorLocalized("shorten_fail").ConfigureAwait(false); + return; } await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor) - .AddField(efb => efb.WithName("Original Url") + .AddField(efb => efb.WithName(GetText("original_url")) .WithValue($"<{arg}>")) - .AddField(efb => efb.WithName("Short Url") + .AddField(efb => efb.WithName(GetText("short_url")) .WithValue($"<{shortened}>"))) .ConfigureAwait(false); } @@ -287,7 +286,7 @@ namespace NadekoBot.Modules.Searches var embed = new EmbedBuilder() .WithOkColor() - .WithAuthor(eab => eab.WithName("Search For: " + terms.TrimTo(50)) + .WithAuthor(eab => eab.WithName(GetText("search_for") + " " + terms.TrimTo(50)) .WithUrl(fullQueryLink) .WithIconUrl("http://i.imgur.com/G46fm8J.png")) .WithTitle(Context.User.ToString()) @@ -296,26 +295,22 @@ namespace NadekoBot.Modules.Searches var desc = await Task.WhenAll(results.Select(async res => $"[{Format.Bold(res?.Title)}]({(await NadekoBot.Google.ShortenUrl(res?.Link))})\n{res?.Text}\n\n")) .ConfigureAwait(false); - await Context.Channel.EmbedAsync(embed.WithDescription(String.Concat(desc))).ConfigureAwait(false); + await Context.Channel.EmbedAsync(embed.WithDescription(string.Concat(desc))).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] - public async Task MagicTheGathering([Remainder] string name = null) + public async Task MagicTheGathering([Remainder] string name) { var arg = name; if (string.IsNullOrWhiteSpace(arg)) - { - await Context.Channel.SendErrorAsync("Please enter a card name to search for.").ConfigureAwait(false); return; - } await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); - string response = ""; using (var http = new HttpClient()) { http.DefaultRequestHeaders.Clear(); - response = await http.GetStringAsync($"https://api.deckbrew.com/mtg/cards?name={Uri.EscapeUriString(arg)}") - .ConfigureAwait(false); + var response = await http.GetStringAsync($"https://api.deckbrew.com/mtg/cards?name={Uri.EscapeUriString(arg)}") + .ConfigureAwait(false); try { var items = JArray.Parse(response).ToArray(); @@ -325,50 +320,46 @@ namespace NadekoBot.Modules.Searches var storeUrl = await NadekoBot.Google.ShortenUrl(item["store_url"].ToString()); var cost = item["cost"].ToString(); var desc = item["text"].ToString(); - var types = String.Join(",\n", item["types"].ToObject()); + var types = string.Join(",\n", item["types"].ToObject()); var img = item["editions"][0]["image_url"].ToString(); var embed = new EmbedBuilder().WithOkColor() .WithTitle(item["name"].ToString()) .WithDescription(desc) .WithImageUrl(img) - .AddField(efb => efb.WithName("Store Url").WithValue(storeUrl).WithIsInline(true)) - .AddField(efb => efb.WithName("Cost").WithValue(cost).WithIsInline(true)) - .AddField(efb => efb.WithName("Types").WithValue(types).WithIsInline(true)); + .AddField(efb => efb.WithName(GetText("store_url")).WithValue(storeUrl).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("cost")).WithValue(cost).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("types")).WithValue(types).WithIsInline(true)); //.AddField(efb => efb.WithName("Store Url").WithValue(await NadekoBot.Google.ShortenUrl(items[0]["store_url"].ToString())).WithIsInline(true)); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } catch { - await Context.Channel.SendErrorAsync($"Error could not find the card '{arg}'.").ConfigureAwait(false); + await ReplyErrorLocalized("card_not_found").ConfigureAwait(false); } } } [NadekoCommand, Usage, Description, Aliases] - public async Task Hearthstone([Remainder] string name = null) + public async Task Hearthstone([Remainder] string name) { var arg = name; if (string.IsNullOrWhiteSpace(arg)) - { - await Context.Channel.SendErrorAsync("Please enter a card name to search for.").ConfigureAwait(false); return; - } if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey)) { - await Context.Channel.SendErrorAsync("Bot owner didn't specify MashapeApiKey. You can't use this functionality.").ConfigureAwait(false); + await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false); return; } await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); - string response = ""; using (var http = new HttpClient()) { http.DefaultRequestHeaders.Clear(); http.DefaultRequestHeaders.Add("X-Mashape-Key", NadekoBot.Credentials.MashapeKey); - response = await http.GetStringAsync($"https://omgvamp-hearthstone-v1.p.mashape.com/cards/search/{Uri.EscapeUriString(arg)}") - .ConfigureAwait(false); + var response = await http.GetStringAsync($"https://omgvamp-hearthstone-v1.p.mashape.com/cards/search/{Uri.EscapeUriString(arg)}") + .ConfigureAwait(false); try { var items = JArray.Parse(response).Shuffle().ToList(); @@ -391,7 +382,7 @@ namespace NadekoBot.Modules.Searches string msg = null; if (items.Count > 4) { - msg = "⚠ Found over 4 images. Showing random 4."; + msg = GetText("hs_over_x", 4); } var ms = new MemoryStream(); await Task.Run(() => images.AsEnumerable().Merge().Save(ms)); @@ -400,8 +391,8 @@ namespace NadekoBot.Modules.Searches } catch (Exception ex) { - await Context.Channel.SendErrorAsync($"Error occured.").ConfigureAwait(false); _log.Error(ex); + await ReplyErrorLocalized("error_occured").ConfigureAwait(false); } } } @@ -411,23 +402,20 @@ namespace NadekoBot.Modules.Searches { if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey)) { - await Context.Channel.SendErrorAsync("Bot owner didn't specify MashapeApiKey. You can't use this functionality.").ConfigureAwait(false); + await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false); return; } - var arg = query; - if (string.IsNullOrWhiteSpace(arg)) - { - await Context.Channel.SendErrorAsync("Please enter a sentence.").ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(query)) return; - } + await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); using (var http = new HttpClient()) { http.DefaultRequestHeaders.Clear(); http.DefaultRequestHeaders.Add("X-Mashape-Key", NadekoBot.Credentials.MashapeKey); http.DefaultRequestHeaders.Add("Accept", "text/plain"); - var res = await http.GetStringAsync($"https://yoda.p.mashape.com/yoda?sentence={Uri.EscapeUriString(arg)}").ConfigureAwait(false); + var res = await http.GetStringAsync($"https://yoda.p.mashape.com/yoda?sentence={Uri.EscapeUriString(query)}").ConfigureAwait(false); try { var embed = new EmbedBuilder() @@ -439,7 +427,7 @@ namespace NadekoBot.Modules.Searches } catch { - await Context.Channel.SendErrorAsync("Failed to yodify your sentence.").ConfigureAwait(false); + await ReplyErrorLocalized("yodify_error").ConfigureAwait(false); } } } @@ -449,22 +437,19 @@ namespace NadekoBot.Modules.Searches { if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey)) { - await Context.Channel.SendErrorAsync("Bot owner didn't specify MashapeApiKey. You can't use this functionality.").ConfigureAwait(false); + await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false); return; } - var arg = query; - if (string.IsNullOrWhiteSpace(arg)) - { - await Context.Channel.SendErrorAsync("Please enter a search term.").ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(query)) return; - } + await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); using (var http = new HttpClient()) { http.DefaultRequestHeaders.Clear(); http.DefaultRequestHeaders.Add("Accept", "application/json"); - var res = await http.GetStringAsync($"http://api.urbandictionary.com/v0/define?term={Uri.EscapeUriString(arg)}").ConfigureAwait(false); + var res = await http.GetStringAsync($"http://api.urbandictionary.com/v0/define?term={Uri.EscapeUriString(query)}").ConfigureAwait(false); try { var items = JObject.Parse(res); @@ -480,7 +465,7 @@ namespace NadekoBot.Modules.Searches } catch { - await Context.Channel.SendErrorAsync("Failed finding a definition for that term.").ConfigureAwait(false); + await ReplyErrorLocalized("ud_error").ConfigureAwait(false); } } } @@ -507,39 +492,36 @@ namespace NadekoBot.Modules.Searches definition = ((JArray)JToken.Parse(sense.Definition.ToString())).First.ToString(); var embed = new EmbedBuilder().WithOkColor() - .WithTitle("Define: " + word) + .WithTitle(GetText("define") + " " + word) .WithDescription(definition) .WithFooter(efb => efb.WithText(sense.Gramatical_info?.type)); if (sense.Examples != null) - embed.AddField(efb => efb.WithName("Example").WithValue(sense.Examples.First().text)); + embed.AddField(efb => efb.WithName(GetText("example")).WithValue(sense.Examples.First().text)); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } } [NadekoCommand, Usage, Description, Aliases] - public async Task Hashtag([Remainder] string query = null) + public async Task Hashtag([Remainder] string query) { - var arg = query; - if (string.IsNullOrWhiteSpace(arg)) - { - await Context.Channel.SendErrorAsync("Please enter a search term.").ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(query)) return; - } + if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.MashapeKey)) { - await Context.Channel.SendErrorAsync("Bot owner didn't specify MashapeApiKey. You can't use this functionality.").ConfigureAwait(false); + await ReplyErrorLocalized("mashape_api_missing").ConfigureAwait(false); return; } await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); - var res = ""; + string res; using (var http = new HttpClient()) { http.DefaultRequestHeaders.Clear(); http.DefaultRequestHeaders.Add("X-Mashape-Key", NadekoBot.Credentials.MashapeKey); - res = await http.GetStringAsync($"https://tagdef.p.mashape.com/one.{Uri.EscapeUriString(arg)}.json").ConfigureAwait(false); + res = await http.GetStringAsync($"https://tagdef.p.mashape.com/one.{Uri.EscapeUriString(query)}.json").ConfigureAwait(false); } try @@ -558,7 +540,7 @@ namespace NadekoBot.Modules.Searches } catch { - await Context.Channel.SendErrorAsync("Failed finding a definition for that tag.").ConfigureAwait(false); + await ReplyErrorLocalized("hashtag_error").ConfigureAwait(false); } } @@ -572,7 +554,7 @@ namespace NadekoBot.Modules.Searches return; var fact = JObject.Parse(response)["facts"][0].ToString(); - await Context.Channel.SendConfirmAsync("🐈fact", fact).ConfigureAwait(false); + await Context.Channel.SendConfirmAsync("🐈" + GetText("catfact"), fact).ConfigureAwait(false); } } @@ -609,7 +591,7 @@ namespace NadekoBot.Modules.Searches var result = await http.GetStringAsync("https://en.wikipedia.org//w/api.php?action=query&format=json&prop=info&redirects=1&formatversion=2&inprop=url&titles=" + Uri.EscapeDataString(query)); var data = JsonConvert.DeserializeObject(result); if (data.Query.Pages[0].Missing) - await Context.Channel.SendErrorAsync("That page could not be found.").ConfigureAwait(false); + await ReplyErrorLocalized("wiki_page_not_found").ConfigureAwait(false); else await Context.Channel.SendMessageAsync(data.Query.Pages[0].FullUrl).ConfigureAwait(false); } @@ -625,26 +607,19 @@ namespace NadekoBot.Modules.Searches img.ApplyProcessor(new BackgroundColorProcessor(ImageSharp.Color.FromHex(color)), img.Bounds); - await Context.Channel.SendFileAsync(img.ToStream(), $"{color}.png").ConfigureAwait(false); ; + await Context.Channel.SendFileAsync(img.ToStream(), $"{color}.png").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] public async Task Videocall([Remainder] params IUser[] users) { - try + var allUsrs = users.Append(Context.User); + var allUsrsArray = allUsrs.ToArray(); + var str = allUsrsArray.Aggregate("http://appear.in/", (current, usr) => current + Uri.EscapeUriString(usr.Username[0].ToString())); + str += new NadekoRandom().Next(); + foreach (var usr in allUsrsArray) { - var allUsrs = users.Append(Context.User); - var allUsrsArray = allUsrs.ToArray(); - var str = allUsrsArray.Aggregate("http://appear.in/", (current, usr) => current + Uri.EscapeUriString(usr.Username[0].ToString())); - str += new NadekoRandom().Next(); - foreach (var usr in allUsrsArray) - { - await (await (usr as IGuildUser).CreateDMChannelAsync()).SendConfirmAsync(str).ConfigureAwait(false); - } - } - catch (Exception ex) - { - _log.Error(ex); + await (await usr.CreateDMChannelAsync()).SendConfirmAsync(str).ConfigureAwait(false); } } @@ -664,11 +639,11 @@ namespace NadekoBot.Modules.Searches } [NadekoCommand, Usage, Description, Aliases] - public async Task Wikia(string target, [Remainder] string query = null) + public async Task Wikia(string target, [Remainder] string query) { if (string.IsNullOrWhiteSpace(target) || string.IsNullOrWhiteSpace(query)) { - await Context.Channel.SendErrorAsync("Please enter a target wikia, followed by search query.").ConfigureAwait(false); + await ReplyErrorLocalized("wikia_input_error").ConfigureAwait(false); return; } await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); @@ -680,90 +655,87 @@ namespace NadekoBot.Modules.Searches var res = await http.GetStringAsync($"http://www.{Uri.EscapeUriString(target)}.wikia.com/api/v1/Search/List?query={Uri.EscapeUriString(query)}&limit=25&minArticleQuality=10&batch=1&namespaces=0%2C14").ConfigureAwait(false); var items = JObject.Parse(res); var found = items["items"][0]; - var response = $@"`Title:` {found["title"].ToString()} -`Quality:` {found["quality"]} -`URL:` {await NadekoBot.Google.ShortenUrl(found["url"].ToString()).ConfigureAwait(false)}"; + var response = $@"`{GetText("title")}` {found["title"]} +`{GetText("quality")}` {found["quality"]} +`{GetText("url")}:` {await NadekoBot.Google.ShortenUrl(found["url"].ToString()).ConfigureAwait(false)}"; await Context.Channel.SendMessageAsync(response).ConfigureAwait(false); } catch { - await Context.Channel.SendErrorAsync($"Failed finding `{query}`.").ConfigureAwait(false); + await ReplyErrorLocalized("wikia_error").ConfigureAwait(false); } } } - [NadekoCommand, Usage, Description, Aliases] - public async Task MCPing([Remainder] string query = null) - { - var arg = query; - if (string.IsNullOrWhiteSpace(arg)) - { - await Context.Channel.SendErrorAsync("💢 Please enter a `ip:port`.").ConfigureAwait(false); - return; - } - await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); - using (var http = new HttpClient()) - { - http.DefaultRequestHeaders.Clear(); - string ip = arg.Split(':')[0]; - string port = arg.Split(':')[1]; - var res = await http.GetStringAsync($"https://api.minetools.eu/ping/{Uri.EscapeUriString(ip)}/{Uri.EscapeUriString(port)}").ConfigureAwait(false); - try - { - var items = JObject.Parse(res); - var sb = new StringBuilder(); - int ping = (int)Math.Ceiling(Double.Parse(items["latency"].ToString())); - sb.AppendLine($"`Server:` {arg}"); - sb.AppendLine($"`Version:` {items["version"]["name"].ToString()} / Protocol {items["version"]["protocol"].ToString()}"); - sb.AppendLine($"`Description:` {items["description"].ToString()}"); - sb.AppendLine($"`Online Players:` {items["players"]["online"].ToString()}/{items["players"]["max"].ToString()}"); - sb.Append($"`Latency:` {ping}"); - await Context.Channel.SendMessageAsync(sb.ToString()); - } - catch - { - await Context.Channel.SendErrorAsync($"Failed finding `{arg}`.").ConfigureAwait(false); - } - } - } + //[NadekoCommand, Usage, Description, Aliases] + //public async Task MCPing([Remainder] string query2 = null) + //{ + // var query = query2; + // if (string.IsNullOrWhiteSpace(query)) + // return; + // await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); + // using (var http = new HttpClient()) + // { + // http.DefaultRequestHeaders.Clear(); + // var ip = query.Split(':')[0]; + // var port = query.Split(':')[1]; + // var res = await http.GetStringAsync($"https://api.minetools.eu/ping/{Uri.EscapeUriString(ip)}/{Uri.EscapeUriString(port)}").ConfigureAwait(false); + // try + // { + // var items = JObject.Parse(res); + // var sb = new StringBuilder(); + // var ping = (int)Math.Ceiling(double.Parse(items["latency"].ToString())); + // sb.AppendLine($"`Server:` {query}"); + // sb.AppendLine($"`Version:` {items["version"]["name"]} / Protocol {items["version"]["protocol"]}"); + // sb.AppendLine($"`Description:` {items["description"]}"); + // sb.AppendLine($"`Online Players:` {items["players"]["online"]}/{items["players"]["max"]}"); + // sb.Append($"`Latency:` {ping}"); + // await Context.Channel.SendMessageAsync(sb.ToString()); + // } + // catch + // { + // await Context.Channel.SendErrorAsync($"Failed finding `{query}`.").ConfigureAwait(false); + // } + // } + //} - [NadekoCommand, Usage, Description, Aliases] - public async Task MCQ([Remainder] string query = null) - { - var arg = query; - if (string.IsNullOrWhiteSpace(arg)) - { - await Context.Channel.SendErrorAsync("Please enter `ip:port`.").ConfigureAwait(false); - return; - } - await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); - using (var http = new HttpClient()) - { - http.DefaultRequestHeaders.Clear(); - try - { - string ip = arg.Split(':')[0]; - string port = arg.Split(':')[1]; - var res = await http.GetStringAsync($"https://api.minetools.eu/query/{Uri.EscapeUriString(ip)}/{Uri.EscapeUriString(port)}").ConfigureAwait(false); - var items = JObject.Parse(res); - var sb = new StringBuilder(); - sb.AppendLine($"`Server:` {arg.ToString()} 〘Status: {items["status"]}〙"); - sb.AppendLine($"`Player List (First 5):`"); - foreach (var item in items["Playerlist"].Take(5)) - { - sb.AppendLine($"〔:rosette: {item}〕"); - } - sb.AppendLine($"`Online Players:` {items["Players"]} / {items["MaxPlayers"]}"); - sb.AppendLine($"`Plugins:` {items["Plugins"]}"); - sb.Append($"`Version:` {items["Version"]}"); - await Context.Channel.SendMessageAsync(sb.ToString()); - } - catch - { - await Context.Channel.SendErrorAsync($"Failed finding server `{arg}`.").ConfigureAwait(false); - } - } - } + //[NadekoCommand, Usage, Description, Aliases] + //public async Task MCQ([Remainder] string query = null) + //{ + // var arg = query; + // if (string.IsNullOrWhiteSpace(arg)) + // { + // await Context.Channel.SendErrorAsync("Please enter `ip:port`.").ConfigureAwait(false); + // return; + // } + // await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); + // using (var http = new HttpClient()) + // { + // http.DefaultRequestHeaders.Clear(); + // try + // { + // var ip = arg.Split(':')[0]; + // var port = arg.Split(':')[1]; + // var res = await http.GetStringAsync($"https://api.minetools.eu/query/{Uri.EscapeUriString(ip)}/{Uri.EscapeUriString(port)}").ConfigureAwait(false); + // var items = JObject.Parse(res); + // var sb = new StringBuilder(); + // sb.AppendLine($"`Server:` {arg} 〘Status: {items["status"]}〙"); + // sb.AppendLine("`Player List (First 5):`"); + // foreach (var item in items["Playerlist"].Take(5)) + // { + // sb.AppendLine($"〔:rosette: {item}〕"); + // } + // sb.AppendLine($"`Online Players:` {items["Players"]} / {items["MaxPlayers"]}"); + // sb.AppendLine($"`Plugins:` {items["Plugins"]}"); + // sb.Append($"`Version:` {items["Version"]}"); + // await Context.Channel.SendMessageAsync(sb.ToString()); + // } + // catch + // { + // await Context.Channel.SendErrorAsync($"Failed finding server `{arg}`.").ConfigureAwait(false); + // } + // } + //} public enum DapiSearchType { @@ -774,7 +746,7 @@ namespace NadekoBot.Modules.Searches Yandere } - public static async Task InternalDapiCommand(IUserMessage umsg, string tag, DapiSearchType type) + public async Task InternalDapiCommand(IUserMessage umsg, string tag, DapiSearchType type) { var channel = umsg.Channel; @@ -783,7 +755,7 @@ namespace NadekoBot.Modules.Searches var url = await InternalDapiSearch(tag, type).ConfigureAwait(false); if (url == null) - await channel.SendErrorAsync(umsg.Author.Mention + " No results."); + await channel.SendErrorAsync(umsg.Author.Mention + " " + GetText("no_results")); else await channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithDescription(umsg.Author.Mention + " " + tag) @@ -794,7 +766,7 @@ namespace NadekoBot.Modules.Searches public static async Task InternalDapiSearch(string tag, DapiSearchType type) { tag = tag?.Replace(" ", "_"); - string website = ""; + var website = ""; switch (type) { case DapiSearchType.Safebooru: @@ -839,10 +811,10 @@ namespace NadekoBot.Modules.Searches return null; } } - public static async Task ValidateQuery(IMessageChannel ch, string query) + public async Task ValidateQuery(IMessageChannel ch, string query) { - if (!string.IsNullOrEmpty(query.Trim())) return true; - await ch.SendErrorAsync("Please specify search parameters.").ConfigureAwait(false); + if (!string.IsNullOrWhiteSpace(query)) return true; + await ch.SendErrorAsync(GetText("specify_search_params")).ConfigureAwait(false); return false; } } diff --git a/src/NadekoBot/NadekoBot.xproj.DotSettings b/src/NadekoBot/NadekoBot.xproj.DotSettings index e418daea..c5dd7773 100644 --- a/src/NadekoBot/NadekoBot.xproj.DotSettings +++ b/src/NadekoBot/NadekoBot.xproj.DotSettings @@ -3,4 +3,5 @@ True True True + True True \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index f0c48b9d..2eaf5acf 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -4073,6 +4073,852 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Abilities. + /// + public static string searches_abilities { + get { + return ResourceManager.GetString("searches_abilities", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No favorite anime yet. + /// + public static string searches_anime_no_fav { + get { + return ResourceManager.GetString("searches_anime_no_fav", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Started automatic translation of messages on this channel. User messages will be auto-deleted.. + /// + public static string searches_atl_ad_started { + get { + return ResourceManager.GetString("searches_atl_ad_started", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to your auto-translate language has been removed.. + /// + public static string searches_atl_removed { + get { + return ResourceManager.GetString("searches_atl_removed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Your auto-translate language has been set to {from}>{to}. + /// + public static string searches_atl_set { + get { + return ResourceManager.GetString("searches_atl_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Started automatic translation of messages on this channel.. + /// + public static string searches_atl_started { + get { + return ResourceManager.GetString("searches_atl_started", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stopped automatic translation of messages on this channel.. + /// + public static string searches_atl_stopped { + get { + return ResourceManager.GetString("searches_atl_stopped", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bad input format, or something went wrong.. + /// + public static string searches_bad_input_format { + get { + return ResourceManager.GetString("searches_bad_input_format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Couldn't find that card.. + /// + public static string searches_card_not_found { + get { + return ResourceManager.GetString("searches_card_not_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to fact. + /// + public static string searches_catfact { + get { + return ResourceManager.GetString("searches_catfact", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Chapters. + /// + public static string searches_chapters { + get { + return ResourceManager.GetString("searches_chapters", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Comic #. + /// + public static string searches_comic_number { + get { + return ResourceManager.GetString("searches_comic_number", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Competitive Loses. + /// + public static string searches_compet_loses { + get { + return ResourceManager.GetString("searches_compet_loses", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Competitive Played. + /// + public static string searches_compet_played { + get { + return ResourceManager.GetString("searches_compet_played", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Competitive Rank. + /// + public static string searches_compet_rank { + get { + return ResourceManager.GetString("searches_compet_rank", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Competitive Wins. + /// + public static string searches_compet_wins { + get { + return ResourceManager.GetString("searches_compet_wins", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Completed. + /// + public static string searches_completed { + get { + return ResourceManager.GetString("searches_completed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Condition. + /// + public static string searches_condition { + get { + return ResourceManager.GetString("searches_condition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cost. + /// + public static string searches_cost { + get { + return ResourceManager.GetString("searches_cost", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Date. + /// + public static string searches_date { + get { + return ResourceManager.GetString("searches_date", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Define:. + /// + public static string searches_define { + get { + return ResourceManager.GetString("searches_define", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Dropped. + /// + public static string searches_dropped { + get { + return ResourceManager.GetString("searches_dropped", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Episodes. + /// + public static string searches_episodes { + get { + return ResourceManager.GetString("searches_episodes", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error occured.. + /// + public static string searches_error_occured { + get { + return ResourceManager.GetString("searches_error_occured", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Example. + /// + public static string searches_example { + get { + return ResourceManager.GetString("searches_example", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed finding that animu.. + /// + public static string searches_failed_finding_anime { + get { + return ResourceManager.GetString("searches_failed_finding_anime", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed finding that mango.. + /// + public static string searches_failed_finding_manga { + get { + return ResourceManager.GetString("searches_failed_finding_manga", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Genres. + /// + public static string searches_genres { + get { + return ResourceManager.GetString("searches_genres", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed finding a definition for that tag.. + /// + public static string searches_hashtag_error { + get { + return ResourceManager.GetString("searches_hashtag_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Height/Weight. + /// + public static string searches_height_weight { + get { + return ResourceManager.GetString("searches_height_weight", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}m/{1}kg. + /// + public static string searches_height_weight_val { + get { + return ResourceManager.GetString("searches_height_weight_val", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Humidity. + /// + public static string searches_humidity { + get { + return ResourceManager.GetString("searches_humidity", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Image Search For:. + /// + public static string searches_image_search_for { + get { + return ResourceManager.GetString("searches_image_search_for", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to find that movie.. + /// + public static string searches_imdb_fail { + get { + return ResourceManager.GetString("searches_imdb_fail", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid source or target language.. + /// + public static string searches_invalid_lang { + get { + return ResourceManager.GetString("searches_invalid_lang", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Joes not loaded.. + /// + public static string searches_jokes_not_loaded { + get { + return ResourceManager.GetString("searches_jokes_not_loaded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lat/Long. + /// + public static string searches_latlong { + get { + return ResourceManager.GetString("searches_latlong", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Level. + /// + public static string searches_level { + get { + return ResourceManager.GetString("searches_level", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lsit of {0}place tags. + /// + public static string searches_list_of_place_tags { + get { + return ResourceManager.GetString("searches_list_of_place_tags", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Location. + /// + public static string searches_location { + get { + return ResourceManager.GetString("searches_location", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Magic Items not loaded.. + /// + public static string searches_magicitems_not_loaded { + get { + return ResourceManager.GetString("searches_magicitems_not_loaded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}'s MAL profile. + /// + public static string searches_mal_profile { + get { + return ResourceManager.GetString("searches_mal_profile", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bot owner didn't specify MashapeApiKey. You can't use this functionality.. + /// + public static string searches_mashape_api_missing { + get { + return ResourceManager.GetString("searches_mashape_api_missing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Min/Max. + /// + public static string searches_min_max { + get { + return ResourceManager.GetString("searches_min_max", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No channel found.. + /// + public static string searches_no_channel_found { + get { + return ResourceManager.GetString("searches_no_channel_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No results found.. + /// + public static string searches_no_results { + get { + return ResourceManager.GetString("searches_no_results", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On-Hold. + /// + public static string searches_on_hold { + get { + return ResourceManager.GetString("searches_on_hold", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Original Url. + /// + public static string searches_original_url { + get { + return ResourceManager.GetString("searches_original_url", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An osu! API key is required.. + /// + public static string searches_osu_api_key { + get { + return ResourceManager.GetString("searches_osu_api_key", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed retreiving osu signature.. + /// + public static string searches_osu_failed { + get { + return ResourceManager.GetString("searches_osu_failed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Found over {0} images. Showing random {0}.. + /// + public static string searches_over_x { + get { + return ResourceManager.GetString("searches_over_x", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User not found! Please check the Region and BattleTag before trying again.. + /// + public static string searches_ow_user_not_found { + get { + return ResourceManager.GetString("searches_ow_user_not_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Plan to watch. + /// + public static string searches_plan_to_watch { + get { + return ResourceManager.GetString("searches_plan_to_watch", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Platform. + /// + public static string searches_platform { + get { + return ResourceManager.GetString("searches_platform", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No ability found.. + /// + public static string searches_pokemon_ability_none { + get { + return ResourceManager.GetString("searches_pokemon_ability_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No pokemon found.. + /// + public static string searches_pokemon_none { + get { + return ResourceManager.GetString("searches_pokemon_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Profile Link:. + /// + public static string searches_profile_link { + get { + return ResourceManager.GetString("searches_profile_link", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Quality:. + /// + public static string searches_quality { + get { + return ResourceManager.GetString("searches_quality", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Quick Playtime. + /// + public static string searches_quick_playtime { + get { + return ResourceManager.GetString("searches_quick_playtime", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Quick Wins. + /// + public static string searches_quick_wins { + get { + return ResourceManager.GetString("searches_quick_wins", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Rating. + /// + public static string searches_rating { + get { + return ResourceManager.GetString("searches_rating", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Score:. + /// + public static string searches_score { + get { + return ResourceManager.GetString("searches_score", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Search For:. + /// + public static string searches_search_for { + get { + return ResourceManager.GetString("searches_search_for", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Short Url. + /// + public static string searches_short_url { + get { + return ResourceManager.GetString("searches_short_url", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to shorten that url.. + /// + public static string searches_shorten_fail { + get { + return ResourceManager.GetString("searches_shorten_fail", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Something went wrong.. + /// + public static string searches_something_went_wrong { + get { + return ResourceManager.GetString("searches_something_went_wrong", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Please specify search parameters.. + /// + public static string searches_specify_search_params { + get { + return ResourceManager.GetString("searches_specify_search_params", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Status. + /// + public static string searches_status { + get { + return ResourceManager.GetString("searches_status", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Store Url. + /// + public static string searches_store_url { + get { + return ResourceManager.GetString("searches_store_url", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No such stream.. + /// + public static string searches_stream_no { + get { + return ResourceManager.GetString("searches_stream_no", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stream probably doesn't exist.. + /// + public static string searches_stream_not_exist { + get { + return ResourceManager.GetString("searches_stream_not_exist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removed {0}'s stream ({1}) from notifications.. + /// + public static string searches_stream_removed { + get { + return ResourceManager.GetString("searches_stream_removed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I will notify this channel when status changes.. + /// + public static string searches_stream_tracked { + get { + return ResourceManager.GetString("searches_stream_tracked", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Streamer {0} is offline.. + /// + public static string searches_streamer_offline { + get { + return ResourceManager.GetString("searches_streamer_offline", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Streamer {0} is online with {1} viewers.. + /// + public static string searches_streamer_online { + get { + return ResourceManager.GetString("searches_streamer_online", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You are following {0} streams on this server.. + /// + public static string searches_streams_following { + get { + return ResourceManager.GetString("searches_streams_following", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You are not following any streams on this server.. + /// + public static string searches_streams_none { + get { + return ResourceManager.GetString("searches_streams_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sunrise. + /// + public static string searches_sunrise { + get { + return ResourceManager.GetString("searches_sunrise", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sunset. + /// + public static string searches_sunset { + get { + return ResourceManager.GetString("searches_sunset", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Temperature. + /// + public static string searches_temperature { + get { + return ResourceManager.GetString("searches_temperature", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Title:. + /// + public static string searches_title { + get { + return ResourceManager.GetString("searches_title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Top 3 favorite anime:. + /// + public static string searches_top_3_fav_anime { + get { + return ResourceManager.GetString("searches_top_3_fav_anime", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Translation:. + /// + public static string searches_translation { + get { + return ResourceManager.GetString("searches_translation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Types. + /// + public static string searches_types { + get { + return ResourceManager.GetString("searches_types", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed finding definition for that term.. + /// + public static string searches_ud_error { + get { + return ResourceManager.GetString("searches_ud_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Url. + /// + public static string searches_url { + get { + return ResourceManager.GetString("searches_url", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Viewers. + /// + public static string searches_viewers { + get { + return ResourceManager.GetString("searches_viewers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Watching. + /// + public static string searches_watching { + get { + return ResourceManager.GetString("searches_watching", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Page not found.. + /// + public static string searches_wiki_page_not_found { + get { + return ResourceManager.GetString("searches_wiki_page_not_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed finding that term on the specified wikia.. + /// + public static string searches_wikia_error { + get { + return ResourceManager.GetString("searches_wikia_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Please enter a target wikia, followed by search query.. + /// + public static string searches_wikia_input_error { + get { + return ResourceManager.GetString("searches_wikia_input_error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wind Speed. + /// + public static string searches_wind_speed { + get { + return ResourceManager.GetString("searches_wind_speed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The {0} most banned champions. + /// + public static string searches_x_most_banned_champs { + get { + return ResourceManager.GetString("searches_x_most_banned_champs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to yodify your sentence.. + /// + public static string searches_yodify_error { + get { + return ResourceManager.GetString("searches_yodify_error", resourceCulture); + } + } + /// /// Looks up a localized string similar to Joined. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index d365b08c..5030e3bd 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1485,6 +1485,289 @@ Don't forget to leave your discord name or id in the message. Word filtering enabled on this server. + + Abilities + + + No favorite anime yet + + + Started automatic translation of messages on this channel. User messages will be auto-deleted. + + + your auto-translate language has been removed. + + + Your auto-translate language has been set to {from}>{to} + + + Started automatic translation of messages on this channel. + + + Stopped automatic translation of messages on this channel. + + + Bad input format, or something went wrong. + + + Couldn't find that card. + + + fact + + + Chapters + + + Comic # + + + Competitive Loses + + + Competitive Played + + + Competitive Rank + + + Competitive Wins + + + Completed + + + Condition + + + Cost + + + Date + + + Define: + + + Dropped + + + Episodes + + + Error occured. + + + Example + + + Failed finding that animu. + + + Failed finding that mango. + + + Genres + + + Failed finding a definition for that tag. + + + Height/Weight + + + {0}m/{1}kg + + + Humidity + + + Image Search For: + + + Failed to find that movie. + + + Invalid source or target language. + + + Joes not loaded. + + + Lat/Long + + + Level + + + Lsit of {0}place tags + Don't translate {0}place + + + Location + + + Magic Items not loaded. + + + {0}'s MAL profile + + + Bot owner didn't specify MashapeApiKey. You can't use this functionality. + + + Min/Max + + + No channel found. + + + No results found. + + + On-Hold + + + Original Url + + + An osu! API key is required. + + + Failed retreiving osu signature. + + + Found over {0} images. Showing random {0}. + + + User not found! Please check the Region and BattleTag before trying again. + + + Plan to watch + + + Platform + + + No ability found. + + + No pokemon found. + + + Profile Link: + + + Quality: + + + Quick Playtime + + + Quick Wins + + + Rating + + + Score: + + + Search For: + + + Failed to shorten that url. + + + Short Url + + + Something went wrong. + + + Please specify search parameters. + + + Status + + + Store Url + + + Streamer {0} is offline. + + + Streamer {0} is online with {1} viewers. + + + You are following {0} streams on this server. + + + You are not following any streams on this server. + + + No such stream. + + + Stream probably doesn't exist. + + + Removed {0}'s stream ({1}) from notifications. + + + I will notify this channel when status changes. + + + Sunrise + + + Sunset + + + Temperature + + + Title: + + + Top 3 favorite anime: + + + Translation: + + + Types + + + Failed finding definition for that term. + + + Url + + + Viewers + + + Watching + + + Failed finding that term on the specified wikia. + + + Please enter a target wikia, followed by search query. + + + Page not found. + + + Wind Speed + + + The {0} most banned champions + + + Failed to yodify your sentence. + Joined From 466ec12de0b8a3eaec1e8d74299c1e89d954619b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 24 Feb 2017 17:15:52 +0100 Subject: [PATCH 344/746] >ttt string fix, thx devedux --- src/NadekoBot/Modules/Games/Commands/TicTacToe.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs index 5769e2e5..d4293e03 100644 --- a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs +++ b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs @@ -135,7 +135,7 @@ namespace NadekoBot.Modules.Games if (_phase == Phase.Ended) embed.WithFooter(efb => efb.WithText(GetText("ttt_no_moves"))); else - embed.WithFooter(efb => efb.WithText(GetText("users_move", _users[_curUserIndex]))); + embed.WithFooter(efb => efb.WithText(GetText("ttt_users_move", _users[_curUserIndex]))); } else embed.WithFooter(efb => efb.WithText(GetText("ttt_has_won", _winner))); From 22f961a093cbe947e3bf643b4cbb356f50861df7 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 25 Feb 2017 02:04:32 +0100 Subject: [PATCH 345/746] localization complete, or nearly complete if I missed something --- .../Modules/Games/Commands/TicTacToe.cs | 4 +- src/NadekoBot/Modules/Music/Classes/Song.cs | 2 +- src/NadekoBot/Modules/Music/Music.cs | 212 ++++---- .../Resources/ResponseStrings.Designer.cs | 477 ++++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 160 ++++++ src/NadekoBot/Services/Impl/StatsService.cs | 4 +- 6 files changed, 761 insertions(+), 98 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs index d4293e03..918a1592 100644 --- a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs +++ b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs @@ -65,7 +65,6 @@ namespace NadekoBot.Modules.Games } private readonly ITextChannel _channel; - private readonly Logger _log; private readonly IGuildUser[] _users; private readonly int?[,] _state; private Phase _phase; @@ -90,8 +89,7 @@ namespace NadekoBot.Modules.Games { null, null, null }, { null, null, null }, }; - - _log = LogManager.GetCurrentClassLogger(); + _phase = Phase.Starting; _moveLock = new SemaphoreSlim(1, 1); } diff --git a/src/NadekoBot/Modules/Music/Classes/Song.cs b/src/NadekoBot/Modules/Music/Classes/Song.cs index 8a69ec6f..d088bfde 100644 --- a/src/NadekoBot/Modules/Music/Classes/Song.cs +++ b/src/NadekoBot/Modules/Music/Classes/Song.cs @@ -40,7 +40,7 @@ namespace NadekoBot.Modules.Music.Classes //pwetty public string PrettyProvider => - $"{(SongInfo.Provider ?? "No Provider")}"; + $"{(SongInfo.Provider ?? "???")}"; public string PrettyFullTime => PrettyCurrentTime + " / " + PrettyTotalTime; diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index a7b46269..5d685bbc 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Music { [NadekoModule("Music", "!!")] [DontAutoLoad] - public partial class Music : NadekoTopLevelModule + public class Music : NadekoTopLevelModule { public static ConcurrentDictionary MusicPlayers { get; } = new ConcurrentDictionary(); @@ -155,7 +155,14 @@ namespace NadekoBot.Modules.Music return; var val = musicPlayer.FairPlay = !musicPlayer.FairPlay; - await channel.SendConfirmAsync("Fair play " + (val ? "enabled" : "disabled") + ".").ConfigureAwait(false); + if (val) + { + await ReplyConfirmLocalized("fp_enabled").ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("fp_disabled").ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -184,34 +191,31 @@ namespace NadekoBot.Modules.Music [RequireContext(ContextType.Guild)] public async Task ListQueue(int page = 1) { - + Song currentSong; MusicPlayer musicPlayer; - if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) + if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer) || + (currentSong = musicPlayer?.CurrentSong) == null) { - await Context.Channel.SendErrorAsync("🎵 No active music player.").ConfigureAwait(false); + await ReplyErrorLocalized("no_music_player").ConfigureAwait(false); return; } if (page <= 0) return; - var currentSong = musicPlayer.CurrentSong; - if (currentSong == null) - { - await Context.Channel.SendErrorAsync("🎵 No active music player.").ConfigureAwait(false); - return; - } - try { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { } const int itemsPerPage = 10; var total = musicPlayer.TotalPlaytime; - var totalStr = total == TimeSpan.MaxValue ? "∞" : $"{(int)total.TotalHours}h {total.Minutes}m {total.Seconds}s"; + var totalStr = total == TimeSpan.MaxValue ? "∞" : GetText("time_format", + (int) total.TotalHours, + total.Minutes, + total.Seconds); var maxPlaytime = musicPlayer.MaxPlaytimeSeconds; var lastPage = musicPlayer.Playlist.Count / itemsPerPage; - Func printAction = (curPage) => + Func printAction = curPage => { - int startAt = itemsPerPage * (curPage - 1); + var startAt = itemsPerPage * (curPage - 1); var number = 0 + startAt; var desc = string.Join("\n", musicPlayer.Playlist .Skip(startAt) @@ -221,19 +225,22 @@ namespace NadekoBot.Modules.Music desc = $"`🔊` {currentSong.PrettyFullName}\n\n" + desc; if (musicPlayer.RepeatSong) - desc = "🔂 Repeating Current Song\n\n" + desc; + desc = "🔂 " + GetText("repeating_cur_song") +"\n\n" + desc; else if (musicPlayer.RepeatPlaylist) - desc = "🔁 Repeating Playlist\n\n" + desc; - + desc = "🔁 " + GetText("repeating_playlist")+"\n\n" + desc; + var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName($"Player Queue - Page {curPage}/{lastPage + 1}") - .WithMusicIcon()) + .WithAuthor(eab => eab.WithName(GetText("player_queue", curPage, lastPage + 1)) + .WithMusicIcon()) .WithDescription(desc) .WithFooter(ef => ef.WithText($"{musicPlayer.PrettyVolume} | {musicPlayer.Playlist.Count} " + - $"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {totalStr} | " + - (musicPlayer.FairPlay ? "✔️fairplay" : "✖️fairplay") + $" | " + (maxPlaytime == 0 ? "unlimited" : $"{maxPlaytime}s limit"))) + $"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {totalStr} | " + + (musicPlayer.FairPlay + ? "✔️" + GetText("fairplay") + : "✖️" + GetText("fairplay")) + " | " + + (maxPlaytime == 0 ? "unlimited" : GetText("play_limit", maxPlaytime)))) .WithOkColor(); return embed; @@ -254,7 +261,7 @@ namespace NadekoBot.Modules.Music try { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { } var embed = new EmbedBuilder().WithOkColor() - .WithAuthor(eab => eab.WithName("Now Playing").WithMusicIcon()) + .WithAuthor(eab => eab.WithName(GetText("now_playing")).WithMusicIcon()) .WithDescription(currentSong.PrettyName) .WithThumbnailUrl(currentSong.Thumbnail) .WithFooter(ef => ef.WithText(musicPlayer.PrettyVolume + " | " + currentSong.PrettyFullTime + $" | {currentSong.PrettyProvider} | {currentSong.QueuerName}")); @@ -271,21 +278,22 @@ namespace NadekoBot.Modules.Music return; if (((IGuildUser)Context.User).VoiceChannel != musicPlayer.PlaybackVoiceChannel) return; - if (val < 0) + if (val < 0 || val > 100) + { + await ReplyErrorLocalized("volume_input_invalid").ConfigureAwait(false); return; + } var volume = musicPlayer.SetVolume(val); - await Context.Channel.SendConfirmAsync($"🎵 Volume set to {volume}%").ConfigureAwait(false); + await ReplyConfirmLocalized("volume_set", volume).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task Defvol([Remainder] int val) { - - if (val < 0 || val > 100) { - await Context.Channel.SendErrorAsync("Volume number invalid. Must be between 0 and 100").ConfigureAwait(false); + await ReplyErrorLocalized("volume_input_invalid").ConfigureAwait(false); return; } using (var uow = DbHandler.UnitOfWork()) @@ -293,7 +301,7 @@ namespace NadekoBot.Modules.Music uow.GuildConfigs.For(Context.Guild.Id, set => set).DefaultMusicVolume = val / 100.0f; uow.Complete(); } - await Context.Channel.SendConfirmAsync($"🎵 Default volume set to {val}%").ConfigureAwait(false); + await ReplyConfirmLocalized("defvol_set").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -307,13 +315,10 @@ namespace NadekoBot.Modules.Music if (((IGuildUser)Context.User).VoiceChannel != musicPlayer.PlaybackVoiceChannel) return; if (musicPlayer.Playlist.Count < 2) - { - await Context.Channel.SendErrorAsync("💢 Not enough songs in order to perform the shuffle.").ConfigureAwait(false); return; - } musicPlayer.Shuffle(); - await Context.Channel.SendConfirmAsync("🎵 Songs shuffled.").ConfigureAwait(false); + await ReplyConfirmLocalized("songs_shuffled").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -326,29 +331,31 @@ namespace NadekoBot.Modules.Music return; if (((IGuildUser)Context.User).VoiceChannel?.Guild != Context.Guild) { - await Context.Channel.SendErrorAsync($"💢 You need to be in a **voice channel** on this server.").ConfigureAwait(false); + await ReplyErrorLocalized("must_be_in_voice").ConfigureAwait(false); return; } var plId = (await NadekoBot.Google.GetPlaylistIdsByKeywordsAsync(arg).ConfigureAwait(false)).FirstOrDefault(); if (plId == null) { - await Context.Channel.SendErrorAsync("No search results for that query."); + await ReplyErrorLocalized("no_search_results").ConfigureAwait(false); return; } var ids = await NadekoBot.Google.GetPlaylistTracksAsync(plId, 500).ConfigureAwait(false); if (!ids.Any()) { - await Context.Channel.SendErrorAsync($"🎵 Failed to find any songs.").ConfigureAwait(false); + await ReplyErrorLocalized("no_search_results").ConfigureAwait(false); return; } var count = ids.Count(); - var msg = await Context.Channel.SendMessageAsync($"🎵 Attempting to queue **{count}** songs".SnPl(count) + "...").ConfigureAwait(false); + var msg = await Context.Channel.SendMessageAsync(GetText("attempting_to_queue", + Format.Bold(count.ToString()))) + .ConfigureAwait(false); var cancelSource = new CancellationTokenSource(); var gusr = (IGuildUser)Context.User; - + //todo use grouping while (ids.Any() && !cancelSource.IsCancellationRequested) { var tasks = Task.WhenAll(ids.Take(5).Select(async id => @@ -367,7 +374,7 @@ namespace NadekoBot.Modules.Music ids = ids.Skip(5); } - await msg.ModifyAsync(m => m.Content = "✅ Playlist queue complete.").ConfigureAwait(false); + await msg.ModifyAsync(m => m.Content = GetText("playlist_queue_complete")).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -393,7 +400,7 @@ namespace NadekoBot.Modules.Music { try { - mp.AddSong(new Song(new Classes.SongInfo + mp.AddSong(new Song(new SongInfo { Title = svideo.FullName, Provider = "SoundCloud", @@ -435,20 +442,20 @@ namespace NadekoBot.Modules.Music // ignored } } - await Context.Channel.SendConfirmAsync("🎵 Directory queue complete.").ConfigureAwait(false); + await ReplyConfirmLocalized("dir_queue_complete").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task Radio(string radio_link) + public async Task Radio(string radioLink) { if (((IGuildUser)Context.User).VoiceChannel?.Guild != Context.Guild) { - await Context.Channel.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 it.").ConfigureAwait(false); + await ReplyErrorLocalized("must_be_in_voice").ConfigureAwait(false); return; } - await QueueSong(((IGuildUser)Context.User), (ITextChannel)Context.Channel, ((IGuildUser)Context.User).VoiceChannel, radio_link, musicType: MusicType.Radio).ConfigureAwait(false); + await QueueSong(((IGuildUser)Context.User), (ITextChannel)Context.Channel, ((IGuildUser)Context.User).VoiceChannel, radioLink, musicType: MusicType.Radio).ConfigureAwait(false); if ((await Context.Guild.GetCurrentUserAsync()).GetPermissions((IGuildChannel)Context.Channel).ManageMessages) { Context.Message.DeleteAfter(10); @@ -505,8 +512,7 @@ namespace NadekoBot.Modules.Music MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) return; musicPlayer.ClearQueue(); - await Context.Channel.SendConfirmAsync($"🎵 Queue cleared!").ConfigureAwait(false); - return; + await ReplyConfirmLocalized("queue_cleared").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -532,7 +538,7 @@ namespace NadekoBot.Modules.Music !int.TryParse(fromtoArr[1], out n2) || n1 < 1 || n2 < 1 || n1 == n2 || n1 > playlist.Count || n2 > playlist.Count) { - await Context.Channel.SendErrorAsync("Invalid input.").ConfigureAwait(false); + await ReplyConfirmLocalized("invalid_input").ConfigureAwait(false); return; } @@ -544,9 +550,9 @@ namespace NadekoBot.Modules.Music var embed = new EmbedBuilder() .WithTitle($"{s.SongInfo.Title.TrimTo(70)}") .WithUrl(s.SongUrl) - .WithAuthor(eab => eab.WithName("Song Moved").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) - .AddField(fb => fb.WithName("**From Position**").WithValue($"#{n1}").WithIsInline(true)) - .AddField(fb => fb.WithName("**To Position**").WithValue($"#{n2}").WithIsInline(true)) + .WithAuthor(eab => eab.WithName(GetText("song_moved")).WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png")) + .AddField(fb => fb.WithName(GetText("from_position")).WithValue($"#{n1}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("to_position")).WithValue($"#{n2}").WithIsInline(true)) .WithColor(NadekoBot.OkColor); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); @@ -564,7 +570,11 @@ namespace NadekoBot.Modules.Music return; musicPlayer.MaxQueueSize = size; - await Context.Channel.SendConfirmAsync($"🎵 Max queue set to {(size == 0 ? ("unlimited") : size + " tracks")}."); + + if(size == 0) + await ReplyConfirmLocalized("max_queue_unlimited").ConfigureAwait(false); + else + await ReplyConfirmLocalized("max_queue_x", size).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -580,9 +590,9 @@ namespace NadekoBot.Modules.Music return; musicPlayer.MaxPlaytimeSeconds = seconds; if (seconds == 0) - await channel.SendConfirmAsync($"🎵 Max playtime has no limit now."); + await ReplyConfirmLocalized("max_playtime_none").ConfigureAwait(false); else - await channel.SendConfirmAsync($"🎵 Max playtime set to {seconds} seconds."); + await ReplyConfirmLocalized("max_playtime_set").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -601,11 +611,11 @@ namespace NadekoBot.Modules.Music if (currentValue) await Context.Channel.EmbedAsync(new EmbedBuilder() .WithOkColor() - .WithAuthor(eab => eab.WithMusicIcon().WithName("🔂 Repeating track")) + .WithAuthor(eab => eab.WithMusicIcon().WithName("🔂 " + GetText("repeating_track"))) .WithDescription(currentSong.PrettyName) .WithFooter(ef => ef.WithText(currentSong.PrettyInfo))).ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync($"🔂 Current track repeat stopped.") + await Context.Channel.SendConfirmAsync("🔂 " + GetText("repeating_track_stopped")) .ConfigureAwait(false); } @@ -618,7 +628,10 @@ namespace NadekoBot.Modules.Music if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) return; var currentValue = musicPlayer.ToggleRepeatPlaylist(); - await Context.Channel.SendConfirmAsync($"🔁 Repeat playlist {(currentValue ? "**enabled**." : "**disabled**.")}").ConfigureAwait(false); + if(currentValue) + await ReplyConfirmLocalized("rpl_enabled").ConfigureAwait(false); + else + await ReplyConfirmLocalized("rpl_disabled").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -655,7 +668,10 @@ namespace NadekoBot.Modules.Music await uow.CompleteAsync().ConfigureAwait(false); } - await Context.Channel.SendConfirmAsync(($"🎵 Saved playlist as **{name}**, ID: {playlist.Id}.")).ConfigureAwait(false); + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle(GetText("playlist_saved")) + .AddField(efb => efb.WithName(GetText("name")).WithValue(name)) + .AddField(efb => efb.WithName(GetText("id")).WithValue(playlist.Id.ToString()))); } [NadekoCommand, Usage, Description, Aliases] @@ -670,11 +686,11 @@ namespace NadekoBot.Modules.Music if (mpl == null) { - await Context.Channel.SendErrorAsync("Can't find playlist with that ID.").ConfigureAwait(false); + await ReplyErrorLocalized("playlist_id_not_found").ConfigureAwait(false); return; } IUserMessage msg = null; - try { msg = await Context.Channel.SendMessageAsync($"🎶 Attempting to load **{mpl.Songs.Count}** songs...").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } + try { msg = await ReplyConfirmLocalized("attempting_to_queue", Format.Bold(mpl.Songs.Count.ToString())).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } foreach (var item in mpl.Songs) { var usr = (IGuildUser)Context.User; @@ -686,15 +702,13 @@ namespace NadekoBot.Modules.Music catch { break; } } if (msg != null) - await msg.ModifyAsync(m => m.Content = $"✅ Done loading playlist **{mpl.Name}**.").ConfigureAwait(false); + await msg.ModifyAsync(m => m.Content = GetText("playlist_queue_complete")).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task Playlists([Remainder] int num = 1) { - - if (num <= 0) return; @@ -706,8 +720,9 @@ namespace NadekoBot.Modules.Music } var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName($"Page {num} of Saved Playlists").WithMusicIcon()) - .WithDescription(string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}** by *{r.Author}* ({r.Songs.Count} songs)"))) + .WithAuthor(eab => eab.WithName(GetText("playlists_page", num)).WithMusicIcon()) + .WithDescription(string.Join("\n", playlists.Select(r => + GetText("playlists", "#" + r.Id, r.Name, r.Author, r.Songs.Count)))) .WithOkColor(); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); @@ -717,13 +732,12 @@ namespace NadekoBot.Modules.Music [RequireContext(ContextType.Guild)] public async Task DeletePlaylist([Remainder] int id) { - bool success = false; - MusicPlaylist pl = null; + var success = false; try { using (var uow = DbHandler.UnitOfWork()) { - pl = uow.MusicPlaylists.Get(id); + var pl = uow.MusicPlaylists.Get(id); if (pl != null) { @@ -733,15 +747,13 @@ namespace NadekoBot.Modules.Music await uow.CompleteAsync().ConfigureAwait(false); success = true; } - else - success = false; } } if (!success) - await Context.Channel.SendErrorAsync("Failed to delete that playlist. It either doesn't exist, or you are not its author.").ConfigureAwait(false); + await ReplyErrorLocalized("playlist_delete_fail").ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync("🗑 Playlist successfully **deleted**.").ConfigureAwait(false); + await ReplyConfirmLocalized("playlist_deleted").ConfigureAwait(false); } catch (Exception ex) { @@ -781,7 +793,7 @@ namespace NadekoBot.Modules.Music if (seconds.Length == 1) seconds = "0" + seconds; - await Context.Channel.SendConfirmAsync($"Skipped to `{minutes}:{seconds}`").ConfigureAwait(false); + await ReplyConfirmLocalized("skipped_to", minutes, seconds).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -793,9 +805,9 @@ namespace NadekoBot.Modules.Music return; if (!musicPlayer.ToggleAutoplay()) - await Context.Channel.SendConfirmAsync("❌ Autoplay disabled.").ConfigureAwait(false); + await ReplyConfirmLocalized("autoplay_disabled").ConfigureAwait(false); else - await Context.Channel.SendConfirmAsync("✅ Autoplay enabled.").ConfigureAwait(false); + await ReplyConfirmLocalized("autoplay_enabled").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -806,29 +818,29 @@ namespace NadekoBot.Modules.Music MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) { - await Context.Channel.SendErrorAsync("Music must be playing before you set an ouput channel.").ConfigureAwait(false); + await ReplyErrorLocalized("player_none").ConfigureAwait(false); return; } musicPlayer.OutputTextChannel = (ITextChannel)Context.Channel; - await Context.Channel.SendConfirmAsync("I will now output playing, finished, paused and removed songs in this channel.").ConfigureAwait(false); + await ReplyConfirmLocalized("set_music_channel").ConfigureAwait(false); } - public static async Task QueueSong(IGuildUser queuer, ITextChannel textCh, IVoiceChannel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal) + public async Task QueueSong(IGuildUser queuer, ITextChannel textCh, IVoiceChannel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal) { if (voiceCh == null || voiceCh.Guild != textCh.Guild) { if (!silent) - await textCh.SendErrorAsync($"💢 You need to be in a voice channel on this server.").ConfigureAwait(false); + await textCh.SendErrorAsync(GetText("must_be_in_voice")).ConfigureAwait(false); throw new ArgumentNullException(nameof(voiceCh)); } if (string.IsNullOrWhiteSpace(query) || query.Length < 3) - throw new ArgumentException("💢 Invalid query for queue song.", nameof(query)); + throw new ArgumentException("Invalid song query.", nameof(query)); var musicPlayer = MusicPlayers.GetOrAdd(textCh.Guild.Id, server => { - float vol = 1;// SpecificConfigurations.Default.Of(server.Id).DefaultMusicVolume; + float vol;// SpecificConfigurations.Default.Of(server.Id).DefaultMusicVolume; using (var uow = DbHandler.UnitOfWork()) { vol = uow.GuildConfigs.For(textCh.Guild.Id, set => set).DefaultMusicVolume; @@ -845,7 +857,7 @@ namespace NadekoBot.Modules.Music try { lastFinishedMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithAuthor(eab => eab.WithName("Finished Song").WithMusicIcon()) + .WithAuthor(eab => eab.WithName(GetText("finished_song")).WithMusicIcon()) .WithDescription(song.PrettyName) .WithFooter(ef => ef.WithText(song.PrettyInfo))) .ConfigureAwait(false); @@ -866,7 +878,10 @@ namespace NadekoBot.Modules.Music true).ConfigureAwait(false); } } - catch { } + catch + { + // ignored + } }; mp.OnStarted += async (player, song) => @@ -876,7 +891,7 @@ namespace NadekoBot.Modules.Music { // ignored } - var sender = player as MusicPlayer; + var sender = player; if (sender == null) return; try @@ -884,12 +899,15 @@ namespace NadekoBot.Modules.Music playingMessage?.DeleteAfter(0); playingMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithAuthor(eab => eab.WithName("Playing Song").WithMusicIcon()) + .WithAuthor(eab => eab.WithName(GetText("playing_song")).WithMusicIcon()) .WithDescription(song.PrettyName) .WithFooter(ef => ef.WithText(song.PrettyInfo))) .ConfigureAwait(false); } - catch { } + catch + { + // ignored + } }; mp.OnPauseChanged += async (paused) => { @@ -897,13 +915,16 @@ namespace NadekoBot.Modules.Music { IUserMessage msg; if (paused) - msg = await mp.OutputTextChannel.SendConfirmAsync("🎵 Music playback **paused**.").ConfigureAwait(false); + msg = await mp.OutputTextChannel.SendConfirmAsync(GetText("music_paused")).ConfigureAwait(false); else - msg = await mp.OutputTextChannel.SendConfirmAsync("🎵 Music playback **resumed**.").ConfigureAwait(false); + msg = await mp.OutputTextChannel.SendConfirmAsync(GetText("music_resumed")).ConfigureAwait(false); msg?.DeleteAfter(10); } - catch { } + catch + { + // ignored + } }; mp.SongRemoved += async (song, index) => @@ -911,7 +932,7 @@ namespace NadekoBot.Modules.Music try { var embed = new EmbedBuilder() - .WithAuthor(eab => eab.WithName("Removed song #" + (index + 1)).WithMusicIcon()) + .WithAuthor(eab => eab.WithName(GetText("removed_song") + " #" + (index + 1)).WithMusicIcon()) .WithDescription(song.PrettyName) .WithFooter(ef => ef.WithText(song.PrettyInfo)) .WithErrorColor(); @@ -939,7 +960,14 @@ namespace NadekoBot.Modules.Music } catch (PlaylistFullException) { - try { await textCh.SendConfirmAsync($"🎵 Queue is full at **{musicPlayer.MaxQueueSize}/{musicPlayer.MaxQueueSize}**."); } catch { } + try + { + await textCh.SendConfirmAsync(GetText("queue_full", musicPlayer.MaxQueueSize)); + } + catch + { + // ignored + } throw; } if (!silent) @@ -948,8 +976,8 @@ namespace NadekoBot.Modules.Music { //var queuedMessage = await textCh.SendConfirmAsync($"🎵 Queued **{resolvedSong.SongInfo.Title}** at `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false); var queuedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithAuthor(eab => eab.WithName("Queued Song #" + (musicPlayer.Playlist.Count + 1)).WithMusicIcon()) - .WithDescription($"{resolvedSong.PrettyName}\nQueue ") + .WithAuthor(eab => eab.WithName(GetText("queued_song") + " #" + (musicPlayer.Playlist.Count + 1)).WithMusicIcon()) + .WithDescription($"{resolvedSong.PrettyName}\n{GetText("queue")} ") .WithThumbnailUrl(resolvedSong.Thumbnail) .WithFooter(ef => ef.WithText(resolvedSong.PrettyProvider))) .ConfigureAwait(false); diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 2eaf5acf..1d11bac1 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -3388,6 +3388,483 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Attempting to queue {0} songs.... + /// + public static string music_attempting_to_queue { + get { + return ResourceManager.GetString("music_attempting_to_queue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Autoplay disabled.. + /// + public static string music_autoplay_disabled { + get { + return ResourceManager.GetString("music_autoplay_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Autoplay enabled.. + /// + public static string music_autoplay_enabled { + get { + return ResourceManager.GetString("music_autoplay_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Default volume set to {0}%. + /// + public static string music_defvol_set { + get { + return ResourceManager.GetString("music_defvol_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Directory queue complete.. + /// + public static string music_dir_queue_complete { + get { + return ResourceManager.GetString("music_dir_queue_complete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Finished Song. + /// + public static string music_finished_song { + get { + return ResourceManager.GetString("music_finished_song", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fair play disabled.. + /// + public static string music_fp_disabled { + get { + return ResourceManager.GetString("music_fp_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fair play enabled.. + /// + public static string music_fp_enabled { + get { + return ResourceManager.GetString("music_fp_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to From position. + /// + public static string music_from_position { + get { + return ResourceManager.GetString("music_from_position", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Id. + /// + public static string music_id { + get { + return ResourceManager.GetString("music_id", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid input.. + /// + public static string music_invalid_input { + get { + return ResourceManager.GetString("music_invalid_input", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Max playtime has no limit now.. + /// + public static string music_max_playtime_none { + get { + return ResourceManager.GetString("music_max_playtime_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Max playtime set to {0} second(s).. + /// + public static string music_max_playtime_set { + get { + return ResourceManager.GetString("music_max_playtime_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Max music queue size set to unlimited.. + /// + public static string music_max_queue_unlimited { + get { + return ResourceManager.GetString("music_max_queue_unlimited", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Max music queue size set to {0} track(s).. + /// + public static string music_max_queue_x { + get { + return ResourceManager.GetString("music_max_queue_x", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You need to be in the voice channel on this server.. + /// + public static string music_must_be_in_voice { + get { + return ResourceManager.GetString("music_must_be_in_voice", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Name. + /// + public static string music_name { + get { + return ResourceManager.GetString("music_name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No active music player.. + /// + public static string music_no_player { + get { + return ResourceManager.GetString("music_no_player", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No search results.. + /// + public static string music_no_search_results { + get { + return ResourceManager.GetString("music_no_search_results", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Now Playing. + /// + public static string music_now_playing { + get { + return ResourceManager.GetString("music_now_playing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Music playback paused.. + /// + public static string music_paused { + get { + return ResourceManager.GetString("music_paused", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}s limit. + /// + public static string music_play_limit { + get { + return ResourceManager.GetString("music_play_limit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No music player active.. + /// + public static string music_player_none { + get { + return ResourceManager.GetString("music_player_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Player Queue - Page {0}/{1}. + /// + public static string music_player_queue { + get { + return ResourceManager.GetString("music_player_queue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Playing Song. + /// + public static string music_playing_song { + get { + return ResourceManager.GetString("music_playing_song", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to delete that playlist. It either doesn't exist, or you are not its author.. + /// + public static string music_playlist_delete_fail { + get { + return ResourceManager.GetString("music_playlist_delete_fail", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Playlist deleted.. + /// + public static string music_playlist_deleted { + get { + return ResourceManager.GetString("music_playlist_deleted", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Playlist with that ID doesn't exist.. + /// + public static string music_playlist_id_not_found { + get { + return ResourceManager.GetString("music_playlist_id_not_found", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Playlist queue complete.. + /// + public static string music_playlist_queue_complete { + get { + return ResourceManager.GetString("music_playlist_queue_complete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Playlist Saved. + /// + public static string music_playlist_saved { + get { + return ResourceManager.GetString("music_playlist_saved", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `#{0}` - **{1}** by *{2}* ({3} songs). + /// + public static string music_playlists { + get { + return ResourceManager.GetString("music_playlists", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Page {0} of Saved Playlists. + /// + public static string music_playlists_page { + get { + return ResourceManager.GetString("music_playlists_page", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Queue. + /// + public static string music_queue { + get { + return ResourceManager.GetString("music_queue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Music queue cleared.. + /// + public static string music_queue_cleared { + get { + return ResourceManager.GetString("music_queue_cleared", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Queue is full at {0}/{0}.. + /// + public static string music_queue_full { + get { + return ResourceManager.GetString("music_queue_full", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Queued Song. + /// + public static string music_queued_song { + get { + return ResourceManager.GetString("music_queued_song", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removed song. + /// + public static string music_removed_song { + get { + return ResourceManager.GetString("music_removed_song", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Repeating Current Song. + /// + public static string music_repeating_cur_song { + get { + return ResourceManager.GetString("music_repeating_cur_song", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Repeating Playlist. + /// + public static string music_repeating_playlist { + get { + return ResourceManager.GetString("music_repeating_playlist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Repeating Track. + /// + public static string music_repeating_track { + get { + return ResourceManager.GetString("music_repeating_track", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Current track repeat stopped.. + /// + public static string music_repeating_track_stopped { + get { + return ResourceManager.GetString("music_repeating_track_stopped", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Music playback resumed.. + /// + public static string music_resumed { + get { + return ResourceManager.GetString("music_resumed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Repeat playlist disabled.. + /// + public static string music_rpl_disabled { + get { + return ResourceManager.GetString("music_rpl_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Repeat playlist enabled.. + /// + public static string music_rpl_enabled { + get { + return ResourceManager.GetString("music_rpl_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I will now output playing, finished, paused and removed songs in this channel.. + /// + public static string music_set_music_channel { + get { + return ResourceManager.GetString("music_set_music_channel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Skipped to `{0}:{1}`. + /// + public static string music_skipped_to { + get { + return ResourceManager.GetString("music_skipped_to", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Song Moved. + /// + public static string music_song_moved { + get { + return ResourceManager.GetString("music_song_moved", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Songs shuffled.. + /// + public static string music_songs_shuffled { + get { + return ResourceManager.GetString("music_songs_shuffled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}h {1}m {2}s. + /// + public static string music_time_format { + get { + return ResourceManager.GetString("music_time_format", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to To position. + /// + public static string music_to_position { + get { + return ResourceManager.GetString("music_to_position", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to unlimited. + /// + public static string music_unlimited { + get { + return ResourceManager.GetString("music_unlimited", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume must be between 0 and 100. + /// + public static string music_volume_input_invalid { + get { + return ResourceManager.GetString("music_volume_input_invalid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Volume set to {0}%. + /// + public static string music_volume_set { + get { + return ResourceManager.GetString("music_volume_set", resourceCulture); + } + } + /// /// Looks up a localized string similar to Autohentai started. Reposting every {0}s with one of the following tags: ///{1}. diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 5030e3bd..8598ae3e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1332,6 +1332,166 @@ Don't forget to leave your discord name or id in the message. {0} vs {1} + + Attempting to queue {0} songs... + + + Autoplay disabled. + + + Autoplay enabled. + + + Default volume set to {0}% + + + Directory queue complete. + + + Finished Song + + + Fair play disabled. + + + Fair play enabled. + + + From position + + + Id + + + Invalid input. + + + Max playtime has no limit now. + + + Max playtime set to {0} second(s). + + + Max music queue size set to unlimited. + + + Max music queue size set to {0} track(s). + + + You need to be in the voice channel on this server. + + + Name + + + Now Playing + + + No active music player. + + + No search results. + + + Music playback paused. + + + No music player active. + + + Player Queue - Page {0}/{1} + + + Playing Song + + + `#{0}` - **{1}** by *{2}* ({3} songs) + + + Page {0} of Saved Playlists + + + Playlist deleted. + + + Failed to delete that playlist. It either doesn't exist, or you are not its author. + + + Playlist with that ID doesn't exist. + + + Playlist queue complete. + + + Playlist Saved + + + {0}s limit + + + Queue + + + Queued Song + + + Music queue cleared. + + + Queue is full at {0}/{0}. + + + Removed song + context: "removed song #5" + + + Repeating Current Song + + + Repeating Playlist + + + Repeating Track + + + Current track repeat stopped. + + + Music playback resumed. + + + Repeat playlist disabled. + + + Repeat playlist enabled. + + + I will now output playing, finished, paused and removed songs in this channel. + + + Skipped to `{0}:{1}` + + + Songs shuffled. + + + Song Moved + + + {0}h {1}m {2}s + + + To position + + + unlimited + + + Volume must be between 0 and 100 + + + Volume set to {0}% + Disabled usage of ALL MODULES on {0} channel. diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index f7f39985..f3058f97 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -14,9 +14,9 @@ namespace NadekoBot.Services.Impl public class StatsService : IStatsService { private readonly DiscordShardedClient _client; - private DateTime _started; + private readonly DateTime _started; - public const string BotVersion = "1.1.8-alpha"; + public const string BotVersion = "1.2-beta"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From 778dbcb1d02d56412b7c4fad5340a2c3e2f6ae20 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 25 Feb 2017 03:43:30 +0100 Subject: [PATCH 346/746] Fixed 3 response strings. Fixed ~pokeab rare bug thanks to infy --- .../Games/Commands/PlantAndPickCommands.cs | 2 +- src/NadekoBot/Modules/Music/Music.cs | 4 ++-- .../Searches/Commands/Models/SearchPokemon.cs | 17 +++++++++-------- .../Searches/Commands/PokemonSearchCommands.cs | 7 +++++-- .../Resources/ResponseStrings.Designer.cs | 9 +++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 3 +++ 6 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 4778e37c..42fea1a4 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -82,7 +82,7 @@ namespace NadekoBot.Modules.Games var prefix = NadekoBot.ModulePrefixes[typeof(Games).Name]; var toSend = dropAmount == 1 ? GetLocalText(channel, "curgen_sn", NadekoBot.BotConfig.CurrencySign, prefix) - : GetLocalText(channel, "curgen_pl", NadekoBot.BotConfig.CurrencySign, prefix); + : GetLocalText(channel, "curgen_pl", dropAmount, NadekoBot.BotConfig.CurrencySign, prefix); var file = GetRandomCurrencyImage(); using (var fileStream = file.Value.ToStream()) { diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 5d685bbc..d1734a2d 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -915,9 +915,9 @@ namespace NadekoBot.Modules.Music { IUserMessage msg; if (paused) - msg = await mp.OutputTextChannel.SendConfirmAsync(GetText("music_paused")).ConfigureAwait(false); + msg = await mp.OutputTextChannel.SendConfirmAsync(GetText("paused")).ConfigureAwait(false); else - msg = await mp.OutputTextChannel.SendConfirmAsync(GetText("music_resumed")).ConfigureAwait(false); + msg = await mp.OutputTextChannel.SendConfirmAsync(GetText("resumed")).ConfigureAwait(false); msg?.DeleteAfter(10); } diff --git a/src/NadekoBot/Modules/Searches/Commands/Models/SearchPokemon.cs b/src/NadekoBot/Modules/Searches/Commands/Models/SearchPokemon.cs index b1e24ad5..ed758f7f 100644 --- a/src/NadekoBot/Modules/Searches/Commands/Models/SearchPokemon.cs +++ b/src/NadekoBot/Modules/Searches/Commands/Models/SearchPokemon.cs @@ -33,22 +33,23 @@ namespace NadekoBot.Modules.Searches.Models public string[] Evos { get; set; } public string[] EggGroups { get; set; } - public override string ToString() => $@"`Name:` {Species} -`Types:` {string.Join(", ", Types)} -`Stats:` {BaseStats} -`Height:` {HeightM,4}m `Weight:` {WeightKg}kg -`Abilities:` {string.Join(", ", Abilities.Values)}"; +// public override string ToString() => $@"`Name:` {Species} +//`Types:` {string.Join(", ", Types)} +//`Stats:` {BaseStats} +//`Height:` {HeightM,4}m `Weight:` {WeightKg}kg +//`Abilities:` {string.Join(", ", Abilities.Values)}"; } public class SearchPokemonAbility { public string Desc { get; set; } + public string ShortDesc { get; set; } public string Name { get; set; } public float Rating { get; set; } - public override string ToString() => $@"`Name:` : {Name} -`Rating:` {Rating} -`Description:` {Desc}"; +// public override string ToString() => $@"`Name:` : {Name} +//`Rating:` {Rating} +//`Description:` {Desc}"; } } diff --git a/src/NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs index b04769fa..bc77cda3 100644 --- a/src/NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs @@ -77,8 +77,11 @@ namespace NadekoBot.Modules.Searches { await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithTitle(kvp.Value.Name) - .WithDescription(kvp.Value.Desc) - .AddField(efb => efb.WithName(GetText("rating")).WithValue(kvp.Value.Rating.ToString(_cultureInfo)).WithIsInline(true)) + .WithDescription(string.IsNullOrWhiteSpace(kvp.Value.Desc) + ? kvp.Value.ShortDesc + : kvp.Value.Desc) + .AddField(efb => efb.WithName(GetText("rating")) + .WithValue(kvp.Value.Rating.ToString(_cultureInfo)).WithIsInline(true)) ).ConfigureAwait(false); return; } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 1d11bac1..e785af5a 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2081,6 +2081,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Animal Race is already running.. + /// + public static string gambling_animal_race_already_started { + get { + return ResourceManager.GetString("gambling_animal_race_already_started", resourceCulture); + } + } + /// /// Looks up a localized string similar to Failed to start since there was not enough participants.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 8598ae3e..79eb3601 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1218,6 +1218,9 @@ Don't forget to leave your discord name or id in the message. Submissions Closed + + Animal Race is already running. + Total: {0} Average: {1} From 68ac62d4e88140b7d29aaf5f40e8ec319bc00356 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 25 Feb 2017 03:52:27 +0100 Subject: [PATCH 347/746] fairplay key was missing --- src/NadekoBot/Resources/ResponseStrings.Designer.cs | 9 +++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 3 +++ 2 files changed, 12 insertions(+) diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index e785af5a..839a9927 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -3442,6 +3442,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to fairplay. + /// + public static string music_fairplay { + get { + return ResourceManager.GetString("music_fairplay", resourceCulture); + } + } + /// /// Looks up a localized string similar to Finished Song. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 79eb3601..8dd225d1 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1350,6 +1350,9 @@ Don't forget to leave your discord name or id in the message. Directory queue complete. + + fairplay + Finished Song From 628504b5fd1916e5039b07e8a5393e5a9c584441 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 25 Feb 2017 03:57:59 +0100 Subject: [PATCH 348/746] videocall fixed --- src/NadekoBot/Modules/Searches/Searches.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 28fb15bb..7ed4dae9 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -611,7 +611,7 @@ namespace NadekoBot.Modules.Searches } [NadekoCommand, Usage, Description, Aliases] - public async Task Videocall([Remainder] params IUser[] users) + public async Task Videocall(params IUser[] users) { var allUsrs = users.Append(Context.User); var allUsrsArray = allUsrs.ToArray(); From 7c00b9fe868dbb89428d0ab4368fb7a779c1b779 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 25 Feb 2017 04:02:11 +0100 Subject: [PATCH 349/746] ~trans now properly throws an error if language is invalid --- .../Modules/Searches/Commands/GoogleTranslator.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/GoogleTranslator.cs b/src/NadekoBot/Modules/Searches/Commands/GoogleTranslator.cs index 5604fdd1..9cd0645c 100644 --- a/src/NadekoBot/Modules/Searches/Commands/GoogleTranslator.cs +++ b/src/NadekoBot/Modules/Searches/Commands/GoogleTranslator.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json.Linq; +using System; +using Newtonsoft.Json.Linq; using System.Collections.Generic; using System.Linq; using System.Net; @@ -155,6 +156,11 @@ namespace NadekoBot.Modules.Searches { string text; + if(!_languageDictionary.ContainsKey(sourceLanguage) || + !_languageDictionary.ContainsKey(targetLanguage)) + throw new ArgumentException(); + + var url = string.Format("https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}", ConvertToLanguageCode(sourceLanguage), ConvertToLanguageCode(targetLanguage), From 8712abe554644b2603ac6e89f6a2248a3c53a58a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 25 Feb 2017 04:18:44 +0100 Subject: [PATCH 350/746] small logging bug --- src/NadekoBot/Modules/Administration/Commands/LogCommand.cs | 1 - src/NadekoBot/Modules/Games/Games.cs | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index 039e8f74..f431caad 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -126,7 +126,6 @@ namespace NadekoBot.Modules.Administration { embed.WithTitle("👥" + g.GetLogText("avatar_changed")) .WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}") - .WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}") .WithThumbnailUrl(before.AvatarUrl) .WithImageUrl(after.AvatarUrl) .WithFooter(fb => fb.WithText(currentTime)) diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index 6e9f8ff4..f9d278d3 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -196,6 +196,10 @@ namespace NadekoBot.Modules.Games var roll = rng.Next(1, 1001); + if (uid == 185968432783687681 || + uid == 265642040950390784) + roll += 100; + double hot; double crazy; string advice; From 0a5036bb5443e1b0f0a0c2ba54b5c715da69a452 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 25 Feb 2017 04:40:21 +0100 Subject: [PATCH 351/746] rategirl gwen rig --- src/NadekoBot/Modules/Games/Games.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index f9d278d3..cbf45ab6 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -200,6 +200,9 @@ namespace NadekoBot.Modules.Games uid == 265642040950390784) roll += 100; + if (uid == 68946899150839808) + roll = 990; + double hot; double crazy; string advice; From 316c05436e3ecf65f4457c1e72ed33855a8e0e52 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 25 Feb 2017 12:16:48 +0100 Subject: [PATCH 352/746] missing key --- 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 d1734a2d..986f3f47 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -196,7 +196,7 @@ namespace NadekoBot.Modules.Music if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer) || (currentSong = musicPlayer?.CurrentSong) == null) { - await ReplyErrorLocalized("no_music_player").ConfigureAwait(false); + await ReplyErrorLocalized("no_player").ConfigureAwait(false); return; } if (page <= 0) From a413184a4387cbb413c16302b8450661844d7132 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 25 Feb 2017 16:35:09 +0100 Subject: [PATCH 353/746] fixed some things --- src/NadekoBot/Modules/Games/Games.cs | 33 ++++++--------- .../Resources/CommandStrings.Designer.cs | 2 +- src/NadekoBot/Resources/CommandStrings.resx | 2 +- src/NadekoBot/Services/Impl/ImagesService.cs | 41 +++++++++---------- 4 files changed, 34 insertions(+), 44 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Games.cs b/src/NadekoBot/Modules/Games/Games.cs index cbf45ab6..2acd06dd 100644 --- a/src/NadekoBot/Modules/Games/Games.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -6,7 +6,6 @@ using NadekoBot.Attributes; using System; using System.Collections.Concurrent; using System.Linq; -using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Threading; @@ -15,8 +14,6 @@ using System.Net.Http; using ImageSharp; using NadekoBot.DataStructures; using NLog; -using ImageSharp.Drawing.Pens; -using SixLabors.Shapes; namespace NadekoBot.Modules.Games { @@ -37,7 +34,7 @@ namespace NadekoBot.Modules.Games if (string.IsNullOrWhiteSpace(list)) return; var listArr = list.Split(';'); - if (listArr.Count() < 2) + if (listArr.Length < 2) return; var rng = new NadekoRandom(); await Context.Channel.SendConfirmAsync("🤔", listArr[rng.Next(0, listArr.Length)]).ConfigureAwait(false); @@ -57,7 +54,7 @@ namespace NadekoBot.Modules.Games [NadekoCommand, Usage, Description, Aliases] public async Task Rps(string input) { - Func GetRPSPick = (p) => + Func getRpsPick = (p) => { switch (p) { @@ -93,15 +90,15 @@ namespace NadekoBot.Modules.Games var nadekoPick = new NadekoRandom().Next(0, 3); string msg; if (pick == nadekoPick) - msg = GetText("rps_draw", GetRPSPick(pick)); + msg = GetText("rps_draw", getRpsPick(pick)); else if ((pick == 0 && nadekoPick == 1) || (pick == 1 && nadekoPick == 2) || (pick == 2 && nadekoPick == 0)) msg = GetText("rps_win", NadekoBot.Client.CurrentUser.Mention, - GetRPSPick(nadekoPick), GetRPSPick(pick)); + getRpsPick(nadekoPick), getRpsPick(pick)); else - msg = GetText("rps_win", Context.User.Mention, GetRPSPick(pick), - GetRPSPick(nadekoPick)); + msg = GetText("rps_win", Context.User.Mention, getRpsPick(pick), + getRpsPick(nadekoPick)); await Context.Channel.SendConfirmAsync(msg).ConfigureAwait(false); } @@ -110,7 +107,7 @@ namespace NadekoBot.Modules.Games public class GirlRating { - private static Logger _log = LogManager.GetCurrentClassLogger(); + private static readonly Logger _log = LogManager.GetCurrentClassLogger(); public double Crazy { get; } public double Hot { get; } @@ -132,19 +129,17 @@ namespace NadekoBot.Modules.Games using (var ms = new MemoryStream(NadekoBot.Images.WifeMatrix.ToArray(), false)) using (var img = new ImageSharp.Image(ms)) { - var clr = new ImageSharp.Color(0x0000ff); const int minx = 35; const int miny = 385; const int length = 345; var pointx = (int)(minx + length * (Hot / 10)); var pointy = (int)(miny - length * ((Crazy - 4) / 6)); - - var p = new Pen(ImageSharp.Color.Red, 5); + using (var pointMs = new MemoryStream(NadekoBot.Images.RategirlDot.ToArray(), false)) using (var pointImg = new ImageSharp.Image(pointMs)) { - img.DrawImage(pointImg, 100, default(ImageSharp.Size), new Point(pointx - 10, pointy - 10)); + img.DrawImage(pointImg, 100, default(Size), new Point(pointx - 10, pointy - 10)); } string url; @@ -196,12 +191,10 @@ namespace NadekoBot.Modules.Games var roll = rng.Next(1, 1001); - if (uid == 185968432783687681 || - uid == 265642040950390784) - roll += 100; + if ((uid == 185968432783687681 || + uid == 265642040950390784) && roll >= 900) + roll = 1000; - if (uid == 68946899150839808) - roll = 990; double hot; double crazy; @@ -234,7 +227,7 @@ namespace NadekoBot.Modules.Games else if (roll < 951) { hot = NextDouble(8, 10); - crazy = NextDouble(4, 10); + crazy = NextDouble(7, .6 * hot + 4); advice = "Below the crazy line, above an 8 hot, but still about 7 crazy. This is your DATE ZONE. " + "You can stay in the date zone indefinitely. These are the girls you introduce to your friends and your family. " + "They're good looking, and they're reasonably not crazy most of the time. You can stay here indefinitely."; diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index a7709227..2ea37420 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -501,7 +501,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders.. + /// Looks up a localized string similar to Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10.. /// public static string antispam_desc { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index a1afe541..662975cf 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2443,7 +2443,7 @@ antispam - Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. + Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10. `{0}antispam 3 Mute` or `{0}antispam 4 Kick` or `{0}antispam 6 Ban` diff --git a/src/NadekoBot/Services/Impl/ImagesService.cs b/src/NadekoBot/Services/Impl/ImagesService.cs index 089aa0e4..1b37e976 100644 --- a/src/NadekoBot/Services/Impl/ImagesService.cs +++ b/src/NadekoBot/Services/Impl/ImagesService.cs @@ -1,13 +1,10 @@ -using NadekoBot.DataStructures; -using NLog; +using NLog; using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; using System.Threading.Tasks; namespace NadekoBot.Services.Impl @@ -16,26 +13,26 @@ namespace NadekoBot.Services.Impl { private readonly Logger _log; - private const string basePath = "data/images/"; + private const string _basePath = "data/images/"; - private const string headsPath = basePath + "coins/heads.png"; - private const string tailsPath = basePath + "coins/tails.png"; + private const string _headsPath = _basePath + "coins/heads.png"; + private const string _tailsPath = _basePath + "coins/tails.png"; - private const string currencyImagesPath = basePath + "currency"; - private const string diceImagesPath = basePath + "dice"; + private const string _currencyImagesPath = _basePath + "currency"; + private const string _diceImagesPath = _basePath + "dice"; - private const string slotBackgroundPath = basePath + "slots/background.png"; - private const string slotNumbersPath = basePath + "slots/numbers/"; - private const string slotEmojisPath = basePath + "slots/emojis/"; + private const string _slotBackgroundPath = _basePath + "slots/background.png"; + private const string _slotNumbersPath = _basePath + "slots/numbers/"; + private const string _slotEmojisPath = _basePath + "slots/emojis/"; - private const string _wifeMatrixPath = basePath + "rategirl/wifematrix.png"; - private const string _rategirlDot = basePath + "rategirl/dot.png"; + private const string _wifeMatrixPath = _basePath + "rategirl/wifematrix.png"; + private const string _rategirlDot = _basePath + "rategirl/dot.png"; public ImmutableArray Heads { get; private set; } public ImmutableArray Tails { get; private set; } - //todo C#7 + //todo C#7 tuples public ImmutableArray>> Currency { get; private set; } public ImmutableArray>> Dice { get; private set; } @@ -65,29 +62,29 @@ namespace NadekoBot.Services.Impl { _log.Info("Loading images..."); var sw = Stopwatch.StartNew(); - Heads = File.ReadAllBytes(headsPath).ToImmutableArray(); - Tails = File.ReadAllBytes(tailsPath).ToImmutableArray(); + Heads = File.ReadAllBytes(_headsPath).ToImmutableArray(); + Tails = File.ReadAllBytes(_tailsPath).ToImmutableArray(); - Currency = Directory.GetFiles(currencyImagesPath) + Currency = Directory.GetFiles(_currencyImagesPath) .Select(x => new KeyValuePair>( Path.GetFileName(x), File.ReadAllBytes(x).ToImmutableArray())) .ToImmutableArray(); - Dice = Directory.GetFiles(diceImagesPath) + Dice = Directory.GetFiles(_diceImagesPath) .OrderBy(x => int.Parse(Path.GetFileNameWithoutExtension(x))) .Select(x => new KeyValuePair>(x, File.ReadAllBytes(x).ToImmutableArray())) .ToImmutableArray(); - SlotBackground = File.ReadAllBytes(slotBackgroundPath).ToImmutableArray(); + SlotBackground = File.ReadAllBytes(_slotBackgroundPath).ToImmutableArray(); - SlotNumbers = Directory.GetFiles(slotNumbersPath) + SlotNumbers = Directory.GetFiles(_slotNumbersPath) .OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f))) .Select(x => File.ReadAllBytes(x).ToImmutableArray()) .ToImmutableArray(); - SlotEmojis = Directory.GetFiles(slotEmojisPath) + SlotEmojis = Directory.GetFiles(_slotEmojisPath) .OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f))) .Select(x => File.ReadAllBytes(x).ToImmutableArray()) .ToImmutableArray(); From 1f09ad67e3825b57b0ae4b2e20c5a929adbdc07f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 26 Feb 2017 22:05:17 +0100 Subject: [PATCH 354/746] some random changes, and fixed ,cw help, thx infy --- .../Modules/ClashOfClans/ClashOfClans.cs | 4 +-- src/NadekoBot/Services/CommandHandler.cs | 32 +++++++++---------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs index 043a12b2..ca56acef 100644 --- a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs +++ b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs @@ -82,11 +82,9 @@ namespace NadekoBot.Modules.ClashOfClans [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] public async Task CreateWar(int size, [Remainder] string enemyClan = null) { - if (!(Context.User as IGuildUser).GuildPermissions.ManageChannels) - return; - if (string.IsNullOrWhiteSpace(enemyClan)) return; diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 336e976c..0f4cf950 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -5,9 +5,7 @@ using System.Linq; using System.Threading.Tasks; using Discord; using NLog; -using System.Diagnostics; using Discord.Commands; -using NadekoBot.Services.Database.Models; using NadekoBot.Modules.Permissions; using Discord.Net; using NadekoBot.Extensions; @@ -22,7 +20,7 @@ using NadekoBot.DataStructures; namespace NadekoBot.Services { - public class IGuildUserComparer : IEqualityComparer + public class GuildUserComparer : IEqualityComparer { public bool Equals(IGuildUser x, IGuildUser y) => x.Id == y.Id; @@ -48,7 +46,7 @@ namespace NadekoBot.Services public ConcurrentDictionary UserMessagesSent { get; } = new ConcurrentDictionary(); public ConcurrentHashSet UsersOnShortCooldown { get; } = new ConcurrentHashSet(); - private Timer clearUsersOnShortCooldown { get; } + private readonly Timer _clearUsersOnShortCooldown; public CommandHandler(DiscordShardedClient client, CommandService commandService) { @@ -56,7 +54,7 @@ namespace NadekoBot.Services _commandService = commandService; _log = LogManager.GetCurrentClassLogger(); - clearUsersOnShortCooldown = new Timer((_) => + _clearUsersOnShortCooldown = new Timer(_ => { UsersOnShortCooldown.Clear(); }, null, GlobalCommandsCooldown, GlobalCommandsCooldown); @@ -68,7 +66,7 @@ namespace NadekoBot.Services await Task.Delay(5000).ConfigureAwait(false); ownerChannels = (await Task.WhenAll(_client.GetGuilds().SelectMany(g => g.Users) .Where(u => NadekoBot.Credentials.OwnerIds.Contains(u.Id)) - .Distinct(new IGuildUserComparer()) + .Distinct(new GuildUserComparer()) .Select(async u => { try @@ -141,7 +139,7 @@ namespace NadekoBot.Services BlacklistCommands.BlacklistedChannels.Contains(usrMsg.Channel.Id) || BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id); - const float oneThousandth = 1.0f / 1000; + private const float _oneThousandth = 1.0f / 1000; private Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int exec1, int exec2, int exec3, int total) { _log.Info("Command Executed after {4}/{5}/{6}/{7}s\n\t" + @@ -153,10 +151,10 @@ namespace NadekoBot.Services (channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1} (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2} usrMsg.Content, // {3} - exec1 * oneThousandth, // {4} - exec2 * oneThousandth, // {5} - exec3 * oneThousandth, // {6} - total * oneThousandth // {7} + exec1 * _oneThousandth, // {4} + exec2 * _oneThousandth, // {5} + exec3 * _oneThousandth, // {6} + total * _oneThousandth // {7} ); return Task.CompletedTask; } @@ -174,10 +172,10 @@ namespace NadekoBot.Services (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2} usrMsg.Content,// {3} exec.Result.ErrorReason, // {4} - exec1 * oneThousandth, // {5} - exec2 * oneThousandth, // {6} - exec3 * oneThousandth, // {7} - total * oneThousandth // {8} + exec1 * _oneThousandth, // {5} + exec2 * _oneThousandth, // {6} + exec3 * _oneThousandth, // {7} + total * _oneThousandth // {8} ); } @@ -429,10 +427,10 @@ 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.")); + 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 a 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 8160408f9a9e97a0a3867539de7a7e0203b8d36c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 26 Feb 2017 22:56:24 +0100 Subject: [PATCH 355/746] fixed guess and defvol keys --- src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs | 4 +--- src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs | 2 +- src/NadekoBot/Modules/Music/Music.cs | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs index ca56acef..53380a86 100644 --- a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs +++ b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs @@ -11,15 +11,13 @@ using NadekoBot.Services.Database.Models; using System.Linq; using NadekoBot.Extensions; using System.Threading; -using System.Diagnostics; -using NLog; namespace NadekoBot.Modules.ClashOfClans { [NadekoModule("ClashOfClans", ",")] public class ClashOfClans : NadekoTopLevelModule { - public static ConcurrentDictionary> ClashWars { get; set; } = new ConcurrentDictionary>(); + public static ConcurrentDictionary> ClashWars { get; set; } private static Timer checkWarTimer { get; } diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs index 0862290f..18e46fa5 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs @@ -201,7 +201,7 @@ namespace NadekoBot.Modules.Games.Trivia return; } await Channel.SendConfirmAsync(GetText("trivia_game"), - GetText("guess", guildUser.Mention, Format.Bold(CurrentQuestion.Answer))).ConfigureAwait(false); + GetText("trivia_guess", guildUser.Mention, Format.Bold(CurrentQuestion.Answer))).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 986f3f47..5baa7c6e 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -301,7 +301,7 @@ namespace NadekoBot.Modules.Music uow.GuildConfigs.For(Context.Guild.Id, set => set).DefaultMusicVolume = val / 100.0f; uow.Complete(); } - await ReplyConfirmLocalized("defvol_set").ConfigureAwait(false); + await ReplyConfirmLocalized("defvol_set", val).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] From f7cd98194d66b2486a32619ec830bc703b346eb2 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 27 Feb 2017 13:23:48 +0100 Subject: [PATCH 356/746] fixed a missing string --- .../Modules/Games/Commands/Acropobia.cs | 2 +- .../Utility/Commands/MessageRepeater.cs | 48 +++++++++++-------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs index ddaf3e98..f90f946b 100644 --- a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -276,7 +276,7 @@ $@"-- { if (!_votes.Any()) { - await _channel.SendErrorAsync(GetText("acrophobia"), GetText("no_votes_cast")).ConfigureAwait(false); + await _channel.SendErrorAsync(GetText("acrophobia"), GetText("acro_no_votes_cast")).ConfigureAwait(false); return; } var table = _votes.OrderByDescending(v => v.Value); diff --git a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs index 7cddce2c..d371330c 100644 --- a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs @@ -9,11 +9,11 @@ using NadekoBot.Services.Database.Models; using NLog; using System; using System.Collections.Concurrent; -using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using Discord.WebSocket; namespace NadekoBot.Modules.Utility { @@ -34,23 +34,16 @@ namespace NadekoBot.Modules.Utility private CancellationTokenSource source { get; set; } private CancellationToken token { get; set; } public Repeater Repeater { get; } - public ITextChannel Channel { get; } + public SocketGuild Guild { get; } + public ITextChannel Channel { get; private set; } public RepeatRunner(Repeater repeater, ITextChannel channel = null) { _log = LogManager.GetCurrentClassLogger(); Repeater = repeater; - //if (channel == null) - //{ - // var guild = NadekoBot.Client.GetGuild(repeater.GuildId); - // Channel = guild.GetTextChannel(repeater.ChannelId); - //} - //else - // Channel = channel; + Channel = channel; - Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannel(repeater.ChannelId); - if (Channel == null) - return; + Guild = NadekoBot.Client.GetGuild(repeater.GuildId); Task.Run(Run); } @@ -72,10 +65,21 @@ namespace NadekoBot.Modules.Utility // continue; if (oldMsg != null) - try { await oldMsg.DeleteAsync(); } catch { } + try + { + await oldMsg.DeleteAsync(); + } + catch + { + // ignored + } try { - oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false); + if (Channel == null) + Channel = Guild.GetTextChannel(Repeater.ChannelId); + + if (Channel != null) + oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false); } catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.Forbidden) { @@ -93,7 +97,9 @@ namespace NadekoBot.Modules.Utility } } } - catch (OperationCanceledException) { } + catch (OperationCanceledException) + { + } } public void Reset() @@ -109,7 +115,8 @@ namespace NadekoBot.Modules.Utility public override string ToString() { - return $"{Channel.Mention} | {(int)Repeater.Interval.TotalHours}:{Repeater.Interval:mm} | {Repeater.Message.TrimTo(33)}"; + return + $"{Channel.Mention} | {(int) Repeater.Interval.TotalHours}:{Repeater.Interval:mm} | {Repeater.Message.TrimTo(33)}"; } } @@ -120,8 +127,7 @@ namespace NadekoBot.Modules.Utility await Task.Delay(5000).ConfigureAwait(false); Repeaters = new ConcurrentDictionary>(NadekoBot.AllGuildConfigs .ToDictionary(gc => gc.GuildId, - gc => new ConcurrentQueue(gc.GuildRepeaters.Select(gr => new RepeatRunner(gr)) - .Where(gr => gr.Channel != null)))); + gc => new ConcurrentQueue(gc.GuildRepeaters.Select(gr => new RepeatRunner(gr))))); _ready = true; }); } @@ -192,7 +198,7 @@ namespace NadekoBot.Modules.Utility if (Repeaters.TryUpdate(Context.Guild.Id, new ConcurrentQueue(repeaterList), rep)) await Context.Channel.SendConfirmAsync(GetText("message_repeater"), - GetText("repeater_stopped" , index + 1) + $"\n\n{repeater}").ConfigureAwait(false); + GetText("repeater_stopped", index + 1) + $"\n\n{repeater}").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -228,9 +234,9 @@ namespace NadekoBot.Modules.Utility await uow.CompleteAsync().ConfigureAwait(false); } - var rep = new RepeatRunner(toAdd, (ITextChannel)Context.Channel); + var rep = new RepeatRunner(toAdd, (ITextChannel) Context.Channel); - Repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue(new[] { rep }), (key, old) => + Repeaters.AddOrUpdate(Context.Guild.Id, new ConcurrentQueue(new[] {rep}), (key, old) => { old.Enqueue(rep); return old; From 6ef76125a2f5711cec0e522516b9a2ae8ec0c76f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 27 Feb 2017 14:54:32 +0100 Subject: [PATCH 357/746] fixed $draw --- src/NadekoBot/Modules/Music/Classes/Song.cs | 5 ----- src/NadekoBot/project.json | 13 ++++++------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/Song.cs b/src/NadekoBot/Modules/Music/Classes/Song.cs index d088bfde..c7e933eb 100644 --- a/src/NadekoBot/Modules/Music/Classes/Song.cs +++ b/src/NadekoBot/Modules/Music/Classes/Song.cs @@ -270,11 +270,6 @@ namespace NadekoBot.Modules.Music.Classes //aidiakapi ftw public static unsafe byte[] AdjustVolume(byte[] audioSamples, float volume) { - Contract.Requires(audioSamples != null); - Contract.Requires(audioSamples.Length % 2 == 0); - Contract.Requires(volume >= 0f && volume <= 1f); - Contract.Assert(BitConverter.IsLittleEndian); - if (Math.Abs(volume - 1f) < 0.0001f) return audioSamples; // 16-bit precision for the multiplication diff --git a/src/NadekoBot/project.json b/src/NadekoBot/project.json index d6b8ad6c..cd69d074 100644 --- a/src/NadekoBot/project.json +++ b/src/NadekoBot/project.json @@ -23,12 +23,12 @@ "Google.Apis.Urlshortener.v1": "1.19.0.138", "Google.Apis.YouTube.v3": "1.20.0.701", "Google.Apis.Customsearch.v1": "1.20.0.466", - "ImageSharp": "1.0.0-alpha2-00090", - "ImageSharp.Processing": "1.0.0-alpha2-00078", - "ImageSharp.Formats.Png": "1.0.0-alpha2-00086", - "ImageSharp.Drawing": "1.0.0-alpha2-00090", - "ImageSharp.Drawing.Paths": "1.0.0-alpha2-00040", - //"ImageSharp.Formats.Jpeg": "1.0.0-alpha2-00090", + "ImageSharp": "1.0.0-alpha2-*", + "ImageSharp.Processing": "1.0.0-alpha2-*", + "ImageSharp.Formats.Png": "1.0.0-alpha2-*", + "ImageSharp.Formats.Jpeg": "1.0.0-alpha2-*", + "ImageSharp.Drawing": "1.0.0-alpha2-*", + "ImageSharp.Drawing.Paths": "1.0.0-alpha2-*", "Microsoft.EntityFrameworkCore": "1.1.0", "Microsoft.EntityFrameworkCore.Design": "1.1.0", "Microsoft.EntityFrameworkCore.Sqlite": "1.1.0", @@ -44,7 +44,6 @@ }, "Newtonsoft.Json": "9.0.2-beta1", "NLog": "5.0.0-beta03", - "System.Diagnostics.Contracts": "4.3.0", "System.Xml.XPath": "4.3.0", "Discord.Net.Commands": { "target": "project", From 1fbe7a034e888ca4a622cccc29b791f95e5bde82 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 27 Feb 2017 22:44:10 +0100 Subject: [PATCH 358/746] fixes --- src/NadekoBot/Modules/Music/Music.cs | 2 +- src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 5baa7c6e..02bf9993 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -690,7 +690,7 @@ namespace NadekoBot.Modules.Music return; } IUserMessage msg = null; - try { msg = await ReplyConfirmLocalized("attempting_to_queue", Format.Bold(mpl.Songs.Count.ToString())).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } + try { msg = await Context.Channel.SendMessageAsync(GetText("attempting_to_queue", Format.Bold(mpl.Songs.Count.ToString()))).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } foreach (var item in mpl.Songs) { var usr = (IGuildUser)Context.User; diff --git a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs index d371330c..c615ef1e 100644 --- a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs @@ -44,7 +44,8 @@ namespace NadekoBot.Modules.Utility Channel = channel; Guild = NadekoBot.Client.GetGuild(repeater.GuildId); - Task.Run(Run); + if(Guild!=null) + Task.Run(Run); } @@ -127,7 +128,9 @@ namespace NadekoBot.Modules.Utility await Task.Delay(5000).ConfigureAwait(false); Repeaters = new ConcurrentDictionary>(NadekoBot.AllGuildConfigs .ToDictionary(gc => gc.GuildId, - gc => new ConcurrentQueue(gc.GuildRepeaters.Select(gr => new RepeatRunner(gr))))); + gc => new ConcurrentQueue(gc.GuildRepeaters + .Select(gr => new RepeatRunner(gr)) + .Where(x => x.Guild != null)))); _ready = true; }); } From 81adc259d923305a67f2bba404adbaa7e858288e Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 28 Feb 2017 03:22:46 +0100 Subject: [PATCH 359/746] french translation added for responses, Some string fixes --- .../Commands/LocalizationCommands.cs | 10 +- src/NadekoBot/Modules/Music/Music.cs | 2 +- .../Resources/ResponseStrings.Designer.cs | 13 +- .../Resources/ResponseStrings.fr-fr.resx | 2202 +++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 7 +- 5 files changed, 2213 insertions(+), 21 deletions(-) create mode 100644 src/NadekoBot/Resources/ResponseStrings.fr-fr.resx diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 3b3467f6..8250bfde 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -19,7 +19,8 @@ namespace NadekoBot.Modules.Administration private ImmutableDictionary supportedLocales { get; } = new Dictionary() { {"en-US", "English, United States" }, - {"sr-cyrl-rs", "Serbian, Cyrillic" } + {"fr-FR", "French, France" } + //{"sr-cyrl-rs", "Serbian, Cyrillic" } }.ToImmutableDictionary(); [NadekoCommand, Usage, Description, Aliases] @@ -94,9 +95,10 @@ namespace NadekoBot.Modules.Administration [OwnerOnly] public async Task LanguagesList() { - await ReplyConfirmLocalized("lang_list", - string.Join("\n", supportedLocales.Select(x => $"{Format.Code(x.Key)} => {x.Value}"))) - .ConfigureAwait(false); + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle(GetText("lang_list", "")) + .WithDescription(string.Join("\n", + supportedLocales.Select(x => $"{Format.Code(x.Key), -10} => {x.Value}")))); } } } diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 02bf9993..79dd3d42 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -818,7 +818,7 @@ namespace NadekoBot.Modules.Music MusicPlayer musicPlayer; if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) { - await ReplyErrorLocalized("player_none").ConfigureAwait(false); + await ReplyErrorLocalized("no_player").ConfigureAwait(false); return; } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 839a9927..3d80c3c9 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -1443,7 +1443,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Text Channel Destroyed . + /// Looks up a localized string similar to Text Channel Created. /// public static string administration_text_chan_created { get { @@ -3604,15 +3604,6 @@ namespace NadekoBot.Resources { } } - /// - /// Looks up a localized string similar to No music player active.. - /// - public static string music_player_none { - get { - return ResourceManager.GetString("music_player_none", resourceCulture); - } - } - /// /// Looks up a localized string similar to Player Queue - Page {0}/{1}. /// @@ -4884,7 +4875,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Joes not loaded.. + /// Looks up a localized string similar to Jokes not loaded.. /// public static string searches_jokes_not_loaded { get { diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx new file mode 100644 index 00000000..68602a62 --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx @@ -0,0 +1,2202 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Cette base a déjà été revendiquée ou détruite + + + Cette base est déjà détruite. + + + Cette base n'est pas revendiquée. + + + Base #{0} **DETRUITE** dans une guerre contre {1} + + + {0} a *ABANDONNÉ* la base #{1} dans une guerre contre {2} + + + {0} a revendiqué une base #{1} dans une guerre contre {2} + + + @{0} Vous avez déjà revendiqué la base {1}. Vous ne pouvez pas en revendiquer une nouvelle. + + + La demande de la part de @{0} pour une guerre contre {1} a expiré. + + + Ennemi + + + Informations concernant la guerre contre {0} + + + Numéro de base invalide. + + + La taille de la guerre n'est pas valide. + + + Liste des guerres en cours. + + + Non réclamé. + + + Vous ne participez pas a cette guerre. + + + @{0} Vous ne pouvez pas participer a cette guerre ou la base a déjà été détruite. + + + Aucune guerre en cours. + + + Taille + + + La guerre contre {0} a déjà commencé! + + + La guerre contre {0} commence! + + + La guerre contre {0} a fini. + + + Cette guerre n'existe pas. + + + La guerre contre {0} a éclaté ! + + + Statistiques de réactions personnalisées effacées. + + + Réaction personnalisée supprimée + + + Permissions insuffisantes. Nécessite d'être le propriétaire du Bot pour avoir les réactions personnalisées globales, et Administrateur pour les réactions personnalisées du serveur. + + + Liste de toutes les réactions personnalisées. + + + + Réactions personnalisées + + + Nouvelle réaction personnalisée + + + Aucune réaction personnalisé trouvée. + + + Aucune réaction personnalisée ne correspond à cet ID. + + + Réponse + + + Statistiques des Réactions Personnalisées + + + Statistiques effacées pour {0} réaction personnalisée. + + + Pas de statistiques pour ce déclencheur trouvées, aucune action effectuée. + + + Déclencheur + + + Autohentai arrêté. + + + Aucun résultat trouvé. + + + {0} est déjà inconscient. + + + {0} a toute sa vie. + + + Votre type est déjà {0} + + + Vous avez utilisé {0}{1} sur {2}{3} pour {4} dégâts. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + Vous ne pouvez pas attaquer de nouveau sans représailles ! + + + Vous ne pouvez pas vous attaquer vous-même. + + + {0} s'est évanoui. + + + Vous avez soigné {0} avec un {1} + + + {0} a {1} points de vie restants. + + + Vous ne pouvez pas utiliser {0}. Ecrivez `{1}ml` pour voir la liste de toutes les actions que vous pouvez effectuer. + + + Liste des attaques pour le type {0} + + + Ce n'est pas très efficace. + + + Vous n'avez pas assez de {0} + + + Vous avez ressuscité {0} avec un {1} + + + Vous vous êtes ressuscité avec un {0}. + + + Votre type a bien été modifié de {0} à {1} + + + C'est légèrement efficace. + + + C'est très efficace ! + + + Vous avez utilisé trop de mouvement d'affilé, donc ne pouvez plus bouger ! + + + Le type de {0} est {1} + + + Utilisateur non trouvé. + + + Vous vous êtes évanoui, vous n'êtes donc pas capable de bouger! + + + **L'affectation automatique du rôle** à l'arrivé d'un nouvel utilisateur est désormais **désactivée**. + + + **L'affectation automatique du rôle** à l'arrivé d'un nouvel utilisateur est désormais **activée**. + + + Liens + + + Avatar modifié + + + Vous avez été banni du serveur {0}. +Raison : {1} + + + banni + PLURAL + + + Utilisateur banni + + + Le nom du Bot a changé pour {0} + + + Le statut du Bot a changé pour {0} + + + La suppression automatique des annonces de départ a été désactivée. + + + Les annonces de départ seront supprimées après {0} secondes. + + + Annonce de départ actuelle : {0} + + + Activez les annonces de départ en entrant {0} + + + Nouvelle annonce de départ définie. + + + Annonce de départ désactivée. + + + Annonce de départ activée sur ce salon. + + + Nom du salon modifié + + + Ancien nom + + + Sujet du salon modifié + + + Nettoyé. + + + Contenu + + + Rôle {0} créé avec succès + + + Salon textuel {0} créé. + + + Salon vocal {0} créé. + + + Mise en sourdine effectuée. + + + Serveur {0} supprimé + + + Suppression automatique des commandes effectuées avec succès, désactivée. + + + Suppression automatique des commandes effectuées avec succès, activée. + + + Le salon textuel {0} a été supprimé. + + + Le salon vocal {0} a été supprimé. + + + MP de + + + Nouveau donateur ajouté avec succès. Montant total des dons de cet utilisateur : {0} 👑 + + + Merci aux personnes ci-dessous pour avoir permis à ce projet d'exister. + + + Je transmettrai désormais les MPs à tous les propriétaires. + + + Je transmettrai désormais les MPs seulement au propriétaire principal. + + + Je vous transmettrai désormais les MPs. + + + Je ne vous transmettrez désormais plus les MPs. + + + Suppression automatique des messages d'accueil a été désactivé. + + + Les messages d'accueil seront supprimés après {0} secondes. + + + Message privé de bienvenue actuel: {0} + + + Activez les messages de bienvenue privés en écrivant {0} + + + Nouveau message de bienvenue privé en service. + + + Messages de bienvenue privés désactivés. + + + Messages de bienvenue privés activés. + + + Message de bienvenue actuel: {0} + + + Activez les messages de bienvenue en écrivant {0} + + + Nouveau message de bienvenue en service. + + + Messages de bienvenue désactivés. + + + Messages de bienvenue activés sur ce salon. + + + Vous ne pouvez pas utiliser cette commande sur les utilisateurs dont le rôle est supérieur ou égal au vôtre dans la hiérarchie. + + + Images chargées après {0} secondes! + + + Format d'entrée invalide. + + + Paramètres invalides. + + + {0} a rejoint {1} + + + Vous avez été expulsé du serveur {0}. +Raison : {1} + + + Utilisateur expulsé + + + Listes des langages +{0} + + + La langue du serveur est désormais {0} - {1} + + + La langue par défaut du bot est désormais {0} - {1} + + + La langue du bot a été changée pour {0} - {1} + + + Échec dans la tentative de changement de langue. Réessayer avec l'aide pour cette commande. + + + La langue de ce serveur est {0} - {0} + + + {0} a quitté {1} + + + Serveur {0} quitté + + + Enregistrement de {0} événements dans ce salon. + + + Enregistrement de tous les événements dans ce salon. + + + Enregistrement désactivé. + + + Événements enregistrés que vous pouvez suivre : + + + L'enregistrement ignorera désormais {0} + + + L'enregistrement n'ignorera pas {0} + + + L’événement {0} ne sera plus enregistré. + + + {0} a émis une notification pour les rôles suivants + + + Message de {0} `[Bot Owner]` : + + + Message envoyé. + + + {0} déplacé de {1} à {2} + L'utilisateur n'a pas forcément été déplacé de son plein gré. S'est déplacé - déplacé + + + Message supprimé dans #{0} + + + Mise à jour du message dans #{0} + + + Tous les utilisateurs ont été mis en sourdine. + PLURAL (users have been muted) + + + L'utilisateur à été mis en sourdine. + singular "User muted." + + + Il semblerait que vous n'ayez pas la permission nécessaire pour effectuer cela. + + + Nouveau rôle de mise en sourdine crée. + + + J'ai besoin de la permission d'**Administrateur** pour effectuer cela. + + + Nouveau message + + + Nouveau pseudonyme + + + Nouveau sujet + + + Pseudonyme changé + + + Impossible de trouver ce serveur + + + Aucun shard avec cet ID trouvé. + Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. + + + Ancien message + + + Ancien pseudonyme + + + Ancien sujet + + + Erreur. Je ne dois sûrement pas posséder les permissions suffisantes. + + + Les permissions pour ce serveur ont été réinitialisées. + + + Protections actives + + + {0} a été **désactivé** sur ce serveur. + + + {0} activé + + + Erreur. J'ai besoin de la permission Gérer les rôles + + + Aucune protection activée. + + + Le seuil pour cet utilisateur doit être entre {0} et {1} + + + Si {0} ou plus d'utilisateurs rejoignent dans les {1} secondes suivantes, je les {2}. + + + Le temps doit être compris entre {0} et {1} secondes. + + + Vous avez retirés tout les rôles de l'utilisateur {0} avec succès + + + Impossible de retirer des rôles. Je n'ai pas les permissions suffisantes. + + + La couleur du rôle {0} a été modifiée. + + + Ce rôle n'existe pas. + + + Le paramètre spécifié est invalide. + + + Erreur due à un manque de permissions ou à une couleur invalide. + + + L'utilisateur {1} n'appartient plus au rôle {0}. + + + Impossible de supprimer ce rôle. Je ne possède pas les permissions suffisantes. + + + Rôle renommé. + + + Impossible de renommer ce rôle. Je ne possède pas les permissions suffisantes. + + + Vous ne pouvez pas modifier les rôles supérieurs au votre. + + + La répétition du message suivant a été désactivé: {0} + + + Le rôle {0} a été ajouté à la liste. + + + {0} introuvable. Nettoyé. + + + Le rôle {0} est déjà présent dans la liste. + + + Ajouté. + + + Rotation du statut de jeu désactivée. + + + Rotation du statut de jeu activée. + + + Voici une liste des rotations de statuts : +{0} + + + Aucune rotation de statuts en place. + + + Vous avez déjà le rôle {0}. + + + Vous avez déjà {0} rôles exclusifs auto-affectés. + + + Rôles auto-affectés désormais exclusifs. + + + Il y a {0} rôles auto-affectés. + + + Ce rôle ne peux pas vous être attribué par vous même. + + + Vous ne possédez pas le rôle {0}. + + + L'affection automatique des rôles n'est désormais plus exclusive! + + + Je suis incapable de vous ajouter ce rôle. `Je ne peux pas ajouter de rôles aux propriétaires et aux autres rôles plus haut que le mien dans la hiérarchie.` + + + {0} a été supprimé de la liste des affectations automatiques de rôle. + + + Vous n'avez plus le rôle {0}. + + + Vous avez désormais le rôle {0}. + + + L'ajout du rôle {0} pour l'utilisateur {1} a été réalisé avec succès. + + + Impossible d'ajouter un rôle. Je ne possède pas les permissions suffisantes. + + + Nouvel avatar défini. + + + Nouveau nom de Salon défini avec succès. + + + Nouveau jeu en service! + + + Nouvelle diffusion en service! + + + Nouveau sujet du salon en service. + + + Shard {0} reconnecté. + Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. + + + Shard {0} se reconnecte. + Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. + + + Arrêt en cours. + + + Les utilisateurs ne peuvent pas envoyer plus de {0} messages toutes les {1} secondes. + + + Mode ralenti désactivé. + + + Mode ralenti activé + + + expulsion + PLURAL + + + {0} ignorera ce Salon. + + + {0} n'ignorera plus ce Salon. + + + Si un utilisateur poste {0} le même message à la suite, je le {1}. + __SalonsIgnorés__: {2} + + + Salon textuel crée. + + + Salon textuel détruit. + + + Son activé avec succès. + + + Micro activé + singular + + + Nom d'utilisateur. + + + Nom d'utilisateur modifié. + + + Utilisateurs + + + Utilisateur banni + + + {0} a été **mis en sourdine** sur le tchat. + + + **La parole a été rétablie** sur le tchat pour {0} + + + L'utilisateur a rejoins + + + L'utilisateur a quité + + + {0} a été **mis en sourdine** à la fois sur le salon textuel et vocal. + + + Rôle ajouté à l'utilisateur + + + Rôle enlevé de l'utilisateur + + + {0} est maintenant {1} + + + {0} n'est **plus en sourdine** des salons textuels et vocaux. + + + {0} a rejoint le salon vocal {1}. + + + {0} a quitté le salon vocal {1}. + + + {0} est allé du salon vocal {1} au {2}. + + + {0} a été **mis en sourdine**. + + + {0} a été **retiré de la sourdine** + + + Salon vocal crée. + + + Salon vocal détruit. + + + Fonctionnalités vocales et textuelles désactivées. + + + Fonctionnalités vocales et textuelles activées. + + + Je n'ai pas la permission **Gérer les rôles** et/ou **Gérer les salons**, je ne peux donc pas utiliser `voice+text` sur le serveur {0}. + + + Vous activez/désactivez cette fonctionnalité et **je n'ai pas les permissions ADMINISTRATEURS**. Cela pourrait causer des dysfonctionnements, et vous devrez nettoyer les salons textuels vous-même après ça. + + + Je nécessite au moins les permissions **Gérer les rôles** et **Gérer les salons** pour activer cette fonctionnalité. (permissions administateurs préférées) + + + Utilisateur {0} depuis un salon textuel. + + + Utilisateur {0} depuis salon textuel et vocal. + + + Utilisateur {0} depuis un salon vocal. + + + Vous avez été expulsé du serveur {0}. +Raison: {1} + + + Utilisateur débanni + + + Migration effectué! + + + Erreur lors de la migration, veuillez consulter la console pour plus d'informations. + + + Présences mises à jour. + + + Utilisateur expulsé. + + + a récompensé {0} pour {1} + + + Pari à pile ou face + + + Vous aurez plus de chance la prochaine fois ^_^ + + + Félicitations! Vous avez gagné {0} pour avoir lancé au dessus de {1} + + + Deck remélangé + + + Renversé {0} + User flipped tails. + + + Vous l'avez deviné! Vous avez gagné {0} + + + Nombre spécifié invalide. Vous pouvez lancer 1 à {0} pièces. + + + Ajoute {0} réaction à ce message pour avoir {1} + + + Cet événement est actif pendant {0} heures. + + + L'événement "réactions fleuries" a démaré! + + + a donné {0} à {1} + X has gifted 15 flowers to Y + + + {0} a {1} + X has Y flowers + + + Face + + + Classement + + + {1} utilisateurs du rôle {2} ont été récompensé de {0} + + + Vous ne pouvez pas miser plus de {0} + + + Vous ne pouvez pas parier moins de {0} + + + Vous n'avez pas assez de {0} + + + Plus de carte dans le deck. + + + Utilisateur tiré au sort + + + Vous êtes tombé {0} + + + Pari + + + WOAAHHHHHH!!! Félicitations!!! x{0} + + + Une simple {0}, x{1} + + + Wow! Quelle chance! Trois du même style! x{0} + + + Bon travail! Deux {0} - bet x{1} + + + Gagné + + + Les utilisateurs doivent écrire un code secret pour avoir {0}. Dure {1} secondes. Ne le dite à personne. Shhh. + + + L’événement "jeu sournois" s'est fini. {0} utilisateurs ont reçu la récompense. + + + L'événement "jeu sournois" a démarré + + + Pile + + + Vous avez pris {0} de {1} avec succès + + + Impossible de prendre {0} de {1} car l'utilisateur n'a pas assez de {2}! + + + Retour à la table des matières + + + Propriétaire du Bot seulement + + + Nécessite {0} permissions du salon + + + Vous pouvez supporter ce projet sur Patreon: <{0}> ou via Paypal <{1}> + + + Commandes et alias + + + Liste des commandes rafraîchie. + + + Écrivez `{0}h NomDeLaCommande` pour voir l'aide spécifique à cette commande. Ex: `{0}h >8ball` + + + Impossible de trouver cette commande. Veuillez vérifier qu'elle existe avant de réessayer. + + + Description + + + Vous pouvez supporter le projet NadekoBot +sur Patreon <{0}> +par Paypal <{1}> +N'oubliez pas de mettre votre nom discord ou ID dans le message. + +**Merci** ♥️ + + + **Liste des Commandes**: <{0}> +**La liste des guides et tous les documents peuvent être trouvés ici**: <{1}> + + + Liste Des Commandes + + + Liste Des Modules + + + Entrez `{0}cmds ModuleName` pour avoir la liste des commandes de ce module. ex `{0}cmds games` + + + Ce module n'existe pas. + + + Permission serveur {0} requise. + + + Table Des Matières + + + Usage + + + Autohentai commencé. Publie toutes les {0}s avec l'un des tags suivants : +{1} + + + Tag + + + Race Animale + + + Pas assez de participants pour commencer. + + + Suffisamment de participants ! La course commence. + + + {0} a rejoint sous la forme d'un {1} + + + {0} a rejoint sous la forme d'un {1} et mise sur {2} ! + + + Entrez {0}jr pour rejoindre la course. + + + Début dans 20 secondes ou quand le nombre maximum de participants est atteint. + + + Début avec {0} participants. + + + {0} sous la forme d'un {1} a gagné la course ! + + + {0} sous la forme d'un {1} a gagné la course et {2}! + + + Nombre spécifié invalide. Vous pouvez lancer de {0} à {1} dés à la fois. + + + tiré au sort {0} + Someone rolled 35 + + + Dé tiré au sort: {0} + Dice Rolled: 5 + + + Le lancement de la course a échoué. Une autre course doit probablement être en cours. + + + Aucune course existe sur ce serveur. + + + Le deuxième nombre doit être plus grand que le premier. + + + Changements de Coeur + + + Revendiquée par + + + Divorces + + + Aime + + + Prix + + + Aucune waifu n'a été revendiquée pour l'instant. + + + Top Waifus + + + votre affinité est déjà liée à ce waifu ou vous êtes en train de retirer votre affinité avec quelqu'un avec qui vous n'en posséder pas. + + + Affinités changées de de {0} à {1}. + +*C'est moralement questionnable* 🤔 + Make sure to get the formatting right, and leave the thinking emoji + + + Vous devez attendre {0} heures et {1} minutes avant de pouvoir changer de nouveau votre affinité. + + + Votre affinité a été réinitialisée. Vous n'avez désormais plus la personne que vous aimez. + + + veut être le waifu de {0}. Aww <3 + + + a revendiqué {0} comme son waifu pour {1} + + + Vous avez divorcé avec un waifu qui vous aimais. Monstre sans cœur. {0} a reçu {1} en guise de compensation. + + + vous ne pouvez pas vous lier d'affinité avec vous-même, espèce d'égocentrique. + + + 🎉Leur amour est comblé !🎉 +La nouvelle valeur de {0} est {1} ! + + + Aucune waifu n'est à ce prix. Tu dois payer au moins {0} pour avoir une waifu, même si sa vraie valeur est inférieure. + + + Tu dois payer {0} ou plus pour avoir cette waifu ! + + + Cette waifu ne t'appartient pas. + + + Tu ne peux pas t'acquérir toi-même. + + + Vous avez récemment divorcé. Vous devez attendre {0} heures et {1} minutes pour divorcer à nouveau. + + + Personne + + + Vous avez divorcé d'une waifu qui ne vous aimé pas. Vous recevez {0} en retour. + + + 8ball + + + Acrophobie + + + Le jeu a pris fin sans soumissions. + + + Personne n'a voté : la partie se termine sans vainqueur. + + + L'acronyme était {0}. + + + Une partie d'Acrophobia est déjà en cours sur ce salon. + + + La partie commence. Créez une phrase avec l'acronyme suivant : {0}. + + + Vous avez {0} secondes pour faire une soumission. + + + {0} a soumit sa phrase. ({1} au total) + + + Votez en entrant le numéro d'une soumission. + + + {0} a voté! + + + Le gagnant est {0} avec {1} points! + + + {0} est le gagnant pour être le seul utilisateur à avoir fait une soumission! + + + Question + + + Egalité ! Vous avez choisi {0}. + + + {0} a gagné ! {1} bat {2}. + + + Inscriptions terminées. + + + Une Course Animale est déjà en cours. + + + Total : {0} Moyenne : {1} + + + Catégorie + + + Cleverbot désactivé sur ce serveur. + + + Cleverbot activé sur ce serveur. + + + La génération actuelle a été désactivée sur ce salon. + + + La génération actuelle a été désactivée sur ce salon. + + + {0} {1} aléatoires sont apparus ! Attrapez-les en entrant `{2}pick` + plural + + + Un {1} aléatoire est apparu ! Attrapez-le en entrant `{1}pick` + + + Impossible de charger une question. + + + Jeu commencé. + + + Partie de pendu commencée. + + + Une partie de pendu est déjà en cours sur ce channel. + + + Initialisation du pendu erronée. + + + Liste des "{0}hangman" types de termes : + + + Classement + + + Vous n'avez pas assez de {0} + + + Pas de résultats + + + choisi {0} + Kwoth picked 5* + + + {0} a planté {1} + Kwoth planted 5* + + + Une partie de Trivia est déjà en cours sur ce serveur. + + + Partie de Trivia + + + {0} a deviné! La réponse était: {1} + + + Aucune partie de trivia en cours sur ce serveur. + + + {0} a {1} points + + + Le jeu s'arrêtera après cette question. + + + Le temps a expiré! La réponse était {0} + + + {0} a deviné la réponse et gagne la partie! La réponse était: {1} + + + Vous ne pouvez pas jouer contre vous-même. + + + Une partie de Morpion est déjà en cours sur ce salon. + + + Égalité! + + + a crée une partie de Morpion. + + + {0} a gagné ! + + + Trois alignés. + + + Aucun mouvement restant ! + + + Le temps a expiré ! + + + Tour de {0}. + + + {0} contre {1} + + + Tentative d'ajouter {0} à la file d'attente... + + + Lecture automatique désactivée + + + Lecture automatique activée + + + Volume de base mis à {0}% + + + File d'attente complète. + + + a tour de rôle + + + Musique finie + + + Système de tour de rôle désactivé. + + + Système de tour de rôle activé. + + + De la position + + + Id + + + Entrée invalide + + + Le temps maximum de lecture n'a désormais plus de limite. + + + Le temps de lecture maximum a été mis à {0} seconde(s). + + + La taille de la file d'attente est désormais illmitée. + + + La taille de la file d'attente est désormais de {0} piste(s). + + + Vous avez besoin d'être dans un salon vocal sur ce serveur. + + + Nom + + + Vous écoutez + + + Aucun lecteur de musique actif. + + + Pas de résultat + + + Musique mise sur pause. + + + Aucun lecteur de musique actif. + + + Liste d'attente - Page {0}/{1} + + + Lecture du son + + + #{0}` - **{1}** par *{2}* ({3} morceaux) + + + Page {0} des playlists sauvegardées + + + Playlist supprimée + + + Impossible de supprimer cette playlist. Soit elle n'existe pas, soit vous n'en êtes pas le créateur. + + + Aucune playlist avec cet ID existe. + + + File d'attente des playlists complète. + + + Playlist sauvegardée + + + Limite à {0}s + + + Liste d'attente + + + Musique ajoutée à la file d'attente + + + Liste d'attente effacée. + + + Liste d'attente complète ({0}/{0}) + + + Musique retirée + context: "removed song #5" + + + Répétition de la musique en cours + + + Playlist en boucle + + + Piste en boucle + + + La piste ne sera lue qu'une fois. + + + Reprise de la lecture. + + + Lecture en boucle désactivée. + + + Lecture en boucle activée. + + + Je vais désormais afficher les musiques en cours, en pause, terminées et supprimées sur ce salon. + + + Saut à `{0}:{1}` + + + Musiques mélangées. + + + Musiques déplacées. + + + {0}h {1}m {2}s + + + En position + + + Illimité + + + Le volume doit être compris entre 0 et 100 + + + Volume réglé sur {0}% + + + Désactivation de l'usage de TOUT LES MODULES pour le salon {0}. + + + Activation de l'usage de TOUT LES MODULES pour le salon {0}. + + + Permis + + + Désactivation de l'usage de TOUT LES MODULES pour le rôle {0}. + + + Activation de l'usage de TOUT LES MODULES pour le rôle {0}. + + + Désactivation de l'usage de TOUT LES MODULES sur ce serveur. + + + Activation de l'usage de TOUT LES MODULES sur ce serveur. + + + Désactivation de l'usage de TOUT LES MODULES pour l'utilisateur {0}. + + + Activation de l'usage de TOUT LES MODULES pour l'utilisateur {0}. + + + Banni {0} avec l'ID {1} + + + La commande {0} a désormais {1}s de temps de recharge. + + + La commande {0} n'a pas de temps de recharge et tout les temps de recharge ont été réinitialisés. + + + Aucune commande n'a de temps de recharge. + + + Coût de la commande : + + + Usage de {0} {1} désactivé sur le salon {2}. + + + Usage de {0} {1} activé sur le salon {2}. + + + Refusé + + + Ajout du mot {0} à la liste des mots filtrés. + + + Liste Des Mots Filtrés + + + Suppression du mot {0} à la liste des mots filtrés. + + + Second paramètre invalide. (nécessite un nombre entre {0} et {1}) + + + Filtrage des invitations désactivé sur ce salon. + + + Filtrage des invitations activé sur ce salon. + + + Filtrage des invitations désactivé sur le serveur. + + + Filtrage des invitations activé sur le serveur. + + + Permission {0} déplacée de #{1} à #{2} + + + Impossible de trouver la permission à l'index #{0} + + + Aucun coût défini. + + + Commande + Gen (of command) + + + Module + Gen. (of module) + + + Page {0} des permissions + + + Le rôle des permissions actuelles est {0}. + + + Il faut maintenant avoir le rôle {0} pour modifier les permissions. + + + Aucune permission trouvée à cet index. + + + Supression des permissions #{0} - {1} + + + Usage de {0} {1} désactivé pour le rôle {2}. + + + Usage de {0} {1} activé pour le rôle {2}. + + + sec. + Short of seconds. + + + Usage de {0} {1} désactivé pour le serveur. + + + Usage de {0} {1} activé pour le serveur. + + + Débanni {0} avec l'ID {1} + + + Non modifiable + + + Usage de {0} {1} désactivé pour l'utilisateur {2}. + + + Usage de {0} {1} activé pour l'utilisateur {2}. + + + Je n'afficherais plus les avertissements des permissions. + + + J'afficherais désormais les avertissements des permissions. + + + Filtrage des mots désactivé sur ce salon. + + + Filtrage des mots activé sur ce salon. + + + Filtrage des mots désactivé sur le serveur. + + + Filtrage des mots activé sur le serveur. + + + Capacités + + + Pas encore d'anime préféré + + + Traduction automatique des messages activée sur ce salon. Les messages utilisateurs vont désormais être supprimés. + + + Votre langue de traduction à été supprimée. + + + Votre langue de traduction a été changée de {from} à {to} + + + Traduction automatique des messages commencée sur ce salon. + + + Traduction automatique des messages arrêtée sur ce salon. + + + Le format est invalide ou une erreur s'est produite. + + + Impossible de trouver cette carte. + + + fait + + + Chapitre + + + Comic # + + + Parties compétitives perdues + + + Parties compétitives jouées + + + Rang en compétitif + + + Parties compétitives gagnées + + + Complété + + + Condition + + + Coût + + + Date + + + Defini: + + + En baisse + + + Episodes + + + Une erreur s'est produite. + + + Exemple + + + Impossible de trouver cet anime + + + Impossible de trouver ce manga + + + Genres + + + Impossible de trouver une définition pour cette citation. + + + Taille/Poid + + + {0}m/{1}kg + + + Humidité + + + Recherche d'images pour: + + + Impossible de trouver ce film. + + + Langue d'origine ou de destination invalide + + + Blagues non chargées. + + + Lat/Long + + + Niveau + + + Liste de {0} tags placés. + Don't translate {0}place + + + Emplacement + + + Les objets magiques ne sont pas chargés. + + + Profil MAL de {0} + + + Le propriétaire du Bot n'a pas spécifié de clé MashapeApi. Fonctionnalité non disponible + + + Min/Max + + + Aucun salon trouvé. + + + Aucun résultat trouvé. + + + En attente + + + Url original + + + Une clé osu!API est nécessaire + + + Impossible de récupérer la signature osu. + + + Trouvé dans {0} images. Affichage de {0} aléatoires. + + + Utilisateur non trouvé! Veuillez vérifier la région and le BattleTag avant de réessayer. + + + Prévision de lecture + + + Plateforme + + + Attaque non trouvée + + + Pokémon non trouvé. + + + Lien du profil : + + + Qualité + + + Durée en Jeux Rapides + + + Victoires Rapides + + + Évaluation + + + Score: + + + Chercher pour: + + + Impossible de réduire cette Url + + + Url réduite + + + Une erreur s'est produite. + + + Veuillez spécifier les paramètres de recherche. + + + Statut + + + Url stockée + + + Le streamer {0} est hors ligne. + + + Le streamer {0} est en ligne avec {1} spectateurs. + + + Vous suivez {0} streams sur ce serveur. + + + Vous ne suivez aucun stream sur ce serveur. + + + Aucune diffusion de ce nom. + + + Cette diffusion n'existe probablement pas. + + + Diffusion de {0} ({1}) retirée des notifications. + + + Je préviendrais ce salon lors d'un changement de statut. + + + Aube + + + Crépuscule + + + Température + + + Titre: + + + Top 3 anime favoris + + + Traduction: + + + Types + + + Impossible de trouver une définition pour ce terme. + + + Url + + + Spectateurs + + + Regardant + + + Impossible de trouver ce terme sur le wikia spécifié. + + + Entrez un wikia cible, suivi d'une requête de recherche + + + Page non trouvée + + + Vitesse du vent + + + Les {0} champions les plus bannis + + + Impossible de yodifier votre phrase. + + + Rejoint + + + `{0}.` {1} [{2:F2}/s] - {3} total + /s and total need to be localized to fit the context - +`1.` + + + Page d'Activité #{0} + + + {0} utilisateurs en total. + + + Créateur + + + ID du Bot + + + Liste des fonctions pour la commande {0}calc + + + {0} de ce salon est {1} + + + Sujet du salon + + + Commandes éxécutées + + + {0} {1} est équivalent à {2} {3} + + + Unités pouvant être converties : + + + Impossible de convertir {0} en {1}: unités non trouvées + + + Impossible de convertire {0} en {1} : les types des unités ne sont pas compatibles. + + + Créé le + + + Salon inter-serveur rejoint. + + + Salon inter-serveur quitté. + + + Voici votre jeton CSC + + + Emojis personnalisées + + + Erreur + + + Fonctionnalités + + + ID + + + Index hors limites. + + + Voici une liste des utilisateurs dans ces rôles : + + + Vous ne pouvez pas utiliser cette commande sur un rôle avec beaucoup d'utilisateurs afin d'éviter les abus. + + + Valeur {0} invalide. + Invalid months value/ Invalid hours value + + + Discord rejoint + + + Serveur rejoint + + + ID: {0} +Membres: {1} +OwnerID: {2} + + + Aucun serveur trouvée sur cette page. + + + Listes des rappels + + + Membres + + + Mémoire + + + Messages + + + Message de rappel + + + Nom + + + Pseudonyme + + + Personne ne joue à ce jeu. + + + Aucun rappel actif. + + + Aucun rôle sur cette page. + + + Aucun shard sur cette page. + Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. + + + Aucun sujet choisi. + + + Propriétaire + + + ID des propriétaires + + + Présence + + + {0} Serveurs +{1} Salons Textuels +{2} Salons Vocaux + + + Toutes les citations possédant le mot-clé {0} ont été supprimées + + + Page {0} des citations + + + Aucune citation sur cette page. + + + Aucune citation que vous puissiez supprimer n'a été trouvé. + + + Citation ajoutée + + + Une citation aléatoire a été supprimée. + + + Région + + + Inscrit sur + + + Je vais vous rappeler {0} pour {1} dans {2} `({3:d.M.yyyy} à {4:HH:mm})` + + + Format de date non valide. Regardez la liste des commandes. + + + Nouveau modèle de rappel en service. + + + Répétition de {0} chaque {1} jour(s), {2} heure(s) et {3} minute(s) + + + Liste des Rappels + + + Aucun rappel actif sur ce serveur. + + + #{0} arrêté. + + + Pas de message de rappel trouvé sur ce serveur. + + + Résultat + + + Rôles + + + Page #{0} de tout les rôles sur ce serveur. + + + Page #{0} des rôles pour {1} + + + Aucunes couleurs sont dans le format correct. Utilisez `#00ff00` par exemple. + + + Couleurs alternées pour le rôle {0} activées. + + + Couleurs alternées pour le rôle {0} arrêtées + + + {0} de ce serveur est {1} + + + Info du serveur + + + Shard + Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. + + + Statistique de Shard + Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. + + + Le shard **#{0}** est en {1} état avec {2} serveurs + Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. + + + **Nom:** {0} **Lien:** {1} + + + Pas d'emojis spéciaux trouvés. + + + Joue actuellement {0} musiques, {1} en attente. + + + Salons textuels + + + Voici le lien pour votre chambre: + + + Durée de fonctionnement + + + {0} de l'utilisateur {1} est {2} + Id of the user kwoth#1234 is 123123123123 + + + Utilisateurs + + + Salons vocaux + + + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 8dd225d1..5485e9ef 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -755,7 +755,7 @@ Reason: {1} __IgnoredChannels__: {2} - Text Channel Destroyed + Text Channel Created Text Channel Destroyed @@ -1401,9 +1401,6 @@ Don't forget to leave your discord name or id in the message. Music playback paused. - - No music player active. - Player Queue - Page {0}/{1} @@ -1757,7 +1754,7 @@ Don't forget to leave your discord name or id in the message. Invalid source or target language. - Joes not loaded. + Jokes not loaded. Lat/Long From 500e128d425a80b99062c1224d4ec16eaed8fc04 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 28 Feb 2017 10:35:36 +0100 Subject: [PATCH 360/746] voicepresence fix --- src/NadekoBot/Modules/Administration/Commands/LogCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index f431caad..f061f045 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -529,7 +529,7 @@ namespace NadekoBot.Modules.Administration else if (afterVch == null) { str = "🎙" + Format.Code(prettyCurrentTime) + logChannel.Guild.GetLogText("user_vleft", - "👤" + Format.Code(prettyCurrentTime), "👤" + Format.Bold(usr.Username + "#" + usr.Discriminator), + "👤" + Format.Bold(usr.Username + "#" + usr.Discriminator), Format.Bold(beforeVch.Name ?? "")); } if (str != null) From 868c5e648732cec23145d8a8377d1a92c0538194 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 28 Feb 2017 14:13:50 +0100 Subject: [PATCH 361/746] Update ResponseStrings.fr-fr.resx (POEditor.com) --- .../Resources/ResponseStrings.fr-fr.resx | 407 +++++++++--------- 1 file changed, 202 insertions(+), 205 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx index 68602a62..5f7a188e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx +++ b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Cette base a déjà été revendiquée ou détruite @@ -136,7 +136,7 @@ {0} a revendiqué une base #{1} dans une guerre contre {2} - @{0} Vous avez déjà revendiqué la base {1}. Vous ne pouvez pas en revendiquer une nouvelle. + @{0} Vous avez déjà revendiqué la base #{1}. Vous ne pouvez pas en revendiquer une nouvelle. La demande de la part de @{0} pour une guerre contre {1} a expiré. @@ -178,7 +178,7 @@ La guerre contre {0} commence! - La guerre contre {0} a fini. + La guerre contre {0} est terminée. Cette guerre n'existe pas. @@ -252,7 +252,7 @@ Vous ne pouvez pas vous attaquer vous-même. - {0} s'est évanoui. + {0} s'est évanoui! Vous avez soigné {0} avec un {1} @@ -261,7 +261,7 @@ {0} a {1} points de vie restants. - Vous ne pouvez pas utiliser {0}. Ecrivez `{1}ml` pour voir la liste de toutes les actions que vous pouvez effectuer. + Vous ne pouvez pas utiliser {0}. Ecrivez `{1}ml` pour voir la liste des actions que vous pouvez effectuer. Liste des attaques pour le type {0} @@ -313,7 +313,7 @@ Vous avez été banni du serveur {0}. -Raison : {1} +Raison: {1} banni @@ -398,7 +398,7 @@ Raison : {1} Nouveau donateur ajouté avec succès. Montant total des dons de cet utilisateur : {0} 👑 - Merci aux personnes ci-dessous pour avoir permis à ce projet d'exister. + Merci aux personnes ci-dessous pour avoir permis à ce projet d'exister! Je transmettrai désormais les MPs à tous les propriétaires. @@ -407,31 +407,31 @@ Raison : {1} Je transmettrai désormais les MPs seulement au propriétaire principal. - Je vous transmettrai désormais les MPs. + Je transmettrai désormais les MPs. - Je ne vous transmettrez désormais plus les MPs. + Je ne transmettrai désormais plus les MPs. - Suppression automatique des messages d'accueil a été désactivé. + La suppression automatique des messages d'accueil a été désactivé. Les messages d'accueil seront supprimés après {0} secondes. - Message privé de bienvenue actuel: {0} + MP de bienvenue actuel: {0} - Activez les messages de bienvenue privés en écrivant {0} + Activez les MPs de bienvenue en écrivant {0} - Nouveau message de bienvenue privé en service. + Nouveau MP de bienvenue en service. - Messages de bienvenue privés désactivés. + MPs de bienvenue désactivés. - Messages de bienvenue privés activés. + MPs de bienvenue activés. Message de bienvenue actuel: {0} @@ -544,7 +544,7 @@ Raison : {1} singular "User muted." - Il semblerait que vous n'ayez pas la permission nécessaire pour effectuer cela. + Il semblerait que je n'ai pas la permission nécessaire pour effectuer cela. Nouveau rôle de mise en sourdine crée. @@ -611,7 +611,7 @@ Raison : {1} Le temps doit être compris entre {0} et {1} secondes. - Vous avez retirés tout les rôles de l'utilisateur {0} avec succès + Vous avez retirés tous les rôles de l'utilisateur {0} avec succès Impossible de retirer des rôles. Je n'ai pas les permissions suffisantes. @@ -690,7 +690,7 @@ Raison : {1} Vous ne possédez pas le rôle {0}. - L'affection automatique des rôles n'est désormais plus exclusive! + L'affectation automatique des rôles n'est désormais plus exclusive! Je suis incapable de vous ajouter ce rôle. `Je ne peux pas ajouter de rôles aux propriétaires et aux autres rôles plus haut que le mien dans la hiérarchie.` @@ -711,7 +711,7 @@ Raison : {1} Impossible d'ajouter un rôle. Je ne possède pas les permissions suffisantes. - Nouvel avatar défini. + Nouvel avatar défini! Nouveau nom de Salon défini avec succès. @@ -746,7 +746,7 @@ Raison : {1} Mode ralenti activé - expulsion + expulsés (kick) PLURAL @@ -785,25 +785,25 @@ Raison : {1} Utilisateur banni - {0} a été **mis en sourdine** sur le tchat. + {0} a été **mis en sourdine** sur le chat. - **La parole a été rétablie** sur le tchat pour {0} + **La parole a été rétablie** sur le chat pour {0} - L'utilisateur a rejoins + L'utilisateur a rejoint - L'utilisateur a quité + L'utilisateur a quitté - {0} a été **mis en sourdine** à la fois sur le salon textuel et vocal. + {0} a été **mis en sourdine** à la fois sur le salon textuel et vocal. Rôle ajouté à l'utilisateur - Rôle enlevé de l'utilisateur + Rôle retiré de l'utilisateur {0} est maintenant {1} @@ -876,13 +876,13 @@ Raison: {1} Utilisateur expulsé. - a récompensé {0} pour {1} + a récompensé {0} à {1} Pari à pile ou face - Vous aurez plus de chance la prochaine fois ^_^ + Meilleure chance la prochaine fois ^_^ Félicitations! Vous avez gagné {0} pour avoir lancé au dessus de {1} @@ -891,7 +891,7 @@ Raison: {1} Deck remélangé - Renversé {0} + Lancé {0} User flipped tails. @@ -942,10 +942,10 @@ Raison: {1} Utilisateur tiré au sort - Vous êtes tombé {0} + Vous avez roulé un {0} - Pari + Mise WOAAHHHHHH!!! Félicitations!!! x{0} @@ -954,10 +954,10 @@ Raison: {1} Une simple {0}, x{1} - Wow! Quelle chance! Trois du même style! x{0} + Wow! Quelle chance! Trois du même genre! x{0} - Bon travail! Deux {0} - bet x{1} + Bon travail! Deux {0} - mise x{1} Gagné @@ -1026,7 +1026,7 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Liste Des Modules - Entrez `{0}cmds ModuleName` pour avoir la liste des commandes de ce module. ex `{0}cmds games` + Entrez `{0}cmds NomDuModule` pour avoir la liste des commandes de ce module. ex `{0}cmds games` Ce module n'existe pas. @@ -1048,7 +1048,7 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Tag - Race Animale + Course d'animaux Pas assez de participants pour commencer. @@ -1092,7 +1092,7 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Le lancement de la course a échoué. Une autre course doit probablement être en cours. - Aucune course existe sur ce serveur. + Aucune course n'existe sur ce serveur. Le deuxième nombre doit être plus grand que le premier. @@ -1119,7 +1119,7 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Top Waifus - votre affinité est déjà liée à ce waifu ou vous êtes en train de retirer votre affinité avec quelqu'un avec qui vous n'en posséder pas. + votre affinité est déjà liée à cette waifu ou vous êtes en train de retirer votre affinité avec quelqu'un avec qui vous n'en posséder pas. Affinités changées de de {0} à {1}. @@ -1134,13 +1134,13 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Votre affinité a été réinitialisée. Vous n'avez désormais plus la personne que vous aimez. - veut être le waifu de {0}. Aww <3 + veut être la waifu de {0}. Aww <3 - a revendiqué {0} comme son waifu pour {1} + a revendiqué {0} comme sa waifu pour {1} - Vous avez divorcé avec un waifu qui vous aimais. Monstre sans cœur. {0} a reçu {1} en guise de compensation. + Vous avez divorcé avec une waifu qui vous aimais. Monstre sans cœur. {0} a reçu {1} en guise de compensation. vous ne pouvez pas vous lier d'affinité avec vous-même, espèce d'égocentrique. @@ -1168,7 +1168,7 @@ La nouvelle valeur de {0} est {1} ! Personne - Vous avez divorcé d'une waifu qui ne vous aimé pas. Vous recevez {0} en retour. + Vous avez divorcé d'une waifu qui ne vous aimait pas. Vous recevez {0} en retour. 8ball @@ -1222,7 +1222,7 @@ La nouvelle valeur de {0} est {1} ! Inscriptions terminées. - Une Course Animale est déjà en cours. + Une Course d'animaux est déjà en cours. Total : {0} Moyenne : {1} @@ -1259,7 +1259,7 @@ La nouvelle valeur de {0} est {1} ! Partie de pendu commencée. - Une partie de pendu est déjà en cours sur ce channel. + Une partie de pendu est déjà en cours sur ce canal Initialisation du pendu erronée. @@ -1348,16 +1348,16 @@ La nouvelle valeur de {0} est {1} ! Lecture automatique activée - Volume de base mis à {0}% + Volume de base défini à {0}% File d'attente complète. - a tour de rôle + à tour de rôle - Musique finie + Musique terminée Système de tour de rôle désactivé. @@ -1404,9 +1404,6 @@ La nouvelle valeur de {0} est {1} ! Musique mise sur pause. - - Aucun lecteur de musique actif. - Liste d'attente - Page {0}/{1} @@ -1417,22 +1414,22 @@ La nouvelle valeur de {0} est {1} ! #{0}` - **{1}** par *{2}* ({3} morceaux) - Page {0} des playlists sauvegardées + Page {0} des listes de lecture sauvegardées - Playlist supprimée + Liste de lecture supprimée - Impossible de supprimer cette playlist. Soit elle n'existe pas, soit vous n'en êtes pas le créateur. + Impossible de supprimer cette liste de lecture. Soit elle n'existe pas, soit vous n'en êtes pas le créateur. - Aucune playlist avec cet ID existe. + Aucune liste de lecture avec cet ID existe. - File d'attente des playlists complète. + File d'attente de la liste complétée. - Playlist sauvegardée + Liste de lecture sauvegardée Limite à {0}s @@ -1457,7 +1454,7 @@ La nouvelle valeur de {0} est {1} ! Répétition de la musique en cours - Playlist en boucle + Liste de lecture en boucle Piste en boucle @@ -1484,7 +1481,7 @@ La nouvelle valeur de {0} est {1} ! Musiques mélangées. - Musiques déplacées. + Musique déplacée. {0}h {1}m {2}s @@ -1502,31 +1499,31 @@ La nouvelle valeur de {0} est {1} ! Volume réglé sur {0}% - Désactivation de l'usage de TOUT LES MODULES pour le salon {0}. + Désactivation de l'usage de TOUS LES MODULES pour le salon {0}. - Activation de l'usage de TOUT LES MODULES pour le salon {0}. + Activation de l'usage de TOUS LES MODULES pour le salon {0}. Permis - Désactivation de l'usage de TOUT LES MODULES pour le rôle {0}. + Désactivation de l'usage de TOUS LES MODULES pour le rôle {0}. - Activation de l'usage de TOUT LES MODULES pour le rôle {0}. + Activation de l'usage de TOUS LES MODULES pour le rôle {0}. - Désactivation de l'usage de TOUT LES MODULES sur ce serveur. + Désactivation de l'usage de TOUS LES MODULES sur ce serveur. - Activation de l'usage de TOUT LES MODULES sur ce serveur. + Activation de l'usage de TOUS LES MODULES sur ce serveur. - Désactivation de l'usage de TOUT LES MODULES pour l'utilisateur {0}. + Désactivation de l'usage de TOUS LES MODULES pour l'utilisateur {0}. - Activation de l'usage de TOUT LES MODULES pour l'utilisateur {0}. + Activation de l'usage de TOUS LES MODULES pour l'utilisateur {0}. Banni {0} avec l'ID {1} @@ -1559,7 +1556,7 @@ La nouvelle valeur de {0} est {1} ! Liste Des Mots Filtrés - Suppression du mot {0} à la liste des mots filtrés. + Suppression du mot {0} de la liste des mots filtrés. Second paramètre invalide. (nécessite un nombre entre {0} et {1}) @@ -1637,10 +1634,10 @@ La nouvelle valeur de {0} est {1} ! Usage de {0} {1} activé pour l'utilisateur {2}. - Je n'afficherais plus les avertissements des permissions. + Je n'afficherai plus les avertissements des permissions. - J'afficherais désormais les avertissements des permissions. + J'afficherai désormais les avertissements des permissions. Filtrage des mots désactivé sur ce salon. @@ -1685,10 +1682,10 @@ La nouvelle valeur de {0} est {1} ! fait - Chapitre + Chapitres - Comic # + Bande dessinée # Parties compétitives perdues @@ -1715,7 +1712,7 @@ La nouvelle valeur de {0} est {1} ! Date - Defini: + Définis: En baisse @@ -1739,7 +1736,7 @@ La nouvelle valeur de {0} est {1} ! Genres - Impossible de trouver une définition pour cette citation. + Impossible de trouver une définition pour ce hashtag. Taille/Poid @@ -1797,7 +1794,7 @@ La nouvelle valeur de {0} est {1} ! En attente - Url original + Url originale Une clé osu!API est nécessaire @@ -1809,7 +1806,7 @@ La nouvelle valeur de {0} est {1} ! Trouvé dans {0} images. Affichage de {0} aléatoires. - Utilisateur non trouvé! Veuillez vérifier la région and le BattleTag avant de réessayer. + Utilisateur non trouvé! Veuillez vérifier la région ainsi que le BattleTag avant de réessayer. Prévision de lecture @@ -1875,13 +1872,13 @@ La nouvelle valeur de {0} est {1} ! Vous ne suivez aucun stream sur ce serveur. - Aucune diffusion de ce nom. + Aucun stream de ce nom. - Cette diffusion n'existe probablement pas. + Ce stream n'existe probablement pas. - Diffusion de {0} ({1}) retirée des notifications. + Stream de {0} ({1}) retirée des notifications. Je préviendrais ce salon lors d'un changement de statut. @@ -1967,7 +1964,7 @@ La nouvelle valeur de {0} est {1} ! Sujet du salon - Commandes éxécutées + Commandes exécutées {0} {1} est équivalent à {2} {3} @@ -1979,7 +1976,7 @@ La nouvelle valeur de {0} est {1} ! Impossible de convertir {0} en {1}: unités non trouvées - Impossible de convertire {0} en {1} : les types des unités ne sont pas compatibles. + Impossible de convertir {0} en {1} : les types des unités ne sont pas compatibles. Créé le @@ -2000,7 +1997,7 @@ La nouvelle valeur de {0} est {1} ! Erreur - Fonctionnalités + Fonctionnalités ID @@ -2012,7 +2009,7 @@ La nouvelle valeur de {0} est {1} ! Voici une liste des utilisateurs dans ces rôles : - Vous ne pouvez pas utiliser cette commande sur un rôle avec beaucoup d'utilisateurs afin d'éviter les abus. + Vous ne pouvez pas utiliser cette commande sur un rôle incluant beaucoup d'utilisateurs afin d'éviter les abus. Valeur {0} invalide. @@ -2033,7 +2030,7 @@ OwnerID: {2} Aucun serveur trouvée sur cette page. - Listes des rappels + Liste des messages répétés Membres @@ -2045,7 +2042,7 @@ OwnerID: {2} Messages - Message de rappel + Répéteur de messages Nom @@ -2057,7 +2054,7 @@ OwnerID: {2} Personne ne joue à ce jeu. - Aucun rappel actif. + Aucune répétition active. Aucun rôle sur cette page. @@ -2120,16 +2117,16 @@ OwnerID: {2} Répétition de {0} chaque {1} jour(s), {2} heure(s) et {3} minute(s) - Liste des Rappels + Liste des répétitions - Aucun rappel actif sur ce serveur. + Aucune répétition active sur ce serveur. #{0} arrêté. - Pas de message de rappel trouvé sur ce serveur. + Pas de message répété trouvé sur ce serveur. Résultat @@ -2144,7 +2141,7 @@ OwnerID: {2} Page #{0} des rôles pour {1} - Aucunes couleurs sont dans le format correct. Utilisez `#00ff00` par exemple. + Aucunes couleurs ne sont dans le format correct. Utilisez `#00ff00` par exemple. Couleurs alternées pour le rôle {0} activées. @@ -2183,7 +2180,7 @@ OwnerID: {2} Salons textuels - Voici le lien pour votre chambre: + Voici le lien pour votre salon: Durée de fonctionnement From 98484b84e5cb79cc716da9e47756aba5daffb54f Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 28 Feb 2017 14:25:57 +0100 Subject: [PATCH 362/746] Update ResponseStrings.fr-fr.resx (POEditor.com) From d58ebd100f8b74802ee3cf6db292dde86c0c5067 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 28 Feb 2017 14:42:26 +0100 Subject: [PATCH 363/746] Fixed ~ani and ~mang, searches might be off for some time --- .../Searches/Commands/AnimeSearchCommands.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs index 9fdf07f0..3fcfb654 100644 --- a/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/AnimeSearchCommands.cs @@ -30,17 +30,19 @@ namespace NadekoBot.Modules.Searches { try { - var headers = new Dictionary { - {"grant_type", "client_credentials"}, - {"client_id", "kwoth-w0ki9"}, - {"client_secret", "Qd6j4FIAi1ZK6Pc7N7V4Z"}, - }; + var headers = new Dictionary + { + {"grant_type", "client_credentials"}, + {"client_id", "kwoth-w0ki9"}, + {"client_secret", "Qd6j4FIAi1ZK6Pc7N7V4Z"}, + }; using (var http = new HttpClient()) { - http.AddFakeHeaders(); + //http.AddFakeHeaders(); + http.DefaultRequestHeaders.Clear(); var formContent = new FormUrlEncodedContent(headers); - var response = await http.PostAsync("http://anilist.co/api/auth/access_token", formContent).ConfigureAwait(false); + var response = await http.PostAsync("https://anilist.co/api/auth/access_token", formContent).ConfigureAwait(false); var stringContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); anilistToken = JObject.Parse(stringContent)["access_token"].ToString(); } From f3e019ca6cac9eeddbab23c413adde012ff23e06 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 28 Feb 2017 21:43:56 +0100 Subject: [PATCH 364/746] Added german, fixed some strings --- .../Resources/ResponseStrings.Designer.cs | 14 +- .../Resources/ResponseStrings.de-DE.resx | 2190 +++++++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 14 +- 3 files changed, 2204 insertions(+), 14 deletions(-) create mode 100644 src/NadekoBot/Resources/ResponseStrings.de-DE.resx diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 3d80c3c9..49072329 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -594,7 +594,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Bot's language is set to {0} - {0}. + /// Looks up a localized string similar to Bot's language is set to {0} - {1}. /// public static string administration_lang_set_bot_show { get { @@ -612,7 +612,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to This server's language is set to {0} - {0}. + /// Looks up a localized string similar to This server's language is set to {0} - {1}. /// public static string administration_lang_set_show { get { @@ -1650,7 +1650,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Voice Channel Destroyed. + /// Looks up a localized string similar to Voice Channel Created. /// public static string administration_voice_chan_created { get { @@ -2235,7 +2235,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Invalid number specified. You can roll up to {0}-{1} dice at a time.. + /// Looks up a localized string similar to Invalid number specified. You can roll {0}-{1} dice at once.. /// public static string gambling_dice_invalid_number { get { @@ -4902,7 +4902,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Lsit of {0}place tags. + /// Looks up a localized string similar to List of {0}place tags. /// public static string searches_list_of_place_tags { get { @@ -5001,7 +5001,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Failed retreiving osu signature.. + /// Looks up a localized string similar to Failed retrieving osu! signature.. /// public static string searches_osu_failed { get { @@ -5995,7 +5995,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Page #{0} of roels for {1}. + /// Looks up a localized string similar to Page #{0} of roles for {1}. /// public static string utility_roles_page { get { diff --git a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx new file mode 100644 index 00000000..9aac2f85 --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx @@ -0,0 +1,2190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Diese Basis wurde bereits beansprucht oder zerstört. + + + Diese Basis ist bereits zertört. + + + Diese Basis ist nicht beansprucht. + + + Basis #{0} im Krieg gegen {1} **ZERSTÖRT** + + + {0} hat die Basis #{1} **UNBEANSPRUCHT** im Krieg gegen {2} + + + {0} hat die Basis #{1} beansprucht im Krieg gegen {2} + + + @{0} sie haben die Basis #{1} bereits beansprucht. Sie können keine weitere beanspruchen. + + + Einnahme von @{0} für den Krieg gegen {1} ist abgelaufen. + + + Gegner + + + informationen über den Krieg mit {0} + + + Ungültige Basisnummer. + + + Keine gültige Kriegsgröße. + + + Liste der aktiven Kriege + + + nicht beansprucht + + + Sie nehmen nicht an diesem Krieg teil. + + + @{0} Sie nehmen nicht an diesem Krieg teil, oder diese Basis ist bereits zerstört. + + + Keine aktiven Kriege. + + + Größe + + + Krieg gegen {0} wurde schon gestartet. + + + Krieg gegen {0} erstellt. + + + Krieg gegen {0} ist beendet. + + + Dieser Krieg existiert nicht. + + + Krieg gegen {0} gestartet! + + + Reaktionsstatistiken gelöscht. + + + Benutzerdefinierte Reaktion gelöscht. + + + Unzureichende Rechte. Dies erfordert das sie den Bot besitzen für globale Reaktionen, und Administratorrechte für serverseitige Reaktionen. + + + Liste aller benutzerdefinierten Reaktionen. + + + Benutzerdefinierte Reaktionen + + + Neue benutzerdefinierte Reaktion + + + Keine benutzerdefinierten Reaktionen gefunden. + + + Keine benutzerdefinierte Reaktion mit dieser ID gefunden. + + + Antwort + + + Reaktionsstatistiken + + + Statistiken für die Reaktion {0} gelöscht. + + + Keine Statistiken für diesen Auslöser gefunden, keine Aktion unternommen. + + + Auslöser + + + Autohentai angehalten. + + + Keine Ergebnisse gefunden. + + + {0} ist bereits ohnmächtig. + + + {0} hat bereits volle LP. + + + Dein Typ ist bereits {0} + + + benutzt {0}{1} auf {2}{3} für {4} Schaden. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + Sie können ohne Gegenangriff nicht erneut angreifen! + + + Sie können sich nicht selber angreifen. + + + {0} wurde ohnmächtig! + + + heilte {0} mit einem {0} + + + {0} hat {1} LP übrig. + + + Sie können {0} nicht benutzen. Schreibe `{1}ml` um eine Liste deiner verfügbaren Angriffe zu sehen. + + + Angriffsliste für den Typ {0} + + + Das ist nicht sehr effektiv. + + + Sie haben nicht genug {0} + + + belebte {0} wieder mit einem {1} + + + Sie haben sich selbst wiederbelebt mit einem {0} + + + Dein Typ wurde verändert von {0} mit einem {1} + + + Das ist effektiv. + + + Das ist sehr effektiv! + + + Sie haben zu viele Angriffe hintereinander eingesetzt, sodass sie sich nicht bewegen können! + + + Typ von {0} ist {1} + + + Benutzer nicht gefunden. + + + Sie sind ohnmächtig, daher können sie sich nicht bewegen! + + + **Automatische Rollenzuteilung** wenn ein Benutzer beitritt ist nun **deaktiviert**. + + + **Automatische Rollenzuteilung** wenn ein Benutzer beitritt ist nun **aktiviert**. + + + Anhänge + + + Avatar varändert + + + Sie wurden vom Server {0} gebannt. +Grund: {1} + + + gebannt + PLURAL + + + Benutzer gebannt + + + Name des Bots geändert zu {0} + + + Status des Bots geändert zu {0} + + + Automatisches Löschen von Abschiedsnachrichten ist nun deaktiviert. + + + Abschiedsnachrichten werden nun nach {0} Sekunden gelöscht. + + + Aktuelle Abschiedsnachricht: {0} + + + Schalte Abschiedsnachrichten ein durch schreiben von {0} + + + Neues Abschiedsnachrichtenset. + + + Abschiedsnachrichten deaktiviert. + + + Abschiedsnachrichten eingeschaltet in diesem Kanal. + + + Kanalname geändert + + + Alter Name + + + Kanalthema geändert + + + Aufgeräumt. + + + Inhalt + + + Rolle {0} erfolgreich erstellt + + + Textkanal {0} erstellt. + + + Sprachkanal {0} erstellt. + + + Taubschaltung erfolgreich. + + + Server {0} gelöscht + + + Automatisches Löschen von erfolgreichen Befehlsausführungen gestoppt. + + + Automatisches Löschen von erfolgreichen Befehlsausführungen gestartet. + + + Textkanal {0} gelöscht. + + + Sprachkanal {0} gelöscht. + + + DN von + + + Erfolgreich einen neuen Spender hinzugefügt. Gesamte Spendenmenge von diesem Benutzer: {0} 👑 + + + Danke für die untenstehenden Leute die dieses Projekt möglich gemacht haben! + + + Ich werde DNs zu allen Besitzern weiterleiten. + + + Ich werde DNs zum ersten Besitzer weiterleiten. + + + Ich werde nun DNs weiterleiten. + + + Ich werde aufhören DNs weiterzuleiten. + + + Automatisches löschen der Begrüßungsnachrichten wurde deaktiviert. + + + Begrüßungsnachrichten werden gelöscht nach {0} sekunden. + + + Aktuelle DN Begrüßungsnachricht: {0} + + + Aktiviere DN Begrüßungsnachrichten durch schreiben von: {0} + + + Neue DN Begrüßungsnachricht wurde gesetzt. + + + Begrüßungsankündigungen wurden deaktiviert. + + + DN Begrüßungsankündigungen wurden aktiviert. + + + Aktuelle Begrüßungsnachricht: {0} + + + Aktiviere Begrüßungsnachrichten durch schreiben von: {0} + + + Neue Begrüßungsnachricht wurde gesetzt. + + + Begrüßungsankündigungen wurden deaktiviert. + + + Begrüßungsankündigungen wurden für diesen Kanal aktiviert. + + + Sie können diesen befehl nicht an Benutzern mit einer Rolle über oder gleich zu ihrer in der Rangordnung benutzen. + + + Bilder wurden geladen nach {0} sekunden! + + + Ungültiges Eingabeformat. + + + Ungültige Übergabevariable. + + + {0} ist {1} beigetreten + + + Sie haben {0} von dem Server gekickt. +Grund: {1} + + + Benutzer wurde gekickt + + + Liste der Sprachen +{0} + + + Ihr Servers Sprachumgebung ist jetzt {1} - {1} + + + Der Bots standard Sprachumgebung ist jetzt {0} - {1} + + + Die Sprache des Bots ist {0} - {1} + + + Setzen der Sprachumgebung fehlgeschlagen. Greifen sie auf diesen Befehls hilfe erneut auf. + + + Dieser Servers Sprache wurde zu {0} - {1} gesetzt + + + {0} verließ {1} + + + Server {0} wurde verlassen + + + Ereignis {0} wird in diesem Kanal aufgezeichnet. + + + Alle Ereignise wird in diesem Kanal aufgezeichnet. + + + Aufzeichnungen wurden deaktiviert. + + + Aufzeichnungs Ereignise die sie abonnieren können: + + + Aufzeichnungen werden {0} ignorieren + + + Aufzeichnungen werden {0} nicht ignorieren + + + Aufzeichnung von Ereignis {0} gestoppt. + + + {0} hat eine Erwähnung von den folgended Rollen aufgerufen + + + nachricht von {0} `[Besitzer des Bots]`: + + + Nachricht gesendet. + + + {0} wurde von {1} zu {2} verschoben + + + Nachricht in #{0} gelöscht + + + Nachricht in #{0} aktualisiert + + + wurden Stumm geschalten + PLURAL (users have been muted) + + + wurde Stumm geschalten + singular "User muted." + + + Ich habe wahrscheinlich die benötigten Rechte für dies nicht. + + + Neue Stumme Rolle gesetzt. + + + Ich brauche **Administrations** rechte um dies tun zu können. + + + Neue Nachricht + + + Neuer Nickname + + + Neues Thema + + + Nickname wurde geändert + + + Konnte den Server nicht finden + + + Kein Shard mit dieser ID gefunden. + + + Alte Nachricht + + + Alter Nickname + + + Altes Thema + + + Fehler. Ich habe wahrscheinlich nicht ausreichend Rechte. + + + Rechte für diesen Server zurückgesetzt. + + + Aktive Schutzmechanismen + + + {0} wurde auf diesem Server **deaktiviert**. + + + {0} aktiviert + + + Fehler. Ich benötige die Berechtigung RollenVerwalten + + + Keine Schutzmechanismen aktiviert. + + + Benutzerschwelle muss zwischen {0} und {1} sein. + + + Wenn {0} oder mehr Benutzer innerhalb von {1} Sekunden beitreten werde ich sie {2}. + + + Zeit muss zwischen {0} und {1} sekunden sein. + + + Erfolgreich alle Rollen vom Benutzer {0} entfernt + + + Rollen konnten nicht entfernt werden. Ich habe nicht die erforderlichen Rechte. + + + Farbe der Rolle {0} wurde geändert. + + + Diese Rolle existiert nicht. + + + Die angegebenen Parameter sind ungültig. + + + Fehler ist aufgetreten aufgrund von einer ungültigen Farbe oder fehlenden Rechten. + + + Erfolgreich die Rolle {0} vom Benutzer {1} entfernt + + + Entfernen der Rolle fehlgeschlagen. Ich habe nicht die erforderlichen Rechte. + + + Rolle umbenannt. + + + Umbenennen der Rolle fehlgeschlagen. Ich habe nicht die erforderlichen Rechte. + + + Sie kännen keine Rollen bearbeiten die höher als ihre eigenen sind. + + + Die Abspielnachricht wurde entfernt: {0} + + + Die Rolle {0} wurde zur Liste hinzugefügt. + + + {0} nicht gefunden. Aufgeräumt. + + + Die Rolle {0} ist bereits in der Liste. + + + Hinzugefügt. + + + Rotation des Spielstatus deaktiviert. + + + Rotation des Spielstatus aktiviert. + + + Hier ist die Liste der rotierenden Status: +{0} + + + Keine rotierenden Status gesetzt. + + + Sie haben bereits die Rolle {0}. + + + Sie haben bereits die exklusive, selbstzugewiesene Rolle {0}. + + + Selbstzuweisbare Rollen sind nun exklusiv! + + + Es gibt {0} selbstzuweisbare Rollen + + + Diese Rolle ist nicht selbstzuweisbar. + + + Sie haben die Rolle {0} nicht. + + + Selbstzuweisbare Rollen sind nicht länger exklusiv! + + + Ich kann dir diese Rolle nicht zuweisen. `Ich kann keine Rollen zu Besitzern oder andere Rollen die höher als meine in der Rangordnung sind hinzufügen.` + + + {0} wurde von der Liste der selbstzuweisbaren Rollen entfernt. + + + Sie haben nicht länger die Rolle {0}. + + + Sie haben nun die Rolle {0}. + + + Erfolgreich die Rolle {0} zum Benutzer {1} hinzugefügt + + + Fehlgeschlagen die Rolle hinzuzufügen. Ich habe nicht die erforderlichen Rechte. + + + Neuer Avatar gesetzt! + + + Neuer Kanalname gesetzt. + + + Neues Spiel gesetzt! + + + Neuer Stream gesetzt! + + + Neues Kanalthema gesetzt. + + + Verbindung zu Shard {0} wiederhergestellt. + + + Verbindung zu Shard {0} wird wiederhergestellt. + + + Fahre herunter + + + Benutzer können nicht mehr als {0} Nachrichten alle {1} Sekunden senden. + + + Slow mode deaktiviert. + + + Slow mode eingeleitet + + + soft-banned (gekickt) + PLURAL + + + {0} wird diesen Kanal ignorieren. + + + {0} wird diesen Kanal nicht mehr ignorieren. + + + Wenn ein Benutzer {0} gleiche Nachrichten sendet werde ich ihn {1}. +__ignoredChannels__: {2} + + + Textkanal erstellt + + + Textkanal zerstört + + + Taubschaltung aufgehoben. + + + Stummschaltung aufgehoben + singular + + + Benutzername + + + Benutzername geändert + + + Benutzer + + + Benutzer gebannt + + + {0} wurde **stummgeschaltet** im Chat. + + + {0} ist nicht länger **stummgeschaltet** im Chat. + + + Benutzer ist beigetreten + + + Benutzer ist gegangen + + + {0} wurde **stummgeschaltet** im Text- und Sprachchat. + + + Benutzerrolle hinzugefügt + + + Benutzerrolle entfernt + + + {0} ist nun {1} + + + {0} ist nicht länger **stummgeschaltet** im Text- und Sprachchat. + + + {0} ist dem Sprachkanal {1} beigetreten. + + + {0} hat den Sprachkanal {1} verlassen. + + + {0} ging vom Sprachkanal {1} zu {2}. + + + {0} wurde **stummgeschaltet** im Sprachchat. + + + {0} ist nicht länger **stummgeschaltet** im Sprachchat. + + + Sprachkanal erstellt + Should say "Voice Channel Created" + + + Sprachkanal zerstört + + + Text- und Sprachfunktion deaktiviert. + + + Text- und Sprachfunktion aktiviert. + + + Ich habe keine **Rollenmanagement**- und/oder **Kanalmanagement**-Rechte, sodass ich `voice+text` auf dem Server {0} nicht ausführen kann. + + + Sie schalten diese Funktion ein bzw. aus und **ich habe keine ADMINISTRATORRECHTE**. Dies könnte einige Probleme hervorrufen, sodass sie ihre Textkanäle eventuell selber aufräumen musst. + + + Ich benötige zumindest **Rollenmanagement**- und **Kanalmanagement**-Rechte um diese Funktion einzuschalten. (Bevorzugt Administratorrechte) + + + Benutzer {0} vom Textchat + + + Benutzer {0} vom Text- und Sprachchat + + + Benutzer {0} vom Sprachchat + + + Sie wurden vom Server {0} gekickt. +Grund: {1} + + + Benutzer entbannt + + + Migration fertig! + + + Fehler beim migrieren von Daten. Prüfe die Konsole des Bots für mehr Informationen. + + + Anwesenheits Änderungen + + + Nutzer wurde gekickt + + + verleiht {1} {0} + + + Münzwurf-Glücksspiel + + + Hoffentlich haben sie beim nächsten Mal mehr Glück ^_^ + + + Glückwunsch! Sie haben {0} gewonnen, weil sie über {1} gewürfelt haben + + + Deck neu gemischt. + + + Münzwurfergebnis: {0}. + User flipped tails. + + + Sie haben es erraten! Sie haben {0} gewonnen + + + Ungültige Anzahl angegeben. Sie können 1 bis {0} Münzen werfen. + + + Füge die {0} Reaktion zu dieser Nachricht hinzu um {1} zu erhalten + + + Dieses Ereignis ist aktiv für bis zu {0} Stunden. + + + Blumen-Reaktions-Ereignis gestartet + + + hat {0} an {1} verschenkt + X has gifted 15 flowers to Y + + + {0} hat eine {1} + X has Y flowers + + + Kopf + + + Bestenliste + + + {0} zu {1} Benutzern der Rolle {2} verliehen. + + + Sie können nicht mehr als {0} wetten + + + Sie können nicht weniger als {0} wetten + + + Sie haben nicht genug {0} + + + Keine Karten mehr im Deck. + + + Ausgewählter Benutzer + + + Sie haben eine {0} gewürfelt. + + + Wette + + + WOAAHHHHHH!!! Glückwunsch!!! x{0} + + + Eine einzelne {0}, x{1} + + + Wow! Glückspilz! Ein Drilling! x{0} + + + Gut gemacht! Zwei {0} - Einsatz x{1} + + + Gewonnen + + + Benutzer müssen einen geheimen Code schreiben um {0} zu erhalten. Gültig für {1} Sekunden. Erzähls niemanden. Pshhh. + + + Das SneakyGame-Event ist beendet. {0} Nutzer haben die Belohnung erhalten + + + SneakyGameStatus-Event wurde gestartet + + + Zahl + + + hat erfolgreich {0} von {1} genommen + + + war es nicht möglich {0} von {1} zu nehmen, da der Benutzer nicht so viele {2} besitzt! + + + Zurück zu ToC + + + Nur Bot-Besitzer + + + Benötigt Kanalrecht {0}. + + + Sie können das Projekt auf Patreon: <{0}> oder Paypal: <{1}> unterstützen. + + + Befehle und Alias + + + Befehlsliste neu generiert. + + + Gebe `{0}h NameDesBefehls` ein, um die Hilfestellung für diesen Befehl zu sehen. Z.B. `{0}h >8ball` + + + Ich konnte diesen Befehl nicht finden. Bitte stelle sicher das dieser Befehl existiert bevor sie es erneut versuchen. + + + Beschreibung + + + Sie können das NadekoBot-Projekt über +Patreon <{0}> oder +PayPal <{1}> unterstützen. +Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu hinterlassen. + +**Vielen Dank**♥️ + + + **Liste der Befehle**: <{0}> +**Hosting Anleitungen und Dokumentationen können hier gefunden werden**: <{1}> + + + Lister der Befehle + + + Liste der Module + + + Schreibe `{0}cmds ModuleName` um eine Liste aller Befehle dieses Moduls zu erhalten. z.B. `{0}cmds games` + + + Dieses Modul existiert nicht. + + + Benötigt Serverrecht {0}. + + + Inhaltsverzeichnis + + + Nutzung + + + Autohentai wurde gestartet. Es wird alle {0} Sekunden etwas mit einem der folgenden Stichwörtern gepostet: {1} + + + Stichwort + + + Tierrennen + + + Das Rennen konnte nicht gestartet werden, da es nicht genügend Teilnehmer gibt. + + + Rennen ist voll! Startet sofort. + + + {0} tritt als {1} bei + + + {0} tritt als {1} bei und wettete {2}! + + + Schreibe {0}jr um dem Rennen beizutreten. + + + Starte in 20 Sekunden oder wenn der Raum voll ist. + + + Starte mit {0} Teilnehmern. + + + {0} hat als {1} das Rennen gewonnen! + + + {0} hat als {1} das Rennen und {2} gewonnen! + + + Ungültige Anzahl angegeben. Sie können {0}-{1} Würfel gleichzeitig Rollen. + + + würfelte {0} + Someone rolled 35 + + + Würfel gerollt: {0} + Dice Rolled: 5 + + + Das Rennen konnte nicht gestartet werden. Ein anderes Rennen läuft wahrscheinlich. + + + Es gibt kein Rennen auf diesem Server + + + Die zweite Zahl muss größer als die erste sein. + + + Sinneswandel + + + Beansprucht von + + + Scheidungen + + + Positive Bewertungen + + + Preis + + + Keine Waifus wurden bisher beansprucht. + + + Top Waifus + + + Ihre Neigung ist bereits zu dieser Waifu gesetzt oder sie versuchsen ihre Neigung zu entfernen während sie keine gesetzt haben. + + + hat seine Neigung von {0} zu {1} geändert. + +*Das ist moralisch nicht vertretbar.*🤔 + Make sure to get the formatting right, and leave the thinking emoji + + + Sie müssen {0} Stunden und {1} Minuten warten bevor sie ihre Neigung ändern können. + + + Ihre Neigung wurde zurückgesetzt. Sie haben keine Person mehr die sie mögen. + + + will {0}s Waifu sein. Aww <3 + + + hat {0} als seine/ihre Waifu für {1} beansprucht! + + + Sie haben sich von ihrer Waifu die sie mochte scheiden lassen. Du herzloses Monster. {0} hat {1} als Kompensation erhalten. + + + Sie können deine Neigung nicht zu ihnen selbst setzen, sie egomanische Person. + + + 🎉 Ihre Liebe ist besiegelt! 🎉 +{0}'s neuer Wert ist {1}! + + + Keine Waifu ist so billig. Sie müssen wenigstens {0} bezahlen um diese Waifu zu beanspruchen, selbst wenn ihr tatsächlicher Wert geringer ist. + + + Sie müssen {0} oder mehr bezahlen um diese Waifu zu beanspruchen! + + + Diese Waifu gehört nicht dir. + + + Sie können sich nicht selbst beanspruchen. + + + Sie haben sich vor kurzem scheiden lassen. Sie müssen {0} Stunden und {1} Minuten warten bevor sie sich erneut scheiden lassen können. + + + Niemand + + + Sie haben sich von einer Waifu scheiden lassen die sie nicht mochte, Du erhältst {0} zurück. + + + 8ball + + + Acrophobie + + + Spiel wurde beendet ohne Einsendungen. + + + Keine Stimmen abgegeben. Spiel endete ohne Gewinner. + + + Das Acronym war {0}. + + + Akrophobia läuft bereits in diesem Kanal. + + + Spiel gestartet. Erstelle einen Satz aus dem folgenden Akronym. + + + Sie haben {0} Sekunden für ihre Einsendung. + + + {0} hat seinen Satz eingereicht. ({1} insgesamt) + + + Stimme ab indem du die Nummer der Einsendung eingibst + + + {0} hat seine/ihre Stimme abgegeben! + + + Der Gewinner ist {0} mit {1} Punkten. + + + {0} gewinnt, weil dieser Benutzer die einzigste Einsendung hat! + + + Frage + + + Unentschieden! Beide haben {0} gewählt + + + {0} hat gewonnen! {1} schlägt {2} + + + Einsendungen geschlossen + + + Tierrennen läuft bereits. + + + Insgesamt: {0} Durchschnitt: {1} + + + Kategorie + + + Cleverbot auf diesem Server deaktiviert. + + + Cleverbot auf diesem Server aktiviert. + + + Währungsgeneration in diesem Kanal deaktiviert. + + + Währungsgeneration in diesem Kanal aktiviert. + + + {0} zufällige {1} sind erschienen! Sammle sie indem sie `{2}pick` schreiben. + plural + + + Eine zufällige {0} ist erschienen! Sammle sie indem sie `{1}pick` schreiben. + + + Laden einer Frage fehlgeschlagen. + + + Spiel gestartet + + + Hangman-Spiel gestartet + + + Hangman-Spiel läuft bereits in diesem Kanal. + + + Starten von Hangman hat einen Fehler ausgelöst. + + + Liste der "{0}hangman" Worttypen: + + + Bestenliste + + + Sie haben nicht genug {0} + + + Keine Ergebnisse + + + {0} aufgehoben + Kwoth picked 5* + + + {0} pflanzte {1} + Kwoth planted 5* + + + Ein Trivia Spiel läuft schon auf diesem Server + + + Trivia Spiel + + + {0} erriet es! Die Antwort war: {1} + + + Kein aktives Trivia Spiel auf diesem Server. + + + {0} hat {1} punkte + + + Wird beendet after dieser Frage. + + + Die Zeit is um! Die richtige Antwort war {0} + + + {0} erriet es und hat das spiel GEWONNEN! Die Antwort war: {1} + + + Sie können nicht gegen sich selber spielen. + + + Ein TicTacToe Spiel läuft schon in diesem Kanal. + + + Unentschieden! + + + hat ein TicTacToe Spiel erstellt. + + + {0} hat gewonnen! + + + Drei in einer Reihe + + + Keine Züge übrig + + + Zeit abgelaufen + + + {0}'s Zug + + + {0} gegen {1} + + + Versuche {0} Songs einzureihen... + + + Autoplay deaktiviert. + + + Autoplay aktiviert. + + + Standard-Lautstärke auf {0}% gesetzt + + + Ordner-Einreihung fertig. + + + fairer Modus + + + Song beendet + + + Fairer Modus deaktiviert. + + + Fairer Modus aktiviert. + + + Von Position + + + ID + + + Ungültige Eingabe. + + + Maximale Spielzeit hat kein Limit mehr + + + Maximale Spielzeit ist nun {0} Sekunden + + + Maximale Musik-Warteschlangengröße ist nun unbegrenzt. + + + Maximale Musik-Warteschlangengröße ist nun {0} Songs. + + + Sie müssen sich in einem Sprachkanal auf diesem Server befinden. + + + Name + + + Aktueller Song: + + + Kein aktiver Musikspieler. + + + Keine Suchergebnisse. + + + Musikwiedergabe pausiert. + + + Musik-Warteschlange - Seite {0}/{1} + + + Spiele Song + + + `#{0}` - **{1}** by *{2}* ({3} Songs) + + + Seite {0} der gespeicherten Playlists + + + Playlist gelöscht. + + + Playlist konnte nicht gelöscht werden. Entweder sie existiert nicht oder sie gehört nicht dir. + + + Es gibt keine Playlist mit dieser ID. + + + Playlist wurde an die Warteschlange angehängt. + + + Playlist gespeichert + + + {0}'s Limit + + + Warteschlange + + + Eingereihter Song + + + Musik-Warteschlange geleert + + + Warteschlange ist voll bei {0}/{1} + + + Song entfernt + context: "removed song #5" + + + Aktueller Song wird wiederholt + + + Playlist wird wiederholt + + + Song wird wiederholt + + + Aktueller Song wird nicht mehr wiederholt. + + + Musikwiedergabe wiederaufgenommen + + + Playlist-Wiederholung deaktiviert. + + + Playlist-Wiederholung aktiviert. + + + Ich werde nun spielende, beendete, pausierte und entfernte Songs in diesen Channel ausgeben. + + + Gesprungen zu `{0}:{1}` + + + Song gemischt + + + Song bewegt + + + {0}h {1}m {2}s + + + Zu Position + + + unbegrenzt + + + Lautstärke muss zwischen 0 und 100 sein + + + Lautstärke auf {0}% gesetzt + + + Benutzung ALLER MODULE für Kanal {0} verboten. + + + Benutzung ALLER MODULE für Kanal {0} erlaubt. + + + Erlaubt + + + Benutzung ALLER MODULE für die Rolle {0} verboten. + + + Benutzung ALLER MODULE für die Rolle {0} erlaubt. + + + Benutzung ALLER MODULE für diesen Server verboten. + + + Benutzung ALLER MODULE für diesen Server erlaubt. + + + Benutzung ALLER MODULE für den Benutzer {0} verboten. + + + Benutzung ALLER MODULE für den Benutzer {0} erlaubt. + + + {0} mit ID {1} wurde zur Sperrliste hinzugefügt + + + Befehl {0} hat nun {1}s Abklingzeit + + + Befehl {0} hat keine Abklingzeit mehr und alle laufenden Abklingzeiten wurden entfernt. + + + Keine Befehls Abklingzeiten gesetzt. + + + Preis für Befehle + + + Benutzung von {0} {1} wurde für Kanal {2} verboten. + + + Benutzung von {0} {1} wurde für Kanal {2} erlaubt. + + + Verweigert + + + Wort {0} zu der Liste der gefilterten Wörter hinzugefügt. + + + Liste der gefilterten Wörter + + + Wort {0} von der Liste der gefilterten Wörter entfernt. + + + Ungültiger zweiter Parameter. (Muss eine Nummer zwischen {0} und {1} sein) + + + Filterung von Einladungen auf diesem Kanal deaktiviert. + + + Filterung von Einladungen auf diesem Kanal aktiviert. + + + Filterung von Einladungen auf diesem Server deaktiviert. + + + Filterung von Einladungen auf diesem Server aktiviert. + + + Berechtigung {0} von #{1} zu #{2} gesetzt + + + Konnte Berechting an Index #{0} nicht finden + + + Kein Preis gesetzt. + + + Befehl + Gen (of command) + + + Modul + Gen. (of module) + + + Berechtigungen Seite {0} + + + Aktuelle Berechtigungsrolle ist {0}. + + + Benutzer brauchen nun Rolle {0} um die Berechtigungen zu editieren. + + + Keine Berechtigung für diesen Index gefunden + + + Berechtigung #{0} - {1} entfernt + + + Benutzung von {0} {1} wurde für Rolle {2} verboten. + + + Benutzung von {0} {1} wurde für Rolle {2} erlaubt. + + + sek. + Short of seconds. + + + Benutzung von {0} {1} wurde für diesen Server verboten + + + Benutzung von {0} {1} wurde für diesen Server erlaubt. + + + {0} mit ID {1} von Sperrliste entfernt + + + Nicht Bearbeitbar + + + Benutzung von {0} {1} wurde für Benutzer {2} verboten. + + + Benutzung von {0} {1} wurde für Benutzer {2} erlaubt. + + + Ich werde nicht mehr Warnungen für Rechte anzeigen. + + + Ich werde jetzt Warnungen für Rechte anzeigen. + + + Filterung für Wörter in diesem Kanal deaktiviert. + + + Filterung für Wörter in diesem Kanal aktiviert. + + + Filterung für Wörter auf diesem Server deaktiviert. + + + Filterung für Wörter auf diesem Server aktiviert. + + + Fähigkeiten + + + Keine favoritisierten anime + + + Startete die Automatische Übersetzung der Nachrichten auf diesem kanal. Nachrichten von Benutzern werden automatisch gelöscht. + + + Ihre Automatische-Übersetzungs Sprache wurde entfernt. + + + Ihre Automatische-Übersetzungs Sprache wurde zu {from}>{to} gesetzt. + + + Automatische Übersetzung der Nachrichten wurde auf diesem kanal gestartet. + + + Automatische Übersetzung der Nachrichten wurde auf diesem kanal gestoppt. + + + Schlechter Eingabeformat, oder etwas lief schief. + + + Konnte diese Karte nicht finden + + + fakt + + + Kapitel + + + Comic # + + + Verlorene Competitives + + + Gespielte Competitives + + + Competitive Rang + + + Gewonnene Competitives + + + Beendet + + + Kondition + + + Kosten + + + Datum + + + Definiere: + + + Abgebrochen + + + Episoden + + + Ein fehler ist aufgetreten. + + + Beispiel + + + Konnte diesen animu nicht finden. + + + Konnte diesen mango nicht finden. + + + Genres + + + Konnte keine definition für dieses Stichwort finden. + + + Höhe/Gewicht + + + {0}m/{1]kg + + + Feuchtigkeit + + + Bildersuche für: + + + Konnte diesen Film nicht finden. + + + Ungültige Quell- oder Zielsprache, + + + Witze nicht geladen. + + + Lat/long + + + Level + + + Liste der "{0}place" Stichwörtern + Don't translate {0}place + + + Standort + + + Magic Items nicht geladen. + + + {0}s MAL Profil + + + Der Besitzer des Bots hat keinen MashapeApi-Schlüssel angegeben. Sie können diese Funktion nicht benutzen. + + + Min/Max + + + Keine Kanäle gefunden. + + + Keine Ergebnisse gefunden. + + + Pausierte + + + Ursprüngliche Url + + + Ein osu! API-Schlüssel wird benötigt. + + + osu! Signatur konnte nicht geholt werden. + + + Über {0} Bilder gefunden. Zeige zufälliges {0}. + + + Benutzer nicht gefunden! Bitte überprüfe die Region und den BattleTag before erneuten versuchen. + + + Vermerkte + + + Platform + + + Keine Fähigkeit gefunden. + + + Kein pokemon gefunden. + + + Profil Link: + + + Qualität + + + Quick Spielzeit + + + Gewonnene Quicks + + + Bewertung + + + Punktzahl: + + + Suche nach: + + + Url konnte nicht gekürzt werden + + + Kurze Url + + + Etwas lief schief. + + + Bitte spezifizieren sie die Such Parameter. + + + Status + + + Geschäfts Url + + + Streamer {0} ist jetzt offline. + + + Streamer {0} ist online mit {1} Zuschauern. + + + Sie folgen {0} Streamer auf diesem Server. + + + Sie folgen keinem Streamer auf diesem Server. + + + Diesen Stream gibt es nicht. + + + Stream existiert wahrscheinlich nicht. + + + {0}s Stream ({1}) von den Benachrichtigungen entfernt. + + + Ich werde diesen Kanal benachrichtigen wenn der Status sich verändert. + + + Sonnenaufgang + + + Sonnenuntergang + + + Temperature + + + Titel: + + + Top 3 Lieblingsanime: + + + Übersetzung: + + + Typen + + + Die definition für den Begriff konnte nicht gefunden werden. + + + Url + + + Zuschauer + + + Am schauen + + + Der Begriff konnte auf dem spezifizierten wikia nicht gefunden werden. + + + Bitte geben sie ein Ziel wikia ein, gefolgt bei der Suchanfrage. + + + Seite konnte nicht gefunden werden. + + + Wind Geschwindigkeit + + + Die {0} meist gebannten Champions + + + Ihre Nachricht konnte nicht yodifiziert werden. + + + Beigetreten + + + `{0}.` {1} [{2:F2}/s] - {3} total + /s and total need to be localized to fit the context - +`1.` + + + Aktivitäten Liste #{0} + + + {0} totale Benutzer. + + + Autor(in) + + + ID des Bots + + + Liste der Funktionen im {0}calc Befehl + + + {0} dieses Kanals ist {1} + + + Thema des Kanals + + + Befehl ausgeführt + + + {0} {1} ist gleich zu {2} {3} + + + Einhetein die von dem Konvertierer benutzt werden können + + + Kann {0} nicht zu {1} konvertieren: Einheiten nicht gefunden + + + Kann {0} nicht zu {1} konvertieren: Einheiten sind nicht gleich + + + Erstellt am + + + Betritt Multi-Server-Kanal. + + + Verließ Multi-Server-Kanal. + + + Dies ist ihr MSK token + + + Benutzerdefinierte Emojis + + + Fehler + + + Funktionalitäten + + + ID + + + Index außer Reichweite. + + + Hier ist eine Liste mit Nutzern in diesen Rollen: + + + Sie haben keine Berechtigung diesen Befehl auf Rollen mit vielen Nutzern zu benutzen um Missbrauch zu verhindern. + + + Ungültiger {0} Wert. + Invalid months value/ Invalid hours value + + + Discord beigetreten + + + Server beigetreten + + + ID: {0} +Mitglieder: {1} +ID des Besitzers: {2} + + + Keine Server auf dieser Seite gefunden. + + + Liste der Wiederholer + + + Mitglieder + + + Speicher + + + Nachrichten + + + Nachrichten Wiederholer + + + Name + + + Nickname + + + Niemand spielt dieses Spiel. + + + Keine aktiven Wiederholer + + + Keine Rollen auf dieser Seite. + + + Keine Shards auf dieser Seite. + + + Kein Thema gesetzt. + + + Besitzer + + + IDs der Besitzer + + + Anwesenheit + + + {0} Server +{1} Text Kanäle +{2} Sprach Kanäle + + + Alle Zitate mit dem Stichwort {0} wurden gelöscht. + + + Seite {0} der Zitate + + + Keine Zitate auf dieser Seite. + + + Kein Zitat das sie entfernen können gefunden. + + + Zitat hinzugefügt + + + Zufälliger Zitat wurde gelöscht. + + + Region + + + Registriert an + + + Ich werde {0} erinnern {1} in {2} `({3:d.M.yyyy.} um {4:HH:mm})` zu tun. + + + Kein gültiges Zeitformat. Überprüfe die Befehlsliste. + + + Neue Erinnerungs Vorlage wurde gesetzt. + + + {0} wird jede {1} Tag(e), {2}stunde(n) und {3} minute(n) wiederholt. + + + Liste der Wiederholungen + + + Auf diesem Server laufen keine Wiederholer. + + + #{0} wurde gestoppt. + + + Auf diesem Server wurden keine wiederholende Nachrichten gefunden. + + + Resultat + + + Rollen + + + Seite #{0} aller Rollen für diesen Server: + + + Seite #{0} der Rollen für {1} + + + Keine Farben sind in dem Richtigen Format. Benutze zum Beispiel `#00ff00`. + + + Startete die Farbrotation für Rolle {0} + + + Stoppte die Farbrotation für Rolle {0} + + + {0} dieses Servers ist {1} + + + Server Info + + + Shard + + + Shard Statistiken + + + Shard **#{0}** ist im {1} status mit {2} Servern + + + **Name:** {0} **Link:** {1} + + + Keine speziellen emoji gefunden. + + + Wiedergabe von {0} Liedern, {1} in der Musikliste. + + + Text Kanäle + + + Hier ist ihr Raum link + + + Betriebszeit + + + {0} von Benutzer {1} ist {2} + Id of the user kwoth#1234 is 123123123123 + + + Benutzer + + + Sprach Kanäle + + + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 5485e9ef..3dfd8571 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -480,13 +480,13 @@ Reason: {1} Bot's default locale is now {0} - {1} - Bot's language is set to {0} - {0} + Bot's language is set to {0} - {1} Failed setting locale. Revisit this command's help. - This server's language is set to {0} - {0} + This server's language is set to {0} - {1} {0} has left {1} @@ -822,7 +822,7 @@ Reason: {1} {0} has been **voice unmuted**. - Voice Channel Destroyed + Voice Channel Created Voice Channel Destroyed @@ -1074,7 +1074,7 @@ Don't forget to leave your discord name or id in the message. {0} as {1} Won the race and {2}! - Invalid number specified. You can roll up to {0}-{1} dice at a time. + Invalid number specified. You can roll {0}-{1} dice at once. rolled {0} @@ -1763,7 +1763,7 @@ Don't forget to leave your discord name or id in the message. Level - Lsit of {0}place tags + List of {0}place tags Don't translate {0}place @@ -1797,7 +1797,7 @@ Don't forget to leave your discord name or id in the message. An osu! API key is required. - Failed retreiving osu signature. + Failed retrieving osu! signature. Found over {0} images. Showing random {0}. @@ -2134,7 +2134,7 @@ OwnerID: {2} Page #{0} of all roles on this server: - Page #{0} of roels for {1} + Page #{0} of roles for {1} No colors are in the correct format. Use `#00ff00` for example. From 31974baa13dffd9c5ae206d0a343c9db6903de26 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 28 Feb 2017 21:46:06 +0100 Subject: [PATCH 365/746] added russian --- .../Resources/ResponseStrings.ru-RU.resx | 2195 +++++++++++++++++ 1 file changed, 2195 insertions(+) create mode 100644 src/NadekoBot/Resources/ResponseStrings.ru-RU.resx diff --git a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx new file mode 100644 index 00000000..f6729bb5 --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx @@ -0,0 +1,2195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + Враг + + + Информация о войне против {0} + + + + + + + + + Список активных войн + + + + + + + + + + + + + + + Размер + + + + + + Война против {0} была создана. + Fuzzy + + + Закончилась война против {0}. + + + Эта война не существует. + + + + + + Вся статистика настраиваемых реакций стёрта. + + + Настраиваемая реакция удалена. + Fuzzy + + + Недостаточно прав. Необходимо владеть Бот-ом для глобальных настраиваемых реакций или быть Администратором для реакций по серверу. + Fuzzy + + + Список всех настраиваемых реакций. + Fuzzy + + + Настроить реакции. + Fuzzy + + + Создана новая реакция. + Fuzzy + + + + + + + + + Ответ + + + + + + + + + + + + Активатор + + + Авто-хентай остановлен :( + + + Запрос не найден. + + + {0} уже потерял сознание. + + + {0} уже имеет полное здоровье. + + + Ваш тип уже {0} + + + использовал {0}{1} против {2}{3} и нанёс {4} урона. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + Нельзя атаковать два раза подряд. + + + Нельзя атаковать самого себя. + + + {0} потерял сознание! + + + вылечил {0}, использовав {1} + + + У {0} осталось {1} здоровья. + + + Вы не можете использовать {0}. Напишите '{1}ml', чтобы увидеть список доступных Вам приёмов. + + + Список приёмов {0} типа + + + Эта атака не эффективна. + + + У вас не достаточно {0} + + + воскресил {0}, использовав один {1} + + + Вы воскресили себя, использовав один {0} + + + Ваш тип изменён с {0} на {1} + + + Эта атака немного эффективна. + + + Эта атака очень эффективна! + + + Вы использовали слишком много приёмов подряд и не можете двигаться! + + + Тип {0} — {1} + + + Пользователь не найден. + + + Вы не можете использовать приёмы потому-что ваш покемон потерял сознание! + + + ***Авто выдача роли*** каждому новому пользователю **отключена** + + + ***Авто выдача роли*** каждому новому пользователю **включена** + + + Приложения + + + Аватар изменён + + + Вас забанили с сервера {0}. Причина бана: {1}. + + + забанены + PLURAL + + + Пользователь забанен. + + + Имя Бот-а сменено на {0} + + + Статус Бот-а сменён на {0} + + + Автоматическое удаление прощальных сообщений отключено. + + + Прощальные сообщения будут удаляться через {0} секунд. + + + Текущее прощальное сообщение: {0} + + + Чтобы включить прощальные сообщения введите {0} + + + Установлено новое прощальное сообщение. + + + Прощальные сообщения выключены. + + + Прощальные сообщения включены на этом канале. + + + Имя канал изменено. + + + Старое имя. + + + Тема канала сменена. + + + + + + + + + Успешно создана роль {0}. + + + Создан текстовый канал {0}. + + + Создан голосовой канал {0}. + + + Успешное оглушение. + Fuzzy + + + Сервер {0} удален. + + + Отключено автоматическое удаление успешно выполненных команд. + + + Включено автоматическое удаление успешно выполненных команд. + + + Удалён текстовый канал {0}. + + + Удален голосовой канал {0}. + + + ПМ от + + + Успешно добавлен новый донатор. Общее количество пожертвований от этого пользователя: {0} 👑 + Fuzzy + + + Спасибо всем, указанным ниже, что помогли этому проекту! + + + Я буду перенаправлять личные сообщения всем владельцам. + + + Я буду перенаправлять личные сообщения только первому владельцу. + + + Я буду перенаправлять личные сообщения. + + + Я прекращаю перенаправление личных сообщений. + + + Автоматическое удаление приветственных сообщений выключено. + + + Приветственные сообщения будут удаляться через {0} секунд. + + + Приветствие, используемое в настоящий момент: {0} + + + Чтобы включить приветствия, напишите {0} + + + Новое приветствие установлено. + + + Приветствия в личных сообщениях отключены. + + + Приветствия в личных сообщениях включены. + + + Текущее привественное сообщение: {0} + + + Чтобы включить привественные сообщения введите {0} + + + Установлено новое приветствие. + + + Привественные сообщения выключены. + + + Привественные сообщения включены на этом канале. + + + Вы не можете использовать эту команду на пользователях равным или более высоким в иерархии ролей. + + + Картинки загружены за {0} секунд! + + + Неправильный формат ввода. + + + Неправильные параметры. + + + {0} присоединился к {1} + + + Вы были выгнаны с сервера {0}. +По причине: {1} + + + Пользователь выгнан + + + Список языков +{0} + + + Язык вашего сервера теперь {0} - {1} + + + Язык Бот-а по умолчанию теперь {0} - {1} + + + Язык Бот-а теперь установлен как {0} - {1} + + + Не удалось выставить язык. Проверьте справку к этой команде. + + + Язык этого сервера теперь установлен как {00} - {1} + + + {0} покинул {1} + + + Покинул сервер {0} + + + В этом канале регистрируется событие {0}. + + + В этом канале регистрируются все события. + + + Регистрация событий отключена. + + + Регистрируйте события, на которые Вы можете подписаться: + + + Регистрация будет пропускать {0}. + + + Регистрация не будет пропускать {0}. + + + Прекращена регистрация события {0}. + + + {0} вызвал оповещение для следующих ролей + + + Сообщение от {0} '[Владелец бота]': + + + Сообщение отправлено. + + + {0} перемещён из {1} в {2} + + + Сообщение удалено в #{0} + + + Сообщение изменено в #{0} + + + Заглушёны + PLURAL (users have been muted) + + + Заглушён + singular "User muted." + + + Скорее всего, у меня нет необходимых прав. + + + Новая немая роль установлена. + Fuzzy + + + Мне нужно право **Администратор**, чтобы это сделать. + Fuzzy + + + Новое сообщение + + + Новое имя + + + Новый заголовок + + + Имя изменено + + + Сервер не найден + + + Не найдено Shard-а с таким ID. + + + Старое сообщение + + + Старое имя + + + Старый заголовок + + + Ошибка. Скорее всего мне не хватает прав. + + + Права для этого сервера + + + + + + {0} был **отключён** на этом сервере. + + + {0} влючён + + + Ошибка. Требуется право на управление ролями. + + + + + + Порог пользователей должен лежать между {0} и {1}. + + + Если {0} или больше пользователей присоединяются в течение {1} секунд, Я {2} их. + + + Время должно быть между {0} и {1} секунд. + + + Успешно убраны все роли пользователя {0}. + + + Не удалось убрать роли. Отсутвуют требуемые разрешения. + + + Цвет роли {0} был изменён. + + + Данная роль не существует. + + + Заданные параметры недействительны. + + + Возникла ошибка из-за недействительного цвета или недостаточных разрешений. + + + Успешно убрана роль {0} пользователя {1}. + + + Не удалось убрать роль. Отсутвуют требуемые разрешения. + + + Роль переименована. + + + Не получилось переименовать роль. У меня недостаточно прав. + + + Вы не можете редактировать роли, находящиеся выше чем ваша роль. + + + + + + Роль {0} добавлена в лист. + + + + + + Роль {0} уже есть в списке. + + + Добавлено. + + + + + + + + + + + + + + + У вас уже есть роль {0} + + + У Вас уже есть исключающая самоназначенная роль {0}. + + + Самоназначенные роли теперь взаимоисключающие! + + + Существует {0} самоназначенных ролей + + + Эта роль не является самоназначаемой. + + + У вас отсуствует роль {0} + + + Самоназначенные роли теперь не взаимоисключающие! + + + Не удалось добавить Вам эту роль. 'Нельзя добавлять роли владельцам или другим ролям, находящимся выше моей роли в ролевой иерархии' + + + {0} убрана из списка самоназначенных ролей. + + + У вас больше нету роли {0} + + + Теперь у вас есть роль {0} + + + Успешно добавлена роль {0} пользователю {1} + + + Не удалось добавить роль. Нет достаточных разрешений. + + + Новый аватар установлен! + + + Новое имя канала установлено. + + + Новая игра установлена! + + + Новый стрим установлен! + + + Новая тема канала установлена. + + + Shard {0} переподключён. + + + Shard {0} переподключается. + + + Выключение + + + Пользователи не могут посылать более {0} сообщений в {1} секунд. + + + Медленный режим выключен. + + + Медленный режим включен. + + + + PLURAL + + + {0} будет игнорировать данный канал. + + + {0} не будет игнорировать данный канал. + + + Если пользователь пишет {0} одинаковых сообщений подряд, я {} их. __Игнорируемые каналы__: {2} + + + Создан текстовый канал + + + Уничтожен текстовый канал. + + + Отключено заглушение. + + + + singular + + + Имя + + + Имя изменено + + + Пользователи + + + Пользователь заблокирован + + + + + + + + + Пользователь присоединился + + + Пользователь вышел + + + + + + Добавлена роль пользователя + + + Удалена роль пользователя + + + {0} теперь {1} + + + + + + {0} присоединился к голосовому каналу {1}. + + + {0} покинул голосовой канал {1}. + + + {0} переместил {1} в голосовой канал {2}. + + + + + + + + + Голосовой канал удалён + Fuzzy + + + Голосовой канал удалён + + + + + + + + + Нет разрешений **Управление ролями** и/или **Управление каналами**, поэтому нельзя использовать команду 'voice+text' на сервере {0}. + + + Вы пытаетесь включить/отключить это свойство и **отсутвует разрешение АДМИНИСТРАТОР**. Это может вызвать ошибки, и Вам придётся удалять текст в текстовых каналах самостоятельно. + + + Для этого свойства требуются как минимум разрешения **управление ролями** и **управление каналами**. (Рекомендуется разрешение Администратор) + + + Пользователь {0} в текстовом чате + + + Пользователь {0} в текстовом и голосовом чатах + + + Пользовать {0} в голосовом чате + + + Вас забанили на сервере {0}. Причина: {1} + + + Пользователь разбанен. + + + Перемещение закончено! + + + Ошибка при переносе файлов, проверьте консоль бота для получения дальнейшей информации. + + + + + + + + + наградил {0} пользователю {1} + + + + + + В следующий раз повезёт ^_^ + + + Поздравляем! Вы выиграли {0}, так как выбросили больше {1} + + + Колода перетасована. + + + подброшено {0} + User flipped tails. + + + Вы угадали! Вы выиграли {0} + + + Указано неверное число. Вы можете подбросить от 1 до {0} монет. + + + Добавьте {0}, как реакцию к этому сообщению, чтобы получить {1}␣ + + + Это событие активно в течение не более {0} часов. + + + Событие получения цветов началось! + + + подарил {0} {1} + X has gifted 15 flowers to Y + + + У {0} есть {1} + X has Y flowers + + + Орёл + + + Таблица рекордов + + + {1} пользователей c ролью {2} награждены {0}. + + + Вы не можете поставить больше {0} + + + Вы не можете поставить меньше {0} + + + У Вас недостаточно {0} + + + В колоде закончились карты. + + + + + + + + + + + + НИЧЕГО СЕБЕ!!! Поздраляем!!! x{0} + + + Один {0}, x{1} + + + Вот это повезло! Тройка! x{0} + + + Молодец! Две {} - ставка x{1} + + + Выиграл + + + Пользователи могут ввести секретный код, чтобы получить {0}. Длится {1} секунд. Никому не говори! + + + Закончилось событие SneakyGame. {0} пользователей получили награду. + + + Началось событие SneakyGameStatus + + + Решка + + + успешно забрал {0} у {1} + + + не смог забрать {0} у {1}, поскольку у пользователя нет столько {2}! + + + Вернуться к содержанию + + + Только для владельца бота + + + Требуется разрешение канала {0}. + + + Вы можете поддержать проект в patreon: <{0}> или через paypal: <{1}> + + + Команды и альтернативные имена команд + + + Список команд создан. + + + Напишите '{0}h ИмяКоманды', чтобы получить справку для этой команды. Например, '{0}h >8ball' + + + Эта команда не найдена. Пожалуйста, убедитесь, что команда существует. + + + Описание + + + Вы можете поддержать проект NadekoBot в +Patreon <{0}> или +Paypal <{1}> +Не забудьте оставить ваше имя в Discord или id в Вашем сообщении. + +**Спасибо** ♥️ + + + **Список команд**: <{0}> +**Руководства по установке и документы можно найти здесь**: <{1}> + + + Список команд + + + Список модулей + + + Напишите '{0}cmds ИмяМодуля', чтобы получить список команд в этом модуле. Например, '{0}cmds games' + + + Этот модуль не существует + + + Требуются серверное право {0} + + + Содержание + + + Использование + + + + + + Тэг + + + Гонка зверей + + + Не удалось начать гонку, так как не хватает участников. + + + В гонке не осталось мест! Гонка начинается. + + + {0} присоединился в роли {1} + + + {0} присоединился в роли {1} и сделал ставку {2}! + + + Напишите {0}jr, чтобы присоединиться к гонке. + + + Гонка начнётся через 20 секунд или когда все места будут заняты. + + + Гонка началась с {0} участниками. + + + {0} в роли {1} победил в гонке! + + + {0} в роли {1} победил в гонке и получил {2}! + + + Задано неправильное число. Можно бросить {0}-{1} костей одновременно. + + + + Someone rolled 35 + + + Брошено {0} костей. + Dice Rolled: 5 + + + Не удалось начать гонку. Другая гонка уже идёт. + + + На данном сервере не идёт гонка. + + + Второе число должно быть больше первого. + + + + + + + + + Разводы + + + Нравится + + + Цена + + + Ни одной вайфу ещё не забрали + + + Рейтинг вайфу + + + Ваша предрасположенность уже установлена для этой вайфу или Вы пытаесь убрать предрасположенность к вайфу, которой нет. + + + сменил свою предрасположенность с {0} на {1}. + +*Это сомнительно с точки зрения морали* :thinking: + Make sure to get the formatting right, and leave the thinking emoji + + + Вам нужно подождать {0} часов и {1} минут перед тем, как опять менять Вашу предрасположенность. + + + Ваша предрасположенность сброшена. У Вас больше нет человека, который Вам нравится. + + + хочет быть вайфу {0}. Как мило <3 + + + объявил {0} своей вайфу за {1}! + + + Вы развелись с вайфу, которой Вы нравитесь. Вы бессердечный прохиндей! {0} получил {1} в качестве компенсации. + + + Вы не можете установить предрасположенность к самому себе, это чересчур эгоистичсно. + + + 🎉Их любовь нашла взаимность!🎉 +Новое значение {0} — {1}. + + + Не бывает таких дешёвых вайфу. Вам нужно заплатить как минимум {0}, чтобы получить вайфу, даже если их фактическая стоимость ниже этого значения. + + + Вам нужно заплатить {0} или больше, чтобы получить эту вайфу! + + + Эта вайфу — не Ваша. + + + Вы не можете потребовать себя в вайфу. + + + Вы недавно развелись. Нужно подождать {0} часов и {1} минут, если хотите снова развестись. + + + Никто + + + Вы развелись с вайфу, которой Вы не нравились. Вам вернули {0}. + + + + + + Акрофобия. + + + Игра закончилась без ответов. + + + Никто не проголосовал. Игра закончилась без победителся. + + + Акроним был {0}. + + + В этом канале уже идёт игра Акрофобии. + + + Игра начинается. Составьте предложение со следующим акронимом: {0}. + + + У Вас есть {0} секунд, чтобы предложить ответ. + + + {0} предложил своё предложение. ({1} в общей сложности) + + + Чтобы проголосовать, напишите номер ответа. + + + {0} проголосовал! + + + Победитель — {0} с {1} очками. + + + {0} — победитель, так как только он привёл ответ! + + + Вопрос + + + Ничья! Оба игрока выбрали {0} + + + {0} выиграл! {1} побеждает {2} + + + Приём ответов закончен. + + + Гонка зверей уже идёт. + + + Итого: {0} Среднее: {1} + + + Категория + + + На этом сервере отключён cleverbot. + + + На этом сервере включён cleverbot. + + + В этом канале отключено появление валюты. + + + В этом канале включено появление валюты. + + + {0} случайных {1} появились! Напишите '{2}pick', чтобы собрать их. + plural + + + Случайный {0} появился! Напишите '{1}pick', чтобы собрать его. + + + Не удалось загрузить вопрос. + + + Игра началась + + + Игра в Виселицу началась + + + Игра в Виселицу уже идёт в этом канале. + + + Не удалось начать игру в Виселицу. + + + Список типов слов для "{0}hangman": + + + Таблица рекордов + + + У вас не хватает {0} + + + Нет результатов + + + собрал {0} + Kwoth picked 5* + + + {0} посадил {1} + Kwoth planted 5* + + + Викторина уже идёт на этом сервере. + + + Викторина + + + {0} угадал! Ответ: {1} + + + На этом сервере не идёт викторина. + + + У {0} {1} очков. + + + Игра закончится после этого вопроса. + + + Время вышло! Правильный ответ — {0} + + + {0} угадал и ВЫИГРАЛ в игре! Ответ: {0} + + + Вы не можете играть против самого себя. + + + В этом канале уже идёт игра в крестики-нолики. + + + Ничья! + + + создал игру в крестики-нолики. + + + {0} выиграл! + + + Выстроил 3 в ряд + + + Ходов не осталось! + + + Время вышло! + + + Ход {0} + + + {0} против {1} + + + Пытаюсь добавить {0} песен в очередь... + + + Автовоспроизведение отключено. + + + Автовоспроизведение включено. + + + Громкость по умолчанию выставлена на {0}% + + + Папка успешно добавлена в очередь воспроизведения. + + + + + + Песня завершилась. + + + + + + + + + С момента + + + Имя + + + Неправильный ввод. + + + Максимальное время воспроизведения теперь неограничено. + + + Максимальное время воспроизведения установлено на {0} секунд. + + + Максимальный размер очереди воспроизведения теперь неограничен. + + + Максимальный размер очереди воспроизведения установлен на {0} песен. + + + Вам требуется быть в голосовом канале на этом сервере. + + + Название + + + Сейчас играет + + + Нет активного музыкального проигрывателя. + + + Нет результатов поиска. + + + Проигрывание музыки приостановлено. + + + Очередь воспроизведения - Страница {0}/{1} + + + Проигрывается песня + + + '#{0}' - **{1}** *{2}* ({3} песен) + + + Страница {0} сохранённых плейлистов. + + + Плейлист удалён. + + + Не удалось удалить плейлист. Он либо не существует, либо Вы не его автор. + + + Плейлист с таким ID не существует. + + + Добавление плейлиста в очередь завершено. + + + Плейлист сохранён. + + + Ограничение {0}c + + + Очередь воспроизведения + + + Песня добавлена в очередь воспроизведения. + + + Очередь воспроизведения музыки очищена. + + + Очередь воспроизведения полна {0}/{0}. + + + Убрана песня + context: "removed song #5" + + + Повторяется текущая песня. + + + Повторяется плейлист. + + + Повторяется песня. + + + Повтор текущей песни приостановлен. + + + Воспроизведение музыки возобновлено. + + + Отключено повторение плейлиста. + + + Включено повторение плейлиста. + + + Проигрываемые, завершённые, приостановленные и удалённые песни будут выводится в этом канале. + + + Пропускаю до '{0}:{1}' + + + Песни перемешаны. + + + Песня перемещена. + + + {0}ч {1}м {2}с + + + К моменту + + + неограничено + + + Уровень громкости должен быть от 0 до 100 + + + Уровень громкости установлен на {0}% + + + Отключено использование ВСЕХ МОДУЛЕЙ в канале {0}. + + + Включено использование ВСЕХ МОДУЛЕЙ в канале {0}. + + + Разрешено + + + Отключено использование ВСЕХ МОДУЛЕЙ для роли {0}. + + + Включено использование ВСЕХ МОДУЛЕЙ для роли {0}. + + + Отключено использование ВСЕХ МОДУЛЕЙ на этом сервере. + + + Включено использование ВСЕХ МОДУЛЕЙ на этом сервере. + + + Отключено использование ВСЕХ МОДУЛЕЙ для пользователя {0}. + + + Включено использование ВСЕХ МОДУЛЕЙ для пользователя {0}. + + + Добавлено {0} в чёрный список c ID {1} + + + У команды {0} теперь есть время перезарядки {1}c + + + У команды {0} больше нет времени перезарядки и все существующие времена перезадки были сброшены. + + + У команды не установлено время перезарядки. + + + Стоимость команды + + + Отключено использование {0} {1} в канале {2} + + + Включено использование {0} {1} в канале {2} + + + Отказано + + + Слово {0} добавлено в список фильтруемых слов. + + + Список фильтруемых слов + + + Слово {0} убрано из списка фильтруемых слов. + + + Неправильный второй параметр. (Должно быть числом от {0} до {1}) + + + Отключена фильтрация приглашений в этом канале. + + + Включена фильтрация приглашений в этом канале. + + + Отключена фильтрация приглашений в этом сервере. + + + Включена фильтрация приглашений в этом сервере. + + + Передано право {0} с #{1} to #{2} + + + Не найдено право с номером #{0} + + + Стоимостой не установлено + + + команда + Gen (of command) + + + модуль + Gen. (of module) + + + Страница прав {0} + + + Текущая роль прав — {0} + + + Пользователям требуется роль {0} для редактирования прав. + + + Не найдено прав с таким номером. + + + Удалены права #{0} - {1} + + + Отключено использование {0} {1} для роли {2}. + + + Включено использование {0} {1} для роли {2}. + + + сек. + Short of seconds. + + + Отключено использование {0} {1} для данного сервера. + + + Включено использование {0} {1} для данного сервера. + + + {0} с ID {1} убраны из черного списка. + + + нередактируемое + + + Отключено использование {0} {1} для пользователя {2}. + + + Включено использование {0} {1} для пользователя {2}. + + + Оповещения о правах больше не будут показываться в чате. + + + Оповещения о правах будут показываться в чате. + + + В данном канале отключена фильтрация слов. + + + В данном канале включена фильтрация слов. + + + На данном сервере оключена фильтрация слов. + + + На данном сервере включена фильтрация слов. + + + Способности + + + Нет любимого аниме + + + Начинается автоматический перевод сообщений в этом канале. Сообщения пользователей будут автоматически удаляться. + + + Ваш язык автоперевода был удалён. + + + Ваш язык автоперевода изменён с {from} на {to} + + + Начинается автоматический перевод сообщений в этом канале. + + + Остановлен автоматический перевод сообщений в этом канале. + + + Неправильный формат ввода, что-то пошло не так. + + + Эта карта не найдена. + + + факт + + + Главы + + + Комикс # + + + Поражения в соревновательном режиме + + + Матчи в соревновательном режиме + + + Соревновательный ранг + + + Победы в соревновательном режиме + + + Завершено + + + Условие + + + Стоимость + + + Дата + + + Определить: + + + + + + Эпизоды + + + Произошла ошибка + + + Образец + + + Не удалось найти это аниму. + + + Не удалось найти это манго. + + + Жанры + + + Не удалось найти определение для этого тэга. + + + Высота/Вес + + + {0}м/{1}кг + + + Влажность + + + Поиск изображений: + + + Не удалос найти этот фильм. + + + Неправильный источник или целевой язык. + + + Шутки не были загружены. + + + Шир/Долг + + + Уровень + + + Список тэгов для команды {0}place + Don't translate {0}place + + + Местоположение + + + Волшебные предметы не были загружены. + + + Профиль в MAL {0} + + + Владелец бота не задал MashapeApiKey. Вы не можете использовать эту функцию. + + + Мин/Макс + + + Каналов не найдено. + + + Результаты не найдены. + + + Ожидание + + + Оригинальный URL + + + Требуется ключ osu! API. + + + Не удалось получить подпись osu! + + + Найдено больше {0} изображений. Показывается случайные {0} изображений. + + + Пользователь не найден! Проверьте регион и BattleTag и попробуйте ещё раз. + + + Планирует смотреть + + + Платформа + + + Способность не найдена + + + Покемон не найден + + + Ссылка на профиль: + + + Качество: + + + + Is this supposed to be Overwatch Quick Play stats? + + + + + + Рейтинг: + + + Отметка: + + + Искать: + + + Не удалось укоротить эту ссылку. + + + Короткая ссылка + + + Что-то пошло не так. + + + Пожалуйста, задайте параметры поиска. + + + Состояние + + + + + + Стример {0} в оффлане. + + + Стример {0} в онлайне с {1} зрителями. + + + Вы подписаны на {0} стримов на этом сервере. + + + Вы не подписаны ни на один стрим на этом сервере. + + + Такого стрима не существует. + + + Скорее всего, этот стрим не существует. + + + Стрим {0} ({1}) убран из оповещений. + + + + + + Рассвет + + + Закат + + + Температура + + + Название: + + + 3 любимых аниме: + + + Перевод: + + + Типы: + + + Не удалось найти определение для этого запроса. + + + Url + + + Зрители + + + Смотрят + + + Не удалось найти этот термин на указаной вики. + + + Укажите целевую вики и после этого поисковый запрос. + + + Страница не найдена. + + + Скорость ветра. + + + {0} наиболее часто забаненных чемпионов. + + + Предложение, как у Йоды, не получилось сделать. + + + Присоединился + + + '{0}.' {1} [{2:F2}/с] - {3} всего + /s and total need to be localized to fit the context - +`1.` + + + + + + Всего {0} пользователей. + + + Автор + + + ID бота + + + Список функций команды {0}calc + + + {0} этого канала — {1} + + + Тема канала + + + Команд запущено + + + {0} {1} равно {2} {3} + + + Единицы, которые можно использовать в конвертировании + + + Нельзя перевести {0} в {1}: единицы измерения не найдены + + + Нельзя перевести {0} в {1}: единицы измерения не эквивалентны. + + + Создано + + + Присоедился к межсерверному каналу. + + + Покинул межсерверный канал. + + + Ваш CSC токен: + + + Серверные emoji + + + Ошибка + + + Признаки + + + Имя + + + Указатель вышел за пределы диапазона. + + + Список пользователей с этими ролями: + + + Вам запрещено использовать эту комманду в отношении ролей с большим числом пользователей для предотвращения + + + + Invalid months value/ Invalid hours value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0} Серверов +{1} Текстовых каналов +{2} Голосовых каналов + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Id of the user kwoth#1234 is 123123123123 + + + + + + + + + \ No newline at end of file From 5f8982d4fb643d73b66d1c732c4f0697d02d5a4e Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 28 Feb 2017 21:47:50 +0100 Subject: [PATCH 366/746] Added german and russian to list of supported languages, russian is unfinished atm btw --- .../Modules/Administration/Commands/LocalizationCommands.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 8250bfde..641f90e8 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -18,8 +18,10 @@ namespace NadekoBot.Modules.Administration { private ImmutableDictionary supportedLocales { get; } = new Dictionary() { - {"en-US", "English, United States" }, - {"fr-FR", "French, France" } + {"en-US", "English, United States"}, + {"fr-FR", "French, France"}, + {"ru-RU", "Russian, Russia"}, + {"de-DE", "German, Germany"} //{"sr-cyrl-rs", "Serbian, Cyrillic" } }.ToImmutableDictionary(); From 9485d94a83eb2af501a2bb4008ff34117d90e79e Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 28 Feb 2017 21:50:34 +0100 Subject: [PATCH 367/746] Update ResponseStrings.fr-fr.resx (POEditor.com) --- .../Resources/ResponseStrings.fr-fr.resx | 105 ++++++++++-------- 1 file changed, 56 insertions(+), 49 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx index 5f7a188e..dbce49d8 100644 --- a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx +++ b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx @@ -163,7 +163,7 @@ Vous ne participez pas a cette guerre. - @{0} Vous ne pouvez pas participer a cette guerre ou la base a déjà été détruite. + @{0} Vous ne participez pas à cette guerre ou la base a déjà été détruite. Aucune guerre en cours. @@ -206,7 +206,7 @@ Nouvelle réaction personnalisée - Aucune réaction personnalisé trouvée. + Aucune réaction personnalisée trouvée. Aucune réaction personnalisée ne correspond à cet ID. @@ -288,7 +288,7 @@ C'est très efficace ! - Vous avez utilisé trop de mouvement d'affilé, donc ne pouvez plus bouger ! + Vous avez utilisé trop de mouvements d'affilée, vous ne pouvez donc plus bouger! Le type de {0} est {1} @@ -300,10 +300,10 @@ Vous vous êtes évanoui, vous n'êtes donc pas capable de bouger! - **L'affectation automatique du rôle** à l'arrivé d'un nouvel utilisateur est désormais **désactivée**. + **L'affectation automatique de rôle** à l'arrivé d'un nouvel utilisateur est désormais **désactivée**. - **L'affectation automatique du rôle** à l'arrivé d'un nouvel utilisateur est désormais **activée**. + **L'affectation automatique de rôle** à l'arrivé d'un nouvel utilisateur est désormais **activée**. Liens @@ -425,7 +425,7 @@ Raison: {1} Activez les MPs de bienvenue en écrivant {0} - Nouveau MP de bienvenue en service. + Nouveau MP de bienvenue défini. MPs de bienvenue désactivés. @@ -440,7 +440,7 @@ Raison: {1} Activez les messages de bienvenue en écrivant {0} - Nouveau message de bienvenue en service. + Nouveau message de bienvenue défini. Messages de bienvenue désactivés. @@ -471,7 +471,7 @@ Raison : {1} Utilisateur expulsé - Listes des langages + Listes des langues {0} @@ -487,7 +487,7 @@ Raison : {1} Échec dans la tentative de changement de langue. Réessayer avec l'aide pour cette commande. - La langue de ce serveur est {0} - {0} + La langue de ce serveur est {0} - {1} {0} a quitté {1} @@ -568,7 +568,7 @@ Raison : {1} Impossible de trouver ce serveur - Aucun shard avec cet ID trouvé. + Aucune partition pour cet ID trouvée. Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. @@ -602,7 +602,7 @@ Raison : {1} Aucune protection activée. - Le seuil pour cet utilisateur doit être entre {0} et {1} + Le seuil d'utilisateurs doit être entre {0} et {1} Si {0} ou plus d'utilisateurs rejoignent dans les {1} secondes suivantes, je les {2}. @@ -684,13 +684,14 @@ Raison : {1} Il y a {0} rôles auto-affectés. - Ce rôle ne peux pas vous être attribué par vous même. + Ce rôle ne peux pas vous être attribué par vous-même. Vous ne possédez pas le rôle {0}. - L'affectation automatique des rôles n'est désormais plus exclusive! + Les rôles auto-attribuables ne sont désormais plus exclusifs! + Je ne pense pas que ce soit la bonne traduction.. self-assignable role serait plutôt rôle auto-attribuable Je suis incapable de vous ajouter ce rôle. `Je ne peux pas ajouter de rôles aux propriétaires et aux autres rôles plus haut que le mien dans la hiérarchie.` @@ -717,20 +718,21 @@ Raison : {1} Nouveau nom de Salon défini avec succès. - Nouveau jeu en service! + Nouveau jeu défini! + Pour "set", je pense que défini irait mieux que "en service" - Nouvelle diffusion en service! + Nouveau stream défini! - Nouveau sujet du salon en service. + Nouveau sujet du salon défini. - Shard {0} reconnecté. + Partition {0} reconnectée. Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. - Shard {0} se reconnecte. + Partition {0} en reconnection. Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. @@ -864,7 +866,7 @@ Raison: {1} Utilisateur débanni - Migration effectué! + Migration effectuée! Erreur lors de la migration, veuillez consulter la console pour plus d'informations. @@ -990,7 +992,7 @@ Raison: {1} Nécessite {0} permissions du salon - Vous pouvez supporter ce projet sur Patreon: <{0}> ou via Paypal <{1}> + Vous pouvez supporter ce projet sur Patreon <{0}> ou via Paypal <{1}> Commandes et alias @@ -1119,7 +1121,7 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Top Waifus - votre affinité est déjà liée à cette waifu ou vous êtes en train de retirer votre affinité avec quelqu'un avec qui vous n'en posséder pas. + votre affinité est déjà liée à cette waifu ou vous êtes en train de retirer votre affinité avec quelqu'un alors que vous n'en possédez pas. Affinités changées de de {0} à {1}. @@ -1237,10 +1239,11 @@ La nouvelle valeur de {0} est {1} ! Cleverbot activé sur ce serveur. - La génération actuelle a été désactivée sur ce salon. + La génération monétaire a été désactivée sur ce salon. + Currency =/= current !!! Il s'agit de monnaie. Par example: Euro is a currency. US Dollar also is. Sur Public Nadeko, il s'agit des fleurs :) - La génération actuelle a été désactivée sur ce salon. + La génération monétaire a été désactivée sur ce salon. {0} {1} aléatoires sont apparus ! Attrapez-les en entrant `{2}pick` @@ -1253,7 +1256,7 @@ La nouvelle valeur de {0} est {1} ! Impossible de charger une question. - Jeu commencé. + La jeu a commencé. Partie de pendu commencée. @@ -1274,7 +1277,7 @@ La nouvelle valeur de {0} est {1} ! Vous n'avez pas assez de {0} - Pas de résultats + Pas de résultat choisi {0} @@ -1357,7 +1360,7 @@ La nouvelle valeur de {0} est {1} ! à tour de rôle - Musique terminée + Lecture terminée Système de tour de rôle désactivé. @@ -1402,13 +1405,13 @@ La nouvelle valeur de {0} est {1} ! Pas de résultat - Musique mise sur pause. + Lecteur mis sur pause. Liste d'attente - Page {0}/{1} - Lecture du son + Lecture en cours: #{0}` - **{1}** par *{2}* ({3} morceaux) @@ -1423,7 +1426,7 @@ La nouvelle valeur de {0} est {1} ! Impossible de supprimer cette liste de lecture. Soit elle n'existe pas, soit vous n'en êtes pas le créateur. - Aucune liste de lecture avec cet ID existe. + Aucune liste de lecture ne correspond a cet ID. File d'attente de la liste complétée. @@ -1438,7 +1441,7 @@ La nouvelle valeur de {0} est {1} ! Liste d'attente - Musique ajoutée à la file d'attente + Son ajouté à la file d'attente Liste d'attente effacée. @@ -1447,7 +1450,7 @@ La nouvelle valeur de {0} est {1} ! Liste d'attente complète ({0}/{0}) - Musique retirée + Son retiré context: "removed song #5" @@ -1478,10 +1481,10 @@ La nouvelle valeur de {0} est {1} ! Saut à `{0}:{1}` - Musiques mélangées. + Lecture aléatoire activée. - Musique déplacée. + Musique déplacée {0}h {1}m {2}s @@ -1527,12 +1530,13 @@ La nouvelle valeur de {0} est {1} ! Banni {0} avec l'ID {1} + Il ne s'agit pas d'un ban mais d'une blacklist interdisant l'utilisateur d'utiliser le bot. La commande {0} a désormais {1}s de temps de recharge. - La commande {0} n'a pas de temps de recharge et tout les temps de recharge ont été réinitialisés. + La commande {0} n'a pas de temps de recharge et tous les temps de recharge ont été réinitialisés. Aucune commande n'a de temps de recharge. @@ -1700,7 +1704,7 @@ La nouvelle valeur de {0} est {1} ! Parties compétitives gagnées - Complété + Complétés Condition @@ -1715,7 +1719,8 @@ La nouvelle valeur de {0} est {1} ! Définis: - En baisse + Abandonnés + droppped as in, "stopped watching" referring to shows/anime Episodes @@ -1779,7 +1784,7 @@ La nouvelle valeur de {0} est {1} ! Profil MAL de {0} - Le propriétaire du Bot n'a pas spécifié de clé MashapeApi. Fonctionnalité non disponible + Le propriétaire du Bot n'a pas spécifié de clé d'API Mashape (MashapeApiKey). Fonctionnalité non disponible Min/Max @@ -1797,10 +1802,10 @@ La nouvelle valeur de {0} est {1} ! Url originale - Une clé osu!API est nécessaire + Une clé d'API osu! est nécessaire - Impossible de récupérer la signature osu. + Impossible de récupérer la signature osu! Trouvé dans {0} images. Affichage de {0} aléatoires. @@ -1810,6 +1815,7 @@ La nouvelle valeur de {0} est {1} ! Prévision de lecture + Je ne pense pas que le sens de la traduction soit le bon. Plateforme @@ -1833,13 +1839,14 @@ La nouvelle valeur de {0} est {1} ! Victoires Rapides - Évaluation + Évaluation Score: Chercher pour: + recherche plutôt non ? Impossible de réduire cette Url @@ -1863,7 +1870,7 @@ La nouvelle valeur de {0} est {1} ! Le streamer {0} est hors ligne. - Le streamer {0} est en ligne avec {1} spectateurs. + Le streamer {0} est en ligne avec {1} viewers. Vous suivez {0} streams sur ce serveur. @@ -1881,7 +1888,7 @@ La nouvelle valeur de {0} est {1} ! Stream de {0} ({1}) retirée des notifications. - Je préviendrais ce salon lors d'un changement de statut. + Je préviendrai ce salon lors d'un changement de statut. Aube @@ -1911,10 +1918,10 @@ La nouvelle valeur de {0} est {1} ! Url - Spectateurs + Viewers - Regardant + En écoute Impossible de trouver ce terme sur le wikia spécifié. @@ -2060,7 +2067,7 @@ OwnerID: {2} Aucun rôle sur cette page. - Aucun shard sur cette page. + Aucune partition sur cette page. Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. @@ -2111,7 +2118,7 @@ OwnerID: {2} Format de date non valide. Regardez la liste des commandes. - Nouveau modèle de rappel en service. + Nouveau modèle de rappel défini. Répétition de {0} chaque {1} jour(s), {2} heure(s) et {3} minute(s) @@ -2156,15 +2163,15 @@ OwnerID: {2} Info du serveur - Shard + Partition Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. - Statistique de Shard + Statistique des partitions Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. - Le shard **#{0}** est en {1} état avec {2} serveurs + La partition **#{0}** est en état {1} avec {2} serveurs. Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. From c4a248889e3e91490e2f96bc414c1820b0b9d322 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 28 Feb 2017 21:50:36 +0100 Subject: [PATCH 368/746] Update ResponseStrings.de-DE.resx (POEditor.com) --- .../Resources/ResponseStrings.de-DE.resx | 234 +++++++++--------- 1 file changed, 117 insertions(+), 117 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx index 9aac2f85..7dd58187 100644 --- a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Diese Basis wurde bereits beansprucht oder zerstört. From 172d401da7da41c356d33d0872f599b8130a2751 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 28 Feb 2017 21:50:39 +0100 Subject: [PATCH 369/746] Update ResponseStrings.ru-RU.resx (POEditor.com) --- .../Resources/ResponseStrings.ru-RU.resx | 243 +++++++++--------- 1 file changed, 122 insertions(+), 121 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx index f6729bb5..bf370873 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 @@ -2014,17 +2014,18 @@ Paypal <{1}> Вам запрещено использовать эту комманду в отношении ролей с большим числом пользователей для предотвращения - + Неправильное значение {0}. Invalid months value/ Invalid hours value - + Присоединился к Discord - + Присоединился к серверу - + Имя: {0} + From b588edeeee88fcd148f85954b795dafa1ad8533a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 1 Mar 2017 01:48:29 +0100 Subject: [PATCH 370/746] added languages in progress to the list too --- .../Commands/LocalizationCommands.cs | 7 +- .../Gambling/Commands/FlipCoinCommand.cs | 2 +- .../Resources/CommandStrings.ja-JP.resx | 3153 +++++++++++++++++ .../Resources/CommandStrings.nl-NL.resx | 3153 +++++++++++++++++ .../Resources/ResponseStrings.Designer.cs | 9 - .../Resources/ResponseStrings.pt-BR.resx | 2184 ++++++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 3 - 7 files changed, 8496 insertions(+), 15 deletions(-) create mode 100644 src/NadekoBot/Resources/CommandStrings.ja-JP.resx create mode 100644 src/NadekoBot/Resources/CommandStrings.nl-NL.resx create mode 100644 src/NadekoBot/Resources/ResponseStrings.pt-BR.resx diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 641f90e8..4200fafb 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -21,8 +21,11 @@ namespace NadekoBot.Modules.Administration {"en-US", "English, United States"}, {"fr-FR", "French, France"}, {"ru-RU", "Russian, Russia"}, - {"de-DE", "German, Germany"} - //{"sr-cyrl-rs", "Serbian, Cyrillic" } + {"de-DE", "German, Germany"}, + {"nl-NL", "Dutch, Netherlands"}, + {"ja-JP", "Japanese, Japan"}, + {"pt-BR", "Portuguese, Brazil"}, + {"sr-cyrl-rs", "Serbian, Serbia - Cyrillic"} }.ToImmutableDictionary(); [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs index 40b8a735..3d58d086 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs @@ -110,7 +110,7 @@ namespace NadekoBot.Modules.Gambling { var toWin = (int)Math.Round(amount * NadekoBot.BotConfig.BetflipMultiplier); str = Context.User.Mention + " " + GetText("flip_guess", toWin + CurrencySign); - await CurrencyHandler.AddCurrencyAsync(Context.User, GetText("betflip_gamble"), toWin, false).ConfigureAwait(false); + await CurrencyHandler.AddCurrencyAsync(Context.User, "Betflip Gamble", toWin, false).ConfigureAwait(false); } else { diff --git a/src/NadekoBot/Resources/CommandStrings.ja-JP.resx b/src/NadekoBot/Resources/CommandStrings.ja-JP.resx new file mode 100644 index 00000000..662975cf --- /dev/null +++ b/src/NadekoBot/Resources/CommandStrings.ja-JP.resx @@ -0,0 +1,3153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + help h + + + Either shows a help for a single command, or DMs you help link if no arguments are specified. + + + `{0}h !!q` or `{0}h` + + + hgit + + + Generates the commandlist.md file. + + + `{0}hgit` + + + donate + + + Instructions for helping the project financially. + + + `{0}donate` + + + modules mdls + + + Lists all bot modules. + + + `{0}modules` + + + commands cmds + + + List all of the bot's commands from a certain module. You can either specify full, or only first few letters of the module name. + + + `{0}commands Administration` or `{0}cmds Admin` + + + greetdel grdel + + + Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set 0 to disable automatic deletion. + + + `{0}greetdel 0` or `{0}greetdel 30` + + + greet + + + Toggles anouncements on the current channel when someone joins the server. + + + `{0}greet` + + + greetmsg + + + Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. + + + `{0}greetmsg Welcome, %user%.` + + + bye + + + Toggles anouncements on the current channel when someone leaves the server. + + + `{0}bye` + + + byemsg + + + Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. + + + `{0}byemsg %user% has left.` + + + byedel + + + Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set 0 to disable automatic deletion. + + + `{0}byedel 0` or `{0}byedel 30` + + + greetdm + + + Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). + + + `{0}greetdm` + + + logserver + + + Enables or Disables ALL log events. If enabled, all log events will log to this channel. + + + `{0}logserver enable` or `{0}logserver disable` + + + logignore + + + Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. + + + `{0}logignore` + + + userpresence + + + Starts logging to this channel when someone from the server goes online/offline/idle. + + + `{0}userpresence` + + + voicepresence + + + Toggles logging to this channel whenever someone joins or leaves a voice channel you are currently in. + + + `{0}voicepresence` + + + repeatinvoke repinv + + + Immediately shows the repeat message on a certain index and restarts its timer. + + + `{0}repinv 1` + + + repeat + + + Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. + + + `{0}repeat 5 Hello there` + + + rotateplaying ropl + + + Toggles rotation of playing status of the dynamic strings you previously specified. + + + `{0}ropl` + + + addplaying adpl + + + Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %time%,%shardid%,%shardcount%, %shardguilds% + + + `{0}adpl` + + + listplaying lipl + + + Lists all playing statuses with their corresponding number. + + + `{0}lipl` + + + removeplaying rmpl repl + + + Removes a playing string on a given number. + + + `{0}rmpl` + + + slowmode + + + Toggles slowmode. Disable by specifying no parameters. To enable, specify a number of messages each user can send, and an interval in seconds. For example 1 message every 5 seconds. + + + `{0}slowmode 1 5` or `{0}slowmode` + + + cleanvplust cv+t + + + Deletes all text channels ending in `-voice` for which voicechannels are not found. Use at your own risk. + + + `{0}cleanv+t` + + + voice+text v+t + + + Creates a text channel for each voice channel only users in that voice channel can see.If you are server owner, keep in mind you will see them all the time regardless. + + + `{0}v+t` + + + scsc + + + Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. + + + `{0}scsc` + + + jcsc + + + Joins current channel to an instance of cross server channel using the token. + + + `{0}jcsc TokenHere` + + + lcsc + + + Leaves Cross server channel instance from this channel. + + + `{0}lcsc` + + + asar + + + Adds a role to the list of self-assignable roles. + + + `{0}asar Gamer` + + + rsar + + + Removes a specified role from the list of self-assignable roles. + + + `{0}rsar` + + + lsar + + + Lists all self-assignable roles. + + + `{0}lsar` + + + togglexclsar tesar + + + Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) + + + `{0}tesar` + + + iam + + + Adds a role to you that you choose. Role must be on a list of self-assignable roles. + + + `{0}iam Gamer` + + + iamnot iamn + + + Removes a role to you that you choose. Role must be on a list of self-assignable roles. + + + `{0}iamn Gamer` + + + addcustreact acr + + + Add a custom reaction with a trigger and a response. Running this command in server requires Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: <http://nadekobot.readthedocs.io/en/latest/Custom%20Reactions/> + + + `{0}acr "hello" Hi there %user%` + + + listcustreact lcr + + + Lists global or server custom reactions (20 commands per page). Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. Specifying `all` argument instead of the number will DM you a text file with a list of all custom reactions. + + + `{0}lcr 1` or `{0}lcr all` + + + listcustreactg lcrg + + + Lists global or server custom reactions (20 commands per page) grouped by trigger, and show a number of responses for each. Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. + + + `{0}lcrg 1` + + + showcustreact scr + + + Shows a custom reaction's response on a given ID. + + + `{0}scr 1` + + + delcustreact dcr + + + Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration priviledges and removes server custom reaction. + + + `{0}dcr 5` + + + autoassignrole aar + + + Automaticaly assigns a specified role to every user who joins the server. + + + `{0}aar` to disable, `{0}aar Role Name` to enable + + + leave + + + Makes Nadeko leave the server. Either name or id required. + + + `{0}leave 123123123331` + + + delmsgoncmd + + + Toggles the automatic deletion of user's successful command message to prevent chat flood. + + + `{0}delmsgoncmd` + + + restart + + + Restarts the bot. Might not work. + + + `{0}restart` + + + setrole sr + + + Sets a role for a given user. + + + `{0}sr @User Guest` + + + removerole rr + + + Removes a role from a given user. + + + `{0}rr @User Admin` + + + renamerole renr + + + Renames a role. Roles you are renaming must be lower than bot's highest role. + + + `{0}renr "First role" SecondRole` + + + removeallroles rar + + + Removes all roles from a mentioned user. + + + `{0}rar @User` + + + createrole cr + + + Creates a role with a given name. + + + `{0}cr Awesome Role` + + + rolecolor rc + + + Set a role's color to the hex or 0-255 rgb color value provided. + + + `{0}rc Admin 255 200 100` or `{0}rc Admin ffba55` + + + ban b + + + Bans a user by ID or name with an optional message. + + + `{0}b "@some Guy" Your behaviour is toxic.` + + + softban sb + + + Bans and then unbans a user by ID or name with an optional message. + + + `{0}sb "@some Guy" Your behaviour is toxic.` + + + kick k + + + Kicks a mentioned user. + + + `{0}k "@some Guy" Your behaviour is toxic.` + + + mute + + + Mutes a mentioned user both from speaking and chatting. + + + `{0}mute @Someone` + + + voiceunmute + + + Gives a previously voice-muted user a permission to speak. + + + `{0}voiceunmute @Someguy` + + + deafen deaf + + + Deafens mentioned user or users. + + + `{0}deaf "@Someguy"` or `{0}deaf "@Someguy" "@Someguy"` + + + undeafen undef + + + Undeafens mentioned user or users. + + + `{0}undef "@Someguy"` or `{0}undef "@Someguy" "@Someguy"` + + + delvoichanl dvch + + + Deletes a voice channel with a given name. + + + `{0}dvch VoiceChannelName` + + + creatvoichanl cvch + + + Creates a new voice channel with a given name. + + + `{0}cvch VoiceChannelName` + + + deltxtchanl dtch + + + Deletes a text channel with a given name. + + + `{0}dtch TextChannelName` + + + creatxtchanl ctch + + + Creates a new text channel with a given name. + + + `{0}ctch TextChannelName` + + + settopic st + + + Sets a topic on the current channel. + + + `{0}st My new topic` + + + setchanlname schn + + + Changes the name of the current channel. + + + `{0}schn NewName` + + + prune clr + + + `{0}prune` removes all nadeko's messages in the last 100 messages.`{0}prune X` removes last X messages from the channel (up to 100)`{0}prune @Someone` removes all Someone's messages in the last 100 messages.`{0}prune @Someone X` removes last X 'Someone's' messages in the channel. + + + `{0}prune` or `{0}prune 5` or `{0}prune @Someone` or `{0}prune @Someone X` + + + die + + + Shuts the bot down. + + + `{0}die` + + + setname newnm + + + Gives the bot a new name. + + + `{0}newnm BotName` + + + setavatar setav + + + Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. + + + `{0}setav http://i.imgur.com/xTG3a1I.jpg` + + + setgame + + + Sets the bots game. + + + `{0}setgame with snakes` + + + send + + + Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prepend channel id with `c:` and user id with `u:`. + + + `{0}send serverid|c:channelid message` or `{0}send serverid|u:userid message` + + + mentionrole menro + + + Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. + + + `{0}menro RoleName` + + + unstuck + + + Clears the message queue. + + + `{0}unstuck` + + + donators + + + List of lovely people who donated to keep this project alive. + + + `{0}donators` + + + donadd + + + Add a donator to the database. + + + `{0}donadd Donate Amount` + + + announce + + + Sends a message to all servers' general channel bot is connected to. + + + `{0}announce Useless spam` + + + savechat + + + Saves a number of messages to a text file and sends it to you. + + + `{0}savechat 150` + + + remind + + + Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message. + + + `{0}remind me 1d5h Do something` or `{0}remind #general 1m Start now!` + + + remindtemplate + + + Sets message for when the remind is triggered. Available placeholders are %user% - user who ran the command, %message% - Message specified in the remind, %target% - target channel of the remind. + + + `{0}remindtemplate %user%, do %message%!` + + + serverinfo sinfo + + + Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. + + + `{0}sinfo Some Server` + + + channelinfo cinfo + + + Shows info about the channel. If no channel is supplied, it defaults to current one. + + + `{0}cinfo #some-channel` + + + userinfo uinfo + + + Shows info about the user. If no user is supplied, it defaults a user running the command. + + + `{0}uinfo @SomeUser` + + + whosplaying whpl + + + Shows a list of users who are playing the specified game. + + + `{0}whpl Overwatch` + + + inrole + + + Lists every person from the provided role or roles, separated with space, on this server. You can use role IDs, role names (in quotes if it has multiple words), or role mention If the list is too long for 1 message, you must have Manage Messages permission. + + + `{0}inrole Role` or `{0}inrole Role1 "Role 2" @role3` + + + checkmyperms + + + Checks your user-specific permissions on this channel. + + + `{0}checkmyperms` + + + stats + + + Shows some basic stats for Nadeko. + + + `{0}stats` + + + userid uid + + + Shows user ID. + + + `{0}uid` or `{0}uid "@SomeGuy"` + + + channelid cid + + + Shows current channel ID. + + + `{0}cid` + + + serverid sid + + + Shows current server ID. + + + `{0}sid` + + + roles + + + List roles on this server or a roles of a specific user if specified. Paginated. 20 roles per page. + + + `{0}roles 2` or `{0}roles @Someone` + + + channeltopic ct + + + Sends current channel's topic as a message. + + + `{0}ct` + + + chnlfilterinv cfi + + + Toggles automatic deleting of invites posted in the channel. Does not negate the {0}srvrfilterinv enabled setting. Does not affect Bot Owner. + + + `{0}cfi` + + + srvrfilterinv sfi + + + Toggles automatic deleting of invites posted in the server. Does not affect Bot Owner. + + + `{0}sfi` + + + chnlfilterwords cfw + + + Toggles automatic deleting of messages containing banned words on the channel. Does not negate the {0}srvrfilterwords enabled setting. Does not affect bot owner. + + + `{0}cfw` + + + fw + + + Adds or removes (if it exists) a word from the list of filtered words. Use`{0}sfw` or `{0}cfw` to toggle filtering. + + + `{0}fw poop` + + + lstfilterwords lfw + + + Shows a list of filtered words. + + + `{0}lfw` + + + srvrfilterwords sfw + + + Toggles automatic deleting of messages containing forbidden words on the server. Does not affect Bot Owner. + + + `{0}sfw` + + + permrole pr + + + Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'. + + + `{0}pr role` + + + verbose v + + + Sets whether to show when a command/module is blocked. + + + `{0}verbose true` + + + srvrmdl sm + + + Sets a module's permission at the server level. + + + `{0}sm ModuleName enable` + + + srvrcmd sc + + + Sets a command's permission at the server level. + + + `{0}sc "command name" disable` + + + rolemdl rm + + + Sets a module's permission at the role level. + + + `{0}rm ModuleName enable MyRole` + + + rolecmd rc + + + Sets a command's permission at the role level. + + + `{0}rc "command name" disable MyRole` + + + chnlmdl cm + + + Sets a module's permission at the channel level. + + + `{0}cm ModuleName enable SomeChannel` + + + chnlcmd cc + + + Sets a command's permission at the channel level. + + + `{0}cc "command name" enable SomeChannel` + + + usrmdl um + + + Sets a module's permission at the user level. + + + `{0}um ModuleName enable SomeUsername` + + + usrcmd uc + + + Sets a command's permission at the user level. + + + `{0}uc "command name" enable SomeUsername` + + + allsrvrmdls asm + + + Enable or disable all modules for your server. + + + `{0}asm [enable/disable]` + + + allchnlmdls acm + + + Enable or disable all modules in a specified channel. + + + `{0}acm enable #SomeChannel` + + + allrolemdls arm + + + Enable or disable all modules for a specific role. + + + `{0}arm [enable/disable] MyRole` + + + ubl + + + Either [add]s or [rem]oves a user specified by a mention or ID from a blacklist. + + + `{0}ubl add @SomeUser` or `{0}ubl rem 12312312313` + + + cbl + + + Either [add]s or [rem]oves a channel specified by an ID from a blacklist. + + + `{0}cbl rem 12312312312` + + + sbl + + + Either [add]s or [rem]oves a server specified by a Name or ID from a blacklist. + + + `{0}sbl add 12312321312` or `{0}sbl rem SomeTrashServer` + + + cmdcooldown cmdcd + + + Sets a cooldown per user for a command. Set to 0 to remove the cooldown. + + + `{0}cmdcd "some cmd" 5` + + + allcmdcooldowns acmdcds + + + Shows a list of all commands and their respective cooldowns. + + + `{0}acmdcds` + + + . + + + Adds a new quote with the specified name and message. + + + `{0}. sayhi Hi` + + + .. + + + Shows a random quote with a specified name. + + + `{0}.. abc` + + + qsearch + + + Shows a random quote for a keyword that contains any text specified in the search. + + + `{0}qsearch keyword text` + + + deletequote delq + + + Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. + + + `{0}delq abc` + + + draw + + + Draws a card from the deck.If you supply number X, she draws up to 5 cards from the deck. + + + `{0}draw` or `{0}draw 5` + + + shuffle sh + + + Shuffles the current playlist. + + + `{0}sh` + + + flip + + + Flips coin(s) - heads or tails, and shows an image. + + + `{0}flip` or `{0}flip 3` + + + betflip bf + + + Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. + + + `{0}bf 5 heads` or `{0}bf 3 t` + + + 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. + + + `{0}roll` or `{0}roll 7` or `{0}roll 3d5` or `{0}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. + + + `{0}rolluo` or `{0}rolluo 7` or `{0}rolluo 3d5` + + + nroll + + + Rolls in a given range. + + + `{0}nroll 5` (rolls 0-5) or `{0}nroll 5-15` + + + race + + + Starts a new animal race. + + + `{0}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. + + + `{0}jr` or `{0}jr 5` + + + raffle + + + Prints a name and ID of a random user from the online list from the (optional) role. + + + `{0}raffle` or `{0}raffle RoleName` + + + give + + + Give someone a certain amount of currency. + + + `{0}give 1 "@SomeGuy"` + + + award + + + Awards someone a certain amount of currency. You can also specify a role name to award currency to all users in a role. + + + `{0}award 100 @person` or `{0}award 5 Role Of Gamblers` + + + take + + + Takes a certain amount of currency from someone. + + + `{0}take 1 "@someguy"` + + + betroll br + + + Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10. + + + `{0}br 5` + + + leaderboard lb + + + Displays bot currency leaderboard. + + + `{0}lb` + + + trivia t + + + Starts a game of trivia. You can add nohint to prevent hints.First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. + + + `{0}t` or `{0}t 5 nohint` + + + tl + + + Shows a current trivia leaderboard. + + + `{0}tl` + + + tq + + + Quits current trivia after current question. + + + `{0}tq` + + + typestart + + + Starts a typing contest. + + + `{0}typestart` + + + typestop + + + Stops a typing contest on the current channel. + + + `{0}typestop` + + + typeadd + + + Adds a new article to the typing contest. + + + `{0}typeadd wordswords` + + + poll + + + Creates a poll which requires users to send the number of the voting option to the bot. + + + `{0}poll Question?;Answer1;Answ 2;A_3` + + + pollend + + + Stops active poll on this server and prints the results in this channel. + + + `{0}pollend` + + + pick + + + Picks the currency planted in this channel. 60 seconds cooldown. + + + `{0}pick` + + + plant + + + Spend an amount of currency to plant it in this channel. Default is 1. (If bot is restarted or crashes, the currency will be lost) + + + `{0}plant` or `{0}plant 5` + + + gencurrency gc + + + Toggles currency generation on this channel. Every posted message will have chance to spawn currency. Chance is specified by the Bot Owner. (default is 2%) + + + `{0}gc` + + + leet + + + Converts a text to leetspeak with 6 (1-6) severity levels + + + `{0}leet 3 Hello` + + + choose + + + Chooses a thing from a list of things + + + `{0}choose Get up;Sleep;Sleep more` + + + 8ball + + + Ask the 8ball a yes/no question. + + + `{0}8ball should I do something` + + + rps + + + Play a game of rocket paperclip scissors with Nadeko. + + + `{0}rps scissors` + + + linux + + + Prints a customizable Linux interjection + + + `{0}linux Spyware Windows` + + + next n + + + Goes to the next song in the queue. You have to be in the same voice channel as the bot. You can skip multiple songs, but in that case songs will not be requeued if {0}rcs or {0}rpl is enabled. + + + `{0}n` or `{0}n 5` + + + stop s + + + Stops the music and clears the playlist. Stays in the channel. + + + `{0}s` + + + destroy d + + + Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) + + + `{0}d` + + + pause p + + + Pauses or Unpauses the song. + + + `{0}p` + + + queue q yq + + + Queue a song using keywords or a link. Bot will join your voice channel.**You must be in a voice channel**. + + + `{0}q Dream Of Venice` + + + soundcloudqueue sq + + + Queue a soundcloud song using keywords. Bot will join your voice channel.**You must be in a voice channel**. + + + `{0}sq Dream Of Venice` + + + listqueue lq + + + Lists 15 currently queued songs per page. Default page is 1. + + + `{0}lq` or `{0}lq 2` + + + nowplaying np + + + Shows the song currently playing. + + + `{0}np` + + + volume vol + + + Sets the music volume 0-100% + + + `{0}vol 50` + + + defvol dv + + + Sets the default music volume when music playback is started (0-100). Persists through restarts. + + + `{0}dv 80` + + + max + + + Sets the music volume to 100%. + + + `{0}max` + + + half + + + Sets the music volume to 50%. + + + `{0}half` + + + playlist pl + + + Queues up to 500 songs from a youtube playlist specified by a link, or keywords. + + + `{0}pl playlist link or name` + + + soundcloudpl scpl + + + Queue a soundcloud playlist using a link. + + + `{0}scpl soundcloudseturl` + + + localplaylst lopl + + + Queues all songs from a directory. + + + `{0}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: <https://streamable.com/al54>) + + + `{0}ra radio link here` + + + local lo + + + Queues a local file by specifying a full path. + + + `{0}lo C:/music/mysong.mp3` + + + move mv + + + Moves the bot to your voice channel. (works only if music is already playing) + + + `{0}mv` + + + remove rm + + + Remove a song by its # in the queue, or 'all' to remove whole queue. + + + `{0}rm 5` + + + movesong ms + + + Moves a song from one position to another. + + + `{0}ms 5>3` + + + setmaxqueue smq + + + Sets a maximum queue size. Supply 0 or no argument to have no limit. + + + `{0}smq 50` or `{0}smq` + + + cleanup + + + Cleans up hanging voice connections. + + + `{0}cleanup` + + + reptcursong rcs + + + Toggles repeat of current song. + + + `{0}rcs` + + + rpeatplaylst rpl + + + Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). + + + `{0}rpl` + + + save + + + Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. + + + `{0}save classical1` + + + load + + + Loads a saved playlist using it's ID. Use `{0}pls` to list all saved playlists and {0}save to save new ones. + + + `{0}load 5` + + + playlists pls + + + Lists all playlists. Paginated. 20 per page. Default page is 0. + + + `{0}pls 1` + + + deleteplaylist delpls + + + Deletes a saved playlist. Only if you made it or if you are the bot owner. + + + `{0}delpls animu-5` + + + goto + + + Goes to a specific time in seconds in a song. + + + `{0}goto 30` + + + autoplay ap + + + Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty) + + + `{0}ap` + + + lolchamp + + + Shows League Of Legends champion statistics. If there are spaces/apostrophes or in the name - omit them. Optional second parameter is a role. + + + `{0}lolchamp Riven` or `{0}lolchamp Annie sup` + + + lolban + + + Shows top banned champions ordered by ban rate. + + + `{0}lolban` + + + hitbox hb + + + Notifies this channel when a certain user starts streaming. + + + `{0}hitbox SomeStreamer` + + + twitch tw + + + Notifies this channel when a certain user starts streaming. + + + `{0}twitch SomeStreamer` + + + beam bm + + + Notifies this channel when a certain user starts streaming. + + + `{0}beam SomeStreamer` + + + removestream rms + + + Removes notifications of a certain streamer from a certain platform on this channel. + + + `{0}rms Twitch SomeGuy` or `{0}rms Beam SomeOtherGuy` + + + liststreams ls + + + Lists all streams you are following on this server. + + + `{0}ls` + + + convert + + + Convert quantities. Use `{0}convertlist` to see supported dimensions and currencies. + + + `{0}convert m km 1000` + + + convertlist + + + List of the convertible dimensions and currencies. + + + `{0}convertlist` + + + wowjoke + + + Get one of Kwoth's penultimate WoW jokes. + + + `{0}wowjoke` + + + calculate calc + + + Evaluate a mathematical expression. + + + `{0}calc 1+1` + + + osu + + + Shows osu stats for a player. + + + `{0}osu Name` or `{0}osu Name taiko` + + + osub + + + Shows information about an osu beatmap. + + + `{0}osub https://osu.ppy.sh/s/127712` + + + osu5 + + + Displays a user's top 5 plays. + + + `{0}osu5 Name` + + + pokemon poke + + + Searches for a pokemon. + + + `{0}poke Sylveon` + + + pokemonability pokeab + + + Searches for a pokemon ability. + + + `{0}pokeab overgrow` + + + memelist + + + Pulls a list of memes you can use with `{0}memegen` from http://memegen.link/templates/ + + + `{0}memelist` + + + memegen + + + Generates a meme from memelist with top and bottom text. + + + `{0}memegen biw "gets iced coffee" "in the winter"` + + + weather we + + + Shows weather data for a specified city. You can also specify a country after a comma. + + + `{0}we Moscow, RU` + + + youtube yt + + + Searches youtubes and shows the first result + + + `{0}yt query` + + + anime ani aq + + + Queries anilist for an anime and shows the first result. + + + `{0}ani aquarion evol` + + + imdb omdb + + + Queries omdb for movies or series, show first result. + + + `{0}imdb Batman vs Superman` + + + manga mang mq + + + Queries anilist for a manga and shows the first result. + + + `{0}mq Shingeki no kyojin` + + + randomcat meow + + + Shows a random cat image. + + + `{0}meow` + + + randomdog woof + + + Shows a random dog image. + + + `{0}woof` + + + image img + + + Pulls the first image found using a search parameter. Use {0}rimg for different results. + + + `{0}img cute kitten` + + + randomimage rimg + + + Pulls a random image using a search parameter. + + + `{0}rimg cute kitten` + + + lmgtfy + + + Google something for an idiot. + + + `{0}lmgtfy query` + + + google g + + + Get a google search link for some terms. + + + `{0}google query` + + + hearthstone hs + + + Searches for a Hearthstone card and shows its image. Takes a while to complete. + + + `{0}hs Ysera` + + + urbandict ud + + + Searches Urban Dictionary for a word. + + + `{0}ud Pineapple` + + + # + + + Searches Tagdef.com for a hashtag. + + + `{0}# ff` + + + catfact + + + Shows a random catfact from <http://catfacts-api.appspot.com/api/facts> + + + `{0}catfact` + + + yomama ym + + + Shows a random joke from <http://api.yomomma.info/> + + + `{0}ym` + + + randjoke rj + + + Shows a random joke from <http://tambal.azurewebsites.net/joke/random> + + + `{0}rj` + + + chucknorris cn + + + Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random> + + + `{0}cn` + + + magicitem mi + + + Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items> + + + `{0}mi` + + + revav + + + Returns a google reverse image search for someone's avatar. + + + `{0}revav "@SomeGuy"` + + + revimg + + + Returns a google reverse image search for an image from a link. + + + `{0}revimg Image link` + + + safebooru + + + Shows a random image from safebooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) + + + `{0}safebooru yuri+kissing` + + + wikipedia wiki + + + Gives you back a wikipedia link + + + `{0}wiki query` + + + color clr + + + Shows you what color corresponds to that hex. + + + `{0}clr 00ff00` + + + videocall + + + Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message. + + + `{0}videocall "@SomeGuy"` + + + avatar av + + + Shows a mentioned person's avatar. + + + `{0}av "@SomeGuy"` + + + 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. + + + `{0}hentai yuri` + + + danbooru + + + Shows a random hentai image from danbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) + + + `{0}danbooru yuri+kissing` + + + atfbooru atf + + + Shows a random hentai image from atfbooru with a given tag. Tag is optional but preferred. + + + `{0}atfbooru yuri+kissing` + + + gelbooru + + + Shows a random hentai image from gelbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) + + + `{0}gelbooru yuri+kissing` + + + rule34 + + + Shows a random image from rule34.xx with a given tag. Tag is optional but preferred. (multiple tags are appended with +) + + + `{0}rule34 yuri+kissing` + + + e621 + + + Shows a random hentai image from e621.net with a given tag. Tag is optional but preferred. Use spaces for multiple tags. + + + `{0}e621 yuri kissing` + + + cp + + + We all know where this will lead you to. + + + `{0}cp` + + + boobs + + + Real adult content. + + + `{0}boobs` + + + butts ass butt + + + Real adult content. + + + `{0}butts` or `{0}ass` + + + createwar cw + + + Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. + + + `{0}cw 15 The Enemy Clan` + + + startwar sw + + + Starts a war with a given number. + + + `{0}sw 15` + + + listwar lw + + + Shows the active war claims by a number. Shows all wars in a short way if no number is specified. + + + `{0}lw [war_number] or {0}lw` + + + claim call c + + + Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. + + + `{0}call [war_number] [base_number] [optional_other_name]` + + + claimfinish cf + + + Finish your claim with 3 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. + + + `{0}cf 1` or `{0}cf 1 5` + + + claimfinish2 cf2 + + + Finish your claim with 2 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. + + + `{0}cf2 1` or `{0}cf2 1 5` + + + claimfinish1 cf1 + + + Finish your claim with 1 star if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. + + + `{0}cf1 1` or `{0}cf1 1 5` + + + unclaim ucall uc + + + Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim + + + `{0}uc [war_number] [optional_other_name]` + + + endwar ew + + + Ends the war with a given index. + + + `{0}ew [war_number]` + + + translate trans + + + Translates from>to text. From the given language to the destination language. + + + `{0}trans en>fr Hello` + + + translangs + + + Lists the valid languages for translation. + + + `{0}translangs` + + + Sends a readme and a guide links to the channel. + + + `{0}readme` or `{0}guide` + + + readme guide + + + Shows all available operations in {0}calc command + + + `{0}calcops` + + + calcops + + + Deletes all quotes on a specified keyword. + + + `{0}delallq kek` + + + delallq daq + + + greetdmmsg + + + `{0}greetdmmsg Welcome to the server, %user%`. + + + Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. + + + Check how much currency a person has. (Defaults to yourself) + + + `{0}$$` or `{0}$$ @SomeGuy` + + + cash $$ + + + Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions. + + + `{0}lp` or `{0}lp 3` + + + listperms lp + + + Enable or disable all modules for a specific user. + + + `{0}aum enable @someone` + + + allusrmdls aum + + + Moves permission from one position to another in Permissions list. + + + `{0}mp 2 4` + + + moveperm mp + + + Removes a permission from a given position in Permissions list. + + + `{0}rp 1` + + + removeperm rp + + + Migrate data from old bot configuration + + + `{0}migratedata` + + + migratedata + + + Checks if a user is online on a certain streaming platform. + + + `{0}cs twitch MyFavStreamer` + + + checkstream cs + + + showemojis se + + + Shows a name and a link to every SPECIAL emoji in the message. + + + `{0}se A message full of SPECIAL emojis` + + + shuffle sh + + + Reshuffles all cards back into the deck. + + + `{0}sh` + + + fwmsgs + + + Toggles forwarding of non-command messages sent to bot's DM to the bot owners + + + `{0}fwmsgs` + + + fwtoall + + + Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json + + + `{0}fwtoall` + + + resetperms + + + Resets BOT's permissions module on this server to the default value. + + + `{0}resetperms` + + + antiraid + + + Sets an anti-raid protection on the server. First argument is number of people which will trigger the protection. Second one is a time interval in which that number of people needs to join in order to trigger the protection, and third argument is punishment for those people (Kick, Ban, Mute) + + + `{0}antiraid 5 20 Kick` + + + antispam + + + Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10. + + + `{0}antispam 3 Mute` or `{0}antispam 4 Kick` or `{0}antispam 6 Ban` + + + chatmute + + + Prevents a mentioned user from chatting in text channels. + + + `{0}chatmute @Someone` + + + voicemute + + + Prevents a mentioned user from speaking in voice channels. + + + `{0}voicemute @Someone` + + + konachan + + + Shows a random hentai image from konachan with a given tag. Tag is optional but preferred. + + + `{0}konachan yuri` + + + setmuterole + + + Sets a name of the role which will be assigned to people who should be muted. Default is nadeko-mute. + + + `{0}setmuterole Silenced` + + + adsarm + + + Toggles the automatic deletion of confirmations for {0}iam and {0}iamn commands. + + + `{0}adsarm` + + + setstream + + + Sets the bots stream. First argument is the twitch link, second argument is stream name. + + + `{0}setstream TWITCHLINK Hello` + + + chatunmute + + + Removes a mute role previously set on a mentioned user with `{0}chatmute` which prevented him from chatting in text channels. + + + `{0}chatunmute @Someone` + + + unmute + + + Unmutes a mentioned user previously muted with `{0}mute` command. + + + `{0}unmute @Someone` + + + xkcd + + + Shows a XKCD comic. No arguments will retrieve random one. Number argument will retrieve a specific comic, and "latest" will get the latest one. + + + `{0}xkcd` or `{0}xkcd 1400` or `{0}xkcd latest` + + + placelist + + + Shows the list of available tags for the `{0}place` command. + + + `{0}placelist` + + + place + + + Shows a placeholder image of a given tag. Use `{0}placelist` to see all available tags. You can specify the width and height of the image as the last two optional arguments. + + + `{0}place Cage` or `{0}place steven 500 400` + + + togethertube totube + + + Creates a new room on <https://togethertube.com> and shows the link in the chat. + + + `{0}totube` + + + publicpoll ppoll + + + Creates a public poll which requires users to type a number of the voting option in the channel command is ran in. + + + `{0}ppoll Question?;Answer1;Answ 2;A_3` + + + autotranslang atl + + + Sets your source and target language to be used with `{0}at`. Specify no arguments to remove previously set value. + + + `{0}atl en>fr` + + + autotrans at + + + Starts automatic translation of all messages by users who set their `{0}atl` in this channel. You can set "del" argument to automatically delete all translated user messages. + + + `{0}at` or `{0}at del` + + + listquotes liqu + + + `{0}liqu` or `{0}liqu 3` + + + Lists all quotes on the server ordered alphabetically. 15 Per page. + + + typedel + + + Deletes a typing article given the ID. + + + `{0}typedel 3` + + + typelist + + + Lists added typing articles with their IDs. 15 per page. + + + `{0}typelist` or `{0}typelist 3` + + + listservers + + + Lists servers the bot is on with some basic info. 15 per page. + + + `{0}listservers 3` + + + hentaibomb + + + Shows a total 5 images (from gelbooru, danbooru, konachan, yandere and atfbooru). Tag is optional but preferred. + + + `{0}hentaibomb yuri` + + + cleverbot + + + Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. + + + `{0}cleverbot` + + + shorten + + + Attempts to shorten an URL, if it fails, returns the input URL. + + + `{0}shorten https://google.com` + + + minecraftping mcping + + + Pings a minecraft server. + + + `{0}mcping 127.0.0.1:25565` + + + minecraftquery mcq + + + Finds information about a minecraft server. + + + `{0}mcq server:ip` + + + wikia + + + Gives you back a wikia link + + + `{0}wikia mtg Vigilance` or `{0}wikia mlp Dashy` + + + yandere + + + Shows a random image from yandere with a given tag. Tag is optional but preferred. (multiple tags are appended with +) + + + `{0}yandere tag1+tag2` + + + magicthegathering mtg + + + Searches for a Magic The Gathering card. + + + `{0}magicthegathering about face` or `{0}mtg about face` + + + yodify yoda + + + Translates your normal sentences into Yoda styled sentences! + + + `{0}yoda my feelings hurt` + + + attack + + + Attacks a target with the given move. Use `{0}movelist` to see a list of moves your type can use. + + + `{0}attack "vine whip" @someguy` + + + heal + + + Heals someone. Revives those who fainted. Costs a NadekoFlower + + + `{0}heal @someone` + + + movelist ml + + + Lists the moves you are able to use + + + `{0}ml` + + + settype + + + Set your poketype. Costs a NadekoFlower. Provide no arguments to see a list of available types. + + + `{0}settype fire` or `{0}settype` + + + type + + + Get the poketype of the target. + + + `{0}type @someone` + + + hangmanlist + + + Shows a list of hangman term types. + + + `{0} hangmanlist` + + + hangman + + + Starts a game of hangman in the channel. Use `{0}hangmanlist` to see a list of available term types. Defaults to 'all'. + + + `{0}hangman` or `{0}hangman movies` + + + crstatsclear + + + Resets the counters on `{0}crstats`. You can specify a trigger to clear stats only for that trigger. + + + `{0}crstatsclear` or `{0}crstatsclear rng` + + + crstats + + + Shows a list of custom reactions and the number of times they have been executed. Paginated with 10 per page. Use `{0}crstatsclear` to reset the counters. + + + `{0}crstats` or `{0}crstats 3` + + + overwatch ow + + + Show's basic stats on a player (competitive rank, playtime, level etc) Region codes are: `eu` `us` `cn` `kr` + + + `{0}ow us Battletag#1337` or `{0}overwatch eu Battletag#2016` + + + acrophobia acro + + + Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60) + + + `{0}acro` or `{0}acro 30` + + + logevents + + + Shows a list of all events you can subscribe to with `{0}log` + + + `{0}logevents` + + + log + + + Toggles logging event. Disables it if it's active anywhere on the server. Enables if it's not active. Use `{0}logevents` to see a list of all events you can subscribe to. + + + `{0}log userpresence` or `{0}log userbanned` + + + fairplay fp + + + Toggles fairplay. While enabled, music player will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue. + + + `{0}fp` + + + define def + + + Finds a definition of a word. + + + `{0}def heresy` + + + setmaxplaytime smp + + + Sets a maximum number of seconds (>14) a song can run before being skipped automatically. Set 0 to have no limit. + + + `{0}smp 0` or `{0}smp 270` + + + activity + + + Checks for spammers. + + + `{0}activity` + + + 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. + + + `{0}autohentai 30 yuri|tail|long_hair` or `{0}autohentai` + + + setstatus + + + Sets the bot's status. (Online/Idle/Dnd/Invisible) + + + `{0}setstatus Idle` + + + rotaterolecolor rrc + + + Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. + + + `{0}rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `{0}rrc 0 MyLsdRole` + + + createinvite crinv + + + Creates a new invite which has infinite max uses and never expires. + + + `{0}crinv` + + + pollstats + + + Shows the poll results without stopping the poll on this server. + + + `{0}pollstats` + + + repeatlist replst + + + Shows currently repeating messages and their indexes. + + + `{0}repeatlist` + + + repeatremove reprm + + + Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes. + + + `{0}reprm 2` + + + antilist antilst + + + Shows currently enabled protection features. + + + `{0}antilist` + + + antispamignore + + + Toggles whether antispam ignores current channel. Antispam must be enabled. + + + `{0}antispamignore` + + + cmdcosts + + + Shows a list of command costs. Paginated with 9 command per page. + + + `{0}cmdcosts` or `{0}cmdcosts 2` + + + commandcost cmdcost + + + Sets a price for a command. Running that command will take currency from users. Set 0 to remove the price. + + + `{0}cmdcost 0 !!q` or `{0}cmdcost 1 >8ball` + + + startevent + + + Starts one of the events seen on public nadeko. + + + `{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` + + + affinity + + + 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 @MyHusband` or `{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 9 waifus. + + + `{0}waifus` + + + 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. + + + `{0}divorce @CheatingSloot` + + + waifuinfo waifustats + + + Shows waifu stats for a target person. Defaults to you if no user is provided. + + + `{0}waifuinfo @MyCrush` or `{0}waifuinfo` + + + mal + + + Shows basic info from myanimelist profile. + + + `{0}mal straysocks` + + + setmusicchannel smch + + + Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in. + + + `{0}smch` + + + reloadimages + + + Reloads images bot is using. Safe to use even when bot is being used heavily. + + + `{0}reloadimages` + + + shardstats + + + Stats for shards. Paginated with 25 shards per page. + + + `{0}shardstats` or `{0}shardstats 2` + + + connectshard + + + Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. + + + `{0}connectshard 2` + + + shardid + + + Shows which shard is a certain guild on, by guildid. + + + `{0}shardid 117523346618318850` + + + tictactoe ttt + + + Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. 15 seconds per move. + + + >ttt + + + timezones + + + List of all timezones available on the system to be used with `{0}timezone`. + + + `{0}timezones` + + + timezone + + + Sets this guilds timezone. This affects bot's time output in this server (logs, etc..) + + + `{0}timezone` + + + langsetdefault langsetd + + + Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. + + + `{0}langsetd en-US` or `{0}langsetd default` + + + languageset langset + + + Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. + + + `{0}langset de-DE ` or `{0}langset default` + + + languageslist langli + + + List of languages for which translation (or part of it) exist atm. + + + `{0}langli` + + + rategirl + + + Use the universal hot-crazy wife zone matrix to determine the girl's worth. It is everything young men need to know about women. At any moment in time, any woman you have previously located on this chart can vanish from that location and appear anywhere else on the chart. + + + `{0}rategirl @SomeGurl` + + \ No newline at end of file diff --git a/src/NadekoBot/Resources/CommandStrings.nl-NL.resx b/src/NadekoBot/Resources/CommandStrings.nl-NL.resx new file mode 100644 index 00000000..662975cf --- /dev/null +++ b/src/NadekoBot/Resources/CommandStrings.nl-NL.resx @@ -0,0 +1,3153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + help h + + + Either shows a help for a single command, or DMs you help link if no arguments are specified. + + + `{0}h !!q` or `{0}h` + + + hgit + + + Generates the commandlist.md file. + + + `{0}hgit` + + + donate + + + Instructions for helping the project financially. + + + `{0}donate` + + + modules mdls + + + Lists all bot modules. + + + `{0}modules` + + + commands cmds + + + List all of the bot's commands from a certain module. You can either specify full, or only first few letters of the module name. + + + `{0}commands Administration` or `{0}cmds Admin` + + + greetdel grdel + + + Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set 0 to disable automatic deletion. + + + `{0}greetdel 0` or `{0}greetdel 30` + + + greet + + + Toggles anouncements on the current channel when someone joins the server. + + + `{0}greet` + + + greetmsg + + + Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. + + + `{0}greetmsg Welcome, %user%.` + + + bye + + + Toggles anouncements on the current channel when someone leaves the server. + + + `{0}bye` + + + byemsg + + + Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. + + + `{0}byemsg %user% has left.` + + + byedel + + + Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set 0 to disable automatic deletion. + + + `{0}byedel 0` or `{0}byedel 30` + + + greetdm + + + Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). + + + `{0}greetdm` + + + logserver + + + Enables or Disables ALL log events. If enabled, all log events will log to this channel. + + + `{0}logserver enable` or `{0}logserver disable` + + + logignore + + + Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. + + + `{0}logignore` + + + userpresence + + + Starts logging to this channel when someone from the server goes online/offline/idle. + + + `{0}userpresence` + + + voicepresence + + + Toggles logging to this channel whenever someone joins or leaves a voice channel you are currently in. + + + `{0}voicepresence` + + + repeatinvoke repinv + + + Immediately shows the repeat message on a certain index and restarts its timer. + + + `{0}repinv 1` + + + repeat + + + Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. + + + `{0}repeat 5 Hello there` + + + rotateplaying ropl + + + Toggles rotation of playing status of the dynamic strings you previously specified. + + + `{0}ropl` + + + addplaying adpl + + + Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %time%,%shardid%,%shardcount%, %shardguilds% + + + `{0}adpl` + + + listplaying lipl + + + Lists all playing statuses with their corresponding number. + + + `{0}lipl` + + + removeplaying rmpl repl + + + Removes a playing string on a given number. + + + `{0}rmpl` + + + slowmode + + + Toggles slowmode. Disable by specifying no parameters. To enable, specify a number of messages each user can send, and an interval in seconds. For example 1 message every 5 seconds. + + + `{0}slowmode 1 5` or `{0}slowmode` + + + cleanvplust cv+t + + + Deletes all text channels ending in `-voice` for which voicechannels are not found. Use at your own risk. + + + `{0}cleanv+t` + + + voice+text v+t + + + Creates a text channel for each voice channel only users in that voice channel can see.If you are server owner, keep in mind you will see them all the time regardless. + + + `{0}v+t` + + + scsc + + + Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. + + + `{0}scsc` + + + jcsc + + + Joins current channel to an instance of cross server channel using the token. + + + `{0}jcsc TokenHere` + + + lcsc + + + Leaves Cross server channel instance from this channel. + + + `{0}lcsc` + + + asar + + + Adds a role to the list of self-assignable roles. + + + `{0}asar Gamer` + + + rsar + + + Removes a specified role from the list of self-assignable roles. + + + `{0}rsar` + + + lsar + + + Lists all self-assignable roles. + + + `{0}lsar` + + + togglexclsar tesar + + + Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) + + + `{0}tesar` + + + iam + + + Adds a role to you that you choose. Role must be on a list of self-assignable roles. + + + `{0}iam Gamer` + + + iamnot iamn + + + Removes a role to you that you choose. Role must be on a list of self-assignable roles. + + + `{0}iamn Gamer` + + + addcustreact acr + + + Add a custom reaction with a trigger and a response. Running this command in server requires Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: <http://nadekobot.readthedocs.io/en/latest/Custom%20Reactions/> + + + `{0}acr "hello" Hi there %user%` + + + listcustreact lcr + + + Lists global or server custom reactions (20 commands per page). Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. Specifying `all` argument instead of the number will DM you a text file with a list of all custom reactions. + + + `{0}lcr 1` or `{0}lcr all` + + + listcustreactg lcrg + + + Lists global or server custom reactions (20 commands per page) grouped by trigger, and show a number of responses for each. Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. + + + `{0}lcrg 1` + + + showcustreact scr + + + Shows a custom reaction's response on a given ID. + + + `{0}scr 1` + + + delcustreact dcr + + + Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration priviledges and removes server custom reaction. + + + `{0}dcr 5` + + + autoassignrole aar + + + Automaticaly assigns a specified role to every user who joins the server. + + + `{0}aar` to disable, `{0}aar Role Name` to enable + + + leave + + + Makes Nadeko leave the server. Either name or id required. + + + `{0}leave 123123123331` + + + delmsgoncmd + + + Toggles the automatic deletion of user's successful command message to prevent chat flood. + + + `{0}delmsgoncmd` + + + restart + + + Restarts the bot. Might not work. + + + `{0}restart` + + + setrole sr + + + Sets a role for a given user. + + + `{0}sr @User Guest` + + + removerole rr + + + Removes a role from a given user. + + + `{0}rr @User Admin` + + + renamerole renr + + + Renames a role. Roles you are renaming must be lower than bot's highest role. + + + `{0}renr "First role" SecondRole` + + + removeallroles rar + + + Removes all roles from a mentioned user. + + + `{0}rar @User` + + + createrole cr + + + Creates a role with a given name. + + + `{0}cr Awesome Role` + + + rolecolor rc + + + Set a role's color to the hex or 0-255 rgb color value provided. + + + `{0}rc Admin 255 200 100` or `{0}rc Admin ffba55` + + + ban b + + + Bans a user by ID or name with an optional message. + + + `{0}b "@some Guy" Your behaviour is toxic.` + + + softban sb + + + Bans and then unbans a user by ID or name with an optional message. + + + `{0}sb "@some Guy" Your behaviour is toxic.` + + + kick k + + + Kicks a mentioned user. + + + `{0}k "@some Guy" Your behaviour is toxic.` + + + mute + + + Mutes a mentioned user both from speaking and chatting. + + + `{0}mute @Someone` + + + voiceunmute + + + Gives a previously voice-muted user a permission to speak. + + + `{0}voiceunmute @Someguy` + + + deafen deaf + + + Deafens mentioned user or users. + + + `{0}deaf "@Someguy"` or `{0}deaf "@Someguy" "@Someguy"` + + + undeafen undef + + + Undeafens mentioned user or users. + + + `{0}undef "@Someguy"` or `{0}undef "@Someguy" "@Someguy"` + + + delvoichanl dvch + + + Deletes a voice channel with a given name. + + + `{0}dvch VoiceChannelName` + + + creatvoichanl cvch + + + Creates a new voice channel with a given name. + + + `{0}cvch VoiceChannelName` + + + deltxtchanl dtch + + + Deletes a text channel with a given name. + + + `{0}dtch TextChannelName` + + + creatxtchanl ctch + + + Creates a new text channel with a given name. + + + `{0}ctch TextChannelName` + + + settopic st + + + Sets a topic on the current channel. + + + `{0}st My new topic` + + + setchanlname schn + + + Changes the name of the current channel. + + + `{0}schn NewName` + + + prune clr + + + `{0}prune` removes all nadeko's messages in the last 100 messages.`{0}prune X` removes last X messages from the channel (up to 100)`{0}prune @Someone` removes all Someone's messages in the last 100 messages.`{0}prune @Someone X` removes last X 'Someone's' messages in the channel. + + + `{0}prune` or `{0}prune 5` or `{0}prune @Someone` or `{0}prune @Someone X` + + + die + + + Shuts the bot down. + + + `{0}die` + + + setname newnm + + + Gives the bot a new name. + + + `{0}newnm BotName` + + + setavatar setav + + + Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. + + + `{0}setav http://i.imgur.com/xTG3a1I.jpg` + + + setgame + + + Sets the bots game. + + + `{0}setgame with snakes` + + + send + + + Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prepend channel id with `c:` and user id with `u:`. + + + `{0}send serverid|c:channelid message` or `{0}send serverid|u:userid message` + + + mentionrole menro + + + Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. + + + `{0}menro RoleName` + + + unstuck + + + Clears the message queue. + + + `{0}unstuck` + + + donators + + + List of lovely people who donated to keep this project alive. + + + `{0}donators` + + + donadd + + + Add a donator to the database. + + + `{0}donadd Donate Amount` + + + announce + + + Sends a message to all servers' general channel bot is connected to. + + + `{0}announce Useless spam` + + + savechat + + + Saves a number of messages to a text file and sends it to you. + + + `{0}savechat 150` + + + remind + + + Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message. + + + `{0}remind me 1d5h Do something` or `{0}remind #general 1m Start now!` + + + remindtemplate + + + Sets message for when the remind is triggered. Available placeholders are %user% - user who ran the command, %message% - Message specified in the remind, %target% - target channel of the remind. + + + `{0}remindtemplate %user%, do %message%!` + + + serverinfo sinfo + + + Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. + + + `{0}sinfo Some Server` + + + channelinfo cinfo + + + Shows info about the channel. If no channel is supplied, it defaults to current one. + + + `{0}cinfo #some-channel` + + + userinfo uinfo + + + Shows info about the user. If no user is supplied, it defaults a user running the command. + + + `{0}uinfo @SomeUser` + + + whosplaying whpl + + + Shows a list of users who are playing the specified game. + + + `{0}whpl Overwatch` + + + inrole + + + Lists every person from the provided role or roles, separated with space, on this server. You can use role IDs, role names (in quotes if it has multiple words), or role mention If the list is too long for 1 message, you must have Manage Messages permission. + + + `{0}inrole Role` or `{0}inrole Role1 "Role 2" @role3` + + + checkmyperms + + + Checks your user-specific permissions on this channel. + + + `{0}checkmyperms` + + + stats + + + Shows some basic stats for Nadeko. + + + `{0}stats` + + + userid uid + + + Shows user ID. + + + `{0}uid` or `{0}uid "@SomeGuy"` + + + channelid cid + + + Shows current channel ID. + + + `{0}cid` + + + serverid sid + + + Shows current server ID. + + + `{0}sid` + + + roles + + + List roles on this server or a roles of a specific user if specified. Paginated. 20 roles per page. + + + `{0}roles 2` or `{0}roles @Someone` + + + channeltopic ct + + + Sends current channel's topic as a message. + + + `{0}ct` + + + chnlfilterinv cfi + + + Toggles automatic deleting of invites posted in the channel. Does not negate the {0}srvrfilterinv enabled setting. Does not affect Bot Owner. + + + `{0}cfi` + + + srvrfilterinv sfi + + + Toggles automatic deleting of invites posted in the server. Does not affect Bot Owner. + + + `{0}sfi` + + + chnlfilterwords cfw + + + Toggles automatic deleting of messages containing banned words on the channel. Does not negate the {0}srvrfilterwords enabled setting. Does not affect bot owner. + + + `{0}cfw` + + + fw + + + Adds or removes (if it exists) a word from the list of filtered words. Use`{0}sfw` or `{0}cfw` to toggle filtering. + + + `{0}fw poop` + + + lstfilterwords lfw + + + Shows a list of filtered words. + + + `{0}lfw` + + + srvrfilterwords sfw + + + Toggles automatic deleting of messages containing forbidden words on the server. Does not affect Bot Owner. + + + `{0}sfw` + + + permrole pr + + + Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'. + + + `{0}pr role` + + + verbose v + + + Sets whether to show when a command/module is blocked. + + + `{0}verbose true` + + + srvrmdl sm + + + Sets a module's permission at the server level. + + + `{0}sm ModuleName enable` + + + srvrcmd sc + + + Sets a command's permission at the server level. + + + `{0}sc "command name" disable` + + + rolemdl rm + + + Sets a module's permission at the role level. + + + `{0}rm ModuleName enable MyRole` + + + rolecmd rc + + + Sets a command's permission at the role level. + + + `{0}rc "command name" disable MyRole` + + + chnlmdl cm + + + Sets a module's permission at the channel level. + + + `{0}cm ModuleName enable SomeChannel` + + + chnlcmd cc + + + Sets a command's permission at the channel level. + + + `{0}cc "command name" enable SomeChannel` + + + usrmdl um + + + Sets a module's permission at the user level. + + + `{0}um ModuleName enable SomeUsername` + + + usrcmd uc + + + Sets a command's permission at the user level. + + + `{0}uc "command name" enable SomeUsername` + + + allsrvrmdls asm + + + Enable or disable all modules for your server. + + + `{0}asm [enable/disable]` + + + allchnlmdls acm + + + Enable or disable all modules in a specified channel. + + + `{0}acm enable #SomeChannel` + + + allrolemdls arm + + + Enable or disable all modules for a specific role. + + + `{0}arm [enable/disable] MyRole` + + + ubl + + + Either [add]s or [rem]oves a user specified by a mention or ID from a blacklist. + + + `{0}ubl add @SomeUser` or `{0}ubl rem 12312312313` + + + cbl + + + Either [add]s or [rem]oves a channel specified by an ID from a blacklist. + + + `{0}cbl rem 12312312312` + + + sbl + + + Either [add]s or [rem]oves a server specified by a Name or ID from a blacklist. + + + `{0}sbl add 12312321312` or `{0}sbl rem SomeTrashServer` + + + cmdcooldown cmdcd + + + Sets a cooldown per user for a command. Set to 0 to remove the cooldown. + + + `{0}cmdcd "some cmd" 5` + + + allcmdcooldowns acmdcds + + + Shows a list of all commands and their respective cooldowns. + + + `{0}acmdcds` + + + . + + + Adds a new quote with the specified name and message. + + + `{0}. sayhi Hi` + + + .. + + + Shows a random quote with a specified name. + + + `{0}.. abc` + + + qsearch + + + Shows a random quote for a keyword that contains any text specified in the search. + + + `{0}qsearch keyword text` + + + deletequote delq + + + Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. + + + `{0}delq abc` + + + draw + + + Draws a card from the deck.If you supply number X, she draws up to 5 cards from the deck. + + + `{0}draw` or `{0}draw 5` + + + shuffle sh + + + Shuffles the current playlist. + + + `{0}sh` + + + flip + + + Flips coin(s) - heads or tails, and shows an image. + + + `{0}flip` or `{0}flip 3` + + + betflip bf + + + Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. + + + `{0}bf 5 heads` or `{0}bf 3 t` + + + 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. + + + `{0}roll` or `{0}roll 7` or `{0}roll 3d5` or `{0}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. + + + `{0}rolluo` or `{0}rolluo 7` or `{0}rolluo 3d5` + + + nroll + + + Rolls in a given range. + + + `{0}nroll 5` (rolls 0-5) or `{0}nroll 5-15` + + + race + + + Starts a new animal race. + + + `{0}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. + + + `{0}jr` or `{0}jr 5` + + + raffle + + + Prints a name and ID of a random user from the online list from the (optional) role. + + + `{0}raffle` or `{0}raffle RoleName` + + + give + + + Give someone a certain amount of currency. + + + `{0}give 1 "@SomeGuy"` + + + award + + + Awards someone a certain amount of currency. You can also specify a role name to award currency to all users in a role. + + + `{0}award 100 @person` or `{0}award 5 Role Of Gamblers` + + + take + + + Takes a certain amount of currency from someone. + + + `{0}take 1 "@someguy"` + + + betroll br + + + Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10. + + + `{0}br 5` + + + leaderboard lb + + + Displays bot currency leaderboard. + + + `{0}lb` + + + trivia t + + + Starts a game of trivia. You can add nohint to prevent hints.First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. + + + `{0}t` or `{0}t 5 nohint` + + + tl + + + Shows a current trivia leaderboard. + + + `{0}tl` + + + tq + + + Quits current trivia after current question. + + + `{0}tq` + + + typestart + + + Starts a typing contest. + + + `{0}typestart` + + + typestop + + + Stops a typing contest on the current channel. + + + `{0}typestop` + + + typeadd + + + Adds a new article to the typing contest. + + + `{0}typeadd wordswords` + + + poll + + + Creates a poll which requires users to send the number of the voting option to the bot. + + + `{0}poll Question?;Answer1;Answ 2;A_3` + + + pollend + + + Stops active poll on this server and prints the results in this channel. + + + `{0}pollend` + + + pick + + + Picks the currency planted in this channel. 60 seconds cooldown. + + + `{0}pick` + + + plant + + + Spend an amount of currency to plant it in this channel. Default is 1. (If bot is restarted or crashes, the currency will be lost) + + + `{0}plant` or `{0}plant 5` + + + gencurrency gc + + + Toggles currency generation on this channel. Every posted message will have chance to spawn currency. Chance is specified by the Bot Owner. (default is 2%) + + + `{0}gc` + + + leet + + + Converts a text to leetspeak with 6 (1-6) severity levels + + + `{0}leet 3 Hello` + + + choose + + + Chooses a thing from a list of things + + + `{0}choose Get up;Sleep;Sleep more` + + + 8ball + + + Ask the 8ball a yes/no question. + + + `{0}8ball should I do something` + + + rps + + + Play a game of rocket paperclip scissors with Nadeko. + + + `{0}rps scissors` + + + linux + + + Prints a customizable Linux interjection + + + `{0}linux Spyware Windows` + + + next n + + + Goes to the next song in the queue. You have to be in the same voice channel as the bot. You can skip multiple songs, but in that case songs will not be requeued if {0}rcs or {0}rpl is enabled. + + + `{0}n` or `{0}n 5` + + + stop s + + + Stops the music and clears the playlist. Stays in the channel. + + + `{0}s` + + + destroy d + + + Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) + + + `{0}d` + + + pause p + + + Pauses or Unpauses the song. + + + `{0}p` + + + queue q yq + + + Queue a song using keywords or a link. Bot will join your voice channel.**You must be in a voice channel**. + + + `{0}q Dream Of Venice` + + + soundcloudqueue sq + + + Queue a soundcloud song using keywords. Bot will join your voice channel.**You must be in a voice channel**. + + + `{0}sq Dream Of Venice` + + + listqueue lq + + + Lists 15 currently queued songs per page. Default page is 1. + + + `{0}lq` or `{0}lq 2` + + + nowplaying np + + + Shows the song currently playing. + + + `{0}np` + + + volume vol + + + Sets the music volume 0-100% + + + `{0}vol 50` + + + defvol dv + + + Sets the default music volume when music playback is started (0-100). Persists through restarts. + + + `{0}dv 80` + + + max + + + Sets the music volume to 100%. + + + `{0}max` + + + half + + + Sets the music volume to 50%. + + + `{0}half` + + + playlist pl + + + Queues up to 500 songs from a youtube playlist specified by a link, or keywords. + + + `{0}pl playlist link or name` + + + soundcloudpl scpl + + + Queue a soundcloud playlist using a link. + + + `{0}scpl soundcloudseturl` + + + localplaylst lopl + + + Queues all songs from a directory. + + + `{0}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: <https://streamable.com/al54>) + + + `{0}ra radio link here` + + + local lo + + + Queues a local file by specifying a full path. + + + `{0}lo C:/music/mysong.mp3` + + + move mv + + + Moves the bot to your voice channel. (works only if music is already playing) + + + `{0}mv` + + + remove rm + + + Remove a song by its # in the queue, or 'all' to remove whole queue. + + + `{0}rm 5` + + + movesong ms + + + Moves a song from one position to another. + + + `{0}ms 5>3` + + + setmaxqueue smq + + + Sets a maximum queue size. Supply 0 or no argument to have no limit. + + + `{0}smq 50` or `{0}smq` + + + cleanup + + + Cleans up hanging voice connections. + + + `{0}cleanup` + + + reptcursong rcs + + + Toggles repeat of current song. + + + `{0}rcs` + + + rpeatplaylst rpl + + + Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). + + + `{0}rpl` + + + save + + + Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. + + + `{0}save classical1` + + + load + + + Loads a saved playlist using it's ID. Use `{0}pls` to list all saved playlists and {0}save to save new ones. + + + `{0}load 5` + + + playlists pls + + + Lists all playlists. Paginated. 20 per page. Default page is 0. + + + `{0}pls 1` + + + deleteplaylist delpls + + + Deletes a saved playlist. Only if you made it or if you are the bot owner. + + + `{0}delpls animu-5` + + + goto + + + Goes to a specific time in seconds in a song. + + + `{0}goto 30` + + + autoplay ap + + + Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty) + + + `{0}ap` + + + lolchamp + + + Shows League Of Legends champion statistics. If there are spaces/apostrophes or in the name - omit them. Optional second parameter is a role. + + + `{0}lolchamp Riven` or `{0}lolchamp Annie sup` + + + lolban + + + Shows top banned champions ordered by ban rate. + + + `{0}lolban` + + + hitbox hb + + + Notifies this channel when a certain user starts streaming. + + + `{0}hitbox SomeStreamer` + + + twitch tw + + + Notifies this channel when a certain user starts streaming. + + + `{0}twitch SomeStreamer` + + + beam bm + + + Notifies this channel when a certain user starts streaming. + + + `{0}beam SomeStreamer` + + + removestream rms + + + Removes notifications of a certain streamer from a certain platform on this channel. + + + `{0}rms Twitch SomeGuy` or `{0}rms Beam SomeOtherGuy` + + + liststreams ls + + + Lists all streams you are following on this server. + + + `{0}ls` + + + convert + + + Convert quantities. Use `{0}convertlist` to see supported dimensions and currencies. + + + `{0}convert m km 1000` + + + convertlist + + + List of the convertible dimensions and currencies. + + + `{0}convertlist` + + + wowjoke + + + Get one of Kwoth's penultimate WoW jokes. + + + `{0}wowjoke` + + + calculate calc + + + Evaluate a mathematical expression. + + + `{0}calc 1+1` + + + osu + + + Shows osu stats for a player. + + + `{0}osu Name` or `{0}osu Name taiko` + + + osub + + + Shows information about an osu beatmap. + + + `{0}osub https://osu.ppy.sh/s/127712` + + + osu5 + + + Displays a user's top 5 plays. + + + `{0}osu5 Name` + + + pokemon poke + + + Searches for a pokemon. + + + `{0}poke Sylveon` + + + pokemonability pokeab + + + Searches for a pokemon ability. + + + `{0}pokeab overgrow` + + + memelist + + + Pulls a list of memes you can use with `{0}memegen` from http://memegen.link/templates/ + + + `{0}memelist` + + + memegen + + + Generates a meme from memelist with top and bottom text. + + + `{0}memegen biw "gets iced coffee" "in the winter"` + + + weather we + + + Shows weather data for a specified city. You can also specify a country after a comma. + + + `{0}we Moscow, RU` + + + youtube yt + + + Searches youtubes and shows the first result + + + `{0}yt query` + + + anime ani aq + + + Queries anilist for an anime and shows the first result. + + + `{0}ani aquarion evol` + + + imdb omdb + + + Queries omdb for movies or series, show first result. + + + `{0}imdb Batman vs Superman` + + + manga mang mq + + + Queries anilist for a manga and shows the first result. + + + `{0}mq Shingeki no kyojin` + + + randomcat meow + + + Shows a random cat image. + + + `{0}meow` + + + randomdog woof + + + Shows a random dog image. + + + `{0}woof` + + + image img + + + Pulls the first image found using a search parameter. Use {0}rimg for different results. + + + `{0}img cute kitten` + + + randomimage rimg + + + Pulls a random image using a search parameter. + + + `{0}rimg cute kitten` + + + lmgtfy + + + Google something for an idiot. + + + `{0}lmgtfy query` + + + google g + + + Get a google search link for some terms. + + + `{0}google query` + + + hearthstone hs + + + Searches for a Hearthstone card and shows its image. Takes a while to complete. + + + `{0}hs Ysera` + + + urbandict ud + + + Searches Urban Dictionary for a word. + + + `{0}ud Pineapple` + + + # + + + Searches Tagdef.com for a hashtag. + + + `{0}# ff` + + + catfact + + + Shows a random catfact from <http://catfacts-api.appspot.com/api/facts> + + + `{0}catfact` + + + yomama ym + + + Shows a random joke from <http://api.yomomma.info/> + + + `{0}ym` + + + randjoke rj + + + Shows a random joke from <http://tambal.azurewebsites.net/joke/random> + + + `{0}rj` + + + chucknorris cn + + + Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random> + + + `{0}cn` + + + magicitem mi + + + Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items> + + + `{0}mi` + + + revav + + + Returns a google reverse image search for someone's avatar. + + + `{0}revav "@SomeGuy"` + + + revimg + + + Returns a google reverse image search for an image from a link. + + + `{0}revimg Image link` + + + safebooru + + + Shows a random image from safebooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) + + + `{0}safebooru yuri+kissing` + + + wikipedia wiki + + + Gives you back a wikipedia link + + + `{0}wiki query` + + + color clr + + + Shows you what color corresponds to that hex. + + + `{0}clr 00ff00` + + + videocall + + + Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message. + + + `{0}videocall "@SomeGuy"` + + + avatar av + + + Shows a mentioned person's avatar. + + + `{0}av "@SomeGuy"` + + + 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. + + + `{0}hentai yuri` + + + danbooru + + + Shows a random hentai image from danbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) + + + `{0}danbooru yuri+kissing` + + + atfbooru atf + + + Shows a random hentai image from atfbooru with a given tag. Tag is optional but preferred. + + + `{0}atfbooru yuri+kissing` + + + gelbooru + + + Shows a random hentai image from gelbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) + + + `{0}gelbooru yuri+kissing` + + + rule34 + + + Shows a random image from rule34.xx with a given tag. Tag is optional but preferred. (multiple tags are appended with +) + + + `{0}rule34 yuri+kissing` + + + e621 + + + Shows a random hentai image from e621.net with a given tag. Tag is optional but preferred. Use spaces for multiple tags. + + + `{0}e621 yuri kissing` + + + cp + + + We all know where this will lead you to. + + + `{0}cp` + + + boobs + + + Real adult content. + + + `{0}boobs` + + + butts ass butt + + + Real adult content. + + + `{0}butts` or `{0}ass` + + + createwar cw + + + Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. + + + `{0}cw 15 The Enemy Clan` + + + startwar sw + + + Starts a war with a given number. + + + `{0}sw 15` + + + listwar lw + + + Shows the active war claims by a number. Shows all wars in a short way if no number is specified. + + + `{0}lw [war_number] or {0}lw` + + + claim call c + + + Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. + + + `{0}call [war_number] [base_number] [optional_other_name]` + + + claimfinish cf + + + Finish your claim with 3 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. + + + `{0}cf 1` or `{0}cf 1 5` + + + claimfinish2 cf2 + + + Finish your claim with 2 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. + + + `{0}cf2 1` or `{0}cf2 1 5` + + + claimfinish1 cf1 + + + Finish your claim with 1 star if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. + + + `{0}cf1 1` or `{0}cf1 1 5` + + + unclaim ucall uc + + + Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim + + + `{0}uc [war_number] [optional_other_name]` + + + endwar ew + + + Ends the war with a given index. + + + `{0}ew [war_number]` + + + translate trans + + + Translates from>to text. From the given language to the destination language. + + + `{0}trans en>fr Hello` + + + translangs + + + Lists the valid languages for translation. + + + `{0}translangs` + + + Sends a readme and a guide links to the channel. + + + `{0}readme` or `{0}guide` + + + readme guide + + + Shows all available operations in {0}calc command + + + `{0}calcops` + + + calcops + + + Deletes all quotes on a specified keyword. + + + `{0}delallq kek` + + + delallq daq + + + greetdmmsg + + + `{0}greetdmmsg Welcome to the server, %user%`. + + + Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. + + + Check how much currency a person has. (Defaults to yourself) + + + `{0}$$` or `{0}$$ @SomeGuy` + + + cash $$ + + + Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions. + + + `{0}lp` or `{0}lp 3` + + + listperms lp + + + Enable or disable all modules for a specific user. + + + `{0}aum enable @someone` + + + allusrmdls aum + + + Moves permission from one position to another in Permissions list. + + + `{0}mp 2 4` + + + moveperm mp + + + Removes a permission from a given position in Permissions list. + + + `{0}rp 1` + + + removeperm rp + + + Migrate data from old bot configuration + + + `{0}migratedata` + + + migratedata + + + Checks if a user is online on a certain streaming platform. + + + `{0}cs twitch MyFavStreamer` + + + checkstream cs + + + showemojis se + + + Shows a name and a link to every SPECIAL emoji in the message. + + + `{0}se A message full of SPECIAL emojis` + + + shuffle sh + + + Reshuffles all cards back into the deck. + + + `{0}sh` + + + fwmsgs + + + Toggles forwarding of non-command messages sent to bot's DM to the bot owners + + + `{0}fwmsgs` + + + fwtoall + + + Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json + + + `{0}fwtoall` + + + resetperms + + + Resets BOT's permissions module on this server to the default value. + + + `{0}resetperms` + + + antiraid + + + Sets an anti-raid protection on the server. First argument is number of people which will trigger the protection. Second one is a time interval in which that number of people needs to join in order to trigger the protection, and third argument is punishment for those people (Kick, Ban, Mute) + + + `{0}antiraid 5 20 Kick` + + + antispam + + + Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10. + + + `{0}antispam 3 Mute` or `{0}antispam 4 Kick` or `{0}antispam 6 Ban` + + + chatmute + + + Prevents a mentioned user from chatting in text channels. + + + `{0}chatmute @Someone` + + + voicemute + + + Prevents a mentioned user from speaking in voice channels. + + + `{0}voicemute @Someone` + + + konachan + + + Shows a random hentai image from konachan with a given tag. Tag is optional but preferred. + + + `{0}konachan yuri` + + + setmuterole + + + Sets a name of the role which will be assigned to people who should be muted. Default is nadeko-mute. + + + `{0}setmuterole Silenced` + + + adsarm + + + Toggles the automatic deletion of confirmations for {0}iam and {0}iamn commands. + + + `{0}adsarm` + + + setstream + + + Sets the bots stream. First argument is the twitch link, second argument is stream name. + + + `{0}setstream TWITCHLINK Hello` + + + chatunmute + + + Removes a mute role previously set on a mentioned user with `{0}chatmute` which prevented him from chatting in text channels. + + + `{0}chatunmute @Someone` + + + unmute + + + Unmutes a mentioned user previously muted with `{0}mute` command. + + + `{0}unmute @Someone` + + + xkcd + + + Shows a XKCD comic. No arguments will retrieve random one. Number argument will retrieve a specific comic, and "latest" will get the latest one. + + + `{0}xkcd` or `{0}xkcd 1400` or `{0}xkcd latest` + + + placelist + + + Shows the list of available tags for the `{0}place` command. + + + `{0}placelist` + + + place + + + Shows a placeholder image of a given tag. Use `{0}placelist` to see all available tags. You can specify the width and height of the image as the last two optional arguments. + + + `{0}place Cage` or `{0}place steven 500 400` + + + togethertube totube + + + Creates a new room on <https://togethertube.com> and shows the link in the chat. + + + `{0}totube` + + + publicpoll ppoll + + + Creates a public poll which requires users to type a number of the voting option in the channel command is ran in. + + + `{0}ppoll Question?;Answer1;Answ 2;A_3` + + + autotranslang atl + + + Sets your source and target language to be used with `{0}at`. Specify no arguments to remove previously set value. + + + `{0}atl en>fr` + + + autotrans at + + + Starts automatic translation of all messages by users who set their `{0}atl` in this channel. You can set "del" argument to automatically delete all translated user messages. + + + `{0}at` or `{0}at del` + + + listquotes liqu + + + `{0}liqu` or `{0}liqu 3` + + + Lists all quotes on the server ordered alphabetically. 15 Per page. + + + typedel + + + Deletes a typing article given the ID. + + + `{0}typedel 3` + + + typelist + + + Lists added typing articles with their IDs. 15 per page. + + + `{0}typelist` or `{0}typelist 3` + + + listservers + + + Lists servers the bot is on with some basic info. 15 per page. + + + `{0}listservers 3` + + + hentaibomb + + + Shows a total 5 images (from gelbooru, danbooru, konachan, yandere and atfbooru). Tag is optional but preferred. + + + `{0}hentaibomb yuri` + + + cleverbot + + + Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. + + + `{0}cleverbot` + + + shorten + + + Attempts to shorten an URL, if it fails, returns the input URL. + + + `{0}shorten https://google.com` + + + minecraftping mcping + + + Pings a minecraft server. + + + `{0}mcping 127.0.0.1:25565` + + + minecraftquery mcq + + + Finds information about a minecraft server. + + + `{0}mcq server:ip` + + + wikia + + + Gives you back a wikia link + + + `{0}wikia mtg Vigilance` or `{0}wikia mlp Dashy` + + + yandere + + + Shows a random image from yandere with a given tag. Tag is optional but preferred. (multiple tags are appended with +) + + + `{0}yandere tag1+tag2` + + + magicthegathering mtg + + + Searches for a Magic The Gathering card. + + + `{0}magicthegathering about face` or `{0}mtg about face` + + + yodify yoda + + + Translates your normal sentences into Yoda styled sentences! + + + `{0}yoda my feelings hurt` + + + attack + + + Attacks a target with the given move. Use `{0}movelist` to see a list of moves your type can use. + + + `{0}attack "vine whip" @someguy` + + + heal + + + Heals someone. Revives those who fainted. Costs a NadekoFlower + + + `{0}heal @someone` + + + movelist ml + + + Lists the moves you are able to use + + + `{0}ml` + + + settype + + + Set your poketype. Costs a NadekoFlower. Provide no arguments to see a list of available types. + + + `{0}settype fire` or `{0}settype` + + + type + + + Get the poketype of the target. + + + `{0}type @someone` + + + hangmanlist + + + Shows a list of hangman term types. + + + `{0} hangmanlist` + + + hangman + + + Starts a game of hangman in the channel. Use `{0}hangmanlist` to see a list of available term types. Defaults to 'all'. + + + `{0}hangman` or `{0}hangman movies` + + + crstatsclear + + + Resets the counters on `{0}crstats`. You can specify a trigger to clear stats only for that trigger. + + + `{0}crstatsclear` or `{0}crstatsclear rng` + + + crstats + + + Shows a list of custom reactions and the number of times they have been executed. Paginated with 10 per page. Use `{0}crstatsclear` to reset the counters. + + + `{0}crstats` or `{0}crstats 3` + + + overwatch ow + + + Show's basic stats on a player (competitive rank, playtime, level etc) Region codes are: `eu` `us` `cn` `kr` + + + `{0}ow us Battletag#1337` or `{0}overwatch eu Battletag#2016` + + + acrophobia acro + + + Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60) + + + `{0}acro` or `{0}acro 30` + + + logevents + + + Shows a list of all events you can subscribe to with `{0}log` + + + `{0}logevents` + + + log + + + Toggles logging event. Disables it if it's active anywhere on the server. Enables if it's not active. Use `{0}logevents` to see a list of all events you can subscribe to. + + + `{0}log userpresence` or `{0}log userbanned` + + + fairplay fp + + + Toggles fairplay. While enabled, music player will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue. + + + `{0}fp` + + + define def + + + Finds a definition of a word. + + + `{0}def heresy` + + + setmaxplaytime smp + + + Sets a maximum number of seconds (>14) a song can run before being skipped automatically. Set 0 to have no limit. + + + `{0}smp 0` or `{0}smp 270` + + + activity + + + Checks for spammers. + + + `{0}activity` + + + 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. + + + `{0}autohentai 30 yuri|tail|long_hair` or `{0}autohentai` + + + setstatus + + + Sets the bot's status. (Online/Idle/Dnd/Invisible) + + + `{0}setstatus Idle` + + + rotaterolecolor rrc + + + Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. + + + `{0}rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `{0}rrc 0 MyLsdRole` + + + createinvite crinv + + + Creates a new invite which has infinite max uses and never expires. + + + `{0}crinv` + + + pollstats + + + Shows the poll results without stopping the poll on this server. + + + `{0}pollstats` + + + repeatlist replst + + + Shows currently repeating messages and their indexes. + + + `{0}repeatlist` + + + repeatremove reprm + + + Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes. + + + `{0}reprm 2` + + + antilist antilst + + + Shows currently enabled protection features. + + + `{0}antilist` + + + antispamignore + + + Toggles whether antispam ignores current channel. Antispam must be enabled. + + + `{0}antispamignore` + + + cmdcosts + + + Shows a list of command costs. Paginated with 9 command per page. + + + `{0}cmdcosts` or `{0}cmdcosts 2` + + + commandcost cmdcost + + + Sets a price for a command. Running that command will take currency from users. Set 0 to remove the price. + + + `{0}cmdcost 0 !!q` or `{0}cmdcost 1 >8ball` + + + startevent + + + Starts one of the events seen on public nadeko. + + + `{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` + + + affinity + + + 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 @MyHusband` or `{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 9 waifus. + + + `{0}waifus` + + + 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. + + + `{0}divorce @CheatingSloot` + + + waifuinfo waifustats + + + Shows waifu stats for a target person. Defaults to you if no user is provided. + + + `{0}waifuinfo @MyCrush` or `{0}waifuinfo` + + + mal + + + Shows basic info from myanimelist profile. + + + `{0}mal straysocks` + + + setmusicchannel smch + + + Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in. + + + `{0}smch` + + + reloadimages + + + Reloads images bot is using. Safe to use even when bot is being used heavily. + + + `{0}reloadimages` + + + shardstats + + + Stats for shards. Paginated with 25 shards per page. + + + `{0}shardstats` or `{0}shardstats 2` + + + connectshard + + + Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. + + + `{0}connectshard 2` + + + shardid + + + Shows which shard is a certain guild on, by guildid. + + + `{0}shardid 117523346618318850` + + + tictactoe ttt + + + Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. 15 seconds per move. + + + >ttt + + + timezones + + + List of all timezones available on the system to be used with `{0}timezone`. + + + `{0}timezones` + + + timezone + + + Sets this guilds timezone. This affects bot's time output in this server (logs, etc..) + + + `{0}timezone` + + + langsetdefault langsetd + + + Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. + + + `{0}langsetd en-US` or `{0}langsetd default` + + + languageset langset + + + Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. + + + `{0}langset de-DE ` or `{0}langset default` + + + languageslist langli + + + List of languages for which translation (or part of it) exist atm. + + + `{0}langli` + + + rategirl + + + Use the universal hot-crazy wife zone matrix to determine the girl's worth. It is everything young men need to know about women. At any moment in time, any woman you have previously located on this chart can vanish from that location and appear anywhere else on the chart. + + + `{0}rategirl @SomeGurl` + + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 49072329..a33b43b9 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2180,15 +2180,6 @@ namespace NadekoBot.Resources { } } - /// - /// Looks up a localized string similar to Betflip Gamble. - /// - public static string gambling_betflip_gamble { - get { - return ResourceManager.GetString("gambling_betflip_gamble", resourceCulture); - } - } - /// /// Looks up a localized string similar to Better luck next time ^_^. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx new file mode 100644 index 00000000..898269f2 --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx @@ -0,0 +1,2184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Esta base já está aclamada ou destruída. + + + Esta base já está destruída. + + + Esta base não está aclamada. + + + + + + + + + + + + @{0} Você já clamou esta base #{1}. Você não pode clamar uma nova. + + + + + + Inimigo + + + + Informações sobre a guerra contra {0} + + + Número de base inválido. + + + Não é um tamanho de guerra válido. + + + Lista de guerras ativas + + + não clamado + + + Você não está participando nesta guerra. + + + @{0} Você não está participando nessa guerra, ou aquela base já está destruída. + + + Nenhuma guerra ativa. + + + Tamanho + + + Guerra contra {0} já começou. + + + Guera contra {0} criada. + + + Guerra contra {0} acabou. + + + Essa guerra não existe. + + + Guerra contra {0} começou! + + + Todos os status de reações personalizadas limpados. + + + Reação personalizada deletada + + + Permissão Insuficiente. Necessita o domínio do bot para reações personalizadas globais, e administrador para reações personalizadas em server. + + + Lista de todas as reações personalizadas + + + Reações personalizadas + + + Nova reação personalizada + + + Nenhuma reação personalizada encontrada. + + + Nenhuma reação personalizada encontrada com este id. + + + Resposta + + + Status de reações customizáveis + + + Status limpado para {0} reação customizável. + + + Nenhum status para aquele comando achado, nenhuma ação foi tomada. + + + Comando + + + Autohentai parou. + + + Nenhum resultado encontrado. + + + {0} já desmaiou. + + + {0} já tem HP cheio. + + + Seu tipo já é {0} + + + usou {0}{1} em {2}{3} para {4} dano. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + Você não pode atacar novamente sem retaliação! + + + Você não pode atacar a si mesmo. + + + {0} desmaiou! + + + curou {0} com uma {1} + + + {0} Tem {1} HP restante. + + + Você não pode usar {0}. Digite `{1}ml` para ver uma lista de ataques que você pode usar. + + + Lista de golpes para tipo {0} + + + Não é efetivo. + + + Você não tem {0} o suficiente + + + Reviveu {0} com uma {1} + + + Você reviveu a si mesmo com uma {0} + + + Seu tipo foi mudado de {0} para {1} + + + É mais ou menos efetivo. + + + É super efetivo! + + + Você usou muitos ataques de uma vez, então você não pode se mexer! + + + Tipo de {0} é {1} + + + Usuário não encontrado. + + + Você desmaiou, então você não pode se mexer! + + + **Cargo Automático** para novos usuários **desabilitado**. + + + **Cargo Automático** para novos usuários **habilitado** + + + Anexos + + + Avatar mudado + + + Você foi BANIDO do servidor {0}. +Razão: {1} + + + Banidos + PLURAL + + + Usuário Banido + + + Nome do bot mudado para {0}. + + + Status do bot mudado para {0}. + + + Deleção automática de mensagens de despedida foi desativado. + + + Mensagens de despedida serão deletas após {0} segundos. + + + Mensagem de despedida atual: {0} + + + Ative mensagens de despedidas digitando {0} + + + Nova mensagem de despedida colocada. + + + Mensagens de despedidas desativadas. + + + Mensagens de despedidas foram ativadas neste canal. + + + Nome do canal mudado + + + Nome antigo + + + Tópico do canal mudado + + + Limpo. + + + Conteúdo + + + Cargo {0} criado com sucesso. + + + Canal de texto {0} criado. + + + Canal de voz {0} criado. + + + Ensurdecido com sucesso. + + + Servidor {0} deletado. + + + Parou a eliminação automática de invocações de comandos bem sucedidos. + + + Agora automaticamente deletando invocações de comandos bem sucedidos + + + Canal de texto {0} deletado. + + + Canal de voz {0} deletado. + + + Mensagem direta de + + + Novo doador adicionado com sucesso. Número total doado por este usuário: {0} 👑 + + + Obrigado às pessoas listadas abaixo por fazer este projeto acontecer! + + + Vou enviar mensagens diretas a todos os donos. + + + Vou enviar mensagens diretas apenas ao primeiro dono. + + + Vou enviar mensagens diretas de agora em diante. + + + Vou parar de enviar mensagens diretas de agora em diante. + + + Eliminação automática de mensagens de boas vindas desabilitada. + + + Mensagens de boas vindas serão deletadas após {0} segundos. + + + Mensagem direta de boas vindas atual: {0} + + + Ative mensagens diretas de boas vindas digitando {0} + + + Novas mensagen direta de boas vindas definida. + + + + + + + + + Mensagem de boas vindas atual: {0} + + + Ative mensagens de boas vindas digitando {0} + + + Nova mensagem de boas vindas definida. + + + Anúncios de boas vindas desabilitados. + + + Anúncios de boas vindas habilitados neste canal. + + + Você não pode usar este comando em usuários com um cargo maior ou igual ao seu na hierarquia dos cargos. + + + Imagens carregadas após {0} segundos! + + + + + + Parâmetros inválidos. + + + {0} juntou-se a {1} + + + Você foi banido do servidor {0}. +Razão: {1} + + + Usuário Chutado + + + Lista de linguagens +{0} + + + A região do seu servidor agora é {0} - {1} + + + A região padrão do bot agora é {0} - {1} + + + A linguagem foi definida para {0} - {1} + + + Falha ao definir região. Veja a ajuda desse comando. + + + A língua do servidor está definida para: {0} - {1} + + + {0} saiu de {1} + + + Servidor {0} deixado. + + + + + + + + + + + + + + + + + + + + + + + + + + + Mensagem de {0} `[Bot Owner]` + + + Mensagem enviada. + + + {0} movido de {1} to {2} + + + Mensagem deletada em #{0} + + + Mensagem atualizada em #{0} + + + Mutados + PLURAL (users have been muted) + + + Mutado + singular "User muted." + + + Não tenho a permissão para isso, provavelmente. + + + Novo cargo mudo definido. + + + Eu preciso da permissão de **Administrador** para fazer isso. + + + Nova mensagem + + + Novo Apelido + + + Novo Tópico + + + Apelido Alterado + + + Não posso achar esse servidor + + + Nenhum shard com aquele ID foi encontrado. + + + Mensagem Antiga + + + Apelido Antigo + + + Tópico Antigo + + + Erro. Não tenho permissões suficientes. + + + As permissões para este servidor foram resetadas. + + + Proteções ativadas + + + {0} foi **desativado** neste servidor. + + + {0} Ativado + + + Erro. Preciso da permissão "Gerenciar Cargos". + + + Nenhuma proteção ativa. + + + + + + + + + O tempo deve ser entre {0} e {1} segundos. + + + Todos os cargos foram removidos do usuário {0} com sucesso. + + + Falha ao remover cargos. Eu não possuo permissões suficientes + + + + A cor do cargo {0} foi alterada. + + + Esse cargo não existe. + + + Os parâmetros especificados são inválidos. + + + Um erro ocorreu devido à cor inválida ou permissões insuficientes. + + + Cargo {0} removido do usuário {1} com sucesso. + + + Falha ao remover o cargo. Não possuo permissões suficientes. + + + Cargo renomeado. + + + Falha ao renomear o cargo. Não possuo permissões suficientes. + + + Você não pode editar cargos superiores ao seu cargo mais elevado. + + + + + + O cargo {0} foi adicionado a lista. + + + {0} não encontrado. Limpo. + + + O cargo {0} já está na lista. + + + Adicionado. + + + + + + + + + + + + + + + Você já possui o cargo {0}. + + + + + + Cargos auto-atribuíveis agora são exclusivos! + + + + + + Esse cargo não é auto-atribuível + + + Você não possui o cargo {0}. + + + + + + Não sou capaz de adicionar esse cargo a você. `Não posso adicionar cargos a donos ou outros cargos maiores que o meu cargo na hierarquia dos cargos.` + + + {0} foi removido da lista de cargos auto-aplicáveis. + + + + + + + + + + + + Falha ao adicionar o cargo. Não possuo permissões suficientes. + + + Novo avatar definido! + + + Novo nome do canal definido. + + + Novo jogo definido! + + + Nova stream definida! + + + Novo tópico do canal definido. + + + Shard {0} reconectado. + + + Reconectando shard {0}. + + + Desligando + + + Usuários não podem mandar mais de {0} mensagens a cada {1} segundos + + + Modo lento desativado. + + + Modo lento iniciado. + + + + PLURAL + + + {0} irá ignorar esse canal. + + + {0} irá deixar de ignorar esse canal. + + + Se um usuário postar {0} mensagens iguais em seguida, eu irei {1} eles. +__Canais Ignorados__: {2} + + + Canal de Texto Criado + + + Canal de Texto Destruído + + + + + + Desmutado + singular + + + Nome de usuário + + + Nome de usuário alterado + + + Usuários + + + Usuário Banido + + + {0} foi **mutado** + + + {0} foi **desmutado** + + + Usuário juntou-se + + + Usuário saiu + + + {0} foi **mutado** nos chats de voz e texto. + + + Cargo do usuário adicionado + + + Cargo do usuário removido + + + {0} agora está {1} + + + + + + {0} juntou-se ao canal de voz {1}. + + + {0} deixou o canal de voz {1}. + + + {0} moveu-se do canal de voz {1} para {2}. + + + {0} foi **mutado por voz** + + + {0} foi **desmutado por voz** + + + Canal de voz criado + + + Canal de voz destruído + + + + + + + + + + + + + + + + + + Usuário {0} do chat de texto + + + Usuário {0} dos chats de voz e texto + + + + + + + + + Usuário desbanido + + + Migração concluída! + + + + + + + + + + + + + + + Mais sorte na próxima vez ^_^ + + + Parabéns! Você ganhou {0} por rolar acima {1} + + + Baralho re-embaralhado. + + + + User flipped tails. + + + Você Adivinhou! Você ganhou {0} + + + O número especificado é inválido. Você pode girar de 1 a {0} moedas. + + + + + + Este evento está ativo por até {0} horas. + + + + + + deu {0} de presente para {1} + X has gifted 15 flowers to Y + + + {0} tem {1} + X has Y flowers + + + Cara + + + Placar de Líderes + + + + + + Você não pode apostar mais que {0} + + + Você não pode apostar menos que {0} + + + Você não tem {0} suficientes. + + + Sem cartas no baralho. + + + Usuario sorteado + + + + + + Aposta + + + WOAAHHHHHH!!! Parabéns!!! x{0} + + + + + + Wow! Que sorte! Três de um tipo! x{0} + + + Bom trabalho! Dois {0} - aposta x{1} + + + Ganhou + + + + + + + + + + + + Coroa + + + Tomou {0} de {1} com sucesso + + + Não foi possível tomar {0} de {1} porque o usuário não possuí tanto {2}! + + + + + + Proprietário do bot apenas. + + + Requer a permissão {0} do canal + + + Você pode dar suporte ao projeto no Patreon: <{0}> ou Paypal: <{1}> + + + Comandos e abreviações + + + + + + Digite `{0}h NomeDoComando` para ver a ajuda para o comando especificado. Ex: `{0}h >8ball` + + + Não consigo encontrar esse comando. Por favor, verifique se esse comando existe antes de tentar de novo. + + + Descrição + + + Você pode dar suporte ao projeto da NadekoBot por +Patreon <{0}> ou +Paypal <{1}> +Não esqueça de deixar seu nome ou id do discord na mensagem. +**Obrigado**♥️ + + + **Lista de Comandos**. <{0}> +**Guias de hosteamento e documentos podem ser encontrados aqui**. <{1}> + + + Lista de Comandos + + + Lista de Módulos + + + Digite `{0}cmds NomeDoMódulo` para receber uma lista de comandos deste módulo. Ex: `{0}cmds games` + + + Esse módulo não existe. + + + Requer a permissão {0} do servidor. + + + Tabela de Conteúdo + + + Modo de uso + + + Autohentai iniciado. Repostando a cada {0}s com uma das seguintes tags: +{1} + + + Tag + + + Corrida de Animais + + + Falha ao iniciar já que não tiveram participantes suficientes. + + + Corrida cheia! Começando imediatamente + + + {0} juntou-se como {1} + + + {0} juntou-se como {1} e apostou {2}! + + + Digite {0}jr para juntar-se a corrida. + + + Iniciando em 20 segundos ou quando estiver completa. + + + Iniciando com {0} participantes. + + + {0} como {1} ganhou a corrida! + + + {0} como {1} ganhou a corrida e {2}! + + + + + + + Someone rolled 35 + + + Dados rolados: {0} + Dice Rolled: 5 + + + Falha ao iniciar a corrida. Outra corrida provavelmente está em andamento. + + + Nenhuma raça existe neste servidor. + + + O segundo número deve ser maior que o primeiro. + + + Mudanças no Coração + + + Clamado por + + + Divórcios + + + + + + Preço + + + Nenhuma waifu foi reivindicada ainda. + + + Top Waifus + + + + + + Mudou a afinidade de {0} para {1}. + +*Isto é moralmente questionável.*🤔 + Make sure to get the formatting right, and leave the thinking emoji + + + + + + Sua afinidade foi reiniciada. Você não possui mas alguém que você goste. + + + quer ser a waifu de {0}. Aww <3 + + + clamou {0} como sua waifu por {1}! + + + Você se divorciou de uma waifu que gostava de você. Seu monstro sem coração. +{0} recebeu {1} como compensação. + + + Você não pode colocar sua afinidade em você mesmo, seu egomaníaco. + + + + + + Nenhuma waifu é tão barata. Você deve pagar pelo menos {0} para ter uma waifu, mesmo se o valor dela for menor. + + + Você deve pagar {0} ou mais para reivindicar essa waifu! + + + Essa waifu não é sua. + + + Você não pode reivindicar a si próprio. + + + Você se divorciou recentemente. Aguarde {0} horas e {1} minutos para se divorciar de novo. + + + Ninguém + + + Você se divorciou de uma waifu que não gostava de você. Você recebeu {0} de volta. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Questão + + + É um empate! ambos escolheram {0} + + + + + + + + + A Corrida de Animais já está em andamento + + + Total: {1} Média: {1} + + + Categoria + + + + + + Cleverbot ativado neste servidor. + + + + + + + + + + plural + + + + + + Falha ao carregar a questão + + + Jogo Iniciado + + + + + + + + + + + + + + + Placar de Lideres + + + Você não possui {0} suficiente + + + Sem resultados + + + pegou {0} + Kwoth picked 5* + + + {0} plantou {1} + Kwoth planted 5* + + + Trivia já está em andamento neste servidor. + + + Trivia + + + + + + Nenhuma trivia está em andamento neste servidor. + + + {0} tem {1} pontos + + + Parando após esta questão. + + + Tempo esgotado! A resposta correta era {0} + + + {0} adivinhou e VENCEU o jogo! A resposta era: {1} + + + Você não pode jogar contra si mesmo. + + + Um Jogo da Velha já está em andamento neste canal. + + + Um empate! + + + criou um Jogo da Velha. + + + {0} venceu! + + + Combinou três + + + Nenhum movimento restante! + + + Tempo Esgotado! + + + É a vez de {0} + + + {0} vs {1} + + + + + + Autoplay desabilitado. + + + Autoplay habilitado. + + + Volume padrão definido para {0}% + + + + + + + + + Música concluída. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Você precisa estar em um canal de voz nesse servidor + + + Nome + + + Tocando agora + + + Nenhum player de música ativo. + + + Nenhum resultado para a busca. + + + + + + + + + Tocando Musica + + + + + + Página {0} de Playlists Salvas + + + Playlist deletada. + + + Falha ao deletar essa playlist. Ela não existe ou você não é seu o criador. + + + + + + + + + Playlist Salva + + + + + + Fila + + + Músicas em fila + + + Fila de músicas limpa. + + + A fila está cheia em {0}/{0} + + + Música removida + context: "removed song #5" + + + Repetindo a Música Atual + + + Repetindo Playlist + + + Repetindo Faixa + + + + + + + + + Repetição de playlist desabilitada. + + + Repetição de playlist habilitada. + + + + + + + + + Musicas embaralhadas. + + + Musica movida. + + + + + + + + + + + + Volume deve estar entre 0 e 100 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Negado + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Comando + Gen (of command) + + + + Gen. (of module) + + + + + + + + + + + + + + + + + + + + + + + + + Short of seconds. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Habilidades + + + Nenhum anime favorito ainda + + + + + + + + + + + + + + + + + + + + + + + + Fato + + + Capítulos + + + + + + + + + + + + + + + + + + Completado + + + Condição + + + Custo + + + Data + + + Defina + + + + + + Episódios + + + Ocorreu um erro. + + + Exemplo + + + Falha ao encontrar este animu. + + + Falha ao encontrar este mango. + + + Gêneros + + + + + + Altura/Peso + + + + + + + + + + + + Falha ao encontrar este filme. + + + + + + + + + + + + + + + + Don't translate {0}place + + + Localização + + + + + + + + + + + + Min/Max + + + Nenhum canal encontrado + + + Nenhum resultado encontrado + + + + + + Url Original + + + + + + + + + + + + Usuário não encontrado! Por favor cheque a região e a BattleTag antes de tentar de novo. + + + + + + Plataforma + + + Nenhuma habilidade encontrada. + + + Nenhum pokemon encontrado + + + Link do Perfil: + + + Qualidade + + + + + + + + + + + + Pontuação + + + + + + + + + + + + Alguma coisa deu errado + + + + + + Status + + + + + + Streamer {0} está offline + + + Streamer {0} está online com {1} espectadores + + + + + + Você não está seguindo nenhuma stream neste servidor + + + + + + + + + + + + Eu notificarei este canal quando o status mudar + + + Nascer do Sol + + + Pôr do Sol + + + Temperatura + + + Título + + + Top 3 animes favoritos: + + + Tradução: + + + Tipos + + + + + + Url + + + + + + Assistindo + + + + + + + + + Página não encontrada + + + Velocidade do Vento + + + + + + + + + + + + + /s and total need to be localized to fit the context - +`1.` + + + + + + + + + Autor + + + + + + + + + + + + Tópico do Canal + + + Comandos utilizados + + + + + + + + + + + + + + + + + + + + + + + + + + + Emojis Personalizados + + + Erro + + + + + + + + + + + + Aqui está uma lista de usuários nestes cargos + + + + + + + Invalid months value/ Invalid hours value + + + + + + + + + + + + Nenhum servidor encontrado nessa página. + + + Lista de Repetidores + + + Membros + + + Memória + + + Mensagens + + + R + + + Nome + + + Apelido + + + Ninguém está jogando esse jogo. + + + + + + Nenhum cargo nesta página. + + + + + + + + + Dono + + + Dono IDs + + + Presença + + + {0} Servidores +{1} Canais de Texto +{2} Canais de Voz + + + + + + + + + Nenhuma citação nesta página + + + Nenhuma citação que você possa remover foi encontrada + + + Citação adicionada + + + + + + Região + + + + + + + + + + + + + + + + + + Lista de repetidores + + + Nenhum repetidor neste server. + + + #{0} parou. + + + Nenhuma mensagens repetidas encontradas. + + + Resultado + + + Cargos + + + + + + + + + + + + + + + + + + {0} deste servidor é {1} + + + Informações do Servidor + + + Fragmento + + + Status de fragmento + + + + + + **Nome:** {0} **Link:** {1} + + + Nenhum emoji especial encontrado. + + + Tocando {0} canções, {1} no queue. + + + Canais de Texto + + + Aqui está o link do quarto: + + + + + + + Id of the user kwoth#1234 is 123123123123 + + + Usuários + + + Canais de Voz + + + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 3dfd8571..efa1fe55 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -873,9 +873,6 @@ Reason: {1} has awarded {0} to {1} - - Betflip Gamble - Better luck next time ^_^ From c48d755c9a8585d1f152572b764022c3ab805159 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 01:50:52 +0100 Subject: [PATCH 371/746] Update ResponseStrings.fr-fr.resx (POEditor.com) --- .../Resources/ResponseStrings.fr-fr.resx | 134 +++++++++--------- 1 file changed, 65 insertions(+), 69 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx index dbce49d8..3708ba7a 100644 --- a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx +++ b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx @@ -118,7 +118,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Cette base a déjà été revendiquée ou détruite + Cette base a déjà été revendiquée ou détruite. Cette base est déjà détruite. @@ -130,7 +130,7 @@ Base #{0} **DETRUITE** dans une guerre contre {1} - {0} a *ABANDONNÉ* la base #{1} dans une guerre contre {2} + {0} a **ABANDONNÉ** la base #{1} dans une guerre contre {2} {0} a revendiqué une base #{1} dans une guerre contre {2} @@ -154,10 +154,10 @@ La taille de la guerre n'est pas valide. - Liste des guerres en cours. + Liste des guerres en cours - Non réclamé. + non réclamé Vous ne participez pas a cette guerre. @@ -196,8 +196,7 @@ Permissions insuffisantes. Nécessite d'être le propriétaire du Bot pour avoir les réactions personnalisées globales, et Administrateur pour les réactions personnalisées du serveur. - Liste de toutes les réactions personnalisées. - + Liste de toutes les réactions personnalisées Réactions personnalisées @@ -236,7 +235,7 @@ {0} est déjà inconscient. - {0} a toute sa vie. + {0} a tous ses PV. Votre type est déjà {0} @@ -276,7 +275,7 @@ Vous avez ressuscité {0} avec un {1} - Vous vous êtes ressuscité avec un {0}. + Vous vous êtes ressuscité avec un {0} Votre type a bien été modifié de {0} à {1} @@ -536,18 +535,18 @@ Raison : {1} Mise à jour du message dans #{0} - Tous les utilisateurs ont été mis en sourdine. + Tous les utilisateurs sont maintenant muets. PLURAL (users have been muted) - L'utilisateur à été mis en sourdine. + L'utilisateur est maintenant muet. singular "User muted." Il semblerait que je n'ai pas la permission nécessaire pour effectuer cela. - Nouveau rôle de mise en sourdine crée. + Nouveau rôle muet créé. J'ai besoin de la permission d'**Administrateur** pour effectuer cela. @@ -568,7 +567,7 @@ Raison : {1} Impossible de trouver ce serveur - Aucune partition pour cet ID trouvée. + Aucun Shard pour cet ID trouvée. Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. @@ -593,16 +592,16 @@ Raison : {1} {0} a été **désactivé** sur ce serveur. - {0} activé + {0} Activé - Erreur. J'ai besoin de la permission Gérer les rôles + Erreur. J'ai besoin de la permission Gérer les rôles. Aucune protection activée. - Le seuil d'utilisateurs doit être entre {0} et {1} + Le seuil d'utilisateurs doit être entre {0} et {1}. Si {0} ou plus d'utilisateurs rejoignent dans les {1} secondes suivantes, je les {2}. @@ -623,7 +622,7 @@ Raison : {1} Ce rôle n'existe pas. - Le paramètre spécifié est invalide. + Les paramètres spécifiés sont invalides. Erreur due à un manque de permissions ou à une couleur invalide. @@ -675,13 +674,13 @@ Raison : {1} Vous avez déjà le rôle {0}. - Vous avez déjà {0} rôles exclusifs auto-affectés. + Vous avez déjà {0} rôles exclusifs auto-attribués. - Rôles auto-affectés désormais exclusifs. + Rôles auto-attribuables désormais exclusifs. - Il y a {0} rôles auto-affectés. + Il y a {0} rôles auto-attribuables. Ce rôle ne peux pas vous être attribué par vous-même. @@ -697,7 +696,7 @@ Raison : {1} Je suis incapable de vous ajouter ce rôle. `Je ne peux pas ajouter de rôles aux propriétaires et aux autres rôles plus haut que le mien dans la hiérarchie.` - {0} a été supprimé de la liste des affectations automatiques de rôle. + {0} a été supprimé de la liste des rôles auto-attribuables. Vous n'avez plus le rôle {0}. @@ -728,11 +727,11 @@ Raison : {1} Nouveau sujet du salon défini. - Partition {0} reconnectée. + Shard {0} reconnectée. Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. - Partition {0} en reconnection. + Shard {0} en reconnection. Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. @@ -787,10 +786,10 @@ Raison : {1} Utilisateur banni - {0} a été **mis en sourdine** sur le chat. + {0} est maintenant **muet** sur le chat. - **La parole a été rétablie** sur le chat pour {0} + **La parole a été rétablie** sur le chat pour {0}. L'utilisateur a rejoint @@ -799,7 +798,7 @@ Raison : {1} L'utilisateur a quitté - {0} a été **mis en sourdine** à la fois sur le salon textuel et vocal. + {0} est maintenant **muet** à la fois sur le salon textuel et vocal. Rôle ajouté à l'utilisateur @@ -811,7 +810,7 @@ Raison : {1} {0} est maintenant {1} - {0} n'est **plus en sourdine** des salons textuels et vocaux. + {0} n'est maintenant **plus muet** des salons textuels et vocaux. {0} a rejoint le salon vocal {1}. @@ -823,10 +822,10 @@ Raison : {1} {0} est allé du salon vocal {1} au {2}. - {0} a été **mis en sourdine**. + {0} est maintenant **muet**. - {0} a été **retiré de la sourdine** + {0} n'est maintenant **plus muet**. Salon vocal crée. @@ -880,9 +879,6 @@ Raison: {1} a récompensé {0} à {1} - - Pari à pile ou face - Meilleure chance la prochaine fois ^_^ @@ -890,10 +886,10 @@ Raison: {1} Félicitations! Vous avez gagné {0} pour avoir lancé au dessus de {1} - Deck remélangé + Deck remélangé. - Lancé {0} + Lancé {0}. User flipped tails. @@ -903,13 +899,13 @@ Raison: {1} Nombre spécifié invalide. Vous pouvez lancer 1 à {0} pièces. - Ajoute {0} réaction à ce message pour avoir {1} + Ajoute la réaction {0} à ce message pour avoir {1} Cet événement est actif pendant {0} heures. - L'événement "réactions fleuries" a démaré! + L'événement "réactions fleuries" a démarré! a donné {0} à {1} @@ -926,7 +922,7 @@ Raison: {1} Classement - {1} utilisateurs du rôle {2} ont été récompensé de {0} + {1} utilisateurs du rôle {2} ont été récompensé de {0}. Vous ne pouvez pas miser plus de {0} @@ -944,7 +940,7 @@ Raison: {1} Utilisateur tiré au sort - Vous avez roulé un {0} + Vous avez roulé un {0}. Mise @@ -989,7 +985,7 @@ Raison: {1} Propriétaire du Bot seulement - Nécessite {0} permissions du salon + Nécessite {0} permissions du salon. Vous pouvez supporter ce projet sur Patreon <{0}> ou via Paypal <{1}> @@ -1022,10 +1018,10 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. **La liste des guides et tous les documents peuvent être trouvés ici**: <{1}> - Liste Des Commandes + Liste des commandes - Liste Des Modules + Liste des modules Entrez `{0}cmds NomDuModule` pour avoir la liste des commandes de ce module. ex `{0}cmds games` @@ -1037,7 +1033,7 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Permission serveur {0} requise. - Table Des Matières + Table des matières Usage @@ -1126,7 +1122,7 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Affinités changées de de {0} à {1}. -*C'est moralement questionnable* 🤔 +*C'est moralement discutable.* 🤔 Make sure to get the formatting right, and leave the thinking emoji @@ -1142,7 +1138,7 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. a revendiqué {0} comme sa waifu pour {1} - Vous avez divorcé avec une waifu qui vous aimais. Monstre sans cœur. {0} a reçu {1} en guise de compensation. + Vous avez divorcé avec une waifu qui vous aimais. Monstre sans cœur. {0} a reçu {1} en guise de compensation. vous ne pouvez pas vous lier d'affinité avec vous-même, espèce d'égocentrique. @@ -1224,7 +1220,7 @@ La nouvelle valeur de {0} est {1} ! Inscriptions terminées. - Une Course d'animaux est déjà en cours. + Une course d'animaux est déjà en cours. Total : {0} Moyenne : {1} @@ -1250,7 +1246,7 @@ La nouvelle valeur de {0} est {1} ! plural - Un {1} aléatoire est apparu ! Attrapez-le en entrant `{1}pick` + Un {0} aléatoire est apparu ! Attrapez-le en entrant `{1}pick` Impossible de charger une question. @@ -1262,7 +1258,7 @@ La nouvelle valeur de {0} est {1} ! Partie de pendu commencée. - Une partie de pendu est déjà en cours sur ce canal + Une partie de pendu est déjà en cours sur ce canal. Initialisation du pendu erronée. @@ -1280,7 +1276,7 @@ La nouvelle valeur de {0} est {1} ! Pas de résultat - choisi {0} + a cueilli {0} Kwoth picked 5* @@ -1297,7 +1293,7 @@ La nouvelle valeur de {0} est {1} ! {0} a deviné! La réponse était: {1} - Aucune partie de trivia en cours sur ce serveur. + Aucune partie de Trivia en cours sur ce serveur. {0} a {1} points @@ -1345,10 +1341,10 @@ La nouvelle valeur de {0} est {1} ! Tentative d'ajouter {0} à la file d'attente... - Lecture automatique désactivée + Lecture automatique désactivée. - Lecture automatique activée + Lecture automatique activée. Volume de base défini à {0}% @@ -1375,7 +1371,7 @@ La nouvelle valeur de {0} est {1} ! Id - Entrée invalide + Entrée invalide. Le temps maximum de lecture n'a désormais plus de limite. @@ -1402,7 +1398,7 @@ La nouvelle valeur de {0} est {1} ! Aucun lecteur de musique actif. - Pas de résultat + Pas de résultat. Lecteur mis sur pause. @@ -1420,7 +1416,7 @@ La nouvelle valeur de {0} est {1} ! Page {0} des listes de lecture sauvegardées - Liste de lecture supprimée + Liste de lecture supprimée. Impossible de supprimer cette liste de lecture. Soit elle n'existe pas, soit vous n'en êtes pas le créateur. @@ -1447,7 +1443,7 @@ La nouvelle valeur de {0} est {1} ! Liste d'attente effacée. - Liste d'attente complète ({0}/{0}) + Liste d'attente complète ({0}/{0}). Son retiré @@ -1732,10 +1728,10 @@ La nouvelle valeur de {0} est {1} ! Exemple - Impossible de trouver cet anime + Impossible de trouver cet anime. - Impossible de trouver ce manga + Impossible de trouver ce manga. Genres @@ -1759,7 +1755,7 @@ La nouvelle valeur de {0} est {1} ! Impossible de trouver ce film. - Langue d'origine ou de destination invalide + Langue d'origine ou de destination invalide. Blagues non chargées. @@ -1802,10 +1798,10 @@ La nouvelle valeur de {0} est {1} ! Url originale - Une clé d'API osu! est nécessaire + Une clé d'API osu! est nécessaire. - Impossible de récupérer la signature osu! + Impossible de récupérer la signature osu!. Trouvé dans {0} images. Affichage de {0} aléatoires. @@ -1821,7 +1817,7 @@ La nouvelle valeur de {0} est {1} ! Plateforme - Attaque non trouvée + Attaque non trouvée. Pokémon non trouvé. @@ -1849,7 +1845,7 @@ La nouvelle valeur de {0} est {1} ! recherche plutôt non ? - Impossible de réduire cette Url + Impossible de réduire cette Url. Url réduite @@ -1927,10 +1923,10 @@ La nouvelle valeur de {0} est {1} ! Impossible de trouver ce terme sur le wikia spécifié. - Entrez un wikia cible, suivi d'une requête de recherche + Entrez un wikia cible, suivi d'une requête de recherche. - Page non trouvée + Page non trouvée. Vitesse du vent @@ -2067,7 +2063,7 @@ OwnerID: {2} Aucun rôle sur cette page. - Aucune partition sur cette page. + Aucun shard sur cette page. Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. @@ -2088,7 +2084,7 @@ OwnerID: {2} {2} Salons Vocaux - Toutes les citations possédant le mot-clé {0} ont été supprimées + Toutes les citations possédant le mot-clé {0} ont été supprimées. Page {0} des citations @@ -2121,7 +2117,7 @@ OwnerID: {2} Nouveau modèle de rappel défini. - Répétition de {0} chaque {1} jour(s), {2} heure(s) et {3} minute(s) + Répétition de {0} chaque {1} jour(s), {2} heure(s) et {3} minute(s). Liste des répétitions @@ -2163,15 +2159,15 @@ OwnerID: {2} Info du serveur - Partition + Shard Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. - Statistique des partitions + Statistique des shards Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. - La partition **#{0}** est en état {1} avec {2} serveurs. + Le shard **#{0}** est en état {1} avec {2} serveurs. Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. From 120da4a604065a61cf6df289f020c5968c941f64 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 01:50:55 +0100 Subject: [PATCH 372/746] Update ResponseStrings.de-DE.resx (POEditor.com) --- .../Resources/ResponseStrings.de-DE.resx | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx index 7dd58187..eb4c7511 100644 --- a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx @@ -874,9 +874,6 @@ Grund: {1} verleiht {1} {0} - - Münzwurf-Glücksspiel - Hoffentlich haben sie beim nächsten Mal mehr Glück ^_^ @@ -1238,11 +1235,11 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Währungsgeneration in diesem Kanal aktiviert. - {0} zufällige {1} sind erschienen! Sammle sie indem sie `{2}pick` schreiben. + {0} zufällige {1} sind erschienen! Sammle sie indem sie `{2}pick` schreiben plural - Eine zufällige {0} ist erschienen! Sammle sie indem sie `{1}pick` schreiben. + Eine zufällige {0} ist erschienen! Sammle sie indem sie `{1}pick` schreiben Laden einer Frage fehlgeschlagen. @@ -1370,10 +1367,10 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Ungültige Eingabe. - Maximale Spielzeit hat kein Limit mehr + Maximale Spielzeit hat kein Limit mehr. - Maximale Spielzeit ist nun {0} Sekunden + Maximale Spielzeit ist nun {0} Sekunden. Maximale Musik-Warteschlangengröße ist nun unbegrenzt. @@ -1436,10 +1433,10 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Eingereihter Song - Musik-Warteschlange geleert + Musik-Warteschlange geleert. - Warteschlange ist voll bei {0}/{1} + Warteschlange ist voll bei {0}/{1}. Song entfernt @@ -1458,7 +1455,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Aktueller Song wird nicht mehr wiederholt. - Musikwiedergabe wiederaufgenommen + Musikwiedergabe wiederaufgenommen. Playlist-Wiederholung deaktiviert. @@ -1473,7 +1470,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Gesprungen zu `{0}:{1}` - Song gemischt + Song gemischt. Song bewegt @@ -1524,7 +1521,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu {0} mit ID {1} wurde zur Sperrliste hinzugefügt - Befehl {0} hat nun {1}s Abklingzeit + Befehl {0} hat nun {1}s Abklingzeit. Befehl {0} hat keine Abklingzeit mehr und alle laufenden Abklingzeiten wurden entfernt. @@ -1595,7 +1592,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Benutzer brauchen nun Rolle {0} um die Berechtigungen zu editieren. - Keine Berechtigung für diesen Index gefunden + Keine Berechtigung für diesen Index gefunden. Berechtigung #{0} - {1} entfernt @@ -1611,7 +1608,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Short of seconds. - Benutzung von {0} {1} wurde für diesen Server verboten + Benutzung von {0} {1} wurde für diesen Server verboten. Benutzung von {0} {1} wurde für diesen Server erlaubt. @@ -1659,7 +1656,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Ihre Automatische-Übersetzungs Sprache wurde entfernt. - Ihre Automatische-Übersetzungs Sprache wurde zu {from}>{to} gesetzt. + Ihre Automatische-Übersetzungs Sprache wurde zu {from}>{to} gesetzt Automatische Übersetzung der Nachrichten wurde auf diesem kanal gestartet. @@ -1671,7 +1668,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Schlechter Eingabeformat, oder etwas lief schief. - Konnte diese Karte nicht finden + Konnte diese Karte nicht finden. fakt @@ -1749,7 +1746,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Konnte diesen Film nicht finden. - Ungültige Quell- oder Zielsprache, + Ungültige Quell- oder Zielsprache. Witze nicht geladen. @@ -2049,7 +2046,7 @@ ID des Besitzers: {2} Niemand spielt dieses Spiel. - Keine aktiven Wiederholer + Keine aktiven Wiederholer. Keine Rollen auf dieser Seite. @@ -2138,7 +2135,7 @@ ID des Besitzers: {2} Keine Farben sind in dem Richtigen Format. Benutze zum Beispiel `#00ff00`. - Startete die Farbrotation für Rolle {0} + Startete die Farbrotation für Rolle {0}. Stoppte die Farbrotation für Rolle {0} From 8be5e0bf61b8d9ed91f46b81d8fcd540d132164b Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 01:50:57 +0100 Subject: [PATCH 373/746] Update ResponseStrings.ru-RU.resx (POEditor.com) --- .../Resources/ResponseStrings.ru-RU.resx | 279 ++++++++++-------- 1 file changed, 156 insertions(+), 123 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx index bf370873..d2980cc8 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx @@ -118,28 +118,34 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + Эта база уже захвачена или разрушена. + Fuzzy - + Эта база уже разрушена - + Эта база не захвачена. + Fuzzy - + **РАЗРУШЕННАЯ** база #{0} ведёт войну против {1}. - + У {0} есть **НЕ ЗАХВАЧЕННАЯ** база #{1}, ведущая войну против {2} + Fuzzy - + {0} захватил базу #{1} после войны с {2} + Fuzzy - + @{0} Вы уже захватили базу #{1}. Вы не можете захватить новую базу. + Fuzzy - + Время действия запроса от @{0} на войну против {1} истёкло. + Fuzzy Враг @@ -148,31 +154,32 @@ Информация о войне против {0} - + Неправильный номер базы. - + Неправильный размер войны. Список активных войн - + не захваченная + Fuzzy - + Вы не участвуете в этой войне. - + @{0} Вы либо не участвуете в этой войне, либо эта база разрушена. - + Нет активных войн. Размер - + Война против {0} уже началась. Война против {0} была создана. @@ -185,10 +192,11 @@ Эта война не существует. - + Война против {0} началась! Вся статистика настраиваемых реакций стёрта. + Fuzzy Настраиваемая реакция удалена. @@ -211,22 +219,27 @@ Fuzzy - + Не найдено настраиваемых реакций. + Fuzzy - + Не найдено настраеваемых реакций с таким номером. + Fuzzy Ответ - + Статистика настраеваемых реакций. + Fuzzy - + Статистика удалена для настраеваемой реакции {0}. + Fuzzy - + Не найдено статистики для этого запроса, никаких действий не применено. + Fuzzy Активатор @@ -267,33 +280,41 @@ Вы не можете использовать {0}. Напишите '{1}ml', чтобы увидеть список доступных Вам приёмов. + Fuzzy Список приёмов {0} типа Эта атака не эффективна. + Fuzzy У вас не достаточно {0} воскресил {0}, использовав один {1} + Fuzzy Вы воскресили себя, использовав один {0} + Fuzzy Ваш тип изменён с {0} на {1} + Fuzzy Эта атака немного эффективна. + Fuzzy Эта атака очень эффективна! + Fuzzy Вы использовали слишком много приёмов подряд и не можете двигаться! + Fuzzy Тип {0} — {1} @@ -363,10 +384,10 @@ Тема канала сменена. - + Чат очищен. - + Содержание Успешно создана роль {0}. @@ -542,11 +563,13 @@ Заглушёны - PLURAL (users have been muted) + PLURAL (users have been muted) +Fuzzy Заглушён - singular "User muted." + singular "User muted." +Fuzzy Скорее всего, у меня нет необходимых прав. @@ -593,7 +616,7 @@ Права для этого сервера - + Активные защиты от рейдов {0} был **отключён** на этом сервере. @@ -605,7 +628,7 @@ Ошибка. Требуется право на управление ролями. - + Нет защит от рейдов Порог пользователей должен лежать между {0} и {1}. @@ -650,13 +673,13 @@ Вы не можете редактировать роли, находящиеся выше чем ваша роль. - + Удалено повторяющееся сообщение: {0} Роль {0} добавлена в лист. - + {0} не найдена. Чат очищен. Роль {0} уже есть в списке. @@ -665,16 +688,17 @@ Добавлено. - + Отключены чередующиеся статусы. - + Чередующиеся статусы отключены. - + Список чередующихся статусов: +{0} - + Чередующиеся статусы не установлены. У вас уже есть роль {0} @@ -749,7 +773,7 @@ Медленный режим включен. - + выгнаны PLURAL @@ -771,8 +795,9 @@ Отключено заглушение. - - singular + Вкл. звук + singular +Fuzzy Имя @@ -787,10 +812,12 @@ Пользователь заблокирован - + {0} получил **запрет** на разговор в чате. + Fuzzy - + {0} потерял **запрет** на разговор в чате. + Fuzzy Пользователь присоединился @@ -799,7 +826,8 @@ Пользователь вышел - + {0} получил **запрет** на разговор в текстовом и голосовом чатах. + Fuzzy Добавлена роль пользователя @@ -811,7 +839,8 @@ {0} теперь {1} - + {0} потерял **запрет** на разговор в текстовом и голосовом чатах. + Fuzzy {0} присоединился к голосовому каналу {1}. @@ -820,26 +849,27 @@ {0} покинул голосовой канал {1}. - {0} переместил {1} в голосовой канал {2}. + {0} переместил из голосового канала {1} в {2}. - + **Выключен микрофон** у {0}. + Fuzzy - + **Включён микрофон** у {0}. + Fuzzy - Голосовой канал удалён - Fuzzy + Голосовой канал создан Голосовой канал удалён - + Отключены голосовые + текстовые функции. - + Включены голосовые + текстовые функции. Нет разрешений **Управление ролями** и/или **Управление каналами**, поэтому нельзя использовать команду 'voice+text' на сервере {0}. @@ -872,17 +902,14 @@ Ошибка при переносе файлов, проверьте консоль бота для получения дальнейшей информации. - + История присутвия пользователей - + Пользователя выгнали наградил {0} пользователю {1} - - - В следующий раз повезёт ^_^ @@ -941,13 +968,13 @@ В колоде закончились карты. - + Победитель лотереи - + Вам выпало {0}. - + Ставка НИЧЕГО СЕБЕ!!! Поздраляем!!! x{0} @@ -1043,7 +1070,8 @@ Paypal <{1}> Использование - + Авто-хентай запущен. Каждые {0}с будут отправляться изображения с одним из следующих тэгов: +{1} Тэг @@ -1082,7 +1110,7 @@ Paypal <{1}> Задано неправильное число. Можно бросить {0}-{1} костей одновременно. - + выпало {0} Someone rolled 35 @@ -1099,10 +1127,11 @@ Paypal <{1}> Второе число должно быть больше первого. - + Смены чувств - + В браке + Fuzzy Разводы @@ -1172,7 +1201,7 @@ Paypal <{1}> Вы развелись с вайфу, которой Вы не нравились. Вам вернули {0}. - + 8ball Акрофобия. @@ -1355,16 +1384,19 @@ Paypal <{1}> Папка успешно добавлена в очередь воспроизведения. - + fairplay + Fuzzy Песня завершилась. - + Отключено справедливое воспроизведение. + Fuzzy - + Включено справедливое воспроизведение. + Fuzzy С момента @@ -1716,7 +1748,7 @@ Paypal <{1}> Определить: - + Брошено Эпизоды @@ -1828,11 +1860,11 @@ Paypal <{1}> Качество: - + Время игры в Быстрой Игре Is this supposed to be Overwatch Quick Play stats? - + Побед в Быстрой Игре Рейтинг: @@ -1859,7 +1891,7 @@ Paypal <{1}> Состояние - + Url Магазина Стример {0} в оффлане. @@ -1883,7 +1915,7 @@ Paypal <{1}> Стрим {0} ({1}) убран из оповещений. - + Этот канал будет оповещён, когда статус стрима изменится. Рассвет @@ -1945,7 +1977,7 @@ Paypal <{1}> `1.` - + Страница списка активности #{0} Всего {0} пользователей. @@ -2025,55 +2057,56 @@ Paypal <{1}> Имя: {0} - +Участники: {1} +IDВладельца: {2} - + На этой странице не найдено серверов. - + Список повторяемых сообщений - + Участники - + Память - + Сообщения - + Повторяемое сообщения - + Имя - + Кличка - + Никто не играет в эту игру - + Нет активных повторяемых сообщений - + На этой странице нет ролей. - + На этой странице нет Shard-ов. - + Тема не задана - + Владелец - + ID владельца - + Присутствие {0} Серверов @@ -2081,116 +2114,116 @@ Paypal <{1}> {2} Голосовых каналов - + Удалены все цитаты с ключевым словом {0}. - + Страница {0} цитат - + На этой странице нет цитат. - + Не найдено цитат, пригодных для удаления. - + Цитата добавлена - + Случайно выбранная цитата удалена. - + Регион - + Зарегистрирован - + Я напомню, чтобы {0} сделал {2} '{3:d.M.yyyy.} в {4:HH:mm}' - + Неправильный формат времени. Проверьте список команд. - + Новый образец для напоминаний задан. - + Повторяю {0} каждые {} дня(ей), {2} час(а) и {3} минут(у). - + Список повторяемых сообщений - + На этом сервере нет повторяемых сообщений. - + #{0} остановлен. - + На этом сервере не найдено повторяемых сообщений - + Результат - + Роли - + Страница #{0} всех ролей на этом сервере: - + Страница #{0} ролей для {1} - + Цвета заданы в неправильном формате. Используйте, например '#00ff00'. - + Начато чередование цветов роли {0}. - + Остановлено чередование цветов роли {0}. - + {0} этого сервера — {1} - + Информация о сервере - + Shard - + Статискика Shard-а - + Shard **#{0}** находится в состоянии {1} с {2} серверами. - + **Имя:** {0} **Link:** {1} - + Серверные emoji не найдены. - + Проигрывается {0} песен, {1} в очереди - + Текстовые каналы - + Ссылка на Вашу комнату: - + Время работы - + {} пользователя {1} — {2} Id of the user kwoth#1234 is 123123123123 - + Пользователи - + Голосовые каналы \ No newline at end of file From 1d38b92757dc2762d73dfc168a93e04d22fb35ea Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 01:51:00 +0100 Subject: [PATCH 374/746] Update CommandStrings.nl-NL.resx (POEditor.com) --- .../Resources/CommandStrings.nl-NL.resx | 5316 +++++++---------- 1 file changed, 2166 insertions(+), 3150 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.nl-NL.resx b/src/NadekoBot/Resources/CommandStrings.nl-NL.resx index 662975cf..d3b70713 100644 --- a/src/NadekoBot/Resources/CommandStrings.nl-NL.resx +++ b/src/NadekoBot/Resources/CommandStrings.nl-NL.resx @@ -1,3153 +1,2169 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Die basis is al veroverd of vernietigd. + + + Die basis is al vernietigd. + + + Die basis is nog niet veroverd. + + + **VERNIETIGD**basis #{0} in een oorlog tegen {1} + + + {0} heeft **ONOVERWONNEN** basis #{1} in een oorlog tegen {2} + + + {0} heeft basis #{1} overwonnen in een oorlog tegen {2} + + + @{0} Jij hebt al een basis overwonnen #{1}. Je kunt niet nog een nemen. + + + De aanvraag van @{0} voor een oorlog tegen {1} is niet meer geldig. + + + Vijand + + + Informatie over oorlog tegen {0} + + + Ongeldige basis nummer + + + Ongeldige oorlogs formaat. + + + Lijst van voorlopende oorlogen. + + + Niet veroverd. + + + Jij doet niet mee aan die oorlog. + + + @{0} Jij doet niet mee aan die oorlog, or die basis is al vernietigd. + + + Geen voorlopende oorlogen. + + + Grootte. + + + Oorlog tegen {0} is al begonnen. + + + Oorlog tegen {0} gecreëerd + + + De oorlog tegen {0} is beëindigd. + + + Die oorlog bestaat niet. + + + De oorlog tegen {0} is begonnen! + + + Alle speciale reactie statistieken zijn verwijderd. + + + Speciale Reactie verwijderdt. + + + Onvoldoende rechten. Bot Eigendom is nodig voor globale speciale reacties, en Administrator voor speciale server-reacties. + + + Lijst van alle zelf gemaakte reacties + + + Speciale Reacties + + + Nieuwe Speciale Reacties + + + Geen speciale reacties gevonden. + + + Geen speciale reacties gevonden met die ID. + + + Antwoord + + + Speciale Reactie Statistieken + + + Statistieke verwijderd voor {0} speciale reactie. + + + Geen statistieken voor die trekker gevonden, geen actie genomen. + + + Trekker + + + Autohentai gestopt. + + + Geen resultaten gevonden + + + {0} is al flauw gevallen. + + + {0} heeft al vol HP. + + + Jouw element is al {0} + + + heeft {0}{1} op {2}{3} gebruikt voor {4} schade. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + Jij zal niet winnen zonder tegenstand! + + + Je kunt je zelf niet aanvallen + + + {0} is verslagen! + + + heeft {0} genezen met een {1} + + + {0} heeft nog {1} HP over + + + Je kan {0} niet gebruiken. Typ `{1}ml` om een lijst te bekijken van de aanvallen die jij kunt gebruiken + + + Aanvallijst voor {0} element + + + Het heeft weinig effect. + + + Je hebt niet genoeg {0} + + + heeft {0} herstelt met een {1} + + + Je kunt jezelf herstellen met een {0} + + + Je element is veranderd van {0} naar {1} + + + Het is een beetje effectief. + + + Het is super effectief! + + + Je hebt te veel aanvallen achter elkaar gemaakt, je kan dus niet bewegen! + + + Element van {0} is {1} + + + Gebruiker niet gevonden. + + + Je bent flauw gevallen, dus je kunt niet bewegen! + + + **Auto aanwijzing van rollen** op gebruiker is nu **uitgeschakeld**. + + + **Auto aanwijzing van rollen** op gebruiker is nu **ingeschakeld**. + + + Bestanden + + + Avatar veranderd + + + Je bent verbannen van {0} server. Reden: {1} + + + Verbannen + PLURAL + + + Gebruiker verbannen + + + Bot naam is veranderd naar {0} + + + Bot status is veranderd naar {0} + + + Automatische verwijdering van de bye berichten is uitgeschakeld. + + + Bye berichten zullen worden verwijderd na {0} seconden. + + + Momenteel is de bye message: {0} + + + Schakel de bye berichten in door {0} te typen. + + + Nieuw bye bericht is geplaatst. + + + Dag aankondigingen uitgeschakeld. + + + Dag aankondigingen ingeschakeld op dit kanaal. + + + Kanaal naam is veranderd. + + + Oude naam + + + Kanaal onderwerp is veranderd + + + Opgeruimd + + + Inhoud + + + Met success een nieuwe rol gecreëerd. + + + Tekst kanaal {0} gecreëerd. + + + Stem kanaal {0} gecreëerd. + + + Dempen succesvol. + + + Server verwijderd {0} + + + Stopt van automatische verwijdering van succesvolle reacties aanroepingen commando. + + + Verwijdert nu automatisch succesvolle commando aanroepingen + + + Tekst kanaal {0} verwijdert. + + + Stem kanaal {0} verwijdert. + + + Privé bericht van + + + Met succes een nieuwe donateur toegevoegt. Totaal gedoneerde bedrag van deze gebruiker {0} + + + Dank aan de mensen hieronder vernoemt voor het waarmaken van dit project! + + + Ik zal alle eigenaren een privé bericht sturen. + + + Ik zal een privé bericht sturen naar de eerste eigenaar + + + Ik zal privé berichten sturen vanaf nu. + + + Ik stop vanaf nu met het sturen van privé berichten. + + + Automatisch verwijderen van groet berichten is uitgeschakeld. + + + Groet berichten zullen worden verwijderd na {0} seconden. + + + Momenteen is het privé groet bericht: {0} + + + Schakel DM begroetings bericht in door {0} in te typen. + + + Nieuwe DM begroetings bericht vastgesteld. + + + DM begroetings aankondiging uitgeschakeld. + + + DM begroetings aankondiging ingeschakeld. + + + Momentele begroetings bericht: {0} + + + Schakel begroetings bericht in door {0} in te typen + + + Nieuwe begroetings message vastgesteld. + + + Begroetings aankondiging uitgeschakeld. + + + Begroetings aankondiging uitschakeld op dit kanaal. + + + Jij kunt geen commando gebruiken op gebruikers met hogere of dezelfde rol als die van jouw in de rollen hiërarchie. + + + Afbeeldingen geplaatst na {0} seconden! + + + Ongelde invoer formaat. + + + Ongeldige parameters. + + + {0} heeft {1} toegetreden. + + + Je bent weggeschopt van de {0} server. +Reden: {1} + + + Gebruiker weggeschopt. + + + Lijst van talen +{0} + + + Jouw server's plaats van handeling is nu {0} - {1} + + + Bot's standaard plaats van handeling is nu {0} - {1} + + + Bot's taal is vastgesteld van {0} - {1} + + + + + + deze server taal is gezet naar: + + + heeft verlaten + + + Heeft de server verlaten + + + + + + + + + Logging uitgeschakeld + + + + + + + + + + + + + + + + + + + + + Bericht verstuurd + + + verplaats van ... naar ... + + + bericht verwijdert in + + + bericht bijgewerkt in + + + gemute + PLURAL (users have been muted) + + + gemute + singular "User muted." + + + + + + nieuwe demp group gezet + + + Ik heb **administrator** rechten nodig voor dat + + + nieuw bericht + + + nieuwe bijnaam + + + Nieuw onderwerp + + + Bijnaam veranderd + + + Kan de server niet vinden + + + + + + Oud bericht + + + Oude bijnaam + + + Oude onderwerp + + + error hoogst waarschijnlijk niet voldoende permissie + + + de rechten op deze server zijn gereset + + + actieve bescherming + + + is ** uitgeschakeld** op deze server + + + aangezet + + + fout. ik heb managergroup rechten nodig + + + geen bescherming aangezet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + group naam veranderd + + + group naam veranderen mislukt. ik heb niet genoeg rechten + + + je kan geen groupen bijwerken die hoger zijn dan jou eigen group + + + Verwijderd van speel bericht + + + group... is toegevoegd aan de lijst + + + niet gevonden. aan het opruimen + + + group is al in de lijst + + + toegevoegd + + + + + + + + + + + + + + + je hebt al .. group + + + + + + + + + + + + deze group is niet zelf + + + + + + + + + + + + + + + je heb niet lang meer de {0} group + + + je hebt nu {0} group + + + met sucess een group {0) toegevoegd aan gebruiker {1} + + + fout bij het toevoegen van een group. je heb onvoldoende rechten + + + Nieuwe avatar gezet! + + + Nieuwe kanaal naam gezet. + + + Nieuwe game gezet! + + + Nieuwe stream gezet! + + + Nieuwe kanaal onderwerp gezet + + + + + + + + + afsluiten + + + + + + langzame mode uitgezet + + + langzame mode gestart + + + zacht-verbannen(kicked) + PLURAL + + + {0} wil deze kanaal dempen + + + + + + + + + + + + + + + + + + + singular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + User flipped tails. + + + + + + + + + + + + + + + + + + + X has gifted 15 flowers to Y + + + + X has Y flowers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Someone rolled 35 + + + + Dice Rolled: 5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Make sure to get the formatting right, and leave the thinking emoji + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + plural + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Kwoth picked 5* + + + + Kwoth planted 5* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + context: "removed song #5" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gen (of command) + + + + Gen. (of module) + + + + + + + + + + + + + + + + + + + + + + + + + Short of seconds. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Don't translate {0}place + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /s and total need to be localized to fit the context - +`1.` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Invalid months value/ Invalid hours value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Id of the user kwoth#1234 is 123123123123 + + + + + + + - mimetype: application/x-microsoft.net.object.bytearray.base64 - value : The object must be serialized into a byte array - : using a System.ComponentModel.TypeConverter - : and then encoded with base64 encoding. - --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - help h - - - Either shows a help for a single command, or DMs you help link if no arguments are specified. - - - `{0}h !!q` or `{0}h` - - - hgit - - - Generates the commandlist.md file. - - - `{0}hgit` - - - donate - - - Instructions for helping the project financially. - - - `{0}donate` - - - modules mdls - - - Lists all bot modules. - - - `{0}modules` - - - commands cmds - - - List all of the bot's commands from a certain module. You can either specify full, or only first few letters of the module name. - - - `{0}commands Administration` or `{0}cmds Admin` - - - greetdel grdel - - - Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set 0 to disable automatic deletion. - - - `{0}greetdel 0` or `{0}greetdel 30` - - - greet - - - Toggles anouncements on the current channel when someone joins the server. - - - `{0}greet` - - - greetmsg - - - Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. - - - `{0}greetmsg Welcome, %user%.` - - - bye - - - Toggles anouncements on the current channel when someone leaves the server. - - - `{0}bye` - - - byemsg - - - Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. - - - `{0}byemsg %user% has left.` - - - byedel - - - Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set 0 to disable automatic deletion. - - - `{0}byedel 0` or `{0}byedel 30` - - - greetdm - - - Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). - - - `{0}greetdm` - - - logserver - - - Enables or Disables ALL log events. If enabled, all log events will log to this channel. - - - `{0}logserver enable` or `{0}logserver disable` - - - logignore - - - Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. - - - `{0}logignore` - - - userpresence - - - Starts logging to this channel when someone from the server goes online/offline/idle. - - - `{0}userpresence` - - - voicepresence - - - Toggles logging to this channel whenever someone joins or leaves a voice channel you are currently in. - - - `{0}voicepresence` - - - repeatinvoke repinv - - - Immediately shows the repeat message on a certain index and restarts its timer. - - - `{0}repinv 1` - - - repeat - - - Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. - - - `{0}repeat 5 Hello there` - - - rotateplaying ropl - - - Toggles rotation of playing status of the dynamic strings you previously specified. - - - `{0}ropl` - - - addplaying adpl - - - Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %time%,%shardid%,%shardcount%, %shardguilds% - - - `{0}adpl` - - - listplaying lipl - - - Lists all playing statuses with their corresponding number. - - - `{0}lipl` - - - removeplaying rmpl repl - - - Removes a playing string on a given number. - - - `{0}rmpl` - - - slowmode - - - Toggles slowmode. Disable by specifying no parameters. To enable, specify a number of messages each user can send, and an interval in seconds. For example 1 message every 5 seconds. - - - `{0}slowmode 1 5` or `{0}slowmode` - - - cleanvplust cv+t - - - Deletes all text channels ending in `-voice` for which voicechannels are not found. Use at your own risk. - - - `{0}cleanv+t` - - - voice+text v+t - - - Creates a text channel for each voice channel only users in that voice channel can see.If you are server owner, keep in mind you will see them all the time regardless. - - - `{0}v+t` - - - scsc - - - Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. - - - `{0}scsc` - - - jcsc - - - Joins current channel to an instance of cross server channel using the token. - - - `{0}jcsc TokenHere` - - - lcsc - - - Leaves Cross server channel instance from this channel. - - - `{0}lcsc` - - - asar - - - Adds a role to the list of self-assignable roles. - - - `{0}asar Gamer` - - - rsar - - - Removes a specified role from the list of self-assignable roles. - - - `{0}rsar` - - - lsar - - - Lists all self-assignable roles. - - - `{0}lsar` - - - togglexclsar tesar - - - Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) - - - `{0}tesar` - - - iam - - - Adds a role to you that you choose. Role must be on a list of self-assignable roles. - - - `{0}iam Gamer` - - - iamnot iamn - - - Removes a role to you that you choose. Role must be on a list of self-assignable roles. - - - `{0}iamn Gamer` - - - addcustreact acr - - - Add a custom reaction with a trigger and a response. Running this command in server requires Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: <http://nadekobot.readthedocs.io/en/latest/Custom%20Reactions/> - - - `{0}acr "hello" Hi there %user%` - - - listcustreact lcr - - - Lists global or server custom reactions (20 commands per page). Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. Specifying `all` argument instead of the number will DM you a text file with a list of all custom reactions. - - - `{0}lcr 1` or `{0}lcr all` - - - listcustreactg lcrg - - - Lists global or server custom reactions (20 commands per page) grouped by trigger, and show a number of responses for each. Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. - - - `{0}lcrg 1` - - - showcustreact scr - - - Shows a custom reaction's response on a given ID. - - - `{0}scr 1` - - - delcustreact dcr - - - Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration priviledges and removes server custom reaction. - - - `{0}dcr 5` - - - autoassignrole aar - - - Automaticaly assigns a specified role to every user who joins the server. - - - `{0}aar` to disable, `{0}aar Role Name` to enable - - - leave - - - Makes Nadeko leave the server. Either name or id required. - - - `{0}leave 123123123331` - - - delmsgoncmd - - - Toggles the automatic deletion of user's successful command message to prevent chat flood. - - - `{0}delmsgoncmd` - - - restart - - - Restarts the bot. Might not work. - - - `{0}restart` - - - setrole sr - - - Sets a role for a given user. - - - `{0}sr @User Guest` - - - removerole rr - - - Removes a role from a given user. - - - `{0}rr @User Admin` - - - renamerole renr - - - Renames a role. Roles you are renaming must be lower than bot's highest role. - - - `{0}renr "First role" SecondRole` - - - removeallroles rar - - - Removes all roles from a mentioned user. - - - `{0}rar @User` - - - createrole cr - - - Creates a role with a given name. - - - `{0}cr Awesome Role` - - - rolecolor rc - - - Set a role's color to the hex or 0-255 rgb color value provided. - - - `{0}rc Admin 255 200 100` or `{0}rc Admin ffba55` - - - ban b - - - Bans a user by ID or name with an optional message. - - - `{0}b "@some Guy" Your behaviour is toxic.` - - - softban sb - - - Bans and then unbans a user by ID or name with an optional message. - - - `{0}sb "@some Guy" Your behaviour is toxic.` - - - kick k - - - Kicks a mentioned user. - - - `{0}k "@some Guy" Your behaviour is toxic.` - - - mute - - - Mutes a mentioned user both from speaking and chatting. - - - `{0}mute @Someone` - - - voiceunmute - - - Gives a previously voice-muted user a permission to speak. - - - `{0}voiceunmute @Someguy` - - - deafen deaf - - - Deafens mentioned user or users. - - - `{0}deaf "@Someguy"` or `{0}deaf "@Someguy" "@Someguy"` - - - undeafen undef - - - Undeafens mentioned user or users. - - - `{0}undef "@Someguy"` or `{0}undef "@Someguy" "@Someguy"` - - - delvoichanl dvch - - - Deletes a voice channel with a given name. - - - `{0}dvch VoiceChannelName` - - - creatvoichanl cvch - - - Creates a new voice channel with a given name. - - - `{0}cvch VoiceChannelName` - - - deltxtchanl dtch - - - Deletes a text channel with a given name. - - - `{0}dtch TextChannelName` - - - creatxtchanl ctch - - - Creates a new text channel with a given name. - - - `{0}ctch TextChannelName` - - - settopic st - - - Sets a topic on the current channel. - - - `{0}st My new topic` - - - setchanlname schn - - - Changes the name of the current channel. - - - `{0}schn NewName` - - - prune clr - - - `{0}prune` removes all nadeko's messages in the last 100 messages.`{0}prune X` removes last X messages from the channel (up to 100)`{0}prune @Someone` removes all Someone's messages in the last 100 messages.`{0}prune @Someone X` removes last X 'Someone's' messages in the channel. - - - `{0}prune` or `{0}prune 5` or `{0}prune @Someone` or `{0}prune @Someone X` - - - die - - - Shuts the bot down. - - - `{0}die` - - - setname newnm - - - Gives the bot a new name. - - - `{0}newnm BotName` - - - setavatar setav - - - Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. - - - `{0}setav http://i.imgur.com/xTG3a1I.jpg` - - - setgame - - - Sets the bots game. - - - `{0}setgame with snakes` - - - send - - - Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prepend channel id with `c:` and user id with `u:`. - - - `{0}send serverid|c:channelid message` or `{0}send serverid|u:userid message` - - - mentionrole menro - - - Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. - - - `{0}menro RoleName` - - - unstuck - - - Clears the message queue. - - - `{0}unstuck` - - - donators - - - List of lovely people who donated to keep this project alive. - - - `{0}donators` - - - donadd - - - Add a donator to the database. - - - `{0}donadd Donate Amount` - - - announce - - - Sends a message to all servers' general channel bot is connected to. - - - `{0}announce Useless spam` - - - savechat - - - Saves a number of messages to a text file and sends it to you. - - - `{0}savechat 150` - - - remind - - - Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message. - - - `{0}remind me 1d5h Do something` or `{0}remind #general 1m Start now!` - - - remindtemplate - - - Sets message for when the remind is triggered. Available placeholders are %user% - user who ran the command, %message% - Message specified in the remind, %target% - target channel of the remind. - - - `{0}remindtemplate %user%, do %message%!` - - - serverinfo sinfo - - - Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. - - - `{0}sinfo Some Server` - - - channelinfo cinfo - - - Shows info about the channel. If no channel is supplied, it defaults to current one. - - - `{0}cinfo #some-channel` - - - userinfo uinfo - - - Shows info about the user. If no user is supplied, it defaults a user running the command. - - - `{0}uinfo @SomeUser` - - - whosplaying whpl - - - Shows a list of users who are playing the specified game. - - - `{0}whpl Overwatch` - - - inrole - - - Lists every person from the provided role or roles, separated with space, on this server. You can use role IDs, role names (in quotes if it has multiple words), or role mention If the list is too long for 1 message, you must have Manage Messages permission. - - - `{0}inrole Role` or `{0}inrole Role1 "Role 2" @role3` - - - checkmyperms - - - Checks your user-specific permissions on this channel. - - - `{0}checkmyperms` - - - stats - - - Shows some basic stats for Nadeko. - - - `{0}stats` - - - userid uid - - - Shows user ID. - - - `{0}uid` or `{0}uid "@SomeGuy"` - - - channelid cid - - - Shows current channel ID. - - - `{0}cid` - - - serverid sid - - - Shows current server ID. - - - `{0}sid` - - - roles - - - List roles on this server or a roles of a specific user if specified. Paginated. 20 roles per page. - - - `{0}roles 2` or `{0}roles @Someone` - - - channeltopic ct - - - Sends current channel's topic as a message. - - - `{0}ct` - - - chnlfilterinv cfi - - - Toggles automatic deleting of invites posted in the channel. Does not negate the {0}srvrfilterinv enabled setting. Does not affect Bot Owner. - - - `{0}cfi` - - - srvrfilterinv sfi - - - Toggles automatic deleting of invites posted in the server. Does not affect Bot Owner. - - - `{0}sfi` - - - chnlfilterwords cfw - - - Toggles automatic deleting of messages containing banned words on the channel. Does not negate the {0}srvrfilterwords enabled setting. Does not affect bot owner. - - - `{0}cfw` - - - fw - - - Adds or removes (if it exists) a word from the list of filtered words. Use`{0}sfw` or `{0}cfw` to toggle filtering. - - - `{0}fw poop` - - - lstfilterwords lfw - - - Shows a list of filtered words. - - - `{0}lfw` - - - srvrfilterwords sfw - - - Toggles automatic deleting of messages containing forbidden words on the server. Does not affect Bot Owner. - - - `{0}sfw` - - - permrole pr - - - Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'. - - - `{0}pr role` - - - verbose v - - - Sets whether to show when a command/module is blocked. - - - `{0}verbose true` - - - srvrmdl sm - - - Sets a module's permission at the server level. - - - `{0}sm ModuleName enable` - - - srvrcmd sc - - - Sets a command's permission at the server level. - - - `{0}sc "command name" disable` - - - rolemdl rm - - - Sets a module's permission at the role level. - - - `{0}rm ModuleName enable MyRole` - - - rolecmd rc - - - Sets a command's permission at the role level. - - - `{0}rc "command name" disable MyRole` - - - chnlmdl cm - - - Sets a module's permission at the channel level. - - - `{0}cm ModuleName enable SomeChannel` - - - chnlcmd cc - - - Sets a command's permission at the channel level. - - - `{0}cc "command name" enable SomeChannel` - - - usrmdl um - - - Sets a module's permission at the user level. - - - `{0}um ModuleName enable SomeUsername` - - - usrcmd uc - - - Sets a command's permission at the user level. - - - `{0}uc "command name" enable SomeUsername` - - - allsrvrmdls asm - - - Enable or disable all modules for your server. - - - `{0}asm [enable/disable]` - - - allchnlmdls acm - - - Enable or disable all modules in a specified channel. - - - `{0}acm enable #SomeChannel` - - - allrolemdls arm - - - Enable or disable all modules for a specific role. - - - `{0}arm [enable/disable] MyRole` - - - ubl - - - Either [add]s or [rem]oves a user specified by a mention or ID from a blacklist. - - - `{0}ubl add @SomeUser` or `{0}ubl rem 12312312313` - - - cbl - - - Either [add]s or [rem]oves a channel specified by an ID from a blacklist. - - - `{0}cbl rem 12312312312` - - - sbl - - - Either [add]s or [rem]oves a server specified by a Name or ID from a blacklist. - - - `{0}sbl add 12312321312` or `{0}sbl rem SomeTrashServer` - - - cmdcooldown cmdcd - - - Sets a cooldown per user for a command. Set to 0 to remove the cooldown. - - - `{0}cmdcd "some cmd" 5` - - - allcmdcooldowns acmdcds - - - Shows a list of all commands and their respective cooldowns. - - - `{0}acmdcds` - - - . - - - Adds a new quote with the specified name and message. - - - `{0}. sayhi Hi` - - - .. - - - Shows a random quote with a specified name. - - - `{0}.. abc` - - - qsearch - - - Shows a random quote for a keyword that contains any text specified in the search. - - - `{0}qsearch keyword text` - - - deletequote delq - - - Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. - - - `{0}delq abc` - - - draw - - - Draws a card from the deck.If you supply number X, she draws up to 5 cards from the deck. - - - `{0}draw` or `{0}draw 5` - - - shuffle sh - - - Shuffles the current playlist. - - - `{0}sh` - - - flip - - - Flips coin(s) - heads or tails, and shows an image. - - - `{0}flip` or `{0}flip 3` - - - betflip bf - - - Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. - - - `{0}bf 5 heads` or `{0}bf 3 t` - - - 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. - - - `{0}roll` or `{0}roll 7` or `{0}roll 3d5` or `{0}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. - - - `{0}rolluo` or `{0}rolluo 7` or `{0}rolluo 3d5` - - - nroll - - - Rolls in a given range. - - - `{0}nroll 5` (rolls 0-5) or `{0}nroll 5-15` - - - race - - - Starts a new animal race. - - - `{0}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. - - - `{0}jr` or `{0}jr 5` - - - raffle - - - Prints a name and ID of a random user from the online list from the (optional) role. - - - `{0}raffle` or `{0}raffle RoleName` - - - give - - - Give someone a certain amount of currency. - - - `{0}give 1 "@SomeGuy"` - - - award - - - Awards someone a certain amount of currency. You can also specify a role name to award currency to all users in a role. - - - `{0}award 100 @person` or `{0}award 5 Role Of Gamblers` - - - take - - - Takes a certain amount of currency from someone. - - - `{0}take 1 "@someguy"` - - - betroll br - - - Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10. - - - `{0}br 5` - - - leaderboard lb - - - Displays bot currency leaderboard. - - - `{0}lb` - - - trivia t - - - Starts a game of trivia. You can add nohint to prevent hints.First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. - - - `{0}t` or `{0}t 5 nohint` - - - tl - - - Shows a current trivia leaderboard. - - - `{0}tl` - - - tq - - - Quits current trivia after current question. - - - `{0}tq` - - - typestart - - - Starts a typing contest. - - - `{0}typestart` - - - typestop - - - Stops a typing contest on the current channel. - - - `{0}typestop` - - - typeadd - - - Adds a new article to the typing contest. - - - `{0}typeadd wordswords` - - - poll - - - Creates a poll which requires users to send the number of the voting option to the bot. - - - `{0}poll Question?;Answer1;Answ 2;A_3` - - - pollend - - - Stops active poll on this server and prints the results in this channel. - - - `{0}pollend` - - - pick - - - Picks the currency planted in this channel. 60 seconds cooldown. - - - `{0}pick` - - - plant - - - Spend an amount of currency to plant it in this channel. Default is 1. (If bot is restarted or crashes, the currency will be lost) - - - `{0}plant` or `{0}plant 5` - - - gencurrency gc - - - Toggles currency generation on this channel. Every posted message will have chance to spawn currency. Chance is specified by the Bot Owner. (default is 2%) - - - `{0}gc` - - - leet - - - Converts a text to leetspeak with 6 (1-6) severity levels - - - `{0}leet 3 Hello` - - - choose - - - Chooses a thing from a list of things - - - `{0}choose Get up;Sleep;Sleep more` - - - 8ball - - - Ask the 8ball a yes/no question. - - - `{0}8ball should I do something` - - - rps - - - Play a game of rocket paperclip scissors with Nadeko. - - - `{0}rps scissors` - - - linux - - - Prints a customizable Linux interjection - - - `{0}linux Spyware Windows` - - - next n - - - Goes to the next song in the queue. You have to be in the same voice channel as the bot. You can skip multiple songs, but in that case songs will not be requeued if {0}rcs or {0}rpl is enabled. - - - `{0}n` or `{0}n 5` - - - stop s - - - Stops the music and clears the playlist. Stays in the channel. - - - `{0}s` - - - destroy d - - - Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) - - - `{0}d` - - - pause p - - - Pauses or Unpauses the song. - - - `{0}p` - - - queue q yq - - - Queue a song using keywords or a link. Bot will join your voice channel.**You must be in a voice channel**. - - - `{0}q Dream Of Venice` - - - soundcloudqueue sq - - - Queue a soundcloud song using keywords. Bot will join your voice channel.**You must be in a voice channel**. - - - `{0}sq Dream Of Venice` - - - listqueue lq - - - Lists 15 currently queued songs per page. Default page is 1. - - - `{0}lq` or `{0}lq 2` - - - nowplaying np - - - Shows the song currently playing. - - - `{0}np` - - - volume vol - - - Sets the music volume 0-100% - - - `{0}vol 50` - - - defvol dv - - - Sets the default music volume when music playback is started (0-100). Persists through restarts. - - - `{0}dv 80` - - - max - - - Sets the music volume to 100%. - - - `{0}max` - - - half - - - Sets the music volume to 50%. - - - `{0}half` - - - playlist pl - - - Queues up to 500 songs from a youtube playlist specified by a link, or keywords. - - - `{0}pl playlist link or name` - - - soundcloudpl scpl - - - Queue a soundcloud playlist using a link. - - - `{0}scpl soundcloudseturl` - - - localplaylst lopl - - - Queues all songs from a directory. - - - `{0}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: <https://streamable.com/al54>) - - - `{0}ra radio link here` - - - local lo - - - Queues a local file by specifying a full path. - - - `{0}lo C:/music/mysong.mp3` - - - move mv - - - Moves the bot to your voice channel. (works only if music is already playing) - - - `{0}mv` - - - remove rm - - - Remove a song by its # in the queue, or 'all' to remove whole queue. - - - `{0}rm 5` - - - movesong ms - - - Moves a song from one position to another. - - - `{0}ms 5>3` - - - setmaxqueue smq - - - Sets a maximum queue size. Supply 0 or no argument to have no limit. - - - `{0}smq 50` or `{0}smq` - - - cleanup - - - Cleans up hanging voice connections. - - - `{0}cleanup` - - - reptcursong rcs - - - Toggles repeat of current song. - - - `{0}rcs` - - - rpeatplaylst rpl - - - Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). - - - `{0}rpl` - - - save - - - Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. - - - `{0}save classical1` - - - load - - - Loads a saved playlist using it's ID. Use `{0}pls` to list all saved playlists and {0}save to save new ones. - - - `{0}load 5` - - - playlists pls - - - Lists all playlists. Paginated. 20 per page. Default page is 0. - - - `{0}pls 1` - - - deleteplaylist delpls - - - Deletes a saved playlist. Only if you made it or if you are the bot owner. - - - `{0}delpls animu-5` - - - goto - - - Goes to a specific time in seconds in a song. - - - `{0}goto 30` - - - autoplay ap - - - Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty) - - - `{0}ap` - - - lolchamp - - - Shows League Of Legends champion statistics. If there are spaces/apostrophes or in the name - omit them. Optional second parameter is a role. - - - `{0}lolchamp Riven` or `{0}lolchamp Annie sup` - - - lolban - - - Shows top banned champions ordered by ban rate. - - - `{0}lolban` - - - hitbox hb - - - Notifies this channel when a certain user starts streaming. - - - `{0}hitbox SomeStreamer` - - - twitch tw - - - Notifies this channel when a certain user starts streaming. - - - `{0}twitch SomeStreamer` - - - beam bm - - - Notifies this channel when a certain user starts streaming. - - - `{0}beam SomeStreamer` - - - removestream rms - - - Removes notifications of a certain streamer from a certain platform on this channel. - - - `{0}rms Twitch SomeGuy` or `{0}rms Beam SomeOtherGuy` - - - liststreams ls - - - Lists all streams you are following on this server. - - - `{0}ls` - - - convert - - - Convert quantities. Use `{0}convertlist` to see supported dimensions and currencies. - - - `{0}convert m km 1000` - - - convertlist - - - List of the convertible dimensions and currencies. - - - `{0}convertlist` - - - wowjoke - - - Get one of Kwoth's penultimate WoW jokes. - - - `{0}wowjoke` - - - calculate calc - - - Evaluate a mathematical expression. - - - `{0}calc 1+1` - - - osu - - - Shows osu stats for a player. - - - `{0}osu Name` or `{0}osu Name taiko` - - - osub - - - Shows information about an osu beatmap. - - - `{0}osub https://osu.ppy.sh/s/127712` - - - osu5 - - - Displays a user's top 5 plays. - - - `{0}osu5 Name` - - - pokemon poke - - - Searches for a pokemon. - - - `{0}poke Sylveon` - - - pokemonability pokeab - - - Searches for a pokemon ability. - - - `{0}pokeab overgrow` - - - memelist - - - Pulls a list of memes you can use with `{0}memegen` from http://memegen.link/templates/ - - - `{0}memelist` - - - memegen - - - Generates a meme from memelist with top and bottom text. - - - `{0}memegen biw "gets iced coffee" "in the winter"` - - - weather we - - - Shows weather data for a specified city. You can also specify a country after a comma. - - - `{0}we Moscow, RU` - - - youtube yt - - - Searches youtubes and shows the first result - - - `{0}yt query` - - - anime ani aq - - - Queries anilist for an anime and shows the first result. - - - `{0}ani aquarion evol` - - - imdb omdb - - - Queries omdb for movies or series, show first result. - - - `{0}imdb Batman vs Superman` - - - manga mang mq - - - Queries anilist for a manga and shows the first result. - - - `{0}mq Shingeki no kyojin` - - - randomcat meow - - - Shows a random cat image. - - - `{0}meow` - - - randomdog woof - - - Shows a random dog image. - - - `{0}woof` - - - image img - - - Pulls the first image found using a search parameter. Use {0}rimg for different results. - - - `{0}img cute kitten` - - - randomimage rimg - - - Pulls a random image using a search parameter. - - - `{0}rimg cute kitten` - - - lmgtfy - - - Google something for an idiot. - - - `{0}lmgtfy query` - - - google g - - - Get a google search link for some terms. - - - `{0}google query` - - - hearthstone hs - - - Searches for a Hearthstone card and shows its image. Takes a while to complete. - - - `{0}hs Ysera` - - - urbandict ud - - - Searches Urban Dictionary for a word. - - - `{0}ud Pineapple` - - - # - - - Searches Tagdef.com for a hashtag. - - - `{0}# ff` - - - catfact - - - Shows a random catfact from <http://catfacts-api.appspot.com/api/facts> - - - `{0}catfact` - - - yomama ym - - - Shows a random joke from <http://api.yomomma.info/> - - - `{0}ym` - - - randjoke rj - - - Shows a random joke from <http://tambal.azurewebsites.net/joke/random> - - - `{0}rj` - - - chucknorris cn - - - Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random> - - - `{0}cn` - - - magicitem mi - - - Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items> - - - `{0}mi` - - - revav - - - Returns a google reverse image search for someone's avatar. - - - `{0}revav "@SomeGuy"` - - - revimg - - - Returns a google reverse image search for an image from a link. - - - `{0}revimg Image link` - - - safebooru - - - Shows a random image from safebooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) - - - `{0}safebooru yuri+kissing` - - - wikipedia wiki - - - Gives you back a wikipedia link - - - `{0}wiki query` - - - color clr - - - Shows you what color corresponds to that hex. - - - `{0}clr 00ff00` - - - videocall - - - Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message. - - - `{0}videocall "@SomeGuy"` - - - avatar av - - - Shows a mentioned person's avatar. - - - `{0}av "@SomeGuy"` - - - 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. - - - `{0}hentai yuri` - - - danbooru - - - Shows a random hentai image from danbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) - - - `{0}danbooru yuri+kissing` - - - atfbooru atf - - - Shows a random hentai image from atfbooru with a given tag. Tag is optional but preferred. - - - `{0}atfbooru yuri+kissing` - - - gelbooru - - - Shows a random hentai image from gelbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) - - - `{0}gelbooru yuri+kissing` - - - rule34 - - - Shows a random image from rule34.xx with a given tag. Tag is optional but preferred. (multiple tags are appended with +) - - - `{0}rule34 yuri+kissing` - - - e621 - - - Shows a random hentai image from e621.net with a given tag. Tag is optional but preferred. Use spaces for multiple tags. - - - `{0}e621 yuri kissing` - - - cp - - - We all know where this will lead you to. - - - `{0}cp` - - - boobs - - - Real adult content. - - - `{0}boobs` - - - butts ass butt - - - Real adult content. - - - `{0}butts` or `{0}ass` - - - createwar cw - - - Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. - - - `{0}cw 15 The Enemy Clan` - - - startwar sw - - - Starts a war with a given number. - - - `{0}sw 15` - - - listwar lw - - - Shows the active war claims by a number. Shows all wars in a short way if no number is specified. - - - `{0}lw [war_number] or {0}lw` - - - claim call c - - - Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. - - - `{0}call [war_number] [base_number] [optional_other_name]` - - - claimfinish cf - - - Finish your claim with 3 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. - - - `{0}cf 1` or `{0}cf 1 5` - - - claimfinish2 cf2 - - - Finish your claim with 2 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. - - - `{0}cf2 1` or `{0}cf2 1 5` - - - claimfinish1 cf1 - - - Finish your claim with 1 star if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. - - - `{0}cf1 1` or `{0}cf1 1 5` - - - unclaim ucall uc - - - Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim - - - `{0}uc [war_number] [optional_other_name]` - - - endwar ew - - - Ends the war with a given index. - - - `{0}ew [war_number]` - - - translate trans - - - Translates from>to text. From the given language to the destination language. - - - `{0}trans en>fr Hello` - - - translangs - - - Lists the valid languages for translation. - - - `{0}translangs` - - - Sends a readme and a guide links to the channel. - - - `{0}readme` or `{0}guide` - - - readme guide - - - Shows all available operations in {0}calc command - - - `{0}calcops` - - - calcops - - - Deletes all quotes on a specified keyword. - - - `{0}delallq kek` - - - delallq daq - - - greetdmmsg - - - `{0}greetdmmsg Welcome to the server, %user%`. - - - Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. - - - Check how much currency a person has. (Defaults to yourself) - - - `{0}$$` or `{0}$$ @SomeGuy` - - - cash $$ - - - Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions. - - - `{0}lp` or `{0}lp 3` - - - listperms lp - - - Enable or disable all modules for a specific user. - - - `{0}aum enable @someone` - - - allusrmdls aum - - - Moves permission from one position to another in Permissions list. - - - `{0}mp 2 4` - - - moveperm mp - - - Removes a permission from a given position in Permissions list. - - - `{0}rp 1` - - - removeperm rp - - - Migrate data from old bot configuration - - - `{0}migratedata` - - - migratedata - - - Checks if a user is online on a certain streaming platform. - - - `{0}cs twitch MyFavStreamer` - - - checkstream cs - - - showemojis se - - - Shows a name and a link to every SPECIAL emoji in the message. - - - `{0}se A message full of SPECIAL emojis` - - - shuffle sh - - - Reshuffles all cards back into the deck. - - - `{0}sh` - - - fwmsgs - - - Toggles forwarding of non-command messages sent to bot's DM to the bot owners - - - `{0}fwmsgs` - - - fwtoall - - - Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json - - - `{0}fwtoall` - - - resetperms - - - Resets BOT's permissions module on this server to the default value. - - - `{0}resetperms` - - - antiraid - - - Sets an anti-raid protection on the server. First argument is number of people which will trigger the protection. Second one is a time interval in which that number of people needs to join in order to trigger the protection, and third argument is punishment for those people (Kick, Ban, Mute) - - - `{0}antiraid 5 20 Kick` - - - antispam - - - Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10. - - - `{0}antispam 3 Mute` or `{0}antispam 4 Kick` or `{0}antispam 6 Ban` - - - chatmute - - - Prevents a mentioned user from chatting in text channels. - - - `{0}chatmute @Someone` - - - voicemute - - - Prevents a mentioned user from speaking in voice channels. - - - `{0}voicemute @Someone` - - - konachan - - - Shows a random hentai image from konachan with a given tag. Tag is optional but preferred. - - - `{0}konachan yuri` - - - setmuterole - - - Sets a name of the role which will be assigned to people who should be muted. Default is nadeko-mute. - - - `{0}setmuterole Silenced` - - - adsarm - - - Toggles the automatic deletion of confirmations for {0}iam and {0}iamn commands. - - - `{0}adsarm` - - - setstream - - - Sets the bots stream. First argument is the twitch link, second argument is stream name. - - - `{0}setstream TWITCHLINK Hello` - - - chatunmute - - - Removes a mute role previously set on a mentioned user with `{0}chatmute` which prevented him from chatting in text channels. - - - `{0}chatunmute @Someone` - - - unmute - - - Unmutes a mentioned user previously muted with `{0}mute` command. - - - `{0}unmute @Someone` - - - xkcd - - - Shows a XKCD comic. No arguments will retrieve random one. Number argument will retrieve a specific comic, and "latest" will get the latest one. - - - `{0}xkcd` or `{0}xkcd 1400` or `{0}xkcd latest` - - - placelist - - - Shows the list of available tags for the `{0}place` command. - - - `{0}placelist` - - - place - - - Shows a placeholder image of a given tag. Use `{0}placelist` to see all available tags. You can specify the width and height of the image as the last two optional arguments. - - - `{0}place Cage` or `{0}place steven 500 400` - - - togethertube totube - - - Creates a new room on <https://togethertube.com> and shows the link in the chat. - - - `{0}totube` - - - publicpoll ppoll - - - Creates a public poll which requires users to type a number of the voting option in the channel command is ran in. - - - `{0}ppoll Question?;Answer1;Answ 2;A_3` - - - autotranslang atl - - - Sets your source and target language to be used with `{0}at`. Specify no arguments to remove previously set value. - - - `{0}atl en>fr` - - - autotrans at - - - Starts automatic translation of all messages by users who set their `{0}atl` in this channel. You can set "del" argument to automatically delete all translated user messages. - - - `{0}at` or `{0}at del` - - - listquotes liqu - - - `{0}liqu` or `{0}liqu 3` - - - Lists all quotes on the server ordered alphabetically. 15 Per page. - - - typedel - - - Deletes a typing article given the ID. - - - `{0}typedel 3` - - - typelist - - - Lists added typing articles with their IDs. 15 per page. - - - `{0}typelist` or `{0}typelist 3` - - - listservers - - - Lists servers the bot is on with some basic info. 15 per page. - - - `{0}listservers 3` - - - hentaibomb - - - Shows a total 5 images (from gelbooru, danbooru, konachan, yandere and atfbooru). Tag is optional but preferred. - - - `{0}hentaibomb yuri` - - - cleverbot - - - Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. - - - `{0}cleverbot` - - - shorten - - - Attempts to shorten an URL, if it fails, returns the input URL. - - - `{0}shorten https://google.com` - - - minecraftping mcping - - - Pings a minecraft server. - - - `{0}mcping 127.0.0.1:25565` - - - minecraftquery mcq - - - Finds information about a minecraft server. - - - `{0}mcq server:ip` - - - wikia - - - Gives you back a wikia link - - - `{0}wikia mtg Vigilance` or `{0}wikia mlp Dashy` - - - yandere - - - Shows a random image from yandere with a given tag. Tag is optional but preferred. (multiple tags are appended with +) - - - `{0}yandere tag1+tag2` - - - magicthegathering mtg - - - Searches for a Magic The Gathering card. - - - `{0}magicthegathering about face` or `{0}mtg about face` - - - yodify yoda - - - Translates your normal sentences into Yoda styled sentences! - - - `{0}yoda my feelings hurt` - - - attack - - - Attacks a target with the given move. Use `{0}movelist` to see a list of moves your type can use. - - - `{0}attack "vine whip" @someguy` - - - heal - - - Heals someone. Revives those who fainted. Costs a NadekoFlower - - - `{0}heal @someone` - - - movelist ml - - - Lists the moves you are able to use - - - `{0}ml` - - - settype - - - Set your poketype. Costs a NadekoFlower. Provide no arguments to see a list of available types. - - - `{0}settype fire` or `{0}settype` - - - type - - - Get the poketype of the target. - - - `{0}type @someone` - - - hangmanlist - - - Shows a list of hangman term types. - - - `{0} hangmanlist` - - - hangman - - - Starts a game of hangman in the channel. Use `{0}hangmanlist` to see a list of available term types. Defaults to 'all'. - - - `{0}hangman` or `{0}hangman movies` - - - crstatsclear - - - Resets the counters on `{0}crstats`. You can specify a trigger to clear stats only for that trigger. - - - `{0}crstatsclear` or `{0}crstatsclear rng` - - - crstats - - - Shows a list of custom reactions and the number of times they have been executed. Paginated with 10 per page. Use `{0}crstatsclear` to reset the counters. - - - `{0}crstats` or `{0}crstats 3` - - - overwatch ow - - - Show's basic stats on a player (competitive rank, playtime, level etc) Region codes are: `eu` `us` `cn` `kr` - - - `{0}ow us Battletag#1337` or `{0}overwatch eu Battletag#2016` - - - acrophobia acro - - - Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60) - - - `{0}acro` or `{0}acro 30` - - - logevents - - - Shows a list of all events you can subscribe to with `{0}log` - - - `{0}logevents` - - - log - - - Toggles logging event. Disables it if it's active anywhere on the server. Enables if it's not active. Use `{0}logevents` to see a list of all events you can subscribe to. - - - `{0}log userpresence` or `{0}log userbanned` - - - fairplay fp - - - Toggles fairplay. While enabled, music player will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue. - - - `{0}fp` - - - define def - - - Finds a definition of a word. - - - `{0}def heresy` - - - setmaxplaytime smp - - - Sets a maximum number of seconds (>14) a song can run before being skipped automatically. Set 0 to have no limit. - - - `{0}smp 0` or `{0}smp 270` - - - activity - - - Checks for spammers. - - - `{0}activity` - - - 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. - - - `{0}autohentai 30 yuri|tail|long_hair` or `{0}autohentai` - - - setstatus - - - Sets the bot's status. (Online/Idle/Dnd/Invisible) - - - `{0}setstatus Idle` - - - rotaterolecolor rrc - - - Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. - - - `{0}rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `{0}rrc 0 MyLsdRole` - - - createinvite crinv - - - Creates a new invite which has infinite max uses and never expires. - - - `{0}crinv` - - - pollstats - - - Shows the poll results without stopping the poll on this server. - - - `{0}pollstats` - - - repeatlist replst - - - Shows currently repeating messages and their indexes. - - - `{0}repeatlist` - - - repeatremove reprm - - - Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes. - - - `{0}reprm 2` - - - antilist antilst - - - Shows currently enabled protection features. - - - `{0}antilist` - - - antispamignore - - - Toggles whether antispam ignores current channel. Antispam must be enabled. - - - `{0}antispamignore` - - - cmdcosts - - - Shows a list of command costs. Paginated with 9 command per page. - - - `{0}cmdcosts` or `{0}cmdcosts 2` - - - commandcost cmdcost - - - Sets a price for a command. Running that command will take currency from users. Set 0 to remove the price. - - - `{0}cmdcost 0 !!q` or `{0}cmdcost 1 >8ball` - - - startevent - - - Starts one of the events seen on public nadeko. - - - `{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` - - - affinity - - - 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 @MyHusband` or `{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 9 waifus. - - - `{0}waifus` - - - 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. - - - `{0}divorce @CheatingSloot` - - - waifuinfo waifustats - - - Shows waifu stats for a target person. Defaults to you if no user is provided. - - - `{0}waifuinfo @MyCrush` or `{0}waifuinfo` - - - mal - - - Shows basic info from myanimelist profile. - - - `{0}mal straysocks` - - - setmusicchannel smch - - - Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in. - - - `{0}smch` - - - reloadimages - - - Reloads images bot is using. Safe to use even when bot is being used heavily. - - - `{0}reloadimages` - - - shardstats - - - Stats for shards. Paginated with 25 shards per page. - - - `{0}shardstats` or `{0}shardstats 2` - - - connectshard - - - Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. - - - `{0}connectshard 2` - - - shardid - - - Shows which shard is a certain guild on, by guildid. - - - `{0}shardid 117523346618318850` - - - tictactoe ttt - - - Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. 15 seconds per move. - - - >ttt - - - timezones - - - List of all timezones available on the system to be used with `{0}timezone`. - - - `{0}timezones` - - - timezone - - - Sets this guilds timezone. This affects bot's time output in this server (logs, etc..) - - - `{0}timezone` - - - langsetdefault langsetd - - - Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. - - - `{0}langsetd en-US` or `{0}langsetd default` - - - languageset langset - - - Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. - - - `{0}langset de-DE ` or `{0}langset default` - - - languageslist langli - - - List of languages for which translation (or part of it) exist atm. - - - `{0}langli` - - - rategirl - - - Use the universal hot-crazy wife zone matrix to determine the girl's worth. It is everything young men need to know about women. At any moment in time, any woman you have previously located on this chart can vanish from that location and appear anywhere else on the chart. - - - `{0}rategirl @SomeGurl` - \ No newline at end of file From 5dcab616415eb135f254e8639786ad5521c09c3f Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 01:51:02 +0100 Subject: [PATCH 375/746] Update CommandStrings.ja-JP.resx (POEditor.com) --- .../Resources/CommandStrings.ja-JP.resx | 5314 +++++++---------- 1 file changed, 2164 insertions(+), 3150 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.ja-JP.resx b/src/NadekoBot/Resources/CommandStrings.ja-JP.resx index 662975cf..17febe51 100644 --- a/src/NadekoBot/Resources/CommandStrings.ja-JP.resx +++ b/src/NadekoBot/Resources/CommandStrings.ja-JP.resx @@ -1,3153 +1,2167 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PLURAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PLURAL (users have been muted) + + + + singular "User muted." + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PLURAL + + + + + + + + + + + + + + + + + + + + + + singular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + User flipped tails. + + + + + + + + + + + + + + + + + + + X has gifted 15 flowers to Y + + + + X has Y flowers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Someone rolled 35 + + + + Dice Rolled: 5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Make sure to get the formatting right, and leave the thinking emoji + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + plural + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Kwoth picked 5* + + + + Kwoth planted 5* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + context: "removed song #5" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gen (of command) + + + + Gen. (of module) + + + + + + + + + + + + + + + + + + + + + + + + + Short of seconds. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Don't translate {0}place + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /s and total need to be localized to fit the context - +`1.` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Invalid months value/ Invalid hours value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Id of the user kwoth#1234 is 123123123123 + + + + + + + - mimetype: application/x-microsoft.net.object.bytearray.base64 - value : The object must be serialized into a byte array - : using a System.ComponentModel.TypeConverter - : and then encoded with base64 encoding. - --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - help h - - - Either shows a help for a single command, or DMs you help link if no arguments are specified. - - - `{0}h !!q` or `{0}h` - - - hgit - - - Generates the commandlist.md file. - - - `{0}hgit` - - - donate - - - Instructions for helping the project financially. - - - `{0}donate` - - - modules mdls - - - Lists all bot modules. - - - `{0}modules` - - - commands cmds - - - List all of the bot's commands from a certain module. You can either specify full, or only first few letters of the module name. - - - `{0}commands Administration` or `{0}cmds Admin` - - - greetdel grdel - - - Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set 0 to disable automatic deletion. - - - `{0}greetdel 0` or `{0}greetdel 30` - - - greet - - - Toggles anouncements on the current channel when someone joins the server. - - - `{0}greet` - - - greetmsg - - - Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. - - - `{0}greetmsg Welcome, %user%.` - - - bye - - - Toggles anouncements on the current channel when someone leaves the server. - - - `{0}bye` - - - byemsg - - - Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. - - - `{0}byemsg %user% has left.` - - - byedel - - - Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set 0 to disable automatic deletion. - - - `{0}byedel 0` or `{0}byedel 30` - - - greetdm - - - Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). - - - `{0}greetdm` - - - logserver - - - Enables or Disables ALL log events. If enabled, all log events will log to this channel. - - - `{0}logserver enable` or `{0}logserver disable` - - - logignore - - - Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. - - - `{0}logignore` - - - userpresence - - - Starts logging to this channel when someone from the server goes online/offline/idle. - - - `{0}userpresence` - - - voicepresence - - - Toggles logging to this channel whenever someone joins or leaves a voice channel you are currently in. - - - `{0}voicepresence` - - - repeatinvoke repinv - - - Immediately shows the repeat message on a certain index and restarts its timer. - - - `{0}repinv 1` - - - repeat - - - Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. - - - `{0}repeat 5 Hello there` - - - rotateplaying ropl - - - Toggles rotation of playing status of the dynamic strings you previously specified. - - - `{0}ropl` - - - addplaying adpl - - - Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %time%,%shardid%,%shardcount%, %shardguilds% - - - `{0}adpl` - - - listplaying lipl - - - Lists all playing statuses with their corresponding number. - - - `{0}lipl` - - - removeplaying rmpl repl - - - Removes a playing string on a given number. - - - `{0}rmpl` - - - slowmode - - - Toggles slowmode. Disable by specifying no parameters. To enable, specify a number of messages each user can send, and an interval in seconds. For example 1 message every 5 seconds. - - - `{0}slowmode 1 5` or `{0}slowmode` - - - cleanvplust cv+t - - - Deletes all text channels ending in `-voice` for which voicechannels are not found. Use at your own risk. - - - `{0}cleanv+t` - - - voice+text v+t - - - Creates a text channel for each voice channel only users in that voice channel can see.If you are server owner, keep in mind you will see them all the time regardless. - - - `{0}v+t` - - - scsc - - - Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. - - - `{0}scsc` - - - jcsc - - - Joins current channel to an instance of cross server channel using the token. - - - `{0}jcsc TokenHere` - - - lcsc - - - Leaves Cross server channel instance from this channel. - - - `{0}lcsc` - - - asar - - - Adds a role to the list of self-assignable roles. - - - `{0}asar Gamer` - - - rsar - - - Removes a specified role from the list of self-assignable roles. - - - `{0}rsar` - - - lsar - - - Lists all self-assignable roles. - - - `{0}lsar` - - - togglexclsar tesar - - - Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) - - - `{0}tesar` - - - iam - - - Adds a role to you that you choose. Role must be on a list of self-assignable roles. - - - `{0}iam Gamer` - - - iamnot iamn - - - Removes a role to you that you choose. Role must be on a list of self-assignable roles. - - - `{0}iamn Gamer` - - - addcustreact acr - - - Add a custom reaction with a trigger and a response. Running this command in server requires Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: <http://nadekobot.readthedocs.io/en/latest/Custom%20Reactions/> - - - `{0}acr "hello" Hi there %user%` - - - listcustreact lcr - - - Lists global or server custom reactions (20 commands per page). Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. Specifying `all` argument instead of the number will DM you a text file with a list of all custom reactions. - - - `{0}lcr 1` or `{0}lcr all` - - - listcustreactg lcrg - - - Lists global or server custom reactions (20 commands per page) grouped by trigger, and show a number of responses for each. Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. - - - `{0}lcrg 1` - - - showcustreact scr - - - Shows a custom reaction's response on a given ID. - - - `{0}scr 1` - - - delcustreact dcr - - - Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration priviledges and removes server custom reaction. - - - `{0}dcr 5` - - - autoassignrole aar - - - Automaticaly assigns a specified role to every user who joins the server. - - - `{0}aar` to disable, `{0}aar Role Name` to enable - - - leave - - - Makes Nadeko leave the server. Either name or id required. - - - `{0}leave 123123123331` - - - delmsgoncmd - - - Toggles the automatic deletion of user's successful command message to prevent chat flood. - - - `{0}delmsgoncmd` - - - restart - - - Restarts the bot. Might not work. - - - `{0}restart` - - - setrole sr - - - Sets a role for a given user. - - - `{0}sr @User Guest` - - - removerole rr - - - Removes a role from a given user. - - - `{0}rr @User Admin` - - - renamerole renr - - - Renames a role. Roles you are renaming must be lower than bot's highest role. - - - `{0}renr "First role" SecondRole` - - - removeallroles rar - - - Removes all roles from a mentioned user. - - - `{0}rar @User` - - - createrole cr - - - Creates a role with a given name. - - - `{0}cr Awesome Role` - - - rolecolor rc - - - Set a role's color to the hex or 0-255 rgb color value provided. - - - `{0}rc Admin 255 200 100` or `{0}rc Admin ffba55` - - - ban b - - - Bans a user by ID or name with an optional message. - - - `{0}b "@some Guy" Your behaviour is toxic.` - - - softban sb - - - Bans and then unbans a user by ID or name with an optional message. - - - `{0}sb "@some Guy" Your behaviour is toxic.` - - - kick k - - - Kicks a mentioned user. - - - `{0}k "@some Guy" Your behaviour is toxic.` - - - mute - - - Mutes a mentioned user both from speaking and chatting. - - - `{0}mute @Someone` - - - voiceunmute - - - Gives a previously voice-muted user a permission to speak. - - - `{0}voiceunmute @Someguy` - - - deafen deaf - - - Deafens mentioned user or users. - - - `{0}deaf "@Someguy"` or `{0}deaf "@Someguy" "@Someguy"` - - - undeafen undef - - - Undeafens mentioned user or users. - - - `{0}undef "@Someguy"` or `{0}undef "@Someguy" "@Someguy"` - - - delvoichanl dvch - - - Deletes a voice channel with a given name. - - - `{0}dvch VoiceChannelName` - - - creatvoichanl cvch - - - Creates a new voice channel with a given name. - - - `{0}cvch VoiceChannelName` - - - deltxtchanl dtch - - - Deletes a text channel with a given name. - - - `{0}dtch TextChannelName` - - - creatxtchanl ctch - - - Creates a new text channel with a given name. - - - `{0}ctch TextChannelName` - - - settopic st - - - Sets a topic on the current channel. - - - `{0}st My new topic` - - - setchanlname schn - - - Changes the name of the current channel. - - - `{0}schn NewName` - - - prune clr - - - `{0}prune` removes all nadeko's messages in the last 100 messages.`{0}prune X` removes last X messages from the channel (up to 100)`{0}prune @Someone` removes all Someone's messages in the last 100 messages.`{0}prune @Someone X` removes last X 'Someone's' messages in the channel. - - - `{0}prune` or `{0}prune 5` or `{0}prune @Someone` or `{0}prune @Someone X` - - - die - - - Shuts the bot down. - - - `{0}die` - - - setname newnm - - - Gives the bot a new name. - - - `{0}newnm BotName` - - - setavatar setav - - - Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. - - - `{0}setav http://i.imgur.com/xTG3a1I.jpg` - - - setgame - - - Sets the bots game. - - - `{0}setgame with snakes` - - - send - - - Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prepend channel id with `c:` and user id with `u:`. - - - `{0}send serverid|c:channelid message` or `{0}send serverid|u:userid message` - - - mentionrole menro - - - Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. - - - `{0}menro RoleName` - - - unstuck - - - Clears the message queue. - - - `{0}unstuck` - - - donators - - - List of lovely people who donated to keep this project alive. - - - `{0}donators` - - - donadd - - - Add a donator to the database. - - - `{0}donadd Donate Amount` - - - announce - - - Sends a message to all servers' general channel bot is connected to. - - - `{0}announce Useless spam` - - - savechat - - - Saves a number of messages to a text file and sends it to you. - - - `{0}savechat 150` - - - remind - - - Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message. - - - `{0}remind me 1d5h Do something` or `{0}remind #general 1m Start now!` - - - remindtemplate - - - Sets message for when the remind is triggered. Available placeholders are %user% - user who ran the command, %message% - Message specified in the remind, %target% - target channel of the remind. - - - `{0}remindtemplate %user%, do %message%!` - - - serverinfo sinfo - - - Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. - - - `{0}sinfo Some Server` - - - channelinfo cinfo - - - Shows info about the channel. If no channel is supplied, it defaults to current one. - - - `{0}cinfo #some-channel` - - - userinfo uinfo - - - Shows info about the user. If no user is supplied, it defaults a user running the command. - - - `{0}uinfo @SomeUser` - - - whosplaying whpl - - - Shows a list of users who are playing the specified game. - - - `{0}whpl Overwatch` - - - inrole - - - Lists every person from the provided role or roles, separated with space, on this server. You can use role IDs, role names (in quotes if it has multiple words), or role mention If the list is too long for 1 message, you must have Manage Messages permission. - - - `{0}inrole Role` or `{0}inrole Role1 "Role 2" @role3` - - - checkmyperms - - - Checks your user-specific permissions on this channel. - - - `{0}checkmyperms` - - - stats - - - Shows some basic stats for Nadeko. - - - `{0}stats` - - - userid uid - - - Shows user ID. - - - `{0}uid` or `{0}uid "@SomeGuy"` - - - channelid cid - - - Shows current channel ID. - - - `{0}cid` - - - serverid sid - - - Shows current server ID. - - - `{0}sid` - - - roles - - - List roles on this server or a roles of a specific user if specified. Paginated. 20 roles per page. - - - `{0}roles 2` or `{0}roles @Someone` - - - channeltopic ct - - - Sends current channel's topic as a message. - - - `{0}ct` - - - chnlfilterinv cfi - - - Toggles automatic deleting of invites posted in the channel. Does not negate the {0}srvrfilterinv enabled setting. Does not affect Bot Owner. - - - `{0}cfi` - - - srvrfilterinv sfi - - - Toggles automatic deleting of invites posted in the server. Does not affect Bot Owner. - - - `{0}sfi` - - - chnlfilterwords cfw - - - Toggles automatic deleting of messages containing banned words on the channel. Does not negate the {0}srvrfilterwords enabled setting. Does not affect bot owner. - - - `{0}cfw` - - - fw - - - Adds or removes (if it exists) a word from the list of filtered words. Use`{0}sfw` or `{0}cfw` to toggle filtering. - - - `{0}fw poop` - - - lstfilterwords lfw - - - Shows a list of filtered words. - - - `{0}lfw` - - - srvrfilterwords sfw - - - Toggles automatic deleting of messages containing forbidden words on the server. Does not affect Bot Owner. - - - `{0}sfw` - - - permrole pr - - - Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'. - - - `{0}pr role` - - - verbose v - - - Sets whether to show when a command/module is blocked. - - - `{0}verbose true` - - - srvrmdl sm - - - Sets a module's permission at the server level. - - - `{0}sm ModuleName enable` - - - srvrcmd sc - - - Sets a command's permission at the server level. - - - `{0}sc "command name" disable` - - - rolemdl rm - - - Sets a module's permission at the role level. - - - `{0}rm ModuleName enable MyRole` - - - rolecmd rc - - - Sets a command's permission at the role level. - - - `{0}rc "command name" disable MyRole` - - - chnlmdl cm - - - Sets a module's permission at the channel level. - - - `{0}cm ModuleName enable SomeChannel` - - - chnlcmd cc - - - Sets a command's permission at the channel level. - - - `{0}cc "command name" enable SomeChannel` - - - usrmdl um - - - Sets a module's permission at the user level. - - - `{0}um ModuleName enable SomeUsername` - - - usrcmd uc - - - Sets a command's permission at the user level. - - - `{0}uc "command name" enable SomeUsername` - - - allsrvrmdls asm - - - Enable or disable all modules for your server. - - - `{0}asm [enable/disable]` - - - allchnlmdls acm - - - Enable or disable all modules in a specified channel. - - - `{0}acm enable #SomeChannel` - - - allrolemdls arm - - - Enable or disable all modules for a specific role. - - - `{0}arm [enable/disable] MyRole` - - - ubl - - - Either [add]s or [rem]oves a user specified by a mention or ID from a blacklist. - - - `{0}ubl add @SomeUser` or `{0}ubl rem 12312312313` - - - cbl - - - Either [add]s or [rem]oves a channel specified by an ID from a blacklist. - - - `{0}cbl rem 12312312312` - - - sbl - - - Either [add]s or [rem]oves a server specified by a Name or ID from a blacklist. - - - `{0}sbl add 12312321312` or `{0}sbl rem SomeTrashServer` - - - cmdcooldown cmdcd - - - Sets a cooldown per user for a command. Set to 0 to remove the cooldown. - - - `{0}cmdcd "some cmd" 5` - - - allcmdcooldowns acmdcds - - - Shows a list of all commands and their respective cooldowns. - - - `{0}acmdcds` - - - . - - - Adds a new quote with the specified name and message. - - - `{0}. sayhi Hi` - - - .. - - - Shows a random quote with a specified name. - - - `{0}.. abc` - - - qsearch - - - Shows a random quote for a keyword that contains any text specified in the search. - - - `{0}qsearch keyword text` - - - deletequote delq - - - Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. - - - `{0}delq abc` - - - draw - - - Draws a card from the deck.If you supply number X, she draws up to 5 cards from the deck. - - - `{0}draw` or `{0}draw 5` - - - shuffle sh - - - Shuffles the current playlist. - - - `{0}sh` - - - flip - - - Flips coin(s) - heads or tails, and shows an image. - - - `{0}flip` or `{0}flip 3` - - - betflip bf - - - Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. - - - `{0}bf 5 heads` or `{0}bf 3 t` - - - 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. - - - `{0}roll` or `{0}roll 7` or `{0}roll 3d5` or `{0}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. - - - `{0}rolluo` or `{0}rolluo 7` or `{0}rolluo 3d5` - - - nroll - - - Rolls in a given range. - - - `{0}nroll 5` (rolls 0-5) or `{0}nroll 5-15` - - - race - - - Starts a new animal race. - - - `{0}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. - - - `{0}jr` or `{0}jr 5` - - - raffle - - - Prints a name and ID of a random user from the online list from the (optional) role. - - - `{0}raffle` or `{0}raffle RoleName` - - - give - - - Give someone a certain amount of currency. - - - `{0}give 1 "@SomeGuy"` - - - award - - - Awards someone a certain amount of currency. You can also specify a role name to award currency to all users in a role. - - - `{0}award 100 @person` or `{0}award 5 Role Of Gamblers` - - - take - - - Takes a certain amount of currency from someone. - - - `{0}take 1 "@someguy"` - - - betroll br - - - Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10. - - - `{0}br 5` - - - leaderboard lb - - - Displays bot currency leaderboard. - - - `{0}lb` - - - trivia t - - - Starts a game of trivia. You can add nohint to prevent hints.First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. - - - `{0}t` or `{0}t 5 nohint` - - - tl - - - Shows a current trivia leaderboard. - - - `{0}tl` - - - tq - - - Quits current trivia after current question. - - - `{0}tq` - - - typestart - - - Starts a typing contest. - - - `{0}typestart` - - - typestop - - - Stops a typing contest on the current channel. - - - `{0}typestop` - - - typeadd - - - Adds a new article to the typing contest. - - - `{0}typeadd wordswords` - - - poll - - - Creates a poll which requires users to send the number of the voting option to the bot. - - - `{0}poll Question?;Answer1;Answ 2;A_3` - - - pollend - - - Stops active poll on this server and prints the results in this channel. - - - `{0}pollend` - - - pick - - - Picks the currency planted in this channel. 60 seconds cooldown. - - - `{0}pick` - - - plant - - - Spend an amount of currency to plant it in this channel. Default is 1. (If bot is restarted or crashes, the currency will be lost) - - - `{0}plant` or `{0}plant 5` - - - gencurrency gc - - - Toggles currency generation on this channel. Every posted message will have chance to spawn currency. Chance is specified by the Bot Owner. (default is 2%) - - - `{0}gc` - - - leet - - - Converts a text to leetspeak with 6 (1-6) severity levels - - - `{0}leet 3 Hello` - - - choose - - - Chooses a thing from a list of things - - - `{0}choose Get up;Sleep;Sleep more` - - - 8ball - - - Ask the 8ball a yes/no question. - - - `{0}8ball should I do something` - - - rps - - - Play a game of rocket paperclip scissors with Nadeko. - - - `{0}rps scissors` - - - linux - - - Prints a customizable Linux interjection - - - `{0}linux Spyware Windows` - - - next n - - - Goes to the next song in the queue. You have to be in the same voice channel as the bot. You can skip multiple songs, but in that case songs will not be requeued if {0}rcs or {0}rpl is enabled. - - - `{0}n` or `{0}n 5` - - - stop s - - - Stops the music and clears the playlist. Stays in the channel. - - - `{0}s` - - - destroy d - - - Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) - - - `{0}d` - - - pause p - - - Pauses or Unpauses the song. - - - `{0}p` - - - queue q yq - - - Queue a song using keywords or a link. Bot will join your voice channel.**You must be in a voice channel**. - - - `{0}q Dream Of Venice` - - - soundcloudqueue sq - - - Queue a soundcloud song using keywords. Bot will join your voice channel.**You must be in a voice channel**. - - - `{0}sq Dream Of Venice` - - - listqueue lq - - - Lists 15 currently queued songs per page. Default page is 1. - - - `{0}lq` or `{0}lq 2` - - - nowplaying np - - - Shows the song currently playing. - - - `{0}np` - - - volume vol - - - Sets the music volume 0-100% - - - `{0}vol 50` - - - defvol dv - - - Sets the default music volume when music playback is started (0-100). Persists through restarts. - - - `{0}dv 80` - - - max - - - Sets the music volume to 100%. - - - `{0}max` - - - half - - - Sets the music volume to 50%. - - - `{0}half` - - - playlist pl - - - Queues up to 500 songs from a youtube playlist specified by a link, or keywords. - - - `{0}pl playlist link or name` - - - soundcloudpl scpl - - - Queue a soundcloud playlist using a link. - - - `{0}scpl soundcloudseturl` - - - localplaylst lopl - - - Queues all songs from a directory. - - - `{0}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: <https://streamable.com/al54>) - - - `{0}ra radio link here` - - - local lo - - - Queues a local file by specifying a full path. - - - `{0}lo C:/music/mysong.mp3` - - - move mv - - - Moves the bot to your voice channel. (works only if music is already playing) - - - `{0}mv` - - - remove rm - - - Remove a song by its # in the queue, or 'all' to remove whole queue. - - - `{0}rm 5` - - - movesong ms - - - Moves a song from one position to another. - - - `{0}ms 5>3` - - - setmaxqueue smq - - - Sets a maximum queue size. Supply 0 or no argument to have no limit. - - - `{0}smq 50` or `{0}smq` - - - cleanup - - - Cleans up hanging voice connections. - - - `{0}cleanup` - - - reptcursong rcs - - - Toggles repeat of current song. - - - `{0}rcs` - - - rpeatplaylst rpl - - - Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). - - - `{0}rpl` - - - save - - - Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. - - - `{0}save classical1` - - - load - - - Loads a saved playlist using it's ID. Use `{0}pls` to list all saved playlists and {0}save to save new ones. - - - `{0}load 5` - - - playlists pls - - - Lists all playlists. Paginated. 20 per page. Default page is 0. - - - `{0}pls 1` - - - deleteplaylist delpls - - - Deletes a saved playlist. Only if you made it or if you are the bot owner. - - - `{0}delpls animu-5` - - - goto - - - Goes to a specific time in seconds in a song. - - - `{0}goto 30` - - - autoplay ap - - - Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty) - - - `{0}ap` - - - lolchamp - - - Shows League Of Legends champion statistics. If there are spaces/apostrophes or in the name - omit them. Optional second parameter is a role. - - - `{0}lolchamp Riven` or `{0}lolchamp Annie sup` - - - lolban - - - Shows top banned champions ordered by ban rate. - - - `{0}lolban` - - - hitbox hb - - - Notifies this channel when a certain user starts streaming. - - - `{0}hitbox SomeStreamer` - - - twitch tw - - - Notifies this channel when a certain user starts streaming. - - - `{0}twitch SomeStreamer` - - - beam bm - - - Notifies this channel when a certain user starts streaming. - - - `{0}beam SomeStreamer` - - - removestream rms - - - Removes notifications of a certain streamer from a certain platform on this channel. - - - `{0}rms Twitch SomeGuy` or `{0}rms Beam SomeOtherGuy` - - - liststreams ls - - - Lists all streams you are following on this server. - - - `{0}ls` - - - convert - - - Convert quantities. Use `{0}convertlist` to see supported dimensions and currencies. - - - `{0}convert m km 1000` - - - convertlist - - - List of the convertible dimensions and currencies. - - - `{0}convertlist` - - - wowjoke - - - Get one of Kwoth's penultimate WoW jokes. - - - `{0}wowjoke` - - - calculate calc - - - Evaluate a mathematical expression. - - - `{0}calc 1+1` - - - osu - - - Shows osu stats for a player. - - - `{0}osu Name` or `{0}osu Name taiko` - - - osub - - - Shows information about an osu beatmap. - - - `{0}osub https://osu.ppy.sh/s/127712` - - - osu5 - - - Displays a user's top 5 plays. - - - `{0}osu5 Name` - - - pokemon poke - - - Searches for a pokemon. - - - `{0}poke Sylveon` - - - pokemonability pokeab - - - Searches for a pokemon ability. - - - `{0}pokeab overgrow` - - - memelist - - - Pulls a list of memes you can use with `{0}memegen` from http://memegen.link/templates/ - - - `{0}memelist` - - - memegen - - - Generates a meme from memelist with top and bottom text. - - - `{0}memegen biw "gets iced coffee" "in the winter"` - - - weather we - - - Shows weather data for a specified city. You can also specify a country after a comma. - - - `{0}we Moscow, RU` - - - youtube yt - - - Searches youtubes and shows the first result - - - `{0}yt query` - - - anime ani aq - - - Queries anilist for an anime and shows the first result. - - - `{0}ani aquarion evol` - - - imdb omdb - - - Queries omdb for movies or series, show first result. - - - `{0}imdb Batman vs Superman` - - - manga mang mq - - - Queries anilist for a manga and shows the first result. - - - `{0}mq Shingeki no kyojin` - - - randomcat meow - - - Shows a random cat image. - - - `{0}meow` - - - randomdog woof - - - Shows a random dog image. - - - `{0}woof` - - - image img - - - Pulls the first image found using a search parameter. Use {0}rimg for different results. - - - `{0}img cute kitten` - - - randomimage rimg - - - Pulls a random image using a search parameter. - - - `{0}rimg cute kitten` - - - lmgtfy - - - Google something for an idiot. - - - `{0}lmgtfy query` - - - google g - - - Get a google search link for some terms. - - - `{0}google query` - - - hearthstone hs - - - Searches for a Hearthstone card and shows its image. Takes a while to complete. - - - `{0}hs Ysera` - - - urbandict ud - - - Searches Urban Dictionary for a word. - - - `{0}ud Pineapple` - - - # - - - Searches Tagdef.com for a hashtag. - - - `{0}# ff` - - - catfact - - - Shows a random catfact from <http://catfacts-api.appspot.com/api/facts> - - - `{0}catfact` - - - yomama ym - - - Shows a random joke from <http://api.yomomma.info/> - - - `{0}ym` - - - randjoke rj - - - Shows a random joke from <http://tambal.azurewebsites.net/joke/random> - - - `{0}rj` - - - chucknorris cn - - - Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random> - - - `{0}cn` - - - magicitem mi - - - Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items> - - - `{0}mi` - - - revav - - - Returns a google reverse image search for someone's avatar. - - - `{0}revav "@SomeGuy"` - - - revimg - - - Returns a google reverse image search for an image from a link. - - - `{0}revimg Image link` - - - safebooru - - - Shows a random image from safebooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) - - - `{0}safebooru yuri+kissing` - - - wikipedia wiki - - - Gives you back a wikipedia link - - - `{0}wiki query` - - - color clr - - - Shows you what color corresponds to that hex. - - - `{0}clr 00ff00` - - - videocall - - - Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message. - - - `{0}videocall "@SomeGuy"` - - - avatar av - - - Shows a mentioned person's avatar. - - - `{0}av "@SomeGuy"` - - - 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. - - - `{0}hentai yuri` - - - danbooru - - - Shows a random hentai image from danbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) - - - `{0}danbooru yuri+kissing` - - - atfbooru atf - - - Shows a random hentai image from atfbooru with a given tag. Tag is optional but preferred. - - - `{0}atfbooru yuri+kissing` - - - gelbooru - - - Shows a random hentai image from gelbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) - - - `{0}gelbooru yuri+kissing` - - - rule34 - - - Shows a random image from rule34.xx with a given tag. Tag is optional but preferred. (multiple tags are appended with +) - - - `{0}rule34 yuri+kissing` - - - e621 - - - Shows a random hentai image from e621.net with a given tag. Tag is optional but preferred. Use spaces for multiple tags. - - - `{0}e621 yuri kissing` - - - cp - - - We all know where this will lead you to. - - - `{0}cp` - - - boobs - - - Real adult content. - - - `{0}boobs` - - - butts ass butt - - - Real adult content. - - - `{0}butts` or `{0}ass` - - - createwar cw - - - Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. - - - `{0}cw 15 The Enemy Clan` - - - startwar sw - - - Starts a war with a given number. - - - `{0}sw 15` - - - listwar lw - - - Shows the active war claims by a number. Shows all wars in a short way if no number is specified. - - - `{0}lw [war_number] or {0}lw` - - - claim call c - - - Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. - - - `{0}call [war_number] [base_number] [optional_other_name]` - - - claimfinish cf - - - Finish your claim with 3 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. - - - `{0}cf 1` or `{0}cf 1 5` - - - claimfinish2 cf2 - - - Finish your claim with 2 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. - - - `{0}cf2 1` or `{0}cf2 1 5` - - - claimfinish1 cf1 - - - Finish your claim with 1 star if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. - - - `{0}cf1 1` or `{0}cf1 1 5` - - - unclaim ucall uc - - - Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim - - - `{0}uc [war_number] [optional_other_name]` - - - endwar ew - - - Ends the war with a given index. - - - `{0}ew [war_number]` - - - translate trans - - - Translates from>to text. From the given language to the destination language. - - - `{0}trans en>fr Hello` - - - translangs - - - Lists the valid languages for translation. - - - `{0}translangs` - - - Sends a readme and a guide links to the channel. - - - `{0}readme` or `{0}guide` - - - readme guide - - - Shows all available operations in {0}calc command - - - `{0}calcops` - - - calcops - - - Deletes all quotes on a specified keyword. - - - `{0}delallq kek` - - - delallq daq - - - greetdmmsg - - - `{0}greetdmmsg Welcome to the server, %user%`. - - - Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. - - - Check how much currency a person has. (Defaults to yourself) - - - `{0}$$` or `{0}$$ @SomeGuy` - - - cash $$ - - - Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions. - - - `{0}lp` or `{0}lp 3` - - - listperms lp - - - Enable or disable all modules for a specific user. - - - `{0}aum enable @someone` - - - allusrmdls aum - - - Moves permission from one position to another in Permissions list. - - - `{0}mp 2 4` - - - moveperm mp - - - Removes a permission from a given position in Permissions list. - - - `{0}rp 1` - - - removeperm rp - - - Migrate data from old bot configuration - - - `{0}migratedata` - - - migratedata - - - Checks if a user is online on a certain streaming platform. - - - `{0}cs twitch MyFavStreamer` - - - checkstream cs - - - showemojis se - - - Shows a name and a link to every SPECIAL emoji in the message. - - - `{0}se A message full of SPECIAL emojis` - - - shuffle sh - - - Reshuffles all cards back into the deck. - - - `{0}sh` - - - fwmsgs - - - Toggles forwarding of non-command messages sent to bot's DM to the bot owners - - - `{0}fwmsgs` - - - fwtoall - - - Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json - - - `{0}fwtoall` - - - resetperms - - - Resets BOT's permissions module on this server to the default value. - - - `{0}resetperms` - - - antiraid - - - Sets an anti-raid protection on the server. First argument is number of people which will trigger the protection. Second one is a time interval in which that number of people needs to join in order to trigger the protection, and third argument is punishment for those people (Kick, Ban, Mute) - - - `{0}antiraid 5 20 Kick` - - - antispam - - - Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10. - - - `{0}antispam 3 Mute` or `{0}antispam 4 Kick` or `{0}antispam 6 Ban` - - - chatmute - - - Prevents a mentioned user from chatting in text channels. - - - `{0}chatmute @Someone` - - - voicemute - - - Prevents a mentioned user from speaking in voice channels. - - - `{0}voicemute @Someone` - - - konachan - - - Shows a random hentai image from konachan with a given tag. Tag is optional but preferred. - - - `{0}konachan yuri` - - - setmuterole - - - Sets a name of the role which will be assigned to people who should be muted. Default is nadeko-mute. - - - `{0}setmuterole Silenced` - - - adsarm - - - Toggles the automatic deletion of confirmations for {0}iam and {0}iamn commands. - - - `{0}adsarm` - - - setstream - - - Sets the bots stream. First argument is the twitch link, second argument is stream name. - - - `{0}setstream TWITCHLINK Hello` - - - chatunmute - - - Removes a mute role previously set on a mentioned user with `{0}chatmute` which prevented him from chatting in text channels. - - - `{0}chatunmute @Someone` - - - unmute - - - Unmutes a mentioned user previously muted with `{0}mute` command. - - - `{0}unmute @Someone` - - - xkcd - - - Shows a XKCD comic. No arguments will retrieve random one. Number argument will retrieve a specific comic, and "latest" will get the latest one. - - - `{0}xkcd` or `{0}xkcd 1400` or `{0}xkcd latest` - - - placelist - - - Shows the list of available tags for the `{0}place` command. - - - `{0}placelist` - - - place - - - Shows a placeholder image of a given tag. Use `{0}placelist` to see all available tags. You can specify the width and height of the image as the last two optional arguments. - - - `{0}place Cage` or `{0}place steven 500 400` - - - togethertube totube - - - Creates a new room on <https://togethertube.com> and shows the link in the chat. - - - `{0}totube` - - - publicpoll ppoll - - - Creates a public poll which requires users to type a number of the voting option in the channel command is ran in. - - - `{0}ppoll Question?;Answer1;Answ 2;A_3` - - - autotranslang atl - - - Sets your source and target language to be used with `{0}at`. Specify no arguments to remove previously set value. - - - `{0}atl en>fr` - - - autotrans at - - - Starts automatic translation of all messages by users who set their `{0}atl` in this channel. You can set "del" argument to automatically delete all translated user messages. - - - `{0}at` or `{0}at del` - - - listquotes liqu - - - `{0}liqu` or `{0}liqu 3` - - - Lists all quotes on the server ordered alphabetically. 15 Per page. - - - typedel - - - Deletes a typing article given the ID. - - - `{0}typedel 3` - - - typelist - - - Lists added typing articles with their IDs. 15 per page. - - - `{0}typelist` or `{0}typelist 3` - - - listservers - - - Lists servers the bot is on with some basic info. 15 per page. - - - `{0}listservers 3` - - - hentaibomb - - - Shows a total 5 images (from gelbooru, danbooru, konachan, yandere and atfbooru). Tag is optional but preferred. - - - `{0}hentaibomb yuri` - - - cleverbot - - - Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. - - - `{0}cleverbot` - - - shorten - - - Attempts to shorten an URL, if it fails, returns the input URL. - - - `{0}shorten https://google.com` - - - minecraftping mcping - - - Pings a minecraft server. - - - `{0}mcping 127.0.0.1:25565` - - - minecraftquery mcq - - - Finds information about a minecraft server. - - - `{0}mcq server:ip` - - - wikia - - - Gives you back a wikia link - - - `{0}wikia mtg Vigilance` or `{0}wikia mlp Dashy` - - - yandere - - - Shows a random image from yandere with a given tag. Tag is optional but preferred. (multiple tags are appended with +) - - - `{0}yandere tag1+tag2` - - - magicthegathering mtg - - - Searches for a Magic The Gathering card. - - - `{0}magicthegathering about face` or `{0}mtg about face` - - - yodify yoda - - - Translates your normal sentences into Yoda styled sentences! - - - `{0}yoda my feelings hurt` - - - attack - - - Attacks a target with the given move. Use `{0}movelist` to see a list of moves your type can use. - - - `{0}attack "vine whip" @someguy` - - - heal - - - Heals someone. Revives those who fainted. Costs a NadekoFlower - - - `{0}heal @someone` - - - movelist ml - - - Lists the moves you are able to use - - - `{0}ml` - - - settype - - - Set your poketype. Costs a NadekoFlower. Provide no arguments to see a list of available types. - - - `{0}settype fire` or `{0}settype` - - - type - - - Get the poketype of the target. - - - `{0}type @someone` - - - hangmanlist - - - Shows a list of hangman term types. - - - `{0} hangmanlist` - - - hangman - - - Starts a game of hangman in the channel. Use `{0}hangmanlist` to see a list of available term types. Defaults to 'all'. - - - `{0}hangman` or `{0}hangman movies` - - - crstatsclear - - - Resets the counters on `{0}crstats`. You can specify a trigger to clear stats only for that trigger. - - - `{0}crstatsclear` or `{0}crstatsclear rng` - - - crstats - - - Shows a list of custom reactions and the number of times they have been executed. Paginated with 10 per page. Use `{0}crstatsclear` to reset the counters. - - - `{0}crstats` or `{0}crstats 3` - - - overwatch ow - - - Show's basic stats on a player (competitive rank, playtime, level etc) Region codes are: `eu` `us` `cn` `kr` - - - `{0}ow us Battletag#1337` or `{0}overwatch eu Battletag#2016` - - - acrophobia acro - - - Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60) - - - `{0}acro` or `{0}acro 30` - - - logevents - - - Shows a list of all events you can subscribe to with `{0}log` - - - `{0}logevents` - - - log - - - Toggles logging event. Disables it if it's active anywhere on the server. Enables if it's not active. Use `{0}logevents` to see a list of all events you can subscribe to. - - - `{0}log userpresence` or `{0}log userbanned` - - - fairplay fp - - - Toggles fairplay. While enabled, music player will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue. - - - `{0}fp` - - - define def - - - Finds a definition of a word. - - - `{0}def heresy` - - - setmaxplaytime smp - - - Sets a maximum number of seconds (>14) a song can run before being skipped automatically. Set 0 to have no limit. - - - `{0}smp 0` or `{0}smp 270` - - - activity - - - Checks for spammers. - - - `{0}activity` - - - 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. - - - `{0}autohentai 30 yuri|tail|long_hair` or `{0}autohentai` - - - setstatus - - - Sets the bot's status. (Online/Idle/Dnd/Invisible) - - - `{0}setstatus Idle` - - - rotaterolecolor rrc - - - Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. - - - `{0}rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `{0}rrc 0 MyLsdRole` - - - createinvite crinv - - - Creates a new invite which has infinite max uses and never expires. - - - `{0}crinv` - - - pollstats - - - Shows the poll results without stopping the poll on this server. - - - `{0}pollstats` - - - repeatlist replst - - - Shows currently repeating messages and their indexes. - - - `{0}repeatlist` - - - repeatremove reprm - - - Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes. - - - `{0}reprm 2` - - - antilist antilst - - - Shows currently enabled protection features. - - - `{0}antilist` - - - antispamignore - - - Toggles whether antispam ignores current channel. Antispam must be enabled. - - - `{0}antispamignore` - - - cmdcosts - - - Shows a list of command costs. Paginated with 9 command per page. - - - `{0}cmdcosts` or `{0}cmdcosts 2` - - - commandcost cmdcost - - - Sets a price for a command. Running that command will take currency from users. Set 0 to remove the price. - - - `{0}cmdcost 0 !!q` or `{0}cmdcost 1 >8ball` - - - startevent - - - Starts one of the events seen on public nadeko. - - - `{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` - - - affinity - - - 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 @MyHusband` or `{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 9 waifus. - - - `{0}waifus` - - - 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. - - - `{0}divorce @CheatingSloot` - - - waifuinfo waifustats - - - Shows waifu stats for a target person. Defaults to you if no user is provided. - - - `{0}waifuinfo @MyCrush` or `{0}waifuinfo` - - - mal - - - Shows basic info from myanimelist profile. - - - `{0}mal straysocks` - - - setmusicchannel smch - - - Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in. - - - `{0}smch` - - - reloadimages - - - Reloads images bot is using. Safe to use even when bot is being used heavily. - - - `{0}reloadimages` - - - shardstats - - - Stats for shards. Paginated with 25 shards per page. - - - `{0}shardstats` or `{0}shardstats 2` - - - connectshard - - - Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. - - - `{0}connectshard 2` - - - shardid - - - Shows which shard is a certain guild on, by guildid. - - - `{0}shardid 117523346618318850` - - - tictactoe ttt - - - Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. 15 seconds per move. - - - >ttt - - - timezones - - - List of all timezones available on the system to be used with `{0}timezone`. - - - `{0}timezones` - - - timezone - - - Sets this guilds timezone. This affects bot's time output in this server (logs, etc..) - - - `{0}timezone` - - - langsetdefault langsetd - - - Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. - - - `{0}langsetd en-US` or `{0}langsetd default` - - - languageset langset - - - Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. - - - `{0}langset de-DE ` or `{0}langset default` - - - languageslist langli - - - List of languages for which translation (or part of it) exist atm. - - - `{0}langli` - - - rategirl - - - Use the universal hot-crazy wife zone matrix to determine the girl's worth. It is everything young men need to know about women. At any moment in time, any woman you have previously located on this chart can vanish from that location and appear anywhere else on the chart. - - - `{0}rategirl @SomeGurl` - \ No newline at end of file From 9a8c77a4b7ab38d2195e5b39dc12a3985b4e9612 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 01:51:05 +0100 Subject: [PATCH 376/746] Update ResponseStrings.pt-BR.resx (POEditor.com) --- .../Resources/ResponseStrings.pt-BR.resx | 280 +++++++++--------- 1 file changed, 140 insertions(+), 140 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx index 898269f2..30bb7b31 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Esta base já está aclamada ou destruída. @@ -1207,7 +1207,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. É um empate! ambos escolheram {0} - + {0} ganhou! {1} vence {2} @@ -1222,10 +1222,10 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Categoria - + Cleverbot desabilitado neste servidor - Cleverbot ativado neste servidor. + Cleverbot habilitado neste servidor. @@ -1241,7 +1241,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. - Falha ao carregar a questão + Falha ao carregar a questão. Jogo Iniciado @@ -1487,7 +1487,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Volume deve estar entre 0 e 100 - + Volume ajustado para {0}% @@ -1582,10 +1582,10 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Gen. (of module) - + Pagina {0} de permissões - + Atual cargo de permissões é {0} @@ -1594,29 +1594,29 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. - + Permissões removidas #{0} - {1} - + Desabilitado o uso de {0} {1} para o cargo {2}. - + Habilitado o uso de {0} {1} para o cargo {2}. Short of seconds. - + Desabilitado o uso de {0} {1} nesse servidor. - + Habilitado o uso de {0} {1} nesse servidor. - + Não editavel @@ -1625,22 +1625,22 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. - + Não vou mas mostrar avisos de permissões. - + Vou passar a mostrar avisos de permissões. - + Filtragem de palavras desabilitada nesse canal. - + Filtragem de palavras habilitada nesse canal. - + Filtragem de palavras desabilitada nesse servidor. - + Filtragem de palavras habilitada nesse servidor. Habilidades @@ -1679,16 +1679,16 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. - + Derrotas Competitivas - + Partidas Competitivas jogadas - + Rank Competitivo - + Vitorias Competitivas Completado From 79681b4958b755c2f42a56a1a42a8918982187a3 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 01:51:07 +0100 Subject: [PATCH 377/746] Update ResponseStrings.sr-cyrl-rs.resx (POEditor.com) --- .../Resources/ResponseStrings.sr-cyrl-rs.resx | 1705 ++++++++++++++--- 1 file changed, 1424 insertions(+), 281 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx index 8d58263b..ea90f4b6 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx @@ -1,189 +1,122 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - {0} је већ онесвешћен. - - - {0} је већ потпуно здрав. - - - Твој тип већ јесте {0} - - - је искористио {0}{1} на {2}{3} и нанео {4} штете. - Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. - - - Не можеш напасти пре узвратног ударца. - - - Не можеш напасти себе. - - - {0} се онесвестио. - - - је излечио {0} са једним {1} - - - {0} има {1} преосталог здравља. - - - Не можеш искористити {0}. Укуцај `{1}ml` да би видео листу удараца које можеш користити. - - - Листа покрета за {0} тип - - - Није ефективно. - - - Немаш довољно {0} - - - је оживео {0} са једним {1} - - - Оживео си себе са једним {0} - - - Твој тип је промењен на {0} за један {1} - - - Има неког ефекта! - - - Супер ефективно! - - - Користио си превише напада узастопно, не можеш да се крећеш! - - - {0}-ов тип је {1} - - - Корисник није нађен. - - - Онесвешћен си, не можеш да се крећеш. - Та база је већ под захетвом или је уништена. @@ -193,6 +126,9 @@ Та база није под захтевом. + + **DESTROYED** base #{0} in a war against {1} + {0} је **ПОНИШТИО ЗАХТЕВ** за базу #{1} у рату против {2} @@ -289,82 +225,79 @@ Окидач - - Назад на Садржај - - - Само Власник Бота - - - Захтева {0} дозволу на каналу. - - - Можете подржати пројекат на Пејтриону: <{0}> или Пејпалу: <{1}> - - - Команде и псеудоними - - - Листа команди је обновљена. - - - Укуцај `{0}h ИмеКоманде` да видиш помоћ за ту команду. нпр. `{0}h >8ball` - - - Не могу да нађем ту команду. Проверите да ли команда постоји, па покушајте поново. - - - Опис - - - Можете подржати НадекоБот пројекат на -Пејтриону <{0}> или -Пејпалу <{1}> -Не заборавите да оставите своје корисничко име или ИД. - -**Хвала** ♥️ - - - **List of Commands**: <{0}> -**Hosting Guides and docs can be found here**: <{1}> - - - Листа Команди - - - Листа Модула - - - Укуцај `{0}cmds ИмеМодула` да видиш листу свих команди у том модулу. нпр `{0}cmds games` - - - Тај модул не постоји. - - - Захтева {0} дозволу на серверу. - - - Садржај - - - Упутство - - - Аутохентаи започет. Постоваћу сваких {0} сек. користећи један од следећих тагова: -{1} - АутоХентаи заустављен. - - Таг - - - **DESTROYED** base #{0} in a war against {1} - No results found. + + {0} је већ онесвешћен. + + + {0} је већ потпуно здрав. + + + Твој тип већ јесте {0} + + + је искористио {0}{1} на {2}{3} и нанео {4} штете. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + Не можеш напасти пре узвратног ударца. + + + Не можеш напасти себе. + + + {0} се онесвестио. + + + је излечио {0} са једним {1} + + + {0} има {1} преосталог здравља. + + + Не можеш искористити {0}. Укуцај `{1}ml` да би видео листу удараца које можеш користити. + + + Листа покрета за {0} тип + + + Није ефективно. + + + Немаш довољно {0} + + + је оживео {0} са једним {1} + + + Оживео си себе са једним {0} + + + Твој тип је промењен на {0} за један {1} + + + Има неког ефекта! + + + Супер ефективно! + + + Користио си превише напада узастопно, не можеш да се крећеш! + + + {0}-ов тип је {1} + + + Корисник није нађен. + + + Онесвешћен си, не можеш да се крећеш. + **Auto assign role** on user join is now **disabled**. @@ -515,7 +448,7 @@ Reason: {1} Greet announcements enabled on this channel. - You can't use this command on users with a role higher or equal to yours in the role hierarchy. + You can't use this command on users with a role higher or equal to yours in the role hierarchy. Images loaded after {0} seconds! @@ -541,19 +474,21 @@ Reason: {1} {0} - Your server's locale is now {0} - {1} + Your server's locale is now {0} - {1} - Bot's default locale is now {0} - {1} + Bot's default locale is now {0} - {1} - Bot's language is set to {0} - {0} + Bot's language is set to {0} - {0} + Fuzzy - Failed setting locale. Revisit this command's help. + Failed setting locale. Revisit this command's help. - This server's language is set to {0} - {0} + This server's language is set to {0} - {0} + Fuzzy {0} has left {1} @@ -606,10 +541,10 @@ Reason: {1} Muted - singular "User muted." + singular "User muted." - I don't have the permission necessary for that most likely. + I don't have the permission necessary for that most likely. New mute role set. @@ -630,7 +565,7 @@ Reason: {1} Nickname Changed - Can't find that server + Can't find that server No shard with that ID found. @@ -645,7 +580,7 @@ Reason: {1} Old Topic - Error. Most likely I don't have sufficient permissions. + Error. Most likely I don't have sufficient permissions. Permissions for this server are reset. @@ -705,7 +640,7 @@ Reason: {1} Failed to rename role. I have insufficient permissions. - You can't edit roles higher than your highest role. + You can't edit roles higher than your highest role. Removed the playing message: {0} @@ -751,13 +686,13 @@ Reason: {1} That role is not self-assignable. - You don't have {0} role. + You don't have {0} role. Self assigned roles are now not exclusive! - I am unable to add that role to you. `I can't add roles to owners or other roles higher than my role in the role hierarchy.` + I am unable to add that role to you. `I can't add roles to owners or other roles higher than my role in the role hierarchy.` {0} has been removed from the list of self-assignable roles. @@ -799,7 +734,7 @@ Reason: {1} Shutting down - Users can't send more than {0} messages every {1} seconds. + Users can't send more than {0} messages every {1} seconds. Slow mode disabled. @@ -862,10 +797,10 @@ Reason: {1} {0} has been **muted** from text and voice chat. - User's Role Added + User's Role Added - User's Role Removed + User's Role Removed {0} is now {1} @@ -901,7 +836,7 @@ Reason: {1} Enabled voice + text feature. - I don't have **manage roles** and/or **manage channels** permission, so I cannot run `voice+text` on {0} server. + I don't have **manage roles** and/or **manage channels** permission, so I cannot run `voice+text` on {0} server. You are enabling/disabling this feature and **I do not have ADMINISTRATOR permissions**. This may cause some issues, and you will have to clean up text channels yourself afterwards. @@ -929,7 +864,7 @@ Reason: {1} Migration done! - Error while migrating, check bot's console for more information. + Error while migrating, check bot's console for more information. Presence Updates @@ -940,9 +875,6 @@ Reason: {1} has awarded {0} to {1} - - Betflip Gamble - Better luck next time ^_^ @@ -989,13 +921,13 @@ Reason: {1} Awarded {0} to {1} users from {2} role. - You can't bet more than {0} + You can't bet more than {0} - You can't bet less than {0} + You can't bet less than {0} - You don't have enough {0} + You don't have enough {0} No more cards in the deck. @@ -1026,7 +958,7 @@ Reason: {1} Users must type a secret code to get {0}. -Lasts {1} seconds. Don't tell anyone. Shhh. +Lasts {1} seconds. Don't tell anyone. Shhh. SneakyGame event ended. {0} users received the reward. @@ -1041,6 +973,1217 @@ Lasts {1} seconds. Don't tell anyone. Shhh. successfully took {0} from {1} - was unable to take {0} from{1} because the user doesn't have that much {2}! + was unable to take {0} from{1} because the user doesn't have that much {2}! + + Назад на Садржај + + + Само Власник Бота + + + Захтева {0} дозволу на каналу. + + + Можете подржати пројекат на Пејтриону: <{0}> или Пејпалу: <{1}> + + + Команде и псеудоними + + + Листа команди је обновљена. + + + Укуцај `{0}h ИмеКоманде` да видиш помоћ за ту команду. нпр. `{0}h >8ball` + + + Не могу да нађем ту команду. Проверите да ли команда постоји, па покушајте поново. + + + Опис + + + Можете подржати НадекоБот пројекат на +Пејтриону <{0}> или +Пејпалу <{1}> +Не заборавите да оставите своје корисничко име или ИД. + +**Хвала** ♥️ + + + **List of Commands**: <{0}> +**Hosting Guides and docs can be found here**: <{1}> + + + Листа Команди + + + Листа Модула + + + Укуцај `{0}cmds ИмеМодула` да видиш листу свих команди у том модулу. нпр `{0}cmds games` + + + Тај модул не постоји. + + + Захтева {0} дозволу на серверу. + + + Садржај + + + Упутство + + + Аутохентаи започет. Постоваћу сваких {0} сек. користећи један од следећих тагова: +{1} + + + Таг + + + Трка Животиња + + + Започињање трке није успело јер нема довољно учесника. + + + Трка је пуна! Почиње одмах. + + + {0} се прикључио као {1} + + + {0} се прикључио као {1} и уложио {2}! + + + Укуцај {0}jr да би се прикључио трци. + + + Почиње за 20 секунди или када је соба пуна. + + + Почиње са {0} учесника. + + + {0} као {1} је победио! + + + {0} као {1} је победио трку и освојио {2}! + + + Неисправан број. Можете бацити {0}-{1} коцкица у исто време. + Fuzzy + + + је добио {0} + Someone rolled 35 + + + Коцкица бачена: {0} + Dice Rolled: 5 + + + Неуспешно започињање партије. Друга трка је вероватно у току. + + + Не постоји трка на овом серверу. + + + Други број мора бити већи од првог. + + + Промена Осећања + + + Присвојена од стране + + + Развода + + + Свиђа јој се + + + Цена + + + Ниједна waifu још није присвојена. + + + Најбоље Waifu + + + твој афинитет је већ постављен на ту waifu или покушаваш да обришеш афинитет који не постоји. + + + + Make sure to get the formatting right, and leave the thinking emoji + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + plural + + + + + + + + + + + + + + + + + + + + + + + + Ранг листа + + + + Немаш довољно {0} + + + + + + + Kwoth picked 5* + + + + Kwoth planted 5* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + context: "removed song #5" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gen (of command) + + + + Gen. (of module) + + + + + + + + + + + + + + + + + + + + + + + + + Short of seconds. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Don't translate {0}place + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /s and total need to be localized to fit the context - +`1.` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Емотикони по Мери + + + Грешка + + + Додатак + + + ИД + + + Индекс је ван опсега. + + + Ево је листа корисника у тим ролама: + + + није ти дозвољено да користиш ову команду на ролама са пуно корисника да би се спречила злоупотреба. + + + Нетачна вредност {0}. + Invalid months value/ Invalid hours value + + + Регистровао се + + + Ушао на сервер + + + ИД: {0} +Чланова; {1} +Ид Власника; {2} + + + Нема сервера на овој страници. + + + Листа Понављача + + + Чланова + + + Меморија + + + Поруке + + + Понављач Порука + + + Име + + + Надимак + + + Нико не игра ту игру. + + + Нема активних понављача. + + + Нема рола на овој страни. + + + Нема шардова на овој страни. + + + Нема теме. + + + Бласник + + + ИДеви Власника + + + Присуство + + + {0} Сервера +{1} Текстуалних Канала +{2} Говорних Канала + + + Обрисани су сви цитати са кључном речи {0}. + + + Страна {0} цитата. + + + Нема цитата на овој страни. + + + Није нађен цитат који можеш да обришеш. + + + Цитат додат + + + Обрисана насумишна + + + Регион + + + Регистрован + + + + + + Није исправан формат времена. Проверите листу команди. + + + Нови темплејт за подсетник је постаљен. + + + + + + Листа понављача + + + Нема понављача на овом серверу. + + + + + + Нису пронађене понављајуће поруке на овом серверу. + + + Резултат + + + Роле + + + + + + + + + + + + + + + + + + + + + Инфо Сервера + + + Шард + + + Статови Шардова + + + + + + + + + Нема специјалних емотикона. + + + + + + Текст Канали + + + Ево га твој линк ка соби: + + + Време Рада + + + + Id of the user kwoth#1234 is 123123123123 + + + Корисници + + + Говорни канал + + \ No newline at end of file From 139bd79778bfa478e5e2d91a75766195acbd079f Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 10:36:27 +0100 Subject: [PATCH 378/746] Update CommandStrings.nl-NL.resx (POEditor.com) From 972726e6afd55d90e56c872ce283c10c8e113c36 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 10:36:32 +0100 Subject: [PATCH 379/746] Update ResponseStrings.fr-fr.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.fr-fr.resx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx index 3708ba7a..72a2957f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx +++ b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx @@ -1410,7 +1410,7 @@ La nouvelle valeur de {0} est {1} ! Lecture en cours: - #{0}` - **{1}** par *{2}* ({3} morceaux) + `#{0}` - **{1}** par *{2}* ({3} morceaux) Page {0} des listes de lecture sauvegardées @@ -1525,7 +1525,7 @@ La nouvelle valeur de {0} est {1} ! Activation de l'usage de TOUS LES MODULES pour l'utilisateur {0}. - Banni {0} avec l'ID {1} + {0} sur liste noire avec l'ID {1} Il ne s'agit pas d'un ban mais d'une blacklist interdisant l'utilisateur d'utiliser le bot. @@ -1767,7 +1767,7 @@ La nouvelle valeur de {0} est {1} ! Niveau - Liste de {0} tags placés. + Liste de tags pour {0}place. Don't translate {0}place @@ -1810,7 +1810,7 @@ La nouvelle valeur de {0} est {1} ! Utilisateur non trouvé! Veuillez vérifier la région ainsi que le BattleTag avant de réessayer. - Prévision de lecture + Prévus de regarder Je ne pense pas que le sens de la traduction soit le bon. @@ -1946,7 +1946,7 @@ La nouvelle valeur de {0} est {1} ! `1.` - Page d'Activité #{0} + Page d'activité #{0} {0} utilisateurs en total. From f025ee646161a55da82ba7376c3c5ea7c2168701 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 10:36:35 +0100 Subject: [PATCH 380/746] Update ResponseStrings.de-DE.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.de-DE.resx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx index eb4c7511..8d8866c5 100644 --- a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx @@ -1956,7 +1956,10 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Thema des Kanals - Befehl ausgeführt + Befehle ausgeführt + Commands ran +9 +^used like that in .stats {0} {1} ist gleich zu {2} {3} From 98a0f97bbe33e43120a7c36f6cbac49e91196e9f Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 10:36:37 +0100 Subject: [PATCH 381/746] Update CommandStrings.ja-JP.resx (POEditor.com) --- .../Resources/CommandStrings.ja-JP.resx | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.ja-JP.resx b/src/NadekoBot/Resources/CommandStrings.ja-JP.resx index 17febe51..76de6cb2 100644 --- a/src/NadekoBot/Resources/CommandStrings.ja-JP.resx +++ b/src/NadekoBot/Resources/CommandStrings.ja-JP.resx @@ -118,16 +118,19 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + その基盤はすでに主張されている。または破壊されました。 + - + ベースが破壊されました + - + その基地は主張されていない。 + - + {1}との戦争中の整数{0}を破壊しました @@ -169,7 +172,7 @@ - + サイズ @@ -211,7 +214,7 @@ - + 反応 @@ -223,7 +226,7 @@ - + トリガー @@ -305,7 +308,7 @@ - + 接続 @@ -314,11 +317,11 @@ - + BANNED PLURAL - + ユーザーはBANNED @@ -351,7 +354,7 @@ - + 古称 @@ -360,7 +363,7 @@ - + コンテント @@ -390,7 +393,7 @@ - + タイレクトメッセージガ @@ -531,11 +534,12 @@ - - PLURAL (users have been muted) + ミュート + PLURAL (users have been muted) +Fuzzy - + ミュート singular "User muted." From 71f542081907fcefd3a904d6de61fa0a95414c29 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 10:36:40 +0100 Subject: [PATCH 382/746] Update ResponseStrings.pt-BR.resx (POEditor.com) --- .../Resources/ResponseStrings.pt-BR.resx | 405 +++++++++--------- 1 file changed, 205 insertions(+), 200 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx index 30bb7b31..634142d7 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx @@ -118,13 +118,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Esta base já está aclamada ou destruída. + Esta base já foi reivindicada ou destruída. Esta base já está destruída. - Esta base não está aclamada. + Esta base não foi reivindicada. @@ -133,10 +133,10 @@ - + {0} clamou a base #{1} durante a guerra contra {2} - @{0} Você já clamou esta base #{1}. Você não pode clamar uma nova. + @{0} Você já reivindicou esta base #{1}. Você não pode reivindicar uma nova. @@ -158,7 +158,7 @@ Lista de guerras ativas - não clamado + não reivindicado Você não está participando nesta guerra. @@ -188,13 +188,13 @@ Guerra contra {0} começou! - Todos os status de reações personalizadas limpados. + Todos os status de reações personalizadas limpos. Reação personalizada deletada - Permissão Insuficiente. Necessita o domínio do bot para reações personalizadas globais, e administrador para reações personalizadas em server. + Permissão Insuficiente. Precisa ser dono do bot para reações personalizadas globais, e permissão de administrador para reações personalizadas no servidor. Lista de todas as reações personalizadas @@ -215,13 +215,13 @@ Resposta - Status de reações customizáveis + Status de reações personalizadas Status limpado para {0} reação customizável. - Nenhum status para aquele comando achado, nenhuma ação foi tomada. + Nenhum status para aquele comando encontrado, nenhuma ação foi tomada. Comando @@ -258,7 +258,7 @@ curou {0} com uma {1} - {0} Tem {1} HP restante. + {0} tem {1} HP restante. Você não pode usar {0}. Digite `{1}ml` para ver uma lista de ataques que você pode usar. @@ -291,7 +291,7 @@ Você usou muitos ataques de uma vez, então você não pode se mexer! - Tipo de {0} é {1} + O tipo de {0} é {1} Usuário não encontrado. @@ -300,20 +300,20 @@ Você desmaiou, então você não pode se mexer! - **Cargo Automático** para novos usuários **desabilitado**. + **Atribuir cargo automaticamente** a novos usuários **desabilitado**. - **Cargo Automático** para novos usuários **habilitado** + **Atribuir cargo automaticamente** a novos usuários **habilitado**. Anexos - Avatar mudado + Avatar alterado Você foi BANIDO do servidor {0}. -Razão: {1} +Motivo: {1} Banidos @@ -323,16 +323,16 @@ Razão: {1} Usuário Banido - Nome do bot mudado para {0}. + Nome do bot alterado para {0}. - Status do bot mudado para {0}. + Status do bot alterado para {0}. Deleção automática de mensagens de despedida foi desativado. - Mensagens de despedida serão deletas após {0} segundos. + Mensagens de despedida serão deletadas após {0} segundos. Mensagem de despedida atual: {0} @@ -341,7 +341,7 @@ Razão: {1} Ative mensagens de despedidas digitando {0} - Nova mensagem de despedida colocada. + Nova mensagem de despedida definida. Mensagens de despedidas desativadas. @@ -350,13 +350,13 @@ Razão: {1} Mensagens de despedidas foram ativadas neste canal. - Nome do canal mudado + Nome do canal alterado Nome antigo - Tópico do canal mudado + Tópico do canal alterado Limpo. @@ -517,7 +517,7 @@ Razão: {1} - + {0} invocou uma menção nos seguintes cargos Mensagem de {0} `[Bot Owner]` @@ -603,7 +603,7 @@ Razão: {1} - + Se {0} ou mais usuários entrarem em menos de {1} segundos, {2}. O tempo deve ser entre {0} e {1} segundos. @@ -643,7 +643,7 @@ Razão: {1} Você não pode editar cargos superiores ao seu cargo mais elevado. - + Removida a mensagem "jogando": {0} O cargo {0} foi adicionado a lista. @@ -658,13 +658,14 @@ Razão: {1} Adicionado. - + Rotação de status "jogando" desativada. - + Rotação de status "jogando" ativada. - + Aqui está uma lista dos status rotacionados: +{0} @@ -688,7 +689,7 @@ Razão: {1} Você não possui o cargo {0}. - + Cargos auto-atribuíveis agora são exclusivos! Não sou capaz de adicionar esse cargo a você. `Não posso adicionar cargos a donos ou outros cargos maiores que o meu cargo na hierarquia dos cargos.` @@ -697,13 +698,13 @@ Razão: {1} {0} foi removido da lista de cargos auto-aplicáveis. - + Voce nao possui mas o cargo {0}. - + Voce agora possui o cargo {0}. - + Cargo {0} adicionado à {1} com sucesso. Falha ao adicionar o cargo. Não possuo permissões suficientes. @@ -829,19 +830,19 @@ __Canais Ignorados__: {2} Canal de voz destruído - + Atributo voz + texto desabilitado. - + Atributo voz + texto habilitado. - + Eu não possuo a permissão de **gerenciar cargos** e/ou **gerenciar canais**, então não posso executar `voz+texto` no servidor {0}. - + Você está habilitando/desabilitando este atributo e **Eu não tenho permissão de ADMINISTRADOR**. Isso pode causar alguns problemas e você terá que limpar os canais de texto você mesmo depois. - + Eu preciso pelo menos das permissões de **gerenciar cargos** e **gerenciar canais** para habilitar este atributo. (Preferencialmente, permissão de Administrador) Usuário {0} do chat de texto @@ -850,10 +851,11 @@ __Canais Ignorados__: {2} Usuário {0} dos chats de voz e texto - + Usuário {0} do chat de voz - + Você foi banido temporariamente do servidor {0}. +Motivo: {1} Usuário desbanido @@ -862,16 +864,16 @@ __Canais Ignorados__: {2} Migração concluída! - + Erro enquanto migrava, verifique o console do bot para mais informações. - + Atualizações de Presença - + Usuário Banido Temporariamente - + concedeu {0} para {1} Mais sorte na próxima vez ^_^ @@ -883,7 +885,7 @@ __Canais Ignorados__: {2} Baralho re-embaralhado. - + girou {0}. User flipped tails. @@ -893,7 +895,7 @@ __Canais Ignorados__: {2} O número especificado é inválido. Você pode girar de 1 a {0} moedas. - + Adicione {0} reação Este evento está ativo por até {0} horas. @@ -934,7 +936,7 @@ __Canais Ignorados__: {2} Usuario sorteado - + Você rolou {0} Aposta @@ -955,7 +957,8 @@ __Canais Ignorados__: {2} Ganhou - + Usuários devem digitar um código secreto pra ganhar {0}. +Dura {1} segundos. Não diga a ninguém. Shhh. @@ -1183,19 +1186,19 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. - + Você tem {0} segundos para fazer uma submissão. - + {0} submeteram suas frases. ({1} total) - + Vote digitando um número da submissão - + {0} lançam seus votos! - + Vence {0} com {1} pontos. @@ -1234,11 +1237,11 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. - + {0} {1} aleatórios aparecem! Capture-os digitando `{2}pick` plural - + Um {0} aleatório apareceu! Capture-o digitando `{1}pick` Falha ao carregar a questão. @@ -1247,16 +1250,16 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Jogo Iniciado - + Jogo da Forca iniciado - + Já existe um Jogo da Forca em andamento neste canal. - + Erro ao iniciar o Jogo da Forca. - + Lista dos tipos de termo do "{0}hangman" Placar de Lideres @@ -1282,7 +1285,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Trivia - + {0} acertou! A resposta era: {1} Nenhuma trivia está em andamento neste servidor. @@ -1330,7 +1333,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. {0} vs {1} - + Tentando adicionar {0} músicas à fila... Autoplay desabilitado. @@ -1360,10 +1363,10 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. - + Id - + Entrada inválida. @@ -1372,13 +1375,13 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. - + Tamanho máximo da fila de música definido para ilimitado. - + Tamanho máximo da fila de música definido para {0} faixa(s). - Você precisa estar em um canal de voz nesse servidor + Você precisa estar em um canal de voz nesse servidor. Nome @@ -1402,7 +1405,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Tocando Musica - + `#{0}` - **{1}** by *{2}* ({3} músicas) Página {0} de Playlists Salvas @@ -1414,7 +1417,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Falha ao deletar essa playlist. Ela não existe ou você não é seu o criador. - + Não existe uma playlist com esse ID. @@ -1451,7 +1454,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Repetindo Faixa - + A repetição da faixa atual parou. @@ -1463,25 +1466,25 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Repetição de playlist habilitada. - + Eu irei mostrar as músicas em andamento, concluídas, pausadas e removidas neste canal. - + Pulando para `{0}:{1}` - Musicas embaralhadas. + Músicas embaralhadas. - Musica movida. + Música movida. - + {0}h {1}m {2}s - + para a posição - + ilimitada Volume deve estar entre 0 e 100 @@ -1490,67 +1493,67 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Volume ajustado para {0}% - + O uso de TODOS OS MÓDULOS foi desabilitado no canal {0}. - + O uso de TODOS OS MÓDULOS foi habilitado no canal {0}. - + Permitido - + O uso de TODOS OS MÓDULOS foi desabilitado para o cargo {0}. - + O uso de TODOS OS MÓDULOS foi habilitado para o cargo {0}. - + O uso de TODOS OS MÓDULOS foi desabilitado neste servidor. - + O uso de TODOS OS MÓDULOS foi habilitado neste servidor. - + O uso de TODOS OS MÓDULOS foi desabilitado para o usuário {0}. - + O uso de TODOS OS MÓDULOS foi habilitado para o usuário {0}. - + O comando {0} agora possui um cooldown de {1}s. - + O comando {0} não possui nenhum cooldown agora e todos os cooldowns existentes foram limpos. - + Nenhum cooldown de comando definido. - + Desabilitado o uso de {0} {1} no canal {2}. - + Desabilitado o uso de {0} {1} no canal {2}. Negado - + A palavra {0} foi adicionada a lista de palavras filtradas. - + Lista de Palavras Filtradas - + A palavra {0} foi removida da lista de palavras filtradas. - + Segundo parâmetro inválido. (Deve ser um número entre {0} e {1}) @@ -1565,24 +1568,24 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. - + Permissão {0} movida de #{1} para #{2} - + Nenhum custo definido. - Comando + comando Gen (of command) - + módulo Gen. (of module) - Pagina {0} de permissões + Página {0} de Permissões Atual cargo de permissões é {0} @@ -1603,7 +1606,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Habilitado o uso de {0} {1} para o cargo {2}. - + sec. Short of seconds. @@ -1616,7 +1619,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. - Não editavel + Não editável @@ -1625,7 +1628,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. - Não vou mas mostrar avisos de permissões. + Não vou mais mostrar avisos de permissões. Vou passar a mostrar avisos de permissões. @@ -1649,25 +1652,25 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Nenhum anime favorito ainda - + A tradução automática de mensagens nesse canal foi iniciada. As mensagens do usuário serão deletadas automaticamente. - + A linguagem de tradução automática foi removida. - + A linguagem de tradução automática foi definida de {from}>{to} - + A tradução automática de mensagens foi ativada neste canal. - + A tradução automática de mensagens neste canal parou. - + Entrada com má formatação ou algo deu errado. - + Não consegui encontrar essa carta. Fato @@ -1676,7 +1679,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Capítulos - + HQ # Derrotas Competitivas @@ -1688,7 +1691,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Rank Competitivo - Vitorias Competitivas + Vitórias Competitivas Completado @@ -1703,10 +1706,10 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Data - Defina + Defina: - + Dropado Episódios @@ -1727,80 +1730,80 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Gêneros - + Falha ao encontrar uma definição para essa tag. Altura/Peso - + {0}m/{1}kg - + Humidade - + Busca de Imagens para: Falha ao encontrar este filme. - + Linguagem ou fonte inválida. - + Piadas não carregadas. - + Nível - + lista de tags {0}place Don't translate {0}place Localização - + Itens mágicos não carregados. - + Perfil MAL de {0} - + O proprietário do bot não especificou a MashapeApiKey. Você não pode usar essa funcionalidade. Min/Max - Nenhum canal encontrado + Nenhum canal encontrado. - Nenhum resultado encontrado + Nenhum resultado encontrado. - + Em espera Url Original - + Requer uma API key de osu! - + Falha ao obter a assinatura osu! - + Cerca de {0} imagens encontradas. Mostrando aleatória {0}. Usuário não encontrado! Por favor cheque a região e a BattleTag antes de tentar de novo. - + Planeja assistir Plataforma @@ -1809,13 +1812,13 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Nenhuma habilidade encontrada. - Nenhum pokemon encontrado + Nenhum pokemon encontrado. Link do Perfil: - Qualidade + Qualidade: @@ -1824,25 +1827,25 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. - + Avaliação - Pontuação + Pontuação: - + Busca Por: - + Falha ao encurtar esse url. - Alguma coisa deu errado + Alguma coisa deu errado. - + Por favor, especifique os parâmetros de busca. Status @@ -1851,28 +1854,28 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. - Streamer {0} está offline + Streamer {0} está offline. - Streamer {0} está online com {1} espectadores + Streamer {0} está online com {1} espectadores. - + Você esta seguindo {0} streams nesse servidor. - Você não está seguindo nenhuma stream neste servidor + Você não está seguindo nenhuma stream neste servidor. - + Nenhuma stream. - + Stream provavelmente não existe. - + Stream de {0} ({1}) removida das notificações. - Eu notificarei este canal quando o status mudar + Eu notificarei este canal quando o status mudar. Nascer do Sol @@ -1884,7 +1887,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Temperatura - Título + Título: Top 3 animes favoritos: @@ -1896,37 +1899,37 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Tipos - + Falha ao encontrar a definição para esse termo. Url - + Espectadores Assistindo - + Falha ao tentar encontrar esse termo na wikia especificada. - + Por favor, insira a wikia alvo, seguida do que deve ser pesquisado. - Página não encontrada + Página não encontrada. Velocidade do Vento - + Os {0} campeões mais banidos - + Falha ao yodificar sua frase. - + Juntou-se @@ -1937,16 +1940,16 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. - + {0} usuários no total. Autor - + Bot ID - + Lista de funções no comando {0}calc @@ -1955,22 +1958,22 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Tópico do Canal - Comandos utilizados + Comandos utilizados - + {0} {1} é igual a {2} {3} - + Unidades que podem ser utilizadas pelo conversor - + Não foi possível converter {0} para {1}: unidades não encontradas - + Não foi possível converter {0} para {1}: as unidades não são do mesmo tipo - + Criado em @@ -1991,29 +1994,31 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. - + ID - + Índice fora de alcance. - Aqui está uma lista de usuários nestes cargos + Aqui está uma lista de usuários nestes cargos: - + você não tem permissão de usar esse comando em cargos com muitos usuários neles para prevenir abuso. - + Valor {0} inválido. Invalid months value/ Invalid hours value - + Juntou-se ao Discord - + Juntou-se ao Servidor - + ID: {0} +Membros: {1} +OwnerID: {2} Nenhum servidor encontrado nessa página. @@ -2031,7 +2036,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Mensagens - R + Repetidor de Mensagem Nome @@ -2043,22 +2048,22 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Ninguém está jogando esse jogo. - + Nenhum repetidor ativo. Nenhum cargo nesta página. - + Nenhum Shard nesta página. - + Nenhum tópico definido. Dono - Dono IDs + IDs do Dono Presença @@ -2069,52 +2074,52 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. {2} Canais de Voz - + Todas as citações com a palavra-chave {0} foram deletadas. - + Página {0} de citações - Nenhuma citação nesta página + Nenhuma citação nesta página. - Nenhuma citação que você possa remover foi encontrada + Nenhuma citação que você possa remover foi encontrada. Citação adicionada - + Uma citação aleatória foi removida. Região - + Registrado em - + Eu lembrarei {0} de {1} em {2} `({3:d.M.yyyy.} at {4:HH:mm})` - + Formato de data inválido. Verifique a lista de comandos. - + Novo modelo de lembrete definido. - + Repetindo {0} a cada {1} dia(s), {2} hora(s) e {3} minuto(s). - Lista de repetidores + Lista de Repetidores - Nenhum repetidor neste server. + Nenhum repetidor neste servidor. #{0} parou. - Nenhuma mensagens repetidas encontradas. + Nenhuma mensagem repetindo neste servidor. Resultado @@ -2123,19 +2128,19 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Cargos - + Página #{0} de todos os cargos neste servidor: - + Página #{0} de cargos para {1} - + Nenhuma cor no formato correto. Use `#00ff00`, por exemplo. - + Começando a rotacionar cores do cargo {0}. - + Parando de rotacionar cores do cargo {0} {0} deste servidor é {1} @@ -2144,13 +2149,13 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Informações do Servidor - Fragmento + Shard - Status de fragmento + Status do Shard - + Shard **#{0}** está no estado {1} com {2} servidores **Nome:** {0} **Link:** {1} @@ -2159,7 +2164,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Nenhum emoji especial encontrado. - Tocando {0} canções, {1} no queue. + Tocando {0} músicas, {1} na fila. Canais de Texto @@ -2168,10 +2173,10 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Aqui está o link do quarto: - + Tempo de Atividade - + {0} do usuário {1} é {2} Id of the user kwoth#1234 is 123123123123 From 130bdd767a4df965ba0f0f7af646ec2a1cdaabae Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 10:36:43 +0100 Subject: [PATCH 383/746] Update ResponseStrings.ru-RU.resx (POEditor.com) From ca4a798d5fcdf36f4ce63db1239d4c44cb7d585b Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 10:36:45 +0100 Subject: [PATCH 384/746] Update ResponseStrings.sr-cyrl-rs.resx (POEditor.com) From d17055f36430e1adab73a50983b26adb80cf1253 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 1 Mar 2017 12:36:28 +0100 Subject: [PATCH 385/746] Fixed .prune X --- src/NadekoBot/Modules/Administration/Administration.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 405485dd..f779a751 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -452,7 +452,6 @@ namespace NadekoBot.Modules.Administration { if (count < 1) return; - count += 1; await Context.Message.DeleteAsync().ConfigureAwait(false); int limit = (count < 100) ? count : 100; var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten().ConfigureAwait(false)); From ca98cc51edb1e8f208612b8b1cfca3aeb2224917 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 16:24:39 +0100 Subject: [PATCH 386/746] Update ResponseStrings.pt-BR.resx (POEditor.com) --- .../Resources/ResponseStrings.pt-BR.resx | 273 +++++++++--------- 1 file changed, 137 insertions(+), 136 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx index 634142d7..27351b00 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx @@ -127,26 +127,26 @@ Esta base não foi reivindicada. - + Base #{0} **DESTRUÍDA** na guerra contra {1} - + {0} **RENUNCIOU** a base #{1} na guerra contra {2} - {0} clamou a base #{1} durante a guerra contra {2} + {0} reivindicou a base #{1} durante a guerra contra {2} - @{0} Você já reivindicou esta base #{1}. Você não pode reivindicar uma nova. + @{0} Você já reivindicou a base #{1}. Você não pode reivindicar uma nova. - + O pedido de guerra de @{0} contra {1} expirou. Inimigo - Informações sobre a guerra contra {0} + Informações sobre a guerra contra {0} Número de base inválido. @@ -164,7 +164,7 @@ Você não está participando nesta guerra. - @{0} Você não está participando nessa guerra, ou aquela base já está destruída. + @{0} Você não está participando nessa guerra, ou essa base já está destruída. Nenhuma guerra ativa. @@ -185,7 +185,7 @@ Essa guerra não existe. - Guerra contra {0} começou! + Guerra contra {0} iniciada! Todos os status de reações personalizadas limpos. @@ -200,10 +200,10 @@ Lista de todas as reações personalizadas - Reações personalizadas + Reações Personalizadas - Nova reação personalizada + Nova Reação Personalizada Nenhuma reação personalizada encontrada. @@ -215,10 +215,10 @@ Resposta - Status de reações personalizadas + Status de Reação Personalizada - Status limpado para {0} reação customizável. + Status da reação customizável {0} limpo. Nenhum status para aquele comando encontrado, nenhuma ação foi tomada. @@ -270,7 +270,7 @@ Não é efetivo. - Você não tem {0} o suficiente + Você não tem {0} suficiente Reviveu {0} com uma {1} @@ -323,13 +323,13 @@ Motivo: {1} Usuário Banido - Nome do bot alterado para {0}. + Nome do bot alterado para {0} - Status do bot alterado para {0}. + Status do bot alterado para {0} - Deleção automática de mensagens de despedida foi desativado. + Remoção automática de mensagens de despedida foi desativada. Mensagens de despedida serão deletadas após {0} segundos. @@ -365,7 +365,7 @@ Motivo: {1} Conteúdo - Cargo {0} criado com sucesso. + Cargo {0} criado com sucesso Canal de texto {0} criado. @@ -383,7 +383,7 @@ Motivo: {1} Parou a eliminação automática de invocações de comandos bem sucedidos. - Agora automaticamente deletando invocações de comandos bem sucedidos + Agora automaticamente deletando invocações de comandos bem sucedidos. Canal de texto {0} deletado. @@ -395,7 +395,7 @@ Motivo: {1} Mensagem direta de - Novo doador adicionado com sucesso. Número total doado por este usuário: {0} 👑 + Novo doador adicionado com sucesso. Valor total doado por este usuário: {0} 👑 Obrigado às pessoas listadas abaixo por fazer este projeto acontecer! @@ -413,7 +413,7 @@ Motivo: {1} Vou parar de enviar mensagens diretas de agora em diante. - Eliminação automática de mensagens de boas vindas desabilitada. + Remoção automática de mensagens de boas vindas desabilitada. Mensagens de boas vindas serão deletadas após {0} segundos. @@ -428,10 +428,10 @@ Motivo: {1} Novas mensagen direta de boas vindas definida. - + Mensagens diretas de boas vindas desabilitadas. - + Mensagens diretas de boas vindas habilitadas. Mensagem de boas vindas atual: {0} @@ -443,10 +443,10 @@ Motivo: {1} Nova mensagem de boas vindas definida. - Anúncios de boas vindas desabilitados. + Mensagens de boas vindas desabilitadas. - Anúncios de boas vindas habilitados neste canal. + Mensagens de boas vindas habilitadas neste canal. Você não pode usar este comando em usuários com um cargo maior ou igual ao seu na hierarquia dos cargos. @@ -455,7 +455,7 @@ Motivo: {1} Imagens carregadas após {0} segundos! - + Formato de entrada inválido. Parâmetros inválidos. @@ -464,14 +464,14 @@ Motivo: {1} {0} juntou-se a {1} - Você foi banido do servidor {0}. + Você foi kickado do servidor {0}. Razão: {1} - Usuário Chutado + Usuário Kickado - Lista de linguagens + Lista de Linguagens {0} @@ -496,25 +496,25 @@ Razão: {1} Servidor {0} deixado. - + Logando o evento {0} neste canal. - + Logando todos os eventos neste canal. - + Log desativado. - + Eventos Log em que você pode se inscrever: - + O log vai ignorar {0} - + O log vai deixar de ignorar {0} - + Parando de logar o evento {0}. {0} invocou uma menção nos seguintes cargos @@ -564,7 +564,7 @@ Razão: {1} Apelido Alterado - Não posso achar esse servidor + Não posso encontrar esse servidor Nenhum shard com aquele ID foi encontrado. @@ -600,7 +600,7 @@ Razão: {1} Nenhuma proteção ativa. - + O limite de usuários deve ser entre {0} e {1}. Se {0} ou mais usuários entrarem em menos de {1} segundos, {2}. @@ -609,10 +609,10 @@ Razão: {1} O tempo deve ser entre {0} e {1} segundos. - Todos os cargos foram removidos do usuário {0} com sucesso. + Todos os cargos foram removidos do usuário {0} com sucesso - Falha ao remover cargos. Eu não possuo permissões suficientes + Falha ao remover cargos. Eu não possuo permissões suficientes. @@ -628,7 +628,7 @@ Razão: {1} Um erro ocorreu devido à cor inválida ou permissões insuficientes. - Cargo {0} removido do usuário {1} com sucesso. + Cargo {0} removido do usuário {1} com sucesso Falha ao remover o cargo. Não possuo permissões suficientes. @@ -668,22 +668,22 @@ Razão: {1} {0} - + Nenhum status de rotação "jogando" definido. Você já possui o cargo {0}. - + Você já possui o cargo auto-atribuível exclusivo {0}. Cargos auto-atribuíveis agora são exclusivos! - + Existem {0} cargos auto-atribuíveis - Esse cargo não é auto-atribuível + Esse cargo não é auto-atribuível. Você não possui o cargo {0}. @@ -695,16 +695,16 @@ Razão: {1} Não sou capaz de adicionar esse cargo a você. `Não posso adicionar cargos a donos ou outros cargos maiores que o meu cargo na hierarquia dos cargos.` - {0} foi removido da lista de cargos auto-aplicáveis. + {0} foi removido da lista de cargos auto-atribuíveis. - Voce nao possui mas o cargo {0}. + Você não possui mais o cargo {0}. - Voce agora possui o cargo {0}. + Você agora possui o cargo {0}. - Cargo {0} adicionado à {1} com sucesso. + Cargo {0} adicionado ao usuário {1} com sucesso. Falha ao adicionar o cargo. Não possuo permissões suficientes. @@ -734,7 +734,7 @@ Razão: {1} Desligando - Usuários não podem mandar mais de {0} mensagens a cada {1} segundos + Usuários não podem mandar mais de {0} mensagens a cada {1} segundos. Modo lento desativado. @@ -743,7 +743,7 @@ Razão: {1} Modo lento iniciado. - + Banidos temporariamente (kickados) PLURAL @@ -753,7 +753,7 @@ Razão: {1} {0} irá deixar de ignorar esse canal. - Se um usuário postar {0} mensagens iguais em seguida, eu irei {1} eles. + Se um usuário postar {0} mensagens iguais em seguida, {1}. __Canais Ignorados__: {2} @@ -763,7 +763,7 @@ __Canais Ignorados__: {2} Canal de Texto Destruído - + Desensurdecido com sucesso. Desmutado @@ -806,7 +806,7 @@ __Canais Ignorados__: {2} {0} agora está {1} - + {0} foi **desmutado** nos chats de voz e texto. {0} juntou-se ao canal de voz {1}. @@ -818,10 +818,10 @@ __Canais Ignorados__: {2} {0} moveu-se do canal de voz {1} para {2}. - {0} foi **mutado por voz** + {0} foi **mutado por voz**. - {0} foi **desmutado por voz** + {0} foi **desmutado por voz**. Canal de voz criado @@ -879,7 +879,7 @@ Motivo: {1} Mais sorte na próxima vez ^_^ - Parabéns! Você ganhou {0} por rolar acima {1} + Parabéns! Você ganhou {0} por rolar acima de {1} Baralho re-embaralhado. @@ -895,13 +895,13 @@ Motivo: {1} O número especificado é inválido. Você pode girar de 1 a {0} moedas. - Adicione {0} reação + Adicione {0} reação a esta mensagem para ganhar {1} Este evento está ativo por até {0} horas. - + Evento de Reação da Flor iniciado! deu {0} de presente para {1} @@ -918,7 +918,7 @@ Motivo: {1} Placar de Líderes - + Concedeu {0} a {1} usuários do cargo {2}. Você não pode apostar mais que {0} @@ -933,10 +933,10 @@ Motivo: {1} Sem cartas no baralho. - Usuario sorteado + Usuário sorteado - Você rolou {0} + Você rolou {0}. Aposta @@ -945,7 +945,7 @@ Motivo: {1} WOAAHHHHHH!!! Parabéns!!! x{0} - + Um único {0}, x{1} Wow! Que sorte! Três de um tipo! x{0} @@ -961,10 +961,10 @@ Motivo: {1} Dura {1} segundos. Não diga a ninguém. Shhh. - + O evento "Jogo Sorrateiro" terminou. {0} usuários receberam o prêmio. - + O evento "Jogo Sorrateiro" começou Coroa @@ -976,13 +976,13 @@ Dura {1} segundos. Não diga a ninguém. Shhh. Não foi possível tomar {0} de {1} porque o usuário não possuí tanto {2}! - + Voltar à Tabela de Conteúdos Proprietário do bot apenas. - Requer a permissão {0} do canal + Requer a permissão {0} do canal. Você pode dar suporte ao projeto no Patreon: <{0}> ou Paypal: <{1}> @@ -991,7 +991,7 @@ Dura {1} segundos. Não diga a ninguém. Shhh. Comandos e abreviações - + Lista de Comandos Regenerada. Digite `{0}h NomeDoComando` para ver a ajuda para o comando especificado. Ex: `{0}h >8ball` @@ -1045,10 +1045,10 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Corrida de Animais - Falha ao iniciar já que não tiveram participantes suficientes. + Falha ao iniciar, não houve participantes suficientes. - Corrida cheia! Começando imediatamente + Corrida cheia! Começando imediatamente. {0} juntou-se como {1} @@ -1072,10 +1072,10 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. {0} como {1} ganhou a corrida e {2}! - + Número especificado inválido. Você pode rolar {0}-{1} dados de uma vez. - + rolou {0} Someone rolled 35 @@ -1095,13 +1095,13 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Mudanças no Coração - Clamado por + Reivindicado por Divórcios - + Gosta de Preço @@ -1113,7 +1113,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Top Waifus - + Sua afinidade já foi definida para essa waifu ou você está tentando remover sua afinidade sem ter uma. Mudou a afinidade de {0} para {1}. @@ -1122,7 +1122,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Make sure to get the formatting right, and leave the thinking emoji - + Você deve esperar {0} horas e {1} minutos para mudar sua afinidade de novo. Sua afinidade foi reiniciada. Você não possui mas alguém que você goste. @@ -1141,7 +1141,8 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Você não pode colocar sua afinidade em você mesmo, seu egomaníaco. - + 🎉 O amor deles está realizado! 🎉 +O novo valor de {0} é {1}! Nenhuma waifu é tão barata. Você deve pagar pelo menos {0} para ter uma waifu, mesmo se o valor dela for menor. @@ -1165,31 +1166,31 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Você se divorciou de uma waifu que não gostava de você. Você recebeu {0} de volta. - + 8ball - + Acrofobia - + O jogo terminou sem submissões. - + Nenhum voto recebido. O jogo terminou sem vencedores. - + O acrônimo era {0}. - + Acrofobia já está em andamento neste canal. - + Jogo iniciado. Crie uma frase com o seguinte acrônimo: {0}. Você tem {0} segundos para fazer uma submissão. - {0} submeteram suas frases. ({1} total) + {0} submeteram suas frases. ({1} no total) Vote digitando um número da submissão @@ -1201,7 +1202,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Vence {0} com {1} pontos. - + {0} venceu por ser o único usuário a fazer uma submissão! Questão @@ -1213,7 +1214,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. {0} ganhou! {1} vence {2} - + Submissões Encerradas A Corrida de Animais já está em andamento @@ -1231,10 +1232,10 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Cleverbot habilitado neste servidor. - + Geração de moeda desabilitada neste canal. - + Geração de moeda habilitada neste canal. {0} {1} aleatórios aparecem! Capture-os digitando `{2}pick` @@ -1259,7 +1260,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Erro ao iniciar o Jogo da Forca. - Lista dos tipos de termo do "{0}hangman" + Lista dos tipos de termos do "{0}hangman" Placar de Lideres @@ -1345,22 +1346,22 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Volume padrão definido para {0}% - + Diretório adicionado à fila. - + fairplay Música concluída. - + Fair play desativado. - + Fair play ativado. - + Da posição Id @@ -1369,10 +1370,10 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Entrada inválida. - + Tempo de atividade máximo agora não tem limite. - + Tempo de atividade máximo definido para {0} segundo(s). Tamanho máximo da fila de música definido para ilimitado. @@ -1396,10 +1397,10 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Nenhum resultado para a busca. - + Música pausada. - + Fila de Músicas - Página {0}/{1} Tocando Musica @@ -1420,13 +1421,13 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Não existe uma playlist com esse ID. - + Playlist adicionada à fila. Playlist Salva - + Limite de {0}s Fila @@ -1441,7 +1442,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. A fila está cheia em {0}/{0} - Música removida + Música removida: context: "removed song #5" @@ -1457,7 +1458,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. A repetição da faixa atual parou. - + Música retomada. Repetição de playlist desabilitada. @@ -1475,7 +1476,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Músicas embaralhadas. - Música movida. + Música movida {0}h {1}m {2}s @@ -1520,7 +1521,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. O uso de TODOS OS MÓDULOS foi habilitado para o usuário {0}. - + {0} entrou na Lista Negra com o ID {1} O comando {0} agora possui um cooldown de {1}s. @@ -1532,13 +1533,13 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Nenhum cooldown de comando definido. - + Custos de Comando Desabilitado o uso de {0} {1} no canal {2}. - Desabilitado o uso de {0} {1} no canal {2}. + Habilitado o uso de {0} {1} no canal {2}. Negado @@ -1556,22 +1557,22 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Segundo parâmetro inválido. (Deve ser um número entre {0} e {1}) - + Filtro de convite desabilitado neste canal. - + Filtro de convite habilitado neste canal. - + Filtro de convite desabilitado neste servidor. - + Filtro de convite habilitado neste servidor. Permissão {0} movida de #{1} para #{2} - + Não consigo encontrar a permissão no índice #{0} Nenhum custo definido. @@ -1588,13 +1589,13 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Página {0} de Permissões - Atual cargo de permissões é {0} + Cargo atual de permissões é {0}. - + Usuários agora precisam do cargo {0} para editar permissões. - + Nenhuma permissão encontrada nesse índice. Permissões removidas #{0} - {1} @@ -1616,16 +1617,16 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Habilitado o uso de {0} {1} nesse servidor. - + {0} saiu da Lista Negra com o ID {1} - Não editável + não editável - + Desabilitado o uso de {0} {1} para o usuário {2}. - + Habilitado o uso de {0} {1} para o usuário {2}. Não vou mais mostrar avisos de permissões. @@ -1652,7 +1653,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Nenhum anime favorito ainda - A tradução automática de mensagens nesse canal foi iniciada. As mensagens do usuário serão deletadas automaticamente. + Iniciada a tradução automática de mensagens nesse canal. As mensagens do usuário serão deletadas automaticamente. A linguagem de tradução automática foi removida. @@ -1673,7 +1674,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Não consegui encontrar essa carta. - Fato + fato Capítulos @@ -1694,7 +1695,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Vitórias Competitivas - Completado + Concluída Condição @@ -1754,7 +1755,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Piadas não carregadas. - + Latitude/Longitude Nível @@ -1821,10 +1822,10 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Qualidade: - + Tempo em Partida Rápida - + Vitórias em Partida Rápida Avaliação @@ -1839,7 +1840,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Falha ao encurtar esse url. - + Url Curta Alguma coisa deu errado. @@ -1851,7 +1852,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Status - + Url da Loja Streamer {0} está offline. @@ -1932,12 +1933,12 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Juntou-se - + `{0}.` {1} [{2:F2}/s] - {3} total /s and total need to be localized to fit the context - `1.` - + Página de Atividade #{0} {0} usuários no total. @@ -1952,13 +1953,13 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Lista de funções no comando {0}calc - + {0} deste canal é {1} Tópico do Canal - Comandos utilizados + Comandos Utilizados {0} {1} é igual a {2} {3} @@ -1976,13 +1977,13 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Criado em - + Juntou-se ao canal de servidor cruzado. - + Deixou o canal de servidor cruzado. - + Este é seu token de Canal de Servidor Cruzado Emojis Personalizados @@ -1991,7 +1992,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Erro - + Atributos ID @@ -2003,7 +2004,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Aqui está uma lista de usuários nestes cargos: - você não tem permissão de usar esse comando em cargos com muitos usuários neles para prevenir abuso. + você não tem permissão de usar esse comando em cargos com muitos usuários para prevenir abuso. Valor {0} inválido. @@ -2170,7 +2171,7 @@ OwnerID: {2} Canais de Texto - Aqui está o link do quarto: + Aqui está o link da sala: Tempo de Atividade From a199891612d7f2c18e4c4b2279d0171054c6708c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 1 Mar 2017 17:12:38 +0100 Subject: [PATCH 387/746] fixed some strings, thx xnaas, closes #1093 --- src/NadekoBot/Modules/Utility/Utility.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index f69aef7d..0452dab6 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -273,7 +273,7 @@ namespace NadekoBot.Modules.Utility [NadekoCommand, Usage, Description, Aliases] public async Task ChannelId() { - await ReplyConfirmLocalized("channelidd", "🆔", Format.Code(Context.Channel.Id.ToString())) + await ReplyConfirmLocalized("channelid", "🆔", Format.Code(Context.Channel.Id.ToString())) .ConfigureAwait(false); } @@ -439,7 +439,7 @@ namespace NadekoBot.Modules.Utility var result = string.Join("\n", tags.Select(m => GetText("showemojis", m, m.Url))); if (string.IsNullOrWhiteSpace(result)) - await ReplyErrorLocalized("emojis_none").ConfigureAwait(false); + await ReplyErrorLocalized("showemojis_none").ConfigureAwait(false); else await Context.Channel.SendMessageAsync(result).ConfigureAwait(false); } From c65398482a1776f9564d238b32a5737a01a7f0dc Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 18:10:58 +0100 Subject: [PATCH 388/746] Update ResponseStrings.fr-fr.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.fr-fr.resx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx index 72a2957f..ac95afb6 100644 --- a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx +++ b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx @@ -483,7 +483,7 @@ Raison : {1} La langue du bot a été changée pour {0} - {1} - Échec dans la tentative de changement de langue. Réessayer avec l'aide pour cette commande. + Échec dans la tentative de changement de langue. Veuillez consulter l'aide pour cette commande. La langue de ce serveur est {0} - {1} @@ -1664,7 +1664,8 @@ La nouvelle valeur de {0} est {1} ! Votre langue de traduction à été supprimée. - Votre langue de traduction a été changée de {from} à {to} + Votre langue de traduction a été changée de {0} à {1} + Fuzzy Traduction automatique des messages commencée sur ce salon. @@ -2111,7 +2112,7 @@ OwnerID: {2} Je vais vous rappeler {0} pour {1} dans {2} `({3:d.M.yyyy} à {4:HH:mm})` - Format de date non valide. Regardez la liste des commandes. + Format de date non valide. Vérifiez la liste des commandes. Nouveau modèle de rappel défini. From 78c2eb4430eca2216e62084707713e7c5c7cce08 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 18:11:01 +0100 Subject: [PATCH 389/746] Update ResponseStrings.de-DE.resx (POEditor.com) --- .../Resources/ResponseStrings.de-DE.resx | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx index 8d8866c5..04611d86 100644 --- a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx @@ -872,7 +872,7 @@ Grund: {1} Nutzer wurde gekickt - verleiht {1} {0} + vegab {0} zu {1} Hoffentlich haben sie beim nächsten Mal mehr Glück ^_^ @@ -907,7 +907,7 @@ Grund: {1} X has gifted 15 flowers to Y - {0} hat eine {1} + {0} hat {1} X has Y flowers @@ -1031,7 +1031,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Inhaltsverzeichnis - Nutzung + Benutzweise Autohentai wurde gestartet. Es wird alle {0} Sekunden etwas mit einem der folgenden Stichwörtern gepostet: {1} @@ -1099,7 +1099,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Scheidungen - Positive Bewertungen + Mag Preis @@ -1202,7 +1202,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu {0} gewinnt, weil dieser Benutzer die einzigste Einsendung hat! - Frage + Gestellte Frage Unentschieden! Beide haben {0} gewählt @@ -1292,7 +1292,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu {0} hat {1} punkte - Wird beendet after dieser Frage. + Wird beendet nach dieser Frage. Die Zeit is um! Die richtige Antwort war {0} @@ -1331,7 +1331,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu {0} gegen {1} - Versuche {0} Songs einzureihen... + Versuche {0} Lieder einzureihen... Autoplay deaktiviert. @@ -1349,7 +1349,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu fairer Modus - Song beendet + Lied beendet Fairer Modus deaktiviert. @@ -1376,7 +1376,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Maximale Musik-Warteschlangengröße ist nun unbegrenzt. - Maximale Musik-Warteschlangengröße ist nun {0} Songs. + Maximale Musik-Warteschlangengröße ist nun {0} Lieder. Sie müssen sich in einem Sprachkanal auf diesem Server befinden. @@ -1385,7 +1385,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Name - Aktueller Song: + Aktuelles Lied: Kein aktiver Musikspieler. @@ -1400,10 +1400,10 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Musik-Warteschlange - Seite {0}/{1} - Spiele Song + Spiele Lied - `#{0}` - **{1}** by *{2}* ({3} Songs) + `#{0}` - **{1}** by *{2}* ({3} Lieder) Seite {0} der gespeicherten Playlists @@ -1430,7 +1430,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Warteschlange - Eingereihter Song + Eingereihtes Lied Musik-Warteschlange geleert. @@ -1439,20 +1439,20 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Warteschlange ist voll bei {0}/{1}. - Song entfernt + Lied entfernt context: "removed song #5" - Aktueller Song wird wiederholt + Aktuelle Lied wird wiederholt Playlist wird wiederholt - Song wird wiederholt + Lied wird wiederholt - Aktueller Song wird nicht mehr wiederholt. + Aktuelles Lied wird nicht mehr wiederholt. Musikwiedergabe wiederaufgenommen. @@ -1464,16 +1464,16 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Playlist-Wiederholung aktiviert. - Ich werde nun spielende, beendete, pausierte und entfernte Songs in diesen Channel ausgeben. + Ich werde nun spielende, beendete, pausierte und entfernte Lieder in diesem Channel ausgeben. Gesprungen zu `{0}:{1}` - Song gemischt. + Lieder gemischt. - Song bewegt + Lieder bewegt {0}h {1}m {2}s @@ -1656,7 +1656,8 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Ihre Automatische-Übersetzungs Sprache wurde entfernt. - Ihre Automatische-Übersetzungs Sprache wurde zu {from}>{to} gesetzt + Ihre Automatische-Übersetzungs Sprache wurde zu {0}>{1} gesetzt + Fuzzy Automatische Übersetzung der Nachrichten wurde auf diesem kanal gestartet. From ded86b51b02a0127a5dc338cc9482c24c7388109 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 18:11:04 +0100 Subject: [PATCH 390/746] Update ResponseStrings.pt-BR.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.pt-BR.resx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx index 27351b00..bac83942 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx @@ -1659,7 +1659,8 @@ O novo valor de {0} é {1}! A linguagem de tradução automática foi removida. - A linguagem de tradução automática foi definida de {from}>{to} + A linguagem de tradução automática foi definida de {0}>{1} + Fuzzy A tradução automática de mensagens foi ativada neste canal. From b93c212c687ddcad38e9f1766e4269c1bbb019f9 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 18:11:07 +0100 Subject: [PATCH 391/746] Update ResponseStrings.ru-RU.resx (POEditor.com) --- .../Resources/ResponseStrings.ru-RU.resx | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx index d2980cc8..21b36460 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx @@ -119,14 +119,12 @@ Эта база уже захвачена или разрушена. - Fuzzy Эта база уже разрушена Эта база не захвачена. - Fuzzy **РАЗРУШЕННАЯ** база #{0} ведёт войну против {1}. @@ -136,7 +134,7 @@ Fuzzy - {0} захватил базу #{1} после войны с {2} + {0} захватил базу #{1} ведя войну против {2} Fuzzy @@ -163,7 +161,7 @@ Список активных войн - не захваченная + не захваченна Fuzzy @@ -211,11 +209,11 @@ Fuzzy - Настроить реакции. + Настроить ответы. Fuzzy - Создана новая реакция. + Новый ответ. Fuzzy @@ -223,7 +221,7 @@ Fuzzy - Не найдено настраеваемых реакций с таким номером. + Не найдено настраиваемых реакций с таким номером. Fuzzy @@ -1010,7 +1008,7 @@ Fuzzy не смог забрать {0} у {1}, поскольку у пользователя нет столько {2}! - Вернуться к содержанию + Вернуться к оглавлению Только для владельца бота @@ -1064,7 +1062,7 @@ Paypal <{1}> Требуются серверное право {0} - Содержание + Оглавление Использование @@ -1384,7 +1382,7 @@ Paypal <{1}> Папка успешно добавлена в очередь воспроизведения. - fairplay + справедливое воспроизведение Fuzzy @@ -1697,7 +1695,7 @@ Paypal <{1}> Ваш язык автоперевода был удалён. - Ваш язык автоперевода изменён с {from} на {to} + Ваш язык автоперевода изменён с {0} на {1} Начинается автоматический перевод сообщений в этом канале. From f294b9997b0793bbea78a9534cef3e518c3dfaa6 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 1 Mar 2017 18:14:22 +0100 Subject: [PATCH 392/746] fixed string --- src/NadekoBot/Resources/ResponseStrings.Designer.cs | 2 +- src/NadekoBot/Resources/ResponseStrings.resx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index a33b43b9..c3d3a842 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -4587,7 +4587,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Your auto-translate language has been set to {from}>{to}. + /// Looks up a localized string similar to Your auto-translate language has been set to {0}>{1}. /// public static string searches_atl_set { get { diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index efa1fe55..c89a5084 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1658,7 +1658,7 @@ Don't forget to leave your discord name or id in the message. your auto-translate language has been removed. - Your auto-translate language has been set to {from}>{to} + Your auto-translate language has been set to {0}>{1} Started automatic translation of messages on this channel. From 50553bd8b01c4e976e2ec455fda8e5190b7636cc Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 1 Mar 2017 20:40:09 +0100 Subject: [PATCH 393/746] Fixed resource filenames --- .../Modules/Administration/Commands/LocalizationCommands.cs | 2 +- .../{ResponseStrings.fr-fr.resx => ResponseStrings.fr-FR.resx} | 0 ...rl-rs.Designer.cs => ResponseStrings.sr-Cyrl-RS.Designer.cs} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename src/NadekoBot/Resources/{ResponseStrings.fr-fr.resx => ResponseStrings.fr-FR.resx} (100%) rename src/NadekoBot/Resources/{ResponseStrings.sr-cyrl-rs.Designer.cs => ResponseStrings.sr-Cyrl-RS.Designer.cs} (100%) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 4200fafb..135a1da7 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -25,7 +25,7 @@ namespace NadekoBot.Modules.Administration {"nl-NL", "Dutch, Netherlands"}, {"ja-JP", "Japanese, Japan"}, {"pt-BR", "Portuguese, Brazil"}, - {"sr-cyrl-rs", "Serbian, Serbia - Cyrillic"} + {"sr-Cyrl-RS", "Serbian, Serbia - Cyrillic"} }.ToImmutableDictionary(); [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx b/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx similarity index 100% rename from src/NadekoBot/Resources/ResponseStrings.fr-fr.resx rename to src/NadekoBot/Resources/ResponseStrings.fr-FR.resx diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.sr-Cyrl-RS.Designer.cs similarity index 100% rename from src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.Designer.cs rename to src/NadekoBot/Resources/ResponseStrings.sr-Cyrl-RS.Designer.cs From c04163e4c1e41794441a7ae65654366d12222896 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 21:36:58 +0100 Subject: [PATCH 394/746] Create ResponseStrings.fr-fr.resx (POEditor.com) --- .../Resources/ResponseStrings.fr-fr.resx | 2203 +++++++++++++++++ 1 file changed, 2203 insertions(+) create mode 100644 src/NadekoBot/Resources/ResponseStrings.fr-fr.resx diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx new file mode 100644 index 00000000..1c802a95 --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx @@ -0,0 +1,2203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Cette base a déjà été revendiquée ou détruite. + + + Cette base est déjà détruite. + + + Cette base n'est pas revendiquée. + + + Base #{0} **DETRUITE** dans une guerre contre {1} + + + {0} a **ABANDONNÉ** la base #{1} dans une guerre contre {2} + + + {0} a revendiqué une base #{1} dans une guerre contre {2} + + + @{0} Vous avez déjà revendiqué la base #{1}. Vous ne pouvez pas en revendiquer une nouvelle. + + + La demande de la part de @{0} pour une guerre contre {1} a expiré. + + + Ennemi + + + Informations concernant la guerre contre {0} + + + Numéro de base invalide. + + + La taille de la guerre n'est pas valide. + + + Liste des guerres en cours + + + non réclamé + + + Vous ne participez pas a cette guerre. + + + @{0} Vous ne participez pas à cette guerre ou la base a déjà été détruite. + + + Aucune guerre en cours. + + + Taille + + + La guerre contre {0} a déjà commencé! + + + La guerre contre {0} commence! + + + La guerre contre {0} est terminée. + + + Cette guerre n'existe pas. + + + La guerre contre {0} a éclaté ! + + + Statistiques de réactions personnalisées effacées. + + + Réaction personnalisée supprimée + + + Permissions insuffisantes. Nécessite d'être le propriétaire du Bot pour avoir les réactions personnalisées globales, et Administrateur pour les réactions personnalisées du serveur. + + + Liste de toutes les réactions personnalisées + + + Réactions personnalisées + + + Nouvelle réaction personnalisée + + + Aucune réaction personnalisée trouvée. + + + Aucune réaction personnalisée ne correspond à cet ID. + + + Réponse + + + Statistiques des Réactions Personnalisées + + + Statistiques effacées pour {0} réaction personnalisée. + + + Pas de statistiques pour ce déclencheur trouvées, aucune action effectuée. + + + Déclencheur + + + Autohentai arrêté. + + + Aucun résultat trouvé. + + + {0} est déjà inconscient. + + + {0} a tous ses PV. + + + Votre type est déjà {0} + + + Vous avez utilisé {0}{1} sur {2}{3} pour {4} dégâts. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + Vous ne pouvez pas attaquer de nouveau sans représailles ! + + + Vous ne pouvez pas vous attaquer vous-même. + + + {0} s'est évanoui! + + + Vous avez soigné {0} avec un {1} + + + {0} a {1} points de vie restants. + + + Vous ne pouvez pas utiliser {0}. Ecrivez `{1}ml` pour voir la liste des actions que vous pouvez effectuer. + + + Liste des attaques pour le type {0} + + + Ce n'est pas très efficace. + + + Vous n'avez pas assez de {0} + + + Vous avez ressuscité {0} avec un {1} + + + Vous vous êtes ressuscité avec un {0} + + + Votre type a bien été modifié de {0} à {1} + + + C'est légèrement efficace. + + + C'est très efficace ! + + + Vous avez utilisé trop de mouvements d'affilée, vous ne pouvez donc plus bouger! + + + Le type de {0} est {1} + + + Utilisateur non trouvé. + + + Vous vous êtes évanoui, vous n'êtes donc pas capable de bouger! + + + **L'affectation automatique de rôle** à l'arrivé d'un nouvel utilisateur est désormais **désactivée**. + + + **L'affectation automatique de rôle** à l'arrivé d'un nouvel utilisateur est désormais **activée**. + + + Liens + + + Avatar modifié + + + Vous avez été banni du serveur {0}. +Raison: {1} + + + banni + PLURAL + + + Utilisateur banni + + + Le nom du Bot a changé pour {0} + + + Le statut du Bot a changé pour {0} + + + La suppression automatique des annonces de départ a été désactivée. + + + Les annonces de départ seront supprimées après {0} secondes. + + + Annonce de départ actuelle : {0} + + + Activez les annonces de départ en entrant {0} + + + Nouvelle annonce de départ définie. + + + Annonce de départ désactivée. + + + Annonce de départ activée sur ce salon. + + + Nom du salon modifié + + + Ancien nom + + + Sujet du salon modifié + + + Nettoyé. + + + Contenu + + + Rôle {0} créé avec succès + + + Salon textuel {0} créé. + + + Salon vocal {0} créé. + + + Mise en sourdine effectuée. + + + Serveur {0} supprimé + + + Suppression automatique des commandes effectuées avec succès, désactivée. + + + Suppression automatique des commandes effectuées avec succès, activée. + + + Le salon textuel {0} a été supprimé. + + + Le salon vocal {0} a été supprimé. + + + MP de + + + Nouveau donateur ajouté avec succès. Montant total des dons de cet utilisateur : {0} 👑 + + + Merci aux personnes ci-dessous pour avoir permis à ce projet d'exister! + + + Je transmettrai désormais les MPs à tous les propriétaires. + + + Je transmettrai désormais les MPs seulement au propriétaire principal. + + + Je transmettrai désormais les MPs. + + + Je ne transmettrai désormais plus les MPs. + + + La suppression automatique des messages d'accueil a été désactivé. + + + Les messages d'accueil seront supprimés après {0} secondes. + + + MP de bienvenue actuel: {0} + + + Activez les MPs de bienvenue en écrivant {0} + + + Nouveau MP de bienvenue défini. + + + MPs de bienvenue désactivés. + + + MPs de bienvenue activés. + + + Message de bienvenue actuel: {0} + + + Activez les messages de bienvenue en écrivant {0} + + + Nouveau message de bienvenue défini. + + + Messages de bienvenue désactivés. + + + Messages de bienvenue activés sur ce salon. + + + Vous ne pouvez pas utiliser cette commande sur les utilisateurs dont le rôle est supérieur ou égal au vôtre dans la hiérarchie. + + + Images chargées après {0} secondes! + + + Format d'entrée invalide. + + + Paramètres invalides. + + + {0} a rejoint {1} + + + Vous avez été expulsé du serveur {0}. +Raison : {1} + + + Utilisateur expulsé + + + Listes des langues +{0} + + + La langue du serveur est désormais {0} - {1} + + + La langue par défaut du bot est désormais {0} - {1} + + + La langue du bot a été changée pour {0} - {1} + + + Échec dans la tentative de changement de langue. Veuillez consulter l'aide pour cette commande. + + + La langue de ce serveur est {0} - {1} + + + {0} a quitté {1} + + + Serveur {0} quitté + + + Enregistrement de {0} événements dans ce salon. + + + Enregistrement de tous les événements dans ce salon. + + + Enregistrement désactivé. + + + Événements enregistrés que vous pouvez suivre : + + + L'enregistrement ignorera désormais {0} + + + L'enregistrement n'ignorera pas {0} + + + L’événement {0} ne sera plus enregistré. + + + {0} a émis une notification pour les rôles suivants + + + Message de {0} `[Bot Owner]` : + + + Message envoyé. + + + {0} déplacé de {1} à {2} + L'utilisateur n'a pas forcément été déplacé de son plein gré. S'est déplacé - déplacé + + + Message supprimé dans #{0} + + + Mise à jour du message dans #{0} + + + Tous les utilisateurs sont maintenant muets. + PLURAL (users have been muted) + + + L'utilisateur est maintenant muet. + singular "User muted." + + + Il semblerait que je n'ai pas la permission nécessaire pour effectuer cela. + + + Nouveau rôle muet créé. + + + J'ai besoin de la permission d'**Administrateur** pour effectuer cela. + + + Nouveau message + + + Nouveau pseudonyme + + + Nouveau sujet + + + Pseudonyme changé + + + Impossible de trouver ce serveur + + + Aucun Shard pour cet ID trouvée. + Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. + + + Ancien message + + + Ancien pseudonyme + + + Ancien sujet + + + Erreur. Je ne dois sûrement pas posséder les permissions suffisantes. + + + Les permissions pour ce serveur ont été réinitialisées. + + + Protections actives + + + {0} a été **désactivé** sur ce serveur. + + + {0} Activé + + + Erreur. J'ai besoin de la permission Gérer les rôles. + + + Aucune protection activée. + + + Le seuil d'utilisateurs doit être entre {0} et {1}. + + + Si {0} ou plus d'utilisateurs rejoignent dans les {1} secondes suivantes, je les {2}. + + + Le temps doit être compris entre {0} et {1} secondes. + + + Vous avez retirés tous les rôles de l'utilisateur {0} avec succès + + + Impossible de retirer des rôles. Je n'ai pas les permissions suffisantes. + + + La couleur du rôle {0} a été modifiée. + + + Ce rôle n'existe pas. + + + Les paramètres spécifiés sont invalides. + + + Erreur due à un manque de permissions ou à une couleur invalide. + + + L'utilisateur {1} n'a plus le rôle {0}. + + + Impossible de supprimer ce rôle. Je ne possède pas les permissions suffisantes. + + + Rôle renommé. + + + Impossible de renommer ce rôle. Je ne possède pas les permissions suffisantes. + + + Vous ne pouvez pas modifier les rôles supérieurs au votre. + + + La répétition du message suivant a été désactivé: {0} + + + Le rôle {0} a été ajouté à la liste. + + + {0} introuvable. Nettoyé. + + + Le rôle {0} est déjà présent dans la liste. + + + Ajouté. + + + Rotation du statut de jeu désactivée. + + + Rotation du statut de jeu activée. + + + Voici une liste des rotations de statuts : +{0} + + + Aucune rotation de statuts en place. + + + Vous avez déjà le rôle {0}. + + + Vous avez déjà {0} rôles exclusifs auto-attribués. + + + Rôles auto-attribuables désormais exclusifs. + + + Il y a {0} rôles auto-attribuables. + + + Ce rôle ne peux pas vous être attribué par vous-même. + + + Vous ne possédez pas le rôle {0}. + + + Les rôles auto-attribuables ne sont désormais plus exclusifs! + Je ne pense pas que ce soit la bonne traduction.. self-assignable role serait plutôt rôle auto-attribuable + + + Je suis incapable de vous ajouter ce rôle. `Je ne peux pas ajouter de rôles aux propriétaires et aux autres rôles plus haut que le mien dans la hiérarchie.` + + + {0} a été supprimé de la liste des rôles auto-attribuables. + + + Vous n'avez plus le rôle {0}. + + + Vous avez désormais le rôle {0}. + + + L'utilisateur {1} a désormais le rôle {0}. + + + Impossible d'ajouter un rôle. Je ne possède pas les permissions suffisantes. + + + Nouvel avatar défini! + + + Nouveau nom de Salon défini avec succès. + + + Nouveau jeu défini! + Pour "set", je pense que défini irait mieux que "en service" + + + Nouveau stream défini! + + + Nouveau sujet du salon défini. + + + Shard {0} reconnecté. + Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. + + + Shard {0} en reconnection. + Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. + + + Arrêt en cours. + + + Les utilisateurs ne peuvent pas envoyer plus de {0} messages toutes les {1} secondes. + + + Mode ralenti désactivé. + + + Mode ralenti activé + + + expulsés (kick) + PLURAL + + + {0} ignorera ce Salon. + + + {0} n'ignorera plus ce Salon. + + + Si un utilisateur poste {0} le même message à la suite, je le {1}. + __SalonsIgnorés__: {2} + + + Salon textuel crée. + + + Salon textuel supprimé. + + + Son activé avec succès. + + + Micro activé + singular + + + Nom d'utilisateur + + + Nom d'utilisateur modifié. + + + Utilisateurs + + + Utilisateur banni + + + {0} est maintenant **muet** sur le chat. + + + **La parole a été rétablie** sur le chat pour {0}. + + + L'utilisateur a rejoint + + + L'utilisateur a quitté + + + {0} est maintenant **muet** à la fois sur les salons textuels et vocaux. + + + Rôle ajouté à l'utilisateur + + + Rôle retiré de l'utilisateur + + + {0} est maintenant {1} + + + {0} n'est maintenant **plus muet** des salons textuels et vocaux. + + + {0} a rejoint le salon vocal {1}. + + + {0} a quitté le salon vocal {1}. + + + {0} est allé du salon vocal {1} à {2}. + + + {0} est maintenant **muet**. + + + {0} n'est maintenant **plus muet**. + + + Salon vocal crée. + + + Salon vocal supprimé. + + + Fonctionnalités vocales et textuelles désactivées. + + + Fonctionnalités vocales et textuelles activées. + + + Je n'ai pas la permission **Gérer les rôles** et/ou **Gérer les salons**, je ne peux donc pas utiliser `voice+text` sur le serveur {0}. + + + Vous activez/désactivez cette fonctionnalité et **je n'ai pas la permission ADMINISTRATEUR**. Cela pourrait causer des dysfonctionnements, et vous devrez nettoyer les salons textuels vous-même après ça. + + + Je nécessite au moins les permissions **Gérer les rôles** et **Gérer les salons** pour activer cette fonctionnalité. (Permission Administrateur de préférence) + + + Utilisateur {0} depuis un salon textuel. + + + Utilisateur {0} depuis salon textuel et vocal. + + + Utilisateur {0} depuis un salon vocal. + + + Vous avez été expulsé du serveur {0}. +Raison: {1} + + + Utilisateur débanni + + + Migration effectuée! + + + Erreur lors de la migration, veuillez consulter la console pour plus d'informations. + + + Présences mises à jour. + + + Utilisateur expulsé. + + + a récompensé {0} à {1} + + + Plus de chance la prochaine fois ^_^ + C'est vraiment québecois ca.. On ne le dit pas comme ca ici xD + + + Félicitations! Vous avez gagné {0} pour avoir lancé au dessus de {1}. + + + Deck remélangé. + + + Lancé {0}. + User flipped tails. + + + Vous avez deviné! Vous avez gagné {0} + + + Nombre spécifié invalide. Vous pouvez lancer 1 à {0} pièces. + + + Ajoute la réaction {0} à ce message pour avoir {1} + + + Cet événement est actif pendant {0} heures. + + + L'événement "réactions fleuries" a démarré! + + + a donné {0} à {1} + X has gifted 15 flowers to Y + + + {0} a {1} + X has Y flowers + + + Face + + + Classement + + + {1} utilisateurs du rôle {2} ont été récompensé de {0}. + + + Vous ne pouvez pas miser plus de {0} + + + Vous ne pouvez pas parier moins de {0} + + + Vous n'avez pas assez de {0} + + + Plus de carte dans le deck. + + + Utilisateur tiré au sort + + + Vous avez roulé un {0}. + + + Mise + + + WOAAHHHHHH!!! Félicitations!!! x{0} + + + Une simple {0}, x{1} + + + Wow! Quelle chance! Trois du même genre! x{0} + + + Bon travail! Deux {0} - mise x{1} + + + Gagné + + + Les utilisateurs doivent écrire un code secret pour avoir {0}. Dure {1} secondes. Ne le dite à personne. Shhh. + + + L’événement "jeu sournois" s'est fini. {0} utilisateurs ont reçu la récompense. + + + L'événement "jeu sournois" a démarré + + + Pile + + + Vous avez pris {0} de {1} avec succès + + + Impossible de prendre {0} de {1} car l'utilisateur n'a pas assez de {2}! + + + Retour à la table des matières + + + Propriétaire du Bot seulement + + + Nécessite {0} permissions du salon. + + + Vous pouvez supporter ce projet sur Patreon <{0}> ou via Paypal <{1}> + + + Commandes et alias + + + Liste des commandes rafraîchie. + + + Écrivez `{0}h NomDeLaCommande` pour voir l'aide spécifique à cette commande. Ex: `{0}h >8ball` + + + Impossible de trouver cette commande. Veuillez vérifier qu'elle existe avant de réessayer. + + + Description + + + Vous pouvez supporter le projet NadekoBot +sur Patreon <{0}> +par Paypal <{1}> +N'oubliez pas de mettre votre nom discord ou ID dans le message. + +**Merci** ♥️ + + + **Liste des Commandes**: <{0}> +**La liste des guides et tous les documents peuvent être trouvés ici**: <{1}> + + + Liste des commandes + + + Liste des modules + + + Entrez `{0}cmds NomDuModule` pour avoir la liste des commandes de ce module. ex `{0}cmds games` + + + Ce module n'existe pas. + + + Permission serveur {0} requise. + + + Table des matières + + + Usage + + + Autohentai commencé. Publie toutes les {0}s avec l'un des tags suivants : +{1} + + + Tag + + + Course d'animaux + + + Pas assez de participants pour commencer. + + + Suffisamment de participants ! La course commence. + + + {0} a rejoint sous la forme d'un {1} + + + {0} a rejoint sous la forme d'un {1} et mise sur {2} ! + + + Entrez {0}jr pour rejoindre la course. + + + Début dans 20 secondes ou quand le nombre maximum de participants est atteint. + + + Début avec {0} participants. + + + {0} sous la forme d'un {1} a gagné la course ! + + + {0} sous la forme d'un {1} a gagné la course et {2}! + + + Nombre spécifié invalide. Vous pouvez lancer de {0} à {1} dés à la fois. + + + tiré au sort {0} + Someone rolled 35 + + + Dé tiré au sort: {0} + Dice Rolled: 5 + + + Le lancement de la course a échoué. Une autre course doit probablement être en cours. + + + Aucune course n'existe sur ce serveur. + + + Le deuxième nombre doit être plus grand que le premier. + + + Changements de Coeur + + + Revendiquée par + + + Divorces + + + Aime + + + Prix + + + Aucune waifu n'a été revendiquée pour l'instant. + + + Top Waifus + + + votre affinité est déjà liée à cette waifu ou vous êtes en train de retirer votre affinité avec quelqu'un alors que vous n'en possédez pas. + + + Affinités changées de de {0} à {1}. + +*C'est moralement discutable.* 🤔 + Make sure to get the formatting right, and leave the thinking emoji + + + Vous devez attendre {0} heures et {1} minutes avant de pouvoir changer de nouveau votre affinité. + + + Votre affinité a été réinitialisée. Vous n'avez désormais plus la personne que vous aimez. + + + veut être la waifu de {0}. Aww <3 + + + a revendiqué {0} comme sa waifu pour {1} + + + Vous avez divorcé avec une waifu qui vous aimais. Monstre sans cœur. {0} a reçu {1} en guise de compensation. + + + vous ne pouvez pas vous lier d'affinité avec vous-même, espèce d'égocentrique. + + + 🎉Leur amour est comblé !🎉 +La nouvelle valeur de {0} est {1} ! + + + Aucune waifu n'est à ce prix. Tu dois payer au moins {0} pour avoir une waifu, même si sa vraie valeur est inférieure. + + + Tu dois payer {0} ou plus pour avoir cette waifu ! + + + Cette waifu ne t'appartient pas. + + + Tu ne peux pas t'acquérir toi-même. + + + Vous avez récemment divorcé. Vous devez attendre {0} heures et {1} minutes pour divorcer à nouveau. + + + Personne + + + Vous avez divorcé d'une waifu qui ne vous aimait pas. Vous recevez {0} en retour. + + + 8ball + + + Acrophobie + + + Le jeu a pris fin sans soumissions. + + + Personne n'a voté : la partie se termine sans vainqueur. + + + L'acronyme était {0}. + + + Une partie d'Acrophobia est déjà en cours sur ce salon. + + + La partie commence. Créez une phrase avec l'acronyme suivant : {0}. + + + Vous avez {0} secondes pour faire une soumission. + + + {0} a soumit sa phrase. ({1} au total) + + + Votez en entrant le numéro d'une soumission. + + + {0} a voté! + + + Le gagnant est {0} avec {1} points! + + + {0} est le gagnant pour être le seul utilisateur à avoir fait une soumission! + + + Question + + + Egalité ! Vous avez choisi {0}. + + + {0} a gagné ! {1} bat {2}. + + + Inscriptions terminées. + + + Une course d'animaux est déjà en cours. + + + Total : {0} Moyenne : {1} + + + Catégorie + + + Cleverbot désactivé sur ce serveur. + + + Cleverbot activé sur ce serveur. + + + La génération monétaire a été désactivée sur ce salon. + Currency =/= current !!! Il s'agit de monnaie. Par example: Euro is a currency. US Dollar also is. Sur Public Nadeko, il s'agit des fleurs :) + + + La génération monétaire a été désactivée sur ce salon. + + + {0} {1} aléatoires sont apparus ! Attrapez-les en entrant `{2}pick` + plural + + + Un {0} aléatoire est apparu ! Attrapez-le en entrant `{1}pick` + + + Impossible de charger une question. + + + La jeu a commencé. + + + Partie de pendu commencée. + + + Une partie de pendu est déjà en cours sur ce canal. + + + Initialisation du pendu erronée. + + + Liste des "{0}hangman" types de termes : + + + Classement + + + Vous n'avez pas assez de {0} + + + Pas de résultat + + + a cueilli {0} + Kwoth picked 5* + + + {0} a planté {1} + Kwoth planted 5* + + + Une partie de Trivia est déjà en cours sur ce serveur. + + + Partie de Trivia + + + {0} a deviné! La réponse était: {1} + + + Aucune partie de Trivia en cours sur ce serveur. + + + {0} a {1} points + + + Le jeu s'arrêtera après cette question. + + + Le temps a expiré! La réponse était {0} + + + {0} a deviné la réponse et gagne la partie! La réponse était: {1} + + + Vous ne pouvez pas jouer contre vous-même. + + + Une partie de Morpion est déjà en cours sur ce salon. + + + Égalité! + + + a crée une partie de Morpion. + + + {0} a gagné ! + + + Trois alignés. + + + Aucun mouvement restant ! + + + Le temps a expiré ! + + + Tour de {0}. + + + {0} contre {1} + + + Tentative d'ajouter {0} musiques à la file d'attente... + + + Lecture automatique désactivée. + + + Lecture automatique activée. + + + Volume par défaut défini à {0}% + + + File d'attente complète. + + + à tour de rôle + + + Lecture terminée + + + Système de tour de rôle désactivé. + + + Système de tour de rôle activé. + + + De la position + + + Id + + + Entrée invalide. + + + Le temps maximum de lecture est désormais illimité. + + + Temps maximum de lecture défini à {0} seconde(s). + + + La taille de la file d'attente est désormais illmitée. + + + La taille de la file d'attente est désormais de {0} piste(s). + + + Vous avez besoin d'être dans un salon vocal sur ce serveur. + + + Nom + + + Vous écoutez + + + Aucun lecteur de musique actif. + + + Pas de résultat. + + + Lecteur mis sur pause. + + + Liste d'attente - Page {0}/{1} + + + Lecture en cours: + + + `#{0}` - **{1}** par *{2}* ({3} morceaux) + + + Page {0} des listes de lecture sauvegardées + + + Liste de lecture supprimée. + + + Impossible de supprimer cette liste de lecture. Soit elle n'existe pas, soit vous n'en êtes pas le créateur. + + + Aucune liste de lecture ne correspond a cet ID. + + + File d'attente de la liste complétée. + + + Liste de lecture sauvegardée + + + Limite à {0}s + + + Liste d'attente + + + Musique ajoutée à la file d'attente + + + Liste d'attente effacée. + + + Liste d'attente complète ({0}/{0}). + + + Musique retirée + context: "removed song #5" + + + Répétition de la musique en cours + + + Liste de lecture en boucle + + + Piste en boucle + + + La piste ne sera lue qu'une fois. + + + Reprise de la lecture. + + + Lecture en boucle désactivée. + + + Lecture en boucle activée. + + + Je vais désormais afficher les musiques en cours, en pause, terminées et supprimées sur ce salon. + + + Saut à `{0}:{1}` + + + Lecture aléatoire activée. + + + Musique déplacée + + + {0}h {1}m {2}s + + + En position + + + Illimité + + + Le volume doit être compris entre 0 et 100 + + + Volume réglé sur {0}% + + + Désactivation de l'usage de TOUS LES MODULES pour le salon {0}. + + + Activation de l'usage de TOUS LES MODULES pour le salon {0}. + + + Permis + + + Désactivation de l'usage de TOUS LES MODULES pour le rôle {0}. + + + Activation de l'usage de TOUS LES MODULES pour le rôle {0}. + + + Désactivation de l'usage de TOUS LES MODULES sur ce serveur. + + + Activation de l'usage de TOUS LES MODULES sur ce serveur. + + + Désactivation de l'usage de TOUS LES MODULES pour l'utilisateur {0}. + + + Activation de l'usage de TOUS LES MODULES pour l'utilisateur {0}. + + + {0} sur liste noire avec l'ID {1} + Il ne s'agit pas d'un ban mais d'une blacklist interdisant l'utilisateur d'utiliser le bot. + + + La commande {0} a désormais {1}s de temps de recharge. + + + La commande {0} n'a pas de temps de recharge et tous les temps de recharge ont été réinitialisés. + + + Aucune commande n'a de temps de recharge. + + + Coût de la commande : + + + Usage de {0} {1} désactivé sur le salon {2}. + + + Usage de {0} {1} activé sur le salon {2}. + + + Refusé + + + Ajout du mot {0} à la liste des mots filtrés. + + + Liste Des Mots Filtrés + + + Suppression du mot {0} de la liste des mots filtrés. + + + Second paramètre invalide. (nécessite un nombre entre {0} et {1}) + + + Filtrage des invitations désactivé sur ce salon. + + + Filtrage des invitations activé sur ce salon. + + + Filtrage des invitations désactivé sur le serveur. + + + Filtrage des invitations activé sur le serveur. + + + Permission {0} déplacée de #{1} à #{2} + + + Impossible de trouver la permission à l'index #{0} + + + Aucun coût défini. + + + Commande + Gen (of command) + + + Module + Gen. (of module) + + + Page {0} des permissions + + + Le rôle des permissions actuelles est {0}. + + + Il faut maintenant avoir le rôle {0} pour modifier les permissions. + + + Aucune permission trouvée à cet index. + + + Supression des permissions #{0} - {1} + + + Usage de {0} {1} désactivé pour le rôle {2}. + + + Usage de {0} {1} activé pour le rôle {2}. + + + sec. + Short of seconds. + + + Usage de {0} {1} désactivé pour le serveur. + + + Usage de {0} {1} activé pour le serveur. + + + Débanni {0} avec l'ID {1} + + + Non modifiable + + + Usage de {0} {1} désactivé pour l'utilisateur {2}. + + + Usage de {0} {1} activé pour l'utilisateur {2}. + + + Je n'afficherai plus les avertissements des permissions. + + + J'afficherai désormais les avertissements des permissions. + + + Filtrage des mots désactivé sur ce salon. + + + Filtrage des mots activé sur ce salon. + + + Filtrage des mots désactivé sur le serveur. + + + Filtrage des mots activé sur le serveur. + + + Capacités + + + Pas encore d'anime préféré + + + Traduction automatique des messages activée sur ce salon. Les messages utilisateurs vont désormais être supprimés. + + + Votre langue de traduction à été supprimée. + + + Votre langue de traduction a été changée de {0} à {1} + + + Traduction automatique des messages commencée sur ce salon. + + + Traduction automatique des messages arrêtée sur ce salon. + + + Le format est invalide ou une erreur s'est produite. + + + Impossible de trouver cette carte. + + + fait + + + Chapitres + + + Bande dessinée # + + + Parties compétitives perdues + + + Parties compétitives jouées + + + Rang en compétitif + + + Parties compétitives gagnées + + + Complétés + + + Condition + + + Coût + + + Date + + + Définis: + + + Abandonnés + droppped as in, "stopped watching" referring to shows/anime + + + Episodes + + + Une erreur s'est produite. + + + Exemple + + + Impossible de trouver cet anime. + + + Impossible de trouver ce manga. + + + Genres + + + Impossible de trouver une définition pour ce hashtag. + + + Taille/Poid + + + {0}m/{1}kg + + + Humidité + + + Recherche d'images pour: + + + Impossible de trouver ce film. + + + Langue d'origine ou de destination invalide. + + + Blagues non chargées. + + + Lat/Long + + + Niveau + + + Liste de tags pour {0}place. + Don't translate {0}place + + + Emplacement + + + Les objets magiques ne sont pas chargés. + + + Profil MAL de {0} + + + Le propriétaire du Bot n'a pas spécifié de clé d'API Mashape (MashapeApiKey). Fonctionnalité non disponible + + + Min/Max + + + Aucun salon trouvé. + + + Aucun résultat trouvé. + + + En attente + + + Url originale + + + Une clé d'API osu! est nécessaire. + + + Impossible de récupérer la signature osu!. + + + Trouvé dans {0} images. Affichage de {0} aléatoires. + + + Utilisateur non trouvé! Veuillez vérifier la région ainsi que le BattleTag avant de réessayer. + + + Prévus de regarder + Je ne pense pas que le sens de la traduction soit le bon. + + + Plateforme + + + Attaque non trouvée. + + + Pokémon non trouvé. + + + Lien du profil : + + + Qualité + + + Durée en Jeux Rapides + + + Victoires Rapides + + + Évaluation + + + Score: + + + Chercher pour: + recherche plutôt non ? + + + Impossible de réduire cette Url. + + + Url réduite + + + Une erreur s'est produite. + + + Veuillez spécifier les paramètres de recherche. + + + Statut + + + Url stockée + + + Le streamer {0} est hors ligne. + + + Le streamer {0} est en ligne avec {1} viewers. + + + Vous suivez {0} streams sur ce serveur. + + + Vous ne suivez aucun stream sur ce serveur. + + + Aucun stream de ce nom. + + + Ce stream n'existe probablement pas. + + + Stream de {0} ({1}) retirée des notifications. + + + Je préviendrai ce salon lors d'un changement de statut. + + + Aube + + + Crépuscule + + + Température + + + Titre: + + + Top 3 anime favoris + + + Traduction: + + + Types + + + Impossible de trouver une définition pour ce terme. + + + Url + + + Viewers + + + En écoute + + + Impossible de trouver ce terme sur le wikia spécifié. + + + Entrez un wikia cible, suivi d'une requête de recherche. + + + Page non trouvée. + + + Vitesse du vent + + + Les {0} champions les plus bannis + + + Impossible de yodifier votre phrase. + + + Rejoint + + + `{0}.` {1} [{2:F2}/s] - {3} total + /s and total need to be localized to fit the context - +`1.` + + + Page d'activité #{0} + + + {0} utilisateurs en total. + + + Créateur + + + ID du Bot + + + Liste des fonctions pour la commande {0}calc + + + {0} de ce salon est {1} + + + Sujet du salon + + + Commandes exécutées + + + {0} {1} est équivalent à {2} {3} + + + Unités pouvant être converties : + + + Impossible de convertir {0} en {1}: unités non trouvées + + + Impossible de convertir {0} en {1} : les types des unités ne sont pas compatibles. + + + Créé le + + + Salon inter-serveur rejoint. + + + Salon inter-serveur quitté. + + + Voici votre jeton CSC + + + Emojis personnalisées + + + Erreur + + + Fonctionnalités + + + ID + + + Index hors limites. + + + Voici une liste des utilisateurs dans ces rôles : + + + Vous ne pouvez pas utiliser cette commande sur un rôle incluant beaucoup d'utilisateurs afin d'éviter les abus. + + + Valeur {0} invalide. + Invalid months value/ Invalid hours value + + + Discord rejoint + + + Serveur rejoint + + + ID: {0} +Membres: {1} +OwnerID: {2} + + + Aucun serveur trouvée sur cette page. + + + Liste des messages répétés + + + Membres + + + Mémoire + + + Messages + + + Répéteur de messages + + + Nom + + + Pseudonyme + + + Personne ne joue à ce jeu. + + + Aucune répétition active. + + + Aucun rôle sur cette page. + + + Aucun shard sur cette page. + Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. + + + Aucun sujet choisi. + + + Propriétaire + + + ID des propriétaires + + + Présence + + + {0} Serveurs +{1} Salons Textuels +{2} Salons Vocaux + + + Toutes les citations possédant le mot-clé {0} ont été supprimées. + + + Page {0} des citations + + + Aucune citation sur cette page. + + + Aucune citation que vous puissiez supprimer n'a été trouvé. + + + Citation ajoutée + + + Une citation aléatoire a été supprimée. + + + Région + + + Inscrit sur + + + Je vais vous rappeler {0} pour {1} dans {2} `({3:d.M.yyyy} à {4:HH:mm})` + + + Format de date non valide. Vérifiez la liste des commandes. + + + Nouveau modèle de rappel défini. + + + Répétition de {0} chaque {1} jour(s), {2} heure(s) et {3} minute(s). + + + Liste des répétitions + + + Aucune répétition active sur ce serveur. + + + #{0} arrêté. + + + Pas de message répété trouvé sur ce serveur. + + + Résultat + + + Rôles + + + Page #{0} de tout les rôles sur ce serveur. + + + Page #{0} des rôles pour {1} + + + Aucune couleur n'est dans le bon format. Utilisez `#00ff00` par exemple. + + + Couleurs alternées pour le rôle {0} activées. + + + Couleurs alternées pour le rôle {0} arrêtées + + + {0} de ce serveur est {1} + + + Info du serveur + + + Shard + Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. + + + Statistique des shards + Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. + + + Le shard **#{0}** est en état {1} avec {2} serveurs. + Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. + + + **Nom:** {0} **Lien:** {1} + + + Pas d'emojis spéciaux trouvés. + + + Joue actuellement {0} musiques, {1} en attente. + + + Salons textuels + + + Voici le lien pour votre salon: + + + Durée de fonctionnement + + + {0} de l'utilisateur {1} est {2} + Id of the user kwoth#1234 is 123123123123 + + + Utilisateurs + + + Salons vocaux + + + \ No newline at end of file From fb574f0925172596886cdf6f54bdabc585b792b4 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 21:37:01 +0100 Subject: [PATCH 395/746] Update ResponseStrings.de-DE.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.de-DE.resx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx index 04611d86..8b3974b3 100644 --- a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx @@ -241,7 +241,7 @@ Dein Typ ist bereits {0} - benutzt {0}{1} auf {2}{3} für {4} Schaden. + benutzte {0}{1} an {2}{3} für {4} Schaden. Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. @@ -281,7 +281,7 @@ Dein Typ wurde verändert von {0} mit einem {1} - Das ist effektiv. + Das ist etwas effektiv. Das ist sehr effektiv! @@ -838,7 +838,7 @@ __ignoredChannels__: {2} Ich habe keine **Rollenmanagement**- und/oder **Kanalmanagement**-Rechte, sodass ich `voice+text` auf dem Server {0} nicht ausführen kann. - Sie schalten diese Funktion ein bzw. aus und **ich habe keine ADMINISTRATORRECHTE**. Dies könnte einige Probleme hervorrufen, sodass sie ihre Textkanäle eventuell selber aufräumen musst. + Sie schalten diese Funktion ein bzw. aus und **ich habe keine ADMINISTRATORRECHTE**. Dies könnte einige Probleme hervorrufen, sodass sie ihre Textkanäle eventuell selber aufräumen müssen. Ich benötige zumindest **Rollenmanagement**- und **Kanalmanagement**-Rechte um diese Funktion einzuschalten. (Bevorzugt Administratorrechte) @@ -1181,7 +1181,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Akrophobia läuft bereits in diesem Kanal. - Spiel gestartet. Erstelle einen Satz aus dem folgenden Akronym. + Spiel gestartet. Erstelle einen Satz aus dem folgenden Akronym: {0}. Sie haben {0} Sekunden für ihre Einsendung. @@ -1942,7 +1942,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu {0} totale Benutzer. - Autor(in) + Autor ID des Bots @@ -2091,7 +2091,7 @@ ID des Besitzers: {2} Zitat hinzugefügt - Zufälliger Zitat wurde gelöscht. + Zufälliges Zitat wurde gelöscht. Region From 8b859ab0278c94f66e2c2298dd48644740508ce6 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 21:37:05 +0100 Subject: [PATCH 396/746] Update ResponseStrings.pt-BR.resx (POEditor.com) From 5e06ccb5bfc4802bd2f2892b71da0ef5af919944 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 1 Mar 2017 21:37:08 +0100 Subject: [PATCH 397/746] Update ResponseStrings.ru-RU.resx (POEditor.com) --- .../Resources/ResponseStrings.ru-RU.resx | 86 ++++++------------- 1 file changed, 24 insertions(+), 62 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx index 21b36460..12a8b4d2 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx @@ -131,19 +131,15 @@ У {0} есть **НЕ ЗАХВАЧЕННАЯ** база #{1}, ведущая войну против {2} - Fuzzy - {0} захватил базу #{1} ведя войну против {2} - Fuzzy + {0} захватил базу #{1}, ведя войну против {2} @{0} Вы уже захватили базу #{1}. Вы не можете захватить новую базу. - Fuzzy Время действия запроса от @{0} на войну против {1} истёкло. - Fuzzy Враг @@ -161,8 +157,7 @@ Список активных войн - не захваченна - Fuzzy + не захвачена Вы не участвуете в этой войне. @@ -180,8 +175,7 @@ Война против {0} уже началась. - Война против {0} была создана. - Fuzzy + Война против {0} была начата. Закончилась война против {0}. @@ -194,50 +188,39 @@ Вся статистика настраиваемых реакций стёрта. - Fuzzy - Настраиваемая реакция удалена. - Fuzzy + Настраиваемая реакция удалена Недостаточно прав. Необходимо владеть Бот-ом для глобальных настраиваемых реакций или быть Администратором для реакций по серверу. - Fuzzy - Список всех настраиваемых реакций. - Fuzzy + Список всех настраиваемых реакций - Настроить ответы. - Fuzzy + Настраиваемые реакции - Новый ответ. - Fuzzy + Новая настраиваемая реакция Не найдено настраиваемых реакций. - Fuzzy Не найдено настраиваемых реакций с таким номером. - Fuzzy Ответ - Статистика настраеваемых реакций. - Fuzzy + Статистика настраеваемых реакций Статистика удалена для настраеваемой реакции {0}. - Fuzzy - Не найдено статистики для этого запроса, никаких действий не применено. - Fuzzy + Не найдено статистики для этого активатора, никаких действий не применено. Активатор @@ -278,41 +261,33 @@ Вы не можете использовать {0}. Напишите '{1}ml', чтобы увидеть список доступных Вам приёмов. - Fuzzy Список приёмов {0} типа Эта атака не эффективна. - Fuzzy У вас не достаточно {0} воскресил {0}, использовав один {1} - Fuzzy Вы воскресили себя, использовав один {0} - Fuzzy Ваш тип изменён с {0} на {1} - Fuzzy Эта атака немного эффективна. - Fuzzy Эта атака очень эффективна! - Fuzzy Вы использовали слишком много приёмов подряд и не можете двигаться! - Fuzzy Тип {0} — {1} @@ -398,7 +373,6 @@ Успешное оглушение. - Fuzzy Сервер {0} удален. @@ -420,7 +394,6 @@ Успешно добавлен новый донатор. Общее количество пожертвований от этого пользователя: {0} 👑 - Fuzzy Спасибо всем, указанным ниже, что помогли этому проекту! @@ -444,19 +417,19 @@ Приветственные сообщения будут удаляться через {0} секунд. - Приветствие, используемое в настоящий момент: {0} + Приветственное ЛС, используемое в настоящий момент: {0} - Чтобы включить приветствия, напишите {0} + Чтобы включить приветственное ЛС, напишите {0} - Новое приветствие установлено. + Новое приветственное ЛС установлено. - Приветствия в личных сообщениях отключены. + Приветственые ЛС отключены. - Приветствия в личных сообщениях включены. + Приветственные ЛС включены. Текущее привественное сообщение: {0} @@ -560,25 +533,21 @@ Сообщение изменено в #{0} - Заглушёны - PLURAL (users have been muted) -Fuzzy + Заглушены + PLURAL (users have been muted) Заглушён - singular "User muted." -Fuzzy + singular "User muted." Скорее всего, у меня нет необходимых прав. - Новая немая роль установлена. - Fuzzy + Новая роль заглушения установлена. Мне нужно право **Администратор**, чтобы это сделать. - Fuzzy Новое сообщение @@ -793,7 +762,7 @@ Fuzzy Отключено заглушение. - Вкл. звук + Вернут звук singular Fuzzy @@ -810,12 +779,10 @@ Fuzzy Пользователь заблокирован - {0} получил **запрет** на разговор в чате. - Fuzzy + {0} получил **запрет** на разговор в текстовых каналах. - {0} потерял **запрет** на разговор в чате. - Fuzzy + {0} получил **разрешение** на разговор в текстовых каналах. Пользователь присоединился @@ -824,8 +791,7 @@ Fuzzy Пользователь вышел - {0} получил **запрет** на разговор в текстовом и голосовом чатах. - Fuzzy + {0} получил **запрет** на разговор в текстовых и голосовых каналах Добавлена роль пользователя @@ -837,8 +803,7 @@ Fuzzy {0} теперь {1} - {0} потерял **запрет** на разговор в текстовом и голосовом чатах. - Fuzzy + {0} получил **разрешение** на разговор в текстовых и голосовых каналах. {0} присоединился к голосовому каналу {1}. @@ -851,11 +816,9 @@ Fuzzy **Выключен микрофон** у {0}. - Fuzzy **Включён микрофон** у {0}. - Fuzzy Голосовой канал создан @@ -1128,7 +1091,7 @@ Paypal <{1}> Смены чувств - В браке + Является мужем Fuzzy @@ -1383,7 +1346,6 @@ Paypal <{1}> справедливое воспроизведение - Fuzzy Песня завершилась. From bef5549f1198281d2413220c59f9613af6a52d4b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 1 Mar 2017 21:38:05 +0100 Subject: [PATCH 398/746] Commented out unfinished languages from the list of supported ones --- .../Modules/Administration/Commands/LocalizationCommands.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 135a1da7..5707429b 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -22,10 +22,10 @@ namespace NadekoBot.Modules.Administration {"fr-FR", "French, France"}, {"ru-RU", "Russian, Russia"}, {"de-DE", "German, Germany"}, - {"nl-NL", "Dutch, Netherlands"}, - {"ja-JP", "Japanese, Japan"}, + //{"nl-NL", "Dutch, Netherlands"}, + //{"ja-JP", "Japanese, Japan"}, {"pt-BR", "Portuguese, Brazil"}, - {"sr-Cyrl-RS", "Serbian, Serbia - Cyrillic"} + //{"sr-Cyrl-RS", "Serbian, Serbia - Cyrillic"} }.ToImmutableDictionary(); [NadekoCommand, Usage, Description, Aliases] From ccef094388335e680eff64911560b1dc069614ee Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 1 Mar 2017 21:42:20 +0100 Subject: [PATCH 399/746] Fixed smp string --- src/NadekoBot/Modules/Music/Music.cs | 2 +- src/NadekoBot/Modules/NadekoModule.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 79dd3d42..eb4cbbdf 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -592,7 +592,7 @@ namespace NadekoBot.Modules.Music if (seconds == 0) await ReplyConfirmLocalized("max_playtime_none").ConfigureAwait(false); else - await ReplyConfirmLocalized("max_playtime_set").ConfigureAwait(false); + await ReplyConfirmLocalized("max_playtime_set", seconds).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index ea4a0049..d71a2ba9 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -69,7 +69,7 @@ namespace NadekoBot.Modules LogManager.GetCurrentClassLogger().Warn(lowerModuleTypeName + "_" + key + " key is missing from " + cultureInfo + " response strings. PLEASE REPORT THIS."); text = NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, _usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} not found!"; if (string.IsNullOrWhiteSpace(text)) - return "I cant tell if you command is executed, because there was an error printing out the response. Key '" + + return "I can't tell you is the command executed, because there was an error printing out the response. Key '" + lowerModuleTypeName + "_" + key + "' " + "is missing from resources. Please report this."; } return text; From f53c68e11372af2d4c71cd55028dfbad00d1628a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Wed, 1 Mar 2017 22:06:37 +0100 Subject: [PATCH 400/746] version upped to 1.2 --- .../Resources/ResponseStrings.fr-fr.resx | 44 +++++++++---------- src/NadekoBot/Services/Impl/StatsService.cs | 2 +- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx index 1c802a95..ac95afb6 100644 --- a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx +++ b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx @@ -628,7 +628,7 @@ Raison : {1} Erreur due à un manque de permissions ou à une couleur invalide. - L'utilisateur {1} n'a plus le rôle {0}. + L'utilisateur {1} n'appartient plus au rôle {0}. Impossible de supprimer ce rôle. Je ne possède pas les permissions suffisantes. @@ -705,7 +705,7 @@ Raison : {1} Vous avez désormais le rôle {0}. - L'utilisateur {1} a désormais le rôle {0}. + L'ajout du rôle {0} pour l'utilisateur {1} a été réalisé avec succès. Impossible d'ajouter un rôle. Je ne possède pas les permissions suffisantes. @@ -727,7 +727,7 @@ Raison : {1} Nouveau sujet du salon défini. - Shard {0} reconnecté. + Shard {0} reconnectée. Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. @@ -758,13 +758,13 @@ Raison : {1} Si un utilisateur poste {0} le même message à la suite, je le {1}. - __SalonsIgnorés__: {2} + __SalonsIgnorés__: {2} Salon textuel crée. - Salon textuel supprimé. + Salon textuel détruit. Son activé avec succès. @@ -774,7 +774,7 @@ Raison : {1} singular - Nom d'utilisateur + Nom d'utilisateur. Nom d'utilisateur modifié. @@ -798,7 +798,7 @@ Raison : {1} L'utilisateur a quitté - {0} est maintenant **muet** à la fois sur les salons textuels et vocaux. + {0} est maintenant **muet** à la fois sur le salon textuel et vocal. Rôle ajouté à l'utilisateur @@ -819,7 +819,7 @@ Raison : {1} {0} a quitté le salon vocal {1}. - {0} est allé du salon vocal {1} à {2}. + {0} est allé du salon vocal {1} au {2}. {0} est maintenant **muet**. @@ -831,7 +831,7 @@ Raison : {1} Salon vocal crée. - Salon vocal supprimé. + Salon vocal détruit. Fonctionnalités vocales et textuelles désactivées. @@ -843,10 +843,10 @@ Raison : {1} Je n'ai pas la permission **Gérer les rôles** et/ou **Gérer les salons**, je ne peux donc pas utiliser `voice+text` sur le serveur {0}. - Vous activez/désactivez cette fonctionnalité et **je n'ai pas la permission ADMINISTRATEUR**. Cela pourrait causer des dysfonctionnements, et vous devrez nettoyer les salons textuels vous-même après ça. + Vous activez/désactivez cette fonctionnalité et **je n'ai pas les permissions ADMINISTRATEURS**. Cela pourrait causer des dysfonctionnements, et vous devrez nettoyer les salons textuels vous-même après ça. - Je nécessite au moins les permissions **Gérer les rôles** et **Gérer les salons** pour activer cette fonctionnalité. (Permission Administrateur de préférence) + Je nécessite au moins les permissions **Gérer les rôles** et **Gérer les salons** pour activer cette fonctionnalité. (permissions administateurs préférées) Utilisateur {0} depuis un salon textuel. @@ -880,11 +880,10 @@ Raison: {1} a récompensé {0} à {1} - Plus de chance la prochaine fois ^_^ - C'est vraiment québecois ca.. On ne le dit pas comme ca ici xD + Meilleure chance la prochaine fois ^_^ - Félicitations! Vous avez gagné {0} pour avoir lancé au dessus de {1}. + Félicitations! Vous avez gagné {0} pour avoir lancé au dessus de {1} Deck remélangé. @@ -894,7 +893,7 @@ Raison: {1} User flipped tails. - Vous avez deviné! Vous avez gagné {0} + Vous l'avez deviné! Vous avez gagné {0} Nombre spécifié invalide. Vous pouvez lancer 1 à {0} pièces. @@ -1339,7 +1338,7 @@ La nouvelle valeur de {0} est {1} ! {0} contre {1} - Tentative d'ajouter {0} musiques à la file d'attente... + Tentative d'ajouter {0} à la file d'attente... Lecture automatique désactivée. @@ -1348,7 +1347,7 @@ La nouvelle valeur de {0} est {1} ! Lecture automatique activée. - Volume par défaut défini à {0}% + Volume de base défini à {0}% File d'attente complète. @@ -1375,10 +1374,10 @@ La nouvelle valeur de {0} est {1} ! Entrée invalide. - Le temps maximum de lecture est désormais illimité. + Le temps maximum de lecture n'a désormais plus de limite. - Temps maximum de lecture défini à {0} seconde(s). + Le temps de lecture maximum a été mis à {0} seconde(s). La taille de la file d'attente est désormais illmitée. @@ -1438,7 +1437,7 @@ La nouvelle valeur de {0} est {1} ! Liste d'attente - Musique ajoutée à la file d'attente + Son ajouté à la file d'attente Liste d'attente effacée. @@ -1447,7 +1446,7 @@ La nouvelle valeur de {0} est {1} ! Liste d'attente complète ({0}/{0}). - Musique retirée + Son retiré context: "removed song #5" @@ -1666,6 +1665,7 @@ La nouvelle valeur de {0} est {1} ! Votre langue de traduction a été changée de {0} à {1} + Fuzzy Traduction automatique des messages commencée sur ce salon. @@ -2145,7 +2145,7 @@ OwnerID: {2} Page #{0} des rôles pour {1} - Aucune couleur n'est dans le bon format. Utilisez `#00ff00` par exemple. + Aucunes couleurs ne sont dans le format correct. Utilisez `#00ff00` par exemple. Couleurs alternées pour le rôle {0} activées. diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index f3058f97..0390cbda 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -16,7 +16,7 @@ namespace NadekoBot.Services.Impl private readonly DiscordShardedClient _client; private readonly DateTime _started; - public const string BotVersion = "1.2-beta"; + public const string BotVersion = "1.2"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From 011b951a29d7a1754ad8e058bc2c092c78c281e3 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Thu, 2 Mar 2017 03:29:27 -0500 Subject: [PATCH 401/746] Update QuoteRepository.cs --- .../Services/Database/Repositories/Impl/QuoteRepository.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs index 898f0efd..3de5853c 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs @@ -26,7 +26,8 @@ namespace NadekoBot.Services.Database.Repositories.Impl public Task SearchQuoteKeywordTextAsync(ulong guildId, string keyword, string text) { var rngk = new NadekoRandom(); - return _set.Where(q => q.Text.Contains(text) && q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); + lowertext = text.toLowerInvariant(); + return _set.Where(q => q.Text.Contains(text) || q.Text.Contains(lowertext) && q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); } } } From 9344c1b498462dc9378a879df9617bcae16e12ac Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Thu, 2 Mar 2017 03:41:33 -0500 Subject: [PATCH 402/746] Support for embeds in .qsearch output - Support for embeds in .qsearch output results - Search can be case insensitive (changes made 011b951a29d7a1754ad8e058bc2c092c78c281e3) - Output shows keyword in lowercase as it's easier to read (line 104) - Minor syntax cleanups --- .../Modules/Utility/Commands/QuoteCommands.cs | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index 5a7fc983..2b5a927d 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -72,8 +72,8 @@ namespace NadekoBot.Modules.Utility await Context.Channel.SendMessageAsync("📣 " + quote.Text.SanitizeMentions()); } - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] public async Task SearchQuote(string keyword, [Remainder] string text) { if (string.IsNullOrWhiteSpace(keyword) || string.IsNullOrWhiteSpace(text)) @@ -83,14 +83,25 @@ namespace NadekoBot.Modules.Utility Quote keywordquote; using (var uow = DbHandler.UnitOfWork()) - { + { keywordquote = await uow.Quotes.SearchQuoteKeywordTextAsync(Context.Guild.Id, keyword, text).ConfigureAwait(false); - } + } if (keywordquote == null) return; - - await Context.Channel.SendMessageAsync("💬 " + keyword + ": " + keywordquote.Text.SanitizeMentions()); + + CREmbed crembed; + if (CREmbed.TryParse(keywordquote.Text, out crembed)) + { + try { await Context.Channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "").ConfigureAwait(false); } + catch (Exception ex) + { + _log.Warn("Sending CREmbed failed"); + _log.Warn(ex); + } + return; + } + await Context.Channel.SendMessageAsync("💬 " + keyword.toLowerInvariant(); + ": " + keywordquote.Text.SanitizeMentions()); } [NadekoCommand, Usage, Description, Aliases] From e2f855a72904c299ff48dc565bdb5d66bf45b364 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Thu, 2 Mar 2017 03:46:10 -0500 Subject: [PATCH 403/746] Support for embeds in .qsearch output + case - Support for embeds in .qsearch output results - Search can be case insensitive (changes made 011b951a29d7a1754ad8e058bc2c092c78c281e3) - Output shows keyword in lowercase as it's easier to read (line 104) - Minor syntax cleanups --- src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index 2b5a927d..654f6853 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -101,7 +101,7 @@ namespace NadekoBot.Modules.Utility } return; } - await Context.Channel.SendMessageAsync("💬 " + keyword.toLowerInvariant(); + ": " + keywordquote.Text.SanitizeMentions()); + await Context.Channel.SendMessageAsync("💬 " + keyword.toLowerInvariant() + ": " + keywordquote.Text.SanitizeMentions()); } [NadekoCommand, Usage, Description, Aliases] From b3080f193fe48312c84f245fce669838fa83f4c0 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Thu, 2 Mar 2017 03:49:34 -0500 Subject: [PATCH 404/746] Update QuoteRepository.cs --- .../Services/Database/Repositories/Impl/QuoteRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs index 3de5853c..fe41b6d2 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs @@ -26,7 +26,7 @@ namespace NadekoBot.Services.Database.Repositories.Impl public Task SearchQuoteKeywordTextAsync(ulong guildId, string keyword, string text) { var rngk = new NadekoRandom(); - lowertext = text.toLowerInvariant(); + lowertext = text.ToLowerInvariant(); return _set.Where(q => q.Text.Contains(text) || q.Text.Contains(lowertext) && q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); } } From 6773d1e86d17feccb78244c5f2d29fd0a18afde8 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Thu, 2 Mar 2017 03:49:53 -0500 Subject: [PATCH 405/746] See 9344c1b498462dc9378a879df9617bcae16e12ac --- src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index 654f6853..e0445e0c 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -101,7 +101,7 @@ namespace NadekoBot.Modules.Utility } return; } - await Context.Channel.SendMessageAsync("💬 " + keyword.toLowerInvariant() + ": " + keywordquote.Text.SanitizeMentions()); + await Context.Channel.SendMessageAsync("💬 " + keyword.ToLowerInvariant() + ": " + keywordquote.Text.SanitizeMentions()); } [NadekoCommand, Usage, Description, Aliases] From 72de465c34ea710b383c5d959397a50b1c6ee5ac Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Thu, 2 Mar 2017 03:57:39 -0500 Subject: [PATCH 406/746] Update QuoteRepository.cs handle all standard cases (matches text that contains the exact, upper, or lowercase forms of the input text to search) --- .../Services/Database/Repositories/Impl/QuoteRepository.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs index fe41b6d2..fff61d22 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs @@ -27,7 +27,8 @@ namespace NadekoBot.Services.Database.Repositories.Impl { var rngk = new NadekoRandom(); lowertext = text.ToLowerInvariant(); - return _set.Where(q => q.Text.Contains(text) || q.Text.Contains(lowertext) && q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); + uppertext = text.ToUpperInvariant(); + return _set.Where(q => q.Text.Contains(text) || q.Text.Contains(lowertext) || q.Text.Contains(uppertext) && q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); } } } From 0a55c6f09c05b0f152684b4d33368a3572b0b0ed Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Thu, 2 Mar 2017 04:09:12 -0500 Subject: [PATCH 407/746] Update QuoteRepository.cs syntax cleanup --- .../Services/Database/Repositories/Impl/QuoteRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs index fff61d22..26639165 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs @@ -28,7 +28,7 @@ namespace NadekoBot.Services.Database.Repositories.Impl var rngk = new NadekoRandom(); lowertext = text.ToLowerInvariant(); uppertext = text.ToUpperInvariant(); - return _set.Where(q => q.Text.Contains(text) || q.Text.Contains(lowertext) || q.Text.Contains(uppertext) && q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); + return _set.Where(q => q.GuildId == guildId && q.Keyword == keyword && (q.Text.Contains(text) || q.Text.Contains(lowertext) || q.Text.Contains(uppertext))).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); } } } From 97b314d61155e5dfa192f1cbf639638a8a112e70 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Thu, 2 Mar 2017 04:44:49 -0500 Subject: [PATCH 408/746] Update QuoteRepository.cs whoops xD --- .../Services/Database/Repositories/Impl/QuoteRepository.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs index 26639165..591c3dde 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs @@ -26,8 +26,8 @@ namespace NadekoBot.Services.Database.Repositories.Impl public Task SearchQuoteKeywordTextAsync(ulong guildId, string keyword, string text) { var rngk = new NadekoRandom(); - lowertext = text.ToLowerInvariant(); - uppertext = text.ToUpperInvariant(); + string lowertext = text.ToLowerInvariant(); + string uppertext = text.ToUpperInvariant(); return _set.Where(q => q.GuildId == guildId && q.Keyword == keyword && (q.Text.Contains(text) || q.Text.Contains(lowertext) || q.Text.Contains(uppertext))).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); } } From 63823d10bf66ba48310b67e738d4b6ad167d6ec3 Mon Sep 17 00:00:00 2001 From: samvaio Date: Thu, 2 Mar 2017 15:17:15 +0530 Subject: [PATCH 409/746] music playlist and weather fixes --- src/NadekoBot/Modules/Music/Music.cs | 8 +++----- src/NadekoBot/Modules/Searches/Searches.cs | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index eb4cbbdf..50ed4089 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -347,10 +347,8 @@ namespace NadekoBot.Modules.Music return; } var count = ids.Count(); - - var msg = await Context.Channel.SendMessageAsync(GetText("attempting_to_queue", - Format.Bold(count.ToString()))) - .ConfigureAwait(false); + var msg = await Context.Channel.SendMessageAsync("🎵 " + GetText("attempting_to_queue", + Format.Bold(count.ToString()))).ConfigureAwait(false); var cancelSource = new CancellationTokenSource(); @@ -374,7 +372,7 @@ namespace NadekoBot.Modules.Music ids = ids.Skip(5); } - await msg.ModifyAsync(m => m.Content = GetText("playlist_queue_complete")).ConfigureAwait(false); + await msg.ModifyAsync(m => m.Content = "✅ " + Format.Bold(GetText("playlist_queue_complete"))).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 7ed4dae9..72969f49 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -41,17 +41,17 @@ namespace NadekoBot.Modules.Searches var data = JsonConvert.DeserializeObject(response); var embed = new EmbedBuilder() - .AddField(fb => fb.WithName("🌍 " + GetText("location")).WithValue(data.name + ", " + data.sys.country).WithIsInline(true)) - .AddField(fb => fb.WithName("📏 " + GetText("latlong")).WithValue($"{data.coord.lat}, {data.coord.lon}").WithIsInline(true)) - .AddField(fb => fb.WithName("☁ " + GetText("condition")).WithValue(string.Join(", ", data.weather.Select(w => w.main))).WithIsInline(true)) - .AddField(fb => fb.WithName("😓 " + GetText("humidity")).WithValue($"{data.main.humidity}%").WithIsInline(true)) - .AddField(fb => fb.WithName("💨 " + GetText("wind_speed")).WithValue(data.wind.speed + " km/h").WithIsInline(true)) - .AddField(fb => fb.WithName("🌡 " + GetText("temperature")).WithValue(data.main.temp + "°C").WithIsInline(true)) - .AddField(fb => fb.WithName("🔆 " + GetText("min_max")).WithValue($"{data.main.temp_min}°C - {data.main.temp_max}°C").WithIsInline(true)) - .AddField(fb => fb.WithName("🌄 " + GetText("sunrise")).WithValue($"{data.sys.sunrise.ToUnixTimestamp():HH:mm}").WithIsInline(true)) - .AddField(fb => fb.WithName("🌇 " + GetText("sunset")).WithValue($"{data.sys.sunset.ToUnixTimestamp():HH:mm}").WithIsInline(true)) + .AddField(fb => fb.WithName("🌍 " + Format.Bold(GetText("location"))).WithValue($"[{data.name + ", " + data.sys.country}](https://openweathermap.org/city/{data.id})").WithIsInline(true)) + .AddField(fb => fb.WithName("📏 " + Format.Bold(GetText("latlong"))).WithValue($"{data.coord.lat}, {data.coord.lon}").WithIsInline(true)) + .AddField(fb => fb.WithName("☁ " + Format.Bold(GetText("condition"))).WithValue(string.Join(", ", data.weather.Select(w => w.main))).WithIsInline(true)) + .AddField(fb => fb.WithName("😓 " + Format.Bold(GetText("humidity"))).WithValue($"{data.main.humidity}%").WithIsInline(true)) + .AddField(fb => fb.WithName("💨 " + Format.Bold(GetText("wind_speed"))).WithValue(data.wind.speed + " m/s").WithIsInline(true)) + .AddField(fb => fb.WithName("🌡 " + Format.Bold(GetText("temperature"))).WithValue(data.main.temp + "°C").WithIsInline(true)) + .AddField(fb => fb.WithName("🔆 " + Format.Bold(GetText("min_max"))).WithValue($"{data.main.temp_min}°C - {data.main.temp_max}°C").WithIsInline(true)) + .AddField(fb => fb.WithName("🌄 " + Format.Bold(GetText("sunrise"))).WithValue($"{data.sys.sunrise.ToUnixTimestamp():HH:mm} UTC").WithIsInline(true)) + .AddField(fb => fb.WithName("🌇 " + Format.Bold(GetText("sunset"))).WithValue($"{data.sys.sunset.ToUnixTimestamp():HH:mm} UTC").WithIsInline(true)) .WithOkColor() - .WithFooter(efb => efb.WithText("Powered by http://openweathermap.org")); + .WithFooter(efb => efb.WithText("Powered by openweathermap.org").WithIconUrl($"http://openweathermap.org/img/w/{string.Join(", ", data.weather.Select(w => w.icon))}.png")); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } From 1418297958047ecd6b5a821dfecab8f22a2767ca Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Thu, 2 Mar 2017 05:20:12 -0500 Subject: [PATCH 410/746] Update QuoteRepository.cs --- .../Services/Database/Repositories/Impl/QuoteRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs index 591c3dde..be9db36d 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs @@ -28,7 +28,7 @@ namespace NadekoBot.Services.Database.Repositories.Impl var rngk = new NadekoRandom(); string lowertext = text.ToLowerInvariant(); string uppertext = text.ToUpperInvariant(); - return _set.Where(q => q.GuildId == guildId && q.Keyword == keyword && (q.Text.Contains(text) || q.Text.Contains(lowertext) || q.Text.Contains(uppertext))).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); + return _set.Where(q => (q.Text.Contains(text) | q.Text.Contains(lowertext) | q.Text.Contains(uppertext)) & (q.GuildId == guildId && q.Keyword == keyword)).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); } } } From c77048769d0775b868ac11b85982998cc3c9857b Mon Sep 17 00:00:00 2001 From: Rajath Ranganath Date: Thu, 2 Mar 2017 17:03:23 +0530 Subject: [PATCH 411/746] Fixed a crap ton of command help messages Added extra markdown too. Command help looks bootiful now :3 --- src/NadekoBot/Resources/CommandStrings.resx | 142 ++++++++++---------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 662975cf..98cc7345 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -124,7 +124,7 @@ Either shows a help for a single command, or DMs you help link if no arguments are specified. - `{0}h !!q` or `{0}h` + `{0}h -cmds` or `{0}h` hgit @@ -157,7 +157,7 @@ commands cmds - List all of the bot's commands from a certain module. You can either specify full, or only first few letters of the module name. + List all of the bot's commands from a certain module. You can either specify the full name or only the first few letters of the module name. `{0}commands Administration` or `{0}cmds Admin` @@ -166,7 +166,7 @@ greetdel grdel - Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set 0 to disable automatic deletion. + Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to 0 to disable automatic deletion. `{0}greetdel 0` or `{0}greetdel 30` @@ -184,7 +184,7 @@ greetmsg - Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. + Sets a new join announcement message which will be shown in the server's channel. Type `%user%` if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. `{0}greetmsg Welcome, %user%.` @@ -202,7 +202,7 @@ byemsg - Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. + Sets a new leave announcement message. Type `%user%` if you want to show the name the user who left. Type `%id%` to show id. Using this command with no message will show the current bye message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. `{0}byemsg %user% has left.` @@ -211,7 +211,7 @@ byedel - Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set 0 to disable automatic deletion. + Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion. `{0}byedel 0` or `{0}byedel 30` @@ -238,7 +238,7 @@ logignore - Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. + Toggles whether the `.logserver` command ignores this channel. Useful if you have hidden admin channel and public log channel. `{0}logignore` @@ -274,7 +274,7 @@ repeat - Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. + Repeat a message every `X` minutes in the current channel. You can have up to 5 repeating messages on the server in total. `{0}repeat 5 Hello there` @@ -292,7 +292,7 @@ addplaying adpl - Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %time%,%shardid%,%shardcount%, %shardguilds% + Adds a specified string to the list of playing strings to rotate. Supported placeholders: `%servers%`, `%users%`, `%playing%`, `%queued%`, `%time%`, `%shardid%`, `%shardcount%`, `%shardguilds%`. `{0}adpl` @@ -337,7 +337,7 @@ voice+text v+t - Creates a text channel for each voice channel only users in that voice channel can see.If you are server owner, keep in mind you will see them all the time regardless. + Creates a text channel for each voice channel only users in that voice channel can see. If you are server owner, keep in mind you will see them all the time regardless. `{0}v+t` @@ -364,7 +364,7 @@ lcsc - Leaves Cross server channel instance from this channel. + Leaves a cross server channel instance from this channel. `{0}lcsc` @@ -427,7 +427,7 @@ addcustreact acr - Add a custom reaction with a trigger and a response. Running this command in server requires Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: <http://nadekobot.readthedocs.io/en/latest/Custom%20Reactions/> + Add a custom reaction with a trigger and a response. Running this command in server requires the Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: <http://nadekobot.readthedocs.io/en/latest/Custom%20Reactions/> `{0}acr "hello" Hi there %user%` @@ -463,7 +463,7 @@ delcustreact dcr - Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration priviledges and removes server custom reaction. + Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration privileges and removes server custom reaction. `{0}dcr 5` @@ -481,7 +481,7 @@ leave - Makes Nadeko leave the server. Either name or id required. + Makes Nadeko leave the server. Either server name or server ID is required. `{0}leave 123123123331` @@ -490,7 +490,7 @@ delmsgoncmd - Toggles the automatic deletion of user's successful command message to prevent chat flood. + Toggles the automatic deletion of the user's successful command message to prevent chat flood. `{0}delmsgoncmd` @@ -526,7 +526,7 @@ renamerole renr - Renames a role. Roles you are renaming must be lower than bot's highest role. + Renames a role. The role you are renaming must be lower than bot's highest role. `{0}renr "First role" SecondRole` @@ -679,7 +679,7 @@ prune clr - `{0}prune` removes all nadeko's messages in the last 100 messages.`{0}prune X` removes last X messages from the channel (up to 100)`{0}prune @Someone` removes all Someone's messages in the last 100 messages.`{0}prune @Someone X` removes last X 'Someone's' messages in the channel. + `{0}prune` removes all Nadeko's messages in the last 100 messages. `{0}prune X` removes last `X` number of messages from the channel (up to 100). `{0}prune @Someone` removes all Someone's messages in the last 100 messages. `{0}prune @Someone X` removes last `X` number of 'Someone's' messages in the channel. `{0}prune` or `{0}prune 5` or `{0}prune @Someone` or `{0}prune @Someone X` @@ -724,7 +724,7 @@ send - Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prepend channel id with `c:` and user id with `u:`. + Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prefix the channel id with `c:` and the user id with `u:`. `{0}send serverid|c:channelid message` or `{0}send serverid|u:userid message` @@ -733,7 +733,7 @@ mentionrole menro - Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. + Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have the mention everyone permission. `{0}menro RoleName` @@ -751,7 +751,7 @@ donators - List of lovely people who donated to keep this project alive. + List of the lovely people who donated to keep this project alive. `{0}donators` @@ -769,7 +769,7 @@ announce - Sends a message to all servers' general channel bot is connected to. + Sends a message to all servers' default channel that bot is connected to. `{0}announce Useless spam` @@ -787,7 +787,7 @@ remind - Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message. + Sends a message to you or a channel after certain amount of time. First argument is `me`/`here`/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword) message. `{0}remind me 1d5h Do something` or `{0}remind #general 1m Start now!` @@ -796,7 +796,7 @@ remindtemplate - Sets message for when the remind is triggered. Available placeholders are %user% - user who ran the command, %message% - Message specified in the remind, %target% - target channel of the remind. + Sets message for when the remind is triggered. Available placeholders are `%user%` - user who ran the command, `%message%` - Message specified in the remind, `%target%` - target channel of the remind. `{0}remindtemplate %user%, do %message%!` @@ -895,7 +895,7 @@ roles - List roles on this server or a roles of a specific user if specified. Paginated. 20 roles per page. + List roles on this server or a roles of a specific user if specified. Paginated, 20 roles per page. `{0}roles 2` or `{0}roles @Someone` @@ -913,7 +913,7 @@ chnlfilterinv cfi - Toggles automatic deleting of invites posted in the channel. Does not negate the {0}srvrfilterinv enabled setting. Does not affect Bot Owner. + Toggles automatic deletion of invites posted in the channel. Does not negate the `{0}srvrfilterinv` enabled setting. Does not affect the Bot Owner. `{0}cfi` @@ -922,7 +922,7 @@ srvrfilterinv sfi - Toggles automatic deleting of invites posted in the server. Does not affect Bot Owner. + Toggles automatic deletion of invites posted in the server. Does not affect the Bot Owner. `{0}sfi` @@ -931,7 +931,7 @@ chnlfilterwords cfw - Toggles automatic deleting of messages containing banned words on the channel. Does not negate the {0}srvrfilterwords enabled setting. Does not affect bot owner. + Toggles automatic deletion of messages containing filtered words on the channel. Does not negate the `{0}srvrfilterwords` enabled setting. Does not affect the Bot Owner. `{0}cfw` @@ -958,7 +958,7 @@ srvrfilterwords sfw - Toggles automatic deleting of messages containing forbidden words on the server. Does not affect Bot Owner. + Toggles automatic deleting of messages containing filtered words on the server. Does not affect the Bot Owner. `{0}sfw` @@ -967,7 +967,7 @@ permrole pr - Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'. + Sets a role which can change permissions. Supply no parameters to find out the current one. Default is 'Nadeko'. `{0}pr role` @@ -1084,7 +1084,7 @@ ubl - Either [add]s or [rem]oves a user specified by a mention or ID from a blacklist. + Either [add]s or [rem]oves a user specified by a Mention or an ID from a blacklist. `{0}ubl add @SomeUser` or `{0}ubl rem 12312312313` @@ -1102,7 +1102,7 @@ sbl - Either [add]s or [rem]oves a server specified by a Name or ID from a blacklist. + Either [add]s or [rem]oves a server specified by a Name or an ID from a blacklist. `{0}sbl add 12312321312` or `{0}sbl rem SomeTrashServer` @@ -1111,7 +1111,7 @@ cmdcooldown cmdcd - Sets a cooldown per user for a command. Set to 0 to remove the cooldown. + Sets a cooldown per user for a command. Set it to 0 to remove the cooldown. `{0}cmdcd "some cmd" 5` @@ -1201,7 +1201,7 @@ 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. + 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. `{0}roll` or `{0}roll 7` or `{0}roll 3d5` or `{0}roll 5dF` @@ -1210,7 +1210,7 @@ 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. + 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`. `{0}rolluo` or `{0}rolluo 7` or `{0}rolluo 3d5` @@ -1291,7 +1291,7 @@ leaderboard lb - Displays bot currency leaderboard. + Displays the bot's currency leaderboard. `{0}lb` @@ -1300,7 +1300,7 @@ trivia t - Starts a game of trivia. You can add nohint to prevent hints.First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. + Starts a game of trivia. You can add `nohint` to prevent hints. First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. `{0}t` or `{0}t 5 nohint` @@ -1426,7 +1426,7 @@ rps - Play a game of rocket paperclip scissors with Nadeko. + Play a game of Rocket-Paperclip-Scissors with Nadeko. `{0}rps scissors` @@ -1480,7 +1480,7 @@ queue q yq - Queue a song using keywords or a link. Bot will join your voice channel.**You must be in a voice channel**. + Queue a song using keywords or a link. Bot will join your voice channel. **You must be in a voice channel**. `{0}q Dream Of Venice` @@ -1489,7 +1489,7 @@ soundcloudqueue sq - Queue a soundcloud song using keywords. Bot will join your voice channel.**You must be in a voice channel**. + Queue a soundcloud song using keywords. Bot will join your voice channel. **You must be in a voice channel**. `{0}sq Dream Of Venice` @@ -1507,7 +1507,7 @@ nowplaying np - Shows the song currently playing. + Shows the song that the bot is currently playing. `{0}np` @@ -1516,7 +1516,7 @@ volume vol - Sets the music volume 0-100% + Sets the music playback volume (0-100%) `{0}vol 50` @@ -1534,7 +1534,7 @@ max - Sets the music volume to 100%. + Sets the music playback volume to 100%. `{0}max` @@ -1543,7 +1543,7 @@ half - Sets the music volume to 50%. + Sets the music playback volume to 50%. `{0}half` @@ -1561,7 +1561,7 @@ soundcloudpl scpl - Queue a soundcloud playlist using a link. + Queue a Soundcloud playlist using a link. `{0}scpl soundcloudseturl` @@ -1660,7 +1660,7 @@ save - Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. + Saves a playlist under a certain name. Playlist name must be no longer than 20 characters and must not contain dashes. `{0}save classical1` @@ -1669,7 +1669,7 @@ load - Loads a saved playlist using it's ID. Use `{0}pls` to list all saved playlists and {0}save to save new ones. + Loads a saved playlist using its ID. Use `{0}pls` to list all saved playlists and `{0}save` to save new ones. `{0}load 5` @@ -1678,7 +1678,7 @@ playlists pls - Lists all playlists. Paginated. 20 per page. Default page is 0. + Lists all playlists. Paginated, 20 per page. Default page is 0. `{0}pls 1` @@ -1687,7 +1687,7 @@ deleteplaylist delpls - Deletes a saved playlist. Only if you made it or if you are the bot owner. + Deletes a saved playlist. Works only if you made it or if you are the bot owner. `{0}delpls animu-5` @@ -1705,7 +1705,7 @@ autoplay ap - Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty) + Toggles autoplay - When the song is finished, automatically queue a related Youtube song. (Works only for Youtube songs and when queue is empty) `{0}ap` @@ -1939,7 +1939,7 @@ image img - Pulls the first image found using a search parameter. Use {0}rimg for different results. + Pulls the first image found using a search parameter. Use `{0}rimg` for different results. `{0}img cute kitten` @@ -1966,7 +1966,7 @@ google g - Get a google search link for some terms. + Get a Google search link for some terms. `{0}google query` @@ -2029,7 +2029,7 @@ chucknorris cn - Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random> + Shows a random Chuck Norris joke from <http://tambal.azurewebsites.net/joke/random> `{0}cn` @@ -2038,7 +2038,7 @@ magicitem mi - Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items> + Shows a random magic item from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items> `{0}mi` @@ -2047,7 +2047,7 @@ revav - Returns a google reverse image search for someone's avatar. + Returns a Google reverse image search for someone's avatar. `{0}revav "@SomeGuy"` @@ -2056,7 +2056,7 @@ revimg - Returns a google reverse image search for an image from a link. + Returns a Google reverse image search for an image from a link. `{0}revimg Image link` @@ -2212,7 +2212,7 @@ Shows the active war claims by a number. Shows all wars in a short way if no number is specified. - `{0}lw [war_number] or {0}lw` + `{0}lw [war_number]` or `{0}lw` claim call c @@ -2296,7 +2296,7 @@ readme guide - Shows all available operations in {0}calc command + Shows all available operations in the `{0}calc` command `{0}calcops` @@ -2320,7 +2320,7 @@ `{0}greetdmmsg Welcome to the server, %user%`. - Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. + Sets a new join announcement message which will be sent to the user who joined. Type `%user%` if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. Check how much currency a person has. (Defaults to yourself) @@ -2350,7 +2350,7 @@ allusrmdls aum - Moves permission from one position to another in Permissions list. + Moves permission from one position to another in the Permissions list. `{0}mp 2 4` @@ -2359,7 +2359,7 @@ moveperm mp - Removes a permission from a given position in Permissions list. + Removes a permission from a given position in the Permissions list. `{0}rp 1` @@ -2416,7 +2416,7 @@ fwtoall - Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json + Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json file `{0}fwtoall` @@ -2425,7 +2425,7 @@ resetperms - Resets BOT's permissions module on this server to the default value. + Resets the bot's permissions module on this server to the default value. `{0}resetperms` @@ -2443,7 +2443,7 @@ antispam - Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10. + Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10. `{0}antispam 3 Mute` or `{0}antispam 4 Kick` or `{0}antispam 6 Ban` @@ -2488,7 +2488,7 @@ adsarm - Toggles the automatic deletion of confirmations for {0}iam and {0}iamn commands. + Toggles the automatic deletion of confirmations for `{0}iam` and `{0}iamn` commands. `{0}adsarm` @@ -2713,7 +2713,7 @@ heal - Heals someone. Revives those who fainted. Costs a NadekoFlower + Heals someone. Revives those who fainted. Costs a NadekoFlower. `{0}heal @someone` @@ -2812,7 +2812,7 @@ log - Toggles logging event. Disables it if it's active anywhere on the server. Enables if it's not active. Use `{0}logevents` to see a list of all events you can subscribe to. + Toggles logging event. Disables it if it iss active anywhere on the server. Enables if it isn't active. Use `{0}logevents` to see a list of all events you can subscribe to. `{0}log userpresence` or `{0}log userbanned` @@ -2821,7 +2821,7 @@ fairplay fp - Toggles fairplay. While enabled, music player will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue. + Toggles fairplay. While enabled, the bot will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue. `{0}fp` @@ -2938,7 +2938,7 @@ cmdcosts - Shows a list of command costs. Paginated with 9 command per page. + Shows a list of command costs. Paginated with 9 commands per page. `{0}cmdcosts` or `{0}cmdcosts 2` @@ -3037,7 +3037,7 @@ mal - Shows basic info from myanimelist profile. + Shows basic info from a MyAnimeList profile. `{0}mal straysocks` @@ -3127,7 +3127,7 @@ languageset langset - Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. + Sets this server's response language. If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. `{0}langset de-DE ` or `{0}langset default` @@ -3150,4 +3150,4 @@ `{0}rategirl @SomeGurl` - \ No newline at end of file + From aba3a5f6f3e37a68cb91891481d9a84388cc8187 Mon Sep 17 00:00:00 2001 From: Rajath Ranganath Date: Thu, 2 Mar 2017 17:08:49 +0530 Subject: [PATCH 412/746] Minor typo fix --- src/NadekoBot/Resources/CommandStrings.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 98cc7345..49bd76e8 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2812,7 +2812,7 @@ log - Toggles logging event. Disables it if it iss active anywhere on the server. Enables if it isn't active. Use `{0}logevents` to see a list of all events you can subscribe to. + Toggles logging event. Disables it if it is active anywhere on the server. Enables if it isn't active. Use `{0}logevents` to see a list of all events you can subscribe to. `{0}log userpresence` or `{0}log userbanned` From f4870c4678112638b693e59872ae936dc2989ae7 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Thu, 2 Mar 2017 11:22:07 -0500 Subject: [PATCH 413/746] Update QuoteRepository.cs --- .../Services/Database/Repositories/Impl/QuoteRepository.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs index be9db36d..a7036dff 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs @@ -1,4 +1,5 @@ -using NadekoBot.Services.Database.Models; +using NadekoBot.Services.Database.Models; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -26,9 +27,7 @@ namespace NadekoBot.Services.Database.Repositories.Impl public Task SearchQuoteKeywordTextAsync(ulong guildId, string keyword, string text) { var rngk = new NadekoRandom(); - string lowertext = text.ToLowerInvariant(); - string uppertext = text.ToUpperInvariant(); - return _set.Where(q => (q.Text.Contains(text) | q.Text.Contains(lowertext) | q.Text.Contains(uppertext)) & (q.GuildId == guildId && q.Keyword == keyword)).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); + return _set.Where(q => q.Text.IndexOf(text, StringComparison.OrdinalIgnoreCase) >=0 && q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); } } } From c7e694fc1d01fe07d9e1b0fd92b769ef1ff81678 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Thu, 2 Mar 2017 11:24:37 -0500 Subject: [PATCH 414/746] Update QuoteCommands.cs --- .../Modules/Utility/Commands/QuoteCommands.cs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index e0445e0c..d811f565 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -89,18 +89,7 @@ namespace NadekoBot.Modules.Utility if (keywordquote == null) return; - - CREmbed crembed; - if (CREmbed.TryParse(keywordquote.Text, out crembed)) - { - try { await Context.Channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "").ConfigureAwait(false); } - catch (Exception ex) - { - _log.Warn("Sending CREmbed failed"); - _log.Warn(ex); - } - return; - } + await Context.Channel.SendMessageAsync("💬 " + keyword.ToLowerInvariant() + ": " + keywordquote.Text.SanitizeMentions()); } From 33faec9649ad47f64ea47af55925e8e3f85006d3 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Thu, 2 Mar 2017 17:21:03 -0500 Subject: [PATCH 415/746] ContainsNoCase Extension for Contains() used extensively, here as `ContainsNoCase` for indexOf() with StringComparison type options: CurrentCulture, CurrentCultureIgnoreCase, InvariantCulture, InvariantCultureIgnoreCase, Ordinal, OrdinalIgnoreCase The extension here implements the String.IndexOf Method (String,StringComparison) method: https://msdn.microsoft.com/en-us/library/ms224425(v=vs.110).aspx Allows clean access to this method as `ContainsNoCase(string, StringComparison.TYPE)` --- src/NadekoBot/_Extensions/Extensions.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index 8dbdf02b..f95e6fbb 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -278,6 +278,15 @@ namespace NadekoBot.Extensions return list; } } + + /// + /// Easy use of fast, efficient case-insensitive Contains check with StringComparison Member Types + /// CurrentCulture, CurrentCultureIgnoreCase, InvariantCulture, InvariantCultureIgnoreCase, Ordinal, OrdinalIgnoreCase + /// + public static bool ContainsNoCase(this string str, string contains, StringComparison compare) + { + return str.IndexOf(contains, compare) >= 0; + } public static string TrimTo(this string str, int maxLength, bool hideDots = false) { @@ -436,4 +445,4 @@ namespace NadekoBot.Extensions : usr.AvatarUrl; } } -} \ No newline at end of file +} From f023251170fd98f683433993165643b9bae6884e Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Thu, 2 Mar 2017 17:26:40 -0500 Subject: [PATCH 416/746] Update QuoteRepository.cs updated with syntax from added extensions --- .../Services/Database/Repositories/Impl/QuoteRepository.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs index a7036dff..c2963c2b 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/QuoteRepository.cs @@ -1,4 +1,5 @@ using NadekoBot.Services.Database.Models; +using NadekoBot.Extensions; using System; using System.Collections.Generic; using System.Linq; @@ -27,7 +28,7 @@ namespace NadekoBot.Services.Database.Repositories.Impl public Task SearchQuoteKeywordTextAsync(ulong guildId, string keyword, string text) { var rngk = new NadekoRandom(); - return _set.Where(q => q.Text.IndexOf(text, StringComparison.OrdinalIgnoreCase) >=0 && q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); + return _set.Where(q => q.Text.ContainsNoCase(text, StringComparison.OrdinalIgnoreCase) && q.GuildId == guildId && q.Keyword == keyword).OrderBy(q => rngk.Next()).FirstOrDefaultAsync(); } } } From 2b35d1c6556a304b8bc07494fda8d9c6639fe394 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 3 Mar 2017 02:06:20 +0100 Subject: [PATCH 417/746] fixed names for jap and nl translations --- ....ja-JP.resx => ResponseStrings.ja-JP.resx} | 234 +++++++++--------- ....nl-NL.resx => ResponseStrings.nl-NL.resx} | 234 +++++++++--------- 2 files changed, 234 insertions(+), 234 deletions(-) rename src/NadekoBot/Resources/{CommandStrings.ja-JP.resx => ResponseStrings.ja-JP.resx} (99%) rename src/NadekoBot/Resources/{CommandStrings.nl-NL.resx => ResponseStrings.nl-NL.resx} (99%) diff --git a/src/NadekoBot/Resources/CommandStrings.ja-JP.resx b/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx similarity index 99% rename from src/NadekoBot/Resources/CommandStrings.ja-JP.resx rename to src/NadekoBot/Resources/ResponseStrings.ja-JP.resx index 76de6cb2..29a0675a 100644 --- a/src/NadekoBot/Resources/CommandStrings.ja-JP.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 その基盤はすでに主張されている。または破壊されました。 diff --git a/src/NadekoBot/Resources/CommandStrings.nl-NL.resx b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx similarity index 99% rename from src/NadekoBot/Resources/CommandStrings.nl-NL.resx rename to src/NadekoBot/Resources/ResponseStrings.nl-NL.resx index d3b70713..f70710fa 100644 --- a/src/NadekoBot/Resources/CommandStrings.nl-NL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Die basis is al veroverd of vernietigd. From ebe662594b1bb3e2f62df37de77333a5c14219f1 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 3 Mar 2017 02:11:21 +0100 Subject: [PATCH 418/746] .langli no longer requires bot ownership --- .../Modules/Administration/Commands/LocalizationCommands.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 5707429b..45dedc1d 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -97,7 +97,6 @@ namespace NadekoBot.Modules.Administration } [NadekoCommand, Usage, Description, Aliases] - [OwnerOnly] public async Task LanguagesList() { await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() From 6390da46143cc867f5ef41a62e3ca4b4d8e72f03 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 3 Mar 2017 02:26:20 +0100 Subject: [PATCH 419/746] Update ResponseStrings.nl-NL.resx (POEditor.com) --- .../Resources/ResponseStrings.nl-NL.resx | 458 +++++++++--------- 1 file changed, 232 insertions(+), 226 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx index f70710fa..b8945702 100644 --- a/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Die basis is al veroverd of vernietigd. @@ -127,7 +127,7 @@ Die basis is nog niet veroverd. - **VERNIETIGD**basis #{0} in een oorlog tegen {1} + **VERNIETIGD** basis #{0} in een oorlog tegen {1} {0} heeft **ONOVERWONNEN** basis #{1} in een oorlog tegen {2} @@ -136,7 +136,7 @@ {0} heeft basis #{1} overwonnen in een oorlog tegen {2} - @{0} Jij hebt al een basis overwonnen #{1}. Je kunt niet nog een nemen. + @{0} Je hebt al basis #{1} overwonnen. Je kunt er niet nog een nemen. De aanvraag van @{0} voor een oorlog tegen {1} is niet meer geldig. @@ -145,7 +145,7 @@ Vijand - Informatie over oorlog tegen {0} + Informatie over de oorlog tegen {0} Ongeldige basis nummer @@ -163,7 +163,7 @@ Jij doet niet mee aan die oorlog. - @{0} Jij doet niet mee aan die oorlog, or die basis is al vernietigd. + @{0} Je doet niet mee aan die oorlog, of die basis is al vernietigd. Geen voorlopende oorlogen. @@ -420,7 +420,7 @@ Momenteen is het privé groet bericht: {0} - Schakel DM begroetings bericht in door {0} in te typen. + Schakel DM begroetings bericht in door {0} in te typen Nieuwe DM begroetings bericht vastgesteld. @@ -429,7 +429,7 @@ DM begroetings aankondiging uitgeschakeld. - DM begroetings aankondiging ingeschakeld. + DM begroetingen aankondiging ingeschakeld. Momentele begroetings bericht: {0} @@ -459,81 +459,81 @@ Ongeldige parameters. - {0} heeft {1} toegetreden. + {0} heeft {1} toegetreden Je bent weggeschopt van de {0} server. Reden: {1} - Gebruiker weggeschopt. + Gebruiker weggeschopt Lijst van talen {0} - Jouw server's plaats van handeling is nu {0} - {1} + Jouw server's locale is nu {0} - {1} - Bot's standaard plaats van handeling is nu {0} - {1} + Bot's standaard locale is nu {0} - {1} - Bot's taal is vastgesteld van {0} - {1} + Taal van de bot is gezet naar {0} - {1} - + Instellen van locale mislukt. Ga naar de hulp voor dit commando. - deze server taal is gezet naar: + De taal van de server is gezet naar {0} - {1} - heeft verlaten + {0} heeft {1} verlaten - Heeft de server verlaten + Server {0} verlaten - + Gebeurtenis {0} wordt bijgehouden in dit kanaal. - + Alle gebeurtenissen worden bijgehouden in dit kanaal. - Logging uitgeschakeld + Logging uitgeschakeld. - + Log gebeurtenissen waar je op kan abonneren: - + Logging zal {0} negeren - + Logging zal {0} niet negeren - + Gestopt met het loggen van {0}. - + {0} heeft een melding geplaatst op de volgende rollen - + Bericht van {0} `[Bot Eigenaar]`: - Bericht verstuurd + Bericht verstuurd. - verplaats van ... naar ... + {0} verplaats van {1} naar {2} - bericht verwijdert in + Bericht in #{0} verwijdert - bericht bijgewerkt in + Bericht in #{0} bijgewerkt - gemute + Gebruikers zijn gedempt PLURAL (users have been muted) @@ -541,13 +541,13 @@ Reden: {1} singular "User muted." - + Ik heb de benodigde rechten daar voor waarschijnlijk niet. - nieuwe demp group gezet + Nieuwe demp rol geplaatst. - Ik heb **administrator** rechten nodig voor dat + Ik heb **administrator** rechten daar voor nodig. nieuw bericht @@ -565,7 +565,7 @@ Reden: {1} Kan de server niet vinden - + Geen shard gevonden met dat ID. Oud bericht @@ -577,160 +577,161 @@ Reden: {1} Oude onderwerp - error hoogst waarschijnlijk niet voldoende permissie + Fout. Hoogst waarschijnlijk heb ik geen voldoende rechten. - de rechten op deze server zijn gereset + De rechten op deze server zijn gereset. - actieve bescherming + Actieve Beschermingen. - is ** uitgeschakeld** op deze server + {0} is nu ** uitgeschakeld** op deze server. - aangezet + {0} Ingeschakeld - fout. ik heb managergroup rechten nodig + Fout. ik heb Beheer Rollen rechten nodig - geen bescherming aangezet + Geen bescherming aangezet. - + Gebruiker's drempel moet tussen {0} en {1} zijn. - + Als {0} of meerdere gebruikers binnen {1} seconden, zal ik hun {2}. - + Aangegeven tijd hoort binnen {0} en {1} seconden te vallen. - + Met succes alle roles van de gebruiker {0} verwijderd - + Het verwijderen van de rollen is mislukt. Ik heb onvoldoende rechten. - + De kleur van de rol {0} is veranderd - + Die rol bestaat niet. - + De aangegeven parameters zijn ongeldig. - + Error opgekomen vanwege ongeldige kleur, of onvoldoende rechten. - + Met sucess rol {0} verwijderd van gebruiker {1}. - + Mislukt om rol te verwijderen. Ik heb onvoldoende rechten. - group naam veranderd + Rol naam veranderd. - group naam veranderen mislukt. ik heb niet genoeg rechten + Rol naam veranderen mislukt. Ik heb onvoldoende rechten. - je kan geen groupen bijwerken die hoger zijn dan jou eigen group + je kan geen rollen bijwerken die hoger zijn dan je eigen rol. - Verwijderd van speel bericht + Speel bericht verwijderd: {0} - group... is toegevoegd aan de lijst + Rol {0} is toegevoegd aan de lijst. - niet gevonden. aan het opruimen + {0} niet gevonden. Klaar met opruimen. - group is al in de lijst + Rol {0} staat al in de lijst. - toegevoegd + Toegevoegd. - + Routerende speelstatus uitgeschakeld. - + Routerende speelstatus ingeschakeld. - + Hier is een lijst met routerende statussen: +{0} - + Nog geen routerende speelstatussen ingesteld. - je hebt al .. group + Je hebt al {0} rol. - + Je hebt {0} exclusieve zelf toegewezen rol al. - + Zelf toegewezen rollen zijn nu exclusief! - + Er zijn {0} zelf toewijsbare rollen - deze group is niet zelf + Deze rol is niet zelf toewijsbaar. - + Je hebt niet {0} rol. - + Zelf toegewezen rollen zijn nu niet exclusief! - + Ik kan deze rol niet aan je toevoegen. `Ik kan niet rollen toevoegen aan eigenaren of andere rollen die boven mij staan in de rol hiërarchie.` - + {0} is verwijderd van de lijst met zelf toewijsbare rollen. - je heb niet lang meer de {0} group + Je hebt {0} rol niet meer. - je hebt nu {0} group + je hebt nu {0} rol. - met sucess een group {0) toegevoegd aan gebruiker {1} + Succesvol de rol {0} toegevoegd aan gebruiker {1} - fout bij het toevoegen van een group. je heb onvoldoende rechten + Fout bij het toevoegen van de rol. Ik heb onvoldoende rechten. - Nieuwe avatar gezet! + Nieuwe avatar ingesteld! - Nieuwe kanaal naam gezet. + Nieuwe kanaal naam ingesteld. - Nieuwe game gezet! + Nieuwe game ingesteld! - Nieuwe stream gezet! + Nieuwe stream ingesteld! - Nieuwe kanaal onderwerp gezet + Nieuwe kanaal onderwerp ingesteld. - + Shard {0} opnieuw verbonden. - + Shard {0} is opnieuw aan het verbinden. - afsluiten + Afsluiten - + Gebruikers kunnen niet meer dan {0} berichten sturen per {1} seconden. langzame mode uitgezet @@ -739,66 +740,71 @@ Reden: {1} langzame mode gestart - zacht-verbannen(kicked) + zacht-verbannen (kicked) PLURAL - {0} wil deze kanaal dempen + {0} zal dit kanaal negeren. - + {0} zal dit kanaal niet meer negeren. - + Als een gebruiker {0} de zelfde berichten plaatst, zal ik ze {1}. +__IgnoredChannels__: {2} - + Tekst kanaal aangemaakt. - + Tekst kanaal verwijderd. - + Ongedempt singular - + Gebruikersnaam - + Gebruikersnaam veranderd - + Gebruikers - + Gebruiker verbannen - + {0} is **gedempt** van chatten. + Fuzzy - + {0} is **ongedempt** van chatten. + Fuzzy - + Gebruiker toegetreden + Fuzzy - + Gebruiker verlaten + Fuzzy - + Gebruiker's rol toegevoegd - + Gebruiker's rol verwijderd - + {0} is nu {1} @@ -1173,16 +1179,16 @@ Reden: {1} - + {0} heeft een zin ingezonden. ({1} in totaal) - + {0} heeft gestemd! - + De winnaar is {0} met {1} punten. @@ -2063,13 +2069,13 @@ Reden: {1} - + Geen verwijderbare citaten gevonden - + Citaat toegevoegd - + Een willekeurig citaat verwijderd From 55fc4432dde3455f799953f29d4b8bfb43fd5213 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 3 Mar 2017 02:26:23 +0100 Subject: [PATCH 420/746] Update ResponseStrings.fr-fr.resx (POEditor.com) --- .../Resources/ResponseStrings.fr-fr.resx | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx index ac95afb6..b0bcd0c5 100644 --- a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx +++ b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx @@ -315,7 +315,7 @@ Raison: {1} - banni + bannis PLURAL @@ -628,7 +628,7 @@ Raison : {1} Erreur due à un manque de permissions ou à une couleur invalide. - L'utilisateur {1} n'appartient plus au rôle {0}. + L'utilisateur {1} n'a plus le rôle {0}. Impossible de supprimer ce rôle. Je ne possède pas les permissions suffisantes. @@ -705,7 +705,7 @@ Raison : {1} Vous avez désormais le rôle {0}. - L'ajout du rôle {0} pour l'utilisateur {1} a été réalisé avec succès. + L'utilisateur {1} a désormais le rôle {0}. Impossible d'ajouter un rôle. Je ne possède pas les permissions suffisantes. @@ -727,7 +727,7 @@ Raison : {1} Nouveau sujet du salon défini. - Shard {0} reconnectée. + Shard {0} reconnecté. Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. @@ -758,13 +758,13 @@ Raison : {1} Si un utilisateur poste {0} le même message à la suite, je le {1}. - __SalonsIgnorés__: {2} + __SalonsIgnorés__: {2} Salon textuel crée. - Salon textuel détruit. + Salon textuel supprimé. Son activé avec succès. @@ -774,7 +774,7 @@ Raison : {1} singular - Nom d'utilisateur. + Nom d'utilisateur Nom d'utilisateur modifié. @@ -798,7 +798,7 @@ Raison : {1} L'utilisateur a quitté - {0} est maintenant **muet** à la fois sur le salon textuel et vocal. + {0} est maintenant **muet** à la fois sur les salons textuels et vocaux. Rôle ajouté à l'utilisateur @@ -819,7 +819,7 @@ Raison : {1} {0} a quitté le salon vocal {1}. - {0} est allé du salon vocal {1} au {2}. + {0} est allé du salon vocal {1} à {2}. {0} est maintenant **muet**. @@ -831,7 +831,7 @@ Raison : {1} Salon vocal crée. - Salon vocal détruit. + Salon vocal supprimé. Fonctionnalités vocales et textuelles désactivées. @@ -843,10 +843,10 @@ Raison : {1} Je n'ai pas la permission **Gérer les rôles** et/ou **Gérer les salons**, je ne peux donc pas utiliser `voice+text` sur le serveur {0}. - Vous activez/désactivez cette fonctionnalité et **je n'ai pas les permissions ADMINISTRATEURS**. Cela pourrait causer des dysfonctionnements, et vous devrez nettoyer les salons textuels vous-même après ça. + Vous activez/désactivez cette fonctionnalité et **je n'ai pas la permission ADMINISTRATEUR**. Cela pourrait causer des dysfonctionnements, et vous devrez nettoyer les salons textuels vous-même après ça. - Je nécessite au moins les permissions **Gérer les rôles** et **Gérer les salons** pour activer cette fonctionnalité. (permissions administateurs préférées) + Je nécessite au moins les permissions **Gérer les rôles** et **Gérer les salons** pour activer cette fonctionnalité. (Permission Administrateur de préférence) Utilisateur {0} depuis un salon textuel. @@ -880,10 +880,11 @@ Raison: {1} a récompensé {0} à {1} - Meilleure chance la prochaine fois ^_^ + Plus de chance la prochaine fois ^_^ + C'est vraiment québecois ca.. On ne le dit pas comme ca ici xD - Félicitations! Vous avez gagné {0} pour avoir lancé au dessus de {1} + Félicitations! Vous avez gagné {0} pour avoir lancé au dessus de {1}. Deck remélangé. @@ -893,7 +894,7 @@ Raison: {1} User flipped tails. - Vous l'avez deviné! Vous avez gagné {0} + Vous avez deviné! Vous avez gagné {0} Nombre spécifié invalide. Vous pouvez lancer 1 à {0} pièces. @@ -1338,7 +1339,7 @@ La nouvelle valeur de {0} est {1} ! {0} contre {1} - Tentative d'ajouter {0} à la file d'attente... + Tentative d'ajouter {0} pistes à la file d'attente... Lecture automatique désactivée. @@ -1347,7 +1348,7 @@ La nouvelle valeur de {0} est {1} ! Lecture automatique activée. - Volume de base défini à {0}% + Volume par défaut défini à {0}% File d'attente complète. @@ -1374,10 +1375,10 @@ La nouvelle valeur de {0} est {1} ! Entrée invalide. - Le temps maximum de lecture n'a désormais plus de limite. + Le temps maximum de lecture est désormais illimité. - Le temps de lecture maximum a été mis à {0} seconde(s). + Temps maximum de lecture défini à {0} seconde(s). La taille de la file d'attente est désormais illmitée. @@ -1401,16 +1402,16 @@ La nouvelle valeur de {0} est {1} ! Pas de résultat. - Lecteur mis sur pause. + Lecteure mise en pause. - Liste d'attente - Page {0}/{1} + File d'attente - Page {0}/{1} - Lecture en cours: + Lecture en cours - `#{0}` - **{1}** par *{2}* ({3} morceaux) + `#{0}` - **{1}** par *{2}* ({3} pistes) Page {0} des listes de lecture sauvegardées @@ -1434,23 +1435,23 @@ La nouvelle valeur de {0} est {1} ! Limite à {0}s - Liste d'attente + File d'attente - Son ajouté à la file d'attente + Piste ajoutée à la file d'attente - Liste d'attente effacée. + File d'attente effacée. - Liste d'attente complète ({0}/{0}). + File d'attente complète ({0}/{0}). - Son retiré + Piste retirée context: "removed song #5" - Répétition de la musique en cours + Répétition de la piste en cours de lecture Liste de lecture en boucle @@ -1471,7 +1472,7 @@ La nouvelle valeur de {0} est {1} ! Lecture en boucle activée. - Je vais désormais afficher les musiques en cours, en pause, terminées et supprimées sur ce salon. + Je vais désormais afficher les pistess en cours, en pause, terminées et supprimées sur ce salon. Saut à `{0}:{1}` @@ -1480,13 +1481,13 @@ La nouvelle valeur de {0} est {1} ! Lecture aléatoire activée. - Musique déplacée + Piste déplacée {0}h {1}m {2}s - En position + À la position Illimité @@ -1665,7 +1666,6 @@ La nouvelle valeur de {0} est {1} ! Votre langue de traduction a été changée de {0} à {1} - Fuzzy Traduction automatique des messages commencée sur ce salon. @@ -2145,7 +2145,7 @@ OwnerID: {2} Page #{0} des rôles pour {1} - Aucunes couleurs ne sont dans le format correct. Utilisez `#00ff00` par exemple. + Aucune couleur n'est dans le bon format. Utilisez `#00ff00` par exemple. Couleurs alternées pour le rôle {0} activées. @@ -2178,7 +2178,7 @@ OwnerID: {2} Pas d'emojis spéciaux trouvés. - Joue actuellement {0} musiques, {1} en attente. + Joue actuellement {0} piste(s), {1} en attente. Salons textuels @@ -2190,7 +2190,7 @@ OwnerID: {2} Durée de fonctionnement - {0} de l'utilisateur {1} est {2} + {0} de l'utilisateur {1}: {2} Id of the user kwoth#1234 is 123123123123 From 8881d32151bd753dc97dcea1be68ffcaa89bc562 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 3 Mar 2017 02:26:25 +0100 Subject: [PATCH 421/746] Update ResponseStrings.de-DE.resx (POEditor.com) --- .../Resources/ResponseStrings.de-DE.resx | 94 +++++++++---------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx index 8b3974b3..6b61e5f6 100644 --- a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx @@ -121,7 +121,7 @@ Diese Basis wurde bereits beansprucht oder zerstört. - Diese Basis ist bereits zertört. + Diese Basis ist bereits zerstört. Diese Basis ist nicht beansprucht. @@ -193,7 +193,7 @@ Benutzerdefinierte Reaktion gelöscht. - Unzureichende Rechte. Dies erfordert das sie den Bot besitzen für globale Reaktionen, und Administratorrechte für serverseitige Reaktionen. + Unzureichende Rechte. Dies erfordert das Sie den Bot besitzen für globale Reaktionen, und Administratorrechte für serverseitige Reaktionen. Liste aller benutzerdefinierten Reaktionen. @@ -287,7 +287,7 @@ Das ist sehr effektiv! - Sie haben zu viele Angriffe hintereinander eingesetzt, sodass sie sich nicht bewegen können! + Sie haben zu viele Angriffe hintereinander eingesetzt, sodass Sie sich nicht bewegen können! Typ von {0} ist {1} @@ -296,7 +296,7 @@ Benutzer nicht gefunden. - Sie sind ohnmächtig, daher können sie sich nicht bewegen! + Sie sind ohnmächtig, daher können Sie sich nicht bewegen! **Automatische Rollenzuteilung** wenn ein Benutzer beitritt ist nun **deaktiviert**. @@ -448,7 +448,7 @@ Grund: {1} Begrüßungsankündigungen wurden für diesen Kanal aktiviert. - Sie können diesen befehl nicht an Benutzern mit einer Rolle über oder gleich zu ihrer in der Rangordnung benutzen. + Sie können diesen befehl nicht an Benutzern mit einer Rolle über oder gleich zu Ihrer in der Rangordnung benutzen. Bilder wurden geladen nach {0} sekunden! @@ -477,13 +477,13 @@ Grund: {1} Ihr Servers Sprachumgebung ist jetzt {1} - {1} - Der Bots standard Sprachumgebung ist jetzt {0} - {1} + Die Sprachumgebung des Bots ist nun {0} - {1} Die Sprache des Bots ist {0} - {1} - Setzen der Sprachumgebung fehlgeschlagen. Greifen sie auf diesen Befehls hilfe erneut auf. + Setzen der Sprachumgebung fehlgeschlagen. Greifen Sie auf diesen Befehls hilfe erneut auf. Dieser Servers Sprache wurde zu {0} - {1} gesetzt @@ -504,7 +504,7 @@ Grund: {1} Aufzeichnungen wurden deaktiviert. - Aufzeichnungs Ereignise die sie abonnieren können: + Aufzeichnungs Ereignise die Sie abonnieren können: Aufzeichnungen werden {0} ignorieren @@ -602,7 +602,7 @@ Grund: {1} Benutzerschwelle muss zwischen {0} und {1} sein. - Wenn {0} oder mehr Benutzer innerhalb von {1} Sekunden beitreten werde ich sie {2}. + Wenn {0} oder mehr Benutzer innerhalb von {1} Sekunden beitreten werde ich Sie {2}. Zeit muss zwischen {0} und {1} sekunden sein. @@ -638,7 +638,7 @@ Grund: {1} Umbenennen der Rolle fehlgeschlagen. Ich habe nicht die erforderlichen Rechte. - Sie kännen keine Rollen bearbeiten die höher als ihre eigenen sind. + Sie kännen keine Rollen bearbeiten die höher als Ihre eigenen sind. Die Abspielnachricht wurde entfernt: {0} @@ -675,25 +675,25 @@ Grund: {1} Sie haben bereits die exklusive, selbstzugewiesene Rolle {0}. - Selbstzuweisbare Rollen sind nun exklusiv! + Selbst zugewiesene Rollen sind nun exklusiv! - Es gibt {0} selbstzuweisbare Rollen + Es gibt {0} Rollen, die man sich selbst zuweisen kann. - Diese Rolle ist nicht selbstzuweisbar. + Diese Rolle kann man sich nicht selbst zuweisen. Sie haben die Rolle {0} nicht. - Selbstzuweisbare Rollen sind nicht länger exklusiv! + Selbst zugewiesene Rollen sind nicht länger exklusiv! - Ich kann dir diese Rolle nicht zuweisen. `Ich kann keine Rollen zu Besitzern oder andere Rollen die höher als meine in der Rangordnung sind hinzufügen.` + Ich kann Ihnen diese Rolle nicht zuweisen. `Ich kann keine Rollen zu Besitzern oder andere Rollen die höher als meine in der Rangordnung sind hinzufügen.` - {0} wurde von der Liste der selbstzuweisbaren Rollen entfernt. + {0} wurde von der Liste der selbst zuweisbaren Rollen entfernt. Sie haben nicht länger die Rolle {0}. @@ -875,10 +875,10 @@ Grund: {1} vegab {0} zu {1} - Hoffentlich haben sie beim nächsten Mal mehr Glück ^_^ + Hoffentlich haben Sie beim nächsten Mal mehr Glück ^_^ - Glückwunsch! Sie haben {0} gewonnen, weil sie über {1} gewürfelt haben + Glückwunsch! Sie haben {0} gewonnen, weil Sie über {1} gewürfelt haben Deck neu gemischt. @@ -995,7 +995,7 @@ Grund: {1} Gebe `{0}h NameDesBefehls` ein, um die Hilfestellung für diesen Befehl zu sehen. Z.B. `{0}h >8ball` - Ich konnte diesen Befehl nicht finden. Bitte stelle sicher das dieser Befehl existiert bevor sie es erneut versuchen. + Ich konnte diesen Befehl nicht finden. Bitte stelle sicher das dieser Befehl existiert bevor Sie es erneut versuchen. Beschreibung @@ -1004,7 +1004,7 @@ Grund: {1} Sie können das NadekoBot-Projekt über Patreon <{0}> oder PayPal <{1}> unterstützen. -Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu hinterlassen. +Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu hinterlassen. **Vielen Dank**♥️ @@ -1031,7 +1031,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Inhaltsverzeichnis - Benutzweise + Verwendung Autohentai wurde gestartet. Es wird alle {0} Sekunden etwas mit einem der folgenden Stichwörtern gepostet: {1} @@ -1111,7 +1111,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Top Waifus - Ihre Neigung ist bereits zu dieser Waifu gesetzt oder sie versuchsen ihre Neigung zu entfernen während sie keine gesetzt haben. + Ihre Neigung ist bereits zu dieser Waifu gesetzt oder Sie versuchsen Ihre Neigung zu entfernen während Sie keine gesetzt haben. hat seine Neigung von {0} zu {1} geändert. @@ -1120,47 +1120,47 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Make sure to get the formatting right, and leave the thinking emoji - Sie müssen {0} Stunden und {1} Minuten warten bevor sie ihre Neigung ändern können. + Sie müssen {0} Stunden und {1} Minuten warten bevor Sie Ihre Neigung ändern können. - Ihre Neigung wurde zurückgesetzt. Sie haben keine Person mehr die sie mögen. + Ihre Neigung wurde zurückgesetzt. Sie haben keine Person mehr die Sie mögen. will {0}s Waifu sein. Aww <3 - hat {0} als seine/ihre Waifu für {1} beansprucht! + hat {0} als seine/Ihre Waifu für {1} beansprucht! - Sie haben sich von ihrer Waifu die sie mochte scheiden lassen. Du herzloses Monster. {0} hat {1} als Kompensation erhalten. + Sie haben sich von Ihrer Waifu die Sie mochte scheiden lassen. Du herzloses Monster. {0} hat {1} als Kompensation erhalten. - Sie können deine Neigung nicht zu ihnen selbst setzen, sie egomanische Person. + Sie können deine Neigung nicht zu Ihnen selbst setzen, Sie egomanische Person. 🎉 Ihre Liebe ist besiegelt! 🎉 {0}'s neuer Wert ist {1}! - Keine Waifu ist so billig. Sie müssen wenigstens {0} bezahlen um diese Waifu zu beanspruchen, selbst wenn ihr tatsächlicher Wert geringer ist. + Keine Waifu ist so billig. Sie müssen wenigstens {0} bezahlen um diese Waifu zu beanspruchen, selbst wenn Ihr tatsächlicher Wert geringer ist. Sie müssen {0} oder mehr bezahlen um diese Waifu zu beanspruchen! - Diese Waifu gehört nicht dir. + Diese Waifu gehört nicht Ihnen. Sie können sich nicht selbst beanspruchen. - Sie haben sich vor kurzem scheiden lassen. Sie müssen {0} Stunden und {1} Minuten warten bevor sie sich erneut scheiden lassen können. + Sie haben sich vor kurzem scheiden lassen. Sie müssen {0} Stunden und {1} Minuten warten bevor Sie sich erneut scheiden lassen können. Niemand - Sie haben sich von einer Waifu scheiden lassen die sie nicht mochte, Du erhältst {0} zurück. + Sie haben sich von einer Waifu scheiden lassen die Sie nicht mochte, Du erhältst {0} zurück. 8ball @@ -1184,7 +1184,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Spiel gestartet. Erstelle einen Satz aus dem folgenden Akronym: {0}. - Sie haben {0} Sekunden für ihre Einsendung. + Sie haben {0} Sekunden für Ihre Einsendung. {0} hat seinen Satz eingereicht. ({1} insgesamt) @@ -1193,7 +1193,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Stimme ab indem du die Nummer der Einsendung eingibst - {0} hat seine/ihre Stimme abgegeben! + {0} hat seine/Ihre Stimme abgegeben! Der Gewinner ist {0} mit {1} Punkten. @@ -1235,11 +1235,11 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Währungsgeneration in diesem Kanal aktiviert. - {0} zufällige {1} sind erschienen! Sammle sie indem sie `{2}pick` schreiben + {0} zufällige {1} sind erschienen! Sammle sie indem Sie `{2}pick` schreiben plural - Eine zufällige {0} ist erschienen! Sammle sie indem sie `{1}pick` schreiben + Eine zufällige {0} ist erschienen! Sammle sie indem Sie `{1}pick` schreiben Laden einer Frage fehlgeschlagen. @@ -1269,7 +1269,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Keine Ergebnisse - {0} aufgehoben + hat {0} aufgehoben Kwoth picked 5* @@ -1367,10 +1367,10 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Ungültige Eingabe. - Maximale Spielzeit hat kein Limit mehr. + Maximale Länge eines Liedes hat kein Limit mehr. - Maximale Spielzeit ist nun {0} Sekunden. + Maximale länge eines Liedes ist nun {0} Sekunden. Maximale Musik-Warteschlangengröße ist nun unbegrenzt. @@ -1412,7 +1412,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Playlist gelöscht. - Playlist konnte nicht gelöscht werden. Entweder sie existiert nicht oder sie gehört nicht dir. + Playlist konnte nicht gelöscht werden. Entweder es existiert nicht oder es gehört nicht Ihnen. Es gibt keine Playlist mit dieser ID. @@ -1473,7 +1473,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Lieder gemischt. - Lieder bewegt + Lied bewegt {0}h {1}m {2}s @@ -1666,7 +1666,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Automatische Übersetzung der Nachrichten wurde auf diesem kanal gestoppt. - Schlechter Eingabeformat, oder etwas lief schief. + Schlechtes Eingabeformat oder etwas lief schief. Konnte diese Karte nicht finden. @@ -1844,7 +1844,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Etwas lief schief. - Bitte spezifizieren sie die Such Parameter. + Bitte spezifizieren Sie die Such Parameter. Status @@ -1883,7 +1883,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Sonnenuntergang - Temperature + Temperatur Titel: @@ -1913,7 +1913,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Der Begriff konnte auf dem spezifizierten wikia nicht gefunden werden. - Bitte geben sie ein Ziel wikia ein, gefolgt bei der Suchanfrage. + Bitte geben Sie ein Ziel wikia ein, gefolgt bei der Suchanfrage. Seite konnte nicht gefunden werden. @@ -1984,7 +1984,7 @@ Vergessen sie bitte nicht, ihren Discord-Namen oder ihre ID in der Nachricht zu Verließ Multi-Server-Kanal. - Dies ist ihr MSK token + Dies ist Ihr MSK token Benutzerdefinierte Emojis @@ -2085,7 +2085,7 @@ ID des Besitzers: {2} Keine Zitate auf dieser Seite. - Kein Zitat das sie entfernen können gefunden. + Kein Zitat das Sie entfernen können gefunden. Zitat hinzugefügt @@ -2172,7 +2172,7 @@ ID des Besitzers: {2} Text Kanäle - Hier ist ihr Raum link + Hier ist Ihr Raum link Betriebszeit From 66b135b2dbafd41cd6d5a1e99a9260a760f53e87 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 3 Mar 2017 02:26:28 +0100 Subject: [PATCH 422/746] Update ResponseStrings.pt-BR.resx (POEditor.com) From 5ddd92fe8d0cd3b5d90ed6d2761b347c07f7af6e Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 3 Mar 2017 02:26:30 +0100 Subject: [PATCH 423/746] Update ResponseStrings.ru-RU.resx (POEditor.com) From 349645c019a5f508f650850d5bbab5b06616b89e Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 3 Mar 2017 02:26:33 +0100 Subject: [PATCH 424/746] Update ResponseStrings.sr-cyrl-rs.resx (POEditor.com) From 71c06f6020a3227f96d4608dbf1f76db6a557a9f Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 3 Mar 2017 02:26:36 +0100 Subject: [PATCH 425/746] Update ResponseStrings.ja-JP.resx (POEditor.com) --- .../Resources/ResponseStrings.ja-JP.resx | 316 ++++++++++-------- 1 file changed, 169 insertions(+), 147 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx b/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx index 29a0675a..1261856c 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 その基盤はすでに主張されている。または破壊されました。 @@ -130,7 +130,7 @@ - {1}との戦争中の整数{0}を破壊しました + {1}との戦いで基地#{0}を**破壊**しました @@ -145,79 +145,99 @@ - + 敵 + - + {0} との戦争に関する情報 - + 無効な城の番号 + - + 有効な戦争サイズではありません。 + - + アクティブな戦争を一覧表示する。 + - + 請求されていない + - + あなたはこの戦争の参加者ではありません。 + - + @{0} +あなたはその戦争に参加していないか、その基地はすでに破壊されています。 - + 活動的な戦争はない サイズ - + 戦争の戦い{0}は既に始まった。 + - + 戦争{0}が作成されました。 + - + {0}に対する戦争は終わった。 + - + その戦争は存在しない。 + - + 戦争{0}が始まった! + - + すべてのカスタム反応がクリアされました。 + - + カスタム反応が削除されました。 + - + すべてのカスタム反応をリストします。 + - + カスタム反応。 + - + 新しいカスタム反応。 + - + カスタム反応が見つかりませんでした。 + - + その識別情報でカスタム反応が見つかりませんでした。 + 反応 - + カスタム反応の統計 + @@ -226,13 +246,14 @@ - トリガー + 引き金 - + 結果が見つかりません + @@ -317,7 +338,7 @@ - BANNED + 亡命 PLURAL @@ -534,12 +555,12 @@ - ミュート + ミュート中 PLURAL (users have been muted) Fuzzy - ミュート + ミュート中 singular "User muted." @@ -633,7 +654,7 @@ Fuzzy - + 役割名を変更しました @@ -773,7 +794,8 @@ Fuzzy - + ユーザーズ + Fuzzy From 2bd7080324c48d6f1989dbab9ca9648649ff2eae Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 3 Mar 2017 03:08:55 +0100 Subject: [PATCH 426/746] fixed calcops --- src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs b/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs index 8eccc500..7617cdc9 100644 --- a/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs +++ b/src/NadekoBot/Modules/Utility/Commands/CalcCommand.cs @@ -53,7 +53,7 @@ namespace NadekoBot.Modules.Utility "GetHashCode", "GetType" }); - await Context.Channel.SendConfirmAsync(GetText("utility_calcops", Prefix), string.Join(", ", selection)); + await Context.Channel.SendConfirmAsync(GetText("calcops", Prefix), string.Join(", ", selection)); } } From ac6ad1d853219ca4b19d7e3c872139f5d3663ee6 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 3 Mar 2017 03:59:12 +0100 Subject: [PATCH 427/746] fixed nsfw string --- src/NadekoBot/Modules/NSFW/NSFW.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/NadekoBot/Modules/NSFW/NSFW.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs index 6e72aefc..5f45af24 100644 --- a/src/NadekoBot/Modules/NSFW/NSFW.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -142,11 +142,11 @@ namespace NadekoBot.Modules.NSFW #endif [NadekoCommand, Usage, Description, Aliases] public Task Yandere([Remainder] string tag = null) - => InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Yandere); + => InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Yandere); [NadekoCommand, Usage, Description, Aliases] public Task Konachan([Remainder] string tag = null) - => InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Konachan); + => InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Konachan); [NadekoCommand, Usage, Description, Aliases] public async Task E621([Remainder] string tag = null) @@ -167,7 +167,7 @@ namespace NadekoBot.Modules.NSFW [NadekoCommand, Usage, Description, Aliases] public Task Rule34([Remainder] string tag = null) - => InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Rule34); + => InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Rule34); [NadekoCommand, Usage, Description, Aliases] public async Task Danbooru([Remainder] string tag = null) @@ -210,7 +210,7 @@ namespace NadekoBot.Modules.NSFW [NadekoCommand, Usage, Description, Aliases] public Task Gelbooru([Remainder] string tag = null) - => InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Gelbooru); + => InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Gelbooru); [NadekoCommand, Usage, Description, Aliases] public async Task Cp() @@ -288,19 +288,17 @@ namespace NadekoBot.Modules.NSFW public static Task GetGelbooruImageLink(string tag) => Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Gelbooru); - public async Task InternalDapiCommand(IUserMessage umsg, string tag, Searches.Searches.DapiSearchType type) + public async Task InternalDapiCommand(string tag, Searches.Searches.DapiSearchType type) { - var channel = umsg.Channel; - tag = tag?.Trim() ?? ""; var url = await Searches.Searches.InternalDapiSearch(tag, type).ConfigureAwait(false); if (url == null) - await channel.SendErrorAsync(umsg.Author.Mention + " " + GetText("no_results")); + await ReplyErrorLocalized("not_found").ConfigureAwait(false); else - await channel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithDescription(umsg.Author.Mention + " " + tag) + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithDescription(Context.User + " " + tag) .WithImageUrl(url) .WithFooter(efb => efb.WithText(type.ToString()))).ConfigureAwait(false); } From 07a0ff078bd832467705e96a51883323d6a70503 Mon Sep 17 00:00:00 2001 From: Rajath Ranganath Date: Fri, 3 Mar 2017 21:34:16 +0530 Subject: [PATCH 428/746] Fixed stuf --- src/NadekoBot/Resources/CommandStrings.resx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 49bd76e8..3d01eb34 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -124,7 +124,7 @@ Either shows a help for a single command, or DMs you help link if no arguments are specified. - `{0}h -cmds` or `{0}h` + `{0}h {0}cmds` or `{0}h` hgit @@ -958,7 +958,7 @@ srvrfilterwords sfw - Toggles automatic deleting of messages containing filtered words on the server. Does not affect the Bot Owner. + Toggles automatic deletion of messages containing filtered words on the server. Does not affect the Bot Owner. `{0}sfw` @@ -967,7 +967,7 @@ permrole pr - Sets a role which can change permissions. Supply no parameters to find out the current one. Default is 'Nadeko'. + Sets a role which can change permissions. Supply no parameters to see the current one. Default is 'Nadeko'. `{0}pr role` From 2ae7fbcab580519d5f9ee85f6ad28b10f3e775fb Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 3 Mar 2017 18:45:59 +0100 Subject: [PATCH 429/746] Changed a string --- src/NadekoBot/Resources/ResponseStrings.Designer.cs | 2 +- src/NadekoBot/Resources/ResponseStrings.resx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index c3d3a842..c91f93cb 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -1794,7 +1794,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Claim from @{0} for a war against {1} has expired.. + /// Looks up a localized string similar to Claim from @{0} in a war against {1} has expired.. /// public static string clashofclans_claim_expired { get { diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index c89a5084..a1674f52 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -139,7 +139,7 @@ @{0} You already claimed base #{1}. You can't claim a new one. - Claim from @{0} for a war against {1} has expired. + Claim from @{0} in a war against {1} has expired. Enemy From 02963151be39f8f93b885062256d763bca8a6969 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 4 Mar 2017 00:32:16 +0100 Subject: [PATCH 430/746] moveorstay gambling game implemented but too profitable, commented out. --- .../Modules/Gambling/Commands/MoveOrStay.cs | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 src/NadekoBot/Modules/Gambling/Commands/MoveOrStay.cs diff --git a/src/NadekoBot/Modules/Gambling/Commands/MoveOrStay.cs b/src/NadekoBot/Modules/Gambling/Commands/MoveOrStay.cs new file mode 100644 index 00000000..e7ca6434 --- /dev/null +++ b/src/NadekoBot/Modules/Gambling/Commands/MoveOrStay.cs @@ -0,0 +1,167 @@ +using System.Collections.Concurrent; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Discord.Commands; +using Discord; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Services; + +namespace NadekoBot.Modules.Gambling +{ + //public partial class Gambling + //{ + // [Group] + // public class MoveOrStayCommands : NadekoSubmodule + // { + // [NadekoCommand, Usage, Description, Aliases] + // [RequireContext(ContextType.Guild)] + // [OwnerOnly] + // public async Task MoveOrStayTest() + // { + // //test 1, just stop on second one + + // //test 2, stop when winning + + // } + + // private static readonly ConcurrentDictionary _games = new ConcurrentDictionary(); + + // [NadekoCommand, Usage, Description, Aliases] + // [RequireContext(ContextType.Guild)] + // public async Task MoveOrStay(int bet) + // { + // if (bet < 4) + // return; + // var game = new MoveOrStayGame(bet); + // if (!_games.TryAdd(Context.User.Id, game)) + // { + // await ReplyAsync("You're already betting on move or stay.").ConfigureAwait(false); + // return; + // } + + // if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User, "MoveOrStay bet", bet, false)) + // { + // await ReplyAsync("You don't have enough money"); + // return; + // } + // await Context.Channel.EmbedAsync(GetGameState(game), + // string.Format("{0} rolled {1}.", Context.User, game.Rolled)).ConfigureAwait(false); + // } + + // public enum Mors + // { + // Move = 1, + // M = 1, + // Stay = 2, + // S = 2 + // } + + // [NadekoCommand, Usage, Description, Aliases] + // [RequireContext(ContextType.Guild)] + // public async Task MoveOrStay(Mors action) + // { + // MoveOrStayGame game; + // if (!_games.TryGetValue(Context.User.Id, out game)) + // { + // await ReplyAsync("You're not betting on move or stay.").ConfigureAwait(false); + // return; + // } + + // if (action == Mors.Move) + // { + // game.Move(); + // await Context.Channel.EmbedAsync(GetGameState(game), string.Format("{0} rolled {1}.", Context.User, game.Rolled)).ConfigureAwait(false); if (game.Ended) + // _games.TryRemove(Context.User.Id, out game); + // } + // else if (action == Mors.Stay) + // { + // var won = game.Stay(); + // await CurrencyHandler.AddCurrencyAsync(Context.User, "MoveOrStay stay", won, false) + // .ConfigureAwait(false); + // _games.TryRemove(Context.User.Id, out game); + // await ReplyAsync(string.Format("You've finished with {0}", + // won + CurrencySign)) + // .ConfigureAwait(false); + // } + + + // } + + // private EmbedBuilder GetGameState(MoveOrStayGame game) + // { + // var arr = MoveOrStayGame.Winnings.ToArray(); + // var sb = new StringBuilder(); + // for (var i = 0; i < arr.Length; i++) + // { + // if (i == game.CurrentPosition) + // { + // sb.Append("[" + arr[i] + "]"); + // } + // else + // { + // sb.Append(arr[i].ToString()); + // } + + // if (i != arr.Length - 1) + // sb.Append(' '); + // } + + // return new EmbedBuilder().WithOkColor() + // .WithTitle("Move or Stay") + // .WithDescription(sb.ToString()) + // .AddField(efb => efb.WithName("Bet") + // .WithValue(game.Bet.ToString()) + // .WithIsInline(true)) + // .AddField(efb => efb.WithName("Current Value") + // .WithValue((game.CurrentMultiplier * game.Bet).ToString(_cultureInfo)) + // .WithIsInline(true)); + // } + // } + + // public class MoveOrStayGame + // { + // public int Bet { get; } + // public bool Ended { get; private set; } + // public int PreviousPosition { get; private set; } + // public int CurrentPosition { get; private set; } = -1; + // public int Rolled { get; private set; } + // public float CurrentMultiplier => Winnings[CurrentPosition]; + // private readonly NadekoRandom _rng = new NadekoRandom(); + + // public static readonly ImmutableArray Winnings = new[] + // { + // 1.5f, 0.75f, 1f, 0.5f, 0.25f, 0.25f, 2.5f, 0f, 0f + // }.ToImmutableArray(); + + // public MoveOrStayGame(int bet) + // { + // Bet = bet; + // Move(); + // } + + // public void Move() + // { + // if (Ended) + // return; + // PreviousPosition = CurrentPosition; + // Rolled = _rng.Next(1, 4); + // CurrentPosition += Rolled; + + // if (CurrentPosition >= 7) + // Ended = true; + // } + + // public int Stay() + // { + // if (Ended) + // return 0; + + // Ended = true; + // return (int) (CurrentMultiplier * Bet); + // } + // } + //} +} From 0be6f8c86c87e763ce396497041f0ffee481224c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 4 Mar 2017 01:38:01 +0100 Subject: [PATCH 431/746] commandlist updated --- docs/Commands List.md | 250 +++++++++++++++++++++--------------------- 1 file changed, 128 insertions(+), 122 deletions(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index d73852f3..1317f263 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -1,4 +1,4 @@ -You can support the project on patreon: or paypal: +You can support the project on patreon: or paypal: ##Table Of Contents - [Help](#help) @@ -18,11 +18,11 @@ You can support the project on patreon: or paypa ### Administration Command and aliases | Description | Usage ----------------|--------------|------- -`.resetperms` | Resets BOT's permissions module on this server to the default value. **Requires Administrator server permission.** | `.resetperms` -`.delmsgoncmd` | Toggles the automatic deletion of user's successful command message to prevent chat flood. **Requires Administrator server permission.** | `.delmsgoncmd` +`.resetperms` | Resets the bot's permissions module on this server to the default value. **Requires Administrator server permission.** | `.resetperms` +`.delmsgoncmd` | Toggles the automatic deletion of the user's successful command message to prevent chat flood. **Requires Administrator server permission.** | `.delmsgoncmd` `.setrole` `.sr` | Sets a role for a given user. **Requires ManageRoles server permission.** | `.sr @User Guest` `.removerole` `.rr` | Removes a role from a given user. **Requires ManageRoles server permission.** | `.rr @User Admin` -`.renamerole` `.renr` | Renames a role. Roles you are renaming must be lower than bot's highest role. **Requires ManageRoles server permission.** | `.renr "First role" SecondRole` +`.renamerole` `.renr` | Renames a role. The role you are renaming must be lower than bot's highest role. **Requires ManageRoles server permission.** | `.renr "First role" SecondRole` `.removeallroles` `.rar` | Removes all roles from a mentioned user. **Requires ManageRoles server permission.** | `.rar @User` `.createrole` `.cr` | Creates a role with a given name. **Requires ManageRoles server permission.** | `.cr Awesome Role` `.rolecolor` `.rc` | Set a role's color to the hex or 0-255 rgb color value provided. **Requires ManageRoles server permission.** | `.rc Admin 255 200 100` or `.rc Admin ffba55` @@ -37,18 +37,19 @@ Command and aliases | Description | Usage `.creatxtchanl` `.ctch` | Creates a new text channel with a given name. **Requires ManageChannels server permission.** | `.ctch TextChannelName` `.settopic` `.st` | Sets a topic on the current channel. **Requires ManageChannels server permission.** | `.st My new topic` `.setchanlname` `.schn` | Changes the name of the current channel. **Requires ManageChannels server permission.** | `.schn NewName` -`.prune` `.clr` | `.prune` removes all nadeko's messages in the last 100 messages.`.prune X` removes last X messages from the channel (up to 100)`.prune @Someone` removes all Someone's messages in the last 100 messages.`.prune @Someone X` removes last X 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X` -`.mentionrole` `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. **Requires MentionEveryone server permission.** | `.menro RoleName` -`.donators` | List of lovely people who donated to keep this project alive. | `.donators` -`.donadd` | Add a donator to the database. **Bot Owner only.** | `.donadd Donate Amount` +`.prune` `.clr` | `.prune` removes all Nadeko's messages in the last 100 messages. `.prune X` removes last `X` number of messages from the channel (up to 100). `.prune @Someone` removes all Someone's messages in the last 100 messages. `.prune @Someone X` removes last `X` number of 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X` +`.mentionrole` `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have the mention everyone permission. **Requires MentionEveryone server permission.** | `.menro RoleName` +`.donators` | List of the lovely people who donated to keep this project alive. | `.donators` +`.donadd` | Add a donator to the database. **Bot Owner Only** | `.donadd Donate Amount` `.autoassignrole` `.aar` | Automaticaly assigns a specified role to every user who joins the server. **Requires ManageRoles server permission.** | `.aar` to disable, `.aar Role Name` to enable -`.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot Owner only.** | `.fwmsgs` -`.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json **Bot Owner only.** | `.fwtoall` -`.logserver` | Enables or Disables ALL log events. If enabled, all log events will log to this channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logserver enable` or `.logserver disable` -`.logignore` | Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logignore` -`.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot Owner only.** | `.logevents` -`.log` | Toggles logging event. Disables it if it's active anywhere on the server. Enables if it's not active. Use `.logevents` to see a list of all events you can subscribe to. **Requires Administrator server permission.** **Bot Owner only.** | `.log userpresence` or `.log userbanned` -`.migratedata` | Migrate data from old bot configuration **Bot Owner only.** | `.migratedata` +`.languageset` `.langset` | Sets this server's response language. If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. | `.langset de-DE ` or `.langset default` +`.langsetdefault` `.langsetd` | Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. | `.langsetd en-US` or `.langsetd default` +`.languageslist` `.langli` | List of languages for which translation (or part of it) exist atm. | `.langli` +`.logserver` | Enables or Disables ALL log events. If enabled, all log events will log to this channel. **Requires Administrator server permission.** **Bot Owner Only** | `.logserver enable` or `.logserver disable` +`.logignore` | Toggles whether the `.logserver` command ignores this channel. Useful if you have hidden admin channel and public log channel. **Requires Administrator server permission.** **Bot Owner Only** | `.logignore` +`.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot Owner Only** | `.logevents` +`.log` | Toggles logging event. Disables it if it is active anywhere on the server. Enables if it isn't active. Use `.logevents` to see a list of all events you can subscribe to. **Requires Administrator server permission.** **Bot Owner Only** | `.log userpresence` or `.log userbanned` +`.migratedata` | Migrate data from old bot configuration **Bot Owner Only** | `.migratedata` `.setmuterole` | Sets a name of the role which will be assigned to people who should be muted. Default is nadeko-mute. **Requires ManageRoles server permission.** | `.setmuterole Silenced` `.mute` | Mutes a mentioned user both from speaking and chatting. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.mute @Someone` `.unmute` | Unmutes a mentioned user previously muted with `.mute` command. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.unmute @Someone` @@ -56,51 +57,54 @@ Command and aliases | Description | Usage `.chatunmute` | Removes a mute role previously set on a mentioned user with `.chatmute` which prevented him from chatting in text channels. **Requires ManageRoles server permission.** | `.chatunmute @Someone` `.voicemute` | Prevents a mentioned user from speaking in voice channels. **Requires MuteMembers server permission.** | `.voicemute @Someone` `.voiceunmute` | Gives a previously voice-muted user a permission to speak. **Requires MuteMembers server permission.** | `.voiceunmute @Someguy` -`.rotateplaying` `.ropl` | Toggles rotation of playing status of the dynamic strings you previously specified. **Bot Owner only.** | `.ropl` -`.addplaying` `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %time%,%shardid%,%shardcount%, %shardguilds% **Bot Owner only.** | `.adpl` -`.listplaying` `.lipl` | Lists all playing statuses with their corresponding number. **Bot Owner only.** | `.lipl` -`.removeplaying` `.rmpl` `.repl` | Removes a playing string on a given number. **Bot Owner only.** | `.rmpl` +`.rotateplaying` `.ropl` | Toggles rotation of playing status of the dynamic strings you previously specified. **Bot Owner Only** | `.ropl` +`.addplaying` `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: `%servers%`, `%users%`, `%playing%`, `%queued%`, `%time%`, `%shardid%`, `%shardcount%`, `%shardguilds%`. **Bot Owner Only** | `.adpl` +`.listplaying` `.lipl` | Lists all playing statuses with their corresponding number. **Bot Owner Only** | `.lipl` +`.removeplaying` `.rmpl` `.repl` | Removes a playing string on a given number. **Bot Owner Only** | `.rmpl` `.antiraid` | Sets an anti-raid protection on the server. First argument is number of people which will trigger the protection. Second one is a time interval in which that number of people needs to join in order to trigger the protection, and third argument is punishment for those people (Kick, Ban, Mute) **Requires Administrator server permission.** | `.antiraid 5 20 Kick` -`.antispam` | Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. **Requires Administrator server permission.** | `.antispam 3 Mute` or `.antispam 4 Kick` or `.antispam 6 Ban` +`.antispam` | Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10. **Requires Administrator server permission.** | `.antispam 3 Mute` or `.antispam 4 Kick` or `.antispam 6 Ban` `.antispamignore` | Toggles whether antispam ignores current channel. Antispam must be enabled. | `.antispamignore` `.antilist` `.antilst` | Shows currently enabled protection features. | `.antilist` `.slowmode` | Toggles slowmode. Disable by specifying no parameters. To enable, specify a number of messages each user can send, and an interval in seconds. For example 1 message every 5 seconds. **Requires ManageMessages server permission.** | `.slowmode 1 5` or `.slowmode` -`.adsarm` | Toggles the automatic deletion of confirmations for .iam and .iamn commands. **Requires ManageMessages server permission.** | `.adsarm` +`.adsarm` | Toggles the automatic deletion of confirmations for `.iam` and `.iamn` commands. **Requires ManageMessages server permission.** | `.adsarm` `.asar` | Adds a role to the list of self-assignable roles. **Requires ManageRoles server permission.** | `.asar Gamer` `.rsar` | Removes a specified role from the list of self-assignable roles. **Requires ManageRoles server permission.** | `.rsar` `.lsar` | Lists all self-assignable roles. | `.lsar` `.togglexclsar` `.tesar` | Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) **Requires ManageRoles server permission.** | `.tesar` `.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | `.iam Gamer` `.iamnot` `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | `.iamn Gamer` -`.leave` | Makes Nadeko leave the server. Either name or id required. **Bot Owner only.** | `.leave 123123123331` -`.die` | Shuts the bot down. **Bot Owner only.** | `.die` -`.setname` `.newnm` | Gives the bot a new name. **Bot Owner only.** | `.newnm BotName` -`.setstatus` | Sets the bot's status. (Online/Idle/Dnd/Invisible) **Bot Owner only.** | `.setstatus Idle` -`.setavatar` `.setav` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner only.** | `.setav http://i.imgur.com/xTG3a1I.jpg` -`.setgame` | Sets the bots game. **Bot Owner only.** | `.setgame with snakes` -`.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot Owner only.** | `.setstream TWITCHLINK Hello` -`.send` | Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prepend channel id with `c:` and user id with `u:`. **Bot Owner only.** | `.send serverid|c:channelid message` or `.send serverid|u:userid message` -`.announce` | Sends a message to all servers' general channel bot is connected to. **Bot Owner only.** | `.announce Useless spam` -`.reloadimages` | Reloads images bot is using. Safe to use even when bot is being used heavily. **Bot Owner only.** | `.reloadimages` -`.greetdel` `.grdel` | Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.greetdel 0` or `.greetdel 30` +`.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot Owner Only** | `.fwmsgs` +`.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json file **Bot Owner Only** | `.fwtoall` +`.connectshard` | Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. **Bot Owner Only** | `.connectshard 2` +`.leave` | Makes Nadeko leave the server. Either server name or server ID is required. **Bot Owner Only** | `.leave 123123123331` +`.die` | Shuts the bot down. **Bot Owner Only** | `.die` +`.setname` `.newnm` | Gives the bot a new name. **Bot Owner Only** | `.newnm BotName` +`.setstatus` | Sets the bot's status. (Online/Idle/Dnd/Invisible) **Bot Owner Only** | `.setstatus Idle` +`.setavatar` `.setav` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only** | `.setav http://i.imgur.com/xTG3a1I.jpg` +`.setgame` | Sets the bots game. **Bot Owner Only** | `.setgame with snakes` +`.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot Owner Only** | `.setstream TWITCHLINK Hello` +`.send` | Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prefix the channel id with `c:` and the user id with `u:`. **Bot Owner Only** | `.send serverid|c:channelid message` or `.send serverid|u:userid message` +`.announce` | Sends a message to all servers' default channel that bot is connected to. **Bot Owner Only** | `.announce Useless spam` +`.reloadimages` | Reloads images bot is using. Safe to use even when bot is being used heavily. **Bot Owner Only** | `.reloadimages` +`.greetdel` `.grdel` | Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.greetdel 0` or `.greetdel 30` `.greet` | Toggles anouncements on the current channel when someone joins the server. **Requires ManageServer server permission.** | `.greet` -`.greetmsg` | Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. **Requires ManageServer server permission.** | `.greetmsg Welcome, %user%.` +`.greetmsg` | Sets a new join announcement message which will be shown in the server's channel. Type `%user%` if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.greetmsg Welcome, %user%.` `.greetdm` | Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). **Requires ManageServer server permission.** | `.greetdm` -`.greetdmmsg` | Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message. **Requires ManageServer server permission.** | `.greetdmmsg Welcome to the server, %user%`. +`.greetdmmsg` | Sets a new join announcement message which will be sent to the user who joined. Type `%user%` if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.greetdmmsg Welcome to the server, %user%`. `.bye` | Toggles anouncements on the current channel when someone leaves the server. **Requires ManageServer server permission.** | `.bye` -`.byemsg` | Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message. **Requires ManageServer server permission.** | `.byemsg %user% has left.` -`.byedel` | Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.byedel 0` or `.byedel 30` -`.voice+text` `.v+t` | Creates a text channel for each voice channel only users in that voice channel can see.If you are server owner, keep in mind you will see them all the time regardless. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.v+t` +`.byemsg` | Sets a new leave announcement message. Type `%user%` if you want to show the name the user who left. Type `%id%` to show id. Using this command with no message will show the current bye message. You can use embed json from instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.byemsg %user% has left.` +`.byedel` | Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion. **Requires ManageServer server permission.** | `.byedel 0` or `.byedel 30` +`.voice+text` `.v+t` | Creates a text channel for each voice channel only users in that voice channel can see. If you are server owner, keep in mind you will see them all the time regardless. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.v+t` `.cleanvplust` `.cv+t` | Deletes all text channels ending in `-voice` for which voicechannels are not found. Use at your own risk. **Requires ManageChannels server permission.** **Requires ManageRoles server permission.** | `.cleanv+t` -###### [Back to TOC](#table-of-contents) +###### [Back to ToC](#table-of-contents) ### ClashOfClans Command and aliases | Description | Usage ----------------|--------------|------- -`,createwar` `,cw` | Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. | `,cw 15 The Enemy Clan` +`,createwar` `,cw` | Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. **Requires ManageMessages server permission.** | `,cw 15 The Enemy Clan` `,startwar` `,sw` | Starts a war with a given number. | `,sw 15` -`,listwar` `,lw` | Shows the active war claims by a number. Shows all wars in a short way if no number is specified. | `,lw [war_number] or ,lw` +`,listwar` `,lw` | Shows the active war claims by a number. Shows all wars in a short way if no number is specified. | `,lw [war_number]` or `,lw` `,claim` `,call` `,c` | Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. | `,call [war_number] [base_number] [optional_other_name]` `,claimfinish1` `,cf1` | Finish your claim with 1 star if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. | `,cf1 1` or `,cf1 1 5` `,claimfinish2` `,cf2` | Finish your claim with 2 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. | `,cf2 1` or `,cf2 1 5` @@ -108,20 +112,20 @@ Command and aliases | Description | Usage `,endwar` `,ew` | Ends the war with a given index. | `,ew [war_number]` `,unclaim` `,ucall` `,uc` | Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim | `,uc [war_number] [optional_other_name]` -###### [Back to TOC](#table-of-contents) +###### [Back to ToC](#table-of-contents) ### CustomReactions Command and aliases | Description | Usage ----------------|--------------|------- -`.addcustreact` `.acr` | Add a custom reaction with a trigger and a response. Running this command in server requires Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: | `.acr "hello" Hi there %user%` +`.addcustreact` `.acr` | Add a custom reaction with a trigger and a response. Running this command in server requires the Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: | `.acr "hello" Hi there %user%` `.listcustreact` `.lcr` | Lists global or server custom reactions (20 commands per page). Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. Specifying `all` argument instead of the number will DM you a text file with a list of all custom reactions. | `.lcr 1` or `.lcr all` `.listcustreactg` `.lcrg` | Lists global or server custom reactions (20 commands per page) grouped by trigger, and show a number of responses for each. Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. | `.lcrg 1` `.showcustreact` `.scr` | Shows a custom reaction's response on a given ID. | `.scr 1` -`.delcustreact` `.dcr` | Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration priviledges and removes server custom reaction. | `.dcr 5` -`.crstatsclear` | Resets the counters on `.crstats`. You can specify a trigger to clear stats only for that trigger. **Bot Owner only.** | `.crstatsclear` or `.crstatsclear rng` +`.delcustreact` `.dcr` | Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration privileges and removes server custom reaction. | `.dcr 5` +`.crstatsclear` | Resets the counters on `.crstats`. You can specify a trigger to clear stats only for that trigger. **Bot Owner Only** | `.crstatsclear` or `.crstatsclear rng` `.crstats` | Shows a list of custom reactions and the number of times they have been executed. Paginated with 10 per page. Use `.crstatsclear` to reset the counters. | `.crstats` or `.crstats 3` -###### [Back to TOC](#table-of-contents) +###### [Back to ToC](#table-of-contents) ### Gambling Command and aliases | Description | Usage @@ -129,22 +133,22 @@ Command and aliases | Description | Usage `$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName` `$cash` `$$$` | Check how much currency a person has. (Defaults to yourself) | `$$$` or `$$$ @SomeGuy` `$give` | Give someone a certain amount of currency. | `$give 1 "@SomeGuy"` -`$award` | Awards someone a certain amount of currency. You can also specify a role name to award currency to all users in a role. **Bot Owner only.** | `$award 100 @person` or `$award 5 Role Of Gamblers` -`$take` | Takes a certain amount of currency from someone. **Bot Owner only.** | `$take 1 "@someguy"` -`$betroll` `$br` | Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x3 and 100 x10. | `$br 5` -`$leaderboard` `$lb` | Displays bot currency leaderboard. | `$lb` +`$award` | Awards someone a certain amount of currency. You can also specify a role name to award currency to all users in a role. **Bot Owner Only** | `$award 100 @person` or `$award 5 Role Of Gamblers` +`$take` | Takes a certain amount of currency from someone. **Bot Owner Only** | `$take 1 "@someguy"` +`$betroll` `$br` | Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10. | `$br 5` +`$leaderboard` `$lb` | Displays the bot's currency leaderboard. | `$lb` `$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` -`$startevent` | Starts one of the events seen on public nadeko. **Bot Owner only.** | `$startevent flowerreaction` -`$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` +`$startevent` | Starts one of the events seen on public nadeko. **Bot Owner Only** | `$startevent flowerreaction` +`$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` `$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` `$shuffle` `$sh` | Reshuffles all cards back into the deck. | `$sh` `$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.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. | `$bf 5 heads` or `$bf 3 t` -`$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` +`$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` `$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` @@ -152,14 +156,15 @@ Command and aliases | Description | Usage `$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` -###### [Back to TOC](#table-of-contents) +###### [Back to ToC](#table-of-contents) ### Games Command and aliases | Description | Usage ----------------|--------------|------- `>choose` | Chooses a thing from a list of things | `>choose Get up;Sleep;Sleep more` `>8ball` | Ask the 8ball a yes/no question. | `>8ball should I do something` -`>rps` | Play a game of rocket paperclip scissors with Nadeko. | `>rps scissors` +`>rps` | Play a game of Rocket-Paperclip-Scissors with Nadeko. | `>rps scissors` +`>rategirl` | Use the universal hot-crazy wife zone matrix to determine the girl's worth. It is everything young men need to know about women. At any moment in time, any woman you have previously located on this chart can vanish from that location and appear anywhere else on the chart. | `>rategirl @SomeGurl` `>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows` `>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | `>leet 3 Hello` `>acrophobia` `>acro` | Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60) | `>acro` or `>acro 30` @@ -175,26 +180,27 @@ Command and aliases | Description | Usage `>pollend` | Stops active poll on this server and prints the results in this channel. **Requires ManageMessages server permission.** | `>pollend` `>typestart` | Starts a typing contest. | `>typestart` `>typestop` | Stops a typing contest on the current channel. | `>typestop` -`>typeadd` | Adds a new article to the typing contest. **Bot Owner only.** | `>typeadd wordswords` +`>typeadd` | Adds a new article to the typing contest. **Bot Owner Only** | `>typeadd wordswords` `>typelist` | Lists added typing articles with their IDs. 15 per page. | `>typelist` or `>typelist 3` -`>typedel` | Deletes a typing article given the ID. **Bot Owner only.** | `>typedel 3` -`>trivia` `>t` | Starts a game of trivia. You can add nohint to prevent hints.First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. | `>t` or `>t 5 nohint` +`>typedel` | Deletes a typing article given the ID. **Bot Owner Only** | `>typedel 3` +`>tictactoe` `>ttt` | Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. 15 seconds per move. | >ttt +`>trivia` `>t` | Starts a game of trivia. You can add `nohint` to prevent hints. First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. | `>t` or `>t 5 nohint` `>tl` | Shows a current trivia leaderboard. | `>tl` `>tq` | Quits current trivia after current question. | `>tq` -###### [Back to TOC](#table-of-contents) +###### [Back to ToC](#table-of-contents) ### Help Command and aliases | Description | Usage ----------------|--------------|------- `-modules` `-mdls` | Lists all bot modules. | `-modules` -`-commands` `-cmds` | List all of the bot's commands from a certain module. You can either specify full, or only first few letters of the module name. | `-commands Administration` or `-cmds Admin` -`-help` `-h` | Either shows a help for a single command, or DMs you help link if no arguments are specified. | `-h !!q` or `-h` -`-hgit` | Generates the commandlist.md file. **Bot Owner only.** | `-hgit` +`-commands` `-cmds` | List all of the bot's commands from a certain module. You can either specify the full name or only the first few letters of the module name. | `-commands Administration` or `-cmds Admin` +`-help` `-h` | Either shows a help for a single command, or DMs you help link if no arguments are specified. | `-h -cmds` or `-h` +`-hgit` | Generates the commandlist.md file. **Bot Owner Only** | `-hgit` `-readme` `-guide` | Sends a readme and a guide links to the channel. | `-readme` or `-guide` `-donate` | Instructions for helping the project financially. | `-donate` -###### [Back to TOC](#table-of-contents) +###### [Back to ToC](#table-of-contents) ### Music Command and aliases | Description | Usage @@ -203,34 +209,34 @@ Command and aliases | Description | Usage `!!stop` `!!s` | Stops the music and clears the playlist. Stays in the channel. | `!!s` `!!destroy` `!!d` | Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) | `!!d` `!!pause` `!!p` | Pauses or Unpauses the song. | `!!p` -`!!fairplay` `!!fp` | Toggles fairplay. While enabled, music player will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue. | `!!fp` -`!!queue` `!!q` `!!yq` | Queue a song using keywords or a link. Bot will join your voice channel.**You must be in a voice channel**. | `!!q Dream Of Venice` -`!!soundcloudqueue` `!!sq` | Queue a soundcloud song using keywords. Bot will join your voice channel.**You must be in a voice channel**. | `!!sq Dream Of Venice` +`!!fairplay` `!!fp` | Toggles fairplay. While enabled, the bot will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue. | `!!fp` +`!!queue` `!!q` `!!yq` | Queue a song using keywords or a link. Bot will join your voice channel. **You must be in a voice channel**. | `!!q Dream Of Venice` +`!!soundcloudqueue` `!!sq` | Queue a soundcloud song using keywords. Bot will join your voice channel. **You must be in a voice channel**. | `!!sq Dream Of Venice` `!!listqueue` `!!lq` | Lists 15 currently queued songs per page. Default page is 1. | `!!lq` or `!!lq 2` -`!!nowplaying` `!!np` | Shows the song currently playing. | `!!np` -`!!volume` `!!vol` | Sets the music volume 0-100% | `!!vol 50` +`!!nowplaying` `!!np` | Shows the song that the bot is currently playing. | `!!np` +`!!volume` `!!vol` | Sets the music playback volume (0-100%) | `!!vol 50` `!!defvol` `!!dv` | Sets the default music volume when music playback is started (0-100). Persists through restarts. | `!!dv 80` `!!shuffle` `!!sh` | Shuffles the current playlist. | `!!sh` `!!playlist` `!!pl` | Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `!!pl playlist link or name` -`!!soundcloudpl` `!!scpl` | Queue a soundcloud playlist using a link. | `!!scpl soundcloudseturl` -`!!localplaylst` `!!lopl` | Queues all songs from a directory. **Bot Owner only.** | `!!lopl C:/music/classical` +`!!soundcloudpl` `!!scpl` | Queue a Soundcloud playlist using a link. | `!!scpl soundcloudseturl` +`!!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` +`!!local` `!!lo` | Queues a local file by specifying a full path. **Bot Owner Only** | `!!lo C:/music/mysong.mp3` `!!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` `!!setmaxplaytime` `!!smp` | Sets a maximum number of seconds (>14) a song can run before being skipped automatically. Set 0 to have no limit. | `!!smp 0` or `!!smp 270` `!!reptcursong` `!!rcs` | Toggles repeat of current song. | `!!rcs` `!!rpeatplaylst` `!!rpl` | Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `!!rpl` -`!!save` | Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. | `!!save classical1` -`!!load` | Loads a saved playlist using it's ID. Use `!!pls` to list all saved playlists and !!save to save new ones. | `!!load 5` -`!!playlists` `!!pls` | Lists all playlists. Paginated. 20 per page. Default page is 0. | `!!pls 1` -`!!deleteplaylist` `!!delpls` | Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!!delpls animu-5` +`!!save` | Saves a playlist under a certain name. Playlist name must be no longer than 20 characters and must not contain dashes. | `!!save classical1` +`!!load` | Loads a saved playlist using its ID. Use `!!pls` to list all saved playlists and `!!save` to save new ones. | `!!load 5` +`!!playlists` `!!pls` | Lists all playlists. Paginated, 20 per page. Default page is 0. | `!!pls 1` +`!!deleteplaylist` `!!delpls` | Deletes a saved playlist. Works only if you made it or if you are the bot owner. | `!!delpls animu-5` `!!goto` | Goes to a specific time in seconds in a song. | `!!goto 30` -`!!autoplay` `!!ap` | Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty) | `!!ap` +`!!autoplay` `!!ap` | Toggles autoplay - When the song is finished, automatically queue a related Youtube song. (Works only for Youtube songs and when queue is empty) | `!!ap` `!!setmusicchannel` `!!smch` | Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in. **Requires ManageMessages server permission.** | `!!smch` -###### [Back to TOC](#table-of-contents) +###### [Back to ToC](#table-of-contents) ### NSFW Command and aliases | Description | Usage @@ -240,24 +246,24 @@ Command and aliases | Description | Usage `~hentaibomb` | Shows a total 5 images (from gelbooru, danbooru, konachan, yandere and atfbooru). Tag is optional but preferred. | `~hentaibomb yuri` `~yandere` | Shows a random image from yandere with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~yandere tag1+tag2` `~konachan` | Shows a random hentai image from konachan with a given tag. Tag is optional but preferred. | `~konachan yuri` -`~rule34` | Shows a random image from rule34.xx with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~rule34 yuri+kissing` `~e621` | Shows a random hentai image from e621.net with a given tag. Tag is optional but preferred. Use spaces for multiple tags. | `~e621 yuri kissing` +`~rule34` | Shows a random image from rule34.xx with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~rule34 yuri+kissing` `~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` `~gelbooru` | Shows a random hentai image from gelbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~gelbooru yuri+kissing` `~cp` | We all know where this will lead you to. | `~cp` `~boobs` | Real adult content. | `~boobs` `~butts` `~ass` `~butt` | Real adult content. | `~butts` or `~ass` -###### [Back to TOC](#table-of-contents) +###### [Back to ToC](#table-of-contents) ### Permissions Command and aliases | Description | Usage ----------------|--------------|------- `;verbose` `;v` | Sets whether to show when a command/module is blocked. | `;verbose true` -`;permrole` `;pr` | Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'. | `;pr role` +`;permrole` `;pr` | Sets a role which can change permissions. Supply no parameters to see the current one. Default is 'Nadeko'. | `;pr role` `;listperms` `;lp` | Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions. | `;lp` or `;lp 3` -`;removeperm` `;rp` | Removes a permission from a given position in Permissions list. | `;rp 1` -`;moveperm` `;mp` | Moves permission from one position to another in Permissions list. | `;mp 2 4` +`;removeperm` `;rp` | Removes a permission from a given position in the Permissions list. | `;rp 1` +`;moveperm` `;mp` | Moves permission from one position to another in the Permissions list. | `;mp 2 4` `;srvrcmd` `;sc` | Sets a command's permission at the server level. | `;sc "command name" disable` `;srvrmdl` `;sm` | Sets a module's permission at the server level. | `;sm ModuleName enable` `;usrcmd` `;uc` | Sets a command's permission at the user level. | `;uc "command name" enable SomeUsername` @@ -270,31 +276,30 @@ Command and aliases | Description | Usage `;allrolemdls` `;arm` | Enable or disable all modules for a specific role. | `;arm [enable/disable] MyRole` `;allusrmdls` `;aum` | Enable or disable all modules for a specific user. | `;aum enable @someone` `;allsrvrmdls` `;asm` | Enable or disable all modules for your server. | `;asm [enable/disable]` -`;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` -`;cbl` | Either [add]s or [rem]oves a channel specified by an ID from a blacklist. **Bot Owner only.** | `;cbl rem 12312312312` -`;sbl` | Either [add]s or [rem]oves a server specified by a Name or ID from a blacklist. **Bot Owner only.** | `;sbl add 12312321312` or `;sbl rem SomeTrashServer` -`;cmdcooldown` `;cmdcd` | Sets a cooldown per user for a command. Set to 0 to remove the cooldown. | `;cmdcd "some cmd" 5` +`;ubl` | Either [add]s or [rem]oves a user specified by a Mention or an ID from a blacklist. **Bot Owner Only** | `;ubl add @SomeUser` or `;ubl rem 12312312313` +`;cbl` | Either [add]s or [rem]oves a channel specified by an ID from a blacklist. **Bot Owner Only** | `;cbl rem 12312312312` +`;sbl` | Either [add]s or [rem]oves a server specified by a Name or an ID from a blacklist. **Bot Owner Only** | `;sbl add 12312321312` or `;sbl rem SomeTrashServer` +`;cmdcooldown` `;cmdcd` | Sets a cooldown per user for a command. Set it to 0 to remove the cooldown. | `;cmdcd "some cmd" 5` `;allcmdcooldowns` `;acmdcds` | Shows a list of all commands and their respective cooldowns. | `;acmdcds` -`;cmdcosts` | Shows a list of command costs. Paginated with 9 command per page. | `;cmdcosts` or `;cmdcosts 2` -`;srvrfilterinv` `;sfi` | Toggles automatic deleting of invites posted in the server. Does not affect Bot Owner. | `;sfi` -`;chnlfilterinv` `;cfi` | Toggles automatic deleting of invites posted in the channel. Does not negate the ;srvrfilterinv enabled setting. Does not affect Bot Owner. | `;cfi` -`;srvrfilterwords` `;sfw` | Toggles automatic deleting of messages containing forbidden words on the server. Does not affect Bot Owner. | `;sfw` -`;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` +`;srvrfilterinv` `;sfi` | Toggles automatic deletion of invites posted in the server. Does not affect the Bot Owner. | `;sfi` +`;chnlfilterinv` `;cfi` | Toggles automatic deletion of invites posted in the channel. Does not negate the `;srvrfilterinv` enabled setting. Does not affect the Bot Owner. | `;cfi` +`;srvrfilterwords` `;sfw` | Toggles automatic deletion of messages containing filtered words on the server. Does not affect the Bot Owner. | `;sfw` +`;chnlfilterwords` `;cfw` | Toggles automatic deletion of messages containing filtered words on the channel. Does not negate the `;srvrfilterwords` enabled setting. Does not affect the 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` -###### [Back to TOC](#table-of-contents) +###### [Back to ToC](#table-of-contents) ### Pokemon Command and aliases | Description | Usage ----------------|--------------|------- `>attack` | Attacks a target with the given move. Use `>movelist` to see a list of moves your type can use. | `>attack "vine whip" @someguy` `>movelist` `>ml` | Lists the moves you are able to use | `>ml` -`>heal` | Heals someone. Revives those who fainted. Costs a NadekoFlower | `>heal @someone` +`>heal` | Heals someone. Revives those who fainted. Costs a NadekoFlower. | `>heal @someone` `>type` | Get the poketype of the target. | `>type @someone` `>settype` | Set your poketype. Costs a NadekoFlower. Provide no arguments to see a list of available types. | `>settype fire` or `>settype` -###### [Back to TOC](#table-of-contents) +###### [Back to ToC](#table-of-contents) ### Searches Command and aliases | Description | Usage @@ -304,39 +309,37 @@ Command and aliases | Description | Usage `~imdb` `~omdb` | Queries omdb for movies or series, show first result. | `~imdb Batman vs Superman` `~randomcat` `~meow` | Shows a random cat image. | `~meow` `~randomdog` `~woof` | Shows a random dog image. | `~woof` -`~image` `~img` | Pulls the first image found using a search parameter. Use ~rimg for different results. | `~img cute kitten` +`~image` `~img` | Pulls the first image found using a search parameter. Use `~rimg` for different results. | `~img cute kitten` `~randomimage` `~rimg` | Pulls a random image using a search parameter. | `~rimg cute kitten` `~lmgtfy` | Google something for an idiot. | `~lmgtfy query` `~shorten` | Attempts to shorten an URL, if it fails, returns the input URL. | `~shorten https://google.com` -`~google` `~g` | Get a google search link for some terms. | `~google query` +`~google` `~g` | Get a Google search link for some terms. | `~google query` `~magicthegathering` `~mtg` | Searches for a Magic The Gathering card. | `~magicthegathering about face` or `~mtg about face` `~hearthstone` `~hs` | Searches for a Hearthstone card and shows its image. Takes a while to complete. | `~hs Ysera` -`~yodify` `~yoda` | Translates your normal sentences into Yoda styled sentences! | ~yodify I was once an adventurer like you` or `~yoda my feelings hurt` +`~yodify` `~yoda` | Translates your normal sentences into Yoda styled sentences! | `~yoda my feelings hurt` `~urbandict` `~ud` | Searches Urban Dictionary for a word. | `~ud Pineapple` `~define` `~def` | Finds a definition of a word. | `~def heresy` `~#` | Searches Tagdef.com for a hashtag. | `~# ff` `~catfact` | Shows a random catfact from | `~catfact` -`~revav` | Returns a google reverse image search for someone's avatar. | `~revav "@SomeGuy"` -`~revimg` | Returns a google reverse image search for an image from a link. | `~revimg Image link` +`~revav` | Returns a Google reverse image search for someone's avatar. | `~revav "@SomeGuy"` +`~revimg` | Returns a Google reverse image search for an image from a link. | `~revimg Image link` `~safebooru` | Shows a random image from safebooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~safebooru yuri+kissing` `~wikipedia` `~wiki` | Gives you back a wikipedia link | `~wiki query` `~color` `~clr` | Shows you what color corresponds to that hex. | `~clr 00ff00` `~videocall` | Creates a private video call link for you and other mentioned people. The link is sent to mentioned people via a private message. | `~videocall "@SomeGuy"` `~avatar` `~av` | Shows a mentioned person's avatar. | `~av "@SomeGuy"` `~wikia` | Gives you back a wikia link | `~wikia mtg Vigilance` or `~wikia mlp Dashy` -`~minecraftping` `~mcping` | Pings a minecraft server. | `~mcping 127.0.0.1:25565` -`~minecraftquery` `~mcq` | Finds information about a minecraft server. | `~mcq server:ip` `~lolban` | Shows top banned champions ordered by ban rate. | `~lolban` -`~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/ | `~memelist` -`~memegen` | Generates a meme from memelist with top and bottom text. | `~memegen biw "gets iced coffee" "in the winter"` -`~mal` | Shows basic info from myanimelist profile. | `~mal straysocks` +`~mal` | Shows basic info from a MyAnimeList profile. | `~mal straysocks` `~anime` `~ani` `~aq` | Queries anilist for an anime and shows the first result. | `~ani aquarion evol` `~manga` `~mang` `~mq` | Queries anilist for a manga and shows the first result. | `~mq Shingeki no kyojin` `~yomama` `~ym` | Shows a random joke from | `~ym` `~randjoke` `~rj` | Shows a random joke from | `~rj` -`~chucknorris` `~cn` | Shows a random chucknorris joke from | `~cn` +`~chucknorris` `~cn` | Shows a random Chuck Norris joke from | `~cn` `~wowjoke` | Get one of Kwoth's penultimate WoW jokes. | `~wowjoke` -`~magicitem` `~mi` | Shows a random magicitem from | `~mi` +`~magicitem` `~mi` | Shows a random magic item from | `~mi` +`~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/ | `~memelist` +`~memegen` | Generates a meme from memelist with top and bottom text. | `~memegen biw "gets iced coffee" "in the winter"` `~osu` | Shows osu stats for a player. | `~osu Name` or `~osu Name taiko` `~osub` | Shows information about an osu beatmap. | `~osub https://osu.ppy.sh/s/127712` `~osu5` | Displays a user's top 5 plays. | `~osu5 Name` @@ -352,50 +355,53 @@ Command and aliases | Description | Usage `~removestream` `~rms` | Removes notifications of a certain streamer from a certain platform on this channel. **Requires ManageMessages server permission.** | `~rms Twitch SomeGuy` or `~rms Beam SomeOtherGuy` `~checkstream` `~cs` | Checks if a user is online on a certain streaming platform. | `~cs twitch MyFavStreamer` `~translate` `~trans` | Translates from>to text. From the given language to the destination language. | `~trans en>fr Hello` -`~autotrans` `~at` | Starts automatic translation of all messages by users who set their `~atl` in this channel. You can set "del" argument to automatically delete all translated user messages. **Requires Administrator server permission.** **Bot Owner only.** | `~at` or `~at del` -`~autotranslang` `~atl` | `~atl en>fr` | Sets your source and target language to be used with `~at`. Specify no arguments to remove previously set value. +`~autotrans` `~at` | Starts automatic translation of all messages by users who set their `~atl` in this channel. You can set "del" argument to automatically delete all translated user messages. **Requires Administrator server permission.** **Bot Owner Only** | `~at` or `~at del` +`~autotranslang` `~atl` | Sets your source and target language to be used with `~at`. Specify no arguments to remove previously set value. | `~atl en>fr` `~translangs` | Lists the valid languages for translation. | `~translangs` `~xkcd` | Shows a XKCD comic. No arguments will retrieve random one. Number argument will retrieve a specific comic, and "latest" will get the latest one. | `~xkcd` or `~xkcd 1400` or `~xkcd latest` -###### [Back to TOC](#table-of-contents) +###### [Back to ToC](#table-of-contents) ### Utility Command and aliases | Description | Usage ----------------|--------------|------- -`.rotaterolecolor` `.rrc` | Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. **Requires ManageRoles server permission.** **Bot Owner only.** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole` +`.rotaterolecolor` `.rrc` | Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. **Requires ManageRoles server permission.** **Bot Owner Only** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole` `.togethertube` `.totube` | Creates a new room on and shows the link in the chat. | `.totube` `.whosplaying` `.whpl` | Shows a list of users who are playing the specified game. | `.whpl Overwatch` -`.inrole` | Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission. | `.inrole Role` +`.inrole` | Lists every person from the provided role or roles, separated with space, on this server. You can use role IDs, role names (in quotes if it has multiple words), or role mention If the list is too long for 1 message, you must have Manage Messages permission. | `.inrole Role` or `.inrole Role1 "Role 2" @role3` `.checkmyperms` | Checks your user-specific permissions on this channel. | `.checkmyperms` `.userid` `.uid` | Shows user ID. | `.uid` or `.uid "@SomeGuy"` `.channelid` `.cid` | Shows current channel ID. | `.cid` `.serverid` `.sid` | Shows current server ID. | `.sid` -`.roles` | List roles on this server or a roles of a specific user if specified. Paginated. 20 roles per page. | `.roles 2` or `.roles @Someone` +`.roles` | List roles on this server or a roles of a specific user if specified. Paginated, 20 roles per page. | `.roles 2` or `.roles @Someone` `.channeltopic` `.ct` | Sends current channel's topic as a message. | `.ct` `.createinvite` `.crinv` | Creates a new invite which has infinite max uses and never expires. **Requires CreateInstantInvite channel permission.** | `.crinv` +`.shardstats` | Stats for shards. Paginated with 25 shards per page. | `.shardstats` or `.shardstats 2` +`.shardid` | Shows which shard is a certain guild on, by guildid. | `.shardid 117523346618318850` `.stats` | Shows some basic stats for Nadeko. | `.stats` `.showemojis` `.se` | Shows a name and a link to every SPECIAL emoji in the message. | `.se A message full of SPECIAL emojis` -`.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot Owner only.** | `.listservers 3` -`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner only.** | `.savechat 150` -`.activity` | Checks for spammers. **Bot Owner only.** | `.activity` +`.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot Owner Only** | `.listservers 3` +`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.savechat 150` +`.activity` | Checks for spammers. **Bot Owner Only** | `.activity` `.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1` -`.calcops` | Shows all available operations in .calc command | `.calcops` -`.scsc` | Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. **Bot Owner only.** | `.scsc` +`.calcops` | Shows all available operations in the `.calc` command | `.calcops` +`.scsc` | Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. **Bot Owner Only** | `.scsc` `.jcsc` | Joins current channel to an instance of cross server channel using the token. **Requires ManageServer server permission.** | `.jcsc TokenHere` -`.lcsc` | Leaves Cross server channel instance from this channel. **Requires ManageServer server permission.** | `.lcsc` +`.lcsc` | Leaves a cross server channel instance from this channel. **Requires ManageServer server permission.** | `.lcsc` `.serverinfo` `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | `.sinfo Some Server` `.channelinfo` `.cinfo` | Shows info about the channel. If no channel is supplied, it defaults to current one. | `.cinfo #some-channel` `.userinfo` `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | `.uinfo @SomeUser` `.repeatinvoke` `.repinv` | Immediately shows the repeat message on a certain index and restarts its timer. **Requires ManageMessages server permission.** | `.repinv 1` `.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2` -`.repeat` | Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` +`.repeat` | Repeat a message every `X` minutes in the current channel. You can have up to 5 repeating messages on the server in total. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` `.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist` `.listquotes` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page. `...` | Shows a random quote with a specified name. | `... abc` +`.qsearch` | Shows a random quote for a keyword that contains any text specified in the search. | `.qsearch keyword text` `..` | Adds a new quote with the specified name and message. | `.. sayhi Hi` `.deletequote` `.delq` | Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. | `.delq abc` `.delallq` `.daq` | Deletes all quotes on a specified keyword. **Requires Administrator server permission.** | `.delallq kek` -`.remind` | Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message. | `.remind me 1d5h Do something` or `.remind #general 1m Start now!` -`.remindtemplate` | Sets message for when the remind is triggered. Available placeholders are %user% - user who ran the command, %message% - Message specified in the remind, %target% - target channel of the remind. **Bot Owner only.** | `.remindtemplate %user%, do %message%!` +`.remind` | Sends a message to you or a channel after certain amount of time. First argument is `me`/`here`/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword) message. | `.remind me 1d5h Do something` or `.remind #general 1m Start now!` +`.remindtemplate` | Sets message for when the remind is triggered. Available placeholders are `%user%` - user who ran the command, `%message%` - Message specified in the remind, `%target%` - target channel of the remind. **Bot Owner Only** | `.remindtemplate %user%, do %message%!` `.convertlist` | List of the convertible dimensions and currencies. | `.convertlist` `.convert` | Convert quantities. Use `.convertlist` to see supported dimensions and currencies. | `.convert m km 1000` From 751bd85b3ee387360399acb54d8fbfdf15618dca Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 4 Mar 2017 03:15:31 +0100 Subject: [PATCH 432/746] move or stay almost complete --- .../Modules/Gambling/Commands/MoveOrStay.cs | 90 +++++--- .../Resources/CommandStrings.Designer.cs | 194 +++++++++++------- src/NadekoBot/Resources/CommandStrings.resx | 20 +- 3 files changed, 203 insertions(+), 101 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/MoveOrStay.cs b/src/NadekoBot/Modules/Gambling/Commands/MoveOrStay.cs index e7ca6434..04120aa6 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/MoveOrStay.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/MoveOrStay.cs @@ -1,4 +1,5 @@ using System.Collections.Concurrent; +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Text; @@ -14,28 +15,54 @@ namespace NadekoBot.Modules.Gambling //public partial class Gambling //{ // [Group] - // public class MoveOrStayCommands : NadekoSubmodule + // public class Lucky7Commands : NadekoSubmodule // { // [NadekoCommand, Usage, Description, Aliases] // [RequireContext(ContextType.Guild)] // [OwnerOnly] - // public async Task MoveOrStayTest() + // public async Task Lucky7Test(uint tests) // { - // //test 1, just stop on second one + // if (tests <= 0) + // return; - // //test 2, stop when winning + // var dict = new Dictionary(); + // var totalWon = 0; + // for (var i = 0; i < tests; i++) + // { + // var g = new Lucky7Game(10); + // while (!g.Ended) + // { + // if (g.CurrentPosition == 0) + // g.Stay(); + // else + // g.Move(); + // } + // totalWon += (int)(g.CurrentMultiplier * g.Bet); + // if (!dict.ContainsKey(g.CurrentMultiplier)) + // dict.Add(g.CurrentMultiplier, 0); + // dict[g.CurrentMultiplier] ++; + + // } + + // await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + // .WithTitle("Move Or Stay test") + // .WithDescription(string.Join("\n", + // dict.Select(x => $"x{x.Key} occured {x.Value} times {x.Value * 1.0f / tests * 100:F2}%"))) + // .WithFooter( + // efb => efb.WithText($"Total Bet: {tests * 10} | Payout: {totalWon} | {totalWon *1.0f / tests * 10}%"))); // } - // private static readonly ConcurrentDictionary _games = new ConcurrentDictionary(); + // private static readonly ConcurrentDictionary _games = + // new ConcurrentDictionary(); // [NadekoCommand, Usage, Description, Aliases] // [RequireContext(ContextType.Guild)] - // public async Task MoveOrStay(int bet) + // public async Task Lucky7(int bet) // { // if (bet < 4) // return; - // var game = new MoveOrStayGame(bet); + // var game = new Lucky7Game(bet); // if (!_games.TryAdd(Context.User.Id, game)) // { // await ReplyAsync("You're already betting on move or stay.").ConfigureAwait(false); @@ -44,14 +71,15 @@ namespace NadekoBot.Modules.Gambling // if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User, "MoveOrStay bet", bet, false)) // { - // await ReplyAsync("You don't have enough money"); + // _games.TryRemove(Context.User.Id, out game); + // await ReplyConfirmLocalized("not_enough", CurrencySign).ConfigureAwait(false); // return; // } - // await Context.Channel.EmbedAsync(GetGameState(game), + // await Context.Channel.EmbedAsync(GetGameState(game), // string.Format("{0} rolled {1}.", Context.User, game.Rolled)).ConfigureAwait(false); // } - // public enum Mors + // public enum MoveOrStay // { // Move = 1, // M = 1, @@ -61,38 +89,40 @@ namespace NadekoBot.Modules.Gambling // [NadekoCommand, Usage, Description, Aliases] // [RequireContext(ContextType.Guild)] - // public async Task MoveOrStay(Mors action) + // public async Task Lucky7(MoveOrStay action) // { - // MoveOrStayGame game; + // Lucky7Game game; // if (!_games.TryGetValue(Context.User.Id, out game)) // { // await ReplyAsync("You're not betting on move or stay.").ConfigureAwait(false); // return; // } - // if (action == Mors.Move) + // if (action == MoveOrStay.Move) // { // game.Move(); - // await Context.Channel.EmbedAsync(GetGameState(game), string.Format("{0} rolled {1}.", Context.User, game.Rolled)).ConfigureAwait(false); if (game.Ended) + // await Context.Channel.EmbedAsync(GetGameState(game), + // string.Format("{0} rolled {1}.", Context.User, game.Rolled)).ConfigureAwait(false); + // if (game.Ended) // _games.TryRemove(Context.User.Id, out game); // } - // else if (action == Mors.Stay) + // else if (action == MoveOrStay.Stay) // { // var won = game.Stay(); // await CurrencyHandler.AddCurrencyAsync(Context.User, "MoveOrStay stay", won, false) // .ConfigureAwait(false); // _games.TryRemove(Context.User.Id, out game); - // await ReplyAsync(string.Format("You've finished with {0}", - // won + CurrencySign)) + // await ReplyAsync(string.Format("You've finished with {0}", + // won + CurrencySign)) // .ConfigureAwait(false); // } - + // } - // private EmbedBuilder GetGameState(MoveOrStayGame game) + // private EmbedBuilder GetGameState(Lucky7Game game) // { - // var arr = MoveOrStayGame.Winnings.ToArray(); + // var arr = Lucky7Game.Winnings.ToArray(); // var sb = new StringBuilder(); // for (var i = 0; i < arr.Length; i++) // { @@ -110,18 +140,18 @@ namespace NadekoBot.Modules.Gambling // } // return new EmbedBuilder().WithOkColor() - // .WithTitle("Move or Stay") + // .WithTitle("Lucky7") // .WithDescription(sb.ToString()) // .AddField(efb => efb.WithName("Bet") - // .WithValue(game.Bet.ToString()) - // .WithIsInline(true)) + // .WithValue(game.Bet.ToString()) + // .WithIsInline(true)) // .AddField(efb => efb.WithName("Current Value") - // .WithValue((game.CurrentMultiplier * game.Bet).ToString(_cultureInfo)) - // .WithIsInline(true)); + // .WithValue((game.CurrentMultiplier * game.Bet).ToString(_cultureInfo)) + // .WithIsInline(true)); // } // } - // public class MoveOrStayGame + // public class Lucky7Game // { // public int Bet { get; } // public bool Ended { get; private set; } @@ -130,13 +160,13 @@ namespace NadekoBot.Modules.Gambling // public int Rolled { get; private set; } // public float CurrentMultiplier => Winnings[CurrentPosition]; // private readonly NadekoRandom _rng = new NadekoRandom(); - + // public static readonly ImmutableArray Winnings = new[] // { - // 1.5f, 0.75f, 1f, 0.5f, 0.25f, 0.25f, 2.5f, 0f, 0f + // 1.2f, 0.8f, 0.75f, 0.90f, 0.7f, 0.5f, 1.8f, 0f, 0f // }.ToImmutableArray(); - // public MoveOrStayGame(int bet) + // public Lucky7Game(int bet) // { // Bet = bet; // Move(); @@ -150,7 +180,7 @@ namespace NadekoBot.Modules.Gambling // Rolled = _rng.Next(1, 4); // CurrentPosition += Rolled; - // if (CurrentPosition >= 7) + // if (CurrentPosition >= 6) // Ended = true; // } diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 2ea37420..41965836 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -150,7 +150,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Add a custom reaction with a trigger and a response. Running this command in server requires Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: <http://nadekobot.readthedocs.io/en/latest/Custom%20Reactions/>. + /// Looks up a localized string similar to Add a custom reaction with a trigger and a response. Running this command in server requires the Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: <http://nadekobot.readthedocs.io/en/latest/Custom%20Reactions/>. /// public static string addcustreact_desc { get { @@ -177,7 +177,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued%, %time%,%shardid%,%shardcount%, %shardguilds%. + /// Looks up a localized string similar to Adds a specified string to the list of playing strings to rotate. Supported placeholders: `%servers%`, `%users%`, `%playing%`, `%queued%`, `%time%`, `%shardid%`, `%shardcount%`, `%shardguilds%`.. /// public static string addplaying_desc { get { @@ -231,7 +231,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Toggles the automatic deletion of confirmations for {0}iam and {0}iamn commands.. + /// Looks up a localized string similar to Toggles the automatic deletion of confirmations for `{0}iam` and `{0}iamn` commands.. /// public static string adsarm_desc { get { @@ -420,7 +420,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sends a message to all servers' general channel bot is connected to.. + /// Looks up a localized string similar to Sends a message to all servers' default channel that bot is connected to.. /// public static string announce_desc { get { @@ -501,7 +501,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10.. + /// Looks up a localized string similar to Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10.. /// public static string antispam_desc { get { @@ -690,7 +690,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty). + /// Looks up a localized string similar to Toggles autoplay - When the song is finished, automatically queue a related Youtube song. (Works only for Youtube songs and when queue is empty). /// public static string autoplay_desc { get { @@ -1014,7 +1014,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set 0 to disable automatic deletion.. + /// Looks up a localized string similar to Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion.. /// public static string byedel_desc { get { @@ -1041,7 +1041,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded.. + /// Looks up a localized string similar to Sets a new leave announcement message. Type `%user%` if you want to show the name the user who left. Type `%id%` to show id. Using this command with no message will show the current bye message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded.. /// public static string byemsg_desc { get { @@ -1068,7 +1068,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Shows all available operations in {0}calc command. + /// Looks up a localized string similar to Shows all available operations in the `{0}calc` command. /// public static string calcops_desc { get { @@ -1419,7 +1419,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Toggles automatic deleting of invites posted in the channel. Does not negate the {0}srvrfilterinv enabled setting. Does not affect Bot Owner.. + /// Looks up a localized string similar to Toggles automatic deletion of invites posted in the channel. Does not negate the `{0}srvrfilterinv` enabled setting. Does not affect the Bot Owner.. /// public static string chnlfilterinv_desc { get { @@ -1446,7 +1446,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Toggles automatic deleting of messages containing banned words on the channel. Does not negate the {0}srvrfilterwords enabled setting. Does not affect bot owner.. + /// Looks up a localized string similar to Toggles automatic deletion of messages containing filtered words on the channel. Does not negate the `{0}srvrfilterwords` enabled setting. Does not affect the Bot Owner.. /// public static string chnlfilterwords_desc { get { @@ -1527,7 +1527,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random>. + /// Looks up a localized string similar to Shows a random Chuck Norris joke from <http://tambal.azurewebsites.net/joke/random>. /// public static string chucknorris_desc { get { @@ -1743,7 +1743,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets a cooldown per user for a command. Set to 0 to remove the cooldown.. + /// Looks up a localized string similar to Sets a cooldown per user for a command. Set it to 0 to remove the cooldown.. /// public static string cmdcooldown_desc { get { @@ -1770,7 +1770,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Shows a list of command costs. Paginated with 9 command per page.. + /// Looks up a localized string similar to Shows a list of command costs. Paginated with 9 commands per page.. /// public static string cmdcosts_desc { get { @@ -1851,7 +1851,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to List all of the bot's commands from a certain module. You can either specify full, or only first few letters of the module name.. + /// Looks up a localized string similar to List all of the bot's commands from a certain module. You can either specify the full name or only the first few letters of the module name.. /// public static string commands_desc { get { @@ -2310,7 +2310,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration priviledges and removes server custom reaction.. + /// Looks up a localized string similar to Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration privileges and removes server custom reaction.. /// public static string delcustreact_desc { get { @@ -2337,7 +2337,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Deletes a saved playlist. Only if you made it or if you are the bot owner.. + /// Looks up a localized string similar to Deletes a saved playlist. Works only if you made it or if you are the bot owner.. /// public static string deleteplaylist_desc { get { @@ -2391,7 +2391,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Toggles the automatic deletion of user's successful command message to prevent chat flood.. + /// Looks up a localized string similar to Toggles the automatic deletion of the user's successful command message to prevent chat flood.. /// public static string delmsgoncmd_desc { get { @@ -2607,7 +2607,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to List of lovely people who donated to keep this project alive.. + /// Looks up a localized string similar to List of the lovely people who donated to keep this project alive.. /// public static string donators_desc { get { @@ -2715,7 +2715,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Toggles fairplay. While enabled, music player will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue.. + /// Looks up a localized string similar to Toggles fairplay. While enabled, the bot will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue.. /// public static string fairplay_desc { get { @@ -2823,7 +2823,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json. + /// Looks up a localized string similar to Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json file. /// public static string forwardtoall_desc { get { @@ -2931,7 +2931,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Get a google search link for some terms.. + /// Looks up a localized string similar to Get a Google search link for some terms.. /// public static string google_desc { get { @@ -3012,7 +3012,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set 0 to disable automatic deletion.. + /// Looks up a localized string similar to Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to 0 to disable automatic deletion.. /// public static string greetdel_desc { get { @@ -3066,7 +3066,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded.. + /// Looks up a localized string similar to Sets a new join announcement message which will be sent to the user who joined. Type `%user%` if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded.. /// public static string greetdmmsg_desc { get { @@ -3093,7 +3093,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded.. + /// Looks up a localized string similar to Sets a new join announcement message which will be shown in the server's channel. Type `%user%` if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded.. /// public static string greetmsg_desc { get { @@ -3156,7 +3156,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}h !!q` or `{0}h`. + /// Looks up a localized string similar to `{0}h {0}cmds` or `{0}h`. /// public static string h_usage { get { @@ -3174,7 +3174,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets the music volume to 50%.. + /// Looks up a localized string similar to Sets the music playback volume to 50%.. /// public static string half_desc { get { @@ -3282,7 +3282,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Heals someone. Revives those who fainted. Costs a NadekoFlower. + /// Looks up a localized string similar to Heals someone. Revives those who fainted. Costs a NadekoFlower. . /// public static string heal_desc { get { @@ -3498,7 +3498,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Pulls the first image found using a search parameter. Use {0}rimg for different results.. + /// Looks up a localized string similar to Pulls the first image found using a search parameter. Use `{0}rimg` for different results.. /// public static string image_desc { get { @@ -3687,7 +3687,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language.. + /// Looks up a localized string similar to Sets this server's response language. If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language.. /// public static string languageset_desc { get { @@ -3768,7 +3768,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Leaves Cross server channel instance from this channel.. + /// Looks up a localized string similar to Leaves a cross server channel instance from this channel.. /// public static string lcsc_desc { get { @@ -3795,7 +3795,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Displays bot currency leaderboard.. + /// Looks up a localized string similar to Displays the bot's currency leaderboard.. /// public static string leaderboard_desc { get { @@ -3822,7 +3822,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Makes Nadeko leave the server. Either name or id required.. + /// Looks up a localized string similar to Makes Nadeko leave the server. Either server name or server ID is required.. /// public static string leave_desc { get { @@ -4128,7 +4128,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}lw [war_number] or {0}lw`. + /// Looks up a localized string similar to `{0}lw [war_number]` or `{0}lw`. /// public static string listwar_usage { get { @@ -4173,7 +4173,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Loads a saved playlist using it's ID. Use `{0}pls` to list all saved playlists and {0}save to save new ones.. + /// Looks up a localized string similar to Loads a saved playlist using its ID. Use `{0}pls` to list all saved playlists and `{0}save` to save new ones.. /// public static string load_desc { get { @@ -4254,7 +4254,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Toggles logging event. Disables it if it's active anywhere on the server. Enables if it's not active. Use `{0}logevents` to see a list of all events you can subscribe to.. + /// Looks up a localized string similar to Toggles logging event. Disables it if it is active anywhere on the server. Enables if it isn't active. Use `{0}logevents` to see a list of all events you can subscribe to.. /// public static string log_desc { get { @@ -4308,7 +4308,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel.. + /// Looks up a localized string similar to Toggles whether the `.logserver` command ignores this channel. Useful if you have hidden admin channel and public log channel.. /// public static string logignore_desc { get { @@ -4460,6 +4460,60 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to lucky7 l7. + /// + public static string lucky7_cmd { + get { + return ResourceManager.GetString("lucky7_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bet currency on the game and start rolling 3 sided dice. At any point you can choose to [m]ove (roll again) or [s]tay (get the amount bet times the current multiplier).. + /// + public static string lucky7_desc { + get { + return ResourceManager.GetString("lucky7_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}l7 10` or `{0}l7 move` or `{0}l7 s`. + /// + public static string lucky7_usage { + get { + return ResourceManager.GetString("lucky7_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to lucky7test l7t. + /// + public static string lucky7test_cmd { + get { + return ResourceManager.GetString("lucky7test_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tests the l7 command.. + /// + public static string lucky7test_desc { + get { + return ResourceManager.GetString("lucky7test_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}l7t 10000`. + /// + public static string lucky7test_usage { + get { + return ResourceManager.GetString("lucky7test_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to magicitem mi. /// @@ -4470,7 +4524,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items>. + /// Looks up a localized string similar to Shows a random magic item from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items>. /// public static string magicitem_desc { get { @@ -4524,7 +4578,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Shows basic info from myanimelist profile.. + /// Looks up a localized string similar to Shows basic info from a MyAnimeList profile.. /// public static string mal_desc { get { @@ -4578,7 +4632,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets the music volume to 100%.. + /// Looks up a localized string similar to Sets the music playback volume to 100%.. /// public static string max_desc { get { @@ -4713,7 +4767,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission.. + /// Looks up a localized string similar to Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have the mention everyone permission.. /// public static string mentionrole_desc { get { @@ -4848,7 +4902,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Moves permission from one position to another in Permissions list.. + /// Looks up a localized string similar to Moves permission from one position to another in the Permissions list.. /// public static string moveperm_desc { get { @@ -4956,7 +5010,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Shows the song currently playing.. + /// Looks up a localized string similar to Shows the song that the bot is currently playing.. /// public static string nowplaying_desc { get { @@ -5145,7 +5199,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'.. + /// Looks up a localized string similar to Sets a role which can change permissions. Supply no parameters to see the current one. Default is 'Nadeko'.. /// public static string permrole_desc { get { @@ -5307,7 +5361,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Lists all playlists. Paginated. 20 per page. Default page is 0.. + /// Looks up a localized string similar to Lists all playlists. Paginated, 20 per page. Default page is 0.. /// public static string playlists_desc { get { @@ -5469,7 +5523,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}prune` removes all nadeko's messages in the last 100 messages.`{0}prune X` removes last X messages from the channel (up to 100)`{0}prune @Someone` removes all Someone's messages in the last 100 messages.`{0}prune @Someone X` removes last X 'Someone's' messages in the channel.. + /// Looks up a localized string similar to `{0}prune` removes all Nadeko's messages in the last 100 messages. `{0}prune X` removes last `X` number of messages from the channel (up to 100). `{0}prune @Someone` removes all Someone's messages in the last 100 messages. `{0}prune @Someone X` removes last `X` number of 'Someone's' messages in the channel.. /// public static string prune_desc { get { @@ -5523,7 +5577,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Queue a song using keywords or a link. Bot will join your voice channel.**You must be in a voice channel**.. + /// Looks up a localized string similar to Queue a song using keywords or a link. Bot will join your voice channel. **You must be in a voice channel**.. /// public static string queue_desc { get { @@ -5793,7 +5847,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message.. + /// Looks up a localized string similar to Sends a message to you or a channel after certain amount of time. First argument is `me`/`here`/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword) message.. /// public static string remind_desc { get { @@ -5820,7 +5874,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets message for when the remind is triggered. Available placeholders are %user% - user who ran the command, %message% - Message specified in the remind, %target% - target channel of the remind.. + /// Looks up a localized string similar to Sets message for when the remind is triggered. Available placeholders are `%user%` - user who ran the command, `%message%` - Message specified in the remind, `%target%` - target channel of the remind.. /// public static string remindtemplate_desc { get { @@ -5901,7 +5955,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Removes a permission from a given position in Permissions list.. + /// Looks up a localized string similar to Removes a permission from a given position in the Permissions list.. /// public static string removeperm_desc { get { @@ -6009,7 +6063,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Renames a role. Roles you are renaming must be lower than bot's highest role.. + /// Looks up a localized string similar to Renames a role. The role you are renaming must be lower than bot's highest role.. /// public static string renamerole_desc { get { @@ -6036,7 +6090,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total.. + /// Looks up a localized string similar to Repeat a message every `X` minutes in the current channel. You can have up to 5 repeating messages on the server in total.. /// public static string repeat_desc { get { @@ -6198,7 +6252,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Resets BOT's permissions module on this server to the default value.. + /// Looks up a localized string similar to Resets the bot's permissions module on this server to the default value.. /// public static string resetpermissions_desc { get { @@ -6252,7 +6306,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Returns a google reverse image search for someone's avatar.. + /// Looks up a localized string similar to Returns a Google reverse image search for someone's avatar.. /// public static string revav_desc { get { @@ -6279,7 +6333,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Returns a google reverse image search for an image from a link.. + /// Looks up a localized string similar to Returns a Google reverse image search for an image from a link.. /// public static string revimg_desc { get { @@ -6387,7 +6441,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to List roles on this server or a roles of a specific user if specified. Paginated. 20 roles per page.. + /// Looks up a localized string similar to List roles on this server or a roles of a specific user if specified. Paginated, 20 roles per page.. /// public static string roles_desc { get { @@ -6414,7 +6468,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to 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.. + /// Looks up a localized string similar to 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.. /// public static string roll_desc { get { @@ -6441,7 +6495,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to 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.. + /// Looks up a localized string similar to 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`.. /// public static string rolluo_desc { get { @@ -6522,7 +6576,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Play a game of rocket paperclip scissors with Nadeko.. + /// Looks up a localized string similar to Play a game of Rocket-Paperclip-Scissors with Nadeko.. /// public static string rps_desc { get { @@ -6630,7 +6684,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes.. + /// Looks up a localized string similar to Saves a playlist under a certain name. Playlist name must be no longer than 20 characters and must not contain dashes.. /// public static string save_desc { get { @@ -6738,7 +6792,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prepend channel id with `c:` and user id with `u:`.. + /// Looks up a localized string similar to Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prefix the channel id with `c:` and the user id with `u:`.. /// public static string send_desc { get { @@ -6765,7 +6819,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Either [add]s or [rem]oves a server specified by a Name or ID from a blacklist.. + /// Looks up a localized string similar to Either [add]s or [rem]oves a server specified by a Name or an ID from a blacklist.. /// public static string serverblacklist_desc { get { @@ -7548,7 +7602,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Queue a soundcloud playlist using a link.. + /// Looks up a localized string similar to Queue a Soundcloud playlist using a link.. /// public static string soundcloudpl_desc { get { @@ -7575,7 +7629,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Queue a soundcloud song using keywords. Bot will join your voice channel.**You must be in a voice channel**.. + /// Looks up a localized string similar to Queue a soundcloud song using keywords. Bot will join your voice channel. **You must be in a voice channel**.. /// public static string soundcloudqueue_desc { get { @@ -7629,7 +7683,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Toggles automatic deleting of invites posted in the server. Does not affect Bot Owner.. + /// Looks up a localized string similar to Toggles automatic deletion of invites posted in the server. Does not affect the Bot Owner.. /// public static string srvrfilterinv_desc { get { @@ -7656,7 +7710,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Toggles automatic deleting of messages containing forbidden words on the server. Does not affect Bot Owner.. + /// Looks up a localized string similar to Toggles automatic deletion of messages containing filtered words on the server. Does not affect the Bot Owner.. /// public static string srvrfilterwords_desc { get { @@ -8088,7 +8142,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Starts a game of trivia. You can add nohint to prevent hints.First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question.. + /// Looks up a localized string similar to Starts a game of trivia. You can add `nohint` to prevent hints. First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question.. /// public static string trivia_desc { get { @@ -8439,7 +8493,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Either [add]s or [rem]oves a user specified by a mention or ID from a blacklist.. + /// Looks up a localized string similar to Either [add]s or [rem]oves a user specified by a Mention or an ID from a blacklist.. /// public static string userblacklist_desc { get { @@ -8682,7 +8736,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Creates a text channel for each voice channel only users in that voice channel can see.If you are server owner, keep in mind you will see them all the time regardless.. + /// Looks up a localized string similar to Creates a text channel for each voice channel only users in that voice channel can see. If you are server owner, keep in mind you will see them all the time regardless.. /// public static string voiceplustext_desc { get { @@ -8763,7 +8817,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sets the music volume 0-100%. + /// Looks up a localized string similar to Sets the music playback volume (0-100%). /// public static string volume_desc { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 3d01eb34..3379b98b 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3150,4 +3150,22 @@ `{0}rategirl @SomeGurl` - + + lucky7test l7t + + + Tests the l7 command. + + + `{0}l7t 10000` + + + lucky7 l7 + + + Bet currency on the game and start rolling 3 sided dice. At any point you can choose to [m]ove (roll again) or [s]tay (get the amount bet times the current multiplier). + + + `{0}l7 10` or `{0}l7 move` or `{0}l7 s` + + \ No newline at end of file From f37a2c4db9469b92f83d7d6f8fa661c5ab43a061 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 4 Mar 2017 17:02:25 +0100 Subject: [PATCH 433/746] added zh-CN --- .../Commands/LocalizationCommands.cs | 1 + .../{MoveOrStay.cs => Lucky7Commands.cs} | 0 .../Resources/ResponseStrings.zh-CN.resx | 2193 +++++++++++++++++ 3 files changed, 2194 insertions(+) rename src/NadekoBot/Modules/Gambling/Commands/{MoveOrStay.cs => Lucky7Commands.cs} (100%) create mode 100644 src/NadekoBot/Resources/ResponseStrings.zh-CN.resx diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 45dedc1d..c02a828c 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -25,6 +25,7 @@ namespace NadekoBot.Modules.Administration //{"nl-NL", "Dutch, Netherlands"}, //{"ja-JP", "Japanese, Japan"}, {"pt-BR", "Portuguese, Brazil"}, + {"zh-CN", "Chinese (Simplified), China"} //{"sr-Cyrl-RS", "Serbian, Serbia - Cyrillic"} }.ToImmutableDictionary(); diff --git a/src/NadekoBot/Modules/Gambling/Commands/MoveOrStay.cs b/src/NadekoBot/Modules/Gambling/Commands/Lucky7Commands.cs similarity index 100% rename from src/NadekoBot/Modules/Gambling/Commands/MoveOrStay.cs rename to src/NadekoBot/Modules/Gambling/Commands/Lucky7Commands.cs diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx b/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx new file mode 100644 index 00000000..f9185084 --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx @@ -0,0 +1,2193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 此基地已被认领或毁坏。 + + + 此基地已被毁坏 + + + + 此基地还未被认领 + + + 在与{1} 对战时**毁坏**基地 #{0} + + + {0} 在与 {2} 对战时 **取消认领** 基地 #{1} + + + {0} 在与 {2} 对战时 **认领** 基地 #{1} + + + @{0} 您已认领基地 #{1}。您不能认领一个新的。 + + + @{0} 在与 {1} 对战后认领的基地已过期。 + + + 敌人 + + + 与{0} 对战的信息 + + + 此基地号码无效。 + + + 此战争大小无效 + + + 现进行的战争列表 + + + 未被认领 + + + 您并未参与此战争。 + + + @{0} 您并未参与此战争或此基地已被毁坏。 + + + 现无战争进行。 + + + 大小 + + + 与{0}的战争已开始。 + + + 与{0}的战争已创建。 + + + 与{0}的战争已结束。 + + + 此战争不存在。 + + + 与{0}的对战已开始! + + + 所有定制反应清除。 + + + 定制反应删除 + + + 权限不足。通用定制反应需要机器人主人之权限而服务器定制反应需要管理员之权限。 + + + 列出所有定制反应 + + + 定制反应 + + + 新定制反应 + + + 没有找到定制反应。 + + + 于此用户标识相联系的定制反应并未找到。 + + + 回应 + + + 定制反应数据 + + + {0} 定制反应数据清除。 + + + 此触发器并无数据, 因此无行动。 + + + 触发器 + + + 自动变态模式停止。 + + + 没有结果。 + + + {0} 已昏厥。 + + + {0} 气血已满。 + + + 您的属性已是 {0} + + + 对 {2}{3} 使出{0}{1} 而造成 {4}伤害。 + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + 您不能在对方未反击之前再次攻击! + + + 您不能攻击自己。 + + + {0} 已昏厥! + + + 用 {1} 医好 {0} + + + {0} 还剩余 {1} 生命值。 + + + 您不能使用{0}. 输入`{1}ml` 观看您能用的招式。 + + + {0} 属性的招式列表 + + + 没有效果。 + + + 你并没有足够的 {0} + + + 使用 {1} 复活 {0} + + + 您使用 {0} 复活自己 + + + 您的属性已从 {0} 改成了 {1} + + + 效果不理想。 + + + 效果绝佳! + + + 您已一连使用太多招式,所以您不能行动! + + + {0} 的属性是 {1} + + + 该用户不存在。 + + + 您已昏厥所以不能移动! + + + **已解除**.为刚加入的用户 **自动指派身份** 的功能。 + + + **已启动**.为刚加入的用户 **自动指派身份** 的功能。 + + + 附件 + + + 头像更换成功。 + + + 你已经被{0}服务器封号。 +原因: {1} + + + 你被禁止了 + PLURAL + + + 用户禁止 + + + 机器人名改成{0} + + + 机器人状态换成{0} + + + 自动告别消息关闭。 + + + 告别消息将在{0}秒钟内删除。 + + + 现在告别消息: {0} + + + 输入{0}以启用告别消息 + + + 新告别消息设定。 + + + 告别公告被关掉。 + + + 此频道启用告别公告。 + + + 频道名字已改 + + + 旧名 + + + 频道主题已改 + + + 清理完毕。 + + + 内容 + + + 身份 {0} 成功创立 + + + 文字频道 {0} 成功创立 + + + 语音频道 {0} 成功创立 + + + 静音成功 + + + 服务器 {0} 已被删除 + + + 自动删除已处理指令已被停止 + + + 自动删除已处理指令已被启动 + + + 文字频道 {0} 成功删除 + + + 语音频道 {0} 成功删除 + + + 私人信息来自 + + + 成功添加新的捐赠者. 此用户总共捐赠了: {0} + + + 感谢下面列出的人们使这个项目发生! + + + 我会将DM转发给所有业主。 + + + 我会将DM转发给第一个业主。 + + + 我将从现在起转发DMs。 + + + 从现在开始我将停止转发DMs。 + + + 已关闭自动删除欢迎消息。 + + + 欢迎消息将在{0}秒后删除。 + + + 现DM欢迎消息:{0} + + + 输入{0}启用DM欢迎消息 + + + 新DM欢迎消息设定成功。 + + + DM欢迎公告关闭。 + + + DM欢迎公告启用。 + + + 当前欢迎消息是:{0} + + + 输入{0}来启用欢迎消息 + + + 新欢迎消息设定成功。 + + + 欢迎公告关闭。 + + + 欢迎公告在此频道开启。 + + + 您不能对身份层次结构中身份高于或等于您的身份的用户使用此命令。 + + + {0}秒后加载图片! + + + 输入格式不正确。 + + + 参数不正确。 + + + {0} 加入了 {1} + + + 你被踢出{0}的服务器。 +理由:{1} + + + 用户已被踢出 + + + 语言列表 +{0} + + + 您的服务器的语言设置现在为{0} - {1} + + + 机器人的默认语言环境现在是{0} - {1} + + + 机器人的语言设置为{0} - {1} + + + 设置语言设置失败。 重新访问此命令帮助。 + + + 此服务器的语言设置为{0} - {1} + + + {0}已离开{1} + + + 离开服务器{0} + + + 在此频道中记录{0}事件。 + + + 记录频道中所有事件 + + + 记录功能取消 + + + 您可以设定的记录项目: + + + 记录会忽略{0} + + + 记录不会忽略{0} + + + 已停止记录{0}事件。 + + + {0}已经提到了以下身份 + + + 来自{0}`[机器人主人]’的消息: + + + 消息已发. + + + {0}被移动由{1}到{2} + + + 在#{0}中删除讯息 + + + 讯息在#{0}中被更新 + + + 已静音 + PLURAL (users have been muted) + + + 已静音 + singular "User muted." + + + 权限不够执行此命令 + + + 新的静音角色设定成功。 + + + 我需要**管理**权限才能做那个。 + + + 新消息 + + + 新昵称 + + + 新主题 + + + 昵称成功更换 + + + 找不到该服务器 + + + 找不到具有该ID的分片。 + + + 旧信息 + + + 旧昵称 + + + 旧题目 + + + 失败。很可能我没有足够的权限。 + + + 重置此服务器的权限。 + + + 主动保护 + + + {0}已在此服务器禁用。 + + + {0}已启用。 + + + 失败。 我需要 ManageRoles 权限 + + + 未启用保护项目。 + + + 用户阈值必须介于{0}和{1}之间。 + + + 如果{0}或更多用户在{1}秒内加入,我将{2}他们。 + + + 时间必须在{0}和{1}秒之间。 + + + 已成功从用户{0}中移除所有身份 + + + 无法移除身份。 我没有足够的权限。 + + + {0}身份的颜色已更改。 + + + 那个身份不存在。 + + + 指定的参数错误。 + + + 由于颜色无效或权限不足而发生错误。 + + + 已成功从用户{1}中删除身份{0} + + + 无法移除身份。 我没有足够的权限。 + + + 身份名已改 + + + 身份重命名失败。我的权限不足。 + + + 您不能编辑比你 + + + 已移除游玩消息:{0} + + + 身份{0}已添加到列表中。 + + + {0}未找到。已清理。 + + + 身份{0}已在列表中。 + + + 添加成功. + + + 旋转游玩状态关闭。 + + + 旋转游玩状态开启。 + + + 以下是旋转状态列表: +{0} + + + 未设置旋转游戏状态。 + + + 您已经拥有{0}身份。 + + + 您已拥有{0}独占的自行分配。 + + + 自行分配身份现在是独家! + + + 有{0}个可自行分配身份 + + + 这个身份是不可自行分配的。 + + + 您没有{0}身份。 + + + 自我分配的身份现在不是独家的! + + + 我无法向您添加该身份。 ‘我不能向身份层次结构中我身份以外的所有者或其他身份添加身份。’ + + + {0}已从可自我分配身份列表中删除。 + + + 您不再拥有{0}身份。 + + + 您现在拥有{0}身份。 + + + 已成功将身份{0}添加到用户{1} + + + 无法添加身份。 我没有足够的权限。 + + + 新头像集! + + + 新频道名称设定。 + + + 新游戏设定! + + + 新直播设定! + + + 新频道主题集。 + + + 分段{0}已重新连接。 + + + 分段{0}重新连接中。 + + + 关闭中 + + + 用户不能在{1}秒内发送超过{0}条消息。 + + + 慢速模式关闭。 + + + 慢速模式启动 + + + 软禁(踢出) + PLURAL + + + {0}将忽略此通道。 + + + 0}将不再忽略此通道。 + + + 如果用户发布{0}个相同的消息,我会{1}他们。 +     __IgnoredChannels__:{2} + + + 新文字频道成立 + + + 文字频道已删除 + + + Undeafen成功。 + + + 已取消静音 + singular + + + 用户名 + + + 用户名已更改 + + + 用户 + + + 用户被禁止 + + + {0}已从聊天内被静音**。 + + + {0}已从聊天内**取消静音**。 + + + 用户已加入 + + + 用户离开了 + + + {0} 已被文字与语音静音了 + + + 用户身份添加成功 + + + 用户身份移除了 + + + {0} 改成了 {1} + + + {0}已从文字和语音频道中取消静音**。 + + + {0}已加入{1}语音通道。 + + + {0}已离开{1}语音通道。 + + + {0}已从{1}移至{2}语音通道。 + + + {0}已被**静音**。 + + + {0}已被**取消静音**。 + + + 语音频道已创建 + + + 语音通道已被毁 + + + 已停用语音+文字功能。 + + + 启用语音+文字功能。 + + + 我没有**管理身份**和/或**管理频道**权限,所以我不能在{0}服务器上运行`语音+文字`。 + + + 您正在启用/禁用此功能,并且**我没有ADMINISTRATOR权限**。 这可能会导致一些问题,您必须自己清理文本频道。 + + + 我需要至少**管理身份**和**管理频道**权限,以启用此功能。 (优先管理权限) + + + 用户{0}来自文字频道 + + + 用户{0}来自文字和语音频道 + + + 用户{0}来自语音频道 + + + 您已从{0}服务器软禁止。 +原因:{1} + + + 用户已取消禁止 + + + 迁移完成! + + + 在迁移时出错,请检查机器人的控制台以获取更多信息。 + + + 在线状态更新 + + + 用户被软禁用 + + + 已将{0}奖励给{1} + + + 下一次好运^ _ ^ + + + 恭喜! 您赢得{0}因为您滚{1}或以上 + + + 卡牌改组。 + + + 抛了{0}。 + User flipped tails. + + + 你猜到了! 您赢得了{0} + + + 指定的数字无效。 你可以抛1到{0}钱币。 + + + 将{0}反应添加到此消息以获取{1} + + + 此活动在{0}小时内有效。 + + + 花反应活动开始了! + + + 给了{1}{0} + X has gifted 15 flowers to Y + + + {0}拥有{1} + X has Y flowers + + + + + + 排行榜 + + + 从{2}身份授予{0}至{1}名用户。 + + + 您赌注不能超过{0} + + + 您赌注不能低于{0} + + + 您没有足够的{0} + + + 卡牌组中没有更多的牌。 + + + 抽奖用户 + + + 您抛了{0}。 + + + 赌注 + + + 哇啊啊啊啊啊啊! 恭喜! x {0} + + + 单个{0},x {1} + + + 哇!好运! 三个相同! x {0} + + + 做得好! 两个{0} - 投注x {1} + + + 胜利 + + + 用户必须键入密码才能获取{0}。 +持续{1}秒。 嘘~别跟任何人说。 + + + SneakyGame事件结束。 {0}个用户收到了奖励。 + + + SneakyGameStatus事件已启动 + + + + + + 已成功从{1}取得{0} + + + 无法从{1}取得{0},因为用户没有那么多{2}! + + + 返回ToC + + + 仅限Bot Owner + + + 需要{0}频道权限。 + + + 您可以在patreon上支持项目:<{0}>或paypal:<{1}> + + + 命令和别名 + + + 命令列表已重新生成。 + + + 输入`{0} h CommandName`可查看该指定命令的帮助。 例如 `{0} h> 8ball` + + + 我找不到该命令。 请再次尝试之前验证该命令是否存在。 + + + 描述 + + + 您可以在: +Patreon <{0}>或 +Paypal <{1}> +上支持NadekoBot +不要忘记在邮件中留下您的不和名字或ID。 + +**谢谢**♥️ + + + **命令列表**:<{0}> +**主机指南和文档可以在这里找到**:<{1}> + + + 命令列表 + + + 组件列表 + + + 输入“{0} cmds ModuleName”以获取该组件中的命令列表。 例如`{0} cmds games` + + + 该组件不存在。 + + + 需要{0}服务器权限。 + + + 目录 + + + 用法 + + + 自动hentai启动。 使用以下标记之一重新排列每个{0}: +{1} + + + 标签 + + + 动物竞赛 + + + 启动失败,因为没有足够的参与者。 + + + 竞赛已满! 立即开始。 + + + {0}加入为{1} + + + {0}加入为{1},赌注{2}! + + + 输入{0} jr 以加入竞赛。 + + + 在20内秒或当房间满后开始。 + + + {0}个参与者开始。 + + + {0}为{1}赢得竞赛! + + + 0}为{1}赢得竞赛,和赢得{2}! + + + 指定的数字无效。 您可以一次滚动{0} - {1}骰子。 + + + 掷了{0} + Someone rolled 35 + + + 掷骰子:{0} + Dice Rolled: 5 + + + 竞赛启动失败。 另一个比赛可能正在运行。 + + + 此服务器上不存在竞赛 + + + 第二个数字必须大于第一个数字。 + + + 爱被改变 + + + 声称 + + + 离婚 + + + 喜欢 + + + 价钱 + + + 没有waifus被要求。 + + + 最佳Waifus + + + 您的兴趣已设置为该waifu,或者您尝试在没有兴趣的情况下删除您的兴趣。 + + + 将把兴趣从{0}更改为{1}。 + +*这在道德上是有问题的*🤔 + Make sure to get the formatting right, and leave the thinking emoji + + + 您必须等待{0}小时和{1}分钟才能再次更改您的兴趣。 + + + 您的兴趣已重置。 你不再有你喜欢的人。 + + + 想成为{0}的waifu。哇非常可爱<3 + + + 声明{0}为他的waifu,花了{1}! + + + 你已经离婚了一个喜欢你的waifu。 你无情的怪物。 +{0}收到了{1}作为补偿。 + + + 你不能设置兴趣自己,你好自卑。 + + + 🎉他的爱实现! 🎉 +{0}的新值为{1}! + + + 没有waifu那么便宜。 您必须至少支付{0}才能获得waifu,即使他们的实际价值较低。 + + + 您必须支付{0}或更多才能认领那个waifu! + + + 那waifu不是你的。 + + + 你不能认领自己。 + + + 你最近离婚了。 您必须等待{0}小时和{1}分钟再次离婚。 + + + 没人 + + + 你离婚了一个不喜欢你的waifu。 您收到了{0}。 + + + 8ball + + + 恐惧症游戏 + + + 游戏结束,没人提交。 + + + 没人投票。 游戏结束,没有赢家。 + + + 首字母缩写是{0}。 + + + 恐惧症游戏已经在这个频道中运行。 + + + 游戏开始。 创建具有以下首字母缩写的句子:{0}。 + + + 您有{0}秒的时间提交。 + + + {0}提交了他的判决。 (总{1}个) + + + 通过输入提交数字投票 + + + {0}投了票! + + + 获胜者{0}获得{1}分。 + + + {0}赢了因为是唯一的提交用户! + + + + + + 平局! 两个都挑了{0} + + + {0}赢了! {1} 打赢了 {2} + + + 提交关闭 + + + 动物竞赛已经运行。 + + + 总计:{0} 平均:{1} + + + 类别 + + + 在此服务器上禁用cleverbot。 + + + 在此服务器上启用cleverbot。 + + + 在此频道上停用的货币生成功能。 + + + 在此频道上启用的货币生成功能。 + + + {0} 个 {1}出现了! 通过输入`{2} pick'来拾取 + plural + + + 一个{0}出现了! 通过输入`{1} pick`来拾取 + + + 加载问题失败。 + + + 游戏开始 + + + Hangman游戏开始了 + + + Hangman游戏已在此频道上打开。 + + + 启动hangman错误。 + + + “{0} hangman”字词类型列表: + + + 排行榜 + + + 您没有足够的{0} + + + 没有结果 + + + 采了{0} + Kwoth picked 5* + + + {0}种了{1} + Kwoth planted 5* + + + 琐事游戏已经在这个服务器上运行。 + + + 琐事游戏 + + + {0}猜对了! 答案是:{1} + + + 此服务器上没有运行琐事游戏。 + + + {0}有{1}分 + + + 这个问题后停止。 + + + 时间到! 正确的答案是{0} + + + {0}猜到了,赢得了游戏! 答案是:{1} + + + 你不能对自己玩。 + + + TicTacToe游戏已在此频道中运行。 + + + 平局! + + + 开始了一局TicTacToe游戏。 + + + {0}赢了! + + + 相配了三个 + + + 没有地方动了! + + + 时间已过! + + + 轮到{0}了 + + + {0}对{1} + + + 正在排{0}首歌... + + + 已停用自动播放。 + + + 已启用自动播放。 + + + 默认音量设置为{0}% + + + 目录队列完成。 + + + 公平播放 + + + 完成歌曲 + + + 停用公平播放。 + + + 启用公平播放。 + + + 从位置 + + + ID + + + 输入错误。 + + + 最大播放时间没有限制移除。 + + + 最大播放时间设置为{0}秒。 + + + 最大音乐队列大小设置为无限。 + + + 最大音乐队列大小设置为{0}首。 + + + 您需要在此服务器上加入语音频道。 + + + + + + 现在播放 + + + 没有活动音乐播放器。 + + + + 没有搜索结果。 + + + 音乐播放暂停。 + + + 播放器队列 - {0} / {1}页 + + + 正在播放 + + + `#{0}` - ** {1} ** by * {2} *({3}首歌) + + + 有保存{0}页的播放列表 + + + 播放列表已删除。 + + + 无法删除该播放列表。 它不存在,或者你不是它的作者。 + + + 具有该ID的播放列表不存在。 + + + 播放列表队列完成。 + + + 播放列表已保存 + + + {0}秒限制 + + + 队列 + + + 歌加入队列 + + + 音乐队列已清除。 + + + 队列已满{0} / {0}。 + + + 歌被移除 + context: "removed song #5" + + + 重复播放当前歌曲 + + + 重复播放列表 + + + 重复曲目 + + + 当前曲目停止重复。 + + + 音乐播放已恢复。 + + + 禁用重复播放列表 + + + 重复播放列表已启用。 + + + 我现在将在此频道里输出播放,完成,暂停和删除歌曲。 + + + 跳到‘{0}:{1}’ + + + 歌播放列表曲被随机。 + + + 歌曲被移动 + + + {0}小时 {1}分钟 {2}秒 + + + 到位置 + + + 无限 + + + 音量必须介于0和100之间 + + + 音量设置为{0}% + + + 在{0}频道上禁止所有组件的使用。 + + + 在{0}频道上允许启用所有组件。 + + + 允许 + + + {0}身份的所有组件被禁止使用。 + + + {0}身份的所有组件被允许使用。 + + + 在此服务器上禁止所有组件的使用。 + + + 在此服务器上允许所有组件的使用。 + + + {0}用户的所有模块被禁止使用。 + + + {0}用户的所有模块被允许使用。 + + + ID为{1}被加入黑名单{0} + + + 命令{0}冷却时间现有{1}秒。 + + + 命令{0}没有冷却时间了,现有所有的冷却时间已被清除。 + + + 没有设置命令冷却时间。 + + + 命令成本 + + + {2}频道上已停用{0} {1}。 + + + 已在{2}频道上启用{0} {1}的使用。 + + + 被拒绝 + + + 以巴{0}添加到已过滤字词列表中。 + + + 被过滤的词列表 + + + 已从过滤字词列表中删除{0}。 + + + 第二个参数无效(必须是{0}和{1}之间的数字) + + + 在此频道上停用邀请过滤功能。 + + + 在此频道上启用邀请过滤。 + + + 在此服务器上停用邀请过滤功能。 + + + 在此服务器上启用邀请过滤功能。 + + + 已将权限{0}从#{1}移至#{2} + + + 在索引#{0}找不到权限 + + + 未设置费用。 + + + 命令 + Gen (of command) + + + 组件 + Gen. (of module) + + + 权限页面第{0}页 + + + 当前权限身份为{0}。 + + + 用户现在需要{0}身份才能编辑权限。 + + + 在该索引中找不到权限。 + + + 已删除权限#{0} - {1} + + + 禁止{2}身份使用{0} {1}。 + + + 允许{2}身份使用{0} {1}。 + + + + Short of seconds. + + + 此服务器上的{0} {1}已被禁止使用。 + + + 此服务器上的{0} {1}已被允许使用。 + + + ID为{1}的{0}从黑名单上移除 + + + 不可编辑 + + + {2}用户的{0} {1}已被禁止使用。 + + + {2}用户的{0} {1}已允许使用。 + + + 我将不再显示权限警告。 + + + 我现在将显示权限警告。 + + + 此频道上的字过滤已停用。 + + + 此频道上的字过滤已启用。 + + + 此服务器上的字过滤已停用。 + + + 此服务器上的字过滤已启用。 + + + 能力 + + + 没有最喜爱的动漫 + + + 开始自动翻译此频道上的消息。 用户消息将被自动删除。 + + + 您的自动翻译语言已删除。 + + + 您的自动翻译语言已设置为{0}> {1} + + + 开始自动翻译此频道上的消息。 + + + 停止自动翻译此频道上的消息。 + + + 错误格式或出现错误。 + + + 找不到该卡。 + + + + + + + + + 漫画# + + + 竞争模式失败次数 + + + 竞争模式玩次数 + + + 竞争模式排名 + + + 竞争模式胜利次数 + + + 完成 + + + 条件 + + + 花费 + + + 日期 + + + 定义: + + + 放掉 + + + 剧集 + + + 发生了错误。 + + + 例子 + + + 找不到那个动画。 + + + 找不到漫画。 + + + 类型 + + + 未能找到该标记的定义。 + + + 身高/体重 + + + {0} m / {1} kg + + + 湿度 + + + 图片搜索: + + + 找不到该电影。 + + + 来源或目标语言错误。 + + + 笑话没加载。 + + + 纬度/经度 + + + 等级 + + + {0}地方标记列表 + Don't translate {0}place + + + 地点 + + + 未加载魔术项目。 + + + {0}的MAL个人资料 + + + 机器人的业主没有指定MashapeApiKey。 您不能使用此功能。 + + + 最小/最大 + + + 找不到频道。 + + + 没找到结果。 + + + 等候接听 + + + 原始网址 + + + 需要osu!API密钥。 + + + 无法检索osu! 线索。 + + + 找到{0}张图片。 显示随机{0}。 + + + 找不到用户! 请再次前检查区域和BattleTag。 + + + 计划看 + + + 平台 + + + 找不到能力。 + + + 找不到宠物小精灵。 + + + 个人资料链接: + + + 质量: + + + 快速游戏时间 + + + 快赢 + + + 评分 + + + 得分: + + + 搜索: + + + 无法缩短该链接。 + + + 短链接 + + + 出了些问题。 + + + 请指定搜索参数。 + + + 状态 + + + 储存链接 + + + 直播台{0}已离线。 + + + 直播台{0}在线有{1}个观众。 + + + 您在此服务器上关注{0}个直播台 + + + 您未在此服务器上关注任何直播台。 + + + 没有这个直播台。 + + + 直播台可能不存在。 + + + 已从({1})的通知中移除{0}的直播台 + + + 状态更改时,我会通知此频道。 + + + 日出 + + + 日落 + + + 温度 + + + 标题: + + + 3个最喜欢的动画: + + + 翻译: + + + 类型 + + + 未能找到该字词的定义。 + + + 链接 + + + 观众 + + + 观看 + + + 无法在指定的维基上找到该字词。 + + + 请输入目标维基,然后搜索查询。 + + + 找不到网页。 + + + 风速 + + + {0}个被禁止最多的英雄 + + + 无法yodify您的句子。 + + + 加入 + + + `{0} .` {1} [{2:F2} / s] - {3}总计 + /s and total need to be localized to fit the context - +`1.` + + + 活动页面#{0} + + + {0}个用户。 + + + 作者 + + + 机器ID + + + {0} calc命令功能列表 + + + 此频道的{0}是{1} + + + 频道主题 + + + 执行命令 + + + {0} {1}等于{2} {3} + + + 转换器可以使用的单位 + + + 无法将{0}转换为{1}:找不到单位 + + + 无法将{0}转换为{1}:单位类型不相等 + + + 创建于 + + + 加入跨服务器频道。 + + + 离开跨服务器频道。 + + + 这是您的CSC令牌 + + + 自定义Emojis + + + 错误 + + + 特征 + + + + ID + + + 索引超出范围。 + + + 以下是这个身份的用户列表: + + + 您不能对其中有用户很多的身份使用此命令来防止滥用。 + + + 值{0}错误。 + Invalid months value/ Invalid hours value + + + 加入Discord + + + 加入服务器 + + + ID:{0} +会员数:{1} +业主ID:{2} + + + 在该网页上找不到服务器。 + + + 重复列表 + + + 会员 + + + 存储 + + + 讯息 + + + 消息重复功能 + + + 名字 + + + 昵称 + + + 没有人在玩那个游戏 + + + 没有活动重复功能。 + + + 此页面上没有身份。 + + + 此页面上没有分片。 + + + 没有主题设置。 + + + 业主 + + + 业主IDs + + + 状态 + + + {0}个服务器 +{1}个文字频道 +{2}个语音频道 + + + 删除所有引号使用{0}关键字。 + + + {0}页引号 + + + 此页面上没有引用。 + + + 没有您可以删除的引用。 + + + 引用被添加 + + + 删除了随机引用。 + + + 区域 + + + 注册日 + + + 我将在{2}`({3:d.M.yyyy。}的{4:HH:mm})提醒{0}关于{1} + + + 无效时间格式。 检查命令列表。 + + + 新的提醒模板被设定。 + + + 会每{1}天{2}小时{3}分钟重复{0}。 + + + 重复列表 + + + 此服务器上没有运行重复消息。 + + + #{0}已停止。 + + + 此服务器上没有找到被重复的消息。 + + + 结果 + + + 身份 + + + 此服务器上所有身份第{0}页: + + + {1}身份的第{0}页 + + + 颜色的格式不正确。 例如,使用‘#00ff00’。 + + + 开始轮流{0}身份的颜色。 + + + 停止{0}身份颜色轮流 + + + 此服务器的{0}是{1} + + + 服务器信息 + + + 分片 + + + 分片统计 + + + 分片**#{0} **处于{1}状态与{2}台服务器 + + + **名称:** {0} **链接:** {1} + + + 没有找到特殊的emojis。 + + + 正在播放{0}首歌,{1}首等待播放。 + + + 文字频道 + + + 这是你的房间链接: + + + 正常运行时间 + + + 此用户 {1} 的{0} 是 {2} + Id of the user kwoth#1234 is 123123123123 + + + 用户 + + + 语音频道 + + + \ No newline at end of file From 023bf46ed7616e49e0da873cb70aabb284781c33 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sat, 4 Mar 2017 17:04:37 +0100 Subject: [PATCH 434/746] Update ResponseStrings.nl-NL.resx (POEditor.com) --- .../Resources/ResponseStrings.nl-NL.resx | 335 +++++++++--------- 1 file changed, 175 insertions(+), 160 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx index b8945702..1363046f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx @@ -760,7 +760,7 @@ __IgnoredChannels__: {2} Tekst kanaal verwijderd. - + Ontdempen succesvol Ongedempt @@ -792,397 +792,411 @@ __IgnoredChannels__: {2} Gebruiker verlaten - Fuzzy - + {0} is **gedempt** van het tekst en stem kanaal. - Gebruiker's rol toegevoegd + Rol van gebruiker toegevoegd - Gebruiker's rol verwijderd + Rol van gebruiker verwijderd {0} is nu {1} - + {0} is **ongedempt** van het tekst en stem kanaal. - + {0} is {1} spraakkanaal toegetreden. - + {0} heeft {1} spraakkanaal verlaten. - + {0} heeft {1} naar {2} spraakkanaal verplaatst. - + {0} is **spraak gedempt** - + {0} is **spraak ongedempt** - + Spraakkanaal gemaakt - + Spraakkanaal vernietigd - + Spraak + tekst mogelijkheid uitgezet. - + Spraak + tekst mogelijkheid aangezet. - + Ik heb geen **Rol Beheering** en/of **Kanaal Beheering** toestemmingen, dus ik kan geen `stem+text` gebruiken op de {0} server. - + Deze eigenschap wordt door jou ingeschakelt/uitgeschakelt maar **Ik heb geen ADMINISTRATIEVE toestemmingen**. Hierdoor kunnen er mogelijk problemen ontstaan, en je zal daarna de tekst kanalen zelf moeten opruimen. - + Ik heb tenminste **Rol Beheering** en **Kanaal Beheering** toestemmingen nodig om deze eigenschap in te schakelen. (Geliefe adminstratieve rechten) - + Gebruiker {0} van tekstkanaal - + Gebruiker {0} van tekst- en spraakkanaal - + Gebruiker {0} van spraakkanaal - + Je bent zacht-verbannen van {0} server. +Reden: {1} - + Gebruiker niet meer verbannen - + Migratie gelukt! - + Fout tijdens het migreren, kijk in de bot's console voor meer informatie. - + Aanwezigheid Updates - + Gebruiker zacht-verbannen - + heeft {0} aan {1} gegeven - + Volgende keer beter ^_^ - + Gefeliciteerd! Je hebt {0} gewonnen voor het rollen boven de {1} - + Dek geschud. - + heeft de munt op {0} gegooid User flipped tails. - + Je hebt het goed gegokt! Je hebt {0} gewonnen - + Ongeldig nummer opgegeven. Je kan 1 tot {0} munten opgooien - + Voeg een {0} reactie toe aan dit bericht om {0} te krijgen - + Dit evenement blijft actief voor {0} uur. - + Bloemen reactie evenement gestart! - + heeft {0} aan {1} cadeau gegeven X has gifted 15 flowers to Y - + {0} heeft {1} X has Y flowers - + Kop - + Scoreboard - + {0} heeft {1} gebruikers beloont met {2} rol. - + Je kan niet meer dan {0} gokken - + Je kan niet minder dan {0} gokken - + Je hebt niet genoeg {0} - + Geen kaarten meer in het dek - + Verloten gebruiker - + Je hebt {0} gerold - + Inzet - + WOAAHHHHHH!!! Gefeliciteerd!!! x{0} - + Een enkele {0}, x{1} - + Wow! Gelukkig! Drie van dezelfde! x{0} - + Goed gedaan! Twee {0} - wed x{1} - + Gewonnen - + Gebruikers moeten een geheime code in typen om {0} te krijgen. +Duurt {1} seconden. Vertel het aan niemand. Shhh. - + SneakyGame evenement geeindigt. {0} gebruikers hebben een beloning ontvangen. - + SneakyGameStatus evenement gestart. - + Munt - + succesvol {0} van {1} genomen - + kon niet {0} van {1} nemen omdat de gebruiker niet zoveel {2} heeft! - + Terug naar de inhoudsopgave - + Alleen Voor Bot Eigenaren - + Heeft {0} kanaal rechten nodig. - + Je kan het project steunen op patreon: <{0}> of paypal: <{1}> - + Command en aliassen. - + Commandolijst Geregenereerd. - + Typ `{0}h CommandoNaam` om de hulp te zien voor die specifieke commando. b.v `{0}h >8bal` - + Ik kan die commando niet vinden. Verifiëren of die commando echt bestaat voor dat je het opnieuw probeert. - + Beschrijving - + Je kan het NadekoBot project steunen op +Patreon <{0}> of +Paypal <{1}> +Vergeet niet je discord naam en id in het bericht te zetten. + +**Hartelijk bedankt** ♥️ - + **Lijst met commando's**: <{0}> +**Hosting gidsen en documenten kunnen hier gevonden worden**: <{1}> - + Lijst Met Commando's - + Lijst Met Modules - + Typ `{0}cmds ModuleNaam` om een lijst van commando's te krijgen voor die module. bv `{0}cmds games` - + Deze module bestaat niet - + Heeft {0} server rechten nodig. - + Inhoudsopgave - + Gebruik - + Autohentai gestart. Elke {0}s word een foto geplaatst met de volgende labels: +{1} + Fuzzy - + Label - + Dieren race - + Gefaalt om te starten omdat er niet genoeg deelnemers zijn. - + De race is vol! De race wordt onmiddelijk gestart. - + {0} doet mee als een {1} - + {0} doet mee als een {1} en wed {2}! - + Typ {0}jr om mee te doen met de race. - + De race zal beginnen in 20 seconden of wanneer de kamer is vol. - + De race zal beginnen met {0} deelnemers. - + {0} heeft de race gewonnen als {1}! - + {0} heeft de race gewonnen als {1} en {2}! - + Ongeldig nummer ingevoerd. Je kan de dobbelsteen van {0}-{1} rollen. - + {0} gerold. Someone rolled 35 - + Dobbelsteen gerold: {0} Dice Rolled: 5 - + Gefaalt om de race te starten. Een andere race is waarschijnlijk bezig. - + Geen enkele race bestaat op deze server. - + Het tweede nummer moet groter zijn dan het eerste nummer. - + Verandering Van Het Hart - + Overwonnen door - + Scheidingen - + Leuk - + Prijs - + Nog geen waifus zijn overwonnen. - + Top Waifus - + Jouw affiniteit is al ingesteld op een waifu, of je probeert om je affiniteit weg te halen terwijl je geen hebt. - + Affiniteit verandert van {0} naar {1} + +Dit is moreel twijfelachtig🤔 Make sure to get the formatting right, and leave the thinking emoji - + Je moet {0} uren en {1} minuten wachten om je affiniteit weer te veranderen. - + Jouw affiniteit is gereset. Je hebt geen persoon meer die je leuk vindt. - + wil {0}'s waifu zijn. Aww <3 - + heeft {0} genomen als hun waifu voor {1}! - + Je bent gescheiden met een waifu die jou leuk vindt. Jij harteloze monster. +{0} ontvangen {1} als compensatie. - + Je kunt geen affiniteit zelf opzetten, jij opgeblazen egoist. - + 🎉Hun liefde overvloeit! 🎉 +{0} nieuwe waarde is {1}! - + Geen enkele waifu is zo goedkoop. Je moet tenminste {0} betalen om een waifu te krijgen, ook al is hun echte waarde lager. - + Je moet tenminste {0} betalen om die waifu te nemen! - + Die waifu is niet van jouw. - + Je kunt jezelf niet als waifu nemen. - + Je bent kort geleden gescheiden. Je moet {0} uren en {1} minuten wachten om weer te scheiden. - + Niemand - + Je bent gescheiden met een waifu die jou niet leuk vindt. Je krijgt {0} terug. - + 8bal - + Acrophobie - + Spel geëindigd zonder submissies. + Fuzzy - + Geen stemmen ingestuurdt. Spel geëindigd zonder winnaar. - + Afkorting was {0} - + Acrophobie spel is al bezig in dit kanaal. - + Game is gestart: maak een zin met de volgende afkorting: {0}. - + Je hebt {0} seconden om een inzending te maken. {0} heeft een zin ingezonden. ({1} in totaal) - + Stem door het nummer van een inzending te typen {0} heeft gestemd! @@ -1191,56 +1205,56 @@ __IgnoredChannels__: {2} De winnaar is {0} met {1} punten. - + {0} is de winnaar doordat deze als enige een inzending heeft gemaakt! - + Vraag - + Het is gelijkspel! Beiden hebben {0} gekozen - + {0} heeft gewonnen! {1} verslaat {2} - + Inzendingen gesloten. - + Dieren Race is al bezig. - + Totaal: {0} Gemiddelde: {1} - + Categorie - + Cleverbot is uitgeschakeld op deze server. - + Cleverbot is ingeschakeld op deze server. - + Valuta generatie is uitgeschakeld op dit kanaal. - + Valuta generatie is ingeschakeld op dit kanaal. - + {0} willekeurige {1} zijn verschenen! Pak ze op door `{2}pick` in te typen. plural - + Een willekeurige {0} is verschenen! Pak ze op door `{1}pick` in te typen. - + Het laden van de vraag is gefaalt. - + Spel gestart. - + Hangman @@ -2123,53 +2137,54 @@ __IgnoredChannels__: {2} - + Gestart met het routeren van kleuren voor de rol {0} + Fuzzy - + Gestopt met het routeren van kleuren voor de rol {0} - + {0} van deze server is {1} - + Server Informatie - + Shard - + Shard Statestieken - + Shard **#{0}** is in {1} status met {2} servers - + *Naam:** {0} **Link:** {1} - + Geen speciale emojis gevonden. - + {0} liedjes aan het spelen, {1} in de wachtrij - + Tekst Kanalen - + Hier is de link naar je sessie: - + {0} van de gebruker {1} is {2} Id of the user kwoth#1234 is 123123123123 - + Gebruikers - + Spraak Kanalen \ No newline at end of file From b8bb9dcddf33a68e8f3c1b4322d31f0ce98c6cd4 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sat, 4 Mar 2017 17:04:39 +0100 Subject: [PATCH 435/746] Update ResponseStrings.fr-fr.resx (POEditor.com) From 47595dc92686dd9bec456a7c23ecebcaca20e4dd Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sat, 4 Mar 2017 17:04:42 +0100 Subject: [PATCH 436/746] Update ResponseStrings.de-DE.resx (POEditor.com) --- .../Resources/ResponseStrings.de-DE.resx | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx index 6b61e5f6..318404de 100644 --- a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx @@ -139,7 +139,7 @@ @{0} sie haben die Basis #{1} bereits beansprucht. Sie können keine weitere beanspruchen. - Einnahme von @{0} für den Krieg gegen {1} ist abgelaufen. + Beanspruchung von @{0} für den Krieg gegen {1} ist abgelaufen. Gegner @@ -474,7 +474,7 @@ Grund: {1} {0} - Ihr Servers Sprachumgebung ist jetzt {1} - {1} + Die Sprachumgebung des Servers ist jetzt {1} - {1} Die Sprachumgebung des Bots ist nun {0} - {1} @@ -486,7 +486,8 @@ Grund: {1} Setzen der Sprachumgebung fehlgeschlagen. Greifen Sie auf diesen Befehls hilfe erneut auf. - Dieser Servers Sprache wurde zu {0} - {1} gesetzt + Diese Servers Sprache wurde zu {0} - {1} gesetzt + Fuzzy {0} verließ {1} @@ -872,7 +873,7 @@ Grund: {1} Nutzer wurde gekickt - vegab {0} zu {1} + gab {0} an {1} Hoffentlich haben Sie beim nächsten Mal mehr Glück ^_^ @@ -1295,10 +1296,10 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Wird beendet nach dieser Frage. - Die Zeit is um! Die richtige Antwort war {0} + Die Zeit ist um! Die richtige Antwort war {0} - {0} erriet es und hat das spiel GEWONNEN! Die Antwort war: {1} + {0} erriet es und hat das Spiel GEWONNEN! Die Antwort war: {1} Sie können nicht gegen sich selber spielen. @@ -1443,7 +1444,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu context: "removed song #5" - Aktuelle Lied wird wiederholt + Aktuelles Lied wird wiederholt Playlist wird wiederholt @@ -1617,7 +1618,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu {0} mit ID {1} von Sperrliste entfernt - Nicht Bearbeitbar + Nicht editierbar Benutzung von {0} {1} wurde für Benutzer {2} verboten. @@ -1626,7 +1627,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Benutzung von {0} {1} wurde für Benutzer {2} erlaubt. - Ich werde nicht mehr Warnungen für Rechte anzeigen. + Ich werde keine Warnungen für Rechte mehr anzeigen. Ich werde jetzt Warnungen für Rechte anzeigen. @@ -1647,10 +1648,10 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Fähigkeiten - Keine favoritisierten anime + Keine favorisierten anime - Startete die Automatische Übersetzung der Nachrichten auf diesem kanal. Nachrichten von Benutzern werden automatisch gelöscht. + Startete die Automatische Übersetzung der Nachrichten auf diesem Kanal. Nachrichten von Benutzern werden automatisch gelöscht. Ihre Automatische-Übersetzungs Sprache wurde entfernt. @@ -1799,19 +1800,19 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Über {0} Bilder gefunden. Zeige zufälliges {0}. - Benutzer nicht gefunden! Bitte überprüfe die Region und den BattleTag before erneuten versuchen. + Benutzer nicht gefunden! Bitte überprüfe die Region und den BattleTag bevor erneuten Versuchen. Vermerkte - Platform + Plattform Keine Fähigkeit gefunden. - Kein pokemon gefunden. + Kein Pokemon gefunden. Profil Link: @@ -1859,7 +1860,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Streamer {0} ist online mit {1} Zuschauern. - Sie folgen {0} Streamer auf diesem Server. + Sie folgen {0} Streamern auf diesem Server. Sie folgen keinem Streamer auf diesem Server. From e891373316b3ab247687ee70292def532925e4dd Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sat, 4 Mar 2017 17:04:45 +0100 Subject: [PATCH 437/746] Update ResponseStrings.pt-BR.resx (POEditor.com) From 6053886c57b6095a9985e0d628c99cf3956a5d95 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sat, 4 Mar 2017 17:04:47 +0100 Subject: [PATCH 438/746] Update ResponseStrings.ru-RU.resx (POEditor.com) From 8fd145a0bb1614b549d259f80a5971831a1a1356 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sat, 4 Mar 2017 17:04:50 +0100 Subject: [PATCH 439/746] Update ResponseStrings.zh-CN.resx (POEditor.com) --- .../Resources/ResponseStrings.zh-CN.resx | 234 +++++++++--------- 1 file changed, 117 insertions(+), 117 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx b/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx index f9185084..3d0396c5 100644 --- a/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx +++ b/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 此基地已被认领或毁坏。 From c4279d7f05da5e15caf4a8b73b7a4fee430ae4b5 Mon Sep 17 00:00:00 2001 From: samvaio Date: Sun, 5 Mar 2017 02:17:28 +0530 Subject: [PATCH 440/746] music cache always clears on update --- scripts/Latest.bat | 18 +++++++++++------- scripts/Stable.bat | 18 +++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/scripts/Latest.bat b/scripts/Latest.bat index a4f9e15b..aee58b33 100644 --- a/scripts/Latest.bat +++ b/scripts/Latest.bat @@ -65,16 +65,19 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) ROBOCOPY "%root%NadekoBot" "%root%NadekoBot_Old" /MIR >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) ECHO. - ECHO Old files backed up to NadekoBot_Old + ECHO Old files backed up to NadekoBot_Old... ::Copies the credentials and database from the backed up data to the new folder COPY "%root%NadekoBot_Old\src\NadekoBot\credentials.json" "%installtemp%NadekoBot\src\NadekoBot\credentials.json" >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) ECHO. - ECHO credentials.json copied to new folder + ECHO credentials.json copied... ROBOCOPY "%root%NadekoBot_Old\src\NadekoBot\bin" "%installtemp%NadekoBot\src\NadekoBot\bin" /E >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) ECHO. - ECHO Old bin folder copied to new folder + ECHO bin folder copied... + DEL "%root%NadekoBot_Old\src\NadekoBot\data\musicdata" + ECHO. + ECHO music cache cleared... ROBOCOPY "%root%NadekoBot_Old\src\NadekoBot\data" "%installtemp%NadekoBot\src\NadekoBot\data" /E >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) ECHO. @@ -136,10 +139,11 @@ ECHO opus.dll downloaded. GOTO end :end ::Normal execution of end of script - TITLE Installation complete! + TITLE NadekoBot Installation complete! CD /D "%root%" RMDIR /S /Q "%installtemp%" >nul 2>&1 ECHO. - ECHO Installation complete, press any key to close this window! - timeout /t 5 - del Latest.bat + ECHO Installation complete! + ECHO. + PAUSE + del Latest.bat \ No newline at end of file diff --git a/scripts/Stable.bat b/scripts/Stable.bat index f55fc958..40673f50 100644 --- a/scripts/Stable.bat +++ b/scripts/Stable.bat @@ -65,16 +65,19 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) ROBOCOPY "%root%NadekoBot" "%root%NadekoBot_Old" /MIR >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) ECHO. - ECHO Old files backed up to NadekoBot_Old + ECHO Old files backed up to NadekoBot_Old... ::Copies the credentials and database from the backed up data to the new folder COPY "%root%NadekoBot_Old\src\NadekoBot\credentials.json" "%installtemp%NadekoBot\src\NadekoBot\credentials.json" >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) ECHO. - ECHO credentials.json copied to new folder + ECHO credentials.json copied... ROBOCOPY "%root%NadekoBot_Old\src\NadekoBot\bin" "%installtemp%NadekoBot\src\NadekoBot\bin" /E >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) ECHO. - ECHO Old bin folder copied to new folder + ECHO bin folder copied... + DEL "%root%NadekoBot_Old\src\NadekoBot\data\musicdata" + ECHO. + ECHO music cache cleared... ROBOCOPY "%root%NadekoBot_Old\src\NadekoBot\data" "%installtemp%NadekoBot\src\NadekoBot\data" /E >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) ECHO. @@ -136,10 +139,11 @@ ECHO opus.dll downloaded. GOTO end :end ::Normal execution of end of script - TITLE Installation complete! + TITLE NadekoBot Installation complete! CD /D "%root%" RMDIR /S /Q "%installtemp%" >nul 2>&1 ECHO. - ECHO Installation complete, press any key to close this window! - timeout /t 5 - del Stable.bat + ECHO Installation complete! + ECHO. + PAUSE + del Latest.bat \ No newline at end of file From ff243f42975cfbca0c8917516590174672c41e67 Mon Sep 17 00:00:00 2001 From: samvaio Date: Sun, 5 Mar 2017 03:34:35 +0530 Subject: [PATCH 441/746] installer updated, no longer uses bitsadmin --- scripts/Latest.bat | 10 ++++++---- scripts/NadekoAutoRun.bat | 10 ++++------ scripts/Stable.bat | 10 ++++++---- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/scripts/Latest.bat b/scripts/Latest.bat index aee58b33..01890d9a 100644 --- a/scripts/Latest.bat +++ b/scripts/Latest.bat @@ -75,13 +75,13 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) ECHO. ECHO bin folder copied... - DEL "%root%NadekoBot_Old\src\NadekoBot\data\musicdata" + RD /S /Q "%root%NadekoBot_Old\src\NadekoBot\data\musicdata" ECHO. ECHO music cache cleared... ROBOCOPY "%root%NadekoBot_Old\src\NadekoBot\data" "%installtemp%NadekoBot\src\NadekoBot\data" /E >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) ECHO. - ECHO Old data folder copied to new folder + ECHO Old data folder copied... ::Moves the setup Nadeko folder RMDIR "%root%NadekoBot\" /S /Q >nul 2>&1 ROBOCOPY "%root%NadekoInstall_Temp" "%rootdir%" /E /MOVE >nul 2>&1 @@ -129,12 +129,14 @@ timeout /t 5 ECHO. ECHO Downloading libsodium.dll and opus.dll... SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll" -bitsadmin.exe /transfer "Downloading libsodium.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll "%FILENAME%" +powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll -OutFile %FILENAME%" +::bitsadmin.exe /transfer "Downloading libsodium.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll "%FILENAME%" ECHO libsodium.dll downloaded. ECHO. timeout /t 5 SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll" -bitsadmin.exe /transfer "Downloading opus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%" +powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll -OutFile %FILENAME%" +::bitsadmin.exe /transfer "Downloading opus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%" ECHO opus.dll downloaded. GOTO end :end diff --git a/scripts/NadekoAutoRun.bat b/scripts/NadekoAutoRun.bat index 90d88f4a..c9d37049 100644 --- a/scripts/NadekoAutoRun.bat +++ b/scripts/NadekoAutoRun.bat @@ -25,13 +25,12 @@ IF ERRORLEVEL 1 GOTO latestar :latestar ECHO Auto Restart and Update with Dev Build (latest) ECHO Bot will auto update on every restart! -timeout /t 3 CD /D %~dp0NadekoBot\src\NadekoBot dotnet run --configuration Release ECHO Updating... -timeout /t 3 SET "FILENAME=%~dp0\Latest.bat" -bitsadmin.exe /transfer "Downloading Nadeko (Latest)" /priority high https://github.com/Kwoth/NadekoBot/raw/master/scripts/Latest.bat "%FILENAME%" +powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/master/scripts/Latest.bat -OutFile %FILENAME%" +::bitsadmin.exe /transfer "Downloading Nadeko (Latest)" /priority high https://github.com/Kwoth/NadekoBot/raw/master/scripts/Latest.bat "%FILENAME%" ECHO NadekoBot Dev Build (latest) downloaded. SET root=%~dp0 CD /D %root% @@ -41,13 +40,12 @@ GOTO latestar :stablear ECHO Auto Restart and Update with Stable Build ECHO Bot will auto update on every restart! -timeout /t 3 CD /D %~dp0NadekoBot\src\NadekoBot dotnet run --configuration Release ECHO Updating... -timeout /t 3 SET "FILENAME=%~dp0\Stable.bat" -bitsadmin.exe /transfer "Downloading Nadeko (Stable)" /priority high https://github.com/Kwoth/NadekoBot/raw/master/scripts/Stable.bat "%FILENAME%" +powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/master/scripts/Stable.bat -OutFile %FILENAME%" +::bitsadmin.exe /transfer "Downloading Nadeko (Stable)" /priority high https://github.com/Kwoth/NadekoBot/raw/master/scripts/Stable.bat "%FILENAME%" ECHO NadekoBot Stable build downloaded. SET root=%~dp0 CD /D %root% diff --git a/scripts/Stable.bat b/scripts/Stable.bat index 40673f50..bde82049 100644 --- a/scripts/Stable.bat +++ b/scripts/Stable.bat @@ -75,13 +75,13 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) ECHO. ECHO bin folder copied... - DEL "%root%NadekoBot_Old\src\NadekoBot\data\musicdata" + RD /S /Q "%root%NadekoBot_Old\src\NadekoBot\data\musicdata" ECHO. ECHO music cache cleared... ROBOCOPY "%root%NadekoBot_Old\src\NadekoBot\data" "%installtemp%NadekoBot\src\NadekoBot\data" /E >nul 2>&1 IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) ECHO. - ECHO Old data folder copied to new folder + ECHO Old data folder copied... ::Moves the setup Nadeko folder RMDIR "%root%NadekoBot\" /S /Q >nul 2>&1 ROBOCOPY "%root%NadekoInstall_Temp" "%rootdir%" /E /MOVE >nul 2>&1 @@ -129,12 +129,14 @@ timeout /t 5 ECHO. ECHO Downloading libsodium.dll and opus.dll... SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll" -bitsadmin.exe /transfer "Downloading libsodium.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll "%FILENAME%" +powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll -OutFile %FILENAME%" +::bitsadmin.exe /transfer "Downloading libsodium.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll "%FILENAME%" ECHO libsodium.dll downloaded. ECHO. timeout /t 5 SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll" -bitsadmin.exe /transfer "Downloading opus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%" +powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll -OutFile %FILENAME%" +::bitsadmin.exe /transfer "Downloading opus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%" ECHO opus.dll downloaded. GOTO end :end From 9e4cfe2a32c5b4002c8c7dcc1ce5e8f79e861316 Mon Sep 17 00:00:00 2001 From: samvaio Date: Sun, 5 Mar 2017 04:35:55 +0530 Subject: [PATCH 442/746] cleaning --- scripts/Latest.bat | 6 ++---- scripts/NadekoAutoRun.bat | 6 ++---- scripts/Stable.bat | 6 ++---- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/scripts/Latest.bat b/scripts/Latest.bat index 01890d9a..6460a618 100644 --- a/scripts/Latest.bat +++ b/scripts/Latest.bat @@ -129,14 +129,12 @@ timeout /t 5 ECHO. ECHO Downloading libsodium.dll and opus.dll... SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll" -powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll -OutFile %FILENAME%" -::bitsadmin.exe /transfer "Downloading libsodium.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll "%FILENAME%" +powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll -OutFile '%FILENAME%'" ECHO libsodium.dll downloaded. ECHO. timeout /t 5 SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll" -powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll -OutFile %FILENAME%" -::bitsadmin.exe /transfer "Downloading opus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%" +powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll -OutFile '%FILENAME%'" ECHO opus.dll downloaded. GOTO end :end diff --git a/scripts/NadekoAutoRun.bat b/scripts/NadekoAutoRun.bat index c9d37049..c1701c7c 100644 --- a/scripts/NadekoAutoRun.bat +++ b/scripts/NadekoAutoRun.bat @@ -29,8 +29,7 @@ CD /D %~dp0NadekoBot\src\NadekoBot dotnet run --configuration Release ECHO Updating... SET "FILENAME=%~dp0\Latest.bat" -powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/master/scripts/Latest.bat -OutFile %FILENAME%" -::bitsadmin.exe /transfer "Downloading Nadeko (Latest)" /priority high https://github.com/Kwoth/NadekoBot/raw/master/scripts/Latest.bat "%FILENAME%" +powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/master/scripts/Latest.bat -OutFile '%FILENAME%'" ECHO NadekoBot Dev Build (latest) downloaded. SET root=%~dp0 CD /D %root% @@ -44,8 +43,7 @@ CD /D %~dp0NadekoBot\src\NadekoBot dotnet run --configuration Release ECHO Updating... SET "FILENAME=%~dp0\Stable.bat" -powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/master/scripts/Stable.bat -OutFile %FILENAME%" -::bitsadmin.exe /transfer "Downloading Nadeko (Stable)" /priority high https://github.com/Kwoth/NadekoBot/raw/master/scripts/Stable.bat "%FILENAME%" +powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/master/scripts/Stable.bat -OutFile '%FILENAME%'" ECHO NadekoBot Stable build downloaded. SET root=%~dp0 CD /D %root% diff --git a/scripts/Stable.bat b/scripts/Stable.bat index bde82049..26c5c422 100644 --- a/scripts/Stable.bat +++ b/scripts/Stable.bat @@ -129,14 +129,12 @@ timeout /t 5 ECHO. ECHO Downloading libsodium.dll and opus.dll... SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll" -powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll -OutFile %FILENAME%" -::bitsadmin.exe /transfer "Downloading libsodium.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll "%FILENAME%" +powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll -OutFile '%FILENAME%'" ECHO libsodium.dll downloaded. ECHO. timeout /t 5 SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll" -powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll -OutFile %FILENAME%" -::bitsadmin.exe /transfer "Downloading opus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%" +powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll -OutFile '%FILENAME%'" ECHO opus.dll downloaded. GOTO end :end From e44a2bd384f9903ad8d77eade3ddf9658dad0389 Mon Sep 17 00:00:00 2001 From: samvaio Date: Sun, 5 Mar 2017 05:37:05 +0530 Subject: [PATCH 443/746] fixo --- scripts/Stable.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Stable.bat b/scripts/Stable.bat index 26c5c422..b2f6a9eb 100644 --- a/scripts/Stable.bat +++ b/scripts/Stable.bat @@ -146,4 +146,4 @@ GOTO end ECHO Installation complete! ECHO. PAUSE - del Latest.bat \ No newline at end of file + del Stable.bat \ No newline at end of file From e741e84190c3a4a75be4bbf6aff0da9add466f9e Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 5 Mar 2017 16:09:54 +0100 Subject: [PATCH 444/746] missing key --- .../Utility/Commands/PatreonCommands.cs | 78 +++++++++++++++++++ .../Modules/Utility/Models/PatreonData.cs | 37 +++++++++ .../Resources/ResponseStrings.Designer.cs | 9 +++ src/NadekoBot/Resources/ResponseStrings.resx | 3 + src/NadekoBot/Services/IBotCredentials.cs | 2 +- src/NadekoBot/Services/Impl/BotCredentials.cs | 5 +- src/NadekoBot/credentials_example.json | 3 +- 7 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs create mode 100644 src/NadekoBot/Modules/Utility/Models/PatreonData.cs diff --git a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs new file mode 100644 index 00000000..b347330f --- /dev/null +++ b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using Discord.Commands; +using Discord; +using NadekoBot.Attributes; +using NadekoBot.Modules.Utility.Models; +using Newtonsoft.Json; + +namespace NadekoBot.Modules.Utility +{ + public partial class Utility + { + //[Group] + //public class PatreonCommands : NadekoSubmodule + //{ + // [NadekoCommand, Usage, Description, Aliases] + // [RequireContext(ContextType.Guild)] + // public async Task ClaimPatreonRewards([Remainder] string arg) + // { + // var pledges = await GetPledges2(); + // } + + // private static async Task GetPledges() + // { + // var pledges = new List(); + // using (var http = new HttpClient()) + // { + // http.DefaultRequestHeaders.Clear(); + // http.DefaultRequestHeaders.Add("Authorization", "Bearer " + NadekoBot.Credentials.PatreonAccessToken); + // var data = new PatreonData() + // { + // Links = new Links() + // { + // Next = "https://api.patreon.com/oauth2/api/campaigns/334038/pledges" + // } + // }; + // do + // { + // var res = + // await http.GetStringAsync(data.Links.Next) + // .ConfigureAwait(false); + // data = JsonConvert.DeserializeObject(res); + // pledges.AddRange(data.Data); + // } while (!string.IsNullOrWhiteSpace(data.Links.Next)); + // } + // return pledges.Where(x => string.IsNullOrWhiteSpace(x.Attributes.declined_since)).ToArray(); + // } + + // private static async Task GetPledges2() + // { + // var pledges = new List(); + // using (var http = new HttpClient()) + // { + // http.DefaultRequestHeaders.Clear(); + // http.DefaultRequestHeaders.Add("Authorization", "Bearer " + NadekoBot.Credentials.PatreonAccessToken); + // var data = new PatreonData() + // { + // Links = new Links() + // { + // Next = "https://api.patreon.com/oauth2/api/current_user/campaigns?include=pledges" + // } + // }; + // do + // { + // var res = + // await http.GetStringAsync(data.Links.Next) + // .ConfigureAwait(false); + // data = JsonConvert.DeserializeObject(res); + // pledges.AddRange(data.Data); + // } while (!string.IsNullOrWhiteSpace(data.Links.Next)); + // } + // return pledges.Where(x => string.IsNullOrWhiteSpace(x.Attributes.declined_since)).ToArray(); + // } + //} + } +} diff --git a/src/NadekoBot/Modules/Utility/Models/PatreonData.cs b/src/NadekoBot/Modules/Utility/Models/PatreonData.cs new file mode 100644 index 00000000..381666e8 --- /dev/null +++ b/src/NadekoBot/Modules/Utility/Models/PatreonData.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Utility.Models +{ + + public class PatreonData + { + public Pledge[] Data { get; set; } + public Links Links { get; set; } + } + + public class Attributes + { + public int amount_cents { get; set; } + public string created_at { get; set; } + public string declined_since { get; set; } + public bool is_twitch_pledge { get; set; } + public bool patron_pays_fees { get; set; } + public int pledge_cap_cents { get; set; } + } + + public class Pledge + { + public Attributes Attributes { get; set; } + public int Id { get; set; } + } + + public class Links + { + public string First { get; set; } + public string Next { get; set; } + } +} diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index c91f93cb..d1bef121 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2081,6 +2081,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to You've already joined this race!. + /// + public static string gambling_animal_race_already_in { + get { + return ResourceManager.GetString("gambling_animal_race_already_in", resourceCulture); + } + } + /// /// Looks up a localized string similar to Animal Race is already running.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index a1674f52..9af8d41f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1218,6 +1218,9 @@ Don't forget to leave your discord name or id in the message. Animal Race is already running. + + You've already joined this race! + Total: {0} Average: {1} diff --git a/src/NadekoBot/Services/IBotCredentials.cs b/src/NadekoBot/Services/IBotCredentials.cs index a03c6db3..63bea8b8 100644 --- a/src/NadekoBot/Services/IBotCredentials.cs +++ b/src/NadekoBot/Services/IBotCredentials.cs @@ -7,13 +7,13 @@ namespace NadekoBot.Services public interface IBotCredentials { ulong ClientId { get; } - ulong BotId { get; } string Token { get; } string GoogleApiKey { get; } ImmutableHashSet OwnerIds { get; } string MashapeKey { get; } string LoLApiKey { get; } + string PatreonAccessToken { get; } DBConfig Db { get; } diff --git a/src/NadekoBot/Services/Impl/BotCredentials.cs b/src/NadekoBot/Services/Impl/BotCredentials.cs index 56851762..a0220778 100644 --- a/src/NadekoBot/Services/Impl/BotCredentials.cs +++ b/src/NadekoBot/Services/Impl/BotCredentials.cs @@ -5,7 +5,6 @@ using Discord; using System.Linq; using NLog; using Microsoft.Extensions.Configuration; -using System.Collections.Generic; using System.Collections.Immutable; namespace NadekoBot.Services.Impl @@ -15,7 +14,6 @@ namespace NadekoBot.Services.Impl private Logger _log; public ulong ClientId { get; } - public ulong BotId { get; } public string GoogleApiKey { get; } @@ -44,6 +42,7 @@ namespace NadekoBot.Services.Impl public string CarbonKey { get; } public string credsFileName { get; } = Path.Combine(Directory.GetCurrentDirectory(), "credentials.json"); + public string PatreonAccessToken { get; } public BotCredentials() { @@ -68,6 +67,7 @@ namespace NadekoBot.Services.Impl GoogleApiKey = data[nameof(GoogleApiKey)]; MashapeKey = data[nameof(MashapeKey)]; OsuApiKey = data[nameof(OsuApiKey)]; + PatreonAccessToken = data[nameof(PatreonAccessToken)]; int ts = 1; int.TryParse(data[nameof(TotalShards)], out ts); @@ -109,6 +109,7 @@ namespace NadekoBot.Services.Impl public string CarbonKey { get; set; } = ""; public DBConfig Db { get; set; } = new DBConfig("sqlite", "Filename=./data/NadekoBot.db"); public int TotalShards { get; set; } = 1; + public string PatreonAccessToken { get; set; } = ""; } private class DbModel diff --git a/src/NadekoBot/credentials_example.json b/src/NadekoBot/credentials_example.json index 240f9029..912b452a 100644 --- a/src/NadekoBot/credentials_example.json +++ b/src/NadekoBot/credentials_example.json @@ -14,5 +14,6 @@ "Type": "sqlite", "ConnectionString": "Filename=./data/NadekoBot.db" }, - "TotalShards": 1 + "TotalShards": 1, + "PatreonAccessToken": "" } \ No newline at end of file From 7d2264270494fb11390d027fa07b61aeb61ed07d Mon Sep 17 00:00:00 2001 From: Rajath Ranganath Date: Sun, 5 Mar 2017 21:22:40 +0530 Subject: [PATCH 445/746] Remove unnecessary capitalization --- src/NadekoBot/Resources/ResponseStrings.resx | 209 +++++++++---------- 1 file changed, 104 insertions(+), 105 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 9af8d41f..1d74dc30 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -1,4 +1,4 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Den basen har allerede blitt tatt over eller ødelagt. + + + Den basen er allerede ødelagt. + + + Ingen har hevdet denne basen. + + + **ØDELAGT** base #{0} i en krig mot {1} + + + + + + {0} har hevdet en base #{1} i en krig mot {2} + + + @{0} Du har allerede hevdet basen #{1}. Du kan ikke kreve en ny. + + + Krav fra @{0} for en krig mot {1} har utløpt. + Fuzzy + + + Fiende + + + Info om krigen mot {0} + + + Ugyldig basenummer + + + Ikke en gyldig krigstørrelse + Fuzzy + + + Liste over aktive kriger + Fuzzy + + + ikke hevdet + + + Du er ikke en deltager i den krigen. + + + @{0} Du deltar enten ikke i denne krigen, eller basen er allerede ødelagt. + + + Ingen aktive kriger. + Fuzzy + + + Størrelse + + + Krig mot {0} har allerede begynt. + + + Krig mot {0} opprettet. + + + Krig mot {0} avsluttet. + + + Den krigen eksisterer ikke. + + + Krig mot {0} startet! + + + Alle tilpassede reaksjons-statistikker fjernet. + + + Tilpasset reaksjon fjernet + + + Utilstrekkelig tilgang. Krever Bot-eierskap for globale tilpassede reaksjoner, og Administrator for server reaksjoner. + + + Liste av alel tilpassede reaksjoner. + + + Tilpassede reaksjoner. + + + Ny tilpasset reaksjon + + + Ingen tilpasset reaksjon funnet. + Fuzzy + + + Ingen tilpasset reaksjon funnet med den ID'en. + + + Respons + + + Tilpassede reaksjon statistikker. + + + Statistikk fjernet for {0} reaksjon + + + Ingen statistikk funnet for den utløseren, ingen handling utført + + + Utløser + + + Autohentai stoppet + + + Ingen resultater. + + + {0} har allerede besvimt + + + {0} har allerede full helse + + + Din type er allerede {0} + + + brukte {0}{1} på {2}{3} for {4} skade. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + Du kan ikke angripe igjen uten motstanderens hevn. + Sjekk om Kwoth oppdaterer original setningen senere. Har sendt forslag om endring. + + + Du kan ikke angripe deg selv. + + + {0} har besvimt! + + + helbredet {0} med én {1} + + + {0} har {1} helse igjen + + + Du kan ikke bruke {0}. Skriv ´{1}ml` for å se en liste med angrep du kan bruke. + + + Angrep for {0} -type. + + + Det er ikke effektivt. + + + Du har ikke nok {0} + + + gjenopplivet {0} med én {1} + + + Du gjenopplivet deg selv med én {0} + + + Din type ble endret til {0} for èn {1} + + + Det er noe effektivt. + + + Det er super effektivt! + + + Du har gjort for mange angrep på rad, du kan nå ikke gjøre flere angrep! + + + {0} sin type er {1} + + + Bruker ikke funnet + + + Du besvimte, så du kan nå ikke bevege deg. + + + **Automatisk rollegivning** når brukere kommer inn er nå **deaktivert** + + + **Automatisk rollegivning** når brukere kommer inn er nå **aktivert** + + + Legg til filer + + + Profilbilde + + + Du har blitt utestengt fra {0} +Grunn: {1} + + + utestengt + PLURAL + + + Bruker ble utestengt + + + Bot navn endret til {0} + + + Bot status endret til {0} + + + Automatisk sletting av 'farvel'-meldinger er aktivert + + + Farvel-meldinger vil bli slettet etter {0} sekunder. + + + Nåværende 'farvel'-melding: {0} + + + Aktivér 'farvel'-meldinger ved å skrive {0} + + + Ny 'farvel'-melding satt. + + + 'farvel'-kunngjøringer deaktivert. + + + 'farvel'-kunngjøringer aktivert i denne kanalen. + + + Kanalnavn endret. + + + Gammelt navn + + + Kanalemne endret. + + + Ryddet opp. + + + Innhold + + + Rolle opprettet + + + Tekstkanal {0} laget. + + + Talekanal {0} laget. + + + Demping vellykket. + + + Slettet server {0} + + + Stoppet automatisk sletting av vellykkede kommando invokationer. + + + Sletter nå kommandomeldinger automatisk. + + + Tekstkanal {0} slettet. + + + Lydkanal {0} slettet. + + + DM fra + + + Vellykket i å legge til ny bidragsyter. Totalt bidratt av denne brukeren: {0} 👑 + + + Takk til folkene under som gjorde dette prosjektet mulig! + + + Jeg videresender de personlige meldingene til alle eierne. + + + Jeg vil bare vidresende de personlige meldingene til den første eieren. + + + Jeg vil videresende personlige meldinger fra nå. + + + Jeg slutter å videresende personlige meldinger fra nå. + + + Automatisk sletting av velkomstmeldinger har blitt deaktivert. + + + Velkomst meldinger blir slettet etter {0} sekunder. + + + Nåværende personlige velkomst melding: {0} + + + Aktiver personlig velkomstmelding ved å skrive {0} + + + Ny personlig velkomstmelding valgt. + + + Personlig velkomstmelding deaktivert. + + + Personlig velkomstmelding aktivert. + + + Nåværende velkomstmelding: {0} + + + Aktiver velkomstmeldinger ved å skrive {0} + + + Ny velkomstmelding satt. + + + Velkomst-kunngjøring deaktivert. + + + Velkomst-kunngjøring aktivert i denne kanalen. + + + Du kan ikke bruke denne kommandoen på brukere som har en rolle høyere eller på samme nivå som deg i hierarkiet. + + + Bilder lastet etter {0} sekunder! + + + Ugyldig tilførings format. + + + Ugyldige parametere + + + {0} ble med i {1} + + + Du har blitt sparket fra {0} +Grunn: {1} + + + Bruker sparket + Fuzzy + + + Liste over språk {0} + Fuzzy + + + Din servers' lokasjon er nå {0} - {1} + + + Bot'ens standard språk er satt til {1} - {1} + + + Bot'ens språk er satt til {0} - {1} + + + Kunne ikke sette språk. Vennligst sjekk denne kommandoens bruksinformasjon. + + + Denne serverens språk er satt til {0} - {1} + + + {0} har forlatt {1} + + + Forlot server {0} + + + Logger {0} hendelse på denne kanalen. + + + Logger alle hendelser i denne kanalen. + + + Logging deaktivert. + + + Logg hendelser du kan abonnere på: + + + Logging vil ignorere {0} + + + Logging vil ikke ignorere {0} + + + Sluttet å logge {0} hendelse. + + + {0} har påkalt en nevnelse av følgende roller + + + Melding fra {0} '[Bot Eier]': + + + Melding sendt. + + + {0} flyttet fra {1} til {2} + + + Melding slettet i #{0} + Fuzzy + + + Melding oppdatert i #{0} + Fuzzy + + + Dempet + PLURAL (users have been muted) + + + Dempet + singular "User muted." + + + Jeg har mest sannsynlig ikke de nødvendige tillatelsene til det. + + + Ny 'dempet'-rolle satt. + + + Jeg trenger **Administrasjon** tillatelse til å gjøre det. + + + Ny Melding + Fuzzy + + + Nytt kallenavn + Fuzzy + + + Nytt emne + Fuzzy + + + Kallenavn endret. + Fuzzy + + + Kan ikke finne den serveren + + + Ingen shard med den IDen funnet. + + + Gammel melding + Fuzzy + + + Gammelt kallenavn + Fuzzy + + + Gammelt emne + Fuzzy + + + Feil. Mest sansynlig har jeg ikke tilstrekkelige tillatelser. + + + Tillatelsene til denne serveren er nullstilt. + + + Aktive Beskyttelser + Fuzzy + + + {0} har blitt **deaktivert** på denne serveren. + + + {0} aktivert + + + Feil. Jeg trenger "Behandle roller" tillatelse. + + + Ingen beskyttelser aktivert + Fuzzy + + + Bruker terskelen må være mellom {0} og {1} + + + Hvis {0} eller flere brukere kommer inn i løpet av {1} sekunder, blir de {2} + + + Tiden må være mellom {1} og {1} sekunder. + + + Fjernet alle roller fra {0} + + + Kunne ikke fjerne roller. Jeg har ikke de rette tillatelsene. + + + Rollen {0} sin farge er blitt endret. + + + Den rollen eksisterer ikke. + + + Gitte parametere er ikke gyldige. + + + En feil oppstod, grunnet ugyldig fargekode, eller ikke tilstrekkelig med tillatelser. + + + Fjernet rollen {0} fra {1} + + + Kunne ikke fjerne rollen. Jeg har ikke tilstrekkelig med tillatelser + + + Endret navn på rolle. + + + Kunne ikke endre navn på rolle. Jeg har ikke tilstrekkelig med tillatelser. + + + Du kan ikke endre på roller som er høyere enn din i hierarkiet. + + + Fjernet 'Spiller'-melding: {0} + + + Roller {0} er lagt til i listen + + + {0} ikke funnet. Renset opp. + + + Rolle {0} er allerede i listen + + + Lagt til. + + + Roterende 'spiller'-status deaktivert. + + + Roterende 'spiller'-status aktivert. + + + Liste med roterende statuser: +{0} + + + Ingen roterende statuser er satt. + + + Du har allerede rollen {0} + + + Du har allerede en eksklusiv rolle: {0} + + + Selvsettende roller er nå eksklusive! + + + Det er nå {0} selvsettende roller. + + + Den rollen er ikke selvsettende. + + + Du har ikke rollen {0}. + + + Selvsettende roller er nå ikke eksklusive! + + + Jeg kan ikke gi deg den rollen. +`Jeg kan ikke gi roller til eiere eller brukere som har en rolle høyere enn min egen i hierarkiet` + + + {0} ble fjernet fra listen over selvsettende roller. + + + Du har ikke lenger rollen {0} + + + Du har nå rollen {0} + + + Gav rollen {0} til {1} + + + Kunne ikke legge til rolle. Jeg har ikke de rette tillatelsene. + + + Nytt profilbilde er satt! + + + Nytt kanalnavn satt. + + + Nytt spill satt. + + + Ny strøm satt. + + + Nytt kanalemne satt + + + Shard {0} gjentilkoblet. + + + Kobler til shard {0} på nytt + + + Avslutter + + + Brukere kan ikke sende flere enn {0} meldinger i løpet av {1} sekunder. + + + Sakte modus deaktivert + + + Sakte modus aktivert + + + soft-banned (sparket) + PLURAL + + + {0} vil nå ignorere denne kanalen. + + + {0} vil ikke lenger ignorere denne kanalen. + + + Hvis en bruker sender {0} like meldinger på rad, vil de bli {1}. +__IgnoredChannels__: {2} + + + Tekstkanal opprettet + Fuzzy + + + Tekstkanal fjernet + Fuzzy + + + Demping fjernet + + + Fjernet demping + singular + + + Brukernavn + + + Brukernavn endret + Fuzzy + + + Brukere + + + Bruker utestengt + Fuzzy + + + {0} har blit **dempet** fra å chatte. + + + Fjernet demping på {0} for chatting. + + + Bruker ble med i samtalen. + Fuzzy + + + Bruker Forlatt. + Fuzzy + + + {0} har blitt **dempet** fra tekst og talekanaler. + + + Brukerrolle lagt til + Fuzzy + + + Brukerrolle fjernet + Fuzzy + + + {0} er nå {1} + + + {0} er ikke lenger dempet fra tekst og tale. + + + {0} har blitt med i {1} + + + {0} har forlatt {1} + + + {0} flyttet fra {1} til {2} + + + {0} har blitt **tale dempet*** + + + {0} er ikke lenger **taledempet** + + + Talekanal laget + Fuzzy + + + Talekanal fjernet + Fuzzy + + + Deaktivert tale + tekst funksjon. + + + Aktivert lyd + tekst funksjon. + + + Jeg har ikke ** + + + Du aktiverer/deaktiverer denne funksjonen og **jeg ikke har administratorrettigheter**. Dette kan føre til noen problemer, og du blir nødt til å rydde opp i tekst kanaler selv etterpå. + + + Jeg trenger **Behandle roller** og **Administrer kanaler** tillatelser for å aktivere denne egenskapen. (Administrator er foretrukket) + + + Bruker {0} fra tekst-chat + + + Bruker {0} fra tekst og tale chat + + + Bruker {0} fra stemmechat + + + Du har blitt 'soft-banned' fra {0} server. +Grunn: {1} + + + Fjernet bruker fra utestenging + + + Migrering fullført! + + + Feil under migrering, sjekk botens konsoll for mer informasjon. + + + Oppdatering av tilstedeværelse + + + Bruker soft-banned + + + har tildelt {0} til {1} + + + Bedre hell neste gang :3 + + + Gratulerer! Du vant {0} for å rulle høyere enn {1} + + + Kortstokk stokket. + + + kastet {0}. + User flipped tails. + + + Du gjettet det! Du vant {0} + + + Ugyldig nummer spesifisert. Du kan kaste 1 til {0} mynter. + + + Legg {0} reaksjon på denne meldingen for å få {1} + + + Denne hendelsen er aktiv i opptil {0} timer. + + + Blomster reaksjonshendelse startet! + + + har gitt {0} til {1} + X has gifted 15 flowers to Y + + + {0} har {1} + X has Y flowers + + + Mynt + Fuzzy + + + Resultattavle + + + Tildelt {0} til {1} brukere fra {2} rollen. + + + Du kan ikke vedde mer enn {0} + + + Du kan ikke vedde mindre enn {0} + + + Du har ikke nok {0} + + + Ikke flere kort i kortstokken. + + + Trakk bruker + + + Du rullet {0}. + + + Vedde + + + WOAAHHHHHH!!! Gratulerer!!! x{0} + + + En enkel {0}, x{1} + + + Wow! Heldig! Tre like! x{0} + + + Godt jobbet! To {0} - veddemål x{1} + + + Vant + + + Brukere må skrive et hemmelig kodeord for å få {0}. +Varer i {1} sekunder. Ikke si det til noen. Shhh. + + + SneakyGame hendelse avsluttet. {0} brukere fikk belønning. + + + SneakyGameStatus hendelse startet + + + Kron + Fuzzy + + + vellykket i og ta {0} fra {1} + + + Kunne ikke ta {0} fra {1} fordi brukeren hadde ikke så mye {2}! + + + Tilbake til innholdsfortegnelsen + + + Kun boteier + Fuzzy + + + Krever {0} kanal tillatelse. + + + Du kan støtte prosjektet på Patreon: <{0}> eller paypal: <{1}> + + + Kommandoer og aliaser + + + Kommandoliste regenerert. + + + Skriv `{0}h Kommandonavn` å se hjelpen for den oppgitte kommandoen. f.eks `{0}h >8ball` + + + Jeg kan ikke finne den kommandoen. Kontroller at kommandoen finnes før du prøver igjen. + + + Beskrivelse + + + Du kan støtte NadekoBot prosjektet på +Patreon <{0}> eller +Paypal <{1}> +Ikke glem å skrive Discord navnet eller ID i meldingen. + +** Takk ** ♥ ️ + + + ** Liste over kommandoer **: <{0}> +** Hosting guider og dokumenter finner du her **: <{1}> + + + Liste av kommandoer + Fuzzy + + + Liste av moduler + Fuzzy + + + + + + Den modulen finnes ikke. + + + Krever {0} servertillatelse. + + + Innholdsfortegnelse + Fuzzy + + + Bruk + + + Autohentai startet. Poster hvert {0}s med følgende stikkord: {1} + + + Stikkord + + + Veddeløp med dyr + + + Kunne ikke starte siden det ikke var nok deltakere + + + Løpet er fullt. Starter nå. + + + {0} ble med som {1} + + + {0} ble med som {1} og veddet {2}! + + + Skriv {0}jr for og bli med i løpet. + + + Starter om 20 sekunder eller når rommet er fullt. + + + Starter med {0} deltakere. + + + {0} som {1} vant løpet! + + + {0} som {1} vant løpet og {2}! + + + Ugyldig nummer spesifisert. Du kan rulle {0}-{1} terninger på en gang. + + + rullet {0} + Someone rolled 35 + + + Terning rullet: {0} + Dice Rolled: 5 + + + Kunne ikke starte løpet. Et annet løp er sannsynligvis igang. + + + Ingen løp eksisterer på denne serveren + + + Det andre tallet må være større enn det første + + + Ombestemmelser + Fuzzy + + + Hevdet av + Fuzzy + + + Skilsmisser + + + Liker + + + Pris + + + Ingen waifus har blitt hevdet enda. + + + Topp Waifus + + + Din affinitet er allerede satt til den waifuen eller så prøver du å fjerne din egen affinitet uten å ha en. + + + byttet affinitet fra {0} til {1}. + +*Dette er moralsk tvilsomt.* + Make sure to get the formatting right, and leave the thinking emoji + + + Du må vente {0} timer og {1} minutt for å bytte affinitet igjen. + + + Affiniteten din er tilbakestillt. Du liker ingen. + + + ønsker å bli {0} sin waifu. Aww <3 + + + hevdet {0} som sin waifu for {1}! + + + Du har skillt deg fra en waifu som liker deg, ditt hjerteløse monster! +{0} fikk {1} som kompensation. + + + du kan ikke sette affiniteten din til deg selv, ditt egoistiske monster! + + + 🎉 Deres kjærlighet er oppfylt 🎉 +{0} sin nye verdi er {1}! + + + Ingen waifu er så billig. Du må betale minst {0} for å få en waifu, selv om deres verdi egentlig er lavere. + + + Du må betale {0} eller mer for å hevde den waifuen! + + + Den waifuen er ikke din. + + + Du kan ikke hevde deg selv. + + + Du er nylig skilt. Du må vente {0} timer og {1} minutter for å kunne skille deg igjen. + + + Ingen + + + Du har skilt deg fra en waifu som ikke liker deg. Du fikk {0} tilbake. + + + 8ball + + + Acrophobia + + + Spill avsluttet uten innleveringer. + + + Ingen stemmer telt. Spillet avsluttet med ingen vinnere. + + + Akronymet var {0}. + + + Acrophobia-spill er allerede i gang i denne kanalen. + + + Spill startet. Lag en setning med det følgende akronymet: {0}. + + + Du har {0} sekunder å levere inn på. + + + {0} leverte inn sin setning. ({1} total) + + + Stem ved å skrive nummer til innleveringen. + + + {0} avga sin stemme! + + + Vinneren er {0} med {1} poeng. + + + {0} er vinneren fordi han hadde den eneste innleveringen + + + Spørsmål + + + Det er uavgjort! Begge valgte {0} + + + {0} vant! {1} slår {2} + + + Innleveringer avluttet. + Fuzzy + + + Veddeløp med dyr er allerede igang. + + + Totalt: {0} Gjennomsnitt: {1} + + + Kategori + + + Deaktivert Cleverbot på denne serveren. + + + Aktivert Cleverbot på denne serveren. + + + Valuta generering har blitt deaktivert på denne kanalen. + + + Valuta generering har blitt aktivert på denne kanalen. + + + {0} tilfeldig {1} dukket opp! Plukk dem opp ved og skrive'{2}pick' + plural + + + En tilfeldig {0} dukket opp! Plukk den opp ved og skrive '{1}pick' + + + Kunne ikke laste inn spørsmål. + + + Spill startet + Fuzzy + + + Hangman spill startet + + + Hangman spill kjører allerede i denne kanalen. + + + Kunne ikke starte Hangman + + + Liste av "{0}hangman" begrepstyper: + + + Resultattavle + + + Du har ikke nok {0} + + + Ingen resultater + + + Plukket {0} + Kwoth picked 5* + + + {0} plantet {1} + Kwoth planted 5* + + + Trivia kjører allerede på denne serveren. + + + Trivia spill + + + {0} gjettet det! Svaret var: {1} + + + Ingen trivia-spill gående på serveren. + + + {0} har {1} poeng + + + Stopper etter dette spørsmålet + + + Tiden er ute! Det riktige svaret var {0} + + + {0} gjettet det og VANT spillet! Svaret var: {1} + + + Du kan ikke spille mot deg selv. + + + Bondesjakk kjører allerede i denne kanalen. + + + Uavgjort! + + + har startet et spill med bondesjakk + + + {0} har vunnet! + Fuzzy + + + Matchet tre + Fuzzy + + + Ingen bevegelser igjen! + + + Tiden er ute! + Fuzzy + + + {0} sin tur + + + {0} mot {1} + + + + + + Automatisk avspilling deaktivert + + + Automatisk spilling aktivert. + + + Standard volume satt til {0}% + + + + + + + + + Sang ferdig + Fuzzy + + + + + + + + + Fra possisjon + + + Id + + + Ugyldig tilføring. + + + Max spilletid har ingen grenser nå. + + + Max spilletid satt til {0} sekund(er). + + + Max musikkkø størrelse satt til uendelig. + + + Max musikkkø størrelse satt til {0} sang(er). + + + Du må være i en talekanal på denne serveren. + + + Navn + + + Spiller + Fuzzy + + + Ingen aktive musikkspillere. + + + Ingen søkeresultater. + + + Musikkavspilling pauset + + + Spilleliste - Side {0}/{1} + Fuzzy + + + Spiller sang + Fuzzy + + + #{0}` - **{1}** av *{2}* ({3} sanger) + + + Side {0} av lagrede spillelister + Fuzzy + + + Spilleliste slettet. + + + Klarte ikke og slette spillelisten. Enten eksisterer den ikke, eller så var det ikke du som lagde den. + + + Spilleliste med den IDen eksisterer ikke. + + + Spilleliste-kø komplett. + + + Spilleliste lagret + Fuzzy + + + {0}er grense + + + + + + Sang i kø + Fuzzy + + + Musikk-kø tømt. + + + Køen er full {0}/{0}- + + + Fjernet sang + context: "removed song #5" + + + + + + + + + + + + + + + Musikk-avspilling startet + + + + + + + + + + + + Skippet til '{0}:{1}' + + + Sanger stokket + + + Sang flyttet + Fuzzy + + + {0}t {1}m {2}s + + + Til posisjon + + + Ubegrenset + + + Lyden må være mellom 0 og 100 + + + Volum satt til {0}% + + + Deaktivert bruk av ALLE MODULER på {0} kanalen. + Fuzzy + + + Aktivert bruk av ALLE MODULER på {0} kanalen. + Fuzzy + + + Tillatt + + + Deaktivert bruk av ALLE MODULER for {0} rolle. + + + Aktivert bruk av ALLE MODULER for {0} rolle. + + + Deaktivert bruk av ALLE MODULER på denne serveren. + + + Aktivert bruk av ALLE MODULER på denne serveren. + + + Deaktivert bruk av ALLE MODULER for {0} bruker. + + + Aktivert bruk av ALLE MODULER for {0} bruker. + + + Svartelistet {0} med ID {1} + + + Kommando {0} har nå en {1}'s ventetid. + + + Kommando {0} har ingen ventetid nå og alle eksisterende ventetider har blitt fjernet. + + + Ingen kommando-ventetid satt. + + + Kommando kostnader + + + Deaktivert bruk av {0} {1} i kanal {2}. + + + Aktivert bruk av {0} {1} i kanal {2}. + + + Benektet + + + La til ordet {0} til listen av filtrerte ord. + + + Liste over filtrerte ord + + + Fjernet ord {0} fra listen over filtrerte ord. + + + Ugyldig andre parameter. (Må være et tall mellom {0} og {1}) + + + Invitasjons-filtrering deaktivert i denne kanalen. + + + Invitasjons-filtrering aktivert i denne kanalen. + + + Invitasjons-filtrering deaktivert på denne serveren. + + + Invitasjons-filtrering aktivert på denne serveren. + + + Flyttet tillatelse {0} fra #{1} til #{2} + + + Finner ikke tillatelse til index #{0} + + + Ingen kostnader satt. + + + kommando + Gen (of command) + + + modul + Gen. (of module) + + + Rettigheter side {0} + + + Nåværende rettighets-rolle er {0}. + + + Brukere må nå ha {0} rollen for og endre rettigheter. + + + Ingen tillatelse funnet på denne indeksen. + + + fjernet rettighet #{0} - {1} + + + Deaktivert bruk av {0} {1} for {2} rollen. + + + Aktivert bruk av {0} {1} for {2} rollen. + + + + Short of seconds. + + + Deaktivert bruk av {0} {1} på denne serveren. + + + Aktivert bruk av {0} {1} på denne serveren. + + + + + + uredigerbar + + + Deaktivert bruk av {0} {1} for {2} bruker. + + + Aktivert bruk av {0} {1} for {2} bruker. + + + Jeg vil ikke lenger vise tillatelse advarsler. + + + Jeg vil nå vise rettighets-advarsler. + + + Ord filtrering er deaktivert i denne kanalen. + + + Ord filtrering aktivert på denne kanalen. + + + Ord filtrering deaktivert på denne serveren. + + + Ord filtrering aktivert på denne serveren. + + + Ferdigheter + + + + + + Startet automatisk oversettelse av meldinger i denne kanalen. Bruker-meldinger vil bli slettet automatisk. + + + + + + + + + Startet automatisk oversettelse av meldinger i denne kanalen. + + + Stoppet automatisk oversettelse av meldinger i denne kanalen. + + + Feil tilførings format, eller noe gikk galt + + + Kunne ikke finne det kortet. + + + fakta + + + Kapittel + + + Tegneserie # + + + Konkurerende tap + + + Konkurranser spillt + + + Konkurrerende rangering + + + + + + Fullført + + + Betingelse + + + Kostnader + + + Dato + + + Definer: + + + Droppet + + + Episoder + + + Feil oppsto. + + + Eksempel + + + + + + + + + Sjangere + + + + + + Høyde/vekt + + + {0}m/{1}kg + + + Luftfuktighet + + + Bildesøk for: + + + Kunne ikke finne den filmen. + + + Ugyldig kilde- eller målspråk. + + + Vitser ikke lastet. + + + + + + Nivå + + + + Don't translate {0}place + + + Plassering + + + + + + + + + Bot eieren ikke spesifisere MashapeApiKey. Du kan ikke bruke denne funksjonaliteten. + + + Min/Max + + + Ingen kanal funnet. + + + Ingen resultater funnet. + + + På vent + + + Original url + + + En 'osu!' API-nøkkel er nødvendig. + + + Kunne ikke hente 'osu!' signatur. + + + Fant mer enn {0} bilder. Viser tilfeldig {0}. + + + Bruker ikke funnet! Vennligst sjekk regionen og BattleTag før du prøver igjen. + + + Planlegg å se + + + Plattform + + + Ingen evne funnet. + + + Ingen pokemon funnet. + + + Profil link: + + + Kvalitet: + + + Rask spilletid + + + Rask vinner + + + Vurdering + + + + + + Søk etter: + + + Kunne forkorte den URLen. + + + Kort url + + + Noe gikk galt. + + + Vennligst oppgi søkeparametere. + + + Status + + + Butikk url + + + Streamer {0} er frakoblet. + + + Streamer {0} er online med {1} seere. + + + Du følger {0} strømmer på denne serveren. + + + Du følger ikke noen strømmer på denne serveren. + + + Ingen slik strøm. + + + Strømmen eksisterer sannsynligvis ikke. + + + Fjernet {0} sin stream ({1}) fra varslinger. + + + Jeg vil varsle denne kanalen når statusen endres. + + + Soloppgang + + + Solnedgang + + + Temperatur + + + Tittel: + + + + + + Oversettelse: + + + Typer + + + Kunne ikke finne definisjonen for dette ordet. + + + + + + Seerne + + + + + + Kunne ikke finne det ordet på den angitte Wikia. + + + Vennligst skriv inn et mål-wikia, etterfulgt av søket. + + + Side ikke funnet. + + + Vindfart + + + De {0} mest forbydde 'champions' + + + + + + Ble med + + + + /s and total need to be localized to fit the context - +`1.` + + + Aktivitet side #{0} + + + {0} brukere totalt. + + + Forfatter + + + + + + Liste over funksjoner i {0}calc kommandoer + + + {0} av denne kanalen er {1} + + + Kanal emne + + + Kommandoer kjørt + + + {0} {1} er lik {2} {3} + + + Enheter som kan brukes av omformeren + + + Kan ikke konvertere {0} til {1}: enheter ikke funnet + + + Kan ikke konvertere {0} til {1}: typer enheter er ikke lik + + + laget på + + + Ble med i kanalen for snakk på tvers av servere + + + Forlatt kanalen for snakk på tvers av servere + + + Dette er din CSC token + + + Spesiallagde emojier + + + Feil + + + Egenskaper + + + ID + + + Indeks utenfor rekkevidde. + + + Her er en liste over brukere i disse rollene: + + + Du har ikke lov til å bruke denne kommandoen på roller med mange brukere i dem for å hindre misbruk. + + + Ugyldig {0} verdi. + Invalid months value/ Invalid hours value + + + Ble med Discord + + + Ble med serveren + + + ID: {0} +Medlemmer: {1} +Eier ID: {2} + + + Ingen servere funnet på denne siden. + + + Liste over repeater + + + Medlemmer + + + Minne + + + Meldinger + + + + + + Navn + + + Kallenavn + + + Det er ingen som spiller det spillet. + + + Det er ingen aktive repeatere. + + + Det er ingen roller på denne siden. + + + Det er ingen shards på denne siden. + + + Ingen emne er satt. + + + Eier + + + Eier Identiteter + + + Tilstedeværelse + + + {0} Servere +{1} Tekst kanaler +{2} Talekanaler + + + Slettet alle sitater med {0} nøkkelord. + + + Side {0} av sitater + + + Det er ingen sitater på denne siden. + + + Ingen sitater funnet som du kan fjerne. + + + Sitat lagt til + + + Slettet et tilfeldig sitat. + + + Region + + + Registrert på + + + Jeg vil minne på {0} til {1} i {2} `({3:. D.M.ÅÅÅÅ} ved {4:TT:mm})` + + + Ikke et gyldig format. Sjekk kommandolisten. + + + + + + Repeterer {0} {1} hver dag(er), {2} time(r) og {3} minutt(er). + + + + + + + + + #{0} stoppet. + + + + + + Resultat + + + Roller + + + Side #{0} av alle roller på denne serveren: + + + Side #{0} av roller for {1} + + + Ingen farger er i riktig format. Bruk `#00ff00` for eksempel. + + + Startet rotering av {0} rolle farge. + + + Stoppet rotering av farger for {0} rolle + + + {0} av denne serveren er {1} + + + Server info + + + + + + + + + + + + **Navn:** {0} **Link:** {1} + + + Ingen spesielle emojier funnet. + + + Spiller {0} sanger, {1} kø. + + + Tekst kanaler + + + Her er linken til rommet ditt: + + + Oppetid + + + {0} til brukeren {1} er {2} + Id of the user kwoth#1234 is 123123123123 + + + Brukere + + + Tale kanaler + + + Du har allerede sluttet deg til dette løpet! + + + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx new file mode 100644 index 00000000..665f605b --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx @@ -0,0 +1,2209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Ta baza została już zdobyta lub zniszczona. + + + Ta baza została już zniszczona. + + + Ta baza nie jest zdobyta. + + + **ZNISZCZONO** bazę #{1} w wojnie przeciwko {1} + + + {0} **POZBYŁ SIĘ** bazy #{1} w wojnie przeciwko {2} + + + {0} zdobył bazę #{1} w wojnie przeciwko {2} + + + @{0} Już zdobyłeś bazę #{1}. Nie możesz zdobyć nowej. + + + Wypowiedzenie wojny od @{0} przeciwko {1} wygasło. + Fuzzy + + + Wróg + + + Informacje o wojnie przeciwko {0} + + + Nieprawidłowy numer bazy. + + + Nieprawidłowy rozmiar wojny. + Fuzzy + + + Lista aktualnych wojen + Fuzzy + + + niezdobyta + + + Nie uczestniczysz w tej wojnie. + + + @{0} nie uczestniczysz w tej wojnie albo ta baza została już zniszczona. + + + Brak aktywnych wojen. + Fuzzy + + + Rozmiar + + + Wojna przeciwko {0} już się zaczęła. + + + Wojna przeciwko {0} stworzona. + + + Wojna przeciwko {0} zakończyła się. + + + Ta wojna nie istnieje. + + + Wojna przeciwko {o} zaczęła się! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Brak rezultatów. + + + {0} już zemdlał. + + + {0} ma już pełne HP. + + + Twoim typem jest już {0} + + + użyto {0}{1} na {2}{3} zadając {4} obrażeń. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + Nie możesz znowu zaatakować bez odwetu! + + + Nie możesz zaatakować sam siebie. + + + {0} zemdlał! + + + wyleczono {0} używając {1} + + + {0} zostało {1} HP. + + + Nie możesz użyć {0}. Napisz `{1}ml` by zobaczyć listę wszystkich ruchów które możesz użyć. + + + Lista ruchów dla typu {0} + + + To nie jest efektywne. + + + Nie masz wystarczająco {0} + + + Ożywiono {0}, używając {1} + + + Ożywiłeś siebie, używając {0} + + + Twój typ został zmieniony z {0} na {1} + + + To trochę efektywne. + + + To bardzo efektywne! + + + Użyłeś za dużo ruchów, więc nie możesz się ruszyć! + + + Typem {0} jest {1} + + + Nie znaleziono użytkownika. + + + Zemdlałeś, więc nie jesteś w stanie się ruszyć! + + + **Automatyczne przydzielanie ról** dla nowych użytkowników jest teraz **wyłączone**. + + + **Automatycznie przydzielanie ról** dla nowych użytkowników jest teraz **włączone*. + + + Załączniki + + + Awatar został zmieniony + + + Zostałeś zbanowany z serwera {0}. +Powód: {1} + + + zbanowany + PLURAL + + + Użytkownik zabanowany + + + Nazwa bota została zmieniona na: {0} + + + Status bota został zmieniony na: {0} + + + Automatyczne usuwanie wiadomości pożegnalnych zostało wyłączone. + + + Wiadomości pożegnalne będą usuwane po {0} sekundach. + + + Obecna wiadomość pożegnalna: {0} + + + Włącz wiadomości pożegnalne, pisząc {0} + + + Nowa wiadomość pożegnalna ustawiona. + + + Powiadomienia pożegnalne wyłączone. + + + Powiadomienia pożegnalne są włączone na tym kanale. + + + Nazwa kanału została zmieniona. + + + Stara nazwa + + + Temat kanału zmieniony + + + Wyczyszczono. + + + Zawartość + + + Stworzono rolę {0} + + + Kanał tekstowy {0} został stworzony. + + + Kanał głosowy {0} został stworzony. + + + Wyciszono pomyślnie. + + + Usunięto serwer {0} + + + Zatrzymano automatyczne usuwanie potwierdzeń o udanych użyciach komend. + + + Rozpoczęto usuwanie potwierdzeń o udanych użyciach komend. + + + Kanał tekstowy {0} został usunięty. + + + Kanał głosowy {0} został usunięty. + + + Prywatna wiadomość od + + + Z powodzeniem dodano nowego darczyńcę. Łączna darowizna przekazana przez tego użytkownika wynosi: {0} 👑 + + + Dziękuję ludziom wypisanym na dole za pomoc w realizacji tego projektu! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Aktualna wiadomość powitalna: {0} + + + + + + + + + + + + + + + Nie możesz użyć tej komendy na użytkowniku z rolą wyższą lub równą twojej. + + + Obrazki załadowane po {0} sekundach. + + + + + + + + + {0} dołączył do {1} + + + Zostałeś wyrzucony z serwera {0}. +Powód: {1} + + + Użytkownik wyrzucony + Fuzzy + + + Lista języków +{0} + Fuzzy + + + + + + + + + + + + + + + Język serwera został zmieniony na {0} - {1} + + + {0} opuścił {1} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Wiadomość została wysłana. + + + {0} przeniesiono z {1} do {2} + + + + + + + + + Wyciszony + PLURAL (users have been muted) + + + Wyciszony + singular "User muted." + + + + + + + + + Potrzebuję uprawnień **administratora* żeby to zrobić. + + + Nowa wiadomość + Fuzzy + + + Nowy pseudonim + Fuzzy + + + Nowy temat + Fuzzy + + + Pseudonim zmieniony + Fuzzy + + + Serwer nie został znaleziony. + + + + + + Stara wiadomość + Fuzzy + + + Stary pseudonim + Fuzzy + + + Stary temat + Fuzzy + + + Wystąpił błąd. Najwyraźniej nie mam wystarczających uprawnień. + + + Uprawnienia tego serwera zostały zresetowane. + + + + + + + + + + + + + + + + + + + + + + + + Czas musi być pomiędzy {0} a {1} sekundą. + + + Z powodzeniem usunięto wszystkie role użytkownika {0} + + + Nie udało się usunąć ról. Nie mam wystarczających uprawnień. + + + Kolor roli {0} został zmieniony. + + + Ta rola nie istnieje. + + + + + + + + + + + + Wystąpił błąd przy usunięciu roli. Masz niewystarczające uprawnienia. + + + Nazwa roli została zmieniona. + + + Nie udało się zmienić nazwy roli. Nie mam wystarczających uprawnień. + + + Nie możesz edytować ról wyższych od twojej. + + + + + + Rola {0} została dodana do listy. + + + + + + + + + + + + + + + + + + + + + + + + Masz już rolę {0}. + + + + + + + + + Istnieje {0} ról, które możesz sam sobie nadać. + + + Tej roli nie możesz nadać sobie sam. + + + Nie posiadasz roli {0} + + + + + + Nie jestem w stanie nadać ci tej roli. `Nie mogę nadawać ról wyższych niż moja.` + + + Rola {0} została usunięta z listy ról, które użytkownik może sobie nadać sam. + + + + + + Masz teraz rolę {0}. + + + Z powodzeniem nadano rolę {0} użytkownikowi {1} + + + Nadanie roli nie powiodło się. Nie mam wystarczających uprawnień. + + + Nowy awatar został ustawiony! + + + Nowa nazwa kanału została ustawiona! + + + + + + + + + + + + + + + + + + + + + Użytkownik nie może wysłać więcej niż {1} wiadomości na {1} sekund. + + + + + + + + + + PLURAL + + + {0} będzie ignorował ten kanał. + + + {0} nie będzie więcej ignorował tego kanału. + + + + + + + + + + + + + + + + singular + + + Nazwa użytkownika + + + Nazwa użytkownika została zmieniona + Fuzzy + + + Użytkownicy + + + Użytkownik zbanowany + Fuzzy + + + + + + + + + + + + + + + + + + + + + + + + {0} jest teraz {1} + + + + + + {0} dołączył do kanału {1}. + + + {0} opuścił kanał {1}. + + + {0} przeniesiony z kanału {1} na {2} + + + + + + + + + Kanał głosowy został stworzony + Fuzzy + + + Kanał głosowy został usunięty + Fuzzy + + + + + + + + + + + + + + + + + + + + + + + + Użytkownik {0} z kanału głosowego + + + Zostałeś tymczasowo zablokowany na serwerze {0} +Powód: {1} + + + Użytkownik został odbanowany + Fuzzy + + + + + + + + + + + + Użytkownik tymczasowo zablokowany + Fuzzy + + + nagrodził {0} {1} + + + Powodzenia następnym razem! ^_^ + + + Gratulacje! Wygrałeś {0} za wyrzucenie ponad {1} + + + Talia została przetasowana. + + + + User flipped tails. + + + Zgadłeś! Wygrałeś {0} + + + + + + Dodaj reakcję {0} do tej wiadomości, aby dostać {1} + + + To wydarzenie jest aktywne {0} godziny. + + + Wydarzenie reagowania kwiatkami rozpoczęło się! + + + dał (0} dla {1} + X has gifted 15 flowers to Y + + + {0} ma {1} + X has Y flowers + + + Orzeł + Fuzzy + + + Ranking + + + + + + Nie możesz założyć się o więcej niż {0} + + + Nie możesz założyć się o mniej niż {0} + + + Nie masz wystarczająco {0} + + + W talii nie ma więcej kart. + + + + + + Wyrzucono {0} + + + Zakład + + + ŁAAAAAAAAAAAAŁ!!! Gratulacje!!! x{0} + + + + + + + + + + + + + + + Użytkownicy muszą wpisać tajny kod aby dostać {0}. +Trwa {0} sekund. Nie nikomu. Ciiii. + + + + + + + + + Reszka + Fuzzy + + + z powodzeniem wziął {0} od {1} + + + nie był w stanie wziąć {0} od {1}, ponieważ użytkownik nie ma tylu {2}! + + + + + + Tylko właściciel bota + + + + + + Możesz wspierać ten projekt na patreonie: <{0}> albo poprzez paypala: <{1}> + + + + + + + + + + + + Nie mogę znaleźć komendy. Proszę sprawdź czy komenda istnieje, zanim jej użyjesz. + + + Opis + + + Możesz wspierać projekt NadekoBot na +Patreonie <{0}> albo +Paypalu <{1}> +Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomości. + +**Dziękujemy** ♥️ + + + **Lista komend**:<{0}> +**Poradniki hostowania i dokumenty znajdziesz tutaj**:<{1}> + Fuzzy + + + Lista komend + Fuzzy + + + Lista modułów + + + + + + Ten moduł nie istnieje. + + + + + + + + + Użycie + + + Autohentai uaktywnione. Obrazki z jednym z tagów: {1} będą zamieszczane co {0} sekund. + + + Tag + + + Wyścig zwierzaków + Fuzzy + + + Nie udało się zacząć wyścigu, ponieważ nie wzięła w nim udziału wystarczająca ilość osób. + + + Wszystkie miejsca są zajęte! Wyścig zacznie się natychmiastowo. + + + {0} dołączył jako {1} + + + {0} dołączył jako {1} i założył się o {2}! + + + Wpisz {0}jr aby wciąć udział w wyścigu. + + + Zacznie się za 20 sekund albo gdy wszystkie miejsca będą zajęte. + + + Zaczyna z {0} uczestnikami. + + + {0} jako {1} wygrał wyścig! + + + {0} jako {1} wygrał wyścig i {2}! + + + + + + + Someone rolled 35 + + + Wyrzucone kostki: {0} + Dice Rolled: 5 + + + Nie można zacząć wyścigu. Prawdopodobnie inny wyścig jest już aktywny. + + + Żaden wyścig nie jest aktywny na tym serwerze. + + + Drugi numer musi być większy od pierwszego. + + + Zmiany serca + Fuzzy + + + + + + Rozwody + + + Lubi + + + Cena + + + Nie zdobyłeś jeszcze żadnej waifu. + + + Ranking + + + + + + + Make sure to get the formatting right, and leave the thinking emoji + + + + + + + + + chce być zdobyta przez {0}. Aww <3 + + + zdobył waifu {0} za {1}! + + + Rozwiodłeś się z waifu, która cię lubi. Ty bezduszny potworze! +{0} odtrzymał {1} jako rekompensatę. + + + + + + + + + Żadna waifu nie jest taka tania. Musisz zapłacić co najmniej {0} aby zdobyć waifu, nawet jeśli nie jest tyle warta. + + + Musisz zapłacić {0} albo więcej aby zdobyć tą waifu. + + + Ta waifu nie jest twoja. + + + Nie możesz zdobyć siebie. + + + Rozwiodłeś się ostatnio. Musisz poczekać {0} ny i {1} minuty aby rozwieść się ponownie. + + + Nikt + + + Rozwiodłeś się z waifu, która cię nie lubi. W zamian dostałeś {0}. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Zwycięzcą jest {0} z {1} punktami. + + + + + + Pytanie + + + + + + + + + + + + Wyścig zwierzaków właśnie się odbywa. + + + Łącznie: {0} Średnia: {1} + + + Kategoria + + + Wyłączono cleverbota na tym serwerze. + + + Włączono cleverbota na tym serwerze. + + + + + + + + + + plural + + + + + + Nie udało się załadować pytania. + + + Gra rozpoczęta. + + + Gra w wisielca rozpoczęta + + + Gra w wisielca już trwa na tym kanale. + + + Rozpoczynanie gry w wisielca nie powiodło się. + + + + + + Ranking + + + Nie masz wystarczająco {0} + + + Brak rezultatów + + + podniósł {0} + Kwoth picked 5* + + + {0} zasadził {1] + Kwoth planted 5* + + + + + + + + + {0} zgadł! Odpowiedź to: {1} + + + + + + {0} posiada {1} punktów + + + + + + Koniec czasu! Prawidłowa odpowiedź to {0} + + + {0} zgadł i wygrał grę! Odpowiedź to: {1} + + + Nie możesz grać przeciwko sobie. + + + + + + Remis! + + + + + + {0} wygrał! + + + + + + Brak ruchów! + + + Koniec czasu! + + + Kolej {0} + + + {0} kontra {1} + + + + + + Automatyczne odtwarzanie wyłączone. + + + Automatyczne odtwarzanie włączone. + + + Domyślna głośność ustawiona na {0}% + + + + + + + + + Zakończono odtwarzanie piosenki + + + + + + + + + + + + ID + + + + + + Maksymalny czas grania ustawiony na: bez limitu. + + + Maksymalny czas grania ustawiony na: {0} sekund. + + + Maksymalna długość kolejki ustawiona na: bez limitu. + + + Maksymalna długość kolejki ustawiona na {5} utworów. + + + + + + Imię + + + Teraz gra + + + + + + Brak wyników + + + + + + + + + + + + + + + + + + Playlista usunięta. + + + Nie możesz usunąć tej playlisty. Albo nie istnieje albo nie jesteś jej autorem. + + + Playlista z takim ID nie istnieje. + + + + + + Playlista zapisana + + + + + + Kolejka + + + Zakolejkowany utwór + + + Kolejka wyczyszczona. + + + + + + Usunięto utwór + context: "removed song #5" + + + + + + Powtarzenie playlisty + + + Powtarzanie utworu + + + Powtarzanie aktualnego utworu zatrzymane. + + + + + + Powtarzanie playlisty wyłączone. + + + Powtarzanie playlisty włączone. + + + + + + Przewinięto do `{0}:{1}` + + + Utwory pomieszane + + + Utwór przeniesiony + + + + + + + + + + + + Głośność musi być pomiędzy 0 a 100. + + + Głośność ustawiona na {0}% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Komenda {0} ma teraz {1}-sekundowy cooldown. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + komenda + Gen (of command) + + + moduł + Gen. (of module) + + + + + + + + + + + + + + + + + + + + + + + + + Short of seconds. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Zdolności + + + + + + Zaczęto automatyczne tłumaczenie wiadomości na tym kanale. Wiadomości użytkowników będą automatycznie usuwane. + + + + + + + + + Zaczęto automatyczne tłumaczenie wiadomości na tym kanale. + + + Zakończono automatyczne tłumaczenie wiadomości na tym kanale. + + + + + + Nieznaleziono tej karty. + + + fakt + + + Rozdziały + + + + + + + + + + + + + + + + + + Zakończony + + + + + + + + + Data + + + + + + + + + Odcinki + + + Wystąpił błąd. + + + Przykład + + + Wyszukiwanie tego animu nie powiodło się. + + + Wyszukiwanie mango nie powiodło się. + + + Gatunki + + + + + + Wysokość/szerokość + + + + + + Wilgotność + + + + + + Wyszukiwanie tego filmu nie powiodło się. + + + + + + Żarty nie zostały załadowane. + + + + + + Poziom + + + + Don't translate {0}place + + + + + + Magiczne przedmioty nie zostały załadowane. + + + MAL użytkownika {0} + + + + + + + + + + + + Brak rezultatów. + + + + + + + + + + + + + + + + + + + + + + + + Platforma + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Skracanie tego url'u nie powiodło się + + + Skróć url + + + Coś poszło nie tak. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Wschód słońca + + + Zachód słońca + + + Temperatura + + + + + + 3 ulubione anime: + + + Tłumaczenie: + + + + + + + + + Url + + + + + + + + + + + + + + + Strona nie została znaleziona. + + + Szybkość wiatru + + + + + + + + + Dołączył + + + + /s and total need to be localized to fit the context - +`1.` + + + + + + + + + + + + ID bota + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Błąd + + + + + + ID + + + + + + + + + + + + + Invalid months value/ Invalid hours value + + + Dołączył do Discorda + + + Dołączył do serwera + + + + + + Nie znaleziono serwerów na tej stronie. + + + + + + Członkowie + + + Pamięć + + + Wiadomości + + + + + + Imię + + + Pseudonim + + + Nikt nie gra w tą grę. + + + + + + + + + + + + + + + Właściciel + + + ID właściciela + + + + + + {0} serwerów +{1} kanałów głosowych +{2} kanałów tekstowych + + + + + + + + + + + + + + + + + + + + + Region + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Wynik + + + Role + + + + + + + + + Kolory zostały podane w niepoprawnej formie. Użyj np. `#00ff00` + + + Zaczęto zmienianie kolorów dla roli {0} + + + Zakończono zmienianie kolorów dla roli {0} + + + + + + Informacje o serwerze + + + + + + + + + + + + + + + Nie znaleziono żadnych specjalnych emotikon + + + + + + Kanały głosowe + + + + + + + + + + Id of the user kwoth#1234 is 123123123123 + + + Użytkownicy + + + Kanały głosowe + + + Już dołączyłeś do tego wyścigu! + + + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx new file mode 100644 index 00000000..a1b017d1 --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx @@ -0,0 +1,2275 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Denna bas är redan tagen eller förstörd. + + + Denna bas är redan förstörd. + + + Denna bas är inte tagen. + + + **FÖRSTÖRD** bas #{0} i krig mot {1} + + + {0} har **TAGIT BORT SITT ANSPRÅK PÅ** bas #{1} i krig mot {2} + + + {0} har gjort anspråk på en bas #{1} i ett krig mot {2} + + + @{0} Du har redan gjort anspråk på bas #{1}. Du kan inte göra ett anspråk på en ny bas. + + + Anspråk från @{0} för ett krig mot {1} har gått ut. + Fuzzy + + + Fiende + + + Information om krig mot {0} + + + Ogiltigt basnummer. + + + Ogiltig krigsstorlek. + Fuzzy + + + Lista Över Aktiva Krig + Fuzzy + + + Inte gjort anspråk på + + + Du är inte med i det kriget. + + + @{0} Du är antingen inte med i det kriget eller så är basen redan förstörd. + + + Inga aktiva krig. + Fuzzy + + + Storlek + + + Krig mot {0} har redan börjat. + + + Krig mot {0} skapat. + + + Krig mot {0} har tagit slut. + + + Det kriget existerar inte. + + + Krig mot {0} har börjat! + + + Alla anpassade emojis uppgifter borttagna. + + + Anpassad emoji har blivit raderad. + + + + Otillräckliga behörigheter. Kräver Bot ägande för globala anpassade reaktioner, och administratör för server anpassade reaktioner. + + + Lista av alla egengjorda reaktioner + + + Egengjorda Reaktioner + + + Nya egengjorda Reaktioner + + + Inga egnagjorde reaktioner hittades. + Fuzzy + + + Ingen egengjord reaktion funnen med det id. + + + svar + + + Egengjord reaktion statistiker. + + + Statistiker rensade för {0} egengjorda reaktioner. + + + Inga statistik för den triggern funnen, inget återgärd gjord. + + + Trigger. + + + Automatisk hentai stoppad. + + + Inga resultat hittades. + + + +{0} har redan svimmat + + + {0} har redan full hälsa + + + din typ är redan {0} + + + har använt {0}{1} på {2}{3} för {4} skada. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + Du kan inte attackera igen utan motståndarens drag! + + + du kan inte attackera dig själv + + + +{0} har svimmat! + + + helade {0} med en {1} + + + + {0} har {1} hälsa kvar + + + Du kan inte använda {0}. Skriv `{1}ml` för att se en lista av attacker du kan använda. + + + Attacker för {0} typer + + + Detta var inte så effektivt. + + + Du har inte nog {0} + + + återupplivade {0} med en {1} + + + Du återupplivade dig själv med en {0} + + + Din typ har blivit ändrad till {0} för en {1} + + + Det är någorlunda effektivt. + + + Det är super effektivt! + + + Du använde för många attacker på raken, så du kan inte attackera! + + + Typ av {0} är {1} + + + Användaren hittades inte. + + + Du svimmade, så du kan inte attackera! + + + **Auto tilldela roll** på användare som ansluter sig är nu **inaktiverad**. + + + **Auto tildela roll** på användare som ansluter sig är nu **aktiverad**. + + + Tillbehör + + + Avatar byttes + + + Du har blivit bannad från {0} server. anledning: {1} + + + bannad + PLURAL + + + Användare bannad + + + Bot namn byttes till {0} + + + Bot status byttes till {0} + + + Automastisk radering av avskeds meddelanden har blivit avaktiverat. + + + Avskeds meddelanden kommer bli raderade efter {0} sekunder. + + + Nuvarande avskeds meddelande: {0} + + + Aktivera avskeds meddelanden genom att skriva {0} + + + Nytt avskeds meddelande satt. + + + Avskeds meddelande inaktiverat. + + + Avskeds meddelanden aktiverad på denna kanal. + + + Kanal namn har byts. + + + Gammalt Namn + + + Kanal ämne har byts. + + + Städats upp. + + + Innehåll + + + Lyckats skapa roll {0} + + + Text kanal {0} skapad. + + + Röst kanal {0} skapad. + + + Dövning lyckats. + + + Raderad server {0} + + + Stoppad automatisk borttagning av lyckade kommando åkallanden. + + + Raderar nu lyckade kommando åkallanden. + + + Text kanal {0} raderad. + + + Röst kanal {0} raderad. + + + Meddelande från + + + Lyckats lägga till en ny donator. Totalt donerat från denna användare: {0} 👑 + + + Tack alla personer listade som har hjälpt oss skapa detta projekt! + + + Jag kommer skicka vidare meddelanden till alla ägare. + + + Jag kommer bara skicka vidare meddelanden till den första ägaren. + + + Jag kommer skicka vidare meddelanden från och med nu. + + + Jag kommer sluta skicka vidare meddelande från och med nu. + + + Automatisk radering av hälsnings meddelanden har blivit avaktiverat. + + + hälsnings meddelanden kommer bli raderade efter {0} sekunder + + + Nuvarande direkt meddelande hälsning: {0} + + + Aktivera hälsnings direkt meddelande genom att skriva {0} + + + Ny direkt meddenlande vid hälsning har gjorts. + + + Direkt meddelande för hälsning har avaktiverats. + + + Direkt meddelande för hälsning har aktiverats. + + + Nuvarande hälsning: {0} + + + Aktivera hälsning genom att skriva {0} + + + Ny hälsning skapad. + + + Hälsningar har blivit avaktiverade. + + + Hälsningar har blivit aktiverade på denna kanal. + + + Du kan inte använda detta kommando på användare med högre eller likastående rank till din egna enligt rankerna. + + + Bilder laddade efter {0} sekunder! + + + Ogiltig inmatnings format. + + + Ogiltiga parametrar. + + + {0} har gått med {1} + + + Du har blivit kickad från {0} server. +Anledning: {1} + + + Användare sparkad + Fuzzy + + + Lista av språk +{0} + Fuzzy + + + Din servers lokal är nu {0} -{ 1} + + + Bottens standard lokal är nu {0} - {1} + + + Bottens språk är nu gjord till {0} - {1} + + + Misslyckades att ställa lokal. Se över kommandots hjälp. + + + Denna servers språk är nu gjord till {0} - {1} + + + {0} har lämnat {1} + + + Lämnat server {0} + + + Loggar {0} händelser i denna kanal. + + + Loggar alla händelser i denna kanal. + + + Loggning avaktiverad. + + + Loggade event du kan prenumerera till: + + + Loggning kommer ignorera {0} + + + Loggning kommer inte ignorera {0} + + + Stoppade loggning {0} händelser. + + + {0} har åkallat ett omnämnande på följande roller + + + Meddelande från {0} `[Bot Ägare]`: + + + Meddelande skickat. + + + {0} flyttad från {1] till {2} + + + Meddelande Raderat i #{0} + Fuzzy + + + Meddelande Uppdaterat i #{0} + Fuzzy + + + Mutade + PLURAL (users have been muted) + + + Mutad + singular "User muted." + + + Jag har sannolikt inte de flesta tillstånd för detta. + + + Ny mute roll gjord. + + + Jag behöver **Administration** tillåtelse för att göra det där. + + + Nytt Meddelande + Fuzzy + + + Nytt Smeknamn + Fuzzy + + + Nytt Ämne + Fuzzy + + + Smeknamn Ändrat + Fuzzy + + + Kan inte hitta den servern + + + Ingen shard med den ID funnen + + + Gammalt Meddelande + Fuzzy + + + Gammalt Smeknamn + Fuzzy + + + Gammalt Ämne + Fuzzy + + + Fel. Troligtvis så har jag inte tillräcklig behörighet. + + + Tillstånd för denna server har blivit återställt. + + + Aktiva Skydd + Fuzzy + + + {0} har blivit **avaktiverat** på denna server. + + + {0} Aktiverad + + + Fel. Jag behöver tillstånd att hantera roller. + + + + + Inga skydd är aktiverade. + Fuzzy + + + Användar + + + Om {0} eller mer användare går med inom {1} sekunder, kommer jag {2} dom. + + + Tiden måste vara inom {0} och {1} sekunder. + + + Lyckats ta bort alla roller från användare {0} + + + Misslyckades att ta bort roller. Jag har inte nog med behörighet. + + + Färger av {0} roll har blivit ändrad. + + + Den rollen existerar inte. + + + Dom angivna parametrarna är ogiltiga. + + + Ett fel uppstod på grund av ogiltig färg eller otillräckliga behörigheter. + + + Lyckats ta bort roll {0} från användare {1} + + + Misslyckades att ta bort roll. Jag har inte tillräckligt med behörighet. + + + Roll omdöpt. + + + Det gick inte att byta namn på roll. Jag har inte tillräckligt behörighet. + + + Du kan inte redigera roller högre än din högsta roll. + + + Tog bort spelande meddelande: {0} + + + Roll {0} har blivit tillagd till listan. + + + {0} inte funnen. Städar upp. + + + Roll {0} finns redan i listan. + + + Tillagd. + + + Rotering av spelar status avaktiverad. + + + Rotering av spelar status aktiverad. + + + Här är en lista av roterande statusar: +{0} + + + Inga roterande spel statusar aktiverade. + + + Du har redan {0} roll. + + + Du har redan {0} exklusiv egentilldelad roll + + + Egentilldelade roller är nu exklusiva! + + + Det finns {0} egentilldelade roller + + + Den rollen är inte möjlig att egentilldela. + + + Du har inte {0} roll. + + + Egentilldelade roller är nu inte exklusiva! + + + Jag är oförmögen att lägga den rollen för dig. 'Jag kan inte lägga till roller till ägare eller andra roller högre än min roll i roll hierarkin.` + + + + + {0} har tagits bort från listan av egentilldelade roller. + + + Du har inte längre {0} roll. + + + Du har nu {0} roll. + + + Lyckats lägga till roll {0} till användare {1} + + + Misslyckades att lägga till roll. Jag har inte nog behörighet. + + + Ny avatar satt! + + + Nytt kanal namn satt. + + + Nytt spel satt! + + + Nytt stream satt! + + + Nytt kanal ämne satt! + + + Shard {0} har återansluts. + + + Shard {0} håller på att återansluta. + + + Stänger ner. + + + Användare kan inte skicka mer än {0} meddelanden varje {1} sekunder. + + + Långsamt läge avaktiverat. + + + Långsamt läge initierad + + + mjukt-bannad (kickad) + PLURAL + + + {0} kommer ignorera denna kanal. + + + {0} kommer inte längre att ignorera denna kanal. + + + Om en användare skriver {0} samma meddelanden på en gång so kommer jag {1} dom. +__IgnoreradeKannaler_: {2} + + + Text kanal skapad + Fuzzy + + + Text kanal förstörd␣ + Fuzzy + + + Borttagning av dövning lyckats. + + + Omutad + singular + + + Användarnamn + + + Användarnamn ändrats + Fuzzy + + + Användare + + + Användare Bannad + Fuzzy + + + {0} har blivit **mutad** från att chatta. + + + {0} har blivit **omutad** från att chatta. + + + Användare har gått med. + Fuzzy + + + Användare har lämnat. + Fuzzy + + + {0} har blivit **mutad** från text och röst kanal. + + + Användarens roll har blivit tillagd. + Fuzzy + + + Användarens roll har blivit borttagen. + Fuzzy + + + {0} är nu {1} + + + {0} har nu blivit **omutad** från text och röst kanal. + + + {0} har gått med {1} röst kanal. + + + {0} har lämnat {1} röst kanal. + + + {0} flyttade från {1} till {2} röst kanal. + + + {0} har blivit **röst mutad**. + + + {0} har blivit **röst omutad**- + + + Röst Kanal Skapad + Fuzzy + + + Röst Kanal Förstörd + Fuzzy + + + Avaktiverat röst + text funktion. + + + Aktiverat röst + text funktion. + + + Jag har inte **hantera roller** och / eller **hantera kanaler** tillstånd, så jag kan inte köra `röst + text` på {0} server. + + + Du aktiverar / inaktiverar funktionen och **Jag har inte administratörsbehörighet**. Detta kan orsaka vissa problem, och du kommer själv att behöva städa upp textkanaler efteråt. + + + Jag behöver minst **hantera roller** och **hantera kanaler** behörighet att aktivera den här funktionen. (Föredrar Administration tillåtelse) + + + Användare {0} från text chat + + + Användare {0} från text och röst chat. + + + Användare {0} från röst kanal + + + Du har blivit mjuk-bannad från {0} server. +Anledning: {1} + + + Användare inte längre bannad. + Fuzzy + + + Migration gjort! + + + Fel vid migrering, kontrollera botens konsol för mer information. + + + Närvaro Uppdateringar. + Fuzzy + + + Användare mjuk-bannad. + Fuzzy + + + har tilldelat {0} till {1} + + + Bättre lycka nästa gång ^_^ + + + Grattis! Du vann {0} för att ha rullat över {1} + + + Kortlek omblandat. + + + Vänt {0}. + User flipped tails. + + + Du gissade rätt! Du vann {0} + + + Ogiltigt nummer anged. Du kan vända 1 till {0} mynt. + + + Lägg till {0} reaktion till detta meddelande för att få {1}␣ + + + Denna händelse är aktiv upptill {0} timmar. + + + Blomm reaktions händelse igång! + + + har begåvat {0} till {1} + X has gifted 15 flowers to Y + + + {0} har {1} + X has Y flowers + + + Krona + Fuzzy + + + Topplista + + + Tilldelat {0} till {1} ​​användare från {2} roll. + + + Du kan inte satsa mer än {0} + + + Du kan inte satsa mindre än {0} + + + Du har inte nog med {0} + + + Inga fler kort i kortleken. + + + Lotto användare + Fuzzy + + + Du rullade {0} + + + Satsa + + + WOAAHHHHHH!!! Grattis!!! x{0} + + + En enda {0}, x {1} + + + Wow! Tur! Tre av en sort! x {0} + + + Bra jobbat! Två {0} - insats x {1} + + + Vann + + + Användare måste ange en hemlig kod för att få {0}. +Varar {1} sekunder. Berätta inte för någon. Shhh. + + + Hemlig spel händelse har tagit slut. {0} användare fick belöningen. + + + Hemlig spel status händelse har börjat + + + Klave + Fuzzy + + + Lyckats ta {0} från {1} + + + Lyckades inte ta {0} från {1} för att användaren inte har så mycket {2}! + + + Tillback till ToC + + + Bara Bot ägare + Fuzzy + + + Kräver {0} kanal tillstånd. + + + Du kan stödja projektet på patreon: <{0}> eööer paypal: <{1}> + + + Kommando och alias + Fuzzy + + + Kommando lista regenereras. + + + Skriv `{0}h CommandName` för att se hjälp för det specifika kommandot. t.ex. `{0}h >8ball` + + + Jag kan inte hitta det kommandot. Var snäll och verifiera om det kommandot existerar innan du provar igen. + + + Beskrivning + + + Du kan stödja NadekoBot projektet på +Patreon <{0}> eller +Paypal <{1}> +Glömm inte att lämna ditt discord namn eller id i meddelandet. + +**Tack så mycket** ♥️ + + + **Lista av kommandon**. <{0}> +**Värd guider och dokument kan bli hittade här*': <{1}> + Fuzzy + + + Kommandolista + Fuzzy + + + Modullista + Fuzzy + + + Skriv `{0}cmds ModuleName` för att få en lista av kommandon i den modulen. t.ex. `{0}cmds games` + + + Modulen existerar inte. + + + Kräver {0} server tillåtelse. + + + Innehållsförteckning + Fuzzy + + + Användning + + + Auto hentai startad. Svarar varje {0}s med en av följande taggar: +{1} + + + Tagg + + + Djur Lopp + Fuzzy + + + Det gick inte att starta eftersom det inte fanns tillräckligt många deltagare. + + + Loppet är full! Startar omedelbart. + + + {0} gick med som en {1} + + + {0} gick med som en {1} och satsa {2}! + + + Skriv {0}jr för att ansluta dig till loppet. + + + Börjar från inom 20 sekunder eller när rummet är fullt. + + + Startar från och med {0} deltagare. + + + {0} som {1} Vann loppet! + + + {0} som {1} Vann loppet och {2}! + + + Ogiltigt nummer specificerat. Du kan rulla {0}-{1} tärningar på en gång. + + + rullade {0} + Someone rolled 35 + + + Tärningar rullade: {0} + Dice Rolled: 5 + + + Misslyckades att starta loppet. Ett annat lopp är förmodligen igång. + + + Inget lopp finns på denna server + + + Andra numret måste vara större än den första. + + + Ändring av hjärta + Fuzzy + + + Anspråk av + Fuzzy + + + Skilsmässor + + + Gillar + + + Pris + + + Inga waifus har blivit tagna hittls. + + + Top Waifus + + + din affinitet är redan inställd på den waifun eller så försöker du att ta bort din affinitet utan att ha en. + + + ändrat sin affinitet från {0} till {1}. + +* Detta är moraliskt tveksamt. * 🤔 + Make sure to get the formatting right, and leave the thinking emoji + + + Du måste vänta {0} timmar och {1} minuter för att byta affinitet igen. + + + Din affinitet återställs. Du har inte en person som du gillar längre. + + + vill vara {0}s waifu. Aww <3 + + + har tagit {0} som deras waifu för {1}! + + + Du har skilt dig från en waifu som gillar dig. Ditt hjärtlösa monster. +{0} har fått {1} som kompensation. + + + du kan inte ställa affinitet till dig själv, din egoist. + + + 🎉 Deras kärlek är uppfyllt! 🎉 +{0} s nya värdet är {1}! + + + Ingen waifu är så billig. Du måste betala minst {0} för att få en waifu, även om deras riktiga värde är lägre. + + + Du måste betala {0} eller mer för att ta den waifun! + + + Denna waifun är inte din. + + + Du kan inte göra anspråk på sig själv. + + + Du blev frånskild nyligen. Du måste vänta {0} timmar och {1} minuter att skilja sig igen. + + + Ingen + + + Du har frånskild en waifu som inte gillar dig. Du har fått {0} tillbaka. + + + 8boll + + + Acrophobia + + + Spelet slutade utan några synpunkter. + + + Inga röster. Spelet slutade med ingen vinnare. + + + Acronym var {0}. + + + Acrophobia spel är redan igång i denna kanal. + + + Spelet började. Skapa en mening med följande akronym: {0}. + + + Du har {0} sekunder för att göra en inlaga. + + + {0} lämnat sitt straff. ({1} totalt) + + + Rösta genom att skriva ett number av det du inlämnar + + + {0} lägger sin röst! + + + Vinnaren är {0} med {1} poäng. + + + {0} är vinnaren för att vara den enda användaren som gjorde ett förslag! + + + Fråga + + + Det är lika! Båda valde {0} + + + {0} vann! {1} slår {2} + + + Förslag Stängda + Fuzzy + + + Djur lopp körs redan. + + + Totalt: {0} Genomsnitt: {1} + + + Kategori + + + Avaktiverade cleverbot på denna server. + + + Aktiverat cleverbot på denna server. + + + Valuta skapande har inaktiverats på denna kanal. + + + Valuta skapande har aktiverats på denna kanal. + + + {0} slumpmässig {1} dök up! Plocka upp genom att skriva `{2} pick` + plural + + + En slumpmässig {0} dök upp! Plocka upp genom att skriva `{1} pick` + + + Misslyckades ladda en fråga. + + + Spel börjat + Fuzzy + + + Hänga gubbe har börjat + + + Hänga gubbe spelas redan i denna kanal. + + + Startar hänga gubbe errored. + + + Lista över "{0} hängagubbe" term typer: + + + Ledartavla + + + Du har inte nog med {0} + + + Inga resultat + + + plockade {0} + Kwoth picked 5* + + + {0} planterade {1} + Kwoth planted 5* + + + Trivia spel pågår redan i denna server. + + + Trivia spel + + + {0} gissade rätt! Svaret var: {1} + + + Inget trivia spel pågår just nu. + + + {0} har {1} poäng + + + Stoppar efter denna fråga. + + + Tiden är slut! Det korrekta svaret var {0} + + + {0} gissade rätt och VANN spelet! Svaret var: {1} + + + Du kan inte spela mot dig själv. + + + Tre I Rad spelet pågår redan i denna kanal. + + + Oavgjort! + + + har skapat ett spel av Tre I Rad. + + + {0} har Vunnit! + Fuzzy + + + Matchade Tre + Fuzzy + + + Inga drag kvar! + + + Tiden är Slut! + Fuzzy + + + {0}s drag + + + {0} mot {1} + + + Försöker köa {0} låtar... + + + Auto spelning avaktiverad. + + + Auto spelning aktiverad. + + + Standard volym satt till {0}% + + + Katalog kö komplett. + + + rent spel + + + Sång Avslutad + Fuzzy + + + Rent spel avaktiverat + + + Rent spel aktiverat + + + Från position + + + Id + + + Ogiltig inmatning. + + + Max speltid har ingen gräns nu. + + + Max speltid satt till {0} sekund(er). + + + Max musik köns storleken inställd på obegränsad. + + + Max musik köns storleken inställd på {0} spår. + + + Du måste vara i röst kanalen på den här servern. + + + Namn + + + Nu Spelas + Fuzzy + + + Ingen aktiv musikspelare. + + + Inga sök resultat. + + + Musikuppspelning pausas. + + + Spelar Kö - Sida {0}/{1} + Fuzzy + + + Spelar låt + Fuzzy + + + `#{0}` - **{1}** by *{2}* ({3} låtar) + + + Sida {0} av Sparade Spellistor + Fuzzy + + + Spelllista borttagen. + + + Kunde ej ta bort den låtlistan. Antingen finns den ej eller så är det inte du som skapat den. + + + Spellista med det ID existerar inte. + + + Spellista komplett. + + + Spellista Sparad + Fuzzy + + + {0}s gräns + + + + + + Köad sång + Fuzzy + + + Musik kön rensad. + + + Kön är full på {0}/{0}. + + + Tog bort låt + context: "removed song #5" + + + Repeterar Nuvarande Låt + Fuzzy + + + Repeterar Spellistan + Fuzzy + + + Repeterar Låt + Fuzzy + + + Nuvarande låt repetering stoppad. + + + Musikuppspelning återupptas. + + + Upprepning av spellista inaktiverad. + + + Upprepning av spellista aktiverad. + + + Jag kommer nu att utgångs spela, färdig pausad och borttagna låtar i denna kanal. + + + Skippat till `{0}:{1}` + + + Sånger blandade. + Fuzzy + + + Sång flyttad + Fuzzy + + + {0}h {1}m {2}s + + + Till position + + + obegränsad + + + Volym måste vara mellan 0 och 100 + + + Volym satt till {0}% + + + Avaktiverat användning av alla MODULER på kanalen {0}. + + + Aktiverat användning av alla MODULER på kanalen {0}. + + + Tillåtet + + + Avaktiverat användning av alla MODULER för roll {0}. + + + Aktiverat användning av alla MODULER för roll {0}. + + + Avaktiverat användning av alla MODULER på denna server. + + + Aktiverat användning av alla MODULER på denna server. + + + Avaktiverat användning av alla MODULER för användare {0}. + + + Aktiverat användning av alla MODULER för användare {0}. + + + Svartlistat {0} med ID {1} + + + Kommando {0} har nu {1}s väntetid. + + + Kommando {0} har nu ingen väntetid och alla existerande väntetider har blivit rensade. + + + Inga kommando väntetider satta. + + + Kommando kostar + + + Avaktiverade användning av {0} {1} på kanal {2}. + + + Aktiverade användning av {0} {1} på kanal {2}. + + + Nekad + + + La till ordet {0} till listan över filtrerade ord. + + + Lista av filtrerade ord + + + Tog bort ord {0} från listan av filtrerade ord. + + + Ogiltig andra parameter.(Måste vara ett nummer mellan {0} och {1}) + + + Inbjuds filtrering avaktiverad på denna kanal. + + + Inbjuds filtrering aktiverad på denna kanal. + + + Inbjuds filtrering avaktiverad på denna server. + + + Inbjuds filtrering aktiverad på denna server. + + + Flyttade behörighet {0} från #{1} till #{2} + + + Kan inte kitta behörighet på index #{0} + + + Inga kostnader satta. + + + kommando + Gen (of command) + + + modul + Gen. (of module) + + + Behörighets sida {0} + + + Nuvarade behörighets roll är {0} + + + Användare behöver nu {0} rollen för att kunna ändra behörigheter. + + + Inga behörigheter funna i den indexen. + + + Tog bort behörighet #{0} - {1} + + + Avaktiverat användning av {0} {1} för {2} rollen. + + + Aktiverat användning av {0} {1} för {2} rollen. + + + sek. + Short of seconds. + + + Avaktiverat användning av {0} {1} på denna server. + + + Aktiverat användning av {0} {1} på denna server. + + + Togbort {0} från svartlistan med ID {1} + + + oredigerbar + + + Avaktiverat användning av {0} {1} för {2} användare. + + + Aktiverat användning av {0} {1} för {2} användare. + + + Jag kommer inte länga visa behörighets varningar. + + + Jag kommer nu visa behörighets varningar. + + + Ord filtrering avaktiverat i denna kanal. + + + Ord filtrering aktiverat i denna kanal. + + + Ord filtrering avaktiverat på denna server. + + + Ord filtrering aktiverat på denna server. + + + Förmågor + + + Ingen favoritanime än + + + Började automatisk översättning av meddelanden på denna kanal. Användarmeddelanden kommer att automatiskt tas bort. + + + ditt automatiska översätta-språk har tagits bort. + + + ditt automatiska översätta-språk har blivit satt till {0}>{1} + + + Började automatisk översättning av meddelanden på denna kanal. + + + Stoppat automatisk översättning av meddelanden på denna kanal. + + + Dålig inmatnings format, eller så gick något fel. + + + Kunde ej hitta det kortet. + + + fakta + + + Kapitel + + + Serie # + + + Kompetitiva Förluster + Fuzzy + + + Kompetitiva Spelade + Enbart kompetitiva eller kompetitiva matcher? :thinking: +Fuzzy + + + Kompetitiv Rank + Fuzzy + + + Kompetitiva Vinster + + + Avslutade + + + Kondition + + + Kostnad + + + Datum + + + Definera: + + + Övergivna + Fuzzy + + + Avsnitt + + + Ett fel inträffade. + + + Exempel + + + Kunde ej hitta den animun. + + + Kunde ej hitta den mangon. + Fuzzy + + + Genres + + + Misslyckades att hitta en definition för den taggen. + + + Längd/Vikt + + + {0}m/{1}kg + + + Fuktighet + + + Bild Sökning För: + Fuzzy + + + Kunde ej hitta den filmen. + + + Ogiltig källa eller mål språk. + + + Skämt ej laddade. + + + Lat/Long + + + Nivå + + + Lista av {0} plats taggar + Don't translate {0}place + + + Plats + + + Magiska föremål inte laddade. + + + {0}:s MAL profil + Fuzzy + + + Bot ägare specificerade inte MashapeApiKey. Du kan inte använda den här funktionen. + + + Min/Max + + + Inga kanaler hittades. + + + Inga resultat hittades. + + + Placerad i kö + + + Original url + + + En osu! API nyckel krävs. + + + Misslyckades att hämta osu! signatur. + + + Hittade över {0} bilder. Visar slumpmässig {0}. + + + Användare inte funnen! Snälla kolla Regionen och BattleTag innan du försöker igen. + + + Planerar att kolla + + + Plattform + + + Ingen förmåga hittad. + + + Ingen pokemon funnen. + + + Profil link: + + + Kvalitet: + + + Snabb speltid + + + Snabba vinster + Fuzzy + + + Betyg + + + Poäng: + + + Leta efter: + Fuzzy + + + Misslyckades att förkorta den url. + + + Kort utl + + + Något gick fel. + + + Var snäll och specificera sök parametrar. + + + Status + + + Butik url + + + Streamer {0} är offline. + + + Streamer {0} är online med {1} tittare. + + + Du följer {0} streams på denna server. + + + Du följer inga streams på denna server. + + + Finns ingen sådan stream. + + + Stream existerar förmodligen inte. + + + Tog bort {0}'s stream från notifikationer. + + + Jag kommer notifikera denna kanal när status ändras. + + + Soluppgång + + + Solnedgång + + + Temperatur + + + Titel: + + + Top 3 favorit anime: + + + Översättning: + + + Typer + + + Misslyckades att hitta definitionen för den termen. + + + Url + + + Tittare + + + Tittar + + + Misslyckades att hitta term på den specificerade wikia. + + + Snälla skriv en wikia, följd av sökfråga. + + + Sidan kunde ej hittas. + + + vindhastighet + + + De {0} mest bannade mästare + + + Misslyckades att yodifiera din mening. + + + Gick med + + + `{0}.` {1} [{2:F2}/s] - {3} total + /s and total need to be localized to fit the context - +`1.` + + + Aktivitets sida #{0} + + + {0} användare totalt. + + + Författare + + + Bot ID + + + Lista av funktioner i {0}calc kommando + + + Kanalens {0} är {1} + + + Kanal ämne + + + Kommandon Körda + Fuzzy + + + {0} {1} är samma som {2} {3} + + + Enheter som kan användas av konverteraren + + + Kan inte konvertera {0} till {1}: enheter inte funna. + + + Kan inte konvertera {0} till {1}: typer av enheter är inte lika värda. + + + Skapad vid + + + Gå med kanal för att prata över servrar. + + + Lämnade kanal för att prata över servrar. + + + Detta är din CSC token + + + Egengjorda emojis + + + Fel + + + Funktioner + + + ID + + + Index utom räckhåll + + + Här är en lista av användare i dom rollerna: + + + Du är inte tillåten att använda detta kommando på roller med många användare i dem för att förhindra missbruk. + + + Ogiltigt {0} värde. + Invalid months value/ Invalid hours value + + + Gick med Discord + + + Gick med Server + Fuzzy + + + ID: {0} +Medlemmar: {1} +ÄgarID: {2} + Fuzzy + + + Inga servrar funna på den sidan. + + + List över repeterare + + + Medlemmar + + + Minne + + + Meddelanden + + + Meddelande repeterare + + + Namn + + + Smeknamn + + + Ingen spelar det spelet. + + + Inga aktiva repeterare. + + + Inga roller på denna sida. + + + Inga shards på denna sida. + + + Inget ämne satt + + + Ägare + + + Ägar IDs + + + Närvaro + + + {0} Servrar +{1} Textkanaler +{2} Röstkanaler + + + Tog bort alla citat med nyckelordet {0}. + + + Sida {0} av citat + + + Inga citat på denna sida. + + + Inga citat hittades som du kan ta bort. + + + Citat tillagt + + + Tog bort ett slumpvalt citat. + + + Region + + + Registrerad på + + + Jag kommer påminna {0} att {1} om {2} `({3:d.M.yyyy.} klockan {4:HH:mm})` + + + Inte en giltig tids format. Kolla kommandolistan. + + + Ny påminnelse mall satt. + + + Repeterar {0} varje {1} dag(ar), {2} timme(ar) and {3} minut(er). + + + Lista av repeterare + + + Ingen repeterare körs på denna server. + + + #{0} slutade. + + + Inga repeterande medelanden funna på denna server. + + + Resultat + + + Roller + + + Sida #{0} av roller på denna server: + + + Sida #{0} av roller för {1} + + + Inga färger använder rätt format. Använd `#00ff00` som exempel. + + + Började rotera {0} rollens färger. + + + Slutade rotera färger för {0} rollen + + + Denna servers {0} är {1} + + + Server Information + Fuzzy + + + Shard + + + Shard status + + + Shard **#{0}** är i {1} status med {2} servers + + + **Namn:** {0} **Länk:** {1} + + + Inga special emojis funna. + + + Spelar {0} låtar, {1} köad. + + + Textkanaler + Fuzzy + + + Här är länken till ditt rum: + + + Upptid + + + {0} av användare {1} är {2} + Id of the user kwoth#1234 is 123123123123 + + + Användare + + + Röstkanaler + Fuzzy + + + Du har redan gått med detta lopp! + + + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx b/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx new file mode 100644 index 00000000..9a4ed57f --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx @@ -0,0 +1,2179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + Düşman + + + + + + Hatalı köy numarası. + + + Savaş büyüklüğü geçerli değil. + + + Aktif olan savaşlar + + + Hak idda edilmedi. + Fuzzy + + + Bu savaşa katılmadınız. + + + @{0} Bu savaşa katılmadınız veya köyünüz yok edildi. + + + Aktif olan savaş yok. + + + Büyüklük + + + {0} İle olan savaş başladı. + + + {0} İle Savaş çıkardın. + + + {0} İle Olan savaş sona erdi. + + + Böyle bir savaş bulunamadı. + + + {0} İle olan savaş başladı. + + + Tüm özel reaksiyonlar temizlendi. + Fuzzy + + + Özel reaksiyonlar silindi. + Fuzzy + + + Yetersiz yetki.Global özel reaksiyonlar için bot sahibi yetkisi gerkirken, server tabanlı özel reaksiyonlar için Administrator yetkisi gerekir. + + + Tüm özel reaksiyonların listesi + + + Özel reaksiyonlar + + + Yeni özel reaksiyon + + + Böyle bir özel reaksiyon bulunamadı. + + + Bu id'ye sahip bir özel reaksiyon bulunamadı. + + + Cevap. + + + Özel reaksiyon istatistikleri + + + {0} özel reaksiyonun istatistikleri temizlendi. + + + + + + Tetiklendi. + Fuzzy + + + Autohentai durduruldu. + + + + + + + + + + + + + + + + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Kullanıcı girişinde otomatik rol tanımlaması devre dışı. + + + Kullanıcı girişinde otomatik rol tanımlaması devrede. + + + Eklentiler + + + Profil fotoğrafı değiştirildi. + + + {0} sunucusundan uzaklaştırıldınız. +Sebep: {1} + + + uzaklaştırıldı + PLURAL + + + Kullanıcı Uzaklaştırıldı + + + Bot ismi {0} ile değiştirildi. + + + Bot durum mesajı {0} ile değiştirildi. + + + Çıkış mesajlarının otomatik silinmesi devre dışı bırakıldı. + + + Çıkış mesajları {0} saniye sonra silinecektir. + + + Şu anki çıkış mesajı: {0} + + + {0} yazarak çıkış mesajlarını etkinleştirin. + + + Yeni çıkış mesajı tanımlandı. + + + Çıkış duyuruları devre dışı. + + + Çıkış duyuruları bu kanalda devreye sokuldu. + + + Kanal İsmi Değişti + + + Eski İsim + + + Kanal Konusu Değişti + + + Temizlendi. + + + İçerik + + + {0} rolü başarıyla yaratıldı. + + + {0} yazı kanalı yaratıldı. + + + {0} ses kanalı yaratıldı. + + + Sağırlaştırma başarılı. + + + {0} sunucusu silindi. + + + Başarılı komut bildirimlerinin otomatik silinmesi durduruldu. + + + Artık başarılı komut bildirimleri siliniyor. + + + {0} yazı kanalı silindi. + + + {0} ses kanalı silindi. + + + Bu kullanıcıdan özel mesaj geldi: + + + Başarıyla yeni bağışçı eklendi. Bu kullanıcının bağışladığı toplam miktar: {0} 👑 + + + Aşağıda ismi bulunan kişilerin bu projeyi gerçekleşmesini sağladıkları için teşekkürler. + + + Özel mesajları bütün sahiplere ileteceğim. + + + Özel mesajları sadece ilk sahibe ileteceğim. + + + Özel mesajları iletmeye başlayacağım. + + + Özel mesajları iletmeyi bırakacağım. + + + Karşılama mesajlarının otomatik silinmesi devre dışı bırakıldı. + + + Karşılama mesajları {0} saniye sonra silinecektir. + + + Şu anki özelden karşılama mesajı: {0} + + + {0} yazarak özelden karşılama mesajlarını aktif edebilirsiniz. + + + Yeni özelden karşılama mesajı tanımlandı. + + + Özel mesajdan karşılama duyuruları devre dışı. + + + Özel mesajdan karşılama duyuruları devrede. + + + Şu anki karşılama mesajı: {0} + + + {0} yazarak karşılama mesajlarını aktif et. + + + Yeni karşılama mesajı tanımlandı. + + + Karşılama duyuruları devre dışı. + + + Karşılama duyuruları bu kanalda aktif edildi. + + + Bu komutu senin dengin veya üstlerin üstünde kullanamazsın. + + + Resimler {0} saniye sonra yüklendi. + + + Geçersiz giriş biçimi. + + + Geçersiz parametreler. + + + {0} {1}'e katıldı. + + + {0} sunucusundan atıldınız. +Sebep: {1} + + + Kullanıcı Atıldı + Fuzzy + + + Dil Listesi +{0} + Fuzzy + + + Sunucunuzun dili değiştirildi: {0} - {1} + + + Bot varsayılan dili değiştirildi: {0} - {1} + + + Bot dili değiştirildi: {0} - {1} + + + Yerel ayarlar değiştirilemedi. Komutun kılavuzuna bakın. + + + Sunucunun dili değiştirildi: {0} - {1} + + + {0} {1}'den ayrıldı. + + + Sunucudan çıkıldı: {0} + + + Bu kanaldaki {0} olayları kayıt ediliyor. + + + Bu kanaldaki bütün olaylar kayıt ediliyor. + + + Kayıtlar devre dışı. + + + Abone olabileceğiniz olaylar: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PLURAL (users have been muted) + + + + singular "User muted." + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PLURAL + + + + + + + + + + + + + + + + + + + + + + singular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + User flipped tails. + + + + + + + + + + + + + + + + + + + X has gifted 15 flowers to Y + + + + X has Y flowers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Someone rolled 35 + + + + Dice Rolled: 5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Make sure to get the formatting right, and leave the thinking emoji + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + plural + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Kwoth picked 5* + + + + Kwoth planted 5* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + context: "removed song #5" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gen (of command) + + + + Gen. (of module) + + + + + + + + + + + + + + + + + + + + + + + + + Short of seconds. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Don't translate {0}place + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /s and total need to be localized to fit the context - +`1.` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Invalid months value/ Invalid hours value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Id of the user kwoth#1234 is 123123123123 + + + + + + + + + + + + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx new file mode 100644 index 00000000..3ab3c220 --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx @@ -0,0 +1,2298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 該基地已被佔領或摧毀。 + + + 該基地已摧毀。 + + + 該基地尚未佔領 + + + 在與 {1} 對戰時 **摧毀** 了基地 #{0} + + + {0} 在與 {2} 對戰時 **解放** 基地 #{1} + + + {0} 在與 {2} 對戰時 **佔領** 基地 #{1} + + + @{0} 您已佔領基地 #{1}。您不能再佔領一個新的。 + + + 在 @{0} 與 {1} 對戰後佔領的基地已失效。 + Fuzzy + + + 敵人 + + + 與 {0} 對戰的信息 + + + 無效的基地編號。 + + + 無效的戰爭大小。 + Fuzzy + + + 目前正在進行的戰爭 + Fuzzy + + + 未佔領 + + + 您並未参與此戰爭。 + + + @{0} 您並未参與此戰爭或此基地已被毁壞。 + + + 目前尚無戰爭進行中。 + Fuzzy + + + 大小 + + + 與 {0} 的戰爭已經開始了。 + + + 與 {0} 的戰爭已創建。 + + + 與 {0} 的戰爭已結束。 + + + 此戰爭不存在。 + + + 與 {0} 的戰爭已開始! + + + 所有自訂回應統計已刪除。 + To simplified chinese crew: You guys forgot about the "stats" + + + 自訂回應已刪除 + + + 權限不足。伺服器自訂回應需要管理員權限,而只有Bot擁有者才能設定全域自訂回應。 + + + 列出所有自訂回應 + + + 自訂回應 + + + 新自訂回應 + + + 沒有找到自訂回應 。 + Fuzzy + + + 找不到輸入的自訂回應編號。 + + + 回應 + + + 自訂回應統計 + + + 清除了 {0} 自訂回應的統計。 + + + 尚未觸發此回應,故無結果。 + + + 觸發 + + + Autohentai指令效果停止。 + Keep in mind Autohentai is the actual command name, avoid translating it. + + + 沒有结果。 + + + {0} 已昏厥。 + + + {0} HP已满。 + + + 您的屬性已是 {0} + + + 對 {2}{3} 使出 {0}{1} 而造成 {4} 點傷害。 + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + 對方反擊前無法對他再次攻擊! + + + 您不能攻擊自己。 + + + {0} 已昏厥! + + + 用了一個 {1} 醫好 {0} + + + {0} 還剩餘 {1} 生命值。 + + + 您不能使用 {0} 。請輸入 `{1}ml` 來查閱您能用的招式。 + + + {0} 屬性的招式列表 + + + 攻擊不太有效。 + + + 你並沒有足够的 {0} + + + 使用了一個 {1} 復活 {0} + + + 您使用了一個 {0} 復活了自己 + + + 您的屬性已從 {0} 變更成 {1} + + + 攻擊有點效果。 + + + 攻擊非常有效! + + + 您已連續使用太多招式,所以您無法行動! + + + {0} 的屬性是 {1} + + + 該用戶不存在。 + + + 您已昏厥所以不能移動! + + + **自動指派身分組**給新加入的成員**已停用**。 + + + **自動指派身分組**給新加入的成員**已啟用**。 + + + 附件 + + + 頭像更換成功。 + + + 你已被 {0} 伺服器封鎖。 +原因:{1} + + + 用戶已封鎖 + PLURAL + + + 用戶已封鎖 + + + Bot 暱稱已改為 {0} + + + Bot 狀態已改為 {0} + + + 自動刪除告別訊息功能已停用。 + + + 告別訊息將於 {0} 秒後刪除。 + + + 目前的告別訊息: {0} + + + 輸入 {0} 來啟用告別訊息 + + + 新的告別訊息已設定。 + + + 告別訊息已停用。 + + + 在這個頻道啟用告別訊息。 + + + 頻道名稱已更改 + + + 舊名 + + + 頻道主題已更改 + + + 清理完畢。 + + + 内容 + + + 成功創建身分組 {0} + + + 成功創建文字頻道 {0} + + + 成功創建語音頻道 {0} + + + 成功禁音 + + + 已刪除伺服器 {0} + + + 自動刪除已處理指令已停用 + + + 自動刪除已處理指令已啟用 + + + 成功刪除文字頻道 {0} + + + 成功刪除語音頻道 {0} + + + 私人訊息來自 + + + 成功新增了新的捐贈者。此用戶總共捐贈了:{0} + + + 感謝下列的人使這個項目繼續運作! + + + 我會將私人訊息轉發給所有擁有者。 + + + 我會將私人訊息轉發給第一個擁有者。 + + + 我將開始轉發私人訊息。 + + + 我將停止轉發私人訊息。 + + + 自動刪除歡迎訊息已停用。 + + + 歡迎訊息將於 {0} 秒後刪除。 + + + 目前的歡迎私訊:{0} + + + 輸入 {0} 來啟用歡迎私訊 + + + 新的歡迎私訊已設定。 + + + DM歡迎公告關閉。 + + + 私訊歡迎公告已啟用。 + + + 当前欢迎消息是:{0} + + + 输入{0}来启用欢迎消息 + + + 新欢迎消息设定成功。 + + + 欢迎公告关闭。 + + + 欢迎公告在此频道开启。 + + + 您不能对身份层次结构中身份高于或等于您的身份的用户使用此命令。 + + + {0} 秒後載入圖片! + + + 格式輸入無效。 + + + 參數無效。 + + + {0} 已加入 {1} + + + 你已被從 {0} 伺服器踢出。 +原因:{1} + + + 用戶已被踢出 + Fuzzy + + + 語言列表 +{0} + Fuzzy + + + 您的服务器的语言设置现在为{0} - {1} + + + 机器人的默认语言环境现在是{0} - {1} + + + 机器人的语言设置为{0} - {1} + + + 设置语言设置失败。 重新访问此命令帮助。 + + + 此服务器的语言设置为{0} - {1} + + + {0}已离开{1} + + + 离开服务器{0} + + + 在此频道中记录{0}事件。 + + + 记录频道中所有事件 + + + 记录功能取消 + + + 您可以设定的记录项目: + + + 记录会忽略{0} + + + 记录不会忽略{0} + + + 已停止记录{0}事件。 + + + {0}已经提到了以下身份 + + + 来自{0}`[机器人主人]’的消息: + + + 消息已发. + + + {0}被移动由{1}到{2} + + + 在#{0}中删除讯息 + Fuzzy + + + 讯息在#{0}中被更新 + Fuzzy + + + 已静音 + PLURAL (users have been muted) + + + 已静音 + singular "User muted." + + + 权限不够执行此命令 + + + 新的静音角色设定成功。 + + + 我需要**管理**权限才能做那个。 + + + 新消息 + Fuzzy + + + 新昵称 + Fuzzy + + + 新主题 + Fuzzy + + + 昵称成功更换 + Fuzzy + + + 找不到该服务器 + + + 找不到具有该ID的分片。 + + + 旧信息 + Fuzzy + + + 旧昵称 + Fuzzy + + + 旧题目 + Fuzzy + + + 失败。很可能我没有足够的权限。 + + + 重置此服务器的权限。 + + + 主动保护 + Fuzzy + + + {0}已在此服务器禁用。 + + + {0}已启用。 + + + 失败。 我需要 ManageRoles 权限 + + + 未启用保护项目。 + Fuzzy + + + 用户阈值必须介于{0}和{1}之间。 + + + 如果{0}或更多用户在{1}秒内加入,我将{2}他们。 + + + 时间必须在{0}和{1}秒之间。 + + + 已成功从用户{0}中移除所有身份 + + + 无法移除身份。 我没有足够的权限。 + + + {0}身份的颜色已更改。 + + + 那个身份不存在。 + + + 指定的参数错误。 + + + 由于颜色无效或权限不足而发生错误。 + + + 已成功从用户{1}中删除身份{0} + + + 无法移除身份。 我没有足够的权限。 + + + 身份名已改 + + + 身份重命名失败。我的权限不足。 + + + 您不能编辑比你 + + + 已移除游玩消息:{0} + + + 身份{0}已添加到列表中。 + + + {0}未找到。已清理。 + + + 身份{0}已在列表中。 + + + 添加成功. + + + 旋转游玩状态关闭。 + + + 旋转游玩状态开启。 + + + 以下是旋转状态列表: +{0} + + + 未设置旋转游戏状态。 + + + 您已经拥有{0}身份。 + + + 您已拥有{0}独占的自行分配。 + + + 自行分配身份现在是独家! + + + 有{0}个可自行分配身份 + + + 这个身份是不可自行分配的。 + + + 您没有{0}身份。 + + + 自我分配的身份现在不是独家的! + + + 我无法向您添加该身份。 ‘我不能向身份层次结构中我身份以外的所有者或其他身份添加身份。’ + + + {0}已从可自我分配身份列表中删除。 + + + 您不再拥有{0}身份。 + + + 您现在拥有{0}身份。 + + + 已成功将身份{0}添加到用户{1} + + + 无法添加身份。 我没有足够的权限。 + + + 新头像集! + + + 新频道名称设定。 + + + 新游戏设定! + + + 新直播设定! + + + 新频道主题集。 + + + 分段{0}已重新连接。 + + + 分段{0}重新连接中。 + + + 关闭中 + + + 用户不能在{1}秒内发送超过{0}条消息。 + + + 慢速模式关闭。 + + + 慢速模式启动 + + + 软禁(踢出) + PLURAL + + + {0}将忽略此通道。 + + + 0}将不再忽略此通道。 + + + 如果用户发布{0}个相同的消息,我会{1}他们。 +     __IgnoredChannels__:{2} + + + 新文字频道成立 + Fuzzy + + + 文字频道已删除 + Fuzzy + + + Undeafen成功。 + + + 已取消静音 + singular + + + 用户名 + + + 用户名已更改 + Fuzzy + + + 用户 + + + 用户被禁止 + Fuzzy + + + {0}已从聊天内被静音**。 + + + {0}已从聊天内**取消静音**。 + + + 用户已加入 + Fuzzy + + + 用户离开了 + Fuzzy + + + {0} 已被文字与语音静音了 + + + 用户身份添加成功 + Fuzzy + + + 用户身份移除了 + Fuzzy + + + {0} 改成了 {1} + + + {0}已从文字和语音频道中取消静音**。 + + + {0}已加入{1}语音通道。 + + + {0}已离开{1}语音通道。 + + + {0}已从{1}移至{2}语音通道。 + + + {0}已被**静音**。 + + + {0}已被**取消静音**。 + + + 语音频道已创建 + Fuzzy + + + 语音通道已被毁 + Fuzzy + + + 已停用语音+文字功能。 + + + 启用语音+文字功能。 + + + 我没有**管理身份**和/或**管理频道**权限,所以我不能在{0}服务器上运行`语音+文字`。 + + + 您正在启用/禁用此功能,并且**我没有ADMINISTRATOR权限**。 这可能会导致一些问题,您必须自己清理文本频道。 + + + 我需要至少**管理身份**和**管理频道**权限,以启用此功能。 (优先管理权限) + + + 用户{0}来自文字频道 + + + 用户{0}来自文字和语音频道 + + + 用户{0}来自语音频道 + + + 您已从{0}服务器软禁止。 +原因:{1} + + + 用户已取消禁止 + Fuzzy + + + 迁移完成! + + + 在迁移时出错,请检查机器人的控制台以获取更多信息。 + + + 在线状态更新 + Fuzzy + + + 用户被软禁用 + Fuzzy + + + 已将{0}奖励给{1} + + + 下一次好运^ _ ^ + + + 恭喜! 您赢得{0}因为您滚{1}或以上 + + + 卡牌改组。 + + + 抛了{0}。 + User flipped tails. + + + 你猜到了! 您赢得了{0} + + + 指定的数字无效。 你可以抛1到{0}钱币。 + + + 将{0}反应添加到此消息以获取{1} + + + 此活动在{0}小时内有效。 + + + 花反应活动开始了! + + + 给了{1}{0} + X has gifted 15 flowers to Y + + + {0}拥有{1} + X has Y flowers + + + + Fuzzy + + + 排行榜 + + + 从{2}身份授予{0}至{1}名用户。 + + + 您赌注不能超过{0} + + + 您赌注不能低于{0} + + + 您没有足够的{0} + + + 卡牌组中没有更多的牌。 + + + 抽奖用户 + Fuzzy + + + 您抛了{0}。 + + + 赌注 + + + 哇啊啊啊啊啊啊! 恭喜! x {0} + + + 单个{0},x {1} + + + 哇!好运! 三个相同! x {0} + + + 做得好! 两个{0} - 投注x {1} + + + 胜利 + + + 用户必须键入密码才能获取{0}。 +持续{1}秒。 嘘~别跟任何人说。 + + + SneakyGame事件结束。 {0}个用户收到了奖励。 + + + SneakyGameStatus事件已启动 + + + + Fuzzy + + + 已成功从{1}取得{0} + + + 无法从{1}取得{0},因为用户没有那么多{2}! + + + 返回ToC + + + 仅限Bot Owner + Fuzzy + + + 需要{0}频道权限。 + + + 您可以在patreon上支持项目:<{0}>或paypal:<{1}> + + + 命令和别名 + Fuzzy + + + 命令列表已重新生成。 + Fuzzy + + + 输入`{0} h CommandName`可查看该指定命令的帮助。 例如 `{0} h> 8ball` + + + 我找不到该命令。 请再次尝试之前验证该命令是否存在。 + + + 描述 + + + 您可以在: +Patreon <{0}>或 +Paypal <{1}> +上支持NadekoBot +不要忘记在邮件中留下您的不和名字或ID。 + +**谢谢**♥️ + + + **命令列表**:<{0}> +**主机指南和文档可以在这里找到**:<{1}> + Fuzzy + + + 命令列表 + Fuzzy + + + 组件列表 + Fuzzy + + + 输入“{0} cmds ModuleName”以获取该组件中的命令列表。 例如`{0} cmds games` + + + 该组件不存在。 + + + 需要{0}服务器权限。 + + + 目录 + Fuzzy + + + 用法 + + + 自动hentai启动。 使用以下标记之一重新排列每个{0}: +{1} + + + 标签 + + + 动物竞赛 + Fuzzy + + + 启动失败,因为没有足够的参与者。 + + + 竞赛已满! 立即开始。 + + + {0}加入为{1} + + + {0}加入为{1},赌注{2}! + + + 输入{0} jr 以加入竞赛。 + + + 在20内秒或当房间满后开始。 + + + {0}个参与者开始。 + + + {0}为{1}赢得竞赛! + + + 0}为{1}赢得竞赛,和赢得{2}! + + + 指定的数字无效。 您可以一次滚动{0} - {1}骰子。 + + + 掷了{0} + Someone rolled 35 + + + 掷骰子:{0} + Dice Rolled: 5 + + + 竞赛启动失败。 另一个比赛可能正在运行。 + + + 此服务器上不存在竞赛 + + + 第二个数字必须大于第一个数字。 + + + 爱被改变 + Fuzzy + + + 声称 + Fuzzy + + + 离婚 + + + 喜欢 + + + 价钱 + + + 没有waifus被要求。 + + + 最佳Waifus + + + 您的兴趣已设置为该waifu,或者您尝试在没有兴趣的情况下删除您的兴趣。 + + + 将把兴趣从{0}更改为{1}。 + +*这在道德上是有问题的*🤔 + Make sure to get the formatting right, and leave the thinking emoji + + + 您必须等待{0}小时和{1}分钟才能再次更改您的兴趣。 + + + 您的兴趣已重置。 你不再有你喜欢的人。 + + + 想成为{0}的waifu。哇非常可爱<3 + + + 声明{0}为他的waifu,花了{1}! + + + 你已经离婚了一个喜欢你的waifu。 你无情的怪物。 +{0}收到了{1}作为补偿。 + + + 你不能设置兴趣自己,你好自卑。 + + + 🎉他的爱实现! 🎉 +{0}的新值为{1}! + + + 没有waifu那么便宜。 您必须至少支付{0}才能获得waifu,即使他们的实际价值较低。 + + + 您必须支付{0}或更多才能认领那个waifu! + + + 那waifu不是你的。 + + + 你不能认领自己。 + + + 你最近离婚了。 您必须等待{0}小时和{1}分钟再次离婚。 + + + 没人 + + + 你离婚了一个不喜欢你的waifu。 您收到了{0}。 + + + 8ball + + + 恐惧症游戏 + + + 游戏结束,没人提交。 + + + 没人投票。 游戏结束,没有赢家。 + + + 首字母缩写是{0}。 + + + 恐惧症游戏已经在这个频道中运行。 + + + 游戏开始。 创建具有以下首字母缩写的句子:{0}。 + + + 您有{0}秒的时间提交。 + + + {0}提交了他的判决。 (总{1}个) + + + 通过输入提交数字投票 + + + {0}投了票! + + + 获胜者{0}获得{1}分。 + + + {0}赢了因为是唯一的提交用户! + + + + + + 平局! 两个都挑了{0} + + + {0}赢了! {1} 打赢了 {2} + + + 提交关闭 + Fuzzy + + + 动物竞赛已经运行。 + + + 总计:{0} 平均:{1} + + + 类别 + + + 在此服务器上禁用cleverbot。 + + + 在此服务器上启用cleverbot。 + + + 在此频道上停用的货币生成功能。 + + + 在此频道上启用的货币生成功能。 + + + {0} 个 {1}出现了! 通过输入`{2} pick'来拾取 + plural + + + 一个{0}出现了! 通过输入`{1} pick`来拾取 + + + 加载问题失败。 + + + 游戏开始 + Fuzzy + + + Hangman游戏开始了 + + + Hangman游戏已在此频道上打开。 + + + 启动hangman错误。 + + + “{0} hangman”字词类型列表: + + + 排行榜 + + + 您没有足够的{0} + + + 没有结果 + + + 采了{0} + Kwoth picked 5* + + + {0}种了{1} + Kwoth planted 5* + + + 琐事游戏已经在这个服务器上运行。 + + + 琐事游戏 + + + {0}猜对了! 答案是:{1} + + + 此服务器上没有运行琐事游戏。 + + + {0}有{1}分 + + + 这个问题后停止。 + + + 时间到! 正确的答案是{0} + + + {0}猜到了,赢得了游戏! 答案是:{1} + + + 你不能对自己玩。 + + + TicTacToe游戏已在此频道中运行。 + + + 平局! + + + 开始了一局TicTacToe游戏。 + + + {0}赢了! + Fuzzy + + + 相配了三个 + Fuzzy + + + 没有地方动了! + + + 时间已过! + Fuzzy + + + 轮到{0}了 + + + {0}对{1} + + + 正在排{0}首歌... + + + 已停用自动播放。 + + + 已启用自动播放。 + + + 默认音量设置为{0}% + + + 目录队列完成。 + + + 公平播放 + + + 完成歌曲 + Fuzzy + + + 停用公平播放。 + + + 启用公平播放。 + + + 从位置 + + + ID + + + 输入错误。 + + + 最大播放时间没有限制移除。 + + + 最大播放时间设置为{0}秒。 + + + 最大音乐队列大小设置为无限。 + + + 最大音乐队列大小设置为{0}首。 + + + 您需要在此服务器上加入语音频道。 + + + + + + 现在播放 + Fuzzy + + + 没有活动音乐播放器。 + + + + 没有搜索结果。 + + + 音乐播放暂停。 + + + 播放器队列 - {0} / {1}页 + Fuzzy + + + 正在播放 + Fuzzy + + + `#{0}` - ** {1} ** by * {2} *({3}首歌) + + + 有保存{0}页的播放列表 + Fuzzy + + + 播放列表已删除。 + + + 无法删除该播放列表。 它不存在,或者你不是它的作者。 + + + 具有该ID的播放列表不存在。 + + + 播放列表队列完成。 + + + 播放列表已保存 + Fuzzy + + + {0}秒限制 + + + 队列 + + + 歌加入队列 + Fuzzy + + + 音乐队列已清除。 + + + 队列已满{0} / {0}。 + + + 歌被移除 + context: "removed song #5" + + + 重复播放当前歌曲 + Fuzzy + + + 重复播放列表 + Fuzzy + + + 重复曲目 + Fuzzy + + + 当前曲目停止重复。 + + + 音乐播放已恢复。 + + + 禁用重复播放列表 + + + 重复播放列表已启用。 + + + 我现在将在此频道里输出播放,完成,暂停和删除歌曲。 + + + 跳到‘{0}:{1}’ + + + 歌播放列表曲被随机。 + Fuzzy + + + 歌曲被移动 + Fuzzy + + + {0}小时 {1}分钟 {2}秒 + + + 到位置 + + + 无限 + + + 音量必须介于0和100之间 + + + 音量设置为{0}% + + + 在{0}频道上禁止所有组件的使用。 + Fuzzy + + + 在{0}频道上允许启用所有组件。 + Fuzzy + + + 允许 + + + {0}身份的所有组件被禁止使用。 + Fuzzy + + + {0}身份的所有组件被允许使用。 + Fuzzy + + + 在此服务器上禁止所有组件的使用。 + + + 在此服务器上允许所有组件的使用。 + + + {0}用户的所有模块被禁止使用。 + Fuzzy + + + {0}用户的所有模块被允许使用。 + Fuzzy + + + ID为{1}被加入黑名单{0} + + + 命令{0}冷却时间现有{1}秒。 + + + 命令{0}没有冷却时间了,现有所有的冷却时间已被清除。 + Fuzzy + + + 没有设置命令冷却时间。 + + + 命令成本 + Fuzzy + + + {2}频道上已停用{0} {1}。 + Fuzzy + + + 已在{2}频道上启用{0} {1}的使用。 + Fuzzy + + + 被拒绝 + + + 以巴{0}添加到已过滤字词列表中。 + + + 被过滤的词列表 + Fuzzy + + + 已从过滤字词列表中删除{0}。 + + + 第二个参数无效(必须是{0}和{1}之间的数字) + + + 在此频道上停用邀请过滤功能。 + + + 在此频道上启用邀请过滤。 + + + 在此服务器上停用邀请过滤功能。 + + + 在此服务器上启用邀请过滤功能。 + + + 已将权限{0}从#{1}移至#{2} + + + 在索引#{0}找不到权限 + + + 未设置费用。 + + + 命令 + Gen (of command) + + + 组件 + Gen. (of module) + + + 权限页面第{0}页 + + + 当前权限身份为{0}。 + + + 用户现在需要{0}身份才能编辑权限。 + + + 在该索引中找不到权限。 + + + 已删除权限#{0} - {1} + + + 禁止{2}身份使用{0} {1}。 + + + 允许{2}身份使用{0} {1}。 + + + + Short of seconds. + + + 此服务器上的{0} {1}已被禁止使用。 + + + 此服务器上的{0} {1}已被允许使用。 + + + ID为{1}的{0}从黑名单上移除 + + + 不可编辑 + + + {2}用户的{0} {1}已被禁止使用。 + + + {2}用户的{0} {1}已允许使用。 + + + 我将不再显示权限警告。 + + + 我现在将显示权限警告。 + + + 此频道上的字过滤已停用。 + + + 此频道上的字过滤已启用。 + + + 此服务器上的字过滤已停用。 + + + 此服务器上的字过滤已启用。 + + + 能力 + + + 没有最喜爱的动漫 + + + 开始自动翻译此频道上的消息。 用户消息将被自动删除。 + + + 您的自动翻译语言已删除。 + + + 您的自动翻译语言已设置为{0}> {1} + + + 开始自动翻译此频道上的消息。 + + + 停止自动翻译此频道上的消息。 + + + 错误格式或出现错误。 + + + 找不到该卡。 + + + + + + + + + 漫画# + + + 竞争模式失败次数 + Fuzzy + + + 竞争模式玩次数 + Fuzzy + + + 竞争模式排名 + Fuzzy + + + 竞争模式胜利次数 + + + 完成 + + + 条件 + + + 花费 + + + 日期 + + + 定义: + + + 放掉 + + + 剧集 + + + 发生了错误。 + + + 例子 + + + 找不到那个动画。 + + + 找不到漫画。 + + + 类型 + + + 未能找到该标记的定义。 + + + 身高/体重 + + + {0} m / {1} kg + + + 湿度 + + + 图片搜索: + Fuzzy + + + 找不到该电影。 + + + 来源或目标语言错误。 + + + 笑话没加载。 + + + 纬度/经度 + + + 等级 + + + {0}地方标记列表 + Don't translate {0}place + + + 地点 + + + 未加载魔术项目。 + + + {0}的MAL个人资料 + + + 机器人的业主没有指定MashapeApiKey。 您不能使用此功能。 + + + 最小/最大 + + + 找不到频道。 + + + 没找到结果。 + + + 等候接听 + Fuzzy + + + 原始网址 + Fuzzy + + + 需要osu!API密钥。 + + + 无法检索osu! 线索。 + + + 找到{0}张图片。 显示随机{0}。 + + + 找不到用户! 请再次前检查区域和BattleTag。 + + + 计划看 + + + 平台 + + + 找不到能力。 + + + 找不到宠物小精灵。 + + + 个人资料链接: + Fuzzy + + + 质量: + + + 快速游戏时间 + Fuzzy + + + 快赢 + Fuzzy + + + 评分 + + + 得分: + + + 搜索: + Fuzzy + + + 无法缩短该链接。 + + + 短链接 + Fuzzy + + + 出了些问题。 + + + 请指定搜索参数。 + + + 状态 + + + 储存链接 + Fuzzy + + + 直播台{0}已离线。 + + + 直播台{0}在线有{1}个观众。 + + + 您在此服务器上关注{0}个直播台 + + + 您未在此服务器上关注任何直播台。 + + + 没有这个直播台。 + + + 直播台可能不存在。 + + + 已从({1})的通知中移除{0}的直播台 + + + 状态更改时,我会通知此频道。 + + + 日出 + + + 日落 + + + 温度 + + + 标题: + + + 3个最喜欢的动画: + + + 翻译: + + + 类型 + + + 未能找到该字词的定义。 + + + 链接 + + + 观众 + + + 观看 + + + 无法在指定的维基上找到该字词。 + + + 请输入目标维基,然后搜索查询。 + + + 找不到网页。 + + + 风速 + Fuzzy + + + {0}个被禁止最多的英雄 + + + 无法yodify您的句子。 + + + 加入 + + + `{0} .` {1} [{2:F2} / s] - {3}总计 + /s and total need to be localized to fit the context - +`1.` + + + 活动页面#{0} + Fuzzy + + + {0}个用户。 + + + 作者 + + + 机器ID + + + {0} calc命令功能列表 + + + 此频道的{0}是{1} + + + 频道主题 + Fuzzy + + + 执行命令 + Fuzzy + + + {0} {1}等于{2} {3} + + + 转换器可以使用的单位 + + + 无法将{0}转换为{1}:找不到单位 + + + 无法将{0}转换为{1}:单位类型不相等 + + + 创建于 + Fuzzy + + + 加入跨服务器频道。 + + + 离开跨服务器频道。 + + + 这是您的CSC令牌 + + + 自定义Emojis + Fuzzy + + + 错误 + + + 特征 + + + + ID + + + 索引超出范围。 + + + 以下是这个身份的用户列表: + + + 您不能对其中有用户很多的身份使用此命令来防止滥用。 + Fuzzy + + + 值{0}错误。 + Invalid months value/ Invalid hours value + + + 加入Discord + + + 加入服务器 + Fuzzy + + + ID:{0} +会员数:{1} +业主ID:{2} + Fuzzy + + + 在该网页上找不到服务器。 + + + 重复列表 + Fuzzy + + + 会员 + + + 存储 + + + 讯息 + + + 消息重复功能 + Fuzzy + + + 名字 + + + 昵称 + + + 没有人在玩那个游戏 + + + 没有活动重复功能。 + + + 此页面上没有身份。 + + + 此页面上没有分片。 + + + 没有主题设置。 + + + 业主 + + + 业主IDs + + + 状态 + + + {0}个服务器 +{1}个文字频道 +{2}个语音频道 + + + 删除所有引号使用{0}关键字。 + + + {0}页引号 + + + 此页面上没有引用。 + + + 没有您可以删除的引用。 + + + 引用被添加 + + + 删除了随机引用。 + + + 区域 + + + 注册日 + Fuzzy + + + 我将在{2}`({3:d.M.yyyy。}的{4:HH:mm})提醒{0}关于{1} + + + 无效时间格式。 检查命令列表。 + + + 新的提醒模板被设定。 + + + 会每{1}天{2}小时{3}分钟重复{0}。 + + + 重复列表 + Fuzzy + + + 此服务器上没有运行重复消息。 + + + #{0}已停止。 + + + 此服务器上没有找到被重复的消息。 + + + 结果 + + + 身份 + + + 此服务器上所有身份第{0}页: + + + {1}身份的第{0}页 + + + 颜色的格式不正确。 例如,使用‘#00ff00’。 + + + 开始轮流{0}身份的颜色。 + + + 停止{0}身份颜色轮流 + + + 此服务器的{0}是{1} + + + 伺服器資訊 + Fuzzy + + + 分片 + + + 分片统计 + Fuzzy + + + 分片**#{0} **处于{1}状态与{2}台服务器 + + + **名称:** {0} **链接:** {1} + + + 找不到特殊的表情符號。 + + + 正在播放 {0} 首歌,{1} 首等待播放。 + + + 文字頻道 + Fuzzy + + + 这是你的房间链接: + + + 運行時間 + + + 此用户 {1} 的{0} 是 {2} + Id of the user kwoth#1234 is 123123123123 + + + 用戶 + + + 語音頻道 + Fuzzy + + + + + + \ No newline at end of file From b0352c20be1a90ec8ba7c92d257e9cd168f1299a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 5 Mar 2017 23:05:38 +0100 Subject: [PATCH 449/746] Updated supported languages list --- .../Administration/Commands/LocalizationCommands.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 8166a633..d7dd424e 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -18,15 +18,19 @@ namespace NadekoBot.Modules.Administration { private ImmutableDictionary supportedLocales { get; } = new Dictionary() { + //{"zh-TW", "Chinese (Traditional), China" }, + {"zh-CN", "Chinese (Simplified), China"}, + //{"nl-NL", "Dutch, Netherlands"}, {"en-US", "English, United States"}, {"fr-FR", "French, France"}, - {"ru-RU", "Russian, Russia"}, {"de-DE", "German, Germany"}, - //{"nl-NL", "Dutch, Netherlands"}, //{"ja-JP", "Japanese, Japan"}, + {"nb-NO", "Norwegian (bokmål), Norway"}, + //{"pl-PL", "Polish, Poland" } {"pt-BR", "Portuguese, Brazil"}, - {"zh-CN", "Chinese (Simplified), China"} + {"ru-RU", "Russian, Russia"}, //{"sr-Cyrl-RS", "Serbian, Serbia - Cyrillic"} + {"sv-SE", "Swedish, Sweden"}, }.ToImmutableDictionary(); [NadekoCommand, Usage, Description, Aliases] From 504da01917cf4879f2811e201ce2cdbca5e56cd4 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 5 Mar 2017 23:34:01 +0100 Subject: [PATCH 450/746] People without manage messages can no longer user reminds on channels --- src/NadekoBot/Modules/Utility/Commands/Remind.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NadekoBot/Modules/Utility/Commands/Remind.cs b/src/NadekoBot/Modules/Utility/Commands/Remind.cs index 572a7afc..45406de9 100644 --- a/src/NadekoBot/Modules/Utility/Commands/Remind.cs +++ b/src/NadekoBot/Modules/Utility/Commands/Remind.cs @@ -114,6 +114,7 @@ namespace NadekoBot.Modules.Utility [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] [Priority(0)] public async Task Remind(IMessageChannel ch, string timeStr, [Remainder] string message) { From f1157f424b0cde47501d5afd6c99f83a5de2c6eb Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 6 Mar 2017 04:20:06 +0100 Subject: [PATCH 451/746] inrole now shows the number of users in a given role --- src/NadekoBot/Modules/Utility/Utility.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 0452dab6..38951dd5 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -225,8 +225,9 @@ namespace NadekoBot.Modules.Utility var usrs = (await Context.Guild.GetUsersAsync()).ToArray(); foreach (var role in roles.Where(r => r.Id != Context.Guild.Id)) { - send += $"```css\n[{role.Name}]\n"; - send += string.Join(", ", usrs.Where(u => u.RoleIds.Contains(role.Id)).Select(u => u.ToString())); + var roleUsers = usrs.Where(u => u.RoleIds.Contains(role.Id)).Select(u => u.ToString()).ToArray(); + send += $"```css\n[{role.Name}] ({roleUsers.Length})\n"; + send += string.Join(", ", roleUsers); send += "\n```"; } var usr = (IGuildUser)Context.User; From c1c8c1c85662a16c4991c2a41cda3603c56facce Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 6 Mar 2017 16:51:02 +0100 Subject: [PATCH 452/746] fixed default language? --- .../Resources/ResponseStrings.en-US.resx | 2221 +++++++++++++++++ 1 file changed, 2221 insertions(+) create mode 100644 src/NadekoBot/Resources/ResponseStrings.en-US.resx diff --git a/src/NadekoBot/Resources/ResponseStrings.en-US.resx b/src/NadekoBot/Resources/ResponseStrings.en-US.resx new file mode 100644 index 00000000..8f964f3a --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.en-US.resx @@ -0,0 +1,2221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + That base is already claimed or destroyed. + + + That base is already destroyed. + + + That base is not claimed. + + + **DESTROYED** base #{0} in a war against {1} + + + {0} has **UNCLAIMED** base #{1} in a war against {2} + + + {0} claimed a base #{1} in a war against {2} + + + @{0} You already claimed base #{1}. You can't claim a new one. + + + Claim from @{0} in a war against {1} has expired. + + + Enemy + + + Info about war against {0} + + + Invalid base number. + + + Not a valid war size. + + + List of active wars + + + not claimed + + + You are not participating in that war. + + + @{0} You are either not participating in that war, or that base is already destroyed. + + + No active war. + + + Size + + + War against {0} has already started. + + + War against {0} created. + + + War against {0} ended. + + + That war does not exist. + + + War against {0} started! + + + All custom reaction stats cleared. + + + Custom Reaction deleted + + + Insufficient permissions. Requires Bot ownership for global custom reactions, and Administrator for server custom reactions. + + + List of all custom reactions + + + Custom Reactions + + + New Custom Reaction + + + No custom reaction found. + + + No custom reaction found with that id. + + + Response + + + Custom Reaction Stats + + + Stats cleared for {0} custom reaction. + + + No stats for that trigger found, no action taken. + + + Trigger + + + Autohentai stopped. + + + No results found. + + + {0} has already fainted. + + + {0} already has full HP. + + + Your type is already {0} + + + used {0}{1} on {2}{3} for {4} damage. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + You can't attack again without retaliation! + + + You can't attack yourself. + + + {0} has fainted! + + + healed {0} with one {1} + + + {0} has {1} HP remaining. + + + You can't use {0}. Type `{1}ml` to see a list of moves you can use. + + + Movelist for {0} type + + + It's not effective. + + + You don't have enough {0} + + + revived {0} with one {1} + + + You revived yourself with one {0} + + + Your type has been changed to {0} for a {1} + + + It's somewhat effective. + + + It's super effective! + + + You used too many moves in a row, so you can't move! + + + Type of {0} is {1} + + + User not found. + + + You fainted, so you are not able to move! + + + **Auto assign role** on user join is now **disabled**. + + + **Auto assign role** on user join is now **enabled**. + + + Attachments + + + Avatar Changed + + + You have been banned from {0} server. +Reason: {1} + + + banned + PLURAL + + + User Banned + + + Bot name changed to {0} + + + Bot status changed to {0} + + + Automatic deletion of bye messages has been disabled. + + + Bye messages will be deleted after {0} seconds. + + + Current bye message: {0} + + + Enable bye messages by typing {0} + + + New bye message set. + + + Bye announcements disabled. + + + Bye announcements enabled on this channel. + + + Channel Name Changed + + + Old Name + + + Channel Topic Changed + + + Cleaned up. + + + Content + + + Sucessfully created role {0} + + + Text channel {0} created. + + + Voice channel {0} created. + + + Deafen successful. + + + Deleted server {0} + + + Stopped automatic deletion of successful command invokations. + + + Now automatically deleting sucessful command invokations. + + + Text channel {0} deleted. + + + Voice channel {0} deleted. + + + DM from + + + Sucessfully added a new donator.Total donated amount from this user: {0} 👑 + + + Thanks to the people listed below for making this project happen! + + + I will forward DMs to all owners. + + + I will forward DMs only to the first owner. + + + I will forward DMs from now on. + + + I will stop forwarding DMs from now on. + + + Automatic deletion of greet messages has been disabled. + + + Greet messages will be deleted after {0} seconds. + + + Current DM greet message: {0} + + + Enable DM greet messages by typing {0} + + + New DM greet message set. + + + DM greet announcements disabled. + + + DM greet announcements enabled. + + + Current greet message: {0} + + + Enable greet messages by typing {0} + + + New greet message set. + + + Greet announcements disabled. + + + Greet announcements enabled on this channel. + + + You can't use this command on users with a role higher or equal to yours in the role hierarchy. + + + Images loaded after {0} seconds! + + + Invalid input format. + + + Invalid parameters. + + + {0} has joined {1} + + + You have been kicked from {0} server. +Reason: {1} + + + User kicked + + + List of languages + + + Your server's locale is now {0} - {1} + + + Bot's default locale is now {0} - {1} + + + Bot's language is set to {0} - {1} + + + Failed setting locale. Revisit this command's help. + + + This server's language is set to {0} - {1} + + + {0} has left {1} + + + Left server {0} + + + Logging {0} event in this channel. + + + Logging all events in this channel. + + + Logging disabled. + + + Log events you can subscribe to: + + + Logging will ignore {0} + + + Logging will not ignore {0} + + + Stopped logging {0} event. + + + {0} has invoked a mention on the following roles + + + Message from {0} `[Bot Owner]`: + + + Message sent. + + + {0} moved from {1} to {2} + + + Message deleted in #{0} + + + Message updated in #{0} + + + Muted + PLURAL (users have been muted) + + + Muted + singular "User muted." + + + I don't have the permission necessary for that most likely. + + + New mute role set. + + + I need **Administration** permission to do that. + + + New message + + + New nickname + + + New topic + + + Nickname changed + + + Can't find that server + + + No shard with that ID found. + + + Old message + + + Old nickname + + + Old topic + + + Error. Most likely I don't have sufficient permissions. + + + Permissions for this server are reset. + + + Active protections + + + {0} has been **disabled** on this server. + + + {0} Enabled + + + Error. I need ManageRoles permission + + + No protection enabled. + + + User threshold must be between {0} and {1}. + + + If {0} or more users join within {1} seconds, I will {2} them. + + + Time must be between {0} and {1} seconds. + + + Successfully removed all roles from user {0} + + + Failed to remove roles. I have insufficient permissions. + + + Color of {0} role has been changed. + + + That role does not exist. + + + The parameters specified are invalid. + + + Error occured due to invalid color or insufficient permissions. + + + Successfully removed role {0} from user {1} + + + Failed to remove role. I have insufficient permissions. + + + Role renamed. + + + Failed to rename role. I have insufficient permissions. + + + You can't edit roles higher than your highest role. + + + Removed the playing message: {0} + + + Role {0} as been added to the list. + + + {0} not found.Cleaned up. + + + Role {0} is already in the list. + + + Added. + + + Rotating playing status disabled. + + + Rotating playing status enabled. + + + Here is a list of rotating statuses: +{0} + + + No rotating playing statuses set. + + + You already have {0} role. + + + You already have {0} exclusive self-assigned role. + + + Self assigned roles are now exclusive! + + + There are {0} self assignable roles + + + That role is not self-assignable. + + + You don't have {0} role. + + + Self assigned roles are now not exclusive! + + + I am unable to add that role to you. `I can't add roles to owners or other roles higher than my role in the role hierarchy.` + + + {0} has been removed from the list of self-assignable roles. + + + You no longer have {0} role. + + + You now have {0} role. + + + Sucessfully added role {0} to user {1} + + + Failed to add role. I have insufficient permissions. + + + New avatar set! + + + New channel name set. + + + New game set! + + + New stream set! + + + New channel topic set. + + + Shard {0} reconnected. + + + Shard {0} reconnecting. + + + Shutting down + + + Users can't send more than {0} messages every {1} seconds. + + + Slow mode disabled. + + + Slow mode initiated + + + soft-banned (kicked) + PLURAL + + + {0} will ignore this channel. + + + {0} will no longer ignore this channel. + + + If a user posts {0} same messages in a row, I will {1} them. + __IgnoredChannels__: {2} + + + Text channel created. + + + Text channel destroyed. + + + Undeafen successful. + + + Unmuted + singular + + + Username + + + Username changed + + + Users + + + User banned + + + {0} has been **muted** from chatting. + + + {0} has been **unmuted** from chatting. + + + User joined + + + User left + + + {0} has been **muted** from text and voice chat. + + + User's role added + + + User's role removed + + + {0} is now {1} + + + {0} has been **unmuted** from text and voice chat. + + + {0} has joined {1} voice channel. + + + {0} has left {1} voice channel. + + + {0} moved from {1} to {2} voice channel. + + + {0} has been **voice muted**. + + + {0} has been **voice unmuted**. + + + Voice channel created + + + Voice channel destroyed + + + Disabled voice + text feature. + + + Enabled voice + text feature. + + + I don't have **manage roles** and/or **manage channels** permission, so I cannot run `voice+text` on {0} server. + + + You are enabling/disabling this feature and **I do not have ADMINISTRATOR permissions**. This may cause some issues, and you will have to clean up text channels yourself afterwards. + + + I require atleast **manage roles** and **manage channels** permissions to enable this feature. (preffered Administration permission) + + + User {0} from text chat + + + User {0} from text and voice chat + + + User {0} from voice chat + + + You have been soft-banned from {0} server. +Reason: {1} + + + User unbanned + + + Migration done! + + + Error while migrating, check bot's console for more information. + + + Presence updates + + + User soft-banned + + + has awarded {0} to {1} + + + Better luck next time ^_^ + + + Congratulations! You won {0} for rolling above {1} + + + Deck reshuffled. + + + flipped {0}. + User flipped tails. + + + You guessed it! You won {0} + + + Invalid number specified. You can flip 1 to {0} coins. + + + Add {0} reaction to this message to get {1} + + + This event is active for up to {0} hours. + + + Flower reaction event started! + + + has gifted {0} to {1} + X has gifted 15 flowers to Y + + + {0} has {1} + X has Y flowers + + + Head + + + Leaderboard + + + Awarded {0} to {1} users from {2} role. + + + You can't bet more than {0} + + + You can't bet less than {0} + + + You don't have enough {0} + + + No more cards in the deck. + + + Raffled user + + + You rolled {0}. + + + Bet + + + WOAAHHHHHH!!! Congratulations!!! x{0} + + + A single {0}, x{1} + + + Wow! Lucky! Three of a kind! x{0} + + + Good job! Two {0} - bet x{1} + + + Won + + + Users must type a secret code to get {0}. +Lasts {1} seconds. Don't tell anyone. Shhh. + + + SneakyGame event ended. {0} users received the reward. + + + SneakyGameStatus event started + + + Tail + + + successfully took {0} from {1} + + + was unable to take {0} from{1} because the user doesn't have that much {2}! + + + Back to ToC + + + Bot owner only + + + Requires {0} channel permission. + + + You can support the project on patreon: <{0}> or paypal: <{1}> + + + Commands and aliases + + + Commandlist regenerated. + + + Type `{0}h CommandName` to see the help for that specified command. e.g. `{0}h >8ball` + + + I can't find that command. Please verify that the command exists before trying again. + + + Description + + + You can support the NadekoBot project on +Patreon <{0}> or +Paypal <{1}> +Don't forget to leave your discord name or id in the message. + +**Thank you** ♥️ + + + **List of commands**: <{0}> +**Hosting guides and docs can be found here**: <{1}> + + + List of commands + + + List of modules + + + Type `{0}cmds ModuleName` to get a list of commands in that module. eg `{0}cmds games` + + + That module does not exist. + + + Requires {0} server permission. + + + Table of contents + + + Usage + + + Autohentai started. Reposting every {0}s with one of the following tags: +{1} + + + Tag + + + Animal race + + + Failed to start since there was not enough participants. + + + Race is full! Starting immediately. + + + {0} joined as a {1} + + + {0} joined as a {1} and bet {2}! + + + Type {0}jr to join the race. + + + Starting in 20 seconds or when the room is full. + + + Starting with {0} participants. + + + {0} as {1} Won the race! + + + {0} as {1} Won the race and {2}! + + + Invalid number specified. You can roll {0}-{1} dice at once. + + + rolled {0} + Someone rolled 35 + + + Dice rolled: {0} + Dice Rolled: 5 + + + Failed starting the race. Another race is probably running. + + + No race exists on this server + + + Second number must be larger than the first one. + + + Changes of heart + + + Claimed by + + + Divorces + + + Likes + + + Nobody + + + Price + + + No waifus have been claimed yet. + + + Top Waifus + + + your affinity is already set to that waifu or you're trying to remove your affinity while not having one. + + + changed their affinity from {0} to {1}. + +*This is morally questionable.*🤔 + Make sure to get the formatting right, and leave the thinking emoji + + + You must wait {0} hours and {1} minutes in order to change your affinity again. + + + Your affinity is reset. You no longer have a person you like. + + + wants to be {0}'s waifu. Aww <3 + + + claimed {0} as their waifu for {1}! + + + You have divorced a waifu who likes you. You heartless monster. +{0} received {1} as a compensation. + + + You have divorced a waifu who doesn't like you. You received {0} back. + + + you can't set affinity to yourself, you egomaniac. + + + 🎉 Their love is fulfilled! 🎉 +{0}'s new value is {1}! + + + No waifu is that cheap. You must pay at least {0} to get a waifu, even if their actual value is lower. + + + You must pay {0} or more to claim that waifu! + + + That waifu is not yours. + + + You can't claim yourself. + + + You divorced recently. You must wait {0} hours and {1} minutes to divorce again. + + + 8ball + + + Acrophobia + + + Game ended with no submissions. + + + No votes cast. Game ended with no winner. + + + Acronym was {0}. + + + Acrophobia game is already running in this channel. + + + Game started. Create a sentence with the following acronym: {0}. + + + You have {0} seconds to make a submission. + + + {0} submitted their sentence. ({1} total) + + + Vote by typing a number of the submission + + + {0} cast their vote! + + + Winner is {0} with {1} points. + + + {0} is the winner for being the only user who made a submission! + + + Question + + + It's a draw! Both picked {0} + + + {0} won! {1} beats {2} + + + Submissions closed + + + Animal Race is already running. + + + You've already joined this race! + + + Total: {0} Average: {1} + + + Category + + + Disabled cleverbot on this server. + + + Enabled cleverbot on this server. + + + Currency generation has been disabled on this channel. + + + Currency generation has been enabled on this channel. + + + {0} random {1} appeared! Pick them up by typing `{2}pick` + plural + + + A random {0} appeared! Pick it up by typing `{1}pick` + + + Failed loading a question. + + + Game started + + + Hangman game started + + + Hangman game already running on this channel. + + + Starting hangman errored. + + + List of "{0}hangman" term types: + + + Leaderboard + + + You don't have enough {0} + + + No results + + + picked {0} + Kwoth picked 5* + + + {0} planted {1} + Kwoth planted 5* + + + Trivia game is already running on this server. + + + Trivia Game + + + {0} guessed it! The answer was: {1} + + + No trivia is running on this server. + + + {0} has {1} points + + + Stopping after this question. + + + Time's up! The correct answer was {0} + + + {0} guessed it and WON the game! The answer was: {1} + + + You can't play against yourself. + + + TicTacToe Game is already running in this channel. + + + A draw! + + + has created a game of TicTacToe. + + + {0} has won! + + + Matched three + + + No moves left! + + + Time expired! + + + {0}'s move + + + {0} vs {1} + + + Attempting to queue {0} songs... + + + Autoplay disabled. + + + Autoplay enabled. + + + Default volume set to {0}% + + + Directory queue complete. + + + fairplay + + + Finished song + + + Fair play disabled. + + + Fair play enabled. + + + From position + + + Id + + + Invalid input. + + + Max playtime has no limit now. + + + Max playtime set to {0} second(s). + + + Max music queue size set to unlimited. + + + Max music queue size set to {0} track(s). + + + You need to be in the voice channel on this server. + + + Name + + + Now playing + + + No active music player. + + + No search results. + + + Music playback paused. + + + Player queue - Page {0}/{1} + + + Playing song + + + `#{0}` - **{1}** by *{2}* ({3} songs) + + + Page {0} of saved playlists + + + Playlist deleted. + + + Failed to delete that playlist. It either doesn't exist, or you are not its author. + + + Playlist with that ID doesn't exist. + + + Playlist queue complete. + + + Playlist saved + + + {0}s limit + + + Queue + + + Queued song + + + Music queue cleared. + + + Queue is full at {0}/{0}. + + + Removed song + context: "removed song #5" + + + Repeating current song + + + Repeating playlist + + + Repeating track + + + Current track repeat stopped. + + + Music playback resumed. + + + Repeat playlist disabled. + + + Repeat playlist enabled. + + + I will now output playing, finished, paused and removed songs in this channel. + + + Skipped to `{0}:{1}` + + + Songs shuffled + + + Song moved + + + {0}h {1}m {2}s + + + To position + + + unlimited + + + Volume must be between 0 and 100 + + + Volume set to {0}% + + + Disabled usage of ALL MODULES on channel {0}. + + + Enabled usage of ALL MODULES on channel {0}. + + + Allowed + + + Disabled usage of ALL MODULES for role {0}. + + + Enabled usage of ALL MODULES for role {0}. + + + Disabled usage of ALL MODULES on this server. + + + Enabled usage of ALL MODULES on this server. + + + Disabled usage of ALL MODULES for user {0}. + + + Enabled usage of ALL MODULES for user {0}. + + + Blacklisted {0} with ID {1} + + + Command {0} now has a {1}s cooldown. + + + Command {0} has no cooldown now and all existing cooldowns have been cleared. + + + No command cooldowns set. + + + Command costs + + + Disabled usage of {0} {1} on channel {2}. + + + Enabled usage of {0} {1} on channel {2}. + + + Denied + + + Added word {0} to the list of filtered words. + + + List of filtered words + + + Removed word {0} from the list of filtered words. + + + Invalid second parameter.(Must be a number between {0} and {1}) + + + Invite filtering disabled on this channel. + + + Invite filtering enabled on this channel. + + + Invite filtering disabled on this server. + + + Invite filtering enabled on this server. + + + Moved permission {0} from #{1} to #{2} + + + Can't find permission at index #{0} + + + No costs set. + + + command + Gen. (of command) + + + module + Gen. (of module) + + + Permissions page {0} + + + Current permissions role is {0}. + + + Users now require {0} role in order to edit permissions. + + + No permission found on that index. + + + removed permission #{0} - {1} + + + Disabled usage of {0} {1} for {2} role. + + + Enabled usage of {0} {1} for {2} role. + + + sec. + Short of seconds. + + + Disabled usage of {0} {1} on this server. + + + Enabled usage of {0} {1} on this server. + + + Unblacklisted {0} with ID {1} + + + uneditable + + + Disabled usage of {0} {1} for {2} user. + + + Enabled usage of {0} {1} for {2} user. + + + I will no longer show permission warnings. + + + I will now show permission warnings. + + + Word filtering disabled on this channel. + + + Word filtering enabled on this channel. + + + Word filtering disabled on this server. + + + Word filtering enabled on this server. + + + Abilities + + + No favorite anime yet + + + Started automatic translation of messages on this channel. User messages will be auto-deleted. + + + your auto-translate language has been removed. + + + Your auto-translate language has been set to {0}>{1} + + + Started automatic translation of messages on this channel. + + + Stopped automatic translation of messages on this channel. + + + Bad input format, or something went wrong. + + + Couldn't find that card. + + + fact + + + Chapters + + + Comic # + + + Competitive losses + + + Competitive played + + + Competitive rank + + + Competitive Wins + + + Completed + + + Condition + + + Cost + + + Date + + + Define: + + + Dropped + + + Episodes + + + Error occured. + + + Example + + + Failed finding that animu. + + + Failed finding that mango. + + + Genres + + + Failed finding a definition for that tag. + + + Height/Weight + + + {0}m/{1}kg + + + Humidity + + + Image search for: + + + Failed to find that movie. + + + Invalid source or target language. + + + Jokes not loaded. + + + Lat/Long + + + Level + + + List of {0}place tags + Don't translate {0}place + + + Location + + + Magic Items not loaded. + + + {0}'s MAL profile + + + Bot owner didn't specify MashapeApiKey. You can't use this functionality. + + + Min/Max + + + No channel found. + + + No results found. + + + On-hold + + + Original url + + + An osu! API key is required. + + + Failed retrieving osu! signature. + + + Found over {0} images. Showing random {0}. + + + User not found! Please check the Region and BattleTag before trying again. + + + Plan to watch + + + Platform + + + No ability found. + + + No pokemon found. + + + Profile link: + + + Quality: + + + Quick playtime + + + Quick wins + + + Rating + + + Score: + + + Search for: + + + Failed to shorten that url. + + + Short url + + + Something went wrong. + + + Please specify search parameters. + + + Status + + + Store url + + + Streamer {0} is offline. + + + Streamer {0} is online with {1} viewers. + + + You are following {0} streams on this server. + + + You are not following any streams on this server. + + + No such stream. + + + Stream probably doesn't exist. + + + Removed {0}'s stream ({1}) from notifications. + + + I will notify this channel when status changes. + + + Sunrise + + + Sunset + + + Temperature + + + Title: + + + Top 3 favorite anime: + + + Translation: + + + Types + + + Failed finding definition for that term. + + + Url + + + Viewers + + + Watching + + + Failed finding that term on the specified wikia. + + + Please enter a target wikia, followed by search query. + + + Page not found. + + + Wind speed + + + The {0} most banned champions + + + Failed to yodify your sentence. + + + Joined + + + `{0}.` {1} [{2:F2}/s] - {3} total + /s and total need to be localized to fit the context - +`1.` + + + Activity page #{0} + + + {0} users total. + + + Author + + + Bot ID + + + List of functions in {0}calc command + + + {0} of this channel is {1} + + + Channel topic + + + Commands ran + + + {0} {1} is equal to {2} {3} + + + Units which can be used by the converter + + + Cannot convert {0} to {1}: units not found + + + Cannot convert {0} to {1}: types of unit are not equal + + + Created at + + + Joined cross server channel. + + + Left cross server channel. + + + This is your CSC token + + + Custom emojis + + + Error + + + Features + + + ID + + + Index out of range. + + + Here is a list of users in those roles: + + + You are not allowed to use this command on roles with a lot of users in them to prevent abuse. + + + Invalid {0} value. + Invalid months value/ Invalid hours value + + + Joined Discord + + + Joined server + + + ID: {0} +Members: {1} +Owner ID: {2} + + + No servers found on that page. + + + List of repeater + + + Members + + + Memory + + + Messages + + + Message repeater + + + Name + + + Nickname + + + Nobody is playing that game. + + + No active repeaters. + + + No roles on this page. + + + No shards on this page. + + + No topic set. + + + Owner + + + Owner IDs + + + Presence + + + {0} Servers +{1} Text Channels +{2} Voice Channels + + + Deleted all quotes with {0} keyword. + + + Page {0} of quotes + + + No quotes on this page. + + + No quotes found which you can remove. + + + Quote Added + + + Deleted a random quote. + + + Region + + + Registered on + + + I will remind {0} to {1} in {2} `({3:d.M.yyyy.} at {4:HH:mm})` + + + Not a valid time format. Check the commandlist. + + + New remind template set. + + + Repeating {0} every {1} day(s), {2} hour(s) and {3} minute(s). + + + List of repeaters + + + No repeaters running on this server. + + + #{0} stopped. + + + No repeating messages found on this server. + + + Result + + + Roles + + + Page #{0} of all roles on this server: + + + Page #{0} of roles for {1} + + + No colors are in the correct format. Use `#00ff00` for example. + + + Started rotating {0} role's color. + + + Stopped rotating colors for the {0} role + + + {0} of this server is {1} + + + Server info + + + Shard + + + Shard stats + + + Shard **#{0}** is in {1} state with {2} servers + + + **Name:** {0} **Link:** {1} + + + No special emojis found. + + + Playing {0} songs, {1} queued. + + + Text channels + + + Here is your room link: + + + Uptime + + + {0} of the user {1} is {2} + Id of the user kwoth#1234 is 123123123123 + + + Users + + + Voice channels + + + Current poll results + + + No votes cast. + + + Poll is already running on this server. + + + 📃 {0} has created a poll which requires your attention: + + + `{0}.` {1} with {2} votes. + + + {0} voted. + Kwoth voted. + + + Private Message me with the corresponding number of the answer. + + + Send a Message here with the corresponding number of the answer. + + + Thank you for voting, {0} + + + {0} total votes cast. + + \ No newline at end of file From 8be5bff792d0e8adc4976a777190480bdc82ecb0 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 6 Mar 2017 17:07:12 +0100 Subject: [PATCH 453/746] Update ResponseStrings.zh-CN.resx (POEditor.com) --- .../Resources/ResponseStrings.zh-CN.resx | 180 +++++++++++++++--- 1 file changed, 157 insertions(+), 23 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx b/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx index 3d0396c5..804e7006 100644 --- a/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx +++ b/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx @@ -141,6 +141,7 @@ @{0} 在与 {1} 对战后认领的基地已过期。 + Fuzzy 敌人 @@ -153,9 +154,11 @@ 此战争大小无效 + Fuzzy 现进行的战争列表 + Fuzzy 未被认领 @@ -168,6 +171,7 @@ 现无战争进行。 + Fuzzy 大小 @@ -188,7 +192,7 @@ 与{0}的对战已开始! - 所有定制反应清除。 + 所有定制反应数据清除。 定制反应删除 @@ -207,6 +211,7 @@ 没有找到定制反应。 + Fuzzy 于此用户标识相联系的定制反应并未找到。 @@ -227,7 +232,7 @@ 触发器 - 自动变态模式停止。 + autohentai停止。 没有结果。 @@ -316,7 +321,7 @@ 原因: {1} - 你被禁止了 + 已被禁止了 PLURAL @@ -329,7 +334,7 @@ 机器人状态换成{0} - 自动告别消息关闭。 + 自动删除告别消息关闭。 告别消息将在{0}秒钟内删除。 @@ -395,7 +400,7 @@ 私人信息来自 - 成功添加新的捐赠者. 此用户总共捐赠了: {0} + 成功添加新的捐赠者. 此用户总共捐赠了: {0} 👑 感谢下面列出的人们使这个项目发生! @@ -469,10 +474,12 @@ 用户已被踢出 + Fuzzy 语言列表 {0} + Fuzzy 您的服务器的语言设置现在为{0} - {1} @@ -530,9 +537,11 @@ 在#{0}中删除讯息 + Fuzzy 讯息在#{0}中被更新 + Fuzzy 已静音 @@ -553,15 +562,19 @@ 新消息 + Fuzzy 新昵称 + Fuzzy 新主题 + Fuzzy 昵称成功更换 + Fuzzy 找不到该服务器 @@ -571,12 +584,15 @@ 旧信息 + Fuzzy 旧昵称 + Fuzzy 旧题目 + Fuzzy 失败。很可能我没有足够的权限。 @@ -586,6 +602,7 @@ 主动保护 + Fuzzy {0}已在此服务器禁用。 @@ -598,6 +615,7 @@ 未启用保护项目。 + Fuzzy 用户阈值必须介于{0}和{1}之间。 @@ -757,9 +775,11 @@ 新文字频道成立 + Fuzzy 文字频道已删除 + Fuzzy Undeafen成功。 @@ -773,12 +793,14 @@ 用户名已更改 + Fuzzy 用户 用户被禁止 + Fuzzy {0}已从聊天内被静音**。 @@ -788,18 +810,22 @@ 用户已加入 + Fuzzy 用户离开了 + Fuzzy {0} 已被文字与语音静音了 用户身份添加成功 + Fuzzy 用户身份移除了 + Fuzzy {0} 改成了 {1} @@ -824,9 +850,11 @@ 语音频道已创建 + Fuzzy 语音通道已被毁 + Fuzzy 已停用语音+文字功能。 @@ -858,6 +886,7 @@ 用户已取消禁止 + Fuzzy 迁移完成! @@ -867,9 +896,11 @@ 在线状态更新 + Fuzzy 用户被软禁用 + Fuzzy 已将{0}奖励给{1} @@ -912,6 +943,7 @@ + Fuzzy 排行榜 @@ -933,6 +965,7 @@ 抽奖用户 + Fuzzy 您抛了{0}。 @@ -967,6 +1000,7 @@ + Fuzzy 已成功从{1}取得{0} @@ -979,6 +1013,7 @@ 仅限Bot Owner + Fuzzy 需要{0}频道权限。 @@ -988,9 +1023,11 @@ 命令和别名 + Fuzzy 命令列表已重新生成。 + Fuzzy 输入`{0} h CommandName`可查看该指定命令的帮助。 例如 `{0} h> 8ball` @@ -1013,12 +1050,15 @@ Paypal <{1}> **命令列表**:<{0}> **主机指南和文档可以在这里找到**:<{1}> + Fuzzy 命令列表 + Fuzzy 组件列表 + Fuzzy 输入“{0} cmds ModuleName”以获取该组件中的命令列表。 例如`{0} cmds games` @@ -1031,6 +1071,7 @@ Paypal <{1}> 目录 + Fuzzy 用法 @@ -1044,6 +1085,7 @@ Paypal <{1}> 动物竞赛 + Fuzzy 启动失败,因为没有足够的参与者。 @@ -1094,9 +1136,11 @@ Paypal <{1}> 爱被改变 + Fuzzy 声称 + Fuzzy 离婚 @@ -1216,6 +1260,7 @@ Paypal <{1}> 提交关闭 + Fuzzy 动物竞赛已经运行。 @@ -1250,6 +1295,7 @@ Paypal <{1}> 游戏开始 + Fuzzy Hangman游戏开始了 @@ -1318,15 +1364,18 @@ Paypal <{1}> {0}赢了! + Fuzzy 相配了三个 + Fuzzy 没有地方动了! 时间已过! + Fuzzy 轮到{0}了 @@ -1354,6 +1403,7 @@ Paypal <{1}> 完成歌曲 + Fuzzy 停用公平播放。 @@ -1390,6 +1440,7 @@ Paypal <{1}> 现在播放 + Fuzzy 没有活动音乐播放器。 @@ -1403,15 +1454,18 @@ Paypal <{1}> 播放器队列 - {0} / {1}页 + Fuzzy 正在播放 + Fuzzy `#{0}` - ** {1} ** by * {2} *({3}首歌) 有保存{0}页的播放列表 + Fuzzy 播放列表已删除。 @@ -1427,6 +1481,7 @@ Paypal <{1}> 播放列表已保存 + Fuzzy {0}秒限制 @@ -1436,6 +1491,7 @@ Paypal <{1}> 歌加入队列 + Fuzzy 音乐队列已清除。 @@ -1449,12 +1505,15 @@ Paypal <{1}> 重复播放当前歌曲 + Fuzzy 重复播放列表 + Fuzzy 重复曲目 + Fuzzy 当前曲目停止重复。 @@ -1476,9 +1535,11 @@ Paypal <{1}> 歌播放列表曲被随机。 + Fuzzy 歌曲被移动 + Fuzzy {0}小时 {1}分钟 {2}秒 @@ -1497,18 +1558,22 @@ Paypal <{1}> 在{0}频道上禁止所有组件的使用。 + Fuzzy 在{0}频道上允许启用所有组件。 + Fuzzy 允许 {0}身份的所有组件被禁止使用。 + Fuzzy {0}身份的所有组件被允许使用。 + Fuzzy 在此服务器上禁止所有组件的使用。 @@ -1518,9 +1583,11 @@ Paypal <{1}> {0}用户的所有模块被禁止使用。 + Fuzzy {0}用户的所有模块被允许使用。 + Fuzzy ID为{1}被加入黑名单{0} @@ -1530,18 +1597,22 @@ Paypal <{1}> 命令{0}没有冷却时间了,现有所有的冷却时间已被清除。 + Fuzzy 没有设置命令冷却时间。 命令成本 + Fuzzy {2}频道上已停用{0} {1}。 + Fuzzy 已在{2}频道上启用{0} {1}的使用。 + Fuzzy 被拒绝 @@ -1551,6 +1622,7 @@ Paypal <{1}> 被过滤的词列表 + Fuzzy 已从过滤字词列表中删除{0}。 @@ -1686,12 +1758,15 @@ Paypal <{1}> 竞争模式失败次数 + Fuzzy 竞争模式玩次数 + Fuzzy 竞争模式排名 + Fuzzy 竞争模式胜利次数 @@ -1746,6 +1821,7 @@ Paypal <{1}> 图片搜索: + Fuzzy 找不到该电影。 @@ -1789,9 +1865,11 @@ Paypal <{1}> 等候接听 + Fuzzy 原始网址 + Fuzzy 需要osu!API密钥。 @@ -1819,15 +1897,18 @@ Paypal <{1}> 个人资料链接: + Fuzzy 质量: 快速游戏时间 + Fuzzy 快赢 + Fuzzy 评分 @@ -1837,12 +1918,14 @@ Paypal <{1}> 搜索: + Fuzzy 无法缩短该链接。 短链接 + Fuzzy 出了些问题。 @@ -1855,6 +1938,7 @@ Paypal <{1}> 储存链接 + Fuzzy 直播台{0}已离线。 @@ -1920,13 +2004,14 @@ Paypal <{1}> 请输入目标维基,然后搜索查询。 - 找不到网页。 + 找不到该页面。 风速 + Fuzzy - {0}个被禁止最多的英雄 + {0}个被封号最多的英雄 无法yodify您的句子。 @@ -1935,12 +2020,13 @@ Paypal <{1}> 加入 - `{0} .` {1} [{2:F2} / s] - {3}总计 + `{0}.` {1} [{2:F2}/秒] - {3} 总计 /s and total need to be localized to fit the context - `1.` 活动页面#{0} + Fuzzy {0}个用户。 @@ -1952,16 +2038,18 @@ Paypal <{1}> 机器ID - {0} calc命令功能列表 + {0} 计算器命令列表 此频道的{0}是{1} 频道主题 + Fuzzy - 执行命令 + 执行的命令 + Fuzzy {0} {1}等于{2} {3} @@ -1973,10 +2061,11 @@ Paypal <{1}> 无法将{0}转换为{1}:找不到单位 - 无法将{0}转换为{1}:单位类型不相等 + 无法将{0}转换为{1}:单位类型不属于一类 创建于 + Fuzzy 加入跨服务器频道。 @@ -1989,13 +2078,13 @@ Paypal <{1}> 自定义Emojis + Fuzzy 错误 - 特征 - + 功能 ID @@ -2007,10 +2096,11 @@ Paypal <{1}> 以下是这个身份的用户列表: - 您不能对其中有用户很多的身份使用此命令来防止滥用。 + 为防止滥用,您不能对有过多用户的身份使用此命令。 + Fuzzy - 值{0}错误。 + {0}值错误。 Invalid months value/ Invalid hours value @@ -2018,17 +2108,20 @@ Paypal <{1}> 加入服务器 + Fuzzy ID:{0} 会员数:{1} 业主ID:{2} + Fuzzy 在该网页上找不到服务器。 重复列表 + Fuzzy 会员 @@ -2041,6 +2134,7 @@ Paypal <{1}> 消息重复功能 + Fuzzy 名字 @@ -2052,7 +2146,7 @@ Paypal <{1}> 没有人在玩那个游戏 - 没有活动重复功能。 + 没有正在重复的消息。 此页面上没有身份。 @@ -2078,10 +2172,10 @@ Paypal <{1}> {2}个语音频道 - 删除所有引号使用{0}关键字。 + 已删除所有使用{0}关键字的引用。 - {0}页引号 + 引用的第{0}页 此页面上没有引用。 @@ -2093,13 +2187,14 @@ Paypal <{1}> 引用被添加 - 删除了随机引用。 + 随机删除了一个引用。 区域 注册日 + Fuzzy 我将在{2}`({3:d.M.yyyy。}的{4:HH:mm})提醒{0}关于{1} @@ -2114,7 +2209,8 @@ Paypal <{1}> 会每{1}天{2}小时{3}分钟重复{0}。 - 重复列表 + 重复消息列表 + Fuzzy 此服务器上没有运行重复消息。 @@ -2138,7 +2234,7 @@ Paypal <{1}> {1}身份的第{0}页 - 颜色的格式不正确。 例如,使用‘#00ff00’。 + 颜色的格式不正确。 例如,使用 “#00ff00”。 开始轮流{0}身份的颜色。 @@ -2151,15 +2247,17 @@ Paypal <{1}> 服务器信息 + Fuzzy 分片 分片统计 + Fuzzy - 分片**#{0} **处于{1}状态与{2}台服务器 + 分片**#{0} **与{2}台服务器处于{1}状态 **名称:** {0} **链接:** {1} @@ -2172,6 +2270,7 @@ Paypal <{1}> 文字频道 + Fuzzy 这是你的房间链接: @@ -2180,7 +2279,7 @@ Paypal <{1}> 正常运行时间 - 此用户 {1} 的{0} 是 {2} + 用户 {1} 的{0} 是 {2} Id of the user kwoth#1234 is 123123123123 @@ -2188,6 +2287,41 @@ Paypal <{1}> 语音频道 + Fuzzy + + + 你已经参加这场比赛! + + + 当前投票结果 + + + 没有票投。 + + + 此服务器上已运行投票。 + + + 📃{0}创建一个需要您注意的投票: + + + '{0}'。{1} 有 {2}票。 + + + {0}投了票。 + Kwoth voted. + + + 私人消息我相应答案的数字。 + + + 在这里发送消息相应答案的数字。 + + + 谢谢投票,{0} + + + {0}投票总数。 \ No newline at end of file From fe2c7171578ccd23ffbb242a361578930647b64a Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 6 Mar 2017 17:07:16 +0100 Subject: [PATCH 454/746] Update ResponseStrings.zh-TW.resx (POEditor.com) --- .../Resources/ResponseStrings.zh-TW.resx | 574 +++++++++--------- 1 file changed, 300 insertions(+), 274 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx index 3ab3c220..7b58202d 100644 --- a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx +++ b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 該基地已被佔領或摧毀。 @@ -344,22 +344,22 @@ 目前的告別訊息: {0} - 輸入 {0} 來啟用告別訊息 + 輸入 {0} 來啟用告別通知 新的告別訊息已設定。 - 告別訊息已停用。 + 告別通知已停用。 - 在這個頻道啟用告別訊息。 + 在這個頻道啟用告別通知。 頻道名稱已更改 - 舊名 + 舊頻道名稱 頻道主題已更改 @@ -434,43 +434,43 @@ 新的歡迎私訊已設定。 - DM歡迎公告關閉。 + 私訊歡迎公告已停用。 私訊歡迎公告已啟用。 - 当前欢迎消息是:{0} + 目前的歡迎訊息: {0} - 输入{0}来启用欢迎消息 + 輸入 {0} 來啟用歡迎訊息 - 新欢迎消息设定成功。 + 新的歡迎訊息已設定。 - 欢迎公告关闭。 + 歡迎通知已關閉。 - 欢迎公告在此频道开启。 + 在這個頻道啟用歡迎通知。 - 您不能对身份层次结构中身份高于或等于您的身份的用户使用此命令。 + 您不能對身分組與您一樣或更高的人使用此指令。 - {0} 秒後載入圖片! + 圖片共花了 {0} 秒載入! - 格式輸入無效。 + 無效的輸入格式。 - 參數無效。 + 無效的參數。 {0} 已加入 {1} - 你已被從 {0} 伺服器踢出。 + 你已被 {0} 伺服器踢出。 原因:{1} @@ -478,71 +478,69 @@ Fuzzy - 語言列表 + 可用的語言清單 {0} Fuzzy - 您的服务器的语言设置现在为{0} - {1} + 您的伺服器語言現在為 {0} - {1} - 机器人的默认语言环境现在是{0} - {1} + Bot的預設語言為 {0} - {1} - 机器人的语言设置为{0} - {1} + Bot的語言已被設定為 {0} - {1} - 设置语言设置失败。 重新访问此命令帮助。 + 語言設定失敗,請重新檢閱本指令說明。 - 此服务器的语言设置为{0} - {1} + 本伺服器的語言現在為 {0} - {1} - {0}已离开{1} + {0} 已離開 {1} - 离开服务器{0} + 已離開伺服器 {0} - 在此频道中记录{0}事件。 + 在此頻道中紀錄 {0} 事件。 - 记录频道中所有事件 + 在此頻道中記錄所有事件。 - 记录功能取消 + 紀錄功能已停用。 - 您可以设定的记录项目: + 您可以記錄的事件: - 记录会忽略{0} + 紀錄將會忽略 {0} - 记录不会忽略{0} + 紀錄將不會忽略 {0} - 已停止记录{0}事件。 + 已停止紀錄 {0} 事件。 - {0}已经提到了以下身份 + {0} 提到了下列身分組 - 来自{0}`[机器人主人]’的消息: + 来自 {0} '[Bot所有者]’ 的消息: - 消息已发. + 訊息已傳送。 - {0}被移动由{1}到{2} + {0} 已從 {1} 移動至 {2} - 在#{0}中删除讯息 - Fuzzy + #{0} 中删除了讯息 - 讯息在#{0}中被更新 - Fuzzy + #{0} 中更新了訊息 已静音 @@ -553,321 +551,317 @@ singular "User muted." - 权限不够执行此命令 + 我並沒有足夠的權限來執行此指令。 - 新的静音角色设定成功。 + 新的禁言身分已設定。 - 我需要**管理**权限才能做那个。 + 我需要此伺服器的**管理**權限才能執行此指令。 - 新消息 + 新訊息 Fuzzy - 新昵称 + 新暱稱 Fuzzy - 新主题 + 新主題 Fuzzy - 昵称成功更换 + 暱稱已變更 Fuzzy - 找不到该服务器 + 找不到那個伺服器 - 找不到具有该ID的分片。 + 找不到有著那個ID的Shard。 - 旧信息 + 舊訊息 Fuzzy - 旧昵称 + 舊暱稱 Fuzzy - 旧题目 + 舊主題 Fuzzy - 失败。很可能我没有足够的权限。 + 錯誤: 很可能我並沒有足夠的權限。 - 重置此服务器的权限。 + 此伺服器的權限已重設。 - 主动保护 - Fuzzy + 生效中的保護機制 - {0}已在此服务器禁用。 + {0} 已在此伺服器 **停用**。 - {0}已启用。 + {0} 已啟用。 - 失败。 我需要 ManageRoles 权限 + 錯誤。我需要此伺服器的 管理身分組 權限 - 未启用保护项目。 + 沒有生效中的保護機制 Fuzzy - 用户阈值必须介于{0}和{1}之间。 + 用戶緩衝數應介於 {0} 和 {1} 之間。 - 如果{0}或更多用户在{1}秒内加入,我将{2}他们。 + 如果 {1} 秒內進入了 {0} 或更多位使用者,我則會將他們 {2} 。 - 时间必须在{0}和{1}秒之间。 + 時間必須在於 {0} 和 {1} 秒之間。 - 已成功从用户{0}中移除所有身份 + 已成功移除了使用者 {0} 上所有的身分組。 - 无法移除身份。 我没有足够的权限。 + 無法移除身分組。我的權限不夠。 - {0}身份的颜色已更改。 + {0} 身份組的顏色已變更。 - 那个身份不存在。 + 那個身分組並不存在。 - 指定的参数错误。 + 指定的參數錯誤。 - 由于颜色无效或权限不足而发生错误。 + 無效的色碼或是權限不足引起錯誤。 - 已成功从用户{1}中删除身份{0} + 成功的移除 {1} 的 {0} 身分組。 - 无法移除身份。 我没有足够的权限。 + 無法移除身分組。我沒有足夠的權限。 - 身份名已改 + 身分組名已改。 - 身份重命名失败。我的权限不足。 + 身分組名變更失敗。我沒有足夠的權限。 - 您不能编辑比你 + 您不能编辑比你最高身分組還高的身分組。 - 已移除游玩消息:{0} + 已移除遊玩訊息: {0} - 身份{0}已添加到列表中。 + 身分組 {0} 已新增至清單。 - {0}未找到。已清理。 + {0} 未找到。已清理。 - 身份{0}已在列表中。 + 身分組 {0} 已在清單中。 - 添加成功. + 新增成功。 - 旋转游玩状态关闭。 + 輪播遊玩狀態已停用。 - 旋转游玩状态开启。 + 輪播遊玩狀態已啟用。 - 以下是旋转状态列表: + 輪播遊玩狀態清單: {0} - 未设置旋转游戏状态。 + 尚未設定輪播遊玩狀態。 - 您已经拥有{0}身份。 + 您已經是 {0} 身分組了。 - 您已拥有{0}独占的自行分配。 + 您已經是 {0} 身分組的成員,您一次只能加入一個自入身分群組。 - 自行分配身份现在是独家! + 自入身分群組現在為擇一模式。 - 有{0}个可自行分配身份 + 有 {0} 個可以自入的身分群組 - 这个身份是不可自行分配的。 + 此身分組並不能自行加入。 - 您没有{0}身份。 + 您並不是 {0} 身份組的成員。 - 自我分配的身份现在不是独家的! + 自入身分群組不再為擇一模式! - 我无法向您添加该身份。 ‘我不能向身份层次结构中我身份以外的所有者或其他身份添加身份。’ + 我無法新增身分組比我還高的身分組給您。 - {0}已从可自我分配身份列表中删除。 + {0} 已從自入身分組清單中移除。 - 您不再拥有{0}身份。 + 您不再是 {0} 身分組的成員了。 - 您现在拥有{0}身份。 + 您現在是 {0} 身份組的成員了。 - 已成功将身份{0}添加到用户{1} + 成功將 {0} 身分組指派給 {1} - 无法添加身份。 我没有足够的权限。 + 無法指派身分組。我沒有足夠的權限。 - 新头像集! + 新的大頭貼已設定! - 新频道名称设定。 + 新的頻道名稱已設定。 - 新游戏设定! + 新的遊戲名稱已設定! - 新直播设定! + 新的實況已設定! - 新频道主题集。 + 新的頻道主題已設定! - 分段{0}已重新连接。 + Shard {0} 已重新連線。 - 分段{0}重新连接中。 + Shard {0} 重新連線中。 - 关闭中 + 關閉中 - 用户不能在{1}秒内发送超过{0}条消息。 + 使用者無法在 {1} 秒發送超過 {0} 條訊息。 - 慢速模式关闭。 + 慢速模式已停用。 - 慢速模式启动 + 慢速模式已啟用 - 软禁(踢出) + 軟禁 (踢出) PLURAL - {0}将忽略此通道。 + {0} 將會忽略此頻道。 - 0}将不再忽略此通道。 + {0} 將會注意此頻道。 - 如果用户发布{0}个相同的消息,我会{1}他们。 -     __IgnoredChannels__:{2} + 如果使用者連續貼出 {0} 個相同的訊息,我將會把他們 {1}。 +     __忽略的頻道__: {2} - 新文字频道成立 + 文字頻道已建立 Fuzzy - 文字频道已删除 + 文字頻道已刪除 Fuzzy - Undeafen成功。 + 成功解除靜音。 - 已取消静音 + 解除靜音 singular - 用户名 + 使用者名稱 - 用户名已更改 + 使用者名稱已更改 Fuzzy - 用户 + 使用者 - 用户被禁止 + 使用者已封鎖 Fuzzy - {0}已从聊天内被静音**。 + {0} 已**被禁**__文字聊天__。 - {0}已从聊天内**取消静音**。 + {0} 已**允許**__文字聊天__。 - 用户已加入 + 使用者已加入 Fuzzy - 用户离开了 + 使用者已離開 Fuzzy - {0} 已被文字与语音静音了 + {0} 已**被禁**__文字和語音聊天__。 - 用户身份添加成功 - Fuzzy + 使用者身分組已新增 - 用户身份移除了 + 已移除用戶的身分組 Fuzzy {0} 改成了 {1} - {0}已从文字和语音频道中取消静音**。 + {0} 已從文字頻道和語音頻道被**取消禁音**。 - {0}已加入{1}语音通道。 + {0} 已加入 {1} 語音頻道。 - {0}已离开{1}语音通道。 + {0} 已離開 {1} 語音頻道。 - {0}已从{1}移至{2}语音通道。 + {0} 已從 {1} 移至 {2} 語音頻道。 - {0}已被**静音**。 + {0} 已被**静音**。 - {0}已被**取消静音**。 + {0} 已被**取消静音**。 - 语音频道已创建 - Fuzzy + 已建立語音頻道 - 语音通道已被毁 - Fuzzy + 已刪除語音頻道 - 已停用语音+文字功能。 + 已停用語音+文字功能。 - 启用语音+文字功能。 + 已啟用語音+文字功能。 - 我没有**管理身份**和/或**管理频道**权限,所以我不能在{0}服务器上运行`语音+文字`。 + 我沒有**管理身分組**和/或**管理頻道**權限,所以我無法在 {0} 伺服器上運行`語音+文字`。 - 您正在启用/禁用此功能,并且**我没有ADMINISTRATOR权限**。 这可能会导致一些问题,您必须自己清理文本频道。 + 您正在啟用/停用此功能,而且**我没有管理員權限**。這可能會造成一些問題,您必須自己清理文字頻道。 我需要至少**管理身份**和**管理频道**权限,以启用此功能。 (优先管理权限) @@ -904,10 +898,10 @@ Fuzzy - 已将{0}奖励给{1} + 已給予 {0} 給 {1} - 下一次好运^ _ ^ + 祝你下一次好運 ^_^ 恭喜! 您赢得{0}因为您滚{1}或以上 @@ -916,35 +910,34 @@ 卡牌改组。 - 抛了{0}。 + 拋出了 {0}。 User flipped tails. - 你猜到了! 您赢得了{0} + 你猜對了!你赢得了 {0} - 指定的数字无效。 你可以抛1到{0}钱币。 + 指定的數字無效。你可以丟 1 至 {0} 個硬幣。 将{0}反应添加到此消息以获取{1} - 此活动在{0}小时内有效。 + 此活動只在 {0} 小時內有效。 花反应活动开始了! - 给了{1}{0} + 送了 {1} 給 {0} X has gifted 15 flowers to Y - {0}拥有{1} + {0} 擁有 {1} X has Y flowers - - Fuzzy + 排行榜 @@ -953,13 +946,13 @@ 从{2}身份授予{0}至{1}名用户。 - 您赌注不能超过{0} + 你的賭注不能大於 {0} - 您赌注不能低于{0} + 你的賭注不能少於 {0} - 您没有足够的{0} + 你沒有足夠的 {0} 卡牌组中没有更多的牌。 @@ -972,10 +965,10 @@ 您抛了{0}。 - 赌注 + 賭注 - 哇啊啊啊啊啊啊! 恭喜! x {0} + 哇啊啊啊啊啊啊!恭喜!x{0} 单个{0},x {1} @@ -987,7 +980,7 @@ 做得好! 两个{0} - 投注x {1} - 胜利 + 獲勝 用户必须键入密码才能获取{0}。 @@ -2292,7 +2285,40 @@ Paypal <{1}> Fuzzy - + 你已經加入這場比賽了! + + + 目前投票結果 + + + 沒有投票。 + + + 投票已在這個伺服器進行。 + + + 📃 {0} 已建立一個投票 which requires your attention: + Fuzzy + + + `{0}.` {1} 有 {2} 票。 + Fuzzy + + + {0} 已投票。 + Kwoth voted. + + + 私訊我相對數字的答案。 + + + 發送相對數字的答案在這裡。 + + + 感謝你的投票, {0} + + + 共收到 {0}票。 \ No newline at end of file From ac752cffea67ef77e382ee0951c26dc9eedb024a Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 6 Mar 2017 17:07:21 +0100 Subject: [PATCH 455/746] Update ResponseStrings.fr-fr.resx (POEditor.com) --- .../Resources/ResponseStrings.fr-fr.resx | 139 +++++++++++++++++- 1 file changed, 137 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx index b0bcd0c5..bed50a57 100644 --- a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx +++ b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx @@ -140,6 +140,7 @@ La demande de la part de @{0} pour une guerre contre {1} a expiré. + Fuzzy Ennemi @@ -152,9 +153,11 @@ La taille de la guerre n'est pas valide. + Fuzzy Liste des guerres en cours + Fuzzy non réclamé @@ -167,6 +170,7 @@ Aucune guerre en cours. + Fuzzy Taille @@ -206,6 +210,7 @@ Aucune réaction personnalisée trouvée. + Fuzzy Aucune réaction personnalisée ne correspond à cet ID. @@ -468,10 +473,12 @@ Raison : {1} Utilisateur expulsé + Fuzzy Listes des langues {0} + Fuzzy La langue du serveur est désormais {0} - {1} @@ -530,9 +537,11 @@ Raison : {1} Message supprimé dans #{0} + Fuzzy Mise à jour du message dans #{0} + Fuzzy Tous les utilisateurs sont maintenant muets. @@ -553,15 +562,19 @@ Raison : {1} Nouveau message + Fuzzy Nouveau pseudonyme + Fuzzy Nouveau sujet + Fuzzy Pseudonyme changé + Fuzzy Impossible de trouver ce serveur @@ -572,12 +585,15 @@ Raison : {1} Ancien message + Fuzzy Ancien pseudonyme + Fuzzy Ancien sujet + Fuzzy Erreur. Je ne dois sûrement pas posséder les permissions suffisantes. @@ -587,6 +603,7 @@ Raison : {1} Protections actives + Fuzzy {0} a été **désactivé** sur ce serveur. @@ -599,6 +616,7 @@ Raison : {1} Aucune protection activée. + Fuzzy Le seuil d'utilisateurs doit être entre {0} et {1}. @@ -762,9 +780,11 @@ Raison : {1} Salon textuel crée. + Fuzzy Salon textuel supprimé. + Fuzzy Son activé avec succès. @@ -778,12 +798,14 @@ Raison : {1} Nom d'utilisateur modifié. + Fuzzy Utilisateurs Utilisateur banni + Fuzzy {0} est maintenant **muet** sur le chat. @@ -793,18 +815,22 @@ Raison : {1} L'utilisateur a rejoint + Fuzzy L'utilisateur a quitté + Fuzzy {0} est maintenant **muet** à la fois sur les salons textuels et vocaux. Rôle ajouté à l'utilisateur + Fuzzy Rôle retiré de l'utilisateur + Fuzzy {0} est maintenant {1} @@ -829,9 +855,11 @@ Raison : {1} Salon vocal crée. + Fuzzy Salon vocal supprimé. + Fuzzy Fonctionnalités vocales et textuelles désactivées. @@ -863,6 +891,7 @@ Raison: {1} Utilisateur débanni + Fuzzy Migration effectuée! @@ -872,9 +901,11 @@ Raison: {1} Présences mises à jour. + Fuzzy Utilisateur expulsé. + Fuzzy a récompensé {0} à {1} @@ -918,6 +949,7 @@ Raison: {1} Face + Fuzzy Classement @@ -939,6 +971,7 @@ Raison: {1} Utilisateur tiré au sort + Fuzzy Vous avez roulé un {0}. @@ -972,6 +1005,7 @@ Raison: {1} Pile + Fuzzy Vous avez pris {0} de {1} avec succès @@ -984,6 +1018,7 @@ Raison: {1} Propriétaire du Bot seulement + Fuzzy Nécessite {0} permissions du salon. @@ -993,9 +1028,11 @@ Raison: {1} Commandes et alias + Fuzzy Liste des commandes rafraîchie. + Fuzzy Écrivez `{0}h NomDeLaCommande` pour voir l'aide spécifique à cette commande. Ex: `{0}h >8ball` @@ -1017,12 +1054,15 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. **Liste des Commandes**: <{0}> **La liste des guides et tous les documents peuvent être trouvés ici**: <{1}> + Fuzzy Liste des commandes + Fuzzy Liste des modules + Fuzzy Entrez `{0}cmds NomDuModule` pour avoir la liste des commandes de ce module. ex `{0}cmds games` @@ -1035,6 +1075,7 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Table des matières + Fuzzy Usage @@ -1048,6 +1089,7 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Course d'animaux + Fuzzy Pas assez de participants pour commencer. @@ -1098,9 +1140,11 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Changements de Coeur + Fuzzy Revendiquée par + Fuzzy Divorces @@ -1219,6 +1263,7 @@ La nouvelle valeur de {0} est {1} ! Inscriptions terminées. + Fuzzy Une course d'animaux est déjà en cours. @@ -1254,6 +1299,7 @@ La nouvelle valeur de {0} est {1} ! La jeu a commencé. + Fuzzy Partie de pendu commencée. @@ -1322,15 +1368,18 @@ La nouvelle valeur de {0} est {1} ! {0} a gagné ! + Fuzzy Trois alignés. + Fuzzy Aucun mouvement restant ! Le temps a expiré ! + Fuzzy Tour de {0}. @@ -1358,6 +1407,7 @@ La nouvelle valeur de {0} est {1} ! Lecture terminée + Fuzzy Système de tour de rôle désactivé. @@ -1394,6 +1444,7 @@ La nouvelle valeur de {0} est {1} ! Vous écoutez + Fuzzy Aucun lecteur de musique actif. @@ -1406,15 +1457,18 @@ La nouvelle valeur de {0} est {1} ! File d'attente - Page {0}/{1} + Fuzzy Lecture en cours + Fuzzy `#{0}` - **{1}** par *{2}* ({3} pistes) Page {0} des listes de lecture sauvegardées + Fuzzy Liste de lecture supprimée. @@ -1430,6 +1484,7 @@ La nouvelle valeur de {0} est {1} ! Liste de lecture sauvegardée + Fuzzy Limite à {0}s @@ -1439,6 +1494,7 @@ La nouvelle valeur de {0} est {1} ! Piste ajoutée à la file d'attente + Fuzzy File d'attente effacée. @@ -1452,12 +1508,15 @@ La nouvelle valeur de {0} est {1} ! Répétition de la piste en cours de lecture + Fuzzy Liste de lecture en boucle + Fuzzy Piste en boucle + Fuzzy La piste ne sera lue qu'une fois. @@ -1479,9 +1538,11 @@ La nouvelle valeur de {0} est {1} ! Lecture aléatoire activée. + Fuzzy Piste déplacée + Fuzzy {0}h {1}m {2}s @@ -1500,18 +1561,22 @@ La nouvelle valeur de {0} est {1} ! Désactivation de l'usage de TOUS LES MODULES pour le salon {0}. + Fuzzy Activation de l'usage de TOUS LES MODULES pour le salon {0}. + Fuzzy Permis Désactivation de l'usage de TOUS LES MODULES pour le rôle {0}. + Fuzzy Activation de l'usage de TOUS LES MODULES pour le rôle {0}. + Fuzzy Désactivation de l'usage de TOUS LES MODULES sur ce serveur. @@ -1521,9 +1586,11 @@ La nouvelle valeur de {0} est {1} ! Désactivation de l'usage de TOUS LES MODULES pour l'utilisateur {0}. + Fuzzy Activation de l'usage de TOUS LES MODULES pour l'utilisateur {0}. + Fuzzy {0} sur liste noire avec l'ID {1} @@ -1534,18 +1601,22 @@ La nouvelle valeur de {0} est {1} ! La commande {0} n'a pas de temps de recharge et tous les temps de recharge ont été réinitialisés. + Fuzzy Aucune commande n'a de temps de recharge. Coût de la commande : + Fuzzy Usage de {0} {1} désactivé sur le salon {2}. + Fuzzy Usage de {0} {1} activé sur le salon {2}. + Fuzzy Refusé @@ -1555,6 +1626,7 @@ La nouvelle valeur de {0} est {1} ! Liste Des Mots Filtrés + Fuzzy Suppression du mot {0} de la liste des mots filtrés. @@ -1690,12 +1762,15 @@ La nouvelle valeur de {0} est {1} ! Parties compétitives perdues + Fuzzy Parties compétitives jouées + Fuzzy Rang en compétitif + Fuzzy Parties compétitives gagnées @@ -1751,6 +1826,7 @@ La nouvelle valeur de {0} est {1} ! Recherche d'images pour: + Fuzzy Impossible de trouver ce film. @@ -1794,9 +1870,11 @@ La nouvelle valeur de {0} est {1} ! En attente + Fuzzy Url originale + Fuzzy Une clé d'API osu! est nécessaire. @@ -1825,15 +1903,18 @@ La nouvelle valeur de {0} est {1} ! Lien du profil : + Fuzzy Qualité Durée en Jeux Rapides + Fuzzy Victoires Rapides + Fuzzy Évaluation @@ -1843,13 +1924,15 @@ La nouvelle valeur de {0} est {1} ! Chercher pour: - recherche plutôt non ? + recherche plutôt non ? +Fuzzy Impossible de réduire cette Url. Url réduite + Fuzzy Une erreur s'est produite. @@ -1862,6 +1945,7 @@ La nouvelle valeur de {0} est {1} ! Url stockée + Fuzzy Le streamer {0} est hors ligne. @@ -1931,6 +2015,7 @@ La nouvelle valeur de {0} est {1} ! Vitesse du vent + Fuzzy Les {0} champions les plus bannis @@ -1948,6 +2033,7 @@ La nouvelle valeur de {0} est {1} ! Page d'activité #{0} + Fuzzy {0} utilisateurs en total. @@ -1966,9 +2052,11 @@ La nouvelle valeur de {0} est {1} ! Sujet du salon + Fuzzy Commandes exécutées + Fuzzy {0} {1} est équivalent à {2} {3} @@ -1984,6 +2072,7 @@ La nouvelle valeur de {0} est {1} ! Créé le + Fuzzy Salon inter-serveur rejoint. @@ -1996,6 +2085,7 @@ La nouvelle valeur de {0} est {1} ! Emojis personnalisées + Fuzzy Erreur @@ -2014,6 +2104,7 @@ La nouvelle valeur de {0} est {1} ! Vous ne pouvez pas utiliser cette commande sur un rôle incluant beaucoup d'utilisateurs afin d'éviter les abus. + Fuzzy Valeur {0} invalide. @@ -2024,17 +2115,20 @@ La nouvelle valeur de {0} est {1} ! Serveur rejoint + Fuzzy ID: {0} Membres: {1} OwnerID: {2} + Fuzzy Aucun serveur trouvée sur cette page. Liste des messages répétés + Fuzzy Membres @@ -2047,6 +2141,7 @@ OwnerID: {2} Répéteur de messages + Fuzzy Nom @@ -2107,6 +2202,7 @@ OwnerID: {2} Inscrit sur + Fuzzy Je vais vous rappeler {0} pour {1} dans {2} `({3:d.M.yyyy} à {4:HH:mm})` @@ -2122,6 +2218,7 @@ OwnerID: {2} Liste des répétitions + Fuzzy Aucune répétition active sur ce serveur. @@ -2158,6 +2255,7 @@ OwnerID: {2} Info du serveur + Fuzzy Shard @@ -2165,7 +2263,8 @@ OwnerID: {2} Statistique des shards - Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. + Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. +Fuzzy Le shard **#{0}** est en état {1} avec {2} serveurs. @@ -2182,6 +2281,7 @@ OwnerID: {2} Salons textuels + Fuzzy Voici le lien pour votre salon: @@ -2198,6 +2298,41 @@ OwnerID: {2} Salons vocaux + Fuzzy + + + Vous avez déjà rejoint cette course! + + + Résultats du sondage actuel + + + Aucun vote enregistré. + + + Un sondage est déjà en cours sur ce serveur. + + + 📃 {0} a créé un sondage qui requiert votre attention: + + + `{0}.` {1} avec {2} votes. + + + {0} a voté. + Kwoth voted. + + + Envoyez moi un message privé avec le numéro correspondant à la réponse. + + + Envoyez un Message ici avec le numéro correspondant à la réponse. + + + Merci d'avoir voté, {0} + + + {0} votes enregistrés au total. \ No newline at end of file From 7ca64392a0f35f78b990eae8f33f4d4e4205f32a Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 6 Mar 2017 17:07:24 +0100 Subject: [PATCH 456/746] Update ResponseStrings.de-DE.resx (POEditor.com) --- .../Resources/ResponseStrings.de-DE.resx | 141 +++++++++++++++++- 1 file changed, 139 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx index 318404de..879094e3 100644 --- a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx @@ -140,6 +140,7 @@ Beanspruchung von @{0} für den Krieg gegen {1} ist abgelaufen. + Fuzzy Gegner @@ -152,9 +153,11 @@ Keine gültige Kriegsgröße. + Fuzzy Liste der aktiven Kriege + Fuzzy nicht beansprucht @@ -167,6 +170,7 @@ Keine aktiven Kriege. + Fuzzy Größe @@ -206,6 +210,7 @@ Keine benutzerdefinierten Reaktionen gefunden. + Fuzzy Keine benutzerdefinierte Reaktion mit dieser ID gefunden. @@ -468,10 +473,12 @@ Grund: {1} Benutzer wurde gekickt + Fuzzy Liste der Sprachen {0} + Fuzzy Die Sprachumgebung des Servers ist jetzt {1} - {1} @@ -530,9 +537,11 @@ Grund: {1} Nachricht in #{0} gelöscht + Fuzzy Nachricht in #{0} aktualisiert + Fuzzy wurden Stumm geschalten @@ -553,15 +562,19 @@ Grund: {1} Neue Nachricht + Fuzzy Neuer Nickname + Fuzzy Neues Thema + Fuzzy Nickname wurde geändert + Fuzzy Konnte den Server nicht finden @@ -571,12 +584,15 @@ Grund: {1} Alte Nachricht + Fuzzy Alter Nickname + Fuzzy Altes Thema + Fuzzy Fehler. Ich habe wahrscheinlich nicht ausreichend Rechte. @@ -586,6 +602,7 @@ Grund: {1} Aktive Schutzmechanismen + Fuzzy {0} wurde auf diesem Server **deaktiviert**. @@ -598,6 +615,7 @@ Grund: {1} Keine Schutzmechanismen aktiviert. + Fuzzy Benutzerschwelle muss zwischen {0} und {1} sein. @@ -757,9 +775,11 @@ __ignoredChannels__: {2} Textkanal erstellt + Fuzzy Textkanal zerstört + Fuzzy Taubschaltung aufgehoben. @@ -773,12 +793,14 @@ __ignoredChannels__: {2} Benutzername geändert + Fuzzy Benutzer Benutzer gebannt + Fuzzy {0} wurde **stummgeschaltet** im Chat. @@ -788,18 +810,22 @@ __ignoredChannels__: {2} Benutzer ist beigetreten + Fuzzy Benutzer ist gegangen + Fuzzy {0} wurde **stummgeschaltet** im Text- und Sprachchat. Benutzerrolle hinzugefügt + Fuzzy Benutzerrolle entfernt + Fuzzy {0} ist nun {1} @@ -824,10 +850,12 @@ __ignoredChannels__: {2} Sprachkanal erstellt - Should say "Voice Channel Created" + Should say "Voice Channel Created" +Fuzzy Sprachkanal zerstört + Fuzzy Text- und Sprachfunktion deaktiviert. @@ -859,6 +887,7 @@ Grund: {1} Benutzer entbannt + Fuzzy Migration fertig! @@ -868,9 +897,11 @@ Grund: {1} Anwesenheits Änderungen + Fuzzy Nutzer wurde gekickt + Fuzzy gab {0} an {1} @@ -913,6 +944,7 @@ Grund: {1} Kopf + Fuzzy Bestenliste @@ -934,6 +966,7 @@ Grund: {1} Ausgewählter Benutzer + Fuzzy Sie haben eine {0} gewürfelt. @@ -967,6 +1000,7 @@ Grund: {1} Zahl + Fuzzy hat erfolgreich {0} von {1} genommen @@ -979,6 +1013,7 @@ Grund: {1} Nur Bot-Besitzer + Fuzzy Benötigt Kanalrecht {0}. @@ -988,9 +1023,11 @@ Grund: {1} Befehle und Alias + Fuzzy Befehlsliste neu generiert. + Fuzzy Gebe `{0}h NameDesBefehls` ein, um die Hilfestellung für diesen Befehl zu sehen. Z.B. `{0}h >8ball` @@ -1012,12 +1049,15 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu **Liste der Befehle**: <{0}> **Hosting Anleitungen und Dokumentationen können hier gefunden werden**: <{1}> + Fuzzy Lister der Befehle + Fuzzy Liste der Module + Fuzzy Schreibe `{0}cmds ModuleName` um eine Liste aller Befehle dieses Moduls zu erhalten. z.B. `{0}cmds games` @@ -1030,6 +1070,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Inhaltsverzeichnis + Fuzzy Verwendung @@ -1042,6 +1083,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Tierrennen + Fuzzy Das Rennen konnte nicht gestartet werden, da es nicht genügend Teilnehmer gibt. @@ -1092,9 +1134,11 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Sinneswandel + Fuzzy Beansprucht von + Fuzzy Scheidungen @@ -1213,6 +1257,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Einsendungen geschlossen + Fuzzy Tierrennen läuft bereits. @@ -1247,6 +1292,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Spiel gestartet + Fuzzy Hangman-Spiel gestartet @@ -1315,15 +1361,18 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu {0} hat gewonnen! + Fuzzy Drei in einer Reihe + Fuzzy Keine Züge übrig Zeit abgelaufen + Fuzzy {0}'s Zug @@ -1351,6 +1400,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Lied beendet + Fuzzy Fairer Modus deaktiviert. @@ -1387,6 +1437,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Aktuelles Lied: + Fuzzy Kein aktiver Musikspieler. @@ -1399,15 +1450,18 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Musik-Warteschlange - Seite {0}/{1} + Fuzzy Spiele Lied + Fuzzy `#{0}` - **{1}** by *{2}* ({3} Lieder) Seite {0} der gespeicherten Playlists + Fuzzy Playlist gelöscht. @@ -1423,6 +1477,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Playlist gespeichert + Fuzzy {0}'s Limit @@ -1432,6 +1487,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Eingereihtes Lied + Fuzzy Musik-Warteschlange geleert. @@ -1445,12 +1501,15 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Aktuelles Lied wird wiederholt + Fuzzy Playlist wird wiederholt + Fuzzy Lied wird wiederholt + Fuzzy Aktuelles Lied wird nicht mehr wiederholt. @@ -1472,9 +1531,11 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Lieder gemischt. + Fuzzy Lied bewegt + Fuzzy {0}h {1}m {2}s @@ -1493,18 +1554,22 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Benutzung ALLER MODULE für Kanal {0} verboten. + Fuzzy Benutzung ALLER MODULE für Kanal {0} erlaubt. + Fuzzy Erlaubt Benutzung ALLER MODULE für die Rolle {0} verboten. + Fuzzy Benutzung ALLER MODULE für die Rolle {0} erlaubt. + Fuzzy Benutzung ALLER MODULE für diesen Server verboten. @@ -1514,9 +1579,11 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Benutzung ALLER MODULE für den Benutzer {0} verboten. + Fuzzy Benutzung ALLER MODULE für den Benutzer {0} erlaubt. + Fuzzy {0} mit ID {1} wurde zur Sperrliste hinzugefügt @@ -1526,18 +1593,22 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Befehl {0} hat keine Abklingzeit mehr und alle laufenden Abklingzeiten wurden entfernt. + Fuzzy Keine Befehls Abklingzeiten gesetzt. Preis für Befehle + Fuzzy Benutzung von {0} {1} wurde für Kanal {2} verboten. + Fuzzy Benutzung von {0} {1} wurde für Kanal {2} erlaubt. + Fuzzy Verweigert @@ -1547,6 +1618,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Liste der gefilterten Wörter + Fuzzy Wort {0} von der Liste der gefilterten Wörter entfernt. @@ -1683,12 +1755,15 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Verlorene Competitives + Fuzzy Gespielte Competitives + Fuzzy Competitive Rang + Fuzzy Gewonnene Competitives @@ -1743,6 +1818,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Bildersuche für: + Fuzzy Konnte diesen Film nicht finden. @@ -1786,9 +1862,11 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Pausierte + Fuzzy Ursprüngliche Url + Fuzzy Ein osu! API-Schlüssel wird benötigt. @@ -1816,15 +1894,18 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Profil Link: + Fuzzy Qualität Quick Spielzeit + Fuzzy Gewonnene Quicks + Fuzzy Bewertung @@ -1834,12 +1915,14 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Suche nach: + Fuzzy Url konnte nicht gekürzt werden Kurze Url + Fuzzy Etwas lief schief. @@ -1852,6 +1935,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Geschäfts Url + Fuzzy Streamer {0} ist jetzt offline. @@ -1921,6 +2005,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Wind Geschwindigkeit + Fuzzy Die {0} meist gebannten Champions @@ -1938,6 +2023,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Aktivitäten Liste #{0} + Fuzzy {0} totale Benutzer. @@ -1956,12 +2042,14 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Thema des Kanals + Fuzzy Befehle ausgeführt Commands ran 9 -^used like that in .stats +^used like that in .stats +Fuzzy {0} {1} ist gleich zu {2} {3} @@ -1977,6 +2065,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Erstellt am + Fuzzy Betritt Multi-Server-Kanal. @@ -1989,6 +2078,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Benutzerdefinierte Emojis + Fuzzy Fehler @@ -2007,6 +2097,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Sie haben keine Berechtigung diesen Befehl auf Rollen mit vielen Nutzern zu benutzen um Missbrauch zu verhindern. + Fuzzy Ungültiger {0} Wert. @@ -2017,17 +2108,20 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Server beigetreten + Fuzzy ID: {0} Mitglieder: {1} ID des Besitzers: {2} + Fuzzy Keine Server auf dieser Seite gefunden. Liste der Wiederholer + Fuzzy Mitglieder @@ -2040,6 +2134,7 @@ ID des Besitzers: {2} Nachrichten Wiederholer + Fuzzy Name @@ -2099,6 +2194,7 @@ ID des Besitzers: {2} Registriert an + Fuzzy Ich werde {0} erinnern {1} in {2} `({3:d.M.yyyy.} um {4:HH:mm})` zu tun. @@ -2114,6 +2210,7 @@ ID des Besitzers: {2} Liste der Wiederholungen + Fuzzy Auf diesem Server laufen keine Wiederholer. @@ -2150,12 +2247,14 @@ ID des Besitzers: {2} Server Info + Fuzzy Shard Shard Statistiken + Fuzzy Shard **#{0}** ist im {1} status mit {2} Servern @@ -2171,6 +2270,7 @@ ID des Besitzers: {2} Text Kanäle + Fuzzy Hier ist Ihr Raum link @@ -2187,6 +2287,43 @@ ID des Besitzers: {2} Sprach Kanäle + Fuzzy + + + Sie sind diesem Rennen schon beigetreten! + + + Aktuelle Umfragewerte + + + Keine Abstimmungen eingereicht. + + + Eine Umfrage läuft bereits auf diesem Server. + + + 📃 {0} hat eine Umfrage erstellt die Ihre Aufmerksamkeit benötigt: + + + `{0}.` {1} mit {2} Abstimmungen. + + + {0} stimmte ab. + Kwoth voted. + + + Senden Sie mir eine Private Nachrciht mit der entsprechenden Nummer der Antwort. + Fuzzy + + + Senden Sie hier eine Nachricht mit der entsprechenden Nummer der Antwort. + + + Danke für das Abstimmen. {0} + + + {0} totale Abstimmungen eingereicht. + Fuzzy \ No newline at end of file From 4fc75f99b4c4508630ae61c4b72e67f7006bb205 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 6 Mar 2017 17:07:26 +0100 Subject: [PATCH 457/746] Update ResponseStrings.ja-JP.resx (POEditor.com) --- .../Resources/ResponseStrings.ja-JP.resx | 491 ++++++++++++------ 1 file changed, 318 insertions(+), 173 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx b/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx index 1261856c..fdfc3df1 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx @@ -118,35 +118,37 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - その基盤はすでに主張されている。または破壊されました。 - + そのベースはもう要求・破壊されました。 - ベースが破壊されました - + そのベースはもう破壊されました。 - その基地は主張されていない。 - + そのベースは要求されていません。 - {1}との戦いで基地#{0}を**破壊**しました + {1}との対戦でベース#{0}を**破壊**しました。 - + {0}は{2}との戦いで、未請求の塩基番号{1}を持っています + + Fuzzy - + {0}は{2}との戦いで塩基番号{1}を主張しました + - + @ {0}あなたはすでに基本番号{1}を主張しています。あなたは新しいものを請求することはできません。 + - + {1}との戦争で@ {0}からの申し立てが終了しました。 + + The English wording is wrong. - 敵 - + {0} との戦争に関する情報 @@ -182,8 +184,7 @@ サイズ - 戦争の戦い{0}は既に始まった。 - + {0}に対する大戦が既に始まった。 戦争{0}が作成されました。 @@ -210,7 +211,8 @@ - + 権限が不十分です。グローバルカスタム反応のために必要なボットの所有権、サーバーカスタム反応の管理者。 + すべてのカスタム反応をリストします。 @@ -227,6 +229,7 @@ カスタム反応が見つかりませんでした。 + Fuzzy その識別情報でカスタム反応が見つかりませんでした。 @@ -240,102 +243,132 @@ - + {0}カスタム反応の統計がクリアされました。 + - + そのトリガーの統計は見つかりませんでした。 + 引き金 - + NSFWが停止しました + 結果が見つかりません - + {0}は既に気絶しています。 + - + {0}健康は既に最大です + - + あなたはすでに{0}です + - - Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + {4}ダメージのために{2} {3}に{0} {1}を使用しました。 + + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. +Fuzzy - + あなたは報復せずに再び攻撃することはできません! + - + あなた自身を攻撃することはできません。 + - + {0}が気絶しました! + - + 1つの{1}で{0}を回復しました + - + {0}は{1} HPが残っています。 + - + {0}を使用することはできません。 `{1} ml`と入力すると、使用できる移動のリストが表示されます。 + - + {0}タイプの攻撃リスト + - + それは効果的ではありません。 + - + あなたに十分な{0}がありません。 + - + 1つの{1}で復活{0} + - + 1つの{0}のために癒された + - + あなたのタイプは{1}のために{0}に変更されました + - + それはやや有効です。 + - + それは超効果的です! + - + あなたは連続してあまりにも多くの動きを使用したので、移動することはできません! + - + タイプ{0}は{1}です。 + - + ユーザーが見つかりません。 + - + あなたが気絶したので、動かすことはできません。 + - + **ユーザー割り当ての**役割を自動割り当て**が無効**になりました。 + - + **ユーザー割り当ての**役割を自動割り当て**が現在有効になっています**。 + 接続 - + 画像が変更されました。 + - + あなたは{0}サーバーから追放されました。 +理由:{1} 亡命 @@ -343,306 +376,377 @@ ユーザーはBANNED + Fuzzy - + ボット名が{0}に変更されました + - + ボットのステータスが{0}に変更されました + - + byeメッセージの自動削除が無効になっています。 + - + Byeメッセージは{0}秒後に削除されます。 + - + 現在の離脱メッセージ:{0} + - + {0}と入力して休暇メッセージを有効にする + - + 新しい出発メッセージセット。 + - + 出発アナウンスが無効になりました。 + - + このチャンネルで有効になっている出発発言。 + - + チャンネル名が変更されました。 + 古称 - + チャネルトピックが変更されました + - + クリーンアップ + コンテント - + 正常に作成されたロール - + 正常に作成されたロール - + 音声チャネル{0}が作成されました。 - + 聴覚障害者は成功です。 - + 削除されたサーバー{0} + - + 成功したコマンド呼び出しの自動削除を停止しました。 + + Invocations* not invokations - + これで正常に実行されたコマンド呼び出しが自動的に削除されます。 + - + テキストチャネル{0}が削除されました。 + - + 音声チャネル{0}が削除されました。 + タイレクトメッセージガ - + 新しい寄付者を追加しました。このユーザーから寄付された金額:{0} + - + このプロジェクトを実現するために、下記の人々に感謝します! + - + 私はDMをすべての所有者に転送します。 - + 私は最初の所有者にDMを転送します。 - + 私は今からDMを転送します。 + - + 私は今からDMを転送するのをやめます。 + - + 挨拶メッセージの自動削除が無効になっています。 + - + {0}秒後にメッセージが削除されます。 + - + 現在のDM挨拶メッセージ:{0} + - + {0}を入力してDM greetメッセージを有効にする + - + 新しいDMはメッセージセットを迎える。 + - + DMのお知らせを無効にする - + DMのお知らせを有効にしました。 - + 現在の挨拶メッセージ:{0} + - + {0}と入力してgreetメッセージを有効にする + - + 新しい挨拶メッセージセット。 - + お知らせを無効にしました。 - + このチャンネルでアナウンスを有効にします。 - + このコマンドは、役割階層内の役割以上のユーザーに対しては使用できません。 - + {0}秒後に画像が読み込まれました! - + 入力フォーマットが無効です。 - + パラメータが無効です。 - + {0}は{1}に参加しました - + あなたは{0}サーバーから蹴られました。 +理由:{1} - + ユーザーが蹴った + Fuzzy - + 言語一覧 +{0} + Fuzzy - + サーバーのロケールが{0} - {1}になりました + - + Botのデフォルトのロケールは{0} - {1}になりました + - + Botの言語は{0} - {1}に設定されています + - + ロケールの設定に失敗しました。このコマンドのヘルプに戻ってください。 - + このサーバーの言語は{0}〜{1}に設定されています + - + {0}さんが{1}を去りました - + {0}サーバーを去った - + このチャネルに{0}イベントを記録します。 - + このチャンネルのすべてのイベントを記録します。 - + ロギングが無効です - + 購読可能なイベントを記録する: - + ロギングは{0}を無視します {0} - + ロギングは{0}を無視しません {0} - + ログに記録された{0}イベントが停止しました。 + - + {0}は次の役割についての言及を呼び出しました + - + {0} `[Bot Owner]`からのメッセージ: + - + メッセージが送信されました。 + - + {0}は{1}から{2}に移動しました + - + #{0}でメッセージが削除されました + - + #{0}で更新されたメッセージ + Fuzzy ミュート中 - PLURAL (users have been muted) -Fuzzy + PLURAL (users have been muted) - ミュート中 + ミュート + singular "User muted." - + 私はそれに必要な許可を持っていません。 + - + 新しいミュートロールセット。 + - + 管理の権利が必要となります。 - + 新しいメッセージ + Is this: make a new message or、 there is a new message? +Fuzzy - + 新しいニックネーム + Fuzzy - + 新しいトピック + Fuzzy - + ニックネームが変更されました + Fuzzy - + そのサーバーを見つけることができません + - + そのIDのシャードは見つかりませんでした。 + - + 古いメッセージ + Fuzzy - + 古いニックネーム + Fuzzy - + 古いトピック + Fuzzy - + エラー。ほとんどの場合、十分な権限がありません。 + - + このサーバーのアクセス許可はリセットされます。 + - + アクティブな保護 + - + このサーバーで{0}は**無効**になっています。 + - + {0}を有効にしました + - + 保護は有効になっていません。 + - + ユーザーのしきい値は{0}から{1}の間でなければなりません。 + - + {0}以上のユーザーが{1}秒以内に参加する場合は、{2}それらを行います。 + - + 時刻は{0}〜{1}秒の間でなければなりません。 + - + ユーザー{0}からすべてのロールを削除しました + - + ロールを削除できませんでした。私には十分な権限がありません。 + - + {0}ロールの色が変更されました。 + - + その役割は存在しません。 + - + 指定されたパラメータは無効です。 + @@ -699,10 +803,10 @@ Fuzzy - + 自分に割り当てられるロールが{0}個あります。 - + そのロールは自分に割り当てられません。 @@ -726,7 +830,7 @@ Fuzzy - + ロールの追加に失敗しました。アクセス権が足りません。 @@ -810,19 +914,19 @@ Fuzzy - + 利用者が去った - + 利用者にロールを追加した - + 利用者のロールを削除した - + {0}さんは今{1}になった @@ -1359,7 +1463,8 @@ Fuzzy - + 曲が終わった + Fuzzy @@ -1392,16 +1497,17 @@ Fuzzy - + 曲名 - + プレイ中 + Fuzzy - + 検索結果なし @@ -1437,10 +1543,11 @@ Fuzzy - + 次に聞く曲一覧 + Does this mean "the song was added to the queue" ? @@ -1614,7 +1721,7 @@ Fuzzy - + Short of seconds. @@ -1627,7 +1734,7 @@ Fuzzy - + 編集不可能 @@ -1784,7 +1891,7 @@ Fuzzy - + 最低/最高 @@ -1796,7 +1903,8 @@ Fuzzy - + 元のURL + Fuzzy @@ -1823,7 +1931,8 @@ Fuzzy - + プロファイルへのリンク + Fuzzy @@ -1838,10 +1947,11 @@ Fuzzy - + スコア: - + 検索: + Fuzzy @@ -2030,22 +2140,23 @@ Fuzzy - + 中継器一覧 + Fuzzy - + メンバー - + メッセージ - + 名前 @@ -2066,10 +2177,10 @@ Fuzzy - + オーナー - + オーナーのID @@ -2096,7 +2207,7 @@ Fuzzy - + 地域 @@ -2126,13 +2237,13 @@ Fuzzy - + 結果 - + 役割 - + このサーバーにある役割一覧のページ{0} @@ -2180,14 +2291,48 @@ Fuzzy - + {1}の{0}は{2} Id of the user kwoth#1234 is 123123123123 - + 利用者 + + + + + + + + + + + + + + + + + + + + + Kwoth voted. + + + + + + + + + + + + + \ No newline at end of file From 2dff5d9883ecabddd8841c0979e01ddadbbc7d01 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 6 Mar 2017 17:07:29 +0100 Subject: [PATCH 458/746] Update ResponseStrings.nb-NO.resx (POEditor.com) --- .../Resources/ResponseStrings.nb-NO.resx | 445 ++++++++++-------- 1 file changed, 238 insertions(+), 207 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx b/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx index 1bdd9412..104eb49a 100644 --- a/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx +++ b/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Den basen har allerede blitt tatt over eller ødelagt. @@ -130,7 +130,7 @@ **ØDELAGT** base #{0} i en krig mot {1} - + {0} har **hevdet** bare #{1} i en krig mot {2} {0} har hevdet en base #{1} i en krig mot {2} @@ -200,7 +200,7 @@ Utilstrekkelig tilgang. Krever Bot-eierskap for globale tilpassede reaksjoner, og Administrator for server reaksjoner. - Liste av alel tilpassede reaksjoner. + Liste av alle tilpassede reaksjoner. Tilpassede reaksjoner. @@ -1053,7 +1053,7 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Fuzzy - + Skriv '{0}cmds ModulNavn' for og få en liste av kommandoer i den modulen. f.eks '{0}cmds spill' Den modulen finnes ikke. @@ -1374,35 +1374,35 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. {0} mot {1} - + Forsøker å sette i kø {0} sanger... Automatisk avspilling deaktivert - Automatisk spilling aktivert. + Automatisk avspilling aktivert. - Standard volume satt til {0}% + Standard volum satt til {0}% - + Mappelisting ferdig. - + fairplay Sang ferdig Fuzzy - + Rettferdig avspilling deaktivert - + Rettferdig avspilling aktivert - Fra possisjon + Fra posisjon Id @@ -1417,10 +1417,10 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Max spilletid satt til {0} sekund(er). - Max musikkkø størrelse satt til uendelig. + Max musikk-kø størrelse satt til uendelig. - Max musikkkø størrelse satt til {0} sang(er). + Max musikk-kø størrelse satt til {0} sang(er). Du må være i en talekanal på denne serveren. @@ -1450,7 +1450,7 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Fuzzy - #{0}` - **{1}** av *{2}* ({3} sanger) + #{0}` - **{1}** av *{2}* ({3} sanger) Side {0} av lagrede spillelister @@ -1460,7 +1460,7 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Spilleliste slettet. - Klarte ikke og slette spillelisten. Enten eksisterer den ikke, eller så var det ikke du som lagde den. + Klarte ikke å slette spillelisten. Enten eksisterer den ikke, eller så var det ikke du som lagde den. Spilleliste med den IDen eksisterer ikke. @@ -1473,7 +1473,7 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Fuzzy - {0}er grense + {0}s grense @@ -1493,28 +1493,28 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. context: "removed song #5" - + Repeterer nåværende sang - + Repeterer spilleliste - + Repeterer spor - + Repetisjon av nåværende sang stoppet - Musikk-avspilling startet + Musikk-avspilling gjenopptatt. - + Repetisjon av spilleliste stoppet. - + Repetisjon av spilleliste startet. - + Meldinger om sanger som spilles av, er ferdige, pauset og fjernet vil bli vist i denne kanalen. Skippet til '{0}:{1}' @@ -1542,21 +1542,21 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Volum satt til {0}% - Deaktivert bruk av ALLE MODULER på {0} kanalen. + Deaktivert bruk av ALLE MODULER i kanalen {0}. Fuzzy - Aktivert bruk av ALLE MODULER på {0} kanalen. + Aktivert bruk av ALLE MODULER i kanalen {0}. Fuzzy Tillatt - Deaktivert bruk av ALLE MODULER for {0} rolle. + Deaktivert bruk av ALLE MODULER for {0} rollen. - Aktivert bruk av ALLE MODULER for {0} rolle. + Aktivert bruk av ALLE MODULER for {0} rollen. Deaktivert bruk av ALLE MODULER på denne serveren. @@ -1565,19 +1565,19 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Aktivert bruk av ALLE MODULER på denne serveren. - Deaktivert bruk av ALLE MODULER for {0} bruker. + Deaktivert bruk av ALLE MODULER for bruker {0}. - Aktivert bruk av ALLE MODULER for {0} bruker. + Aktivert bruk av ALLE MODULER for bruker {0}. Svartelistet {0} med ID {1} - Kommando {0} har nå en {1}'s ventetid. + Kommando {0} har nå en {1}s ventetid. - Kommando {0} har ingen ventetid nå og alle eksisterende ventetider har blitt fjernet. + Kommando {0} har ingen ventetid og alle eksisterende ventetider har blitt fjernet. Ingen kommando-ventetid satt. @@ -1592,7 +1592,7 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Aktivert bruk av {0} {1} i kanal {2}. - Benektet + Nektet La til ordet {0} til listen av filtrerte ord. @@ -1622,7 +1622,7 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Flyttet tillatelse {0} fra #{1} til #{2} - Finner ikke tillatelse til index #{0} + Finner ikke tillatelse ved index #{0} Ingen kostnader satt. @@ -1636,13 +1636,13 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Gen. (of module) - Rettigheter side {0} + Tillatelser side {0} - Nåværende rettighets-rolle er {0}. + Nåværende tillatelses-rolle er {0}. - Brukere må nå ha {0} rollen for og endre rettigheter. + Brukere må nå ha {0} rollen for å endre tillatelser. Ingen tillatelse funnet på denne indeksen. @@ -1657,7 +1657,7 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Aktivert bruk av {0} {1} for {2} rollen. - + sek. Short of seconds. @@ -1667,7 +1667,7 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Aktivert bruk av {0} {1} på denne serveren. - + Fjernet {0} med ID {1} fra svartelisten uredigerbar @@ -1679,10 +1679,10 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Aktivert bruk av {0} {1} for {2} bruker. - Jeg vil ikke lenger vise tillatelse advarsler. + Jeg vil ikke lenger vise tillatelses-advarsler. - Jeg vil nå vise rettighets-advarsler. + Jeg vil nå vise tillatelses-advarsler. Ord filtrering er deaktivert i denne kanalen. @@ -1700,16 +1700,16 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Ferdigheter - + Ingen favoritt anime Startet automatisk oversettelse av meldinger i denne kanalen. Bruker-meldinger vil bli slettet automatisk. - + Ditt automatisk oversatte språk er fjernet - + Ditt automatisk oversatte språk er satt til {0}>{1} Startet automatisk oversettelse av meldinger i denne kanalen. @@ -1742,7 +1742,7 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Konkurrerende rangering - + Konkurerende vinn Fullført @@ -1772,16 +1772,16 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Eksempel - + Kunne ikke finne anime. - + Kunne ikke finne manga - Sjangere + Sjangre - + Fant ingen definisjon for det ordet Høyde/vekt @@ -1802,32 +1802,32 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Ugyldig kilde- eller målspråk. - Vitser ikke lastet. + Kunne ikke laste vitser. - + Bred./Lengd. Nivå - + Liste over {0}place stikkord Don't translate {0}place Plassering - + Magiske ting ble ikke lastet - + {0} sin MAL profil - Bot eieren ikke spesifisere MashapeApiKey. Du kan ikke bruke denne funksjonaliteten. + Bot eieren har ikke spesifiser MashapeApiKey. Du kan ikke bruke denne funksjonen. - Min/Max + Min/Max Ingen kanal funnet. @@ -1854,7 +1854,7 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Bruker ikke funnet! Vennligst sjekk regionen og BattleTag før du prøver igjen. - Planlegg å se + Planlegger å se Plattform @@ -1881,7 +1881,7 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Vurdering - + Resultat: Søk etter: @@ -1923,7 +1923,7 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Strømmen eksisterer sannsynligvis ikke. - Fjernet {0} sin stream ({1}) fra varslinger. + Fjernet {0} sin strøm ({1}) fra varslinger. Jeg vil varsle denne kanalen når statusen endres. @@ -1941,7 +1941,7 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Tittel: - + Topp 3 favoritt animer: Oversettelse: @@ -1953,13 +1953,13 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Kunne ikke finne definisjonen for dette ordet. - + URL - Seerne + Seere - + Ser på Kunne ikke finne det ordet på den angitte Wikia. @@ -1977,13 +1977,13 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. De {0} mest forbydde 'champions' - + Kunne ikke 'yodify' setningen din Ble med - + `{0}.` {1} [{2:F2}/s] - {3} totalt /s and total need to be localized to fit the context - `1.` @@ -1997,13 +1997,13 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Forfatter - + BOT ID - Liste over funksjoner i {0}calc kommandoer + Liste over funksjoner i {0}calc kommandoen - {0} av denne kanalen er {1} + denne kanalens {0} er {1} Kanal emne @@ -2024,13 +2024,13 @@ Ikke glem å skrive Discord navnet eller ID i meldingen. Kan ikke konvertere {0} til {1}: typer enheter er ikke lik - laget på + Laget på Ble med i kanalen for snakk på tvers av servere - Forlatt kanalen for snakk på tvers av servere + Forlot kanalen for snakk på tvers av servere Dette er din CSC token @@ -2075,7 +2075,7 @@ Eier ID: {2} Ingen servere funnet på denne siden. - Liste over repeater + Liste over gjentagende meldinger Medlemmer @@ -2087,7 +2087,7 @@ Eier ID: {2} Meldinger - + Meldingsgjentager Navn @@ -2099,7 +2099,7 @@ Eier ID: {2} Det er ingen som spiller det spillet. - Det er ingen aktive repeatere. + Det er ingen aktive gjentagere. Det er ingen roller på denne siden. @@ -2114,7 +2114,7 @@ Eier ID: {2} Eier - Eier Identiteter + Eier IDer Tilstedeværelse @@ -2125,10 +2125,10 @@ Eier ID: {2} {2} Talekanaler - Slettet alle sitater med {0} nøkkelord. + Slettet alle sitater med nøkkelordet `{0}`. - Side {0} av sitater + Side {0} med sitater Det er ingen sitater på denne siden. @@ -2146,31 +2146,31 @@ Eier ID: {2} Region - Registrert på + Registrert den - Jeg vil minne på {0} til {1} i {2} `({3:. D.M.ÅÅÅÅ} ved {4:TT:mm})` + Jeg vil minne på {0} til {1} i {2} `({3:. d.M.yyyy} ved {4:HH:mm})` Ikke et gyldig format. Sjekk kommandolisten. - + Ny påminnelses-mal satt - Repeterer {0} {1} hver dag(er), {2} time(r) og {3} minutt(er). + Gjentar {0} hver {1} dag(er), {2} time(r) og {3} minutt(er). - + Liste over gjentagere - + Ingen gjentagere kjører på denne serveren #{0} stoppet. - + Ingen gjentagende meldinger funnet på denne serveren. Resultat @@ -2185,13 +2185,13 @@ Eier ID: {2} Side #{0} av roller for {1} - Ingen farger er i riktig format. Bruk `#00ff00` for eksempel. + Ingen farger er i riktig format. Bruk for eksempel `#00ff00`. - Startet rotering av {0} rolle farge. + Startet rotering av {0} rollens farge. - Stoppet rotering av farger for {0} rolle + Stoppet rotering av farger for {0} rollen {0} av denne serveren er {1} @@ -2200,13 +2200,13 @@ Eier ID: {2} Server info - + Shard - + Shard status - + Shard **#{0}** sin status: {1} med {2} servere **Navn:** {0} **Link:** {1} @@ -2215,7 +2215,7 @@ Eier ID: {2} Ingen spesielle emojier funnet. - Spiller {0} sanger, {1} kø. + Spiller {0} sanger, {1} i kø. Tekst kanaler @@ -2239,5 +2239,36 @@ Eier ID: {2} Du har allerede sluttet deg til dette løpet! + + Foreløpige stemmeresultater + + + Ingen stemmer samlet + + + Det kjøres allerede en avstemming på serveren. + + + 📃 {0} har startet en avstemming som krever din oppmerksomhet: + + + `{0}.` {1} med {2} stemmer. + + + {0} stemte. + Kwoth voted. + + + Send meg en privat melding med korresponderende antall svar. + + + Send en melding her med tilsvarende nummer til ditt svar. + + + Takk for at du stemte, {0} + + + {0} totalt stemmer avgitt. + \ No newline at end of file From 1fbd537c17f4ce60520ff1a7acf50248f7f94f02 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 6 Mar 2017 17:07:32 +0100 Subject: [PATCH 459/746] Update ResponseStrings.pl-PL.resx (POEditor.com) --- .../Resources/ResponseStrings.pl-PL.resx | 424 ++++++++++-------- 1 file changed, 228 insertions(+), 196 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx index 665f605b..eb8b202b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Ta baza została już zdobyta lub zniszczona. @@ -194,28 +194,28 @@ - + Własne reakcje zostały usunięte - + Lista własnych reakcji - + Własne reakcje - + Nowe własne reakcje - + Własne reakcje nie zostały znalezione. - + Własne reakcje z tym ID nie zostały znalezione. - + Odpowiedź @@ -230,7 +230,7 @@ - + Zatrzymano autohentai. Brak rezultatów. @@ -404,31 +404,31 @@ Powód: {1} Dziękuję ludziom wypisanym na dole za pomoc w realizacji tego projektu! - + Wyślę prywatne wiadomości do wszystkich właścicieli. - + Wyślę prywatną wiadomość tylko do pierwszego właściciela. - + Od teraz będę wysyłać prywatne wiadomości. - + Od teraz nie będę wysyłać prywatnych wiadomości. - + Wiadomości powitalne będą usuwane po {0} sekundach. - + Aktualna prywatna wiadomość powitalna: {0} - + Aby włączyć prywatną wiadomość powitalną, wpisz {0} - + Nowa prywatna wiadomość powitalna została ustawiona. @@ -440,16 +440,16 @@ Powód: {1} Aktualna wiadomość powitalna: {0} - + Włącz wiadomości powitalne wpisując {0} - + Nowa wiadomość powitalna ustawiona. - + Ogłoszenie powitalne wyłączone. - + Ogłoszenie powitalne włączone na tym kanale. Nie możesz użyć tej komendy na użytkowniku z rolą wyższą lub równą twojej. @@ -498,7 +498,7 @@ Powód: {1} {0} opuścił {1} - + Opuścił serwer {0} @@ -525,7 +525,7 @@ Powód: {1} - + Wiadomość od {0} `[Właściciel bota]`: Wiadomość została wysłana. @@ -534,10 +534,10 @@ Powód: {1} {0} przeniesiono z {1} do {2} - + Wiadomość usunięta w #{0} - + Wiadomość zaktualizowana w #{0} Wyciszony @@ -548,7 +548,7 @@ Powód: {1} singular "User muted." - + Nie mam wystarczających uprawnień aby to zrobić. @@ -576,7 +576,7 @@ Powód: {1} Serwer nie został znaleziony. - + Żaden shard z tym ID nie został znaleziony. Stara wiadomość @@ -600,13 +600,13 @@ Powód: {1} - + {0} został **wyłączony** na tym serwerze. - + {0} włączone - + Wystąpił błąd. Potrzebuję uprawnień zarządzania rolami @@ -615,7 +615,7 @@ Powód: {1} - + Jeśli {0} lub więcej użytkowników dołączy w ciągu {1} sekund, {2} ich. Czas musi być pomiędzy {0} a {1} sekundą. @@ -633,13 +633,13 @@ Powód: {1} Ta rola nie istnieje. - + Wyszczególnione parametry są błędne - + Wystąpił błąd w związku z błędnym kolorem albo niewystarczającymi uprawnieniami. - + Z powodzeniem usunięto rolę {0} użytkownikowi {1} Wystąpił błąd przy usunięciu roli. Masz niewystarczające uprawnienia. @@ -663,10 +663,10 @@ Powód: {1} - + Rola {0} jest już na liście. - + Dodano. @@ -687,7 +687,7 @@ Powód: {1} - + Role, które można nadawać sobie samemu, są teraz ekskluzywne. Istnieje {0} ról, które możesz sam sobie nadać. @@ -699,7 +699,7 @@ Powód: {1} Nie posiadasz roli {0} - + Role, które można nadawać sobie samemu, nie są już ekskluzywne. Nie jestem w stanie nadać ci tej roli. `Nie mogę nadawać ról wyższych niż moja.` @@ -708,7 +708,7 @@ Powód: {1} Rola {0} została usunięta z listy ról, które użytkownik może sobie nadać sam. - + Nie masz więcej roli {0} Masz teraz rolę {0}. @@ -726,34 +726,34 @@ Powód: {1} Nowa nazwa kanału została ustawiona! - + Nowa gra ustawiona! - + Nowy stream ustawiony! - + Nowy temat kanału ustawiony. - + Shard {0} połączony ponownie. - + Shard {0} łączy się ponownie. - + Wyłączanie. Użytkownik nie może wysłać więcej niż {1} wiadomości na {1} sekund. - + Slow mode wyłączony. - + Slow mode włączony - + lekko zbanowany (wyrzucony) PLURAL @@ -763,19 +763,20 @@ Powód: {1} {0} nie będzie więcej ignorował tego kanału. - + Jeśli użytkownik napisze {0} takich samych wiadomości pod rząd, {0} go. + __IgnorowaneKanały__: {2} - + Kanał tekstowy został stworzony. - + Kanał tekstowy został usunięty. - + Odciszony singular @@ -793,31 +794,31 @@ Powód: {1} Fuzzy - + {0} został **wyciszony** z chatowania. - + {0} został **odciszony** z chatowania. - + Użytkownik dołączył - + Użytkownik wyszedł - + {0} został **wyciszony** z chatu głosowego i pisanego. - + Rola użytkownika dodana - + Rola użytkownika usunięta {0} jest teraz {1} - + {0} został **odciszony** z chatu głosowego i pisanego. {0} dołączył do kanału {1}. @@ -829,10 +830,10 @@ Powód: {1} {0} przeniesiony z kanału {1} na {2} - + {0} został **wyciszony z chatu głosowego**. - + {0} został **odciszony z chatu głosowego**. Kanał głosowy został stworzony @@ -843,28 +844,28 @@ Powód: {1} Fuzzy - + Wyłączono funkcję głos + tekst. - + Włączono funkcję głos + tekst. - + Nie mam uprawnień: **zarządzanie rolami** i **zarządzanie kanałami**, więc nie mogę uruchomić funkcji `głos+tekst` na serwerze {0}. - + Włączasz/Wyłączasz tą funkcję i **Nie mam uprawnień ADMINISTRATORA**. Może to spowodować problemy i będziesz musiał czyścić kanały tekstowe sam. - + Użytkownik {0} z tekstowego czatu - + Użytkownik {0} z tekstowego i głosowego czatu - Użytkownik {0} z kanału głosowego + Użytkownik {0} z czatu głosowego Zostałeś tymczasowo zablokowany na serwerze {0} @@ -934,7 +935,7 @@ Powód: {1} Ranking - + Nagrodził {0} dla {1} użytkowników z roli {2} Nie możesz założyć się o więcej niż {0} @@ -1229,7 +1230,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + {0} wygrał! {1} pokonuje {2} @@ -1352,7 +1353,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś {0} kontra {1} - + Próba dołączenia {0} piosenek do kolejki... Automatyczne odtwarzanie wyłączone. @@ -1367,16 +1368,16 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + fairplay Zakończono odtwarzanie piosenki - + Fair play wyłączony. - + Fair play włączony. @@ -1464,7 +1465,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś context: "removed song #5" - + Powtarzanie aktualnego utworu Powtarzenie playlisty @@ -1497,7 +1498,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Utwór przeniesiony - + {0}g {1}m {2}s @@ -1625,7 +1626,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + sek. Short of seconds. @@ -1755,7 +1756,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Wysokość/szerokość - + {0}m/{1}kg Wilgotność @@ -1798,7 +1799,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Nie znaleziono kanału. Brak rezultatów. @@ -2205,5 +2206,36 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Już dołączyłeś do tego wyścigu! + + + + + + + + + + + + + + + + + + Kwoth voted. + + + + + + + + + + + + + \ No newline at end of file From 5c8c2a0db9797036c70530ef009f41731d4b831a Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 6 Mar 2017 17:07:35 +0100 Subject: [PATCH 460/746] Update ResponseStrings.pt-BR.resx (POEditor.com) --- .../Resources/ResponseStrings.pt-BR.resx | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx index bac83942..5502e166 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx @@ -140,6 +140,7 @@ O pedido de guerra de @{0} contra {1} expirou. + Fuzzy Inimigo @@ -153,9 +154,11 @@ Não é um tamanho de guerra válido. + Fuzzy Lista de guerras ativas + Fuzzy não reivindicado @@ -168,6 +171,7 @@ Nenhuma guerra ativa. + Fuzzy Tamanho @@ -207,6 +211,7 @@ Nenhuma reação personalizada encontrada. + Fuzzy Nenhuma reação personalizada encontrada com este id. @@ -469,10 +474,12 @@ Razão: {1} Usuário Kickado + Fuzzy Lista de Linguagens {0} + Fuzzy A região do seu servidor agora é {0} - {1} @@ -530,9 +537,11 @@ Razão: {1} Mensagem deletada em #{0} + Fuzzy Mensagem atualizada em #{0} + Fuzzy Mutados @@ -553,15 +562,19 @@ Razão: {1} Nova mensagem + Fuzzy Novo Apelido + Fuzzy Novo Tópico + Fuzzy Apelido Alterado + Fuzzy Não posso encontrar esse servidor @@ -571,12 +584,15 @@ Razão: {1} Mensagem Antiga + Fuzzy Apelido Antigo + Fuzzy Tópico Antigo + Fuzzy Erro. Não tenho permissões suficientes. @@ -586,6 +602,7 @@ Razão: {1} Proteções ativadas + Fuzzy {0} foi **desativado** neste servidor. @@ -598,6 +615,7 @@ Razão: {1} Nenhuma proteção ativa. + Fuzzy O limite de usuários deve ser entre {0} e {1}. @@ -758,9 +776,11 @@ __Canais Ignorados__: {2} Canal de Texto Criado + Fuzzy Canal de Texto Destruído + Fuzzy Desensurdecido com sucesso. @@ -774,12 +794,14 @@ __Canais Ignorados__: {2} Nome de usuário alterado + Fuzzy Usuários Usuário Banido + Fuzzy {0} foi **mutado** @@ -789,18 +811,22 @@ __Canais Ignorados__: {2} Usuário juntou-se + Fuzzy Usuário saiu + Fuzzy {0} foi **mutado** nos chats de voz e texto. Cargo do usuário adicionado + Fuzzy Cargo do usuário removido + Fuzzy {0} agora está {1} @@ -825,9 +851,11 @@ __Canais Ignorados__: {2} Canal de voz criado + Fuzzy Canal de voz destruído + Fuzzy Atributo voz + texto desabilitado. @@ -859,6 +887,7 @@ Motivo: {1} Usuário desbanido + Fuzzy Migração concluída! @@ -868,9 +897,11 @@ Motivo: {1} Atualizações de Presença + Fuzzy Usuário Banido Temporariamente + Fuzzy concedeu {0} para {1} @@ -913,6 +944,7 @@ Motivo: {1} Cara + Fuzzy Placar de Líderes @@ -934,6 +966,7 @@ Motivo: {1} Usuário sorteado + Fuzzy Você rolou {0}. @@ -968,6 +1001,7 @@ Dura {1} segundos. Não diga a ninguém. Shhh. Coroa + Fuzzy Tomou {0} de {1} com sucesso @@ -980,6 +1014,7 @@ Dura {1} segundos. Não diga a ninguém. Shhh. Proprietário do bot apenas. + Fuzzy Requer a permissão {0} do canal. @@ -989,9 +1024,11 @@ Dura {1} segundos. Não diga a ninguém. Shhh. Comandos e abreviações + Fuzzy Lista de Comandos Regenerada. + Fuzzy Digite `{0}h NomeDoComando` para ver a ajuda para o comando especificado. Ex: `{0}h >8ball` @@ -1012,12 +1049,15 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. **Lista de Comandos**. <{0}> **Guias de hosteamento e documentos podem ser encontrados aqui**. <{1}> + Fuzzy Lista de Comandos + Fuzzy Lista de Módulos + Fuzzy Digite `{0}cmds NomeDoMódulo` para receber uma lista de comandos deste módulo. Ex: `{0}cmds games` @@ -1030,6 +1070,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Tabela de Conteúdo + Fuzzy Modo de uso @@ -1043,6 +1084,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Corrida de Animais + Fuzzy Falha ao iniciar, não houve participantes suficientes. @@ -1093,9 +1135,11 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. Mudanças no Coração + Fuzzy Reivindicado por + Fuzzy Divórcios @@ -1215,6 +1259,7 @@ O novo valor de {0} é {1}! Submissões Encerradas + Fuzzy A Corrida de Animais já está em andamento @@ -1249,6 +1294,7 @@ O novo valor de {0} é {1}! Jogo Iniciado + Fuzzy Jogo da Forca iniciado @@ -1317,15 +1363,18 @@ O novo valor de {0} é {1}! {0} venceu! + Fuzzy Combinou três + Fuzzy Nenhum movimento restante! Tempo Esgotado! + Fuzzy É a vez de {0} @@ -1353,6 +1402,7 @@ O novo valor de {0} é {1}! Música concluída. + Fuzzy Fair play desativado. @@ -1389,6 +1439,7 @@ O novo valor de {0} é {1}! Tocando agora + Fuzzy Nenhum player de música ativo. @@ -1401,15 +1452,18 @@ O novo valor de {0} é {1}! Fila de Músicas - Página {0}/{1} + Fuzzy Tocando Musica + Fuzzy `#{0}` - **{1}** by *{2}* ({3} músicas) Página {0} de Playlists Salvas + Fuzzy Playlist deletada. @@ -1425,6 +1479,7 @@ O novo valor de {0} é {1}! Playlist Salva + Fuzzy Limite de {0}s @@ -1434,6 +1489,7 @@ O novo valor de {0} é {1}! Músicas em fila + Fuzzy Fila de músicas limpa. @@ -1447,12 +1503,15 @@ O novo valor de {0} é {1}! Repetindo a Música Atual + Fuzzy Repetindo Playlist + Fuzzy Repetindo Faixa + Fuzzy A repetição da faixa atual parou. @@ -1474,9 +1533,11 @@ O novo valor de {0} é {1}! Músicas embaralhadas. + Fuzzy Música movida + Fuzzy {0}h {1}m {2}s @@ -1495,18 +1556,22 @@ O novo valor de {0} é {1}! O uso de TODOS OS MÓDULOS foi desabilitado no canal {0}. + Fuzzy O uso de TODOS OS MÓDULOS foi habilitado no canal {0}. + Fuzzy Permitido O uso de TODOS OS MÓDULOS foi desabilitado para o cargo {0}. + Fuzzy O uso de TODOS OS MÓDULOS foi habilitado para o cargo {0}. + Fuzzy O uso de TODOS OS MÓDULOS foi desabilitado neste servidor. @@ -1516,9 +1581,11 @@ O novo valor de {0} é {1}! O uso de TODOS OS MÓDULOS foi desabilitado para o usuário {0}. + Fuzzy O uso de TODOS OS MÓDULOS foi habilitado para o usuário {0}. + Fuzzy {0} entrou na Lista Negra com o ID {1} @@ -1528,18 +1595,22 @@ O novo valor de {0} é {1}! O comando {0} não possui nenhum cooldown agora e todos os cooldowns existentes foram limpos. + Fuzzy Nenhum cooldown de comando definido. Custos de Comando + Fuzzy Desabilitado o uso de {0} {1} no canal {2}. + Fuzzy Habilitado o uso de {0} {1} no canal {2}. + Fuzzy Negado @@ -1549,6 +1620,7 @@ O novo valor de {0} é {1}! Lista de Palavras Filtradas + Fuzzy A palavra {0} foi removida da lista de palavras filtradas. @@ -1685,12 +1757,15 @@ O novo valor de {0} é {1}! Derrotas Competitivas + Fuzzy Partidas Competitivas jogadas + Fuzzy Rank Competitivo + Fuzzy Vitórias Competitivas @@ -1745,6 +1820,7 @@ O novo valor de {0} é {1}! Busca de Imagens para: + Fuzzy Falha ao encontrar este filme. @@ -1788,9 +1864,11 @@ O novo valor de {0} é {1}! Em espera + Fuzzy Url Original + Fuzzy Requer uma API key de osu! @@ -1818,15 +1896,18 @@ O novo valor de {0} é {1}! Link do Perfil: + Fuzzy Qualidade: Tempo em Partida Rápida + Fuzzy Vitórias em Partida Rápida + Fuzzy Avaliação @@ -1836,12 +1917,14 @@ O novo valor de {0} é {1}! Busca Por: + Fuzzy Falha ao encurtar esse url. Url Curta + Fuzzy Alguma coisa deu errado. @@ -1854,6 +1937,7 @@ O novo valor de {0} é {1}! Url da Loja + Fuzzy Streamer {0} está offline. @@ -1923,6 +2007,7 @@ O novo valor de {0} é {1}! Velocidade do Vento + Fuzzy Os {0} campeões mais banidos @@ -1940,6 +2025,7 @@ O novo valor de {0} é {1}! Página de Atividade #{0} + Fuzzy {0} usuários no total. @@ -1958,9 +2044,11 @@ O novo valor de {0} é {1}! Tópico do Canal + Fuzzy Comandos Utilizados + Fuzzy {0} {1} é igual a {2} {3} @@ -1976,6 +2064,7 @@ O novo valor de {0} é {1}! Criado em + Fuzzy Juntou-se ao canal de servidor cruzado. @@ -1988,6 +2077,7 @@ O novo valor de {0} é {1}! Emojis Personalizados + Fuzzy Erro @@ -2006,6 +2096,7 @@ O novo valor de {0} é {1}! você não tem permissão de usar esse comando em cargos com muitos usuários para prevenir abuso. + Fuzzy Valor {0} inválido. @@ -2016,17 +2107,20 @@ O novo valor de {0} é {1}! Juntou-se ao Servidor + Fuzzy ID: {0} Membros: {1} OwnerID: {2} + Fuzzy Nenhum servidor encontrado nessa página. Lista de Repetidores + Fuzzy Membros @@ -2039,6 +2133,7 @@ OwnerID: {2} Repetidor de Mensagem + Fuzzy Nome @@ -2098,6 +2193,7 @@ OwnerID: {2} Registrado em + Fuzzy Eu lembrarei {0} de {1} em {2} `({3:d.M.yyyy.} at {4:HH:mm})` @@ -2113,6 +2209,7 @@ OwnerID: {2} Lista de Repetidores + Fuzzy Nenhum repetidor neste servidor. @@ -2149,12 +2246,14 @@ OwnerID: {2} Informações do Servidor + Fuzzy Shard Status do Shard + Fuzzy Shard **#{0}** está no estado {1} com {2} servidores @@ -2170,6 +2269,7 @@ OwnerID: {2} Canais de Texto + Fuzzy Aqui está o link da sala: @@ -2186,6 +2286,41 @@ OwnerID: {2} Canais de Voz + Fuzzy + + + Você já entrou nesta corrida! + + + Resultado atual da votação + + + Nenhum voto proferido. + + + Uma votação já está ocorrendo neste servidor. + + + 📃 {0} criou uma votação que requer sua atenção: + + + `{0}.` {1} com {2} votos. + + + {0} votou. + Kwoth voted. + + + Mande uma Mensagem Direta para mim com o número que corresponde à resposta. + + + Mande uma Mensagem aqui com o número que corresponde à resposta. + + + Obrigado por votar, {0} + + + Total de {0} votos proferidos. \ No newline at end of file From 6217491a57aa734275545add84978c384257143f Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 6 Mar 2017 17:07:37 +0100 Subject: [PATCH 461/746] Update ResponseStrings.ru-RU.resx (POEditor.com) --- .../Resources/ResponseStrings.ru-RU.resx | 136 +++++++++++++++++- 1 file changed, 135 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx index 12a8b4d2..20b53a3d 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx @@ -140,6 +140,7 @@ Время действия запроса от @{0} на войну против {1} истёкло. + Fuzzy Враг @@ -152,9 +153,11 @@ Неправильный размер войны. + Fuzzy Список активных войн + Fuzzy не захвачена @@ -167,6 +170,7 @@ Нет активных войн. + Fuzzy Размер @@ -206,6 +210,7 @@ Не найдено настраиваемых реакций. + Fuzzy Не найдено настраиваемых реакций с таким номером. @@ -467,10 +472,12 @@ Пользователь выгнан + Fuzzy Список языков {0} + Fuzzy Язык вашего сервера теперь {0} - {1} @@ -528,9 +535,11 @@ Сообщение удалено в #{0} + Fuzzy Сообщение изменено в #{0} + Fuzzy Заглушены @@ -551,15 +560,19 @@ Новое сообщение + Fuzzy Новое имя + Fuzzy Новый заголовок + Fuzzy Имя изменено + Fuzzy Сервер не найден @@ -569,12 +582,15 @@ Старое сообщение + Fuzzy Старое имя + Fuzzy Старый заголовок + Fuzzy Ошибка. Скорее всего мне не хватает прав. @@ -584,6 +600,7 @@ Активные защиты от рейдов + Fuzzy {0} был **отключён** на этом сервере. @@ -596,6 +613,7 @@ Нет защит от рейдов + Fuzzy Порог пользователей должен лежать между {0} и {1}. @@ -754,9 +772,11 @@ Создан текстовый канал + Fuzzy Уничтожен текстовый канал. + Fuzzy Отключено заглушение. @@ -771,12 +791,14 @@ Fuzzy Имя изменено + Fuzzy Пользователи Пользователь заблокирован + Fuzzy {0} получил **запрет** на разговор в текстовых каналах. @@ -786,18 +808,22 @@ Fuzzy Пользователь присоединился + Fuzzy Пользователь вышел + Fuzzy {0} получил **запрет** на разговор в текстовых и голосовых каналах Добавлена роль пользователя + Fuzzy Удалена роль пользователя + Fuzzy {0} теперь {1} @@ -822,9 +848,11 @@ Fuzzy Голосовой канал создан + Fuzzy Голосовой канал удалён + Fuzzy Отключены голосовые + текстовые функции. @@ -855,6 +883,7 @@ Fuzzy Пользователь разбанен. + Fuzzy Перемещение закончено! @@ -864,9 +893,11 @@ Fuzzy История присутвия пользователей + Fuzzy Пользователя выгнали + Fuzzy наградил {0} пользователю {1} @@ -909,6 +940,7 @@ Fuzzy Орёл + Fuzzy Таблица рекордов @@ -930,6 +962,7 @@ Fuzzy Победитель лотереи + Fuzzy Вам выпало {0}. @@ -963,6 +996,7 @@ Fuzzy Решка + Fuzzy успешно забрал {0} у {1} @@ -975,6 +1009,7 @@ Fuzzy Только для владельца бота + Fuzzy Требуется разрешение канала {0}. @@ -984,9 +1019,11 @@ Fuzzy Команды и альтернативные имена команд + Fuzzy Список команд создан. + Fuzzy Напишите '{0}h ИмяКоманды', чтобы получить справку для этой команды. Например, '{0}h >8ball' @@ -1008,12 +1045,15 @@ Paypal <{1}> **Список команд**: <{0}> **Руководства по установке и документы можно найти здесь**: <{1}> + Fuzzy Список команд + Fuzzy Список модулей + Fuzzy Напишите '{0}cmds ИмяМодуля', чтобы получить список команд в этом модуле. Например, '{0}cmds games' @@ -1026,6 +1066,7 @@ Paypal <{1}> Оглавление + Fuzzy Использование @@ -1039,6 +1080,7 @@ Paypal <{1}> Гонка зверей + Fuzzy Не удалось начать гонку, так как не хватает участников. @@ -1089,6 +1131,7 @@ Paypal <{1}> Смены чувств + Fuzzy Является мужем @@ -1211,6 +1254,7 @@ Paypal <{1}> Приём ответов закончен. + Fuzzy Гонка зверей уже идёт. @@ -1245,6 +1289,7 @@ Paypal <{1}> Игра началась + Fuzzy Игра в Виселицу началась @@ -1313,15 +1358,18 @@ Paypal <{1}> {0} выиграл! + Fuzzy Выстроил 3 в ряд + Fuzzy Ходов не осталось! Время вышло! + Fuzzy Ход {0} @@ -1349,6 +1397,7 @@ Paypal <{1}> Песня завершилась. + Fuzzy Отключено справедливое воспроизведение. @@ -1387,6 +1436,7 @@ Paypal <{1}> Сейчас играет + Fuzzy Нет активного музыкального проигрывателя. @@ -1399,15 +1449,18 @@ Paypal <{1}> Очередь воспроизведения - Страница {0}/{1} + Fuzzy Проигрывается песня + Fuzzy '#{0}' - **{1}** *{2}* ({3} песен) Страница {0} сохранённых плейлистов. + Fuzzy Плейлист удалён. @@ -1423,6 +1476,7 @@ Paypal <{1}> Плейлист сохранён. + Fuzzy Ограничение {0}c @@ -1432,6 +1486,7 @@ Paypal <{1}> Песня добавлена в очередь воспроизведения. + Fuzzy Очередь воспроизведения музыки очищена. @@ -1445,12 +1500,15 @@ Paypal <{1}> Повторяется текущая песня. + Fuzzy Повторяется плейлист. + Fuzzy Повторяется песня. + Fuzzy Повтор текущей песни приостановлен. @@ -1472,9 +1530,11 @@ Paypal <{1}> Песни перемешаны. + Fuzzy Песня перемещена. + Fuzzy {0}ч {1}м {2}с @@ -1493,18 +1553,22 @@ Paypal <{1}> Отключено использование ВСЕХ МОДУЛЕЙ в канале {0}. + Fuzzy Включено использование ВСЕХ МОДУЛЕЙ в канале {0}. + Fuzzy Разрешено Отключено использование ВСЕХ МОДУЛЕЙ для роли {0}. + Fuzzy Включено использование ВСЕХ МОДУЛЕЙ для роли {0}. + Fuzzy Отключено использование ВСЕХ МОДУЛЕЙ на этом сервере. @@ -1514,9 +1578,11 @@ Paypal <{1}> Отключено использование ВСЕХ МОДУЛЕЙ для пользователя {0}. + Fuzzy Включено использование ВСЕХ МОДУЛЕЙ для пользователя {0}. + Fuzzy Добавлено {0} в чёрный список c ID {1} @@ -1526,18 +1592,22 @@ Paypal <{1}> У команды {0} больше нет времени перезарядки и все существующие времена перезадки были сброшены. + Fuzzy У команды не установлено время перезарядки. Стоимость команды + Fuzzy Отключено использование {0} {1} в канале {2} + Fuzzy Включено использование {0} {1} в канале {2} + Fuzzy Отказано @@ -1547,6 +1617,7 @@ Paypal <{1}> Список фильтруемых слов + Fuzzy Слово {0} убрано из списка фильтруемых слов. @@ -1682,12 +1753,15 @@ Paypal <{1}> Поражения в соревновательном режиме + Fuzzy Матчи в соревновательном режиме + Fuzzy Соревновательный ранг + Fuzzy Победы в соревновательном режиме @@ -1742,6 +1816,7 @@ Paypal <{1}> Поиск изображений: + Fuzzy Не удалос найти этот фильм. @@ -1785,9 +1860,11 @@ Paypal <{1}> Ожидание + Fuzzy Оригинальный URL + Fuzzy Требуется ключ osu! API. @@ -1815,16 +1892,19 @@ Paypal <{1}> Ссылка на профиль: + Fuzzy Качество: Время игры в Быстрой Игре - Is this supposed to be Overwatch Quick Play stats? + Is this supposed to be Overwatch Quick Play stats? +Fuzzy Побед в Быстрой Игре + Fuzzy Рейтинг: @@ -1834,12 +1914,14 @@ Paypal <{1}> Искать: + Fuzzy Не удалось укоротить эту ссылку. Короткая ссылка + Fuzzy Что-то пошло не так. @@ -1852,6 +1934,7 @@ Paypal <{1}> Url Магазина + Fuzzy Стример {0} в оффлане. @@ -1921,6 +2004,7 @@ Paypal <{1}> Скорость ветра. + Fuzzy {0} наиболее часто забаненных чемпионов. @@ -1938,6 +2022,7 @@ Paypal <{1}> Страница списка активности #{0} + Fuzzy Всего {0} пользователей. @@ -1956,9 +2041,11 @@ Paypal <{1}> Тема канала + Fuzzy Команд запущено + Fuzzy {0} {1} равно {2} {3} @@ -1974,6 +2061,7 @@ Paypal <{1}> Создано + Fuzzy Присоедился к межсерверному каналу. @@ -1986,6 +2074,7 @@ Paypal <{1}> Серверные emoji + Fuzzy Ошибка @@ -2004,6 +2093,7 @@ Paypal <{1}> Вам запрещено использовать эту комманду в отношении ролей с большим числом пользователей для предотвращения + Fuzzy Неправильное значение {0}. @@ -2014,17 +2104,20 @@ Paypal <{1}> Присоединился к серверу + Fuzzy Имя: {0} Участники: {1} IDВладельца: {2} + Fuzzy На этой странице не найдено серверов. Список повторяемых сообщений + Fuzzy Участники @@ -2037,6 +2130,7 @@ IDВладельца: {2} Повторяемое сообщения + Fuzzy Имя @@ -2096,6 +2190,7 @@ IDВладельца: {2} Зарегистрирован + Fuzzy Я напомню, чтобы {0} сделал {2} '{3:d.M.yyyy.} в {4:HH:mm}' @@ -2111,6 +2206,7 @@ IDВладельца: {2} Список повторяемых сообщений + Fuzzy На этом сервере нет повторяемых сообщений. @@ -2147,12 +2243,14 @@ IDВладельца: {2} Информация о сервере + Fuzzy Shard Статискика Shard-а + Fuzzy Shard **#{0}** находится в состоянии {1} с {2} серверами. @@ -2168,6 +2266,7 @@ IDВладельца: {2} Текстовые каналы + Fuzzy Ссылка на Вашу комнату: @@ -2184,6 +2283,41 @@ IDВладельца: {2} Голосовые каналы + Fuzzy + + + + + + + + + + + + + + + + + + + + + + Kwoth voted. + + + + + + + + + + + + \ No newline at end of file From 763ae7598c1bc2fce4f71df301d0c70f5f1f6a80 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 6 Mar 2017 17:07:40 +0100 Subject: [PATCH 462/746] Update ResponseStrings.sr-cyrl-rs.resx (POEditor.com) --- .../Resources/ResponseStrings.sr-cyrl-rs.resx | 210 +++++++++++++----- 1 file changed, 150 insertions(+), 60 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx index ea90f4b6..5e1f33f3 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx @@ -140,6 +140,7 @@ Захтев од @{0} за рат против {1} је истекао. + Fuzzy Противник @@ -152,9 +153,11 @@ Величина рата није валидна. + Fuzzy Листа Ратова У Току + Fuzzy нема захтева @@ -167,6 +170,7 @@ Нема ратова у току. + Fuzzy Величина @@ -206,6 +210,7 @@ Реакција по избору није нађена. + Fuzzy Није нађена реакција са тим идентификатором. @@ -468,10 +473,12 @@ Reason: {1} User Kicked + Fuzzy List Of Languages {0} + Fuzzy Your server's locale is now {0} - {1} @@ -531,9 +538,11 @@ Reason: {1} Message Deleted in #{0} + Fuzzy Message Updated in #{0} + Fuzzy Muted @@ -554,15 +563,19 @@ Reason: {1} New Message + Fuzzy New Nickname + Fuzzy New Topic + Fuzzy Nickname Changed + Fuzzy Can't find that server @@ -572,12 +585,15 @@ Reason: {1} Old Message + Fuzzy Old Nickname + Fuzzy Old Topic + Fuzzy Error. Most likely I don't have sufficient permissions. @@ -587,6 +603,7 @@ Reason: {1} Active Protections + Fuzzy {0} has been **disabled** on this server. @@ -599,6 +616,7 @@ Reason: {1} No protections enabled. + Fuzzy User threshold must be between {0} and {1}. @@ -758,9 +776,11 @@ Reason: {1} Text Channel Destroyed + Fuzzy Text Channel Destroyed + Fuzzy Undeafen successful. @@ -774,12 +794,14 @@ Reason: {1} Username Changed + Fuzzy Users User Banned + Fuzzy {0} has been **muted** from chatting. @@ -789,18 +811,22 @@ Reason: {1} User Joined + Fuzzy User Left + Fuzzy {0} has been **muted** from text and voice chat. User's Role Added + Fuzzy User's Role Removed + Fuzzy {0} is now {1} @@ -825,9 +851,11 @@ Reason: {1} Voice Channel Destroyed + Fuzzy Voice Channel Destroyed + Fuzzy Disabled voice + text feature. @@ -859,6 +887,7 @@ Reason: {1} User Unbanned + Fuzzy Migration done! @@ -868,9 +897,11 @@ Reason: {1} Presence Updates + Fuzzy User Soft-Banned + Fuzzy has awarded {0} to {1} @@ -913,6 +944,7 @@ Reason: {1} Heads + Fuzzy Leaderboard @@ -934,6 +966,7 @@ Reason: {1} Raffled User + Fuzzy You rolled {0}. @@ -968,6 +1001,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Tails + Fuzzy successfully took {0} from {1} @@ -980,6 +1014,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Само Власник Бота + Fuzzy Захтева {0} дозволу на каналу. @@ -989,9 +1024,11 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Команде и псеудоними + Fuzzy Листа команди је обновљена. + Fuzzy Укуцај `{0}h ИмеКоманде` да видиш помоћ за ту команду. нпр. `{0}h >8ball` @@ -1013,12 +1050,15 @@ Lasts {1} seconds. Don't tell anyone. Shhh. **List of Commands**: <{0}> **Hosting Guides and docs can be found here**: <{1}> + Fuzzy Листа Команди + Fuzzy Листа Модула + Fuzzy Укуцај `{0}cmds ИмеМодула` да видиш листу свих команди у том модулу. нпр `{0}cmds games` @@ -1031,6 +1071,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Садржај + Fuzzy Упутство @@ -1044,6 +1085,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Трка Животиња + Fuzzy Започињање трке није успело јер нема довољно учесника. @@ -1095,9 +1137,11 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Промена Осећања + Fuzzy Присвојена од стране + Fuzzy Развода @@ -1149,37 +1193,37 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Та waifu није твоја. - + Не можеш присвојити себе. - + Нико - + 8кугла - + Акрофобија - + Игра је се завршила без уноса. - + Нема гласова. Игра је се завршила без победника. - + Игра акрофобије већ постоји у овом каналу. @@ -1191,7 +1235,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Гласај тако што укуцаш број уноса. @@ -1203,7 +1247,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Питање @@ -1212,28 +1256,28 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Уноси затворени - + Трка животиња већ постоји. - + Категорија - + Клевербот је угашен на овом серверу. - + Клевербот је упаљен на овом серверу. - + Генерација валуте је угашена на овом каналу. - + Генерација валуте је упаљена на овом каналу. @@ -1243,19 +1287,19 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Није успело учитавање питања. - + Игра је почела - + Игра вешалица је почела - + Игра вешалица већ постоји на овом каналу. - + Игра вешалица није успешно почела. @@ -1268,7 +1312,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Немаш довољно {0} - + Нема резултата. @@ -1279,22 +1323,22 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Kwoth planted 5* - + Игра тривије већ постоји на овом серверу. - + Игра тривије - + Нема тривије у току на овом серверу. - + Игра се зауставља после овог питања. @@ -1303,28 +1347,28 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Не можеш играти против себе. - + Игра икс-окс већ постоји на овом каналу. - + Нерешено! - + је направио игру икс-окса. - + Три спојене - + Нема више потеза! - + Време је истекло! @@ -1336,73 +1380,73 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Аутопуштање је угашено. - + Аутопуштање је упаљено. - + Директоријум успешно стављен у плејлисту. - + ферплеј - + Песма је завршена - + Ферплеј је угашен. - + Ферплеј је упаљен. - + Са позиције - + ИД - + Нисправан унос. - + Максимални плејтајм више нема лимит. - + Максимална величина реда је неограничена. - + Требаш бити у говорном каналу на овом серверу. - + Име - + Сада се пушта - + Нема активног музичког плејера. - + Нема резултата претраге. - + Музика је паузирана. - + Пушта се песма @@ -1411,28 +1455,28 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Плејлиста обрисана. - + Није успело брисање те плејлисте. Или не постоји, или ниси ти ниси њен аутор. - + Плејлиста са тим ИДем не постоји. - + Успешно учитавање плејлисте. - + Плејлиста је сачувана. - + Ред - + Песма је учитана @@ -1986,6 +2030,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Емотикони по Мери + Fuzzy Грешка @@ -2004,6 +2049,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. није ти дозвољено да користиш ову команду на ролама са пуно корисника да би се спречила злоупотреба. + Fuzzy Нетачна вредност {0}. @@ -2014,17 +2060,20 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Ушао на сервер + Fuzzy ИД: {0} Чланова; {1} Ид Власника; {2} + Fuzzy Нема сервера на овој страници. Листа Понављача + Fuzzy Чланова @@ -2037,6 +2086,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Понављач Порука + Fuzzy Име @@ -2096,6 +2146,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Регистрован + Fuzzy @@ -2111,6 +2162,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Листа понављача + Fuzzy Нема понављача на овом серверу. @@ -2147,12 +2199,14 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Инфо Сервера + Fuzzy Шард Статови Шардова + Fuzzy @@ -2168,6 +2222,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Текст Канали + Fuzzy Ево га твој линк ка соби: @@ -2184,6 +2239,41 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Говорни канал + Fuzzy + + + + + + + + + + + + + + + + + + + + + + Kwoth voted. + + + + + + + + + + + + \ No newline at end of file From b210ea680a41d909d06f2df641606a17bf770347 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 6 Mar 2017 17:07:43 +0100 Subject: [PATCH 463/746] Update ResponseStrings.sv-SE.resx (POEditor.com) --- .../Resources/ResponseStrings.sv-SE.resx | 272 ++++++++++-------- 1 file changed, 152 insertions(+), 120 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx index a1b017d1..305c8788 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Denna bas är redan tagen eller förstörd. @@ -780,11 +780,11 @@ Anledning: {1} __IgnoreradeKannaler_: {2} - Text kanal skapad + Text kanal skapad. Fuzzy - Text kanal förstörd␣ + Text kanal förstörd. Fuzzy @@ -1815,7 +1815,7 @@ Fuzzy Fuktighet - Bild Sökning För: + Bild sökning för: Fuzzy @@ -2271,5 +2271,37 @@ Medlemmar: {1} Du har redan gått med detta lopp! + + Nuvarande röstningsresultat + + + Inga röster gjorda. + + + Rösten är redan igång på denna server. + + + 📃 {0} har skapat en röst som kräver din uppmärksamhet: + + + `{0}.` {1} med {2} röster. + + + {0} röstade. + Kwoth voted. + + + Privat Meddela mig det nummer som stämmer överens med svaret. + Fuzzy + + + Skicka ett Meddelande här med det nummer som stämmer överens med svaret. + + + Tack för att du röstade, {0} + + + {0} antal röster gjorda. + \ No newline at end of file From 11f51249525b2a4afd97a8f5993ffabe64e0d1ed Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 6 Mar 2017 17:07:46 +0100 Subject: [PATCH 464/746] Update ResponseStrings.tr-TR.resx (POEditor.com) --- .../Resources/ResponseStrings.tr-TR.resx | 525 ++++++++++-------- 1 file changed, 279 insertions(+), 246 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx b/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx index 9a4ed57f..8ebe09d9 100644 --- a/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx @@ -1,130 +1,130 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + Bu köy daha önceden alınmış veya yok edilmiş. - + Bu köy önceden yok edilmiş. - + Bu köy alınmamış. @@ -157,7 +157,7 @@ Aktif olan savaşlar - Hak idda edilmedi. + Alınmamış Fuzzy @@ -233,74 +233,75 @@ Autohentai durduruldu. - + Sonuç bulunamadı. - + {0} zaten bayılmış. - + {0} zaten canı dolu. - + Senin türn zaten {0} Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. - + İntikam almadan bir daha saldıramassın. - + Kendine saldıramassın. - + {0} bayıldı. - + {0} iyileştirdi kullanarak {1} + Fuzzy - + {0} canı {1} kaldı. - + {0} tipi için hareklerin listesi - + Efektif değil. - + Sende yeteri kadar {0} yok - + Kendini yeniden canlardırdın bir tane {0} kullanarak. - + Senin tipin {0}'dan {1}'e değiştirildi. - + BU oldukça efektif! - + Bu süper efektif! - + Arka arkaya çok fazla harekt kullandın, artık haraket edemiyorsun! - + Kullanıcı bulunamadı. - + Bayıldın,yani hareket edemiyiceksin. Kullanıcı girişinde otomatik rol tanımlaması devre dışı. @@ -525,69 +526,69 @@ Sebep: {1} - + Bot sahibine mesaj {0} `[Bot Owner]`: - + Mesaj yollandı. - + {0} {1}'den {2}'ye taşındı. - + Mesajlar silinicek {0} içinde - + Susturuldunuz PLURAL (users have been muted) - + Susturuldun singular "User muted." - + Yeni swssiz rolu atandı. - + Yeni mesaj - + Yeni nick - + Yeni konu - + Nick değiştirildi - + Server bulunamadı - + Eski mesaj - + Eski nick - + Eski konu - + Hata.Yüksek ihtimalle yeterki kadar yetki'ye sahip değilim. - + Bu server için yetkiler sıfırlandı. @@ -599,7 +600,7 @@ Sebep: {1} - + Hata. Rolleri değiştirme iznine sahip değilim @@ -614,37 +615,37 @@ Sebep: {1} - + {0} yetkileri başarı ile alındı - + Yetkileri almada hata . Yüksek ihtimalle yeteri kadar yetkim yok. - + {0}ın rolünün renki değiştirildi - + Bu röl bulunmamakta. - + Bu parametreler hatalı. - + {1} kullanıcısının sahip olduğu {0} rolü başarı ile alındı - + Yetkiyi almada hata . Yüksek ihtimalle yeteri kadar yetkim yok. - + Rol yeniden adlandırıldı. - + Rol yeniden adladırılmasında hata. Yüksek ihtimalle yeteri kadar yetkim yok. - + Kendi rolunüzden daha yüksek rolleri değiştiremezsiniz. @@ -659,7 +660,7 @@ Sebep: {1} - + Eklendi. @@ -719,7 +720,7 @@ Sebep: {1} - + Yeni oyun başladı! @@ -734,19 +735,19 @@ Sebep: {1} - + Kapatılıyor - + Yavaş modu deaktive edildi - + Yavaş modu aktive edildi - + Kicklendiniz PLURAL @@ -759,50 +760,50 @@ Sebep: {1} - + Mesaj kanalı oluşturuldu. - + Mesaj kanalı kapatıldı. - + Susturulmanız kaldırıldı singular - + Kullanıcı adı - + Kullanıcı adı değiştirildi - + Kullanıcılar - + Kullanıcı uzaklaştırıldı. - + {0} bundan sonra mesajlaşmak için susturuldu. - + {0} bundan sonra mesajlaşmak için susturulması kaldırıldı. - + Kullanıcı katıldı - + Kullanıcı ayrıldı - + Kullanıcı rolü eklendi - + Kullanıcı rölü kaldırıldı @@ -826,10 +827,10 @@ Sebep: {1} - + Ses kanalı kuruldu - + Ses kanalı kapatıldı @@ -877,20 +878,20 @@ Sebep: {1} - + Birdaki sefere daha iyi bir şansın olur umarım ^_^ - + Deste karıldı User flipped tails. - + Tebrikler bildin! {0} kazandın @@ -902,7 +903,7 @@ Sebep: {1} - + Çiçek reaksiyonu etkinliği başladı! @@ -913,25 +914,25 @@ Sebep: {1} X has Y flowers - + Tura - + Liderlik Listesi - + {0}'dan fazla bahis yapamazssın - + {0}'dan az bahis yapamassın - + {0} yeteri kadar yok - + Destede kart kalmadı @@ -940,10 +941,10 @@ Sebep: {1} - + Bahis - + WOAAHHHHHH!!!Tebrikler!!! x{0} @@ -955,7 +956,7 @@ Sebep: {1} - + Kazandın @@ -967,7 +968,7 @@ Sebep: {1} - + Yazı @@ -979,7 +980,7 @@ Sebep: {1} - + Bot sahibine özel @@ -1000,7 +1001,7 @@ Sebep: {1} - + Açıklama @@ -1009,16 +1010,16 @@ Sebep: {1} - + Komutların listesi - + Modüllerin listesi - + Böyle bir modül bulunamadı @@ -1027,7 +1028,7 @@ Sebep: {1} - + Kullanım @@ -1036,51 +1037,51 @@ Sebep: {1} - + Hayvan yarışı - + Yarış dolu ! Hemen Başlıyor. - + {0} {1} olarak katıldı - + yarışa katılmak için {0}jr yazın. - + Yarışın başlaması için 20 saniye beklenmeli veya odanın dolması gerekmektedir. - + {0} katılımcı ile başlıyor - + {1} olan {0} yarışı kazandı! - + {1} olan {0} yarışı kazandı ve şu kadarlık bahisi topladı {2}! - + atıldı {0} Someone rolled 35 - + Zar atıldı: {0} Dice Rolled: 5 - + Yarış başlayamadı. Büyük ihtimalle bir başka yariş aktif. - + BU serverda bir yariş bulunmuyor. @@ -1089,22 +1090,23 @@ Sebep: {1} - + tarafından alındı. - + Ayrılıklar + is that plural? - + Sevdikleri - + Ücreti - + En yüksek Waifular @@ -1141,22 +1143,22 @@ Sebep: {1} - + BU waifu senin değil. - + Kendini alamazsın. - + Hiç kimse - + Seni sevemeyen bir waifundan ayrıldın.{0} kadarını geri aldın. - + 8NumaralıTop @@ -1222,7 +1224,7 @@ Sebep: {1} - + Bu kanalda birim üretimi kapatıldı. @@ -1262,11 +1264,11 @@ Sebep: {1} - + {0} aldı Kwoth picked 5* - + {0} ekti {1} aldı Kwoth planted 5* @@ -1423,7 +1425,7 @@ Sebep: {1} - + Şarkı sırasına eklendi. @@ -1432,7 +1434,7 @@ Sebep: {1} - + Şarkı kaldırıldı context: "removed song #5" @@ -1511,7 +1513,7 @@ Sebep: {1} - + {0} adlı ve {1} idli kullanıcı karalisteye alındı. @@ -1538,7 +1540,7 @@ Sebep: {1} - + Filtrelenmiş sözler listesi @@ -1568,11 +1570,11 @@ Sebep: {1} - + komut Gen (of command) - + modül Gen. (of module) @@ -1597,7 +1599,7 @@ Sebep: {1} - + sn Short of seconds. @@ -1700,7 +1702,7 @@ Sebep: {1} - + Ara verildi @@ -1794,7 +1796,7 @@ Sebep: {1} - + İzlemeyi düşünülen @@ -1824,7 +1826,7 @@ Sebep: {1} - + Şunu ara: @@ -1949,7 +1951,7 @@ Sebep: {1} - + Komutlar yürütüyor @@ -1991,7 +1993,7 @@ Sebep: {1} - + Bu roldeki kullanıcıların listesi: @@ -2175,5 +2177,36 @@ Sebep: {1} + + + + + + + + + + + + + + + + + {0} oyladı. + Kwoth voted. + + + + + + + + + + + + + \ No newline at end of file From 6437fb6f90701eb6b5d579f45b2c57b311feba1e Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 6 Mar 2017 18:43:03 +0100 Subject: [PATCH 465/746] Fixed .remind me --- .../Modules/Utility/Commands/Remind.cs | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/Remind.cs b/src/NadekoBot/Modules/Utility/Commands/Remind.cs index 45406de9..092d1470 100644 --- a/src/NadekoBot/Modules/Utility/Commands/Remind.cs +++ b/src/NadekoBot/Modules/Utility/Commands/Remind.cs @@ -64,7 +64,10 @@ namespace NadekoBot.Modules.Utility IMessageChannel ch; if (r.IsPrivate) { - ch = await NadekoBot.Client.GetDMChannelAsync(r.ChannelId).ConfigureAwait(false); + var user = NadekoBot.Client.GetGuild(r.ServerId).GetUser(r.ChannelId); + if(user == null) + return; + ch = await user.CreateDMChannelAsync().ConfigureAwait(false); } else { @@ -100,23 +103,16 @@ namespace NadekoBot.Modules.Utility [Priority(1)] public async Task Remind(MeOrHere meorhere, string timeStr, [Remainder] string message) { - IMessageChannel target; - if (meorhere == MeOrHere.Me) - { - target = await ((IGuildUser)Context.User).CreateDMChannelAsync().ConfigureAwait(false); - } - else - { - target = Context.Channel; - } - await Remind(target, timeStr, message).ConfigureAwait(false); + ulong target; + target = meorhere == MeOrHere.Me ? Context.User.Id : Context.Channel.Id; + await Remind(target, meorhere == MeOrHere.Me, timeStr, message).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageMessages)] [Priority(0)] - public async Task Remind(IMessageChannel ch, string timeStr, [Remainder] string message) + public async Task Remind(ulong targetId, bool isPrivate, string timeStr, [Remainder] string message) { var channel = (ITextChannel)Context.Channel; @@ -164,8 +160,8 @@ namespace NadekoBot.Modules.Utility var rem = new Reminder { - ChannelId = ch.Id, - IsPrivate = ch is IDMChannel, + ChannelId = targetId, + IsPrivate = isPrivate, When = time, Message = message, UserId = Context.User.Id, @@ -182,7 +178,7 @@ namespace NadekoBot.Modules.Utility { await channel.SendConfirmAsync( "⏰ " + GetText("remind", - Format.Bold(ch is ITextChannel ? ((ITextChannel) ch).Name : Context.User.Username), + Format.Bold(!isPrivate ? $"<#{targetId}>" : Context.User.Username), Format.Bold(message.SanitizeMentions()), Format.Bold(output), time, time)).ConfigureAwait(false); From 74ac9858dcd0643641482a791c06038f5c5b1f53 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 6 Mar 2017 19:19:23 +0100 Subject: [PATCH 466/746] .inrole nerfed, takes only one role, prettier --- src/NadekoBot/Modules/Utility/Utility.cs | 33 ++++--------------- .../Resources/CommandStrings.Designer.cs | 4 +-- src/NadekoBot/Resources/CommandStrings.resx | 4 +-- .../Resources/ResponseStrings.Designer.cs | 2 +- src/NadekoBot/Resources/ResponseStrings.resx | 2 +- 5 files changed, 13 insertions(+), 32 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 38951dd5..fefa35bd 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -217,34 +217,15 @@ namespace NadekoBot.Modules.Utility [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task InRole(params IRole[] roles) + public async Task InRole([Remainder] IRole role) { - if (roles.Length == 0) - return; - var send = "ℹ️ " + Format.Bold(GetText("inrole_list")); + var usrs = (await Context.Guild.GetUsersAsync()).ToArray(); - foreach (var role in roles.Where(r => r.Id != Context.Guild.Id)) - { - var roleUsers = usrs.Where(u => u.RoleIds.Contains(role.Id)).Select(u => u.ToString()).ToArray(); - send += $"```css\n[{role.Name}] ({roleUsers.Length})\n"; - send += string.Join(", ", roleUsers); - send += "\n```"; - } - var usr = (IGuildUser)Context.User; - while (send.Length > 2000) - { - if (!usr.GetPermissions((ITextChannel)Context.Channel).ManageMessages) - { - await ReplyErrorLocalized("inrole_not_allowed").ConfigureAwait(false); - return; - } - var curstr = send.Substring(0, 2000); - await Context.Channel.SendConfirmAsync(curstr.Substring(0, - curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1)).ConfigureAwait(false); - send = curstr.Substring(curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1) + - send.Substring(2000); - } - await Context.Channel.SendConfirmAsync(send).ConfigureAwait(false); + var roleUsers = usrs.Where(u => u.RoleIds.Contains(role.Id)).Select(u => u.ToString()).ToArray(); + var embed = new EmbedBuilder().WithOkColor() + .WithTitle("ℹ️ " + Format.Bold(GetText("inrole_list")) + $" - {roleUsers.Length}") + .WithDescription(string.Join(", ", roleUsers)); + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 41965836..3b42debd 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -3552,7 +3552,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Lists every person from the provided role or roles, separated with space, on this server. You can use role IDs, role names (in quotes if it has multiple words), or role mention If the list is too long for 1 message, you must have Manage Messages permission.. + /// Looks up a localized string similar to Lists every person from the specified role on this server. You can use role ID, role name.. /// public static string inrole_desc { get { @@ -3561,7 +3561,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}inrole Role` or `{0}inrole Role1 "Role 2" @role3`. + /// Looks up a localized string similar to `{0}inrole Some Role`. /// public static string inrole_usage { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 3379b98b..528700c3 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -841,10 +841,10 @@ inrole - Lists every person from the provided role or roles, separated with space, on this server. You can use role IDs, role names (in quotes if it has multiple words), or role mention If the list is too long for 1 message, you must have Manage Messages permission. + Lists every person from the specified role on this server. You can use role ID, role name. - `{0}inrole Role` or `{0}inrole Role1 "Role 2" @role3` + `{0}inrole Some Role` checkmyperms diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 7e2b3173..44f51416 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -5702,7 +5702,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Here is a list of users in those roles:. + /// Looks up a localized string similar to List of users in {0} role. /// public static string utility_inrole_list { get { diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 8f964f3a..a74c16db 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2002,7 +2002,7 @@ Don't forget to leave your discord name or id in the message. Index out of range. - Here is a list of users in those roles: + List of users in {0} role You are not allowed to use this command on roles with a lot of users in them to prevent abuse. From 05d6152936bc7c1b9bc4178beb4027cb6b5e0375 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 6 Mar 2017 20:13:06 +0100 Subject: [PATCH 467/746] Cleverbot is beyond stupid, but works. Not using cleverbot, but program-o.com --- .../Games/Commands/CleverBotCommands.cs | 50 ++++++++++++++++--- src/NadekoBot/Services/Impl/StatsService.cs | 2 +- src/NadekoBot/_Extensions/Extensions.cs | 6 +++ 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs index fa04a2c6..3d7fb832 100644 --- a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs @@ -5,12 +5,15 @@ using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; using NLog; -using Services.CleverBotApi; +//using Services.CleverBotApi; using System; using System.Collections.Concurrent; using System.Diagnostics; using System.Linq; +using System.Net.Http; using System.Threading.Tasks; +using Newtonsoft.Json; +using Services.CleverBotApi; namespace NadekoBot.Modules.Games { @@ -27,13 +30,11 @@ namespace NadekoBot.Modules.Games { _log = LogManager.GetCurrentClassLogger(); var sw = Stopwatch.StartNew(); - - var bot = ChatterBotFactory.Create(ChatterBotType.CLEVERBOT); CleverbotGuilds = new ConcurrentDictionary>( NadekoBot.AllGuildConfigs .Where(gc => gc.CleverbotEnabled) - .ToDictionary(gc => gc.GuildId, gc => new Lazy(() => bot.CreateSession(), true))); + .ToDictionary(gc => gc.GuildId, gc => new Lazy(() => new ChatterBotSession(gc.GuildId), true))); sw.Stop(); _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); @@ -100,9 +101,7 @@ namespace NadekoBot.Modules.Games return; } - var cleverbot = ChatterBotFactory.Create(ChatterBotType.CLEVERBOT); - - CleverbotGuilds.TryAdd(channel.Guild.Id, new Lazy(() => cleverbot.CreateSession(), true)); + CleverbotGuilds.TryAdd(channel.Guild.Id, new Lazy(() => new ChatterBotSession(Context.Guild.Id), true)); using (var uow = DbHandler.UnitOfWork()) { @@ -113,5 +112,42 @@ namespace NadekoBot.Modules.Games await ReplyConfirmLocalized("cleverbot_enabled").ConfigureAwait(false); } } + + public class ChatterBotSession + { + private static NadekoRandom rng { get; } = new NadekoRandom(); + public string ChatterbotId { get; } + public string ChannelId { get; } + private int _botId = 15; + + public ChatterBotSession(ulong channelId) + { + ChannelId = channelId.ToString().ToBase64(); + ChatterbotId = rng.Next(0, 1000000).ToString().ToBase64(); + } + + private string apiEndpoint => "http://api.program-o.com/v2/chatbot/" + + $"?bot_id={_botId}&" + + "say={0}&" + + $"convo_id=nadekobot_{ChatterbotId}_{ChannelId}&" + + "format=json"; + + public async Task Think(string message) + { + using (var http = new HttpClient()) + { + var res = await http.GetStringAsync(string.Format(apiEndpoint, message)).ConfigureAwait(false); + var cbr = JsonConvert.DeserializeObject(res); + //Console.WriteLine(cbr.Convo_id); + return cbr.BotSay.Replace("
", "\n"); + } + } + } + + public class ChatterBotResponse + { + public string Convo_id { get; set; } + public string BotSay { get; set; } + } } } \ No newline at end of file diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index 0390cbda..946bf11f 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -16,7 +16,7 @@ namespace NadekoBot.Services.Impl private readonly DiscordShardedClient _client; private readonly DateTime _started; - public const string BotVersion = "1.2"; + public const string BotVersion = "1.21"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index f95e6fbb..429e9c80 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -21,6 +21,12 @@ namespace NadekoBot.Extensions private const string arrow_left = "⬅"; private const string arrow_right = "➡"; + public static string ToBase64(this string plainText) + { + var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText); + return Convert.ToBase64String(plainTextBytes); + } + public static Stream ToStream(this IEnumerable bytes, bool canWrite = false) { var ms = new MemoryStream(bytes as byte[] ?? bytes.ToArray(), canWrite); From cf44ff9b7923509cfeb4731ef7e66136ffeba32a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 6 Mar 2017 20:17:43 +0100 Subject: [PATCH 468/746] woops, forgot to put botid back --- src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs index 3d7fb832..0e85e4b0 100644 --- a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs @@ -118,7 +118,7 @@ namespace NadekoBot.Modules.Games private static NadekoRandom rng { get; } = new NadekoRandom(); public string ChatterbotId { get; } public string ChannelId { get; } - private int _botId = 15; + private int _botId = 6; public ChatterBotSession(ulong channelId) { From 1d8387b8d971faa82a05cd60208604d5ccb5b827 Mon Sep 17 00:00:00 2001 From: samvaio Date: Wed, 8 Mar 2017 01:41:57 +0530 Subject: [PATCH 469/746] .NET Core 1.1.0 SDK Preview 2.1 build 3177 --- docs/guides/Windows Guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/Windows Guide.md b/docs/guides/Windows Guide.md index 0d569909..c0e62c76 100644 --- a/docs/guides/Windows Guide.md +++ b/docs/guides/Windows Guide.md @@ -120,7 +120,7 @@ In order to have a functioning music module, you need to install ffmpeg and setu -[.NET Core SDK]: https://www.microsoft.com/net/core#windowscmd +[.NET Core SDK]: https://github.com/dotnet/core/blob/master/release-notes/download-archives/1.1-preview2.1-download.md [Git]: https://git-scm.com/download/win [7zip]: http://www.7-zip.org/download.html [DiscordApp]: https://discordapp.com/developers/applications/me From 4c1d405d51b11edf82833807bd20ed1654246bf7 Mon Sep 17 00:00:00 2001 From: samvaio Date: Wed, 8 Mar 2017 02:19:18 +0530 Subject: [PATCH 470/746] linux and macos update links changed to .NET Core 1.1.0 SDK Preview 2.1 build 3177 --- docs/guides/Linux Guide.md | 48 +++++++++++++++++++++++++++++++------- docs/guides/OSX Guide.md | 3 ++- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/docs/guides/Linux Guide.md b/docs/guides/Linux Guide.md index 1997407b..4e168cf4 100644 --- a/docs/guides/Linux Guide.md +++ b/docs/guides/Linux Guide.md @@ -198,17 +198,49 @@ CentOS: ![img2](https://cdn.discordapp.com/attachments/251504306010849280/251504746987388938/dotnet.gif) Go to [this link](https://www.microsoft.com/net/core#ubuntu) (for Ubuntu) or to [this link](https://www.microsoft.com/net/core#linuxcentos) (for CentOS) provided by microsoft for instructions on how to get the most up to date version of the dotnet core sdk! -Make sure that you're on the correct page for your distribution of linux as the guides are different for the various distributions +Make sure that you're on the correct page for your distribution of linux as the guides are different for the various distributions. +Install the **currently supported version** `1.0.0-preview2-1-003177`. +You can find it [here](https://github.com/dotnet/core/blob/master/release-notes/download-archives/1.1-preview2.1-download.md) if you prefer manual installing `dpkg` files. -We'll go over the steps here for Ubuntu 16.04 anyway (these will **only** work on Ubuntu 16.04), accurate as of 3/2/2017 +We'll go over the steps here for few linux distributions, accurate as of March 08, 2017: +**NOTE:** .NET CORE SDK only supports 64-bit Linux Operating Systems (Raspberry Pis are not supported because of this) +**Ubuntu x64 17.04 & 16.10** +```sh +sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ yakkety main" > /etc/apt/sources.list.d/dotnetdev.list' +sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 417A0893 +sudo apt-get update && sudo apt-get install dotnet-dev-1.0.0-preview2.1-003177 -y ``` + +**Ubuntu x64 16.04** +```sh sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ xenial main" > /etc/apt/sources.list.d/dotnetdev.list' sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 417A0893 sudo apt-get update && sudo apt-get install dotnet-dev-1.0.0-preview2.1-003177 -y ``` -**NOTE:** .NET CORE SDK only supports 64-bit Linux Operating Systems (Raspberry Pis are not supported because of this) +**Ubuntu x64 14.04** +```sh +sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ trusty main" > /etc/apt/sources.list.d/dotnetdev.list' +sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 417A0893 +sudo apt-get update && sudo apt-get install dotnet-dev-1.0.0-preview2.1-003177 -y +``` + +**Debian 8 x64** +```sh +sudo apt-get install curl libunwind8 gettext -y +curl -sSL -o dotnet.tar.gz https://go.microsoft.com/fwlink/?LinkID=835021 +sudo mkdir -p /opt/dotnet && sudo tar zxf dotnet.tar.gz -C /opt/dotnet +sudo ln -s /opt/dotnet/dotnet /usr/local/bin +``` + +**CentOS 7 x64** +```sh +sudo yum install libunwind libicu -y +curl -sSL -o dotnet.tar.gz https://go.microsoft.com/fwlink/?LinkID=835019 +sudo mkdir -p /opt/dotnet && sudo tar zxf dotnet.tar.gz -C /opt/dotnet +sudo ln -s /opt/dotnet/dotnet /usr/local/bin +``` #####Installing Opus Voice Codec and libsodium @@ -232,14 +264,14 @@ Ubuntu: Centos: -``` +```sh yum -y install http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm epel-release yum -y install ffmpeg ``` **NOTE:** If you are running **UBUNTU 14.04**, you must run these first: -``` +```sh sudo add-apt-repository ppa:mc3man/trusty-media sudo apt-get update sudo apt-get dist-upgrade @@ -250,7 +282,7 @@ sudo apt-get dist-upgrade **NOTE:** If you are running **Debian 8 Jessie**, please, follow these steps: -``` +```sh sudo apt-get update echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/debian-backports.list sudo apt-get update && sudo apt-get install ffmpeg -y @@ -330,14 +362,14 @@ If the [Nadeko installer](http://nadekobot.readthedocs.io/en/latest/guides/Linux **OR** -``` +```sh cd ~ && git clone -b dev --recursive --depth 1 https://github.com/Kwoth/NadekoBot.git cd ~/NadekoBot/discord.net/src/Discord.Net && dotnet restore && cd ../Discord.Net.Commands && dotnet restore && cd ../../../src/NadekoBot/ && dotnet restore && dotnet build --configuration Release ``` If you are getting error using the above steps try: -``` +```sh cd ~/NadekoBot/discord.net && dotnet restore -s https://dotnet.myget.org/F/dotnet-core/api/v3/index.json && dotnet restore cd ~/NadekoBot/src/NadekoBot/ && dotnet restore && dotnet build --configuration Release ``` diff --git a/docs/guides/OSX Guide.md b/docs/guides/OSX Guide.md index 7475a911..366a5319 100644 --- a/docs/guides/OSX Guide.md +++ b/docs/guides/OSX Guide.md @@ -30,7 +30,7 @@ brew install tmux - `ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/` - `ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/` -- Download the [.NET Core SDK](https://www.microsoft.com/net/core#macos), found [here.](https://go.microsoft.com/fwlink/?LinkID=835011) +- Download the [.NET Core SDK][.NET Core SDK] - Open the `.pkg` file you downloaded and install it. - `ln -s /usr/local/share/dotnet/dotnet /usr/local/bin` @@ -166,6 +166,7 @@ If you used Screen press CTRL+A+D (this will detach the nadeko screen) - `dotnet build --configuration Release` [Homebrew]: http://brew.sh/ +[.NET Core SDK]: https://github.com/dotnet/core/blob/master/release-notes/download-archives/1.1-preview2.1-download.md [DiscordApp]: https://discordapp.com/developers/applications/me [Atom]: https://atom.io/ [Invite Guide]: http://discord.kongslien.net/guide.html From 96bf2a5233bf9769baf58c5b9ad37dece2580e27 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 8 Mar 2017 02:17:30 +0100 Subject: [PATCH 471/746] Update ResponseStrings.zh-CN.resx (POEditor.com) From 221ca3f4de316849c2af4ecd4ac6ee52baa280e6 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 8 Mar 2017 02:17:33 +0100 Subject: [PATCH 472/746] Update ResponseStrings.zh-TW.resx (POEditor.com) --- .../Resources/ResponseStrings.zh-TW.resx | 622 +++++++++++++----- 1 file changed, 468 insertions(+), 154 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx index 7b58202d..cb7f3b62 100644 --- a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx +++ b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx @@ -140,7 +140,6 @@
在 @{0} 與 {1} 對戰後佔領的基地已失效。 - Fuzzy 敵人 @@ -153,11 +152,9 @@ 無效的戰爭大小。 - Fuzzy 目前正在進行的戰爭 - Fuzzy 未佔領 @@ -170,7 +167,6 @@ 目前尚無戰爭進行中。 - Fuzzy 大小 @@ -211,7 +207,6 @@ 沒有找到自訂回應 。 - Fuzzy 找不到輸入的自訂回應編號。 @@ -300,7 +295,7 @@ {0} 的屬性是 {1} - 該用戶不存在。 + 該成員不存在。 您已昏厥所以不能移動! @@ -326,7 +321,7 @@ PLURAL - 用戶已封鎖 + 成員已封鎖 Bot 暱稱已改為 {0} @@ -401,7 +396,7 @@ 私人訊息來自 - 成功新增了新的捐贈者。此用戶總共捐贈了:{0} + 成功新增了新的捐贈者。此成員總共捐贈了:{0} 感謝下列的人使這個項目繼續運作! @@ -455,7 +450,7 @@ 在這個頻道啟用歡迎通知。 - 您不能對身分組與您一樣或更高的人使用此指令。 + 您不能對身分組與您一樣或更高的成員使用此指令。 圖片共花了 {0} 秒載入! @@ -474,7 +469,7 @@ 原因:{1} - 用戶已被踢出 + 成員已被踢出 Fuzzy @@ -616,16 +611,16 @@ Fuzzy - 用戶緩衝數應介於 {0} 和 {1} 之間。 + 成員緩衝數應介於 {0} 和 {1} 之間。 - 如果 {1} 秒內進入了 {0} 或更多位使用者,我則會將他們 {2} 。 + 如果 {1} 秒內進入了 {0} 或更多位成員,我則會將他們 {2} 。 時間必須在於 {0} 和 {1} 秒之間。 - 已成功移除了使用者 {0} 上所有的身分組。 + 成功的移除了 {0} 所有的身分組。 無法移除身分組。我的權限不夠。 @@ -643,7 +638,7 @@ 無效的色碼或是權限不足引起錯誤。 - 成功的移除 {1} 的 {0} 身分組。 + 成功的移除了 {1} 的 {0} 身分組。 無法移除身分組。我沒有足夠的權限。 @@ -744,293 +739,352 @@ Shard {0} 重新連線中。 + Fuzzy 關閉中 + Fuzzy - 使用者無法在 {1} 秒發送超過 {0} 條訊息。 + 成員無法在 {1} 秒發送超過 {0} 條訊息。 + Fuzzy 慢速模式已停用。 + Fuzzy 慢速模式已啟用 + Fuzzy 軟禁 (踢出) - PLURAL + PLURAL +Fuzzy {0} 將會忽略此頻道。 + Fuzzy {0} 將會注意此頻道。 + Fuzzy - 如果使用者連續貼出 {0} 個相同的訊息,我將會把他們 {1}。 + 如果成員連續貼出 {0} 個相同的訊息,我將會把他們 {1}。      __忽略的頻道__: {2} + Fuzzy 文字頻道已建立 - Fuzzy 文字頻道已刪除 - Fuzzy 成功解除靜音。 + Fuzzy 解除靜音 - singular + singular +Fuzzy - 使用者名稱 + 成員名稱 + Fuzzy - 使用者名稱已更改 - Fuzzy + 成員名稱已更改 - 使用者 - - - 使用者已封鎖 + 成員 Fuzzy + + 成員已封鎖 + - {0} 已**被禁**__文字聊天__。 + 已**禁止** {0} 的__文字聊天__。 + Fuzzy - {0} 已**允許**__文字聊天__。 + 已**開啟** {0} 的__文字聊天__。 + Fuzzy 使用者已加入 - Fuzzy 使用者已離開 - Fuzzy - {0} 已**被禁**__文字和語音聊天__。 + 已**禁止** {0} 的__文字和語音聊天__。 + Fuzzy 使用者身分組已新增 + Fuzzy 已移除用戶的身分組 - Fuzzy {0} 改成了 {1} + Fuzzy - {0} 已從文字頻道和語音頻道被**取消禁音**。 + 已**開放** {0} 的__文字和語音聊天__。 + Fuzzy {0} 已加入 {1} 語音頻道。 + Fuzzy {0} 已離開 {1} 語音頻道。 + Fuzzy {0} 已從 {1} 移至 {2} 語音頻道。 + Fuzzy - {0} 已被**静音**。 + 已**禁止** {0} 的__語音聊天__。 + Fuzzy - {0} 已被**取消静音**。 + 已**開放** {0} 的__語音聊天__。 + Fuzzy 已建立語音頻道 + Fuzzy 已刪除語音頻道 + Fuzzy 已停用語音+文字功能。 + Fuzzy 已啟用語音+文字功能。 + Fuzzy - 我沒有**管理身分組**和/或**管理頻道**權限,所以我無法在 {0} 伺服器上運行`語音+文字`。 + 我沒有**管理身分組**和/或**管理頻道**權限,所以我無法在 {0} 伺服器上執行`語音+文字`功能。 + Fuzzy - 您正在啟用/停用此功能,而且**我没有管理員權限**。這可能會造成一些問題,您必須自己清理文字頻道。 + 您正在啟用/停用此功能,但我**__没有__管理員權限**。這可能會造成一些問題,而事後您必須自行處理這些文字頻道。 + Fuzzy - 我需要至少**管理身份**和**管理频道**权限,以启用此功能。 (优先管理权限) + 我至少需要**管理身份組**和**管理頻道**權限才能使用此功能。(建議給我管理員權限) + Fuzzy - 用户{0}来自文字频道 + 使用者被 {0} 文字聊天 + Fuzzy - 用户{0}来自文字和语音频道 + 使用者被 {0} 文字及語音聊天 + Fuzzy - 用户{0}来自语音频道 + 使用者被 {0} 語音聊天 + Fuzzy - 您已从{0}服务器软禁止。 -原因:{1} + 您已被伺服器 {0} 軟禁。 +理由: {1} + Fuzzy - 用户已取消禁止 - Fuzzy + 使用者已解禁 迁移完成! + Fuzzy 在迁移时出错,请检查机器人的控制台以获取更多信息。 + Fuzzy 在线状态更新 - Fuzzy 用户被软禁用 - Fuzzy 已給予 {0} 給 {1} + Fuzzy 祝你下一次好運 ^_^ + Fuzzy 恭喜! 您赢得{0}因为您滚{1}或以上 + Fuzzy 卡牌改组。 + Fuzzy 拋出了 {0}。 - User flipped tails. + User flipped tails. +Fuzzy 你猜對了!你赢得了 {0} + Fuzzy 指定的數字無效。你可以丟 1 至 {0} 個硬幣。 + Fuzzy 将{0}反应添加到此消息以获取{1} + Fuzzy 此活動只在 {0} 小時內有效。 + Fuzzy 花反应活动开始了! + Fuzzy 送了 {1} 給 {0} - X has gifted 15 flowers to Y + X has gifted 15 flowers to Y +Fuzzy {0} 擁有 {1} - X has Y flowers + X has Y flowers +Fuzzy + Fuzzy 排行榜 + Fuzzy 从{2}身份授予{0}至{1}名用户。 + Fuzzy 你的賭注不能大於 {0} + Fuzzy 你的賭注不能少於 {0} + Fuzzy 你沒有足夠的 {0} + Fuzzy 卡牌组中没有更多的牌。 + Fuzzy - 抽奖用户 - Fuzzy + 得獎用戶 您抛了{0}。 + Fuzzy 賭注 + Fuzzy 哇啊啊啊啊啊啊!恭喜!x{0} + Fuzzy 单个{0},x {1} + Fuzzy 哇!好运! 三个相同! x {0} + Fuzzy 做得好! 两个{0} - 投注x {1} + Fuzzy 獲勝 + Fuzzy 用户必须键入密码才能获取{0}。 持续{1}秒。 嘘~别跟任何人说。 + Fuzzy SneakyGame事件结束。 {0}个用户收到了奖励。 + Fuzzy SneakyGameStatus事件已启动 + Fuzzy - Fuzzy 已成功从{1}取得{0} + Fuzzy 无法从{1}取得{0},因为用户没有那么多{2}! + Fuzzy 返回ToC + Fuzzy - 仅限Bot Owner + 只限 BOT 擁有者 Fuzzy - 需要{0}频道权限。 + 需要 {0} 頻道權限。 + Fuzzy - 您可以在patreon上支持项目:<{0}>或paypal:<{1}> + 您可以在 patreon 上:<{0}> 或 paypal:<{1}> 支持這個項目 命令和别名 - Fuzzy 命令列表已重新生成。 - Fuzzy 输入`{0} h CommandName`可查看该指定命令的帮助。 例如 `{0} h> 8ball` + Fuzzy 我找不到该命令。 请再次尝试之前验证该命令是否存在。 + Fuzzy 描述 + Fuzzy 您可以在: @@ -1040,1285 +1094,1545 @@ Paypal <{1}> 不要忘记在邮件中留下您的不和名字或ID。 **谢谢**♥️ + Fuzzy **命令列表**:<{0}> **主机指南和文档可以在这里找到**:<{1}> - Fuzzy - 命令列表 - Fuzzy + 指令列表 组件列表 - Fuzzy 输入“{0} cmds ModuleName”以获取该组件中的命令列表。 例如`{0} cmds games` + Fuzzy 该组件不存在。 + Fuzzy 需要{0}服务器权限。 + Fuzzy 目录 - Fuzzy - 用法 + 使用方式 + Fuzzy - 自动hentai启动。 使用以下标记之一重新排列每个{0}: + Autohentai 啟動。每 {0} 秒發送一張含有以下標籤的圖片: {1} - 标签 - - - 动物竞赛 + 標籤 Fuzzy + + 動物競速比賽 + - 启动失败,因为没有足够的参与者。 + 參賽者不足,無法啟動比賽。 + Fuzzy - 竞赛已满! 立即开始。 + 參賽者已滿!將立即開始比賽。 + Fuzzy - {0}加入为{1} + {0} 扮演為 {1} - {0}加入为{1},赌注{2}! + {0} 扮演為 {1} 並下注了 {2}! - 输入{0} jr 以加入竞赛。 + 輸入 {0}jr 來加入比賽。 + Fuzzy - 在20内秒或当房间满后开始。 + 比賽將開始於20秒內或房間人數滿後。 + Fuzzy - {0}个参与者开始。 + 比賽開始,共有 {0} 個參賽者。 {0}为{1}赢得竞赛! + Fuzzy 0}为{1}赢得竞赛,和赢得{2}! + Fuzzy 指定的数字无效。 您可以一次滚动{0} - {1}骰子。 + Fuzzy 掷了{0} - Someone rolled 35 + Someone rolled 35 +Fuzzy 掷骰子:{0} - Dice Rolled: 5 + Dice Rolled: 5 +Fuzzy 竞赛启动失败。 另一个比赛可能正在运行。 + Fuzzy 此服务器上不存在竞赛 + Fuzzy 第二个数字必须大于第一个数字。 + Fuzzy 爱被改变 - Fuzzy 声称 - Fuzzy 离婚 + Fuzzy 喜欢 + Fuzzy - 价钱 + 價格 + Fuzzy 没有waifus被要求。 + Fuzzy 最佳Waifus + Fuzzy 您的兴趣已设置为该waifu,或者您尝试在没有兴趣的情况下删除您的兴趣。 + Fuzzy 将把兴趣从{0}更改为{1}。 *这在道德上是有问题的*🤔 - Make sure to get the formatting right, and leave the thinking emoji + Make sure to get the formatting right, and leave the thinking emoji +Fuzzy 您必须等待{0}小时和{1}分钟才能再次更改您的兴趣。 + Fuzzy 您的兴趣已重置。 你不再有你喜欢的人。 + Fuzzy 想成为{0}的waifu。哇非常可爱<3 + Fuzzy 声明{0}为他的waifu,花了{1}! + Fuzzy 你已经离婚了一个喜欢你的waifu。 你无情的怪物。 {0}收到了{1}作为补偿。 + Fuzzy 你不能设置兴趣自己,你好自卑。 + Fuzzy 🎉他的爱实现! 🎉 {0}的新值为{1}! + Fuzzy 没有waifu那么便宜。 您必须至少支付{0}才能获得waifu,即使他们的实际价值较低。 + Fuzzy 您必须支付{0}或更多才能认领那个waifu! + Fuzzy 那waifu不是你的。 + Fuzzy 你不能认领自己。 + Fuzzy 你最近离婚了。 您必须等待{0}小时和{1}分钟再次离婚。 + Fuzzy 没人 + Fuzzy 你离婚了一个不喜欢你的waifu。 您收到了{0}。 + Fuzzy 8ball + Fuzzy 恐惧症游戏 + Fuzzy 游戏结束,没人提交。 + Fuzzy 没人投票。 游戏结束,没有赢家。 + Fuzzy 首字母缩写是{0}。 + Fuzzy 恐惧症游戏已经在这个频道中运行。 + Fuzzy 游戏开始。 创建具有以下首字母缩写的句子:{0}。 + Fuzzy 您有{0}秒的时间提交。 + Fuzzy {0}提交了他的判决。 (总{1}个) + Fuzzy 通过输入提交数字投票 + Fuzzy {0}投了票! + Fuzzy 获胜者{0}获得{1}分。 + Fuzzy {0}赢了因为是唯一的提交用户! + Fuzzy + Fuzzy 平局! 两个都挑了{0} + Fuzzy {0}赢了! {1} 打赢了 {2} + Fuzzy 提交关闭 - Fuzzy 动物竞赛已经运行。 + Fuzzy 总计:{0} 平均:{1} + Fuzzy 类别 + Fuzzy 在此服务器上禁用cleverbot。 + Fuzzy 在此服务器上启用cleverbot。 + Fuzzy 在此频道上停用的货币生成功能。 + Fuzzy 在此频道上启用的货币生成功能。 + Fuzzy {0} 个 {1}出现了! 通过输入`{2} pick'来拾取 - plural + plural +Fuzzy 一个{0}出现了! 通过输入`{1} pick`来拾取 + Fuzzy 加载问题失败。 + Fuzzy 游戏开始 - Fuzzy Hangman游戏开始了 + Fuzzy Hangman游戏已在此频道上打开。 + Fuzzy 启动hangman错误。 + Fuzzy “{0} hangman”字词类型列表: + Fuzzy 排行榜 + Fuzzy 您没有足够的{0} + Fuzzy 没有结果 + Fuzzy 采了{0} - Kwoth picked 5* + Kwoth picked 5* +Fuzzy {0}种了{1} - Kwoth planted 5* + Kwoth planted 5* +Fuzzy 琐事游戏已经在这个服务器上运行。 + Fuzzy 琐事游戏 + Fuzzy {0}猜对了! 答案是:{1} + Fuzzy 此服务器上没有运行琐事游戏。 + Fuzzy {0}有{1}分 + Fuzzy 这个问题后停止。 + Fuzzy 时间到! 正确的答案是{0} + Fuzzy {0}猜到了,赢得了游戏! 答案是:{1} + Fuzzy 你不能对自己玩。 + Fuzzy TicTacToe游戏已在此频道中运行。 + Fuzzy 平局! + Fuzzy 开始了一局TicTacToe游戏。 + Fuzzy {0}赢了! - Fuzzy 相配了三个 - Fuzzy 没有地方动了! + Fuzzy 时间已过! - Fuzzy 轮到{0}了 + Fuzzy {0}对{1} + Fuzzy 正在排{0}首歌... + Fuzzy 已停用自动播放。 + Fuzzy 已启用自动播放。 + Fuzzy 默认音量设置为{0}% + Fuzzy 目录队列完成。 + Fuzzy 公平播放 + Fuzzy 完成歌曲 - Fuzzy 停用公平播放。 + Fuzzy 启用公平播放。 + Fuzzy 从位置 + Fuzzy ID + Fuzzy 输入错误。 + Fuzzy 最大播放时间没有限制移除。 + Fuzzy 最大播放时间设置为{0}秒。 + Fuzzy 最大音乐队列大小设置为无限。 + Fuzzy 最大音乐队列大小设置为{0}首。 + Fuzzy 您需要在此服务器上加入语音频道。 + Fuzzy + Fuzzy 现在播放 - Fuzzy 没有活动音乐播放器。 + Fuzzy 没有搜索结果。 + Fuzzy 音乐播放暂停。 + Fuzzy 播放器队列 - {0} / {1}页 - Fuzzy 正在播放 - Fuzzy `#{0}` - ** {1} ** by * {2} *({3}首歌) + Fuzzy 有保存{0}页的播放列表 - Fuzzy 播放列表已删除。 + Fuzzy 无法删除该播放列表。 它不存在,或者你不是它的作者。 + Fuzzy 具有该ID的播放列表不存在。 + Fuzzy 播放列表队列完成。 + Fuzzy 播放列表已保存 - Fuzzy {0}秒限制 + Fuzzy 队列 + Fuzzy 歌加入队列 - Fuzzy 音乐队列已清除。 + Fuzzy 队列已满{0} / {0}。 + Fuzzy 歌被移除 - context: "removed song #5" + context: "removed song #5" +Fuzzy 重复播放当前歌曲 - Fuzzy 重复播放列表 - Fuzzy 重复曲目 - Fuzzy 当前曲目停止重复。 + Fuzzy 音乐播放已恢复。 + Fuzzy 禁用重复播放列表 + Fuzzy 重复播放列表已启用。 + Fuzzy 我现在将在此频道里输出播放,完成,暂停和删除歌曲。 + Fuzzy 跳到‘{0}:{1}’ + Fuzzy 歌播放列表曲被随机。 - Fuzzy 歌曲被移动 - Fuzzy {0}小时 {1}分钟 {2}秒 + Fuzzy 到位置 + Fuzzy 无限 + Fuzzy 音量必须介于0和100之间 + Fuzzy 音量设置为{0}% + Fuzzy 在{0}频道上禁止所有组件的使用。 - Fuzzy 在{0}频道上允许启用所有组件。 - Fuzzy 允许 + Fuzzy {0}身份的所有组件被禁止使用。 - Fuzzy {0}身份的所有组件被允许使用。 - Fuzzy 在此服务器上禁止所有组件的使用。 + Fuzzy 在此服务器上允许所有组件的使用。 + Fuzzy {0}用户的所有模块被禁止使用。 - Fuzzy {0}用户的所有模块被允许使用。 - Fuzzy ID为{1}被加入黑名单{0} + Fuzzy 命令{0}冷却时间现有{1}秒。 + Fuzzy 命令{0}没有冷却时间了,现有所有的冷却时间已被清除。 - Fuzzy 没有设置命令冷却时间。 + Fuzzy 命令成本 - Fuzzy {2}频道上已停用{0} {1}。 - Fuzzy 已在{2}频道上启用{0} {1}的使用。 - Fuzzy 被拒绝 + Fuzzy 以巴{0}添加到已过滤字词列表中。 + Fuzzy 被过滤的词列表 - Fuzzy 已从过滤字词列表中删除{0}。 + Fuzzy 第二个参数无效(必须是{0}和{1}之间的数字) + Fuzzy 在此频道上停用邀请过滤功能。 + Fuzzy 在此频道上启用邀请过滤。 + Fuzzy 在此服务器上停用邀请过滤功能。 + Fuzzy 在此服务器上启用邀请过滤功能。 + Fuzzy 已将权限{0}从#{1}移至#{2} + Fuzzy 在索引#{0}找不到权限 + Fuzzy 未设置费用。 + Fuzzy 命令 - Gen (of command) + Gen (of command) +Fuzzy 组件 - Gen. (of module) + Gen. (of module) +Fuzzy 权限页面第{0}页 + Fuzzy 当前权限身份为{0}。 + Fuzzy 用户现在需要{0}身份才能编辑权限。 + Fuzzy 在该索引中找不到权限。 + Fuzzy 已删除权限#{0} - {1} + Fuzzy 禁止{2}身份使用{0} {1}。 + Fuzzy 允许{2}身份使用{0} {1}。 + Fuzzy - Short of seconds. + Short of seconds. +Fuzzy 此服务器上的{0} {1}已被禁止使用。 + Fuzzy 此服务器上的{0} {1}已被允许使用。 + Fuzzy ID为{1}的{0}从黑名单上移除 + Fuzzy 不可编辑 + Fuzzy {2}用户的{0} {1}已被禁止使用。 + Fuzzy {2}用户的{0} {1}已允许使用。 + Fuzzy 我将不再显示权限警告。 + Fuzzy 我现在将显示权限警告。 + Fuzzy 此频道上的字过滤已停用。 + Fuzzy 此频道上的字过滤已启用。 + Fuzzy 此服务器上的字过滤已停用。 + Fuzzy 此服务器上的字过滤已启用。 + Fuzzy 能力 + Fuzzy 没有最喜爱的动漫 + Fuzzy 开始自动翻译此频道上的消息。 用户消息将被自动删除。 + Fuzzy 您的自动翻译语言已删除。 + Fuzzy 您的自动翻译语言已设置为{0}> {1} + Fuzzy 开始自动翻译此频道上的消息。 + Fuzzy 停止自动翻译此频道上的消息。 + Fuzzy 错误格式或出现错误。 + Fuzzy 找不到该卡。 + Fuzzy + Fuzzy + Fuzzy 漫画# + Fuzzy 竞争模式失败次数 - Fuzzy 竞争模式玩次数 - Fuzzy 竞争模式排名 - Fuzzy 竞争模式胜利次数 + Fuzzy 完成 + Fuzzy 条件 + Fuzzy 花费 + Fuzzy 日期 + Fuzzy 定义: + Fuzzy 放掉 + Fuzzy 剧集 + Fuzzy 发生了错误。 + Fuzzy 例子 + Fuzzy 找不到那个动画。 + Fuzzy 找不到漫画。 + Fuzzy 类型 + Fuzzy 未能找到该标记的定义。 + Fuzzy 身高/体重 + Fuzzy {0} m / {1} kg + Fuzzy 湿度 + Fuzzy 图片搜索: - Fuzzy 找不到该电影。 + Fuzzy 来源或目标语言错误。 + Fuzzy 笑话没加载。 + Fuzzy 纬度/经度 + Fuzzy 等级 + Fuzzy {0}地方标记列表 - Don't translate {0}place + Don't translate {0}place +Fuzzy 地点 + Fuzzy 未加载魔术项目。 + Fuzzy {0}的MAL个人资料 + Fuzzy 机器人的业主没有指定MashapeApiKey。 您不能使用此功能。 + Fuzzy 最小/最大 + Fuzzy 找不到频道。 + Fuzzy 没找到结果。 + Fuzzy 等候接听 - Fuzzy 原始网址 - Fuzzy 需要osu!API密钥。 + Fuzzy 无法检索osu! 线索。 + Fuzzy 找到{0}张图片。 显示随机{0}。 + Fuzzy 找不到用户! 请再次前检查区域和BattleTag。 + Fuzzy 计划看 + Fuzzy 平台 + Fuzzy 找不到能力。 + Fuzzy 找不到宠物小精灵。 + Fuzzy 个人资料链接: - Fuzzy 质量: + Fuzzy 快速游戏时间 - Fuzzy 快赢 - Fuzzy 评分 + Fuzzy 得分: + Fuzzy 搜索: - Fuzzy 无法缩短该链接。 + Fuzzy 短链接 - Fuzzy 出了些问题。 + Fuzzy 请指定搜索参数。 + Fuzzy 状态 + Fuzzy 储存链接 - Fuzzy 直播台{0}已离线。 + Fuzzy 直播台{0}在线有{1}个观众。 + Fuzzy 您在此服务器上关注{0}个直播台 + Fuzzy 您未在此服务器上关注任何直播台。 + Fuzzy 没有这个直播台。 + Fuzzy 直播台可能不存在。 + Fuzzy 已从({1})的通知中移除{0}的直播台 + Fuzzy 状态更改时,我会通知此频道。 + Fuzzy 日出 + Fuzzy 日落 + Fuzzy 温度 + Fuzzy 标题: + Fuzzy 3个最喜欢的动画: + Fuzzy 翻译: + Fuzzy 类型 + Fuzzy 未能找到该字词的定义。 + Fuzzy 链接 + Fuzzy 观众 + Fuzzy 观看 + Fuzzy 无法在指定的维基上找到该字词。 + Fuzzy 请输入目标维基,然后搜索查询。 + Fuzzy 找不到网页。 + Fuzzy 风速 - Fuzzy {0}个被禁止最多的英雄 + Fuzzy 无法yodify您的句子。 + Fuzzy 加入 + Fuzzy `{0} .` {1} [{2:F2} / s] - {3}总计 /s and total need to be localized to fit the context - -`1.` +`1.` +Fuzzy 活动页面#{0} - Fuzzy {0}个用户。 + Fuzzy 作者 + Fuzzy 机器ID + Fuzzy {0} calc命令功能列表 + Fuzzy 此频道的{0}是{1} + Fuzzy 频道主题 - Fuzzy 执行命令 - Fuzzy {0} {1}等于{2} {3} + Fuzzy 转换器可以使用的单位 + Fuzzy 无法将{0}转换为{1}:找不到单位 + Fuzzy 无法将{0}转换为{1}:单位类型不相等 + Fuzzy 创建于 - Fuzzy 加入跨服务器频道。 + Fuzzy 离开跨服务器频道。 + Fuzzy 这是您的CSC令牌 + Fuzzy 自定义Emojis - Fuzzy 错误 + Fuzzy 特征 + Fuzzy ID + Fuzzy 索引超出范围。 + Fuzzy 以下是这个身份的用户列表: + Fuzzy 您不能对其中有用户很多的身份使用此命令来防止滥用。 - Fuzzy 值{0}错误。 - Invalid months value/ Invalid hours value + Invalid months value/ Invalid hours value +Fuzzy 加入Discord + Fuzzy 加入服务器 - Fuzzy ID:{0} 会员数:{1} 业主ID:{2} - Fuzzy 在该网页上找不到服务器。 + Fuzzy 重复列表 - Fuzzy 会员 + Fuzzy 存储 + Fuzzy 讯息 + Fuzzy 消息重复功能 - Fuzzy 名字 + Fuzzy 昵称 + Fuzzy 没有人在玩那个游戏 + Fuzzy 没有活动重复功能。 + Fuzzy 此页面上没有身份。 + Fuzzy 此页面上没有分片。 + Fuzzy 没有主题设置。 + Fuzzy 业主 + Fuzzy 业主IDs + Fuzzy 状态 + Fuzzy {0}个服务器 {1}个文字频道 {2}个语音频道 + Fuzzy 删除所有引号使用{0}关键字。 + Fuzzy {0}页引号 + Fuzzy 此页面上没有引用。 + Fuzzy 没有您可以删除的引用。 + Fuzzy 引用被添加 + Fuzzy 删除了随机引用。 + Fuzzy 区域 + Fuzzy 注册日 - Fuzzy 我将在{2}`({3:d.M.yyyy。}的{4:HH:mm})提醒{0}关于{1} + Fuzzy 无效时间格式。 检查命令列表。 + Fuzzy 新的提醒模板被设定。 + Fuzzy 会每{1}天{2}小时{3}分钟重复{0}。 + Fuzzy 重复列表 - Fuzzy 此服务器上没有运行重复消息。 + Fuzzy #{0}已停止。 + Fuzzy 此服务器上没有找到被重复的消息。 + Fuzzy 结果 + Fuzzy 身份 + Fuzzy 此服务器上所有身份第{0}页: + Fuzzy {1}身份的第{0}页 + Fuzzy 颜色的格式不正确。 例如,使用‘#00ff00’。 + Fuzzy 开始轮流{0}身份的颜色。 + Fuzzy 停止{0}身份颜色轮流 + Fuzzy 此服务器的{0}是{1} + Fuzzy 伺服器資訊 - Fuzzy 分片 + Fuzzy 分片统计 - Fuzzy 分片**#{0} **处于{1}状态与{2}台服务器 + Fuzzy **名称:** {0} **链接:** {1} + Fuzzy 找不到特殊的表情符號。 + Fuzzy 正在播放 {0} 首歌,{1} 首等待播放。 + Fuzzy 文字頻道 - Fuzzy 这是你的房间链接: + Fuzzy 運行時間 + Fuzzy 此用户 {1} 的{0} 是 {2} - Id of the user kwoth#1234 is 123123123123 + Id of the user kwoth#1234 is 123123123123 +Fuzzy 用戶 + Fuzzy 語音頻道 - Fuzzy 你已經加入這場比賽了! + Fuzzy 目前投票結果 + Fuzzy 沒有投票。 + Fuzzy 投票已在這個伺服器進行。 + Fuzzy 📃 {0} 已建立一個投票 which requires your attention: - Fuzzy `{0}.` {1} 有 {2} 票。 - Fuzzy {0} 已投票。 - Kwoth voted. + Kwoth voted. +Fuzzy 私訊我相對數字的答案。 + Fuzzy 發送相對數字的答案在這裡。 + Fuzzy 感謝你的投票, {0} + Fuzzy 共收到 {0}票。 + Fuzzy \ No newline at end of file From 5648394d8ddca4e6ff5febf99765e7470a6d7fe8 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 8 Mar 2017 02:17:35 +0100 Subject: [PATCH 473/746] Update ResponseStrings.nl-NL.resx (POEditor.com) --- .../Resources/ResponseStrings.nl-NL.resx | 380 +++++++++++------- 1 file changed, 227 insertions(+), 153 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx index 1363046f..ef811d3e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx @@ -140,6 +140,7 @@
De aanvraag van @{0} voor een oorlog tegen {1} is niet meer geldig. + Fuzzy Vijand @@ -152,9 +153,11 @@ Ongeldige oorlogs formaat. + Fuzzy Lijst van voorlopende oorlogen. + Fuzzy Niet veroverd. @@ -167,6 +170,7 @@ Geen voorlopende oorlogen. + Fuzzy Grootte. @@ -206,6 +210,7 @@ Geen speciale reacties gevonden. + Fuzzy Geen speciale reacties gevonden met die ID. @@ -467,10 +472,12 @@ Reden: {1} Gebruiker weggeschopt + Fuzzy Lijst van talen {0} + Fuzzy Jouw server's locale is nu {0} - {1} @@ -528,9 +535,11 @@ Reden: {1} Bericht in #{0} verwijdert + Fuzzy Bericht in #{0} bijgewerkt + Fuzzy Gebruikers zijn gedempt @@ -551,15 +560,19 @@ Reden: {1} nieuw bericht + Fuzzy nieuwe bijnaam + Fuzzy Nieuw onderwerp + Fuzzy Bijnaam veranderd + Fuzzy Kan de server niet vinden @@ -569,12 +582,15 @@ Reden: {1} Oud bericht + Fuzzy Oude bijnaam + Fuzzy Oude onderwerp + Fuzzy Fout. Hoogst waarschijnlijk heb ik geen voldoende rechten. @@ -584,6 +600,7 @@ Reden: {1} Actieve Beschermingen. + Fuzzy {0} is nu ** uitgeschakeld** op deze server. @@ -596,6 +613,7 @@ Reden: {1} Geen bescherming aangezet. + Fuzzy Gebruiker's drempel moet tussen {0} en {1} zijn. @@ -771,12 +789,14 @@ __IgnoredChannels__: {2} Gebruikersnaam veranderd + Fuzzy Gebruikers Gebruiker verbannen + Fuzzy {0} is **gedempt** van chatten. @@ -792,15 +812,18 @@ __IgnoredChannels__: {2} Gebruiker verlaten + Fuzzy {0} is **gedempt** van het tekst en stem kanaal. Rol van gebruiker toegevoegd + Fuzzy Rol van gebruiker verwijderd + Fuzzy {0} is nu {1} @@ -825,9 +848,11 @@ __IgnoredChannels__: {2} Spraakkanaal gemaakt + Fuzzy Spraakkanaal vernietigd + Fuzzy Spraak + tekst mogelijkheid uitgezet. @@ -868,9 +893,11 @@ Reden: {1} Aanwezigheid Updates + Fuzzy Gebruiker zacht-verbannen + Fuzzy heeft {0} aan {1} gegeven @@ -980,6 +1007,7 @@ Duurt {1} seconden. Vertel het aan niemand. Shhh. Alleen Voor Bot Eigenaren + Fuzzy Heeft {0} kanaal rechten nodig. @@ -989,9 +1017,11 @@ Duurt {1} seconden. Vertel het aan niemand. Shhh. Command en aliassen. + Fuzzy Commandolijst Geregenereerd. + Fuzzy Typ `{0}h CommandoNaam` om de hulp te zien voor die specifieke commando. b.v `{0}h >8bal` @@ -1013,12 +1043,15 @@ Vergeet niet je discord naam en id in het bericht te zetten. **Lijst met commando's**: <{0}> **Hosting gidsen en documenten kunnen hier gevonden worden**: <{1}> + Fuzzy Lijst Met Commando's + Fuzzy Lijst Met Modules + Fuzzy Typ `{0}cmds ModuleNaam` om een lijst van commando's te krijgen voor die module. bv `{0}cmds games` @@ -1031,6 +1064,7 @@ Vergeet niet je discord naam en id in het bericht te zetten. Inhoudsopgave + Fuzzy Gebruik @@ -1094,10 +1128,10 @@ Vergeet niet je discord naam en id in het bericht te zetten. Het tweede nummer moet groter zijn dan het eerste nummer. - Verandering Van Het Hart + Verandering van het hart - Overwonnen door + Opgeëist door Scheidingen @@ -1174,8 +1208,7 @@ Dit is moreel twijfelachtig🤔 Acrophobie - Spel geëindigd zonder submissies. - Fuzzy + Spel afgelopen zonder inzendingen. Geen stemmen ingestuurdt. Spel geëindigd zonder winnaar. @@ -1257,7 +1290,7 @@ Dit is moreel twijfelachtig🤔 Hangman - + Er is al een spel galgje aan de gang in dit kanaal. @@ -1266,36 +1299,36 @@ Dit is moreel twijfelachtig🤔 - + Scoreboard - + Je hebt niet genoeg {0} - + Geen resultaten - + {0} geplukt Kwoth picked 5* - + {0} heeft {1} geplant Kwoth planted 5* - + Trivia spel - + {0} heeft 'm geraden! Het antwoord was: {1} - + {0} heeft {1} punten @@ -1307,19 +1340,19 @@ Dit is moreel twijfelachtig🤔 - + Je kan niet tegen jezelf spelen. - + Gelijkspel! - + heeft een Boter, Kaas en eieren sessie aangemaakt. - + {0} heeft gewonnen! @@ -1328,25 +1361,25 @@ Dit is moreel twijfelachtig🤔 - + Tijd voorbij! - + {0}'s beurt - + Aan het proberen om {0} liedjes in de wachtrij te zetten... - + Autoplay uitgezet. - + Autoplay aangezet. - + Standaard volume op {0}% gezet @@ -1355,7 +1388,7 @@ Dit is moreel twijfelachtig🤔 - + Liedje afgelopen @@ -1364,43 +1397,44 @@ Dit is moreel twijfelachtig🤔 - + van positie - + ongeldige invoer. - + Maximale speeltijd heeft geen limiet meer. - + Maximale speeltijd op {0} seconden gezet. - + Maximale muziek wachtrij heeft geen limiet meer. - + Maximale muziek wachtrij is nu {0} liedjes. - + Je moet in het spraakkanaal van de server zijn. - + Naam - + Nu aan het spelen + Fuzzy - + Geen actieve muziek speler. - + Geen zoekresultaten. - + Muziek gepauzeerd. @@ -1412,10 +1446,11 @@ Dit is moreel twijfelachtig🤔 - + Pagina {0} van opgeslagen afspeellijsten + - + Afspeellijst verwijderd @@ -1427,32 +1462,32 @@ Dit is moreel twijfelachtig🤔 - + Afspeellijst opgeslagen - + {0}s limiet - + Wachtrij - + Muziek wachtrij leeggemaakt. - + Wachtrij is vol op {0}/{0}. - + Liedje verwijderd context: "removed song #5" - + Huidig liedje word herhaald - + Huidige afspeellijst word herhaald @@ -1476,25 +1511,25 @@ Dit is moreel twijfelachtig🤔 - + Liedjes geschud - + Liedje verzet - + {0}u {1}m {2}s - + Naar positie - + ongelimiteerd - + Volume moet tussen 0 en 100 zijn - + Volume op {0}% gezet @@ -1503,7 +1538,7 @@ Dit is moreel twijfelachtig🤔 - + Toegestaan @@ -1527,13 +1562,13 @@ Dit is moreel twijfelachtig🤔 - + Commando {0} heeft nu een {1}s afkoel tijd. - + Commando {0} heeft geen afkoel tijd meer, en alle bestaande afkoeltijden zijn weggehaald. - + Geen commando afkoeltijden ingesteld. @@ -1545,13 +1580,13 @@ Dit is moreel twijfelachtig🤔 - + Geweigerd - + Lijst van gefilterde worden @@ -1581,15 +1616,15 @@ Dit is moreel twijfelachtig🤔 - + Commando Gen (of command) - + Module Gen. (of module) - + Rechten pagina {0} @@ -1656,7 +1691,7 @@ Dit is moreel twijfelachtig🤔 - + Gestart met het automatisch vertalen van berichten op dit kanaal. Gebruiker berichten worden automatisch verwijderd. @@ -1665,10 +1700,10 @@ Dit is moreel twijfelachtig🤔 - + Gestart met het automatisch vertalen van berichten op dit kanaal. - + Gestopt met het automatisch vertalen van berichten op dit kanaal. @@ -1677,10 +1712,10 @@ Dit is moreel twijfelachtig🤔 - + feit - + hoofdstukken @@ -1698,64 +1733,66 @@ Dit is moreel twijfelachtig🤔 - + Voltooid - + Conditie - + Kost - + Datum - + Definiëren: - + Laten vallen - + Afleveringen - + Fout opgedaagd. - + Voorbeeld - + Mislukt in het vinden van die chinese tekenfilm + Fuzzy - + Mislukt in het vinden van die + Fuzzy - + Genres - + Lengte/Gewicht - + Vochtigheid - + Afbeelding zoekopdracht voor: - + Mislukt in het vinden van die film. - + Grapjes niet geladen. @@ -1768,13 +1805,13 @@ Dit is moreel twijfelachtig🤔 Don't translate {0}place - + Lokatie - + {0}'s MAL profiel @@ -1783,19 +1820,19 @@ Dit is moreel twijfelachtig🤔 - + Geen kanaal gevonden. - + Geen resultaten gevonden. - + Originele URL - + Een osu! API sleutel is vereist. @@ -1822,7 +1859,7 @@ Dit is moreel twijfelachtig🤔 - + Kwaliteit: @@ -1858,16 +1895,16 @@ Dit is moreel twijfelachtig🤔 - + Streamer {0} is offline. - + Streamer {0} is online met {1} kijkers. - + Je volgt {0} streams op deze server. - + Je volgt geen streams op deze server. @@ -1882,25 +1919,25 @@ Dit is moreel twijfelachtig🤔 - + Zon's opgang - + Zon's ondergang - + Temperatuur - + Titel: - + Vertaling: - + Types @@ -1909,7 +1946,7 @@ Dit is moreel twijfelachtig🤔 - + Kijkers @@ -1921,13 +1958,13 @@ Dit is moreel twijfelachtig🤔 - + Pagina niet gevonden - + Wind snelheid - + De {0} meest verbannen kampioenen. @@ -1941,16 +1978,16 @@ Dit is moreel twijfelachtig🤔 `1.` - + Activiteit pagina #{0} - + {0} gebruikers totaal. - + Auteur - + Bot ID @@ -1959,25 +1996,25 @@ Dit is moreel twijfelachtig🤔 - + Kanaal onderwerp - + Commando's uitgevoerd - + {0} {1} is gelijk aan {2} {3} - + Eenheden die gebruikt kunnen worden door de omvormer - + Kan {0} niet naar {1} omvormen: Eenheden niet gevonden - + Kan {0} niet naar {1} omvormen: Type eenheden zijn niet gelijk - + Gemaakt op @@ -1986,31 +2023,31 @@ Dit is moreel twijfelachtig🤔 - + Dit is je CSC token - + Speciale emojis - + Fout - + Kenmerken - + ID - + Index buiten bereik. - + Hier is de lijst met gebruikers in die rollen: - + Om misbruik te voorkomen ben je niet gemachtigd om dit commando te gebruiken op rollen met veel gebruikers. - + Ongeldige {0} waarde. Invalid months value/ Invalid hours value @@ -2020,67 +2057,71 @@ Dit is moreel twijfelachtig🤔 - + ID: {0} +Leden: {1} +Eigenaar ID: {2} - + Geen servers gevonden op die pagina. - + Lijst van de repeater - + Leden - + Geheugen - + Berichten - + Bericht repeater - + Naam - + Roepnaam - + Niemand speelt dat spel. - + Geen rollen op deze pagina. - + Geen shards op deze pagina. - + Geen onderwerp ingesteld. - + Eigenaar - + Eigenaar IDs - + Aanwezigheid - + {0} Servers +{1} Tekst Kanalen +{2} Spraak Kanalen - + Verwijder alle citaten met het trefwoord {0} - + Pagina {0} met citaten - + Geen citaten op deze pagina. Geen verwijderbare citaten gevonden @@ -2092,13 +2133,13 @@ Dit is moreel twijfelachtig🤔 Een willekeurig citaat verwijderd - + Regio - + Geregistreerd op - + Ik zal {0} herinneren om {1} in {2} `({3:d.M.yyyy.} op {4:HH:mm})` @@ -2107,13 +2148,13 @@ Dit is moreel twijfelachtig🤔 - + Herhalen van {0} elke {1} dagen, {2} uren en {3} minuten. - + Lijst van repeaters - + Geen repeaters actief op deze server. @@ -2137,8 +2178,7 @@ Dit is moreel twijfelachtig🤔 - Gestart met het routeren van kleuren voor de rol {0} - Fuzzy + Begonnen met het routeren van kleuren voor de rol {0} Gestopt met het routeren van kleuren voor de rol {0} @@ -2186,5 +2226,39 @@ Dit is moreel twijfelachtig🤔 Spraak Kanalen + + Je maakt al deel uit van deze race! + + + + + + + + + + + + + + + + + + {0} gestemd. + Kwoth voted. + + + + + + + + + + + + + \ No newline at end of file From 77bd6b46344a8f5a8879655271341974a734007a Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 8 Mar 2017 02:17:38 +0100 Subject: [PATCH 474/746] Update ResponseStrings.fr-fr.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.fr-fr.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx index bed50a57..4a8a4a27 100644 --- a/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx +++ b/src/NadekoBot/Resources/ResponseStrings.fr-fr.resx @@ -1531,7 +1531,7 @@ La nouvelle valeur de {0} est {1} ! Lecture en boucle activée. - Je vais désormais afficher les pistess en cours, en pause, terminées et supprimées sur ce salon. + Je vais désormais afficher les pistes en cours, en pause, terminées et supprimées dans ce salon. Saut à `{0}:{1}` From 74b366b83409e7e60cbe352d97c40d8b9a4c567a Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 8 Mar 2017 02:17:41 +0100 Subject: [PATCH 475/746] Update ResponseStrings.de-DE.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.de-DE.resx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx index 879094e3..cd13fb9b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx @@ -1052,7 +1052,7 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Fuzzy - Lister der Befehle + Liste der Befehle Fuzzy @@ -1281,11 +1281,11 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Währungsgeneration in diesem Kanal aktiviert. - {0} zufällige {1} sind erschienen! Sammle sie indem Sie `{2}pick` schreiben + {0} zufällige {1} sind erschienen! Sammlen Sie sie indem Sie `{2}pick` schreiben plural - Eine zufällige {0} ist erschienen! Sammle sie indem Sie `{1}pick` schreiben + Eine zufällige {0} ist erschienen! Sammlen Sie sie indem Sie `{1}pick` schreiben Laden einer Frage fehlgeschlagen. From 2a3653080c02ecceddcbe1bd82291a0c4b61a7f1 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 8 Mar 2017 02:17:44 +0100 Subject: [PATCH 476/746] Update ResponseStrings.ja-JP.resx (POEditor.com) --- .../Resources/ResponseStrings.ja-JP.resx | 301 ++++++++++++------ 1 file changed, 197 insertions(+), 104 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx b/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx index fdfc3df1..62cacf4a 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx @@ -749,58 +749,79 @@ Fuzzy - + 無効な色または権限が不十分なためにエラーが発生しました。 + + TYPO, "Occured" should be 'Occurred' - + ユーザー{1}からロール{0}を削除しました + - + 役割を削除できませんでした。私には十分な権限がありません。 + 役割名を変更しました - + 役割の名前を変更できませんでした。私には十分な権限がありません。 + - + 最高のロールよりも上位のロールは編集できません。 + - + 再生メッセージを削除しました:{0} + - + ロール{0}がリストに追加されました。 + + TYPO. "as" should be 'has' - + {0}は見つかりませんでした。 + - + ロール{0}はすでにリストにあります。 + - + 追加されました。 + - + 回転再生状態が無効になっています。 + - + 回転再生状態が有効になっています。 + - + +回転状態の一覧は次のとおりです: +{0} + - + 回転再生状態は設定されません。 + - + あなたはすでに{0}ロールがあります。 + - + {0}はすでに自己割り当てロールを持っています。 + - + 自己割り当ての役割は今排他的です! + 自分に割り当てられるロールが{0}個あります。 @@ -809,55 +830,72 @@ Fuzzy そのロールは自分に割り当てられません。 - + あなたは{0}ロールを持っていません。 + - + 自己割り当ての役割は現在無制限です + - + 私はあなたにその役割を追加することができません。 `私は役割階層に私の役割よりも高い所有者または他の役割に役割を追加することはできません。 + - + 自己割り当て可能なロールのリストから{0}が削除されました。 + - + あなたはもはや{0}ロールを持っていません。 + - + あなたは今{0}の役割を持っています。 + - + ユーザー{1}にロール{0}を追加しました + + Typo- "Sucessfully" should be 'Successfully' ロールの追加に失敗しました。アクセス権が足りません。 - + 新しいアバターセット! + - + 新しいチャンネル名が設定されました。 + - + 新しいゲームセット! + - + 新しいストリームセット! + - + 新しいチャンネルのトピックセット。 + - + シャード{0}が再接続されました。 + - + シャード{0}再接続中です。 + - + シャットダウン + - + ユーザーは{1}秒ごとに{0}以上のメッセージを送信することはできません。 + @@ -870,19 +908,21 @@ Fuzzy PLURAL - + {0}はこのチャンネルを無視します。 - + {0}はこのチャンネルを無視しなくなりました。 - + ユーザーが同じメッセージを{0}行に投稿した場合は、{1}それらを送信します。 + - + テキストチャンネルが作成されました。 - + テキストチャネルが破棄されました。 + @@ -892,32 +932,38 @@ Fuzzy singular - + ユーザー名 + - + ユーザー名が変更されました + ユーザーズ - Fuzzy - + 追放されたユーザー + - + {0}はチャットから**ミュートされています**。 + - + {0}は、チャットから**ミュートされていません**。 + - + ユーザーが参加しました + 利用者が去った - + {0}はテキストチャットとボイスチャットから**ミュート**されています。 + 利用者にロールを追加した @@ -929,187 +975,234 @@ Fuzzy {0}さんは今{1}になった - + {0}はテキストとボイスチャットから**ミュートされていません**。 - + {0}は{1}音声チャンネルに参加しました - + {0}は音声チャネルを残しました{1} - + {0}は{1}から{2}音声チャネルに移動しました。 + - + {0}は**音声ミュートされました**。 + - + {0}は**音声ミュートされていません**。 - + 音声チャネルが作成されました + - + 音声チャネルが破壊されました + - + 音声+テキスト機能が無効になっています。 + - + 音声+テキスト機能を有効にしました。 + - + **私は役割を管理していません**そして/または**チャンネルを管理しています**許可。だから{0}サーバーで音声+テキストを実行できません。 + - + あなたはこの機能を有効/無効にしています。**私は管理者権限を持っていません**。これによりいくつかの問題が発生する可能性があります。その後、自分でテキストチャネルをクリーンアップする必要があります。 + - + この機能を有効にするには、少なくとも**役割を管理する**と**チャネルを管理する**権限が必要です。 (管理権限が必要です) + + TYPO > "atleast" isn't a word. It's 'At least' - + テキストチャットのユーザー{0} + - + テキストとボイスチャットのユーザー{0} + - + ボイスチャットからのユーザー{0} + - + あなたは{0}サーバーからソフト禁止されました。 +理由:{1} - + Since I'm using "exiled" for banned. need to rethink a new word.. so just leave this one alone + + Fuzzy - + 移行が完了しました! + - + 移行中にエラーが発生しました。詳細については、ボットのコンソールを確認してください。 + - + 存在の更新 - + And this is where using exiled screws me over.. again lol + + Fuzzy - + {0}から{1}に授与されました + - + 次回より良い運がいいよ^ _ ^ + - + おめでとう!あなたは{1}以上で転がって{0}勝った - + デッキが再編されました。 + - + 反転した{0}。 User flipped tails. - + ご想像の通り!あなたは{0}を獲得しました + - + 無効な番号が指定されました。 1を{0}コインにすることができます。 + - + このメッセージに{0}反応を加えて{1}を得る␣ + - + このイベントは最大{0}時間有効です。 + - + 花の反応が始まった! + - + は{0}から{1}に才能を与えました + X has gifted 15 flowers to Y - + {0}には{1}があります + X has Y flowers - + 頭 + - + リーダーボード + - + {2}から{0}人の{1}人のユーザーを獲得しました。 + - + {0}以上の賭けはできません + - + あなたは{0}未満に賭けることはできません + - + あなたに十分な{0}がありません。 + - + デッキにはもうカードがありません。 + - + 抽選でユーザーを入力しました。 + - + あなたは{0}をロールした。 + - + 賭ける - + 素晴らしい!おめでとう! x {0} - + 単一の{0}、x {1} - + うわー!幸運な! 3種類の! x {0} + - + よくやった! 2つの{0} - ベットx {1} + - + ウォン - + ユーザーは{0}を取得するために秘密のコードを入力する必要があります。 +{1}秒続く。誰にも言わないでください。 :ウィンク: - + 卑劣なゲームイベントが終了しました。 {0}ユーザーは報酬を受け取った。 - + 卑劣なゲームステータスイベントが開始されました - + テイル - + {1}から{0}を正常に受け取りました + - + ユーザーが{2}をあまり持っていないので{1}から{0}を取ることができませんでした! + - + ボットの所有者のみ + - + {0}チャンネル許可が必要です。 + - + コマンドとエイリアス + From a1830fbc780ca0d9dcb1c7ec921ff2d6dec85958 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 8 Mar 2017 02:17:46 +0100 Subject: [PATCH 477/746] Update ResponseStrings.pl-PL.resx (POEditor.com) --- .../Resources/ResponseStrings.pl-PL.resx | 142 +++++++++--------- 1 file changed, 72 insertions(+), 70 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx index eb8b202b..381b43c2 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx @@ -856,7 +856,7 @@ Powód: {1} Włączasz/Wyłączasz tą funkcję i **Nie mam uprawnień ADMINISTRATORA**. Może to spowodować problemy i będziesz musiał czyścić kanały tekstowe sam. - + By włączyć tą funkcję, muszę posiadać uprawnienia: **zarządzanie rolami** i **zarządzanie kanałami**. (Preferowane uprawnienia administratora) Użytkownik {0} z tekstowego czatu @@ -901,7 +901,7 @@ Powód: {1} Talia została przetasowana. - + wyrzucono {0}. User flipped tails. @@ -950,7 +950,7 @@ Powód: {1} W talii nie ma więcej kart. - + Wylosowano użytkownika Wyrzucono {0} @@ -1117,7 +1117,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Fuzzy - + Zdobyta przez Rozwody @@ -1138,11 +1138,13 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + lubi teraz {0} zamiast {1}. + +*Czy to aby na pewno moralne?* Make sure to get the formatting right, and leave the thinking emoji - + Musisz poczekać {0} godzin i {1} minut aby zmienić swój obiekt westchnień. @@ -1221,19 +1223,19 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Zwycięzcą jest {0} z {1} punktami. - + Użytkownik {0} wygrywa, ponieważ jako jedyny coś zgłosił! Pytanie - + Remis! Dwie osoby wybrały {0} {0} wygrał! {1} pokonuje {2} - + Zgłoszenia zakończone Wyścig zwierzaków właśnie się odbywa. @@ -1261,7 +1263,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś plural - + {0} się pojawiły! Zdobądź je, pisząc `{1}pick` Nie udało się załadować pytania. @@ -1401,7 +1403,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Maksymalna długość kolejki ustawiona na {5} utworów. - + Musisz być na kanale głosowym na tym serwerze. Imię @@ -1422,7 +1424,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Gra utwór @@ -1458,7 +1460,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Kolejka wyczyszczona. - + Zapełnienie kolejki: {0}/{0} Usunięto utwór @@ -1504,7 +1506,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + bez limitu Głośność musi być pomiędzy 0 a 100. @@ -1513,67 +1515,67 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Głośność ustawiona na {0}% - + Wyłączono użycie WSZYSTKICH MODÓŁÓW na kanale {0}. - + Włączono użycie WSZYSTKICH MODÓŁÓW na kanale {0}. - + Wyłączono użycie WSZYSTKICH MODÓŁÓW dla roli {0}. - + Włączono użycie WSZYSTKICH MODÓŁÓW dla roli {0}. - + Wyłączono użycie WSZYSTKICH MODÓŁÓW na tym serwerze. - + Włączono użycie WSZYSTKICH MODÓŁÓW na tym serwerze. - + Wyłączono użycie WSZYSTKICH MODÓŁÓW dla użytkownika {0}. - + Włączono użycie WSZYSTKICH MODÓŁÓW dla użytkownika {0}. - + Na czarną listę wpisano użytkownika {0} z ID {1} Komenda {0} ma teraz {1}-sekundowy cooldown. - + Komenda {0} nie ma teraz cooldown'a. Wszystkie aktywne cooldown'y zostały zresetowane. - + Żadna komenda nie ma cooldown'a. - + Komenda kosztuje - + Wyłączono użycie {0} {1} na kanale {2}. - + Włączono użycie {0} {1} na kanale {2}. - + Odmówiono - + Dodano słowo {0} do listy odfiltrowanych słów. - + Lista odfiltrowanych słów - + Usunięto słowo {0} z listy odfiltrowanych słów. - + Błędny drugi parametr. (Musi być to liczba od {0} do {1}) @@ -1588,10 +1590,10 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Przeniesiono uprawnienia {0} z #{1} to #{2} - + Nie znaleziono uprawnień w indeksie #{0} @@ -1605,80 +1607,80 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Gen. (of module) - + Strona uprawnień {0} - + Użytkownicy wymagają roli {0}, by móc edytować uprawnienia. - + Żadne uprawnienia nie zostały znalezione w tym indeksie. - + przeniesiono uprawnienia #{0} - {1} - + Wyłączono użycie {0} {1} dla roli {2}. - + Włączono użycie {0} {1} dla roli {2}. sek. Short of seconds. - + Wyłączono użycie {0} {1} na tym serwerze. - + Włączono użycie {0} {1} na tym serwerze. - + Z czarnej listy usunięto użytkownika {0} z ID {1} - + nie do edytowania - + Wyłączono użycie {0} {1} dla użytkownika {2}. - + Włączono użycie {0} {1} dla użytkownika {2}. - + Nie będę więcej pokazywać ostrzeżeń dotyczących uprawnień. - + Będę pokazywać ostrzeżenia dotyczące uprawnień. - + Filtrowanie słów wyłączone na tym kanale. - + Filtrowanie słów włączone na tym kanale. - + Filtrowanie słów wyłączone na tym serwerze. - + Filtrowanie słów włączone na tym serwerze. Zdolności - + Brak ulubionego zwierzęcia Zaczęto automatyczne tłumaczenie wiadomości na tym kanale. Wiadomości użytkowników będą automatycznie usuwane. - + twój auto-tłumaczący język został usunięty. - + twój auto-tłumaczący język został ustawiony {0}>{1} Zaczęto automatyczne tłumaczenie wiadomości na tym kanale. @@ -1687,7 +1689,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Zakończono automatyczne tłumaczenie wiadomości na tym kanale. - + Złe dane wejściowe albo coś poszło nie tak. Nieznaleziono tej karty. @@ -1702,25 +1704,25 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Przegrane rywalizacje - + Grane rywalizacje - + Ranking rywalizacji - + Wygrane rywalizacje Zakończony - + Warunek - + Koszt Data @@ -1750,7 +1752,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Gatunki - + Nie udało się znaleźć definicji dla tego tagu. Wysokość/szerokość @@ -1762,7 +1764,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Wilgotność - + Szukanie obrazka dla: Wyszukiwanie tego filmu nie powiodło się. @@ -1784,7 +1786,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Don't translate {0}place - + Lokalizacja Magiczne przedmioty nie zostały załadowane. @@ -1793,10 +1795,10 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś MAL użytkownika {0} - + Właściciel bota nie sprecyzował MashapeApiKey. Nie możesz użyć tej funkcji. - + Min/Max Nie znaleziono kanału. @@ -1808,7 +1810,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Oryginalny URL @@ -1817,7 +1819,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Znaleziono {0} obrazków. Pokazuję przypadkowe {0} From 1be2512ca19d052d20a89cf751b7e0555a5f2c22 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 8 Mar 2017 02:17:49 +0100 Subject: [PATCH 478/746] Update ResponseStrings.pt-BR.resx (POEditor.com) From d1060932b05ef8e880673f250884f68607765981 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 8 Mar 2017 02:17:51 +0100 Subject: [PATCH 479/746] Update ResponseStrings.ru-RU.resx (POEditor.com) --- .../Resources/ResponseStrings.ru-RU.resx | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx index 20b53a3d..9efa419f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx @@ -2286,38 +2286,40 @@ IDВладельца: {2} Fuzzy - + Вы уже участвуете в этой гонке! - + Результаты опроса - + Не получено ни одного ответа. - + На данном сервере уже идёт опрос. - + {0} создал опрос, требующий Вашего внимания: + Fuzzy - + '{0}.' У {1} {2} голосов. + Fuzzy - + {0} проголосовал. Kwoth voted. - + Отправьте сообщение в этом текстовом канале с номером, соответствующему Вашему ответу. - + Отправьте сообщение в этом текстовом канале с номером, соответствующему Вашему ответу. - + Спасибо за Ваш ответ, {0}. - + Всего получено {0} ответов. \ No newline at end of file From cd997639493f49b7a51a5bd7bb45fb3b86a19c6e Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 8 Mar 2017 02:17:54 +0100 Subject: [PATCH 480/746] Update ResponseStrings.sr-cyrl-rs.resx (POEditor.com) --- .../Resources/ResponseStrings.sr-cyrl-rs.resx | 296 +++++++++--------- 1 file changed, 148 insertions(+), 148 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx index 5e1f33f3..69809693 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx @@ -1169,10 +1169,10 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Твој афинитет је ресетован, Више немаш особу која ти се свиђа. - + хоће да буде waifu од {0} @@ -1181,16 +1181,16 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + не можеш ставити афинитет на себе, егоманијаче. - + Ни једна waifu није тако јефтина. Мораш да платиш бар {0} да би имао waifu, чак иако је њена вредност мања. - + Мораш да платиш {0} или више да би присвојио ту waifu. Та waifu није твоја. @@ -1205,7 +1205,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Нико - + Развео си waifu којој се не свиђаш. Добио си {0} назад. 8кугла @@ -1220,16 +1220,16 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Нема гласова. Игра је се завршила без победника. - + Акроним је био {0}. Игра акрофобије већ постоји у овом каналу. - + Игра је почела. Направи реченицу са овим акронимом: {0} - + Имате {0} секунди за унос. @@ -1238,22 +1238,22 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Гласај тако што укуцаш број уноса. - + {0} је гласао! - + Победник је {0} са {1} поена. - + {0} је победник зато што је једини корисник са уносом. Питање - + Нерешено! Обоје сте изабрали {0} - + {0} је победио! {1} је јаче од {2} Уноси затворени @@ -1315,11 +1315,11 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Нема резултата. - + је убрао {0} Kwoth picked 5* - + {0} је засадио {1} Kwoth planted 5* @@ -1329,22 +1329,22 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Игра тривије - + {0} је погодио! Одговор је био: {1} Нема тривије у току на овом серверу. - + {0} има {1} поена Игра се зауставља после овог питања. - + Време је истекло! Тачан одговор је {0} - + {0} је погодио и ПОБЕДИО игру! Одговор је био: {1} Не можеш играти против себе. @@ -1359,7 +1359,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. је направио игру икс-окса. - + {0} је победио! Три спојене @@ -1371,13 +1371,13 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Време је истекло! - + {0}-ов потез. - + {0} против {1} - + Покушавам да учитам {0} песама... Аутопуштање је угашено. @@ -1479,35 +1479,35 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Песма је учитана - + Музички ред је очишћен. - + Песма је обрисана context: "removed song #5" - + Понављам тренутну песму - + Понављам плејлисту - + Понављам нумеру - + Понављање нумбере стопирано. - + Музика је пуштена. - + Понављање плејлисте је угашено. - + Понављање плејлисте је упаљено. @@ -1516,19 +1516,19 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Песме су измешане - + Песме су померене - + На позицију - + неограничено @@ -1543,7 +1543,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Дозвољено @@ -1573,10 +1573,10 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Нема кулдауна за команде. - + Цене команди @@ -1585,13 +1585,13 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Забрањено - + Листа филтрираних речи @@ -1600,16 +1600,16 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Филтрирање позивница је угашено на овом каналу. - + Филтрирање позивница је упаљено на овом каналу. - + Филтрирање позивница је угашено на овом серверу. - + Филтрирање позивница је упаљено на овом серверу. @@ -1618,14 +1618,14 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Нема постављених цена. - + команде Gen (of command) - + модула Gen. (of module) @@ -1650,7 +1650,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + сек. Short of seconds. @@ -1663,7 +1663,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + неизмењиво @@ -1672,58 +1672,58 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Више нећу приказивати упозорења за дозволе. - + Од сада ћу приказивати упозорења за дозволе. - + Филтрирање речи је угашено на овом каналу. - + Филтрирање речи је упаљено на овом каналу. - + Филтрирање речи је угашено на овом серверу. - + Филтрирање речи је упаљено на овом серверу. - + Моћи - + Нема омиљених анимеа. - + твој језик ауто-превођења је обрисан. - + Започето аутоматско превођење порука на овом каналу - + Стопирано аутоматско превођење порука на овом каналу - + Није добар формат уноса, или нешто друго. - + Не могу да нађем ту карту. - + чињеница - + Поглавља - + Стрип # @@ -1735,83 +1735,83 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Такмичних победа - + Завршено - + Услови - + Цена - + Датум - + Дефиниши: - + Испуштене - + Епизода - + Дошло је до грешке. - + Пример - + Није нађен тај аниму. - + Није нађен тај манго. - + Жанрови - + Није успешно проналажење дефиниције за тај таг. - + Висина/Ширина - + {0}м/{1}кг - + Влажност Ваздуха - + Претрага слика за: - + Филм није нађен. - + Неисправан почетни или крајњи језик. - + Вицеви нису учитани - + Лат/Лонг - + Ниво Don't translate {0}place - + Место - + Магични предмети нису учитани. @@ -1820,19 +1820,19 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Мин/Макс - + Канал није пронађен. - + Нема резултата. - + Паузирано - + Оригинални линк @@ -1847,55 +1847,55 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Планира да гледа - + Платформа - + Није пронађена моћ. - + Није пронађен покемон. - + Линк ка профилу: - + Квалитет: - + Време игре у квик моду - + Победа у квик моду - + Рејтинг - + Скор: - + Тражи за: - + Није успешно скраћивање тог линка. - + Кратак линк - + Дошло је до грешке. - + Унеси параметре за претрагу. - + Статус - + Линк Продавнице @@ -1907,73 +1907,73 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Не пратиш ниједан стрим ан овом серверу. - + Нема тог стрима. - + Стрим вероватно не постоји. - + Обавестићу овај канал када се статус промени. - + Излазак сунца - + Залазак сунца - + Температура - + Наслов: - + 3 омиљене аниме: - + Превод: - + Типови - + Неуспешно проналажење дефиниције за тај термин - + Линк - + Гледаоци - + Гледа - + Није успешно проналажење термина на тој викији. - + Унеси име викије, а затим термин за претрагу. - + Страница није нађена. - + Брзина ветра - + Јодификовање реченице није успешно. - + Ушао @@ -1987,10 +1987,10 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Аутор - + Бот ИД @@ -1999,10 +1999,10 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Тема канала - + Извршених команди @@ -2017,7 +2017,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. - + Направљен @@ -2242,32 +2242,32 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Fuzzy - + Већ си у овој трци! - + Тренутни резултати анкете - + Нема гласова. - + Анкета већ постоји на овом серверу. - + 📃 {0} је направио анкету која захтева вашу пажњу. - + {0} је гласао Kwoth voted. - + Пошаљите ми број одговора у приватној поруци. - + Пошаљите број одговора у овом каналу. From 2ef57465cfdf0ab92fd828ff606106da06bdf082 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 8 Mar 2017 02:17:57 +0100 Subject: [PATCH 481/746] Update ResponseStrings.sv-SE.resx (POEditor.com) --- .../Resources/ResponseStrings.sv-SE.resx | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx index 305c8788..2eb472e8 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx @@ -118,7 +118,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Denna bas är redan tagen eller förstörd. + Denna bas är redan tagen eller förstörd. Denna bas är redan förstörd. @@ -194,8 +194,7 @@ Alla anpassade emojis uppgifter borttagna. - Anpassad emoji har blivit raderad. - + Anpassad emoji har blivit raderad Otillräckliga behörigheter. Kräver Bot ägande för globala anpassade reaktioner, och administratör för server anpassade reaktioner. @@ -217,10 +216,10 @@ Ingen egengjord reaktion funnen med det id. - svar + Svar - Egengjord reaktion statistiker. + Egengjord reaktion statistiker Statistiker rensade för {0} egengjorda reaktioner. @@ -229,7 +228,7 @@ Inga statistik för den triggern funnen, inget återgärd gjord. - Trigger. + Trigger Automatisk hentai stoppad. @@ -238,11 +237,10 @@ Inga resultat hittades. - -{0} har redan svimmat + {0} har redan svimmat. - {0} har redan full hälsa + {0} har redan full hälsa. din typ är redan {0} From 6f5850830ad191876ce764102175d0ee92673054 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 8 Mar 2017 02:17:59 +0100 Subject: [PATCH 482/746] Update ResponseStrings.tr-TR.resx (POEditor.com) From a20fa2ef14b0d4693472ee6ca1b7a254a7b5fb1b Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 8 Mar 2017 02:18:02 +0100 Subject: [PATCH 483/746] Update ResponseStrings.en-US.resx (POEditor.com) --- .../Resources/ResponseStrings.en-US.resx | 371 +++++++++--------- 1 file changed, 186 insertions(+), 185 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.en-US.resx b/src/NadekoBot/Resources/ResponseStrings.en-US.resx index 8f964f3a..51f02785 100644 --- a/src/NadekoBot/Resources/ResponseStrings.en-US.resx +++ b/src/NadekoBot/Resources/ResponseStrings.en-US.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 That base is already claimed or destroyed. @@ -136,7 +136,7 @@ {0} claimed a base #{1} in a war against {2} - @{0} You already claimed base #{1}. You can't claim a new one. + @{0} You already claimed base #{1}. You can't claim a new one. Claim from @{0} in a war against {1} has expired. @@ -245,10 +245,10 @@ Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. - You can't attack again without retaliation! + You can't attack again without retaliation! - You can't attack yourself. + You can't attack yourself. {0} has fainted! @@ -260,16 +260,16 @@ {0} has {1} HP remaining. - You can't use {0}. Type `{1}ml` to see a list of moves you can use. + You can't use {0}. Type `{1}ml` to see a list of moves you can use. Movelist for {0} type - It's not effective. + It's not effective. - You don't have enough {0} + You don't have enough {0} revived {0} with one {1} @@ -281,13 +281,13 @@ Your type has been changed to {0} for a {1} - It's somewhat effective. + It's somewhat effective. - It's super effective! + It's super effective! - You used too many moves in a row, so you can't move! + You used too many moves in a row, so you can't move! Type of {0} is {1} @@ -448,7 +448,7 @@ Reason: {1} Greet announcements enabled on this channel. - You can't use this command on users with a role higher or equal to yours in the role hierarchy. + You can't use this command on users with a role higher or equal to yours in the role hierarchy. Images loaded after {0} seconds! @@ -473,19 +473,19 @@ Reason: {1} List of languages - Your server's locale is now {0} - {1} + Your server's locale is now {0} - {1} - Bot's default locale is now {0} - {1} + Bot's default locale is now {0} - {1} - Bot's language is set to {0} - {1} + Bot's language is set to {0} - {1} - Failed setting locale. Revisit this command's help. + Failed setting locale. Revisit this command's help. - This server's language is set to {0} - {1} + This server's language is set to {0} - {1} {0} has left {1} @@ -538,10 +538,10 @@ Reason: {1} Muted - singular "User muted." + singular "User muted." - I don't have the permission necessary for that most likely. + I don't have the permission necessary for that most likely. New mute role set. @@ -562,7 +562,7 @@ Reason: {1} Nickname changed - Can't find that server + Can't find that server No shard with that ID found. @@ -577,7 +577,7 @@ Reason: {1} Old topic - Error. Most likely I don't have sufficient permissions. + Error. Most likely I don't have sufficient permissions. Permissions for this server are reset. @@ -637,7 +637,7 @@ Reason: {1} Failed to rename role. I have insufficient permissions. - You can't edit roles higher than your highest role. + You can't edit roles higher than your highest role. Removed the playing message: {0} @@ -683,13 +683,13 @@ Reason: {1} That role is not self-assignable. - You don't have {0} role. + You don't have {0} role. Self assigned roles are now not exclusive! - I am unable to add that role to you. `I can't add roles to owners or other roles higher than my role in the role hierarchy.` + I am unable to add that role to you. `I can't add roles to owners or other roles higher than my role in the role hierarchy.` {0} has been removed from the list of self-assignable roles. @@ -731,7 +731,7 @@ Reason: {1} Shutting down - Users can't send more than {0} messages every {1} seconds. + Users can't send more than {0} messages every {1} seconds. Slow mode disabled. @@ -794,10 +794,10 @@ Reason: {1} {0} has been **muted** from text and voice chat. - User's role added + User's role added - User's role removed + User's role removed {0} is now {1} @@ -833,7 +833,7 @@ Reason: {1} Enabled voice + text feature. - I don't have **manage roles** and/or **manage channels** permission, so I cannot run `voice+text` on {0} server. + I don't have **manage roles** and/or **manage channels** permission, so I cannot run `voice+text` on {0} server. You are enabling/disabling this feature and **I do not have ADMINISTRATOR permissions**. This may cause some issues, and you will have to clean up text channels yourself afterwards. @@ -861,7 +861,7 @@ Reason: {1} Migration done! - Error while migrating, check bot's console for more information. + Error while migrating, check bot's console for more information. Presence updates @@ -918,13 +918,13 @@ Reason: {1} Awarded {0} to {1} users from {2} role. - You can't bet more than {0} + You can't bet more than {0} - You can't bet less than {0} + You can't bet less than {0} - You don't have enough {0} + You don't have enough {0} No more cards in the deck. @@ -955,7 +955,7 @@ Reason: {1} Users must type a secret code to get {0}. -Lasts {1} seconds. Don't tell anyone. Shhh. +Lasts {1} seconds. Don't tell anyone. Shhh. SneakyGame event ended. {0} users received the reward. @@ -970,7 +970,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. successfully took {0} from {1} - was unable to take {0} from{1} because the user doesn't have that much {2}! + was unable to take {0} from{1} because the user doesn't have that much {2}! Back to ToC @@ -994,7 +994,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Type `{0}h CommandName` to see the help for that specified command. e.g. `{0}h >8ball` - I can't find that command. Please verify that the command exists before trying again. + I can't find that command. Please verify that the command exists before trying again. Description @@ -1003,7 +1003,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. You can support the NadekoBot project on Patreon <{0}> or Paypal <{1}> -Don't forget to leave your discord name or id in the message. +Don't forget to leave your discord name or id in the message. **Thank you** ♥️ @@ -1101,9 +1101,6 @@ Don't forget to leave your discord name or id in the message. Likes - - Nobody - Price @@ -1114,7 +1111,7 @@ Don't forget to leave your discord name or id in the message. Top Waifus - your affinity is already set to that waifu or you're trying to remove your affinity while not having one. + your affinity is already set to that waifu or you're trying to remove your affinity while not having one. changed their affinity from {0} to {1}. @@ -1129,7 +1126,7 @@ Don't forget to leave your discord name or id in the message. Your affinity is reset. You no longer have a person you like. - wants to be {0}'s waifu. Aww <3 + wants to be {0}'s waifu. Aww <3 claimed {0} as their waifu for {1}! @@ -1138,15 +1135,12 @@ Don't forget to leave your discord name or id in the message. You have divorced a waifu who likes you. You heartless monster. {0} received {1} as a compensation. - - You have divorced a waifu who doesn't like you. You received {0} back. - - you can't set affinity to yourself, you egomaniac. + you can't set affinity to yourself, you egomaniac. 🎉 Their love is fulfilled! 🎉 -{0}'s new value is {1}! +{0}'s new value is {1}! No waifu is that cheap. You must pay at least {0} to get a waifu, even if their actual value is lower. @@ -1158,11 +1152,17 @@ Don't forget to leave your discord name or id in the message. That waifu is not yours. - You can't claim yourself. + You can't claim yourself. You divorced recently. You must wait {0} hours and {1} minutes to divorce again. + + Nobody + + + You have divorced a waifu who doesn't like you. You received {0} back. + 8ball @@ -1206,7 +1206,7 @@ Don't forget to leave your discord name or id in the message. Question - It's a draw! Both picked {0} + It's a draw! Both picked {0} {0} won! {1} beats {2} @@ -1217,9 +1217,6 @@ Don't forget to leave your discord name or id in the message. Animal Race is already running. - - You've already joined this race! - Total: {0} Average: {1} @@ -1261,13 +1258,13 @@ Don't forget to leave your discord name or id in the message. Starting hangman errored. - List of "{0}hangman" term types: + List of "{0}hangman" term types: Leaderboard - You don't have enough {0} + You don't have enough {0} No results @@ -1299,13 +1296,13 @@ Don't forget to leave your discord name or id in the message. Stopping after this question. - Time's up! The correct answer was {0} + Time's up! The correct answer was {0} {0} guessed it and WON the game! The answer was: {1} - You can't play against yourself. + You can't play against yourself. TicTacToe Game is already running in this channel. @@ -1329,7 +1326,7 @@ Don't forget to leave your discord name or id in the message. Time expired! - {0}'s move + {0}'s move {0} vs {1} @@ -1416,10 +1413,10 @@ Don't forget to leave your discord name or id in the message. Playlist deleted. - Failed to delete that playlist. It either doesn't exist, or you are not its author. + Failed to delete that playlist. It either doesn't exist, or you are not its author. - Playlist with that ID doesn't exist. + Playlist with that ID doesn't exist. Playlist queue complete. @@ -1444,7 +1441,7 @@ Don't forget to leave your discord name or id in the message. Removed song - context: "removed song #5" + context: "removed song #5" Repeating current song @@ -1573,14 +1570,14 @@ Don't forget to leave your discord name or id in the message. Moved permission {0} from #{1} to #{2} - Can't find permission at index #{0} + Can't find permission at index #{0} No costs set. command - Gen. (of command) + Gen (of command) module @@ -1672,7 +1669,7 @@ Don't forget to leave your discord name or id in the message. Bad input format, or something went wrong. - Couldn't find that card. + Couldn't find that card. fact @@ -1763,7 +1760,7 @@ Don't forget to leave your discord name or id in the message. List of {0}place tags - Don't translate {0}place + Don't translate {0}place Location @@ -1772,10 +1769,10 @@ Don't forget to leave your discord name or id in the message. Magic Items not loaded. - {0}'s MAL profile + {0}'s MAL profile - Bot owner didn't specify MashapeApiKey. You can't use this functionality. + Bot owner didn't specify MashapeApiKey. You can't use this functionality. Min/Max @@ -1871,10 +1868,10 @@ Don't forget to leave your discord name or id in the message. No such stream. - Stream probably doesn't exist. + Stream probably doesn't exist. - Removed {0}'s stream ({1}) from notifications. + Removed {0}'s stream ({1}) from notifications. I will notify this channel when status changes. @@ -1936,7 +1933,7 @@ Don't forget to leave your discord name or id in the message. `{0}.` {1} [{2:F2}/s] - {3} total /s and total need to be localized to fit the context - -`1.` +`1.` Activity page #{0} @@ -2139,7 +2136,7 @@ Owner ID: {2} No colors are in the correct format. Use `#00ff00` for example. - Started rotating {0} role's color. + Started rotating {0} role's color. Stopped rotating colors for the {0} role @@ -2187,6 +2184,9 @@ Owner ID: {2} Voice channels + + You've already joined this race! + Current poll results @@ -2218,4 +2218,5 @@ Owner ID: {2} {0} total votes cast. + \ No newline at end of file From 1fe229fb7a85eac7e3742b4fddbc81c5d35f9ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mehmet=20Do=C4=9Fan?= Date: Wed, 8 Mar 2017 04:52:26 +0200 Subject: [PATCH 484/746] Update ResponseStrings.tr-TR.resx --- .../Resources/ResponseStrings.tr-TR.resx | 4192 +++++++++-------- 1 file changed, 2097 insertions(+), 2095 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx b/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx index 8ebe09d9..49168340 100644 --- a/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx @@ -1,4 +1,4 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Cette base a déjà été revendiquée ou détruite. - - - Cette base est déjà détruite. - - - Cette base n'est pas revendiquée. - - - Base #{0} **DETRUITE** dans une guerre contre {1} - - - {0} a **ABANDONNÉ** la base #{1} dans une guerre contre {2} - - - {0} a revendiqué une base #{1} dans une guerre contre {2} - - - @{0} Vous avez déjà revendiqué la base #{1}. Vous ne pouvez pas en revendiquer une nouvelle. - - - La demande de la part de @{0} pour une guerre contre {1} a expiré. - Fuzzy - - - Ennemi - - - Informations concernant la guerre contre {0} - - - Numéro de base invalide. - - - La taille de la guerre n'est pas valide. - Fuzzy - - - Liste des guerres en cours - Fuzzy - - - non réclamé - - - Vous ne participez pas a cette guerre. - - - @{0} Vous ne participez pas à cette guerre ou la base a déjà été détruite. - - - Aucune guerre en cours. - Fuzzy - - - Taille - - - La guerre contre {0} a déjà commencé! - - - La guerre contre {0} commence! - - - La guerre contre {0} est terminée. - - - Cette guerre n'existe pas. - - - La guerre contre {0} a éclaté ! - - - Statistiques de réactions personnalisées effacées. - - - Réaction personnalisée supprimée - - - Permissions insuffisantes. Nécessite d'être le propriétaire du Bot pour avoir les réactions personnalisées globales, et Administrateur pour les réactions personnalisées du serveur. - - - Liste de toutes les réactions personnalisées - - - Réactions personnalisées - - - Nouvelle réaction personnalisée - - - Aucune réaction personnalisée trouvée. - Fuzzy - - - Aucune réaction personnalisée ne correspond à cet ID. - - - Réponse - - - Statistiques des Réactions Personnalisées - - - Statistiques effacées pour {0} réaction personnalisée. - - - Pas de statistiques pour ce déclencheur trouvées, aucune action effectuée. - - - Déclencheur - - - Autohentai arrêté. - - - Aucun résultat trouvé. - - - {0} est déjà inconscient. - - - {0} a tous ses PV. - - - Votre type est déjà {0} - - - Vous avez utilisé {0}{1} sur {2}{3} pour {4} dégâts. - Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. - - - Vous ne pouvez pas attaquer de nouveau sans représailles ! - - - Vous ne pouvez pas vous attaquer vous-même. - - - {0} s'est évanoui! - - - Vous avez soigné {0} avec un {1} - - - {0} a {1} points de vie restants. - - - Vous ne pouvez pas utiliser {0}. Ecrivez `{1}ml` pour voir la liste des actions que vous pouvez effectuer. - - - Liste des attaques pour le type {0} - - - Ce n'est pas très efficace. - - - Vous n'avez pas assez de {0} - - - Vous avez ressuscité {0} avec un {1} - - - Vous vous êtes ressuscité avec un {0} - - - Votre type a bien été modifié de {0} à {1} - - - C'est légèrement efficace. - - - C'est très efficace ! - - - Vous avez utilisé trop de mouvements d'affilée, vous ne pouvez donc plus bouger! - - - Le type de {0} est {1} - - - Utilisateur non trouvé. - - - Vous vous êtes évanoui, vous n'êtes donc pas capable de bouger! - - - **L'affectation automatique de rôle** à l'arrivé d'un nouvel utilisateur est désormais **désactivée**. - - - **L'affectation automatique de rôle** à l'arrivé d'un nouvel utilisateur est désormais **activée**. - - - Liens - - - Avatar modifié - - - Vous avez été banni du serveur {0}. -Raison: {1} - - - bannis - PLURAL - - - Utilisateur banni - - - Le nom du Bot a changé pour {0} - - - Le statut du Bot a changé pour {0} - - - La suppression automatique des annonces de départ a été désactivée. - - - Les annonces de départ seront supprimées après {0} secondes. - - - Annonce de départ actuelle : {0} - - - Activez les annonces de départ en entrant {0} - - - Nouvelle annonce de départ définie. - - - Annonce de départ désactivée. - - - Annonce de départ activée sur ce salon. - - - Nom du salon modifié - - - Ancien nom - - - Sujet du salon modifié - - - Nettoyé. - - - Contenu - - - Rôle {0} créé avec succès - - - Salon textuel {0} créé. - - - Salon vocal {0} créé. - - - Mise en sourdine effectuée. - - - Serveur {0} supprimé - - - Suppression automatique des commandes effectuées avec succès, désactivée. - - - Suppression automatique des commandes effectuées avec succès, activée. - - - Le salon textuel {0} a été supprimé. - - - Le salon vocal {0} a été supprimé. - - - MP de - - - Nouveau donateur ajouté avec succès. Montant total des dons de cet utilisateur : {0} 👑 - - - Merci aux personnes ci-dessous pour avoir permis à ce projet d'exister! - - - Je transmettrai désormais les MPs à tous les propriétaires. - - - Je transmettrai désormais les MPs seulement au propriétaire principal. - - - Je transmettrai désormais les MPs. - - - Je ne transmettrai désormais plus les MPs. - - - La suppression automatique des messages d'accueil a été désactivé. - - - Les messages d'accueil seront supprimés après {0} secondes. - - - MP de bienvenue actuel: {0} - - - Activez les MPs de bienvenue en écrivant {0} - - - Nouveau MP de bienvenue défini. - - - MPs de bienvenue désactivés. - - - MPs de bienvenue activés. - - - Message de bienvenue actuel: {0} - - - Activez les messages de bienvenue en écrivant {0} - - - Nouveau message de bienvenue défini. - - - Messages de bienvenue désactivés. - - - Messages de bienvenue activés sur ce salon. - - - Vous ne pouvez pas utiliser cette commande sur les utilisateurs dont le rôle est supérieur ou égal au vôtre dans la hiérarchie. - - - Images chargées après {0} secondes! - - - Format d'entrée invalide. - - - Paramètres invalides. - - - {0} a rejoint {1} - - - Vous avez été expulsé du serveur {0}. -Raison : {1} - - - Utilisateur expulsé - Fuzzy - - - Listes des langues -{0} - Fuzzy - - - La langue du serveur est désormais {0} - {1} - - - La langue par défaut du bot est désormais {0} - {1} - - - La langue du bot a été changée pour {0} - {1} - - - Échec dans la tentative de changement de langue. Veuillez consulter l'aide pour cette commande. - - - La langue de ce serveur est {0} - {1} - - - {0} a quitté {1} - - - Serveur {0} quitté - - - Enregistrement de {0} événements dans ce salon. - - - Enregistrement de tous les événements dans ce salon. - - - Enregistrement désactivé. - - - Événements enregistrés que vous pouvez suivre : - - - L'enregistrement ignorera désormais {0} - - - L'enregistrement n'ignorera pas {0} - - - L’événement {0} ne sera plus enregistré. - - - {0} a émis une notification pour les rôles suivants - - - Message de {0} `[Bot Owner]` : - - - Message envoyé. - - - {0} déplacé de {1} à {2} - L'utilisateur n'a pas forcément été déplacé de son plein gré. S'est déplacé - déplacé - - - Message supprimé dans #{0} - Fuzzy - - - Mise à jour du message dans #{0} - Fuzzy - - - Tous les utilisateurs sont maintenant muets. - PLURAL (users have been muted) - - - L'utilisateur est maintenant muet. - singular "User muted." - - - Il semblerait que je n'ai pas la permission nécessaire pour effectuer cela. - - - Nouveau rôle muet créé. - - - Je nécessite la permission **Administrateur** pour effectuer cela. - - - Nouveau message - Fuzzy - - - Nouveau pseudonyme - Fuzzy - - - Nouveau sujet - Fuzzy - - - Pseudonyme changé - Fuzzy - - - Impossible de trouver ce serveur - - - Aucun Shard pour cet ID trouvée. - Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. - - - Ancien message - Fuzzy - - - Ancien pseudonyme - Fuzzy - - - Ancien sujet - Fuzzy - - - Erreur. Je ne dois sûrement pas posséder les permissions suffisantes. - - - Les permissions pour ce serveur ont été réinitialisées. - - - Protections actives - Fuzzy - - - {0} a été **désactivé** sur ce serveur. - - - {0} Activé - - - Erreur. J'ai besoin de la permission Gérer les rôles. - - - Aucune protection activée. - Fuzzy - - - Le seuil d'utilisateurs doit être entre {0} et {1}. - - - Si {0} ou plus d'utilisateurs rejoignent dans les {1} secondes suivantes, je les {2}. - - - Le temps doit être compris entre {0} et {1} secondes. - - - Vous avez retirés tous les rôles de l'utilisateur {0} avec succès - - - Impossible de retirer des rôles. Je n'ai pas les permissions suffisantes. - - - La couleur du rôle {0} a été modifiée. - - - Ce rôle n'existe pas. - - - Les paramètres spécifiés sont invalides. - - - Erreur due à un manque de permissions ou à une couleur invalide. - - - L'utilisateur {1} n'a plus le rôle {0}. - - - Impossible de supprimer ce rôle. Je ne possède pas les permissions suffisantes. - - - Rôle renommé. - - - Impossible de renommer ce rôle. Je ne possède pas les permissions suffisantes. - - - Vous ne pouvez pas modifier les rôles supérieurs au votre. - - - La répétition du message suivant a été désactivé: {0} - - - Le rôle {0} a été ajouté à la liste. - - - {0} introuvable. Nettoyé. - - - Le rôle {0} est déjà présent dans la liste. - - - Ajouté. - - - Rotation du statut de jeu désactivée. - - - Rotation du statut de jeu activée. - - - Voici une liste des rotations de statuts : -{0} - - - Aucune rotation de statuts en place. - - - Vous avez déjà le rôle {0}. - - - Vous avez déjà {0} rôles exclusifs auto-attribués. - - - Rôles auto-attribuables désormais exclusifs. - - - Il y a {0} rôles auto-attribuables. - - - Ce rôle ne peux pas vous être attribué par vous-même. - - - Vous ne possédez pas le rôle {0}. - - - Les rôles auto-attribuables ne sont désormais plus exclusifs! - Je ne pense pas que ce soit la bonne traduction.. self-assignable role serait plutôt rôle auto-attribuable - - - Je suis incapable de vous ajouter ce rôle. `Je ne peux pas ajouter de rôles aux propriétaires et aux autres rôles plus haut que le mien dans la hiérarchie.` - - - {0} a été supprimé de la liste des rôles auto-attribuables. - - - Vous n'avez plus le rôle {0}. - - - Vous avez désormais le rôle {0}. - - - L'utilisateur {1} a désormais le rôle {0}. - - - Impossible d'ajouter un rôle. Je ne possède pas les permissions suffisantes. - - - Nouvel avatar défini! - - - Nouveau nom de Salon défini avec succès. - - - Nouveau jeu défini! - Pour "set", je pense que défini irait mieux que "en service" - - - Nouveau stream défini! - - - Nouveau sujet du salon défini. - - - Shard {0} reconnecté. - Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. - - - Shard {0} en reconnection. - Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. - - - Arrêt en cours. - - - Les utilisateurs ne peuvent pas envoyer plus de {0} messages toutes les {1} secondes. - - - Mode ralenti désactivé. - - - Mode ralenti activé - - - expulsés (kick) - PLURAL - - - {0} ignorera ce Salon. - - - {0} n'ignorera plus ce Salon. - - - Si un utilisateur poste {0} le même message à la suite, je le {1}. - __SalonsIgnorés__: {2} - - - Salon textuel créé. - Fuzzy - - - Salon textuel supprimé. - Fuzzy - - - Son activé avec succès. - - - Micro activé - singular - - - Nom d'utilisateur - - - Nom d'utilisateur modifié. - Fuzzy - - - Utilisateurs - - - Utilisateur banni - Fuzzy - - - {0} est maintenant **muet** sur le chat. - - - **La parole a été rétablie** sur le chat pour {0}. - - - L'utilisateur a rejoint - Fuzzy - - - L'utilisateur a quitté - Fuzzy - - - {0} est maintenant **muet** à la fois sur les salons textuels et vocaux. - - - Rôle ajouté à l'utilisateur - Fuzzy - - - Rôle retiré de l'utilisateur - Fuzzy - - - {0} est maintenant {1} - - - {0} n'est maintenant **plus muet** des salons textuels et vocaux. - - - {0} a rejoint le salon vocal {1}. - - - {0} a quitté le salon vocal {1}. - - - {0} est allé du salon vocal {1} à {2}. - - - {0} est maintenant **muet**. - - - {0} n'est maintenant **plus muet**. - - - Salon vocal créé. - Fuzzy - - - Salon vocal supprimé. - Fuzzy - - - Fonctionnalités vocales et textuelles désactivées. - - - Fonctionnalités vocales et textuelles activées. - - - Je n'ai pas la permission **Gérer les rôles** et/ou **Gérer les salons**, je ne peux donc pas utiliser `voice+text` sur le serveur {0}. - - - Vous activez/désactivez cette fonctionnalité et **je n'ai pas la permission ADMINISTRATEUR**. Cela pourrait causer des dysfonctionnements, et vous devrez nettoyer les salons textuels vous-même après ça. - - - Je nécessite au minimum les rôles **Gérer les rôles** et **Gérer les salons** pour activer cette fonctionnalité. (Permission Administrateur de préférence) - - - Utilisateur {0} depuis un salon textuel. - - - Utilisateur {0} depuis salon textuel et vocal. - - - Utilisateur {0} depuis un salon vocal. - - - Vous avez été expulsé du serveur {0}. -Raison: {1} - - - Utilisateur débanni - Fuzzy - - - Migration effectuée! - - - Erreur lors de la migration, veuillez consulter la console pour plus d'informations. - - - Présences mises à jour. - Fuzzy - - - Utilisateur expulsé. - Fuzzy - - - a récompensé {0} à {1} - - - Plus de chance la prochaine fois ^_^ - C'est vraiment québecois ca.. On ne le dit pas comme ca ici xD - - - Félicitations! Vous avez gagné {0} pour avoir lancé au dessus de {1}. - - - Deck remélangé. - - - Lancé {0}. - User flipped tails. - - - Vous avez deviné! Vous avez gagné {0} - - - Nombre spécifié invalide. Vous pouvez lancer 1 à {0} pièces. - - - Ajoute la réaction {0} à ce message pour avoir {1} - - - Cet événement est actif pendant {0} heures. - - - L'événement "réactions fleuries" a démarré! - - - a donné {0} à {1} - X has gifted 15 flowers to Y - - - {0} a {1} - X has Y flowers - - - Face - Fuzzy - - - Classement - - - {1} utilisateurs du rôle {2} ont été récompensé de {0}. - - - Vous ne pouvez pas miser plus de {0} - - - Vous ne pouvez pas parier moins de {0} - - - Vous n'avez pas assez de {0} - - - Plus de carte dans le deck. - - - Utilisateur tiré au sort - Fuzzy - - - Vous avez roulé un {0}. - - - Mise - - - WOAAHHHHHH!!! Félicitations!!! x{0} - - - Une simple {0}, x{1} - - - Wow! Quelle chance! Trois du même genre! x{0} - - - Bon travail! Deux {0} - mise x{1} - - - Gagné - - - Les utilisateurs doivent écrire un code secret pour avoir {0}. Dure {1} secondes. Ne le dites à personne. Shhh. - "Ne le dis à personne" ou "Ne le dites à personne". Je vous laisse faire le choix - - - L’événement "jeu sournois" s'est fini. {0} utilisateurs ont reçu la récompense. - - - L'événement "jeu sournois" a démarré - - - Pile - C'est pas plutôt face ca ? -Fuzzy - - - Vous avez pris {0} de {1} avec succès - - - Impossible de prendre {0} de {1} car l'utilisateur n'a pas assez de {2}! - - - Retour à la table des matières - - - Propriétaire du Bot seulement - Fuzzy - - - Nécessite {0} permissions du salon. - - - Vous pouvez supporter ce projet sur Patreon <{0}> ou via Paypal <{1}> - - - Commandes et alias - Fuzzy - - - Liste des commandes rafraîchie. - Fuzzy - - - Écrivez `{0}h NomDeLaCommande` pour voir l'aide spécifique à cette commande. Ex: `{0}h >8ball` - - - Impossible de trouver cette commande. Veuillez vérifier qu'elle existe avant de réessayer. - - - Description - - - Vous pouvez supporter le projet NadekoBot -sur Patreon <{0}> -par Paypal <{1}> -N'oubliez pas de mettre votre nom discord ou ID dans le message. - -**Merci** ♥️ - - - **Liste des Commandes**: <{0}> -**La liste des guides et tous les documents peuvent être trouvés ici**: <{1}> - Fuzzy - - - Liste des commandes - Fuzzy - - - Liste des modules - Fuzzy - - - Entrez `{0}cmds NomDuModule` pour avoir la liste des commandes de ce module. ex `{0}cmds games` - - - Ce module n'existe pas. - - - Permission serveur {0} requise. - - - Table des matières - Fuzzy - - - Usage - - - Autohentai commencé. Publie toutes les {0}s avec l'un des tags suivants : -{1} - - - Tag - - - Course d'animaux - Fuzzy - - - Pas assez de participants pour commencer. - - - Suffisamment de participants ! La course commence. - - - {0} a rejoint sous la forme d'un {1} - - - {0} a rejoint sous la forme d'un {1} et mise sur {2} ! - - - Entrez {0}jr pour rejoindre la course. - - - Début dans 20 secondes ou quand le nombre maximum de participants est atteint. - - - Début avec {0} participants. - - - {0} sous la forme d'un {1} a gagné la course ! - - - {0} sous la forme d'un {1} a gagné la course et {2}! - - - Nombre spécifié invalide. Vous pouvez lancer de {0} à {1} dés à la fois. - - - tiré au sort {0} - Someone rolled 35 - - - Dé tiré au sort: {0} - Dice Rolled: 5 - - - Le lancement de la course a échoué. Une autre course doit probablement être en cours. - - - Aucune course n'existe sur ce serveur. - - - Le deuxième nombre doit être plus grand que le premier. - - - Changements de Coeur - Fuzzy - - - Revendiquée par - Fuzzy - - - Divorces - - - Aime - - - Prix - - - Aucune waifu n'a été revendiquée pour l'instant. - - - Top Waifus - - - votre affinité est déjà liée à cette waifu ou vous êtes en train de retirer votre affinité avec quelqu'un alors que vous n'en possédez pas. - - - Affinités changées de de {0} à {1}. - -*C'est moralement discutable.* 🤔 - Make sure to get the formatting right, and leave the thinking emoji - - - Vous devez attendre {0} heures et {1} minutes avant de pouvoir changer de nouveau votre affinité. - - - Votre affinité a été réinitialisée. Vous n'avez désormais plus la personne que vous aimez. - - - veut être la waifu de {0}. Aww <3 - - - a revendiqué {0} comme sa waifu pour {1} - - - Vous avez divorcé avec une waifu qui vous aimais. Monstre sans cœur. {0} a reçu {1} en guise de compensation. - - - vous ne pouvez pas vous lier d'affinité avec vous-même, espèce d'égocentrique. - - - 🎉Leur amour est comblé !🎉 -La nouvelle valeur de {0} est {1} ! - - - Aucune waifu n'est à ce prix. Tu dois payer au moins {0} pour avoir une waifu, même si sa vraie valeur est inférieure. - - - Tu dois payer {0} ou plus pour avoir cette waifu ! - - - Cette waifu ne t'appartient pas. - - - Tu ne peux pas t'acquérir toi-même. - - - Vous avez récemment divorcé. Vous devez attendre {0} heures et {1} minutes pour divorcer à nouveau. - - - Personne - - - Vous avez divorcé d'une waifu qui ne vous aimait pas. Vous recevez {0} en retour. - - - 8ball - - - Acrophobie - - - Le jeu a pris fin sans soumissions. - - - Personne n'a voté : la partie se termine sans vainqueur. - - - L'acronyme était {0}. - - - Une partie d'Acrophobia est déjà en cours sur ce salon. - - - La partie commence. Créez une phrase avec l'acronyme suivant : {0}. - - - Vous avez {0} secondes pour faire une soumission. - - - {0} a soumit sa phrase. ({1} au total) - - - Votez en entrant le numéro d'une soumission. - - - {0} a voté! - - - Le gagnant est {0} avec {1} points! - - - {0} est le gagnant pour être le seul utilisateur à avoir fait une soumission! - - - Question - - - Egalité ! Vous avez choisi {0}. - - - {0} a gagné ! {1} bat {2}. - - - Inscriptions terminées. - Fuzzy - - - Une course d'animaux est déjà en cours. - - - Total : {0} Moyenne : {1} - - - Catégorie - - - Cleverbot désactivé sur ce serveur. - - - Cleverbot activé sur ce serveur. - - - La génération monétaire a été désactivée sur ce salon. - Currency =/= current !!! Il s'agit de monnaie. Par example: Euro is a currency. US Dollar also is. Sur Public Nadeko, il s'agit des fleurs :) - - - La génération monétaire a été désactivée sur ce salon. - - - {0} {1} aléatoires sont apparus! - plural -Fuzzy - - - Un {0} aléatoire est apparu! - Fuzzy - - - Impossible de charger une question. - - - La jeu a commencé. - Fuzzy - - - Partie de pendu commencée. - - - Une partie de pendu est déjà en cours sur ce canal. - - - Initialisation du pendu erronée. - - - Liste des "{0}hangman" types de termes : - - - Classement - - - Vous n'avez pas assez de {0} - - - Pas de résultat - - - a cueilli {0} - Kwoth picked 5* - - - {0} a planté {1} - Kwoth planted 5* - - - Une partie de Trivia est déjà en cours sur ce serveur. - - - Partie de Trivia - - - {0} a deviné! La réponse était: {1} - - - Aucune partie de Trivia en cours sur ce serveur. - - - {0} a {1} points - - - Le jeu s'arrêtera après cette question. - - - Le temps a expiré! La réponse était {0} - - - {0} a deviné la réponse et gagne la partie! La réponse était: {1} - - - Vous ne pouvez pas jouer contre vous-même. - - - Une partie de Morpion est déjà en cours sur ce salon. - - - Égalité! - - - a créé une partie de Morpion. - - - {0} a gagné ! - Fuzzy - - - Trois alignés. - Fuzzy - - - Aucun mouvement restant ! - - - Le temps a expiré ! - Fuzzy - - - Tour de {0}. - - - {0} contre {1} - - - Tentative d'ajouter {0} pistes à la file d'attente... - - - Lecture automatique désactivée. - - - Lecture automatique activée. - - - Volume par défaut défini à {0}% - - - File d'attente complète. - - - à tour de rôle - - - Lecture terminée - Fuzzy - - - Système de tour de rôle désactivé. - - - Système de tour de rôle activé. - - - De la position - - - Id - - - Entrée invalide. - - - Le temps maximum de lecture est désormais illimité. - - - Temps maximum de lecture défini à {0} seconde(s). - - - La taille de la file d'attente est désormais illmitée. - - - La taille de la file d'attente est désormais de {0} piste(s). - - - Vous avez besoin d'être dans un salon vocal sur ce serveur. - - - Nom - - - Vous écoutez - Fuzzy - - - Aucun lecteur de musique actif. - - - Pas de résultat. - - - Lecteure mise en pause. - - - File d'attente - Page {0}/{1} - Fuzzy - - - Lecture en cours - Fuzzy - - - `#{0}` - **{1}** par *{2}* ({3} pistes) - - - Page {0} des listes de lecture sauvegardées - Fuzzy - - - Liste de lecture supprimée. - - - Impossible de supprimer cette liste de lecture. Soit elle n'existe pas, soit vous n'en êtes pas le créateur. - - - Aucune liste de lecture ne correspond a cet ID. - - - File d'attente de la liste complétée. - - - Liste de lecture sauvegardée - Fuzzy - - - Limite à {0}s - - - File d'attente - - - Piste ajoutée à la file d'attente - Fuzzy - - - File d'attente effacée. - - - File d'attente complète ({0}/{0}). - - - Piste retirée - context: "removed song #5" - - - Répétition de la piste en cours de lecture - Fuzzy - - - Liste de lecture en boucle - Fuzzy - - - Piste en boucle - Fuzzy - - - La piste ne sera lue qu'une fois. - - - Reprise de la lecture. - - - Lecture en boucle désactivée. - - - Lecture en boucle activée. - - - Je vais désormais afficher les pistes en cours, en pause, terminées et supprimées dans ce salon. - - - Saut à `{0}:{1}` - - - Lecture aléatoire activée. - Fuzzy - - - Piste déplacée - Fuzzy - - - {0}h {1}m {2}s - - - À la position - - - Illimité - - - Le volume doit être compris entre 0 et 100 - - - Volume réglé sur {0}% - - - Désactivation de TOUS LES MODULES pour le salon {0}. - Fuzzy - - - Activation de TOUS LES MODULES pour le salon {0}. - Fuzzy - - - Permis - - - Désactivation de TOUS LES MODULES pour le rôle {0}. - Fuzzy - - - Activation de TOUS LES MODULES pour le rôle {0}. - Fuzzy - - - Désactivation de TOUS LES MODULES sur ce serveur. - - - Activation de TOUS LES MODULES sur ce serveur. - - - Désactivation de TOUS LES MODULES pour l'utilisateur {0}. - Fuzzy - - - Activation de TOUS LES MODULES pour l'utilisateur {0}. - Fuzzy - - - {0} sur liste noire avec l'ID {1} - Il ne s'agit pas d'un ban mais d'une blacklist interdisant l'utilisateur d'utiliser le bot. - - - La commande {0} a désormais {1}s de temps de recharge. - - - La commande {0} n'a pas de temps de recharge et tous les temps de recharge ont été réinitialisés. - Fuzzy - - - Aucune commande n'a de temps de recharge. - - - Coût de la commande : - Fuzzy - - - Désactivation: {1} {0} sur le salon {2}. - Fuzzy - - - Activation: {1} {0} sur le salon {2}. - Fuzzy - - - Refusé - - - Ajout du mot {0} à la liste des mots filtrés. - - - Liste Des Mots Filtrés - Fuzzy - - - Suppression du mot {0} de la liste des mots filtrés. - - - Second paramètre invalide. (nécessite un nombre entre {0} et {1}) - - - Filtrage des invitations désactivé sur ce salon. - - - Filtrage des invitations activé sur ce salon. - - - Filtrage des invitations désactivé sur le serveur. - - - Filtrage des invitations activé sur le serveur. - - - Permission {0} déplacée de #{1} à #{2} - - - Impossible de trouver la permission à l'index #{0} - - - Aucun coût défini. - - - Commande - Gen (of command) - - - Module - Gen. (of module) - - - Page {0} des permissions - - - Le rôle des permissions actuelles est {0}. - - - Il faut maintenant avoir le rôle {0} pour modifier les permissions. - - - Aucune permission trouvée à cet index. - - - Supression des permissions #{0} - {1} - - - Désactivation: {1} {0} pour le rôle {2}. - - - Activation: {1} {0} pour le rôle {2}. - - - sec. - Short of seconds. - - - Désactivation: {1} {0} sur tout le serveur. - - - Activation: {1} {0} sur tout le serveur. - - - Débanni {0} avec l'ID {1} - - - Non modifiable - - - Désactivation: {1} {0} pour l'utilisateur {2}. - - - Activation: {1} {0} pour l'utilisateur {2}. - - - Je n'afficherai plus les avertissements des permissions. - - - J'afficherai désormais les avertissements des permissions. - - - Filtrage des mots désactivé sur ce salon. - - - Filtrage des mots activé sur ce salon. - - - Filtrage des mots désactivé sur le serveur. - - - Filtrage des mots activé sur le serveur. - - - Capacités - - - Pas encore d'anime préféré - - - Traduction automatique des messages activée sur ce salon. Les messages utilisateurs vont désormais être supprimés. - - - Votre langue de traduction à été supprimée. - - - Votre langue de traduction a été changée de {0} à {1} - - - Traduction automatique des messages commencée sur ce salon. - - - Traduction automatique des messages arrêtée sur ce salon. - - - Le format est invalide ou une erreur s'est produite. - - - Impossible de trouver cette carte. - - - fait - - - Chapitres - - - Bande dessinée # - - - Parties compétitives perdues - Fuzzy - - - Parties compétitives jouées - Fuzzy - - - Rang en compétitif - Fuzzy - - - Parties compétitives gagnées - - - Complétés - - - Condition - - - Coût - - - Date - - - Définis: - - - Abandonnés - droppped as in, "stopped watching" referring to shows/anime - - - Episodes - - - Une erreur s'est produite. - - - Exemple - - - Impossible de trouver cet anime. - - - Impossible de trouver ce manga. - - - Genres - - - Impossible de trouver une définition pour ce hashtag. - - - Taille/Poid - - - {0}m/{1}kg - - - Humidité - - - Recherche d'images pour: - Fuzzy - - - Impossible de trouver ce film. - - - Langue d'origine ou de destination invalide. - - - Blagues non chargées. - - - Lat/Long - - - Niveau - - - Liste de tags pour {0}place. - Don't translate {0}place - - - Emplacement - - - Les objets magiques ne sont pas chargés. - - - Profil MAL de {0} - - - Le propriétaire du Bot n'a pas spécifié de clé d'API Mashape (MashapeApiKey). Fonctionnalité non disponible - - - Min/Max - - - Aucun salon trouvé. - - - Aucun résultat trouvé. - - - En attente - Fuzzy - - - Url originale - Fuzzy - - - Une clé d'API osu! est nécessaire. - - - Impossible de récupérer la signature osu!. - - - Trouvé dans {0} images. Affichage de {0} aléatoires. - - - Utilisateur non trouvé! Veuillez vérifier la région ainsi que le BattleTag avant de réessayer. - - - Prévus de regarder - Je ne pense pas que le sens de la traduction soit le bon. - - - Plateforme - - - Attaque non trouvée. - - - Pokémon non trouvé. - - - Lien du profil : - Fuzzy - - - Qualité - - - Durée en Jeux Rapides - Fuzzy - - - Victoires Rapides - Fuzzy - - - Évaluation - - - Score: - - - Chercher pour: - recherche plutôt non ? -Fuzzy - - - Impossible de réduire cette Url. - - - Url réduite - Fuzzy - - - Une erreur s'est produite. - - - Veuillez spécifier les paramètres de recherche. - - - Statut - - - Url stockée - Fuzzy - - - Le streamer {0} est hors ligne. - - - Le streamer {0} est en ligne avec {1} viewers. - - - Vous suivez {0} streams sur ce serveur. - - - Vous ne suivez aucun stream sur ce serveur. - - - Aucun stream de ce nom. - - - Ce stream n'existe probablement pas. - - - Stream de {0} ({1}) retirée des notifications. - - - Je préviendrai ce salon lors d'un changement de statut. - - - Aube - - - Crépuscule - - - Température - - - Titre: - - - Top 3 anime favoris - - - Traduction: - - - Types - - - Impossible de trouver une définition pour ce terme. - - - Url - - - Viewers - - - En écoute - - - Impossible de trouver ce terme sur le wikia spécifié. - - - Entrez un wikia cible, suivi d'une requête de recherche. - - - Page non trouvée. - - - Vitesse du vent - Fuzzy - - - Les {0} champions les plus bannis - - - Impossible de yodifier votre phrase. - - - Rejoint - - - `{0}.` {1} [{2:F2}/s] - {3} total - /s and total need to be localized to fit the context - -`1.` - - - Page d'activité #{0} - Fuzzy - - - {0} utilisateurs en total. - - - Créateur - - - ID du Bot - - - Liste des fonctions pour la commande {0}calc - - - {0} de ce salon est {1} - - - Sujet du salon - Fuzzy - - - Commandes exécutées - Fuzzy - - - {0} {1} est équivalent à {2} {3} - - - Unités pouvant être converties : - - - Impossible de convertir {0} en {1}: unités non trouvées - - - Impossible de convertir {0} en {1} : les types des unités ne sont pas compatibles. - - - Créé le - Fuzzy - - - Salon inter-serveur rejoint. - - - Salon inter-serveur quitté. - - - Voici votre jeton CSC - - - Emojis personnalisées - Fuzzy - - - Erreur - - - Fonctionnalités - - - ID - - - Index hors limites. - - - Voici une liste des utilisateurs dans ces rôles : - Fuzzy - - - Vous ne pouvez pas utiliser cette commande sur un rôle incluant beaucoup d'utilisateurs afin d'éviter les abus. - Fuzzy - - - Valeur {0} invalide. - Invalid months value/ Invalid hours value - - - Discord rejoint - - - Serveur rejoint - Fuzzy - - - ID: {0} -Membres: {1} -OwnerID: {2} - Fuzzy - - - Aucun serveur trouvée sur cette page. - - - Liste des messages répétés - Fuzzy - - - Membres - - - Mémoire - - - Messages - - - Répéteur de messages - Fuzzy - - - Nom - - - Pseudonyme - - - Personne ne joue à ce jeu. - - - Aucune répétition active. - - - Aucun rôle sur cette page. - - - Aucun shard sur cette page. - Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. - - - Aucun sujet choisi. - - - Propriétaire - - - ID des propriétaires - - - Présence - - - {0} Serveurs -{1} Salons Textuels -{2} Salons Vocaux - - - Toutes les citations possédant le mot-clé {0} ont été supprimées. - - - Page {0} des citations - - - Aucune citation sur cette page. - - - Aucune citation que vous puissiez supprimer n'a été trouvé. - - - Citation ajoutée - - - Citation #{0} supprimée. - Fuzzy - - - Région - - - Inscrit sur - Fuzzy - - - Je vais vous rappeler {0} pour {1} dans {2} `({3:d.M.yyyy} à {4:HH:mm})` - - - Format de date non valide. Vérifiez la liste des commandes. - - - Nouveau modèle de rappel défini. - - - Répétition de {0} chaque {1} jour(s), {2} heure(s) et {3} minute(s). - - - Liste des répétitions - Fuzzy - - - Aucune répétition active sur ce serveur. - - - #{0} arrêté. - - - Pas de message répété trouvé sur ce serveur. - - - Résultat - - - Rôles - - - Page #{0} de tout les rôles sur ce serveur. - - - Page #{0} des rôles pour {1} - - - Aucune couleur n'est dans le bon format. Utilisez `#00ff00` par exemple. - - - Couleurs alternées pour le rôle {0} activées. - - - Couleurs alternées pour le rôle {0} arrêtées - - - {0} de ce serveur est {1} - - - Info du serveur - Fuzzy - - - Shard - Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. - - - Statistique des shards - Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. -Fuzzy - - - Le shard **#{0}** est en état {1} avec {2} serveurs. - Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. - - - **Nom:** {0} **Lien:** {1} - - - Pas d'emojis spéciaux trouvés. - - - Joue actuellement {0} piste(s), {1} en attente. - - - Salons textuels - Fuzzy - - - Voici le lien pour votre salon: - - - Durée de fonctionnement - - - {0} de l'utilisateur {1}: {2} - Id of the user kwoth#1234 is 123123123123 - - - Utilisateurs - - - Salons vocaux - Fuzzy - - - Vous avez déjà rejoint cette course! - - - Résultats du sondage actuel - - - Aucun vote enregistré. - - - Un sondage est déjà en cours sur ce serveur. - - - 📃 {0} a créé un sondage qui requiert votre attention: - - - `{0}.` {1} avec {2} votes. - - - {0} a voté. - Kwoth voted. - - - Envoyez moi un message privé avec le numéro correspondant à la réponse. - - - Envoyez un Message ici avec le numéro correspondant à la réponse. - - - Merci d'avoir voté, {0} - - - {0} votes enregistrés au total. - - - Attrapez-les en écrivant `{0}pick` - - - Attrapez-le en écrivant `{0}pick` - - - Aucun utilisateur trouvé. - - - page {0} - - - \ No newline at end of file From 9430222c219f6474f854106b0c2588be60c50c7b Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sat, 11 Mar 2017 08:23:57 +0100 Subject: [PATCH 534/746] Update ResponseStrings.zh-TW.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.zh-TW.resx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx index 10576b58..74edb3a9 100644 --- a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx +++ b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx @@ -2237,22 +2237,22 @@ Paypal <{1}> 第 {0} 頁 - + 您必須要在此伺服器上的語音頻道。 - + 沒有語音頻道身分組。 - + {0} 已被 **禁止** __文字和語音聊天__,持續 {1} 分鐘。 - + 進入 {0} 頻道的成員將會獲得 {1} 身分組。 - + 進入 {0} 頻道的成員將不再獲得身分組。 - + 語音頻道身分組 \ No newline at end of file From 4d1140bb8080541ab22e3e66a4b2841b9f80017a Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sat, 11 Mar 2017 08:24:00 +0100 Subject: [PATCH 535/746] Update ResponseStrings.fr-FR.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.fr-FR.resx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx b/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx index 6786100e..c061305e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx @@ -2353,22 +2353,22 @@ Fuzzy page {0} - + Vous devez être sur un canal vocal sur ce serveur. - + Il n'y a pas de rôle de canal vocal. - + {0} est désormais **muet** du chat textuel et vocal pour {1} minutes. - + Les utilisateurs rejoignant le canal vocal {0} obtiendrons le rôle {1}. - + Les utilisateurs rejoignant le canal vocal {0} n’obtiendrons plus de rôle. - + Rôles du canal vocal \ No newline at end of file From efb9f32389502210cb03ca6da43d237775ab5a97 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sat, 11 Mar 2017 08:24:03 +0100 Subject: [PATCH 536/746] Update ResponseStrings.tr-TR.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.tr-TR.resx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx b/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx index 2b4011de..f38f1a21 100644 --- a/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx @@ -2239,22 +2239,22 @@ Kurucu Kimliği: {2} sayfa {0}
- + Bu sunucudaki bir ses kanalda olmalısınız. - + Sesli kanal rolü yok. - + {0} metin ve sesli sohbetten {1} dakika **sessiz** hale getirildi. - + {0} sesli kanalına katılan kullanıcılar {1} rolünü alacaktır. - + {0} sesli kanalına katılan kullanıcılar artık bir rol almaz. - + Sesli kanal rolleri \ No newline at end of file From 4673736b60a7a54ed5f56e3c4607d577581d111d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 11 Mar 2017 10:22:41 +0100 Subject: [PATCH 537/746] $lb should have correct numbers now on pages > 1 --- src/NadekoBot/Modules/Gambling/Gambling.cs | 2 +- src/NadekoBot/Services/Impl/StatsService.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index fa5f462e..760f8156 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -274,7 +274,7 @@ namespace NadekoBot.Modules.Gambling : usr.Username?.TrimTo(20, true); var j = i; - embed.AddField(efb => efb.WithName("#" + (j + 1) + " " + usrStr) + embed.AddField(efb => efb.WithName("#" + (9 * (page - 1) + j + 1) + " " + usrStr) .WithValue(x.Amount.ToString() + " " + NadekoBot.BotConfig.CurrencySign) .WithIsInline(true)); } diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index 11f7802c..bd8eff0b 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -16,7 +16,7 @@ namespace NadekoBot.Services.Impl private readonly DiscordShardedClient _client; private readonly DateTime _started; - public const string BotVersion = "1.22"; + public const string BotVersion = "1.23"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From a7f70ad4e8a5a20aa40610cf26b01e1003ccd42e Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sat, 11 Mar 2017 10:25:55 +0100 Subject: [PATCH 538/746] Update ResponseStrings.de-DE.resx (POEditor.com) --- .../Resources/ResponseStrings.de-DE.resx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx index 03ed4b83..34346f0c 100644 --- a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx @@ -544,11 +544,11 @@ Grund: {1} Fuzzy - wurden Stumm geschalten + wurden Stummgeschalten PLURAL (users have been muted) - wurde Stumm geschalten + wurde Stummgeschalten singular "User muted." @@ -2289,7 +2289,7 @@ ID des Besitzers: {2} Benutzer - Sprach Kanäle + Sprach-Kanäle Fuzzy @@ -2341,22 +2341,22 @@ ID des Besitzers: {2} Seite {0} - + Sie müssen in einem Sprachkanal auf diesem Server sein. - + Keine Sprachkanal Rollen gefunden. - + {0} wurde **stummgeschaltet** im Text- und Sprachchat für {1} minuten. - + Benutzer die dem Sprachkanal {0} beitreten werden der Rolle {1} zugeweist. - + Benutzer die den Sprachkanal {0} beitreten werden nicht länger einer Rolle zugeweist. - + Rollen für Sprachkanäle \ No newline at end of file From 65867992bb787a538bb8b21a1b590789457f4b9e Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sun, 12 Mar 2017 07:37:40 +0100 Subject: [PATCH 539/746] Update ResponseStrings.ru-RU.resx (POEditor.com) --- .../Resources/ResponseStrings.ru-RU.resx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx index 9651864c..5f333da0 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx @@ -789,7 +789,7 @@ Пользователь вышел - {0} получил **запрет** на разговор в текстовых и голосовых каналах + {0} получил **запрет** на разговор в текстовых и голосовых каналах. Добавлена роль пользователя @@ -1114,7 +1114,7 @@ Paypal <{1}> сменил свою предрасположенность с {0} на {1}. -*Это сомнительно с точки зрения морали* :thinking: +*Это сомнительно с моральной точки зрения* :thinking: Make sure to get the formatting right, and leave the thinking emoji @@ -2232,22 +2232,22 @@ IDВладельца: {2} Страница {0} - + Вы должны быть в голосовом канале на этом сервере. - + Нет ролей для голосовых каналов. - + {0} получил **запрет** на разговор в текстовых и голосовых каналах на {1} минут. - + Пользователи, присоединяющиеся к голосовому каналу {0}, получат роль {1}. - + Пользователи, присоединяющиеся к голосовому каналу {0}, больше не будут получать роль. - + Роли голосовых каналов \ No newline at end of file From cc2d96f461966d7bcd4771f502062e5b4ffc6233 Mon Sep 17 00:00:00 2001 From: Rajath Ranganath Date: Sun, 12 Mar 2017 21:35:24 +0530 Subject: [PATCH 540/746] Fix delq usage --- src/NadekoBot/Resources/CommandStrings.resx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index bb284bcf..638735a0 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -1159,7 +1159,7 @@ Deletes a quote with the specified ID. You have to be either server Administrator or the creator of the quote to delete it. - `{0}delq abc` + `{0}delq 123456` draw @@ -3186,4 +3186,4 @@ `{0}vcrole SomeRole` or `{0}vcrole` - \ No newline at end of file + From 3337a2675ac7ecf01c10be335eda6f2550668fb1 Mon Sep 17 00:00:00 2001 From: samvaio Date: Mon, 13 Mar 2017 09:35:32 +0530 Subject: [PATCH 541/746] branch changed to dev --- scripts/NadekoAutoRun.bat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/NadekoAutoRun.bat b/scripts/NadekoAutoRun.bat index c1701c7c..69060962 100644 --- a/scripts/NadekoAutoRun.bat +++ b/scripts/NadekoAutoRun.bat @@ -29,7 +29,7 @@ CD /D %~dp0NadekoBot\src\NadekoBot dotnet run --configuration Release ECHO Updating... SET "FILENAME=%~dp0\Latest.bat" -powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/master/scripts/Latest.bat -OutFile '%FILENAME%'" +powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/scripts/Latest.bat -OutFile '%FILENAME%'" ECHO NadekoBot Dev Build (latest) downloaded. SET root=%~dp0 CD /D %root% @@ -43,7 +43,7 @@ CD /D %~dp0NadekoBot\src\NadekoBot dotnet run --configuration Release ECHO Updating... SET "FILENAME=%~dp0\Stable.bat" -powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/master/scripts/Stable.bat -OutFile '%FILENAME%'" +powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/scripts/Stable.bat -OutFile '%FILENAME%'" ECHO NadekoBot Stable build downloaded. SET root=%~dp0 CD /D %root% From 731330467b83dc166445ae2cd7d0631a1c7f6834 Mon Sep 17 00:00:00 2001 From: samvaio Date: Mon, 13 Mar 2017 10:45:51 +0530 Subject: [PATCH 542/746] better installation for 32bit users --- scripts/Latest.bat | 57 +++++++++++++++++++++++++-------------- scripts/NadekoAutoRun.bat | 22 +++++++-------- scripts/NadekoRun.bat | 4 +-- scripts/Stable.bat | 57 +++++++++++++++++++++++++-------------- 4 files changed, 87 insertions(+), 53 deletions(-) diff --git a/scripts/Latest.bat b/scripts/Latest.bat index 6460a618..13248a96 100644 --- a/scripts/Latest.bat +++ b/scripts/Latest.bat @@ -1,24 +1,25 @@ @ECHO off TITLE Downloading Latest Build of NadekoBot... ::Setting convenient to read variables which don't delete the windows temp folder -SET root=%~dp0 -CD /D %root% -SET rootdir=%cd% -SET build1=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Core\ -SET build2=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Rest\ -SET build3=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.WebSocket\ -SET build4=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Commands\ -SET build5=%root%NadekoInstall_Temp\NadekoBot\src\NadekoBot\ -SET installtemp=%root%NadekoInstall_Temp\ +SET "root=%~dp0" +CD /D "%root%" +SET "rootdir=%cd%" +SET "build1=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Core\" +SET "build2=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Rest\" +SET "build3=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.WebSocket\" +SET "build4=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Commands\" +SET "build5=%root%NadekoInstall_Temp\NadekoBot\src\NadekoBot\" +SET "installtemp=%root%NadekoInstall_Temp\" ::Deleting traces of last setup for the sake of clean folders, if by some miracle it still exists -IF EXIST %installtemp% ( RMDIR %installtemp% /S /Q >nul 2>&1) +IF EXIST "%installtemp%" ( RMDIR "%installtemp%" /S /Q >nul 2>&1) +timeout /t 5 ::Checks that both git and dotnet are installed dotnet --version >nul 2>&1 || GOTO :dotnet git --version >nul 2>&1 || GOTO :git ::Creates the install directory to work in and get the current directory because spaces ruins everything otherwise :start -MKDIR NadekoInstall_Temp -CD /D %installtemp% +MKDIR "%root%NadekoInstall_Temp" +CD /D "%installtemp%" ::Downloads the latest version of Nadeko ECHO Downloading Nadeko... ECHO. @@ -28,28 +29,28 @@ TITLE Installing NadekoBot, please wait... ECHO. ECHO Installing Discord.Net(1/4)... ::Building Nadeko -CD /D %build1% +CD /D "%build1%" dotnet restore >nul 2>&1 ECHO Installing Discord.Net(2/4)... -CD /D %build2% +CD /D "%build2%" dotnet restore >nul 2>&1 ECHO Installing Discord.Net(3/4)... -CD /D %build3% +CD /D "%build3%" dotnet restore >nul 2>&1 ECHO Installing Discord.Net(4/4)... -CD /D %build4% +CD /D "%build4%" dotnet restore >nul 2>&1 ECHO. ECHO Discord.Net installation completed successfully... ECHO. ECHO Installing NadekoBot... -CD /D %build5% +CD /D "%build5%" dotnet restore >nul 2>&1 dotnet build --configuration Release >nul 2>&1 ECHO. ECHO NadekoBot installation completed successfully... ::Attempts to backup old files if they currently exist in the same folder as the batch file -IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) +IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) ELSE (GOTO :freshinstall) :freshinstall ::Moves the NadekoBot folder to keep things tidy ECHO. @@ -106,7 +107,7 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) :giterror ECHO. ECHO Git clone failed, trying again - RMDIR %installtemp% /S /Q >nul 2>&1 + RMDIR "%installtemp%" /S /Q >nul 2>&1 GOTO :start :copyerror ::If at any point a copy error is encountered @@ -127,12 +128,28 @@ ECHO. ECHO Your System Architecture is 32bit... timeout /t 5 ECHO. -ECHO Downloading libsodium.dll and opus.dll... +ECHO Getting 32bit libsodium.dll and opus.dll... +IF EXIST "%root%NadekoBot\src\NadekoBot\_libs\32\libsodium.dll" (GOTO copysodium) ELSE (GOTO downloadsodium) +:copysodium +del "%root%NadekoBot\src\NadekoBot\libsodium.dll" +copy "%root%NadekoBot\src\NadekoBot\_libs\32\libsodium.dll" "%root%NadekoBot\src\NadekoBot\libsodium.dll" +ECHO libsodium.dll copied. +ECHO. +timeout /t 5 +IF EXIST "%root%NadekoBot\src\NadekoBot\_libs\32\opus.dll" (GOTO copyopus) ELSE (GOTO downloadopus) +:downloadsodium SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll" powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll -OutFile '%FILENAME%'" ECHO libsodium.dll downloaded. ECHO. timeout /t 5 +IF EXIST "%root%NadekoBot\src\NadekoBot\_libs\32\opus.dll" (GOTO copyopus) ELSE (GOTO downloadopus) +:copyopus +del "%root%NadekoBot\src\NadekoBot\opus.dll" +copy "%root%NadekoBot\src\NadekoBot\_libs\32\opus.dll" "%root%NadekoBot\src\NadekoBot\opus.dll" +ECHO opus.dll copied. +GOTO end +:downloadopus SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll" powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll -OutFile '%FILENAME%'" ECHO opus.dll downloaded. diff --git a/scripts/NadekoAutoRun.bat b/scripts/NadekoAutoRun.bat index 69060962..4441e25b 100644 --- a/scripts/NadekoAutoRun.bat +++ b/scripts/NadekoAutoRun.bat @@ -2,8 +2,8 @@ @TITLE NadekoBot -SET root=%~dp0 -CD /D %root% +SET "root=%~dp0" +CD /D "%root%" CLS ECHO Welcome to NadekoBot Auto Restart and Update! @@ -25,28 +25,28 @@ IF ERRORLEVEL 1 GOTO latestar :latestar ECHO Auto Restart and Update with Dev Build (latest) ECHO Bot will auto update on every restart! -CD /D %~dp0NadekoBot\src\NadekoBot +CD /D "%~dp0NadekoBot\src\NadekoBot" dotnet run --configuration Release ECHO Updating... SET "FILENAME=%~dp0\Latest.bat" powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/scripts/Latest.bat -OutFile '%FILENAME%'" ECHO NadekoBot Dev Build (latest) downloaded. -SET root=%~dp0 -CD /D %root% +SET "root=%~dp0" +CD /D "%root%" CALL Latest.bat GOTO latestar :stablear ECHO Auto Restart and Update with Stable Build ECHO Bot will auto update on every restart! -CD /D %~dp0NadekoBot\src\NadekoBot +CD /D "%~dp0NadekoBot\src\NadekoBot" dotnet run --configuration Release ECHO Updating... SET "FILENAME=%~dp0\Stable.bat" powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/scripts/Stable.bat -OutFile '%FILENAME%'" ECHO NadekoBot Stable build downloaded. -SET root=%~dp0 -CD /D %root% +SET "root=%~dp0" +CD /D "%root%" CALL Stable.bat GOTO stablear @@ -54,12 +54,12 @@ GOTO stablear ECHO Normal Auto Restart ECHO Bot will not auto update on every restart! timeout /t 3 -CD /D %~dp0NadekoBot\src\NadekoBot +CD /D "%~dp0NadekoBot\src\NadekoBot" dotnet run --configuration Release goto autorun :Exit -SET root=%~dp0 -CD /D %root% +SET "root=%~dp0" +CD /D "%root%" del NadekoAutoRun.bat CALL NadekoInstaller.bat diff --git a/scripts/NadekoRun.bat b/scripts/NadekoRun.bat index 207fb278..73c66b17 100644 --- a/scripts/NadekoRun.bat +++ b/scripts/NadekoRun.bat @@ -1,9 +1,9 @@ @ECHO off @TITLE NadekoBot -CD /D %~dp0NadekoBot\src\NadekoBot +CD /D "%~dp0NadekoBot\src\NadekoBot" dotnet run --configuration Release ECHO NadekoBot has been succesfully stopped, press any key to close this window. TITLE NadekoBot - Stopped -CD /D %~dp0 +CD /D "%~dp0" PAUSE >nul 2>&1 del NadekoRunNormal.bat diff --git a/scripts/Stable.bat b/scripts/Stable.bat index b2f6a9eb..a3ffb6f4 100644 --- a/scripts/Stable.bat +++ b/scripts/Stable.bat @@ -1,24 +1,25 @@ @ECHO off TITLE Downloading Stable Build of NadekoBot... ::Setting convenient to read variables which don't delete the windows temp folder -SET root=%~dp0 -CD /D %root% -SET rootdir=%cd% -SET build1=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Core\ -SET build2=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Rest\ -SET build3=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.WebSocket\ -SET build4=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Commands\ -SET build5=%root%NadekoInstall_Temp\NadekoBot\src\NadekoBot\ -SET installtemp=%root%NadekoInstall_Temp\ +SET "root=%~dp0" +CD /D "%root%" +SET "rootdir=%cd%" +SET "build1=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Core\" +SET "build2=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Rest\" +SET "build3=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.WebSocket\" +SET "build4=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Commands\" +SET "build5=%root%NadekoInstall_Temp\NadekoBot\src\NadekoBot\" +SET "installtemp=%root%NadekoInstall_Temp\" ::Deleting traces of last setup for the sake of clean folders, if by some miracle it still exists -IF EXIST %installtemp% ( RMDIR %installtemp% /S /Q >nul 2>&1) +IF EXIST "%installtemp%" ( RMDIR "%installtemp%" /S /Q >nul 2>&1) +timeout /t 5 ::Checks that both git and dotnet are installed dotnet --version >nul 2>&1 || GOTO :dotnet git --version >nul 2>&1 || GOTO :git ::Creates the install directory to work in and get the current directory because spaces ruins everything otherwise :start -MKDIR NadekoInstall_Temp -CD /D %installtemp% +MKDIR "%root%NadekoInstall_Temp" +CD /D "%installtemp%" ::Downloads the latest version of Nadeko ECHO Downloading Nadeko... ECHO. @@ -28,28 +29,28 @@ TITLE Installing NadekoBot, please wait... ECHO. ECHO Installing Discord.Net(1/4)... ::Building Nadeko -CD /D %build1% +CD /D "%build1%" dotnet restore >nul 2>&1 ECHO Installing Discord.Net(2/4)... -CD /D %build2% +CD /D "%build2%" dotnet restore >nul 2>&1 ECHO Installing Discord.Net(3/4)... -CD /D %build3% +CD /D "%build3%" dotnet restore >nul 2>&1 ECHO Installing Discord.Net(4/4)... -CD /D %build4% +CD /D "%build4%" dotnet restore >nul 2>&1 ECHO. ECHO Discord.Net installation completed successfully... ECHO. ECHO Installing NadekoBot... -CD /D %build5% +CD /D "%build5%" dotnet restore >nul 2>&1 dotnet build --configuration Release >nul 2>&1 ECHO. ECHO NadekoBot installation completed successfully... ::Attempts to backup old files if they currently exist in the same folder as the batch file -IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) +IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) ELSE (GOTO :freshinstall) :freshinstall ::Moves the NadekoBot folder to keep things tidy ECHO. @@ -106,7 +107,7 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) :giterror ECHO. ECHO Git clone failed, trying again - RMDIR %installtemp% /S /Q >nul 2>&1 + RMDIR "%installtemp%" /S /Q >nul 2>&1 GOTO :start :copyerror ::If at any point a copy error is encountered @@ -127,12 +128,28 @@ ECHO. ECHO Your System Architecture is 32bit... timeout /t 5 ECHO. -ECHO Downloading libsodium.dll and opus.dll... +ECHO Getting 32bit libsodium.dll and opus.dll... +IF EXIST "%root%NadekoBot\src\NadekoBot\_libs\32\libsodium.dll" (GOTO copysodium) ELSE (GOTO downloadsodium) +:copysodium +del "%root%NadekoBot\src\NadekoBot\libsodium.dll" +copy "%root%NadekoBot\src\NadekoBot\_libs\32\libsodium.dll" "%root%NadekoBot\src\NadekoBot\libsodium.dll" +ECHO libsodium.dll copied. +ECHO. +timeout /t 5 +IF EXIST "%root%NadekoBot\src\NadekoBot\_libs\32\opus.dll" (GOTO copyopus) ELSE (GOTO downloadopus) +:downloadsodium SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll" powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll -OutFile '%FILENAME%'" ECHO libsodium.dll downloaded. ECHO. timeout /t 5 +IF EXIST "%root%NadekoBot\src\NadekoBot\_libs\32\opus.dll" (GOTO copyopus) ELSE (GOTO downloadopus) +:copyopus +del "%root%NadekoBot\src\NadekoBot\opus.dll" +copy "%root%NadekoBot\src\NadekoBot\_libs\32\opus.dll" "%root%NadekoBot\src\NadekoBot\opus.dll" +ECHO opus.dll copied. +GOTO end +:downloadopus SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll" powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll -OutFile '%FILENAME%'" ECHO opus.dll downloaded. From 07aa25c56f7dc3f7a9971806e9775fffb213518e Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Mar 2017 08:08:13 +0100 Subject: [PATCH 543/746] You can now use permissions module to disable individual custom reactions. Not fully tested, seems to work. public bot global cooldown reduced to 750ms, slot cooldown from 2 to 1 second --- .../CustomReactions/CustomReactions.cs | 70 +++++++------------ .../Modules/Gambling/Commands/Slots.cs | 2 +- .../Modules/Permissions/Permissions.cs | 34 ++++----- src/NadekoBot/NadekoBot.cs | 1 + src/NadekoBot/Services/CommandHandler.cs | 47 +++++++++++-- .../Database/Models/CustomReaction.cs | 2 + .../Impl/GuildConfigRepository.cs | 5 +- .../TypeReaders/BotCommandTypeReader.cs | 44 ++++++++++++ 8 files changed, 136 insertions(+), 69 deletions(-) diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index efd3717e..bbe73e51 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -13,9 +13,27 @@ using Discord.WebSocket; using System; using Newtonsoft.Json; using NadekoBot.DataStructures; +using NLog.Fluent; namespace NadekoBot.Modules.CustomReactions { + public static class CustomReactionExtensions + { + public static Task Send(this CustomReaction cr, IUserMessage context) + { + var channel = context.Channel; + + CustomReactions.ReactionStats.AddOrUpdate(cr.Trigger, 1, (k, old) => ++old); + + CREmbed crembed; + if (CREmbed.TryParse(cr.Response, out crembed)) + { + return channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? ""); + } + return channel.SendMessageAsync(cr.ResponseWithContext(context)); + } + } + [NadekoModule("CustomReactions", ".")] public class CustomReactions : NadekoTopLevelModule { @@ -25,7 +43,7 @@ namespace NadekoBot.Modules.CustomReactions public static ConcurrentDictionary ReactionStats { get; } = new ConcurrentDictionary(); - private static new readonly Logger _log; + private new static readonly Logger _log; static CustomReactions() { @@ -43,11 +61,11 @@ namespace NadekoBot.Modules.CustomReactions public void ClearStats() => ReactionStats.Clear(); - public static async Task TryExecuteCustomReaction(SocketUserMessage umsg) + public static async Task TryGetCustomReaction(SocketUserMessage umsg) { var channel = umsg.Channel as SocketTextChannel; if (channel == null) - return false; + return null; var content = umsg.Content.Trim().ToLowerInvariant(); CustomReaction[] reactions; @@ -70,26 +88,9 @@ namespace NadekoBot.Modules.CustomReactions var reaction = rs[new NadekoRandom().Next(0, rs.Length)]; if (reaction != null) { - if (reaction.Response != "-") - { - CREmbed crembed; - if (CREmbed.TryParse(reaction.Response, out crembed)) - { - try { await channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "").ConfigureAwait(false); } - catch (Exception ex) - { - _log.Warn("Sending CREmbed failed"); - _log.Warn(ex); - } - } - else - { - try { await channel.SendMessageAsync(reaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { } - } - } - - ReactionStats.AddOrUpdate(reaction.Trigger, 1, (k, old) => ++old); - return true; + if (reaction.Response == "-") + return null; + return reaction; } } } @@ -103,29 +104,10 @@ namespace NadekoBot.Modules.CustomReactions return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger); }).ToArray(); if (grs.Length == 0) - return false; + return null; var greaction = grs[new NadekoRandom().Next(0, grs.Length)]; - if (greaction != null) - { - CREmbed crembed; - if (CREmbed.TryParse(greaction.Response, out crembed)) - { - try { await channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "").ConfigureAwait(false); } - catch (Exception ex) - { - _log.Warn("Sending CREmbed failed"); - _log.Warn(ex); - } - } - else - { - try { await channel.SendMessageAsync(greaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { } - } - ReactionStats.AddOrUpdate(greaction.Trigger, 1, (k, old) => ++old); - return true; - } - return false; + return greaction; } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs index ea20b4b1..79dbe75a 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs @@ -223,7 +223,7 @@ namespace NadekoBot.Modules.Gambling { var _ = Task.Run(async () => { - await Task.Delay(2000); + await Task.Delay(1500); _runningUsers.Remove(Context.User.Id); }); } diff --git a/src/NadekoBot/Modules/Permissions/Permissions.cs b/src/NadekoBot/Modules/Permissions/Permissions.cs index bc95d158..837bea9d 100644 --- a/src/NadekoBot/Modules/Permissions/Permissions.cs +++ b/src/NadekoBot/Modules/Permissions/Permissions.cs @@ -12,6 +12,7 @@ using Discord.WebSocket; using System.Diagnostics; using Microsoft.EntityFrameworkCore; using NadekoBot.DataStructures; +using NadekoBot.TypeReaders; using NLog; namespace NadekoBot.Modules.Permissions @@ -89,6 +90,7 @@ namespace NadekoBot.Modules.Permissions var gc = uow.GuildConfigs.For(oc.Key, set => set.Include(x => x.Permissions)); var oldPerms = oc.Value.RootPermission.AsEnumerable().Reverse().ToList(); + uow._context.Set().RemoveRange(oldPerms); gc.RootPermission = null; if (oldPerms.Count > 2) { @@ -316,27 +318,27 @@ namespace NadekoBot.Modules.Permissions [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task SrvrCmd(CommandInfo command, PermissionAction action) + public async Task SrvrCmd(CommandOrCrInfo command, PermissionAction action) { await AddPermissions(Context.Guild.Id, new Permissionv2 { PrimaryTarget = PrimaryPermissionType.Server, PrimaryTargetId = 0, SecondaryTarget = SecondaryPermissionType.Command, - SecondaryTargetName = command.Aliases.First().ToLowerInvariant(), + SecondaryTargetName = command.Name.ToLowerInvariant(), State = action.Value, }); if (action.Value) { await ReplyConfirmLocalized("sx_enable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command")).ConfigureAwait(false); } else { await ReplyConfirmLocalized("sx_disable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command")).ConfigureAwait(false); } } @@ -370,28 +372,28 @@ namespace NadekoBot.Modules.Permissions [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task UsrCmd(CommandInfo command, PermissionAction action, [Remainder] IGuildUser user) + public async Task UsrCmd(CommandOrCrInfo command, PermissionAction action, [Remainder] IGuildUser user) { await AddPermissions(Context.Guild.Id, new Permissionv2 { PrimaryTarget = PrimaryPermissionType.User, PrimaryTargetId = user.Id, SecondaryTarget = SecondaryPermissionType.Command, - SecondaryTargetName = command.Aliases.First().ToLowerInvariant(), + SecondaryTargetName = command.Name.ToLowerInvariant(), State = action.Value, }); if (action.Value) { await ReplyConfirmLocalized("ux_enable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command"), Format.Code(user.ToString())).ConfigureAwait(false); } else { await ReplyConfirmLocalized("ux_disable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command"), Format.Code(user.ToString())).ConfigureAwait(false); } @@ -428,7 +430,7 @@ namespace NadekoBot.Modules.Permissions [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task RoleCmd(CommandInfo command, PermissionAction action, [Remainder] IRole role) + public async Task RoleCmd(CommandOrCrInfo command, PermissionAction action, [Remainder] IRole role) { if (role == role.Guild.EveryoneRole) return; @@ -438,21 +440,21 @@ namespace NadekoBot.Modules.Permissions PrimaryTarget = PrimaryPermissionType.Role, PrimaryTargetId = role.Id, SecondaryTarget = SecondaryPermissionType.Command, - SecondaryTargetName = command.Aliases.First().ToLowerInvariant(), + SecondaryTargetName = command.Name.ToLowerInvariant(), State = action.Value, }); if (action.Value) { await ReplyConfirmLocalized("rx_enable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command"), Format.Code(role.Name)).ConfigureAwait(false); } else { await ReplyConfirmLocalized("rx_disable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command"), Format.Code(role.Name)).ConfigureAwait(false); } @@ -493,28 +495,28 @@ namespace NadekoBot.Modules.Permissions [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task ChnlCmd(CommandInfo command, PermissionAction action, [Remainder] ITextChannel chnl) + public async Task ChnlCmd(CommandOrCrInfo command, PermissionAction action, [Remainder] ITextChannel chnl) { await AddPermissions(Context.Guild.Id, new Permissionv2 { PrimaryTarget = PrimaryPermissionType.Channel, PrimaryTargetId = chnl.Id, SecondaryTarget = SecondaryPermissionType.Command, - SecondaryTargetName = command.Aliases.First().ToLowerInvariant(), + SecondaryTargetName = command.Name.ToLowerInvariant(), State = action.Value, }); if (action.Value) { await ReplyConfirmLocalized("cx_enable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command"), Format.Code(chnl.Name)).ConfigureAwait(false); } else { await ReplyConfirmLocalized("cx_disable", - Format.Code(command.Aliases.First()), + Format.Code(command.Name), GetText("of_command"), Format.Code(chnl.Name)).ConfigureAwait(false); } diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 7da895d6..6673cacb 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -110,6 +110,7 @@ namespace NadekoBot //setup typereaders CommandService.AddTypeReader(new PermissionActionTypeReader()); CommandService.AddTypeReader(new CommandTypeReader()); + CommandService.AddTypeReader(new CommandOrCrTypeReader()); CommandService.AddTypeReader(new ModuleTypeReader()); CommandService.AddTypeReader(new GuildTypeReader()); diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index d6678d23..ae005e95 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -29,11 +29,7 @@ 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; @@ -274,9 +270,47 @@ namespace NadekoBot.Services // maybe this message is a custom reaction // todo log custom reaction executions. return struct with info - var crExecuted = await Task.Run(() => CustomReactions.TryExecuteCustomReaction(usrMsg)).ConfigureAwait(false); - if (crExecuted) //if it was, don't execute the command + var cr = await Task.Run(() => CustomReactions.TryGetCustomReaction(usrMsg)).ConfigureAwait(false); + if (cr != null) //if it was, don't execute the command + { + try + { + if (guild != null) + { + PermissionCache pc; + if (!Permissions.Cache.TryGetValue(guild.Id, out pc)) + { + using (var uow = DbHandler.UnitOfWork()) + { + var config = uow.GuildConfigs.For(guild.Id, + set => set.Include(x => x.Permissions)); + Permissions.UpdateCache(config); + } + Permissions.Cache.TryGetValue(guild.Id, out pc); + if (pc == null) + throw new Exception("Cache is null."); + } + int index; + if ( + !pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions", + out index)) + { + //todo print in guild actually + var returnMsg = + $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action."; + _log.Info(returnMsg); + return; + } + } + await cr.Send(usrMsg).ConfigureAwait(false); + } + catch (Exception ex) + { + _log.Warn("Sending CREmbed failed"); + _log.Warn(ex); + } return; + } var exec3 = Environment.TickCount - execTime; @@ -384,6 +418,7 @@ namespace NadekoBot.Services PermissionCache pc; if (context.Guild != null) { + //todo move to permissions module? if (!Permissions.Cache.TryGetValue(context.Guild.Id, out pc)) { using (var uow = DbHandler.UnitOfWork()) diff --git a/src/NadekoBot/Services/Database/Models/CustomReaction.cs b/src/NadekoBot/Services/Database/Models/CustomReaction.cs index 394e5084..695c1cd3 100644 --- a/src/NadekoBot/Services/Database/Models/CustomReaction.cs +++ b/src/NadekoBot/Services/Database/Models/CustomReaction.cs @@ -12,6 +12,8 @@ namespace NadekoBot.Services.Database.Models public string Trigger { get; set; } public bool IsRegex { get; set; } public bool OwnerOnly { get; set; } + + public bool IsGlobal => !GuildId.HasValue; } public class ReactionResponse : DbEntity diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index 428171b5..909a15d5 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -32,8 +32,9 @@ namespace NadekoBot.Services.Database.Repositories.Impl /// /// Gets and creates if it doesn't exist a config for a guild. /// - /// - /// + /// For which guild + /// Use to manipulate the set however you want + /// Config for the guild public GuildConfig For(ulong guildId, Func, IQueryable> includes = null) { GuildConfig config; diff --git a/src/NadekoBot/TypeReaders/BotCommandTypeReader.cs b/src/NadekoBot/TypeReaders/BotCommandTypeReader.cs index 9b4e06c2..0699ae43 100644 --- a/src/NadekoBot/TypeReaders/BotCommandTypeReader.cs +++ b/src/NadekoBot/TypeReaders/BotCommandTypeReader.cs @@ -1,6 +1,8 @@ using Discord.Commands; using System.Linq; using System.Threading.Tasks; +using NadekoBot.Modules.CustomReactions; +using NadekoBot.Services.Database.Models; namespace NadekoBot.TypeReaders { @@ -17,4 +19,46 @@ namespace NadekoBot.TypeReaders return Task.FromResult(TypeReaderResult.FromSuccess(cmd)); } } + + public class CommandOrCrTypeReader : CommandTypeReader + { + public override async Task Read(ICommandContext context, string input) + { + input = input.ToUpperInvariant(); + + if (CustomReactions.GlobalReactions.Any(x => x.Trigger.ToUpperInvariant() == input)) + { + return TypeReaderResult.FromSuccess(new CommandOrCrInfo(input)); + } + var guild = context.Guild; + if (guild != null) + { + CustomReaction[] crs; + if (CustomReactions.GuildReactions.TryGetValue(guild.Id, out crs)) + { + if (crs.Any(x => x.Trigger.ToUpperInvariant() == input)) + { + return TypeReaderResult.FromSuccess(new CommandOrCrInfo(input)); + } + } + } + + var cmd = await base.Read(context, input); + if (cmd.IsSuccess) + { + return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Aliases.First())); + } + return TypeReaderResult.FromError(CommandError.ParseFailed, "No such command or cr found."); + } + } + + public class CommandOrCrInfo + { + public string Name { get; set; } + + public CommandOrCrInfo(string input) + { + this.Name = input; + } + } } From 506d058eccdbbf8717d59c9aee012d8fab4e91ee Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Mar 2017 08:43:27 +0100 Subject: [PATCH 544/746] xkcd latest fixed --- src/NadekoBot/Modules/Searches/Commands/XkcdCommands.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/XkcdCommands.cs b/src/NadekoBot/Modules/Searches/Commands/XkcdCommands.cs index b747f2bd..a4b031a3 100644 --- a/src/NadekoBot/Modules/Searches/Commands/XkcdCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/XkcdCommands.cs @@ -26,12 +26,17 @@ namespace NadekoBot.Modules.Searches { var res = await http.GetStringAsync($"{_xkcdUrl}/info.0.json").ConfigureAwait(false); var comic = JsonConvert.DeserializeObject(res); - var sent = await Context.Channel.SendMessageAsync($"{Context.User.Mention} " + comic) + var embed = new EmbedBuilder().WithColor(NadekoBot.OkColor) + .WithImageUrl(comic.ImageLink) + .WithAuthor(eab => eab.WithName(comic.Title).WithUrl($"{_xkcdUrl}/{comic.Num}").WithIconUrl("http://xkcd.com/s/919f27.ico")) + .AddField(efb => efb.WithName(GetText("comic_number")).WithValue(comic.Num.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("date")).WithValue($"{comic.Month}/{comic.Year}").WithIsInline(true)); + var sent = await Context.Channel.EmbedAsync(embed) .ConfigureAwait(false); await Task.Delay(10000).ConfigureAwait(false); - await sent.ModifyAsync(m => m.Content = sent.Content + $"\n`Alt:` {comic.Alt}"); + await sent.ModifyAsync(m => m.Embed = embed.AddField(efb => efb.WithName("Alt").WithValue(comic.Alt.ToString()).WithIsInline(false)).Build()); } return; } From ac671a7f0cc1ed7a5aed7ef46c52d859f66d5bc6 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Mar 2017 09:03:21 +0100 Subject: [PATCH 545/746] Changes of heart no longer counts affinity removals, and counts each user only once --- .../Modules/Gambling/Commands/WaifuClaimCommands.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs index 7f3e4b03..5605e3e6 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs @@ -395,7 +395,7 @@ namespace NadekoBot.Modules.Gambling target = Context.User; WaifuInfo w; IList claims; - int divorces = 0; + int divorces; using (var uow = DbHandler.UnitOfWork()) { w = uow.Waifus.ByWaifuUserId(target.Id); @@ -494,7 +494,10 @@ namespace NadekoBot.Modules.Gambling int count; using (var uow = DbHandler.UnitOfWork()) { - count = uow._context.WaifuUpdates.Count(w => w.User.UserId == userId && w.UpdateType == WaifuUpdateType.AffinityChanged); + count = uow._context.WaifuUpdates + .Where(w => w.User.UserId == userId && w.UpdateType == WaifuUpdateType.AffinityChanged && w.New != null) + .GroupBy(x => x.New) + .Count(); } AffinityTitles title; From da60df7e5180dca282304a55dcd340fd1266a271 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 14 Mar 2017 21:02:31 +0100 Subject: [PATCH 546/746] Fixed warning --- src/NadekoBot/Modules/CustomReactions/CustomReactions.cs | 2 +- src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index bbe73e51..e67cb64b 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -61,7 +61,7 @@ namespace NadekoBot.Modules.CustomReactions public void ClearStats() => ReactionStats.Clear(); - public static async Task TryGetCustomReaction(SocketUserMessage umsg) + public static CustomReaction TryGetCustomReaction(SocketUserMessage umsg) { var channel = umsg.Channel as SocketTextChannel; if (channel == null) diff --git a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs index 21b3c67b..58752c28 100644 --- a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs @@ -246,7 +246,7 @@ namespace NadekoBot.Modules.Utility await Context.Channel.SendConfirmAsync( "🔁 " + GetText("repeater", - Format.Bold(rep.Repeater.Message), + Format.Bold(((IGuildUser)Context.User).GuildPermissions.MentionEveryone ? rep.Repeater.Message : rep.Repeater.Message.SanitizeMentions()), Format.Bold(rep.Repeater.Interval.Days.ToString()), Format.Bold(rep.Repeater.Interval.Hours.ToString()), Format.Bold(rep.Repeater.Interval.Minutes.ToString()))).ConfigureAwait(false); From b90bf3ac8a137f534795dd1bb8ebc9fa54425700 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 16 Mar 2017 09:12:15 +0100 Subject: [PATCH 547/746] fixed ~we when multiple weathers are received --- src/NadekoBot/Modules/Searches/Searches.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 72969f49..88d688c9 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -51,7 +51,7 @@ namespace NadekoBot.Modules.Searches .AddField(fb => fb.WithName("🌄 " + Format.Bold(GetText("sunrise"))).WithValue($"{data.sys.sunrise.ToUnixTimestamp():HH:mm} UTC").WithIsInline(true)) .AddField(fb => fb.WithName("🌇 " + Format.Bold(GetText("sunset"))).WithValue($"{data.sys.sunset.ToUnixTimestamp():HH:mm} UTC").WithIsInline(true)) .WithOkColor() - .WithFooter(efb => efb.WithText("Powered by openweathermap.org").WithIconUrl($"http://openweathermap.org/img/w/{string.Join(", ", data.weather.Select(w => w.icon))}.png")); + .WithFooter(efb => efb.WithText("Powered by openweathermap.org").WithIconUrl($"http://openweathermap.org/img/w/{data.weather[0].icon}.png")); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } @@ -217,7 +217,7 @@ namespace NadekoBot.Modules.Searches if (string.IsNullOrWhiteSpace(ffs)) return; - await Context.Channel.SendConfirmAsync(await NadekoBot.Google.ShortenUrl($"")) + await Context.Channel.SendConfirmAsync("<" + await NadekoBot.Google.ShortenUrl($"http://lmgtfy.com/?q={ Uri.EscapeUriString(ffs) }") + ">") .ConfigureAwait(false); } From 1069cb17db84e0b4c9b42f830af386623a570f60 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 16 Mar 2017 09:19:12 +0100 Subject: [PATCH 548/746] $waifuinfo will now show up to 30 random waifus, down from 40 --- src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs index 5605e3e6..c1d16578 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/WaifuClaimCommands.cs @@ -434,7 +434,7 @@ namespace NadekoBot.Modules.Gambling .AddField(efb => efb.WithName(GetText("likes")).WithValue(w.Affinity?.ToString() ?? nobody).WithIsInline(true)) .AddField(efb => efb.WithName(GetText("changes_of_heart")).WithValue($"{affInfo.Count} - \"the {affInfo.Title}\"").WithIsInline(true)) .AddField(efb => efb.WithName(GetText("divorces")).WithValue(divorces.ToString()).WithIsInline(true)) - .AddField(efb => efb.WithName($"Waifus ({claims.Count})").WithValue(claims.Count == 0 ? nobody : string.Join("\n", claims.OrderBy(x => rng.Next()).Take(40).Select(x => x.Waifu))).WithIsInline(true)); + .AddField(efb => efb.WithName($"Waifus ({claims.Count})").WithValue(claims.Count == 0 ? nobody : string.Join("\n", claims.OrderBy(x => rng.Next()).Take(30).Select(x => x.Waifu))).WithIsInline(true)); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } From 07a9e9788edb823eec25293c2f1815c727c79fcb Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 16 Mar 2017 09:47:38 +0100 Subject: [PATCH 549/746] Some debugging thingy --- src/NadekoBot/Services/Database/Models/Permission.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NadekoBot/Services/Database/Models/Permission.cs b/src/NadekoBot/Services/Database/Models/Permission.cs index 4367cd63..fe692221 100644 --- a/src/NadekoBot/Services/Database/Models/Permission.cs +++ b/src/NadekoBot/Services/Database/Models/Permission.cs @@ -62,6 +62,7 @@ namespace NadekoBot.Services.Database.Models int Index { get; set; } } + [DebuggerDisplay("{PrimaryTarget}{SecondaryTarget} {SecondaryTargetName} {State} {PrimaryTargetId}")] public class Permissionv2 : DbEntity, IIndexed { public int? GuildConfigId { get; set; } From 7f07508c7c4e9d9afb323af50b61c18c39ee6c43 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 16 Mar 2017 12:31:57 +0100 Subject: [PATCH 550/746] Permissions bugs fixed? --- src/NadekoBot/Modules/Permissions/Permissions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Permissions/Permissions.cs b/src/NadekoBot/Modules/Permissions/Permissions.cs index 837bea9d..ce04f75c 100644 --- a/src/NadekoBot/Modules/Permissions/Permissions.cs +++ b/src/NadekoBot/Modules/Permissions/Permissions.cs @@ -161,7 +161,7 @@ namespace NadekoBot.Modules.Permissions { using (var uow = DbHandler.UnitOfWork()) { - var config = uow.GuildConfigs.For(Context.Guild.Id, set => set); + var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.Permissions)); config.VerbosePermissions = action.Value; await uow.CompleteAsync().ConfigureAwait(false); UpdateCache(config); From 7f7c53af3466ca5ee28984544ff9e6a5789661be Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 17 Mar 2017 16:42:08 +0100 Subject: [PATCH 551/746] Spanish added --- .../Commands/LocalizationCommands.cs | 1 + .../Resources/ResponseStrings.es-ES.resx | 2251 +++++++++++++++++ 2 files changed, 2252 insertions(+) create mode 100644 src/NadekoBot/Resources/ResponseStrings.es-ES.resx diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 077eeb85..86a41f7a 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -30,6 +30,7 @@ namespace NadekoBot.Modules.Administration {"pt-BR", "Portuguese, Brazil"}, {"ru-RU", "Russian, Russia"}, //{"sr-Cyrl-RS", "Serbian, Serbia - Cyrillic"} + {"es-ES", "Spanish, Spain"}, {"sv-SE", "Swedish, Sweden"}, {"tr-TR", "Turkish, Turkey" } }.ToImmutableDictionary(); diff --git a/src/NadekoBot/Resources/ResponseStrings.es-ES.resx b/src/NadekoBot/Resources/ResponseStrings.es-ES.resx new file mode 100644 index 00000000..a4bf4b50 --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.es-ES.resx @@ -0,0 +1,2251 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Esa base ya fue reclamada o destruida. + + + Esa base ya fue destruida. + + + Esa base no ha sido reclamada. + + + **Destruida** la base #{0} en la guerrra contra {1} + + + {0} ha **liberado** la base #{1} en la guerra contra {2} + + + {0} reclamó la base #{1} en la guerra contra {2} + + + @{0} Ya has reclamado la base #{1}. No puedes reclamar otra. + + + La reclamación de @{0} en la guerra contra {1} ha expirado. + + + Enemigo + + + Información sobre la guerra contra {0} + + + Número de base inválido. + + + No es un tamaño de guerra válido. + + + Lista de guerras activas + + + no reclamada + + + No estás participando en esa guerra. + + + @{0} No estás participando en esa guerra o esa base ya fue destruida. + + + No hay guerra activa. + + + Tamaño + + + La guerra contra {0} ya ha iniciado. + + + La guerra contra {0} ha sido creada. + + + La guerra contra {0} ha terminado. + + + Esa guerra no existe. + + + ¡La guerra contra {0} ha iniciado! + + + Las estadísticas de los comandos personalizados han sido borradas. + + + Comando personalizado eliminado + + + Insuficientes permisos. Necesitas administrar propiamente el Bot para comandos globales y ser administrador del servidor para locales. + + + Lista de todos los comandos personalizados + + + Comandos personalizados + + + Nuevo comando personalizado + + + No se ha encontrado el comando. + + + No se ha encontrado ningún comando con esa ID. + + + Respuesta + + + Estadísticas de los comandos personales + + + Estadísticas borradas para el comando personalizado {0}. + + + No se encontraron estadísticas. + + + Escribe + + + Hentai automático detenido. + + + Sin resultados. + + + {0} ya ha sido derrotado. + + + {0} ya tiene todo su HP. + + + Tu tipo ya es {0} + + + usó {0}{1} en {2}{3} y le hizo {4} de daño. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + ¡No puedes atacar de nuevo sin ser atacado! + + + No puedes atacarte a ti mismo. + + + ¡{0} ha sido derrotado! + + + se curó {0} con una {1} + + + {0} le queda {1} de HP. + + + No puedes usar {0}. Escribe `{1}ml` para ver la lista de movimientos que puedes usar. + + + Lista de movimientos para el tipo {0} + + + No es efectivo. + + + No tienes suficientes {0} + + + revivido {0} con una {1} + + + Te has revivido con una {0} + + + Tu tipo ha cambiado a {0} por una {1} + + + Es efectivo. + + + ¡Es superefectivo! + + + ¡Has usado muchos movimientos seguidos, así que no puedes moverte! + + + El tipo de {0} es {1} + + + No encuentro ese usuario. + + + ¡Ya no puedes continuar! + + + **Rol autoasignable** en usuarios que ingresen **desactivado**. + + + **Rol autoasignable** en usuarios que ingresen **activado**. + + + Adjuntos + + + Avatar cambiado + + + Has sido bloqueado del servidor {0}. +Razón: {1} + + + Bloqueado + PLURAL + + + Usuario bloqueado + + + Cambiado el nombre del Bot a {0} + + + Cambiado el estado del bot a {0} + + + Eliminación automática de mensajes de despedida desactivada. + + + Los mensajes de despedida serán eliminados después de {0} segundos. + + + El mensaje de despedida actual es: {0} + + + Activa los mensajes de despedida escribiendo {0} + + + Nuevo mensaje de despedida configurado. + + + Anuncio de despedida desactivado. + + + Anuncio de despedida activado en este canal. + + + Nombre del canal cambiado. + + + Nombre anterior + + + Tema del canal cambiado + + + Ordenado. + + + Contenido + + + Rol creado con éxito {0} + + + Canal de texto {0} creado. + + + Canal de voz {0} creado. + + + Ensordecimiento satisfactorio. + + + Servidor eliminado {0} + + + Detenida la eliminación automática de comandos de invocación. + + + Eliminación automática de comandos de invocación activada. + + + Canal de texto {0} eliminado. + + + Canal de voz {0} eliminado. + + + MP de + + + Añadido nuevo donador satisfactoriamente. Total donado por este usuario: {0} 👑 + + + ¡Gracias a las personas enlistadas por apoyar el proyecto! + + + Enviaré los MPs a todos los administradores. + + + Enviaré los MPs solamente al primer administrador. + + + Redirigiré los MPs desde ahora. + + + Ya no redirigiré los MPs. + + + Eliminación automática de los mensajes de bienvenida desactivada. + + + Los mensajes de bienvenida serán eliminados después de {0} segundos. + + + Actual mensaje de bienvenida por MP: {0} + + + Activa los mensajes de bienvenida por MP escribiendo {0} + + + Nuevo mensaje de bienvenida por MP configurado. + + + Anuncio de bienvenida por mensaje privado desactivado. + + + Anuncio de bienvenida por mensaje privado activado. + + + Mensaje de bienvenida actual: {0} + + + Activa los mensajes de bienvenida escribiendo {0} + + + Nuevo mensaje de bienvenida configurado. + + + Bienvenida desactivada. + + + Bienvenida activada en este canal. + + + No puedes usar este comando con usuarios que tienen un rol más alto o igual al tuyo. + + + ¡Imágenes cargadas después de {0} segundos! + + + Formato de entrada no válido. + + + Parámetros no válidos. + + + {0} ha entrado {1} + + + Has sido expulsado del servidor {0}. +Razón: {1} + + + Usuario expulsado: + + + Lista de lenguajes + + + El lenguaje local del servidor ahora es {0} - {1} + + + El lenguaje local del Bot ahora es {0} - {1} + + + Lenguaje del Bot configurado {0} - {1} + + + No pude configurar el lenguaje local. Revisa la ayuda. + + + El lenguaje del servidor fue configurado a {0} - {1} + + + {0} ha salido {1} + + + Servidor abandonado {0} + + + Registrando los eventos {0} en este canal. + + + Registrando todos los eventos en este canal. + + + Registro deshabilitado. + + + Registro de eventos a los que te puedes suscribir: + + + El registro ignorará {0}. + + + El registro no ignorará {0}. + + + El registro del {0} evento fue detenido. + + + {0} ha pedido mención de los siguientes roles: + + + Mensaje de {0} `[Administrador del Bot]`: + + + Mensaje enviado. + + + {0} movido de {1} a {2} + + + Mensaje eliminado en #{0} + + + Mensaje actualizado en #{0} + + + Silenciados. + PLURAL (users have been muted) + + + Silenciado. + singular "User muted." + + + No tengo los permisos necesarios. + + + Nuevo rol de Silenciar definido. + + + Necesito permisos de **administrador** para hacer eso. + + + Nuevo mensaje. + + + Nuevo apodo. + + + Nuevo tema. + + + Apodo cambiado. + + + No se puede encontrar ese servidor. + + + No encontré un fragmento con esa ID. + + + Mensaje anterior + Creo que "anterior" suena más acorde. + + + Apodo anterior + + + Tema anterior + + + Error. Creo que no tengo suficientes permisos. + + + Los permisos de este servidor han sido reiniciados. + + + Protecciones activas + + + {0} ha sido **desactivado** en este servidor. + + + {0} activado + + + Error. Necesito permisos para administrar roles. + + + Sin protección activada. + + + La entrada del usuario debe ser entre {0} y {1}. + + + Si {0} o más usuarios entran entre {1} segundos, los voy a {2} + + + El tiempo debe ser entre {0} y {1} segundos. + + + He removido todos los roles del usuario {0} + + + No pude mover los roles. No tengo suficientes permisos. + + + El color del rol {0} ha sido cambiado. + + + Ese rol no existe. + + + Los parámetros especificados no son válidos. + + + Error debido a un color no válido o insuficiencia de permisos. + + + He removido satisfactoriamente el rol {0} del usuario {1}. + + + No pude remover el rol. Insuficientes permisos. + + + Rol renombrado. + + + No pude renombrar el rol. No tengo suficientes permisos. + + + No puedes editar roles con más poder que el tuyo. + + + Removido el mensaje de juego: {0} + + + El rol {0} ha sido añadido a la lista. + + + No encontré {0}. + Fuzzy + + + El rol {0} ya está en la lista. + + + Añadido. + + + Rotación de estados desactivada. + + + Rotación de estado activada. + + + Aquí está la lista de rotaciones de estado: {0} + + + No hay rotaciones de estado configuradas. + + + Ya tienes el rol {0}. + + + Ya tienes el rol autoasignable exclusivo {0}. + + + Ahora los roles autoasignables son exclusivos. + + + Hay {0} roles autoasignables. + + + Ese rol no es autoasignable. + + + No tienes el rol {0}. + + + Los roles autoasignables ya no son exclusivos. + + + No puedo añadirte ese rol. No puedo añadirle roles a administradores u otros roles con rangos más altos. + + + {0} ha sido removido de la lista de roles autoasignables. + + + Ya no tienes el rol {0}. + + + Ahora tienes el rol {0}. + + + Añadido satisfactoriamente el rol {0} al usuario {1}. + + + No pude añadir el rol. Insuficientes permisos. + + + Nuevo avatar configurado. + + + Nuevo nombre del canal configurado. + + + Nuevo juego configurado. + + + Nueva transmisión configurada. + + + Nuevo tema del canal configurado. + + + Fragmento {0} reconectado. + + + Fragmento {0} reconectando. + + + Apagando + + + Los usuarios no pueden enviar más de {0} mensajes cada {1} segundos. + + + Modo lento desactivado. + + + Modo lento iniciado + + + advertido (expulsado) + PLURAL + + + {0} ignorará este canal. + + + {0} no ignorará este canal. + + + Si un usuario publica {0} el mismo mensaje rápidamente, voy a {1}. +__CanalesIgnorados__: {2} + + + Canal de texto creado. + + + Canal de texto removido. + + + Ensordecimiento removido. + + + Desilenciado + singular + + + Usuario + + + Usuario cambiado + + + Usuarios + + + Usuario bloqueado + + + {0} ha sido **silenciado** en chat. + + + {0} ahora puede escribir en el chat. + + + Usuario se unió. + + + Usuario se fue. + + + {0} ha sido **silenciado** de chat y voz. + + + Rol del usuario añadido + + + Rol del usuario removido + + + {0} ahora está {1} + + + {0} ha sido removido del mundo de los silenciados. + + + {0} ha entrado al canal de voz {1}. + + + {0} ha salido del canal de voz {1}. + + + {0} movido del canal de voz {1} a {2}. + + + {0} ha sido **silenciado de voz** + + + {0} ya puede hablar por voz. + + + Canal de voz creado + + + Canal de voz destruido + + + Desactivada la opción de voz + texto. + + + Activada la opción de voz + texto. + + + No tengo los permisos para **administrar roles** y/o **administrar canales**, así que no puedo ejecutar `voz+texto` en el servidor {0}. + + + Estás activando o desactivando esto y **no poseo permisos de administración**. Esto puede causar problemas y tendrás que arreglar los canales tú mismo después. + + + Necesito permisos para **administrar roles** y **administrar canales** para hacer esto. De preferencia permisos de Administración. + + + Usuario {0} de chat. + + + Usuario {0} de chat y voz. + + + Usuario {0} del chat de voz + + + Has sido advertido en el servidor {0}. +Razón: {1} + + + Usuario desbloqueado: + + + ¡Migración terminada! + + + Error al migrar, revisa la consola para más información. + + + Actualizaciones de presencia + + + Usuario advertido + + + le ha regalado {0} a {1} + + + Suerte la próxima. + + + ¡Felicitaciones! Ganaste {0} por sacar sobre {1} + + + Mazo reconstruido. + + + lanzó {0} + User flipped tails. + + + ¡Adivinaste! Ganas {0} + + + Número especificado no es válido. Puedes lanzar de 1 a {0} monedas. + + + Añade la reacción {0} a este mensaje para obtener {1} + + + Este evento estará activo por {0} horas. + + + ¡Inicia el evento de reacción! + + + le ha regalado {0} a {1} + X has gifted 15 flowers to Y + + + {0} tiene {1} + X has Y flowers + + + Cara + + + Marcador + + + Enviados {0} a {1} usuarios en el rol {2}. + + + No puedes apostar más de {0} + + + No puedes apostar menos de {0} + + + No tienes suficientes {0} + + + No hay más cartas en el mazo. + + + Usuario escogido: + + + Sacaste {0}. + + + Apostó + + + ¡Cielos! ¡Felicitaciones! x{0} + + + Solo una {0}, x{1} + + + ¡Guau! ¡Suertudo! ¡Tres iguales! x{0} + + + ¡Buen trabajo! Dos {0} - Apostado x{1} + + + Ganó + + + Los usuarios deben escribir un código secreto para obtener {0}. Quedan {1} segundos. No le digas a nadie. + + + El evento de Estado Escurridizo ha terminado. {0} recibieron el premio. + + + Evento de Estado Escurridizo iniciado + + + Cruz + + + le quitó {0} a {1} + + + no pudo quitarle {0} a {1} porque el usuario no tiene tal cantidad {2}. + + + Regresar a la tabla de contenidos + + + Solo el dueño del Bot. + + + Requiere {0} permisos del canal. + + + Puedes apoyar el proyecto en Patreon: <{0}> o PayPal: <{1}> + + + Comandos y alias + + + Lista de comandos regenerada. + + + Escribe `{0}h NombreDelComando` para recibir ayuda específica. Ej: `{0}h >8ball` + + + No puedo encontrar ese comando. Por favor verifica que el comando exista y trata de nuevo. + + + Descripción + + + Puedes apoyar el proyecto de NadekoBot en +Patreon <{0}> o +PayPal <{1}> +No olvides dejar tu usuario de Discord o ID en el mensaje. + +*Gracias** ♥ + + + **Lista de comandos**. <{0}> +**Las guías para albergar y documentos pueden ser encontradas aquí**: <{1}> + + + Lista de comandos + + + Lista de módulos + + + Escribe `{0}cmds NombreDelMódulo` para obtener una lista de comandos en ese módulo. Ej: `{0}cmds games` + + + Ese módulo no existe. + + + Requiere {0} permisos del servidor + + + Tabla de contenidos + + + Uso + + + Hentai automático iniciado. Publicando cada {0}s con los siguientes tags: +{1} + + + Tag + + + Carrera de animales + + + No pude iniciar la carrera porque no hay suficientes participantes. + + + ¡Todo listo! ¡Allá vamos! + + + {} entró como un {1} + + + {0} entró como un {1} y apostó {2}. + + + Escribe {0}jr para entrar en la carrera. + + + Empezaremos en 20 segundos o cuando ya no haya lugar. + + + Empezando con {0} participantes. + + + {0} como un {1} ganó la carrera. + + + {0} como {1} ganó la carrera y {2}. + + + Número especificado no válido. Puedes lanzar {0}-{1} dados a la vez. + + + sacaste {0} + Someone rolled 35 + + + Dado lanzado: {0} + Dice Rolled: 5 + + + No pude iniciar la carrera. Probablemente otra está en curso. + + + No hay carrera en este servidor. + + + El segundo número debe ser más largo que el primero. + + + Cambios de opinión + + + Reclamado por + + + Divorcios + + + Le gusta + + + Precio + + + Ninguna waifu ha sido reclamada aún. + + + Top de waifus + + + tu afinidad ya ha sido configurada hacia esa waifu o intentas remover tu afinidad sin tenerla. + + + cambió su afinidad de {0} a {1}. + +*Esto es moralmente cuestionable.* 🤔 + Make sure to get the formatting right, and leave the thinking emoji + + + Debes esperar {0} horas y {1} minutos para cambair tu afinidad otra vez. + + + Tu afinidad ha sido reiniciada. Ya no tienes una persona que te guste. + + + quiere ser la waifu de {0}. Aww <3 + + + reclamó a {0} como su waifu por {1} + + + Te has divorciado de una waifu que te quería. Monstruo sin corazón. {0} recibió {1} como compensación. + + + no puedes configurar tu afinidad hacia ti mismo, rarito. + + + 🎉 ¡Su amor es correspondido! 🎉 +¡El nuevo valor de {0} es {1}! + + + Ninguna waifu es tan barata. Debes pagar al menos {0} para obtener una waifu, aunque su valor actual sea bajo. + + + ¡Debes pagar {0} o más para reclamar esa waifu! + + + Esa waifu no es tuya. + + + No puedes reclamarte a ti mismo. + + + Te divorciaste recientemente. Debes esperar {0} horas y {1} minutos para divorciarte otra vez. + + + Nadi + + + Te has divorciado de uan waifu que no te querías. Recibes {0} de regreso. + + + Bola 8 + + + Acrofobia + + + El juego terminó sin oraciones. + + + Nadie votó. El juego ha terminado sin ganador. + + + El acrónimo era {0}. + + + Acrofobia ya se está ejecutando en este canal. + + + Inicia el juego. Crea una oración con el siguiente acrónimo: {0}. + + + Tienes {0} segundos. + + + {0} enviaron sus oraciones. ({1} en total) + + + Vota escribiendo el número correspondiente. + + + ¡{0} votaron! + + + El ganador es {0} con {1} puntos. + + + ¡{0} gana por ser el único que envió una oración! + + + Pregunta + + + ¡Empate! Ambos eligieron {0} + + + ¡{0} gana! {1} vence {2} + + + Envíos cerrados + + + La carrera de animales ya está en ejecución. + + + Total: {0} Promedio: {1} + + + Categoría + + + Cleverbot desactivado en este servidor. + + + Cleverbot activado en este servidor. + + + La regeneración ha sido desactivada en este canal. + + + La regeneración ha sido activada en este canal. + + + {0} {1} apareció. + plural + + + ¡Una {0} apareció! + + + No pue cargar la pregunta. + + + Inicia el juego + + + Juego del ahorcado iniciado + + + Un juego del ahorcado ya se está ejecutando. + + + Error iniciando el ahorcado. + + + Lista de "{0}hangman" términos: + + + Marcador + + + No tienes suficientes {0} + + + Sin resultados + + + tomó {0} + Kwoth picked 5* + + + {0} plantó {1} + Kwoth planted 5* + + + Ya se está ejecutando una trivia en este servidor. + + + Trivia + + + ¡{0} adivinó! La respuesta era: {1} + + + No se está ejecutando ninguna trivia en este servidor. + + + {0} tiene {1} puntos + + + La trivia se detendrá luego de esta pregunta. + + + ¡Tiempo! La respuesta correcta era {0} + + + ¡{0} adivinó y ganó el juego! La respuesta era: {1} + + + No puedes jugar contra ti mismo. + + + El juego de Tres en raya ya se ha iniciado en este canal. + + + ¡Empate! + + + ha creado un juego de Tres en raya. + + + ¡{0} gana! + + + Hizo coincidir tres + + + ¡No quedan más movimientos! + + + ¡Tiempo! + + + Movimiento de {0} + + + {0} vs {1} + + + Intentando añadir a la cola {0} canciones... + + + Reproducción automática desactivada. + + + Reproducción automática activada. + + + El volumen por defecto configurado en {0}% + + + Directorio completo + + + Juego sucio + + + Canción finalizada + + + Juego sucio desactivado. + + + Juego sucio activado. + + + De la posición + + + ID + + + Entrada no válida. + + + Tiempo de reproducción sin límite. + + + Tiempo de reproducción máximo configurado en {0} segundo(s). + + + Tamaño máximo de la cola configurada en ilimitado. + + + Tamaño máximo de la cola configurado en {0} pista(s). + + + Tienes que estar en un canal de voz. + + + Nombre + + + Reproduciendo + + + No hay reproducción activa. + + + Sin resultados. + + + Música pausada. + + + Cola - Página {0}/{1} + + + Reproduciendo + + + `#{0}` - **{1}** por *{2}* ({3} canciones) + + + Página {0} de listas de reproducción guardadas. + + + Lista de reproducción eliminada. + + + No pude eliminar esa lista. O no existe, o no eres el autor. + + + No existe una lista con tal ID. + + + Cola de lista de reproducción completa. + + + Lista de reproducción guardada + + + Límite de {0} + + + Cola. + + + Canción en cola. + + + Se eliminó la cola de música. + + + La cola está llena con {0}. + + + Canción eliminada: + context: "removed song #5" + + + Repitiendo la canción actual + + + Repitiendo lista de reproducción + + + Repitiendo pista + + + Repetición de la pista actual detenida. + + + Reproducción resumida + + + Repetición de listas de reproducción desactivada. + + + Repetición de listas de reproducción activada. + + + Desde ahora publicaré la reproducción, finalización, pausa y eliminación de canciones en este canal. + + + Saltado a `{0}:{1}` + + + Canciones reorganizadas. + + + Canción movida + + + {0}h {1}m {2}s + + + A la posición + + + ilimitada + + + El volumen debe ser entre 0 y 100. + + + Volumen definido en {0}% + + + Desactivado el uso de todos los módulos en el canal {0}. + + + Activado el uso de todos los módulos en el canal {0}. + + + Permitido + + + Desactivado el uso de todos los módulos para el rol {0}. + + + Activado el uso de todos los módulos para el rol {0}. + + + Desactivado el uso de todos los módulos en este servidor. + + + Activado el uso de todo los módulos en este servidor. + + + Desactivado el uso de todos los módulos para el usuario {0}. + + + Activado el uso de todos los módulos para el usuario {0}. + + + Enviado a la lista negra a: {0} con la ID: {1} + + + El comando {0} ahora tiene {1} de enfriamiento. + + + El comando {0} ya no se está enfriando y todos los tiempos de enfriamiento han sido reiniciados. + + + No se ha configurado tiempo de enfriamiento. + + + Costo del comando + + + Desactivado el uso de {0} {1} en el canal {2}. + + + Activado el uso de {0} {1} en el canal {2}. + + + Prohibido + + + Se ha añadido la palabra {0} a la lista de groserías. + + + Lista de palabras filtradas + + + Removida la palabra {0} de la lista de palabras filtradas. + + + Segundo parámetro no válido. (Debe ser un número entre {0} y {1}) + + + Filtro de invitaciones desactivado en este canal. + + + Filtro de invitaciones activado en este canal. + + + Filtro de invitaciones desactivado en este servidor. + + + Filtro de invitaciones activado en este servidor. + + + Permiso {0} movido de #{1} a #{2} + + + No puedo encontrar el permiso en #{0} + + + No hay costo configurado. + + + comando + Gen (of command) + + + módulo + Gen. (of module) + + + Página de permisos {0} + + + El rol de permisos actual es {0} + + + Los usuarios ahora requieren el rol {0} para editar permisos. + + + No se encontraron permisos. + + + permisos removidos #{0} - {1} + + + Desactivado el uso de {0} {1} para el rol {2}. + + + Activado el uso de {0} {1} para el rol {2}. + + + seg. + Short of seconds. + + + Desactivado el uso de {0} {1} en este servidor. + + + Activado el uso de {0} {1} en este servidor. + + + Removido de la lista negra a: {0} con la ID: {1} + + + ineditable + + + Desactivado el uso de {0} {1} para el usuario {2}. + + + Activado el uso de {0} {1} para el usuario {2}. + + + No mostraré más advertencias de permisos. + + + Desde ahora mostraré las advertencias de permisos. + + + Filtro de groserías activado en este canal. + + + Filtro de groserías activado en este canal. + + + Filtro de groserías desactivado en este servidor. + + + Filtro de groserías activado en este servidor. + + + Habilidades + + + No tiene anime favorito aún + + + Iniciada la traducción automática de mensajes en este canal. Los mensajes del usuario serán eliminados automáticamente. + + + tu lenguaje de traducción automática ha sido removido. + + + Tu lenguaje de traducción automática ha sido configurado a {0}>{1} + + + Iniciada la traducción automática de mensajes en este canal. + + + Detenida la traducción automática de mensajes en este canal. + + + Mal formato o algo salió mal. + + + No encontré esa carta. + + + hecho + + + Capítulos + + + Cómic # + + + Pérdidas en competitivo + + + Juegos en competitivo + + + Rango en competitivo + + + Victorias en competitivo + + + Completada + + + Condición + + + Costo + + + Fecha + + + Defininir: + + + Eliminadas + + + Episodios + + + Ocurrió un error. + + + Ejemplo + + + No encontré ese anime. + + + No encontré ese manga. + + + Géneros + + + No encontré una definición para ese tag. + + + Altura/Peso + + + {0}m/{1}kg + + + Humedad + + + Búsqueda de imagen para: + + + No encontré esa película. + + + Fuente o lenguaje no válido. + + + No se cargaron las bromas. + + + Lat/Long + + + Nivel + + + Lista de tags en {0}place + Don't translate {0}place + + + Locación + + + Objetos mágicos no cargados. + + + Perfil de MAL de {0} + + + El dueño del Bot no especificó una clave MashapeApi. No puedes usar esto. + + + Mín/Máx + + + No encontré ese canal. + + + Sin resultados. + + + En espera + + + Original + + + Se requiere una clave de API de osu! + + + No pude encontrar esa firma de osu! + + + Encontré alrededor de {0} imágenes. Mostrando {0} aleatorias. + + + ¡Usuario no encontrado! Por favor revisa la región y BattleTag antes de intentar de nuevo. + + + Planeadas + + + Plataforma + + + No encontré tal habilidad. + + + No encontré ese Pokémon. + + + Enlace al perfil: + + + Atributo: + + + Reproducción rápida: + + + Victorias rápidas + + + Rating + + + Puntuación: + + + Búsqueda para: + + + No pude acortar ese enlace. + + + Acortada + + + Algo salió mal. + + + Por favor especifica parámetros de búsqueda. + + + Estado + + + Depósito de enlace + + + El usuario {0} está desconectado. + + + El usuario {0} está en línea con {1} espectadores. + + + Estás siguiendo {0} transmisiones en este servidor. + + + No estás siguiendo ninguna transmisión en este servidor. + + + No existe esa transmisión. + + + La transmisión probablemente no existe. + + + Removida la transmisión de {0} ({1}) de las notificaciones. + + + Notificaré en este canal cuando el estado cambie. + + + Salida del sol + + + Puesta del sol + + + Temperatura + + + Título: + + + Top 3 de anime favoritos: + + + Traducción: + + + Tipos: + + + No pude encontrar una definición para ese término. + + + Enlace + + + Espectadores + + + Mirando + + + No pude encontrar ese término en la Wikia especificada. + + + Por favor ingresa la Wikia seguido por el término de búsqueda. + + + Página no encontrada. + + + Velocidad del viento + + + Los {0} campeones bloqueados + + + No pude yodificar tu oración + + + Entró + + + `{0}.` {1} [{2:F2}/s] - {3} en total + /s and total need to be localized to fit the context - +`1.` + + + Página de actividad #{0} + + + {0} usuarios en total. + + + Autor + + + ID del Bot + + + Lista de funciones en el comando {0}calc + + + {0} de este canal es {1} + + + Tema del canal + + + Comandos ejecutados + + + {0} {1} es igual a {2} {3} + + + Unidades que pueden ser usadas por el conversor + + + No pude convertir {0} a {1}: Unidades no encontradas + + + No pude convertir {0} a {1}: el tipo de unidad no es igual + + + Creada el + + + Entró al canal del cruce de servidor. + + + Salió del canal del cruce de servidor. + + + Este es tu token CSC + + + Emoticones personales + + + Error + + + Características + + + ID + + + Entrada fuera de rango + + + Lista de usuarios en el rol {0} + + + No tienes permitido usar este comando en roles con muchos usuarios para prevenir abuso. + + + Valor {0} no válido. + Invalid months value/ Invalid hours value + + + Ingresó a Discord + + + Ingresó al servidor + + + ID: {0} +Miembros: {1} +ID del admin: {2} + + + No encontré servidores en esa página. + + + Lista de repetidores + + + Miembros + + + Memoria + + + Mensajes + + + Repetidor de mensajes + + + Nombre + + + Apodo + + + Nadie está jugando eso. + + + No hay repeticiones activas + + + No hay roles en esta página. + + + No hay fragmentos en esta página. + + + No hay tema configurado. + + + Administrador + + + ID del administrador + + + En + + + {0} servidores +{2} canales de texto +{2} canales de voz + + + Eliminadas todas las citas con la palabra clave {0} + + + Página {0} de citas + + + No hay citas en esta página + + + No hay citas que puedas remover + + + Cita añadida + + + Cita #{0} eliminada. + + + Región + + + Registrado el + + + Le recordaré a {0} que {1} en {2} `({3:d.M.yyyy.} a las {4:HH:mm})` + + + Formato de tiempo no válido. Revisa la lista de comandos. + + + Nueva plantilla de recordatorio configurada. + + + Repitiendo {0} cada {1} día(s), {2} hora(s) y {3} minuto(s). + + + Lista de repeticiones + + + No hay repetidores ejecutándose. + + + #{0} detenido. + + + No hay repeticiones de mensajes en este servidor. + + + Resultado + + + Roles + + + Página #{0} de todos los roles en este servidor. + + + Página #{0} de roles para {1} + + + Los colores no están en el formato correcto. Usa `#00ff00` por ejemplo. + + + Iniciada la rotación de colores para el rol {0}. + + + Detenida la rotación de colores para el rol {0} + + + {0} de este servidor es {1} + + + Información del servidor + + + Fragmento. + + + Estadísticas del fragmento. + + + Fragmento **#{0}** está en estado {1} con {2} servidores. + + + **Nombre:** {0} **Enlace:** {1} + + + No encontré emoticones especiales. + + + Reproduciendo {0} canciones, {1} en cola. + + + Canales de texto + + + Aquí está el enlace a tu cuarto: + + + Tiempo en línea + + + {0} del usuario {1} es {2} + Id of the user kwoth#1234 is 123123123123 + + + Usuarios + + + Canales de voz + + + ¡Ya entraste a esta carrera! + + + Resultados de la encuesta + + + Sin votos. + + + Ya hay una encuesta en ejecución. + + + 📃 {0} ha creado una encuesta que requiere de tu atención. + + + `{0}.` {1} con {2} votos. + + + {0} votó. + Kwoth voted. + + + Envíame un mensaje privado con el número correspondiente a la respuesta. + + + Envía un mensaje aquí con el número correspondiente a la respuesta. + + + Gracias por votar, {0} + + + {0} votos totales. + + + Atrápala escribiendo `{0}pick` + + + Atrápala escribiendo `{0}pick` + + + No encontré ese usuario. + + + página {0} + + + debes estar en un canal de voz. + + + No hay roles para el canal de voz. + + + {0} ha sido **silenciado** de chat y voz por {1} minutos. + + + Los usuarios que entren al canal de voz {0} obtendrán el rol {1}. + + + Los usuarios que entren al canal de voz {0} ya no obtendrán un rol. + + + Roles para el canal de voz + + + \ No newline at end of file From a60f0bb1e9aed8a5211a3108e8e4de3d69dc77c6 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 17 Mar 2017 16:43:28 +0100 Subject: [PATCH 552/746] Update ResponseStrings.zh-CN.resx (POEditor.com) From 6ec32045d3a216ba38abc86673ba65ba1748fc34 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 17 Mar 2017 16:43:30 +0100 Subject: [PATCH 553/746] Update ResponseStrings.zh-TW.resx (POEditor.com) --- .../Resources/ResponseStrings.zh-TW.resx | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx index 74edb3a9..f299b7f2 100644 --- a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx +++ b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx @@ -803,7 +803,7 @@ 成員身分組已移除 - {0} 改名為 {1} + {0} 現在 {1} 已**開放** {0} 的__文字和語音聊天__。 @@ -1340,10 +1340,10 @@ Paypal <{1}> 正在排 {0} 首歌... - 已停用自動撥放。 + 已停用自動播放。 - 已啟用自動撥放。 + 已啟用自動播放。 預設音量設定為 {0}% @@ -1352,10 +1352,10 @@ Paypal <{1}> 目錄載入完成。 - 公平撥放 + 公平播放 - 完成撥放 + 完成播放 停用公平播放。 @@ -1379,10 +1379,10 @@ Paypal <{1}> 每首音樂最長長度設定為{0}秒。 - 撥放清單大小現在沒有限制了。 + 播放清單大小現在沒有限制了。 - 撥放清單最多可以排序{0}首。 + 播放清單最多可以排序 {0} 首。 你必須要進入在此伺服器上的語音頻道。 @@ -1391,19 +1391,19 @@ Paypal <{1}> 名稱 - 正在撥放 + 正在播放 - 沒有正在運行中的撥放器。 + 沒有正在運行中的播放器。 沒有搜尋結果。 - 暫停撥放音樂。 + 暫停播放音樂。 - 撥放清單 - 第 {0} / {1} 頁 + 播放清單 - 第 {0} / {1} 頁 正在播放 @@ -1412,22 +1412,22 @@ Paypal <{1}> `#{0}` - **{1}** by *{2}* ({3}首歌) - 已儲存的撥放清單第 {0} 頁 + 已儲存的播放清單第 {0} 頁 - 撥放清單已刪除。 + 播放清單已刪除。 刪除清單失敗。清單要不是不存在,或你不是該清單的作者。 - 此撥放清單代號並不存在。 + 此播放清單代號並不存在。 - 撥放清單載入完成。 + 播放清單載入完成。 - 撥放清單已儲存 + 播放清單已儲存 {0} 秒限制 @@ -1449,34 +1449,34 @@ Paypal <{1}> context: "removed song #5" - 重複撥放目前歌曲 + 重複播放目前歌曲 - 重複撥放目前清單 + 重複播放目前清單 重複曲目 - 停止重複撥放目前歌曲。 + 停止重複播放目前歌曲。 - 繼續撥放音樂。 + 繼續播放音樂。 - 停用重複撥放清單 + 停用重複播放清單 - 啟用重複撥放清單。 + 啟用重複播放清單。 - 我將在此頻道輸出撥放、暫停、結束和移除的歌曲。 + 我將在此頻道輸出播放、暫停、結束和移除的歌曲。 跳至 ‘{0}:{1}’ - 隨機撥放 + 隨機播放 歌曲移至 @@ -2035,7 +2035,7 @@ Paypal <{1}> 成員 - 記憶 + 記憶體 訊息 @@ -2169,7 +2169,7 @@ Paypal <{1}> 找不到特殊的表情符號。 - 撥放 {0} 首歌,{1} 首已排序。 + 正在播放 {0} 首歌,{1} 首已點播。 文字頻道 From 0beac938e95c6fba9cfe161379eb03450d935231 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 17 Mar 2017 16:43:33 +0100 Subject: [PATCH 554/746] Update ResponseStrings.nl-NL.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.nl-NL.resx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx index 7c8f1723..9b49d118 100644 --- a/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx @@ -152,7 +152,8 @@ Ongeldige basis nummer - Ongeldige oorlogs formaat. + Ongeldig oorlogs +formaat. Fuzzy From 08808730f849d96aeef7a49d96e4f9ab419c1ee5 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 17 Mar 2017 16:43:36 +0100 Subject: [PATCH 555/746] Update ResponseStrings.en-US.resx (POEditor.com) From d5c049ba90ec1ba2209f95a9c48c6d6885cf162b Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 17 Mar 2017 16:43:38 +0100 Subject: [PATCH 556/746] Update ResponseStrings.fr-FR.resx (POEditor.com) --- .../Resources/ResponseStrings.fr-FR.resx | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx b/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx index c061305e..a6a0fa29 100644 --- a/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx @@ -476,8 +476,7 @@ Raison : {1} Fuzzy - Listes des langues -{0} + Listes des langues Fuzzy @@ -673,20 +672,20 @@ Raison : {1} Le rôle {0} est déjà présent dans la liste. - Ajouté. + Ajouté - Rotation du statut de jeu désactivée. + Alternance du statut de jeu désactivé. - Rotation du statut de jeu activée. + Alternance du statut de jeu activé. - Voici une liste des rotations de statuts : + Liste des statuts alternants: {0} - Aucune rotation de statuts en place. + Aucun statut alternant défini. Vous avez déjà le rôle {0}. @@ -1164,7 +1163,7 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Top Waifus - votre affinité est déjà liée à cette waifu ou vous êtes en train de retirer votre affinité avec quelqu'un alors que vous n'en possédez pas. + Votre affinité est déjà liée à cette waifu ou vous êtes en train de retirer votre affinité avec quelqu'un alors que vous n'en possédez pas. Affinités changées de de {0} à {1}. @@ -1176,16 +1175,16 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Vous devez attendre {0} heures et {1} minutes avant de pouvoir changer de nouveau votre affinité. - Votre affinité a été réinitialisée. Vous n'avez désormais plus la personne que vous aimez. + Votre affinité a été réinitialisée. Vous n'aimez plus personne désormais. veut être la waifu de {0}. Aww <3 - a revendiqué {0} comme sa waifu pour {1} + a revendiqué {0} comme sa waifu pour {1}! - Vous avez divorcé avec une waifu qui vous aimais. Monstre sans cœur. {0} a reçu {1} en guise de compensation. + Vous avez divorcé d'une waifu qui vous aimait. Monstre sans cœur. {0} a reçu {1} en guise de compensation. vous ne pouvez pas vous lier d'affinité avec vous-même, espèce d'égocentrique. @@ -1309,7 +1308,7 @@ Fuzzy Partie de pendu commencée. - Une partie de pendu est déjà en cours sur ce canal. + Une partie de pendu est déjà en cours sur ce salon. Initialisation du pendu erronée. @@ -2104,7 +2103,7 @@ Fuzzy Index hors limites. - Voici une liste des utilisateurs dans ces rôles : + Liste des utilisateurs ayant le rôle {0}: Fuzzy @@ -2168,7 +2167,7 @@ OwnerID: {2} Ne pas confondre Shard et Shared ;) Dans discord, le mot shard n'a pas d'équivalent francophone. - Aucun sujet choisi. + Aucun sujet défini. Propriétaire @@ -2251,10 +2250,10 @@ OwnerID: {2} Aucune couleur n'est dans le bon format. Utilisez `#00ff00` par exemple. - Couleurs alternées pour le rôle {0} activées. + Alternance de couleurs pour le rôle {0} activée. - Couleurs alternées pour le rôle {0} arrêtées + Alternance de couleurs pour le rôle {0} désactivée. {0} de ce serveur est {1} @@ -2353,22 +2352,22 @@ Fuzzy page {0} - Vous devez être sur un canal vocal sur ce serveur. + Vous devez être sur un salon vocal sur ce serveur. - Il n'y a pas de rôle de canal vocal. + Il n'y a pas de rôle de salon vocal. {0} est désormais **muet** du chat textuel et vocal pour {1} minutes. - Les utilisateurs rejoignant le canal vocal {0} obtiendrons le rôle {1}. + Les utilisateurs rejoignant le salon vocal {0} obtiendront le rôle {1}. - Les utilisateurs rejoignant le canal vocal {0} n’obtiendrons plus de rôle. + Les utilisateurs rejoignant le salon vocal {0} n’obtiendront plus de rôle. - Rôles du canal vocal + Rôles du salon vocal \ No newline at end of file From a4411f24c6946bbfee287b666924dc1e80a6c0cb Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 17 Mar 2017 16:43:41 +0100 Subject: [PATCH 557/746] Update ResponseStrings.de-DE.resx (POEditor.com) From 79ea4c8270d145220a08f441b6238e6e8f1c4104 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 17 Mar 2017 16:43:44 +0100 Subject: [PATCH 558/746] Update ResponseStrings.ja-JP.resx (POEditor.com) --- .../Resources/ResponseStrings.ja-JP.resx | 129 +++++++++--------- 1 file changed, 65 insertions(+), 64 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx b/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx index cd347e9f..b4c12bf6 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx @@ -227,7 +227,7 @@ - カスタム反応が見つかりませんでした。 + カスタムリアクションが見つかりませんでした。 Fuzzy @@ -710,7 +710,7 @@ Fuzzy - + エラー。管理権限が必要です。 保護は有効になっていません。 @@ -898,13 +898,13 @@ Fuzzy - + 低速モードは無効です。 - + 低速モードが初期化しました。 - + ソフトバン(キック) PLURAL @@ -928,7 +928,7 @@ Fuzzy - + ミュート解除 singular @@ -1056,8 +1056,7 @@ Fuzzy 存在の更新 - And this is where using exiled screws me over.. again lol - + ユーザはソフトバン Fuzzy @@ -1273,16 +1272,16 @@ Paypal <{1}> - + アニマルレース - + 十分な参加者がいなかったのでスタートできませんでした。 - + レースは満員になりました。すぐにスタートします。 - + {0} は {1} として参加しました。 @@ -1291,10 +1290,10 @@ Paypal <{1}> - + 部屋がいっぱいになるか、20秒後にスタートします。 - + {0} 人の参加者でスタートします。 @@ -1303,24 +1302,25 @@ Paypal <{1}> - + 数が正しくありません。一度に {0}-{1} のダイスを触れます。 - + ロール状{0} + Someone rolled 35 - + サイコロ振りました。: {0} Dice Rolled: 5 - + レーズが開始できませんでした。他のレースが行われているかもしれません。 - + このサーバーでは、どのレースも存在していません。 - + 最初の数よりも2番めの数が大きくなければなりません。 @@ -1393,7 +1393,7 @@ Paypal <{1}> - + エイトボール @@ -1420,7 +1420,7 @@ Paypal <{1}> - + 数字を入力して投票 @@ -1432,7 +1432,7 @@ Paypal <{1}> - + 質問 @@ -1450,13 +1450,13 @@ Paypal <{1}> - + カテゴリー - + このサーバーではCleverbotが有効です。 @@ -1469,22 +1469,22 @@ Paypal <{1}> plural - + ランダム {0} が出現! - + 質問のロードに失敗しました。 - + ゲームが始まりました。 - + ハングマンゲームが始まりました。 - + ハングマンゲームはすでにこのチャンネルで開始されています。 - + ハングマンのスタート時にエラーが起きました。 @@ -1537,13 +1537,13 @@ Paypal <{1}> - + 引き分け - + {0} の勝ち! @@ -1564,16 +1564,16 @@ Paypal <{1}> - + オートプレイは無効です。 - + オートプレイは有効です。 - + デフォルトの音量を{0}% にしました。 - + ディレクトリのキューが完了しました。 @@ -1598,19 +1598,19 @@ Paypal <{1}> - + 最大再生時間は制限ありません。 - + 最大再生時間を {0} 秒にセットしました。 - + 最大の音楽キューサイズを無制限にしました。 - + 最大の音楽キューサイズを {0} トラックに設定しました。 - + このサーバーのボイスチャンネルにいる必要があります。 曲名 @@ -1620,56 +1620,56 @@ Paypal <{1}> Fuzzy - + アクティブな音楽再生がありません。 検索結果なし - + 音楽の再生を一時停止します。 - + キュー Page {0}/{1} - + 音楽を再生しています。 - + `#{0}` - **{1}** by *{2}* ({3} 曲) - + 保存されたリストの {0} ページ目 - + プレイリストは削除されました。 - + プレイリストの削除に失敗しました。存在しないか、権限がありません。 - + そのIDのプレイリストは存在しません。 - + プレイリストのキューは完了しました。 - + プレイリストを保存しました。 - + {0} の上限です 次に聞く曲一覧 - + キューに追加した曲 Does this mean "the song was added to the queue" ? - + キューの音楽はクリアされました。 - + キュー( {0}/{0} ) はいっぱいです。 @@ -1733,28 +1733,29 @@ Paypal <{1}> - + 役割 {0} のすべてのモジュールの使用は無効になりました。 - + 役割 {0} のすべてのモジュールの使用は有効になりました。 - + このサーバーのすべてのモジュールの使用が無効になりました。 - + このサーバーのすべてのモジュールの使用が有効になりました。 - + ユーザー {0} へのすべてのモジュールの使用を無効にしました。 - + ユーザー {0} へのすべてのモジュールの使用を有効にしました。 - + {0} (ID {1})をブラックリストに登録しました。 + Cooldown? From e8ec73306ea0bdc66951db69ea425ba22bb45441 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 17 Mar 2017 16:43:46 +0100 Subject: [PATCH 559/746] Update ResponseStrings.nb-NO.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.nb-NO.resx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx b/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx index db86bfe2..e634ce06 100644 --- a/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx +++ b/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx @@ -2287,22 +2287,22 @@ Eier ID: {2} side {0} - + Du må være i en talekanal på denne serveren - + Det finnes ingen stemmekanal-roller - + {0} har blitt **dempet** fra tekst og tale i {1} minutt(er) - + Brukere som blir med i talekanalen {0} får rollen {1}. - + Brukere som blir med i talekanalen {0} får ikke lenger noen rolle. - + Stemmekanal-roller \ No newline at end of file From 0811ae7454d2c8b480da6f47c96e8bb5fa42dafa Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 17 Mar 2017 16:43:49 +0100 Subject: [PATCH 560/746] Update ResponseStrings.pl-PL.resx (POEditor.com) --- .../Resources/ResponseStrings.pl-PL.resx | 89 ++++++++++--------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx index ca2d82dc..62b2df49 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx @@ -191,13 +191,13 @@ Wojna przeciwko {o} zaczęła się! - + Wszystkie statystyki niestandardowych reakcji zostały wyczyszczone. Własne reakcje zostały usunięte - + Niewystarczające uprawnienia. Wymagane są uprawnienia właściciela dla globalnych niestandardowych reakcji oraz uprawnienia administratora dla niestandardowych reakcji na serwerze. Lista własnych reakcji @@ -218,7 +218,7 @@ Odpowiedź - + Statystyki niestandardowych reakcji @@ -416,7 +416,8 @@ Powód: {1} Od teraz nie będę wysyłać prywatnych wiadomości. - + Automatyczne usuwanie wiadomości powitalnych zostało wyłączone. + Wiadomości powitalne będą usuwane po {0} sekundach. @@ -458,10 +459,10 @@ Powód: {1} Obrazki załadowane po {0} sekundach. - + Niepoprawny format zmiennej. - + Niepoprawne parametry. {0} dołączył do {1} @@ -1086,16 +1087,16 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Zaczyna z {0} uczestnikami. - {0} jako {1} wygrał wyścig! + {1} czyli {0} wygrał wyścig! - {0} jako {1} wygrał wyścig i {2}! + {1} czyli {0} wygrał wyścig i {2}! - + wyrzucono {0} Someone rolled 35 @@ -1186,7 +1187,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Rozwiodłeś się z waifu, która cię nie lubi. W zamian dostałeś {0}. - + Magiczna kula nr 8 @@ -1195,10 +1196,10 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Brak głosów. Gra zakończyła się bez zwycięzcy. - + Akronim to {0}. @@ -1252,10 +1253,10 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Włączono cleverbota na tym serwerze. - + Generowanie przychodów zostało wyłączone na tym kanale. - + Generowanie przychodów zostało włączone na tym kanale. @@ -1334,7 +1335,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Remis! - + stworzył grę w kółko i krzyżyk. {0} wygrał! @@ -1388,7 +1389,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś ID - + Niepoprawna zmienna. Maksymalny czas grania ustawiony na: bez limitu. @@ -1418,7 +1419,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Brak wyników - + Odtwarzanie muzyki wstrzymane. @@ -1479,7 +1480,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Powtarzanie aktualnego utworu zatrzymane. - + Odtwarzanie muzyki wznowione. Powtarzanie playlisty wyłączone. @@ -1521,7 +1522,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Włączono użycie WSZYSTKICH MODÓŁÓW na kanale {0}. - + Dozwolone Wyłączono użycie WSZYSTKICH MODÓŁÓW dla roli {0}. @@ -1671,7 +1672,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Zdolności - Brak ulubionego zwierzęcia + Brak ulubionego anime Zaczęto automatyczne tłumaczenie wiadomości na tym kanale. Wiadomości użytkowników będą automatycznie usuwane. @@ -1701,7 +1702,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Rozdziały - + Komiks # Przegrane rywalizacje @@ -1728,7 +1729,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Data - + Zdefiniuj: @@ -1837,7 +1838,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Link profilowy: @@ -1849,13 +1850,13 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Ocena - + Wynik: - + Szukaj: Skracanie tego url'u nie powiodło się @@ -1870,7 +1871,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Status @@ -1909,7 +1910,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Temperatura - + Tytuł: 3 ulubione anime: @@ -1927,7 +1928,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Url - + Widzowie: @@ -1965,7 +1966,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Autor ID bota @@ -1977,7 +1978,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Temat kanału @@ -1995,7 +1996,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Stworzono w @@ -2007,13 +2008,13 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Niestandardowe emotikony Błąd - + Funkcje ID @@ -2038,7 +2039,9 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Dołączył do serwera - + ID: {0} +Członkowie: {1} +ID właściciela: {2} Nie znaleziono serwerów na tej stronie. @@ -2127,7 +2130,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Powtarzanie {0} co {1} dni, {2} godzin i {3} minut. @@ -2136,7 +2139,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + #{0} zatrzymany. @@ -2221,10 +2224,10 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + `{0}.` {1} z {2} głosami. - + {0} głosów. Kwoth voted. @@ -2252,22 +2255,22 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Musisz znajdować się w kanale głosowym na tym serwerze. - + {0} został **wyciszony** w kanałach tekstowych oraz głosowych na {1} minut. - + Użytkownicy którzy dołączą do kanału głosowego {0} , otrzymają rolę {1}. - + Uprawnienia kanału głosowego \ No newline at end of file From d570e7c7bda8c550bd29e83690cf335849fc07ae Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 17 Mar 2017 16:43:51 +0100 Subject: [PATCH 561/746] Update ResponseStrings.pt-BR.resx (POEditor.com) --- .../Resources/ResponseStrings.pt-BR.resx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx index 40aa59b7..147fd952 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx @@ -2327,34 +2327,34 @@ OwnerID: {2} Total de {0} votos proferidos. - + Pegue digitando `{0}pick` - + Pegue digitando `{0}pick` - + Nenhum usuário encontrado. - + Página {0} - + Você deve estar em um canal de voz neste servidor. - + Não há cargos de canais de voz. - + {0} foi **mutado** nos chats de texto e voz por {1} minutos. - + Usuários que entrarem no canal de voz {0} receberão o cargo {1}. - + Usuários que entrarem no canal de voz {0} não irão mais receber um cargo. - + Cargos de canais de voz \ No newline at end of file From 1846dc167966e753edf65f39bc0a2540011d04fe Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 17 Mar 2017 16:43:54 +0100 Subject: [PATCH 562/746] Update ResponseStrings.ru-RU.resx (POEditor.com) From f2fa6e1032638f4228159a28bbfc763db9903978 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 17 Mar 2017 16:43:57 +0100 Subject: [PATCH 563/746] Update ResponseStrings.sr-cyrl-rs.resx (POEditor.com) --- .../Resources/ResponseStrings.sr-cyrl-rs.resx | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx index e444eee6..17eb5bdc 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx @@ -127,7 +127,7 @@ Та база није под захтевом. - **DESTROYED** base #{0} in a war against {1} + **УНИШТЕНА** база #{0} у рату против {1} {0} је **ПОНИШТИО ЗАХТЕВ** за базу #{1} у рату против {2} @@ -1174,10 +1174,10 @@ Lasts {1} seconds. Don't tell anyone. Shhh. хоће да буде waifu од {0} - + је присвојио {0} као своју waifu за {1}! - + Развео си waifu којој се свиђаш. Душмане! {0} је добио {1} као компензацију. не можеш ставити афинитет на себе, егоманијаче. @@ -1415,7 +1415,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Максимални плејтајм више нема лимит. - + Максимално време пуштања је сада {0} секунди. Максимална величина реда је неограничена. @@ -1509,7 +1509,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Понављање плејлисте је упаљено. - + Исписиваћу поруке за почетак, крај, паузу и брисање песме у овом каналу. Прескочено на `{0}:{1}` @@ -1563,7 +1563,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Укључено коришћење СВИХ МОДУЛА за корисника {0}. - + {0} сa ИДем {1} је стављен на црну листу. Команда {0} сада има {1}с кулдаун. @@ -1659,7 +1659,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Укључено коришћење {0} {1} на овом серверу. - + {0} сa ИДем {1} је скинут са црне листе. неизмењиво @@ -1725,13 +1725,13 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Стрип # - + Такмичарских партија изгубљено - + Такмичарских партија играно - + Такмичарски ранг Такмичних победа @@ -1803,7 +1803,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Ниво - + Листа {0}place тагова Don't translate {0}place @@ -2019,10 +2019,10 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Направљен - + Прикључен у међусерверни канал. - + Међусерверни канал напуштен. Ово је твој CSC токен @@ -2150,7 +2150,7 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Fuzzy - + Подсетићу {0} да {1} у {2} `({3:d.M.yyyy.} at {4:HH:mm})` Није исправан формат времена. Проверите листу команди. @@ -2280,25 +2280,25 @@ Lasts {1} seconds. Don't tell anyone. Shhh. Покупите их куцајући `{0}pick` - + Покупи тако што укуцаш `{0}pick` - + Нема корисника. - + страница {0} - + Мораш бити у гласовном каналу на овом серверу. - + Нема рола за говорне канале. - + {0} је **занемљен** из текстовних и гласовних канала на {1} минута. - + Корисници који уђу у говорни канал {0} ће добити ролу {1}. From 5474a9761407cfcdd2d2420eff57739cf2e4ecaa Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 17 Mar 2017 16:43:59 +0100 Subject: [PATCH 564/746] Update ResponseStrings.sv-SE.resx (POEditor.com) --- .../Resources/ResponseStrings.sv-SE.resx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx index 79aa14d5..7ecb7286 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx @@ -376,7 +376,7 @@ Text kanal {0} skapad. - Röst kanal {0} skapad. + Röstkanal {0} skapad. Dövning lyckats. @@ -394,7 +394,7 @@ Text kanal {0} raderad. - Röst kanal {0} raderad. + Röstkanal {0} raderad. Meddelande från @@ -853,11 +853,11 @@ __IgnoreradeKannaler_: {2} {0} har blivit **röst omutad**- - Röst Kanal Skapad + Röstkanal Skapad Fuzzy - Röst Kanal Förstörd + Röstkanal Förstörd Fuzzy @@ -2318,22 +2318,22 @@ Medlemmar: {1} sida {0} - + Du måste vara i en röstkanal på denna server. - + Det finns inga röstkanalsroller. - + {0} har blivit **mutad** från text och röstchatt i {1} minuter. - + Användare som går in i röstkanalen {0} får rollen {1}. - + Användare som går - + Röstkanalsroller \ No newline at end of file From 2a30b6d23e52516822b6fd18921eaaa9a5708473 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 17 Mar 2017 16:44:02 +0100 Subject: [PATCH 565/746] Update ResponseStrings.tr-TR.resx (POEditor.com) --- .../Resources/ResponseStrings.tr-TR.resx | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx b/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx index f38f1a21..b807152e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx @@ -190,8 +190,7 @@ Tüm özel reaksiyon istatistikleri temizlendi. - Özel reaksiyonlar silindi. - Fuzzy + Özel reaksiyon silindi Yetersiz yetki.Global özel reaksiyonlar için bot sahibi yetkisi gerkirken, server tabanlı özel reaksiyonlar için Administrator yetkisi gerekir. @@ -255,8 +254,7 @@ {0} bayıldı! - {1} kullanarak {0} iyileştirildi. - Fuzzy + Bir {1} kullanılarak {0} iyileştirildi {0} canı {1} kaldı. @@ -469,8 +467,7 @@ Sebep: {1} Sebep: {1} - Kullanıcı Atıldı - Fuzzy + Kullanıcı atıldı Dil Listesi @@ -2005,8 +2002,7 @@ Fuzzy Dizin aralık dışında. - {0} rolündeki kullanıcıların listesi - Fuzzy + {0} rolüne sahip kullanıcı listesi Kötüye kullanımını önlemek için bu komutlar, çok sayıda kullanıcısı olan rollerde kullanmanıza izin verilmez. @@ -2095,8 +2091,7 @@ Kurucu Kimliği: {2} Alıntı Eklendi - Rastgele alıntı silindi. - Fuzzy + {0} numaralı alıntı silindi. Bölge From f157a0ba90fc43d1bddd862e4f3e8d64408cc316 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Fri, 17 Mar 2017 16:44:05 +0100 Subject: [PATCH 566/746] Update ResponseStrings.es-ES.resx (POEditor.com) --- .../Resources/ResponseStrings.es-ES.resx | 234 +++++++++--------- 1 file changed, 117 insertions(+), 117 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.es-ES.resx b/src/NadekoBot/Resources/ResponseStrings.es-ES.resx index a4bf4b50..fe1f8793 100644 --- a/src/NadekoBot/Resources/ResponseStrings.es-ES.resx +++ b/src/NadekoBot/Resources/ResponseStrings.es-ES.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Esa base ya fue reclamada o destruida. From 60dda075a5374cd9da49678f18352a8921f20afe Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 18 Mar 2017 02:18:31 +0100 Subject: [PATCH 567/746] Fixed permissions duplication bug WOOHOO --- .../Modules/Administration/Administration.cs | 2 +- .../Modules/Permissions/Permissions.cs | 12 +++--- src/NadekoBot/Services/CommandHandler.cs | 2 +- .../Repositories/IGuildConfigRepository.cs | 1 + .../Impl/GuildConfigRepository.cs | 43 ++++++++++++++++--- 5 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index d98458b4..4eb9d28c 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -59,7 +59,7 @@ namespace NadekoBot.Modules.Administration { using (var uow = DbHandler.UnitOfWork()) { - var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.Permissions)); + var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id); config.Permissions = Permissionv2.GetDefaultPermlist; await uow.CompleteAsync(); UpdateCache(config); diff --git a/src/NadekoBot/Modules/Permissions/Permissions.cs b/src/NadekoBot/Modules/Permissions/Permissions.cs index ce04f75c..2d21630d 100644 --- a/src/NadekoBot/Modules/Permissions/Permissions.cs +++ b/src/NadekoBot/Modules/Permissions/Permissions.cs @@ -87,7 +87,7 @@ namespace NadekoBot.Modules.Permissions if (i % 3 == 0) log.Info("Migrating Permissions #" + i + " - GuildId: " + oc.Key); i++; - var gc = uow.GuildConfigs.For(oc.Key, set => set.Include(x => x.Permissions)); + var gc = uow.GuildConfigs.GcWithPermissionsv2For(oc.Key); var oldPerms = oc.Value.RootPermission.AsEnumerable().Reverse().ToList(); uow._context.Set().RemoveRange(oldPerms); @@ -126,7 +126,7 @@ namespace NadekoBot.Modules.Permissions { using (var uow = DbHandler.UnitOfWork()) { - var config = uow.GuildConfigs.For(guildId, set => set.Include(x => x.Permissions)); + var config = uow.GuildConfigs.GcWithPermissionsv2For(guildId); //var orderedPerms = new PermissionsCollection(config.Permissions); var max = config.Permissions.Max(x => x.Index); //have to set its index to be the highest foreach (var perm in perms) @@ -161,7 +161,7 @@ namespace NadekoBot.Modules.Permissions { using (var uow = DbHandler.UnitOfWork()) { - var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.Permissions)); + var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id); config.VerbosePermissions = action.Value; await uow.CompleteAsync().ConfigureAwait(false); UpdateCache(config); @@ -185,7 +185,7 @@ namespace NadekoBot.Modules.Permissions using (var uow = DbHandler.UnitOfWork()) { - var config = uow.GuildConfigs.For(Context.Guild.Id, set => set); + var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id); if (role == null) { await ReplyConfirmLocalized("permrole", Format.Bold(config.PermissionRole)).ConfigureAwait(false); @@ -247,7 +247,7 @@ namespace NadekoBot.Modules.Permissions Permissionv2 p; using (var uow = DbHandler.UnitOfWork()) { - var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.Permissions)); + var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id); var permsCol = new PermissionsCollection(config.Permissions); p = permsCol[index]; permsCol.RemoveAt(index); @@ -278,7 +278,7 @@ namespace NadekoBot.Modules.Permissions Permissionv2 fromPerm; using (var uow = DbHandler.UnitOfWork()) { - var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.Permissions)); + var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id); var permsCol = new PermissionsCollection(config.Permissions); var fromFound = from < permsCol.Count; diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index ae005e95..297b606b 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -423,7 +423,7 @@ namespace NadekoBot.Services { using (var uow = DbHandler.UnitOfWork()) { - var config = uow.GuildConfigs.For(context.Guild.Id, set => set.Include(x => x.Permissions)); + var config = uow.GuildConfigs.GcWithPermissionsv2For(context.Guild.Id); Permissions.UpdateCache(config); } Permissions.Cache.TryGetValue(context.Guild.Id, out pc); diff --git a/src/NadekoBot/Services/Database/Repositories/IGuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/IGuildConfigRepository.cs index c71b2824..cca54609 100644 --- a/src/NadekoBot/Services/Database/Repositories/IGuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/IGuildConfigRepository.cs @@ -15,5 +15,6 @@ namespace NadekoBot.Services.Database.Repositories IEnumerable GetAllFollowedStreams(); void SetCleverbotEnabled(ulong id, bool cleverbotEnabled); IEnumerable Permissionsv2ForAll(); + GuildConfig GcWithPermissionsv2For(ulong guildId); } } diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index 909a15d5..150d671d 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -67,19 +67,25 @@ namespace NadekoBot.Services.Database.Repositories.Impl })); _context.SaveChanges(); } - else if (config.Permissions == null) - { - config.Permissions = Permissionv2.GetDefaultPermlist; - _context.SaveChanges(); - } return config; } public GuildConfig LogSettingsFor(ulong guildId) { - return _set.Include(gc => gc.LogSetting) + var config = _set.Include(gc => gc.LogSetting) .ThenInclude(gc => gc.IgnoredChannels) .FirstOrDefault(); + + if (config == null) + { + _set.Add((config = new GuildConfig + { + GuildId = guildId, + Permissions = Permissionv2.GetDefaultPermlist + })); + _context.SaveChanges(); + } + return config; } public IEnumerable OldPermissionsForAll() @@ -108,6 +114,31 @@ namespace NadekoBot.Services.Database.Repositories.Impl return query.ToList(); } + public GuildConfig GcWithPermissionsv2For(ulong guildId) + { + var config = _set + .Where(gc => gc.GuildId == guildId) + .Include(gc => gc.Permissions) + .FirstOrDefault(); + + if (config == null) // if there is no guildconfig, create new one + { + _set.Add((config = new GuildConfig + { + GuildId = guildId, + Permissions = Permissionv2.GetDefaultPermlist + })); + _context.SaveChanges(); + } + else if (config.Permissions == null || !config.Permissions.Any()) // if no perms, add default ones + { + config.Permissions = Permissionv2.GetDefaultPermlist; + _context.SaveChanges(); + } + + return config; + } + public IEnumerable GetAllFollowedStreams() => _set.Include(gc => gc.FollowedStreams) .SelectMany(gc => gc.FollowedStreams) From 2331b2ea20923b94e3a42158553cc1c249ec6a9e Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 18 Mar 2017 09:33:13 +0100 Subject: [PATCH 568/746] .v+t missing perms string was missing --- .../Modules/Administration/Commands/VoicePlusTextCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs index 7302b09d..b7a7b326 100644 --- a/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommands.cs @@ -166,7 +166,7 @@ namespace NadekoBot.Modules.Administration var botUser = await guild.GetCurrentUserAsync().ConfigureAwait(false); if (!botUser.GuildPermissions.ManageRoles || !botUser.GuildPermissions.ManageChannels) { - await ReplyErrorLocalized("vt_no_perms").ConfigureAwait(false); + await ReplyErrorLocalized("vt_perms").ConfigureAwait(false); return; } From 0d1e870325ddc14281280d19a2dec6cae5c0a7d8 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 18 Mar 2017 13:23:39 +0100 Subject: [PATCH 569/746] .vcrole will try twice to remove role from leaving users --- .../Administration/Commands/VcRoleCommands.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/VcRoleCommands.cs b/src/NadekoBot/Modules/Administration/Commands/VcRoleCommands.cs index a6211d3d..672d85f9 100644 --- a/src/NadekoBot/Modules/Administration/Commands/VcRoleCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/VcRoleCommands.cs @@ -71,8 +71,17 @@ namespace NadekoBot.Modules.Administration { if (gusr.RoleIds.Contains(role.Id)) { - await gusr.RemoveRolesAsync(role).ConfigureAwait(false); - await Task.Delay(500).ConfigureAwait(false); + try + { + await gusr.RemoveRolesAsync(role).ConfigureAwait(false); + await Task.Delay(500).ConfigureAwait(false); + } + catch + { + await Task.Delay(200).ConfigureAwait(false); + await gusr.RemoveRolesAsync(role).ConfigureAwait(false); + await Task.Delay(500).ConfigureAwait(false); + } } } //add new From 7e6411e25b6b803bdb9afcdfca730de99951c37c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 18 Mar 2017 20:23:26 +0100 Subject: [PATCH 570/746] .crad and .crdm added :O --- .../20170318190018_crad-and-crdm.Designer.cs | 1264 +++++++++++++++++ .../20170318190018_crad-and-crdm.cs | 35 + .../NadekoSqliteContextModelSnapshot.cs | 4 + .../CustomReactions/CustomReactions.cs | 112 +- .../Resources/CommandStrings.Designer.cs | 56 +- src/NadekoBot/Resources/CommandStrings.resx | 20 +- .../Resources/ResponseStrings.Designer.cs | 36 + src/NadekoBot/Resources/ResponseStrings.resx | 12 + src/NadekoBot/Services/CommandHandler.cs | 5 + .../Database/Models/CustomReaction.cs | 3 + 10 files changed, 1539 insertions(+), 8 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170318190018_crad-and-crdm.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170318190018_crad-and-crdm.cs diff --git a/src/NadekoBot/Migrations/20170318190018_crad-and-crdm.Designer.cs b/src/NadekoBot/Migrations/20170318190018_crad-and-crdm.Designer.cs new file mode 100644 index 00000000..1bfcd350 --- /dev/null +++ b/src/NadekoBot/Migrations/20170318190018_crad-and-crdm.Designer.cs @@ -0,0 +1,1264 @@ +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("20170318190018_crad-and-crdm")] + partial class cradandcrdm + { + 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("DateAdded"); + + 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.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("AutoDeleteTrigger"); + + b.Property("DateAdded"); + + b.Property("DmResponse"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissionv2"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UnmuteAt"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.Property("VoiceChannelId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Permissionv2", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("Permissions") + .HasForeignKey("GuildConfigId"); + }); + + 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.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId"); + }); + + 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/20170318190018_crad-and-crdm.cs b/src/NadekoBot/Migrations/20170318190018_crad-and-crdm.cs new file mode 100644 index 00000000..898a19ca --- /dev/null +++ b/src/NadekoBot/Migrations/20170318190018_crad-and-crdm.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class cradandcrdm : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "AutoDeleteTrigger", + table: "CustomReactions", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "DmResponse", + table: "CustomReactions", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "AutoDeleteTrigger", + table: "CustomReactions"); + + migrationBuilder.DropColumn( + name: "DmResponse", + table: "CustomReactions"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 9fd15cad..11f9bad5 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -310,8 +310,12 @@ namespace NadekoBot.Migrations b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("AutoDeleteTrigger"); + b.Property("DateAdded"); + b.Property("DmResponse"); + b.Property("GuildId"); b.Property("IsRegex"); diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index e67cb64b..024e79b5 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -11,26 +11,24 @@ using NLog; using System.Diagnostics; using Discord.WebSocket; using System; -using Newtonsoft.Json; using NadekoBot.DataStructures; -using NLog.Fluent; namespace NadekoBot.Modules.CustomReactions { public static class CustomReactionExtensions { - public static Task Send(this CustomReaction cr, IUserMessage context) + public static async Task Send(this CustomReaction cr, IUserMessage context) { - var channel = context.Channel; + var channel = cr.DmResponse ? await context.Author.CreateDMChannelAsync() : context.Channel; CustomReactions.ReactionStats.AddOrUpdate(cr.Trigger, 1, (k, old) => ++old); CREmbed crembed; if (CREmbed.TryParse(cr.Response, out crembed)) { - return channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? ""); + return await channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? ""); } - return channel.SendMessageAsync(cr.ResponseWithContext(context)); + return await channel.SendMessageAsync(cr.ResponseWithContext(context)); } } @@ -341,6 +339,108 @@ namespace NadekoBot.Modules.CustomReactions } } + [NadekoCommand, Usage, Description, Aliases] + public async Task CrDm(int id) + { + if ((Context.Guild == null && !NadekoBot.Credentials.IsOwner(Context.User)) || + (Context.Guild != null && !((IGuildUser)Context.User).GuildPermissions.Administrator)) + { + await ReplyErrorLocalized("insuff_perms").ConfigureAwait(false); + return; + } + + CustomReaction[] reactions = new CustomReaction[0]; + + if (Context.Guild == null) + reactions = GlobalReactions; + else + { + GuildReactions.TryGetValue(Context.Guild.Id, out reactions); + } + if (reactions.Any()) + { + var reaction = reactions.FirstOrDefault(x => x.Id == id); + + if (reaction == null) + { + await ReplyErrorLocalized("no_found_id").ConfigureAwait(false); + return; + } + + var setValue = reaction.DmResponse = !reaction.DmResponse; + + using (var uow = DbHandler.UnitOfWork()) + { + uow.CustomReactions.Get(id).DmResponse = setValue; + uow.Complete(); + } + + if (setValue) + { + await ReplyConfirmLocalized("crdm_enabled", Format.Code(reaction.Id.ToString())).ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("crdm_disabled", Format.Code(reaction.Id.ToString())).ConfigureAwait(false); + } + } + else + { + await ReplyErrorLocalized("no_found").ConfigureAwait(false); + } + } + + [NadekoCommand, Usage, Description, Aliases] + public async Task CrAd(int id) + { + if ((Context.Guild == null && !NadekoBot.Credentials.IsOwner(Context.User)) || + (Context.Guild != null && !((IGuildUser)Context.User).GuildPermissions.Administrator)) + { + await ReplyErrorLocalized("insuff_perms").ConfigureAwait(false); + return; + } + + CustomReaction[] reactions = new CustomReaction[0]; + + if (Context.Guild == null) + reactions = GlobalReactions; + else + { + GuildReactions.TryGetValue(Context.Guild.Id, out reactions); + } + if (reactions.Any()) + { + var reaction = reactions.FirstOrDefault(x => x.Id == id); + + if (reaction == null) + { + await ReplyErrorLocalized("no_found_id").ConfigureAwait(false); + return; + } + + var setValue = reaction.AutoDeleteTrigger = !reaction.AutoDeleteTrigger; + + using (var uow = DbHandler.UnitOfWork()) + { + uow.CustomReactions.Get(id).AutoDeleteTrigger = setValue; + uow.Complete(); + } + + if (setValue) + { + await ReplyConfirmLocalized("crad_enabled", Format.Code(reaction.Id.ToString())).ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("crad_disabled", Format.Code(reaction.Id.ToString())).ConfigureAwait(false); + } + } + else + { + await ReplyErrorLocalized("no_found").ConfigureAwait(false); + } + } + [NadekoCommand, Usage, Description, Aliases] [OwnerOnly] public async Task CrStatsClear(string trigger = null) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 2a679ee2..385c67e6 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -1976,6 +1976,60 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to crad. + /// + public static string crad_cmd { + get { + return ResourceManager.GetString("crad_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Toggles whether the message triggering the custom reaction will be automatically deleted.. + /// + public static string crad_desc { + get { + return ResourceManager.GetString("crad_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}crad 59`. + /// + public static string crad_usage { + get { + return ResourceManager.GetString("crad_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to crdm. + /// + public static string crdm_cmd { + get { + return ResourceManager.GetString("crdm_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Toggles whether the response message of the custom reaction will be sent as a direct message.. + /// + public static string crdm_desc { + get { + return ResourceManager.GetString("crdm_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}crad 44`. + /// + public static string crdm_usage { + get { + return ResourceManager.GetString("crdm_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to createinvite crinv. /// @@ -2373,7 +2427,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}delq abc`. + /// Looks up a localized string similar to `{0}delq 123456`. /// public static string deletequote_usage { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 638735a0..5f16e07b 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3186,4 +3186,22 @@ `{0}vcrole SomeRole` or `{0}vcrole` - + + crad + + + Toggles whether the message triggering the custom reaction will be automatically deleted. + + + `{0}crad 59` + + + crdm + + + Toggles whether the response message of the custom reaction will be sent as a direct message. + + + `{0}crad 44` + + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 8d70613f..53939695 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2017,6 +2017,42 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Message triggering the custom reaction with id {0} won't get automatically deleted.. + /// + public static string customreactions_crad_disabled { + get { + return ResourceManager.GetString("customreactions_crad_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Message triggering the custom reaction with id {0} will get automatically deleted.. + /// + public static string customreactions_crad_enabled { + get { + return ResourceManager.GetString("customreactions_crad_enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Response message for the custom reaction with id {0} won't be sent as a DM.. + /// + public static string customreactions_crdm_disabled { + get { + return ResourceManager.GetString("customreactions_crdm_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Response message for the custom reaction with id {0} will be sent as a DM.. + /// + public static string customreactions_crdm_enabled { + get { + return ResourceManager.GetString("customreactions_crdm_enabled", resourceCulture); + } + } + /// /// Looks up a localized string similar to Custom Reaction deleted. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index c0728a53..fda3abc3 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2248,4 +2248,16 @@ Owner ID: {2} Voice channel roles + + Message triggering the custom reaction with id {0} won't get automatically deleted. + + + Message triggering the custom reaction with id {0} will get automatically deleted. + + + Response message for the custom reaction with id {0} won't be sent as a DM. + + + Response message for the custom reaction with id {0} will be sent as a DM. + \ No newline at end of file diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 297b606b..5841d879 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -303,6 +303,11 @@ namespace NadekoBot.Services } } await cr.Send(usrMsg).ConfigureAwait(false); + + if (cr.AutoDeleteTrigger) + { + try { await msg.DeleteAsync().ConfigureAwait(false); } catch { } + } } catch (Exception ex) { diff --git a/src/NadekoBot/Services/Database/Models/CustomReaction.cs b/src/NadekoBot/Services/Database/Models/CustomReaction.cs index 695c1cd3..25bb34fb 100644 --- a/src/NadekoBot/Services/Database/Models/CustomReaction.cs +++ b/src/NadekoBot/Services/Database/Models/CustomReaction.cs @@ -10,8 +10,11 @@ namespace NadekoBot.Services.Database.Models public Regex Regex { get; set; } public string Response { get; set; } public string Trigger { get; set; } + public bool IsRegex { get; set; } public bool OwnerOnly { get; set; } + public bool AutoDeleteTrigger { get; set; } + public bool DmResponse { get; set; } public bool IsGlobal => !GuildId.HasValue; } From 0bc839ebe361f04e3d0be4fb6236d18083f4fe24 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 19 Mar 2017 15:48:12 +0100 Subject: [PATCH 571/746] embed and image support for .savechat --- .../Administration/Commands/MuteCommands.cs | 2 +- src/NadekoBot/Modules/Utility/Utility.cs | 26 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs index 0c49ef9e..0a130383 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs @@ -113,7 +113,7 @@ namespace NadekoBot.Modules.Administration public static async Task UnmuteUser(IGuildUser usr) { StopUnmuteTimer(usr.GuildId, usr.Id); - await usr.ModifyAsync(x => x.Mute = false).ConfigureAwait(false); + try { await usr.ModifyAsync(x => x.Mute = false).ConfigureAwait(false); } catch { } try { await usr.RemoveRolesAsync(await GetMuteRole(usr.Guild)).ConfigureAwait(false); } catch { /*ignore*/ } using (var uow = DbHandler.UnitOfWork()) { diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 2b809781..ee92b771 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -466,7 +466,31 @@ namespace NadekoBot.Modules.Utility var title = $"Chatlog-{Context.Guild.Name}/#{Context.Channel.Name}-{DateTime.Now}.txt"; var grouping = msgs.GroupBy(x => $"{x.CreatedAt.Date:dd.MM.yyyy}") - .Select(g => new { date = g.Key, messages = g.OrderBy(x => x.CreatedAt).Select(s => $"【{s.Timestamp:HH:mm:ss}】{s.Author}:" + s.ToString()) }); + .Select(g => new + { + date = g.Key, + messages = g.OrderBy(x => x.CreatedAt).Select(s => + { + var msg = $"【{s.Timestamp:HH:mm:ss}】{s.Author}:"; + if (string.IsNullOrWhiteSpace(s.ToString())) + { + if (s.Attachments.Any()) + { + msg += "FILES_UPLOADED: " + string.Join("\n", s.Attachments.Select(x => x.Url)); + } + else if (s.Embeds.Any()) + { + //todo probably just go through all properties and check if they are set, if they are, add them + msg += "EMBEDS: " + string.Join("\n--------\n", s.Embeds.Select(x => $"Description: {x.Description}")); + } + } + else + { + msg += s.ToString(); + } + return msg; + }) + }); await Context.User.SendFileAsync( await JsonConvert.SerializeObject(grouping, Formatting.Indented).ToStream().ConfigureAwait(false), title, title).ConfigureAwait(false); } From f680c476a67b9da303e7ec160dbda7dc9643156f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 20 Mar 2017 10:53:04 +0100 Subject: [PATCH 572/746] Command aliasing added - `.alias` and `.aliases` commands --- ...0170320090138_command-aliasing.Designer.cs | 1291 +++++++++++++++++ .../20170320090138_command-aliasing.cs | 45 + .../NadekoSqliteContextModelSnapshot.cs | 27 + .../Utility/Commands/CommandMapCommands.cs | 149 ++ .../Resources/CommandStrings.Designer.cs | 54 + src/NadekoBot/Resources/CommandStrings.resx | 18 + .../Resources/ResponseStrings.Designer.cs | 45 + src/NadekoBot/Resources/ResponseStrings.resx | 15 + src/NadekoBot/Services/CommandHandler.cs | 20 + .../Services/Database/Models/GuildConfig.cs | 24 + .../Impl/GuildConfigRepository.cs | 1 + 11 files changed, 1689 insertions(+) create mode 100644 src/NadekoBot/Migrations/20170320090138_command-aliasing.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170320090138_command-aliasing.cs create mode 100644 src/NadekoBot/Modules/Utility/Commands/CommandMapCommands.cs diff --git a/src/NadekoBot/Migrations/20170320090138_command-aliasing.Designer.cs b/src/NadekoBot/Migrations/20170320090138_command-aliasing.Designer.cs new file mode 100644 index 00000000..0017cd76 --- /dev/null +++ b/src/NadekoBot/Migrations/20170320090138_command-aliasing.Designer.cs @@ -0,0 +1,1291 @@ +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("20170320090138_command-aliasing")] + partial class commandaliasing + { + 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("DateAdded"); + + 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.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Mapping"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("AutoDeleteTrigger"); + + b.Property("DateAdded"); + + b.Property("DmResponse"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissionv2"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UnmuteAt"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.Property("VoiceChannelId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.CommandAlias", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId"); + }); + + 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.Permissionv2", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("Permissions") + .HasForeignKey("GuildConfigId"); + }); + + 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.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId"); + }); + + 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/20170320090138_command-aliasing.cs b/src/NadekoBot/Migrations/20170320090138_command-aliasing.cs new file mode 100644 index 00000000..d3ee3411 --- /dev/null +++ b/src/NadekoBot/Migrations/20170320090138_command-aliasing.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class commandaliasing : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "CommandAlias", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DateAdded = table.Column(nullable: true), + GuildConfigId = table.Column(nullable: true), + Mapping = table.Column(nullable: true), + Trigger = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_CommandAlias", x => x.Id); + table.ForeignKey( + name: "FK_CommandAlias_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_CommandAlias_GuildConfigId", + table: "CommandAlias", + column: "GuildConfigId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CommandAlias"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 11f9bad5..18195d44 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -207,6 +207,26 @@ namespace NadekoBot.Migrations b.ToTable("ClashOfClans"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Mapping"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => { b.Property("Id") @@ -1078,6 +1098,13 @@ namespace NadekoBot.Migrations .OnDelete(DeleteBehavior.Cascade); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => { b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") diff --git a/src/NadekoBot/Modules/Utility/Commands/CommandMapCommands.cs b/src/NadekoBot/Modules/Utility/Commands/CommandMapCommands.cs new file mode 100644 index 00000000..51fa03d1 --- /dev/null +++ b/src/NadekoBot/Modules/Utility/Commands/CommandMapCommands.cs @@ -0,0 +1,149 @@ +using Discord; +using Discord.Commands; +using Microsoft.EntityFrameworkCore; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Services; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System; + +namespace NadekoBot.Modules.Utility +{ + public partial class Utility + { + + public class CommandAliasEqualityComparer : IEqualityComparer + { + public bool Equals(CommandAlias x, CommandAlias y) => x.Trigger == y.Trigger; + + public int GetHashCode(CommandAlias obj) => obj.Trigger.GetHashCode(); + } + + [Group] + public class CommandMapCommands : NadekoSubmodule + { + //guildId, (trigger, mapping) + public static ConcurrentDictionary> AliasMaps { get; } = new ConcurrentDictionary>(); + + static CommandMapCommands() + { + var eq = new CommandAliasEqualityComparer(); + AliasMaps = new ConcurrentDictionary>( + NadekoBot.AllGuildConfigs.ToDictionary( + x => x.GuildId, + x => new ConcurrentDictionary(x.CommandAliases + .Distinct(eq) + .ToDictionary(ca => ca.Trigger, ca => ca.Mapping)))); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireUserPermission(GuildPermission.Administrator)] + [RequireContext(ContextType.Guild)] + public async Task Alias(string trigger, [Remainder] string mapping = null) + { + var channel = (ITextChannel)Context.Channel; + + if (string.IsNullOrWhiteSpace(trigger)) + return; + + trigger = trigger.Trim().ToLowerInvariant(); + + if (string.IsNullOrWhiteSpace(mapping)) + { + ConcurrentDictionary maps; + string throwaway; + if (!AliasMaps.TryGetValue(Context.Guild.Id, out maps) || + !maps.TryRemove(trigger, out throwaway)) + { + await ReplyErrorLocalized("alias_remove_fail", Format.Code(trigger)).ConfigureAwait(false); + return; + } + + using (var uow = DbHandler.UnitOfWork()) + { + var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.CommandAliases)); + var toAdd = new CommandAlias() + { + Mapping = mapping, + Trigger = trigger + }; + config.CommandAliases.RemoveWhere(x => x.Trigger == trigger); + uow.Complete(); + } + + await ReplyConfirmLocalized("alias_removed", Format.Code(trigger)).ConfigureAwait(false); + return; + } + AliasMaps.AddOrUpdate(Context.Guild.Id, (_) => + { + using (var uow = DbHandler.UnitOfWork()) + { + var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.CommandAliases)); + config.CommandAliases.Add(new CommandAlias() + { + Mapping = mapping, + Trigger = trigger + }); + uow.Complete(); + } + return new ConcurrentDictionary(new Dictionary() { + {trigger.Trim().ToLowerInvariant(), mapping.ToLowerInvariant() }, + }); + }, (_, map) => + { + using (var uow = DbHandler.UnitOfWork()) + { + var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.CommandAliases)); + var toAdd = new CommandAlias() + { + Mapping = mapping, + Trigger = trigger + }; + config.CommandAliases.RemoveWhere(x => x.Trigger == trigger); + config.CommandAliases.Add(toAdd); + uow.Complete(); + } + map.AddOrUpdate(trigger, mapping, (key, old) => mapping); + return map; + }); + + await ReplyConfirmLocalized("alias_added", Format.Code(trigger), Format.Code(mapping)).ConfigureAwait(false); + } + + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task AliasList(int page = 1) + { + var channel = (ITextChannel)Context.Channel; + page -= 1; + + if (page < 0) + return; + + ConcurrentDictionary maps; + if (!AliasMaps.TryGetValue(Context.Guild.Id, out maps) || !maps.Any()) + { + await ReplyErrorLocalized("aliases_none").ConfigureAwait(false); + return; + } + + var arr = maps.ToArray(); + + await Context.Channel.SendPaginatedConfirmAsync(page + 1, (curPage) => + { + return new EmbedBuilder().WithOkColor() + .WithTitle(GetText("alias_list")) + .WithDescription(string.Join("\n", + arr.Skip((curPage - 1) * 10).Take(10).Select(x => $"`{x.Key}` => `{x.Value}`"))); + + }, arr.Length / 10).ConfigureAwait(false); + } + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 385c67e6..045f5885 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -248,6 +248,60 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to alias cmdmap. + /// + public static string alias_cmd { + get { + return ResourceManager.GetString("alias_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Create a custom alias for a certain Nadeko command. Provide no alias to remove the existing one.. + /// + public static string alias_desc { + get { + return ResourceManager.GetString("alias_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}alias allin $bf 100 h` or `{0}alias "linux thingy" >loonix Spyware Windows`. + /// + public static string alias_usage { + get { + return ResourceManager.GetString("alias_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to aliaslist cmdmaplist aliases. + /// + public static string aliaslist_cmd { + get { + return ResourceManager.GetString("aliaslist_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows the list of currently set aliases. Paginated.. + /// + public static string aliaslist_desc { + get { + return ResourceManager.GetString("aliaslist_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}aliaslist` or `{0}aliaslist 3`. + /// + public static string aliaslist_usage { + get { + return ResourceManager.GetString("aliaslist_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to allchnlmdls acm. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 5f16e07b..14a6e44a 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3204,4 +3204,22 @@ `{0}crad 44` + + aliaslist cmdmaplist aliases + + + Shows the list of currently set aliases. Paginated. + + + `{0}aliaslist` or `{0}aliaslist 3` + + + alias cmdmap + + + Create a custom alias for a certain Nadeko command. Provide no alias to remove the existing one. + + + `{0}alias allin $bf 100 h` or `{0}alias "linux thingy" >loonix Spyware Windows` + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 53939695..48c4a4f8 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -5656,6 +5656,51 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Typing {0} will now be an alias of {1}.. + /// + public static string utility_alias_added { + get { + return ResourceManager.GetString("utility_alias_added", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List of aliases. + /// + public static string utility_alias_list { + get { + return ResourceManager.GetString("utility_alias_list", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trigger {0} didn't have an alias.. + /// + public static string utility_alias_remove_fail { + get { + return ResourceManager.GetString("utility_alias_remove_fail", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trigger {0} no longer has an alias.. + /// + public static string utility_alias_removed { + get { + return ResourceManager.GetString("utility_alias_removed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No alias found. + /// + public static string utility_aliases_none { + get { + return ResourceManager.GetString("utility_aliases_none", resourceCulture); + } + } + /// /// Looks up a localized string similar to Author. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index fda3abc3..d954325d 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2260,4 +2260,19 @@ Owner ID: {2} Response message for the custom reaction with id {0} will be sent as a DM. + + No alias found + + + Typing {0} will now be an alias of {1}. + + + List of aliases + + + Trigger {0} no longer has an alias. + + + Trigger {0} didn't have an alias. + \ No newline at end of file diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 5841d879..17521cab 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -320,6 +320,26 @@ namespace NadekoBot.Services var exec3 = Environment.TickCount - execTime; string messageContent = usrMsg.Content; + if (guild != null) + { + ConcurrentDictionary maps; + if (Modules.Utility.Utility.CommandMapCommands.AliasMaps.TryGetValue(guild.Id, out maps)) + { + string newMessageContent; + if (maps.TryGetValue(messageContent.Trim().ToLowerInvariant(), out newMessageContent)) + { + _log.Info(@"--Mapping Command-- + GuildId: {0} + Trigger: {1} + Mapping: {2}", guild.Id, messageContent, newMessageContent); + var oldMessageContent = messageContent; + messageContent = newMessageContent; + + try { await usrMsg.Channel.SendConfirmAsync($"{oldMessageContent} => {newMessageContent}").ConfigureAwait(false); } catch { } + } + } + } + // execute the command and measure the time it took var exec = await Task.Run(() => ExecuteCommand(new CommandContext(_client, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best)).ConfigureAwait(false); diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs index a1c12ba1..00693f16 100644 --- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs +++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs @@ -71,10 +71,34 @@ namespace NadekoBot.Services.Database.Models public HashSet UnmuteTimers { get; set; } = new HashSet(); public HashSet VcRoleInfos { get; set; } + public HashSet CommandAliases { get; set; } = new HashSet(); //public List ProtectionIgnoredChannels { get; set; } = new List(); } + public class CommandAlias : DbEntity + { + public string Trigger { get; set; } + public string Mapping { get; set; } + + //// override object.Equals + //public override bool Equals(object obj) + //{ + // if (obj == null || GetType() != obj.GetType()) + // { + // return false; + // } + + // return ((CommandAlias)obj).Trigger.Trim().ToLowerInvariant() == Trigger.Trim().ToLowerInvariant(); + //} + + //// override object.GetHashCode + //public override int GetHashCode() + //{ + // return Trigger.Trim().ToLowerInvariant().GetHashCode(); + //} + } + public class VcRoleInfo : DbEntity { public ulong VoiceChannelId { get; set; } diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index 150d671d..7098888d 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -16,6 +16,7 @@ namespace NadekoBot.Services.Database.Repositories.Impl _set.Include(gc => gc.LogSetting) .ThenInclude(ls => ls.IgnoredChannels) .Include(gc => gc.MutedUsers) + .Include(gc => gc.CommandAliases) .Include(gc => gc.UnmuteTimers) .Include(gc => gc.VcRoleInfos) .Include(gc => gc.GenerateCurrencyChannelIds) From a24b151b2a9f916953ce8d81ab941289b25806f9 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 20 Mar 2017 13:45:36 +0100 Subject: [PATCH 573/746] Now even compiles and runs! --- src/NadekoBot/Modules/Searches/Searches.cs | 3 ++- src/NadekoBot/project.json | 8 ++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 88d688c9..472a17d5 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -22,6 +22,7 @@ using Configuration = AngleSharp.Configuration; using NadekoBot.Attributes; using Discord.Commands; using ImageSharp.Processing.Processors; +using ImageSharp; namespace NadekoBot.Modules.Searches { @@ -605,7 +606,7 @@ namespace NadekoBot.Modules.Searches return; var img = new ImageSharp.Image(50, 50); - img.ApplyProcessor(new BackgroundColorProcessor(ImageSharp.Color.FromHex(color)), img.Bounds); + img.BackgroundColor(ImageSharp.Color.FromHex(color)); await Context.Channel.SendFileAsync(img.ToStream(), $"{color}.png").ConfigureAwait(false); } diff --git a/src/NadekoBot/project.json b/src/NadekoBot/project.json index cd69d074..fe93d0d3 100644 --- a/src/NadekoBot/project.json +++ b/src/NadekoBot/project.json @@ -23,12 +23,8 @@ "Google.Apis.Urlshortener.v1": "1.19.0.138", "Google.Apis.YouTube.v3": "1.20.0.701", "Google.Apis.Customsearch.v1": "1.20.0.466", - "ImageSharp": "1.0.0-alpha2-*", - "ImageSharp.Processing": "1.0.0-alpha2-*", - "ImageSharp.Formats.Png": "1.0.0-alpha2-*", - "ImageSharp.Formats.Jpeg": "1.0.0-alpha2-*", - "ImageSharp.Drawing": "1.0.0-alpha2-*", - "ImageSharp.Drawing.Paths": "1.0.0-alpha2-*", + "ImageSharp": "1.0.0-alpha4-00031", + "ImageSharp.Drawing": "1.0.0-alpha4-00031", "Microsoft.EntityFrameworkCore": "1.1.0", "Microsoft.EntityFrameworkCore.Design": "1.1.0", "Microsoft.EntityFrameworkCore.Sqlite": "1.1.0", From 4ba487534e94b2873c50ef231fbafc317f013065 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 20 Mar 2017 18:19:11 +0100 Subject: [PATCH 574/746] Added a missed string --- .../Modules/Searches/Commands/OverwatchCommands.cs | 2 +- src/NadekoBot/Resources/ResponseStrings.Designer.cs | 9 +++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 3 +++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs index 199c9b53..99ce317d 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OverwatchCommands.cs @@ -58,7 +58,7 @@ namespace NadekoBot.Modules.Searches .AddField(fb => fb.WithName(GetText("compet_loses")).WithValue($"{model.Games.Competitive.lost}").WithIsInline(true)) .AddField(fb => fb.WithName(GetText("compet_played")).WithValue($"{model.Games.Competitive.played}").WithIsInline(true)) .AddField(fb => fb.WithName(GetText("compet_rank")).WithValue(rank).WithIsInline(true)) - .AddField(fb => fb.WithName(GetText("compet_played")).WithValue($"{model.Playtime.competitive}").WithIsInline(true)) + .AddField(fb => fb.WithName(GetText("compet_playtime")).WithValue($"{model.Playtime.competitive}").WithIsInline(true)) .AddField(fb => fb.WithName(GetText("quick_playtime")).WithValue($"{model.Playtime.quick}").WithIsInline(true)) .WithColor(NadekoBot.OkColor); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 48c4a4f8..fec34b11 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -4900,6 +4900,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Competitive playtime. + /// + public static string searches_compet_playtime { + get { + return ResourceManager.GetString("searches_compet_playtime", resourceCulture); + } + } + /// /// Looks up a localized string similar to Competitive rank. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index d954325d..56ada3ed 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2275,4 +2275,7 @@ Owner ID: {2} Trigger {0} didn't have an alias. + + Competitive playtime + \ No newline at end of file From f9f0fc31b5549c24bef33bc45b7be6652151a6ff Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 21 Mar 2017 04:54:14 +0100 Subject: [PATCH 575/746] Update ResponseStrings.zh-CN.resx (POEditor.com) --- .../Resources/ResponseStrings.zh-CN.resx | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx b/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx index baf824c3..57e2e91c 100644 --- a/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx +++ b/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx @@ -2353,5 +2353,35 @@ Fuzzy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From abeaba2173515bd2332ed71f75a42211664b486c Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 21 Mar 2017 04:54:16 +0100 Subject: [PATCH 576/746] Update ResponseStrings.zh-TW.resx (POEditor.com) --- .../Resources/ResponseStrings.zh-TW.resx | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx index f299b7f2..d42f47bc 100644 --- a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx +++ b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx @@ -1382,7 +1382,7 @@ Paypal <{1}> 播放清單大小現在沒有限制了。 - 播放清單最多可以排序 {0} 首。 + 播放清單最多可以點播 {0} 首。 你必須要進入在此伺服器上的語音頻道。 @@ -1470,7 +1470,7 @@ Paypal <{1}> 啟用重複播放清單。 - 我將在此頻道輸出播放、暫停、結束和移除的歌曲。 + 我將在此頻道輸出播放、暫停、結束和移除歌曲的訊息。 跳至 ‘{0}:{1}’ @@ -2254,5 +2254,35 @@ Paypal <{1}> 語音頻道身分組 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 031bfb25fdb05f550184b957b471f96b5f0266a9 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 21 Mar 2017 04:54:19 +0100 Subject: [PATCH 577/746] Update ResponseStrings.nl-NL.resx (POEditor.com) --- .../Resources/ResponseStrings.nl-NL.resx | 351 ++++++++++-------- 1 file changed, 191 insertions(+), 160 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx index 9b49d118..15bc2419 100644 --- a/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx @@ -1296,10 +1296,10 @@ Fuzzy Er is al een spel galgje aan de gang in dit kanaal. - + Galgje kon niet opstarten vanwege een fout. - + lijst van {0}Galgje term types: Scoreboard @@ -1319,7 +1319,7 @@ Fuzzy Kwoth planted 5* - + Trivia spel is al bezig in deze server. Trivia spel @@ -1328,25 +1328,25 @@ Fuzzy {0} heeft 'm geraden! Het antwoord was: {1} - + Trivia is niet bezig in deze server. {0} heeft {1} punten - + Stopt na deze vraag. - + Tijd is op! Het goede antwoord was {0} - + {0} heeft het antwoord geraden en wint het spel! Het antwoord was: {1} Je kan niet tegen jezelf spelen. - + BoterKaasenEieren spel is al bezig in dit kannal. Gelijkspel! @@ -1358,10 +1358,10 @@ Fuzzy {0} heeft gewonnen! - + Drie op een rij - + Geen zetten over! Tijd voorbij! @@ -1370,7 +1370,7 @@ Fuzzy {0}'s beurt - + {0} tegen {1} Aan het proberen om {0} liedjes in de wachtrij te zetten... @@ -1385,25 +1385,25 @@ Fuzzy Standaard volume op {0}% gezet - + Map afspeellijst geladen/compleet. - + Eerlijk spel. Liedje afgelopen - + Eerlijk spel uitgeschakeld. - + Eerlijk spel ingeschakeld. van positie - + ID ongeldige invoer. @@ -1440,13 +1440,13 @@ Fuzzy Muziek gepauzeerd. - + Speler afspeellijst - Pagina {0}/{1} - + Liedje aan het spelen - + `#{0}` - **{1}** van *{2}* ({3} liedjes) Pagina {0} van opgeslagen afspeellijsten @@ -1456,13 +1456,13 @@ Fuzzy Afspeellijst verwijderd - + Fout bij het verwijderen van de afspeellijst. Of het bestaat niet of U bent niet de auteur. - + Afspeellijst met dat ID bestaat niet. - + Speler afspeellijst afgerond. Afspeellijst opgeslagen @@ -1474,7 +1474,8 @@ Fuzzy Wachtrij - + Gekozen nummer + Muziek wachtrij leeggemaakt. @@ -1493,25 +1494,25 @@ Fuzzy Huidige afspeellijst word herhaald - + Herhaal nummer - + Huidig nummer herhaling gestopt. - + Nummer word hervat. - + Herhaal afspeellijst uitgeschakeld. - + Herhaal afspeellijst ingeschakeld. - + Muziek dat wordt gespeeld, afloopt, gepauzeerd en wordt verwijder laat ik in dit kanaal zien. - + Overslaan naar `{0}:{1}` Liedjes geschud @@ -1535,34 +1536,34 @@ Fuzzy Volume op {0}% gezet - + Uitgeschakelde gebruik op alle moddelen in dit kanaal {0}. - + Ingeschakelde gebruik op alle moddelen in dit kanaal {0}. Toegestaan - + Uitgeschakelde gebruik op alle moddelen voor deze rol {0}. - + Ingeschakelde gebruik op alle moddelen voor deze rol{0}. - + Uitgeschakelde gebruik op alle moddelen in deze server. - + ingeschakelde gebruik op alle moddelen in deze server. - + Uitgeschakelde gebruik op alle moddelen voor deze gebruiker{0}. - + Ingeschakelde gebruik op alle moddelen voor deze gebruiker{0}. - + Blacklisted {0} met ID {1} Commando {0} heeft nu een {1}s afkoel tijd. @@ -1574,49 +1575,49 @@ Fuzzy Geen commando afkoeltijden ingesteld. - + Command kosten - + Uitgeschakelde gebruik van {0} {1} in kanaal {2}. - + Ingeschakelde gebruik van {0} {1} in kanaal {2}. Geweigerd - + Woord {0} tegevoegd aan de lijst met foute woorden. Lijst van gefilterde worden - + Woord {0} verwijderd van de lijst met foute woorden. - + Ongeldige tweede parameter.(Moet een number zijn tussen {0} en {1}) - + Uitnodiging filter uitgeschakeld in dit kanaal. - + Uitnodiging filter ingeschakeld in dit kanaal. - + Uitnodiging filter uitgeschakeld in deze server. - + Uitnodiging filter ingeschakeld in deze server. - + Verplaat toestemming {0} voor #{1} naar #{2} - + Kan geen toestemming vinden in inhoudsopgave #{0} - + Geen kosten ingesteld. Commando @@ -1630,77 +1631,77 @@ Fuzzy Rechten pagina {0} - + Actueel toestemming rol is {0}. - + Gebruiker heeft nu {0} rol om toestemmingen te veranderen. - + Geen toestemming gevonden in de inhoudsopgave. - + Verwijderd toestemming #{0} - {1} - + Uitgeschakelde gebruik van {0} {1} voor rol {2}. - + Ingeschakelde gebruik van {0} {1} voor rol {2}. - + Seconden Short of seconds. - + Uitgeschakelde gebruik van {0} {1} op deze server. - + Ingeschakelde gebruik van {0} {1} op deze server. - + Unblacklisted {0} met ID {1} - + Niet veranderbaar - + Uitgeschakelde gebruik van {0} {1} voor gebruiker {2}. - + Ingeschakelde gebruik van {0} {1} voor gebruiker {2}. - + Ik zal geen permissie waarschuwingen meer weergeven. - + Ik zal permissie waarschuwingen weergeven. - + Woord filter gedeactiveerd in dit kanaal. - + Woord filter geactiveerd in dit kanaal. - + Woord filter gedeactiveerd in deze server. - + Woord filter geactiveerd in deze server. - + Talenten - + Nog geen favoriete anime Gestart met het automatisch vertalen van berichten op dit kanaal. Gebruiker berichten worden automatisch verwijderd. - + Jouw automatisch translatie taal is verwijderd. - + Jouw automatisch translatie taal is aangepast naar {0}>{1} Gestart met het automatisch vertalen van berichten op dit kanaal. @@ -1709,10 +1710,10 @@ Fuzzy Gestopt met het automatisch vertalen van berichten op dit kanaal. - + Verkeerde invoer formaat, of ging er iets mis. - + Gekozen kaart is niet gevonden. feit @@ -1721,19 +1722,19 @@ Fuzzy hoofdstukken - + Stripboek # - + Competitief verloren - + Competitief gespeeld - + Competitief rang - + Competitief Gewonnen Voltooid @@ -1774,13 +1775,13 @@ Fuzzy Genres - + Definitie vinden voor de label is mislukt. Lengte/Gewicht - + {0}m/{1}kg Vochtigheid @@ -1792,35 +1793,35 @@ Fuzzy Mislukt in het vinden van die film. - + Invalide taal -bron of -doel. Grapjes niet geladen. - + Lengte- en breedtegraad - + Niveau - + Lijst van {0}plaats labels Don't translate {0}place Lokatie - + Magische Items niet geladen. {0}'s MAL profiel - + Je kunt deze functie niet gebruiken. Bot eigenaar heeft MashapeApiKey niet gedefinieërd. - + Minimaal/Maximaal Geen kanaal gevonden. @@ -1829,7 +1830,7 @@ Fuzzy Geen resultaten gevonden. - + On-hold Originele URL @@ -1838,64 +1839,64 @@ Fuzzy Een osu! API sleutel is vereist. - + Kon het osu! handtekening niet ontvangen. - + Meer dan {0} afbeeldingen gevonden. Willekeurig Resultaat {0}. - + Gebruiker niet gevonden! Check de Regio en de BattleTag voordat je het opnieuw probeert. - + Van plan om te bekijken. - + Platform - + Geen talent gevonden. - + Geen Pokémon gevonden. - + Profiel link: Kwaliteit: - + Snel kijktijd - + Snelle overwinningen. - + Beoordeling - + Score: - + Zoekopdracht voor: - + Fout bij het inkorten van de URL. - + Korte URL - + Er is iets mis gegaan. - + Specificeer zoek parameters alsjeblieft. - + Status - + Winkel URL Streamer {0} is offline. @@ -1910,16 +1911,16 @@ Fuzzy Je volgt geen streams op deze server. - + Stream niet gevonden. - + Stream bestaat mogelijk niet. - + Verwijderd {0}'s stream ({1}) van notificaties. - + Ik zal dit kanaal op de hoogte houden wanneer de status verandert. Zon's opgang @@ -1934,7 +1935,7 @@ Fuzzy Titel: - + Top 3 favoriete anime: Vertaling: @@ -1943,22 +1944,22 @@ Fuzzy Types - + Fout bij het opzoeken van definitie voor die term. - + Url Kijkers - + Kijken/Bekijken <-- ga even na welke correct is.!!! - + Mislukt met het vinden van de term op de gespecificeerde Wikia. - + Vul een Wikia doel in alsjeblieft, gevolgd door een zoek query. Pagina niet gevonden @@ -1970,13 +1971,13 @@ Fuzzy De {0} meest verbannen kampioenen. - + Het yodifying van jou zin is mislukt. - + Aangesloten - + `{0}.` {1} [{2:F2}/s] - {3} totaal /s and total need to be localized to fit the context - `1.` @@ -1993,10 +1994,10 @@ Fuzzy Bot ID - + Lijst van functies in {0}calc commando - + {0} van dit kanaal is {1} Kanaal onderwerp @@ -2020,10 +2021,10 @@ Fuzzy Gemaakt op - + Aangesloten cross server kanaal. - + Verbroken cross server kanaal. Dit is je CSC token @@ -2055,10 +2056,10 @@ Fuzzy Invalid months value/ Invalid hours value - + Bij Discord aangesloten - + Bij server aangesloten ID: {0} @@ -2093,7 +2094,7 @@ Eigenaar ID: {2} Niemand speelt dat spel. - + Geen actieve herhaling Geen rollen op deze pagina. @@ -2147,10 +2148,10 @@ Eigenaar ID: {2} Ik zal {0} herinneren om {1} in {2} `({3:d.M.yyyy.} op {4:HH:mm})` - + Incorrecte tijd formaat. Controleer de commandolijst. - + Nieuwe herinnering sjabloon. Herhalen van {0} elke {1} dagen, {2} uren en {3} minuten. @@ -2162,25 +2163,25 @@ Eigenaar ID: {2} Geen repeaters actief op deze server. - + #{0} gestopt. - + Geen herhalende berichten gevonden op deze server. - + Resultaat - + Rollen - + Pagina #{0} van alle rollen op deze server: - + Pagina #{0} van kleuren voor {1} - + Kleuren staan niet in de correcte format. Gebruik #00ff00` als voorbeeld. Begonnen met het routeren van kleuren voor de rol {0} @@ -2219,7 +2220,7 @@ Eigenaar ID: {2} Hier is de link naar je sessie: - + Uptime {0} van de gebruker {1} is {2} @@ -2235,65 +2236,95 @@ Eigenaar ID: {2} Je maakt al deel uit van deze race! - + Huidige poll resultaten - + Geen stemmen ingediend. - + Poll is al actief op deze server. - + 📃 {0} heeft een poll gecreëerd dat vraagt om uw aandacht: - + `{0}.` {1} met {2} stemmen. {0} gestemd. Kwoth voted. - + Stuur mij een privé bericht met het overeenkomende nummer van het antwoord. - + Stuur een bericht hier met de overeenkomende nummer van het antwoord. - + Bedankt voor het stemmen, {0} - + Totaal aantal stemmen: {0}. - + Raap hun op door te typen `{0}pick` - + Raap het op door te typen `{0}pick` - + Geen gebruiker gevonden. - + pagina {0} - + U moet zich in een spreekkanaal bevinden op deze server. - + Er zijn geen spreekkanaal rollen. - + {0} is **gedempt** van text en spreek chat voor {1} minuten. - + Gebruikers die aansluiten op {0} geluid kanaal krijgen {1} rol. - + Gebruiker dat aansloot {0} geluid kanaal krijgt niet langer meer een rol. - + Spreekkanaal rollen + + + Bericht triggering met aangepaste reactie id {0} wordt niet automatisch gedeletet. + + + Bericht triggering met aangepaste reactie id {0} wordt automatisch gedeletet. + + + Response-bericht van aangepaste reactie met id {0} wordt niet privé verstuurd. + + + Response-bericht van aangepaste reactie met id {0} wordt verstuurd als privé bericht. + + + Geen alias gevonden. + + + Trigger {0} heeft nu de alias {1}. + + + Lijst van aliassen + + + Trigger {0} heeft geen alias meer. + + + Trigger {0} had geen alias + + + Competitieve speeltijd \ No newline at end of file From 0cc9879136320dafd216197c2ff65e0d80714d3e Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 21 Mar 2017 04:54:22 +0100 Subject: [PATCH 578/746] Update ResponseStrings.en-US.resx (POEditor.com) --- .../Resources/ResponseStrings.en-US.resx | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/NadekoBot/Resources/ResponseStrings.en-US.resx b/src/NadekoBot/Resources/ResponseStrings.en-US.resx index 25c6550d..c384f48e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.en-US.resx +++ b/src/NadekoBot/Resources/ResponseStrings.en-US.resx @@ -2248,5 +2248,35 @@ Owner ID: {2} Voice channel roles + + Message triggering the custom reaction with id {0} won't get automatically deleted. + + + Message triggering the custom reaction with id {0} will get automatically deleted. + + + Response message for the custom reaction with id {0} won't be sent as a DM. + + + Response message for the custom reaction with id {0} will be sent as a DM. + + + No alias found + + + Typing {0} will now be an alias of {1}. + + + List of aliases + + + Trigger {0} no longer has an alias. + + + Trigger {0} didn't have an alias. + + + Competitive playtime + \ No newline at end of file From 81d0205e5128db996ee288b8088958f24fc6c2ab Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 21 Mar 2017 04:54:24 +0100 Subject: [PATCH 579/746] Update ResponseStrings.fr-FR.resx (POEditor.com) --- .../Resources/ResponseStrings.fr-FR.resx | 77 +++++++++++++------ 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx b/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx index a6a0fa29..ee351ef0 100644 --- a/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx @@ -339,7 +339,7 @@ Raison: {1} Les annonces de départ seront supprimées après {0} secondes. - Annonce de départ actuelle : {0} + Annonce de départ actuelle: {0} Activez les annonces de départ en entrant {0} @@ -469,7 +469,7 @@ Raison: {1} Vous avez été expulsé du serveur {0}. -Raison : {1} +Raison: {1} Utilisateur expulsé @@ -510,7 +510,7 @@ Raison : {1} Enregistrement désactivé. - Événements enregistrés que vous pouvez suivre : + Événements enregistrés que vous pouvez suivre: L'enregistrement ignorera désormais {0} @@ -525,7 +525,7 @@ Raison : {1} {0} a émis une notification pour les rôles suivants - Message de {0} `[Bot Owner]` : + Message de {0} `[Propriétaire du bot]`: Message envoyé. @@ -1082,7 +1082,7 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Usage - Autohentai commencé. Publie toutes les {0}s avec l'un des tags suivants : + Autohentai commencé. Publie toutes les {0}s avec l'un des tags suivants: {1} @@ -1127,7 +1127,7 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Someone rolled 35 - Dé tiré au sort: {0} + Dés lancés: {0} Dice Rolled: 5 @@ -1140,8 +1140,9 @@ N'oubliez pas de mettre votre nom discord ou ID dans le message. Le deuxième nombre doit être plus grand que le premier. - Changements de Coeur - Fuzzy + Changements d'avis + La plus proche traduction pour cette expression serait "Changement d'avis" +Fuzzy Revendiquée par @@ -1263,14 +1264,14 @@ La nouvelle valeur de {0} est {1} ! {0} a gagné ! {1} bat {2}. - Inscriptions terminées. + Soumissions fermées. Fuzzy Une course d'animaux est déjà en cours. - Total : {0} Moyenne : {1} + Total: {0} Moyenne: {1} Catégorie @@ -1314,7 +1315,7 @@ Fuzzy Initialisation du pendu erronée. - Liste des "{0}hangman" types de termes : + Liste des types de termes pour "{0}hangman": Classement @@ -1370,7 +1371,7 @@ Fuzzy a créé une partie de Morpion. - {0} a gagné ! + {0} a gagné! Fuzzy @@ -1381,7 +1382,7 @@ Fuzzy Aucun mouvement restant ! - Le temps a expiré ! + Le temps a expiré! Fuzzy @@ -1456,7 +1457,7 @@ Fuzzy Pas de résultat. - Lecteure mise en pause. + Lecture mise en pause. File d'attente - Page {0}/{1} @@ -1510,7 +1511,7 @@ Fuzzy context: "removed song #5" - Répétition de la piste en cours de lecture + Répétition de la piste actuelle Fuzzy @@ -1540,7 +1541,7 @@ Fuzzy Saut à `{0}:{1}` - Lecture aléatoire activée. + Pistes mélangées. Fuzzy @@ -1876,7 +1877,7 @@ Fuzzy Fuzzy - Url originale + Url d'origine Fuzzy @@ -1912,11 +1913,11 @@ Fuzzy Qualité - Durée en Jeux Rapides + Temps en parties rapides Fuzzy - Victoires Rapides + Parties rapides gagnées Fuzzy @@ -2107,7 +2108,7 @@ Fuzzy Fuzzy - Vous ne pouvez pas utiliser cette commande sur un rôle incluant beaucoup d'utilisateurs afin d'éviter les abus. + Vous ne pouvez pas utiliser cette commande sur les rôles associés à beaucoup d'utilisateurs afin d'éviter les abus. Fuzzy @@ -2124,7 +2125,7 @@ Fuzzy ID: {0} Membres: {1} -OwnerID: {2} +ID du propriétaire: {2} Fuzzy @@ -2210,7 +2211,7 @@ OwnerID: {2} Fuzzy - Je vais vous rappeler {0} pour {1} dans {2} `({3:d.M.yyyy} à {4:HH:mm})` + Je vais rappeler {0} de {1} dans {2} `({3:d.M.yyyy} à {4:HH:mm})` Format de date non valide. Vérifiez la liste des commandes. @@ -2241,7 +2242,7 @@ OwnerID: {2} Rôles - Page #{0} de tout les rôles sur ce serveur. + Page #{0} de tous les rôles de ce serveur: Page #{0} des rôles pour {1} @@ -2369,5 +2370,35 @@ Fuzzy Rôles du salon vocal + + Le message déclenchant la réaction personnalisée avec l'ID {0} ne sera pas automatiquement effacé. + + + Le message déclenchant la réaction personnalisée avec l'ID {0} sera automatiquement effacé. + + + Le message de réponse pour la réaction personnalisée avec l'ID {0} ne sera pas envoyé en MP. + + + Le message de réponse pour la réaction personnalisée avec l'ID {0} sera envoyé en MP. + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 351b85977597ce35b02eeed3695a19a94aade6eb Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 21 Mar 2017 04:54:27 +0100 Subject: [PATCH 580/746] Update ResponseStrings.de-DE.resx (POEditor.com) --- .../Resources/ResponseStrings.de-DE.resx | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx index 34346f0c..db44d4ac 100644 --- a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx @@ -2329,10 +2329,10 @@ ID des Besitzers: {2} Fuzzy - Sammel sie durch das Schreiben von `{0}pick` + sammel sie durch das Schreiben von `{0}pick` - Sammel sie durch das Schreiben von `{0}pick + sammel sie durch das Schreiben von `{0}pick Kein Benutzer gefunden. @@ -2358,5 +2358,35 @@ ID des Besitzers: {2} Rollen für Sprachkanäle + + Auslösende Nachricht der benutzerdefinierten Reaktion mit der ID {0} wird nicht automatisch gelöscht. + + + Auslösende Nachricht der benutzerdefinierten Reaktion mit der ID {0} wird automatisch gelöscht. + + + Reaktionsnachricht für die benutzerdefinierte Reaktion mit der ID {0} wird nicht als DN gesendet. + + + Reaktionsnachricht für die benutzerdefinierte Reaktion mit der ID {0} wird nicht als DN gesendet. + + + + + + + + + + + + + + + + + + + \ No newline at end of file From ebdaadee650f4d4c40d50978f88970e048e9c2f5 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 21 Mar 2017 04:54:30 +0100 Subject: [PATCH 581/746] Update ResponseStrings.ja-JP.resx (POEditor.com) --- .../Resources/ResponseStrings.ja-JP.resx | 88 ++++++++++++++----- 1 file changed, 67 insertions(+), 21 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx b/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx index b4c12bf6..6e52fbe0 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx @@ -925,7 +925,8 @@ Fuzzy - + 逆の聴覚障害を成功させる。 + ミュート解除 @@ -1284,10 +1285,10 @@ Paypal <{1}> {0} は {1} として参加しました。 - + {0}は{1}と{2}に参加しました! - + レースに参加するには{0} jrと入力してください。 部屋がいっぱいになるか、20秒後にスタートします。 @@ -1296,10 +1297,12 @@ Paypal <{1}> {0} 人の参加者でスタートします。 - + {0}を{1}としてレースを獲得しました! + - + {0}を{1}に、レースを{2}獲得しました! + 数が正しくありません。一度に {0}-{1} のダイスを触れます。 @@ -1323,53 +1326,66 @@ Paypal <{1}> 最初の数よりも2番めの数が大きくなければなりません。 - + 「心」の変化 - + が主張する + - + 離婚 + - + 好き - + 価格 - + waifusはまだ主張されていません。 - + トップワイフス + - + あなたの親和性はすでにそのwaifuに設定されているか、親和性を持たずに削除しようとしています。 + - + {0}から{1}にアフィニティを変更しました。 + +*これは道徳的に疑問です。*🤔 Make sure to get the formatting right, and leave the thinking emoji - + アフィニティを再度変更するには、{0}時間と{1}分を待つ必要があります。 + - + 親和性がリセットされます。あなたはもはや好きな人がいません。 + - + {0}のwaifuになりたいAww <3 - + {1}のウェイフとして{0}が主張されています! + - + あなたが好きな人と離婚しました。あなたは無情な怪物です。 +{0}は補償として{1}を受け取りました。 - + あなたは自分自身に親和性を設定することはできません。 + - + +🎉彼らの愛が成就した! 🎉 +{0}の新しい値は{1}です! @@ -2481,5 +2497,35 @@ Paypal <{1}> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From ff5eddd64d414629a1148ec9bdce962ad6c16534 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 21 Mar 2017 04:54:32 +0100 Subject: [PATCH 582/746] Update ResponseStrings.nb-NO.resx (POEditor.com) --- .../Resources/ResponseStrings.nb-NO.resx | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx b/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx index e634ce06..f566494b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx +++ b/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx @@ -2304,5 +2304,35 @@ Eier ID: {2} Stemmekanal-roller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 384f58669fd3132c5b1499eb530b550b81f914df Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 21 Mar 2017 04:54:35 +0100 Subject: [PATCH 583/746] Update ResponseStrings.pl-PL.resx (POEditor.com) --- .../Resources/ResponseStrings.pl-PL.resx | 84 +++++++++++++------ 1 file changed, 57 insertions(+), 27 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx index 62b2df49..6517d703 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx @@ -432,10 +432,10 @@ Powód: {1} Nowa prywatna wiadomość powitalna została ustawiona. - + Prywatne ogłoszenie powitalne zostało włączone - + Prywatne ogłoszenie powitalne zostało wyłączone Aktualna wiadomość powitalna: {0} @@ -504,10 +504,10 @@ Powód: {1} - + Logowanie wszystkich wydarzeń na tym kanale. - + Logowanie wyłączone. @@ -516,7 +516,7 @@ Powód: {1} - + Logowanie nie będzie ignorowało {0} @@ -551,7 +551,7 @@ Powód: {1} Nie mam wystarczających uprawnień aby to zrobić. - + Nowa wyciszająca rola ustawiona. Potrzebuję uprawnień **administratora* żeby to zrobić. @@ -597,7 +597,7 @@ Powód: {1} Uprawnienia tego serwera zostały zresetowane. - + Aktywne zabezpieczenia {0} został **wyłączony** na tym serwerze. @@ -609,7 +609,7 @@ Powód: {1} Wystąpił błąd. Potrzebuję uprawnień zarządzania rolami - + Żadne zabezpieczenie nie jest aktywne. @@ -773,7 +773,7 @@ Powód: {1} Kanał tekstowy został usunięty. - + wyciszenie wyłączone Odciszony @@ -876,7 +876,7 @@ Powód: {1} Fuzzy - + Migracja zakończona! @@ -908,7 +908,7 @@ Powód: {1} Zgadłeś! Wygrałeś {0} - + Użyty numer jest niepoprawny. Możesz rzucić 1 do {0} monet Dodaj reakcję {0} do tej wiadomości, aby dostać {1} @@ -962,16 +962,16 @@ Powód: {1} ŁAAAAAAAAAAAAŁ!!! Gratulacje!!! x{0} - + Pojedyńczy {0}, x{1} - + Wow! Szczęściarz! Trójka! x{0} - + Nieźle! Dwójka {0} - stawka x{1} - + Wygrana Użytkownicy muszą wpisać tajny kod aby dostać {0}. @@ -994,13 +994,13 @@ Trwa {0} sekund. Nie nikomu. Ciiii. nie był w stanie wziąć {0} od {1}, ponieważ użytkownik nie ma tylu {2}! - + Powrót do ToC Tylko właściciel bota - + Wymagane {0} uprawnienie kanału. Możesz wspierać ten projekt na patreonie: <{0}> albo poprzez paypala: <{1}> @@ -1050,7 +1050,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Spis treści Użycie @@ -1093,7 +1093,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś {1} czyli {0} wygrał wyścig i {2}! - + Użyty numer jest nie poprawny. Możesz rzucić {0}-{1} kośćmi na raz wyrzucono {0} @@ -1302,22 +1302,22 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Kwoth planted 5* - + Trivia jest aktywna na tym serwerze - + Trivia {0} zgadł! Odpowiedź to: {1} - + Trivia nie jest aktywna na tym serwerze {0} posiada {1} punktów - + Koniec po tym pytaniu Koniec czasu! Prawidłowa odpowiedź to {0} @@ -1431,7 +1431,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Strona {0} zapisanych playlist Playlista usunięta. @@ -1443,7 +1443,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Playlista z takim ID nie istnieje. - + Kolejka do playlisty zakończona Playlista zapisana @@ -1835,7 +1835,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Pokemon nieznaleziony Link profilowy: @@ -1949,7 +1949,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Problem z napisaniem Twojego zdania w stylu Yody Dołączył @@ -2272,5 +2272,35 @@ ID właściciela: {2} Uprawnienia kanału głosowego + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From b91fa24d16ecc63ae777b75119574c00e1b73447 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 21 Mar 2017 04:54:37 +0100 Subject: [PATCH 584/746] Update ResponseStrings.pt-BR.resx (POEditor.com) --- .../Resources/ResponseStrings.pt-BR.resx | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx index 147fd952..1fa1070b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx @@ -284,7 +284,7 @@ Você reviveu a si mesmo com uma {0} - Seu tipo foi mudado de {0} para {1} + Seu tipo foi mudado para {0} por uma {1} É mais ou menos efetivo. @@ -2356,5 +2356,35 @@ OwnerID: {2} Cargos de canais de voz + + A mensagem que ativa a reação personalizada com id {0} não será deletada automaticamente. + + + A mensagem que ativa a reação personalizada com id {0} será deletada automaticamente. + + + A resposta para a reação personalizada com o id {0} não será enviada como mensagem direta. + + + A resposta para a reação personalizada com o id {0} será enviada como mensagem direta. + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 94f55d46156ef5174e878b4b57844282b080db3b Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 21 Mar 2017 04:54:40 +0100 Subject: [PATCH 585/746] Update ResponseStrings.ru-RU.resx (POEditor.com) --- .../Resources/ResponseStrings.ru-RU.resx | 176 +++++++++++------- 1 file changed, 109 insertions(+), 67 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx index 5f333da0..250cb254 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx @@ -139,7 +139,7 @@ @{0} Вы уже захватили базу #{1}. Вы не можете захватить новую базу. - Время действия запроса от @{0} на войну против {1} истёкло. + Время действия запроса от @{0} на войну против {1} истекло. Враг @@ -163,7 +163,7 @@ Вы не участвуете в этой войне. - @{0} Вы либо не участвуете в этой войне, либо эта база разрушена. + @{0} Вы либо не участвуете в этой войне, либо эта база уже разрушена. Нет активных войн. @@ -175,13 +175,13 @@ Война против {0} уже началась. - Война против {0} была начата. + Война против {0} начата. - Закончилась война против {0}. + Война против {0} закончилась. - Эта война не существует. + Этой войны не существует. Война против {0} началась! @@ -193,7 +193,7 @@ Настраиваемая реакция удалена - Недостаточно прав. Необходимо владеть Бот-ом для глобальных настраиваемых реакций или быть Администратором для реакций по серверу. + Недостаточно прав. Необходимо иметь права владельца бота для глобальных настраиваемых реакций, и права Администратора для реакций по серверу. Список всех настраиваемых реакций @@ -217,7 +217,7 @@ Статистика настраеваемых реакций - Статистика удалена для настраеваемой реакции {0}. + Статистика для настраиваемой реакции {0} очищена. Не найдено статистики для этого активатора, никаких действий не применено. @@ -226,10 +226,10 @@ Активатор - Авто-хентай остановлен :( + Авто-хентай остановлен. - Запрос не найден. + Результатов не найдено. {0} уже потерял сознание. @@ -245,10 +245,10 @@ Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. - Нельзя атаковать два раза подряд. + Вы не можете атаковать два раза подряд. - Нельзя атаковать самого себя. + Вы не можете атаковать самого себя. {0} потерял сознание! @@ -266,10 +266,10 @@ Список приёмов {0} типа - Эта атака не эффективна. + Эта атака неэффективна. - У вас не достаточно {0} + У вас недостаточно {0} воскресил {0}, использовав один {1} @@ -287,7 +287,7 @@ Эта атака очень эффективна! - Вы использовали слишком много приёмов подряд и не можете двигаться! + Вы использовали слишком много приёмов подряд, поэтому вы не можете двигаться! Тип {0} — {1} @@ -296,7 +296,7 @@ Пользователь не найден. - Вы не можете использовать приёмы потому-что ваш покемон потерял сознание! + Вы потеряли сознание, поэтому вы не можете двигаться! ***Авто выдача роли*** каждому новому пользователю **отключена** @@ -305,13 +305,13 @@ ***Авто выдача роли*** каждому новому пользователю **включена** - Приложения + Вложения Аватар изменён - Вас забанили с сервера {0}. Причина бана: {1}. + Вы были забанены на сервере {0}. Причина бана: {1}. забанены @@ -321,10 +321,10 @@ Пользователь забанен. - Имя Бот-а сменено на {0} + Имя бота изменено на {0} - Статус Бот-а сменён на {0} + Статус бота изменен на {0} Автоматическое удаление прощальных сообщений отключено. @@ -339,7 +339,7 @@ Чтобы включить прощальные сообщения введите {0} - Установлено новое прощальное сообщение. + Новое прощальное сообщение было установлено. Прощальные сообщения выключены. @@ -348,13 +348,13 @@ Прощальные сообщения включены на этом канале. - Имя канал изменено. + Имя канала изменено Старое имя. - Тема канала сменена. + Тема канала изменена Чат очищен. @@ -363,13 +363,13 @@ Содержание - Успешно создана роль {0}. + Роль {0} создана успешно - Создан текстовый канал {0}. + Текстовый канал {0} создан. - Создан голосовой канал {0}. + Голосовой канал {0} создан. Успешное оглушение. @@ -381,22 +381,22 @@ Отключено автоматическое удаление успешно выполненных команд. - Включено автоматическое удаление успешно выполненных команд. + Включено автоматическое удаление сообщений для успешно выполненных команд. - Удалён текстовый канал {0}. + Текстовый канал {0} удален. - Удален голосовой канал {0}. + Голосовой канал {0} удален. - ПМ от + ЛС от Успешно добавлен новый донатор. Общее количество пожертвований от этого пользователя: {0} 👑 - Спасибо всем, указанным ниже, что помогли этому проекту! + Спасибо ниже перечисленным людям за помощь в развитии этого проекта! Я буду перенаправлять личные сообщения всем владельцам. @@ -405,10 +405,10 @@ Я буду перенаправлять личные сообщения только первому владельцу. - Я буду перенаправлять личные сообщения. + Теперь я буду перенаправлять ЛС. - Я прекращаю перенаправление личных сообщений. + Теперь я прекращу перенаправлять ЛС. Автоматическое удаление приветственных сообщений выключено. @@ -417,10 +417,10 @@ Приветственные сообщения будут удаляться через {0} секунд. - Приветственное ЛС, используемое в настоящий момент: {0} + Текущее приветственное ЛС: {0} - Чтобы включить приветственное ЛС, напишите {0} + Включите приветственные ЛС, написав {0} Новое приветственное ЛС установлено. @@ -432,19 +432,19 @@ Приветственные ЛС включены. - Текущее привественное сообщение: {0} + Текущее приветственное сообщение: {0} - Чтобы включить привественные сообщения введите {0} + Чтобы включить приветственные сообщения введите {0} - Установлено новое приветствие. + Новое приветственное сообщение установлено. - Привественные сообщения выключены. + Приветственные сообщения выключены. - Привественные сообщения включены на этом канале. + Приветственные сообщения включены на этом канале. Вы не можете использовать эту команду на пользователях равным или более высоким в иерархии ролей. @@ -463,7 +463,7 @@ Вы были выгнаны с сервера {0}. -По причине: {1} +Причина: {1} Пользователь выгнан @@ -475,16 +475,16 @@ Язык вашего сервера теперь {0} - {1} - Язык Бот-а по умолчанию теперь {0} - {1} + Язык бота по умолчанию теперь {0} - {1} - Язык Бот-а теперь установлен как {0} - {1} + Язык бота установлен как {0} - {1} Не удалось выставить язык. Проверьте справку к этой команде. - Язык этого сервера теперь установлен как {00} - {1} + Язык этого сервера установлен как {0} - {1} {0} покинул {1} @@ -505,10 +505,10 @@ Регистрируйте события, на которые Вы можете подписаться: - Регистрация будет пропускать {0}. + Регистрация будет игнорировать {0}. - Регистрация не будет пропускать {0}. + Регистрация не будет игнорировать {0}. Прекращена регистрация события {0}. @@ -540,7 +540,7 @@ singular "User muted." - Скорее всего, у меня нет необходимых прав. + Похоже, у меня нет необходимых прав. Новая роль заглушения установлена. @@ -561,7 +561,7 @@ Имя изменено - Сервер не найден + Не могу найти этот сервер Не найдено Shard-а с таким ID. @@ -579,7 +579,7 @@ Ошибка. Скорее всего мне не хватает прав. - Права для этого сервера + Права для этого сервера были сброшены. Активные защиты от рейдов @@ -588,13 +588,13 @@ {0} был **отключён** на этом сервере. - {0} влючён + {0} включен Ошибка. Требуется право на управление ролями. - Нет защит от рейдов + Защита от рейдов отключена. Порог пользователей должен лежать между {0} и {1}. @@ -606,7 +606,8 @@ Время должно быть между {0} и {1} секунд. - Успешно убраны все роли пользователя {0}. + Все роли пользователя {0} были успешно убраны с него + Fuzzy Не удалось убрать роли. Отсутвуют требуемые разрешения. @@ -640,12 +641,13 @@ Удалено повторяющееся сообщение: {0} + Fuzzy Роль {0} добавлена в лист. - {0} не найдена. Чат очищен. + Роль {0} не найдена. Чат очищен. Роль {0} уже есть в списке. @@ -654,10 +656,10 @@ Добавлено. - Отключены чередующиеся статусы. + Чередующиеся статусы отключены. - Чередующиеся статусы отключены. + Чередующиеся статусы включены. Список чередующихся статусов: @@ -670,7 +672,8 @@ У вас уже есть роль {0} - У Вас уже есть исключающая самоназначенная роль {0}. + У Вас уже есть исключенная самоназначенная роль {0}. + Я не понял что значит "исключающая", заменил на "исключенная". Самоназначенные роли теперь взаимоисключающие! @@ -691,10 +694,10 @@ Не удалось добавить Вам эту роль. 'Нельзя добавлять роли владельцам или другим ролям, находящимся выше моей роли в ролевой иерархии' - {0} убрана из списка самоназначенных ролей. + Роль {0} убрана из списка самоназначаемых ролей. - У вас больше нету роли {0} + У вас больше нет роли {0} Теперь у вас есть роль {0} @@ -703,7 +706,7 @@ Успешно добавлена роль {0} пользователю {1} - Не удалось добавить роль. Нет достаточных разрешений. + Не удалось добавить роль. Недостаточно прав. Новый аватар установлен! @@ -715,7 +718,7 @@ Новая игра установлена! - Новый стрим установлен! + Новая трансляция установлена! Новая тема канала установлена. @@ -730,13 +733,13 @@ Выключение - Пользователи не могут посылать более {0} сообщений в {1} секунд. + Пользователи не могут писать более {0} сообщений в {1} секунд. Медленный режим выключен. - Медленный режим включен. + Медленный режим включен выгнаны @@ -752,7 +755,7 @@ Если пользователь пишет {0} одинаковых сообщений подряд, я {} их. __Игнорируемые каналы__: {2} - Создан текстовый канал + Создан текстовый канал. Уничтожен текстовый канал. @@ -810,7 +813,8 @@ {0} покинул голосовой канал {1}. - {0} переместил из голосового канала {1} в {2}. + {0} переместился из голосового канала {1} в {2}. + Забыли "ся" в "переместил" **Выключен микрофон** у {0}. @@ -831,10 +835,10 @@ Включены голосовые + текстовые функции. - Нет разрешений **Управление ролями** и/или **Управление каналами**, поэтому нельзя использовать команду 'voice+text' на сервере {0}. + Нет разрешения на **Управление ролями** и/или **Управление каналами**, поэтому нельзя использовать команду 'voice+text' на сервере {0}. - Вы пытаетесь включить/отключить это свойство и **отсутвует разрешение АДМИНИСТРАТОР**. Это может вызвать ошибки, и Вам придётся удалять текст в текстовых каналах самостоятельно. + Вы пытаетесь включить/отключить это свойство и **отсутствует разрешение АДМИНИСТРАТОР**. Это может вызвать ошибки, и вам придётся удалять текст в текстовых каналах самостоятельно. Для этого свойства требуются как минимум разрешения **управление ролями** и **управление каналами**. (Рекомендуется разрешение Администратор) @@ -983,6 +987,7 @@ Команды и альтернативные имена команд + Fuzzy Список команд создан. @@ -1351,7 +1356,8 @@ Paypal <{1}> Отключено справедливое воспроизведение. - Fuzzy + "Честное воспроизведение" не подойдет? +Fuzzy Включено справедливое воспроизведение. @@ -1820,7 +1826,7 @@ Paypal <{1}> Качество: - Время игры в Быстрой Игре + Время в Быстрой игре Is this supposed to be Overwatch Quick Play stats? @@ -2249,5 +2255,41 @@ IDВладельца: {2} Роли голосовых каналов + + Сообщение, инициирующее настраеваемую реакцию с ИД {0}, не будет автоматически удалено. + Fuzzy + + + Сообщение, инициирующее настраеваемую реакцию с ИД {0}, будет автоматически удалено. + + + Ответное сообщение для настраеваемой реакцией с ИД {0} не будет отправлено в ЛС. + + + Ответное сообщение для настраиваемой реакцией с ИД {0} будет отправлено в ЛС. + + + Альтернативная команда не найдена + Fuzzy + + + {0} будет теперь альтернативной командой для {1}. + Fuzzy + + + Список альтернативных команд + Fuzzy + + + У триггера {0} больше нет альтернативных команд. + Fuzzy + + + У триггера {0} не было альтернативных команд. + Fuzzy + + + Время в игре + \ No newline at end of file From e8335a25e921e00a2c495d5a556dc0972ff1f6ba Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 21 Mar 2017 04:54:43 +0100 Subject: [PATCH 586/746] Update ResponseStrings.sr-cyrl-rs.resx (POEditor.com) --- .../Resources/ResponseStrings.sr-cyrl-rs.resx | 56 +++++++++++++------ 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx index 17eb5bdc..8fe7d18e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx @@ -152,11 +152,9 @@ Величина рата није валидна. - Fuzzy - Листа Ратова У Току - Fuzzy + Листа ратова у току нема захтева @@ -169,7 +167,6 @@ Нема ратова у току. - Fuzzy Величина @@ -209,7 +206,6 @@ Реакција по избору није нађена. - Fuzzy Није нађена реакција са тим идентификатором. @@ -471,7 +467,7 @@ Reason: {1} Reason: {1} - User Kicked + Кикован корисник Fuzzy @@ -583,16 +579,13 @@ Reason: {1} No shard with that ID found. - Old Message - Fuzzy + Стара порука - Old Nickname - Fuzzy + Стари надимак - Old Topic - Fuzzy + Стара тема Error. Most likely I don't have sufficient permissions. @@ -601,8 +594,7 @@ Reason: {1} Permissions for this server are reset. - Active Protections - Fuzzy + Активне заштите {0} has been **disabled** on this server. @@ -614,8 +606,7 @@ Reason: {1} Error. I need ManageRoles permission - No protections enabled. - Fuzzy + Нема активних заштита. User threshold must be between {0} and {1}. @@ -774,8 +765,7 @@ Reason: {1} __IgnoredChannels__: {2} - Text Channel Destroyed - Fuzzy + Уништен текстуелни канал Text Channel Destroyed @@ -2306,5 +2296,35 @@ Lasts {1} seconds. Don't tell anyone. Shhh. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 1871c2d76dd13acfbef91438299e60c58cf594e4 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 21 Mar 2017 04:54:46 +0100 Subject: [PATCH 587/746] Update ResponseStrings.es-ES.resx (POEditor.com) --- .../Resources/ResponseStrings.es-ES.resx | 174 ++++++++++-------- 1 file changed, 102 insertions(+), 72 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.es-ES.resx b/src/NadekoBot/Resources/ResponseStrings.es-ES.resx index fe1f8793..4e34bf78 100644 --- a/src/NadekoBot/Resources/ResponseStrings.es-ES.resx +++ b/src/NadekoBot/Resources/ResponseStrings.es-ES.resx @@ -315,7 +315,7 @@ Razón: {1} - Bloqueado + bloqueados PLURAL @@ -376,7 +376,7 @@ Razón: {1} Ensordecimiento satisfactorio. - Servidor eliminado {0} + Servidor {0} eliminado Detenida la eliminación automática de comandos de invocación. @@ -400,10 +400,10 @@ Razón: {1} ¡Gracias a las personas enlistadas por apoyar el proyecto! - Enviaré los MPs a todos los administradores. + Redirigiré los MPs a todos los administradores. - Enviaré los MPs solamente al primer administrador. + Redirigiré los MPs solamente al primer administrador. Redirigiré los MPs desde ahora. @@ -427,10 +427,10 @@ Razón: {1} Nuevo mensaje de bienvenida por MP configurado. - Anuncio de bienvenida por mensaje privado desactivado. + Anuncio de bienvenida por MP desactivado. - Anuncio de bienvenida por mensaje privado activado. + Anuncio de bienvenida por MP activado. Mensaje de bienvenida actual: {0} @@ -442,10 +442,10 @@ Razón: {1} Nuevo mensaje de bienvenida configurado. - Bienvenida desactivada. + Anuncio de bienvenida desactivado. - Bienvenida activada en este canal. + Anuncio de bienvenida activado en este canal. No puedes usar este comando con usuarios que tienen un rol más alto o igual al tuyo. @@ -476,10 +476,10 @@ Razón: {1} El lenguaje local del servidor ahora es {0} - {1} - El lenguaje local del Bot ahora es {0} - {1} + Lenguaje local por defecto del Bot ahora es {0} - {1} - Lenguaje del Bot configurado {0} - {1} + Lenguaje del Bot configurado a {0} - {1} No pude configurar el lenguaje local. Revisa la ayuda. @@ -494,7 +494,7 @@ Razón: {1} Servidor abandonado {0} - Registrando los eventos {0} en este canal. + Registrando los eventos de {0} en este canal. Registrando todos los eventos en este canal. @@ -512,7 +512,7 @@ Razón: {1} El registro no ignorará {0}. - El registro del {0} evento fue detenido. + El registro de los eventos de {0} fue detenido. {0} ha pedido mención de los siguientes roles: @@ -611,7 +611,7 @@ Razón: {1} He removido todos los roles del usuario {0} - No pude mover los roles. No tengo suficientes permisos. + No pude remover los roles. No tengo suficientes permisos. El color del rol {0} ha sido cambiado. @@ -641,7 +641,7 @@ Razón: {1} No puedes editar roles con más poder que el tuyo. - Removido el mensaje de juego: {0} + Removido el mensaje de estado: {0} El rol {0} ha sido añadido a la lista. @@ -726,7 +726,7 @@ Razón: {1} Fragmento {0} reconectado. - Fragmento {0} reconectando. + Reconectando fragmento {0}. Apagando @@ -768,10 +768,10 @@ __CanalesIgnorados__: {2} singular - Usuario + Nombre de usuario - Usuario cambiado + Nombre de usuario cambiado Usuarios @@ -780,10 +780,10 @@ __CanalesIgnorados__: {2} Usuario bloqueado - {0} ha sido **silenciado** en chat. + {0} ha sido **silenciado** del chat. - {0} ahora puede escribir en el chat. + {0} ha sido **desilenciado** del chat. Usuario se unió. @@ -804,7 +804,7 @@ __CanalesIgnorados__: {2} {0} ahora está {1} - {0} ha sido removido del mundo de los silenciados. + {0} ha sido **desilenciado** de chat y voz. {0} ha entrado al canal de voz {1}. @@ -819,7 +819,7 @@ __CanalesIgnorados__: {2} {0} ha sido **silenciado de voz** - {0} ya puede hablar por voz. + {0} ha sido **desilenciado de voz**. Canal de voz creado @@ -837,7 +837,7 @@ __CanalesIgnorados__: {2} No tengo los permisos para **administrar roles** y/o **administrar canales**, así que no puedo ejecutar `voz+texto` en el servidor {0}. - Estás activando o desactivando esto y **no poseo permisos de administración**. Esto puede causar problemas y tendrás que arreglar los canales tú mismo después. + Estás activando o desactivando esto y **no poseo permisos de ADMINISTRADOR**. Esto puede causar problemas y tendrás que arreglar los canales tú mismo después. Necesito permisos para **administrar roles** y **administrar canales** para hacer esto. De preferencia permisos de Administración. @@ -877,7 +877,7 @@ Razón: {1} Suerte la próxima. - ¡Felicitaciones! Ganaste {0} por sacar sobre {1} + ¡Felicitaciones! Ganaste {0} por sacar sobre {1}. Mazo reconstruido. @@ -958,10 +958,10 @@ Razón: {1} Los usuarios deben escribir un código secreto para obtener {0}. Quedan {1} segundos. No le digas a nadie. - El evento de Estado Escurridizo ha terminado. {0} recibieron el premio. + El evento de EstadoEscurridizo ha terminado. {0} recibieron el premio. - Evento de Estado Escurridizo iniciado + Evento de EstadoEscurridizo iniciado Cruz @@ -970,7 +970,7 @@ Razón: {1} le quitó {0} a {1} - no pudo quitarle {0} a {1} porque el usuario no tiene tal cantidad {2}. + no pudo quitarle {0} a {1} porque el usuario no tiene tal cantidad de {2}. Regresar a la tabla de contenidos @@ -994,7 +994,7 @@ Razón: {1} Escribe `{0}h NombreDelComando` para recibir ayuda específica. Ej: `{0}h >8ball` - No puedo encontrar ese comando. Por favor verifica que el comando exista y trata de nuevo. + No puedo encontrar ese comando. Por favor verifica que el comando exista antes de tratar de nuevo. Descripción @@ -1009,7 +1009,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. **Lista de comandos**. <{0}> -**Las guías para albergar y documentos pueden ser encontradas aquí**: <{1}> +**Las guías para albergar y documentos pueden ser encontrados aquí**: <{1}> Lista de comandos @@ -1049,7 +1049,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. ¡Todo listo! ¡Allá vamos! - {} entró como un {1} + {0} entró como un {1} {0} entró como un {1} y apostó {2}. @@ -1067,7 +1067,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. {0} como un {1} ganó la carrera. - {0} como {1} ganó la carrera y {2}. + {0} como un {1} ganó la carrera y {2}. Número especificado no válido. Puedes lanzar {0}-{1} dados a la vez. @@ -1135,14 +1135,14 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Te has divorciado de una waifu que te quería. Monstruo sin corazón. {0} recibió {1} como compensación. - no puedes configurar tu afinidad hacia ti mismo, rarito. + no puedes configurar tu afinidad hacia ti mismo, ególatra. 🎉 ¡Su amor es correspondido! 🎉 ¡El nuevo valor de {0} es {1}! - Ninguna waifu es tan barata. Debes pagar al menos {0} para obtener una waifu, aunque su valor actual sea bajo. + Ninguna waifu es tan barata. Debes pagar al menos {0} para obtener una waifu, aunque su valor actual sea menor. ¡Debes pagar {0} o más para reclamar esa waifu! @@ -1157,10 +1157,10 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Te divorciaste recientemente. Debes esperar {0} horas y {1} minutos para divorciarte otra vez. - Nadi + Nadie - Te has divorciado de uan waifu que no te querías. Recibes {0} de regreso. + Te has divorciado de una waifu que no te quería. Recibes {0} de regreso. Bola 8 @@ -1184,7 +1184,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Inicia el juego. Crea una oración con el siguiente acrónimo: {0}. - Tienes {0} segundos. + Tienes {0} segundos para enviar tu oración. {0} enviaron sus oraciones. ({1} en total) @@ -1193,7 +1193,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Vota escribiendo el número correspondiente. - ¡{0} votaron! + ¡{0} votó! El ganador es {0} con {1} puntos. @@ -1229,29 +1229,29 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Cleverbot activado en este servidor. - La regeneración ha sido desactivada en este canal. + La generación de moneda ha sido desactivada en este canal. - La regeneración ha sido activada en este canal. + La generación de moneda ha sido activada en este canal. - {0} {1} apareció. + {0} {1} aparecieron. plural ¡Una {0} apareció! - No pue cargar la pregunta. + No pude cargar la pregunta. - Inicia el juego + Juego iniciado Juego del ahorcado iniciado - Un juego del ahorcado ya se está ejecutando. + Un juego del ahorcado ya se está ejecutando en este canal. Error iniciando el ahorcado. @@ -1269,7 +1269,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Sin resultados - tomó {0} + recogió {0} Kwoth picked 5* @@ -1340,22 +1340,22 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Reproducción automática activada. - El volumen por defecto configurado en {0}% + El volumen por defecto configurado es {0}% Directorio completo - Juego sucio + Juego limpio Canción finalizada - Juego sucio desactivado. + Juego limpio desactivado. - Juego sucio activado. + Juego limpio activado. De la posición @@ -1376,7 +1376,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Tamaño máximo de la cola configurada en ilimitado. - Tamaño máximo de la cola configurado en {0} pista(s). + Tamaño máximo de la cola configurado en {0} canción(es). Tienes que estar en un canal de voz. @@ -1436,10 +1436,10 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Se eliminó la cola de música. - La cola está llena con {0}. + La cola está llena con {0}/{0}. - Canción eliminada: + Canción eliminada context: "removed song #5" @@ -1449,10 +1449,10 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Repitiendo lista de reproducción - Repitiendo pista + Repitiendo canción - Repetición de la pista actual detenida. + Repetición de la canción actual detenida. Reproducción resumida @@ -1518,13 +1518,13 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Activado el uso de todos los módulos para el usuario {0}. - Enviado a la lista negra a: {0} con la ID: {1} + Enviado a la lista negra a: {0} con el ID: {1} El comando {0} ahora tiene {1} de enfriamiento. - El comando {0} ya no se está enfriando y todos los tiempos de enfriamiento han sido reiniciados. + El comando {0} ya no tiene enfriamiento y todos los tiempos de enfriamiento han sido reiniciados. No se ha configurado tiempo de enfriamiento. @@ -1542,7 +1542,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Prohibido - Se ha añadido la palabra {0} a la lista de groserías. + Se ha añadido la palabra {0} a la lista de palabras filtradas. Lista de palabras filtradas @@ -1614,7 +1614,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Activado el uso de {0} {1} en este servidor. - Removido de la lista negra a: {0} con la ID: {1} + Removido de la lista negra a: {0} con el ID: {1} ineditable @@ -1632,7 +1632,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Desde ahora mostraré las advertencias de permisos. - Filtro de groserías activado en este canal. + Filtro de groserías desactivado en este canal. Filtro de groserías activado en este canal. @@ -1692,7 +1692,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Victorias en competitivo - Completada + Completadas Condición @@ -1707,7 +1707,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Defininir: - Eliminadas + Dejadas de ver Episodios @@ -1771,7 +1771,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Perfil de MAL de {0} - El dueño del Bot no especificó una clave MashapeApi. No puedes usar esto. + El dueño del Bot no especificó una MashapeApiKey. No puedes usar esto. Mín/Máx @@ -1786,7 +1786,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. En espera - Original + Enlace original Se requiere una clave de API de osu! @@ -1801,7 +1801,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. ¡Usuario no encontrado! Por favor revisa la región y BattleTag antes de intentar de nuevo. - Planeadas + Planeadas ver Plataforma @@ -1837,7 +1837,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. No pude acortar ese enlace. - Acortada + Enlace acortado Algo salió mal. @@ -1849,7 +1849,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Estado - Depósito de enlace + Guardar enlace El usuario {0} está desconectado. @@ -1921,7 +1921,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Velocidad del viento - Los {0} campeones bloqueados + Los {0} campeones más bloqueados No pude yodificar tu oración @@ -2004,7 +2004,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. No tienes permitido usar este comando en roles con muchos usuarios para prevenir abuso. - Valor {0} no válido. + Valor en {0} no válido. Invalid months value/ Invalid hours value @@ -2016,7 +2016,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. ID: {0} Miembros: {1} -ID del admin: {2} +IDs de dueños: {2} No encontré servidores en esa página. @@ -2058,13 +2058,13 @@ ID del admin: {2} No hay tema configurado. - Administrador + Dueño - ID del administrador + ID del dueño - En + Presencia {0} servidores @@ -2218,10 +2218,10 @@ ID del admin: {2} {0} votos totales. - Atrápala escribiendo `{0}pick` + Tómalas escribiendo `{0}pick` - Atrápala escribiendo `{0}pick` + Tómala escribiendo `{0}pick` No encontré ese usuario. @@ -2247,5 +2247,35 @@ ID del admin: {2} Roles para el canal de voz + + El mensaje de ejecución del comando personalizado con la ID {0} no será eliminado automáticamente. + + + El mensaje de ejecución del comando personalizado con la ID {0} será eliminado automáticamente. + + + Respuesta del mensaje para el comando personalizado con la ID {0} no será enviada como MP. + + + Respuesta del mensaje para el comando personalizado con la ID {0} será enviada como MP. + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 45ee96170decf43a90f566d003eaeeb6c3d505db Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 21 Mar 2017 04:54:49 +0100 Subject: [PATCH 588/746] Update ResponseStrings.sv-SE.resx (POEditor.com) --- .../Resources/ResponseStrings.sv-SE.resx | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx index 7ecb7286..f5297053 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx @@ -2335,5 +2335,35 @@ Medlemmar: {1} Röstkanalsroller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From bf82baf8847007dccbcac7990a88f146111190ff Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 21 Mar 2017 04:54:51 +0100 Subject: [PATCH 589/746] Update ResponseStrings.tr-TR.resx (POEditor.com) --- .../Resources/ResponseStrings.tr-TR.resx | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx b/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx index b807152e..b63550e8 100644 --- a/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx @@ -2251,5 +2251,35 @@ Kurucu Kimliği: {2} Sesli kanal rolleri + + {0} kimliğiyle özel reaksiyonu tetikleyen mesaj otomatik olarak silinmeyecek. + + + {0} kimliğiyle özel reaksiyonu tetikleyen mesaj otomatik olarak silinecek. + + + {0} kimliğine sahip özel reaksiyon için verilen yanıt mesajı DM olarak gönderilmeyecek. + + + {0} kimliğine sahip özel reaksiyon için verilen yanıt mesajı bir DM olarak gönderilecek. + + + Takma ad bulunamadı + + + Yazma {0} şimdi {1} 'in bir takma adı olacak. + + + Takma ad listesi + + + Tetikleyici {0} artık bir takma ada sahip değil. + + + Tetikleyici {0} 'nin takma adı yoktu. + + + Rekabetçi oyun süresi + \ No newline at end of file From aeb671cec0bc7fe4eac2c63325ebc3f4bdedc186 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Mar 2017 04:56:16 +0100 Subject: [PATCH 590/746] Updated supported language list --- .../Modules/Administration/Commands/LocalizationCommands.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 86a41f7a..c8c07fe2 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -20,16 +20,16 @@ namespace NadekoBot.Modules.Administration { {"zh-TW", "Chinese (Traditional), China" }, {"zh-CN", "Chinese (Simplified), China"}, - //{"nl-NL", "Dutch, Netherlands"}, + {"nl-NL", "Dutch, Netherlands"}, {"en-US", "English, United States"}, {"fr-FR", "French, France"}, {"de-DE", "German, Germany"}, //{"ja-JP", "Japanese, Japan"}, {"nb-NO", "Norwegian (bokmål), Norway"}, - //{"pl-PL", "Polish, Poland" } + {"pl-PL", "Polish, Poland" }, {"pt-BR", "Portuguese, Brazil"}, {"ru-RU", "Russian, Russia"}, - //{"sr-Cyrl-RS", "Serbian, Serbia - Cyrillic"} + {"sr-Cyrl-RS", "Serbian, Serbia - Cyrillic"}, {"es-ES", "Spanish, Spain"}, {"sv-SE", "Swedish, Sweden"}, {"tr-TR", "Turkish, Turkey" } From dde37f4be816633e23d03dd179d00a98440dd16a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Mar 2017 04:59:25 +0100 Subject: [PATCH 591/746] Updated version --- 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 bd8eff0b..72996002 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -16,7 +16,7 @@ namespace NadekoBot.Services.Impl private readonly DiscordShardedClient _client; private readonly DateTime _started; - public const string BotVersion = "1.23"; + public const string BotVersion = "1.25"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From 49fbbbd325dc2ff3e04b74875ff1d569c3a4329c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Mar 2017 07:12:43 +0100 Subject: [PATCH 592/746] $rolluo now works without arguments --- src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs index 8a0323b9..a9bfc8db 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs @@ -62,7 +62,7 @@ namespace NadekoBot.Modules.Gambling [NadekoCommand, Usage, Description, Aliases] [Priority(0)] - public async Task Rolluo(int num) + public async Task Rolluo(int num = 1) { await InternalRoll(num, false).ConfigureAwait(false); } From 30bef19e8c6aef29104ce1d237e189ee6107ae4a Mon Sep 17 00:00:00 2001 From: DogeOps97 Date: Tue, 21 Mar 2017 00:14:53 -0700 Subject: [PATCH 593/746] A slight edit on replacing OwnerID A slight edit on replacing OwnerID If people asks about it, then it's not clear enough(?) lol http://i.imgur.com/WxZiu3G.png --- docs/guides/Windows Guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/Windows Guide.md b/docs/guides/Windows Guide.md index c0e62c76..0f141fad 100644 --- a/docs/guides/Windows Guide.md +++ b/docs/guides/Windows Guide.md @@ -45,7 +45,7 @@ ________________________________________________________________________________ - Again, copy the same `Client ID` and replace the `null` part of the `BotId` line with it. - Go to a server on discord and attempt to mention yourself, but put a backslash at the start like shown below - So the message `\@fearnlj01#3535` will appears as `<@145521851676884992>` after you send the message (to make it slightly easier, add the backslash after you type the mention out) -- The message will appear as a mention if done correctly, copy the numbers from the message you sent (`145521851676884992`) and replace the `0` on the `OwnerIds` section with your user ID shown earlier. +- The message will appear as a mention if done correctly, copy the numbers from the message you sent (`145521851676884992`) and replace the ID (By default, the ID is `105635576866156544`) on the `OwnerIds` section with your user ID shown earlier. - Save `credentials.json` (make sure you aren't saving it as `credentials.json.txt`) - If done correctly, you are now the bot owner. You can add multiple owners by seperating each owner ID with a comma within the square brackets. From e646debda5d4abd79c7c6adbb60d040e7441fb51 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Mar 2017 08:46:13 +0100 Subject: [PATCH 594/746] Fixed a permission bug --- .../Modules/Gambling/Commands/DiceRollCommand.cs | 2 -- .../Modules/Permissions/PermissionExtensions.cs | 10 ++-------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs index a9bfc8db..5b992996 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs @@ -1,6 +1,5 @@ using Discord; using Discord.Commands; -using ImageSharp; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; @@ -10,7 +9,6 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; -using ImageSharp.Formats; using Image = ImageSharp.Image; namespace NadekoBot.Modules.Gambling diff --git a/src/NadekoBot/Modules/Permissions/PermissionExtensions.cs b/src/NadekoBot/Modules/Permissions/PermissionExtensions.cs index d9afcc1f..db0fdfd6 100644 --- a/src/NadekoBot/Modules/Permissions/PermissionExtensions.cs +++ b/src/NadekoBot/Modules/Permissions/PermissionExtensions.cs @@ -106,19 +106,13 @@ namespace NadekoBot.Modules.Permissions switch (perm.PrimaryTarget) { case PrimaryPermissionType.User: - if (guild == null) - com += $"<@{perm.PrimaryTargetId}>"; - else - com += guild.GetUser(perm.PrimaryTargetId).ToString() ?? $"<@{perm.PrimaryTargetId}>"; + com += guild?.GetUser(perm.PrimaryTargetId).ToString() ?? $"<@{perm.PrimaryTargetId}>"; break; case PrimaryPermissionType.Channel: com += $"<#{perm.PrimaryTargetId}>"; break; case PrimaryPermissionType.Role: - if(guild == null) - com += $"<@&{perm.PrimaryTargetId}>"; - else - com += guild.GetRole(perm.PrimaryTargetId).ToString() ?? $"<@{perm.PrimaryTargetId}>"; + com += guild?.GetRole(perm.PrimaryTargetId)?.ToString() ?? $"<@&{perm.PrimaryTargetId}>"; break; case PrimaryPermissionType.Server: break; From 59f0fb56e2727194d6d77e6b9f26a754c698940c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Mar 2017 08:48:35 +0100 Subject: [PATCH 595/746] upped version --- 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 72996002..676d7407 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -16,7 +16,7 @@ namespace NadekoBot.Services.Impl private readonly DiscordShardedClient _client; private readonly DateTime _started; - public const string BotVersion = "1.25"; + public const string BotVersion = "1.25a"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From 655b98d16d5e3401ce122bb6222c05f8a6a365d6 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 21 Mar 2017 13:12:47 +0100 Subject: [PATCH 596/746] slot max bet increased to 9999 --- .../Modules/Gambling/Commands/Slots.cs | 2 +- src/NadekoBot/Services/Impl/ImagesService.cs | 2 +- .../data/images/slots/background2.png | Bin 0 -> 103813 bytes 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 src/NadekoBot/data/images/slots/background2.png diff --git a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs index 79dbe75a..f4cf201a 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs @@ -145,7 +145,7 @@ namespace NadekoBot.Modules.Gambling return; } - if (amount > 999) + if (amount > 9999) { GetText("slot_maxbet", 999 + CurrencySign); await ReplyErrorLocalized("max_bet_limit", 999 + CurrencySign).ConfigureAwait(false); diff --git a/src/NadekoBot/Services/Impl/ImagesService.cs b/src/NadekoBot/Services/Impl/ImagesService.cs index 1b37e976..97e1c129 100644 --- a/src/NadekoBot/Services/Impl/ImagesService.cs +++ b/src/NadekoBot/Services/Impl/ImagesService.cs @@ -21,7 +21,7 @@ namespace NadekoBot.Services.Impl private const string _currencyImagesPath = _basePath + "currency"; private const string _diceImagesPath = _basePath + "dice"; - private const string _slotBackgroundPath = _basePath + "slots/background.png"; + private const string _slotBackgroundPath = _basePath + "slots/background2.png"; private const string _slotNumbersPath = _basePath + "slots/numbers/"; private const string _slotEmojisPath = _basePath + "slots/emojis/"; diff --git a/src/NadekoBot/data/images/slots/background2.png b/src/NadekoBot/data/images/slots/background2.png new file mode 100644 index 0000000000000000000000000000000000000000..5be870f26397fda00c27a240bb0e218be04b8632 GIT binary patch literal 103813 zcmafaRajh2(=D#S9fAgT*Wfz1ySrO(hu{QvcXubaYjAgh1c%_xoFVV`U!RN7{p{V{ z)m>Gqs#ZlP%1a_4;3I&6fgu5;#FW9nAZS1@YB(6sKULG-9iR{JZ_1J)U^P>pk3m16 zEQIBR!NBTc5nqjq^Ti1oxCB$hc;{-wnB9s=k zn-hEuz|mc2V{>y;PZabn3I&h~3h_8G*v`2~Kgr1%(H^fRutc(Ej^A3|mfQ_ZsH6G*tiRy&4>E=Cf z9EsL-e59x)uk={*z~<_f=ikKz3QL1G??c0n;o*Ig)QU}CCGX4K#eCR65 z_s2^WHUCE9C36MB3rV^Bm0BPFznRrSuHgY0l8;q$qI}uIL~12@lAmtB#6s+T2=7o$ zl<)VjstEfgt0a<_Z_NzwU9HpfzZqF$tR26nyLGdbB_Z;&j8Nb54$T4a!&77bZLGYV z5Z?x{#93$l%~>`?zfqS~ZfIik-*iS&X5{Y)Xtj)cCRi}M&Lhhl!?gd+#TNct_eDim z+am^R#zs@N_`8SJe+$$^IM;}OG388d6=+&f504y2*`@gNZ*xr;n*>9?pTWp2kJnS& zwi};>y_Egm1!D2$-Rca+WEFy$(@fFgZjZ75i3{pnkY%V5FrVyfjp3DDc(5rdIx2LEdqs!@I)6PTOg8daJgwF_g5D*Y@!*lidZ@Ys*dneJU z_HS;TdNVPOfh98gWlEa2s;{?Ry>Dm^SpSWT(u86w#Mfsm=RT^mciebbRB>{*sD^nt zExF6^Pdg6J1Kj*1gLC3c;u7YTPrlL#VI{Bs-?dnj^GAFoPhZL)uJF!Rh^zV2?^~7n zyVWnEH{xMAz}3MTjR{ISucr6wQv2w$vojBBPSCKOb~Eyqohv{mYm&?QV`*tKGb|dK z=B|T~ty)!Df2OT&L2^|Vye7ZH-xYip-Gc*6X<0pgWU*`4pUzVK3S+ozH*fgb$N4fi zJ~sF!EacwPz>zNU_$wnlx?sA5pD<~8MT7707q96*5v_kw0HPiG*?OI?Lye0{(#hQ_ zI1cLWXQwXLY#lW~ikd0V8O;(TYieAlYXLftC)cjTV@Zec%$&*)eI3UEHqa;>wE!hM zqy4#=o7qfXv!FB!7Xli%jV>b3hTS%M(ELAiE=v%-De*;tmcqCLC~>`iTq#$V0$lk@ z0sYncUBt1ynM09zNarc6$SE^N(01+H!cItKSrxfW3!%qWmFu*@VD85`IgEuk-=_>e zelli9YGCX1Xt-y+Renr(3hqarkS%t2Q2*D5Coyz=Vx3c|Mw-@Fa3lJZwWMI3^ zqNPbQuM5_0C{b0kqTgB)WWD6H->j5*$j4x;UH3cEGPN!6fMyqR%6fiTI}3HY2U68c ze~5?+YptFEbKO0vuPKalWLQJkS|Wuxk~4WXmBPHbRzh4nWED*Sy*a-K%u7CXaQ#_* zra*kz-_m^9dp81cnQl;q1Ppp^%c-4ey7WWj4$Mvb{;6)Z^%*6b&Iq|*o7?AGLm!LS zuM({=S4YP<58uCBC3+^MYQ#|~h)X_{ER4@YU-Y4oUKDictrkiSQ~&q0#5}?^#d`kMw9;tkA6xLoHEGXIZ1U6IbbpPwE&kRZq&`|V!taG zYP#-mcKKsy{I`){c0Ipi6Dq968TQNo<*1P_yzrl*KGa3{H^x=sovHajWbQB6NVN;m z2_Nm=M2l%837lEGo+4mZ@+?EN&RtW7%e>m@5K`%d(malM?;Kgpzk}b7Y}W&fax+&C z*-v9L3nbSqHfv#MfQ4OY`el2?G|ybhY$&(?wN7^oY)PIE?}fjswQ^ABZE1GaZy~>Q zT0dMP2(@PiZm!AhQhwL?!zM4dT2d|P+YT^5kdBL#x{zX z0~bV<`C|R)$!=yZtS9g>)d~}vzu8Iv$0iw5HW^R)MjykmgL>Fy{af~s5PX*e^6t6c zspY2c3JmA3m;E6EtX$yATkZd5Xl4o9B5B*h(4Q6Ao#OUKiqyd}67FT1oegS5bpo0! z#Tr6AU6-!Zdxz<&w;zs_nkMe-1tp|sG4BCadqd|qYPQTZ_Bl+!V97c_u_CkeoL^7( z*T;#5i^A!7QLF3*z8#=+ZHKWpo?bcZCJ3@OL4LzncW7iO&0tz;G}SI_YLcz+KS{IZVJ$Jm9T1~{u53bec+wfkt8c7PW62lTvtW9_ z!~wYs`OWC9-oB68`{!92T5NL>DGvDyPY(2Ne0B$s3B2$G&8RpyMYR7iTJ`9#`rvumPCGV}1w(pNWxiiG~dQ?XMIWg=`_#DX65u{J)nMlNc_Whd4cTx9^{A>qG*v7 zyqJ;giYs}oYioXHM$7TmhUJ$wkE@QqI#z2f?zzamgb&qQZX^U+a>?0X?*h($tXCEE zLVvMo{ItAPsWs?aZKoL0P+?> zu)oGx_JD-IKrO$bg`*jAvHC&FqYp2_X7h~^+eSlXtL)-6j{()G?-!9qh=PUODl-O$Z+K;uXKbsY*5U|^~NQ&}#C(gzBU+W$E zr?)%WArQENg^X-jJ@YsvYlpdg>Kf9^6bB%A@@V#(pbsjP1X{&rIERuH3{O%?y-u(@ z6Yr;UWTR(VZsg*opeQD?n#g-Nd#Tst*`|Fj%99Ghml)1_@JaW0IsH_o`#HDD0c)V6 z!wwh`Y3|lV6Z2#?tMN8k0g#EEE`3mF{_cUL2uPJr)}V-=XnbY$DHS zyn;3u4mfB@|8Sr52dUnuC4ZrzN+@%^r@!r{h-&Sb0%3)yo+sCxHkmQ2^j)R#pXYy6 z-u4_sTQv88iz_v!I7HojyV&qrU9SFhZQ&m(O(?g1|McD)ArmxWhNh+n6PZSaV zcIAy`;e{kLm1;;d7I;b;HuMr%(mvWyRHttN%4YIid1Yvcl=YL^vjCiM_}i z0iX03M3>RF8_+F+a*;QexOTrNT3D{kyaSt0cwHuE*)%2=oG*K8%L}{ad8(-12kA4K zFRzJwdj_k~8my+3YKlOZN&_(|epQC6q)@oFs)8&Lrz*z5(!!w9D3uy<+h#E7+w9d? zgZ}Tj{VhNEs!zQYDYEPk7^?m;Gaao&9$A({eZc$Aea zjgVzwaF2yE1FYUWZgpTY@g09>XINo@27+TbaZ~Dz;ji5--^+h|x^`0Y`M;(*evIO-r znrI~MgqR!%;HDi!K};xFnpQog@~)KJ98C1Lb7)zzVyf^fvT7EK!`FPTSA88fOE4}- zsyp&{uI1%^FQA&9Ip#tq{@y;tH@S9e@4i!Hj)3C<8?5fXnP02bt>frr!C)XdG96Oz z5e_#`xAuI(9m+VGJqB*LFW6WGXRO{`L}bzL=EHsF@%`BZINh?V`&=k$Ch2;;JJ~QS z=;mMS2jSA{FBv;v*%qa}iKkNH<>(feuaqHZ4JI8+BVSjy)8>($+KDtzHJk)N;Sp*b zN#C9uFTcT)E zw*Jzl(q*mFcN?5buhWeGGUFT;ai+{~+p1UjiVoc6hw4}c>HEST5_d%OwLSw_ijz#0 zK493iuASCvLlJ&F4eA`3n#S)yNs2UhnZe`o>qAWhsEl>;?Z7|DhIoV3_3(XDmEWudVZ1N z9wh*MuHtZJI#gbF#{VkgTxI!^o7--)W}q@Ar_1?wKT@g`&UC;=UfoeDuAYgP2)ZVo z2$^w&f?--5E>aNt%_D&{OcKtURXJ@UnRi^oGNyG#q;P2vGEU?tvJhG5cY+8GYBcH2 zV^6v_hopUSs)Wb|sa@ASe1H@ukv1U#fx?`sa~UpT{jjINC|gw%jek_3T4F{LW?c3Q zm{tr>(&xt(oT9_X5FJ=4b%6I$k=-=WuJHi9{_DjYQb*ID;)&Lcip=+!(`a6I5O4^c zYcd(}-|)W8`W4#k@^-%T2W5w$puMuCp$g|6t?%%vTiyqHe~ZCDf}4~ z2b+xJR@dnYLZoCuq{KPIiS*C3-L04peF zH+b6c*RNvz-3s$ri@}AZ)(sz4*>VOGhEeFC897Z&Ww|obPc}kwi}AB#3#Q_IoXl_F zlIobjY{{S6^@^cKafg@;5^Sc3Bz%<|J6C7(gMuL7A2^7NZi6lasb-=~VLgtX{+2yG zNs;u!A6g$h{+8)`*DueKf-t~UDH&#Myr5b`B7S$@HMx_RS*Wp~PV0mONl1oOvFIDvI;VqEGgiNo~V#8ON#<0Yal zuF6HKOsi9tYR&&a&pPOeQ;W4*co$mtxCx2^BqPI^9-mx}_AGw^-m{@ATSB5L5dpvP zSMMz87(scptTl^YKZ>U;1Kfys?=~_b2b;xja$jykbAJUU;xzy9dJJZ_vg`NZ9f*tg zwq{{^fUBx#h{f%4eSMXIzA~$}T};?Cvo5R^gd!^9jDNmjjl7&(67)%q$rBbg_oVOr zhn$trY{1@4BhJv^q>heWkHn6uwR{^(@4bz3JM*LpCP7tm!Qf+Cl*~e(YsAex$w9hP z(N~Jd4U}s#yayL0f#D>~4MAZ5OPn;ZG?q=VvWg-J99r!dyk^1QvH6DdC@y~r0ep}F zcEw|jmrH2%nt1>Em>nKv#%{CzQVK>nXZsSExO!`om}LjbV~kL;TP+qs(o>Iykoc)B zdmOe3@5xtf`YGDdMlgrWRq0)7?Ox+QwG7MvZ{ZPCvL!w5U&WhC4Wu@bwwG~bho(jN zIv&c7tnlzdD6~ekBavrO!=3xC=&~(kjvhF8Ci{T{sEUeE6n~6z;xM4s*`Qrs|IkvG zSw^2VujG=BPfP&hlZH{Cl~X`E%25fEWAtA{$b_cQtY;?4}z3Tn#F_?#C-12w(I`aS_8T5oTwTsk$Xwvi2WwJ zQOc|hIf~-D@aLwN9bT|r=K@~#a@(_P{>1aB-^#G{hT_ zDT>VzVroJIng{#pgpMzK(-yV#a1{nmztM!!5I zmHmke5iz$5=?id$-?Zo9SD;;FLX8UyzCl0*X2)34+UeH zz;7Ki(bv?*yJOd^)?{A`&-Inqd7p+{&0q2gqb27>y5eP74h?Rf>|g6cEZq!>@tWE`hOU?vS3jY>A#cqI~lKy*8n-IEss#dVclQk zaeIKPtvy2TGWQ<}YwRXD+kmSwhB$@k_sUnrgP6y~soBP=qOleNS5k4?(E+1F;6;1X zG2BNq>&FfEgOB)uMK4eSVKXgUp$C00~Y<@+#l^`YK8kCNyn@noKPX6^u#cC%3;t6}tB9FW zsw8jcav$?NPdD~;1e$zsIguR3Ght^PCu03rbboDYa`5ShXxIA*6aMG7bSPax8Rv$% z;2Fb%X0yNq2$m!PP`QSkqPXOkXhVU+jG0n^=kO35gOG}lM)g^N!|K{ybKwm)3U@y*z{5a5c}r9W;(gaweF zHJwp|G}=;BL|rwdW@A8a2G@l)QBK^WuM!E38K7cjuTV=B1~Lk;x}qm}a(iBdE}cG| zCG%k!xEwv@POd$?UA%Hwq^BR9E%HtOWI_O~2{-?ve$b1Dl?Q21Z&mwO%Xt2x5Za*m z&ucveHqhHI~}{pFcJDHUDpb{ zi4iSrGOzE*@l%sK^SaygehvDi8Y)$O-$hsw-t$p(jKMDp`ixh2%x!q>u>Nho&|4N0 zcCN}DkKM1Qt^HtTn4tU~1ifGV6aQ4(a+~}*_PguX!Ohi90q1pj%vIFr%Ob+w?uXxXT`1=a=x-%2M| zP9rV8UB50)c~JdV>XAeOB_1gb4!dLc{?u-eMP+wgoM{P5erFiUP3zrt_eQ}7zGpDN z!fZI+ukB!=p5UP+dgRh#4%G$c6>2=k_9}x@9IxIO2dVyc6bNplgQ7XeckC5}>ZY)5 zb96&0zsTl)mGUxgnXS|3_@M^P3F{)S=x8ZP!Toplvo!>AQAB=UJ2g>7mg*l$#3wmg zee8tZIA$j~o}*Wh{(c5!MG}hXo8#t1g%e5|nq;*_7({Z3D0R|eQ?rc$q6NR3j>o}0KG!n0#yGCD5syh;)$0w(g03NU3aEsY{(J5qYx z;d%^YXd{n6+>-z6239@?_iQ)YsMQ}0DyA*n3mnWG>Ew9nW~HAThTe53t2QM7lI_mecikV`+f*&^4HCg z!45)s*6b)H1wkSrfaC}P>QM5-Za+BotkC(gg76NjvILe2EyyYp*&W29!8ndjKkbg( zuGrLkzV|nDAm=C^7Wk>#t>y-JGs+b<=(ZnUcLF+c7zWios*NT;Lf!av>dVJpVso63 zpX9M?wiq)NgxW!ASd=u%cUizYNn%jOWKCf?Z+o_ARj9)uiKVyovsMkBlBZU>`c{sIHBTIw!(AtTP9RU za9JpqNhCe{SJ{@D;)Kk~8d*?S%B7(!q3MWH<&?!yR1^@t5_}fs8OkxyRu9N`dRr-H4vRD+N3Dx}DjieXiFjFhfKM#8555)03in4%BO|D2hQ8D@W=d3^Dwd=Qx_8E{r1EOkX6b>XAzU|f&m~RktCzc zOWid}R*Z{^nYKCFCH2;GF~-EKsQH;h?3-5-d;2)I=b4uAbgQeXTKcMygNzPT@bSr_ z6bV;k{c+pP^5s?uLTMkaBez!Vw(H}k0?WU)-N-u*i|+di9Icx^<4!r!8$J*d-7jW_ z3Qn#cRi!it5fUcdo=Q87WqZLm;U2%z{H`}(W}|K5uM7wScu<7R6&90o7agS`1XrS% zWT=WHPEN~M{`#y}dxnAIu(8_qGTKt!Q=7fiom%L-r_O)Qy!Lt>wsrZ%x@@AiKASlq z)C_VeK?-Ra;j<>`@7XJng)nVcMGQr$yf&eTUN=LmpgTBhI8B|nej-;l=4v&JH0wYG zBwmTE%Ho|?o(JN%{URu3?OP!=qd0Qn0cA7~*L;tBIob zP>Ws{#7(Gt8sDqh!9BR5ydMF(-`el_RO0eQoqpeLzvUaNiES7c?0?1V&nlkVQx}(R zL|=;+Ipy`+-bE_ZH=6Wnjil(90?92??c4GOlB}qXHdNReXs7jD`> zd|QE7ZiL_Z+%DUHyKyyi)d9?1$!09)U^8(i~! zNE&T}*O8Rpbz9F<#UCQ3ixW*J$R%0-gqasz!UE;aPJyW;U8g`Qyhl&|2H!Q@YifRZ zO+h*x|8ZE-VMVCjL24pwT`C&w2sNpN;Of^2h|27Y+GsH;583D6^BUNgJw8^qC41a4 zIX}@C&2}EQt(CMqOY`-%6+&gxI-VaxPNC<1(glWC-E5g)$?@GYvdB!P))EXI9_{lkpY(cy#bd%j+E#%7y$$TO*uIYO-@n|{R}N?C=@n|0T8Tj zZ2)2$t0xaNJqYpus{8_lDO)Dexm4lka6)EBIQZcLsZOJ@0BP?t^4c) zc-~G9C|PYs&O3uoN(#CBwe_Dk3VLI*e&Ta^{5oUd%z*KNRUg@gi6L&Zp70aw*$J06 z!HfBw*LC>_-C(To?r*(Sqi}iZ&L2`_fu8n< z$NRv|Gxm2Pp^~nm?xHR8Vj+9H400O%cs#8S?g~EB5&1XbeKaPZB045EgY1FOs&LqQ zyAX^vwThzb?yfOl)}$gTVq8=%Xwdp%%g+m&K$Zm>3R($T0;5kw4h!$0F>LJFX<)3Y z4fXso-i&kSnTPfIbQ=1=)ayIS*ivjaS(tXymzT^Yvh{6;5~?jp`2-9d&V)WBK@!C0 z2a+e+?ux&J%9UN;QEl={KoZidmt3+gg~2@7l$^5HZM_*~`iVl6j;W$AUz;E1;JCWv zJK}&uAn5QbRq)Qr)R^>_yCKqRy9v->_?K>r^Xb+e%NDp1Rwyf}j8OXZEh2XRq!FHW z*Lgs08~=yR(iCCq*ut0vx5U>H36;xom(;y2Rbs;dieO<@(?E`cISWDsOC&h>9Sdsf zPLhGVqodMB6_~_{bv%)@4MY+-Cx1uMxhe!9bcq>qPG^ytwxM007d5vgf#C^U#7=_B zyp*$a!_F`3ahDinR<;CykW^ca+L68+V?<=+OidU~7JnmELf1{{xbpViOSMXt)FliM zFw9v-r70KVvmOY=per8aX8;gMt)|LJJWSZk^`%l#mS2x0zq*1aA6-uUb$my_)9ByR zWCSo{~47NeHVHF+HlQYJy^{WK8IL6)GmP~zonSmPQbk;j%bAYA8pP9eg(h?vypvFWd3+H&W!#s}{mn{Y zwv4l#xDrk+tP~LyMU^U_JKKR1K6;IqADI9_(vWl+F}ag(LJ`bT?sf1eD?o|l;%d=c9xeQ zuWqNvv(jhgQMz}|d3oO8RR+>WJgbBep}}m#P){lB{%zf#L;Q7Uxxf@p40`U$-Xy@TqA) z?TLY$jx$(yqe)j$eIcbW0mvNX@eFe$ciC&aPk<_$gT0Yj9lOSV5RtzRzvrKTyDu!k z{*uJa2@EnFwy`$@%wja`4b+;BhqJ(Ux#%e>ld!PVtI{ODgy-d;u|78J5J?-2Rf!Z( zrcD`@9xn(e5cP7Pu({=(8}V5+=aB07knr=@&f*oS`LGeP}b*O z(HqqE!{ixFC)by76PR52&`U@hN%Q;xa$!t7uC!OTh-mL9(F^YPP*&*=x5}fX5|4=o z1LuJ4SfKRt!V42?=exmZ@H5hA6$~-Fe5nk+kNh9@$Fv`n2DzV}kN6ur6cx}~s?5zh@6JpejrAeT(&+P{Ts!h~Re2>h!n@Dk>^Mh>R>vt!<+qR3y_>JOqqy7pO`n z1+9s5(2&F;=EiyRJZm{5_f}wKCjDvmxH7H|`Z4ne;*+Ev-;h)$o5;j{VrHhVum#0M zHG;0hOO@hL*#6&rxh`iO!d3<`SLKgAd&&-h7xndsfmq0S$~4x# z?e#JtD?ACTbgS&OI86hb^Lz4gzx%i(s?fNKPM4<#GX;Q8rwzv4JMs zT`%LFo$u)Td!oqA&&k2I+X_Lg7Zg{AHE_93RRjd=q!{lHUsxZQa;>H%Y5XcV;a^6Y z$HvA;soXEg%4yn9BQKMaGqsAvl_fsGCmE>p`m#Yk5>Swr66QyackC8Y1Y`(+?4GVv z@g1)2XTsdvEb-b{j+z-W$rrIC{^IWayKNe8AXHY5EYbWP zxRRuN;<+l#Pkxur@CH94g6Z{Sd`f`w_Z;tl^`D|zS_^e}$H1W%)8(^>pqmQWbZVL; zErFfN-QVY5_6?1ME$~r4%R4u?%yXAWy?2SRw#|l-3ozzVyRF?`OoSp6{Gsm(AzGgW*GNJx(9d}iBYtr zmWY`Pdqzhn)F8(KG)0LSn*Tnycb|T3+p2@V$p%3h=f{=~2UA5&RnjWv@XnwD#3)is z2eD=&1hiSRtw1BD+6^~_ZSUJNyRdRZ4N^3n`54i6rHvAz>UN~_ici@ioc@ole=(h~ z{(10;=j^aM5#Ajt7QZQ0yU82}UgWg6teV_u2v0`JUs~}qyB070SQ=_(qmMj%6o_z9 z`Lab|0yNftyqCsQtn=P0t$+XOL9b|PM^C@8EeEPfvPM#_o7tJ z&6jWur}GX_bmKJ&+HsJRYool6gv7pb_C#OBV3a}hl>xA8?o1~aGbm^<2kwp|xzfJF zk;#dXqR+I_@UGpmDbb(B&@mE6%NZd}M<~XUfG?UL3we6VMd>XtL&KZ^Ww%B_gw&OL zOBDTD1MkG|AM_QSL6_T{o2#)mgESwc{bX`Ii%>Z{qJZtB-suopg2ir9w8kOHU(}ViDGMYY_|$1 zn%!g-siPwZHC{eyew1%kJtBM_mr+zwvClvNrMo?qShEn|C$BmFSX2ZK`O~moMUqe9 za(?C5V)@PJ7@^K+3QZxv$*9KK1%;kk8knwHaT^kRa-Ee%Cz&!u3Q#f%5*({$nKv78 zIZnI`0Uo{{u(9qk5ywXua8hLwuv6$8G*Mazri782cuA3sFK1Rc;*w{5&zn&)Og1jv zG92r7N0%-ZqjBH3^VR(XegNCU0$m%RsA^r)z4u#C$!9?y>+(l#^I4qo@o)!=)5W;V zE-%ORfx;&Kq|Q%@iA}EXeSSvFB=%sF+;*2nFHmk&KU(|l9q=#y-;)2sxXGUS6;F;4r1vRp@}6-`hT04m`^Ce@@&`0GmbmreUkDW}jz>I}xk& zdR-i6tP4-(R&-7Z3tK>=smN%+P(j6`wnywNNRe^-QYCQwGUh$FJSnHBXc*1C(H=Ep zMf_R<3GyUCXYU2YEnl`5^59p6#Gf;hA-CPh>+9=9SlNTW&?UnIh2BmkjFjrhDbi^z zBVFaNsL_~+EaEGiqpx>*>@)8@82z95BPLeeT$RIa{m|Q~8DE%konLbL zn9p0u(HE3f(6L%Jd6X!EM*SB*JK%sqWL=DPaqu6=4(%R@xhCk!6*}(3_k4PCHV_W$ zHv7CB&|qSNlcXV}M_>sp^|qVtBCq7I zDS-_Zv7^6g&O@wns=rylAxMjekkK$QQXaOW%(-n;^**`$^dj=8UyQHfC;SXORJHJerk?JB8JuKS4?cj_Z2R=R&Rjpwcc(J&s9T>4<4(lQjM zHQls9g(neE(~PHQa;m`*6sRD}u4h6+_`=(a@+q1Y%e@vlW~~t<6FChQ8z6%};Ta}A zR+vmN0{W0#P7iOfRfqoh@kz6nJxHNd4jmtm=6EymAiF?xcC)J~T@YQlzj#$CbDxt>$^^AsaTDlRf+U1_1{RjS!v_d0-YJx>Wyg%-Loq zM(V;1BTb+Z<4E8^d%Bgq!6@OivG^rWa>1^fW<2gp8jIV5Fa^h{_yp~R-RAcY>{e35d=}$_ zRd^(^61#}msY(UjQ-XbO=prni8x7@FnVw4?Yd2|$2tjDh7mHB z98+kMWb|T^21ze z3MmdUN4_bkKOG;E-(C^FnDffm)GtfmK{=DFVbRuo)?^M%to|(KE>~r{we)c zt3+!RCg18m>sRDRpDJhvAj5B^n*FAcaJ0P~S5}S)_*GF&?sW~(7m42CM!++(5p(v` zKtVG#frApaMXPD1+Cq$<|1Cj0#emvp2A=;-6v`}7O*(0Jocc!_j4}kbNiS_6FLwz< z$gqJb%*4b*rCuk5>C#u7nV-NigSad8l?aGOc_dtZo36GBiq0Fk5pYpAVu2S;2Cg`$ zl1~=&+U`A0nfio7+aTif6fr?=@88$gp#Bp%@0jf1WGE$G6`U%0b#9Xuw7#AIgO5LU^JV}dUjANgPX(i z^2NnOLT;#zqztX30(v7(koXJ?;+eZ^|P;N%$ zXL%vS2cM#H!%tJIgQqJ`ILIahttISZbH!tnhM=So_WMgSsPRFGWod-|h|Nyd^f@I4 zP4(}koJ9qijz0X`HffGuVatNBepnGJvBdBHvA`EhE);x|9*>GD4^pn^=2s#k>kpPE z7J5>VpY4kj#?n)RE^aFlyA&8u&b#-a?sHpZwonmzf&tX`u}Q?9LR`Ow$2PCB+igA! zfWUYMZlnE%^Oau=HQ^N%XQ9zVH*mH{E_P{h?H<3=aB)eBoZs~78l~EP)v6caUvk^C z!*ZiSVg7*NVMB7v8${Avbv^nOHFmS?5uMhQXFEOn&GayTK4{>}E2HL&l_4$6JOsL< ziyCLU^bT&+XiiW+RsTW|zAYI8HA9+o?~w{T0(7Wk@TqGrmTEe8hgEYN0Tf)}0y2My z{AX-*0NT%|ClryQPf5vNh?`05<<`-2mo@>8)4%u6Ebu8PEcdX_-M*KL+%|~q=|q%M zi#^o6RCAQmQz$e#j|SGR!;duO5;aa73dZM!x(&WeEbZTpWYD*dmUs&W>!Vbxl-Y;H z_o8MGA*#3}V9+DdO9%uS^>z3i2Q{9K1Gvfkh&ncMkQi&sg+3jIQ7T zzX&W*&VtZ1j4I2DNHRG;tX9g-=*o3&JMuB*d)3lo(YM2%^F3x)wt}!hJ;aT>+sgL} z(QT()Ymn11;YB(>1CD97jB^Dtt>5|ipH-RlmCYN&r`3#2`BJ;Q)0gZ|##!GQN(V;o z8!1uZiW+lsNb1Q#i%E=Bxb?%~$wx1^4jOeJTk$$q#I^aZN-HYA`qfi`cS)iG8NW;I zH$`=HpS2YlV(Yl zv{3rsGe`V4V0@qSa%cbsht4*9k-2H{ly3b~<-_@zYN=@+RMYAC-}gZtx==z;y474) z**cmd;D{&5{Y22MtSv$#NUs)6{z5>wL2005Q&Qh&wdA4nqoe824hH(V`|0QQXi0TD z!DL8)7x#^Zop1N)-{Zr*!>Yf)_tw6>ZPi*I_MPf>WWA=#$0v*7Ut7{Um=p3NQX~$c zs>Lg)pzcOf`Q~v?Pk0}LUt)oIJ9!PrsQt-CV-a$)lxoG#fF%;CSOdLss~4Fgzv6|5 z5ege=3_kQ33v&2$<}fHeISK*6S4yADjWQ0NXA_Ht*4fyiS9pGn_Uad&WAeA0;eJT} zjI=bVuD8YRuV2)LLiRn~DsnKlOS8M1^ouR26@v+75>hhqnuAHMh!XablQk@@zm&V| z{xxyFfyb;e)%02qU`06mvukOiTT>JwQNa(HbEczgze>)0tQF8C^G7ZPLv3#6GB?TMJP})jc}sF4VB-sr4}bd&M*0WU6C8R z1D!24xd60Bpz6~py}k$|`g0GtBC|;0E>tc7N8Dc&H2u&dt^J-4b`OyCQ%*W4vjyrg z!obL-ztKwQRmH+&6dkdH(}c#UT63;u)D+Wcvb^GQsmse=4(`8p4eMV2;7lFb73S;3 z*4At-VdX-`sNm@1;8X@BErU`!3vA$duN__Ux0y|?z{a+dOypm`E`Q{7KSqV8c@#cP z=NFY@(U=B)E14tS8EZTgdG_YmVfqpxGe8^&O-P=3&OyrOTa;4K1 zarQ2llb?(5CO6AOfI4BuVNn_o*@E52<`W( z1Ty%FF9R%ENE?#C9k}n}WhS@?Uxb#B8nK%s3CsZHV%L5NDZVxh7314FH z^E@|BVFcaqSkoAqnL(Um_GgaV>)(!B61;1%Yk5t`pK{xFBHLC-xT1boCT?|P_chFFIJKE#&JMr$L$MM%5EcvgjK&m zviVDC%0a*7%tlx6B`lGrtz97^U_3~K#{%ghPwMM?CBu;NCFVGbo%<0GsQN1)pmmWn zNzi5?DH5`+g<1GHyShmYn|VN~*w+acR3q0(tyDz?_<{sSS?jy}y0cxRW$*99QyEIN zA1!IQcf13Kf^I+yUdOqNa>KE~Ua5~(y)DW=jN6!uEzl5-WVV|okCaaJN;{sH%&z$; ze~wpSyjDXuA3li_bkevGeSI{T(*5ZxhS16Z!`qNi;AM=ieEXS*;?p7`M9^KxJ258X zbR~FWcf!o5r80oesCh~Ym7Eh2CJPWfMl249h>5`boCW?lR+Mb-788SGY}~gj9m1HF zvXLZ_g>|L@elw198#6Be-y7yr;AajeSyo;OZe&>`(gZkY#N(^4n=QcoMftapTgzGF z+wJgJFTMTjw~_xx(pfN6^?Y5}pph<>hD$d}cXMej-7VeSEnS!Hx^yF*QqtX_NJ)41 zdw&1-E6h2wXJ+kZtvzYo=%hRQ%hu}#C)JTVt2v^P4}AnBLVR|jrc7_LdUG>FtK&|u zQplxO*PadnU-+7mjWB_|=&|*Y&GlvRZNBn@cEDT16|S#l@AIAt^F`M80lnxM3w)d&d|D`RssFY$f~R$VL`g{VJia+>YzkWy%}&n01t zy_0}5`t|)u@Js-^W`L#y8U9L6SUP*IqH%Xd z#d&0#zn-H4o~daE`IQ@eGG+iJvd1BGBT2cgu4pnORtMJZw$cCT@)NcD9Du~6DX9tHkL!4j zf{6>y%@L+NFsro3i~Aln&V^fE38(U9@#JGp*IOl-qQC&Sq%CI+>m24@7s^g^IVO-*zMBIKGGV+BGe3#Ed;uUhW1MhZ1s*p{POu#$wied-4Z;QRAl)ufa)1sn_ zT3%e`6Bo+R*j9Ovd1fMAz{I68F_l%NK(9vlYJXi87(=2c?K2_BY}B=F!r+9T?jGi% zlv^QXlvJ9ryM0O83U8KU<}Xfb$<}nsKK3l`_lFXyafEii_sUWuuv-&|fwSK%G}ygs z^L<^gxx!|Q0Pd~&)XYH5x5pXfI>qvm(o8UCUdD{W6n0El&MRDRc?@6Z!&H&_AD+it z{o~3l>j97|O8w+Y-sX|zeF^00E>>nN_Ken221U!G8um|Q+-v#c-n9v98HsE*&n3al zPpo`)yiL)8w`*^!sMa9ZiOpo5BS0aqCaf;y38KrI-K{}sg#g`^Gqk_~Ssr*q%ueS- z`i$>BP*D8tc7Nz$y>}IY(;@BRviFhC$&%J6CnU7xpG!0D!&t|f`_)tV_wKn)y1Y>9 zruOhKx;GLX;KQ80|1aalYgs$)Q<#RJr2>=g<;_L>;31NQ^wYiN3M%=PYa4RrYL%ar z{O-%ep#WfLy+A>`_c2c{FR{;Dl>xn&IE9>5&7}MiR3QFAo>+Wv^tVZp!VhV|VpXSi zVw6Lp=2v{l=&KON%OojQqc#Bfmva5x2Et0%SYb6FdcCjU3Qf9!UKo|Hb^4|zNqQve z)~xnljyXE*+&R{NJM;^}eBm$W&cjzVv`Df-Pn@Y|H{z8VkunWOUDUH;6byG(($-Zf z?r~fx=p0{h_p~2w%k~zd+>((4(-LIHLmCdJ(g&(|uG-w@i-Ti zYmG9WMpOU{dviprZx(0Xbl;U6fR8ZYcQ<_mi4(FLRWtBf1lUd*v|j6P-TZ#h&@ECp z8)tbwJQeVo=$qRomb1_6WjZ87HNb6*%`0z7!j&?M|4Yd=oR|lKywrxPrY=?@)_E#w zE}fYip$Rg}C>V4}NG-Mb5Vo9D=LnW(Hx)rspk$dTy@I-H@;{1A*9#*nMs6FKCQ(Q+ zF%0zFmZye3LUVE|O9JLVc&cTs&JVCWnD9u!Gx+*Pn5f!bS{hQl?J0S^;m)^>^nd|) z%bVmB98E3Ea=XeVj1!K9GH`mJ!Hlc~d+Qynq5RaJ_=+LN9v54;;oIP!fZ9@H6-Lhp zy8X!;;_lkU(VuKJ73vdw0>s6!MUzcOh6yyKxmzw=j>LdG-89|edfRhWCLH#~rniG| zb5T7o3!$R<#GmncJxz*~XXiGc4I0z5J2b2Z5IQLReP2-i0T%f1HEhOOFIwvc)$Q2{ zk8?}xWd{o6iqq0W1O?E;p(V)r#qolD!J(HcB(j`Npb{FSq_J~_E?ly+xx>Ps8Sbjw zs9AN{Bpz?Fy<)53c=&luo{|0ICoQo#Wu{>?bB&E;I6TI|3K; znh=>nAMiYm7Y6QQ?{#2ry~i0l*{N~DDll$Y}&B)jO_RsPa;TyBMBeT z;pk|dh%*u~IN0%rMrGIW$t7m~1xLc;UuAf;hOEIc-IYVN&YCppoQuZ;%Jk*dmN|Cj zKMrL!GsRNYj%xo~pi=os766GsM(h12Fn9s@14)+)C1;yD`Sd!ss)_OPnU!)ARBE~= zo<1Uz+irNVvU{xiKp&;4wDhSkH%3L9jjEYJXmu8uBIAJH+mD=$nRUR46=Gf^fWi3(Gkz3Fvqz-V)aAsy# z(Ntca%#4;>oT5mgB1KV@wpkhJW9dKq>PuylsAw4Zo9>d;b{23qWZm=QRknMY5@2aC zlj5@!+^f3mk!@&ze&`usVtGV}$$mbhS$BOQa8%)ZKQi~X&iR{O#|fnL+p)-!Z-t$h zdw7L2ukkUbhNZ-;_!A^NtaMml2Hm( z2)NUZaUF$-UfJSg=6W@#mvZBuS-V9p{mO7|r;pyp^Y@C~8B82$2N5y8jd+Qqe{R>K zoh@#wcPOZxeno(y+)}mb=O9wzSLoN|@^BNi(D^bm{HJXFz!p*AkK3iEB`pQAAlL6O z1(&8@3Aue6Pa+>VjZVzIemJANFM2I~-dt?@n?3P7NMy{=*;`gSSPS0OH`|&uo8tB+ zsCnaBqxya9NVg|dcw7-4WfYB|X2h*i((cLjZ`wI)wuu)_-J^^EJZRjJ&l4+w8TYcn z<0+c|I-Fb!Rq;UneW*XTcJ0qvGXJm{(ziTdkY9?QjIi0WnYq#Rf zSY2E>S!>m_H`P5j6VpEV+vS{IUBUA6yRw@tY?TUt7rtO#ce&>GxY$g%=EJDT`eCyb z?f64I`h>@36El44N@A;+MW4(2df~ke@b`KgKQ*>%1sW;OSH7!4$T_wF2%eW91 z9bcCZ^eDO3mCR^arja8m?w(%}b)G-gVu@n0Jt+KOyd~X97=(`lpU+BdSBJ&jG2vz- zK`x^Im?SIAVbl5MDB7*NQZb*9l#eDu^mX$dI;-GOMgZq`gVFjPX3g)e3O)V!R2`F) zWkgS2S=5D2=Z&CWkWs@msViQS^tZz$BQ89h z>ND$U3Sjqk5t+hg>1)(O(YDdjf?vfuh_#<_aZ!F$vFDKqiv+5TYx_>4d`wiK;Kbf!%WQ+3Id5K(d+;ChxDaGo`9amWg{2yYH1-KC|%n zk>TO2PS;IQ`bEa;KUtx-0s2zkp4T3KB`2*(-Pd>j&eoH*gkhA?H^>X70XmkbkuWkX zB@&Oi*hp&7lzSt{k#L3>Ekob(>YUTs zSaHAU;S;dDmdE-^**CjoAX5sLSVk>S7k~R`GtG9;A;JeQX1O=Lmjg7BVQS4r70J$< zyF#B<=DP!f)$0OGC-~*c2NK#_$w2A97q-5%?SB&I%zNMWB*dO2Ll&qlCt43^Gkg4y znJ?gB=kcovVht`^^UckTs${Q}(NT(@+ zePN)p5qQY;lH0U0W_Q4wo>y7Xazq$hB>lmH;V0<8r}r-)E5JTIcGnDc|>@oTI zWv;P@i}>N%a&gpgxMg`%vHG_knc-^$>V65!Z~6|G*~Tl*1N_$e-nb}w$_X<7dZSxv z*tNI-T=%C<$H%p;TJ3_*fGfx7Yue4y$P6+6ZG$UJAGe2Dpm!b?&?|L?O|yI@TJ zxD~P`>*nFqLoDD9r0^cLx zzh0l-jmR51U=GVEV)IJeS#r0l?1a4AVdS9Fui5g!*;%nQ*TPK<`IfO;ZD?k+$l{k$ zvVT<<8)-NKm%u->{_?g5#&2L3Q5Pz#b#Z}F>^&8*ZLh?bEZl?iVODN2UDPaUNqaN+g=cCVtUxYS1f;`3QGfk~PNr;SgmmRMM)F{`->!$jQlh zC^6_U=sgqfFF@Cw%D0%AGWjJT#Fh)t7rjc*N(Y zpJ`2~P*PaTg8c9_c=F0vZTtn(bJn_lZgfN%KVbU2?s9R|kC@d>5p86IultIWV`!XD zdfq3<(+5CIHa98=8|(9OM(UgwWmaxKwbrHU#rfkjm%&s1R5rLJB~V(=SE`WyipfOF z394H~se(f1%wz7VsO#Zgkiz+)0fkhR3~4B=_#+V(^qNXbE>}ZcC^PIohB~87k8kY@ z@?zuJAK-W#;+v^JszUCv;vPt?E*tf7bjm2jOR&iew)5=)oR}bUoHEQ3?utEuLVwEa zF8^9)E7aubd8Gwg<3LFD*yH<(X!0j9ii)mRS3}bCbKrHJ#TAF{o2~u>J^W)fS}ymx zR25G1XYWU$=F{Vr9D1yBLC{CboK_zI_FUpg&1^WHek&7vC)*R@I(5gxfUUwlRkHW? z5cy!abaGaMT&B3bX3Iq_3QcYfh$JKB_Uu0brN(Uw(k@3SOzX?Jrs4-%kXk-s<;GCX zo8bioCBKq|fus;{G+6Y+k%~R1(tGpOwJemtUS5%TrTkv;bS}|pFM&bt*7y&rIf@R9 z=*z|w^0W~<-RVck_bnr~o1*v}-EJwG^#F%gH3^Am70FH;+cZ}H^BOWV9hXH#MpJ~_ zfnDth*6sVW^TN0=`lW3HrH!&&F>3uDVb2OB9~SsIZvV34pEG4(yfeO>R-I==l5YFq z{br`Y!z!Z@B~S!9AedHs?gRhi7VO{0R^#keM^_a&Y`AAMpYjmzKO;|&R=`gGS`fzp=RZZKSB|Yix>ZS-d9~o z1>L7th?nbn*g)0C@6v;u>=&@oxcaM>W1&fp_0PDH#n8txWZ0$=N|{fROl&SU(;dy5 zBfZE6VR`Z$o_bSLt0Wv#ZKlEz6v1`3d2uLQsKoLwh|*1nDog@euDh!FZ6s$W!JC9j z+7m`l#yqC3H%Jr_7ehg^s|bZ!kY1eSZ)6A{38Xx!87D%(Mt;W{?&zo(cuDeq_e(No zRE!w|NwG2LpA#|PemiOnz&Ttbe&EC+^#&L>&mY1fHK>cHBgUv~1GTQ}=jI0PwWJCf zb*=Ap3*7{SNOY8cId!`4b_1GhWcGnNxge;b&mVZ;gq2oggO)usUF3 zHYpy6$0PXbQ>0|ZK|+8F-7LviBl%Prqv zS8%ugh!g41hMyNuBV}!suj}QSx`V!OnaQB^kL&F!9THSlfK651ayBrxb*8j{oMeKn>;VO#ZE&nMcbEMEWV;$-O7RzdjT@)i&V zG5n!;=tz-@-Pbz#L;1OX0<^wr3hoH6f;GIW)r5YV zC^`|J#M9Gr2+GiiE6Sylw45A>$Ne51OFHd?_xe1e&778y>0aJpPfk-C>?ebv5 zQ|+7EXFe8uOerlzstP*#S9PhV3{8?b%}1iA+~WDxv)=h#5q*q>b|#ZW4b?W~=VgP> z4y}d3^33C{PADx>rt^==jW)?|J7YB zpG(=-7e4eXdiEqylDs;xa%);NLU-cf+*TK{q3~hU2{#f}w^0_~Z2acaE!J*dmN1^X zwbu1C*XOKnL_|X7_t}7SOLN5Sa`1^=)!2@BRoUt8%8a}qv$7orN|x}={1;sP|tjjr}r2Iaor=RjSv*bo;!-T4}n)pg%(ITB*iC$g@K|3KGo zfe)m<#3g!e*XWf=6xeca(Z~wiFhc|4jeXQr#6P@!jS^E4BJcJ;?TZeEKYW31F$z01d#Bfs8K6MZ)RIR+kp~(j|9&7M!I!Jf z=9USn&Y1@yLM*$g%SR$W%ICu%L7w?0Ph~4idm*7?-!l}XWV|HRpz9@8Q;yM%Y>_ry zzF(lSQ*9A8^&sD@E|MzK;E5`%#nI{ZF_0AE~jd5-kQmax1xf zW7a2F0%#Z!H2?ia(s1#In^eCqekXhfKSNp>bW`nD2%CW;sM2?EVpq2Q@hn{`(~T5t z(BNj?KSbBPZZT`J6pK&%pimI0G3qFf@a%0NAf?en-t1b>DfaUN>B3KN`+6mhw`wwu z`pH^H(eWDpQ&3|rj>;ER${b;BFN8A2A?h8vg#K|cjWKjePgQik_(El4E5#g3+(fJL zHPP}B(`5}NJY0+ppPLV@yS`B!NY`Y{d^hpNw|v@k$PTl#bQ>c7El~Iq3JS9FZz=A>lAzy-HoTKthff(Pi6vd!1xcb_*yIo+ z=%ej~PTj!!WvhWcC3D~mN;rzad#KVcl-+YTy3TH@NAno@8v|?Wb*YFRP*qEW30gNk z#@KKNCKdIU(*rSR3NaLK$ussybv`HSk4mBn!AxCk9_q2i+dqi$qChp(? zc4OVUl4TR~n)rI-a=6l?iYD>!%7VXto_HN>Vq{PoYu%DASOu<#4>|!w*L_a6Mvnt|PkE zvF!=LbWKe9D0@M&(p8#M1tMpT)a7#x;zzrkQrO*o_(LwjcQaaDlA}~aHSZWUl`o5e zf(s`n=5^okaMUjNHpAj8?q}Uv<3db*`ww)gpU6;|o|-}RsoC>6=68c8(h`Ed!-C48 z>^-94WpXze+qsb3g^;+}hEVIR&yD-{MR#q0j50y`0l4;a{TE=<^^|}682-m{zT7;@ zaU8*A`EejVVpou)>G}kba^jKm<367DBpb7w@=ryE2IZK;+ISB>yUIUP7D^hLLj6@b z5=)QhLP}Icsw)^26f#if0qQolo;}W&U5ORvXgk5sBy;LgdXUuxh%)64-tyr7=L{S? zCKljFx*3SMRrgDj#6UFx2vl&&+Roa+Oy0LvMB6!3H~Z7ON?M zdR!)F88locqp>3Hd^)DsgnVCulGIeE4sW7W>B_0PQ3CBTDQeaPI)^%T2=_XJS4=-z zYGaUvcKe4@&r}qg@kBg11>HQcQ=bxaarNUY(i*i%X$w6Svh_9;ey(LF7IeNJh|>#; z9cX9l;{C50hyBeCzYTlUaR>$`4N#e4Jqd~)^8EwH6q;=+NxXLBF8|yYa|9wYu5(lb z%JbGzn^0AF7zt}42X~)McdsoLJ=M(m)411XjN!Y69WMs+6Yz2cA z0{D>gh_fo(1C*$=s@^AW)9H~A5K7duCnAeR&M%bNieU2^uwZO@?=aFuolmPMfjn#f z1>AT^`mm>TAjwlnH1|pW8|wqrZ-_5ne+Mc2RxD@5yI8t-w+*%LJiSn zb9l;bGfW0zE#QaKpI&}3tT>A%Eser?;%0p=?HE_U=m`oB3HmO~-U{TCx!bM)bmk_* ze{qfWBqXO8ukGPpvFi~sU};T(LF_W}hB|)Knq6+`wJNQ<#mt-AtJ}a8TMh>bjN74X zXKNhT&$t)2;u~FKopB1h*5UtpDd*14DQZ7MsRn3hbw8RhTn@k4UKv8Y#;T+XbhnGY zniHR&P?49(*-6~nLxN@z(YRDw9nO6R{gO&p-BlPacAJASj%4<~u)@Jvf72V3rT z`otZc3Q)lMTks_0#XUbc!Zszk4%n?>LHe^m=0k*(1+Nk$Pt#&@$Cm~|WZ9x0 z2R(?CfiB4tG({gmz<7HZ!s6=(Rga{vbGCb`)s;Xg9+P9-{vn?XhQeD1wMM>`?7RI(lF0Xh%NhH}R*xVqPE`y;#m8@~gq{Y93H(%)&HuL$d1X%qYTPs0fL`Z!jKZBR>zp6C~lI;DvR`?+wWhkOu z-f2?Hlz0vzHL|kc45vb@W=>L4h7tdmG~CPALpKt7t9A43HWvSbS!thv|1$fpMev~Z zz~;B988&{0vjQnEPQ1Ik2|)nO(@e$U(ftr;!IXWOMyarsDv zoK)8ao4YFVky8R_+Nq0*ow7Vl;>c5&*B}U~Q~y(!yR@ri!h;h7ycx2(y#N_W`o1^| zcY%N(klcVcXtO6w-nC_X>?V51qi_4$^=uKq6hD|2Mnng8NTk}esVinQ(*x(VFE!V5 z{^DzR4bgvlM)2I9_#u}Zjfh4?f=tG0>OC!n z=VX4i$BSV=)*V9qA&kCvvhl~@E*qtWhAWvXgog=$kEs1j5n2&Wxvc0^1vvVL@QWfUTb7V zC+^a!n(;~&O2_V%KP|t~31+kybV{R$eT`Tg!!Dl!x#iS!7N^x?R=QB1&3#cXUfZtZ zF7uD3g1>rzOPDjfrlr-9c7hNs`)*fys1_^d+$M?pLl?d#SDh%`kJR5hg+5r<8) z*yriD_g{xA-sI=cyd;bk;FgVB(x|B=Rh0*%(JOx08fukYY(R-9$t^x3>y5rdbwU35 zrjj|1bRT7poK71e#|=JrCg9ydX=8#-&`@im6%_PJ)2T_)vlp0-yssp8WL}gG7-hmH zCXvg*6O4aG9|2oA5uLYrCa>K(r#vqZ(S_iJw$@;{?^EQ+k&ipJ-!#`2s|uJA)ot<9;HQ|4-;uaC#HEWJ!AwoVC^jgvRWAGR+MV#q)Wz#B zx-m)8N6nMn=|nTUb~HoV>Tq|p6Iu5o1^)GJ^)I}<_U*&xRUEEy;Pm-NDZcyFp`nDb zoQ!k$6NB=2NkZlQAlOlkx`SAIqj zn^#5Y0A|v1v1(%rELU1lxlbA;eA)E&MWYTJM>2>Co;HeQ(@sKCVu%-vRLP*69|-C_ zMyHEDqcn>!f^F*amw9DLl*fdui7q1{UC|_8-O5Nv04kb2^vEy!?oWrP=yNAnT>8y< zn`1gZQcFc!*Dy9^bAkBmZhd(_|0~5tS9o_AuKvwTjt-T;E0op%x@WRxFreM)^Netg zhC&cm`pqyQ7|KBGyi%IIi9Pyrj=&p@V%^<>xl2%6`#+pi=+^P5b9YbcG-Ufq#<{O3 zm)}=GN!SH=MZ_t;R@_he(r`8%zQi!$d~pIMld$HK#=I;}Jy4d+NYY2y)`E~<9dN-U zwIbmSWz1iWlI}+GW2mwW8V7;9Tvp5tz?rb7_|>R2VYe}I9jIzCOqs}?bnAOZCm1Mz z25)j^+#pSWJrn~+bT}UmacKXNtDm^yv8bP>-}<&HseFb4n*ay=?spcrpyUf(1O|SV z&8P~6w1fh78GW7%YH?`Vwt2Y1`QF9NFtf#d*zVp9X= zL#=31jea9%G_-WdH2aaVtV}{9fbB*Uo8y&_3mo)l3;A4wtcMQ*n^=~Ojp8yg4Jckp z3mXRHb*O$@s4V@M7&+$vA=xcylYk>V5j$<{=1HWT4#fYbe{iPnZr>X*i>;V*D*pCQ6JL+S2m!v;Vp~$=xa- z&c*@6O-^cZg@M+xYDn#UFAd-nO9SF&o2+i?<>BA|8f%;F5L-`P>_Fvk=M=N5p z!1$M(h@79QpJH#vc7P|*h;}Y6n4Y8{5B6>zt1LO2#I!g=!M}Gj3pY zHrr#pOC-onmzu@+y(@~WF>RSonq5wvqI0{i*OJRFOv)=AQow2!KRI_vV?Lst`a zFU&F7FwNIE7)h5~Z}SZE{ReG-sdvj%&5?LH#k`C{Sy_GkG(RLYsoQq&cUYFZ`p;Xn zP>HLjO1K2E9xS%)zr#_c|Db4-{>MW9thP7>hy`Ek9)+U3|6|@k7Vocwfa@O@WO@?r zu?q)$(4NBIN=PTC+yMq%YZVG$c-cuW{HqqILHNg~x)K=__0o1I3%_&O)5_2cF51h| zzV5%+BT>(Tt?4!7n%cL>Hn9NXgJ2T<@Up)I%5l^8K2}f*{2) z$c)7~!&k{sQ6)1d5`NoR~Mqefp z0jL+`b)EN&FdO3B+6VO1{^DMGC5HyBReil*liFRzgMli{Kw#!LMoe^txaJp~&Sl** z@j}k|NO^CdhwnO+^6mJsi{=ChbXtZDU2wJ69rb}{MM)b1n6j1~#%n{#(knlyuC>_0 zwOe|Ul}1M*y^^L^Gti^K^6Z;=zcPXA>L!z8E$Ua1^G8FCmoZ_r;x-{GhI#v6r2t5# zp?FP06LN8ZDxHsaFQ*yUcU(odI2>%KSY-y^7zl(ig0G`GK9|^n0ImzROs$48vh@`D zS>Tg?bNFIoR1iEOM+nSUP;jfbvlw$uq#l7BS8ENw0tWI}n>zW?v^|g*27LAF&4j&R z3r3M))dvoa3~~BMISe#)iQ2KF89SU)`P#_YN_kCS)Q@D9_uOl_Z>|9V!3fy@iDVjd zBjq9VILWvaQ|yjUbp)3M4eafVVjCR{;{IK%ce?D_U4L1#N61Clboir$|7v;OPJW&3 z6|&$wHpeMhU>FH9*%X98zuoKB&rczgJx$|OWWR=BUqxO9_cuOft9G&4b{QaimSLy@ zW4MpZt`q!5!Ar&51Y-JBKTArfJs;(l_Zms-n~I~V<20IaHCZMlRie2M{~I6-^`%S3 z#U+i7L|Hs!Wx^A`TWj-71bMDa)6?ruG>4k0-GA~ziGa}maE^PR;e8XU*+12hUszZGgEg&|<1N0z1NQ1iY z9=AIw7AuGyd*OnDUp}F8*(hwurh~WiB53X*X65>+#d7seHt&@y(V};Ml3C)v8s1u` z%RiakaXC>Tc+?<@ribMyy7$=0R{y0zEl;--!UT@v`N`*O=3eIV)>|NLiUx9PA^i66D8` z50}%c{b9{v?dmh*9QJ_lvUd2x=oa9YDYJ%qcHQ%zk=(^zeItVD$1wI=XR$aFzWgJl z6IpQ)v#P4Rp<3Pdf>k50)iHf1NnI-vB!XD$?x}KJdNZy23sW5hzJ4mFrW1k6{Ynd| zDpgJ^XvukC|MQSr=jrGPO~U)c6jZ=xIyP4Yy6vG9(PUmP?F2AV7LvqK0%j;*i6W#( zV(UXi0!>goBsrH(Gj3_U!{b3Z?ZL2HWhA(&P00wUShzBu`zA-usEfGe(gz~QvMt5TAaq4!fbCY=v@Zg7_I<*=AA5%8Xr4rNFRXA#_PwAG zuurEI=v4oi@6i!ShSF1>crPSAwFq~bA!<~UYY~1`5xjf7`;!QI?DDai9AF3lQT;k_ z&*DtV6ZUtyJ<*#tlNlanC&AY{XVqxoTJc_UukxVA7fpWS8Ps_W~ zAnr?ive|SxAac}kPHU;*7C#~47r|qXx%@!|N%oIpeDQ6qJb{XfI<@`%II=L`^LW+I zBMST;B)Q2t-+B-EVsSF#xnfyXuU=f9WBash5Y~Y1k&w+Yq?;cBC@1oH6AIG4gO)Dh zu&OiE9;C6A>EbdnYpRR#{udBS;G~R&@1T^?HPP(SDM{`RX7=}8lt(uOI&uU=j^prU zzcxq{mz=QD-xLH=wY5Y5(JO^8D>T`(yqQ+(sicuV^z%GhIeB`QMs2@#&{x}Lb5j1&Vl=Bn( zN5NfCk9@O`GksD)#+T0Toh6UYk|wJ_vaDDxlNsE{Tyh z|0;OJXS?!zhmKkWK{6zcv|`t4XTc?GfYm$hBpS!uXVMeUHhp75F&AHXi<_^x8cN9g zcJnhkAhd`7hytQV)P%grRKCh3M0&GM^J0mD{ZU)Px*>0;R_7!#CUmg@YurW_Cahg zY-a3TNOByzboHQoy$Dr3;w^%pI4}+;@{=!TvY&iPKq;AJ=GAYIyAY8P3nx_#o;dmU z1?K~a)d<#yKS`F8I?OElY`dY0?pGLPr?r7EzsE~@^85!+0Y7CLZP8vBl*{mnk-(_$ zKZz<33&B^pFg;cCEEJReNtB; zgVZ>)$nRj$&wbZ(wFYZJT>Q0{+TKTM5zy|J7E_Tb`w@ELcbhLhi zir8@#8q&i*_?=j&Qr5Kn19XKPk_2TR2CM0dBw&myxh+I|pt%~O9%rY~aVcrkpWl=f zq^e1Q5t!aG6oQLd-%fml(!Vwy&TD$`7*HbT@;!Y~<5ie3fiPKU2X}lZ?Cw18spa&J z%btBGv03rGLjK**^qm0M`2%G8*uFfM%LMpzi@Au@5jB>_Zw%ssF8$aO>vW0U_5N`_ zs`^Uq{d9ZhUm!C|Y1!Ft$507@#iR3QebOsIU$^Q~`+oBJr^BT8)F@QMqM_*LG`>R2 z%()Ugm4=g~jqzfIzOmK!^5(4$yv(oJI?Fha^i=Bq{jy1{7elA`t?m9ljvi+o!P~d_ zTa7X@{pg-)3_c`zusb-oefI)aX_?K$(0$_lw%+cM&#X)lR>LzlN);t-;$u&;$zju! zVTq`ToXCre&d!v&q!OBdR+;Qbli;-_tNdTUu!IFY94bh7#(Gba5DD zY^kyF(QgQr>-%&T6PNH(L(sW=3i)GlxJ zI6sufwkEG5$*f#=5h@D7-)Equ`(n<7OaD$bDJco6Q!NOWo~zYeT)D0oX|0J4r4nUJ zXo?_`07hKN7?cE;u}+omIvDU$ORLTfgHGcaJk!%CX}`row{#eaKwr&3O3$G6R}yEZK2GGw!ej&M zlBs3*;bSP`ad+17=wPZD#o)m!b3=kr4d7+7XmeX6Et|3Kcf=tHihP);SdzO;#fR0h z0%0C;Li;l=eUUE3^DrjqJem-bFDZd}06LI&;|#v(Erji5Akt07E3VGbVkCk+Mf37X z#g!#?EUiFv?YWGMvZ&V-d{R%$E-gmZ)!|YVZ!d3`TQNd$xAg_P9@RJx>iXv-pR?r2PZg+d~EHnxb}TNKNv} zdItS@HzNf`vjO$aa>h|_@^VB_&;|ce%$Q#BFcPEV=)8{f-;_D2-9_AG4`}?yDf+$k z6kg*Bw@j?uSe&GQid6*yFD{3@fL#?IRfA6(*Tj6^7u-FViE%)6i&iTOY1JVV$|e&R z&h@YeOgT@32VV>g2rzpMEo*d7)+61Q93C|QZ=&SaPifM^&n}xsf*hOixKBA^q(q4x z9tin|y~FZ%#JKM(pu^J$T%Las#@VLOKMa~Pvuyn^%btIZ(HNjg$tTKI+5dhi33{id z`D^yqU7c~O2++$U0z0n>=d8I<;uX{@C#u4}BLnxwqZBn$(?!AUyXtWmh$dm|;E>j( zCBeEHIs?&5nb{o}=uN^nyQ%S35ljmL=o(#by}x8=i00OYhkSr3C6aNE8_JDFDk+n@ zn*dv4-JHsgQx^#gVdR(av;Py^;>Rxf$frK_$#|Pt{4Xu8N0H(0F-z|u=hW38D7MQ6 zE|2eiiic?k5GyhLm_Qx!@kh6Jt)6+n4_wvPZ*dsc5o9y#SD$=QUdy%>sh_LPdKcJT za-a9}fF`iepRF-VL?#jok%-YWCt7=Y*x!5H#2y`xk?c{{gr)9 zW)%|>-QB=H&_XSzT5<+A=YH1b8Rqx(!Jy2^N$24Yc7!!wD!-ton4(tMkUaD?I}!M! zPDqx)=yBQ#%<_Lki(_2Kz8p!R5Zi4&=)hnNs{B@7{st-WOCh)$&JZgEINeI}aVofiz2e`el|l@h0JLR3VX>CkBuFzZ#`1&oo2+H%ZJu(C(`968=iBASr8jz{zze_dmbxo z_z#^tJ+6OY%dnBinGbJPzj8}du;fgm{X(8*Z+zPuCARMTQDQxc{#dZgIHCOpdi|cs zi!@|k=a&rlc8mNZ1L(wX7T`%78h+o0x0Xt=%A=M(X_K{bK1p`Da)z6g-y}~L2Sk>> z8P3X>u>ev0b&*6m9OSif{XJeil>m0=l9*k+6pD}akaiv_PH3`4@>T)T`XuoSPe+ak zQakC_U;kN39y6;^J~<@-7AXR!(X~w95PDF9Gdt^N#l4Pr{@aUrda5$Y1r-TvUhqjX zbS<+kihs!gic8cjtpCuKK(mq4pRZz{Ul^nBm#~)Js&hxwe1jm8?voNQMZ56|%(&h> zwth%boS*f%m}5#?Gw@e9>mEvLki`_=_}gA^D7eyZks^H^_0G%RRS02ptM_)lA>0l8B6~qWX{-oYRE!*9rJXv83+24PNm9{U9~y<@EpL7i$H{afP-ZU!(a4HJ>&9aTVyVe60Z^+o^T&q$k@{NkGT?zURXi1)jp`U(z}QHQRtX(*QT9pcRpf&yt|m@?)60Te;&zM&09cBRLv zSCmz=Ev}?+I7Xq$f;LlY)}mA5>uEihSC^G+7lpo*Az|-1HWhboHsK9M{76S6+PP=U z)mww)oQen;bBiP*bdj}qKoCh_O|ix20ZFp$;rxWrFq7O4zAqJz^^3=u3j7f;J*1p2 zV9y1gVR=!WpCr-W&n5SkT&+<_L8<%juwZg|@)mM$@eM(ok7-iH7o2qyEIG1m(+)4@ z`&mNN2*Oz*_#E4Mp4wEQAc@_Uk(aTFGNnW*54K#C{pQJC-7#81!3DW*%OfZq^m~ZM zUYzF@syHYLVA6BLb7o0-g_=NqpV(IObo+YWiR8{aLBg18rip$Ne_$bqR%2@&px+zm=K+Z_6SE+A8S6PN zq795Tgw|ZpIMEm0OWGzzq}CKTL~@gCB<*;S^8Ybr+45KTX-#4_F>#+s?+yIL*yEz@KoRYj8;Gy9SqN=Fy^$NW z=S2lkf=|6-#l6`O`W(VP56@)I^0Tx}lV`!E=TQbLiFjx-BHtVJJylR*+4XS`vKOBs zg;xTZ?Kl*3pA-(q07CLM>1Ao)C`1xi1#O}8PkHH$chx;?E@ zWo;N`=By(^J`{5sZ&)!(oFBZ-;3W6!@4ZEmXL^ zWjU5lNty$jNRSoeBeE7LaU0$lIA$ACCe?s~CRZ$-Zer?Ie6>wNqo6n{6qE_p)x|Oc zSTqGCjX4i`JkP@3cl=U3M9DdJCly&yR=mS_Ho(K(w{^d-?~o(@l*8dD3289mYw2Zy zVqwh`0y+*v?GVa&C*+&UV8@wv;P9Ra6_86$ZAsp4X zt%52f@Xvt%*7INsot2y5Ull-)ke z{uU!PxM`zy2%k-cuFEFwVg(_?*6?tzvut}I^+pa1X)x+9v@w4neU~z1leo6+sVI0R z@juA*{Z`J!$($Ol3`E1bk-Tb5Z%!ynHYiDPwfZo+|{VTr@tG0_Q?D{FXL&!9o;M zeTVJRcfvG9jG5ulW>OrPAv^~Ucgc$eszMbNHb;nXe9@UgTKsEM_K~#AY;i>m=N29o zl$6-Ei*>(2ew*Z6aSiK$g+rNKEc&ZSvip@a|G2oeW#Cv@tIUOlBZz&=PUN(MJpT#S zkxcuq11Lw*vB2RP(-hW#NG4dUOv&R?6Ufmb9UBD7xcHhIM3Zb%=PVCju-9QhVSz;z zzDVr3XoWs=h|nv|)K`d6;hkMK=&w$niKofoaFkf9q~JwGrdRf*3$5qyD7@aNZ^d2M z1iIa6+I`T@py-wrA-=S8P3*bK>`@pL8@7XD1^yJ)fCwJl_8h9h>y5MvsXyvtIOa*; zr_&Mps{n=8OzqU*RLeR!e#JvvOT+CWH%Z#0ld{en))-rY$l{! zk33!dNlYtUaxW-1))Zef1QLy*qmcF^37lQ60Zzm0_9CY2B>p?jk`S4KGEQ*lwG~hd z(BYdKvW$$hI36VXtIYzTEKmUPULialS&of?Xff%UQK<~8=lF^6vMUJw>xlYv*#l`^ zSnCQd_={V4{lJM`I4-I(C%Hh2AgugfDQ~JVaqh*jZ z%oJ38Q0hBm8)|HM;_=`1|3u%1FlikKa{Jf{ zt7{k0HV~FI)P6EWiA0FB+}YOQrg*9x4#yCvmjjJndU23Q%oH$U(!FegWMO(j+^o$& zE(O|vX{(yT+0_~_A8yvDly(g1<8~|0RV(p7FA~hxmV!Dv?DR)SeaD@uxnK${&js@$ zEKR5*giM^)_{|uE_MOOnD;@9ow$li%$n~A4NLYxNT#H^u)_(<^d!-fmZA<|cGiiSa zi?;@(S(mm2xxe)~@ovNv`lI*I+$b?az_}FR-|TY%1qhDKrjotv3`yv^oc6?)Kbtjy zRQ|ZeQnqGEaBod{$5MyuGP%;{{et+)3uxW}hvV#a;S6k!qGk;E7GX;4RRLczWF%(J z_gTdI!#@yDm&4&0LUhi2F1Iz0`ozqXs#a$JoDM}lnEWFK5?-kYbkATk)2lBUht=*$>CKS%Fm8ls`W#Gm^(Ga zf^q?vf{?a_(XK5EuSsMtIj!ACK%3cu#XH11fSlZ~i7F9Bk<7FR>bulBqVJJlg|K3J zP$-+gq?|`FKxL}*?8WksYfC}RCTySGHbkSOn66;rybbw9*aC#wBO9yoIB}2jj>&zI z3;{=6>36Jh?M;5xF{R4Y{yxD><`&4>@yiuf=k4 z^%fG!m`9PD!x~I={F8uh0Xv#yj|C!REwzH8+u^e9-5s%*oZY)exQ^0yLM|99rYVqI zj@^eOx$7^BYuE-f#L~7AH3gLbf~0OjN&lZU6{aB=QCb^qVk*eY`_#ia9}$_=kaoh7 zAA%&w12>rcY^hNklPMc*vjYDeQ)_BLnL!zWT7fFom`Xxut=e%4&fO;JgLnp|-}!$x zN&DVkUb2ydexQ5TFtvsf8@2%1so}H>=Ua2@UYQHZ6tI<(wNlUVu&vTEa5!%TRI6Vj zy+8=<8>f$w8|RLx z%h_YZuam9_o=uWbnSqeToAEaY{b&>kY{@vz(sRR9jim_Ti>-BaR)U*OAU97QA?}lP zmKBIK6{(;3$Q?adO9qs$r#5u(l&VNW;Qt{hDG4bVO}E(M#x@Stn=Yld;7V8fxFLJ{?LiM%c3WYV zLe2VO`O|kD@BOXA2T5=f-F3jVHgyWRCg4ylB`k!}XDiE$61>~UD61@s5LVv-8EBWB zvvCz@4(AUKeR;Y|FOm?3Y(~TdJo=OD^@|ABD74e}x_pXw-8!c#KHK)nI@RoD)+eJf z75D@oIzfA^v_lUZwSt5(3CQ55VhyOatld5p|3zDf*SQlU^mAPYi25{^j?mFivSFT~ zUydXGYj%*ZPjqHyoTI6u^O|7Od?Wj;q@=uf{DcI2p>vSLF&Rw~X9Q)*04R~RjHFS+ zP~tuaI#6pARSASEvx*O%`_!RS8DK1T4|m-X*RBCNz<9L(uK0(IpxZ3G9xV7qX^&AM zc$Ulw@5Xb7T1L|E1IDc)UN_H@z%EQ3DS91jbuP%|1nZKtZ47#(49T_v=Y-SU5AhJGc^iI4fw`HHr6%JVXdc=P|wRG z)PX7KPZgtQK9=W#P-d?UTf9}cwqeWV=Vpt19vD4KnQ9>s9p-73l-!NF@MK|s78bBn z7W9(@>FKR0MPLm0EEvj*19`CHrnsi%z^6&Bpg57-)u&1BN?ra9_+r6|VG0O=h4sf) z!1{o+{_M1;QqU=zI~{}PPP+}NjD#LNNBX`t^*U`3(6FI_M?o<( zSJp(%stdAx#2!3M zVlSQ+8Z_xUWUI6kp|UeGbr4}UgTw{j5Uy=pz;&55#TG^9Fv^#<2e~tD0eMpJn3O#z zlpRNMzxCoT%!hTdR0=DaycB1IfT`7oG86q7}?o6$rduQ zYF}X57^iw%Ch75a^(FcaiTFY1Jctqct4cr|mBrWhdiR!GYc8uH`=BCnT z!RU?cm|X3qkn~t*64hN7(ShaG)R&PJ|D(!P%Gs0J>zlamkZu{3M+YtQ50Sugf-?Ei z_B?->P6F>-B_0>g$co8XlhVI5{h_SZiGQ<6#J!um`Z4@(YzZP`*zL0dUjrPIHQ>6* zIyZWs@($jl56BaeIh`pnLEjaWDli4)53tP!zPsp&}M3D3qt(@_ae*3%8KS zb~?)`o)v3yA+Z$Q38(KgQ}B_I_+OS-G~J1FP9C^X)>g0*`R!zqv}3>UUd!4xNSyPN zoMe~gVzbNPa7-ooL&yIOWAc$;09Pm-&zOs2ew#<`r@NE;8TyjCZJ%~MNWpnO zaYMCBN$LYxdiU^8$B?YM7fJeYxtZ9SaA1%z^`LGaAC4yHww)mUn|H|ek+brgxVHH` z4@r?Vp79PVwAVH_?k*PgNJUKLKyzsZQ44H{7f<8a& z^czAsQ(OZ{1;T=vf`aHYY(`ZzN%(cCcH2s^cA5uasY(ab`y0>G-tQ?Xy6!7`S1^TY z3YZSHl@;YhM7mM`69}TUEGaRd^p%QeGJzz`lTY)YaGx!JHJ7bc9scoXk~m)On2wrb z2r)MYWnn={qJEr4(zfp>_fyyB9pl@%Tz?dN~}9sf5;ZI3vAqLPDlI>#QkA zn8YUVf`orEnmlm7ObYIM>q&m98;Sf%H!6?+WwA{{J8J@#5kxgk!A`B?KDgKJ*Ipt4IzE%8LQn61etd+u>)cKZUl#K zE9>$|uyt>gf@n5tEqnJjGgd_^X--=O3(7OEP}ww3WaCMuT{jE__TRP0Dxd@w3}aD7 zkfdI#El$LT%(U#bQf6!rln3eW_zsI~VmU?f!`N1g11nYhvi2V)1zDaXhOyc}ppd1F z*+mL21&F^k3=%iu9hH8IV^0{ogydW}O$u`L+cZP+_`dh!qC7utQQ>gRA-coNAHrF` zh>_cbQJ-1RQD|{grZ7TLIvolM3VoTM75J%2=4z%;A#GHUiMu4?6UKp-D$0ncF$FlGVyeyq|oaMDR~yCD$mo9AWGLrBT<}Hov4Z2S45vA z+Akz83;oFpIx326s+<0?)~W-Ai`~zOo^wb+TCOZ97P5p|ni&@ORBld3%5+5LSORLIu-nQ%e={gEd z&(@++?m;UiJFpr6N!C~e2);-8R5?i=pa|io?~kd)5TO_fPSzGaHxh6HjcUq7oGAnf z1gc|O`cA^i74x0k0+G2$7ZMDy)ijUtolYLIl#~>S?}8`~Po0phlQsXi_-o@Jv#|7= z$R-oWORD&=+cj5SJ_{%+eiHPJ*bH+x95o(44*Zw0;vnCOmqDcDfj5b1DbIR|;(D+m zya-DbA`&1^+@i?Cy>|pBO-zHZ(-^Ek@yMd1m@@h@WBZ0AbGB|&j!|TBWV+Za)E*i~ zS>18Rd_RShjewCd9!e6DtV!QVl6TZy{FQl>-7l1-^G6b{ zs;VkML3tjWqF<4kp0l+%HIN+6P$pG$(pFWWrk%U2kR*g2vr?hQbAb0sIMEuw)FTvI zSU{{nm?kt5#e@6%JRnhA+kB80M{qP{wwb+pC*7{jni2ccT$?0UgTpgxsfzh&8Yz9` zqkR`3WmI8_ZKG2bqnb@IDUt}s2Wy`6yNv1UW!tq>%8P>vtII;Z7Mo)Zhr?1`9r!Pm zB|(0br6EL;7tzinva#`b>6#?6(Re{QDb4lPZr6|$$GeblCj2mctaXXfOaajuY)09L zPsfnwVYh_iDY@sVZ`H8^MOk|C=*Ur0oIuZ+nOZ|ZIZJ_wobBvV9areCZ%HtT@2pFZ z71eC2#g+{Tp~9}XJqVNoHc=J?QBa7iuyo`t6xb8Dg^v4qc$&~}Kfd6vH;stU=8`n) zqHTa)E)7OZ9cdc^#T{8iQB7cFF*!M1RkffLVyeI^mzID?)v%%R}jCM=md^;t*$NU~b-!&_+11=K}iDA19U10`<13E+HgslqOX* zL>RHwQgSYdsu!j5bpG_XAD=y`J*IoJm{A{XK&_c4uN0zCbfd4hcBsV@OwvZL(tanL zvxOnYn1V{|q1#r(=VM7(rl*+$sSIZR3kx{5JjGRC0z8)Q* z&xZIONK%^aAt*1>Iw)Ld>Qov0?4;jCe>;U#Q{_UreQTtuJmhh8b=2o#^UUGA-N1rU zT@m6#Dne;1sxH;VK_rj9=n22hB@v&D78=EH+IR{7(?%w``6QA&U@^&AzMT|aJxj`S zy;QejOkM=v)R?`+mmfYbwMtc$5Y{Q}PqWW0+T$sKg@bW0MZ;tb@Ga2piz-7;ZeJk9 z;k4nl(K#z4QSNWptvwg)3rdT$Oh|)oVM=-lOck;FV@>N2nC-2Z7D1;8{~u|4=)mEB z!gdf4SXXS3@l}9!aBvc5x6exUV(XIkA$sg(>^&hHET&13o%HcJUy^s&jTBt)H!lR1 z_NRic4tgi z=0^W8m6R6xk@6RTv;#jND3sDNTbR^^q-q~C5hx0Q?~=7e|KP*IZZmtuIg;2zXK91r znxRIDtq>BoDJ(SFeOYNmu_;uU5~9KAu|j#P$hYpe1RoqGngi@*wRl zNt(Py_B}caOqE#bA0mP17TI@S5m0y|L_T%);V6=R}wYq_80@-Q>mwV~K- zb2x7Y{{CnGJ~r&qo%rx8Fs8+Yj$Hm&Ey;Cs94*6u2@-gz?F$muexc3xX9@7Rf#a@pT6#t{=Y>p)kQH|Q)Qi(1 zNZ@MuJ|69L7JpzSbYv$h*hojJ0b90_(3bK%7f`gU2_4l^Rb?|t}86gs%lFR8mr9O{P?t$?+Scy9JdR3W}bS+h+kR{ z{A*D#UB#LfP@$I=hzyf2~X0W^GYJI7qVl^B%H5e;+^2vAA~|>sW~(SEbUy61CCOTNN>G@rhIX3D2q9L4ye_ubj{;?~I7yJx z!_v|Owge8PxR30y+2UP+FB1j@wtVOEj(G@5iS}6EcOq^xR_NZbGkZx$W1ZtE9F?sF z)*yDDKE3D2-fPJ1W4lO5Bi(+5QUec*#4Xee)@3b2c$by?sBO7%e&78o$9M6lpSp&< zz5Snu^&Rt`!+_D>I1P4c$;C36GJ3)frw(kobNbL0Qdh*yo(XxRjhU@0*lMAjA8Ng5 z_eI64!&GwSp!|65j9VmI$C}ji=u8v4=|+sfpN}SIcWoqh#wzxK`F{&Qm0P{)w9F_G zg1j!aazMtsyHbFbgz&#t)z zOW9(Ap&vTw?cTUON>Iksr2(1=MdzL3(pmdHQlrQHw2_p5Q_z`7N( z<2kry1quF4H&ROIyws`@X5qD9**>ofnJw%ih}}n*W#-pJ5)pERFx!_2RaP=*9JWb; zHVI`1gi&SQ5jSzE^}yMd&EhEurm9fqrnX>xJOrT%K-MA~S%$0tBX>jL(66dggsI>; zyQjF0As;xAb7SVo-Z6-KJKa@>FhQHtHK3#907f0)|B16ob=BX%nCX3E< z`FXP5K3=74TeFOeA3k2St>+ajBHu=%$!4k~Uh2v01C}ETi_~HIhCL@%&|p8}B%2D-h&!u_^_94QQQ4rG3(SB1FsBNC80Sjpq;3esDN`;u0wcoHgO73xTBs z${up1;J!f+9?wQMv4Z2Zrfh<(LEey*A@Zu)!5=x1!%q5b&aOH0Nhp(D*%ncJY-AD? zqwVwN%l5f@)_mc3q;-VS4F%7|Uz-LBV@kgdr2~LHQ|HR|@j7J9qWNUpuyLwwJ{Qx( zalq(^QT<1KEUF!*Lx0$rYCGj>8|7l2KtY)^aSB;FXJ(y}9V6vgHxWWx8^GhA9i4}~ z??`qI)4v|;CQT>7Oyh~FzSe*OY|^$M`vy!VYbVbj!5=dFpbfi4*)?egiYOX(`;s8Z z6cU8l8a9Jx#AoBlQ&Us6n}{+33X(ivgVmwTM!|JtQuw3ux20tW_ZAiz_MB`XsF77y zKw>&1?PHHG;A1DU&0(tEJGODcbmIG^?j9o|&Dw}5IKs12VVB#ElkIcG%$dafE1fcr zdu(#K0TC2##2`xA#;ulPW&3!YvT(+9GG@pa)wZ9DX+m|4M`kH1PJNv|bQ&=FncBv< zm@iXCjU%%sOsG>bXZ!@>(o{EkMQs;2@YxzfY#=g2+7IMlr!lI>bm1p?LuO4XcZ@6} z8|i8R-EHC|?Bk4`d>@wP_&}yorSAzO`s?ZBMTG5(F`~euWKKsKd~1u?=}}cpk_T>( zor{p--pY))HGya+$=MQ}P~nvzafxj}vzoFBUHhI1&HmuAzq(5 zk>$h3>%Ctqhm9wGpUSUA+Spy<#w>?TwI51Fxo`HJg9y`jX2MPf!iutTsQ&rAPMI-o zJQ+P$z5VB6novb0u5aJIe=n*b#&H@r>W11zxR@_vhdGjoBkP{5@2YDwAV|k;b7&)q z+zae}&VQqRJPZ428XsvrYe%ZtOuBe9oGW@dk~xDkRvhVj3+>bqX;a$>iQBqp95~@?@YKV0;kQ7U`BW)*E&@K( zh~G!FbN^H$Zl606moGJPy{Q8^`jh;3n09#GU_gQAmpv}X)n*Q4`cVD%Ye`=x;!n?! zT^C``*7{4qshOQpz1B>=-wj>lN)eKXq0L{z{NCi z95`yBsD>D3WWO=Z=!(^98{lG|IP@PzwZp-6PMrD=Ca#}5XkU73LwpSZv%Rzri1X(o z$r$?~`o~0%=VG&w+VwD9Vohg{;(+Yv@?z5w!hVi^H$wXztSBWZmgR*|3zbb7ve~L+ zbH;kU!n`Y(wzRftwN+5XA67hNgjWcBG=3PadTtAU8%6>?(5(x>Aix$@vS+Y_G230y zQP<|p>OPbNGW(7Easnx}pgQ)w*+;b7z(8h3ca=7zj)+5l9GjDBf54??aU3uze{|Q; z{~)R(>NpJ;wOZ}RT+ESCWJs@pWMKEcby8Ne8l-*cA-2eXsss*-Yz9`J4;{#uPWGzD zGrRo&+41D8I45q!0;=WJQPFr$?AVViZ8MMrvzD4k`@|oZhv2-*L>OSI0;TV3D@?Y! zv|Lb5ki5;(nnE>!@MW9}5~ z!;gb$=dM#wAde1MSGC$25NVV?kv`kv^q3^xAC4q*+xAyIkNNEek|4%<2)Q@!n9Xvs zpdz-kUC)n3l0o#kVZRPt?1}5Ax`79*b0~vhE=oVCV@-$Zonu{-K|T6WWyMjYU*KYj zI1C)!Q&dOPfv2t754o5oR1+lq=nLBOmu_`Z`gZJ2+-YMXz4Wz_xD8HjtfOpj0|zqo zr{1c^)2m}Qa{aU6+I5kd-kOmrA}&}Tg#Aqhku~4;7nBw0J2ZM0MKM7E8mG$zf$cmx za93PdJ75|P$?s~*N`r!p@Ug(Oi?ziF%>jN4v3B!GS(fcBLqHY@LS;g$UaHTZnoMfl zo7`lcNlD^6F0OSS9W`+85rHF9jzu~3LdOfiRYle6l)V2!Z_m`+1s zMQQsxnhg~8+lRI>=f51P+bTU^6)w=NSK-!KBZ>N5)bxrzo?#UGu3&nBZs2!p@ zqR;T*!~f1{z~~ohKjdPX^zPJ~{Mx2dos~t+`^Xv(6d$uC7$GYiWtTVWqk1fm*)4j> z*0pM+N*gugu8_7BKpV9K4F}4$k7*uD{Vmw)yl9*e##)=8z#ptawOK<6MG8@A7x(Q| zf%8hTUsr3@jNz|=sRiktpZt7~>a(Ym0Y7yi2kG+yrAGQK1kVhT5Mo;FRZ^02pX98* zAX5Y+@qT|KnbW+N>Ulusf8ASt9#nC+b-_@Ca7)|AzJ|B#N`7n8ne1&Ow~Qta+Gx>0 z2tG=zbNbfC{Z!Aju1eSTUCBtUsF*E|14p}wDv3U$?MMHs_n_ zq0UODmOm5M4|O9%Od;4bSr!~+r^_8>_kZ4>{H$^;kk0gYT$tlQ7^OA7F;Cs2W%~}P zFE`Z-c||S-h-;e%rgP$d(G*3)6ooaBN2Y=(AyXQ6Aw<}M(J``&q7yXdx3F?qTTBmG zT5HQP1d!uIy5}KO27mLb>hmW__wRop>l^hYK~$-gekTd)=^($#>p)huTNEe*`{+A` zV^%vCylcNV?IlxCpkzHdX!~g@wgBa=kA?~RUf-~<_B#j?#aVK%(GJAfEzoYq>-`br zx0W4M&$%v3*LGc1`wA|Gh3X(-qDrCYonc1wntO2pL6-B5Q z!fgNAM?(e0NbOi4%NzHWt#8SkwFEkIOkJ_tV+AAYXFhS_+UA2KU)T;Z;MRpoyb|z{ zd9d}m_?LOSj5jYz2xOQ^sD1p@i&y%^JbBq33H`RFR(?P1w9t0izx<-A7e*?yM zLKIA`;JUufl>E52tOK|=?Wjkz_)Ya(BvHOoP*9NRxi-LbowT2AU)qypihX11wlwpR zxVCw~>cehpUelhc=ldqe!0v-o`wTAX!j+U-lKx!>s6L=|MLJT!Xh(YKQTE=Jz9`Rw zQ)CWqXi)op+e!6UAici(MbzK%7=^Z2Z z5In;fQw|6T2Ce-BdHnE#oJP;vzC(N`$8BhqCIMx z=fTNBdicbitHf_=kMakFB)+4@B8ECe=8`gOi}v2%7N;Qay#3PhXEKH=EXO|^s5cD= zfyDutZ);;356_LI)0nVcu@1ARRV+g|$1POpV$TQ8&`+Er#I4vKSYg@yv4Ru=&%7+LB>4OxM+Q>B6Uc%o47o)RK&_cObvCGHf|`-2$_>^x`8cYIV77@}j`0 zGqJ}i?Y1FH8~0K@21$m}MhCtE()!kRv@pxF`7R8~z6S4oTAL;&c57M=L zw>l$3TJ?~P9&K6HpLL#t9B({KFmI|I2c%oOZsgpjgSG1miQ955pRN!_nxE;1W+Jm? zMWOX+{ws@2-v+{YVR5N7sP2PlEooYXeKJIN$9lBwMh<>1kEFqR zFT!nKmO%-^vDy7XVA->#=pw9x;Y=l#v*PraB5LQOF} zA?-^NbCncR3JFGkJ43Kcm|KC@Qs8Ke{lfBPO(^-Jz4Bt2t9}_pE_@|V>IUB{bDg0r z0q>SnM@o|9{_CyEvxB6C3BN7VZV#Dd7yZUl%)gDom6W$kMhzHETtC+}CNOQ=0-@j? zAP-4*<5*nP1n+|8|) zn=)jR;6D@b=~y8=He=dBK?$mSQY^0V3Zdu6W=n-YQL+Y1zp>ks1o?$b&7h22Le|zv zg3=7XD521$4g9a3ddJBuGlE5y4rtWc5H5dw;Y!L|CR^I-UVcOgSescCQ3^=YE^QOC zt5wYk%Gmy+iPtB(-yn3>nj91_!qQ~v?}dVCuP~+Tkx?r9Rm%1@%!rvb-bHu9#f@4(Rkd&~nr+b$_rjA_o14u6 z9idR@O*$VcnEJA%p92c3vDPZ3*fKW?I=Q$G3sv_6c^;A?u4z3`AYkEOw-4*d>W&&k z7YeWRJ^Vx3v)qc}nUsRdf!b{e&fx_nlop`xEowlqN`3w*(<9bu z3p{t2E|QK3PR<+Kb3c@~UAU6+mdUM#x`xTxY@tE}$&3!&K651F`l;`imGSnYiQh+> z-$3BlYE9>ZwCcjP=&|Ikzx+x^g@VOFVM&6(AH`P30dqW($FbWF_)zy5VV<_ymyo1Q zp$xI*^`U$TY4>da!m}}oXZMBkTFf{|F8Nii%+^)`!rBB@F7_OKnP(pnOxBbH5Xv+B zyhwBouX#IgxJFfR)(IK{pQcw)+QATT-iI}nJ*MN|az7Lq=fVim<=X-jErd@6yX_0joyg{Px@!n0N%+H93o?R6HkOC|UT^F~wlMpG zDc%;-XecJAEIjG+u_Kw+eU$838Q*`j%rE7^4$Gfei=hfMoS`j2NG$m6OzrWzQ$>D3 zH|F`LVy!g=IbBR~4u?fYSxbu*$GET>~P*R?H#mbaU2$Ugo6r0*J zN=ox-bYIr(3^i!jIxi59PaVmO-s;cHs=cvo=8NB$hqC6( zO7T6p#GDhtt!vvt1Se=XlC#GWKnE7*zSbQF1lfIUWhpZSoVU`i=2{acGIoIav%ux; z6RxDZWpaa#jHSi^RaMQVs!9l3W*e0QKRT)IOHFpSW=4?>oUE!Si_s&hsutY}6~8e~ z!3BRop}D`sy5x0&b%RMw4nf1Z_b1)8Mg9$oJ5&0*hscA$Or;^j6x)}sxg5q zCX`k!>{n8Tu&3cMeD=1tT;Y!L|CP%;5HApbAn%j}0ehS;DTxqK7 z%xaPe{YDdi)`~JSHB(jk%Qz`_{52ke3{V4^bYR^w~zkyZ5nnY;EfFc5AR;frqip)%9k3oR+Tiin^ z1?+jT?;-@zVHQ1?M!+-3T0J3{a$>DkxV})J*mdBS1Z!cfK+h3=I?8EGJPX`{!bK@u zNqNgeIVv@${5?Wy*@ys`=rMhxwjVXwZYSS23e{NyoK|Z>==7D2g7kCYwP0}#(?C+Q zoR#Ng+ktgsAMMabi{}R=EST}1!2G{C2$3#R4`_c6fj@@YR2mv{jE1H4;Jjln$zC4Dj4;*tJ&a%D3A9sT6XIcXiku@jWap)TJ?2i14Xrtjtny@JFhUshp1_%YUVcipsNzaC%FU zz2zNsmrdb8PEqA~484bH`)38~?E6XHJ_tgU!h7?Mo9|Rh^;l%1O|sX|k_;sr{!VJg z!G((?R0rWo%G)Sg>Bv}F5fzoXWzs(9 z^wK|XDE63|dmfM^Q*xo`vkE<)yNOhpWY0lOe(yd?W@(fJN^Z)K&4Mo!oQ{oJaikn5 z%o|lB)8?|j3k_Fx6zA##$*E6=&Ji&Se zhf!sHA;J3et9kn}Br7|Q)>9fFP#iFAgX@ZE83_CzFp7tgs9c{FJR?xt4L#ex)APnU zYQKduFwPe~NNHns$(C)S+f>`0noRCDM(|xR^lUZyvn5kxVppc{A>rBs)jVD=To;QV()uUSO>?7C+%=&_EFzfO@iww z>`P_4Y61mnK@Zy~D3UXG*_UY!&!87CroFl?}wEM^!^`isXsMiNZdbjGHJU? zfg*_OtDK%RM_?gaPL)@+?VBqz=yQTxHKyKgHGxHGU#n5VHB{RN7cPc`D=A!rhI9>W zsL@~>Y8d~2_Ra$=ifjGDH$6sU@4YLcC{mOvMWxsfdzYespeP_Cnv~38FJs-Zs=Q3Ezu4I7|NzJ*i`hY??!P*p2UHe&eSc>Zo&7j@Bq8$xweJ zcia&{4wUbs%@Sc%&@k5d^0sRY8co}TvLe3$-5eS@q7wk#`bwcXTGnnD6J7bE`_`cQ zl+=!pDPanVJ>7h(RGvuY=onlOK3tP*3;vl{my`jHl$7BR-zPyGeG5sjnM7suvrgh; zL7!Q|p}*ru?L7?gBNJh1a3ZYpOMuP3^dVn~>~-Gq)|e74yMYfol3%XhH)w@+Uvv|$ z`E04Lw2X)0eGK(ttV4Z$%QGV}yf>chN5#XUz&P0G6$d+842Atohr%+yI7pD^%shXL zcmtfj$=)Lo-(zg&c$gm?2kX7#;1!Rdu-9!UY;P6E-e0~fQ6!)AzbGWRcOv9>On_B> z@vz-99$sq^53hQ}!?M5xNMid1>qnz}jlgV7i%5jk{wQ=_39uXAXAi#LR-XhI(TBf| zrr`fDsz)Ns4NHIxzVWaV>wY)BKS4il@`;DVK?#r-mB983Z+{hwS$5?4NyPdc+a&=O z1r=uIRrjIn=ZtQc2idaRY%rwk=!r8!dOfjsJY;lO0)}y2qMHlXnRIvXa|T4>i|(ict=Kb`v@bQIuMb1 zIucRPDMC-@h-f{Lo%BR?f-a2C&?Q<=*XSBGJu^7>MZ_1Kp6AuH7M~ zn?x*hk0E;K>CPdxCw#qSTvToM2KuNV4bt5?w6s#v%pl=_qzXva&|LzOlEX+!52YX} zFo>jpbeFWWbT^zmJn#Gd&+mLVA7SsAz4ltyx>nrlzUQaMZdX8Ti$x@?j(>=}R>iI5 zG+zJj*gO~E?zv^fxpMVYE;wiXqVAPelGrBBcJOaG!EpmE6G0423^|i$Oc)m%IM%ey zdv=>x0S;H$4(T<~Vloa?jdP9oi~^2fo^}FZ$yRoIwxQKW@5lL!f(ljCtSz!F@Q9WM zj>LocKB#W0O()g}{Kz`G(V^f@)R8G}(DArnT)#D4xE<%`!uX9D{!G=0>wPs|=wQ4c zHUU9M`JfY0`hEC@4dYzU&^=dWx1Z6(#3=$S@Q7$jMbjF#+{Z?WoV{d2)Q9F6n;+vR zs&r1@Be1#?5eY0$giQDphJC@id>>V~vvl5U1jgS8Y}_Jl9BpJ(FGEj=w|Ra$GBei^ z*~qfkH?ds!$4uei53i|o$7V50>gd^4n*9n!5O~9|iB2h^Df(tCM6AldJ%a}b)Ss#q zZTqiR(-)hrp({j3h0hmnLvLxtHS1)LymNU&)6I(&E@Ru5e~BmzO)6JhnOy3yDTF;0 z9ncWB{}4U(csWWaP~U|dx4!^ zM2pAB`~KI@*T;)pnTIm)6*nW{5y4*-*@$sov$Evi4LuGXLMfvB| zycf=G!#9yuT->LRQ8c|?#|cu+r5_?>2@W~Nz*JDVznQ%Lhzgs&oM4FbANs2Y+0u(^ z1K6B`jHW4xg1sLUiyUdCWf~vJo7BiR_-89!D+?BNGQk*OoUc@&K7>JrFaIjIrWOer zFu!=5OwPfL4T0p8oc*=P7wy7rRm4nCY-i$WX=LLTGLQo^r<71B0e|0X;R3yXqmzPU zqTkCN{{Z2F;10*4Z+x!92A0#(ii(PQqk9B@`-og>Jrzl%#GW=pO%$O00)!xAox~(Yke!TUm@-N%1U8WVW&ym2X%0kZO-ceg(r`<)JC>2?2_pHVNx+u@oQn$ zi*ujAU{|0dj?R6nAC@FQMm}QytxcoYb6~C{gac>4T|+68C$C8V7owU-)hD&cB-|RL zR(%^z7!$JCmYBoYSnD0zD{P+0SRA`@UXex%C%c;aqQ^+}n1w(&=6QI~11wt1(BFK& zu`Uw%Lb3(HIUXAKmEL27Hm3iIl+%h*jY`e_#oo@u^_pEyu0A(g@JRw*)C=fQ@LO)s zYVg~5GO$)FzRO!OGVLdii4hA-2r>le{gwBFYPj7v!Tm_dQg;EizXW| z{nNY8bS;xAKCyv5Q1Ax}G+n{>*Lzfa7^H&}IW^OkyWmK-pZ-t04|M80wrQ@;3pZ3q z{r20F%gs8~2Fr{CVPUZOMgrr&>u=n!nL1N=G8tLo;o3kOqh;3HoAb4-w$;A$oMgGt z_eg62P$`Y5Y4E{SQ>G=nb+c_d=q1?sXeG0LjCP}V2-{HXm0cR?O8oP})#*sMd^5fgq(T`+jNT|2+fMkM_r(upJ) zoXAn(0!NnUH{K7pIk#Gx2V1V690Jy|UXb@(^awNw23&u0g3(?u2Ar?xJ-mKyoaKLlddvd?728iA zDOqq%`Rpy2B|3bPcGXplqGt=mSPA9KvIu4Y?Bem-PWV*rz&hfRA-wT|nx8S*)Hgf!7(IB9b$(e~f zirB^>VhrdQzr6OOx1XvEef=lFMbTX-;7XALa-?)1;<+RB70E_O3#%(ba^f>cA$}+u zw}r7+IFJ+<+iZ!VkPSEW0coWh0No7{T6~40fva=NE@V zL{8tA%t_^*ymZ7qB8V9D6q1KNVg}ukfj2_wANvnQ$Xjjk_PL4{nh;)I8jw+O7hYu| z)M<}L{u#6&^)5jAoA86G=lS0>{2I?mh#nnH;4px%74di+4Oc$Rh>Z-_v4SJjv!F#4~}GnW7F7xZG+D-O(H%q2*f%$A8@tLi9ozTzfZTBT9n?1 zB?l{4e>}q64i1lo!-Mgj-iIT?zNJ&-yvQh6*a*u7;3wdz*=;cuQ!293$YM*Zd z+2D~4G)&-4U5ijwT@N6+cp7*UT+t8A``x#j_!{!&$0b#j_9x`guI!`nviWzLyrPyX z^S3wRMlf;}=(26g=j$^F0~Re zebuBB`MT7R4}LAaXFG1FiYxXjkQ|&7w(gYITIdT4U8^9f(>^@z`Iehl{bSsVNwId* zWF6oPZ1DLS81he&T)pGcXqWcFL`|v9SHI`3#}aUtt4ZgYD=bDoYd;KwO!hai6nuuQ zfEpMg1%V{`^hM=^{%ptIshAbyeb4_n#**nx&$F!P&&wZVn zNE>yYbMcZDghDMvYmy~oZ_oV*pZzY+DlQML23)Pzu(J4OeO;v9hncn+dnL}s1QXT<_~gp zd?{<}?$%gwD?suZHwLFOem4FFm)FD`QiL69^;;8?*MDO3pGCP+0zeN%PI7?)7)lq~ ztsqYMKR@Mgff{6H7_vk36A;W@_0>6O?OwJE-+Li{sLZf+L&gmHDgaWnwI-@F;o!#b z=N9sBxV0MbY|UE%>shCWoAg?J^gZ~dF{zQlAnhFp%I(XMJoU9p!PFP%}k+2O6mK2405^xpnH=wAC=`mLHBdt z*S)#Z;xnuYUQjV10%3Z+l_2j;x)~Njb&4|8@gK#0GVuoKJp6Cfc9-p6-AeojqEDL+$B(E>yqJ zT2Tvu6RMmRS=w~};aE{0t~Hj2k^!E!TDVmuKt@cg_Vd`|6B3C^Lb3_&YlWzc=>Atb zqgw7Cc5sFLFPl>@k}OtY>YX1kj((feP*#nKM+8V;Y5reICJoh%K0MJHEZ|gc^)E)K6A0WA>c+aH{En4M zhKblv>{v&gr*`~VRunH=`!Rbvc9OT^_Z`8BFGTjvjQ{x35{2avgbSXCFkoCOJT=<- z*GV|ly457#yrn-#>NAR-g0I>B%4Xi$6@dds#Yl_7S)~7_CnU6=5XWQ=u00rgQ=^H;6l2jw}*sli!q8JEatBYXXl-Qv7*r9`3NQfXb-eHr!l-R;`P9=*x=-8mFqfSdNRnJVtK zKpL-l+WtpN_xwVeA{ivzP^0E^x`%pS*C+C6y=*M?y~BDB?*#3L?KAC(ck4^9eRj(h z$E@JSy4|1geRBTxY)LaB?!%p~qdp=`92wIwLsg%F7mpWDnm;3>qZGiAouTy4hMN`l z+)gV~$NPRX8v__1ON>=k#bw@Bv1x*2d>Czc1bzJodi`s&w;_=kS)cSbGyb4?)84*6 ze(}e*?zrl#o6m5PQ2I=f2R!aGZcV?6wF?*i7*WP(E)7;6fx+MsASop6)O;^oI8Z)> zeUVGFnn$aShZ=|I zp$9I{NTpwFZsT>&qD`0NA{*&+;pA%qobUSrI_wM>DH_N-P^V^#v#nTHp#aA|_7IVW zV%x|BguV?C&q>`WOQdM>58U35pkL6*`un7HX)~Jx@3pF@6cPHhNrV zT$GnA8>VJ_fl`3AmH#yDc$I)GG5X$L{=QPc6`XUel5A58n|(O%cNk+@+$sPkg~t-J z4%bn`*TR+6qb_O0cq7wkY5H<}q03o5y#D^D+n(jNE8HhPHqIL7(kKsp>M-QZI@M3o?386_t0Zi)XC<%fKe>q1R2a!?DpH#?4=@A-ExP&?=q}X zOl8T>C3iG`Pk_N7;DE_{->-yVGhXXMdC6d)^kEy&q%1KL(=NGZn4GQoEXgWNunV7m z`n#v`No3EF!Ltt(e3r?<>j!Zu&f}HH_um}wKB|3OfrJ~9T;~4QKFWE>=nhPJIb2AT zrkd2CXmc&O7#+i#h3Q<;0M3SNf+48pwCt6dMo@L^`wE5T zZPG;&{fEIc(vhti!ECJfl7=KP^1;rGkK{&8nSv&pN$%ZDnljx)FnZ7^8jahWJ^pxg}@58LkBJ3#ig;Yn2loht6{{p`rJUKxrSs>F0>;j1tk^km_C z{*>4=%y+~xg0_y@`Zuz8-|9qsd}yJvj?jp5$Wv_e$wuwJotvcb677*>P3|(CfQvw? zu-k$I|xq*t$ed@v~j=4$k4LN2^cZ zg2uptCt_LUMmBw|lTFfr;8H7-v8}Ntg+3|kPbF(2(R&xIlyu9%=iP*>VU;7*&ZO4A zi*Q72CX3>gW2WqQjl%qfe5xC5YL0eSUcCBR{t5auss{niv<@tn+BkjTZ18907ZhMD z*0BmH*;Q|*=Ryh&M0O$Ne6901KCdqfG}%~#vyZ8XA3miB4%Q;G7cQO^$&s$fv&@zf z+`HX;caV*xX^2A>DZghGn^tLYQ3oxR+QSu|N_DoCWwmaG;o`4Ik+G1ysVn?zL()3y7KvL|vE7s!A(F zcV&2K7Zy(z1bp??$dFohRa(OP{}!`dbV;9k=rSM1nwY;LIrGJ`{@;zvU{I(_4tdvu zKR~#V{za9vY6vG;AT6TK2fRo(VZqHs5m?O|iwZ;_=dWoLKSk^;&&qH#8McJ*Z8 zx4>)&;$c&| zvzU`Av|IKyR9Kl%eF6QNR_}q+bLsPGlf`i9i@kkx7 zRi!>E^5kYfAURkXIhZ;t?JI3o5@9S8j}3+!{zehCJQM@a;-2PODrZ&@WZ>g?^iiGS zznY0kMgWCgwcG6b7aI%M9R)~vMSY|tg7iOtkYEG7gdj$uhj7{e1HPuRQG#;BLME6O zuq#!N^5$L$O9an)TMz0$3_ z@PGRB|7%e6<}(R&Xzw-Q56heSl?kD6f;IH33rNpaA{XQd6A{ifHiN}xR()Io|J72a z|KBG?2KAMe<^-C5fSZBT;5mb^ayXER$-1z)MXu*kuk^fJ{=digUOXv!{WZ-JfDHP6 zli`%dN$eJo4yxJF-p32r9MLp5uk-5v4?x~KscSiJ^3&21GCuYG*U+hHsX=gf5Z-iF zU?=* zrrz1&xog|)eAM2j;~6PVm$rFN%d3~J3Kn9k9b19igmW@Ng-)`Ew>NsNbEq7%WIgfz zg>x&lXG?#NMa*8=;-dQ#=LWiL7QZK-&mL_(cfv^Qj1HURuSi>b4))$}uUue!gb~>W zH$C}uUT$+JHo1SG;bk!a^Kw6xnf$)XL?_{e5lbgc*r}NrHe&TAd}3Y#Yi*zjlTzSy z7>{0A%W>^|kmvk&oLbm?(D&21aH8G$@Hp9XGKPQ?YQOUp*0a@V$Hhy=fOlB|7m;$Z zBX-9A*P=JqYG+%A1B)Z!M9vv;i+NZ?lNXGBXUsGHw-4%EcNu0HeUlw7SGT8~md5$& zoDVq~JeN2ce3!y9Pv=5Bd$T7TXX?AgQT}U$ur+?zuD{o92$9nzW9xOC%-db1-Se)( ztjg2EgMe6z^ZPwVD|sq=K-Q&C-E^}`t2^h|bV=BFdE=}1w10Q+pP7Rz~e;(Upva=^tRB{jFe)-vTvp*HVqj&Fj=zBRA2u*K#6SkPcR4i($ zz5C`jLodON02UE_`^=|zq?I#+w;GoV-D8`3Cz89BJ`L`d{4;I!je)nUH3M8kaSZ;L z^M7P+7sCUq{2`aWQ)o*lKj(#K1wPD5Sy}a;ndd;Y)Cs37--{ zamNO4hJNF^UoHxl^6oIF`Sj(7o12N6jBn`!qK^%p!^&^+XBrB#e+;dyCN=&*si9Dv zH7eUFGU7z~up-zo>O6X7LQ34&4A$5(<9GSm8I>beUH-!qb*`J0j>V`AlX;h33tN)$ ziK90|q>Dcmx9V?vAtF9mGa?h{y=GT#zJW{i#8%{e*thUXjZY+b7?3EV(y)g#RPh1) zJKv97hvqvAW6*?ZVyGKt0Zz?KEKW~I#Edn8bXczseJixoaSKN3e9?VCLXv3GS07Un zGF5+V;kEHm&vfmJuVCG!>3mR|)85`=iKv_cr>vHaef2F9uA}6#_>=}a77hTn#FDBE z0m@jjtoGULkI$(CfCl8*;ehPo?al7(Lg4Ks<7Mib%asY^DLG}V#oBrQ0h(hKML09(`M zowllbZA%tS-&GqHi$VK*M~!d_c&2MMKl3TlVD=k?zgy)tc-c&^t@M zmOTn2K2n-@ucLDaskuZ|>}PAN@lRV#d~JG=%x@fu=lJ?9!Jdu%GmY|xKbd$ZQ6o3= zZ8QnjB^n1DYaza_M6lOS;ZNQFwnU7+DEGK7U_nj&(95E=#n=dZ5=o+*@fi%;3oLwi zyILw)5|ZQNxAz!ldrg1Wcv0q(FrfJ<;8w~#HH62v686-{)^Yi5u84Sb*=@5~ji9*C6kl)5n^#c)a*h3AT8e;FCtp-y zML#Oy(~TdCH@$$lrO@)$ew!KGZMyv$5}4QQcYG|)Wos-*o$IgYApA{Suk43ITDov3 zD#yQ(F*ILL{4%u~8Q1^*_qR=#&EZUh*AAvr*@(U{NA&X*0E^5cK;NRbYq+ns@4kwl zs2%=M)J8rvIgf+})LQ?Wuf2eNnANK<6EHzB8hPj|J*c(fhrgjuGkPnYXgnFoFJQLwlf&Y^eKb-u_c-k`1E7^oZ zA!t8mF)J)hSunqu{T)K71vMPC`%LYD+ zxKx=>;TCDv%GAbg%f0q1D;}|Qab-n!MwGhyK6&FA&^CWDD+QhVfvv}Wy%y$((E#!~ z59Wy|Bv~}$mvrd>UWwq1De6JanleiXc_{bGuegbY8fFtgA626&7N5Py*-U|kD@?TG zDTVGRp<2EM{Z(3#vD0Uix$0%&o^L*#-`rKod6-Uv7aUL!0w>g}f5Yp@yUsLXEG*_G z7^WOdb8noT+yxk@+l%}o6`-0<6G>rrZz0jvZZ1stG8RHc#ll&*d^Y^6id zsc*+rzJ)zu)KemEfp!a-?~5C7sV-1AI&^!%v$D#WMEko*$@OqBg|^r=!NpZGiPp^W zk+;V*N~N}Pqe+!2C((IY{H}+t6Z}+()uhMSJ%t_*GaUl z71FHkBArL4RAj3KUf>*`TpzocI#BJ`Z%AiSajq0$MhZRy*h?svxUU52aZ`9?WYkpT zQ0M5JYA)0shR>;hpcQ_SuoGUDl78CfVwRNJIzzQ1*K%Auo4Y;a!PxB@!g8I@#>;^^ zmotSuZ&%7n&q{S0!XchbKfJ*@C3tI;LaQzJ!~srg2bVvtw(avNGWbG>e!6)ibg(`$ z-10fKFdUsU2Rj>3u;nuq_HN;rxw~>iW2y+Uaz3~?-YTU2$o*Rn3Q6Y2BIVEs^Twla zWw%&bbvV0#QYFA~Ul1oO%zhU2suK@SBIz>{G$iJeqRJ#;;G-^OH>|lY5UHD4$M+yJ zb75(Urirw2g4nSC%SU_Z2i2wW=DRr*hI%!8ho`1gJ*I|Y{5k<)N4M)aw{h2TVJk=n zwH1@g?(+G`0Ff*a_^XCBkciaWA|W{rk5jy(Cal?F zvc~EAmOsIY*6`fmMMiEev;U~In7q-a87NG*z zc=GPU{9II){b_yM_FUpRg>G5IWjl=Fl#oX3rH-{0y51NRQVZtd(h-v7XaqxH_J_KR zFgHj`?sM^rpO09zjA+XCl=|{{?T1pf473>uA5;wk>jtk=QXCARPRz4XuLg++j|=7e zv22trBq0zjCu}iY*C~-PJ4!D*bM$r_1@Tl zWd!Pf*P5(!P)Se@`MPW8&FXM|@X-Wv6U_pbr`J#n$A(Q|_qm2#wsAK^r?eSqvR~B) z(v|mr2uUPR8*HpZ(9-l5eo9%h#Dh4-(0oHtmxt1b+O>&Djff>9Fh3;8t7=KYrXs>7 zK@`Q8o%c@5l)R`HTa5Jnzh9F+=OrYc`gnlgb!DD6+>6@l6(pIPpk*!~?J=vB2)Z^| zX98-m76jdFD+slKz51LEPXP;mEV}#SXBVC==Nxci(U4#=0vJW0#9^DN0!D)(A|l?u z`Ejuzq<~9}ln#j!Bzs8Uq5hCo@OBm<(Sr{%S0(;KUA;Z$e<4?>k&zRlNo(&#Ls4AV zKa`;#!t5v#u}{kBENp@|`}VEr@91C__^@z|Rl#daN;G;miy2qD8>*Oxm19;dn<*ZeWN5>d;qs`+s0eN- zLw8MCt$?D6XGiacnO_N&rZ?X~mC<|6eq7xIHOIvCtOnDX{_nh{3DoHN`}#~?WhDo7 z=07hMdbCQ3q^@%5bh>o9G*N<5sP~QW^$!4y=Li-1Nf12}&Fv9SRu4MrXx$ z_P<(|v)@@IoUJg+1=n|2#+gkZF#ALPI_O+btxwm=dVRBXfa)oBr1Y}HJe0GlY~U@* zQH+EOK6Zo$SegAWZ4PkW4J9`AC*Fz)F4eFN9Dl7e>oDyE+BF4-0NdYO5$%cb6gz$Df1`d{ z@Q>$v!`3;h(_B9!hj!-lez3?;>MnPI8#?B`3lkGiU8fuAp(8Qj%qvE02DV}4915)D2T$|9AJ`PVnX`VRI7PE{+jC#WR@)?^9ZNcUJJp;m?Ej(=o1SNAGe!cQo-eYcLi9W|hJoM%a8eyXhKT$LTx-0Y#m7P>mI*Lac>H&aGK@gY(m_@(?>WO{uOO%K6st)tJhBy4ERars3(z+hIBqZHm>KVzW_5*_Bz7Q!JXyW;T#A)Jc_>vj92 zQ+uVp+Tw{}tOAZM3Cd=_qYY*N)mRP40Pmxycr&L?D;gGX{jj`W&|%qneWsX4QdmPn z!{YYAZXoF-(eJe`Q1M``X5jj0F&?rY_HFQV)9o`|;EXYzW?)KVsgIpq z+CRF>SKMwG;U270gCMpU#1Ynbk_-5T1cU8Tam+?c?l8(#Ps~THQ{?!bn{14ZhR+_ZGCMkQ-08c@~Xrp&+I@Zy9FVk&Pt8P4<;6`iSBnMrl$7&HOC((8ne(ci3iWN z6T}F>Y14{6BxB|e=CACNa*!vG9i|^D>_NTbBVzuRP~#OuqiX__^Iqp9w*2hgZUa&`9z2eBtop&@ z2t+)R`sMZ>sMh=^aOPdxR)d&>_RN*D@7wFnJH&=O3H5KM~vwR{5$a?N>xOQV!Sj7KvpK2ASO z-VW5@iW|cgs8lU^)B!oObLy zTkez^Zkm6`lA4pq@`iyS9CwBL+3wfJX%$?u>F5NGyoy6V3Got>)a}dKa}1Sow+=5= zjpsx7rR<^o1&18ePia$;iYgRy7Md{+XStLJ3>>9+3U}S|(wp70ZQ5-_l5gBRWu9&R7EZ%*% zoRl3WyI>)YBWgFk3c>9Q=KdidJ*=krSu0i51vK4IiT4Ss52BHLTl|AL2a!eQzS){Q z4b6wR3Y+qfR}j!VnpP7|dfu}L*ybPlpOwgxRAISV%N<20j2^3)aN;%^~wOc9zd4HlBMSnbjXz= zP4xEG5?<*ye%E>*?@!lnKyE35r^=Z$YfTr~oG`u&r70Ig598~_Bc@!}s-BQyd~FL; zH+pRdeX9jsZ`<;+pp+oGV3N>FCcB82LmSoXrnNonGK}M?9<PS;tJNCb->9+>FZ)?4b7>5}rSgZi?&Qb!@U8N_PZOn9#z)D!E%5jj!p`Fw!l zfqJz70*(wFvm1Bq;df%Nn{ebtAnrlfLw79xthLe*(2Bj_107|e(a{Od=ZO{<=Se23 ze;Jg8XH=x0Bcvy0Z!xyDe^)UlBGf-{Y>EkF;>Vh7Ux5XmI#dH9D2ta4<>md>s&``_ zgIBsuLA)FW0)p@=HpisJqLCO*!a46hzuYWJLJ*|aIH5&IueGn0gG!5x;a(^^>Mu}NaF_Q;52Y$V-eC5*FEw*WqhwOBm}mZ{G}h*t_BgjQ%GqL z3pj_?iX99zzSz;|3z0e2KVHc!$h^Z_9z_&eD1+liHjDWng&DM3ejn2koFciJX0-Dm z(l8GDd}w>xtEuvj-wrukE}eYKy}QVI;FS*NWV0tL+AYNPucR=ARIF^2OY3*`MqSB8 z^Io;rbF=4*ml)L&$7V>dJ24Y7KKbgy);=NoDIJG>v}n6PAE-XvmbQAz8oK$uH+v6a ze=-C++YN;Qmqk1dp?n~f*vy3_0EA)=a~%cw*)v=p5w_pbTmaX7`C06p+z%hSjtfju zG*%{S{61TNry5;8!#cbDoG{XpH9{+>r_x@OWpYXx=O$U|e4eQ;AJXCirHeTPjabb; zs(Zw#kqMw6;NA67G_^NG+e9z1B}C?8vLQTmIRwdG2omtAVg%2_}HrTr5>8hmIZf=jK{r&6D! z4b=tEa$U60z+BZ}+YeeX$VMvq^zfkyYi@Jh#9 zIrOuZ7IIiWv$t1S_`*043yTaThR`>Ghf=j$_t*Bj`}JY~3bz6!ATHefP^sk~>qQM) z7v=z2M&Muo!3+)6-1C*lhDwh#*jhcX1XPnJx)R$rhJV^2r?s!-*;iyVYxE7-aCD$i z=d}^l94ZmGmGI8g|-lZ-FfyapzHx=uUs#kzL$HXVS=X&v@9nsHtO}nd;d|{8&2C0 zMw3U<+AC19X zw$8wJY8fpS{=5su+1qFZB=wVK)lutS;hCrd=q2ul@9CGunUP#)E^*SDKe_{PJhU~H z4(()U<9L*2y=XvwdIt7(Si+y(Q5S9@ZfJl#eEut=h+2m4seA^cF>R_JX`tTaGR?xAhVYg#pX$muk4~5qIU&C7nC(! z^P?@~ys%(82LH1$9+Zw_WHTg46?U{yNIk8m4x|Gfrg`MxsVa*C*lv=+0=9=k3Xb;@ zr%jk~kH%oR?K?{^5d=XKH-fBwYG-^Kt&iDL7{Dp~^bgTuWUVHAW)FR;h-T2GK37T| zHAqUJ03gMqPl0Mj-n&AwFY4z1vF`0_5w2O;WUU zEprZ-@v;_amhUf*LUq68iM9>!DSt!KNqf*S_+1q@hn_98T^0!UbJxv`@H`C#c&qww zD_<45e29Ei?-z>Zc3`&LVGKU}L?RZr>UOkSs0GE{1)uNTJh+2!Z|cNL%~gs&Q{ezQ zaGZ8=ov$BSci5#D0Cw?xNBGtN8oTqURI=WVP$KwRa<#eoiaL#W$nqbriS5tSK|9i8 zVBCiXKO?pG_NoRj`G1DQ$v&nBzhDCSOXj-(nh`8({LH@c_uJ+jrAzKM7GAh$*2XKM zK|(I5^$qEF)m3(@5{WluzXt2Q`(tEAay7dX*@en3&PvqC?o<5@~(da?X!8cHdc9x z(7Aw1`ny-|h)Ew*7lRLL1tEWiaR5Mm-yfs^+};+Rb%)ip{tP|oRHOH&j{st2@6Dt9 zX=eHD?QTsf+CFr??q4y%Pb%tryJlV8IZt~Zs5qHVNTrCn##*`^Yre~V=r5Y*k7r<& zrv2LIjH}VJtw2XH-uC;|+b-*ZEgth5B+Oj?D%cz^);s=>_w@T}vpn%$_Q z<({xoI-mS^=oDP|a@8maF+s#X_`}(nSt2;mm$G%{$)RYTl@@okBUvH!5FaU^;qK$GmZY?Xux{iUK0UC`tF1ptqQB}#8K>_mCsXe zfHmGbb@b?c1$K!%h5DcheQ5!eXq1M_w>HbA$(=?4lPlkyoN_F{Pdv?YcCLn$7O*uK z^)U`t`9`A~w}+W4y9E2z|D=`xE>I?$DI0k2=6aVAKy9s;N1iS;%ssssV2roZX&z$j z;HWF&|klJ{;<9nyDzhib`31lmAOsDo=9OlQy zc!)``2*#tAzOSLv6sMhXaxlutFJY&Y^aH^20bY-J^|R@(r!AhjC6e{6ucm%BgwEAF z5eHmsSOLhrK9vOs7MUW2)_qm!9ddVOeY4P-Ia|-e`m6#CbNhuhoWH^_pi&~)tMofJ z4*=Xe+1KY1@Sk=s_Lg!v1(BuYId60dNoQC|W3z7&HkK+$j`cQ3VqAKQQ z^AsxlR@x#aOdgE#+Gn}C*enBB9$3(;eE~(xNu-kqqehqlC9!JHmF|~=*Zbjs zM^n?fB=$(-%6zxdIW+*>#xy>QR~(mp1sHljXCp*uT`*?vDZ|5Six#ZZpu=vQwkR<`PMEWj_LOh?fC&A(0~>fD6QrN)s~fx z&;Dq9NZ0b6a-uoSomQ0fo5DSOd$E_oVLs|WIz4O-^8up>Z?AU)0m9k!s<9D*=PqO- zdM7afdoj-iM)`oxmr3ui{9&L;FoBFcYgSmug%I#BDhkUqfTD9pHtteOqgqwy=<6M7 z2EjzMuKq|eK>v`4EOpcNpeNw!Tpd0FP;RR4{oy(OSH{bcPa-&7Z=$9CI9-Ibbcv2? zOGaJzPeWlboUC$nb0QR3M^mE;(cNMJpz+K~$(B77Hhh;xHJ-@>8sa}is`Re`bmN9H zEJa=co0QP_#`0fHGz5cjKlPzC;vh^6{X;6cbaB4&pA-g;$gtR%e^q$7KJMd$;W;<= z&!#wRDEbBcTAS8sYFfgAFi?Ip_+LAm0aU~3#Jp~=U5YgC%Z~pKn>vD*w|NSa)!4R^28&QIS$dHWZk*i_VizNc6KLz0KO#i9zxNoR0Y(#Zw$Nc zhN@Ke;Rn)??oLm!bs1FcJ^Mwoe!JmKr5g{=2Q$8otoAbv>cYw@yzkFeG1DIRS|vRN zx9mDLU5j1K-(F`mhh|r)qmUxHOrR&yN$7M2`Huk%p$e(pc@9N45#j`z{E&c~rxYon zjmYj-05}#flyS#5lC`^3yV^(@xkx1PA)vxmU6N^y(9xfZY0ig#xf5?@kOJa+k54vc zCZ3cT_*}Ql9s>|x45xL^@~^|8YYDFva|VXAg;*#Q-X5aT9?w|S5Wo)z#p~{`F(;Gd zC!$tP^!w2od4Q(_hKM5&0}KHj=qgsq=ScN9x+?XB8oJiEtt+0v1)tlwtZC#Rx#+=Q zJi}jTn;oV^!FG=+~Dsm(nsx&z;Hyvd^sfz(LKyNlt()-~eG$b7-ZdpO-5=+KuC6 zrtA%%jn{r(cD@hP2C<%PmSR&8(fi0BcXWZPN@ilPjpcy&(O$k0( zg&_T4T%~6&AIr)bFCfP;RZ}l`(47D4q`;*o83F7Adx{5k?kf8(1b*=p4ri!F08R_u z&%(@uYl|!aR!3{X?{bQw2iOv~(RlloRw8%+3>AY70dt;zKAc+gsCF-bqwFy>fT@U+ z4{S=?(x9m!K<69AaAY)XnID^yFBtR;MU_MCrp*iNj>MYxuj%Vn?Y1JM185-TlB=TB zT!}w?nc{<}+5262V6$q701C;T0z!|0DH+5iY-s-s~IKs76WipGIq_k3`48%79r; zk40@B_`z7Ak(+T~Jvm(qCnK=4p`f<*V=wmS_0Tk6Q|Rt~J6rqSy^wAds4DafRUTI7 ze6qW5aT!x}^-3R@H<@4h0EU$C!CMDH`36qivoNvc{(BZi8;%5|6>cZ>8&KFH< zxy!@-AAIE=v&wzHqO&{eC~TFZ%DgbnclRuMRv4~Xe*s@-rWnr$XJL@@_$J_kVNi;U zjww)yKSz~!s4B%VQ9^Jn41qZr{~^|2wuSAQR&h*+uBLdPdsR%V4hS?HrSIU#01S8v zFxrpj6uo2ha!O{i2(dJGLw3zjSSwe?l~e&v^;SrHBJY6JSC~%*NcB{;MfhaEki`{-ebBG3SpK+`7YSqt-~;yTPfR$>^W%o1 zPv?!$v(&BrYH*i8tJHxV$2+yw1^Nn?yom|UAWDG2#)ctZu@H7^uIvebPH>6 z*4-G9UYf+hKX5gTK|CAjSB^ybU2ObYw*n)NIY3Rz0l^hO6N31)3B&?^fOXe-*&OGK zhT#?a0h&#+aHDWi-5Z@QhNNuIQJW$NAK$x{tsmD7(P(1 z=ZU}i?h!NF%i%^FT4d~;)iKPO9>{SFswIt&V8`vO^dV`+gnf&1sAik)K zPjLZ^;c*OXMPCcV;Q#5^l#Bc&aLN^rm|^Ha#}b!p8!PP@X^;!}9N0zm9}#X}9j`FJ z$=(2oC5s;rKO=YU|1Wj=%>=TM`wbjLeNUK4l2uK3r}29%x?Bw3HM$@(M<6tJ9fqZ^ z{sFcM?9NYO@aUEd11Z9)f|PE&F8*PHyBLtcaznZq18+c1%mL@edSh@nF!$X91U>tB z1Qugp?_Jk+Migk#ongBukG=)SKid#0IMQ@|BY9_mr4IF_m@0^@i6A-JLyUlw<=&H2 zgEZ&0ZTJ6$Ak7`vsQ<+chZDx>+%$Gia@jEc#ny+j)hf|83NXs$n0x)^OkqL(>Z(UT zOtl+|jxc1_zo&pA1&i^ny-y^2*{cj*1RDFGMPZ;Q16pr)p%|Db4*Tm3UC$HoN-Zac zBW6nM`|AAt`Ti}0fN;Mg355HZHca~FSx@oSN(&xQGxM`o5v~G*(Ta`+R%S1t_>4U< zaF_FL^0U{4q;-#Eudk|X!CkSh(H+Mytbf}Gd2tMPg+-Q(pS}d2%=k+MOt=t-3o$xE z;bi3i?Vv=|5EnDL{j@*lD;}+RdZgopvQh++TMl~*uVyzYaWNxd*lXiXbk6_44t}uE z&oSHSDGp@Xm;K86^=_e-(fC;*l00V zUhe>ilpv32O%RAnM*p981|rq7mHlq@d|4jQoJk_`>HzPqbG-9?w>SX90R6$q*1hHp zK^aLsKnkNfDMBQHsE}tw>wXs%P}e8Q`juX(mV;6c6w(JqqcIrs;quA8M{t*oVfGV| z$Y%F5AT=FRgZw{?eRn*SfB1L92qB@2knJQRJFAd!jBt`Yv-jRBgviKoGLFqLDzf*c z$d*m^-YTL9&*whAzu)ux`TY6)>cxG3?(1`n_xpWaS1c=(9%yHRKF~+Oe&_8c*mPCG z8C0v;$_P1mu4Ry7b}bBpuQc%J9BV)g`~CGFKniIErI38$PBc*iQUIF-NwYH+14A@m zrsc84;rSu3k?K#5ufDuVu#vO*V@I_p`HX)NI+8YD1ZbScX+Ast2+E+N=5u=#MQ);R zN5_9Ttuh3%`~q5UEJVog=#TdAVTl~(+fWY05{hJMW)H1?$T-9L5yv5yIlzH4i^?)cVg5X+?{Tyx_paAKb!i!39hyjzX0>B-k6nk9EFX* z`iY*SftgInmGOmehJX?&1jxU#a8g)SPODkN9FGlr&gvuDl#D= zPOCbL2^QFG?l#p&r}qKOb3Utyy%!Oe^U|V`w3d7S3uT;L1sIeM_J@kBvH`Vg;S6Ve zkh$nLYXYoH9)Y~NaqrTj+f|u~C<64)-4$%g*bvwri2<2=$nI63t7`Ccm$;wQtj3RM zvuL|}WQ`_U2iBKrpVZ3WpiJ5Nnjm1`^KiW?| zIHuB3K8%G*cv9iM=$mlH%WF`DX!Ys-sRRrp3|0=Th9H_exK{pZub7er+iN{tUpiZc znfCW=B$34hMPK50>pyRhu|9Oe(^PA+xc)mqkOt7~@>!TvvA}fVRzm%7$ELqyVBOP_ zo#_`S%@DMULxHpuYYuK1Z>QoY8ZkdWd|5Dg25b`uxI3|TM_&JJ6WVnE--w{SSf*Aq5_`7Mxe>E%@L6 zkT+5^r&1B-I%(1uP(ZxJDEFses2z>;dw|mjeh&AhWnG~InP7vzGhOeOtLmIc>HOBm zo`o#YRGUSHh*__Fl|Q>Dd!YEuDQ+rLL5P5W;@3j4g+w&}c=i^KaG0sXe*Qs!X@Tx9 zEV2tL>2Yzu{?yt^oQ9`C!BO0FhQ=aYZhy;s-~_2%;3-(}RD!zV*=#%9k^eWs*`rWm z6`5CSVvv0K#xWKwq02e4PrpSm8UkhUf&{F%`6pZYj31~voBR&G0#ncfC%7*o(z~=1?uXH&fFESp)b!5QK%1?S%^E2$Q^8 zbtafmz~9%TLd={_i&p;(`@Lt0!vL}PRj{i)t*X*1XK!vSV3{ab+$4y83zn>; z`%s?YM)2uJIx2{eH5ZGXge9+ral(jclNAUFM6fi+LYrO(DU}9b&R(gg{r-?5b7iMm z4Z*$GMl!!RIm#>OSZ47VR~uGm`}fqd2mlu~P$~(1L|E%PozYy8};?-NlF@x{p93&9{L zMwvyx&|kqa8L5&g$m~Fz+QhavRL#q-i*pfAk^n(t@Z}W?27z@GG{L2GW(ZR9J%!=?BsQOR;5GL^o$@AmkMunz3Ons|%ud)Fg`21b5da@c4 zVaFMvI8+BAi#ZFn^rV_+kJrORN@rA@tfs6%A&j&R$MPSAS?CdlMOGPNjAW!$RuXt% zp&2tWNSCd{3pRA3bSV@W>>mv1(~I}d+F@&%_9hZs>Wja4tb>kwJ;1!SZRjK%map~G z>s?+dFB3G)Jl9@dNXVtGQs{2-$Ddfi1s7#DT2Bt1MQ!;G-hCZ1%@)u-@&=g=l3P(} zv|bSQEO1(Sm=&GNR$YH6y|ahe9tFIc1iQ>5>B!WVi7-0kF{SxAQ-F zef$0Typ}%OKwpGAy^;y$2(%GPaxwG0-zeXv#N|?7{l}jr|7>S{SX8MJvprLt0Yx!< z^g|79m?8j+qLLx76z@;;bD+E0n1pbUPC!TAR*Y=3{u%C>imj(!p}Xx%k-^jn;8RIp zy}O9ta=~WTbP~o1*l9?Jt4=`0;_s!8P^YqpsS2XMaIDeYgIFY(Up_&mKS{aoE!DdbKse3Pe?!;XH@)QEl6kYWa)XmfsNmqw0dxxUR<+T8JkNDtewR-*duYC%qq1SmD;U{@p|1bB%R47qV6_1FAgAcI4r5u;!0b3sgnvya4Jt{)7n00bW| z6SJ(EmPegWS_~=U=BFdxfim^;J-SFjkzjKC1ZlZV1@NbZ=w6^-uv$OiQT+|XL~9?N zcBZ~xxg9KdJDkQ1RLg%}wvJFi5EUv@0kKKhF9L9>?Fj-b_p|(-KXf0%(cmmpYDy1z zRjL=FS2`0>VH~i~*t`GkT2Wm|tkELwR=7}t z<)|A^q2FSHbn!b!P{kwjsQp17f&=(4`D<3-!~Ei`pGdB6arfFXqf>XVq+!!EMO9f zB+W0cC!vIO_@C12_Cr}kN@tNmH*KfZ#;o{LqN$9flZ3YQWis@)`aXsANJXMG4O-y2~*UTOX?7y*>(xsls3J@ z3m?a$&I9uX!Z={08(XpVgRjKz3kycvf=CBeX}O1;N?-Ge{$TE7NG5UCu!O;&S=>ZZB@ zJ_kqxzgniUUIdW!rYDuip#jJH5PdoxD4oY9gvsJ$j4z!I$-FHlU151cdbY7DjAH zm#ZEz+-1Zj7pIhpk$x;IDiltT>I$?3R>*=g0VHw&q-9IB0KWi??{GRSpoBjJW<>$8 zMft<~K^3n|(BFnVaX>Q1I_8Q3UZTz(zrp*A3tY{8190_0D!`E?EObMW1=Qk}b7vt~ z+$7q;ee1*dcKT&PR@P5TUeLXH^w|yPX_rFx76%qg#-B+nFhrC=IKgZ{&RtKt7>hgK z!;#SRxz^-%a5;M8DC^4QHD5A|H26Nibgm2mM5`X2=m=mpZyEaAlR}1AYPlEi8#xrj z0-?bZOfdGRY1mA=%07_bg{kic6bgi0yIji@jjzfKIn?2vJV00O(Taq`h7aA1Lu1$+ zoN@3yxq=r$!ffO`_gG$c5DrCB4QPOS5YTQRM1TT++-Do3f<;+}nQh6NEh|5tOn#Cai;9pnq5V&3IIKZ_MK3cUD^cW z6?Mm0-0=g@?=V1}$??Hmj5zIa2QdO)zU2H}=-b!$&6;leG+~q|4E2n-JW$?L+6tHO zdj@Set^arc9*GGufp3}~$%Da|ua2qy8!HC?a}JHuIf+o#`3*V-6K60>ZAK4E$=_&qtUo;Xwt>WOoNlKB1h4^Q^O{(*uiEp%%KE(izSDYcv`Za@{ZhvuTm$hn z))s{9rtR(k&FUn!TA5IcQss+Mrq80r_uztBE9d`6assAtJ!Y>Hz|OOYw;${8ok34< zMRU-pZ+$a4TNeQ&9&d;{)q$Mc^PCYp66E<_+jG_{7pNhs90F?&-70~Ow^xhT5k z3)!}}_2ugulUn?BUL7(|mVleeeO_h**C}-o-0lpMnHSxj^lkZbt&9fi{${>^m7Avk zb*5b>HZ0^|Y*@|JPD&vo@e~8RB`ZiBOoy=P9lDbCu8`(A?5iScX!^BfQ1;e&lZHS9 zyp)!N7s%iy>U$$G+fwk!9>9nAdh~`%N%+{xSq_M-Pl%}Vi&iTl7-8g-N9LTGt@L&x zAeH-Af0V39D0F~0rDTUi%yd8{>8`yQvlBoi9ICMG3RQN#a6kfwh(sGf_jr)QtqUF_ z@TvwD!9z4oB^$EcH$;FcuxzWc5o^B&zs3jRgONiYtAS3R9|;Qdjm3ADx}2v<*K$K4 zXz@-J8%*AVXP9mh(rDR!Uu}PxM2{w$vAO2f0$j#ZK!hx^_UJ&7%W(ED`e!;tE~s?e zXd##QV(Ke5Imk8LX@#)Z0Ijg&bN^aP;}fVt%G5^?$|DRXE3vXQ?IxFKkYB&}j)5rV zw8ljfk<}-h9(&r*tfAJ084y4QKlZqV8$le&N4+(f^G~H{vQZb_3dcLe)ZdE2zv zOcCb5@e$PBaBxkiF%cet8O+&gaJiO>Z}3Y?40&@&EEpI<#NnMQKTq*&IzE11g~V4* zgV~sEeS_7OPq`qC(H}h9o)*9DBkwsHbuIStjajeP;1LvoM&EUf=as#fArN1sRPUCU zu;8+W#sh7qJ#)RX6^NhImT&~<_HKt_WT9?3eck&8=L9%}t*(FTzi^-#?4jw87a?r# z7Pq0UNHXmqK_pAA3L&KI*?CB{cuX=FWuUi)eJJBZAY4E1zBv<=rqn{#P-abX5DB{6 z==2W42jxNpnaj)@?!g&t^T4bV*`Tcw=Y1h?Ckh`U7VEG;5_i)kYv?Ca?9p>-7J;Jh zbSf4CRZCmDfw#DmrR>;dhy5whE$+BJk&nuVy1#i)ScxmbYaNt46);^}g~XMT_p9#1 zPVR8PcpOu&N-$*$=E%GWm?kWz)MLptJ`^8=5$faDT}B`&a#fGSV=!)qAf#5@h5hQ0 z0AC#2Tar+uZ2;_o=jebq@DBU|_PeN6c|-Cd@BQ0dlE!MuKys_H3d#>AJ(5?g6Aad0 zI8*Mh!%hrK*{kg6)KZ$s|<3F5_zNq0MJ3)Dv0J0S%{QRru%q@jH0U|ke~avylkN+)AD z>e+KYIzk%3o8Me6dA2>%^EMyWhwewAVz(g*i-Qht?{HP8Q*MTO%mzBCQVNYpjb z-$*{wRlAE*sD2z!E1!%pgB0_S{|J^zp-7Mx5(BG!F^J%YywA^h_<`*0M za36%ZjYTogv!l1M{*3|e^WjKTqHsU9nXy<9bT61jIP56_`eUNWfy9kytAN^Mw~?`C z;ZooF{DUWz80F56P#Th;t;eeU1@BOd1|U~eldg!}=F5_XCpSAifIPF5@Z(#GkN_K- zMRG8*O&l2JEwad-xea^}+`{G-I^}EKEV7ddik46oYL^=#|7d-VOOxMliWh2n3y}~5 z*~Kp18@HMpTvnb{#c9L_(o?o_NxnRVnIOKlnw9|GHbW@hJrZ=iS-dnu1{2p0^+?Fn znL(A8RffnYlF##u3G1xD#Dx#6xt@O%F8t-e@S=9XH7V$AgaWkBC3jDFZ)|f&}37E?3!wipyN;gTFtT%$R^SH zaA1?nu#jXd>tw|+X)Ya#_w=HHB0qspeO2ke_v7Mg5v>}oI#=)^hX8d2(Ah7Duu zom)HxCiehk0O$@cc-K6*dg{O?3McomzVZWqWqj>#LM14O&IBv(nU{IghO>m0^uoO0*hV=?h!ZU)LV53VbKv%!%8+-v4dWLul;u>CmcP^f#8Cc8+}%5w}^tY zrF6+=Uu4?AvsO03#DGBv=YF7rQ-c|UKvBTtZ+657@H!eMEV-a?XH*iPWYACQfQkVO zq{50p^OjYGr{lB#xu^<2k)-P8RKx9qDBySW#(SZ>ZhqAM7K=H%V)v&aB6qAI2op^37aXn5fpzA?Oqml?J@L>tJatY{hHfPCwo_GvJ6@9dXykv=O zk2EK;442iMlY9G;P*Ex_-FG}2Ij4B4YXz}DWnjMQ06tq41Uevlq zOm?q6$Az*NEZ3za#5K4eU6DC6S>wl6arARIs-?rAm6TI~QyP8rj0^U#mRviZ!-=k- zREraKRSoIlOukhFxY@ZatISY&}Cup3M{A_KZrj(}U9 ze7K~Y&jPCcTgH{3v0yzFLMKIidK_x1?!tzm%SXtDeyy(D5=n$ZPx0X$$_&c09}XV8 z=Vb-MU-Yqtp&`7cA@-(#WK=Tv4lVjK zcrrkD>Bc~>o%!v6zI2m?wapg$cSkB{-3SQAqlkMfA+5xZAvs%Q*=1I9W?*h(TxpjX z(9Eo^H$nk_w?;2GEVb8uvmzNvVml|co$=u6XV+Zhi(4W5$$0qFAWTGqU+6vn z#STEPdpHOWr6x^Sihhc9n6V}|(c+I_RG853I$OCCU(l7s$7XteivsjD&+KLSu;dOy z9(Qn7$)mke8lF}56QVjbghPe<@A=}?`hInSehR~W1ZG&peJDD{2@2tZ${Wy9i73$Q zHKF)8p8EzJRW>y^_GRD^j60A2g67$iUxiA~yxzkj5IM-Wg$D!c5fBT9r^ z1JLC(Gm8Nh(v zSls-x;uH&<+9M4vSdLt@No*#8emDU+d-9Bk?Wv2Z5f*8=;Sd7)50#;)Bkyr20&v0^ z>6=hytMPKcZRl)W+WH8AKDTHP* zce(qH_)Jyhek)m_t_bnJX~5*^Y|z)ip-K~sr4h0tAc9Bv!~#ZnbW zA1bG9J4rlF$ZCF&RLBI~!>FiI5Rz>bu%$2|FV+byFURm8z>ov#2=)&W8iu2cc-i&++SZo2`IxZWjkGxFZNzc9&sF!1@#Q>~FD`S~J{eGN4pDeypfSQ(vzK zikDmpsDpzgS2dpu6tj#PxtKvShnyeVZ?MvfP@w+L2J?BrXSTAPd}cz(8p=(Mh2ojzqXE{svj|xL zrrGCz9stHXq+tXmCPVF(MSp~%K+m5Ly3}XE4VxS)b#HptaY4!971l5HQqTIV4219K zj&ES7&-xDdgFeKeOxoj3l;siti^l(AgUl=!IV6VdWPIh-olXeI0GcF)?$;x6&<&6W z6JUTgGS}b^l$QJu_IEP?HH-=xvQYfAf{u>E7w#AhgtWv7l$uBqi=vg?j%x;ss3FeX z&d^*IAyl0HQAYi;e2L$z#*YtkPx!^R!h+a=-tZ5I{inkKa)T?}=?~il9wCh^1uXQq zsP!8!qJx+$@&(Xvry?)f#i^Zvq~5nKpZ}t&vhD-WkMVM${GrGz2UB6Y zQbf&p`@eDPvIxR%J6%C7tbEGy@AP|)ThRhJ&(qXcbou{Hzo1ZxH0%5MGvcifp8)_x zsY}5#L6ymlxVdU5h>8nv7}gu4k$rrJdb$$^rH?UZd9k1NSs}3DztZ7}xcYN3RmInq z4A7nY7=UjzKBV+NsA!62f8~7`tvW*JTQG_7WGZa%gU3~30;z0)oFYA8AWxD*@V=D^ zXPc*h*Lt-&5Ob zzzO@}hr$K#y5Rxgs}-tknam6q3{ScTu|qh%z#z)+Vms4sX7EN~A3~|xW)B`gLJ#qG zqJNV6i$SNS7r3yuZA?cL2@RN50qmnYP86QGS|nilSO0?g7y1MuBg=PwI^>onU+Q`?K-~C3O15mI7;&B7G$qLA56eAVljAQD19Q_H)UJ<|CyC?p!t+iC2qHP2NcaQOL* z+7D0LENZ1S?2t&~Qx`2HN+&)`2MiYf=3{K@XBuJ_# zB)<}%g0}4#n&f7IZ6)-5D>4cLWr8d}dx%~r4SK;);u3m%JCj;c1-vE0`b<8980W1T zl99;*5cXuTrys-xE`bgb6%dM)Zfk?0pPHp9isGM6S9E#Y1y0&fbQ2Eq!%5~-nZ%~@ z#|Jx(C<;;M=S;95=wD0_&SXqhmDXF_hb2KH%UkQr$5_la>^k9K-uWO#U$D<`|K( zoz~zD@4*6PO6Un<^-QW3XIOMW#bz)wQbVABjp9I4CO=N8 zNZ7?y3|xzpI}-yOoHE^2Xc)q)L7}|;Esi(}LjX#L##mM&7x&13M60M~{QAo=cN&|H zw&Zx=b_}%bWT7miNUzZg^s;;ZCC_q*a6x~=MDl2=6fc4fdQwm zvyz_l8lt@B*BE`>W&r-5vAZ#ps~5*dl&YjvNDd5p9jnR*JWK=hxqn~o@I{n3stlZh;gx_=XNx{Cpj>G^>Q%~0TajiJFtHmc8P>5fO~(AGI9wE>0UrdC8Smu*_A(h$L3CZHiO1bbAfH6g%uR=p zj}NT}9ywE#F$g1?osz2JkV?F&q$ma^af5uPWf)KhEU+TID!wKj^F#}QTt4;iubkB_ zwQ3F+$)H^=l#=3YyKt}CEOlQ1zkDh3(X-NN{AAIaA`}5m_o~|skY!~)u6AMMvI?|N zO}`|V!JSJ@%<1h6Cj5b7&4mmeu`}CFCCYT~9*v7jXE}fB;f|PeXH49c+u1VV*Oro1 z=9*4bL{sKpwlEQQRMCmGHa{13phpd6(|6m?qL`p#u=X>usVTV1;+(BSK=;H!pQM`@ zWS{O&j%dD$rC5nmgBgV1>fjKJ^}~h#ogN$!%$xITdeEN)Wq$nB9NSg7uASFK?drnL z8;9DAS&trik)F);-Eehv!P!c;k=RS)V-EHHuYFL&Nobp>AT)b<28*;`0w;L|h1yhY z%A_W~R~6PV8Z5}lCHV0*X0R{u*Zki~Yod)Denv19EPF7!y?sh1sl_}~E<|!j($M))7z#Bf~7 z8R|5qGnY|tdJUf;rr|A6a2Ru(?&u3fphpQqBglzXz^Ef`3p#_7ABXpQtgSadH{{A~ z5&UlAXw0CqgpV@YpOe2SBQvj2BTThA4PJu6q_HybAM7)|S9H-2JZEvL#TkpFv>U-JU$mNCJ{6sRliq6b*-wbBACVI^mYZEL>q6%oJ}@GVbm~Y0KaNa&o811rgO#S%2Tt!9m1Lw5 zi}2rPtIz^IHq!wCF-xnuQ`EVTU`vncg>~%v+5pJ&zlrh2f3Eg_u;`=5tbi9|c zx|`ESqkJfJrQ2pelNnhY)rOWkyHrJX^+v!yK`I#0YF-2as(w&93zp*Se8 zcm9!3jpIn0=LS<`KX$0P(`X^T9zgE8jvyqijp?H5`9w^rsu)ydKZPFA+0W}U2BT|b zX`)dk55W*VM!rHvGI+9ZU|iQJ?yKtj+b3##o7ef(U#ue;XL6*^uNFVumW>mQZ`GT< z*p_+ouA;{9(ux##1@ysCLuBDdH%)V|>Yl zz1+n(yC_#!yh8 zbc8$;NN#82?)3LYEM@*`PX89=vm%jcGI~kHT9==yLp2HU1kqu!hStwv)6Fh8*quov zCVQs#{&E%xl15DHW%pv_iuaw!IZb+Be`UE_V&o1>OSWLD<-WoTSLCKL8k!%zX%nqVTdd9<=v)7mylu#cRMY)plzMn^3~tNb++k}q)Kro!VmL7wp9YEtr_-%QJ{pTGGU%}Tg6;Q>8| z?Y?}jWr^g=Cz^&@BU;MIqD2Z0LJm`SeVebKX@vqG7I7U`K3L1OE=K^ki@Uc{02vIX zfRQM6>jMcs*w}GAK8#kc_9L=V8#Qu0KD?v(1OYe|JPF?eJ_05w&$;T~_C2eOnL772 zaz@C*S#{Xrs2s>db2t@m$}}|{2>-47HU2#QZpe`*!Cx1`h|aJ?8YAZEo%M6M9$i*L z(jC|1OrE;Q2OPZDrfHH%M#*=6xQo&XISN<+9?GKSRv3vQ7+s4>0h;zmRCrkE>G$Ju zvdqg@@ygFbQYarX3H#K1FMS})Q882BDV_N!Ju``Tl-zBf-@HRyIG*j66TdMLGm;;S zoLph6NZas#@MKsny0kE;u$Sfj!MRg8Q|EJ6Q^W8EbC%x3=a0pAX~BHxuTfxbvEBC~ zz3YD}fAV|#sAbOVQv2BZrwHnB^EjJR4m*Q~AZ~Z#6@KjTncFK4rVXL8O&<`;?-d*rJVN~Ipx+ZTYw$*auu>4PZdV@72~C%&C+mO-`7p$78{V;$%d>no z50)QKjZd4iMD3l9cM(_qtl0DZE$wz~uf^p>dP<+3$IEJ83gN4~x8@CJ@Yj&FWRlABNpS>&XSZ3F;K;b1e1V@^Ek{E6;NQ zGmfd!Me1II$;!9p2NtqS{<#q96K;}Q;e@gzB&LwHyVkfD6TB18Qhy(be&D+31%U~- z29iPN5uqBw0xaJ&KK6=c&DD1;(5fvmu+m_@RK~}CD-Hz)(YFD@)p)ul;>O^Z(bvc~ zi(p8%nT1&^XT70}$8BqYu}^bXiqLNJ;4ud)JZ?lWJgR(+QK;?ey+dT*;9p~YOC+O8 zvPnCTT*tzzR;ToZguqAIHfY|mcZgb&xVId5uW5+Dl*^00QmmOi4bnl?$9j*F_{?=n zYjsMDSp_~(e+6@w3yexB1^lvtEqYTys|cirTD$^slxwW!54hGZ zZE9MZ3hN3Hg#Y`e1Ewza;2&VFrJY{C!~1roYo^SbNQeS{M0>+6y55VX+(d@PrRti) zfEfp>y4UFP`+s1p$l-;p}2(J%P7T#i=%m?}2%e%n^dPggCRKamrbQe|i9`S%$WER|vij5iOR@jYyB zx*9$|xRB#?@COdmUe|#F6|cd2_lmyP)=e-pi}I6!FYT=Nkpx%?a|<-w+@3w3mw_hl z{OHOjT>zarFF~I_4VeBT2DSqA<~jn?u$^9CMUMiziW$&Di9<^7cby^dAA#?HDud+bqw~~vOJJ1DOZixOliKFs;^s4&roV@J ze-6Lz&DZZWhwKIZp%3`8Fjx2wY_?#Ab}(Hd)<;o(-H}1dk39yLeq#k=Sq$j2S!buoHOv9#A->s~c-4_;iob9M< z#Ah%z2z=!(?f&!2ZKE>(^O>W$@>9F?l;Yajzc}OP1%IZEZ=qK35+AIt(mxW;pjcfk zAIP2d>+1eI&_{Y-_|f767&9wGSg}TMJ93 z?;u@VzrIcJpYFHV*KC~lwW+Jr7UJ7B?fs?(jLrt5MK#h5iYcpveGln*yZYV_TP|#G zIkr9Q?bAc0a3;}C-`+zwI8eLD>_q2I&o`Y(rPGR6y{Qt;1N%do?bB&{WlL+b#(A|y zgy6MVJA;Q-^%ed;3<)XW4by(+g2Im|<7to6&WyVIIy3wtJIPj84-LGI8fmwwOlu#W z-)eYT+j{Dqy0TisD16+z-MJT9J2}wT7Z&|J3Hzj*nm=Cp47>w_+Lt;(aaPaUgU0ke zfhT_f>ZHH5wQ4IHYXUi%wH9jm$k-X{nZm2e$+}>7BS*mqoc?o18wdM@c0+_oAW-z$ z-TwsbO!{(lfsOvNX9>R-11X8rKFB4w3)sPG( zExBxLZ2Fiu_>Rx1q=#-rOp~+MwTu^&lI=SIjDpuEIQ&j`gpb26le*pGA-{2dSk>#t zxpMU7g#Yh7G7p7PE5I_z`Y$x3n{KlvWzuwqw2tZF!xKRnE&hJne_%kMU-KNE#lP_N z$Jw-K6~4WAj=IxYkRY7#VU`O6n5EbY6R}=5Q+5eC7ZcnDcda$--&M_6Qpq#a%Bm7Y zy<&wYM)#-uz!sn+9{}@;Bwn7hiM#rn=th0a-y2$+2_j9H%lRh`^`wZWN>;K&#bM}W^%tP}0A5rX$7zF7p3kxVm-!@ zW_)N}iC8mLl7uIturO%7V3$Fr&Yy!lg04>eZ&Sd!tMbDzXv>j`gO$;FP^X=VLx4a} zpH`van~TLU^hwKMQ^ibRc}$12gMxTK&h$F3u(pG3ZPr}ixdHyUT*TkaEl0J0CgUNw zlh;!gHjbb8bih4PHgT}Z09!Jje-sWj+UlPc9ZUVimAPA50h-8n}n^rrsaeCE<80(q4RB4iiU@VCSBJXK3 zQ6Ft6v=XMm>JH(<$!Fl7%Ytz&yKWxa`QjeMQ9TKvI?-uPd8K@Ouu} zXa?tdY8F`KJ)eg+9IyS@xU%H3Z?aRT0v6Kf12{&z!iv%@nx>b;EFewvisLon*P#s! z$@;aF$VFYy7QpAZ%lG=)R?lXPQT|~#-}eUxXNB#9aegg*DW3EF2B>$W zyGv5P2>gz3n6D6_-W4~Q99gL?oow+mo5=j+1gn~I!a{d-7~f}wYz>EJlx}@+dpmQ! zewm!X2D7(#S^j&I{}FxtQ&oHhcNaHSIyz>qZDdda9OvMZx=vC>DB#yP>iWQiAf zuALfzHg#Gd?&k8nNB>?D7$tf-F5AuM2V%PHJ2>=8{RwKk4bxR zl0@^S@r1;ry^*xa-WPYZUk9(Ny`wBkQ}m_x?=^~&`{{k6EtzNUdA*11gzhM3yzX`h zF`tvEZ9NYa?KkaIZGX>HTN_jRO^JJSX{MfGo%Ocs{*5E*(NEzhi zHz?jU?R0D{WPMAOczKpSuJBWh`#KIsyCfGgqr(r5uNk7Z#|menkV>(&yJ1>=F0RvW zQ^u1E^`Gd}UeV$e9yhP8HBF%H4nd_b5QAk*DxKS&_l4&+T|<6lj`@Z9d$9e@A*d$`uY-myg|*p_dxg&Z%~#8#>zo0z#LrYgOfe5 zsSL+;pRsApz7Bu4QE!_nXF4^1x487vXJSRmPNCwn zJJLGhCV|JeeMyo2f{^TeAB+jmN1?ojou%*}BM~3Xs6l7ad-bf!;r9_EMVmy#Hh-i- z&;f&kubav0^feS-rcYfSoKVP27Y!QxtnfCyE^JS3xo3U+!6(NjP4?fdG#^p<={=GD z$hPpOKA`^KGkN2xCeMVn=J8CmEDrY^$&}ZVpnN^wLm%5}l5I~GanSlIo%wv-ISFO-LAdHG^(`I zJv(@-XSDUvEnPtp^WQAR!j`7Z(>H2((oiYVBHx7@ioJCrUl@8&9|STAq#FKtL{rr_ zD}R30acVvhNK7!<^zP8J(Z*h%n>Ha6fHdAMpKv^?*+7t)29Zuq9X+Sh~i zSgGTuoy`7;GT$HUnl1$-m>M3%UbQ?4I}+@>MhYXn6WJ5})BoT^!P;Sc!aaE!XC0R%z2o(@{4>b`siTCoU1;J)bU&8HImhrqbet)hNrj?KUnc58g;_T-c=W4^{tbirg_gV>ua?a~ zQkxlqL;DH5@mK~+eF+~5&0hU$(Iw7tV`SIP9PXp}66qLR`gguNiYG9I_}uzi|LRdU z0bNf+Gu_OYV%*Wqnj7Y5>EG-b!%Q44$3|fX*gvt3Wo(HR+ilN`VlTT%W(1 zSH#rIU)YLNnX-dv)ubo2nyfr*L?asmU;8b4+=#b&0vHlSNu<>tudm_8Ta-6*rATI+ z25bzP{II3&G9`& zZHg!Cebl$?+PR~K-N?Vuf z#2zzV^m0>1i!8?s&IgIVQ5MSdDSd#T!R}s7mT*TqJe35XG8 z6hxPt%pWbNDY;8`_v=UUlVqAkiLL7SIlU~7<+5>6ywB3FRc{~i!wHM(-KP9%JhrL8 zH@RNLt-nH9yWge<&+wzCl4))M970;xgR6CT(>Kt-=f4#rC= z_Vwj$$M}-#6+0?KS|uSUIo~AA{6Na>q8BR|ei_|nLqUeaa-6Q4jodf>&Aep^eM<3* zpS?XB<~jjy`I?n8Imdj(baIZ=Ve<0+FT$v($l-GXX;J$6%01g(buF^qrDPgs zpbH7eFD|~KpgH=J@jdVrf2kp8-hIrY9_^`-ddJ6w%z_>ze$@!(cq{Q5v>zn8tfy1xT6{;2DkCg`r@+33?PA3q_#SB+0QY>Pu0u7i7=nfXMl8h72Xnuum5|5T${mLL>$M`4T zjs*@>ddLo%1&Wpi3~xhslux1i*t=%}-u40bji2+36V=YNV)Ry@7x+D>fGrgQ4z_LknXJ)!2)~cWP<-T@f}fg&-h5xrg@6=3SS?t zM=maTlqt`SS+qfG&4yaNi>*lY-lc{*4|3bD>pp^9v}SK_1N%#JNM(gvtF_;5oANME zbUU=4?oQ}>+HcV_Xnq%o`miFN`AmVwV@!UJeeM$rOpwzj8*^Y8sI;DjBlzR!G^MI_ z!=SkIM0I`pEs1vB9x#G9I^Aa3c4MnOhIX?^mRz{~qr-b7PQ0e$mmT?Exw=< z$yjr(zv!aXiu6b6=~+Y1#xBzu+@$r1W(g(H zM$#SopOjS&7HH~KrK;{9+OdSQi2^tHYbC7iFTKsXZV2&Xm+uZWfkMciR2?-HRl7exnF#) ztwjiXC|+w%85mnKh5Q!&9(R4P0H={HEiKJ&<+-@RK@ToqWdp!Q4?}l`L$TS{YrM|#TUIe7_Z0zW8tp&1U`~!mK0*0?>?RHL0Uk*X@MktxInf-^OmFL zBO7Vj*qDwT1$H)rHlGwbqj|Ijw+_RHN09G?HZudTE9f~K>@wzay$N~FY>dE1gcg4i zreQ+a*mC{X)3G1-6=E4o{rYm$c_TZt*T>BZehOCCoo!c6ygu7LGW-^Dm-zv?jfR!A zepvsqRr2eW-R+~+(unPJGB(jLbJ6g_7d@~3cvv*ElPY{M?|A&KtZ$N<>6EL)9p(Ht zOwgZ^$Vh4PQQIFHvQQU6e)bFrLJ1cIQGri02@**CkI4Kkmn*Gvq3P;ZCx0?Zb?&qz zd6};230&vu@jty1>T*`^Kz9FdeHSzYfiq<&`n(=*8m(Ctw+M}M8){c)Zv zmtOy&R#_eTjLi^x7!7eev>R^Crks%UYup%l`Plp4ADCJ_`nK?%OPh=-qvbRX zl`!K#RK#1(2Zp#diNbG9Umgh)obr(?x0a>E+ec6Tyg|#KRR3sML++arU0kSr`*j(~ zJ48IihjQn$W&db@VJK0mQyI+i7BZ9+as#(^biRw(AK(9)Aw-_XXHjCFx7u?UYIh2c z-)D?X5_l)otlFD`*GGfzy7evf7sqN^4*uh_gDdU6ihJR|@B6Agv^%HjzH2#z@;f}c z=^g*uJiA#X;{k0L3Ecdgz4%V7k}L`(s`_p)>SsJ84C?O9cEWPcgDW_@wNX3)s(ugw5W88>9>KsX6rR7 zp#ps$#GnV{m8?=iJ7|S4nf)irYq@&`K&JG)Ne@%t*GF;TinACPZ$KMM?;jkh6bTZ( zau+Hv(GFPMOpQB?U9^lrIYs@F>raVwf3RcM+;1=RO=4?ssFE>#g7t1gC@*b~+Dr4K zhqffjiQPdjWEQ2(laqvT*_2bSgUyDezs%O6!XYKFxG7&p+pC7Ix2dUJT%AjZ_fI4W zjz);k55QDO?0^!$t@D|DaF}|6C6_7+XB7B9WMWYMQhIW+{h?sr)(uK(;#R5FFXZdG zIM#A+ug}ggT<0l-{LTx;0(4{$$jABdL7g&L`hK(3lz!pmAhJfSTK{6$m#k;*ck8Nn};mMH?523hXb6 zD*8D!{y2y!+6-6pZ3e`>cBf5f0w^1#5o+K*SaR#WwS&E98N0jsj_wh)Cna1%4P>+` zV}tO(y2Yo)^`3@m05OYBs|h!&VGR}$n;yDCLh;931?_e~AZG>=SdWb8>wQz^Rc$v? zq7W)?zM#f)<|ldB=)F$H2qbAYB)(0Oaya+9ByolcjTgpyCL4sx)GdO6MgN&ex>+9?;QF~r15-rt* z@0#^Zoq^ZX;9BQCuW`ZzkhU4LIRe$l#CqTDvw?Vs`B%TH0D1<}kpv;PkdN1zU! z8U9E#Wum0+x4c4Bw1;~F`jp>~8^O8ZunHVsrhc+QH8^ummdGS?ZhqdL*AR^Gtch8z zoH=*Umt9H2FWKA-5nq7Ai=)A=-v!~7)hy^QK-a|4V3X6}{|G3iM-*Lo5h5$7=8ep~ zGy1O<Q7{e#GMLPt&s-H4s1}3e$l3OlO-m?9~f#(y$Zln zgcYs0>1!9A*X9!)Nbx^?%Lq1?Ke-GI0QgSRIOC9jT)E$dQu0Zq1K}d46v^GNAX||_ zk2KWdB6l#wVm`^%G;hf1rTKJ>E(I`k`}GC)5k8$YPr9NYvJ;i<~$SAY%?Eg(lM(xlVy@TOia`i|r6on$F8VukgzArk(6O?rmM4CW&8{ip^rC^1O)DL~LTet^esoZTwi0Jfu5j1zx%j*u$& zwN^QLwT*8;CZ_q&s_4z4r?d>Rn;>C2F@am|hioKM`f{lPkN1v;!3Na8=;C)iWqKu*g9#!-K2Bf9(Dwy#S%G<=J8>C2I7->(QkT*IW`pD^z3y7+T5^F zlENU3_|w5~*&-U=3?IDYpO-5I$9ALzvLbSbz@iay=B#}5@qn6d%=Spmag0LPL-I|0 z!dQ7#D)8k)SOq@frS507w1JWASRl!i=EEx*gX02=eoTs&Ys@_UmTXNYyx_ilrl9#e^QW3D|H-ajnq*{wPdiMX%1FK z3Km&p@@)i~&nAsYGFxgIF+Yvh5qlx&k)Y(m#=xR3#`!^njF#}|(A=@PV$Vxv@I9JA znTSI^1y&_%BWoo?mURcv{|bGRC~q;8{uH1RT9fbZR?^QZ)K|D7uHkk{<~jdJ_+t7U zP{~}`=|&AGcw>$vxI7)i(W$l&^;$w`eHy(f#7dsn{KXQJjsQHXsIJ9k{5qf}fJMYO zc>UE2Cn!t+sL1K1wv>V8MWtllR}gbJxIA&^waNn~D|>=fCU{#%))FHBXwM}@TsM(>i^ldHmGEaLzn;xT%-JJ2f!nF*>O$>cHbyVL@;)n1_%Fg z)SB);mT*=FF@fV_J#|`}TrqEtzxCD7gOlQ~0hL$3665St8EBz3O~%2M5&d!z1KK4W zlsXcr14rPJ*S;Fk!wrMTM<$=Yl$XCuqM2_%9G#6$gQ5N7feJLGX1pXP2IjJQeMMgh zmQF>cPSN5i%9b!r2EGSm1=-`#(KhtcGoh~j_gA_lpW&D!IzgW#6Rcl8iPyHktiMG6mq$-Y*3%j=krBYk;qEB?`pT75B*`3 zBP-;5E3%CfJyqr>zAIiU;i&?DW_`=#=yUry(?B)EhME2PWH<3k1g^bWx`m~monWPG z-4FGVm0gA`tb}N?)qZAfO&r|HJ6_c3l2BN-@vsK0C?~USdH4H~mnMi%lv$Gz;ios_ z&fkUpT_D@+Or)y6k>N16c|;6y^qc;IBFyHwLmgWrQo}2YLWB2}Wu7O? zD|5RxsATdAA4Fpf4#R7m2*GY1HsaKno3)xo7eT1^Hk`I4lcZE>TW={&mb+ zA`+X=qN!D3G=?LsI;mBe?s=83BOL?2OJDF*emCq+C~bLriJDwS)-?3Z%qX8c5T(7tsZfROm_AY-&}5LH z!GXiba|4XZ0++s!NPOnZ0`atUr^HVH=>GYcCnX5?*HPUa4v5_45$@6Z3o#489GTBN zMSrvLUP+rHa6}1@aH=0pcDP#A7meh6?4{2Yx{EX_`z6A+ah05ob;aL4+N;iVl6rUh z!c-6_OFT8Aq}$tkZ%ynhh!i`cOwM}MMqkuCey__g+E5i4 zy2|v5&mpcx>F}HW6d9*sgQPr+3m}`J>Rw-yY#(*s!Y3RuOt6}&syBkcCo(6o&+Bib zvo#g=Mitra*|}q*o(hqU{wX<1g8u=^rnF)y$v1lBmLYGJF|rYk4bdN)qgm$=o1RIw zo@s2CTXGN8l$jfup8!AtSMrDy%!9ux|$TMJ)C0kF#>Yi8{_RUC z35x-FF5JP#<5S)XI>M1WF8)?~M?+9@Ua|{n0SxU@BmXbcrR479K=2<6&^`43Bo*W| zy(%%_uvigaqA(XzBR9AB;pejmMd~5LXt~SuWJtDN`Fb1$-;y#n}#EM51?vJ^*sr(h@=C5z#AW{Fb`3KC9vz@ zsIyF3H0jl%P}q#d96RlMGQV^stRxgv&6u+9Oj56ZGH2m%V|C91LD=(hWL5RI}=H@G09|PKA@Mhv>re^-P_?rhCQiXW==ye2p9pv-{W7%eW5kzf%15y{cRH)Xai5VIg+|08bEqVw30(L9=L9*Q{p=HuUvVaDVeXJcQtXaP z*FZ#~r^L0NSrTXE1GlCo0wd3L%`MQxgqe?ETEltUx?8!q+P%F;gRmBw=eg+ zUHJ!7MW5=`V)B$4e{rCDM|bZpWp$^w8iyoIW&vb&>zFiPiy0Ph9W^1)gm>(uat!p_ zHN+v0cH^EyImH(I0aaBSA5q?&=hY^-PT6jc1k@X|SZXFG%SH;cqV1hMdxn81+L$f# zJ;bQT|DMHgU|Q0v4D?L^wQd06%+LE)SQ_Z@+vQxqXBkN>C16I*2^Nh~OeMW4i!1biuTiFGuISu79lcV`%cK63NBf7y-#+{~Y&|;Ky!pC3 zB?9rOXID%Uqns+9!>HUCd|aEb*liCPwMBC#0wDiz(i3a;OaJrQjTJtzcKh4MEjPEe z0>6I(N*+d6MyoSk_!{V^fKwnF^{IN7zx?wnxiT{J%F>8Wb4!N7;&)&CjsKi-8+f{) zcQ;c#*2Nyz4VD||zBqVmkYN@Pi3Cundlu1q02Ef?5CLlyXY45nJR1niV$*@Yy!*8R zP=3_1F#rmhsqZj{kGHgp{y<+J6&(XPpA@c863#I4vMAQ6>t%wagRm z4hgne<)gR4^8BHNB0rckbZnQFJ$H>#y6lDAKkQnJOQ43wXqf3os&Q=$>UUaT4;dz7 zI+t3sJ#GDqY=mWLWdp^;3Vb47W%_5m5>s`{*G|7U@>}eD ze(hG{Mi$)NVy{aregwQ@X9Hu;Nu6vWc~slZnVVHx3JDsdhru9qd9i&AYx3X_Aarml zoh0t3=p?y2VdemM%T#=eRbsZC=C~gA0aIl_x8Kg{VU>XrH?%PFF;BBmetz3O zUnT7$fLDJmS>M`>B=Tcm8N;^5)bv_u699sg(a1^(nzTBPL?D3QHy)q)Ch|I>c<-3Q zM;2wRWH1nIx?*`j?yZx@%>e)N-SayR(?wRk^Y?!wjscTDBjo^Iiq}n_IfxQ{Hpj^4 z?eW4(*V{WaXZM;bzn&IqRDSBK`8`)1>^)DUl$%~t#@}?j?R(%BqJ3BrG)NiB@hCCZ zb!S59vMv&4{)OZa>TwWAHt$0_mTms*CPuUxF4^<=yZ$m1vdqcw=d&{3%(3R$)u;j% zB{gvKEh0-ncIxTYchm`Q0q$+M(r$_ZRv%`GN?bi*ECHrLO9HT1LzIE;LZV9~=tF(J z?d2Wdw_6?HS$U&+;L7*U{)i+kn=E}gXFF|bP&S9*Flk>L)?9HOJ?+q0Q_m&O2KKMN zU#b%duoiWK^*G(6|4PQ+^Th%Y4`@TEDUfXDa5H;?>QOTmal#B9$&|1Or3X_|(1TIa z%<<@HMXag9bcdCyL_P;l2I{8`wJh^BKS{{$L_|3NLTp}H3+9CMW-e{J!YS}c z7q8ER052}}=?S`ypHW#5Pg~R!f|!ISOp<#zS#hh|cZz?Co|#8QUdrzGS(5UxVh%Gs zBO^fr6ju<24XB@xtz61dY`G?zW)p>me@3dB8e>1TNzQIscFr|Nm{{gZ`vh#r7hZ@A z3F*6V@$Wpa>Q*MRA5)io>QK9QIy3h3!m3-BOvVJanGDJ)@|O;xF*OU*6Y4=FTmmS= zO8x4u{(79zJIv>7Oop<%l!g+#xTM2c$(}EDcOAMXHMK$zH_Nxy$$(?|A*IFvf3SfE z-U!In9}WkkYQtx}CP16(EZ=!%wcLA@i|w3=hWsO@y_{=l$~O@xoHb0F&r6V7neCHJ!aw2y+n>*Q4ABaR?gUA?r-XwFM7>qEtcV#^o{nl z(eCqgN78-)%rIbSl8bQ^ho6l>uol?O21LO`0Jn=c@GhO#M<-!0rX_p6v=xiVeNP~;e}m;gxj1>oS+NE04)-4+w-fv0QkI%wQXSVLr z`NyiyXr>o~pgBtXPlutAUnm-e zm2()*NX0fH-)Y)?+~$UE;j3sG1ZAobijHt1)j-!c)XvbtFu!pUARTK&DU*Ax4ha0v zMMS=*vr`SWTnqI?`>F}GJ{BE$=O3Uin@icx}mTuBitjO{-Rh= zM`R@r9G?Wg3y60D2tW~*-fk~;einYj(;_GN24DZf#sMbB!4L|^?i;7_2*J5W2?si; zbTB!|{9#Tza;Gic>$&lLh1X}ZI)H6-w+cSXJEZDa^s+K|DB}O8(p#VErO#`37#6Ex zIX+CqZPh{Q&5uB75-;W_7KDT5yORZDAMID6gXl^d2>`Oh0vw(?^k%?G>GS8SXnZQ}=s zmGP)^tyj|wDMB$3B@QuR2Z(vChCXes`T2Jq2zlUp`+o~{42 zBVT~xc|g?ChTnpsa0%nd^xF`g3V;rnbownuzN)HK3P9!rFjpq_Y4yKJ8Lu(Z9qN@I z2BR|tYT8nmZ6Le$e}ZX%5gDvS;>bD}TJRaS9G z$)1*o_(aad9KE8+Y%S4g4tlAudsHJc>Q&-pPT9$X1ERSx8rVGcx#=8EI4144`>iLsk{aQvXiOf3YvF?PCVX?C7~ z=l_Mg_etllDb-yV zr1Ueg+tVTY-F#_TR4oVj__eU@cCDb?1qN3fNZErbm`mp^3VXr?P9h+m6d|%uhXdrG z%(9UIwYcLrjNlQiQ2@dOLU5S@FPt5aSE=uL4o3NgH{UcsiZ5;e9Ke7OzNLp8XgDQnbfSYH{0)#Eq-Hu4I`h zC-bM`lf56OWH=N8Bn@u+PZ%6O$nQ@4$xB4w9r6546-rR*0d3)ch~FB}JN$Q+@i!wu ze=wYy(TB3UbA=cuOO^&#s;<%+vykt0VC^OKWoj@hu3AmaU2Y?}`nt6#gyTpVruVag zsNI)myZHL5rNFf7n{T+JXuA(7T>LtD7T}acND3vrUvU98q*w$eAl7hkx6hMfP@jCX z#=Xuf1CgishnsEx@~WJ$0d&|9taMITg&Ao`NQfVx$kK5}TKRLPaP{luiL(2z6@* zS^C*x(>{d9cFNB_obA?b?hc=#)g5TquEI2GuEJGL6@KzUtJLBq(>c*Wwb|1?&J_xq z5d|}YCr3{&LQ#cx0c7V5P!LtdB6PJ5pw?sK#Cl%8QbyZ5rrRe(1xM>`-vTj)y80aC z>ohoWwCc+F#k6_q+i}pM<9k!@`2}3D{hTO$v1`}R@85ST?fdh)qPNE~?&Hsc&g(RF zRc-t(smcL4VVux7 zh5iY~rXxvfM&dN#_knCP%M;C%n3x?ixs;wI>iKLxx3|rofhJssvds0WPu}bTfjrzF zM3HWzHQT)KG&qBTGhlB<%|XQ-Ipn;Gqlj-u7c&$ z_HzxZnv^(&FR*cFfi%PIeelTRg3MOoro&w0L>--6wz<6DkI)hk6uYsJxaf(kekI(f5*qKuA&)n3>uK4$ zy$tJp`2#?}DIle>HU?Cm)LRY&E1!~>og#G*h>~YyM3^1HksLG>!gnhSfwC}9M*!ZX!uPaBQo(%7eEV2R-k5w+RR!mZ(JY z_pf)PqIW^UCPM%=b{lDH!DJWt7DammhG!a?iCz>Fv$P`|*7IDKmr5OGqX!VHAB8nP z_1%QZ+Xup7^AVM+wQ7g!kJM;)Du@Tsg>|v6^kS5IeO(c~LaQ>)>n#K^FeAsV+Viign2s-8drvW&XVr zV3w~kX};PR_p$%IEESQxmpj>{o2@o{4Eisvb+K9zaUx2as{5BXPydmq32pzU$JJ~0RBG;!Shcg-?2*T_p z0NIe-K5DP`NbCTpv@U=8uDkAh;0F??^!IVWN)`I~0x2oz*pk2(1K5`3?eQ^>a8^OM z_{1@NaFn=^uT_0^PY?Ir)pNo8=%7p}_HNeKiTB`LSG?pGxivIPPEeZJ(s12EiR{QF zXbt)6bb978gmJQCLSD_L(uQm{45hOF1nlq2WF-phv?ykfP-6lIky^fl0J+n-Ou3P} zuXev|2s|%I0bxdvID9;mK2SXoUui)P$nGYv8DL2n7oba}e;I`MWU(}9HKG{U0xw*L zoxD^=hj$IWroHUi6Ll}&NcXhM#h5l+t|tK5pBoozE8{#riwIJ_AfSO84aoNK`S>~5 zT}!`1HI+4!a?z0+V%82SR-29*i6kNS%!Si>H2_SLiSGpgb~+)ZuBBL} zcg9eaOI4|nxqC=9%cT+)P`%m#Ag(h`Jm3tFrk6tk3e@{;`YPFZ@qkt6^;z~EPf z$)K?t&~g!Y1;9SrJ3Qon`}j!;2cH)$Yma$2Idprn{xL9@faEl*cf;c){#~S0G|=Nfa=va)zsa&34Mxc=pWBJS?IzpIJwQy%0C>K=5jTCfU@18o5=u{pddn8s z0x25{!Fs8X^OC26F8I%9dZ)8Q_pOFT@Cdh}SY9m7N^MpjdzIjuKf5*}BKJilza$F*MwbaZ*)}n` z;)$HK8K8Af2)Ar7KW+y2eG~|wn5zKJR)f7;IuSZ=B?p$7bU$%*(~%{1V9EEzfo4q) zM!(p$6hh%JB3q{*M~&o>?~zgx$;uo^aiLBSTM8OThIQlC^VNI*QY7`sc(??8oj$K!+q!^U+O z0L$-&yu91600wUO3V?FbgdAeT?Kl3^zTZ@dT)L#}u|M?GRYt+TtRL`Mx~%@%RxzI_ zfC`~_*y*!Z@zu7BU+j$+L66(PWI2J?{!A!=u<}Z$GKH`se7Gu&&l;XL;gYv6KAJb7 zoVF8eVdV3{gY)58?3v8<$*l;=C&gN@$jxMBQh$l`boo1%`JAJW zmQhqz92={Y8pYTO=XD95S{G>Trdt3Nwk&y9V1Dr~7)Ebf$8TWZNC+MPfnS_GxM@R| zk+&T1h(6XrCf%*F%E&v&5>+VY3&id)&YHh%2XAs6qMmuwDR>WWsL%R*mfzf;{otGI z1v49eOGRn7&b4PIZ8yoMXG4 zDzFBTN^ zE^U@bBN3Vz5->fgzVlBM!l8xyOnnLa=XrWFzIzYQa=+)b9@JkNIetxCVsCdq4w8*d z^S`=mbr+eZ_hOC4|1sj$H%x4|sS|ReHlMM=1YS{zC>!_tGdYn_6OPa}_M-fAIwl8n zEsOuS$@wgB$e!-C$Oa2gn0u;f7jC@VN3HUuyPHqsWQHJ5wOlsrye0#${AAElagKhN zm|gYP+IjwwKv%zMv~f?4iy)rho7QI|Up!*o$Tam|nuigVi>_!3uS_ey@#15*TmJNA znnTny#-V2)OPDAi>REhG2qd;-dGVdetToc^1skj3zk!;jJ&8^(!LoF{?QCDx>lbta~ex z?OkfC#2tRPn4inIyijud5Y}bXv}Nk)DMrj}KwxdFipvtxno+No0aJug z2q>3p_^kNYaldMNeZw%tWUt2h>CXcZaM~{}B_;bj|8lzzwYjjaoaSa?N=nI$b%e|K zT(GL8rFgkVYxp7)WnOg3(!m}+^^)*NY@LC(pBJ{CvI8cMX`D;O31=JOt{C%8(o4q= z8=HxMatV_%^D|0kEKW0fAMDoK;HCXv`-evHhheH$KZ1jy}g&-X`XE_~;EcqOx7F?Ifmh{o4puk-IgfzPND{XQa_q!q>=(}ZBzvSsB=IomFn0;=ZW7b? zLdTnjD`hXbG6G&i3@vqc!JYZ8uG*elgBFPp-95Ybf1MA=59Sbn$6@_N7&j?EO2fhZOi|W5UiAG(ye5 zy}!au^Zs%5H-%>)SyO1&xs)zi7{Uxa9x~oVcwLN zJp8ogbC9@B=`wDa{;fJW9Jk9HE-=BmW8p!lQfzp+tEb8tO1AQ68GW6lTEfrXUqg`o zh4@eN6a{qLo0>V~9GRcGW`-=VONY$nvkLrBu9wk$2kQ5`K*W|ze%AX`nBEHW8xHAyU!RsI}*=vS;jBKfBaR>B4@#Fi3nPg~(T9EJcB9wE@G zJX)1YtMd45N$!oIR6dETgR7&S@6kB_e>uO8=w zv8gW;OW&A0+c%XsOG3{I0mXR3<(#%TM_R<6=~fw=!ExZq<58F>5C(A1Z%4hl5$gN{ zVQaW|Mn)Qa9D&igdrFP+z7TW{YUR~clRtKs=0S@(dsdyeTPE%M8Z~TdMwLvyC;CW0 zLxwS%Zv#ZOqCSd10J%TbD$BL(7x@ove|4!6CrYRrg@zW9DNgggZrNr{(AO^?8;jas zbTFXY>&eNHswVy}wC0 zZeEo2Zv8@aST((};Qal{#2IbTmbL4~wd*Rg=$SZps3#b${>np(&o?$X^l9A0@e>a^ zFm4%r-ts_b;gzBRR%uUqdrx*;Il<=uSD^&*tt1g>&yTS-tFs%q><*Psi&oXiF~`h= zD9qaIbT;8)RY`?U%a{s32=5n@fl4;tg-V`AdxLa>5#r+(nJ`2s=e|Apj%E&vAolvP z^~v+tShTR$#Nda4z5BBA2zupWGsidUB#brpKMEmu^s%(Pv|S(;u?UcJfx9@2LP|!u ze<(O?sK@?M7b8q@J_PY51p=;+md}cV^vy+rut0cV>l-?TNLmJl5ejf02pkF`_KL-? zB?j{XyH%ybcr~mX+FBqq!?c0Jwc!Ys28V{U1&H<6P=t^(lKwjksajyRCo9hy#=;Ei z2g8^(+~{&gJ&;zcvDrB{u3-mn@xZ1oLXs48xfA%{&8=gra%uS-2G|Y-ZSFiic%?jE zM*az2)*Ev0_LJB*SnjZ6cSeWRr(wFk}7Sf@HV8LLdyG1UUaK)J<)T*oj_AK3w+Cvj{AB(_4Dz{f3aX=GnI~KrGH6N`6~MJ6&Kodc+%Y3gJ{V=KAZ8<8Tvm zigLeK?>trA;lf(`MBD2p-OZ_7ECAbsK9u zOx*-vIe&%gR7Wc#E_}$h&`H0;m4+Jj92=jsN1%KKQqF`4`a~B<^gK}j_HTQlg2b@2 zHcrQlZlmoAZanw_(M_6d-}~*SpO<%5Fv0>44t=Q`(<{&&N+=g53eCiz09QSz@BD96 z?oVWuck5w9`iTMS+57qC*zBeDRFkpX?a#VAYoLLg&RAB68O3U67+qI7y((%HNbjS; z%6|`2&^wkkL{&FaRW}R6aXm(+KS71g+}Cjye4C15=_J1{Yk)0Y@%Z%I9hCi68X#gghVjpe_TmZENyCzs;;K& zcn!rM2wcHCk8L2^|9dSVRuWB2BDUgd0~>E^m0zBplShca|GKL8NDO-r3pt2|m>FV5 zB%63qwq(R5zD^6ZQPGtCucu25mX!PWFa<=fkB^-b z4tP1jY;}0xIG!=$JoYypr+#T&)vi^DsoqDOloiio9U}-{M1j2EukZw5Rwz!P|JnS# z$pXeMV@}Ujn7zjup^EICdiQp;J_Mn=fVMinhIZBdnf~d&#Cg~O7yA=grwlTpjQsDzt8BnMt8vNX5*#psZInPkTm}ly#@AOUbF;XH zLuWL&v8V}lZ)%v`o=9goKgUXar1q17SrYOi2d>Ka16w5~r@&EzCg7m3svvWwP<0RZ zi4hu)9TgiQD>Ld#>&6oBNmWWDcV#uX^4om&p-J zFO&TfBuE+h8^OGmFH6HNN>)!g*4q~$;pT=@;q)dpULoAah+-UTC036ldZOzX!WJs` zM)%Z8MAJMlH_sRIKWgHopx*Dq{BFjMF?EcI;pQs++4a6#T)#!`(#H)|(M$7G{rURdY#ROULJ%LA z@spc!3aWeT?Y^M=0-@QW){hOGV~^3zgnjBLgRnU7>*SZ&Z*Al|`6bVA5du`-NBMou zU5f1#`(K@IvsUG9X45r35cTLHVP@@6wMOe^vB@kc>`|1W+Zd^N{mX!yPe{0YVLJTF z4vI)N>9@EBN0FS2&P`&=3`_q=(?RN4GN_Xc1+_$(@E5bfQ zS4QvYT9#%%Qm2-63733#zqCX1)i4gaEK)e~^}rKjW@%G#K0T^Dqws!}F*moCl3(#| zRf92IVYn@yVB*+JlB{%WvsJ3+&%M8=(U*jy62M6R=GPR|dZ_j!@iV^;%SVu%*qRjWS~_b2T3wnl!K@<8HT?nKfxSH1@Jkeuc&Q#GGLNOwMSJ~`j| zcRva{>7<*n*$3%-MU9qie{WI2-*94>&OFn(UtmTM?cX`cwvwEvz_*lfvj6TU!)97A z6tN*Fv*b}yUS|0C-%&fFWv*0U(M`sC1Z?*Al%LaUFgIhz7lbVK1o@x*cbEg^dn&Nu z5Sgj=0Lj0LRaj+(O@<9u=5!BR;QrfHxVpFXEp~j0k7#_6=XdMA65YR>C~qyN@4L&= z`Vw88MtXgD8rkvR&D8{D)v`iqsY`JE-`4ULSkwL;n8Q?CRpaWl5bvs~%aQ7-ryu_g zwYJ_4`rYJsCR^40U$mYC@lRj;;Yay5;*)28c+Gp8H^>~h$ZW6K(n}8hJ?mOt&C9#O z@}janIL)w}lvKxYcTsuz&6Po?F(<4%jd}LvI>bBu?)J0&y zKgvqbn=)I4;Xicu7dWE?cKBm%54}loWuP1|H@A#W82tGSC>Nm;aX Date: Wed, 22 Mar 2017 20:04:00 +0100 Subject: [PATCH 597/746] small fix --- src/NadekoBot/Modules/Gambling/Commands/Slots.cs | 8 ++++---- src/NadekoBot/Resources/CommandStrings.Designer.cs | 2 +- src/NadekoBot/Resources/CommandStrings.resx | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs index f4cf201a..198d4d72 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/Slots.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/Slots.cs @@ -144,11 +144,11 @@ namespace NadekoBot.Modules.Gambling await ReplyErrorLocalized("min_bet_limit", 1 + CurrencySign).ConfigureAwait(false); return; } - - if (amount > 9999) + const int maxAmount = 9999; + if (amount > maxAmount) { - GetText("slot_maxbet", 999 + CurrencySign); - await ReplyErrorLocalized("max_bet_limit", 999 + CurrencySign).ConfigureAwait(false); + GetText("slot_maxbet", maxAmount + CurrencySign); + await ReplyErrorLocalized("max_bet_limit", maxAmount + CurrencySign).ConfigureAwait(false); return; } diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 045f5885..cc7550b6 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -9006,7 +9006,7 @@ namespace NadekoBot.Resources { } /// - /// 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.. + /// Looks up a localized string similar to Claim a waifu for yourself by spending currency. You must spend at least 10% more than her current value unless she set `{0}affinity` towards you.. /// public static string waifuclaim_desc { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 14a6e44a..790df4de 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3001,7 +3001,7 @@ 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. + Claim a waifu for yourself by spending currency. You must spend at least 10% more than her current value unless she set `{0}affinity` towards you. `{0}claim 50 @Himesama` From 9f5a71ae67d48f9b01de68ab9fc3592fe73b9211 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 22 Mar 2017 20:31:44 +0100 Subject: [PATCH 598/746] Update ResponseStrings.zh-CN.resx (POEditor.com) --- .../Resources/ResponseStrings.zh-CN.resx | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx b/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx index 57e2e91c..e756cf57 100644 --- a/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx +++ b/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx @@ -2324,64 +2324,64 @@ Fuzzy {0}投票总数。 - + 用 `{0}pick` 命令來捡起。 - + 用 `{0}pick` 命令來捡起。 - + 此用户不存在。 - + 页面 {0} - + 您必须加入此服务器的语音频道。 - + 没有可设置的语音频道身份。 - + 用户 {0} 被静音和禁言 {1} 分钟。 - + 新加入{0}语音频道的用户会得到{1}身份。 - + 新加入{0}语音频道的用户不会再得到身份。 - + 语音频道身份 - + 触发 ID{0} 定制反应的命令不会被自动删除。 - + 触发 ID{0} 定制反应的命令将会被被自动删除。 - + ID {0}定制反应的回复不会已私聊模式发送。 - + ID {0}定制反应的回复会以私聊模式发送。 - + 没有找到任何命令别名。 - + {1} 命令的新别名设置成为 {0}。 - + 别名列表 - + {0} 命令的别名已经成功删除。 - + {0} 命令没有已经设置的别名。 - + 竞争比赛游戏时间。 \ No newline at end of file From 085ac26a5e06835e87fe511adc8cf0242b8d1342 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 22 Mar 2017 20:31:48 +0100 Subject: [PATCH 599/746] Update ResponseStrings.zh-TW.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.zh-TW.resx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx index d42f47bc..051bb851 100644 --- a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx +++ b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx @@ -2181,7 +2181,7 @@ Paypal <{1}> 上線時間 - {1} 成員的 {0} 是 {2} + {1} 的 {0} 是 {2} Id of the user kwoth#1234 is 123123123123 @@ -2267,13 +2267,13 @@ Paypal <{1}> - + 找不到別名 - + 現在輸入 {0} 會被辨識為 {1} 的別名了。 - + 別名列表 From c9985ede2ccb0dcdb55622ec9518e4e9f8c483d7 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 22 Mar 2017 20:31:51 +0100 Subject: [PATCH 600/746] Update ResponseStrings.en-US.resx (POEditor.com) From f8efb04d78240955cd75f53a7826ceec7224ca98 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 22 Mar 2017 20:31:55 +0100 Subject: [PATCH 601/746] Update ResponseStrings.fr-FR.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.fr-FR.resx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx b/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx index ee351ef0..783470c2 100644 --- a/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx @@ -2383,22 +2383,22 @@ Fuzzy Le message de réponse pour la réaction personnalisée avec l'ID {0} sera envoyé en MP. - + Pas d'alias trouvé. - + {0} sera maintenant l'alias de {1}. - + Liste des alias. - + {0} n'a plus d'alias. - + {0} n'avait pas d'alias. - + Temps en jeu compétitif. \ No newline at end of file From ca49a39c5b2a6da63c9961a3450fa3bfb720acc9 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 22 Mar 2017 20:31:58 +0100 Subject: [PATCH 602/746] Update ResponseStrings.de-DE.resx (POEditor.com) --- .../Resources/ResponseStrings.de-DE.resx | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx index db44d4ac..9c071e54 100644 --- a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx @@ -476,8 +476,7 @@ Grund: {1} Fuzzy - Liste der Sprachen -{0} + Liste der Sprachen Fuzzy @@ -1281,12 +1280,12 @@ Vergessen Sie bitte nicht, Ihren Discord-Namen oder Ihre ID in der Nachricht zu Währungsgeneration in diesem Kanal aktiviert. - {0} zufällige {1} sind erschienen! Sammlen Sie sie indem Sie `{2}pick` schreiben + {0} zufällige {1} sind erschienen! plural Fuzzy - Eine zufällige {0} ist erschienen! Sammlen Sie sie indem Sie `{1}pick` schreiben + Eine zufällige {0} ist erschienen! Fuzzy @@ -2371,22 +2370,22 @@ ID des Besitzers: {2} Reaktionsnachricht für die benutzerdefinierte Reaktion mit der ID {0} wird nicht als DN gesendet. - + Keinen Alias gefunden - + {0} ist nun ein Alias für {1} - + Liste der Aliasse - + Der Auslöser {0} hat keinen Alias mehr - + Der Auslöser {0} hatte keinen Alias - + Kompetetive Spielzeit \ No newline at end of file From f89bd49c5272050e097cfe0c2f12d7ce25f950c6 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 22 Mar 2017 20:32:02 +0100 Subject: [PATCH 603/746] Update ResponseStrings.ja-JP.resx (POEditor.com) From 9c5a1ffabc7bf8bd103dbd027a19053ba568b2fa Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 22 Mar 2017 20:32:06 +0100 Subject: [PATCH 604/746] Update ResponseStrings.pl-PL.resx (POEditor.com) --- .../Resources/ResponseStrings.pl-PL.resx | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx index 6517d703..013b1cd8 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx @@ -1006,7 +1006,7 @@ Trwa {0} sekund. Nie nikomu. Ciiii. Możesz wspierać ten projekt na patreonie: <{0}> albo poprzez paypala: <{1}> - + Komendy i aliasy @@ -1194,6 +1194,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś + Jakies pomysły jak przetlumaczyć Submission by miało sens? Brak głosów. Gra zakończyła się bez zwycięzcy. @@ -1585,10 +1586,10 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Filtrowanie zaproszeń na tym serwerze wyłączone. - + Filtrowanie zaproszeń na tym serwerze włączone. Przeniesiono uprawnienia {0} z #{1} to #{2} @@ -1732,7 +1733,8 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Zdefiniuj: - + Porzucone + Fuzzy Odcinki @@ -1783,7 +1785,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Poziom - + Lista {0}place tagów Don't translate {0}place @@ -1877,22 +1879,23 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Streamer {0} jest niedostępny. - + Streamer {0} jest online z {1} widzami. - + Śledzisz {0} streamów na tym serwerze. - + Nie śledzisz żadnych streamów na tym serwerze. + Jak lepiej by brzmiało; streamy/strumyki - + Nie ma takiego streamu. - + Stream prawdopodobnie nie istnieje. @@ -1919,7 +1922,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Tłumaczenie: - + Typy @@ -2237,7 +2240,7 @@ ID właściciela: {2} - + Dziękuję za oddany głos, {0} From 77f80e8309543c0bfa6ad60eaa6408b66b8397a4 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 22 Mar 2017 20:32:10 +0100 Subject: [PATCH 605/746] Update ResponseStrings.pt-BR.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.pt-BR.resx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx index 1fa1070b..f24177e0 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx @@ -2369,22 +2369,22 @@ OwnerID: {2} A resposta para a reação personalizada com o id {0} será enviada como mensagem direta. - + Atalho não encontrado - + Digitar {0} agora será um atalho de {1}. - + Lista de atalhos - + Comando {0} não possui mais um atalho. - + Comando {0} não possui um atalho. - + Tempo de jogo competitivo \ No newline at end of file From 42fbbb51d886d40f8a72acd67cf7da851da4631a Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 22 Mar 2017 20:32:13 +0100 Subject: [PATCH 606/746] Update ResponseStrings.ru-RU.resx (POEditor.com) --- .../Resources/ResponseStrings.ru-RU.resx | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx index 250cb254..b1039c13 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx @@ -607,7 +607,6 @@ Все роли пользователя {0} были успешно убраны с него - Fuzzy Не удалось убрать роли. Отсутвуют требуемые разрешения. @@ -641,7 +640,8 @@ Удалено повторяющееся сообщение: {0} - Fuzzy + What does it mean? +Fuzzy Роль {0} добавлена в лист. @@ -1092,7 +1092,7 @@ Paypal <{1}> Второе число должно быть больше первого. - Смены чувств + Изменения в чувствах Fuzzy @@ -1355,12 +1355,12 @@ Paypal <{1}> Песня завершилась. - Отключено справедливое воспроизведение. + Отключено честное воспроизведение. "Честное воспроизведение" не подойдет? Fuzzy - Включено справедливое воспроизведение. + Включено честное воспроизведение. Fuzzy @@ -1421,7 +1421,8 @@ Fuzzy Не удалось удалить плейлист. Он либо не существует, либо Вы не его автор. - Плейлист с таким ID не существует. + Плейлист с таким номером не существует. + Fuzzy Добавление плейлиста в очередь завершено. @@ -1524,13 +1525,14 @@ Fuzzy Включено использование ВСЕХ МОДУЛЕЙ для пользователя {0}. - Добавлено {0} в чёрный список c ID {1} + {0} добавлено в чёрный список под номером {1} + Fuzzy У команды {0} теперь есть время перезарядки {1}c - У команды {0} больше нет времени перезарядки и все существующие времена перезадки были сброшены. + У команды {0} больше нет времени перезарядки и все существующие перезарядки были сброшены. Fuzzy @@ -1621,7 +1623,8 @@ Fuzzy Включено использование {0} {1} для данного сервера. - {0} с ID {1} убраны из черного списка. + {0} с номером {1} убраны из черного списка. + Fuzzy нередактируемое @@ -2024,7 +2027,7 @@ Fuzzy Имя: {0} Участники: {1} -IDВладельца: {2} +ID Владельца: {2} На этой странице не найдено серверов. @@ -2182,7 +2185,7 @@ IDВладельца: {2} Время работы - {} пользователя {1} — {2} + {0} пользователя {1} — {2} Id of the user kwoth#1234 is 123123123123 @@ -2256,24 +2259,28 @@ IDВладельца: {2} Роли голосовых каналов - Сообщение, инициирующее настраеваемую реакцию с ИД {0}, не будет автоматически удалено. - Fuzzy + Сообщение, инициирующее настраиваемую реакцию с номером {0}, не будет автоматически удалено. + Изменил "ИД" на "номером" +Fuzzy - Сообщение, инициирующее настраеваемую реакцию с ИД {0}, будет автоматически удалено. + Сообщение, инициирующее настраеваемую реакцию с номером {0}, будет автоматически удалено. + Fuzzy - Ответное сообщение для настраеваемой реакцией с ИД {0} не будет отправлено в ЛС. + Ответное сообщение для настраеваемой реакцией с номером {0} не будет отправлено в ЛС. + Fuzzy - Ответное сообщение для настраиваемой реакцией с ИД {0} будет отправлено в ЛС. + Ответное сообщение для настраиваемой реакцией с номером {0} будет отправлено в ЛС. + Fuzzy Альтернативная команда не найдена Fuzzy - {0} будет теперь альтернативной командой для {1}. + {0} теперь будет альтернативной командой для {1}. Fuzzy From b860a17f240c1244800d74189d2bca997c135686 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 22 Mar 2017 20:32:19 +0100 Subject: [PATCH 607/746] Update ResponseStrings.sr-cyrl-rs.resx (POEditor.com) From c2e0bb84de0e315eea7d081018387ef06742a28a Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 22 Mar 2017 20:32:22 +0100 Subject: [PATCH 608/746] Update ResponseStrings.es-ES.resx (POEditor.com) --- .../Resources/ResponseStrings.es-ES.resx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.es-ES.resx b/src/NadekoBot/Resources/ResponseStrings.es-ES.resx index 4e34bf78..37e12fc6 100644 --- a/src/NadekoBot/Resources/ResponseStrings.es-ES.resx +++ b/src/NadekoBot/Resources/ResponseStrings.es-ES.resx @@ -1518,7 +1518,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Activado el uso de todos los módulos para el usuario {0}. - Enviado a la lista negra a: {0} con el ID: {1} + Enviado a la lista negra a: {0} con la ID: {1} El comando {0} ahora tiene {1} de enfriamiento. @@ -1614,7 +1614,7 @@ No olvides dejar tu usuario de Discord o ID en el mensaje. Activado el uso de {0} {1} en este servidor. - Removido de la lista negra a: {0} con el ID: {1} + Removido de la lista negra a: {0} con la ID: {1} ineditable @@ -2260,22 +2260,22 @@ IDs de dueños: {2} Respuesta del mensaje para el comando personalizado con la ID {0} será enviada como MP. - + No encontré ningún alias. - + Escribir {0} ahora será un alias de {1}. - + Lista de alias - + El comando {0} ya no tiene un alias. - + El comando {0} no tiene un alias. - + Tiempo de juego en competitivo \ No newline at end of file From 692d6d2db32b8810123b91b65bc9792a1fb5578c Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 22 Mar 2017 20:32:25 +0100 Subject: [PATCH 609/746] Update ResponseStrings.sv-SE.resx (POEditor.com) --- .../Resources/ResponseStrings.sv-SE.resx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx index f5297053..bd3d6093 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx @@ -2336,25 +2336,26 @@ Medlemmar: {1} Röstkanalsroller - + Meddelande som triggrar den egengjorda reaktion med id {0} kommer inte bli automatiskt raderad. - + Meddelandet som triggrar den egengjorda reaktion med id {0} kommer bli - + + - + Ingen alias hittad - + Skriver {0} kommer nu vara en alias av {1}. - + Lista av aliaser @@ -2363,7 +2364,7 @@ Medlemmar: {1} - + Kompetitiv speltid \ No newline at end of file From 2d41f4aa02ee953142fa912264a6ae8c8f7d4483 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 22 Mar 2017 20:32:29 +0100 Subject: [PATCH 610/746] Update ResponseStrings.tr-TR.resx (POEditor.com) From 64c52f1cd08c717b1e57885448733b55be36c353 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 23 Mar 2017 12:09:15 +0100 Subject: [PATCH 611/746] >trivia pokemon added --- global.json | 5 +- .../Games/Commands/Trivia/TriviaGame.cs | 39 +- .../Games/Commands/Trivia/TriviaQuestion.cs | 6 +- .../Commands/Trivia/TriviaQuestionPool.cs | 28 +- .../Modules/Games/Commands/TriviaCommands.cs | 14 +- src/NadekoBot/data/pokemon/name-id_map.json | 3246 +++++++++++++++++ 6 files changed, 3319 insertions(+), 19 deletions(-) create mode 100644 src/NadekoBot/data/pokemon/name-id_map.json diff --git a/global.json b/global.json index ae345495..2c5832ca 100644 --- a/global.json +++ b/global.json @@ -1,3 +1,6 @@ { - "projects": [ "Discord.Net/src", "src" ] + "projects": [ "Discord.Net/src", "src" ], + "sdk": { + "version": "1.0.0-preview2-1-003177" + } } diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs index 18e46fa5..3bfb8b1a 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs @@ -25,6 +25,7 @@ namespace NadekoBot.Modules.Games.Trivia private int questionDurationMiliseconds { get; } = 30000; private int hintTimeoutMiliseconds { get; } = 6000; public bool ShowHints { get; } + public bool IsPokemon { get; } private CancellationTokenSource triviaCancelSource { get; set; } public TriviaQuestion CurrentQuestion { get; private set; } @@ -37,7 +38,7 @@ namespace NadekoBot.Modules.Games.Trivia public int WinRequirement { get; } - public TriviaGame(IGuild guild, ITextChannel channel, bool showHints, int winReq) + public TriviaGame(IGuild guild, ITextChannel channel, bool showHints, int winReq, bool isPokemon) { _log = LogManager.GetCurrentClassLogger(); @@ -45,6 +46,7 @@ namespace NadekoBot.Modules.Games.Trivia Guild = guild; Channel = channel; WinRequirement = winReq; + IsPokemon = isPokemon; } private string GetText(string key, params object[] replacements) => @@ -61,7 +63,7 @@ namespace NadekoBot.Modules.Games.Trivia triviaCancelSource = new CancellationTokenSource(); // load question - CurrentQuestion = TriviaQuestionPool.Instance.GetRandomQuestion(OldQuestions); + CurrentQuestion = TriviaQuestionPool.Instance.GetRandomQuestion(OldQuestions, IsPokemon); if (string.IsNullOrWhiteSpace(CurrentQuestion?.Answer) || string.IsNullOrWhiteSpace(CurrentQuestion.Question)) { await Channel.SendErrorAsync(GetText("trivia_game"), GetText("failed_loading_question")).ConfigureAwait(false); @@ -76,7 +78,8 @@ namespace NadekoBot.Modules.Games.Trivia questionEmbed = new EmbedBuilder().WithOkColor() .WithTitle(GetText("trivia_game")) .AddField(eab => eab.WithName(GetText("category")).WithValue(CurrentQuestion.Category)) - .AddField(eab => eab.WithName(GetText("question")).WithValue(CurrentQuestion.Question)); + .AddField(eab => eab.WithName(GetText("question")).WithValue(CurrentQuestion.Question)) + .WithImageUrl(CurrentQuestion.ImageUrl); questionMessage = await Channel.EmbedAsync(questionEmbed).ConfigureAwait(false); } @@ -128,7 +131,19 @@ namespace NadekoBot.Modules.Games.Trivia NadekoBot.Client.MessageReceived -= PotentialGuess; } if (!triviaCancelSource.IsCancellationRequested) - try { await Channel.SendErrorAsync(GetText("trivia_game"), GetText("trivia_times_up", Format.Bold(CurrentQuestion.Answer))).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } + { + try + { + await Channel.EmbedAsync(new EmbedBuilder().WithErrorColor() + .WithTitle(GetText("trivia_game")) + .WithDescription(GetText("trivia_times_up", Format.Bold(CurrentQuestion.Answer)))) + .ConfigureAwait(false); + } + catch (Exception ex) + { + _log.Warn(ex); + } + } await Task.Delay(2000).ConfigureAwait(false); } } @@ -186,10 +201,13 @@ namespace NadekoBot.Modules.Games.Trivia ShouldStopGame = true; try { - await Channel.SendConfirmAsync(GetText("trivia_game"), - GetText("trivia_win", + await Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle(GetText("trivia_game")) + .WithDescription(GetText("trivia_win", guildUser.Mention, - Format.Bold(CurrentQuestion.Answer))).ConfigureAwait(false); + Format.Bold(CurrentQuestion.Answer))) + .WithImageUrl(CurrentQuestion.AnswerImageUrl)) + .ConfigureAwait(false); } catch { @@ -200,9 +218,12 @@ namespace NadekoBot.Modules.Games.Trivia await CurrencyHandler.AddCurrencyAsync(guildUser, "Won trivia", reward, true).ConfigureAwait(false); return; } - await Channel.SendConfirmAsync(GetText("trivia_game"), - GetText("trivia_guess", guildUser.Mention, Format.Bold(CurrentQuestion.Answer))).ConfigureAwait(false); + await Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle(GetText("trivia_game")) + .WithDescription(GetText("trivia_guess", guildUser.Mention, Format.Bold(CurrentQuestion.Answer))) + .WithImageUrl(CurrentQuestion.AnswerImageUrl)) + .ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); } } diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestion.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestion.cs index d9c908a8..01e676fd 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestion.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestion.cs @@ -20,13 +20,17 @@ namespace NadekoBot.Modules.Games.Trivia public string Category { get; set; } public string Question { get; set; } + public string ImageUrl { get; set; } + public string AnswerImageUrl { get; set; } public string Answer { get; set; } - public TriviaQuestion(string q, string a, string c) + public TriviaQuestion(string q, string a, string c, string img = null, string answerImage = null) { this.Question = q; this.Answer = a; this.Category = c; + this.ImageUrl = img; + this.AnswerImageUrl = answerImage ?? img; } public string GetHint() => Scramble(Answer); diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs index d85a15c1..854db99d 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs @@ -1,10 +1,9 @@ using NadekoBot.Extensions; using NadekoBot.Services; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using System; -using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.Immutable; using System.IO; using System.Linq; @@ -12,27 +11,50 @@ namespace NadekoBot.Modules.Games.Trivia { public class TriviaQuestionPool { + public class PokemonNameId + { + public int Id { get; set; } + public string Name { get; set; } + } + private static TriviaQuestionPool _instance; public static TriviaQuestionPool Instance { get; } = _instance ?? (_instance = new TriviaQuestionPool()); private const string questionsFile = "data/trivia_questions.json"; + private const string pokemonMapPath = "data/pokemon/name-id_map.json"; + private readonly int maxPokemonId; private Random rng { get; } = new NadekoRandom(); private TriviaQuestion[] pool { get; } + private ImmutableDictionary map { get; } static TriviaQuestionPool() { } private TriviaQuestionPool() { pool = JsonConvert.DeserializeObject(File.ReadAllText(questionsFile)); + map = JsonConvert.DeserializeObject(File.ReadAllText(pokemonMapPath)) + .ToDictionary(x => x.Id, x => x.Name) + .ToImmutableDictionary(); + + maxPokemonId = 721; //xd } - public TriviaQuestion GetRandomQuestion(HashSet exclude) + public TriviaQuestion GetRandomQuestion(HashSet exclude, bool isPokemon) { if (pool.Length == 0) return null; + if (isPokemon) + { + var num = rng.Next(1, maxPokemonId + 1); + return new TriviaQuestion("Who's That Pokémon?", + map[num].ToTitleCase(), + "Pokemon", + $@"http://nadekobot.xyz/images/pokemon/shadows/{num}.png", + $@"http://nadekobot.xyz/images/pokemon/real/{num}.png"); + } TriviaQuestion randomQuestion; while (exclude.Contains(randomQuestion = pool[rng.Next(0, pool.Length)])) ; diff --git a/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs b/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs index 60dc4216..c8bd3e73 100644 --- a/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs @@ -19,17 +19,21 @@ namespace NadekoBot.Modules.Games [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public Task Trivia([Remainder] string additionalArgs = "") - => Trivia(10, additionalArgs); + => InternalTrivia(10, additionalArgs); [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task Trivia(int winReq = 10, [Remainder] string additionalArgs = "") + public Task Trivia(int winReq = 10, [Remainder] string additionalArgs = "") + => InternalTrivia(winReq, additionalArgs); + + public async Task InternalTrivia(int winReq, string additionalArgs = "") { var channel = (ITextChannel)Context.Channel; var showHints = !additionalArgs.Contains("nohint"); + var isPokemon = additionalArgs.Contains("pokemon"); - var trivia = new TriviaGame(channel.Guild, channel, showHints, winReq); + var trivia = new TriviaGame(channel.Guild, channel, showHints, winReq, isPokemon); if (RunningTrivias.TryAdd(channel.Guild.Id, trivia)) { try @@ -41,9 +45,9 @@ namespace NadekoBot.Modules.Games RunningTrivias.TryRemove(channel.Guild.Id, out trivia); await trivia.EnsureStopped().ConfigureAwait(false); } - return; + return; } - + await Context.Channel.SendErrorAsync(GetText("trivia_already_running") + "\n" + trivia.CurrentQuestion) .ConfigureAwait(false); } diff --git a/src/NadekoBot/data/pokemon/name-id_map.json b/src/NadekoBot/data/pokemon/name-id_map.json new file mode 100644 index 00000000..334a2380 --- /dev/null +++ b/src/NadekoBot/data/pokemon/name-id_map.json @@ -0,0 +1,3246 @@ +[ + { + "Id": 1, + "Name": "bulbasaur" + }, + { + "Id": 2, + "Name": "ivysaur" + }, + { + "Id": 3, + "Name": "venusaur" + }, + { + "Id": 4, + "Name": "charmander" + }, + { + "Id": 5, + "Name": "charmeleon" + }, + { + "Id": 6, + "Name": "charizard" + }, + { + "Id": 7, + "Name": "squirtle" + }, + { + "Id": 8, + "Name": "wartortle" + }, + { + "Id": 9, + "Name": "blastoise" + }, + { + "Id": 10, + "Name": "caterpie" + }, + { + "Id": 11, + "Name": "metapod" + }, + { + "Id": 12, + "Name": "butterfree" + }, + { + "Id": 13, + "Name": "weedle" + }, + { + "Id": 14, + "Name": "kakuna" + }, + { + "Id": 15, + "Name": "beedrill" + }, + { + "Id": 16, + "Name": "pidgey" + }, + { + "Id": 17, + "Name": "pidgeotto" + }, + { + "Id": 18, + "Name": "pidgeot" + }, + { + "Id": 19, + "Name": "rattata" + }, + { + "Id": 20, + "Name": "raticate" + }, + { + "Id": 21, + "Name": "spearow" + }, + { + "Id": 22, + "Name": "fearow" + }, + { + "Id": 23, + "Name": "ekans" + }, + { + "Id": 24, + "Name": "arbok" + }, + { + "Id": 25, + "Name": "pikachu" + }, + { + "Id": 26, + "Name": "raichu" + }, + { + "Id": 27, + "Name": "sandshrew" + }, + { + "Id": 28, + "Name": "sandslash" + }, + { + "Id": 29, + "Name": "nidoran" + }, + { + "Id": 30, + "Name": "nidorina" + }, + { + "Id": 31, + "Name": "nidoqueen" + }, + { + "Id": 32, + "Name": "nidoran" + }, + { + "Id": 33, + "Name": "nidorino" + }, + { + "Id": 34, + "Name": "nidoking" + }, + { + "Id": 35, + "Name": "clefairy" + }, + { + "Id": 36, + "Name": "clefable" + }, + { + "Id": 37, + "Name": "vulpix" + }, + { + "Id": 38, + "Name": "ninetales" + }, + { + "Id": 39, + "Name": "jigglypuff" + }, + { + "Id": 40, + "Name": "wigglytuff" + }, + { + "Id": 41, + "Name": "zubat" + }, + { + "Id": 42, + "Name": "golbat" + }, + { + "Id": 43, + "Name": "oddish" + }, + { + "Id": 44, + "Name": "gloom" + }, + { + "Id": 45, + "Name": "vileplume" + }, + { + "Id": 46, + "Name": "paras" + }, + { + "Id": 47, + "Name": "parasect" + }, + { + "Id": 48, + "Name": "venonat" + }, + { + "Id": 49, + "Name": "venomoth" + }, + { + "Id": 50, + "Name": "diglett" + }, + { + "Id": 51, + "Name": "dugtrio" + }, + { + "Id": 52, + "Name": "meowth" + }, + { + "Id": 53, + "Name": "persian" + }, + { + "Id": 54, + "Name": "psyduck" + }, + { + "Id": 55, + "Name": "golduck" + }, + { + "Id": 56, + "Name": "mankey" + }, + { + "Id": 57, + "Name": "primeape" + }, + { + "Id": 58, + "Name": "growlithe" + }, + { + "Id": 59, + "Name": "arcanine" + }, + { + "Id": 60, + "Name": "poliwag" + }, + { + "Id": 61, + "Name": "poliwhirl" + }, + { + "Id": 62, + "Name": "poliwrath" + }, + { + "Id": 63, + "Name": "abra" + }, + { + "Id": 64, + "Name": "kadabra" + }, + { + "Id": 65, + "Name": "alakazam" + }, + { + "Id": 66, + "Name": "machop" + }, + { + "Id": 67, + "Name": "machoke" + }, + { + "Id": 68, + "Name": "machamp" + }, + { + "Id": 69, + "Name": "bellsprout" + }, + { + "Id": 70, + "Name": "weepinbell" + }, + { + "Id": 71, + "Name": "victreebel" + }, + { + "Id": 72, + "Name": "tentacool" + }, + { + "Id": 73, + "Name": "tentacruel" + }, + { + "Id": 74, + "Name": "geodude" + }, + { + "Id": 75, + "Name": "graveler" + }, + { + "Id": 76, + "Name": "golem" + }, + { + "Id": 77, + "Name": "ponyta" + }, + { + "Id": 78, + "Name": "rapidash" + }, + { + "Id": 79, + "Name": "slowpoke" + }, + { + "Id": 80, + "Name": "slowbro" + }, + { + "Id": 81, + "Name": "magnemite" + }, + { + "Id": 82, + "Name": "magneton" + }, + { + "Id": 83, + "Name": "farfetchd" + }, + { + "Id": 84, + "Name": "doduo" + }, + { + "Id": 85, + "Name": "dodrio" + }, + { + "Id": 86, + "Name": "seel" + }, + { + "Id": 87, + "Name": "dewgong" + }, + { + "Id": 88, + "Name": "grimer" + }, + { + "Id": 89, + "Name": "muk" + }, + { + "Id": 90, + "Name": "shellder" + }, + { + "Id": 91, + "Name": "cloyster" + }, + { + "Id": 92, + "Name": "gastly" + }, + { + "Id": 93, + "Name": "haunter" + }, + { + "Id": 94, + "Name": "gengar" + }, + { + "Id": 95, + "Name": "onix" + }, + { + "Id": 96, + "Name": "drowzee" + }, + { + "Id": 97, + "Name": "hypno" + }, + { + "Id": 98, + "Name": "krabby" + }, + { + "Id": 99, + "Name": "kingler" + }, + { + "Id": 100, + "Name": "voltorb" + }, + { + "Id": 101, + "Name": "electrode" + }, + { + "Id": 102, + "Name": "exeggcute" + }, + { + "Id": 103, + "Name": "exeggutor" + }, + { + "Id": 104, + "Name": "cubone" + }, + { + "Id": 105, + "Name": "marowak" + }, + { + "Id": 106, + "Name": "hitmonlee" + }, + { + "Id": 107, + "Name": "hitmonchan" + }, + { + "Id": 108, + "Name": "lickitung" + }, + { + "Id": 109, + "Name": "koffing" + }, + { + "Id": 110, + "Name": "weezing" + }, + { + "Id": 111, + "Name": "rhyhorn" + }, + { + "Id": 112, + "Name": "rhydon" + }, + { + "Id": 113, + "Name": "chansey" + }, + { + "Id": 114, + "Name": "tangela" + }, + { + "Id": 115, + "Name": "kangaskhan" + }, + { + "Id": 116, + "Name": "horsea" + }, + { + "Id": 117, + "Name": "seadra" + }, + { + "Id": 118, + "Name": "goldeen" + }, + { + "Id": 119, + "Name": "seaking" + }, + { + "Id": 120, + "Name": "staryu" + }, + { + "Id": 121, + "Name": "starmie" + }, + { + "Id": 122, + "Name": "mr" + }, + { + "Id": 123, + "Name": "scyther" + }, + { + "Id": 124, + "Name": "jynx" + }, + { + "Id": 125, + "Name": "electabuzz" + }, + { + "Id": 126, + "Name": "magmar" + }, + { + "Id": 127, + "Name": "pinsir" + }, + { + "Id": 128, + "Name": "tauros" + }, + { + "Id": 129, + "Name": "magikarp" + }, + { + "Id": 130, + "Name": "gyarados" + }, + { + "Id": 131, + "Name": "lapras" + }, + { + "Id": 132, + "Name": "ditto" + }, + { + "Id": 133, + "Name": "eevee" + }, + { + "Id": 134, + "Name": "vaporeon" + }, + { + "Id": 135, + "Name": "jolteon" + }, + { + "Id": 136, + "Name": "flareon" + }, + { + "Id": 137, + "Name": "porygon" + }, + { + "Id": 138, + "Name": "omanyte" + }, + { + "Id": 139, + "Name": "omastar" + }, + { + "Id": 140, + "Name": "kabuto" + }, + { + "Id": 141, + "Name": "kabutops" + }, + { + "Id": 142, + "Name": "aerodactyl" + }, + { + "Id": 143, + "Name": "snorlax" + }, + { + "Id": 144, + "Name": "articuno" + }, + { + "Id": 145, + "Name": "zapdos" + }, + { + "Id": 146, + "Name": "moltres" + }, + { + "Id": 147, + "Name": "dratini" + }, + { + "Id": 148, + "Name": "dragonair" + }, + { + "Id": 149, + "Name": "dragonite" + }, + { + "Id": 150, + "Name": "mewtwo" + }, + { + "Id": 151, + "Name": "mew" + }, + { + "Id": 152, + "Name": "chikorita" + }, + { + "Id": 153, + "Name": "bayleef" + }, + { + "Id": 154, + "Name": "meganium" + }, + { + "Id": 155, + "Name": "cyndaquil" + }, + { + "Id": 156, + "Name": "quilava" + }, + { + "Id": 157, + "Name": "typhlosion" + }, + { + "Id": 158, + "Name": "totodile" + }, + { + "Id": 159, + "Name": "croconaw" + }, + { + "Id": 160, + "Name": "feraligatr" + }, + { + "Id": 161, + "Name": "sentret" + }, + { + "Id": 162, + "Name": "furret" + }, + { + "Id": 163, + "Name": "hoothoot" + }, + { + "Id": 164, + "Name": "noctowl" + }, + { + "Id": 165, + "Name": "ledyba" + }, + { + "Id": 166, + "Name": "ledian" + }, + { + "Id": 167, + "Name": "spinarak" + }, + { + "Id": 168, + "Name": "ariados" + }, + { + "Id": 169, + "Name": "crobat" + }, + { + "Id": 170, + "Name": "chinchou" + }, + { + "Id": 171, + "Name": "lanturn" + }, + { + "Id": 172, + "Name": "pichu" + }, + { + "Id": 173, + "Name": "cleffa" + }, + { + "Id": 174, + "Name": "igglybuff" + }, + { + "Id": 175, + "Name": "togepi" + }, + { + "Id": 176, + "Name": "togetic" + }, + { + "Id": 177, + "Name": "natu" + }, + { + "Id": 178, + "Name": "xatu" + }, + { + "Id": 179, + "Name": "mareep" + }, + { + "Id": 180, + "Name": "flaaffy" + }, + { + "Id": 181, + "Name": "ampharos" + }, + { + "Id": 182, + "Name": "bellossom" + }, + { + "Id": 183, + "Name": "marill" + }, + { + "Id": 184, + "Name": "azumarill" + }, + { + "Id": 185, + "Name": "sudowoodo" + }, + { + "Id": 186, + "Name": "politoed" + }, + { + "Id": 187, + "Name": "hoppip" + }, + { + "Id": 188, + "Name": "skiploom" + }, + { + "Id": 189, + "Name": "jumpluff" + }, + { + "Id": 190, + "Name": "aipom" + }, + { + "Id": 191, + "Name": "sunkern" + }, + { + "Id": 192, + "Name": "sunflora" + }, + { + "Id": 193, + "Name": "yanma" + }, + { + "Id": 194, + "Name": "wooper" + }, + { + "Id": 195, + "Name": "quagsire" + }, + { + "Id": 196, + "Name": "espeon" + }, + { + "Id": 197, + "Name": "umbreon" + }, + { + "Id": 198, + "Name": "murkrow" + }, + { + "Id": 199, + "Name": "slowking" + }, + { + "Id": 200, + "Name": "misdreavus" + }, + { + "Id": 201, + "Name": "unown" + }, + { + "Id": 202, + "Name": "wobbuffet" + }, + { + "Id": 203, + "Name": "girafarig" + }, + { + "Id": 204, + "Name": "pineco" + }, + { + "Id": 205, + "Name": "forretress" + }, + { + "Id": 206, + "Name": "dunsparce" + }, + { + "Id": 207, + "Name": "gligar" + }, + { + "Id": 208, + "Name": "steelix" + }, + { + "Id": 209, + "Name": "snubbull" + }, + { + "Id": 210, + "Name": "granbull" + }, + { + "Id": 211, + "Name": "qwilfish" + }, + { + "Id": 212, + "Name": "scizor" + }, + { + "Id": 213, + "Name": "shuckle" + }, + { + "Id": 214, + "Name": "heracross" + }, + { + "Id": 215, + "Name": "sneasel" + }, + { + "Id": 216, + "Name": "teddiursa" + }, + { + "Id": 217, + "Name": "ursaring" + }, + { + "Id": 218, + "Name": "slugma" + }, + { + "Id": 219, + "Name": "magcargo" + }, + { + "Id": 220, + "Name": "swinub" + }, + { + "Id": 221, + "Name": "piloswine" + }, + { + "Id": 222, + "Name": "corsola" + }, + { + "Id": 223, + "Name": "remoraid" + }, + { + "Id": 224, + "Name": "octillery" + }, + { + "Id": 225, + "Name": "delibird" + }, + { + "Id": 226, + "Name": "mantine" + }, + { + "Id": 227, + "Name": "skarmory" + }, + { + "Id": 228, + "Name": "houndour" + }, + { + "Id": 229, + "Name": "houndoom" + }, + { + "Id": 230, + "Name": "kingdra" + }, + { + "Id": 231, + "Name": "phanpy" + }, + { + "Id": 232, + "Name": "donphan" + }, + { + "Id": 233, + "Name": "porygon2" + }, + { + "Id": 234, + "Name": "stantler" + }, + { + "Id": 235, + "Name": "smeargle" + }, + { + "Id": 236, + "Name": "tyrogue" + }, + { + "Id": 237, + "Name": "hitmontop" + }, + { + "Id": 238, + "Name": "smoochum" + }, + { + "Id": 239, + "Name": "elekid" + }, + { + "Id": 240, + "Name": "magby" + }, + { + "Id": 241, + "Name": "miltank" + }, + { + "Id": 242, + "Name": "blissey" + }, + { + "Id": 243, + "Name": "raikou" + }, + { + "Id": 244, + "Name": "entei" + }, + { + "Id": 245, + "Name": "suicune" + }, + { + "Id": 246, + "Name": "larvitar" + }, + { + "Id": 247, + "Name": "pupitar" + }, + { + "Id": 248, + "Name": "tyranitar" + }, + { + "Id": 249, + "Name": "lugia" + }, + { + "Id": 250, + "Name": "ho" + }, + { + "Id": 251, + "Name": "celebi" + }, + { + "Id": 252, + "Name": "treecko" + }, + { + "Id": 253, + "Name": "grovyle" + }, + { + "Id": 254, + "Name": "sceptile" + }, + { + "Id": 255, + "Name": "torchic" + }, + { + "Id": 256, + "Name": "combusken" + }, + { + "Id": 257, + "Name": "blaziken" + }, + { + "Id": 258, + "Name": "mudkip" + }, + { + "Id": 259, + "Name": "marshtomp" + }, + { + "Id": 260, + "Name": "swampert" + }, + { + "Id": 261, + "Name": "poochyena" + }, + { + "Id": 262, + "Name": "mightyena" + }, + { + "Id": 263, + "Name": "zigzagoon" + }, + { + "Id": 264, + "Name": "linoone" + }, + { + "Id": 265, + "Name": "wurmple" + }, + { + "Id": 266, + "Name": "silcoon" + }, + { + "Id": 267, + "Name": "beautifly" + }, + { + "Id": 268, + "Name": "cascoon" + }, + { + "Id": 269, + "Name": "dustox" + }, + { + "Id": 270, + "Name": "lotad" + }, + { + "Id": 271, + "Name": "lombre" + }, + { + "Id": 272, + "Name": "ludicolo" + }, + { + "Id": 273, + "Name": "seedot" + }, + { + "Id": 274, + "Name": "nuzleaf" + }, + { + "Id": 275, + "Name": "shiftry" + }, + { + "Id": 276, + "Name": "taillow" + }, + { + "Id": 277, + "Name": "swellow" + }, + { + "Id": 278, + "Name": "wingull" + }, + { + "Id": 279, + "Name": "pelipper" + }, + { + "Id": 280, + "Name": "ralts" + }, + { + "Id": 281, + "Name": "kirlia" + }, + { + "Id": 282, + "Name": "gardevoir" + }, + { + "Id": 283, + "Name": "surskit" + }, + { + "Id": 284, + "Name": "masquerain" + }, + { + "Id": 285, + "Name": "shroomish" + }, + { + "Id": 286, + "Name": "breloom" + }, + { + "Id": 287, + "Name": "slakoth" + }, + { + "Id": 288, + "Name": "vigoroth" + }, + { + "Id": 289, + "Name": "slaking" + }, + { + "Id": 290, + "Name": "nincada" + }, + { + "Id": 291, + "Name": "ninjask" + }, + { + "Id": 292, + "Name": "shedinja" + }, + { + "Id": 293, + "Name": "whismur" + }, + { + "Id": 294, + "Name": "loudred" + }, + { + "Id": 295, + "Name": "exploud" + }, + { + "Id": 296, + "Name": "makuhita" + }, + { + "Id": 297, + "Name": "hariyama" + }, + { + "Id": 298, + "Name": "azurill" + }, + { + "Id": 299, + "Name": "nosepass" + }, + { + "Id": 300, + "Name": "skitty" + }, + { + "Id": 301, + "Name": "delcatty" + }, + { + "Id": 302, + "Name": "sableye" + }, + { + "Id": 303, + "Name": "mawile" + }, + { + "Id": 304, + "Name": "aron" + }, + { + "Id": 305, + "Name": "lairon" + }, + { + "Id": 306, + "Name": "aggron" + }, + { + "Id": 307, + "Name": "meditite" + }, + { + "Id": 308, + "Name": "medicham" + }, + { + "Id": 309, + "Name": "electrike" + }, + { + "Id": 310, + "Name": "manectric" + }, + { + "Id": 311, + "Name": "plusle" + }, + { + "Id": 312, + "Name": "minun" + }, + { + "Id": 313, + "Name": "volbeat" + }, + { + "Id": 314, + "Name": "illumise" + }, + { + "Id": 315, + "Name": "roselia" + }, + { + "Id": 316, + "Name": "gulpin" + }, + { + "Id": 317, + "Name": "swalot" + }, + { + "Id": 318, + "Name": "carvanha" + }, + { + "Id": 319, + "Name": "sharpedo" + }, + { + "Id": 320, + "Name": "wailmer" + }, + { + "Id": 321, + "Name": "wailord" + }, + { + "Id": 322, + "Name": "numel" + }, + { + "Id": 323, + "Name": "camerupt" + }, + { + "Id": 324, + "Name": "torkoal" + }, + { + "Id": 325, + "Name": "spoink" + }, + { + "Id": 326, + "Name": "grumpig" + }, + { + "Id": 327, + "Name": "spinda" + }, + { + "Id": 328, + "Name": "trapinch" + }, + { + "Id": 329, + "Name": "vibrava" + }, + { + "Id": 330, + "Name": "flygon" + }, + { + "Id": 331, + "Name": "cacnea" + }, + { + "Id": 332, + "Name": "cacturne" + }, + { + "Id": 333, + "Name": "swablu" + }, + { + "Id": 334, + "Name": "altaria" + }, + { + "Id": 335, + "Name": "zangoose" + }, + { + "Id": 336, + "Name": "seviper" + }, + { + "Id": 337, + "Name": "lunatone" + }, + { + "Id": 338, + "Name": "solrock" + }, + { + "Id": 339, + "Name": "barboach" + }, + { + "Id": 340, + "Name": "whiscash" + }, + { + "Id": 341, + "Name": "corphish" + }, + { + "Id": 342, + "Name": "crawdaunt" + }, + { + "Id": 343, + "Name": "baltoy" + }, + { + "Id": 344, + "Name": "claydol" + }, + { + "Id": 345, + "Name": "lileep" + }, + { + "Id": 346, + "Name": "cradily" + }, + { + "Id": 347, + "Name": "anorith" + }, + { + "Id": 348, + "Name": "armaldo" + }, + { + "Id": 349, + "Name": "feebas" + }, + { + "Id": 350, + "Name": "milotic" + }, + { + "Id": 351, + "Name": "castform" + }, + { + "Id": 352, + "Name": "kecleon" + }, + { + "Id": 353, + "Name": "shuppet" + }, + { + "Id": 354, + "Name": "banette" + }, + { + "Id": 355, + "Name": "duskull" + }, + { + "Id": 356, + "Name": "dusclops" + }, + { + "Id": 357, + "Name": "tropius" + }, + { + "Id": 358, + "Name": "chimecho" + }, + { + "Id": 359, + "Name": "absol" + }, + { + "Id": 360, + "Name": "wynaut" + }, + { + "Id": 361, + "Name": "snorunt" + }, + { + "Id": 362, + "Name": "glalie" + }, + { + "Id": 363, + "Name": "spheal" + }, + { + "Id": 364, + "Name": "sealeo" + }, + { + "Id": 365, + "Name": "walrein" + }, + { + "Id": 366, + "Name": "clamperl" + }, + { + "Id": 367, + "Name": "huntail" + }, + { + "Id": 368, + "Name": "gorebyss" + }, + { + "Id": 369, + "Name": "relicanth" + }, + { + "Id": 370, + "Name": "luvdisc" + }, + { + "Id": 371, + "Name": "bagon" + }, + { + "Id": 372, + "Name": "shelgon" + }, + { + "Id": 373, + "Name": "salamence" + }, + { + "Id": 374, + "Name": "beldum" + }, + { + "Id": 375, + "Name": "metang" + }, + { + "Id": 376, + "Name": "metagross" + }, + { + "Id": 377, + "Name": "regirock" + }, + { + "Id": 378, + "Name": "regice" + }, + { + "Id": 379, + "Name": "registeel" + }, + { + "Id": 380, + "Name": "latias" + }, + { + "Id": 381, + "Name": "latios" + }, + { + "Id": 382, + "Name": "kyogre" + }, + { + "Id": 383, + "Name": "groudon" + }, + { + "Id": 384, + "Name": "rayquaza" + }, + { + "Id": 385, + "Name": "jirachi" + }, + { + "Id": 386, + "Name": "deoxys" + }, + { + "Id": 387, + "Name": "turtwig" + }, + { + "Id": 388, + "Name": "grotle" + }, + { + "Id": 389, + "Name": "torterra" + }, + { + "Id": 390, + "Name": "chimchar" + }, + { + "Id": 391, + "Name": "monferno" + }, + { + "Id": 392, + "Name": "infernape" + }, + { + "Id": 393, + "Name": "piplup" + }, + { + "Id": 394, + "Name": "prinplup" + }, + { + "Id": 395, + "Name": "empoleon" + }, + { + "Id": 396, + "Name": "starly" + }, + { + "Id": 397, + "Name": "staravia" + }, + { + "Id": 398, + "Name": "staraptor" + }, + { + "Id": 399, + "Name": "bidoof" + }, + { + "Id": 400, + "Name": "bibarel" + }, + { + "Id": 401, + "Name": "kricketot" + }, + { + "Id": 402, + "Name": "kricketune" + }, + { + "Id": 403, + "Name": "shinx" + }, + { + "Id": 404, + "Name": "luxio" + }, + { + "Id": 405, + "Name": "luxray" + }, + { + "Id": 406, + "Name": "budew" + }, + { + "Id": 407, + "Name": "roserade" + }, + { + "Id": 408, + "Name": "cranidos" + }, + { + "Id": 409, + "Name": "rampardos" + }, + { + "Id": 410, + "Name": "shieldon" + }, + { + "Id": 411, + "Name": "bastiodon" + }, + { + "Id": 412, + "Name": "burmy" + }, + { + "Id": 413, + "Name": "wormadam" + }, + { + "Id": 414, + "Name": "mothim" + }, + { + "Id": 415, + "Name": "combee" + }, + { + "Id": 416, + "Name": "vespiquen" + }, + { + "Id": 417, + "Name": "pachirisu" + }, + { + "Id": 418, + "Name": "buizel" + }, + { + "Id": 419, + "Name": "floatzel" + }, + { + "Id": 420, + "Name": "cherubi" + }, + { + "Id": 421, + "Name": "cherrim" + }, + { + "Id": 422, + "Name": "shellos" + }, + { + "Id": 423, + "Name": "gastrodon" + }, + { + "Id": 424, + "Name": "ambipom" + }, + { + "Id": 425, + "Name": "drifloon" + }, + { + "Id": 426, + "Name": "drifblim" + }, + { + "Id": 427, + "Name": "buneary" + }, + { + "Id": 428, + "Name": "lopunny" + }, + { + "Id": 429, + "Name": "mismagius" + }, + { + "Id": 430, + "Name": "honchkrow" + }, + { + "Id": 431, + "Name": "glameow" + }, + { + "Id": 432, + "Name": "purugly" + }, + { + "Id": 433, + "Name": "chingling" + }, + { + "Id": 434, + "Name": "stunky" + }, + { + "Id": 435, + "Name": "skuntank" + }, + { + "Id": 436, + "Name": "bronzor" + }, + { + "Id": 437, + "Name": "bronzong" + }, + { + "Id": 438, + "Name": "bonsly" + }, + { + "Id": 439, + "Name": "mime" + }, + { + "Id": 440, + "Name": "happiny" + }, + { + "Id": 441, + "Name": "chatot" + }, + { + "Id": 442, + "Name": "spiritomb" + }, + { + "Id": 443, + "Name": "gible" + }, + { + "Id": 444, + "Name": "gabite" + }, + { + "Id": 445, + "Name": "garchomp" + }, + { + "Id": 446, + "Name": "munchlax" + }, + { + "Id": 447, + "Name": "riolu" + }, + { + "Id": 448, + "Name": "lucario" + }, + { + "Id": 449, + "Name": "hippopotas" + }, + { + "Id": 450, + "Name": "hippowdon" + }, + { + "Id": 451, + "Name": "skorupi" + }, + { + "Id": 452, + "Name": "drapion" + }, + { + "Id": 453, + "Name": "croagunk" + }, + { + "Id": 454, + "Name": "toxicroak" + }, + { + "Id": 455, + "Name": "carnivine" + }, + { + "Id": 456, + "Name": "finneon" + }, + { + "Id": 457, + "Name": "lumineon" + }, + { + "Id": 458, + "Name": "mantyke" + }, + { + "Id": 459, + "Name": "snover" + }, + { + "Id": 460, + "Name": "abomasnow" + }, + { + "Id": 461, + "Name": "weavile" + }, + { + "Id": 462, + "Name": "magnezone" + }, + { + "Id": 463, + "Name": "lickilicky" + }, + { + "Id": 464, + "Name": "rhyperior" + }, + { + "Id": 465, + "Name": "tangrowth" + }, + { + "Id": 466, + "Name": "electivire" + }, + { + "Id": 467, + "Name": "magmortar" + }, + { + "Id": 468, + "Name": "togekiss" + }, + { + "Id": 469, + "Name": "yanmega" + }, + { + "Id": 470, + "Name": "leafeon" + }, + { + "Id": 471, + "Name": "glaceon" + }, + { + "Id": 472, + "Name": "gliscor" + }, + { + "Id": 473, + "Name": "mamoswine" + }, + { + "Id": 474, + "Name": "porygon" + }, + { + "Id": 475, + "Name": "gallade" + }, + { + "Id": 476, + "Name": "probopass" + }, + { + "Id": 477, + "Name": "dusknoir" + }, + { + "Id": 478, + "Name": "froslass" + }, + { + "Id": 479, + "Name": "rotom" + }, + { + "Id": 480, + "Name": "uxie" + }, + { + "Id": 481, + "Name": "mesprit" + }, + { + "Id": 482, + "Name": "azelf" + }, + { + "Id": 483, + "Name": "dialga" + }, + { + "Id": 484, + "Name": "palkia" + }, + { + "Id": 485, + "Name": "heatran" + }, + { + "Id": 486, + "Name": "regigigas" + }, + { + "Id": 487, + "Name": "giratina" + }, + { + "Id": 488, + "Name": "cresselia" + }, + { + "Id": 489, + "Name": "phione" + }, + { + "Id": 490, + "Name": "manaphy" + }, + { + "Id": 491, + "Name": "darkrai" + }, + { + "Id": 492, + "Name": "shaymin" + }, + { + "Id": 493, + "Name": "arceus" + }, + { + "Id": 494, + "Name": "victini" + }, + { + "Id": 495, + "Name": "snivy" + }, + { + "Id": 496, + "Name": "servine" + }, + { + "Id": 497, + "Name": "serperior" + }, + { + "Id": 498, + "Name": "tepig" + }, + { + "Id": 499, + "Name": "pignite" + }, + { + "Id": 500, + "Name": "emboar" + }, + { + "Id": 501, + "Name": "oshawott" + }, + { + "Id": 502, + "Name": "dewott" + }, + { + "Id": 503, + "Name": "samurott" + }, + { + "Id": 504, + "Name": "patrat" + }, + { + "Id": 505, + "Name": "watchog" + }, + { + "Id": 506, + "Name": "lillipup" + }, + { + "Id": 507, + "Name": "herdier" + }, + { + "Id": 508, + "Name": "stoutland" + }, + { + "Id": 509, + "Name": "purrloin" + }, + { + "Id": 510, + "Name": "liepard" + }, + { + "Id": 511, + "Name": "pansage" + }, + { + "Id": 512, + "Name": "simisage" + }, + { + "Id": 513, + "Name": "pansear" + }, + { + "Id": 514, + "Name": "simisear" + }, + { + "Id": 515, + "Name": "panpour" + }, + { + "Id": 516, + "Name": "simipour" + }, + { + "Id": 517, + "Name": "munna" + }, + { + "Id": 518, + "Name": "musharna" + }, + { + "Id": 519, + "Name": "pidove" + }, + { + "Id": 520, + "Name": "tranquill" + }, + { + "Id": 521, + "Name": "unfezant" + }, + { + "Id": 522, + "Name": "blitzle" + }, + { + "Id": 523, + "Name": "zebstrika" + }, + { + "Id": 524, + "Name": "roggenrola" + }, + { + "Id": 525, + "Name": "boldore" + }, + { + "Id": 526, + "Name": "gigalith" + }, + { + "Id": 527, + "Name": "woobat" + }, + { + "Id": 528, + "Name": "swoobat" + }, + { + "Id": 529, + "Name": "drilbur" + }, + { + "Id": 530, + "Name": "excadrill" + }, + { + "Id": 531, + "Name": "audino" + }, + { + "Id": 532, + "Name": "timburr" + }, + { + "Id": 533, + "Name": "gurdurr" + }, + { + "Id": 534, + "Name": "conkeldurr" + }, + { + "Id": 535, + "Name": "tympole" + }, + { + "Id": 536, + "Name": "palpitoad" + }, + { + "Id": 537, + "Name": "seismitoad" + }, + { + "Id": 538, + "Name": "throh" + }, + { + "Id": 539, + "Name": "sawk" + }, + { + "Id": 540, + "Name": "sewaddle" + }, + { + "Id": 541, + "Name": "swadloon" + }, + { + "Id": 542, + "Name": "leavanny" + }, + { + "Id": 543, + "Name": "venipede" + }, + { + "Id": 544, + "Name": "whirlipede" + }, + { + "Id": 545, + "Name": "scolipede" + }, + { + "Id": 546, + "Name": "cottonee" + }, + { + "Id": 547, + "Name": "whimsicott" + }, + { + "Id": 548, + "Name": "petilil" + }, + { + "Id": 549, + "Name": "lilligant" + }, + { + "Id": 550, + "Name": "basculin" + }, + { + "Id": 551, + "Name": "sandile" + }, + { + "Id": 552, + "Name": "krokorok" + }, + { + "Id": 553, + "Name": "krookodile" + }, + { + "Id": 554, + "Name": "darumaka" + }, + { + "Id": 555, + "Name": "darmanitan" + }, + { + "Id": 556, + "Name": "maractus" + }, + { + "Id": 557, + "Name": "dwebble" + }, + { + "Id": 558, + "Name": "crustle" + }, + { + "Id": 559, + "Name": "scraggy" + }, + { + "Id": 560, + "Name": "scrafty" + }, + { + "Id": 561, + "Name": "sigilyph" + }, + { + "Id": 562, + "Name": "yamask" + }, + { + "Id": 563, + "Name": "cofagrigus" + }, + { + "Id": 564, + "Name": "tirtouga" + }, + { + "Id": 565, + "Name": "carracosta" + }, + { + "Id": 566, + "Name": "archen" + }, + { + "Id": 567, + "Name": "archeops" + }, + { + "Id": 568, + "Name": "trubbish" + }, + { + "Id": 569, + "Name": "garbodor" + }, + { + "Id": 570, + "Name": "zorua" + }, + { + "Id": 571, + "Name": "zoroark" + }, + { + "Id": 572, + "Name": "minccino" + }, + { + "Id": 573, + "Name": "cinccino" + }, + { + "Id": 574, + "Name": "gothita" + }, + { + "Id": 575, + "Name": "gothorita" + }, + { + "Id": 576, + "Name": "gothitelle" + }, + { + "Id": 577, + "Name": "solosis" + }, + { + "Id": 578, + "Name": "duosion" + }, + { + "Id": 579, + "Name": "reuniclus" + }, + { + "Id": 580, + "Name": "ducklett" + }, + { + "Id": 581, + "Name": "swanna" + }, + { + "Id": 582, + "Name": "vanillite" + }, + { + "Id": 583, + "Name": "vanillish" + }, + { + "Id": 584, + "Name": "vanilluxe" + }, + { + "Id": 585, + "Name": "deerling" + }, + { + "Id": 586, + "Name": "sawsbuck" + }, + { + "Id": 587, + "Name": "emolga" + }, + { + "Id": 588, + "Name": "karrablast" + }, + { + "Id": 589, + "Name": "escavalier" + }, + { + "Id": 590, + "Name": "foongus" + }, + { + "Id": 591, + "Name": "amoonguss" + }, + { + "Id": 592, + "Name": "frillish" + }, + { + "Id": 593, + "Name": "jellicent" + }, + { + "Id": 594, + "Name": "alomomola" + }, + { + "Id": 595, + "Name": "joltik" + }, + { + "Id": 596, + "Name": "galvantula" + }, + { + "Id": 597, + "Name": "ferroseed" + }, + { + "Id": 598, + "Name": "ferrothorn" + }, + { + "Id": 599, + "Name": "klink" + }, + { + "Id": 600, + "Name": "klang" + }, + { + "Id": 601, + "Name": "klinklang" + }, + { + "Id": 602, + "Name": "tynamo" + }, + { + "Id": 603, + "Name": "eelektrik" + }, + { + "Id": 604, + "Name": "eelektross" + }, + { + "Id": 605, + "Name": "elgyem" + }, + { + "Id": 606, + "Name": "beheeyem" + }, + { + "Id": 607, + "Name": "litwick" + }, + { + "Id": 608, + "Name": "lampent" + }, + { + "Id": 609, + "Name": "chandelure" + }, + { + "Id": 610, + "Name": "axew" + }, + { + "Id": 611, + "Name": "fraxure" + }, + { + "Id": 612, + "Name": "haxorus" + }, + { + "Id": 613, + "Name": "cubchoo" + }, + { + "Id": 614, + "Name": "beartic" + }, + { + "Id": 615, + "Name": "cryogonal" + }, + { + "Id": 616, + "Name": "shelmet" + }, + { + "Id": 617, + "Name": "accelgor" + }, + { + "Id": 618, + "Name": "stunfisk" + }, + { + "Id": 619, + "Name": "mienfoo" + }, + { + "Id": 620, + "Name": "mienshao" + }, + { + "Id": 621, + "Name": "druddigon" + }, + { + "Id": 622, + "Name": "golett" + }, + { + "Id": 623, + "Name": "golurk" + }, + { + "Id": 624, + "Name": "pawniard" + }, + { + "Id": 625, + "Name": "bisharp" + }, + { + "Id": 626, + "Name": "bouffalant" + }, + { + "Id": 627, + "Name": "rufflet" + }, + { + "Id": 628, + "Name": "braviary" + }, + { + "Id": 629, + "Name": "vullaby" + }, + { + "Id": 630, + "Name": "mandibuzz" + }, + { + "Id": 631, + "Name": "heatmor" + }, + { + "Id": 632, + "Name": "durant" + }, + { + "Id": 633, + "Name": "deino" + }, + { + "Id": 634, + "Name": "zweilous" + }, + { + "Id": 635, + "Name": "hydreigon" + }, + { + "Id": 636, + "Name": "larvesta" + }, + { + "Id": 637, + "Name": "volcarona" + }, + { + "Id": 638, + "Name": "cobalion" + }, + { + "Id": 639, + "Name": "terrakion" + }, + { + "Id": 640, + "Name": "virizion" + }, + { + "Id": 641, + "Name": "tornadus" + }, + { + "Id": 642, + "Name": "thundurus" + }, + { + "Id": 643, + "Name": "reshiram" + }, + { + "Id": 644, + "Name": "zekrom" + }, + { + "Id": 645, + "Name": "landorus" + }, + { + "Id": 646, + "Name": "kyurem" + }, + { + "Id": 647, + "Name": "keldeo" + }, + { + "Id": 648, + "Name": "meloetta" + }, + { + "Id": 649, + "Name": "genesect" + }, + { + "Id": 650, + "Name": "chespin" + }, + { + "Id": 651, + "Name": "quilladin" + }, + { + "Id": 652, + "Name": "chesnaught" + }, + { + "Id": 653, + "Name": "fennekin" + }, + { + "Id": 654, + "Name": "braixen" + }, + { + "Id": 655, + "Name": "delphox" + }, + { + "Id": 656, + "Name": "froakie" + }, + { + "Id": 657, + "Name": "frogadier" + }, + { + "Id": 658, + "Name": "greninja" + }, + { + "Id": 659, + "Name": "bunnelby" + }, + { + "Id": 660, + "Name": "diggersby" + }, + { + "Id": 661, + "Name": "fletchling" + }, + { + "Id": 662, + "Name": "fletchinder" + }, + { + "Id": 663, + "Name": "talonflame" + }, + { + "Id": 664, + "Name": "scatterbug" + }, + { + "Id": 665, + "Name": "spewpa" + }, + { + "Id": 666, + "Name": "vivillon" + }, + { + "Id": 667, + "Name": "litleo" + }, + { + "Id": 668, + "Name": "pyroar" + }, + { + "Id": 669, + "Name": "flabebe" + }, + { + "Id": 670, + "Name": "floette" + }, + { + "Id": 671, + "Name": "florges" + }, + { + "Id": 672, + "Name": "skiddo" + }, + { + "Id": 673, + "Name": "gogoat" + }, + { + "Id": 674, + "Name": "pancham" + }, + { + "Id": 675, + "Name": "pangoro" + }, + { + "Id": 676, + "Name": "furfrou" + }, + { + "Id": 677, + "Name": "espurr" + }, + { + "Id": 678, + "Name": "meowstic" + }, + { + "Id": 679, + "Name": "honedge" + }, + { + "Id": 680, + "Name": "doublade" + }, + { + "Id": 681, + "Name": "aegislash" + }, + { + "Id": 682, + "Name": "spritzee" + }, + { + "Id": 683, + "Name": "aromatisse" + }, + { + "Id": 684, + "Name": "swirlix" + }, + { + "Id": 685, + "Name": "slurpuff" + }, + { + "Id": 686, + "Name": "inkay" + }, + { + "Id": 687, + "Name": "malamar" + }, + { + "Id": 688, + "Name": "binacle" + }, + { + "Id": 689, + "Name": "barbaracle" + }, + { + "Id": 690, + "Name": "skrelp" + }, + { + "Id": 691, + "Name": "dragalge" + }, + { + "Id": 692, + "Name": "clauncher" + }, + { + "Id": 693, + "Name": "clawitzer" + }, + { + "Id": 694, + "Name": "helioptile" + }, + { + "Id": 695, + "Name": "heliolisk" + }, + { + "Id": 696, + "Name": "tyrunt" + }, + { + "Id": 697, + "Name": "tyrantrum" + }, + { + "Id": 698, + "Name": "amaura" + }, + { + "Id": 699, + "Name": "aurorus" + }, + { + "Id": 700, + "Name": "sylveon" + }, + { + "Id": 701, + "Name": "hawlucha" + }, + { + "Id": 702, + "Name": "dedenne" + }, + { + "Id": 703, + "Name": "carbink" + }, + { + "Id": 704, + "Name": "goomy" + }, + { + "Id": 705, + "Name": "sliggoo" + }, + { + "Id": 706, + "Name": "goodra" + }, + { + "Id": 707, + "Name": "klefki" + }, + { + "Id": 708, + "Name": "phantump" + }, + { + "Id": 709, + "Name": "trevenant" + }, + { + "Id": 710, + "Name": "pumpkaboo" + }, + { + "Id": 711, + "Name": "gourgeist" + }, + { + "Id": 712, + "Name": "bergmite" + }, + { + "Id": 713, + "Name": "avalugg" + }, + { + "Id": 714, + "Name": "noibat" + }, + { + "Id": 715, + "Name": "noivern" + }, + { + "Id": 716, + "Name": "xerneas" + }, + { + "Id": 717, + "Name": "yveltal" + }, + { + "Id": 718, + "Name": "zygarde" + }, + { + "Id": 719, + "Name": "diancie" + }, + { + "Id": 720, + "Name": "hoopa" + }, + { + "Id": 721, + "Name": "volcanion" + }, + { + "Id": 10001, + "Name": "deoxys" + }, + { + "Id": 10002, + "Name": "deoxys" + }, + { + "Id": 10003, + "Name": "deoxys" + }, + { + "Id": 10004, + "Name": "wormadam" + }, + { + "Id": 10005, + "Name": "wormadam" + }, + { + "Id": 10006, + "Name": "shaymin" + }, + { + "Id": 10007, + "Name": "giratina" + }, + { + "Id": 10008, + "Name": "rotom" + }, + { + "Id": 10009, + "Name": "rotom" + }, + { + "Id": 10010, + "Name": "rotom" + }, + { + "Id": 10011, + "Name": "rotom" + }, + { + "Id": 10012, + "Name": "rotom" + }, + { + "Id": 10013, + "Name": "castform" + }, + { + "Id": 10014, + "Name": "castform" + }, + { + "Id": 10015, + "Name": "castform" + }, + { + "Id": 10016, + "Name": "basculin" + }, + { + "Id": 10017, + "Name": "darmanitan" + }, + { + "Id": 10018, + "Name": "meloetta" + }, + { + "Id": 10019, + "Name": "tornadus" + }, + { + "Id": 10020, + "Name": "thundurus" + }, + { + "Id": 10021, + "Name": "landorus" + }, + { + "Id": 10022, + "Name": "kyurem" + }, + { + "Id": 10023, + "Name": "kyurem" + }, + { + "Id": 10024, + "Name": "keldeo" + }, + { + "Id": 10025, + "Name": "meowstic" + }, + { + "Id": 10026, + "Name": "aegislash" + }, + { + "Id": 10027, + "Name": "pumpkaboo" + }, + { + "Id": 10028, + "Name": "pumpkaboo" + }, + { + "Id": 10029, + "Name": "pumpkaboo" + }, + { + "Id": 10030, + "Name": "gourgeist" + }, + { + "Id": 10031, + "Name": "gourgeist" + }, + { + "Id": 10032, + "Name": "gourgeist" + }, + { + "Id": 10033, + "Name": "venusaur" + }, + { + "Id": 10034, + "Name": "charizard" + }, + { + "Id": 10035, + "Name": "charizard" + }, + { + "Id": 10036, + "Name": "blastoise" + }, + { + "Id": 10037, + "Name": "alakazam" + }, + { + "Id": 10038, + "Name": "gengar" + }, + { + "Id": 10039, + "Name": "kangaskhan" + }, + { + "Id": 10040, + "Name": "pinsir" + }, + { + "Id": 10041, + "Name": "gyarados" + }, + { + "Id": 10042, + "Name": "aerodactyl" + }, + { + "Id": 10043, + "Name": "mewtwo" + }, + { + "Id": 10044, + "Name": "mewtwo" + }, + { + "Id": 10045, + "Name": "ampharos" + }, + { + "Id": 10046, + "Name": "scizor" + }, + { + "Id": 10047, + "Name": "heracross" + }, + { + "Id": 10048, + "Name": "houndoom" + }, + { + "Id": 10049, + "Name": "tyranitar" + }, + { + "Id": 10050, + "Name": "blaziken" + }, + { + "Id": 10051, + "Name": "gardevoir" + }, + { + "Id": 10052, + "Name": "mawile" + }, + { + "Id": 10053, + "Name": "aggron" + }, + { + "Id": 10054, + "Name": "medicham" + }, + { + "Id": 10055, + "Name": "manectric" + }, + { + "Id": 10056, + "Name": "banette" + }, + { + "Id": 10057, + "Name": "absol" + }, + { + "Id": 10058, + "Name": "garchomp" + }, + { + "Id": 10059, + "Name": "lucario" + }, + { + "Id": 10060, + "Name": "abomasnow" + }, + { + "Id": 10061, + "Name": "floette" + }, + { + "Id": 10062, + "Name": "latias" + }, + { + "Id": 10063, + "Name": "latios" + }, + { + "Id": 10064, + "Name": "swampert" + }, + { + "Id": 10065, + "Name": "sceptile" + }, + { + "Id": 10066, + "Name": "sableye" + }, + { + "Id": 10067, + "Name": "altaria" + }, + { + "Id": 10068, + "Name": "gallade" + }, + { + "Id": 10069, + "Name": "audino" + }, + { + "Id": 10070, + "Name": "sharpedo" + }, + { + "Id": 10071, + "Name": "slowbro" + }, + { + "Id": 10072, + "Name": "steelix" + }, + { + "Id": 10073, + "Name": "pidgeot" + }, + { + "Id": 10074, + "Name": "glalie" + }, + { + "Id": 10075, + "Name": "diancie" + }, + { + "Id": 10076, + "Name": "metagross" + }, + { + "Id": 10077, + "Name": "kyogre" + }, + { + "Id": 10078, + "Name": "groudon" + }, + { + "Id": 10079, + "Name": "rayquaza" + }, + { + "Id": 10080, + "Name": "pikachu" + }, + { + "Id": 10081, + "Name": "pikachu" + }, + { + "Id": 10082, + "Name": "pikachu" + }, + { + "Id": 10083, + "Name": "pikachu" + }, + { + "Id": 10084, + "Name": "pikachu" + }, + { + "Id": 10085, + "Name": "pikachu" + }, + { + "Id": 10086, + "Name": "hoopa" + }, + { + "Id": 10087, + "Name": "camerupt" + }, + { + "Id": 10088, + "Name": "lopunny" + }, + { + "Id": 10089, + "Name": "salamence" + }, + { + "Id": 10090, + "Name": "beedrill" + } +] \ No newline at end of file From dfbef6d16147d566708b61c4391234ddb4363e93 Mon Sep 17 00:00:00 2001 From: samvaio Date: Thu, 23 Mar 2017 23:29:22 +0530 Subject: [PATCH 612/746] Update README.md Markdown header needed some space :D --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cb00cdc9..ae4aa579 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ [![nadeko1](https://cdn.discordapp.com/attachments/266240393639755778/281920134967328768/part2.png)](https://discordapp.com/oauth2/authorize?client_id=170254782546575360&scope=bot&permissions=66186303) [![nadeko2](https://cdn.discordapp.com/attachments/266240393639755778/281920161311883264/part3.png)](http://nadekobot.readthedocs.io/en/latest/Commands%20List/) -##For Update, Help and Guidelines +## For Updates, Help and Guidelines | [![twitter](https://cdn.discordapp.com/attachments/155726317222887425/252192520094613504/twiter_banner.JPG)](https://twitter.com/TheNadekoBot) | [![discord](https://cdn.discordapp.com/attachments/266240393639755778/281920766490968064/discord.png)](https://discord.gg/nadekobot) | [![Wiki](https://cdn.discordapp.com/attachments/266240393639755778/281920793330581506/datcord.png)](http://nadekobot.readthedocs.io/en/latest/) | --- | --- | --- | -| Follow me on Twitter for updates. | Join my Discord server if you need help. | Read the Docs for hosting guides. | \ No newline at end of file +| **Follow me on Twitter.** | **Join my Discord server for help.** | **Read the Docs for self-hosting.** | From a2ed4ac49bee66106d0cf5791014ac36655ccf52 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 24 Mar 2017 11:15:31 +0100 Subject: [PATCH 613/746] Fixed ;lp, thanks manuel --- src/NadekoBot/Modules/Permissions/Permissions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Permissions/Permissions.cs b/src/NadekoBot/Modules/Permissions/Permissions.cs index 2d21630d..ec0e1016 100644 --- a/src/NadekoBot/Modules/Permissions/Permissions.cs +++ b/src/NadekoBot/Modules/Permissions/Permissions.cs @@ -203,7 +203,7 @@ namespace NadekoBot.Modules.Permissions [RequireContext(ContextType.Guild)] public async Task ListPerms(int page = 1) { - if (page < 1 || page > 4) + if (page < 1) return; PermissionCache permCache; From 921725005c46c51e4412f2df62265ed9966da49b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 24 Mar 2017 11:29:17 +0100 Subject: [PATCH 614/746] mr mime fix --- .../Commands/Trivia/TriviaQuestionPool.cs | 2 +- src/NadekoBot/data/pokemon/name-id_map2.json | 3246 +++++++++++++++++ 2 files changed, 3247 insertions(+), 1 deletion(-) create mode 100644 src/NadekoBot/data/pokemon/name-id_map2.json diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs index 854db99d..cbad9815 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs @@ -21,7 +21,7 @@ namespace NadekoBot.Modules.Games.Trivia public static TriviaQuestionPool Instance { get; } = _instance ?? (_instance = new TriviaQuestionPool()); private const string questionsFile = "data/trivia_questions.json"; - private const string pokemonMapPath = "data/pokemon/name-id_map.json"; + private const string pokemonMapPath = "data/pokemon/name-id_map2.json"; private readonly int maxPokemonId; private Random rng { get; } = new NadekoRandom(); diff --git a/src/NadekoBot/data/pokemon/name-id_map2.json b/src/NadekoBot/data/pokemon/name-id_map2.json new file mode 100644 index 00000000..1de578a0 --- /dev/null +++ b/src/NadekoBot/data/pokemon/name-id_map2.json @@ -0,0 +1,3246 @@ +[ + { + "Id": 1, + "Name": "bulbasaur" + }, + { + "Id": 2, + "Name": "ivysaur" + }, + { + "Id": 3, + "Name": "venusaur" + }, + { + "Id": 4, + "Name": "charmander" + }, + { + "Id": 5, + "Name": "charmeleon" + }, + { + "Id": 6, + "Name": "charizard" + }, + { + "Id": 7, + "Name": "squirtle" + }, + { + "Id": 8, + "Name": "wartortle" + }, + { + "Id": 9, + "Name": "blastoise" + }, + { + "Id": 10, + "Name": "caterpie" + }, + { + "Id": 11, + "Name": "metapod" + }, + { + "Id": 12, + "Name": "butterfree" + }, + { + "Id": 13, + "Name": "weedle" + }, + { + "Id": 14, + "Name": "kakuna" + }, + { + "Id": 15, + "Name": "beedrill" + }, + { + "Id": 16, + "Name": "pidgey" + }, + { + "Id": 17, + "Name": "pidgeotto" + }, + { + "Id": 18, + "Name": "pidgeot" + }, + { + "Id": 19, + "Name": "rattata" + }, + { + "Id": 20, + "Name": "raticate" + }, + { + "Id": 21, + "Name": "spearow" + }, + { + "Id": 22, + "Name": "fearow" + }, + { + "Id": 23, + "Name": "ekans" + }, + { + "Id": 24, + "Name": "arbok" + }, + { + "Id": 25, + "Name": "pikachu" + }, + { + "Id": 26, + "Name": "raichu" + }, + { + "Id": 27, + "Name": "sandshrew" + }, + { + "Id": 28, + "Name": "sandslash" + }, + { + "Id": 29, + "Name": "nidoran" + }, + { + "Id": 30, + "Name": "nidorina" + }, + { + "Id": 31, + "Name": "nidoqueen" + }, + { + "Id": 32, + "Name": "nidoran" + }, + { + "Id": 33, + "Name": "nidorino" + }, + { + "Id": 34, + "Name": "nidoking" + }, + { + "Id": 35, + "Name": "clefairy" + }, + { + "Id": 36, + "Name": "clefable" + }, + { + "Id": 37, + "Name": "vulpix" + }, + { + "Id": 38, + "Name": "ninetales" + }, + { + "Id": 39, + "Name": "jigglypuff" + }, + { + "Id": 40, + "Name": "wigglytuff" + }, + { + "Id": 41, + "Name": "zubat" + }, + { + "Id": 42, + "Name": "golbat" + }, + { + "Id": 43, + "Name": "oddish" + }, + { + "Id": 44, + "Name": "gloom" + }, + { + "Id": 45, + "Name": "vileplume" + }, + { + "Id": 46, + "Name": "paras" + }, + { + "Id": 47, + "Name": "parasect" + }, + { + "Id": 48, + "Name": "venonat" + }, + { + "Id": 49, + "Name": "venomoth" + }, + { + "Id": 50, + "Name": "diglett" + }, + { + "Id": 51, + "Name": "dugtrio" + }, + { + "Id": 52, + "Name": "meowth" + }, + { + "Id": 53, + "Name": "persian" + }, + { + "Id": 54, + "Name": "psyduck" + }, + { + "Id": 55, + "Name": "golduck" + }, + { + "Id": 56, + "Name": "mankey" + }, + { + "Id": 57, + "Name": "primeape" + }, + { + "Id": 58, + "Name": "growlithe" + }, + { + "Id": 59, + "Name": "arcanine" + }, + { + "Id": 60, + "Name": "poliwag" + }, + { + "Id": 61, + "Name": "poliwhirl" + }, + { + "Id": 62, + "Name": "poliwrath" + }, + { + "Id": 63, + "Name": "abra" + }, + { + "Id": 64, + "Name": "kadabra" + }, + { + "Id": 65, + "Name": "alakazam" + }, + { + "Id": 66, + "Name": "machop" + }, + { + "Id": 67, + "Name": "machoke" + }, + { + "Id": 68, + "Name": "machamp" + }, + { + "Id": 69, + "Name": "bellsprout" + }, + { + "Id": 70, + "Name": "weepinbell" + }, + { + "Id": 71, + "Name": "victreebel" + }, + { + "Id": 72, + "Name": "tentacool" + }, + { + "Id": 73, + "Name": "tentacruel" + }, + { + "Id": 74, + "Name": "geodude" + }, + { + "Id": 75, + "Name": "graveler" + }, + { + "Id": 76, + "Name": "golem" + }, + { + "Id": 77, + "Name": "ponyta" + }, + { + "Id": 78, + "Name": "rapidash" + }, + { + "Id": 79, + "Name": "slowpoke" + }, + { + "Id": 80, + "Name": "slowbro" + }, + { + "Id": 81, + "Name": "magnemite" + }, + { + "Id": 82, + "Name": "magneton" + }, + { + "Id": 83, + "Name": "farfetchd" + }, + { + "Id": 84, + "Name": "doduo" + }, + { + "Id": 85, + "Name": "dodrio" + }, + { + "Id": 86, + "Name": "seel" + }, + { + "Id": 87, + "Name": "dewgong" + }, + { + "Id": 88, + "Name": "grimer" + }, + { + "Id": 89, + "Name": "muk" + }, + { + "Id": 90, + "Name": "shellder" + }, + { + "Id": 91, + "Name": "cloyster" + }, + { + "Id": 92, + "Name": "gastly" + }, + { + "Id": 93, + "Name": "haunter" + }, + { + "Id": 94, + "Name": "gengar" + }, + { + "Id": 95, + "Name": "onix" + }, + { + "Id": 96, + "Name": "drowzee" + }, + { + "Id": 97, + "Name": "hypno" + }, + { + "Id": 98, + "Name": "krabby" + }, + { + "Id": 99, + "Name": "kingler" + }, + { + "Id": 100, + "Name": "voltorb" + }, + { + "Id": 101, + "Name": "electrode" + }, + { + "Id": 102, + "Name": "exeggcute" + }, + { + "Id": 103, + "Name": "exeggutor" + }, + { + "Id": 104, + "Name": "cubone" + }, + { + "Id": 105, + "Name": "marowak" + }, + { + "Id": 106, + "Name": "hitmonlee" + }, + { + "Id": 107, + "Name": "hitmonchan" + }, + { + "Id": 108, + "Name": "lickitung" + }, + { + "Id": 109, + "Name": "koffing" + }, + { + "Id": 110, + "Name": "weezing" + }, + { + "Id": 111, + "Name": "rhyhorn" + }, + { + "Id": 112, + "Name": "rhydon" + }, + { + "Id": 113, + "Name": "chansey" + }, + { + "Id": 114, + "Name": "tangela" + }, + { + "Id": 115, + "Name": "kangaskhan" + }, + { + "Id": 116, + "Name": "horsea" + }, + { + "Id": 117, + "Name": "seadra" + }, + { + "Id": 118, + "Name": "goldeen" + }, + { + "Id": 119, + "Name": "seaking" + }, + { + "Id": 120, + "Name": "staryu" + }, + { + "Id": 121, + "Name": "starmie" + }, + { + "Id": 122, + "Name": "mr mime" + }, + { + "Id": 123, + "Name": "scyther" + }, + { + "Id": 124, + "Name": "jynx" + }, + { + "Id": 125, + "Name": "electabuzz" + }, + { + "Id": 126, + "Name": "magmar" + }, + { + "Id": 127, + "Name": "pinsir" + }, + { + "Id": 128, + "Name": "tauros" + }, + { + "Id": 129, + "Name": "magikarp" + }, + { + "Id": 130, + "Name": "gyarados" + }, + { + "Id": 131, + "Name": "lapras" + }, + { + "Id": 132, + "Name": "ditto" + }, + { + "Id": 133, + "Name": "eevee" + }, + { + "Id": 134, + "Name": "vaporeon" + }, + { + "Id": 135, + "Name": "jolteon" + }, + { + "Id": 136, + "Name": "flareon" + }, + { + "Id": 137, + "Name": "porygon" + }, + { + "Id": 138, + "Name": "omanyte" + }, + { + "Id": 139, + "Name": "omastar" + }, + { + "Id": 140, + "Name": "kabuto" + }, + { + "Id": 141, + "Name": "kabutops" + }, + { + "Id": 142, + "Name": "aerodactyl" + }, + { + "Id": 143, + "Name": "snorlax" + }, + { + "Id": 144, + "Name": "articuno" + }, + { + "Id": 145, + "Name": "zapdos" + }, + { + "Id": 146, + "Name": "moltres" + }, + { + "Id": 147, + "Name": "dratini" + }, + { + "Id": 148, + "Name": "dragonair" + }, + { + "Id": 149, + "Name": "dragonite" + }, + { + "Id": 150, + "Name": "mewtwo" + }, + { + "Id": 151, + "Name": "mew" + }, + { + "Id": 152, + "Name": "chikorita" + }, + { + "Id": 153, + "Name": "bayleef" + }, + { + "Id": 154, + "Name": "meganium" + }, + { + "Id": 155, + "Name": "cyndaquil" + }, + { + "Id": 156, + "Name": "quilava" + }, + { + "Id": 157, + "Name": "typhlosion" + }, + { + "Id": 158, + "Name": "totodile" + }, + { + "Id": 159, + "Name": "croconaw" + }, + { + "Id": 160, + "Name": "feraligatr" + }, + { + "Id": 161, + "Name": "sentret" + }, + { + "Id": 162, + "Name": "furret" + }, + { + "Id": 163, + "Name": "hoothoot" + }, + { + "Id": 164, + "Name": "noctowl" + }, + { + "Id": 165, + "Name": "ledyba" + }, + { + "Id": 166, + "Name": "ledian" + }, + { + "Id": 167, + "Name": "spinarak" + }, + { + "Id": 168, + "Name": "ariados" + }, + { + "Id": 169, + "Name": "crobat" + }, + { + "Id": 170, + "Name": "chinchou" + }, + { + "Id": 171, + "Name": "lanturn" + }, + { + "Id": 172, + "Name": "pichu" + }, + { + "Id": 173, + "Name": "cleffa" + }, + { + "Id": 174, + "Name": "igglybuff" + }, + { + "Id": 175, + "Name": "togepi" + }, + { + "Id": 176, + "Name": "togetic" + }, + { + "Id": 177, + "Name": "natu" + }, + { + "Id": 178, + "Name": "xatu" + }, + { + "Id": 179, + "Name": "mareep" + }, + { + "Id": 180, + "Name": "flaaffy" + }, + { + "Id": 181, + "Name": "ampharos" + }, + { + "Id": 182, + "Name": "bellossom" + }, + { + "Id": 183, + "Name": "marill" + }, + { + "Id": 184, + "Name": "azumarill" + }, + { + "Id": 185, + "Name": "sudowoodo" + }, + { + "Id": 186, + "Name": "politoed" + }, + { + "Id": 187, + "Name": "hoppip" + }, + { + "Id": 188, + "Name": "skiploom" + }, + { + "Id": 189, + "Name": "jumpluff" + }, + { + "Id": 190, + "Name": "aipom" + }, + { + "Id": 191, + "Name": "sunkern" + }, + { + "Id": 192, + "Name": "sunflora" + }, + { + "Id": 193, + "Name": "yanma" + }, + { + "Id": 194, + "Name": "wooper" + }, + { + "Id": 195, + "Name": "quagsire" + }, + { + "Id": 196, + "Name": "espeon" + }, + { + "Id": 197, + "Name": "umbreon" + }, + { + "Id": 198, + "Name": "murkrow" + }, + { + "Id": 199, + "Name": "slowking" + }, + { + "Id": 200, + "Name": "misdreavus" + }, + { + "Id": 201, + "Name": "unown" + }, + { + "Id": 202, + "Name": "wobbuffet" + }, + { + "Id": 203, + "Name": "girafarig" + }, + { + "Id": 204, + "Name": "pineco" + }, + { + "Id": 205, + "Name": "forretress" + }, + { + "Id": 206, + "Name": "dunsparce" + }, + { + "Id": 207, + "Name": "gligar" + }, + { + "Id": 208, + "Name": "steelix" + }, + { + "Id": 209, + "Name": "snubbull" + }, + { + "Id": 210, + "Name": "granbull" + }, + { + "Id": 211, + "Name": "qwilfish" + }, + { + "Id": 212, + "Name": "scizor" + }, + { + "Id": 213, + "Name": "shuckle" + }, + { + "Id": 214, + "Name": "heracross" + }, + { + "Id": 215, + "Name": "sneasel" + }, + { + "Id": 216, + "Name": "teddiursa" + }, + { + "Id": 217, + "Name": "ursaring" + }, + { + "Id": 218, + "Name": "slugma" + }, + { + "Id": 219, + "Name": "magcargo" + }, + { + "Id": 220, + "Name": "swinub" + }, + { + "Id": 221, + "Name": "piloswine" + }, + { + "Id": 222, + "Name": "corsola" + }, + { + "Id": 223, + "Name": "remoraid" + }, + { + "Id": 224, + "Name": "octillery" + }, + { + "Id": 225, + "Name": "delibird" + }, + { + "Id": 226, + "Name": "mantine" + }, + { + "Id": 227, + "Name": "skarmory" + }, + { + "Id": 228, + "Name": "houndour" + }, + { + "Id": 229, + "Name": "houndoom" + }, + { + "Id": 230, + "Name": "kingdra" + }, + { + "Id": 231, + "Name": "phanpy" + }, + { + "Id": 232, + "Name": "donphan" + }, + { + "Id": 233, + "Name": "porygon2" + }, + { + "Id": 234, + "Name": "stantler" + }, + { + "Id": 235, + "Name": "smeargle" + }, + { + "Id": 236, + "Name": "tyrogue" + }, + { + "Id": 237, + "Name": "hitmontop" + }, + { + "Id": 238, + "Name": "smoochum" + }, + { + "Id": 239, + "Name": "elekid" + }, + { + "Id": 240, + "Name": "magby" + }, + { + "Id": 241, + "Name": "miltank" + }, + { + "Id": 242, + "Name": "blissey" + }, + { + "Id": 243, + "Name": "raikou" + }, + { + "Id": 244, + "Name": "entei" + }, + { + "Id": 245, + "Name": "suicune" + }, + { + "Id": 246, + "Name": "larvitar" + }, + { + "Id": 247, + "Name": "pupitar" + }, + { + "Id": 248, + "Name": "tyranitar" + }, + { + "Id": 249, + "Name": "lugia" + }, + { + "Id": 250, + "Name": "ho" + }, + { + "Id": 251, + "Name": "celebi" + }, + { + "Id": 252, + "Name": "treecko" + }, + { + "Id": 253, + "Name": "grovyle" + }, + { + "Id": 254, + "Name": "sceptile" + }, + { + "Id": 255, + "Name": "torchic" + }, + { + "Id": 256, + "Name": "combusken" + }, + { + "Id": 257, + "Name": "blaziken" + }, + { + "Id": 258, + "Name": "mudkip" + }, + { + "Id": 259, + "Name": "marshtomp" + }, + { + "Id": 260, + "Name": "swampert" + }, + { + "Id": 261, + "Name": "poochyena" + }, + { + "Id": 262, + "Name": "mightyena" + }, + { + "Id": 263, + "Name": "zigzagoon" + }, + { + "Id": 264, + "Name": "linoone" + }, + { + "Id": 265, + "Name": "wurmple" + }, + { + "Id": 266, + "Name": "silcoon" + }, + { + "Id": 267, + "Name": "beautifly" + }, + { + "Id": 268, + "Name": "cascoon" + }, + { + "Id": 269, + "Name": "dustox" + }, + { + "Id": 270, + "Name": "lotad" + }, + { + "Id": 271, + "Name": "lombre" + }, + { + "Id": 272, + "Name": "ludicolo" + }, + { + "Id": 273, + "Name": "seedot" + }, + { + "Id": 274, + "Name": "nuzleaf" + }, + { + "Id": 275, + "Name": "shiftry" + }, + { + "Id": 276, + "Name": "taillow" + }, + { + "Id": 277, + "Name": "swellow" + }, + { + "Id": 278, + "Name": "wingull" + }, + { + "Id": 279, + "Name": "pelipper" + }, + { + "Id": 280, + "Name": "ralts" + }, + { + "Id": 281, + "Name": "kirlia" + }, + { + "Id": 282, + "Name": "gardevoir" + }, + { + "Id": 283, + "Name": "surskit" + }, + { + "Id": 284, + "Name": "masquerain" + }, + { + "Id": 285, + "Name": "shroomish" + }, + { + "Id": 286, + "Name": "breloom" + }, + { + "Id": 287, + "Name": "slakoth" + }, + { + "Id": 288, + "Name": "vigoroth" + }, + { + "Id": 289, + "Name": "slaking" + }, + { + "Id": 290, + "Name": "nincada" + }, + { + "Id": 291, + "Name": "ninjask" + }, + { + "Id": 292, + "Name": "shedinja" + }, + { + "Id": 293, + "Name": "whismur" + }, + { + "Id": 294, + "Name": "loudred" + }, + { + "Id": 295, + "Name": "exploud" + }, + { + "Id": 296, + "Name": "makuhita" + }, + { + "Id": 297, + "Name": "hariyama" + }, + { + "Id": 298, + "Name": "azurill" + }, + { + "Id": 299, + "Name": "nosepass" + }, + { + "Id": 300, + "Name": "skitty" + }, + { + "Id": 301, + "Name": "delcatty" + }, + { + "Id": 302, + "Name": "sableye" + }, + { + "Id": 303, + "Name": "mawile" + }, + { + "Id": 304, + "Name": "aron" + }, + { + "Id": 305, + "Name": "lairon" + }, + { + "Id": 306, + "Name": "aggron" + }, + { + "Id": 307, + "Name": "meditite" + }, + { + "Id": 308, + "Name": "medicham" + }, + { + "Id": 309, + "Name": "electrike" + }, + { + "Id": 310, + "Name": "manectric" + }, + { + "Id": 311, + "Name": "plusle" + }, + { + "Id": 312, + "Name": "minun" + }, + { + "Id": 313, + "Name": "volbeat" + }, + { + "Id": 314, + "Name": "illumise" + }, + { + "Id": 315, + "Name": "roselia" + }, + { + "Id": 316, + "Name": "gulpin" + }, + { + "Id": 317, + "Name": "swalot" + }, + { + "Id": 318, + "Name": "carvanha" + }, + { + "Id": 319, + "Name": "sharpedo" + }, + { + "Id": 320, + "Name": "wailmer" + }, + { + "Id": 321, + "Name": "wailord" + }, + { + "Id": 322, + "Name": "numel" + }, + { + "Id": 323, + "Name": "camerupt" + }, + { + "Id": 324, + "Name": "torkoal" + }, + { + "Id": 325, + "Name": "spoink" + }, + { + "Id": 326, + "Name": "grumpig" + }, + { + "Id": 327, + "Name": "spinda" + }, + { + "Id": 328, + "Name": "trapinch" + }, + { + "Id": 329, + "Name": "vibrava" + }, + { + "Id": 330, + "Name": "flygon" + }, + { + "Id": 331, + "Name": "cacnea" + }, + { + "Id": 332, + "Name": "cacturne" + }, + { + "Id": 333, + "Name": "swablu" + }, + { + "Id": 334, + "Name": "altaria" + }, + { + "Id": 335, + "Name": "zangoose" + }, + { + "Id": 336, + "Name": "seviper" + }, + { + "Id": 337, + "Name": "lunatone" + }, + { + "Id": 338, + "Name": "solrock" + }, + { + "Id": 339, + "Name": "barboach" + }, + { + "Id": 340, + "Name": "whiscash" + }, + { + "Id": 341, + "Name": "corphish" + }, + { + "Id": 342, + "Name": "crawdaunt" + }, + { + "Id": 343, + "Name": "baltoy" + }, + { + "Id": 344, + "Name": "claydol" + }, + { + "Id": 345, + "Name": "lileep" + }, + { + "Id": 346, + "Name": "cradily" + }, + { + "Id": 347, + "Name": "anorith" + }, + { + "Id": 348, + "Name": "armaldo" + }, + { + "Id": 349, + "Name": "feebas" + }, + { + "Id": 350, + "Name": "milotic" + }, + { + "Id": 351, + "Name": "castform" + }, + { + "Id": 352, + "Name": "kecleon" + }, + { + "Id": 353, + "Name": "shuppet" + }, + { + "Id": 354, + "Name": "banette" + }, + { + "Id": 355, + "Name": "duskull" + }, + { + "Id": 356, + "Name": "dusclops" + }, + { + "Id": 357, + "Name": "tropius" + }, + { + "Id": 358, + "Name": "chimecho" + }, + { + "Id": 359, + "Name": "absol" + }, + { + "Id": 360, + "Name": "wynaut" + }, + { + "Id": 361, + "Name": "snorunt" + }, + { + "Id": 362, + "Name": "glalie" + }, + { + "Id": 363, + "Name": "spheal" + }, + { + "Id": 364, + "Name": "sealeo" + }, + { + "Id": 365, + "Name": "walrein" + }, + { + "Id": 366, + "Name": "clamperl" + }, + { + "Id": 367, + "Name": "huntail" + }, + { + "Id": 368, + "Name": "gorebyss" + }, + { + "Id": 369, + "Name": "relicanth" + }, + { + "Id": 370, + "Name": "luvdisc" + }, + { + "Id": 371, + "Name": "bagon" + }, + { + "Id": 372, + "Name": "shelgon" + }, + { + "Id": 373, + "Name": "salamence" + }, + { + "Id": 374, + "Name": "beldum" + }, + { + "Id": 375, + "Name": "metang" + }, + { + "Id": 376, + "Name": "metagross" + }, + { + "Id": 377, + "Name": "regirock" + }, + { + "Id": 378, + "Name": "regice" + }, + { + "Id": 379, + "Name": "registeel" + }, + { + "Id": 380, + "Name": "latias" + }, + { + "Id": 381, + "Name": "latios" + }, + { + "Id": 382, + "Name": "kyogre" + }, + { + "Id": 383, + "Name": "groudon" + }, + { + "Id": 384, + "Name": "rayquaza" + }, + { + "Id": 385, + "Name": "jirachi" + }, + { + "Id": 386, + "Name": "deoxys" + }, + { + "Id": 387, + "Name": "turtwig" + }, + { + "Id": 388, + "Name": "grotle" + }, + { + "Id": 389, + "Name": "torterra" + }, + { + "Id": 390, + "Name": "chimchar" + }, + { + "Id": 391, + "Name": "monferno" + }, + { + "Id": 392, + "Name": "infernape" + }, + { + "Id": 393, + "Name": "piplup" + }, + { + "Id": 394, + "Name": "prinplup" + }, + { + "Id": 395, + "Name": "empoleon" + }, + { + "Id": 396, + "Name": "starly" + }, + { + "Id": 397, + "Name": "staravia" + }, + { + "Id": 398, + "Name": "staraptor" + }, + { + "Id": 399, + "Name": "bidoof" + }, + { + "Id": 400, + "Name": "bibarel" + }, + { + "Id": 401, + "Name": "kricketot" + }, + { + "Id": 402, + "Name": "kricketune" + }, + { + "Id": 403, + "Name": "shinx" + }, + { + "Id": 404, + "Name": "luxio" + }, + { + "Id": 405, + "Name": "luxray" + }, + { + "Id": 406, + "Name": "budew" + }, + { + "Id": 407, + "Name": "roserade" + }, + { + "Id": 408, + "Name": "cranidos" + }, + { + "Id": 409, + "Name": "rampardos" + }, + { + "Id": 410, + "Name": "shieldon" + }, + { + "Id": 411, + "Name": "bastiodon" + }, + { + "Id": 412, + "Name": "burmy" + }, + { + "Id": 413, + "Name": "wormadam" + }, + { + "Id": 414, + "Name": "mothim" + }, + { + "Id": 415, + "Name": "combee" + }, + { + "Id": 416, + "Name": "vespiquen" + }, + { + "Id": 417, + "Name": "pachirisu" + }, + { + "Id": 418, + "Name": "buizel" + }, + { + "Id": 419, + "Name": "floatzel" + }, + { + "Id": 420, + "Name": "cherubi" + }, + { + "Id": 421, + "Name": "cherrim" + }, + { + "Id": 422, + "Name": "shellos" + }, + { + "Id": 423, + "Name": "gastrodon" + }, + { + "Id": 424, + "Name": "ambipom" + }, + { + "Id": 425, + "Name": "drifloon" + }, + { + "Id": 426, + "Name": "drifblim" + }, + { + "Id": 427, + "Name": "buneary" + }, + { + "Id": 428, + "Name": "lopunny" + }, + { + "Id": 429, + "Name": "mismagius" + }, + { + "Id": 430, + "Name": "honchkrow" + }, + { + "Id": 431, + "Name": "glameow" + }, + { + "Id": 432, + "Name": "purugly" + }, + { + "Id": 433, + "Name": "chingling" + }, + { + "Id": 434, + "Name": "stunky" + }, + { + "Id": 435, + "Name": "skuntank" + }, + { + "Id": 436, + "Name": "bronzor" + }, + { + "Id": 437, + "Name": "bronzong" + }, + { + "Id": 438, + "Name": "bonsly" + }, + { + "Id": 439, + "Name": "mime" + }, + { + "Id": 440, + "Name": "happiny" + }, + { + "Id": 441, + "Name": "chatot" + }, + { + "Id": 442, + "Name": "spiritomb" + }, + { + "Id": 443, + "Name": "gible" + }, + { + "Id": 444, + "Name": "gabite" + }, + { + "Id": 445, + "Name": "garchomp" + }, + { + "Id": 446, + "Name": "munchlax" + }, + { + "Id": 447, + "Name": "riolu" + }, + { + "Id": 448, + "Name": "lucario" + }, + { + "Id": 449, + "Name": "hippopotas" + }, + { + "Id": 450, + "Name": "hippowdon" + }, + { + "Id": 451, + "Name": "skorupi" + }, + { + "Id": 452, + "Name": "drapion" + }, + { + "Id": 453, + "Name": "croagunk" + }, + { + "Id": 454, + "Name": "toxicroak" + }, + { + "Id": 455, + "Name": "carnivine" + }, + { + "Id": 456, + "Name": "finneon" + }, + { + "Id": 457, + "Name": "lumineon" + }, + { + "Id": 458, + "Name": "mantyke" + }, + { + "Id": 459, + "Name": "snover" + }, + { + "Id": 460, + "Name": "abomasnow" + }, + { + "Id": 461, + "Name": "weavile" + }, + { + "Id": 462, + "Name": "magnezone" + }, + { + "Id": 463, + "Name": "lickilicky" + }, + { + "Id": 464, + "Name": "rhyperior" + }, + { + "Id": 465, + "Name": "tangrowth" + }, + { + "Id": 466, + "Name": "electivire" + }, + { + "Id": 467, + "Name": "magmortar" + }, + { + "Id": 468, + "Name": "togekiss" + }, + { + "Id": 469, + "Name": "yanmega" + }, + { + "Id": 470, + "Name": "leafeon" + }, + { + "Id": 471, + "Name": "glaceon" + }, + { + "Id": 472, + "Name": "gliscor" + }, + { + "Id": 473, + "Name": "mamoswine" + }, + { + "Id": 474, + "Name": "porygon" + }, + { + "Id": 475, + "Name": "gallade" + }, + { + "Id": 476, + "Name": "probopass" + }, + { + "Id": 477, + "Name": "dusknoir" + }, + { + "Id": 478, + "Name": "froslass" + }, + { + "Id": 479, + "Name": "rotom" + }, + { + "Id": 480, + "Name": "uxie" + }, + { + "Id": 481, + "Name": "mesprit" + }, + { + "Id": 482, + "Name": "azelf" + }, + { + "Id": 483, + "Name": "dialga" + }, + { + "Id": 484, + "Name": "palkia" + }, + { + "Id": 485, + "Name": "heatran" + }, + { + "Id": 486, + "Name": "regigigas" + }, + { + "Id": 487, + "Name": "giratina" + }, + { + "Id": 488, + "Name": "cresselia" + }, + { + "Id": 489, + "Name": "phione" + }, + { + "Id": 490, + "Name": "manaphy" + }, + { + "Id": 491, + "Name": "darkrai" + }, + { + "Id": 492, + "Name": "shaymin" + }, + { + "Id": 493, + "Name": "arceus" + }, + { + "Id": 494, + "Name": "victini" + }, + { + "Id": 495, + "Name": "snivy" + }, + { + "Id": 496, + "Name": "servine" + }, + { + "Id": 497, + "Name": "serperior" + }, + { + "Id": 498, + "Name": "tepig" + }, + { + "Id": 499, + "Name": "pignite" + }, + { + "Id": 500, + "Name": "emboar" + }, + { + "Id": 501, + "Name": "oshawott" + }, + { + "Id": 502, + "Name": "dewott" + }, + { + "Id": 503, + "Name": "samurott" + }, + { + "Id": 504, + "Name": "patrat" + }, + { + "Id": 505, + "Name": "watchog" + }, + { + "Id": 506, + "Name": "lillipup" + }, + { + "Id": 507, + "Name": "herdier" + }, + { + "Id": 508, + "Name": "stoutland" + }, + { + "Id": 509, + "Name": "purrloin" + }, + { + "Id": 510, + "Name": "liepard" + }, + { + "Id": 511, + "Name": "pansage" + }, + { + "Id": 512, + "Name": "simisage" + }, + { + "Id": 513, + "Name": "pansear" + }, + { + "Id": 514, + "Name": "simisear" + }, + { + "Id": 515, + "Name": "panpour" + }, + { + "Id": 516, + "Name": "simipour" + }, + { + "Id": 517, + "Name": "munna" + }, + { + "Id": 518, + "Name": "musharna" + }, + { + "Id": 519, + "Name": "pidove" + }, + { + "Id": 520, + "Name": "tranquill" + }, + { + "Id": 521, + "Name": "unfezant" + }, + { + "Id": 522, + "Name": "blitzle" + }, + { + "Id": 523, + "Name": "zebstrika" + }, + { + "Id": 524, + "Name": "roggenrola" + }, + { + "Id": 525, + "Name": "boldore" + }, + { + "Id": 526, + "Name": "gigalith" + }, + { + "Id": 527, + "Name": "woobat" + }, + { + "Id": 528, + "Name": "swoobat" + }, + { + "Id": 529, + "Name": "drilbur" + }, + { + "Id": 530, + "Name": "excadrill" + }, + { + "Id": 531, + "Name": "audino" + }, + { + "Id": 532, + "Name": "timburr" + }, + { + "Id": 533, + "Name": "gurdurr" + }, + { + "Id": 534, + "Name": "conkeldurr" + }, + { + "Id": 535, + "Name": "tympole" + }, + { + "Id": 536, + "Name": "palpitoad" + }, + { + "Id": 537, + "Name": "seismitoad" + }, + { + "Id": 538, + "Name": "throh" + }, + { + "Id": 539, + "Name": "sawk" + }, + { + "Id": 540, + "Name": "sewaddle" + }, + { + "Id": 541, + "Name": "swadloon" + }, + { + "Id": 542, + "Name": "leavanny" + }, + { + "Id": 543, + "Name": "venipede" + }, + { + "Id": 544, + "Name": "whirlipede" + }, + { + "Id": 545, + "Name": "scolipede" + }, + { + "Id": 546, + "Name": "cottonee" + }, + { + "Id": 547, + "Name": "whimsicott" + }, + { + "Id": 548, + "Name": "petilil" + }, + { + "Id": 549, + "Name": "lilligant" + }, + { + "Id": 550, + "Name": "basculin" + }, + { + "Id": 551, + "Name": "sandile" + }, + { + "Id": 552, + "Name": "krokorok" + }, + { + "Id": 553, + "Name": "krookodile" + }, + { + "Id": 554, + "Name": "darumaka" + }, + { + "Id": 555, + "Name": "darmanitan" + }, + { + "Id": 556, + "Name": "maractus" + }, + { + "Id": 557, + "Name": "dwebble" + }, + { + "Id": 558, + "Name": "crustle" + }, + { + "Id": 559, + "Name": "scraggy" + }, + { + "Id": 560, + "Name": "scrafty" + }, + { + "Id": 561, + "Name": "sigilyph" + }, + { + "Id": 562, + "Name": "yamask" + }, + { + "Id": 563, + "Name": "cofagrigus" + }, + { + "Id": 564, + "Name": "tirtouga" + }, + { + "Id": 565, + "Name": "carracosta" + }, + { + "Id": 566, + "Name": "archen" + }, + { + "Id": 567, + "Name": "archeops" + }, + { + "Id": 568, + "Name": "trubbish" + }, + { + "Id": 569, + "Name": "garbodor" + }, + { + "Id": 570, + "Name": "zorua" + }, + { + "Id": 571, + "Name": "zoroark" + }, + { + "Id": 572, + "Name": "minccino" + }, + { + "Id": 573, + "Name": "cinccino" + }, + { + "Id": 574, + "Name": "gothita" + }, + { + "Id": 575, + "Name": "gothorita" + }, + { + "Id": 576, + "Name": "gothitelle" + }, + { + "Id": 577, + "Name": "solosis" + }, + { + "Id": 578, + "Name": "duosion" + }, + { + "Id": 579, + "Name": "reuniclus" + }, + { + "Id": 580, + "Name": "ducklett" + }, + { + "Id": 581, + "Name": "swanna" + }, + { + "Id": 582, + "Name": "vanillite" + }, + { + "Id": 583, + "Name": "vanillish" + }, + { + "Id": 584, + "Name": "vanilluxe" + }, + { + "Id": 585, + "Name": "deerling" + }, + { + "Id": 586, + "Name": "sawsbuck" + }, + { + "Id": 587, + "Name": "emolga" + }, + { + "Id": 588, + "Name": "karrablast" + }, + { + "Id": 589, + "Name": "escavalier" + }, + { + "Id": 590, + "Name": "foongus" + }, + { + "Id": 591, + "Name": "amoonguss" + }, + { + "Id": 592, + "Name": "frillish" + }, + { + "Id": 593, + "Name": "jellicent" + }, + { + "Id": 594, + "Name": "alomomola" + }, + { + "Id": 595, + "Name": "joltik" + }, + { + "Id": 596, + "Name": "galvantula" + }, + { + "Id": 597, + "Name": "ferroseed" + }, + { + "Id": 598, + "Name": "ferrothorn" + }, + { + "Id": 599, + "Name": "klink" + }, + { + "Id": 600, + "Name": "klang" + }, + { + "Id": 601, + "Name": "klinklang" + }, + { + "Id": 602, + "Name": "tynamo" + }, + { + "Id": 603, + "Name": "eelektrik" + }, + { + "Id": 604, + "Name": "eelektross" + }, + { + "Id": 605, + "Name": "elgyem" + }, + { + "Id": 606, + "Name": "beheeyem" + }, + { + "Id": 607, + "Name": "litwick" + }, + { + "Id": 608, + "Name": "lampent" + }, + { + "Id": 609, + "Name": "chandelure" + }, + { + "Id": 610, + "Name": "axew" + }, + { + "Id": 611, + "Name": "fraxure" + }, + { + "Id": 612, + "Name": "haxorus" + }, + { + "Id": 613, + "Name": "cubchoo" + }, + { + "Id": 614, + "Name": "beartic" + }, + { + "Id": 615, + "Name": "cryogonal" + }, + { + "Id": 616, + "Name": "shelmet" + }, + { + "Id": 617, + "Name": "accelgor" + }, + { + "Id": 618, + "Name": "stunfisk" + }, + { + "Id": 619, + "Name": "mienfoo" + }, + { + "Id": 620, + "Name": "mienshao" + }, + { + "Id": 621, + "Name": "druddigon" + }, + { + "Id": 622, + "Name": "golett" + }, + { + "Id": 623, + "Name": "golurk" + }, + { + "Id": 624, + "Name": "pawniard" + }, + { + "Id": 625, + "Name": "bisharp" + }, + { + "Id": 626, + "Name": "bouffalant" + }, + { + "Id": 627, + "Name": "rufflet" + }, + { + "Id": 628, + "Name": "braviary" + }, + { + "Id": 629, + "Name": "vullaby" + }, + { + "Id": 630, + "Name": "mandibuzz" + }, + { + "Id": 631, + "Name": "heatmor" + }, + { + "Id": 632, + "Name": "durant" + }, + { + "Id": 633, + "Name": "deino" + }, + { + "Id": 634, + "Name": "zweilous" + }, + { + "Id": 635, + "Name": "hydreigon" + }, + { + "Id": 636, + "Name": "larvesta" + }, + { + "Id": 637, + "Name": "volcarona" + }, + { + "Id": 638, + "Name": "cobalion" + }, + { + "Id": 639, + "Name": "terrakion" + }, + { + "Id": 640, + "Name": "virizion" + }, + { + "Id": 641, + "Name": "tornadus" + }, + { + "Id": 642, + "Name": "thundurus" + }, + { + "Id": 643, + "Name": "reshiram" + }, + { + "Id": 644, + "Name": "zekrom" + }, + { + "Id": 645, + "Name": "landorus" + }, + { + "Id": 646, + "Name": "kyurem" + }, + { + "Id": 647, + "Name": "keldeo" + }, + { + "Id": 648, + "Name": "meloetta" + }, + { + "Id": 649, + "Name": "genesect" + }, + { + "Id": 650, + "Name": "chespin" + }, + { + "Id": 651, + "Name": "quilladin" + }, + { + "Id": 652, + "Name": "chesnaught" + }, + { + "Id": 653, + "Name": "fennekin" + }, + { + "Id": 654, + "Name": "braixen" + }, + { + "Id": 655, + "Name": "delphox" + }, + { + "Id": 656, + "Name": "froakie" + }, + { + "Id": 657, + "Name": "frogadier" + }, + { + "Id": 658, + "Name": "greninja" + }, + { + "Id": 659, + "Name": "bunnelby" + }, + { + "Id": 660, + "Name": "diggersby" + }, + { + "Id": 661, + "Name": "fletchling" + }, + { + "Id": 662, + "Name": "fletchinder" + }, + { + "Id": 663, + "Name": "talonflame" + }, + { + "Id": 664, + "Name": "scatterbug" + }, + { + "Id": 665, + "Name": "spewpa" + }, + { + "Id": 666, + "Name": "vivillon" + }, + { + "Id": 667, + "Name": "litleo" + }, + { + "Id": 668, + "Name": "pyroar" + }, + { + "Id": 669, + "Name": "flabebe" + }, + { + "Id": 670, + "Name": "floette" + }, + { + "Id": 671, + "Name": "florges" + }, + { + "Id": 672, + "Name": "skiddo" + }, + { + "Id": 673, + "Name": "gogoat" + }, + { + "Id": 674, + "Name": "pancham" + }, + { + "Id": 675, + "Name": "pangoro" + }, + { + "Id": 676, + "Name": "furfrou" + }, + { + "Id": 677, + "Name": "espurr" + }, + { + "Id": 678, + "Name": "meowstic" + }, + { + "Id": 679, + "Name": "honedge" + }, + { + "Id": 680, + "Name": "doublade" + }, + { + "Id": 681, + "Name": "aegislash" + }, + { + "Id": 682, + "Name": "spritzee" + }, + { + "Id": 683, + "Name": "aromatisse" + }, + { + "Id": 684, + "Name": "swirlix" + }, + { + "Id": 685, + "Name": "slurpuff" + }, + { + "Id": 686, + "Name": "inkay" + }, + { + "Id": 687, + "Name": "malamar" + }, + { + "Id": 688, + "Name": "binacle" + }, + { + "Id": 689, + "Name": "barbaracle" + }, + { + "Id": 690, + "Name": "skrelp" + }, + { + "Id": 691, + "Name": "dragalge" + }, + { + "Id": 692, + "Name": "clauncher" + }, + { + "Id": 693, + "Name": "clawitzer" + }, + { + "Id": 694, + "Name": "helioptile" + }, + { + "Id": 695, + "Name": "heliolisk" + }, + { + "Id": 696, + "Name": "tyrunt" + }, + { + "Id": 697, + "Name": "tyrantrum" + }, + { + "Id": 698, + "Name": "amaura" + }, + { + "Id": 699, + "Name": "aurorus" + }, + { + "Id": 700, + "Name": "sylveon" + }, + { + "Id": 701, + "Name": "hawlucha" + }, + { + "Id": 702, + "Name": "dedenne" + }, + { + "Id": 703, + "Name": "carbink" + }, + { + "Id": 704, + "Name": "goomy" + }, + { + "Id": 705, + "Name": "sliggoo" + }, + { + "Id": 706, + "Name": "goodra" + }, + { + "Id": 707, + "Name": "klefki" + }, + { + "Id": 708, + "Name": "phantump" + }, + { + "Id": 709, + "Name": "trevenant" + }, + { + "Id": 710, + "Name": "pumpkaboo" + }, + { + "Id": 711, + "Name": "gourgeist" + }, + { + "Id": 712, + "Name": "bergmite" + }, + { + "Id": 713, + "Name": "avalugg" + }, + { + "Id": 714, + "Name": "noibat" + }, + { + "Id": 715, + "Name": "noivern" + }, + { + "Id": 716, + "Name": "xerneas" + }, + { + "Id": 717, + "Name": "yveltal" + }, + { + "Id": 718, + "Name": "zygarde" + }, + { + "Id": 719, + "Name": "diancie" + }, + { + "Id": 720, + "Name": "hoopa" + }, + { + "Id": 721, + "Name": "volcanion" + }, + { + "Id": 10001, + "Name": "deoxys" + }, + { + "Id": 10002, + "Name": "deoxys" + }, + { + "Id": 10003, + "Name": "deoxys" + }, + { + "Id": 10004, + "Name": "wormadam" + }, + { + "Id": 10005, + "Name": "wormadam" + }, + { + "Id": 10006, + "Name": "shaymin" + }, + { + "Id": 10007, + "Name": "giratina" + }, + { + "Id": 10008, + "Name": "rotom" + }, + { + "Id": 10009, + "Name": "rotom" + }, + { + "Id": 10010, + "Name": "rotom" + }, + { + "Id": 10011, + "Name": "rotom" + }, + { + "Id": 10012, + "Name": "rotom" + }, + { + "Id": 10013, + "Name": "castform" + }, + { + "Id": 10014, + "Name": "castform" + }, + { + "Id": 10015, + "Name": "castform" + }, + { + "Id": 10016, + "Name": "basculin" + }, + { + "Id": 10017, + "Name": "darmanitan" + }, + { + "Id": 10018, + "Name": "meloetta" + }, + { + "Id": 10019, + "Name": "tornadus" + }, + { + "Id": 10020, + "Name": "thundurus" + }, + { + "Id": 10021, + "Name": "landorus" + }, + { + "Id": 10022, + "Name": "kyurem" + }, + { + "Id": 10023, + "Name": "kyurem" + }, + { + "Id": 10024, + "Name": "keldeo" + }, + { + "Id": 10025, + "Name": "meowstic" + }, + { + "Id": 10026, + "Name": "aegislash" + }, + { + "Id": 10027, + "Name": "pumpkaboo" + }, + { + "Id": 10028, + "Name": "pumpkaboo" + }, + { + "Id": 10029, + "Name": "pumpkaboo" + }, + { + "Id": 10030, + "Name": "gourgeist" + }, + { + "Id": 10031, + "Name": "gourgeist" + }, + { + "Id": 10032, + "Name": "gourgeist" + }, + { + "Id": 10033, + "Name": "venusaur" + }, + { + "Id": 10034, + "Name": "charizard" + }, + { + "Id": 10035, + "Name": "charizard" + }, + { + "Id": 10036, + "Name": "blastoise" + }, + { + "Id": 10037, + "Name": "alakazam" + }, + { + "Id": 10038, + "Name": "gengar" + }, + { + "Id": 10039, + "Name": "kangaskhan" + }, + { + "Id": 10040, + "Name": "pinsir" + }, + { + "Id": 10041, + "Name": "gyarados" + }, + { + "Id": 10042, + "Name": "aerodactyl" + }, + { + "Id": 10043, + "Name": "mewtwo" + }, + { + "Id": 10044, + "Name": "mewtwo" + }, + { + "Id": 10045, + "Name": "ampharos" + }, + { + "Id": 10046, + "Name": "scizor" + }, + { + "Id": 10047, + "Name": "heracross" + }, + { + "Id": 10048, + "Name": "houndoom" + }, + { + "Id": 10049, + "Name": "tyranitar" + }, + { + "Id": 10050, + "Name": "blaziken" + }, + { + "Id": 10051, + "Name": "gardevoir" + }, + { + "Id": 10052, + "Name": "mawile" + }, + { + "Id": 10053, + "Name": "aggron" + }, + { + "Id": 10054, + "Name": "medicham" + }, + { + "Id": 10055, + "Name": "manectric" + }, + { + "Id": 10056, + "Name": "banette" + }, + { + "Id": 10057, + "Name": "absol" + }, + { + "Id": 10058, + "Name": "garchomp" + }, + { + "Id": 10059, + "Name": "lucario" + }, + { + "Id": 10060, + "Name": "abomasnow" + }, + { + "Id": 10061, + "Name": "floette" + }, + { + "Id": 10062, + "Name": "latias" + }, + { + "Id": 10063, + "Name": "latios" + }, + { + "Id": 10064, + "Name": "swampert" + }, + { + "Id": 10065, + "Name": "sceptile" + }, + { + "Id": 10066, + "Name": "sableye" + }, + { + "Id": 10067, + "Name": "altaria" + }, + { + "Id": 10068, + "Name": "gallade" + }, + { + "Id": 10069, + "Name": "audino" + }, + { + "Id": 10070, + "Name": "sharpedo" + }, + { + "Id": 10071, + "Name": "slowbro" + }, + { + "Id": 10072, + "Name": "steelix" + }, + { + "Id": 10073, + "Name": "pidgeot" + }, + { + "Id": 10074, + "Name": "glalie" + }, + { + "Id": 10075, + "Name": "diancie" + }, + { + "Id": 10076, + "Name": "metagross" + }, + { + "Id": 10077, + "Name": "kyogre" + }, + { + "Id": 10078, + "Name": "groudon" + }, + { + "Id": 10079, + "Name": "rayquaza" + }, + { + "Id": 10080, + "Name": "pikachu" + }, + { + "Id": 10081, + "Name": "pikachu" + }, + { + "Id": 10082, + "Name": "pikachu" + }, + { + "Id": 10083, + "Name": "pikachu" + }, + { + "Id": 10084, + "Name": "pikachu" + }, + { + "Id": 10085, + "Name": "pikachu" + }, + { + "Id": 10086, + "Name": "hoopa" + }, + { + "Id": 10087, + "Name": "camerupt" + }, + { + "Id": 10088, + "Name": "lopunny" + }, + { + "Id": 10089, + "Name": "salamence" + }, + { + "Id": 10090, + "Name": "beedrill" + } +] \ No newline at end of file From 0cc3102f2b0d286f05f2675ff3c414c90d864649 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 24 Mar 2017 11:56:42 +0100 Subject: [PATCH 615/746] mime jr fix --- src/NadekoBot/data/pokemon/name-id_map.json | 3246 ------------------ src/NadekoBot/data/pokemon/name-id_map2.json | 2 +- 2 files changed, 1 insertion(+), 3247 deletions(-) delete mode 100644 src/NadekoBot/data/pokemon/name-id_map.json diff --git a/src/NadekoBot/data/pokemon/name-id_map.json b/src/NadekoBot/data/pokemon/name-id_map.json deleted file mode 100644 index 334a2380..00000000 --- a/src/NadekoBot/data/pokemon/name-id_map.json +++ /dev/null @@ -1,3246 +0,0 @@ -[ - { - "Id": 1, - "Name": "bulbasaur" - }, - { - "Id": 2, - "Name": "ivysaur" - }, - { - "Id": 3, - "Name": "venusaur" - }, - { - "Id": 4, - "Name": "charmander" - }, - { - "Id": 5, - "Name": "charmeleon" - }, - { - "Id": 6, - "Name": "charizard" - }, - { - "Id": 7, - "Name": "squirtle" - }, - { - "Id": 8, - "Name": "wartortle" - }, - { - "Id": 9, - "Name": "blastoise" - }, - { - "Id": 10, - "Name": "caterpie" - }, - { - "Id": 11, - "Name": "metapod" - }, - { - "Id": 12, - "Name": "butterfree" - }, - { - "Id": 13, - "Name": "weedle" - }, - { - "Id": 14, - "Name": "kakuna" - }, - { - "Id": 15, - "Name": "beedrill" - }, - { - "Id": 16, - "Name": "pidgey" - }, - { - "Id": 17, - "Name": "pidgeotto" - }, - { - "Id": 18, - "Name": "pidgeot" - }, - { - "Id": 19, - "Name": "rattata" - }, - { - "Id": 20, - "Name": "raticate" - }, - { - "Id": 21, - "Name": "spearow" - }, - { - "Id": 22, - "Name": "fearow" - }, - { - "Id": 23, - "Name": "ekans" - }, - { - "Id": 24, - "Name": "arbok" - }, - { - "Id": 25, - "Name": "pikachu" - }, - { - "Id": 26, - "Name": "raichu" - }, - { - "Id": 27, - "Name": "sandshrew" - }, - { - "Id": 28, - "Name": "sandslash" - }, - { - "Id": 29, - "Name": "nidoran" - }, - { - "Id": 30, - "Name": "nidorina" - }, - { - "Id": 31, - "Name": "nidoqueen" - }, - { - "Id": 32, - "Name": "nidoran" - }, - { - "Id": 33, - "Name": "nidorino" - }, - { - "Id": 34, - "Name": "nidoking" - }, - { - "Id": 35, - "Name": "clefairy" - }, - { - "Id": 36, - "Name": "clefable" - }, - { - "Id": 37, - "Name": "vulpix" - }, - { - "Id": 38, - "Name": "ninetales" - }, - { - "Id": 39, - "Name": "jigglypuff" - }, - { - "Id": 40, - "Name": "wigglytuff" - }, - { - "Id": 41, - "Name": "zubat" - }, - { - "Id": 42, - "Name": "golbat" - }, - { - "Id": 43, - "Name": "oddish" - }, - { - "Id": 44, - "Name": "gloom" - }, - { - "Id": 45, - "Name": "vileplume" - }, - { - "Id": 46, - "Name": "paras" - }, - { - "Id": 47, - "Name": "parasect" - }, - { - "Id": 48, - "Name": "venonat" - }, - { - "Id": 49, - "Name": "venomoth" - }, - { - "Id": 50, - "Name": "diglett" - }, - { - "Id": 51, - "Name": "dugtrio" - }, - { - "Id": 52, - "Name": "meowth" - }, - { - "Id": 53, - "Name": "persian" - }, - { - "Id": 54, - "Name": "psyduck" - }, - { - "Id": 55, - "Name": "golduck" - }, - { - "Id": 56, - "Name": "mankey" - }, - { - "Id": 57, - "Name": "primeape" - }, - { - "Id": 58, - "Name": "growlithe" - }, - { - "Id": 59, - "Name": "arcanine" - }, - { - "Id": 60, - "Name": "poliwag" - }, - { - "Id": 61, - "Name": "poliwhirl" - }, - { - "Id": 62, - "Name": "poliwrath" - }, - { - "Id": 63, - "Name": "abra" - }, - { - "Id": 64, - "Name": "kadabra" - }, - { - "Id": 65, - "Name": "alakazam" - }, - { - "Id": 66, - "Name": "machop" - }, - { - "Id": 67, - "Name": "machoke" - }, - { - "Id": 68, - "Name": "machamp" - }, - { - "Id": 69, - "Name": "bellsprout" - }, - { - "Id": 70, - "Name": "weepinbell" - }, - { - "Id": 71, - "Name": "victreebel" - }, - { - "Id": 72, - "Name": "tentacool" - }, - { - "Id": 73, - "Name": "tentacruel" - }, - { - "Id": 74, - "Name": "geodude" - }, - { - "Id": 75, - "Name": "graveler" - }, - { - "Id": 76, - "Name": "golem" - }, - { - "Id": 77, - "Name": "ponyta" - }, - { - "Id": 78, - "Name": "rapidash" - }, - { - "Id": 79, - "Name": "slowpoke" - }, - { - "Id": 80, - "Name": "slowbro" - }, - { - "Id": 81, - "Name": "magnemite" - }, - { - "Id": 82, - "Name": "magneton" - }, - { - "Id": 83, - "Name": "farfetchd" - }, - { - "Id": 84, - "Name": "doduo" - }, - { - "Id": 85, - "Name": "dodrio" - }, - { - "Id": 86, - "Name": "seel" - }, - { - "Id": 87, - "Name": "dewgong" - }, - { - "Id": 88, - "Name": "grimer" - }, - { - "Id": 89, - "Name": "muk" - }, - { - "Id": 90, - "Name": "shellder" - }, - { - "Id": 91, - "Name": "cloyster" - }, - { - "Id": 92, - "Name": "gastly" - }, - { - "Id": 93, - "Name": "haunter" - }, - { - "Id": 94, - "Name": "gengar" - }, - { - "Id": 95, - "Name": "onix" - }, - { - "Id": 96, - "Name": "drowzee" - }, - { - "Id": 97, - "Name": "hypno" - }, - { - "Id": 98, - "Name": "krabby" - }, - { - "Id": 99, - "Name": "kingler" - }, - { - "Id": 100, - "Name": "voltorb" - }, - { - "Id": 101, - "Name": "electrode" - }, - { - "Id": 102, - "Name": "exeggcute" - }, - { - "Id": 103, - "Name": "exeggutor" - }, - { - "Id": 104, - "Name": "cubone" - }, - { - "Id": 105, - "Name": "marowak" - }, - { - "Id": 106, - "Name": "hitmonlee" - }, - { - "Id": 107, - "Name": "hitmonchan" - }, - { - "Id": 108, - "Name": "lickitung" - }, - { - "Id": 109, - "Name": "koffing" - }, - { - "Id": 110, - "Name": "weezing" - }, - { - "Id": 111, - "Name": "rhyhorn" - }, - { - "Id": 112, - "Name": "rhydon" - }, - { - "Id": 113, - "Name": "chansey" - }, - { - "Id": 114, - "Name": "tangela" - }, - { - "Id": 115, - "Name": "kangaskhan" - }, - { - "Id": 116, - "Name": "horsea" - }, - { - "Id": 117, - "Name": "seadra" - }, - { - "Id": 118, - "Name": "goldeen" - }, - { - "Id": 119, - "Name": "seaking" - }, - { - "Id": 120, - "Name": "staryu" - }, - { - "Id": 121, - "Name": "starmie" - }, - { - "Id": 122, - "Name": "mr" - }, - { - "Id": 123, - "Name": "scyther" - }, - { - "Id": 124, - "Name": "jynx" - }, - { - "Id": 125, - "Name": "electabuzz" - }, - { - "Id": 126, - "Name": "magmar" - }, - { - "Id": 127, - "Name": "pinsir" - }, - { - "Id": 128, - "Name": "tauros" - }, - { - "Id": 129, - "Name": "magikarp" - }, - { - "Id": 130, - "Name": "gyarados" - }, - { - "Id": 131, - "Name": "lapras" - }, - { - "Id": 132, - "Name": "ditto" - }, - { - "Id": 133, - "Name": "eevee" - }, - { - "Id": 134, - "Name": "vaporeon" - }, - { - "Id": 135, - "Name": "jolteon" - }, - { - "Id": 136, - "Name": "flareon" - }, - { - "Id": 137, - "Name": "porygon" - }, - { - "Id": 138, - "Name": "omanyte" - }, - { - "Id": 139, - "Name": "omastar" - }, - { - "Id": 140, - "Name": "kabuto" - }, - { - "Id": 141, - "Name": "kabutops" - }, - { - "Id": 142, - "Name": "aerodactyl" - }, - { - "Id": 143, - "Name": "snorlax" - }, - { - "Id": 144, - "Name": "articuno" - }, - { - "Id": 145, - "Name": "zapdos" - }, - { - "Id": 146, - "Name": "moltres" - }, - { - "Id": 147, - "Name": "dratini" - }, - { - "Id": 148, - "Name": "dragonair" - }, - { - "Id": 149, - "Name": "dragonite" - }, - { - "Id": 150, - "Name": "mewtwo" - }, - { - "Id": 151, - "Name": "mew" - }, - { - "Id": 152, - "Name": "chikorita" - }, - { - "Id": 153, - "Name": "bayleef" - }, - { - "Id": 154, - "Name": "meganium" - }, - { - "Id": 155, - "Name": "cyndaquil" - }, - { - "Id": 156, - "Name": "quilava" - }, - { - "Id": 157, - "Name": "typhlosion" - }, - { - "Id": 158, - "Name": "totodile" - }, - { - "Id": 159, - "Name": "croconaw" - }, - { - "Id": 160, - "Name": "feraligatr" - }, - { - "Id": 161, - "Name": "sentret" - }, - { - "Id": 162, - "Name": "furret" - }, - { - "Id": 163, - "Name": "hoothoot" - }, - { - "Id": 164, - "Name": "noctowl" - }, - { - "Id": 165, - "Name": "ledyba" - }, - { - "Id": 166, - "Name": "ledian" - }, - { - "Id": 167, - "Name": "spinarak" - }, - { - "Id": 168, - "Name": "ariados" - }, - { - "Id": 169, - "Name": "crobat" - }, - { - "Id": 170, - "Name": "chinchou" - }, - { - "Id": 171, - "Name": "lanturn" - }, - { - "Id": 172, - "Name": "pichu" - }, - { - "Id": 173, - "Name": "cleffa" - }, - { - "Id": 174, - "Name": "igglybuff" - }, - { - "Id": 175, - "Name": "togepi" - }, - { - "Id": 176, - "Name": "togetic" - }, - { - "Id": 177, - "Name": "natu" - }, - { - "Id": 178, - "Name": "xatu" - }, - { - "Id": 179, - "Name": "mareep" - }, - { - "Id": 180, - "Name": "flaaffy" - }, - { - "Id": 181, - "Name": "ampharos" - }, - { - "Id": 182, - "Name": "bellossom" - }, - { - "Id": 183, - "Name": "marill" - }, - { - "Id": 184, - "Name": "azumarill" - }, - { - "Id": 185, - "Name": "sudowoodo" - }, - { - "Id": 186, - "Name": "politoed" - }, - { - "Id": 187, - "Name": "hoppip" - }, - { - "Id": 188, - "Name": "skiploom" - }, - { - "Id": 189, - "Name": "jumpluff" - }, - { - "Id": 190, - "Name": "aipom" - }, - { - "Id": 191, - "Name": "sunkern" - }, - { - "Id": 192, - "Name": "sunflora" - }, - { - "Id": 193, - "Name": "yanma" - }, - { - "Id": 194, - "Name": "wooper" - }, - { - "Id": 195, - "Name": "quagsire" - }, - { - "Id": 196, - "Name": "espeon" - }, - { - "Id": 197, - "Name": "umbreon" - }, - { - "Id": 198, - "Name": "murkrow" - }, - { - "Id": 199, - "Name": "slowking" - }, - { - "Id": 200, - "Name": "misdreavus" - }, - { - "Id": 201, - "Name": "unown" - }, - { - "Id": 202, - "Name": "wobbuffet" - }, - { - "Id": 203, - "Name": "girafarig" - }, - { - "Id": 204, - "Name": "pineco" - }, - { - "Id": 205, - "Name": "forretress" - }, - { - "Id": 206, - "Name": "dunsparce" - }, - { - "Id": 207, - "Name": "gligar" - }, - { - "Id": 208, - "Name": "steelix" - }, - { - "Id": 209, - "Name": "snubbull" - }, - { - "Id": 210, - "Name": "granbull" - }, - { - "Id": 211, - "Name": "qwilfish" - }, - { - "Id": 212, - "Name": "scizor" - }, - { - "Id": 213, - "Name": "shuckle" - }, - { - "Id": 214, - "Name": "heracross" - }, - { - "Id": 215, - "Name": "sneasel" - }, - { - "Id": 216, - "Name": "teddiursa" - }, - { - "Id": 217, - "Name": "ursaring" - }, - { - "Id": 218, - "Name": "slugma" - }, - { - "Id": 219, - "Name": "magcargo" - }, - { - "Id": 220, - "Name": "swinub" - }, - { - "Id": 221, - "Name": "piloswine" - }, - { - "Id": 222, - "Name": "corsola" - }, - { - "Id": 223, - "Name": "remoraid" - }, - { - "Id": 224, - "Name": "octillery" - }, - { - "Id": 225, - "Name": "delibird" - }, - { - "Id": 226, - "Name": "mantine" - }, - { - "Id": 227, - "Name": "skarmory" - }, - { - "Id": 228, - "Name": "houndour" - }, - { - "Id": 229, - "Name": "houndoom" - }, - { - "Id": 230, - "Name": "kingdra" - }, - { - "Id": 231, - "Name": "phanpy" - }, - { - "Id": 232, - "Name": "donphan" - }, - { - "Id": 233, - "Name": "porygon2" - }, - { - "Id": 234, - "Name": "stantler" - }, - { - "Id": 235, - "Name": "smeargle" - }, - { - "Id": 236, - "Name": "tyrogue" - }, - { - "Id": 237, - "Name": "hitmontop" - }, - { - "Id": 238, - "Name": "smoochum" - }, - { - "Id": 239, - "Name": "elekid" - }, - { - "Id": 240, - "Name": "magby" - }, - { - "Id": 241, - "Name": "miltank" - }, - { - "Id": 242, - "Name": "blissey" - }, - { - "Id": 243, - "Name": "raikou" - }, - { - "Id": 244, - "Name": "entei" - }, - { - "Id": 245, - "Name": "suicune" - }, - { - "Id": 246, - "Name": "larvitar" - }, - { - "Id": 247, - "Name": "pupitar" - }, - { - "Id": 248, - "Name": "tyranitar" - }, - { - "Id": 249, - "Name": "lugia" - }, - { - "Id": 250, - "Name": "ho" - }, - { - "Id": 251, - "Name": "celebi" - }, - { - "Id": 252, - "Name": "treecko" - }, - { - "Id": 253, - "Name": "grovyle" - }, - { - "Id": 254, - "Name": "sceptile" - }, - { - "Id": 255, - "Name": "torchic" - }, - { - "Id": 256, - "Name": "combusken" - }, - { - "Id": 257, - "Name": "blaziken" - }, - { - "Id": 258, - "Name": "mudkip" - }, - { - "Id": 259, - "Name": "marshtomp" - }, - { - "Id": 260, - "Name": "swampert" - }, - { - "Id": 261, - "Name": "poochyena" - }, - { - "Id": 262, - "Name": "mightyena" - }, - { - "Id": 263, - "Name": "zigzagoon" - }, - { - "Id": 264, - "Name": "linoone" - }, - { - "Id": 265, - "Name": "wurmple" - }, - { - "Id": 266, - "Name": "silcoon" - }, - { - "Id": 267, - "Name": "beautifly" - }, - { - "Id": 268, - "Name": "cascoon" - }, - { - "Id": 269, - "Name": "dustox" - }, - { - "Id": 270, - "Name": "lotad" - }, - { - "Id": 271, - "Name": "lombre" - }, - { - "Id": 272, - "Name": "ludicolo" - }, - { - "Id": 273, - "Name": "seedot" - }, - { - "Id": 274, - "Name": "nuzleaf" - }, - { - "Id": 275, - "Name": "shiftry" - }, - { - "Id": 276, - "Name": "taillow" - }, - { - "Id": 277, - "Name": "swellow" - }, - { - "Id": 278, - "Name": "wingull" - }, - { - "Id": 279, - "Name": "pelipper" - }, - { - "Id": 280, - "Name": "ralts" - }, - { - "Id": 281, - "Name": "kirlia" - }, - { - "Id": 282, - "Name": "gardevoir" - }, - { - "Id": 283, - "Name": "surskit" - }, - { - "Id": 284, - "Name": "masquerain" - }, - { - "Id": 285, - "Name": "shroomish" - }, - { - "Id": 286, - "Name": "breloom" - }, - { - "Id": 287, - "Name": "slakoth" - }, - { - "Id": 288, - "Name": "vigoroth" - }, - { - "Id": 289, - "Name": "slaking" - }, - { - "Id": 290, - "Name": "nincada" - }, - { - "Id": 291, - "Name": "ninjask" - }, - { - "Id": 292, - "Name": "shedinja" - }, - { - "Id": 293, - "Name": "whismur" - }, - { - "Id": 294, - "Name": "loudred" - }, - { - "Id": 295, - "Name": "exploud" - }, - { - "Id": 296, - "Name": "makuhita" - }, - { - "Id": 297, - "Name": "hariyama" - }, - { - "Id": 298, - "Name": "azurill" - }, - { - "Id": 299, - "Name": "nosepass" - }, - { - "Id": 300, - "Name": "skitty" - }, - { - "Id": 301, - "Name": "delcatty" - }, - { - "Id": 302, - "Name": "sableye" - }, - { - "Id": 303, - "Name": "mawile" - }, - { - "Id": 304, - "Name": "aron" - }, - { - "Id": 305, - "Name": "lairon" - }, - { - "Id": 306, - "Name": "aggron" - }, - { - "Id": 307, - "Name": "meditite" - }, - { - "Id": 308, - "Name": "medicham" - }, - { - "Id": 309, - "Name": "electrike" - }, - { - "Id": 310, - "Name": "manectric" - }, - { - "Id": 311, - "Name": "plusle" - }, - { - "Id": 312, - "Name": "minun" - }, - { - "Id": 313, - "Name": "volbeat" - }, - { - "Id": 314, - "Name": "illumise" - }, - { - "Id": 315, - "Name": "roselia" - }, - { - "Id": 316, - "Name": "gulpin" - }, - { - "Id": 317, - "Name": "swalot" - }, - { - "Id": 318, - "Name": "carvanha" - }, - { - "Id": 319, - "Name": "sharpedo" - }, - { - "Id": 320, - "Name": "wailmer" - }, - { - "Id": 321, - "Name": "wailord" - }, - { - "Id": 322, - "Name": "numel" - }, - { - "Id": 323, - "Name": "camerupt" - }, - { - "Id": 324, - "Name": "torkoal" - }, - { - "Id": 325, - "Name": "spoink" - }, - { - "Id": 326, - "Name": "grumpig" - }, - { - "Id": 327, - "Name": "spinda" - }, - { - "Id": 328, - "Name": "trapinch" - }, - { - "Id": 329, - "Name": "vibrava" - }, - { - "Id": 330, - "Name": "flygon" - }, - { - "Id": 331, - "Name": "cacnea" - }, - { - "Id": 332, - "Name": "cacturne" - }, - { - "Id": 333, - "Name": "swablu" - }, - { - "Id": 334, - "Name": "altaria" - }, - { - "Id": 335, - "Name": "zangoose" - }, - { - "Id": 336, - "Name": "seviper" - }, - { - "Id": 337, - "Name": "lunatone" - }, - { - "Id": 338, - "Name": "solrock" - }, - { - "Id": 339, - "Name": "barboach" - }, - { - "Id": 340, - "Name": "whiscash" - }, - { - "Id": 341, - "Name": "corphish" - }, - { - "Id": 342, - "Name": "crawdaunt" - }, - { - "Id": 343, - "Name": "baltoy" - }, - { - "Id": 344, - "Name": "claydol" - }, - { - "Id": 345, - "Name": "lileep" - }, - { - "Id": 346, - "Name": "cradily" - }, - { - "Id": 347, - "Name": "anorith" - }, - { - "Id": 348, - "Name": "armaldo" - }, - { - "Id": 349, - "Name": "feebas" - }, - { - "Id": 350, - "Name": "milotic" - }, - { - "Id": 351, - "Name": "castform" - }, - { - "Id": 352, - "Name": "kecleon" - }, - { - "Id": 353, - "Name": "shuppet" - }, - { - "Id": 354, - "Name": "banette" - }, - { - "Id": 355, - "Name": "duskull" - }, - { - "Id": 356, - "Name": "dusclops" - }, - { - "Id": 357, - "Name": "tropius" - }, - { - "Id": 358, - "Name": "chimecho" - }, - { - "Id": 359, - "Name": "absol" - }, - { - "Id": 360, - "Name": "wynaut" - }, - { - "Id": 361, - "Name": "snorunt" - }, - { - "Id": 362, - "Name": "glalie" - }, - { - "Id": 363, - "Name": "spheal" - }, - { - "Id": 364, - "Name": "sealeo" - }, - { - "Id": 365, - "Name": "walrein" - }, - { - "Id": 366, - "Name": "clamperl" - }, - { - "Id": 367, - "Name": "huntail" - }, - { - "Id": 368, - "Name": "gorebyss" - }, - { - "Id": 369, - "Name": "relicanth" - }, - { - "Id": 370, - "Name": "luvdisc" - }, - { - "Id": 371, - "Name": "bagon" - }, - { - "Id": 372, - "Name": "shelgon" - }, - { - "Id": 373, - "Name": "salamence" - }, - { - "Id": 374, - "Name": "beldum" - }, - { - "Id": 375, - "Name": "metang" - }, - { - "Id": 376, - "Name": "metagross" - }, - { - "Id": 377, - "Name": "regirock" - }, - { - "Id": 378, - "Name": "regice" - }, - { - "Id": 379, - "Name": "registeel" - }, - { - "Id": 380, - "Name": "latias" - }, - { - "Id": 381, - "Name": "latios" - }, - { - "Id": 382, - "Name": "kyogre" - }, - { - "Id": 383, - "Name": "groudon" - }, - { - "Id": 384, - "Name": "rayquaza" - }, - { - "Id": 385, - "Name": "jirachi" - }, - { - "Id": 386, - "Name": "deoxys" - }, - { - "Id": 387, - "Name": "turtwig" - }, - { - "Id": 388, - "Name": "grotle" - }, - { - "Id": 389, - "Name": "torterra" - }, - { - "Id": 390, - "Name": "chimchar" - }, - { - "Id": 391, - "Name": "monferno" - }, - { - "Id": 392, - "Name": "infernape" - }, - { - "Id": 393, - "Name": "piplup" - }, - { - "Id": 394, - "Name": "prinplup" - }, - { - "Id": 395, - "Name": "empoleon" - }, - { - "Id": 396, - "Name": "starly" - }, - { - "Id": 397, - "Name": "staravia" - }, - { - "Id": 398, - "Name": "staraptor" - }, - { - "Id": 399, - "Name": "bidoof" - }, - { - "Id": 400, - "Name": "bibarel" - }, - { - "Id": 401, - "Name": "kricketot" - }, - { - "Id": 402, - "Name": "kricketune" - }, - { - "Id": 403, - "Name": "shinx" - }, - { - "Id": 404, - "Name": "luxio" - }, - { - "Id": 405, - "Name": "luxray" - }, - { - "Id": 406, - "Name": "budew" - }, - { - "Id": 407, - "Name": "roserade" - }, - { - "Id": 408, - "Name": "cranidos" - }, - { - "Id": 409, - "Name": "rampardos" - }, - { - "Id": 410, - "Name": "shieldon" - }, - { - "Id": 411, - "Name": "bastiodon" - }, - { - "Id": 412, - "Name": "burmy" - }, - { - "Id": 413, - "Name": "wormadam" - }, - { - "Id": 414, - "Name": "mothim" - }, - { - "Id": 415, - "Name": "combee" - }, - { - "Id": 416, - "Name": "vespiquen" - }, - { - "Id": 417, - "Name": "pachirisu" - }, - { - "Id": 418, - "Name": "buizel" - }, - { - "Id": 419, - "Name": "floatzel" - }, - { - "Id": 420, - "Name": "cherubi" - }, - { - "Id": 421, - "Name": "cherrim" - }, - { - "Id": 422, - "Name": "shellos" - }, - { - "Id": 423, - "Name": "gastrodon" - }, - { - "Id": 424, - "Name": "ambipom" - }, - { - "Id": 425, - "Name": "drifloon" - }, - { - "Id": 426, - "Name": "drifblim" - }, - { - "Id": 427, - "Name": "buneary" - }, - { - "Id": 428, - "Name": "lopunny" - }, - { - "Id": 429, - "Name": "mismagius" - }, - { - "Id": 430, - "Name": "honchkrow" - }, - { - "Id": 431, - "Name": "glameow" - }, - { - "Id": 432, - "Name": "purugly" - }, - { - "Id": 433, - "Name": "chingling" - }, - { - "Id": 434, - "Name": "stunky" - }, - { - "Id": 435, - "Name": "skuntank" - }, - { - "Id": 436, - "Name": "bronzor" - }, - { - "Id": 437, - "Name": "bronzong" - }, - { - "Id": 438, - "Name": "bonsly" - }, - { - "Id": 439, - "Name": "mime" - }, - { - "Id": 440, - "Name": "happiny" - }, - { - "Id": 441, - "Name": "chatot" - }, - { - "Id": 442, - "Name": "spiritomb" - }, - { - "Id": 443, - "Name": "gible" - }, - { - "Id": 444, - "Name": "gabite" - }, - { - "Id": 445, - "Name": "garchomp" - }, - { - "Id": 446, - "Name": "munchlax" - }, - { - "Id": 447, - "Name": "riolu" - }, - { - "Id": 448, - "Name": "lucario" - }, - { - "Id": 449, - "Name": "hippopotas" - }, - { - "Id": 450, - "Name": "hippowdon" - }, - { - "Id": 451, - "Name": "skorupi" - }, - { - "Id": 452, - "Name": "drapion" - }, - { - "Id": 453, - "Name": "croagunk" - }, - { - "Id": 454, - "Name": "toxicroak" - }, - { - "Id": 455, - "Name": "carnivine" - }, - { - "Id": 456, - "Name": "finneon" - }, - { - "Id": 457, - "Name": "lumineon" - }, - { - "Id": 458, - "Name": "mantyke" - }, - { - "Id": 459, - "Name": "snover" - }, - { - "Id": 460, - "Name": "abomasnow" - }, - { - "Id": 461, - "Name": "weavile" - }, - { - "Id": 462, - "Name": "magnezone" - }, - { - "Id": 463, - "Name": "lickilicky" - }, - { - "Id": 464, - "Name": "rhyperior" - }, - { - "Id": 465, - "Name": "tangrowth" - }, - { - "Id": 466, - "Name": "electivire" - }, - { - "Id": 467, - "Name": "magmortar" - }, - { - "Id": 468, - "Name": "togekiss" - }, - { - "Id": 469, - "Name": "yanmega" - }, - { - "Id": 470, - "Name": "leafeon" - }, - { - "Id": 471, - "Name": "glaceon" - }, - { - "Id": 472, - "Name": "gliscor" - }, - { - "Id": 473, - "Name": "mamoswine" - }, - { - "Id": 474, - "Name": "porygon" - }, - { - "Id": 475, - "Name": "gallade" - }, - { - "Id": 476, - "Name": "probopass" - }, - { - "Id": 477, - "Name": "dusknoir" - }, - { - "Id": 478, - "Name": "froslass" - }, - { - "Id": 479, - "Name": "rotom" - }, - { - "Id": 480, - "Name": "uxie" - }, - { - "Id": 481, - "Name": "mesprit" - }, - { - "Id": 482, - "Name": "azelf" - }, - { - "Id": 483, - "Name": "dialga" - }, - { - "Id": 484, - "Name": "palkia" - }, - { - "Id": 485, - "Name": "heatran" - }, - { - "Id": 486, - "Name": "regigigas" - }, - { - "Id": 487, - "Name": "giratina" - }, - { - "Id": 488, - "Name": "cresselia" - }, - { - "Id": 489, - "Name": "phione" - }, - { - "Id": 490, - "Name": "manaphy" - }, - { - "Id": 491, - "Name": "darkrai" - }, - { - "Id": 492, - "Name": "shaymin" - }, - { - "Id": 493, - "Name": "arceus" - }, - { - "Id": 494, - "Name": "victini" - }, - { - "Id": 495, - "Name": "snivy" - }, - { - "Id": 496, - "Name": "servine" - }, - { - "Id": 497, - "Name": "serperior" - }, - { - "Id": 498, - "Name": "tepig" - }, - { - "Id": 499, - "Name": "pignite" - }, - { - "Id": 500, - "Name": "emboar" - }, - { - "Id": 501, - "Name": "oshawott" - }, - { - "Id": 502, - "Name": "dewott" - }, - { - "Id": 503, - "Name": "samurott" - }, - { - "Id": 504, - "Name": "patrat" - }, - { - "Id": 505, - "Name": "watchog" - }, - { - "Id": 506, - "Name": "lillipup" - }, - { - "Id": 507, - "Name": "herdier" - }, - { - "Id": 508, - "Name": "stoutland" - }, - { - "Id": 509, - "Name": "purrloin" - }, - { - "Id": 510, - "Name": "liepard" - }, - { - "Id": 511, - "Name": "pansage" - }, - { - "Id": 512, - "Name": "simisage" - }, - { - "Id": 513, - "Name": "pansear" - }, - { - "Id": 514, - "Name": "simisear" - }, - { - "Id": 515, - "Name": "panpour" - }, - { - "Id": 516, - "Name": "simipour" - }, - { - "Id": 517, - "Name": "munna" - }, - { - "Id": 518, - "Name": "musharna" - }, - { - "Id": 519, - "Name": "pidove" - }, - { - "Id": 520, - "Name": "tranquill" - }, - { - "Id": 521, - "Name": "unfezant" - }, - { - "Id": 522, - "Name": "blitzle" - }, - { - "Id": 523, - "Name": "zebstrika" - }, - { - "Id": 524, - "Name": "roggenrola" - }, - { - "Id": 525, - "Name": "boldore" - }, - { - "Id": 526, - "Name": "gigalith" - }, - { - "Id": 527, - "Name": "woobat" - }, - { - "Id": 528, - "Name": "swoobat" - }, - { - "Id": 529, - "Name": "drilbur" - }, - { - "Id": 530, - "Name": "excadrill" - }, - { - "Id": 531, - "Name": "audino" - }, - { - "Id": 532, - "Name": "timburr" - }, - { - "Id": 533, - "Name": "gurdurr" - }, - { - "Id": 534, - "Name": "conkeldurr" - }, - { - "Id": 535, - "Name": "tympole" - }, - { - "Id": 536, - "Name": "palpitoad" - }, - { - "Id": 537, - "Name": "seismitoad" - }, - { - "Id": 538, - "Name": "throh" - }, - { - "Id": 539, - "Name": "sawk" - }, - { - "Id": 540, - "Name": "sewaddle" - }, - { - "Id": 541, - "Name": "swadloon" - }, - { - "Id": 542, - "Name": "leavanny" - }, - { - "Id": 543, - "Name": "venipede" - }, - { - "Id": 544, - "Name": "whirlipede" - }, - { - "Id": 545, - "Name": "scolipede" - }, - { - "Id": 546, - "Name": "cottonee" - }, - { - "Id": 547, - "Name": "whimsicott" - }, - { - "Id": 548, - "Name": "petilil" - }, - { - "Id": 549, - "Name": "lilligant" - }, - { - "Id": 550, - "Name": "basculin" - }, - { - "Id": 551, - "Name": "sandile" - }, - { - "Id": 552, - "Name": "krokorok" - }, - { - "Id": 553, - "Name": "krookodile" - }, - { - "Id": 554, - "Name": "darumaka" - }, - { - "Id": 555, - "Name": "darmanitan" - }, - { - "Id": 556, - "Name": "maractus" - }, - { - "Id": 557, - "Name": "dwebble" - }, - { - "Id": 558, - "Name": "crustle" - }, - { - "Id": 559, - "Name": "scraggy" - }, - { - "Id": 560, - "Name": "scrafty" - }, - { - "Id": 561, - "Name": "sigilyph" - }, - { - "Id": 562, - "Name": "yamask" - }, - { - "Id": 563, - "Name": "cofagrigus" - }, - { - "Id": 564, - "Name": "tirtouga" - }, - { - "Id": 565, - "Name": "carracosta" - }, - { - "Id": 566, - "Name": "archen" - }, - { - "Id": 567, - "Name": "archeops" - }, - { - "Id": 568, - "Name": "trubbish" - }, - { - "Id": 569, - "Name": "garbodor" - }, - { - "Id": 570, - "Name": "zorua" - }, - { - "Id": 571, - "Name": "zoroark" - }, - { - "Id": 572, - "Name": "minccino" - }, - { - "Id": 573, - "Name": "cinccino" - }, - { - "Id": 574, - "Name": "gothita" - }, - { - "Id": 575, - "Name": "gothorita" - }, - { - "Id": 576, - "Name": "gothitelle" - }, - { - "Id": 577, - "Name": "solosis" - }, - { - "Id": 578, - "Name": "duosion" - }, - { - "Id": 579, - "Name": "reuniclus" - }, - { - "Id": 580, - "Name": "ducklett" - }, - { - "Id": 581, - "Name": "swanna" - }, - { - "Id": 582, - "Name": "vanillite" - }, - { - "Id": 583, - "Name": "vanillish" - }, - { - "Id": 584, - "Name": "vanilluxe" - }, - { - "Id": 585, - "Name": "deerling" - }, - { - "Id": 586, - "Name": "sawsbuck" - }, - { - "Id": 587, - "Name": "emolga" - }, - { - "Id": 588, - "Name": "karrablast" - }, - { - "Id": 589, - "Name": "escavalier" - }, - { - "Id": 590, - "Name": "foongus" - }, - { - "Id": 591, - "Name": "amoonguss" - }, - { - "Id": 592, - "Name": "frillish" - }, - { - "Id": 593, - "Name": "jellicent" - }, - { - "Id": 594, - "Name": "alomomola" - }, - { - "Id": 595, - "Name": "joltik" - }, - { - "Id": 596, - "Name": "galvantula" - }, - { - "Id": 597, - "Name": "ferroseed" - }, - { - "Id": 598, - "Name": "ferrothorn" - }, - { - "Id": 599, - "Name": "klink" - }, - { - "Id": 600, - "Name": "klang" - }, - { - "Id": 601, - "Name": "klinklang" - }, - { - "Id": 602, - "Name": "tynamo" - }, - { - "Id": 603, - "Name": "eelektrik" - }, - { - "Id": 604, - "Name": "eelektross" - }, - { - "Id": 605, - "Name": "elgyem" - }, - { - "Id": 606, - "Name": "beheeyem" - }, - { - "Id": 607, - "Name": "litwick" - }, - { - "Id": 608, - "Name": "lampent" - }, - { - "Id": 609, - "Name": "chandelure" - }, - { - "Id": 610, - "Name": "axew" - }, - { - "Id": 611, - "Name": "fraxure" - }, - { - "Id": 612, - "Name": "haxorus" - }, - { - "Id": 613, - "Name": "cubchoo" - }, - { - "Id": 614, - "Name": "beartic" - }, - { - "Id": 615, - "Name": "cryogonal" - }, - { - "Id": 616, - "Name": "shelmet" - }, - { - "Id": 617, - "Name": "accelgor" - }, - { - "Id": 618, - "Name": "stunfisk" - }, - { - "Id": 619, - "Name": "mienfoo" - }, - { - "Id": 620, - "Name": "mienshao" - }, - { - "Id": 621, - "Name": "druddigon" - }, - { - "Id": 622, - "Name": "golett" - }, - { - "Id": 623, - "Name": "golurk" - }, - { - "Id": 624, - "Name": "pawniard" - }, - { - "Id": 625, - "Name": "bisharp" - }, - { - "Id": 626, - "Name": "bouffalant" - }, - { - "Id": 627, - "Name": "rufflet" - }, - { - "Id": 628, - "Name": "braviary" - }, - { - "Id": 629, - "Name": "vullaby" - }, - { - "Id": 630, - "Name": "mandibuzz" - }, - { - "Id": 631, - "Name": "heatmor" - }, - { - "Id": 632, - "Name": "durant" - }, - { - "Id": 633, - "Name": "deino" - }, - { - "Id": 634, - "Name": "zweilous" - }, - { - "Id": 635, - "Name": "hydreigon" - }, - { - "Id": 636, - "Name": "larvesta" - }, - { - "Id": 637, - "Name": "volcarona" - }, - { - "Id": 638, - "Name": "cobalion" - }, - { - "Id": 639, - "Name": "terrakion" - }, - { - "Id": 640, - "Name": "virizion" - }, - { - "Id": 641, - "Name": "tornadus" - }, - { - "Id": 642, - "Name": "thundurus" - }, - { - "Id": 643, - "Name": "reshiram" - }, - { - "Id": 644, - "Name": "zekrom" - }, - { - "Id": 645, - "Name": "landorus" - }, - { - "Id": 646, - "Name": "kyurem" - }, - { - "Id": 647, - "Name": "keldeo" - }, - { - "Id": 648, - "Name": "meloetta" - }, - { - "Id": 649, - "Name": "genesect" - }, - { - "Id": 650, - "Name": "chespin" - }, - { - "Id": 651, - "Name": "quilladin" - }, - { - "Id": 652, - "Name": "chesnaught" - }, - { - "Id": 653, - "Name": "fennekin" - }, - { - "Id": 654, - "Name": "braixen" - }, - { - "Id": 655, - "Name": "delphox" - }, - { - "Id": 656, - "Name": "froakie" - }, - { - "Id": 657, - "Name": "frogadier" - }, - { - "Id": 658, - "Name": "greninja" - }, - { - "Id": 659, - "Name": "bunnelby" - }, - { - "Id": 660, - "Name": "diggersby" - }, - { - "Id": 661, - "Name": "fletchling" - }, - { - "Id": 662, - "Name": "fletchinder" - }, - { - "Id": 663, - "Name": "talonflame" - }, - { - "Id": 664, - "Name": "scatterbug" - }, - { - "Id": 665, - "Name": "spewpa" - }, - { - "Id": 666, - "Name": "vivillon" - }, - { - "Id": 667, - "Name": "litleo" - }, - { - "Id": 668, - "Name": "pyroar" - }, - { - "Id": 669, - "Name": "flabebe" - }, - { - "Id": 670, - "Name": "floette" - }, - { - "Id": 671, - "Name": "florges" - }, - { - "Id": 672, - "Name": "skiddo" - }, - { - "Id": 673, - "Name": "gogoat" - }, - { - "Id": 674, - "Name": "pancham" - }, - { - "Id": 675, - "Name": "pangoro" - }, - { - "Id": 676, - "Name": "furfrou" - }, - { - "Id": 677, - "Name": "espurr" - }, - { - "Id": 678, - "Name": "meowstic" - }, - { - "Id": 679, - "Name": "honedge" - }, - { - "Id": 680, - "Name": "doublade" - }, - { - "Id": 681, - "Name": "aegislash" - }, - { - "Id": 682, - "Name": "spritzee" - }, - { - "Id": 683, - "Name": "aromatisse" - }, - { - "Id": 684, - "Name": "swirlix" - }, - { - "Id": 685, - "Name": "slurpuff" - }, - { - "Id": 686, - "Name": "inkay" - }, - { - "Id": 687, - "Name": "malamar" - }, - { - "Id": 688, - "Name": "binacle" - }, - { - "Id": 689, - "Name": "barbaracle" - }, - { - "Id": 690, - "Name": "skrelp" - }, - { - "Id": 691, - "Name": "dragalge" - }, - { - "Id": 692, - "Name": "clauncher" - }, - { - "Id": 693, - "Name": "clawitzer" - }, - { - "Id": 694, - "Name": "helioptile" - }, - { - "Id": 695, - "Name": "heliolisk" - }, - { - "Id": 696, - "Name": "tyrunt" - }, - { - "Id": 697, - "Name": "tyrantrum" - }, - { - "Id": 698, - "Name": "amaura" - }, - { - "Id": 699, - "Name": "aurorus" - }, - { - "Id": 700, - "Name": "sylveon" - }, - { - "Id": 701, - "Name": "hawlucha" - }, - { - "Id": 702, - "Name": "dedenne" - }, - { - "Id": 703, - "Name": "carbink" - }, - { - "Id": 704, - "Name": "goomy" - }, - { - "Id": 705, - "Name": "sliggoo" - }, - { - "Id": 706, - "Name": "goodra" - }, - { - "Id": 707, - "Name": "klefki" - }, - { - "Id": 708, - "Name": "phantump" - }, - { - "Id": 709, - "Name": "trevenant" - }, - { - "Id": 710, - "Name": "pumpkaboo" - }, - { - "Id": 711, - "Name": "gourgeist" - }, - { - "Id": 712, - "Name": "bergmite" - }, - { - "Id": 713, - "Name": "avalugg" - }, - { - "Id": 714, - "Name": "noibat" - }, - { - "Id": 715, - "Name": "noivern" - }, - { - "Id": 716, - "Name": "xerneas" - }, - { - "Id": 717, - "Name": "yveltal" - }, - { - "Id": 718, - "Name": "zygarde" - }, - { - "Id": 719, - "Name": "diancie" - }, - { - "Id": 720, - "Name": "hoopa" - }, - { - "Id": 721, - "Name": "volcanion" - }, - { - "Id": 10001, - "Name": "deoxys" - }, - { - "Id": 10002, - "Name": "deoxys" - }, - { - "Id": 10003, - "Name": "deoxys" - }, - { - "Id": 10004, - "Name": "wormadam" - }, - { - "Id": 10005, - "Name": "wormadam" - }, - { - "Id": 10006, - "Name": "shaymin" - }, - { - "Id": 10007, - "Name": "giratina" - }, - { - "Id": 10008, - "Name": "rotom" - }, - { - "Id": 10009, - "Name": "rotom" - }, - { - "Id": 10010, - "Name": "rotom" - }, - { - "Id": 10011, - "Name": "rotom" - }, - { - "Id": 10012, - "Name": "rotom" - }, - { - "Id": 10013, - "Name": "castform" - }, - { - "Id": 10014, - "Name": "castform" - }, - { - "Id": 10015, - "Name": "castform" - }, - { - "Id": 10016, - "Name": "basculin" - }, - { - "Id": 10017, - "Name": "darmanitan" - }, - { - "Id": 10018, - "Name": "meloetta" - }, - { - "Id": 10019, - "Name": "tornadus" - }, - { - "Id": 10020, - "Name": "thundurus" - }, - { - "Id": 10021, - "Name": "landorus" - }, - { - "Id": 10022, - "Name": "kyurem" - }, - { - "Id": 10023, - "Name": "kyurem" - }, - { - "Id": 10024, - "Name": "keldeo" - }, - { - "Id": 10025, - "Name": "meowstic" - }, - { - "Id": 10026, - "Name": "aegislash" - }, - { - "Id": 10027, - "Name": "pumpkaboo" - }, - { - "Id": 10028, - "Name": "pumpkaboo" - }, - { - "Id": 10029, - "Name": "pumpkaboo" - }, - { - "Id": 10030, - "Name": "gourgeist" - }, - { - "Id": 10031, - "Name": "gourgeist" - }, - { - "Id": 10032, - "Name": "gourgeist" - }, - { - "Id": 10033, - "Name": "venusaur" - }, - { - "Id": 10034, - "Name": "charizard" - }, - { - "Id": 10035, - "Name": "charizard" - }, - { - "Id": 10036, - "Name": "blastoise" - }, - { - "Id": 10037, - "Name": "alakazam" - }, - { - "Id": 10038, - "Name": "gengar" - }, - { - "Id": 10039, - "Name": "kangaskhan" - }, - { - "Id": 10040, - "Name": "pinsir" - }, - { - "Id": 10041, - "Name": "gyarados" - }, - { - "Id": 10042, - "Name": "aerodactyl" - }, - { - "Id": 10043, - "Name": "mewtwo" - }, - { - "Id": 10044, - "Name": "mewtwo" - }, - { - "Id": 10045, - "Name": "ampharos" - }, - { - "Id": 10046, - "Name": "scizor" - }, - { - "Id": 10047, - "Name": "heracross" - }, - { - "Id": 10048, - "Name": "houndoom" - }, - { - "Id": 10049, - "Name": "tyranitar" - }, - { - "Id": 10050, - "Name": "blaziken" - }, - { - "Id": 10051, - "Name": "gardevoir" - }, - { - "Id": 10052, - "Name": "mawile" - }, - { - "Id": 10053, - "Name": "aggron" - }, - { - "Id": 10054, - "Name": "medicham" - }, - { - "Id": 10055, - "Name": "manectric" - }, - { - "Id": 10056, - "Name": "banette" - }, - { - "Id": 10057, - "Name": "absol" - }, - { - "Id": 10058, - "Name": "garchomp" - }, - { - "Id": 10059, - "Name": "lucario" - }, - { - "Id": 10060, - "Name": "abomasnow" - }, - { - "Id": 10061, - "Name": "floette" - }, - { - "Id": 10062, - "Name": "latias" - }, - { - "Id": 10063, - "Name": "latios" - }, - { - "Id": 10064, - "Name": "swampert" - }, - { - "Id": 10065, - "Name": "sceptile" - }, - { - "Id": 10066, - "Name": "sableye" - }, - { - "Id": 10067, - "Name": "altaria" - }, - { - "Id": 10068, - "Name": "gallade" - }, - { - "Id": 10069, - "Name": "audino" - }, - { - "Id": 10070, - "Name": "sharpedo" - }, - { - "Id": 10071, - "Name": "slowbro" - }, - { - "Id": 10072, - "Name": "steelix" - }, - { - "Id": 10073, - "Name": "pidgeot" - }, - { - "Id": 10074, - "Name": "glalie" - }, - { - "Id": 10075, - "Name": "diancie" - }, - { - "Id": 10076, - "Name": "metagross" - }, - { - "Id": 10077, - "Name": "kyogre" - }, - { - "Id": 10078, - "Name": "groudon" - }, - { - "Id": 10079, - "Name": "rayquaza" - }, - { - "Id": 10080, - "Name": "pikachu" - }, - { - "Id": 10081, - "Name": "pikachu" - }, - { - "Id": 10082, - "Name": "pikachu" - }, - { - "Id": 10083, - "Name": "pikachu" - }, - { - "Id": 10084, - "Name": "pikachu" - }, - { - "Id": 10085, - "Name": "pikachu" - }, - { - "Id": 10086, - "Name": "hoopa" - }, - { - "Id": 10087, - "Name": "camerupt" - }, - { - "Id": 10088, - "Name": "lopunny" - }, - { - "Id": 10089, - "Name": "salamence" - }, - { - "Id": 10090, - "Name": "beedrill" - } -] \ No newline at end of file diff --git a/src/NadekoBot/data/pokemon/name-id_map2.json b/src/NadekoBot/data/pokemon/name-id_map2.json index 1de578a0..eb6cf559 100644 --- a/src/NadekoBot/data/pokemon/name-id_map2.json +++ b/src/NadekoBot/data/pokemon/name-id_map2.json @@ -1753,7 +1753,7 @@ }, { "Id": 439, - "Name": "mime" + "Name": "mime jr" }, { "Id": 440, From c8179cdf2a170cb10393102216bbe0032ef5724f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 24 Mar 2017 12:15:50 +0100 Subject: [PATCH 616/746] .lcr will now indicate autodeleting and dming custom reactions with emojis before the id --- .../Modules/CustomReactions/CustomReactions.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index 024e79b5..f28a7bc9 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -188,7 +188,19 @@ namespace NadekoBot.Modules.CustomReactions .WithDescription(string.Join("\n", customReactions.OrderBy(cr => cr.Trigger) .Skip((curPage - 1) * 20) .Take(20) - .Select(cr => $"`#{cr.Id}` `{GetText("trigger")}:` {cr.Trigger}"))), lastPage) + .Select(cr => + { + var str = $"`#{cr.Id}` {cr.Trigger}"; + if (cr.AutoDeleteTrigger) + { + str = "🗑" + str; + } + if (cr.DmResponse) + { + str = "📪" + str; + } + return str; + }))), lastPage) .ConfigureAwait(false); } From 86105df59acce318dbdb0737770d8c704a71de88 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 25 Mar 2017 07:39:50 +0100 Subject: [PATCH 617/746] pokemon and nohint trivia args are now case-insensitive --- src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs b/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs index c8bd3e73..a18763c1 100644 --- a/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs @@ -30,6 +30,8 @@ namespace NadekoBot.Modules.Games { var channel = (ITextChannel)Context.Channel; + additionalArgs = additionalArgs?.Trim()?.ToLowerInvariant(); + var showHints = !additionalArgs.Contains("nohint"); var isPokemon = additionalArgs.Contains("pokemon"); From 77b6d42d9358d01d702b381cc5f000e9b2f7eaec Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 25 Mar 2017 09:32:04 +0100 Subject: [PATCH 618/746] Fixes to some pokemans, higher delay between questions --- .../Games/Commands/Trivia/TriviaGame.cs | 5 +- .../Commands/Trivia/TriviaQuestionPool.cs | 2 +- src/NadekoBot/data/pokemon/name-id_map2.json | 3246 ----------------- src/NadekoBot/data/pokemon/name-id_map3.json | 1 + 4 files changed, 5 insertions(+), 3249 deletions(-) delete mode 100644 src/NadekoBot/data/pokemon/name-id_map2.json create mode 100644 src/NadekoBot/data/pokemon/name-id_map3.json diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs index 3bfb8b1a..0fba8200 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs @@ -136,7 +136,8 @@ namespace NadekoBot.Modules.Games.Trivia { await Channel.EmbedAsync(new EmbedBuilder().WithErrorColor() .WithTitle(GetText("trivia_game")) - .WithDescription(GetText("trivia_times_up", Format.Bold(CurrentQuestion.Answer)))) + .WithDescription(GetText("trivia_times_up", Format.Bold(CurrentQuestion.Answer))) + .WithImageUrl(CurrentQuestion.AnswerImageUrl)) .ConfigureAwait(false); } catch (Exception ex) @@ -144,7 +145,7 @@ namespace NadekoBot.Modules.Games.Trivia _log.Warn(ex); } } - await Task.Delay(2000).ConfigureAwait(false); + await Task.Delay(5000).ConfigureAwait(false); } } diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs index cbad9815..e98830f5 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs @@ -21,7 +21,7 @@ namespace NadekoBot.Modules.Games.Trivia public static TriviaQuestionPool Instance { get; } = _instance ?? (_instance = new TriviaQuestionPool()); private const string questionsFile = "data/trivia_questions.json"; - private const string pokemonMapPath = "data/pokemon/name-id_map2.json"; + private const string pokemonMapPath = "data/pokemon/name-id_map3.json"; private readonly int maxPokemonId; private Random rng { get; } = new NadekoRandom(); diff --git a/src/NadekoBot/data/pokemon/name-id_map2.json b/src/NadekoBot/data/pokemon/name-id_map2.json deleted file mode 100644 index eb6cf559..00000000 --- a/src/NadekoBot/data/pokemon/name-id_map2.json +++ /dev/null @@ -1,3246 +0,0 @@ -[ - { - "Id": 1, - "Name": "bulbasaur" - }, - { - "Id": 2, - "Name": "ivysaur" - }, - { - "Id": 3, - "Name": "venusaur" - }, - { - "Id": 4, - "Name": "charmander" - }, - { - "Id": 5, - "Name": "charmeleon" - }, - { - "Id": 6, - "Name": "charizard" - }, - { - "Id": 7, - "Name": "squirtle" - }, - { - "Id": 8, - "Name": "wartortle" - }, - { - "Id": 9, - "Name": "blastoise" - }, - { - "Id": 10, - "Name": "caterpie" - }, - { - "Id": 11, - "Name": "metapod" - }, - { - "Id": 12, - "Name": "butterfree" - }, - { - "Id": 13, - "Name": "weedle" - }, - { - "Id": 14, - "Name": "kakuna" - }, - { - "Id": 15, - "Name": "beedrill" - }, - { - "Id": 16, - "Name": "pidgey" - }, - { - "Id": 17, - "Name": "pidgeotto" - }, - { - "Id": 18, - "Name": "pidgeot" - }, - { - "Id": 19, - "Name": "rattata" - }, - { - "Id": 20, - "Name": "raticate" - }, - { - "Id": 21, - "Name": "spearow" - }, - { - "Id": 22, - "Name": "fearow" - }, - { - "Id": 23, - "Name": "ekans" - }, - { - "Id": 24, - "Name": "arbok" - }, - { - "Id": 25, - "Name": "pikachu" - }, - { - "Id": 26, - "Name": "raichu" - }, - { - "Id": 27, - "Name": "sandshrew" - }, - { - "Id": 28, - "Name": "sandslash" - }, - { - "Id": 29, - "Name": "nidoran" - }, - { - "Id": 30, - "Name": "nidorina" - }, - { - "Id": 31, - "Name": "nidoqueen" - }, - { - "Id": 32, - "Name": "nidoran" - }, - { - "Id": 33, - "Name": "nidorino" - }, - { - "Id": 34, - "Name": "nidoking" - }, - { - "Id": 35, - "Name": "clefairy" - }, - { - "Id": 36, - "Name": "clefable" - }, - { - "Id": 37, - "Name": "vulpix" - }, - { - "Id": 38, - "Name": "ninetales" - }, - { - "Id": 39, - "Name": "jigglypuff" - }, - { - "Id": 40, - "Name": "wigglytuff" - }, - { - "Id": 41, - "Name": "zubat" - }, - { - "Id": 42, - "Name": "golbat" - }, - { - "Id": 43, - "Name": "oddish" - }, - { - "Id": 44, - "Name": "gloom" - }, - { - "Id": 45, - "Name": "vileplume" - }, - { - "Id": 46, - "Name": "paras" - }, - { - "Id": 47, - "Name": "parasect" - }, - { - "Id": 48, - "Name": "venonat" - }, - { - "Id": 49, - "Name": "venomoth" - }, - { - "Id": 50, - "Name": "diglett" - }, - { - "Id": 51, - "Name": "dugtrio" - }, - { - "Id": 52, - "Name": "meowth" - }, - { - "Id": 53, - "Name": "persian" - }, - { - "Id": 54, - "Name": "psyduck" - }, - { - "Id": 55, - "Name": "golduck" - }, - { - "Id": 56, - "Name": "mankey" - }, - { - "Id": 57, - "Name": "primeape" - }, - { - "Id": 58, - "Name": "growlithe" - }, - { - "Id": 59, - "Name": "arcanine" - }, - { - "Id": 60, - "Name": "poliwag" - }, - { - "Id": 61, - "Name": "poliwhirl" - }, - { - "Id": 62, - "Name": "poliwrath" - }, - { - "Id": 63, - "Name": "abra" - }, - { - "Id": 64, - "Name": "kadabra" - }, - { - "Id": 65, - "Name": "alakazam" - }, - { - "Id": 66, - "Name": "machop" - }, - { - "Id": 67, - "Name": "machoke" - }, - { - "Id": 68, - "Name": "machamp" - }, - { - "Id": 69, - "Name": "bellsprout" - }, - { - "Id": 70, - "Name": "weepinbell" - }, - { - "Id": 71, - "Name": "victreebel" - }, - { - "Id": 72, - "Name": "tentacool" - }, - { - "Id": 73, - "Name": "tentacruel" - }, - { - "Id": 74, - "Name": "geodude" - }, - { - "Id": 75, - "Name": "graveler" - }, - { - "Id": 76, - "Name": "golem" - }, - { - "Id": 77, - "Name": "ponyta" - }, - { - "Id": 78, - "Name": "rapidash" - }, - { - "Id": 79, - "Name": "slowpoke" - }, - { - "Id": 80, - "Name": "slowbro" - }, - { - "Id": 81, - "Name": "magnemite" - }, - { - "Id": 82, - "Name": "magneton" - }, - { - "Id": 83, - "Name": "farfetchd" - }, - { - "Id": 84, - "Name": "doduo" - }, - { - "Id": 85, - "Name": "dodrio" - }, - { - "Id": 86, - "Name": "seel" - }, - { - "Id": 87, - "Name": "dewgong" - }, - { - "Id": 88, - "Name": "grimer" - }, - { - "Id": 89, - "Name": "muk" - }, - { - "Id": 90, - "Name": "shellder" - }, - { - "Id": 91, - "Name": "cloyster" - }, - { - "Id": 92, - "Name": "gastly" - }, - { - "Id": 93, - "Name": "haunter" - }, - { - "Id": 94, - "Name": "gengar" - }, - { - "Id": 95, - "Name": "onix" - }, - { - "Id": 96, - "Name": "drowzee" - }, - { - "Id": 97, - "Name": "hypno" - }, - { - "Id": 98, - "Name": "krabby" - }, - { - "Id": 99, - "Name": "kingler" - }, - { - "Id": 100, - "Name": "voltorb" - }, - { - "Id": 101, - "Name": "electrode" - }, - { - "Id": 102, - "Name": "exeggcute" - }, - { - "Id": 103, - "Name": "exeggutor" - }, - { - "Id": 104, - "Name": "cubone" - }, - { - "Id": 105, - "Name": "marowak" - }, - { - "Id": 106, - "Name": "hitmonlee" - }, - { - "Id": 107, - "Name": "hitmonchan" - }, - { - "Id": 108, - "Name": "lickitung" - }, - { - "Id": 109, - "Name": "koffing" - }, - { - "Id": 110, - "Name": "weezing" - }, - { - "Id": 111, - "Name": "rhyhorn" - }, - { - "Id": 112, - "Name": "rhydon" - }, - { - "Id": 113, - "Name": "chansey" - }, - { - "Id": 114, - "Name": "tangela" - }, - { - "Id": 115, - "Name": "kangaskhan" - }, - { - "Id": 116, - "Name": "horsea" - }, - { - "Id": 117, - "Name": "seadra" - }, - { - "Id": 118, - "Name": "goldeen" - }, - { - "Id": 119, - "Name": "seaking" - }, - { - "Id": 120, - "Name": "staryu" - }, - { - "Id": 121, - "Name": "starmie" - }, - { - "Id": 122, - "Name": "mr mime" - }, - { - "Id": 123, - "Name": "scyther" - }, - { - "Id": 124, - "Name": "jynx" - }, - { - "Id": 125, - "Name": "electabuzz" - }, - { - "Id": 126, - "Name": "magmar" - }, - { - "Id": 127, - "Name": "pinsir" - }, - { - "Id": 128, - "Name": "tauros" - }, - { - "Id": 129, - "Name": "magikarp" - }, - { - "Id": 130, - "Name": "gyarados" - }, - { - "Id": 131, - "Name": "lapras" - }, - { - "Id": 132, - "Name": "ditto" - }, - { - "Id": 133, - "Name": "eevee" - }, - { - "Id": 134, - "Name": "vaporeon" - }, - { - "Id": 135, - "Name": "jolteon" - }, - { - "Id": 136, - "Name": "flareon" - }, - { - "Id": 137, - "Name": "porygon" - }, - { - "Id": 138, - "Name": "omanyte" - }, - { - "Id": 139, - "Name": "omastar" - }, - { - "Id": 140, - "Name": "kabuto" - }, - { - "Id": 141, - "Name": "kabutops" - }, - { - "Id": 142, - "Name": "aerodactyl" - }, - { - "Id": 143, - "Name": "snorlax" - }, - { - "Id": 144, - "Name": "articuno" - }, - { - "Id": 145, - "Name": "zapdos" - }, - { - "Id": 146, - "Name": "moltres" - }, - { - "Id": 147, - "Name": "dratini" - }, - { - "Id": 148, - "Name": "dragonair" - }, - { - "Id": 149, - "Name": "dragonite" - }, - { - "Id": 150, - "Name": "mewtwo" - }, - { - "Id": 151, - "Name": "mew" - }, - { - "Id": 152, - "Name": "chikorita" - }, - { - "Id": 153, - "Name": "bayleef" - }, - { - "Id": 154, - "Name": "meganium" - }, - { - "Id": 155, - "Name": "cyndaquil" - }, - { - "Id": 156, - "Name": "quilava" - }, - { - "Id": 157, - "Name": "typhlosion" - }, - { - "Id": 158, - "Name": "totodile" - }, - { - "Id": 159, - "Name": "croconaw" - }, - { - "Id": 160, - "Name": "feraligatr" - }, - { - "Id": 161, - "Name": "sentret" - }, - { - "Id": 162, - "Name": "furret" - }, - { - "Id": 163, - "Name": "hoothoot" - }, - { - "Id": 164, - "Name": "noctowl" - }, - { - "Id": 165, - "Name": "ledyba" - }, - { - "Id": 166, - "Name": "ledian" - }, - { - "Id": 167, - "Name": "spinarak" - }, - { - "Id": 168, - "Name": "ariados" - }, - { - "Id": 169, - "Name": "crobat" - }, - { - "Id": 170, - "Name": "chinchou" - }, - { - "Id": 171, - "Name": "lanturn" - }, - { - "Id": 172, - "Name": "pichu" - }, - { - "Id": 173, - "Name": "cleffa" - }, - { - "Id": 174, - "Name": "igglybuff" - }, - { - "Id": 175, - "Name": "togepi" - }, - { - "Id": 176, - "Name": "togetic" - }, - { - "Id": 177, - "Name": "natu" - }, - { - "Id": 178, - "Name": "xatu" - }, - { - "Id": 179, - "Name": "mareep" - }, - { - "Id": 180, - "Name": "flaaffy" - }, - { - "Id": 181, - "Name": "ampharos" - }, - { - "Id": 182, - "Name": "bellossom" - }, - { - "Id": 183, - "Name": "marill" - }, - { - "Id": 184, - "Name": "azumarill" - }, - { - "Id": 185, - "Name": "sudowoodo" - }, - { - "Id": 186, - "Name": "politoed" - }, - { - "Id": 187, - "Name": "hoppip" - }, - { - "Id": 188, - "Name": "skiploom" - }, - { - "Id": 189, - "Name": "jumpluff" - }, - { - "Id": 190, - "Name": "aipom" - }, - { - "Id": 191, - "Name": "sunkern" - }, - { - "Id": 192, - "Name": "sunflora" - }, - { - "Id": 193, - "Name": "yanma" - }, - { - "Id": 194, - "Name": "wooper" - }, - { - "Id": 195, - "Name": "quagsire" - }, - { - "Id": 196, - "Name": "espeon" - }, - { - "Id": 197, - "Name": "umbreon" - }, - { - "Id": 198, - "Name": "murkrow" - }, - { - "Id": 199, - "Name": "slowking" - }, - { - "Id": 200, - "Name": "misdreavus" - }, - { - "Id": 201, - "Name": "unown" - }, - { - "Id": 202, - "Name": "wobbuffet" - }, - { - "Id": 203, - "Name": "girafarig" - }, - { - "Id": 204, - "Name": "pineco" - }, - { - "Id": 205, - "Name": "forretress" - }, - { - "Id": 206, - "Name": "dunsparce" - }, - { - "Id": 207, - "Name": "gligar" - }, - { - "Id": 208, - "Name": "steelix" - }, - { - "Id": 209, - "Name": "snubbull" - }, - { - "Id": 210, - "Name": "granbull" - }, - { - "Id": 211, - "Name": "qwilfish" - }, - { - "Id": 212, - "Name": "scizor" - }, - { - "Id": 213, - "Name": "shuckle" - }, - { - "Id": 214, - "Name": "heracross" - }, - { - "Id": 215, - "Name": "sneasel" - }, - { - "Id": 216, - "Name": "teddiursa" - }, - { - "Id": 217, - "Name": "ursaring" - }, - { - "Id": 218, - "Name": "slugma" - }, - { - "Id": 219, - "Name": "magcargo" - }, - { - "Id": 220, - "Name": "swinub" - }, - { - "Id": 221, - "Name": "piloswine" - }, - { - "Id": 222, - "Name": "corsola" - }, - { - "Id": 223, - "Name": "remoraid" - }, - { - "Id": 224, - "Name": "octillery" - }, - { - "Id": 225, - "Name": "delibird" - }, - { - "Id": 226, - "Name": "mantine" - }, - { - "Id": 227, - "Name": "skarmory" - }, - { - "Id": 228, - "Name": "houndour" - }, - { - "Id": 229, - "Name": "houndoom" - }, - { - "Id": 230, - "Name": "kingdra" - }, - { - "Id": 231, - "Name": "phanpy" - }, - { - "Id": 232, - "Name": "donphan" - }, - { - "Id": 233, - "Name": "porygon2" - }, - { - "Id": 234, - "Name": "stantler" - }, - { - "Id": 235, - "Name": "smeargle" - }, - { - "Id": 236, - "Name": "tyrogue" - }, - { - "Id": 237, - "Name": "hitmontop" - }, - { - "Id": 238, - "Name": "smoochum" - }, - { - "Id": 239, - "Name": "elekid" - }, - { - "Id": 240, - "Name": "magby" - }, - { - "Id": 241, - "Name": "miltank" - }, - { - "Id": 242, - "Name": "blissey" - }, - { - "Id": 243, - "Name": "raikou" - }, - { - "Id": 244, - "Name": "entei" - }, - { - "Id": 245, - "Name": "suicune" - }, - { - "Id": 246, - "Name": "larvitar" - }, - { - "Id": 247, - "Name": "pupitar" - }, - { - "Id": 248, - "Name": "tyranitar" - }, - { - "Id": 249, - "Name": "lugia" - }, - { - "Id": 250, - "Name": "ho" - }, - { - "Id": 251, - "Name": "celebi" - }, - { - "Id": 252, - "Name": "treecko" - }, - { - "Id": 253, - "Name": "grovyle" - }, - { - "Id": 254, - "Name": "sceptile" - }, - { - "Id": 255, - "Name": "torchic" - }, - { - "Id": 256, - "Name": "combusken" - }, - { - "Id": 257, - "Name": "blaziken" - }, - { - "Id": 258, - "Name": "mudkip" - }, - { - "Id": 259, - "Name": "marshtomp" - }, - { - "Id": 260, - "Name": "swampert" - }, - { - "Id": 261, - "Name": "poochyena" - }, - { - "Id": 262, - "Name": "mightyena" - }, - { - "Id": 263, - "Name": "zigzagoon" - }, - { - "Id": 264, - "Name": "linoone" - }, - { - "Id": 265, - "Name": "wurmple" - }, - { - "Id": 266, - "Name": "silcoon" - }, - { - "Id": 267, - "Name": "beautifly" - }, - { - "Id": 268, - "Name": "cascoon" - }, - { - "Id": 269, - "Name": "dustox" - }, - { - "Id": 270, - "Name": "lotad" - }, - { - "Id": 271, - "Name": "lombre" - }, - { - "Id": 272, - "Name": "ludicolo" - }, - { - "Id": 273, - "Name": "seedot" - }, - { - "Id": 274, - "Name": "nuzleaf" - }, - { - "Id": 275, - "Name": "shiftry" - }, - { - "Id": 276, - "Name": "taillow" - }, - { - "Id": 277, - "Name": "swellow" - }, - { - "Id": 278, - "Name": "wingull" - }, - { - "Id": 279, - "Name": "pelipper" - }, - { - "Id": 280, - "Name": "ralts" - }, - { - "Id": 281, - "Name": "kirlia" - }, - { - "Id": 282, - "Name": "gardevoir" - }, - { - "Id": 283, - "Name": "surskit" - }, - { - "Id": 284, - "Name": "masquerain" - }, - { - "Id": 285, - "Name": "shroomish" - }, - { - "Id": 286, - "Name": "breloom" - }, - { - "Id": 287, - "Name": "slakoth" - }, - { - "Id": 288, - "Name": "vigoroth" - }, - { - "Id": 289, - "Name": "slaking" - }, - { - "Id": 290, - "Name": "nincada" - }, - { - "Id": 291, - "Name": "ninjask" - }, - { - "Id": 292, - "Name": "shedinja" - }, - { - "Id": 293, - "Name": "whismur" - }, - { - "Id": 294, - "Name": "loudred" - }, - { - "Id": 295, - "Name": "exploud" - }, - { - "Id": 296, - "Name": "makuhita" - }, - { - "Id": 297, - "Name": "hariyama" - }, - { - "Id": 298, - "Name": "azurill" - }, - { - "Id": 299, - "Name": "nosepass" - }, - { - "Id": 300, - "Name": "skitty" - }, - { - "Id": 301, - "Name": "delcatty" - }, - { - "Id": 302, - "Name": "sableye" - }, - { - "Id": 303, - "Name": "mawile" - }, - { - "Id": 304, - "Name": "aron" - }, - { - "Id": 305, - "Name": "lairon" - }, - { - "Id": 306, - "Name": "aggron" - }, - { - "Id": 307, - "Name": "meditite" - }, - { - "Id": 308, - "Name": "medicham" - }, - { - "Id": 309, - "Name": "electrike" - }, - { - "Id": 310, - "Name": "manectric" - }, - { - "Id": 311, - "Name": "plusle" - }, - { - "Id": 312, - "Name": "minun" - }, - { - "Id": 313, - "Name": "volbeat" - }, - { - "Id": 314, - "Name": "illumise" - }, - { - "Id": 315, - "Name": "roselia" - }, - { - "Id": 316, - "Name": "gulpin" - }, - { - "Id": 317, - "Name": "swalot" - }, - { - "Id": 318, - "Name": "carvanha" - }, - { - "Id": 319, - "Name": "sharpedo" - }, - { - "Id": 320, - "Name": "wailmer" - }, - { - "Id": 321, - "Name": "wailord" - }, - { - "Id": 322, - "Name": "numel" - }, - { - "Id": 323, - "Name": "camerupt" - }, - { - "Id": 324, - "Name": "torkoal" - }, - { - "Id": 325, - "Name": "spoink" - }, - { - "Id": 326, - "Name": "grumpig" - }, - { - "Id": 327, - "Name": "spinda" - }, - { - "Id": 328, - "Name": "trapinch" - }, - { - "Id": 329, - "Name": "vibrava" - }, - { - "Id": 330, - "Name": "flygon" - }, - { - "Id": 331, - "Name": "cacnea" - }, - { - "Id": 332, - "Name": "cacturne" - }, - { - "Id": 333, - "Name": "swablu" - }, - { - "Id": 334, - "Name": "altaria" - }, - { - "Id": 335, - "Name": "zangoose" - }, - { - "Id": 336, - "Name": "seviper" - }, - { - "Id": 337, - "Name": "lunatone" - }, - { - "Id": 338, - "Name": "solrock" - }, - { - "Id": 339, - "Name": "barboach" - }, - { - "Id": 340, - "Name": "whiscash" - }, - { - "Id": 341, - "Name": "corphish" - }, - { - "Id": 342, - "Name": "crawdaunt" - }, - { - "Id": 343, - "Name": "baltoy" - }, - { - "Id": 344, - "Name": "claydol" - }, - { - "Id": 345, - "Name": "lileep" - }, - { - "Id": 346, - "Name": "cradily" - }, - { - "Id": 347, - "Name": "anorith" - }, - { - "Id": 348, - "Name": "armaldo" - }, - { - "Id": 349, - "Name": "feebas" - }, - { - "Id": 350, - "Name": "milotic" - }, - { - "Id": 351, - "Name": "castform" - }, - { - "Id": 352, - "Name": "kecleon" - }, - { - "Id": 353, - "Name": "shuppet" - }, - { - "Id": 354, - "Name": "banette" - }, - { - "Id": 355, - "Name": "duskull" - }, - { - "Id": 356, - "Name": "dusclops" - }, - { - "Id": 357, - "Name": "tropius" - }, - { - "Id": 358, - "Name": "chimecho" - }, - { - "Id": 359, - "Name": "absol" - }, - { - "Id": 360, - "Name": "wynaut" - }, - { - "Id": 361, - "Name": "snorunt" - }, - { - "Id": 362, - "Name": "glalie" - }, - { - "Id": 363, - "Name": "spheal" - }, - { - "Id": 364, - "Name": "sealeo" - }, - { - "Id": 365, - "Name": "walrein" - }, - { - "Id": 366, - "Name": "clamperl" - }, - { - "Id": 367, - "Name": "huntail" - }, - { - "Id": 368, - "Name": "gorebyss" - }, - { - "Id": 369, - "Name": "relicanth" - }, - { - "Id": 370, - "Name": "luvdisc" - }, - { - "Id": 371, - "Name": "bagon" - }, - { - "Id": 372, - "Name": "shelgon" - }, - { - "Id": 373, - "Name": "salamence" - }, - { - "Id": 374, - "Name": "beldum" - }, - { - "Id": 375, - "Name": "metang" - }, - { - "Id": 376, - "Name": "metagross" - }, - { - "Id": 377, - "Name": "regirock" - }, - { - "Id": 378, - "Name": "regice" - }, - { - "Id": 379, - "Name": "registeel" - }, - { - "Id": 380, - "Name": "latias" - }, - { - "Id": 381, - "Name": "latios" - }, - { - "Id": 382, - "Name": "kyogre" - }, - { - "Id": 383, - "Name": "groudon" - }, - { - "Id": 384, - "Name": "rayquaza" - }, - { - "Id": 385, - "Name": "jirachi" - }, - { - "Id": 386, - "Name": "deoxys" - }, - { - "Id": 387, - "Name": "turtwig" - }, - { - "Id": 388, - "Name": "grotle" - }, - { - "Id": 389, - "Name": "torterra" - }, - { - "Id": 390, - "Name": "chimchar" - }, - { - "Id": 391, - "Name": "monferno" - }, - { - "Id": 392, - "Name": "infernape" - }, - { - "Id": 393, - "Name": "piplup" - }, - { - "Id": 394, - "Name": "prinplup" - }, - { - "Id": 395, - "Name": "empoleon" - }, - { - "Id": 396, - "Name": "starly" - }, - { - "Id": 397, - "Name": "staravia" - }, - { - "Id": 398, - "Name": "staraptor" - }, - { - "Id": 399, - "Name": "bidoof" - }, - { - "Id": 400, - "Name": "bibarel" - }, - { - "Id": 401, - "Name": "kricketot" - }, - { - "Id": 402, - "Name": "kricketune" - }, - { - "Id": 403, - "Name": "shinx" - }, - { - "Id": 404, - "Name": "luxio" - }, - { - "Id": 405, - "Name": "luxray" - }, - { - "Id": 406, - "Name": "budew" - }, - { - "Id": 407, - "Name": "roserade" - }, - { - "Id": 408, - "Name": "cranidos" - }, - { - "Id": 409, - "Name": "rampardos" - }, - { - "Id": 410, - "Name": "shieldon" - }, - { - "Id": 411, - "Name": "bastiodon" - }, - { - "Id": 412, - "Name": "burmy" - }, - { - "Id": 413, - "Name": "wormadam" - }, - { - "Id": 414, - "Name": "mothim" - }, - { - "Id": 415, - "Name": "combee" - }, - { - "Id": 416, - "Name": "vespiquen" - }, - { - "Id": 417, - "Name": "pachirisu" - }, - { - "Id": 418, - "Name": "buizel" - }, - { - "Id": 419, - "Name": "floatzel" - }, - { - "Id": 420, - "Name": "cherubi" - }, - { - "Id": 421, - "Name": "cherrim" - }, - { - "Id": 422, - "Name": "shellos" - }, - { - "Id": 423, - "Name": "gastrodon" - }, - { - "Id": 424, - "Name": "ambipom" - }, - { - "Id": 425, - "Name": "drifloon" - }, - { - "Id": 426, - "Name": "drifblim" - }, - { - "Id": 427, - "Name": "buneary" - }, - { - "Id": 428, - "Name": "lopunny" - }, - { - "Id": 429, - "Name": "mismagius" - }, - { - "Id": 430, - "Name": "honchkrow" - }, - { - "Id": 431, - "Name": "glameow" - }, - { - "Id": 432, - "Name": "purugly" - }, - { - "Id": 433, - "Name": "chingling" - }, - { - "Id": 434, - "Name": "stunky" - }, - { - "Id": 435, - "Name": "skuntank" - }, - { - "Id": 436, - "Name": "bronzor" - }, - { - "Id": 437, - "Name": "bronzong" - }, - { - "Id": 438, - "Name": "bonsly" - }, - { - "Id": 439, - "Name": "mime jr" - }, - { - "Id": 440, - "Name": "happiny" - }, - { - "Id": 441, - "Name": "chatot" - }, - { - "Id": 442, - "Name": "spiritomb" - }, - { - "Id": 443, - "Name": "gible" - }, - { - "Id": 444, - "Name": "gabite" - }, - { - "Id": 445, - "Name": "garchomp" - }, - { - "Id": 446, - "Name": "munchlax" - }, - { - "Id": 447, - "Name": "riolu" - }, - { - "Id": 448, - "Name": "lucario" - }, - { - "Id": 449, - "Name": "hippopotas" - }, - { - "Id": 450, - "Name": "hippowdon" - }, - { - "Id": 451, - "Name": "skorupi" - }, - { - "Id": 452, - "Name": "drapion" - }, - { - "Id": 453, - "Name": "croagunk" - }, - { - "Id": 454, - "Name": "toxicroak" - }, - { - "Id": 455, - "Name": "carnivine" - }, - { - "Id": 456, - "Name": "finneon" - }, - { - "Id": 457, - "Name": "lumineon" - }, - { - "Id": 458, - "Name": "mantyke" - }, - { - "Id": 459, - "Name": "snover" - }, - { - "Id": 460, - "Name": "abomasnow" - }, - { - "Id": 461, - "Name": "weavile" - }, - { - "Id": 462, - "Name": "magnezone" - }, - { - "Id": 463, - "Name": "lickilicky" - }, - { - "Id": 464, - "Name": "rhyperior" - }, - { - "Id": 465, - "Name": "tangrowth" - }, - { - "Id": 466, - "Name": "electivire" - }, - { - "Id": 467, - "Name": "magmortar" - }, - { - "Id": 468, - "Name": "togekiss" - }, - { - "Id": 469, - "Name": "yanmega" - }, - { - "Id": 470, - "Name": "leafeon" - }, - { - "Id": 471, - "Name": "glaceon" - }, - { - "Id": 472, - "Name": "gliscor" - }, - { - "Id": 473, - "Name": "mamoswine" - }, - { - "Id": 474, - "Name": "porygon" - }, - { - "Id": 475, - "Name": "gallade" - }, - { - "Id": 476, - "Name": "probopass" - }, - { - "Id": 477, - "Name": "dusknoir" - }, - { - "Id": 478, - "Name": "froslass" - }, - { - "Id": 479, - "Name": "rotom" - }, - { - "Id": 480, - "Name": "uxie" - }, - { - "Id": 481, - "Name": "mesprit" - }, - { - "Id": 482, - "Name": "azelf" - }, - { - "Id": 483, - "Name": "dialga" - }, - { - "Id": 484, - "Name": "palkia" - }, - { - "Id": 485, - "Name": "heatran" - }, - { - "Id": 486, - "Name": "regigigas" - }, - { - "Id": 487, - "Name": "giratina" - }, - { - "Id": 488, - "Name": "cresselia" - }, - { - "Id": 489, - "Name": "phione" - }, - { - "Id": 490, - "Name": "manaphy" - }, - { - "Id": 491, - "Name": "darkrai" - }, - { - "Id": 492, - "Name": "shaymin" - }, - { - "Id": 493, - "Name": "arceus" - }, - { - "Id": 494, - "Name": "victini" - }, - { - "Id": 495, - "Name": "snivy" - }, - { - "Id": 496, - "Name": "servine" - }, - { - "Id": 497, - "Name": "serperior" - }, - { - "Id": 498, - "Name": "tepig" - }, - { - "Id": 499, - "Name": "pignite" - }, - { - "Id": 500, - "Name": "emboar" - }, - { - "Id": 501, - "Name": "oshawott" - }, - { - "Id": 502, - "Name": "dewott" - }, - { - "Id": 503, - "Name": "samurott" - }, - { - "Id": 504, - "Name": "patrat" - }, - { - "Id": 505, - "Name": "watchog" - }, - { - "Id": 506, - "Name": "lillipup" - }, - { - "Id": 507, - "Name": "herdier" - }, - { - "Id": 508, - "Name": "stoutland" - }, - { - "Id": 509, - "Name": "purrloin" - }, - { - "Id": 510, - "Name": "liepard" - }, - { - "Id": 511, - "Name": "pansage" - }, - { - "Id": 512, - "Name": "simisage" - }, - { - "Id": 513, - "Name": "pansear" - }, - { - "Id": 514, - "Name": "simisear" - }, - { - "Id": 515, - "Name": "panpour" - }, - { - "Id": 516, - "Name": "simipour" - }, - { - "Id": 517, - "Name": "munna" - }, - { - "Id": 518, - "Name": "musharna" - }, - { - "Id": 519, - "Name": "pidove" - }, - { - "Id": 520, - "Name": "tranquill" - }, - { - "Id": 521, - "Name": "unfezant" - }, - { - "Id": 522, - "Name": "blitzle" - }, - { - "Id": 523, - "Name": "zebstrika" - }, - { - "Id": 524, - "Name": "roggenrola" - }, - { - "Id": 525, - "Name": "boldore" - }, - { - "Id": 526, - "Name": "gigalith" - }, - { - "Id": 527, - "Name": "woobat" - }, - { - "Id": 528, - "Name": "swoobat" - }, - { - "Id": 529, - "Name": "drilbur" - }, - { - "Id": 530, - "Name": "excadrill" - }, - { - "Id": 531, - "Name": "audino" - }, - { - "Id": 532, - "Name": "timburr" - }, - { - "Id": 533, - "Name": "gurdurr" - }, - { - "Id": 534, - "Name": "conkeldurr" - }, - { - "Id": 535, - "Name": "tympole" - }, - { - "Id": 536, - "Name": "palpitoad" - }, - { - "Id": 537, - "Name": "seismitoad" - }, - { - "Id": 538, - "Name": "throh" - }, - { - "Id": 539, - "Name": "sawk" - }, - { - "Id": 540, - "Name": "sewaddle" - }, - { - "Id": 541, - "Name": "swadloon" - }, - { - "Id": 542, - "Name": "leavanny" - }, - { - "Id": 543, - "Name": "venipede" - }, - { - "Id": 544, - "Name": "whirlipede" - }, - { - "Id": 545, - "Name": "scolipede" - }, - { - "Id": 546, - "Name": "cottonee" - }, - { - "Id": 547, - "Name": "whimsicott" - }, - { - "Id": 548, - "Name": "petilil" - }, - { - "Id": 549, - "Name": "lilligant" - }, - { - "Id": 550, - "Name": "basculin" - }, - { - "Id": 551, - "Name": "sandile" - }, - { - "Id": 552, - "Name": "krokorok" - }, - { - "Id": 553, - "Name": "krookodile" - }, - { - "Id": 554, - "Name": "darumaka" - }, - { - "Id": 555, - "Name": "darmanitan" - }, - { - "Id": 556, - "Name": "maractus" - }, - { - "Id": 557, - "Name": "dwebble" - }, - { - "Id": 558, - "Name": "crustle" - }, - { - "Id": 559, - "Name": "scraggy" - }, - { - "Id": 560, - "Name": "scrafty" - }, - { - "Id": 561, - "Name": "sigilyph" - }, - { - "Id": 562, - "Name": "yamask" - }, - { - "Id": 563, - "Name": "cofagrigus" - }, - { - "Id": 564, - "Name": "tirtouga" - }, - { - "Id": 565, - "Name": "carracosta" - }, - { - "Id": 566, - "Name": "archen" - }, - { - "Id": 567, - "Name": "archeops" - }, - { - "Id": 568, - "Name": "trubbish" - }, - { - "Id": 569, - "Name": "garbodor" - }, - { - "Id": 570, - "Name": "zorua" - }, - { - "Id": 571, - "Name": "zoroark" - }, - { - "Id": 572, - "Name": "minccino" - }, - { - "Id": 573, - "Name": "cinccino" - }, - { - "Id": 574, - "Name": "gothita" - }, - { - "Id": 575, - "Name": "gothorita" - }, - { - "Id": 576, - "Name": "gothitelle" - }, - { - "Id": 577, - "Name": "solosis" - }, - { - "Id": 578, - "Name": "duosion" - }, - { - "Id": 579, - "Name": "reuniclus" - }, - { - "Id": 580, - "Name": "ducklett" - }, - { - "Id": 581, - "Name": "swanna" - }, - { - "Id": 582, - "Name": "vanillite" - }, - { - "Id": 583, - "Name": "vanillish" - }, - { - "Id": 584, - "Name": "vanilluxe" - }, - { - "Id": 585, - "Name": "deerling" - }, - { - "Id": 586, - "Name": "sawsbuck" - }, - { - "Id": 587, - "Name": "emolga" - }, - { - "Id": 588, - "Name": "karrablast" - }, - { - "Id": 589, - "Name": "escavalier" - }, - { - "Id": 590, - "Name": "foongus" - }, - { - "Id": 591, - "Name": "amoonguss" - }, - { - "Id": 592, - "Name": "frillish" - }, - { - "Id": 593, - "Name": "jellicent" - }, - { - "Id": 594, - "Name": "alomomola" - }, - { - "Id": 595, - "Name": "joltik" - }, - { - "Id": 596, - "Name": "galvantula" - }, - { - "Id": 597, - "Name": "ferroseed" - }, - { - "Id": 598, - "Name": "ferrothorn" - }, - { - "Id": 599, - "Name": "klink" - }, - { - "Id": 600, - "Name": "klang" - }, - { - "Id": 601, - "Name": "klinklang" - }, - { - "Id": 602, - "Name": "tynamo" - }, - { - "Id": 603, - "Name": "eelektrik" - }, - { - "Id": 604, - "Name": "eelektross" - }, - { - "Id": 605, - "Name": "elgyem" - }, - { - "Id": 606, - "Name": "beheeyem" - }, - { - "Id": 607, - "Name": "litwick" - }, - { - "Id": 608, - "Name": "lampent" - }, - { - "Id": 609, - "Name": "chandelure" - }, - { - "Id": 610, - "Name": "axew" - }, - { - "Id": 611, - "Name": "fraxure" - }, - { - "Id": 612, - "Name": "haxorus" - }, - { - "Id": 613, - "Name": "cubchoo" - }, - { - "Id": 614, - "Name": "beartic" - }, - { - "Id": 615, - "Name": "cryogonal" - }, - { - "Id": 616, - "Name": "shelmet" - }, - { - "Id": 617, - "Name": "accelgor" - }, - { - "Id": 618, - "Name": "stunfisk" - }, - { - "Id": 619, - "Name": "mienfoo" - }, - { - "Id": 620, - "Name": "mienshao" - }, - { - "Id": 621, - "Name": "druddigon" - }, - { - "Id": 622, - "Name": "golett" - }, - { - "Id": 623, - "Name": "golurk" - }, - { - "Id": 624, - "Name": "pawniard" - }, - { - "Id": 625, - "Name": "bisharp" - }, - { - "Id": 626, - "Name": "bouffalant" - }, - { - "Id": 627, - "Name": "rufflet" - }, - { - "Id": 628, - "Name": "braviary" - }, - { - "Id": 629, - "Name": "vullaby" - }, - { - "Id": 630, - "Name": "mandibuzz" - }, - { - "Id": 631, - "Name": "heatmor" - }, - { - "Id": 632, - "Name": "durant" - }, - { - "Id": 633, - "Name": "deino" - }, - { - "Id": 634, - "Name": "zweilous" - }, - { - "Id": 635, - "Name": "hydreigon" - }, - { - "Id": 636, - "Name": "larvesta" - }, - { - "Id": 637, - "Name": "volcarona" - }, - { - "Id": 638, - "Name": "cobalion" - }, - { - "Id": 639, - "Name": "terrakion" - }, - { - "Id": 640, - "Name": "virizion" - }, - { - "Id": 641, - "Name": "tornadus" - }, - { - "Id": 642, - "Name": "thundurus" - }, - { - "Id": 643, - "Name": "reshiram" - }, - { - "Id": 644, - "Name": "zekrom" - }, - { - "Id": 645, - "Name": "landorus" - }, - { - "Id": 646, - "Name": "kyurem" - }, - { - "Id": 647, - "Name": "keldeo" - }, - { - "Id": 648, - "Name": "meloetta" - }, - { - "Id": 649, - "Name": "genesect" - }, - { - "Id": 650, - "Name": "chespin" - }, - { - "Id": 651, - "Name": "quilladin" - }, - { - "Id": 652, - "Name": "chesnaught" - }, - { - "Id": 653, - "Name": "fennekin" - }, - { - "Id": 654, - "Name": "braixen" - }, - { - "Id": 655, - "Name": "delphox" - }, - { - "Id": 656, - "Name": "froakie" - }, - { - "Id": 657, - "Name": "frogadier" - }, - { - "Id": 658, - "Name": "greninja" - }, - { - "Id": 659, - "Name": "bunnelby" - }, - { - "Id": 660, - "Name": "diggersby" - }, - { - "Id": 661, - "Name": "fletchling" - }, - { - "Id": 662, - "Name": "fletchinder" - }, - { - "Id": 663, - "Name": "talonflame" - }, - { - "Id": 664, - "Name": "scatterbug" - }, - { - "Id": 665, - "Name": "spewpa" - }, - { - "Id": 666, - "Name": "vivillon" - }, - { - "Id": 667, - "Name": "litleo" - }, - { - "Id": 668, - "Name": "pyroar" - }, - { - "Id": 669, - "Name": "flabebe" - }, - { - "Id": 670, - "Name": "floette" - }, - { - "Id": 671, - "Name": "florges" - }, - { - "Id": 672, - "Name": "skiddo" - }, - { - "Id": 673, - "Name": "gogoat" - }, - { - "Id": 674, - "Name": "pancham" - }, - { - "Id": 675, - "Name": "pangoro" - }, - { - "Id": 676, - "Name": "furfrou" - }, - { - "Id": 677, - "Name": "espurr" - }, - { - "Id": 678, - "Name": "meowstic" - }, - { - "Id": 679, - "Name": "honedge" - }, - { - "Id": 680, - "Name": "doublade" - }, - { - "Id": 681, - "Name": "aegislash" - }, - { - "Id": 682, - "Name": "spritzee" - }, - { - "Id": 683, - "Name": "aromatisse" - }, - { - "Id": 684, - "Name": "swirlix" - }, - { - "Id": 685, - "Name": "slurpuff" - }, - { - "Id": 686, - "Name": "inkay" - }, - { - "Id": 687, - "Name": "malamar" - }, - { - "Id": 688, - "Name": "binacle" - }, - { - "Id": 689, - "Name": "barbaracle" - }, - { - "Id": 690, - "Name": "skrelp" - }, - { - "Id": 691, - "Name": "dragalge" - }, - { - "Id": 692, - "Name": "clauncher" - }, - { - "Id": 693, - "Name": "clawitzer" - }, - { - "Id": 694, - "Name": "helioptile" - }, - { - "Id": 695, - "Name": "heliolisk" - }, - { - "Id": 696, - "Name": "tyrunt" - }, - { - "Id": 697, - "Name": "tyrantrum" - }, - { - "Id": 698, - "Name": "amaura" - }, - { - "Id": 699, - "Name": "aurorus" - }, - { - "Id": 700, - "Name": "sylveon" - }, - { - "Id": 701, - "Name": "hawlucha" - }, - { - "Id": 702, - "Name": "dedenne" - }, - { - "Id": 703, - "Name": "carbink" - }, - { - "Id": 704, - "Name": "goomy" - }, - { - "Id": 705, - "Name": "sliggoo" - }, - { - "Id": 706, - "Name": "goodra" - }, - { - "Id": 707, - "Name": "klefki" - }, - { - "Id": 708, - "Name": "phantump" - }, - { - "Id": 709, - "Name": "trevenant" - }, - { - "Id": 710, - "Name": "pumpkaboo" - }, - { - "Id": 711, - "Name": "gourgeist" - }, - { - "Id": 712, - "Name": "bergmite" - }, - { - "Id": 713, - "Name": "avalugg" - }, - { - "Id": 714, - "Name": "noibat" - }, - { - "Id": 715, - "Name": "noivern" - }, - { - "Id": 716, - "Name": "xerneas" - }, - { - "Id": 717, - "Name": "yveltal" - }, - { - "Id": 718, - "Name": "zygarde" - }, - { - "Id": 719, - "Name": "diancie" - }, - { - "Id": 720, - "Name": "hoopa" - }, - { - "Id": 721, - "Name": "volcanion" - }, - { - "Id": 10001, - "Name": "deoxys" - }, - { - "Id": 10002, - "Name": "deoxys" - }, - { - "Id": 10003, - "Name": "deoxys" - }, - { - "Id": 10004, - "Name": "wormadam" - }, - { - "Id": 10005, - "Name": "wormadam" - }, - { - "Id": 10006, - "Name": "shaymin" - }, - { - "Id": 10007, - "Name": "giratina" - }, - { - "Id": 10008, - "Name": "rotom" - }, - { - "Id": 10009, - "Name": "rotom" - }, - { - "Id": 10010, - "Name": "rotom" - }, - { - "Id": 10011, - "Name": "rotom" - }, - { - "Id": 10012, - "Name": "rotom" - }, - { - "Id": 10013, - "Name": "castform" - }, - { - "Id": 10014, - "Name": "castform" - }, - { - "Id": 10015, - "Name": "castform" - }, - { - "Id": 10016, - "Name": "basculin" - }, - { - "Id": 10017, - "Name": "darmanitan" - }, - { - "Id": 10018, - "Name": "meloetta" - }, - { - "Id": 10019, - "Name": "tornadus" - }, - { - "Id": 10020, - "Name": "thundurus" - }, - { - "Id": 10021, - "Name": "landorus" - }, - { - "Id": 10022, - "Name": "kyurem" - }, - { - "Id": 10023, - "Name": "kyurem" - }, - { - "Id": 10024, - "Name": "keldeo" - }, - { - "Id": 10025, - "Name": "meowstic" - }, - { - "Id": 10026, - "Name": "aegislash" - }, - { - "Id": 10027, - "Name": "pumpkaboo" - }, - { - "Id": 10028, - "Name": "pumpkaboo" - }, - { - "Id": 10029, - "Name": "pumpkaboo" - }, - { - "Id": 10030, - "Name": "gourgeist" - }, - { - "Id": 10031, - "Name": "gourgeist" - }, - { - "Id": 10032, - "Name": "gourgeist" - }, - { - "Id": 10033, - "Name": "venusaur" - }, - { - "Id": 10034, - "Name": "charizard" - }, - { - "Id": 10035, - "Name": "charizard" - }, - { - "Id": 10036, - "Name": "blastoise" - }, - { - "Id": 10037, - "Name": "alakazam" - }, - { - "Id": 10038, - "Name": "gengar" - }, - { - "Id": 10039, - "Name": "kangaskhan" - }, - { - "Id": 10040, - "Name": "pinsir" - }, - { - "Id": 10041, - "Name": "gyarados" - }, - { - "Id": 10042, - "Name": "aerodactyl" - }, - { - "Id": 10043, - "Name": "mewtwo" - }, - { - "Id": 10044, - "Name": "mewtwo" - }, - { - "Id": 10045, - "Name": "ampharos" - }, - { - "Id": 10046, - "Name": "scizor" - }, - { - "Id": 10047, - "Name": "heracross" - }, - { - "Id": 10048, - "Name": "houndoom" - }, - { - "Id": 10049, - "Name": "tyranitar" - }, - { - "Id": 10050, - "Name": "blaziken" - }, - { - "Id": 10051, - "Name": "gardevoir" - }, - { - "Id": 10052, - "Name": "mawile" - }, - { - "Id": 10053, - "Name": "aggron" - }, - { - "Id": 10054, - "Name": "medicham" - }, - { - "Id": 10055, - "Name": "manectric" - }, - { - "Id": 10056, - "Name": "banette" - }, - { - "Id": 10057, - "Name": "absol" - }, - { - "Id": 10058, - "Name": "garchomp" - }, - { - "Id": 10059, - "Name": "lucario" - }, - { - "Id": 10060, - "Name": "abomasnow" - }, - { - "Id": 10061, - "Name": "floette" - }, - { - "Id": 10062, - "Name": "latias" - }, - { - "Id": 10063, - "Name": "latios" - }, - { - "Id": 10064, - "Name": "swampert" - }, - { - "Id": 10065, - "Name": "sceptile" - }, - { - "Id": 10066, - "Name": "sableye" - }, - { - "Id": 10067, - "Name": "altaria" - }, - { - "Id": 10068, - "Name": "gallade" - }, - { - "Id": 10069, - "Name": "audino" - }, - { - "Id": 10070, - "Name": "sharpedo" - }, - { - "Id": 10071, - "Name": "slowbro" - }, - { - "Id": 10072, - "Name": "steelix" - }, - { - "Id": 10073, - "Name": "pidgeot" - }, - { - "Id": 10074, - "Name": "glalie" - }, - { - "Id": 10075, - "Name": "diancie" - }, - { - "Id": 10076, - "Name": "metagross" - }, - { - "Id": 10077, - "Name": "kyogre" - }, - { - "Id": 10078, - "Name": "groudon" - }, - { - "Id": 10079, - "Name": "rayquaza" - }, - { - "Id": 10080, - "Name": "pikachu" - }, - { - "Id": 10081, - "Name": "pikachu" - }, - { - "Id": 10082, - "Name": "pikachu" - }, - { - "Id": 10083, - "Name": "pikachu" - }, - { - "Id": 10084, - "Name": "pikachu" - }, - { - "Id": 10085, - "Name": "pikachu" - }, - { - "Id": 10086, - "Name": "hoopa" - }, - { - "Id": 10087, - "Name": "camerupt" - }, - { - "Id": 10088, - "Name": "lopunny" - }, - { - "Id": 10089, - "Name": "salamence" - }, - { - "Id": 10090, - "Name": "beedrill" - } -] \ No newline at end of file diff --git a/src/NadekoBot/data/pokemon/name-id_map3.json b/src/NadekoBot/data/pokemon/name-id_map3.json new file mode 100644 index 00000000..06422033 --- /dev/null +++ b/src/NadekoBot/data/pokemon/name-id_map3.json @@ -0,0 +1 @@ +[{"Id":1,"Name":"bulbasaur"},{"Id":2,"Name":"ivysaur"},{"Id":3,"Name":"venusaur"},{"Id":4,"Name":"charmander"},{"Id":5,"Name":"charmeleon"},{"Id":6,"Name":"charizard"},{"Id":7,"Name":"squirtle"},{"Id":8,"Name":"wartortle"},{"Id":9,"Name":"blastoise"},{"Id":10,"Name":"caterpie"},{"Id":11,"Name":"metapod"},{"Id":12,"Name":"butterfree"},{"Id":13,"Name":"weedle"},{"Id":14,"Name":"kakuna"},{"Id":15,"Name":"beedrill"},{"Id":16,"Name":"pidgey"},{"Id":17,"Name":"pidgeotto"},{"Id":18,"Name":"pidgeot"},{"Id":19,"Name":"rattata"},{"Id":20,"Name":"raticate"},{"Id":21,"Name":"spearow"},{"Id":22,"Name":"fearow"},{"Id":23,"Name":"ekans"},{"Id":24,"Name":"arbok"},{"Id":25,"Name":"pikachu"},{"Id":26,"Name":"raichu"},{"Id":27,"Name":"sandshrew"},{"Id":28,"Name":"sandslash"},{"Id":29,"Name":"nidoran"},{"Id":30,"Name":"nidorina"},{"Id":31,"Name":"nidoqueen"},{"Id":32,"Name":"nidoran"},{"Id":33,"Name":"nidorino"},{"Id":34,"Name":"nidoking"},{"Id":35,"Name":"clefairy"},{"Id":36,"Name":"clefable"},{"Id":37,"Name":"vulpix"},{"Id":38,"Name":"ninetales"},{"Id":39,"Name":"jigglypuff"},{"Id":40,"Name":"wigglytuff"},{"Id":41,"Name":"zubat"},{"Id":42,"Name":"golbat"},{"Id":43,"Name":"oddish"},{"Id":44,"Name":"gloom"},{"Id":45,"Name":"vileplume"},{"Id":46,"Name":"paras"},{"Id":47,"Name":"parasect"},{"Id":48,"Name":"venonat"},{"Id":49,"Name":"venomoth"},{"Id":50,"Name":"diglett"},{"Id":51,"Name":"dugtrio"},{"Id":52,"Name":"meowth"},{"Id":53,"Name":"persian"},{"Id":54,"Name":"psyduck"},{"Id":55,"Name":"golduck"},{"Id":56,"Name":"mankey"},{"Id":57,"Name":"primeape"},{"Id":58,"Name":"growlithe"},{"Id":59,"Name":"arcanine"},{"Id":60,"Name":"poliwag"},{"Id":61,"Name":"poliwhirl"},{"Id":62,"Name":"poliwrath"},{"Id":63,"Name":"abra"},{"Id":64,"Name":"kadabra"},{"Id":65,"Name":"alakazam"},{"Id":66,"Name":"machop"},{"Id":67,"Name":"machoke"},{"Id":68,"Name":"machamp"},{"Id":69,"Name":"bellsprout"},{"Id":70,"Name":"weepinbell"},{"Id":71,"Name":"victreebel"},{"Id":72,"Name":"tentacool"},{"Id":73,"Name":"tentacruel"},{"Id":74,"Name":"geodude"},{"Id":75,"Name":"graveler"},{"Id":76,"Name":"golem"},{"Id":77,"Name":"ponyta"},{"Id":78,"Name":"rapidash"},{"Id":79,"Name":"slowpoke"},{"Id":80,"Name":"slowbro"},{"Id":81,"Name":"magnemite"},{"Id":82,"Name":"magneton"},{"Id":83,"Name":"farfetchd"},{"Id":84,"Name":"doduo"},{"Id":85,"Name":"dodrio"},{"Id":86,"Name":"seel"},{"Id":87,"Name":"dewgong"},{"Id":88,"Name":"grimer"},{"Id":89,"Name":"muk"},{"Id":90,"Name":"shellder"},{"Id":91,"Name":"cloyster"},{"Id":92,"Name":"gastly"},{"Id":93,"Name":"haunter"},{"Id":94,"Name":"gengar"},{"Id":95,"Name":"onix"},{"Id":96,"Name":"drowzee"},{"Id":97,"Name":"hypno"},{"Id":98,"Name":"krabby"},{"Id":99,"Name":"kingler"},{"Id":100,"Name":"voltorb"},{"Id":101,"Name":"electrode"},{"Id":102,"Name":"exeggcute"},{"Id":103,"Name":"exeggutor"},{"Id":104,"Name":"cubone"},{"Id":105,"Name":"marowak"},{"Id":106,"Name":"hitmonlee"},{"Id":107,"Name":"hitmonchan"},{"Id":108,"Name":"lickitung"},{"Id":109,"Name":"koffing"},{"Id":110,"Name":"weezing"},{"Id":111,"Name":"rhyhorn"},{"Id":112,"Name":"rhydon"},{"Id":113,"Name":"chansey"},{"Id":114,"Name":"tangela"},{"Id":115,"Name":"kangaskhan"},{"Id":116,"Name":"horsea"},{"Id":117,"Name":"seadra"},{"Id":118,"Name":"goldeen"},{"Id":119,"Name":"seaking"},{"Id":120,"Name":"staryu"},{"Id":121,"Name":"starmie"},{"Id":122,"Name":"mr mime"},{"Id":123,"Name":"scyther"},{"Id":124,"Name":"jynx"},{"Id":125,"Name":"electabuzz"},{"Id":126,"Name":"magmar"},{"Id":127,"Name":"pinsir"},{"Id":128,"Name":"tauros"},{"Id":129,"Name":"magikarp"},{"Id":130,"Name":"gyarados"},{"Id":131,"Name":"lapras"},{"Id":132,"Name":"ditto"},{"Id":133,"Name":"eevee"},{"Id":134,"Name":"vaporeon"},{"Id":135,"Name":"jolteon"},{"Id":136,"Name":"flareon"},{"Id":137,"Name":"porygon"},{"Id":138,"Name":"omanyte"},{"Id":139,"Name":"omastar"},{"Id":140,"Name":"kabuto"},{"Id":141,"Name":"kabutops"},{"Id":142,"Name":"aerodactyl"},{"Id":143,"Name":"snorlax"},{"Id":144,"Name":"articuno"},{"Id":145,"Name":"zapdos"},{"Id":146,"Name":"moltres"},{"Id":147,"Name":"dratini"},{"Id":148,"Name":"dragonair"},{"Id":149,"Name":"dragonite"},{"Id":150,"Name":"mewtwo"},{"Id":151,"Name":"mew"},{"Id":152,"Name":"chikorita"},{"Id":153,"Name":"bayleef"},{"Id":154,"Name":"meganium"},{"Id":155,"Name":"cyndaquil"},{"Id":156,"Name":"quilava"},{"Id":157,"Name":"typhlosion"},{"Id":158,"Name":"totodile"},{"Id":159,"Name":"croconaw"},{"Id":160,"Name":"feraligatr"},{"Id":161,"Name":"sentret"},{"Id":162,"Name":"furret"},{"Id":163,"Name":"hoothoot"},{"Id":164,"Name":"noctowl"},{"Id":165,"Name":"ledyba"},{"Id":166,"Name":"ledian"},{"Id":167,"Name":"spinarak"},{"Id":168,"Name":"ariados"},{"Id":169,"Name":"crobat"},{"Id":170,"Name":"chinchou"},{"Id":171,"Name":"lanturn"},{"Id":172,"Name":"pichu"},{"Id":173,"Name":"cleffa"},{"Id":174,"Name":"igglybuff"},{"Id":175,"Name":"togepi"},{"Id":176,"Name":"togetic"},{"Id":177,"Name":"natu"},{"Id":178,"Name":"xatu"},{"Id":179,"Name":"mareep"},{"Id":180,"Name":"flaaffy"},{"Id":181,"Name":"ampharos"},{"Id":182,"Name":"bellossom"},{"Id":183,"Name":"marill"},{"Id":184,"Name":"azumarill"},{"Id":185,"Name":"sudowoodo"},{"Id":186,"Name":"politoed"},{"Id":187,"Name":"hoppip"},{"Id":188,"Name":"skiploom"},{"Id":189,"Name":"jumpluff"},{"Id":190,"Name":"aipom"},{"Id":191,"Name":"sunkern"},{"Id":192,"Name":"sunflora"},{"Id":193,"Name":"yanma"},{"Id":194,"Name":"wooper"},{"Id":195,"Name":"quagsire"},{"Id":196,"Name":"espeon"},{"Id":197,"Name":"umbreon"},{"Id":198,"Name":"murkrow"},{"Id":199,"Name":"slowking"},{"Id":200,"Name":"misdreavus"},{"Id":201,"Name":"unown"},{"Id":202,"Name":"wobbuffet"},{"Id":203,"Name":"girafarig"},{"Id":204,"Name":"pineco"},{"Id":205,"Name":"forretress"},{"Id":206,"Name":"dunsparce"},{"Id":207,"Name":"gligar"},{"Id":208,"Name":"steelix"},{"Id":209,"Name":"snubbull"},{"Id":210,"Name":"granbull"},{"Id":211,"Name":"qwilfish"},{"Id":212,"Name":"scizor"},{"Id":213,"Name":"shuckle"},{"Id":214,"Name":"heracross"},{"Id":215,"Name":"sneasel"},{"Id":216,"Name":"teddiursa"},{"Id":217,"Name":"ursaring"},{"Id":218,"Name":"slugma"},{"Id":219,"Name":"magcargo"},{"Id":220,"Name":"swinub"},{"Id":221,"Name":"piloswine"},{"Id":222,"Name":"corsola"},{"Id":223,"Name":"remoraid"},{"Id":224,"Name":"octillery"},{"Id":225,"Name":"delibird"},{"Id":226,"Name":"mantine"},{"Id":227,"Name":"skarmory"},{"Id":228,"Name":"houndour"},{"Id":229,"Name":"houndoom"},{"Id":230,"Name":"kingdra"},{"Id":231,"Name":"phanpy"},{"Id":232,"Name":"donphan"},{"Id":233,"Name":"porygon2"},{"Id":234,"Name":"stantler"},{"Id":235,"Name":"smeargle"},{"Id":236,"Name":"tyrogue"},{"Id":237,"Name":"hitmontop"},{"Id":238,"Name":"smoochum"},{"Id":239,"Name":"elekid"},{"Id":240,"Name":"magby"},{"Id":241,"Name":"miltank"},{"Id":242,"Name":"blissey"},{"Id":243,"Name":"raikou"},{"Id":244,"Name":"entei"},{"Id":245,"Name":"suicune"},{"Id":246,"Name":"larvitar"},{"Id":247,"Name":"pupitar"},{"Id":248,"Name":"tyranitar"},{"Id":249,"Name":"lugia"},{"Id":250,"Name":"ho-oh"},{"Id":251,"Name":"celebi"},{"Id":252,"Name":"treecko"},{"Id":253,"Name":"grovyle"},{"Id":254,"Name":"sceptile"},{"Id":255,"Name":"torchic"},{"Id":256,"Name":"combusken"},{"Id":257,"Name":"blaziken"},{"Id":258,"Name":"mudkip"},{"Id":259,"Name":"marshtomp"},{"Id":260,"Name":"swampert"},{"Id":261,"Name":"poochyena"},{"Id":262,"Name":"mightyena"},{"Id":263,"Name":"zigzagoon"},{"Id":264,"Name":"linoone"},{"Id":265,"Name":"wurmple"},{"Id":266,"Name":"silcoon"},{"Id":267,"Name":"beautifly"},{"Id":268,"Name":"cascoon"},{"Id":269,"Name":"dustox"},{"Id":270,"Name":"lotad"},{"Id":271,"Name":"lombre"},{"Id":272,"Name":"ludicolo"},{"Id":273,"Name":"seedot"},{"Id":274,"Name":"nuzleaf"},{"Id":275,"Name":"shiftry"},{"Id":276,"Name":"taillow"},{"Id":277,"Name":"swellow"},{"Id":278,"Name":"wingull"},{"Id":279,"Name":"pelipper"},{"Id":280,"Name":"ralts"},{"Id":281,"Name":"kirlia"},{"Id":282,"Name":"gardevoir"},{"Id":283,"Name":"surskit"},{"Id":284,"Name":"masquerain"},{"Id":285,"Name":"shroomish"},{"Id":286,"Name":"breloom"},{"Id":287,"Name":"slakoth"},{"Id":288,"Name":"vigoroth"},{"Id":289,"Name":"slaking"},{"Id":290,"Name":"nincada"},{"Id":291,"Name":"ninjask"},{"Id":292,"Name":"shedinja"},{"Id":293,"Name":"whismur"},{"Id":294,"Name":"loudred"},{"Id":295,"Name":"exploud"},{"Id":296,"Name":"makuhita"},{"Id":297,"Name":"hariyama"},{"Id":298,"Name":"azurill"},{"Id":299,"Name":"nosepass"},{"Id":300,"Name":"skitty"},{"Id":301,"Name":"delcatty"},{"Id":302,"Name":"sableye"},{"Id":303,"Name":"mawile"},{"Id":304,"Name":"aron"},{"Id":305,"Name":"lairon"},{"Id":306,"Name":"aggron"},{"Id":307,"Name":"meditite"},{"Id":308,"Name":"medicham"},{"Id":309,"Name":"electrike"},{"Id":310,"Name":"manectric"},{"Id":311,"Name":"plusle"},{"Id":312,"Name":"minun"},{"Id":313,"Name":"volbeat"},{"Id":314,"Name":"illumise"},{"Id":315,"Name":"roselia"},{"Id":316,"Name":"gulpin"},{"Id":317,"Name":"swalot"},{"Id":318,"Name":"carvanha"},{"Id":319,"Name":"sharpedo"},{"Id":320,"Name":"wailmer"},{"Id":321,"Name":"wailord"},{"Id":322,"Name":"numel"},{"Id":323,"Name":"camerupt"},{"Id":324,"Name":"torkoal"},{"Id":325,"Name":"spoink"},{"Id":326,"Name":"grumpig"},{"Id":327,"Name":"spinda"},{"Id":328,"Name":"trapinch"},{"Id":329,"Name":"vibrava"},{"Id":330,"Name":"flygon"},{"Id":331,"Name":"cacnea"},{"Id":332,"Name":"cacturne"},{"Id":333,"Name":"swablu"},{"Id":334,"Name":"altaria"},{"Id":335,"Name":"zangoose"},{"Id":336,"Name":"seviper"},{"Id":337,"Name":"lunatone"},{"Id":338,"Name":"solrock"},{"Id":339,"Name":"barboach"},{"Id":340,"Name":"whiscash"},{"Id":341,"Name":"corphish"},{"Id":342,"Name":"crawdaunt"},{"Id":343,"Name":"baltoy"},{"Id":344,"Name":"claydol"},{"Id":345,"Name":"lileep"},{"Id":346,"Name":"cradily"},{"Id":347,"Name":"anorith"},{"Id":348,"Name":"armaldo"},{"Id":349,"Name":"feebas"},{"Id":350,"Name":"milotic"},{"Id":351,"Name":"castform"},{"Id":352,"Name":"kecleon"},{"Id":353,"Name":"shuppet"},{"Id":354,"Name":"banette"},{"Id":355,"Name":"duskull"},{"Id":356,"Name":"dusclops"},{"Id":357,"Name":"tropius"},{"Id":358,"Name":"chimecho"},{"Id":359,"Name":"absol"},{"Id":360,"Name":"wynaut"},{"Id":361,"Name":"snorunt"},{"Id":362,"Name":"glalie"},{"Id":363,"Name":"spheal"},{"Id":364,"Name":"sealeo"},{"Id":365,"Name":"walrein"},{"Id":366,"Name":"clamperl"},{"Id":367,"Name":"huntail"},{"Id":368,"Name":"gorebyss"},{"Id":369,"Name":"relicanth"},{"Id":370,"Name":"luvdisc"},{"Id":371,"Name":"bagon"},{"Id":372,"Name":"shelgon"},{"Id":373,"Name":"salamence"},{"Id":374,"Name":"beldum"},{"Id":375,"Name":"metang"},{"Id":376,"Name":"metagross"},{"Id":377,"Name":"regirock"},{"Id":378,"Name":"regice"},{"Id":379,"Name":"registeel"},{"Id":380,"Name":"latias"},{"Id":381,"Name":"latios"},{"Id":382,"Name":"kyogre"},{"Id":383,"Name":"groudon"},{"Id":384,"Name":"rayquaza"},{"Id":385,"Name":"jirachi"},{"Id":386,"Name":"deoxys"},{"Id":387,"Name":"turtwig"},{"Id":388,"Name":"grotle"},{"Id":389,"Name":"torterra"},{"Id":390,"Name":"chimchar"},{"Id":391,"Name":"monferno"},{"Id":392,"Name":"infernape"},{"Id":393,"Name":"piplup"},{"Id":394,"Name":"prinplup"},{"Id":395,"Name":"empoleon"},{"Id":396,"Name":"starly"},{"Id":397,"Name":"staravia"},{"Id":398,"Name":"staraptor"},{"Id":399,"Name":"bidoof"},{"Id":400,"Name":"bibarel"},{"Id":401,"Name":"kricketot"},{"Id":402,"Name":"kricketune"},{"Id":403,"Name":"shinx"},{"Id":404,"Name":"luxio"},{"Id":405,"Name":"luxray"},{"Id":406,"Name":"budew"},{"Id":407,"Name":"roserade"},{"Id":408,"Name":"cranidos"},{"Id":409,"Name":"rampardos"},{"Id":410,"Name":"shieldon"},{"Id":411,"Name":"bastiodon"},{"Id":412,"Name":"burmy"},{"Id":413,"Name":"wormadam"},{"Id":414,"Name":"mothim"},{"Id":415,"Name":"combee"},{"Id":416,"Name":"vespiquen"},{"Id":417,"Name":"pachirisu"},{"Id":418,"Name":"buizel"},{"Id":419,"Name":"floatzel"},{"Id":420,"Name":"cherubi"},{"Id":421,"Name":"cherrim"},{"Id":422,"Name":"shellos"},{"Id":423,"Name":"gastrodon"},{"Id":424,"Name":"ambipom"},{"Id":425,"Name":"drifloon"},{"Id":426,"Name":"drifblim"},{"Id":427,"Name":"buneary"},{"Id":428,"Name":"lopunny"},{"Id":429,"Name":"mismagius"},{"Id":430,"Name":"honchkrow"},{"Id":431,"Name":"glameow"},{"Id":432,"Name":"purugly"},{"Id":433,"Name":"chingling"},{"Id":434,"Name":"stunky"},{"Id":435,"Name":"skuntank"},{"Id":436,"Name":"bronzor"},{"Id":437,"Name":"bronzong"},{"Id":438,"Name":"bonsly"},{"Id":439,"Name":"mime jr"},{"Id":440,"Name":"happiny"},{"Id":441,"Name":"chatot"},{"Id":442,"Name":"spiritomb"},{"Id":443,"Name":"gible"},{"Id":444,"Name":"gabite"},{"Id":445,"Name":"garchomp"},{"Id":446,"Name":"munchlax"},{"Id":447,"Name":"riolu"},{"Id":448,"Name":"lucario"},{"Id":449,"Name":"hippopotas"},{"Id":450,"Name":"hippowdon"},{"Id":451,"Name":"skorupi"},{"Id":452,"Name":"drapion"},{"Id":453,"Name":"croagunk"},{"Id":454,"Name":"toxicroak"},{"Id":455,"Name":"carnivine"},{"Id":456,"Name":"finneon"},{"Id":457,"Name":"lumineon"},{"Id":458,"Name":"mantyke"},{"Id":459,"Name":"snover"},{"Id":460,"Name":"abomasnow"},{"Id":461,"Name":"weavile"},{"Id":462,"Name":"magnezone"},{"Id":463,"Name":"lickilicky"},{"Id":464,"Name":"rhyperior"},{"Id":465,"Name":"tangrowth"},{"Id":466,"Name":"electivire"},{"Id":467,"Name":"magmortar"},{"Id":468,"Name":"togekiss"},{"Id":469,"Name":"yanmega"},{"Id":470,"Name":"leafeon"},{"Id":471,"Name":"glaceon"},{"Id":472,"Name":"gliscor"},{"Id":473,"Name":"mamoswine"},{"Id":474,"Name":"porygon"},{"Id":475,"Name":"gallade"},{"Id":476,"Name":"probopass"},{"Id":477,"Name":"dusknoir"},{"Id":478,"Name":"froslass"},{"Id":479,"Name":"rotom"},{"Id":480,"Name":"uxie"},{"Id":481,"Name":"mesprit"},{"Id":482,"Name":"azelf"},{"Id":483,"Name":"dialga"},{"Id":484,"Name":"palkia"},{"Id":485,"Name":"heatran"},{"Id":486,"Name":"regigigas"},{"Id":487,"Name":"giratina"},{"Id":488,"Name":"cresselia"},{"Id":489,"Name":"phione"},{"Id":490,"Name":"manaphy"},{"Id":491,"Name":"darkrai"},{"Id":492,"Name":"shaymin"},{"Id":493,"Name":"arceus"},{"Id":494,"Name":"victini"},{"Id":495,"Name":"snivy"},{"Id":496,"Name":"servine"},{"Id":497,"Name":"serperior"},{"Id":498,"Name":"tepig"},{"Id":499,"Name":"pignite"},{"Id":500,"Name":"emboar"},{"Id":501,"Name":"oshawott"},{"Id":502,"Name":"dewott"},{"Id":503,"Name":"samurott"},{"Id":504,"Name":"patrat"},{"Id":505,"Name":"watchog"},{"Id":506,"Name":"lillipup"},{"Id":507,"Name":"herdier"},{"Id":508,"Name":"stoutland"},{"Id":509,"Name":"purrloin"},{"Id":510,"Name":"liepard"},{"Id":511,"Name":"pansage"},{"Id":512,"Name":"simisage"},{"Id":513,"Name":"pansear"},{"Id":514,"Name":"simisear"},{"Id":515,"Name":"panpour"},{"Id":516,"Name":"simipour"},{"Id":517,"Name":"munna"},{"Id":518,"Name":"musharna"},{"Id":519,"Name":"pidove"},{"Id":520,"Name":"tranquill"},{"Id":521,"Name":"unfezant"},{"Id":522,"Name":"blitzle"},{"Id":523,"Name":"zebstrika"},{"Id":524,"Name":"roggenrola"},{"Id":525,"Name":"boldore"},{"Id":526,"Name":"gigalith"},{"Id":527,"Name":"woobat"},{"Id":528,"Name":"swoobat"},{"Id":529,"Name":"drilbur"},{"Id":530,"Name":"excadrill"},{"Id":531,"Name":"audino"},{"Id":532,"Name":"timburr"},{"Id":533,"Name":"gurdurr"},{"Id":534,"Name":"conkeldurr"},{"Id":535,"Name":"tympole"},{"Id":536,"Name":"palpitoad"},{"Id":537,"Name":"seismitoad"},{"Id":538,"Name":"throh"},{"Id":539,"Name":"sawk"},{"Id":540,"Name":"sewaddle"},{"Id":541,"Name":"swadloon"},{"Id":542,"Name":"leavanny"},{"Id":543,"Name":"venipede"},{"Id":544,"Name":"whirlipede"},{"Id":545,"Name":"scolipede"},{"Id":546,"Name":"cottonee"},{"Id":547,"Name":"whimsicott"},{"Id":548,"Name":"petilil"},{"Id":549,"Name":"lilligant"},{"Id":550,"Name":"basculin"},{"Id":551,"Name":"sandile"},{"Id":552,"Name":"krokorok"},{"Id":553,"Name":"krookodile"},{"Id":554,"Name":"darumaka"},{"Id":555,"Name":"darmanitan"},{"Id":556,"Name":"maractus"},{"Id":557,"Name":"dwebble"},{"Id":558,"Name":"crustle"},{"Id":559,"Name":"scraggy"},{"Id":560,"Name":"scrafty"},{"Id":561,"Name":"sigilyph"},{"Id":562,"Name":"yamask"},{"Id":563,"Name":"cofagrigus"},{"Id":564,"Name":"tirtouga"},{"Id":565,"Name":"carracosta"},{"Id":566,"Name":"archen"},{"Id":567,"Name":"archeops"},{"Id":568,"Name":"trubbish"},{"Id":569,"Name":"garbodor"},{"Id":570,"Name":"zorua"},{"Id":571,"Name":"zoroark"},{"Id":572,"Name":"minccino"},{"Id":573,"Name":"cinccino"},{"Id":574,"Name":"gothita"},{"Id":575,"Name":"gothorita"},{"Id":576,"Name":"gothitelle"},{"Id":577,"Name":"solosis"},{"Id":578,"Name":"duosion"},{"Id":579,"Name":"reuniclus"},{"Id":580,"Name":"ducklett"},{"Id":581,"Name":"swanna"},{"Id":582,"Name":"vanillite"},{"Id":583,"Name":"vanillish"},{"Id":584,"Name":"vanilluxe"},{"Id":585,"Name":"deerling"},{"Id":586,"Name":"sawsbuck"},{"Id":587,"Name":"emolga"},{"Id":588,"Name":"karrablast"},{"Id":589,"Name":"escavalier"},{"Id":590,"Name":"foongus"},{"Id":591,"Name":"amoonguss"},{"Id":592,"Name":"frillish"},{"Id":593,"Name":"jellicent"},{"Id":594,"Name":"alomomola"},{"Id":595,"Name":"joltik"},{"Id":596,"Name":"galvantula"},{"Id":597,"Name":"ferroseed"},{"Id":598,"Name":"ferrothorn"},{"Id":599,"Name":"klink"},{"Id":600,"Name":"klang"},{"Id":601,"Name":"klinklang"},{"Id":602,"Name":"tynamo"},{"Id":603,"Name":"eelektrik"},{"Id":604,"Name":"eelektross"},{"Id":605,"Name":"elgyem"},{"Id":606,"Name":"beheeyem"},{"Id":607,"Name":"litwick"},{"Id":608,"Name":"lampent"},{"Id":609,"Name":"chandelure"},{"Id":610,"Name":"axew"},{"Id":611,"Name":"fraxure"},{"Id":612,"Name":"haxorus"},{"Id":613,"Name":"cubchoo"},{"Id":614,"Name":"beartic"},{"Id":615,"Name":"cryogonal"},{"Id":616,"Name":"shelmet"},{"Id":617,"Name":"accelgor"},{"Id":618,"Name":"stunfisk"},{"Id":619,"Name":"mienfoo"},{"Id":620,"Name":"mienshao"},{"Id":621,"Name":"druddigon"},{"Id":622,"Name":"golett"},{"Id":623,"Name":"golurk"},{"Id":624,"Name":"pawniard"},{"Id":625,"Name":"bisharp"},{"Id":626,"Name":"bouffalant"},{"Id":627,"Name":"rufflet"},{"Id":628,"Name":"braviary"},{"Id":629,"Name":"vullaby"},{"Id":630,"Name":"mandibuzz"},{"Id":631,"Name":"heatmor"},{"Id":632,"Name":"durant"},{"Id":633,"Name":"deino"},{"Id":634,"Name":"zweilous"},{"Id":635,"Name":"hydreigon"},{"Id":636,"Name":"larvesta"},{"Id":637,"Name":"volcarona"},{"Id":638,"Name":"cobalion"},{"Id":639,"Name":"terrakion"},{"Id":640,"Name":"virizion"},{"Id":641,"Name":"tornadus"},{"Id":642,"Name":"thundurus"},{"Id":643,"Name":"reshiram"},{"Id":644,"Name":"zekrom"},{"Id":645,"Name":"landorus"},{"Id":646,"Name":"kyurem"},{"Id":647,"Name":"keldeo"},{"Id":648,"Name":"meloetta"},{"Id":649,"Name":"genesect"},{"Id":650,"Name":"chespin"},{"Id":651,"Name":"quilladin"},{"Id":652,"Name":"chesnaught"},{"Id":653,"Name":"fennekin"},{"Id":654,"Name":"braixen"},{"Id":655,"Name":"delphox"},{"Id":656,"Name":"froakie"},{"Id":657,"Name":"frogadier"},{"Id":658,"Name":"greninja"},{"Id":659,"Name":"bunnelby"},{"Id":660,"Name":"diggersby"},{"Id":661,"Name":"fletchling"},{"Id":662,"Name":"fletchinder"},{"Id":663,"Name":"talonflame"},{"Id":664,"Name":"scatterbug"},{"Id":665,"Name":"spewpa"},{"Id":666,"Name":"vivillon"},{"Id":667,"Name":"litleo"},{"Id":668,"Name":"pyroar"},{"Id":669,"Name":"flabebe"},{"Id":670,"Name":"floette"},{"Id":671,"Name":"florges"},{"Id":672,"Name":"skiddo"},{"Id":673,"Name":"gogoat"},{"Id":674,"Name":"pancham"},{"Id":675,"Name":"pangoro"},{"Id":676,"Name":"furfrou"},{"Id":677,"Name":"espurr"},{"Id":678,"Name":"meowstic"},{"Id":679,"Name":"honedge"},{"Id":680,"Name":"doublade"},{"Id":681,"Name":"aegislash"},{"Id":682,"Name":"spritzee"},{"Id":683,"Name":"aromatisse"},{"Id":684,"Name":"swirlix"},{"Id":685,"Name":"slurpuff"},{"Id":686,"Name":"inkay"},{"Id":687,"Name":"malamar"},{"Id":688,"Name":"binacle"},{"Id":689,"Name":"barbaracle"},{"Id":690,"Name":"skrelp"},{"Id":691,"Name":"dragalge"},{"Id":692,"Name":"clauncher"},{"Id":693,"Name":"clawitzer"},{"Id":694,"Name":"helioptile"},{"Id":695,"Name":"heliolisk"},{"Id":696,"Name":"tyrunt"},{"Id":697,"Name":"tyrantrum"},{"Id":698,"Name":"amaura"},{"Id":699,"Name":"aurorus"},{"Id":700,"Name":"sylveon"},{"Id":701,"Name":"hawlucha"},{"Id":702,"Name":"dedenne"},{"Id":703,"Name":"carbink"},{"Id":704,"Name":"goomy"},{"Id":705,"Name":"sliggoo"},{"Id":706,"Name":"goodra"},{"Id":707,"Name":"klefki"},{"Id":708,"Name":"phantump"},{"Id":709,"Name":"trevenant"},{"Id":710,"Name":"pumpkaboo"},{"Id":711,"Name":"gourgeist"},{"Id":712,"Name":"bergmite"},{"Id":713,"Name":"avalugg"},{"Id":714,"Name":"noibat"},{"Id":715,"Name":"noivern"},{"Id":716,"Name":"xerneas"},{"Id":717,"Name":"yveltal"},{"Id":718,"Name":"zygarde"},{"Id":719,"Name":"diancie"},{"Id":720,"Name":"hoopa"},{"Id":721,"Name":"volcanion"}] \ No newline at end of file From 58996b7286bfe5a152a36e7248bd420cf8808dfe Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 25 Mar 2017 09:44:17 +0100 Subject: [PATCH 619/746] another pokeman fix --- src/NadekoBot/data/pokemon/name-id_map3.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/data/pokemon/name-id_map3.json b/src/NadekoBot/data/pokemon/name-id_map3.json index 06422033..fa0b9d9c 100644 --- a/src/NadekoBot/data/pokemon/name-id_map3.json +++ b/src/NadekoBot/data/pokemon/name-id_map3.json @@ -1 +1 @@ -[{"Id":1,"Name":"bulbasaur"},{"Id":2,"Name":"ivysaur"},{"Id":3,"Name":"venusaur"},{"Id":4,"Name":"charmander"},{"Id":5,"Name":"charmeleon"},{"Id":6,"Name":"charizard"},{"Id":7,"Name":"squirtle"},{"Id":8,"Name":"wartortle"},{"Id":9,"Name":"blastoise"},{"Id":10,"Name":"caterpie"},{"Id":11,"Name":"metapod"},{"Id":12,"Name":"butterfree"},{"Id":13,"Name":"weedle"},{"Id":14,"Name":"kakuna"},{"Id":15,"Name":"beedrill"},{"Id":16,"Name":"pidgey"},{"Id":17,"Name":"pidgeotto"},{"Id":18,"Name":"pidgeot"},{"Id":19,"Name":"rattata"},{"Id":20,"Name":"raticate"},{"Id":21,"Name":"spearow"},{"Id":22,"Name":"fearow"},{"Id":23,"Name":"ekans"},{"Id":24,"Name":"arbok"},{"Id":25,"Name":"pikachu"},{"Id":26,"Name":"raichu"},{"Id":27,"Name":"sandshrew"},{"Id":28,"Name":"sandslash"},{"Id":29,"Name":"nidoran"},{"Id":30,"Name":"nidorina"},{"Id":31,"Name":"nidoqueen"},{"Id":32,"Name":"nidoran"},{"Id":33,"Name":"nidorino"},{"Id":34,"Name":"nidoking"},{"Id":35,"Name":"clefairy"},{"Id":36,"Name":"clefable"},{"Id":37,"Name":"vulpix"},{"Id":38,"Name":"ninetales"},{"Id":39,"Name":"jigglypuff"},{"Id":40,"Name":"wigglytuff"},{"Id":41,"Name":"zubat"},{"Id":42,"Name":"golbat"},{"Id":43,"Name":"oddish"},{"Id":44,"Name":"gloom"},{"Id":45,"Name":"vileplume"},{"Id":46,"Name":"paras"},{"Id":47,"Name":"parasect"},{"Id":48,"Name":"venonat"},{"Id":49,"Name":"venomoth"},{"Id":50,"Name":"diglett"},{"Id":51,"Name":"dugtrio"},{"Id":52,"Name":"meowth"},{"Id":53,"Name":"persian"},{"Id":54,"Name":"psyduck"},{"Id":55,"Name":"golduck"},{"Id":56,"Name":"mankey"},{"Id":57,"Name":"primeape"},{"Id":58,"Name":"growlithe"},{"Id":59,"Name":"arcanine"},{"Id":60,"Name":"poliwag"},{"Id":61,"Name":"poliwhirl"},{"Id":62,"Name":"poliwrath"},{"Id":63,"Name":"abra"},{"Id":64,"Name":"kadabra"},{"Id":65,"Name":"alakazam"},{"Id":66,"Name":"machop"},{"Id":67,"Name":"machoke"},{"Id":68,"Name":"machamp"},{"Id":69,"Name":"bellsprout"},{"Id":70,"Name":"weepinbell"},{"Id":71,"Name":"victreebel"},{"Id":72,"Name":"tentacool"},{"Id":73,"Name":"tentacruel"},{"Id":74,"Name":"geodude"},{"Id":75,"Name":"graveler"},{"Id":76,"Name":"golem"},{"Id":77,"Name":"ponyta"},{"Id":78,"Name":"rapidash"},{"Id":79,"Name":"slowpoke"},{"Id":80,"Name":"slowbro"},{"Id":81,"Name":"magnemite"},{"Id":82,"Name":"magneton"},{"Id":83,"Name":"farfetchd"},{"Id":84,"Name":"doduo"},{"Id":85,"Name":"dodrio"},{"Id":86,"Name":"seel"},{"Id":87,"Name":"dewgong"},{"Id":88,"Name":"grimer"},{"Id":89,"Name":"muk"},{"Id":90,"Name":"shellder"},{"Id":91,"Name":"cloyster"},{"Id":92,"Name":"gastly"},{"Id":93,"Name":"haunter"},{"Id":94,"Name":"gengar"},{"Id":95,"Name":"onix"},{"Id":96,"Name":"drowzee"},{"Id":97,"Name":"hypno"},{"Id":98,"Name":"krabby"},{"Id":99,"Name":"kingler"},{"Id":100,"Name":"voltorb"},{"Id":101,"Name":"electrode"},{"Id":102,"Name":"exeggcute"},{"Id":103,"Name":"exeggutor"},{"Id":104,"Name":"cubone"},{"Id":105,"Name":"marowak"},{"Id":106,"Name":"hitmonlee"},{"Id":107,"Name":"hitmonchan"},{"Id":108,"Name":"lickitung"},{"Id":109,"Name":"koffing"},{"Id":110,"Name":"weezing"},{"Id":111,"Name":"rhyhorn"},{"Id":112,"Name":"rhydon"},{"Id":113,"Name":"chansey"},{"Id":114,"Name":"tangela"},{"Id":115,"Name":"kangaskhan"},{"Id":116,"Name":"horsea"},{"Id":117,"Name":"seadra"},{"Id":118,"Name":"goldeen"},{"Id":119,"Name":"seaking"},{"Id":120,"Name":"staryu"},{"Id":121,"Name":"starmie"},{"Id":122,"Name":"mr mime"},{"Id":123,"Name":"scyther"},{"Id":124,"Name":"jynx"},{"Id":125,"Name":"electabuzz"},{"Id":126,"Name":"magmar"},{"Id":127,"Name":"pinsir"},{"Id":128,"Name":"tauros"},{"Id":129,"Name":"magikarp"},{"Id":130,"Name":"gyarados"},{"Id":131,"Name":"lapras"},{"Id":132,"Name":"ditto"},{"Id":133,"Name":"eevee"},{"Id":134,"Name":"vaporeon"},{"Id":135,"Name":"jolteon"},{"Id":136,"Name":"flareon"},{"Id":137,"Name":"porygon"},{"Id":138,"Name":"omanyte"},{"Id":139,"Name":"omastar"},{"Id":140,"Name":"kabuto"},{"Id":141,"Name":"kabutops"},{"Id":142,"Name":"aerodactyl"},{"Id":143,"Name":"snorlax"},{"Id":144,"Name":"articuno"},{"Id":145,"Name":"zapdos"},{"Id":146,"Name":"moltres"},{"Id":147,"Name":"dratini"},{"Id":148,"Name":"dragonair"},{"Id":149,"Name":"dragonite"},{"Id":150,"Name":"mewtwo"},{"Id":151,"Name":"mew"},{"Id":152,"Name":"chikorita"},{"Id":153,"Name":"bayleef"},{"Id":154,"Name":"meganium"},{"Id":155,"Name":"cyndaquil"},{"Id":156,"Name":"quilava"},{"Id":157,"Name":"typhlosion"},{"Id":158,"Name":"totodile"},{"Id":159,"Name":"croconaw"},{"Id":160,"Name":"feraligatr"},{"Id":161,"Name":"sentret"},{"Id":162,"Name":"furret"},{"Id":163,"Name":"hoothoot"},{"Id":164,"Name":"noctowl"},{"Id":165,"Name":"ledyba"},{"Id":166,"Name":"ledian"},{"Id":167,"Name":"spinarak"},{"Id":168,"Name":"ariados"},{"Id":169,"Name":"crobat"},{"Id":170,"Name":"chinchou"},{"Id":171,"Name":"lanturn"},{"Id":172,"Name":"pichu"},{"Id":173,"Name":"cleffa"},{"Id":174,"Name":"igglybuff"},{"Id":175,"Name":"togepi"},{"Id":176,"Name":"togetic"},{"Id":177,"Name":"natu"},{"Id":178,"Name":"xatu"},{"Id":179,"Name":"mareep"},{"Id":180,"Name":"flaaffy"},{"Id":181,"Name":"ampharos"},{"Id":182,"Name":"bellossom"},{"Id":183,"Name":"marill"},{"Id":184,"Name":"azumarill"},{"Id":185,"Name":"sudowoodo"},{"Id":186,"Name":"politoed"},{"Id":187,"Name":"hoppip"},{"Id":188,"Name":"skiploom"},{"Id":189,"Name":"jumpluff"},{"Id":190,"Name":"aipom"},{"Id":191,"Name":"sunkern"},{"Id":192,"Name":"sunflora"},{"Id":193,"Name":"yanma"},{"Id":194,"Name":"wooper"},{"Id":195,"Name":"quagsire"},{"Id":196,"Name":"espeon"},{"Id":197,"Name":"umbreon"},{"Id":198,"Name":"murkrow"},{"Id":199,"Name":"slowking"},{"Id":200,"Name":"misdreavus"},{"Id":201,"Name":"unown"},{"Id":202,"Name":"wobbuffet"},{"Id":203,"Name":"girafarig"},{"Id":204,"Name":"pineco"},{"Id":205,"Name":"forretress"},{"Id":206,"Name":"dunsparce"},{"Id":207,"Name":"gligar"},{"Id":208,"Name":"steelix"},{"Id":209,"Name":"snubbull"},{"Id":210,"Name":"granbull"},{"Id":211,"Name":"qwilfish"},{"Id":212,"Name":"scizor"},{"Id":213,"Name":"shuckle"},{"Id":214,"Name":"heracross"},{"Id":215,"Name":"sneasel"},{"Id":216,"Name":"teddiursa"},{"Id":217,"Name":"ursaring"},{"Id":218,"Name":"slugma"},{"Id":219,"Name":"magcargo"},{"Id":220,"Name":"swinub"},{"Id":221,"Name":"piloswine"},{"Id":222,"Name":"corsola"},{"Id":223,"Name":"remoraid"},{"Id":224,"Name":"octillery"},{"Id":225,"Name":"delibird"},{"Id":226,"Name":"mantine"},{"Id":227,"Name":"skarmory"},{"Id":228,"Name":"houndour"},{"Id":229,"Name":"houndoom"},{"Id":230,"Name":"kingdra"},{"Id":231,"Name":"phanpy"},{"Id":232,"Name":"donphan"},{"Id":233,"Name":"porygon2"},{"Id":234,"Name":"stantler"},{"Id":235,"Name":"smeargle"},{"Id":236,"Name":"tyrogue"},{"Id":237,"Name":"hitmontop"},{"Id":238,"Name":"smoochum"},{"Id":239,"Name":"elekid"},{"Id":240,"Name":"magby"},{"Id":241,"Name":"miltank"},{"Id":242,"Name":"blissey"},{"Id":243,"Name":"raikou"},{"Id":244,"Name":"entei"},{"Id":245,"Name":"suicune"},{"Id":246,"Name":"larvitar"},{"Id":247,"Name":"pupitar"},{"Id":248,"Name":"tyranitar"},{"Id":249,"Name":"lugia"},{"Id":250,"Name":"ho-oh"},{"Id":251,"Name":"celebi"},{"Id":252,"Name":"treecko"},{"Id":253,"Name":"grovyle"},{"Id":254,"Name":"sceptile"},{"Id":255,"Name":"torchic"},{"Id":256,"Name":"combusken"},{"Id":257,"Name":"blaziken"},{"Id":258,"Name":"mudkip"},{"Id":259,"Name":"marshtomp"},{"Id":260,"Name":"swampert"},{"Id":261,"Name":"poochyena"},{"Id":262,"Name":"mightyena"},{"Id":263,"Name":"zigzagoon"},{"Id":264,"Name":"linoone"},{"Id":265,"Name":"wurmple"},{"Id":266,"Name":"silcoon"},{"Id":267,"Name":"beautifly"},{"Id":268,"Name":"cascoon"},{"Id":269,"Name":"dustox"},{"Id":270,"Name":"lotad"},{"Id":271,"Name":"lombre"},{"Id":272,"Name":"ludicolo"},{"Id":273,"Name":"seedot"},{"Id":274,"Name":"nuzleaf"},{"Id":275,"Name":"shiftry"},{"Id":276,"Name":"taillow"},{"Id":277,"Name":"swellow"},{"Id":278,"Name":"wingull"},{"Id":279,"Name":"pelipper"},{"Id":280,"Name":"ralts"},{"Id":281,"Name":"kirlia"},{"Id":282,"Name":"gardevoir"},{"Id":283,"Name":"surskit"},{"Id":284,"Name":"masquerain"},{"Id":285,"Name":"shroomish"},{"Id":286,"Name":"breloom"},{"Id":287,"Name":"slakoth"},{"Id":288,"Name":"vigoroth"},{"Id":289,"Name":"slaking"},{"Id":290,"Name":"nincada"},{"Id":291,"Name":"ninjask"},{"Id":292,"Name":"shedinja"},{"Id":293,"Name":"whismur"},{"Id":294,"Name":"loudred"},{"Id":295,"Name":"exploud"},{"Id":296,"Name":"makuhita"},{"Id":297,"Name":"hariyama"},{"Id":298,"Name":"azurill"},{"Id":299,"Name":"nosepass"},{"Id":300,"Name":"skitty"},{"Id":301,"Name":"delcatty"},{"Id":302,"Name":"sableye"},{"Id":303,"Name":"mawile"},{"Id":304,"Name":"aron"},{"Id":305,"Name":"lairon"},{"Id":306,"Name":"aggron"},{"Id":307,"Name":"meditite"},{"Id":308,"Name":"medicham"},{"Id":309,"Name":"electrike"},{"Id":310,"Name":"manectric"},{"Id":311,"Name":"plusle"},{"Id":312,"Name":"minun"},{"Id":313,"Name":"volbeat"},{"Id":314,"Name":"illumise"},{"Id":315,"Name":"roselia"},{"Id":316,"Name":"gulpin"},{"Id":317,"Name":"swalot"},{"Id":318,"Name":"carvanha"},{"Id":319,"Name":"sharpedo"},{"Id":320,"Name":"wailmer"},{"Id":321,"Name":"wailord"},{"Id":322,"Name":"numel"},{"Id":323,"Name":"camerupt"},{"Id":324,"Name":"torkoal"},{"Id":325,"Name":"spoink"},{"Id":326,"Name":"grumpig"},{"Id":327,"Name":"spinda"},{"Id":328,"Name":"trapinch"},{"Id":329,"Name":"vibrava"},{"Id":330,"Name":"flygon"},{"Id":331,"Name":"cacnea"},{"Id":332,"Name":"cacturne"},{"Id":333,"Name":"swablu"},{"Id":334,"Name":"altaria"},{"Id":335,"Name":"zangoose"},{"Id":336,"Name":"seviper"},{"Id":337,"Name":"lunatone"},{"Id":338,"Name":"solrock"},{"Id":339,"Name":"barboach"},{"Id":340,"Name":"whiscash"},{"Id":341,"Name":"corphish"},{"Id":342,"Name":"crawdaunt"},{"Id":343,"Name":"baltoy"},{"Id":344,"Name":"claydol"},{"Id":345,"Name":"lileep"},{"Id":346,"Name":"cradily"},{"Id":347,"Name":"anorith"},{"Id":348,"Name":"armaldo"},{"Id":349,"Name":"feebas"},{"Id":350,"Name":"milotic"},{"Id":351,"Name":"castform"},{"Id":352,"Name":"kecleon"},{"Id":353,"Name":"shuppet"},{"Id":354,"Name":"banette"},{"Id":355,"Name":"duskull"},{"Id":356,"Name":"dusclops"},{"Id":357,"Name":"tropius"},{"Id":358,"Name":"chimecho"},{"Id":359,"Name":"absol"},{"Id":360,"Name":"wynaut"},{"Id":361,"Name":"snorunt"},{"Id":362,"Name":"glalie"},{"Id":363,"Name":"spheal"},{"Id":364,"Name":"sealeo"},{"Id":365,"Name":"walrein"},{"Id":366,"Name":"clamperl"},{"Id":367,"Name":"huntail"},{"Id":368,"Name":"gorebyss"},{"Id":369,"Name":"relicanth"},{"Id":370,"Name":"luvdisc"},{"Id":371,"Name":"bagon"},{"Id":372,"Name":"shelgon"},{"Id":373,"Name":"salamence"},{"Id":374,"Name":"beldum"},{"Id":375,"Name":"metang"},{"Id":376,"Name":"metagross"},{"Id":377,"Name":"regirock"},{"Id":378,"Name":"regice"},{"Id":379,"Name":"registeel"},{"Id":380,"Name":"latias"},{"Id":381,"Name":"latios"},{"Id":382,"Name":"kyogre"},{"Id":383,"Name":"groudon"},{"Id":384,"Name":"rayquaza"},{"Id":385,"Name":"jirachi"},{"Id":386,"Name":"deoxys"},{"Id":387,"Name":"turtwig"},{"Id":388,"Name":"grotle"},{"Id":389,"Name":"torterra"},{"Id":390,"Name":"chimchar"},{"Id":391,"Name":"monferno"},{"Id":392,"Name":"infernape"},{"Id":393,"Name":"piplup"},{"Id":394,"Name":"prinplup"},{"Id":395,"Name":"empoleon"},{"Id":396,"Name":"starly"},{"Id":397,"Name":"staravia"},{"Id":398,"Name":"staraptor"},{"Id":399,"Name":"bidoof"},{"Id":400,"Name":"bibarel"},{"Id":401,"Name":"kricketot"},{"Id":402,"Name":"kricketune"},{"Id":403,"Name":"shinx"},{"Id":404,"Name":"luxio"},{"Id":405,"Name":"luxray"},{"Id":406,"Name":"budew"},{"Id":407,"Name":"roserade"},{"Id":408,"Name":"cranidos"},{"Id":409,"Name":"rampardos"},{"Id":410,"Name":"shieldon"},{"Id":411,"Name":"bastiodon"},{"Id":412,"Name":"burmy"},{"Id":413,"Name":"wormadam"},{"Id":414,"Name":"mothim"},{"Id":415,"Name":"combee"},{"Id":416,"Name":"vespiquen"},{"Id":417,"Name":"pachirisu"},{"Id":418,"Name":"buizel"},{"Id":419,"Name":"floatzel"},{"Id":420,"Name":"cherubi"},{"Id":421,"Name":"cherrim"},{"Id":422,"Name":"shellos"},{"Id":423,"Name":"gastrodon"},{"Id":424,"Name":"ambipom"},{"Id":425,"Name":"drifloon"},{"Id":426,"Name":"drifblim"},{"Id":427,"Name":"buneary"},{"Id":428,"Name":"lopunny"},{"Id":429,"Name":"mismagius"},{"Id":430,"Name":"honchkrow"},{"Id":431,"Name":"glameow"},{"Id":432,"Name":"purugly"},{"Id":433,"Name":"chingling"},{"Id":434,"Name":"stunky"},{"Id":435,"Name":"skuntank"},{"Id":436,"Name":"bronzor"},{"Id":437,"Name":"bronzong"},{"Id":438,"Name":"bonsly"},{"Id":439,"Name":"mime jr"},{"Id":440,"Name":"happiny"},{"Id":441,"Name":"chatot"},{"Id":442,"Name":"spiritomb"},{"Id":443,"Name":"gible"},{"Id":444,"Name":"gabite"},{"Id":445,"Name":"garchomp"},{"Id":446,"Name":"munchlax"},{"Id":447,"Name":"riolu"},{"Id":448,"Name":"lucario"},{"Id":449,"Name":"hippopotas"},{"Id":450,"Name":"hippowdon"},{"Id":451,"Name":"skorupi"},{"Id":452,"Name":"drapion"},{"Id":453,"Name":"croagunk"},{"Id":454,"Name":"toxicroak"},{"Id":455,"Name":"carnivine"},{"Id":456,"Name":"finneon"},{"Id":457,"Name":"lumineon"},{"Id":458,"Name":"mantyke"},{"Id":459,"Name":"snover"},{"Id":460,"Name":"abomasnow"},{"Id":461,"Name":"weavile"},{"Id":462,"Name":"magnezone"},{"Id":463,"Name":"lickilicky"},{"Id":464,"Name":"rhyperior"},{"Id":465,"Name":"tangrowth"},{"Id":466,"Name":"electivire"},{"Id":467,"Name":"magmortar"},{"Id":468,"Name":"togekiss"},{"Id":469,"Name":"yanmega"},{"Id":470,"Name":"leafeon"},{"Id":471,"Name":"glaceon"},{"Id":472,"Name":"gliscor"},{"Id":473,"Name":"mamoswine"},{"Id":474,"Name":"porygon"},{"Id":475,"Name":"gallade"},{"Id":476,"Name":"probopass"},{"Id":477,"Name":"dusknoir"},{"Id":478,"Name":"froslass"},{"Id":479,"Name":"rotom"},{"Id":480,"Name":"uxie"},{"Id":481,"Name":"mesprit"},{"Id":482,"Name":"azelf"},{"Id":483,"Name":"dialga"},{"Id":484,"Name":"palkia"},{"Id":485,"Name":"heatran"},{"Id":486,"Name":"regigigas"},{"Id":487,"Name":"giratina"},{"Id":488,"Name":"cresselia"},{"Id":489,"Name":"phione"},{"Id":490,"Name":"manaphy"},{"Id":491,"Name":"darkrai"},{"Id":492,"Name":"shaymin"},{"Id":493,"Name":"arceus"},{"Id":494,"Name":"victini"},{"Id":495,"Name":"snivy"},{"Id":496,"Name":"servine"},{"Id":497,"Name":"serperior"},{"Id":498,"Name":"tepig"},{"Id":499,"Name":"pignite"},{"Id":500,"Name":"emboar"},{"Id":501,"Name":"oshawott"},{"Id":502,"Name":"dewott"},{"Id":503,"Name":"samurott"},{"Id":504,"Name":"patrat"},{"Id":505,"Name":"watchog"},{"Id":506,"Name":"lillipup"},{"Id":507,"Name":"herdier"},{"Id":508,"Name":"stoutland"},{"Id":509,"Name":"purrloin"},{"Id":510,"Name":"liepard"},{"Id":511,"Name":"pansage"},{"Id":512,"Name":"simisage"},{"Id":513,"Name":"pansear"},{"Id":514,"Name":"simisear"},{"Id":515,"Name":"panpour"},{"Id":516,"Name":"simipour"},{"Id":517,"Name":"munna"},{"Id":518,"Name":"musharna"},{"Id":519,"Name":"pidove"},{"Id":520,"Name":"tranquill"},{"Id":521,"Name":"unfezant"},{"Id":522,"Name":"blitzle"},{"Id":523,"Name":"zebstrika"},{"Id":524,"Name":"roggenrola"},{"Id":525,"Name":"boldore"},{"Id":526,"Name":"gigalith"},{"Id":527,"Name":"woobat"},{"Id":528,"Name":"swoobat"},{"Id":529,"Name":"drilbur"},{"Id":530,"Name":"excadrill"},{"Id":531,"Name":"audino"},{"Id":532,"Name":"timburr"},{"Id":533,"Name":"gurdurr"},{"Id":534,"Name":"conkeldurr"},{"Id":535,"Name":"tympole"},{"Id":536,"Name":"palpitoad"},{"Id":537,"Name":"seismitoad"},{"Id":538,"Name":"throh"},{"Id":539,"Name":"sawk"},{"Id":540,"Name":"sewaddle"},{"Id":541,"Name":"swadloon"},{"Id":542,"Name":"leavanny"},{"Id":543,"Name":"venipede"},{"Id":544,"Name":"whirlipede"},{"Id":545,"Name":"scolipede"},{"Id":546,"Name":"cottonee"},{"Id":547,"Name":"whimsicott"},{"Id":548,"Name":"petilil"},{"Id":549,"Name":"lilligant"},{"Id":550,"Name":"basculin"},{"Id":551,"Name":"sandile"},{"Id":552,"Name":"krokorok"},{"Id":553,"Name":"krookodile"},{"Id":554,"Name":"darumaka"},{"Id":555,"Name":"darmanitan"},{"Id":556,"Name":"maractus"},{"Id":557,"Name":"dwebble"},{"Id":558,"Name":"crustle"},{"Id":559,"Name":"scraggy"},{"Id":560,"Name":"scrafty"},{"Id":561,"Name":"sigilyph"},{"Id":562,"Name":"yamask"},{"Id":563,"Name":"cofagrigus"},{"Id":564,"Name":"tirtouga"},{"Id":565,"Name":"carracosta"},{"Id":566,"Name":"archen"},{"Id":567,"Name":"archeops"},{"Id":568,"Name":"trubbish"},{"Id":569,"Name":"garbodor"},{"Id":570,"Name":"zorua"},{"Id":571,"Name":"zoroark"},{"Id":572,"Name":"minccino"},{"Id":573,"Name":"cinccino"},{"Id":574,"Name":"gothita"},{"Id":575,"Name":"gothorita"},{"Id":576,"Name":"gothitelle"},{"Id":577,"Name":"solosis"},{"Id":578,"Name":"duosion"},{"Id":579,"Name":"reuniclus"},{"Id":580,"Name":"ducklett"},{"Id":581,"Name":"swanna"},{"Id":582,"Name":"vanillite"},{"Id":583,"Name":"vanillish"},{"Id":584,"Name":"vanilluxe"},{"Id":585,"Name":"deerling"},{"Id":586,"Name":"sawsbuck"},{"Id":587,"Name":"emolga"},{"Id":588,"Name":"karrablast"},{"Id":589,"Name":"escavalier"},{"Id":590,"Name":"foongus"},{"Id":591,"Name":"amoonguss"},{"Id":592,"Name":"frillish"},{"Id":593,"Name":"jellicent"},{"Id":594,"Name":"alomomola"},{"Id":595,"Name":"joltik"},{"Id":596,"Name":"galvantula"},{"Id":597,"Name":"ferroseed"},{"Id":598,"Name":"ferrothorn"},{"Id":599,"Name":"klink"},{"Id":600,"Name":"klang"},{"Id":601,"Name":"klinklang"},{"Id":602,"Name":"tynamo"},{"Id":603,"Name":"eelektrik"},{"Id":604,"Name":"eelektross"},{"Id":605,"Name":"elgyem"},{"Id":606,"Name":"beheeyem"},{"Id":607,"Name":"litwick"},{"Id":608,"Name":"lampent"},{"Id":609,"Name":"chandelure"},{"Id":610,"Name":"axew"},{"Id":611,"Name":"fraxure"},{"Id":612,"Name":"haxorus"},{"Id":613,"Name":"cubchoo"},{"Id":614,"Name":"beartic"},{"Id":615,"Name":"cryogonal"},{"Id":616,"Name":"shelmet"},{"Id":617,"Name":"accelgor"},{"Id":618,"Name":"stunfisk"},{"Id":619,"Name":"mienfoo"},{"Id":620,"Name":"mienshao"},{"Id":621,"Name":"druddigon"},{"Id":622,"Name":"golett"},{"Id":623,"Name":"golurk"},{"Id":624,"Name":"pawniard"},{"Id":625,"Name":"bisharp"},{"Id":626,"Name":"bouffalant"},{"Id":627,"Name":"rufflet"},{"Id":628,"Name":"braviary"},{"Id":629,"Name":"vullaby"},{"Id":630,"Name":"mandibuzz"},{"Id":631,"Name":"heatmor"},{"Id":632,"Name":"durant"},{"Id":633,"Name":"deino"},{"Id":634,"Name":"zweilous"},{"Id":635,"Name":"hydreigon"},{"Id":636,"Name":"larvesta"},{"Id":637,"Name":"volcarona"},{"Id":638,"Name":"cobalion"},{"Id":639,"Name":"terrakion"},{"Id":640,"Name":"virizion"},{"Id":641,"Name":"tornadus"},{"Id":642,"Name":"thundurus"},{"Id":643,"Name":"reshiram"},{"Id":644,"Name":"zekrom"},{"Id":645,"Name":"landorus"},{"Id":646,"Name":"kyurem"},{"Id":647,"Name":"keldeo"},{"Id":648,"Name":"meloetta"},{"Id":649,"Name":"genesect"},{"Id":650,"Name":"chespin"},{"Id":651,"Name":"quilladin"},{"Id":652,"Name":"chesnaught"},{"Id":653,"Name":"fennekin"},{"Id":654,"Name":"braixen"},{"Id":655,"Name":"delphox"},{"Id":656,"Name":"froakie"},{"Id":657,"Name":"frogadier"},{"Id":658,"Name":"greninja"},{"Id":659,"Name":"bunnelby"},{"Id":660,"Name":"diggersby"},{"Id":661,"Name":"fletchling"},{"Id":662,"Name":"fletchinder"},{"Id":663,"Name":"talonflame"},{"Id":664,"Name":"scatterbug"},{"Id":665,"Name":"spewpa"},{"Id":666,"Name":"vivillon"},{"Id":667,"Name":"litleo"},{"Id":668,"Name":"pyroar"},{"Id":669,"Name":"flabebe"},{"Id":670,"Name":"floette"},{"Id":671,"Name":"florges"},{"Id":672,"Name":"skiddo"},{"Id":673,"Name":"gogoat"},{"Id":674,"Name":"pancham"},{"Id":675,"Name":"pangoro"},{"Id":676,"Name":"furfrou"},{"Id":677,"Name":"espurr"},{"Id":678,"Name":"meowstic"},{"Id":679,"Name":"honedge"},{"Id":680,"Name":"doublade"},{"Id":681,"Name":"aegislash"},{"Id":682,"Name":"spritzee"},{"Id":683,"Name":"aromatisse"},{"Id":684,"Name":"swirlix"},{"Id":685,"Name":"slurpuff"},{"Id":686,"Name":"inkay"},{"Id":687,"Name":"malamar"},{"Id":688,"Name":"binacle"},{"Id":689,"Name":"barbaracle"},{"Id":690,"Name":"skrelp"},{"Id":691,"Name":"dragalge"},{"Id":692,"Name":"clauncher"},{"Id":693,"Name":"clawitzer"},{"Id":694,"Name":"helioptile"},{"Id":695,"Name":"heliolisk"},{"Id":696,"Name":"tyrunt"},{"Id":697,"Name":"tyrantrum"},{"Id":698,"Name":"amaura"},{"Id":699,"Name":"aurorus"},{"Id":700,"Name":"sylveon"},{"Id":701,"Name":"hawlucha"},{"Id":702,"Name":"dedenne"},{"Id":703,"Name":"carbink"},{"Id":704,"Name":"goomy"},{"Id":705,"Name":"sliggoo"},{"Id":706,"Name":"goodra"},{"Id":707,"Name":"klefki"},{"Id":708,"Name":"phantump"},{"Id":709,"Name":"trevenant"},{"Id":710,"Name":"pumpkaboo"},{"Id":711,"Name":"gourgeist"},{"Id":712,"Name":"bergmite"},{"Id":713,"Name":"avalugg"},{"Id":714,"Name":"noibat"},{"Id":715,"Name":"noivern"},{"Id":716,"Name":"xerneas"},{"Id":717,"Name":"yveltal"},{"Id":718,"Name":"zygarde"},{"Id":719,"Name":"diancie"},{"Id":720,"Name":"hoopa"},{"Id":721,"Name":"volcanion"}] \ No newline at end of file +[{"Id":1,"Name":"bulbasaur"},{"Id":2,"Name":"ivysaur"},{"Id":3,"Name":"venusaur"},{"Id":4,"Name":"charmander"},{"Id":5,"Name":"charmeleon"},{"Id":6,"Name":"charizard"},{"Id":7,"Name":"squirtle"},{"Id":8,"Name":"wartortle"},{"Id":9,"Name":"blastoise"},{"Id":10,"Name":"caterpie"},{"Id":11,"Name":"metapod"},{"Id":12,"Name":"butterfree"},{"Id":13,"Name":"weedle"},{"Id":14,"Name":"kakuna"},{"Id":15,"Name":"beedrill"},{"Id":16,"Name":"pidgey"},{"Id":17,"Name":"pidgeotto"},{"Id":18,"Name":"pidgeot"},{"Id":19,"Name":"rattata"},{"Id":20,"Name":"raticate"},{"Id":21,"Name":"spearow"},{"Id":22,"Name":"fearow"},{"Id":23,"Name":"ekans"},{"Id":24,"Name":"arbok"},{"Id":25,"Name":"pikachu"},{"Id":26,"Name":"raichu"},{"Id":27,"Name":"sandshrew"},{"Id":28,"Name":"sandslash"},{"Id":29,"Name":"nidoran"},{"Id":30,"Name":"nidorina"},{"Id":31,"Name":"nidoqueen"},{"Id":32,"Name":"nidoran"},{"Id":33,"Name":"nidorino"},{"Id":34,"Name":"nidoking"},{"Id":35,"Name":"clefairy"},{"Id":36,"Name":"clefable"},{"Id":37,"Name":"vulpix"},{"Id":38,"Name":"ninetales"},{"Id":39,"Name":"jigglypuff"},{"Id":40,"Name":"wigglytuff"},{"Id":41,"Name":"zubat"},{"Id":42,"Name":"golbat"},{"Id":43,"Name":"oddish"},{"Id":44,"Name":"gloom"},{"Id":45,"Name":"vileplume"},{"Id":46,"Name":"paras"},{"Id":47,"Name":"parasect"},{"Id":48,"Name":"venonat"},{"Id":49,"Name":"venomoth"},{"Id":50,"Name":"diglett"},{"Id":51,"Name":"dugtrio"},{"Id":52,"Name":"meowth"},{"Id":53,"Name":"persian"},{"Id":54,"Name":"psyduck"},{"Id":55,"Name":"golduck"},{"Id":56,"Name":"mankey"},{"Id":57,"Name":"primeape"},{"Id":58,"Name":"growlithe"},{"Id":59,"Name":"arcanine"},{"Id":60,"Name":"poliwag"},{"Id":61,"Name":"poliwhirl"},{"Id":62,"Name":"poliwrath"},{"Id":63,"Name":"abra"},{"Id":64,"Name":"kadabra"},{"Id":65,"Name":"alakazam"},{"Id":66,"Name":"machop"},{"Id":67,"Name":"machoke"},{"Id":68,"Name":"machamp"},{"Id":69,"Name":"bellsprout"},{"Id":70,"Name":"weepinbell"},{"Id":71,"Name":"victreebel"},{"Id":72,"Name":"tentacool"},{"Id":73,"Name":"tentacruel"},{"Id":74,"Name":"geodude"},{"Id":75,"Name":"graveler"},{"Id":76,"Name":"golem"},{"Id":77,"Name":"ponyta"},{"Id":78,"Name":"rapidash"},{"Id":79,"Name":"slowpoke"},{"Id":80,"Name":"slowbro"},{"Id":81,"Name":"magnemite"},{"Id":82,"Name":"magneton"},{"Id":83,"Name":"farfetchd"},{"Id":84,"Name":"doduo"},{"Id":85,"Name":"dodrio"},{"Id":86,"Name":"seel"},{"Id":87,"Name":"dewgong"},{"Id":88,"Name":"grimer"},{"Id":89,"Name":"muk"},{"Id":90,"Name":"shellder"},{"Id":91,"Name":"cloyster"},{"Id":92,"Name":"gastly"},{"Id":93,"Name":"haunter"},{"Id":94,"Name":"gengar"},{"Id":95,"Name":"onix"},{"Id":96,"Name":"drowzee"},{"Id":97,"Name":"hypno"},{"Id":98,"Name":"krabby"},{"Id":99,"Name":"kingler"},{"Id":100,"Name":"voltorb"},{"Id":101,"Name":"electrode"},{"Id":102,"Name":"exeggcute"},{"Id":103,"Name":"exeggutor"},{"Id":104,"Name":"cubone"},{"Id":105,"Name":"marowak"},{"Id":106,"Name":"hitmonlee"},{"Id":107,"Name":"hitmonchan"},{"Id":108,"Name":"lickitung"},{"Id":109,"Name":"koffing"},{"Id":110,"Name":"weezing"},{"Id":111,"Name":"rhyhorn"},{"Id":112,"Name":"rhydon"},{"Id":113,"Name":"chansey"},{"Id":114,"Name":"tangela"},{"Id":115,"Name":"kangaskhan"},{"Id":116,"Name":"horsea"},{"Id":117,"Name":"seadra"},{"Id":118,"Name":"goldeen"},{"Id":119,"Name":"seaking"},{"Id":120,"Name":"staryu"},{"Id":121,"Name":"starmie"},{"Id":122,"Name":"mr mime"},{"Id":123,"Name":"scyther"},{"Id":124,"Name":"jynx"},{"Id":125,"Name":"electabuzz"},{"Id":126,"Name":"magmar"},{"Id":127,"Name":"pinsir"},{"Id":128,"Name":"tauros"},{"Id":129,"Name":"magikarp"},{"Id":130,"Name":"gyarados"},{"Id":131,"Name":"lapras"},{"Id":132,"Name":"ditto"},{"Id":133,"Name":"eevee"},{"Id":134,"Name":"vaporeon"},{"Id":135,"Name":"jolteon"},{"Id":136,"Name":"flareon"},{"Id":137,"Name":"porygon z"},{"Id":138,"Name":"omanyte"},{"Id":139,"Name":"omastar"},{"Id":140,"Name":"kabuto"},{"Id":141,"Name":"kabutops"},{"Id":142,"Name":"aerodactyl"},{"Id":143,"Name":"snorlax"},{"Id":144,"Name":"articuno"},{"Id":145,"Name":"zapdos"},{"Id":146,"Name":"moltres"},{"Id":147,"Name":"dratini"},{"Id":148,"Name":"dragonair"},{"Id":149,"Name":"dragonite"},{"Id":150,"Name":"mewtwo"},{"Id":151,"Name":"mew"},{"Id":152,"Name":"chikorita"},{"Id":153,"Name":"bayleef"},{"Id":154,"Name":"meganium"},{"Id":155,"Name":"cyndaquil"},{"Id":156,"Name":"quilava"},{"Id":157,"Name":"typhlosion"},{"Id":158,"Name":"totodile"},{"Id":159,"Name":"croconaw"},{"Id":160,"Name":"feraligatr"},{"Id":161,"Name":"sentret"},{"Id":162,"Name":"furret"},{"Id":163,"Name":"hoothoot"},{"Id":164,"Name":"noctowl"},{"Id":165,"Name":"ledyba"},{"Id":166,"Name":"ledian"},{"Id":167,"Name":"spinarak"},{"Id":168,"Name":"ariados"},{"Id":169,"Name":"crobat"},{"Id":170,"Name":"chinchou"},{"Id":171,"Name":"lanturn"},{"Id":172,"Name":"pichu"},{"Id":173,"Name":"cleffa"},{"Id":174,"Name":"igglybuff"},{"Id":175,"Name":"togepi"},{"Id":176,"Name":"togetic"},{"Id":177,"Name":"natu"},{"Id":178,"Name":"xatu"},{"Id":179,"Name":"mareep"},{"Id":180,"Name":"flaaffy"},{"Id":181,"Name":"ampharos"},{"Id":182,"Name":"bellossom"},{"Id":183,"Name":"marill"},{"Id":184,"Name":"azumarill"},{"Id":185,"Name":"sudowoodo"},{"Id":186,"Name":"politoed"},{"Id":187,"Name":"hoppip"},{"Id":188,"Name":"skiploom"},{"Id":189,"Name":"jumpluff"},{"Id":190,"Name":"aipom"},{"Id":191,"Name":"sunkern"},{"Id":192,"Name":"sunflora"},{"Id":193,"Name":"yanma"},{"Id":194,"Name":"wooper"},{"Id":195,"Name":"quagsire"},{"Id":196,"Name":"espeon"},{"Id":197,"Name":"umbreon"},{"Id":198,"Name":"murkrow"},{"Id":199,"Name":"slowking"},{"Id":200,"Name":"misdreavus"},{"Id":201,"Name":"unown"},{"Id":202,"Name":"wobbuffet"},{"Id":203,"Name":"girafarig"},{"Id":204,"Name":"pineco"},{"Id":205,"Name":"forretress"},{"Id":206,"Name":"dunsparce"},{"Id":207,"Name":"gligar"},{"Id":208,"Name":"steelix"},{"Id":209,"Name":"snubbull"},{"Id":210,"Name":"granbull"},{"Id":211,"Name":"qwilfish"},{"Id":212,"Name":"scizor"},{"Id":213,"Name":"shuckle"},{"Id":214,"Name":"heracross"},{"Id":215,"Name":"sneasel"},{"Id":216,"Name":"teddiursa"},{"Id":217,"Name":"ursaring"},{"Id":218,"Name":"slugma"},{"Id":219,"Name":"magcargo"},{"Id":220,"Name":"swinub"},{"Id":221,"Name":"piloswine"},{"Id":222,"Name":"corsola"},{"Id":223,"Name":"remoraid"},{"Id":224,"Name":"octillery"},{"Id":225,"Name":"delibird"},{"Id":226,"Name":"mantine"},{"Id":227,"Name":"skarmory"},{"Id":228,"Name":"houndour"},{"Id":229,"Name":"houndoom"},{"Id":230,"Name":"kingdra"},{"Id":231,"Name":"phanpy"},{"Id":232,"Name":"donphan"},{"Id":233,"Name":"porygon2"},{"Id":234,"Name":"stantler"},{"Id":235,"Name":"smeargle"},{"Id":236,"Name":"tyrogue"},{"Id":237,"Name":"hitmontop"},{"Id":238,"Name":"smoochum"},{"Id":239,"Name":"elekid"},{"Id":240,"Name":"magby"},{"Id":241,"Name":"miltank"},{"Id":242,"Name":"blissey"},{"Id":243,"Name":"raikou"},{"Id":244,"Name":"entei"},{"Id":245,"Name":"suicune"},{"Id":246,"Name":"larvitar"},{"Id":247,"Name":"pupitar"},{"Id":248,"Name":"tyranitar"},{"Id":249,"Name":"lugia"},{"Id":250,"Name":"ho-oh"},{"Id":251,"Name":"celebi"},{"Id":252,"Name":"treecko"},{"Id":253,"Name":"grovyle"},{"Id":254,"Name":"sceptile"},{"Id":255,"Name":"torchic"},{"Id":256,"Name":"combusken"},{"Id":257,"Name":"blaziken"},{"Id":258,"Name":"mudkip"},{"Id":259,"Name":"marshtomp"},{"Id":260,"Name":"swampert"},{"Id":261,"Name":"poochyena"},{"Id":262,"Name":"mightyena"},{"Id":263,"Name":"zigzagoon"},{"Id":264,"Name":"linoone"},{"Id":265,"Name":"wurmple"},{"Id":266,"Name":"silcoon"},{"Id":267,"Name":"beautifly"},{"Id":268,"Name":"cascoon"},{"Id":269,"Name":"dustox"},{"Id":270,"Name":"lotad"},{"Id":271,"Name":"lombre"},{"Id":272,"Name":"ludicolo"},{"Id":273,"Name":"seedot"},{"Id":274,"Name":"nuzleaf"},{"Id":275,"Name":"shiftry"},{"Id":276,"Name":"taillow"},{"Id":277,"Name":"swellow"},{"Id":278,"Name":"wingull"},{"Id":279,"Name":"pelipper"},{"Id":280,"Name":"ralts"},{"Id":281,"Name":"kirlia"},{"Id":282,"Name":"gardevoir"},{"Id":283,"Name":"surskit"},{"Id":284,"Name":"masquerain"},{"Id":285,"Name":"shroomish"},{"Id":286,"Name":"breloom"},{"Id":287,"Name":"slakoth"},{"Id":288,"Name":"vigoroth"},{"Id":289,"Name":"slaking"},{"Id":290,"Name":"nincada"},{"Id":291,"Name":"ninjask"},{"Id":292,"Name":"shedinja"},{"Id":293,"Name":"whismur"},{"Id":294,"Name":"loudred"},{"Id":295,"Name":"exploud"},{"Id":296,"Name":"makuhita"},{"Id":297,"Name":"hariyama"},{"Id":298,"Name":"azurill"},{"Id":299,"Name":"nosepass"},{"Id":300,"Name":"skitty"},{"Id":301,"Name":"delcatty"},{"Id":302,"Name":"sableye"},{"Id":303,"Name":"mawile"},{"Id":304,"Name":"aron"},{"Id":305,"Name":"lairon"},{"Id":306,"Name":"aggron"},{"Id":307,"Name":"meditite"},{"Id":308,"Name":"medicham"},{"Id":309,"Name":"electrike"},{"Id":310,"Name":"manectric"},{"Id":311,"Name":"plusle"},{"Id":312,"Name":"minun"},{"Id":313,"Name":"volbeat"},{"Id":314,"Name":"illumise"},{"Id":315,"Name":"roselia"},{"Id":316,"Name":"gulpin"},{"Id":317,"Name":"swalot"},{"Id":318,"Name":"carvanha"},{"Id":319,"Name":"sharpedo"},{"Id":320,"Name":"wailmer"},{"Id":321,"Name":"wailord"},{"Id":322,"Name":"numel"},{"Id":323,"Name":"camerupt"},{"Id":324,"Name":"torkoal"},{"Id":325,"Name":"spoink"},{"Id":326,"Name":"grumpig"},{"Id":327,"Name":"spinda"},{"Id":328,"Name":"trapinch"},{"Id":329,"Name":"vibrava"},{"Id":330,"Name":"flygon"},{"Id":331,"Name":"cacnea"},{"Id":332,"Name":"cacturne"},{"Id":333,"Name":"swablu"},{"Id":334,"Name":"altaria"},{"Id":335,"Name":"zangoose"},{"Id":336,"Name":"seviper"},{"Id":337,"Name":"lunatone"},{"Id":338,"Name":"solrock"},{"Id":339,"Name":"barboach"},{"Id":340,"Name":"whiscash"},{"Id":341,"Name":"corphish"},{"Id":342,"Name":"crawdaunt"},{"Id":343,"Name":"baltoy"},{"Id":344,"Name":"claydol"},{"Id":345,"Name":"lileep"},{"Id":346,"Name":"cradily"},{"Id":347,"Name":"anorith"},{"Id":348,"Name":"armaldo"},{"Id":349,"Name":"feebas"},{"Id":350,"Name":"milotic"},{"Id":351,"Name":"castform"},{"Id":352,"Name":"kecleon"},{"Id":353,"Name":"shuppet"},{"Id":354,"Name":"banette"},{"Id":355,"Name":"duskull"},{"Id":356,"Name":"dusclops"},{"Id":357,"Name":"tropius"},{"Id":358,"Name":"chimecho"},{"Id":359,"Name":"absol"},{"Id":360,"Name":"wynaut"},{"Id":361,"Name":"snorunt"},{"Id":362,"Name":"glalie"},{"Id":363,"Name":"spheal"},{"Id":364,"Name":"sealeo"},{"Id":365,"Name":"walrein"},{"Id":366,"Name":"clamperl"},{"Id":367,"Name":"huntail"},{"Id":368,"Name":"gorebyss"},{"Id":369,"Name":"relicanth"},{"Id":370,"Name":"luvdisc"},{"Id":371,"Name":"bagon"},{"Id":372,"Name":"shelgon"},{"Id":373,"Name":"salamence"},{"Id":374,"Name":"beldum"},{"Id":375,"Name":"metang"},{"Id":376,"Name":"metagross"},{"Id":377,"Name":"regirock"},{"Id":378,"Name":"regice"},{"Id":379,"Name":"registeel"},{"Id":380,"Name":"latias"},{"Id":381,"Name":"latios"},{"Id":382,"Name":"kyogre"},{"Id":383,"Name":"groudon"},{"Id":384,"Name":"rayquaza"},{"Id":385,"Name":"jirachi"},{"Id":386,"Name":"deoxys"},{"Id":387,"Name":"turtwig"},{"Id":388,"Name":"grotle"},{"Id":389,"Name":"torterra"},{"Id":390,"Name":"chimchar"},{"Id":391,"Name":"monferno"},{"Id":392,"Name":"infernape"},{"Id":393,"Name":"piplup"},{"Id":394,"Name":"prinplup"},{"Id":395,"Name":"empoleon"},{"Id":396,"Name":"starly"},{"Id":397,"Name":"staravia"},{"Id":398,"Name":"staraptor"},{"Id":399,"Name":"bidoof"},{"Id":400,"Name":"bibarel"},{"Id":401,"Name":"kricketot"},{"Id":402,"Name":"kricketune"},{"Id":403,"Name":"shinx"},{"Id":404,"Name":"luxio"},{"Id":405,"Name":"luxray"},{"Id":406,"Name":"budew"},{"Id":407,"Name":"roserade"},{"Id":408,"Name":"cranidos"},{"Id":409,"Name":"rampardos"},{"Id":410,"Name":"shieldon"},{"Id":411,"Name":"bastiodon"},{"Id":412,"Name":"burmy"},{"Id":413,"Name":"wormadam"},{"Id":414,"Name":"mothim"},{"Id":415,"Name":"combee"},{"Id":416,"Name":"vespiquen"},{"Id":417,"Name":"pachirisu"},{"Id":418,"Name":"buizel"},{"Id":419,"Name":"floatzel"},{"Id":420,"Name":"cherubi"},{"Id":421,"Name":"cherrim"},{"Id":422,"Name":"shellos"},{"Id":423,"Name":"gastrodon"},{"Id":424,"Name":"ambipom"},{"Id":425,"Name":"drifloon"},{"Id":426,"Name":"drifblim"},{"Id":427,"Name":"buneary"},{"Id":428,"Name":"lopunny"},{"Id":429,"Name":"mismagius"},{"Id":430,"Name":"honchkrow"},{"Id":431,"Name":"glameow"},{"Id":432,"Name":"purugly"},{"Id":433,"Name":"chingling"},{"Id":434,"Name":"stunky"},{"Id":435,"Name":"skuntank"},{"Id":436,"Name":"bronzor"},{"Id":437,"Name":"bronzong"},{"Id":438,"Name":"bonsly"},{"Id":439,"Name":"mime jr"},{"Id":440,"Name":"happiny"},{"Id":441,"Name":"chatot"},{"Id":442,"Name":"spiritomb"},{"Id":443,"Name":"gible"},{"Id":444,"Name":"gabite"},{"Id":445,"Name":"garchomp"},{"Id":446,"Name":"munchlax"},{"Id":447,"Name":"riolu"},{"Id":448,"Name":"lucario"},{"Id":449,"Name":"hippopotas"},{"Id":450,"Name":"hippowdon"},{"Id":451,"Name":"skorupi"},{"Id":452,"Name":"drapion"},{"Id":453,"Name":"croagunk"},{"Id":454,"Name":"toxicroak"},{"Id":455,"Name":"carnivine"},{"Id":456,"Name":"finneon"},{"Id":457,"Name":"lumineon"},{"Id":458,"Name":"mantyke"},{"Id":459,"Name":"snover"},{"Id":460,"Name":"abomasnow"},{"Id":461,"Name":"weavile"},{"Id":462,"Name":"magnezone"},{"Id":463,"Name":"lickilicky"},{"Id":464,"Name":"rhyperior"},{"Id":465,"Name":"tangrowth"},{"Id":466,"Name":"electivire"},{"Id":467,"Name":"magmortar"},{"Id":468,"Name":"togekiss"},{"Id":469,"Name":"yanmega"},{"Id":470,"Name":"leafeon"},{"Id":471,"Name":"glaceon"},{"Id":472,"Name":"gliscor"},{"Id":473,"Name":"mamoswine"},{"Id":474,"Name":"porygon"},{"Id":475,"Name":"gallade"},{"Id":476,"Name":"probopass"},{"Id":477,"Name":"dusknoir"},{"Id":478,"Name":"froslass"},{"Id":479,"Name":"rotom"},{"Id":480,"Name":"uxie"},{"Id":481,"Name":"mesprit"},{"Id":482,"Name":"azelf"},{"Id":483,"Name":"dialga"},{"Id":484,"Name":"palkia"},{"Id":485,"Name":"heatran"},{"Id":486,"Name":"regigigas"},{"Id":487,"Name":"giratina"},{"Id":488,"Name":"cresselia"},{"Id":489,"Name":"phione"},{"Id":490,"Name":"manaphy"},{"Id":491,"Name":"darkrai"},{"Id":492,"Name":"shaymin"},{"Id":493,"Name":"arceus"},{"Id":494,"Name":"victini"},{"Id":495,"Name":"snivy"},{"Id":496,"Name":"servine"},{"Id":497,"Name":"serperior"},{"Id":498,"Name":"tepig"},{"Id":499,"Name":"pignite"},{"Id":500,"Name":"emboar"},{"Id":501,"Name":"oshawott"},{"Id":502,"Name":"dewott"},{"Id":503,"Name":"samurott"},{"Id":504,"Name":"patrat"},{"Id":505,"Name":"watchog"},{"Id":506,"Name":"lillipup"},{"Id":507,"Name":"herdier"},{"Id":508,"Name":"stoutland"},{"Id":509,"Name":"purrloin"},{"Id":510,"Name":"liepard"},{"Id":511,"Name":"pansage"},{"Id":512,"Name":"simisage"},{"Id":513,"Name":"pansear"},{"Id":514,"Name":"simisear"},{"Id":515,"Name":"panpour"},{"Id":516,"Name":"simipour"},{"Id":517,"Name":"munna"},{"Id":518,"Name":"musharna"},{"Id":519,"Name":"pidove"},{"Id":520,"Name":"tranquill"},{"Id":521,"Name":"unfezant"},{"Id":522,"Name":"blitzle"},{"Id":523,"Name":"zebstrika"},{"Id":524,"Name":"roggenrola"},{"Id":525,"Name":"boldore"},{"Id":526,"Name":"gigalith"},{"Id":527,"Name":"woobat"},{"Id":528,"Name":"swoobat"},{"Id":529,"Name":"drilbur"},{"Id":530,"Name":"excadrill"},{"Id":531,"Name":"audino"},{"Id":532,"Name":"timburr"},{"Id":533,"Name":"gurdurr"},{"Id":534,"Name":"conkeldurr"},{"Id":535,"Name":"tympole"},{"Id":536,"Name":"palpitoad"},{"Id":537,"Name":"seismitoad"},{"Id":538,"Name":"throh"},{"Id":539,"Name":"sawk"},{"Id":540,"Name":"sewaddle"},{"Id":541,"Name":"swadloon"},{"Id":542,"Name":"leavanny"},{"Id":543,"Name":"venipede"},{"Id":544,"Name":"whirlipede"},{"Id":545,"Name":"scolipede"},{"Id":546,"Name":"cottonee"},{"Id":547,"Name":"whimsicott"},{"Id":548,"Name":"petilil"},{"Id":549,"Name":"lilligant"},{"Id":550,"Name":"basculin"},{"Id":551,"Name":"sandile"},{"Id":552,"Name":"krokorok"},{"Id":553,"Name":"krookodile"},{"Id":554,"Name":"darumaka"},{"Id":555,"Name":"darmanitan"},{"Id":556,"Name":"maractus"},{"Id":557,"Name":"dwebble"},{"Id":558,"Name":"crustle"},{"Id":559,"Name":"scraggy"},{"Id":560,"Name":"scrafty"},{"Id":561,"Name":"sigilyph"},{"Id":562,"Name":"yamask"},{"Id":563,"Name":"cofagrigus"},{"Id":564,"Name":"tirtouga"},{"Id":565,"Name":"carracosta"},{"Id":566,"Name":"archen"},{"Id":567,"Name":"archeops"},{"Id":568,"Name":"trubbish"},{"Id":569,"Name":"garbodor"},{"Id":570,"Name":"zorua"},{"Id":571,"Name":"zoroark"},{"Id":572,"Name":"minccino"},{"Id":573,"Name":"cinccino"},{"Id":574,"Name":"gothita"},{"Id":575,"Name":"gothorita"},{"Id":576,"Name":"gothitelle"},{"Id":577,"Name":"solosis"},{"Id":578,"Name":"duosion"},{"Id":579,"Name":"reuniclus"},{"Id":580,"Name":"ducklett"},{"Id":581,"Name":"swanna"},{"Id":582,"Name":"vanillite"},{"Id":583,"Name":"vanillish"},{"Id":584,"Name":"vanilluxe"},{"Id":585,"Name":"deerling"},{"Id":586,"Name":"sawsbuck"},{"Id":587,"Name":"emolga"},{"Id":588,"Name":"karrablast"},{"Id":589,"Name":"escavalier"},{"Id":590,"Name":"foongus"},{"Id":591,"Name":"amoonguss"},{"Id":592,"Name":"frillish"},{"Id":593,"Name":"jellicent"},{"Id":594,"Name":"alomomola"},{"Id":595,"Name":"joltik"},{"Id":596,"Name":"galvantula"},{"Id":597,"Name":"ferroseed"},{"Id":598,"Name":"ferrothorn"},{"Id":599,"Name":"klink"},{"Id":600,"Name":"klang"},{"Id":601,"Name":"klinklang"},{"Id":602,"Name":"tynamo"},{"Id":603,"Name":"eelektrik"},{"Id":604,"Name":"eelektross"},{"Id":605,"Name":"elgyem"},{"Id":606,"Name":"beheeyem"},{"Id":607,"Name":"litwick"},{"Id":608,"Name":"lampent"},{"Id":609,"Name":"chandelure"},{"Id":610,"Name":"axew"},{"Id":611,"Name":"fraxure"},{"Id":612,"Name":"haxorus"},{"Id":613,"Name":"cubchoo"},{"Id":614,"Name":"beartic"},{"Id":615,"Name":"cryogonal"},{"Id":616,"Name":"shelmet"},{"Id":617,"Name":"accelgor"},{"Id":618,"Name":"stunfisk"},{"Id":619,"Name":"mienfoo"},{"Id":620,"Name":"mienshao"},{"Id":621,"Name":"druddigon"},{"Id":622,"Name":"golett"},{"Id":623,"Name":"golurk"},{"Id":624,"Name":"pawniard"},{"Id":625,"Name":"bisharp"},{"Id":626,"Name":"bouffalant"},{"Id":627,"Name":"rufflet"},{"Id":628,"Name":"braviary"},{"Id":629,"Name":"vullaby"},{"Id":630,"Name":"mandibuzz"},{"Id":631,"Name":"heatmor"},{"Id":632,"Name":"durant"},{"Id":633,"Name":"deino"},{"Id":634,"Name":"zweilous"},{"Id":635,"Name":"hydreigon"},{"Id":636,"Name":"larvesta"},{"Id":637,"Name":"volcarona"},{"Id":638,"Name":"cobalion"},{"Id":639,"Name":"terrakion"},{"Id":640,"Name":"virizion"},{"Id":641,"Name":"tornadus"},{"Id":642,"Name":"thundurus"},{"Id":643,"Name":"reshiram"},{"Id":644,"Name":"zekrom"},{"Id":645,"Name":"landorus"},{"Id":646,"Name":"kyurem"},{"Id":647,"Name":"keldeo"},{"Id":648,"Name":"meloetta"},{"Id":649,"Name":"genesect"},{"Id":650,"Name":"chespin"},{"Id":651,"Name":"quilladin"},{"Id":652,"Name":"chesnaught"},{"Id":653,"Name":"fennekin"},{"Id":654,"Name":"braixen"},{"Id":655,"Name":"delphox"},{"Id":656,"Name":"froakie"},{"Id":657,"Name":"frogadier"},{"Id":658,"Name":"greninja"},{"Id":659,"Name":"bunnelby"},{"Id":660,"Name":"diggersby"},{"Id":661,"Name":"fletchling"},{"Id":662,"Name":"fletchinder"},{"Id":663,"Name":"talonflame"},{"Id":664,"Name":"scatterbug"},{"Id":665,"Name":"spewpa"},{"Id":666,"Name":"vivillon"},{"Id":667,"Name":"litleo"},{"Id":668,"Name":"pyroar"},{"Id":669,"Name":"flabebe"},{"Id":670,"Name":"floette"},{"Id":671,"Name":"florges"},{"Id":672,"Name":"skiddo"},{"Id":673,"Name":"gogoat"},{"Id":674,"Name":"pancham"},{"Id":675,"Name":"pangoro"},{"Id":676,"Name":"furfrou"},{"Id":677,"Name":"espurr"},{"Id":678,"Name":"meowstic"},{"Id":679,"Name":"honedge"},{"Id":680,"Name":"doublade"},{"Id":681,"Name":"aegislash"},{"Id":682,"Name":"spritzee"},{"Id":683,"Name":"aromatisse"},{"Id":684,"Name":"swirlix"},{"Id":685,"Name":"slurpuff"},{"Id":686,"Name":"inkay"},{"Id":687,"Name":"malamar"},{"Id":688,"Name":"binacle"},{"Id":689,"Name":"barbaracle"},{"Id":690,"Name":"skrelp"},{"Id":691,"Name":"dragalge"},{"Id":692,"Name":"clauncher"},{"Id":693,"Name":"clawitzer"},{"Id":694,"Name":"helioptile"},{"Id":695,"Name":"heliolisk"},{"Id":696,"Name":"tyrunt"},{"Id":697,"Name":"tyrantrum"},{"Id":698,"Name":"amaura"},{"Id":699,"Name":"aurorus"},{"Id":700,"Name":"sylveon"},{"Id":701,"Name":"hawlucha"},{"Id":702,"Name":"dedenne"},{"Id":703,"Name":"carbink"},{"Id":704,"Name":"goomy"},{"Id":705,"Name":"sliggoo"},{"Id":706,"Name":"goodra"},{"Id":707,"Name":"klefki"},{"Id":708,"Name":"phantump"},{"Id":709,"Name":"trevenant"},{"Id":710,"Name":"pumpkaboo"},{"Id":711,"Name":"gourgeist"},{"Id":712,"Name":"bergmite"},{"Id":713,"Name":"avalugg"},{"Id":714,"Name":"noibat"},{"Id":715,"Name":"noivern"},{"Id":716,"Name":"xerneas"},{"Id":717,"Name":"yveltal"},{"Id":718,"Name":"zygarde"},{"Id":719,"Name":"diancie"},{"Id":720,"Name":"hoopa"},{"Id":721,"Name":"volcanion"}] \ No newline at end of file From 3604f6a2474aa29483587982398c9dbc6486a930 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Wed, 22 Mar 2017 02:08:08 -0400 Subject: [PATCH 620/746] Add quote ID to output of .qsearch --- src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index 41c29a44..ea4bc674 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -97,7 +97,7 @@ namespace NadekoBot.Modules.Utility if (keywordquote == null) return; - await Context.Channel.SendMessageAsync("💬 " + keyword.ToLowerInvariant() + ": " + + await Context.Channel.SendMessageAsync($"`#{keywordquote.Id}` 💬 " + keyword.ToLowerInvariant() + ": " + keywordquote.Text.SanitizeMentions()); } @@ -176,4 +176,4 @@ namespace NadekoBot.Modules.Utility } } } -} \ No newline at end of file +} From 529343ceb6469ebc25a9fdc3aab1796f2785126e Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Sun, 26 Mar 2017 12:16:17 -0400 Subject: [PATCH 621/746] Fix RepeatSong/RepeatPlaylist bug bug where song would be added to the queue at the last index when repeatplaylist was enabled + repeatsong, as the actionqueue events are not mutually independent --- src/NadekoBot/Modules/Music/Classes/MusicControls.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs index bf07a508..d5581884 100644 --- a/src/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/src/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -163,7 +163,7 @@ namespace NadekoBot.Modules.Music.Classes } - if (RepeatPlaylist) + if (RepeatPlaylist & !RepeatSong) AddSong(CurrentSong, CurrentSong.QueuerName); if (RepeatSong) From 683107bb9134217e708d3cd96d37f8cd99852d68 Mon Sep 17 00:00:00 2001 From: Hubcapp Date: Sun, 26 Mar 2017 21:04:09 -0500 Subject: [PATCH 622/746] Fix trailing sentences, grammar, untypable characters, and remove poor quality articles. --- src/NadekoBot/data/typing_articles.json | 164 +++++------------------- 1 file changed, 34 insertions(+), 130 deletions(-) diff --git a/src/NadekoBot/data/typing_articles.json b/src/NadekoBot/data/typing_articles.json index ab34341c..9850103f 100644 --- a/src/NadekoBot/data/typing_articles.json +++ b/src/NadekoBot/data/typing_articles.json @@ -9,7 +9,7 @@ }, { "Title":"Forensic and Legal Psychology", - "Text":"Using research in clinical, cognitive, developmental, and social psychology, Forensic and Legal Psychology shows how psychological science can enhance the gathering and presentation of evidence, improve legal decision-making, prevent crime," + "Text":"Using research in clinical, cognitive, developmental, and social psychology, Forensic and Legal Psychology shows how psychological science can enhance the gathering and presentation of evidence, improve legal decision-making, prevent crime, and other things." }, { "Title":"International Handbook of Psychology in Education", @@ -17,7 +17,7 @@ }, { "Title":"Handbook of Personality Psychology", - "Text":"This comprehensive reference work on personality psychology discusses the development and measurement of personality, biological and social determinants, dynamic personality processes, the personality's relation to the self, and personality" + "Text":"This comprehensive reference work on personality psychology discusses the development and measurement of personality, biological and social determinants, dynamic personality processes, the personality's relation to the self, and personality." }, { "Title":"Dictionary of Theories, Laws, and Concepts in Psychology", @@ -25,19 +25,7 @@ }, { "Title":"Essays on Plato's Psychology", - "Text":"With a comprehensive introduction to the major issues of Plato's psychology and an up-to-date bibliography of work on the relevant issues, this much-needed text makes the study of Plato's psychology accessible to scholars in ancient Greek" - }, - { - "Title":"Psychology Statistics For Dummies", - "Text":"As an alternative to typical, lead-heavy statistics texts or supplements to assigned course reading, this is one book psychology students won't want to be without." - }, - { - "Title":"Doing Psychology Experiments", - "Text":"David W. Martin’s unique blend of informality, humor, clear instruction, and solid scholarship make this concise text a popular choice for research methods courses in psychology." - }, - { - "Title":"A Handbook of Research Methods for Clinical and Health", - "Text":"For both undergraduate and postgraduate students, the book will be essential in making them aware of the full range of techniques available to them, helping them to design scientifically rigorous experiments." + "Text":"With a comprehensive introduction to the major issues of Plato's psychology and an up-to-date bibliography of work on the relevant issues, this much-needed text makes the study of Plato's psychology accessible to scholars in ancient Greece." }, { "Title":"A History of Psychology", @@ -57,19 +45,19 @@ }, { "Title":"Psychology and Deterrence", - "Text":"Now available in paperback, Psychology and Deterrence reveals deterrence strategy's hidden and generally simplistic assumptions about the nature of power and aggression, threat and response, and calculation and behavior in the international" + "Text":"Now available in paperback, Psychology and Deterrence reveals deterrence strategy's hidden and generally simplistic assumptions about the nature of power and aggression, threat and response, and calculation and behavior internationally." }, { "Title":"Psychology: An International Perspective", - "Text":"Unlike typical American texts, this book provides an international approach to introductory psychology, providing comprehensive and lively coverage of current research from a global perspective, including the UK, Germany, Scandinavia," + "Text":"Unlike typical American texts, this book provides an international approach to introductory psychology, providing comprehensive and lively coverage of current research from a global perspective, including the UK, Germany, Scandinavia, and probably others." }, { "Title":"Psychology, Briefer Course", - "Text":"Despite its title, 'Psychology: Briefer Course' is more than a simple condensation of the great 'Principles of Psychology." + "Text":"Despite its title, \"Psychology: Briefer Course\" is more than a simple condensation of the great Principles of Psychology." }, { "Title":"Psychology, Seventh Edition (High School)", - "Text":"This new edition continues the story of psychology with added research and enhanced content from the most dynamic areas of the field—cognition, gender and diversity studies, neuroscience and more, while at the same time using the most" + "Text":"This new edition continues the story of psychology with added research and enhanced content from the most dynamic areas of the field cognition, gender and diversity studies, neuroscience and more." }, { "Title":"Psychology of Russia: Past, Present, Future", @@ -79,25 +67,17 @@ "Title":"Barron's AP Psychology", "Text":"Provides information on scoring and structure of the test, offers tips on test-taking strategies, and includes practice examinations and subject review." }, - { - "Title":"Psychology for Inclusive Education: New Directions in", - "Text":"International in focus and at the very cutting edge of the field, this is essential reading for all those interested in the development of inclusive education." - }, { "Title":"Applied Psychology: Putting Theory Into Practice", "Text":"Applied Psychology: Putting theory into practice demonstrates how psychology theory is applied in the real world." }, - { - "Title":"The Psychology of Science: A Reconnaissance", - "Text":"' This eBook edition contains the complete 168 page text of the original 1966 hardcover edition. Contents: Preface by Abraham H. Maslow Acknowledgments 1. Mechanistic and Humanistic Science 2." - }, { "Title":"Filipino American Psychology: A Handbook of Theory,", "Text":"This book is the first of its kind and aims to promote visibility of this invisible group, so that 2.4 million Filipino Americans will have their voices heard." }, { "Title":"The Psychology of Visual Illusion", - "Text":"Well-rounded perspective on the ambiguities of visual display emphasizes geometrical optical illusions: framing and contrast effects, distortion of angles and direction, and apparent 'movement' of images. 240 drawings. 1972 edition." + "Text":"Well-rounded perspective on the ambiguities of visual display emphasizes geometrical optical illusions: framing and contrast effects, distortion of angles and direction, and apparent \"movement\" of images. 240 drawings. 1972 edition." }, { "Title":"The Psychology of Women", @@ -105,15 +85,11 @@ }, { "Title":"Psychology and Race", - "Text":"' Psychology and Race is divided into two major parts. The first half of the book looks at the interracial situation itself." - }, - { - "Title":"Psychology for A-Level", - "Text":"'Precisely targeted at AQA A Level Psychology, specification A. It will also be of interest to those who are new to psychology, and who want to get a flavour of the kinds of topics in which psychologists are interested'--Preface, p. vii." + "Text":"Psychology and Race is divided into two major parts. The first half of the book looks at the interracial situation itself. The second half is a mystery." }, { "Title":"Biological Psychology", - "Text":"Updated with new topics, examples, and recent research findings--and supported by new online bio-labs, part of the strongest media package yet--this text speaks to today’s students and instructors." + "Text":"Updated with new topics, examples, and recent research findings -- and supported by new online bio-labs, part of the strongest media package yet. This text speaks to today's students and instructors." }, { "Title":"Psychology: Concepts & Connections", @@ -121,15 +97,15 @@ }, { "Title":"The Psychology of Adoption", - "Text":"In this volume David Brodzinsky, who has conducted one of the nation's largest studies of adopted children, and Marshall Schechter, a noted child psychiatrist who has been involved with adoption related issues for over forty years, have" + "Text":"In this volume David Brodzinsky, who has conducted one of the nation's largest studies of adopted children, and Marshall Schechter, a noted child psychiatrist who has been involved with adoption related issues for over forty years, have done what was previously thought impossible." }, { "Title":"Psychology and Adult Learning", - "Text":"This new edition is thoroughly revised and updated in light of the impact of globalising processes and the application of new information technologies, and the influence of postmodernism on psychology." + "Text":"This new edition is thoroughly revised and updated in light of the impact of new processes and the application of new information technologies, and the influence of postmodernism on psychology." }, { "Title":"Gestalt Psychology: An Introduction to New Concepts in", - "Text":"The general reader, if he looks to psychology for something more than entertainment or practical advice, will discover in this book a storehouse of searching criticism and brilliant suggestions from the pen of a rare thinker, and one who" + "Text":"The general reader, if he looks to psychology for something more than entertainment or practical advice, will discover in this book a storehouse of searching criticism and brilliant suggestions from the pen of a rare thinker, and one who enjoys the smell of his own farts." }, { "Title":"The Psychology of Goals", @@ -139,29 +115,17 @@ "Title":"Metaphors in the History of Psychology", "Text":"Through the identification of these metaphors, the contributors to this volume have provided a remarkably useful guide to the history, current orientations, and future prospects of modern psychology." }, - { - "Title":"Abnormal Psychology: An Integrative Approach", - "Text":"ABNORMAL PSYCHOLOGY: AN INTEGRATIVE APPROACH, Seventh Edition, is the perfect book to help you succeed in your abnormal psychology course!" - }, - { - "Title":"Art and Visual Perception: A Psychology of the Creative Eye", - "Text":"Gestalt theory and the psychology of visual perception form the basis for an analysis of art and its basic elements" - }, { "Title":"Psychology & Christianity: Five Views", "Text":"This revised edition of a widely appreciated text now presents five models for understanding the relationship between psychology and Christianity." }, { "Title":"The Psychology of Hope: You Can Get There from Here", - "Text":"Why do some people lead positive, hope-filled lives, while others wallow in pessimism? In The Psychology of Hope, a professor of psychology reveals the specific character traits that produce highly hopeful individuals." + "Text":"Why do some people lead positive, hope-filled lives, while others wallow in pessimism? In \"The Psychology of Hope\", a professor of psychology reveals the specific character traits that produce highly hopeful individuals." }, { "Title":"Perspectives on Psychology", - "Text":"This is a title in the modular 'Principles in Psychology Series', designed for A-level and other introductory courses, aiming to provide students embarking on psychology courses with the necessary background and context." - }, - { - "Title":"Psychology the Easy Way", - "Text":"Material is presented in a way that makes these books ideal as self-teaching guides, but Easy Way titles are also preferred by many teachers as supplements to classroom textbooks." + "Text":"This is a title in the modular \"Principles in Psychology Series\", designed for A-level and other introductory courses, aiming to provide students embarking on psychology courses with the necessary background and context." }, { "Title":"Ethics in Psychology: Professional Standards and Cases", @@ -169,35 +133,23 @@ }, { "Title":"Psychology Gets in the Game: Sport, Mind, and Behavior,", - "Text":"The essays collected in this volume tell the stories not only of these psychologists and their subjects but of the social and academic context that surrounded them, shaping and being shaped by their ideas'--Provided by publisher." - }, - { - "Title":"Psychology for Physical Educators: Student in Focus", - "Text":"This updated edition focuses on attitude and motivation as important aspects of the physical education curriculum, illustrating practical ideas and pedagogical solutions for any PE setting." + "Text":"The essays collected in this volume tell the stories not only of these psychologists and their subjects but of the social and academic context that surrounded them, shaping and being shaped by their ideas." }, { "Title":"The Psychology of Leadership: New Perspectives and Research", - "Text":"In this book, some of the world's leading scholars come together to describe their thinking and research on the topic of the psychology of leadership." + "Text":"Some of the world's leading scholars came together to describe their thinking and research on the topic of the psychology of leadership." }, { "Title":"The Psychology of Interpersonal Relations", - "Text":"As the title suggests, this book examines the psychology of interpersonal relations. In the context of this book, the term 'interpersonal relations' denotes relations between a few, usually between two, people." - }, - { - "Title":"Applied Psychology", - "Text":"The chapters on Counselling Psychology and Teaching Psychology are available online via the Student Companion Site at: http://tinyurl.com/c3ztvtj The text is written to be accessible to Level 1 Introductory Psychology students, and also to" + "Text":"As the title suggests, this book examines the psychology of interpersonal relations. In the context of this book, the term \"interpersonal relations\" denotes relations between a few, usually between two, people." }, { "Title":"Psychology", "Text":"An exciting read for anyone interested in psychology and research; because of its comprehensive appendix, glossary, and reference section, this book is a must-have desk reference for psychologists and others in the field." }, - { - "Title":"The Psychology of Music", - "Text":"On interpreting musical phenomena in terms of mental function" - }, { "Title":"Abnormal Psychology", - "Text":"Ron Comer's Abnormal Psychology continues to captivate students with its integrated coverage of theory, diagnosis, and treatment, its inclusive wide-ranging cross-cultural perspective, and its compassionate emphasis on the real impact of" + "Text":"Ron Comer's Abnormal Psychology continues to captivate students with its integrated coverage of theory, diagnosis, and treatment, its inclusive wide-ranging cross-cultural perspective, and its compassionate emphasis on the real impact of hugs." }, { "Title":"The Psychology of Food Choice", @@ -205,19 +157,15 @@ }, { "Title":"Psychology: brain, behavior, & culture", - "Text":"Rather than present psychological science as a series of facts for memorization, this book takes readers on a psychological journey that uncovers things they didn't know or new ways of thinking about things they did know." + "Text":"Rather than present psychological science as a series of facts for memorization, this book takes readers on a psychological journey that uncovers things they didn't know and new ways of thinking about things they did know." }, { "Title":"A Brief History of Psychology", - "Text":"Due to its brevity and engaging style, the book is often used in introductory courses to introduce students to the field. The enormous index and substantial glossary make this volume a useful desk reference for the entire field." - }, - { - "Title":"Psychology AS: The Complete Companion", - "Text":"Presented in double-page spreads this book written to the average AS ability level, provides information on psychology in bite-sized chunks with learning and revision features." + "Text":"Due to its brevity and engaging style, this book is often used in introductory courses to introduce students to the field. The enormous index and substantial glossary make this volume a useful desk reference for the entire field." }, { "Title":"The Psychology Book: From Shamanism to Cutting-Edge", - "Text":"Lavishly illustrated, this new addition in the Sterling's Milestones series chronicles the history of psychology through 250 groundbreaking events, theories, publications, experiments and discoveries." + "Text":"Lavishly illustrated, this new addition in Sterling's Milestones series chronicles the history of psychology through 250 groundbreaking events, theories, publications, experiments and discoveries." }, { "Title":"The Psychology Book", @@ -225,15 +173,15 @@ }, { "Title":"Handbook of Positive Psychology", - "Text":"' The Handbook of Positive Psychology provides a forum for a more positive view of the human condition. In its pages, readers are treated to an analysis of what the foremost experts believe to be the fundamental strengths of humankind." + "Text":"The Handbook of Positive Psychology provides a forum for a more positive view of the human condition. In its pages, readers are treated to an analysis of what the foremost experts believe to be the fundamental strengths of humankind." }, { "Title":"Psychology of Sustainable Development", - "Text":"With contributions from an international team of policy shapers and makers, the book will be an important reference for environmental, developmental, social, and organizational psychologists, in addition to other social scientists concerned" + "Text":"With contributions from an international team of policy shapers and makers, the book will be an important reference for environmental, developmental, social, and organizational psychologists, in addition to other social scientists concerned about the environment." }, { "Title":"An Introduction to the History of Psychology", - "Text":"In this Fifth Edition, B.R. Hergenhahn demonstrates that most of the concerns of contemporary psychologists are manifestations of themes that have been part of psychology for hundreds-or even thousands-of years." + "Text":"In this Fifth Edition, B.R. Hergenhahn demonstrates that most of the concerns of contemporary psychologists are manifestations of themes that have been part of psychology for thousands of years." }, { "Title":"Careers in Psychology: Opportunities in a Changing World", @@ -241,39 +189,23 @@ }, { "Title":"Philosophy of Psychology", - "Text":"This is the story of the clattering of elevated subways and the cacophony of crowded neighborhoods, the heady optimism of industrial progress and the despair of economic recession, and the vibrancy of ethnic cultures and the resilience of" + "Text":"This is the story of the clattering of elevated subways and the cacophony of crowded neighborhoods, the heady optimism of industrial progress and the despair of economic recession, and the vibrancy of ethnic cultures and the resilience of the lower class." }, { "Title":"The Psychology of Risk Taking Behavior", "Text":"This book aims to help the reader to understand what motivates people to engage in risk taking behavior, such as participating in traffic, sports, financial investments, or courtship." }, { - "Title":"The Nazi Doctors: Medical Killing and the Psychology of", - "Text":"This book explores the psychological conditions that promote the human potential for evil, relating medical killing to broader principles of doubling and genocide" - }, - { - "Title":"The Body and Psychology", - "Text":"The material in this volume was previously published as a Special Issue of th" - }, - { - "Title":"Introduction to Psychology: Gateways to Mind and Behavior", + "Title":"Legal Notices", "Text":"Important Notice: Media content referenced within the product description or the product text may not be available in the ebook version." }, - { - "Title":"Psychology of Time", - "Text":"Basic Structure The book would contain 14 or 15 chapters of roughly 12 000 words. The exact final number of chapters would depend on further discussions with you about the book's basic structure." - }, { "Title":"Handbook of Psychology, Experimental Psychology", "Text":"Includes established theories and cutting-edge developments. Presents the work of an international group of experts. Presents the nature, origin, implications, and future course of major unresolved issues in the area." }, - { - "Title":"Study Guide for Psychology, Seventh Edition", - "Text":"This new edition continues the story of psychology with added research and enhanced content from the most dynamic areas of the field--cognition, gender and diversity studies, neuroscience and more, while at the same time using the most" - }, { "Title":"Culture and Psychology", - "Text":"In addition, the text encourages students to question traditionally held beliefs and theories as and their relevance to different cultural groups today." + "Text":"In addition, the text encourages students to question traditionally held beliefs and theories and their relevance to different cultural groups today." }, { "Title":"Exploring the Psychology of Interest", @@ -289,43 +221,23 @@ }, { "Title":"The Psychology of Social Class", - "Text":"By addressing differences in social class, the book broadens the perspective of social psychological research to examine such topics as the effect of achievement motivation and other personality variables on social mobility and the effect" - }, - { - "Title":"Applied Psychology: Current Issues and New Directions", - "Text":"Key features of this book: - Consistently pedagogical throughout - chapter summaries, questions for reflection and discussion and annotated further reading in every chapter - Comprehensive coverage - all areas of applied psychology included" + "Text":"By addressing differences in social class, the book broadens the perspective of social psychological research to examine such topics as the effect of achievement motivation, personality variables on social mobility, and the effect of winning the lottery." }, { "Title":"Popular Psychology: An Encyclopedia", "Text":"Entries cover a variety of topics in the field of popular psychology, including acupuncture, emotional intelligence, brainwashing, chemical inbalance, and seasonal affective disorder." }, - { - "Title":"Advanced Psychology: Applications, Issues and Perspectives", - "Text":"The second of two books, Advanced Psychology covers units 4 to 6 for the second year at Advanced Level." - }, - { - "Title":"Mindset: The New Psychology of Success", - "Text":"This is a book that can change your life, as its ideas have changed mine.”—Robert J. Sternberg, IBM Professor of Education and Psychology at Yale University, director of the PACE Center of Yale University, and author of Successful" - }, { "Title":"E-Z Psychology", - "Text":"This book covers material as it is taught on a college-101 level." - }, - { - "Title":"Myers' Psychology for AP*", - "Text":"Already The Bestselling AP* Psychology Author, Myers Writes His First Exclusive AP* Psych Text Watch Dave G. Myers introduce this new text here." + "Text":"This book covers material as it is taught on a college-101 level. There is no substance in this book that the casual observer of humans would not already know." }, { "Title":"Psychology and Health", "Text":"Part of a series of textbooks which have been written to support A levels in psychology. The books use real life applications to make theories come alive for students and teach them what they need to know." }, - { - "Title":"Applying Psychology in Business: The Handbook for Managers", - "Text":"To learn more about Rowman & Littlefield titles please visit us at www.rowmanlittlefield.com." - }, { "Title":"Influence", - "Text":"Influence, the classic book on persuasion, explains the psychology of why people say 'yes'—and how to apply these understandings. Dr. Robert Cialdini is the seminal expert in the rapidly expanding field of influence and persuasion." + "Text":"Influence is the classic book on persuasion. It explains the psychology of why people say 'yes' and how to apply these understandings. Dr. Robert Cialdini is the seminal expert in the rapidly expanding field of influence and persuasion." }, { "Title":"Psychology and Policing", @@ -333,11 +245,7 @@ }, { "Title":"Applied Psychology: New Frontiers and Rewarding Careers", - "Text":"This book examines how psychological science is, and can be, used to prevent and ameliorate pressing human problems to promote positive social change." - }, - { - "Title":"Psychology: Concepts and Applications", - "Text":"Nevid developed the effective teaching devices in this text based on a comprehensive system derived from research on learning and memory as well as his own research on textbook pedagogy." + "Text":"This book examines how psychological science is, and can be, used to prevent and improve pressing human problems to promote positive social change." }, { "Title":"Foundations of Sport and Exercise Psychology, 6E: ", @@ -345,7 +253,7 @@ }, { "Title":"Biographical Dictionary of Psychology", - "Text":"This Dictionary provides biographical and bibliographical information on over 500 psychologists from all over the world from 1850 to the present day. All branches of psychology and its related disciplines are featured." + "Text":"This dictionary provides biographical and bibliographical information on over 500 psychologists from all over the world from 1850 to the present day. All branches of psychology and its related disciplines are featured." }, { "Title":"Psychology: A Self-Teaching Guide", @@ -354,8 +262,4 @@ { "Title":"A Dictionary of Psychology", "Text":"Entries are extensively cross-referenced for ease of use, and cover word origins and derivations as well as definitions. Over 80 illustrations complement the text." - }, - { - "Title":"An Intellectual History of Psychology", - "Text":"Invaluable as a text for students and as a stimulating and insightful overview for scholars and practicing psychologists, this volume can be read either as a history of psychology in both its philosophical and aspiring scientific periods or" - }] \ No newline at end of file + }] From 0a32e0251e1550885a466e348a2c80b452e8eebb Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 27 Mar 2017 11:30:21 +0200 Subject: [PATCH 623/746] Fixes to pokemon names: porygon, porygon z and ho-oh --- .../Modules/Games/Commands/Trivia/TriviaQuestionPool.cs | 2 +- .../data/pokemon/{name-id_map3.json => name-id_map4.json} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/NadekoBot/data/pokemon/{name-id_map3.json => name-id_map4.json} (52%) diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs index e98830f5..ad752e95 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaQuestionPool.cs @@ -21,7 +21,7 @@ namespace NadekoBot.Modules.Games.Trivia public static TriviaQuestionPool Instance { get; } = _instance ?? (_instance = new TriviaQuestionPool()); private const string questionsFile = "data/trivia_questions.json"; - private const string pokemonMapPath = "data/pokemon/name-id_map3.json"; + private const string pokemonMapPath = "data/pokemon/name-id_map4.json"; private readonly int maxPokemonId; private Random rng { get; } = new NadekoRandom(); diff --git a/src/NadekoBot/data/pokemon/name-id_map3.json b/src/NadekoBot/data/pokemon/name-id_map4.json similarity index 52% rename from src/NadekoBot/data/pokemon/name-id_map3.json rename to src/NadekoBot/data/pokemon/name-id_map4.json index fa0b9d9c..ed6411fa 100644 --- a/src/NadekoBot/data/pokemon/name-id_map3.json +++ b/src/NadekoBot/data/pokemon/name-id_map4.json @@ -1 +1 @@ -[{"Id":1,"Name":"bulbasaur"},{"Id":2,"Name":"ivysaur"},{"Id":3,"Name":"venusaur"},{"Id":4,"Name":"charmander"},{"Id":5,"Name":"charmeleon"},{"Id":6,"Name":"charizard"},{"Id":7,"Name":"squirtle"},{"Id":8,"Name":"wartortle"},{"Id":9,"Name":"blastoise"},{"Id":10,"Name":"caterpie"},{"Id":11,"Name":"metapod"},{"Id":12,"Name":"butterfree"},{"Id":13,"Name":"weedle"},{"Id":14,"Name":"kakuna"},{"Id":15,"Name":"beedrill"},{"Id":16,"Name":"pidgey"},{"Id":17,"Name":"pidgeotto"},{"Id":18,"Name":"pidgeot"},{"Id":19,"Name":"rattata"},{"Id":20,"Name":"raticate"},{"Id":21,"Name":"spearow"},{"Id":22,"Name":"fearow"},{"Id":23,"Name":"ekans"},{"Id":24,"Name":"arbok"},{"Id":25,"Name":"pikachu"},{"Id":26,"Name":"raichu"},{"Id":27,"Name":"sandshrew"},{"Id":28,"Name":"sandslash"},{"Id":29,"Name":"nidoran"},{"Id":30,"Name":"nidorina"},{"Id":31,"Name":"nidoqueen"},{"Id":32,"Name":"nidoran"},{"Id":33,"Name":"nidorino"},{"Id":34,"Name":"nidoking"},{"Id":35,"Name":"clefairy"},{"Id":36,"Name":"clefable"},{"Id":37,"Name":"vulpix"},{"Id":38,"Name":"ninetales"},{"Id":39,"Name":"jigglypuff"},{"Id":40,"Name":"wigglytuff"},{"Id":41,"Name":"zubat"},{"Id":42,"Name":"golbat"},{"Id":43,"Name":"oddish"},{"Id":44,"Name":"gloom"},{"Id":45,"Name":"vileplume"},{"Id":46,"Name":"paras"},{"Id":47,"Name":"parasect"},{"Id":48,"Name":"venonat"},{"Id":49,"Name":"venomoth"},{"Id":50,"Name":"diglett"},{"Id":51,"Name":"dugtrio"},{"Id":52,"Name":"meowth"},{"Id":53,"Name":"persian"},{"Id":54,"Name":"psyduck"},{"Id":55,"Name":"golduck"},{"Id":56,"Name":"mankey"},{"Id":57,"Name":"primeape"},{"Id":58,"Name":"growlithe"},{"Id":59,"Name":"arcanine"},{"Id":60,"Name":"poliwag"},{"Id":61,"Name":"poliwhirl"},{"Id":62,"Name":"poliwrath"},{"Id":63,"Name":"abra"},{"Id":64,"Name":"kadabra"},{"Id":65,"Name":"alakazam"},{"Id":66,"Name":"machop"},{"Id":67,"Name":"machoke"},{"Id":68,"Name":"machamp"},{"Id":69,"Name":"bellsprout"},{"Id":70,"Name":"weepinbell"},{"Id":71,"Name":"victreebel"},{"Id":72,"Name":"tentacool"},{"Id":73,"Name":"tentacruel"},{"Id":74,"Name":"geodude"},{"Id":75,"Name":"graveler"},{"Id":76,"Name":"golem"},{"Id":77,"Name":"ponyta"},{"Id":78,"Name":"rapidash"},{"Id":79,"Name":"slowpoke"},{"Id":80,"Name":"slowbro"},{"Id":81,"Name":"magnemite"},{"Id":82,"Name":"magneton"},{"Id":83,"Name":"farfetchd"},{"Id":84,"Name":"doduo"},{"Id":85,"Name":"dodrio"},{"Id":86,"Name":"seel"},{"Id":87,"Name":"dewgong"},{"Id":88,"Name":"grimer"},{"Id":89,"Name":"muk"},{"Id":90,"Name":"shellder"},{"Id":91,"Name":"cloyster"},{"Id":92,"Name":"gastly"},{"Id":93,"Name":"haunter"},{"Id":94,"Name":"gengar"},{"Id":95,"Name":"onix"},{"Id":96,"Name":"drowzee"},{"Id":97,"Name":"hypno"},{"Id":98,"Name":"krabby"},{"Id":99,"Name":"kingler"},{"Id":100,"Name":"voltorb"},{"Id":101,"Name":"electrode"},{"Id":102,"Name":"exeggcute"},{"Id":103,"Name":"exeggutor"},{"Id":104,"Name":"cubone"},{"Id":105,"Name":"marowak"},{"Id":106,"Name":"hitmonlee"},{"Id":107,"Name":"hitmonchan"},{"Id":108,"Name":"lickitung"},{"Id":109,"Name":"koffing"},{"Id":110,"Name":"weezing"},{"Id":111,"Name":"rhyhorn"},{"Id":112,"Name":"rhydon"},{"Id":113,"Name":"chansey"},{"Id":114,"Name":"tangela"},{"Id":115,"Name":"kangaskhan"},{"Id":116,"Name":"horsea"},{"Id":117,"Name":"seadra"},{"Id":118,"Name":"goldeen"},{"Id":119,"Name":"seaking"},{"Id":120,"Name":"staryu"},{"Id":121,"Name":"starmie"},{"Id":122,"Name":"mr mime"},{"Id":123,"Name":"scyther"},{"Id":124,"Name":"jynx"},{"Id":125,"Name":"electabuzz"},{"Id":126,"Name":"magmar"},{"Id":127,"Name":"pinsir"},{"Id":128,"Name":"tauros"},{"Id":129,"Name":"magikarp"},{"Id":130,"Name":"gyarados"},{"Id":131,"Name":"lapras"},{"Id":132,"Name":"ditto"},{"Id":133,"Name":"eevee"},{"Id":134,"Name":"vaporeon"},{"Id":135,"Name":"jolteon"},{"Id":136,"Name":"flareon"},{"Id":137,"Name":"porygon z"},{"Id":138,"Name":"omanyte"},{"Id":139,"Name":"omastar"},{"Id":140,"Name":"kabuto"},{"Id":141,"Name":"kabutops"},{"Id":142,"Name":"aerodactyl"},{"Id":143,"Name":"snorlax"},{"Id":144,"Name":"articuno"},{"Id":145,"Name":"zapdos"},{"Id":146,"Name":"moltres"},{"Id":147,"Name":"dratini"},{"Id":148,"Name":"dragonair"},{"Id":149,"Name":"dragonite"},{"Id":150,"Name":"mewtwo"},{"Id":151,"Name":"mew"},{"Id":152,"Name":"chikorita"},{"Id":153,"Name":"bayleef"},{"Id":154,"Name":"meganium"},{"Id":155,"Name":"cyndaquil"},{"Id":156,"Name":"quilava"},{"Id":157,"Name":"typhlosion"},{"Id":158,"Name":"totodile"},{"Id":159,"Name":"croconaw"},{"Id":160,"Name":"feraligatr"},{"Id":161,"Name":"sentret"},{"Id":162,"Name":"furret"},{"Id":163,"Name":"hoothoot"},{"Id":164,"Name":"noctowl"},{"Id":165,"Name":"ledyba"},{"Id":166,"Name":"ledian"},{"Id":167,"Name":"spinarak"},{"Id":168,"Name":"ariados"},{"Id":169,"Name":"crobat"},{"Id":170,"Name":"chinchou"},{"Id":171,"Name":"lanturn"},{"Id":172,"Name":"pichu"},{"Id":173,"Name":"cleffa"},{"Id":174,"Name":"igglybuff"},{"Id":175,"Name":"togepi"},{"Id":176,"Name":"togetic"},{"Id":177,"Name":"natu"},{"Id":178,"Name":"xatu"},{"Id":179,"Name":"mareep"},{"Id":180,"Name":"flaaffy"},{"Id":181,"Name":"ampharos"},{"Id":182,"Name":"bellossom"},{"Id":183,"Name":"marill"},{"Id":184,"Name":"azumarill"},{"Id":185,"Name":"sudowoodo"},{"Id":186,"Name":"politoed"},{"Id":187,"Name":"hoppip"},{"Id":188,"Name":"skiploom"},{"Id":189,"Name":"jumpluff"},{"Id":190,"Name":"aipom"},{"Id":191,"Name":"sunkern"},{"Id":192,"Name":"sunflora"},{"Id":193,"Name":"yanma"},{"Id":194,"Name":"wooper"},{"Id":195,"Name":"quagsire"},{"Id":196,"Name":"espeon"},{"Id":197,"Name":"umbreon"},{"Id":198,"Name":"murkrow"},{"Id":199,"Name":"slowking"},{"Id":200,"Name":"misdreavus"},{"Id":201,"Name":"unown"},{"Id":202,"Name":"wobbuffet"},{"Id":203,"Name":"girafarig"},{"Id":204,"Name":"pineco"},{"Id":205,"Name":"forretress"},{"Id":206,"Name":"dunsparce"},{"Id":207,"Name":"gligar"},{"Id":208,"Name":"steelix"},{"Id":209,"Name":"snubbull"},{"Id":210,"Name":"granbull"},{"Id":211,"Name":"qwilfish"},{"Id":212,"Name":"scizor"},{"Id":213,"Name":"shuckle"},{"Id":214,"Name":"heracross"},{"Id":215,"Name":"sneasel"},{"Id":216,"Name":"teddiursa"},{"Id":217,"Name":"ursaring"},{"Id":218,"Name":"slugma"},{"Id":219,"Name":"magcargo"},{"Id":220,"Name":"swinub"},{"Id":221,"Name":"piloswine"},{"Id":222,"Name":"corsola"},{"Id":223,"Name":"remoraid"},{"Id":224,"Name":"octillery"},{"Id":225,"Name":"delibird"},{"Id":226,"Name":"mantine"},{"Id":227,"Name":"skarmory"},{"Id":228,"Name":"houndour"},{"Id":229,"Name":"houndoom"},{"Id":230,"Name":"kingdra"},{"Id":231,"Name":"phanpy"},{"Id":232,"Name":"donphan"},{"Id":233,"Name":"porygon2"},{"Id":234,"Name":"stantler"},{"Id":235,"Name":"smeargle"},{"Id":236,"Name":"tyrogue"},{"Id":237,"Name":"hitmontop"},{"Id":238,"Name":"smoochum"},{"Id":239,"Name":"elekid"},{"Id":240,"Name":"magby"},{"Id":241,"Name":"miltank"},{"Id":242,"Name":"blissey"},{"Id":243,"Name":"raikou"},{"Id":244,"Name":"entei"},{"Id":245,"Name":"suicune"},{"Id":246,"Name":"larvitar"},{"Id":247,"Name":"pupitar"},{"Id":248,"Name":"tyranitar"},{"Id":249,"Name":"lugia"},{"Id":250,"Name":"ho-oh"},{"Id":251,"Name":"celebi"},{"Id":252,"Name":"treecko"},{"Id":253,"Name":"grovyle"},{"Id":254,"Name":"sceptile"},{"Id":255,"Name":"torchic"},{"Id":256,"Name":"combusken"},{"Id":257,"Name":"blaziken"},{"Id":258,"Name":"mudkip"},{"Id":259,"Name":"marshtomp"},{"Id":260,"Name":"swampert"},{"Id":261,"Name":"poochyena"},{"Id":262,"Name":"mightyena"},{"Id":263,"Name":"zigzagoon"},{"Id":264,"Name":"linoone"},{"Id":265,"Name":"wurmple"},{"Id":266,"Name":"silcoon"},{"Id":267,"Name":"beautifly"},{"Id":268,"Name":"cascoon"},{"Id":269,"Name":"dustox"},{"Id":270,"Name":"lotad"},{"Id":271,"Name":"lombre"},{"Id":272,"Name":"ludicolo"},{"Id":273,"Name":"seedot"},{"Id":274,"Name":"nuzleaf"},{"Id":275,"Name":"shiftry"},{"Id":276,"Name":"taillow"},{"Id":277,"Name":"swellow"},{"Id":278,"Name":"wingull"},{"Id":279,"Name":"pelipper"},{"Id":280,"Name":"ralts"},{"Id":281,"Name":"kirlia"},{"Id":282,"Name":"gardevoir"},{"Id":283,"Name":"surskit"},{"Id":284,"Name":"masquerain"},{"Id":285,"Name":"shroomish"},{"Id":286,"Name":"breloom"},{"Id":287,"Name":"slakoth"},{"Id":288,"Name":"vigoroth"},{"Id":289,"Name":"slaking"},{"Id":290,"Name":"nincada"},{"Id":291,"Name":"ninjask"},{"Id":292,"Name":"shedinja"},{"Id":293,"Name":"whismur"},{"Id":294,"Name":"loudred"},{"Id":295,"Name":"exploud"},{"Id":296,"Name":"makuhita"},{"Id":297,"Name":"hariyama"},{"Id":298,"Name":"azurill"},{"Id":299,"Name":"nosepass"},{"Id":300,"Name":"skitty"},{"Id":301,"Name":"delcatty"},{"Id":302,"Name":"sableye"},{"Id":303,"Name":"mawile"},{"Id":304,"Name":"aron"},{"Id":305,"Name":"lairon"},{"Id":306,"Name":"aggron"},{"Id":307,"Name":"meditite"},{"Id":308,"Name":"medicham"},{"Id":309,"Name":"electrike"},{"Id":310,"Name":"manectric"},{"Id":311,"Name":"plusle"},{"Id":312,"Name":"minun"},{"Id":313,"Name":"volbeat"},{"Id":314,"Name":"illumise"},{"Id":315,"Name":"roselia"},{"Id":316,"Name":"gulpin"},{"Id":317,"Name":"swalot"},{"Id":318,"Name":"carvanha"},{"Id":319,"Name":"sharpedo"},{"Id":320,"Name":"wailmer"},{"Id":321,"Name":"wailord"},{"Id":322,"Name":"numel"},{"Id":323,"Name":"camerupt"},{"Id":324,"Name":"torkoal"},{"Id":325,"Name":"spoink"},{"Id":326,"Name":"grumpig"},{"Id":327,"Name":"spinda"},{"Id":328,"Name":"trapinch"},{"Id":329,"Name":"vibrava"},{"Id":330,"Name":"flygon"},{"Id":331,"Name":"cacnea"},{"Id":332,"Name":"cacturne"},{"Id":333,"Name":"swablu"},{"Id":334,"Name":"altaria"},{"Id":335,"Name":"zangoose"},{"Id":336,"Name":"seviper"},{"Id":337,"Name":"lunatone"},{"Id":338,"Name":"solrock"},{"Id":339,"Name":"barboach"},{"Id":340,"Name":"whiscash"},{"Id":341,"Name":"corphish"},{"Id":342,"Name":"crawdaunt"},{"Id":343,"Name":"baltoy"},{"Id":344,"Name":"claydol"},{"Id":345,"Name":"lileep"},{"Id":346,"Name":"cradily"},{"Id":347,"Name":"anorith"},{"Id":348,"Name":"armaldo"},{"Id":349,"Name":"feebas"},{"Id":350,"Name":"milotic"},{"Id":351,"Name":"castform"},{"Id":352,"Name":"kecleon"},{"Id":353,"Name":"shuppet"},{"Id":354,"Name":"banette"},{"Id":355,"Name":"duskull"},{"Id":356,"Name":"dusclops"},{"Id":357,"Name":"tropius"},{"Id":358,"Name":"chimecho"},{"Id":359,"Name":"absol"},{"Id":360,"Name":"wynaut"},{"Id":361,"Name":"snorunt"},{"Id":362,"Name":"glalie"},{"Id":363,"Name":"spheal"},{"Id":364,"Name":"sealeo"},{"Id":365,"Name":"walrein"},{"Id":366,"Name":"clamperl"},{"Id":367,"Name":"huntail"},{"Id":368,"Name":"gorebyss"},{"Id":369,"Name":"relicanth"},{"Id":370,"Name":"luvdisc"},{"Id":371,"Name":"bagon"},{"Id":372,"Name":"shelgon"},{"Id":373,"Name":"salamence"},{"Id":374,"Name":"beldum"},{"Id":375,"Name":"metang"},{"Id":376,"Name":"metagross"},{"Id":377,"Name":"regirock"},{"Id":378,"Name":"regice"},{"Id":379,"Name":"registeel"},{"Id":380,"Name":"latias"},{"Id":381,"Name":"latios"},{"Id":382,"Name":"kyogre"},{"Id":383,"Name":"groudon"},{"Id":384,"Name":"rayquaza"},{"Id":385,"Name":"jirachi"},{"Id":386,"Name":"deoxys"},{"Id":387,"Name":"turtwig"},{"Id":388,"Name":"grotle"},{"Id":389,"Name":"torterra"},{"Id":390,"Name":"chimchar"},{"Id":391,"Name":"monferno"},{"Id":392,"Name":"infernape"},{"Id":393,"Name":"piplup"},{"Id":394,"Name":"prinplup"},{"Id":395,"Name":"empoleon"},{"Id":396,"Name":"starly"},{"Id":397,"Name":"staravia"},{"Id":398,"Name":"staraptor"},{"Id":399,"Name":"bidoof"},{"Id":400,"Name":"bibarel"},{"Id":401,"Name":"kricketot"},{"Id":402,"Name":"kricketune"},{"Id":403,"Name":"shinx"},{"Id":404,"Name":"luxio"},{"Id":405,"Name":"luxray"},{"Id":406,"Name":"budew"},{"Id":407,"Name":"roserade"},{"Id":408,"Name":"cranidos"},{"Id":409,"Name":"rampardos"},{"Id":410,"Name":"shieldon"},{"Id":411,"Name":"bastiodon"},{"Id":412,"Name":"burmy"},{"Id":413,"Name":"wormadam"},{"Id":414,"Name":"mothim"},{"Id":415,"Name":"combee"},{"Id":416,"Name":"vespiquen"},{"Id":417,"Name":"pachirisu"},{"Id":418,"Name":"buizel"},{"Id":419,"Name":"floatzel"},{"Id":420,"Name":"cherubi"},{"Id":421,"Name":"cherrim"},{"Id":422,"Name":"shellos"},{"Id":423,"Name":"gastrodon"},{"Id":424,"Name":"ambipom"},{"Id":425,"Name":"drifloon"},{"Id":426,"Name":"drifblim"},{"Id":427,"Name":"buneary"},{"Id":428,"Name":"lopunny"},{"Id":429,"Name":"mismagius"},{"Id":430,"Name":"honchkrow"},{"Id":431,"Name":"glameow"},{"Id":432,"Name":"purugly"},{"Id":433,"Name":"chingling"},{"Id":434,"Name":"stunky"},{"Id":435,"Name":"skuntank"},{"Id":436,"Name":"bronzor"},{"Id":437,"Name":"bronzong"},{"Id":438,"Name":"bonsly"},{"Id":439,"Name":"mime jr"},{"Id":440,"Name":"happiny"},{"Id":441,"Name":"chatot"},{"Id":442,"Name":"spiritomb"},{"Id":443,"Name":"gible"},{"Id":444,"Name":"gabite"},{"Id":445,"Name":"garchomp"},{"Id":446,"Name":"munchlax"},{"Id":447,"Name":"riolu"},{"Id":448,"Name":"lucario"},{"Id":449,"Name":"hippopotas"},{"Id":450,"Name":"hippowdon"},{"Id":451,"Name":"skorupi"},{"Id":452,"Name":"drapion"},{"Id":453,"Name":"croagunk"},{"Id":454,"Name":"toxicroak"},{"Id":455,"Name":"carnivine"},{"Id":456,"Name":"finneon"},{"Id":457,"Name":"lumineon"},{"Id":458,"Name":"mantyke"},{"Id":459,"Name":"snover"},{"Id":460,"Name":"abomasnow"},{"Id":461,"Name":"weavile"},{"Id":462,"Name":"magnezone"},{"Id":463,"Name":"lickilicky"},{"Id":464,"Name":"rhyperior"},{"Id":465,"Name":"tangrowth"},{"Id":466,"Name":"electivire"},{"Id":467,"Name":"magmortar"},{"Id":468,"Name":"togekiss"},{"Id":469,"Name":"yanmega"},{"Id":470,"Name":"leafeon"},{"Id":471,"Name":"glaceon"},{"Id":472,"Name":"gliscor"},{"Id":473,"Name":"mamoswine"},{"Id":474,"Name":"porygon"},{"Id":475,"Name":"gallade"},{"Id":476,"Name":"probopass"},{"Id":477,"Name":"dusknoir"},{"Id":478,"Name":"froslass"},{"Id":479,"Name":"rotom"},{"Id":480,"Name":"uxie"},{"Id":481,"Name":"mesprit"},{"Id":482,"Name":"azelf"},{"Id":483,"Name":"dialga"},{"Id":484,"Name":"palkia"},{"Id":485,"Name":"heatran"},{"Id":486,"Name":"regigigas"},{"Id":487,"Name":"giratina"},{"Id":488,"Name":"cresselia"},{"Id":489,"Name":"phione"},{"Id":490,"Name":"manaphy"},{"Id":491,"Name":"darkrai"},{"Id":492,"Name":"shaymin"},{"Id":493,"Name":"arceus"},{"Id":494,"Name":"victini"},{"Id":495,"Name":"snivy"},{"Id":496,"Name":"servine"},{"Id":497,"Name":"serperior"},{"Id":498,"Name":"tepig"},{"Id":499,"Name":"pignite"},{"Id":500,"Name":"emboar"},{"Id":501,"Name":"oshawott"},{"Id":502,"Name":"dewott"},{"Id":503,"Name":"samurott"},{"Id":504,"Name":"patrat"},{"Id":505,"Name":"watchog"},{"Id":506,"Name":"lillipup"},{"Id":507,"Name":"herdier"},{"Id":508,"Name":"stoutland"},{"Id":509,"Name":"purrloin"},{"Id":510,"Name":"liepard"},{"Id":511,"Name":"pansage"},{"Id":512,"Name":"simisage"},{"Id":513,"Name":"pansear"},{"Id":514,"Name":"simisear"},{"Id":515,"Name":"panpour"},{"Id":516,"Name":"simipour"},{"Id":517,"Name":"munna"},{"Id":518,"Name":"musharna"},{"Id":519,"Name":"pidove"},{"Id":520,"Name":"tranquill"},{"Id":521,"Name":"unfezant"},{"Id":522,"Name":"blitzle"},{"Id":523,"Name":"zebstrika"},{"Id":524,"Name":"roggenrola"},{"Id":525,"Name":"boldore"},{"Id":526,"Name":"gigalith"},{"Id":527,"Name":"woobat"},{"Id":528,"Name":"swoobat"},{"Id":529,"Name":"drilbur"},{"Id":530,"Name":"excadrill"},{"Id":531,"Name":"audino"},{"Id":532,"Name":"timburr"},{"Id":533,"Name":"gurdurr"},{"Id":534,"Name":"conkeldurr"},{"Id":535,"Name":"tympole"},{"Id":536,"Name":"palpitoad"},{"Id":537,"Name":"seismitoad"},{"Id":538,"Name":"throh"},{"Id":539,"Name":"sawk"},{"Id":540,"Name":"sewaddle"},{"Id":541,"Name":"swadloon"},{"Id":542,"Name":"leavanny"},{"Id":543,"Name":"venipede"},{"Id":544,"Name":"whirlipede"},{"Id":545,"Name":"scolipede"},{"Id":546,"Name":"cottonee"},{"Id":547,"Name":"whimsicott"},{"Id":548,"Name":"petilil"},{"Id":549,"Name":"lilligant"},{"Id":550,"Name":"basculin"},{"Id":551,"Name":"sandile"},{"Id":552,"Name":"krokorok"},{"Id":553,"Name":"krookodile"},{"Id":554,"Name":"darumaka"},{"Id":555,"Name":"darmanitan"},{"Id":556,"Name":"maractus"},{"Id":557,"Name":"dwebble"},{"Id":558,"Name":"crustle"},{"Id":559,"Name":"scraggy"},{"Id":560,"Name":"scrafty"},{"Id":561,"Name":"sigilyph"},{"Id":562,"Name":"yamask"},{"Id":563,"Name":"cofagrigus"},{"Id":564,"Name":"tirtouga"},{"Id":565,"Name":"carracosta"},{"Id":566,"Name":"archen"},{"Id":567,"Name":"archeops"},{"Id":568,"Name":"trubbish"},{"Id":569,"Name":"garbodor"},{"Id":570,"Name":"zorua"},{"Id":571,"Name":"zoroark"},{"Id":572,"Name":"minccino"},{"Id":573,"Name":"cinccino"},{"Id":574,"Name":"gothita"},{"Id":575,"Name":"gothorita"},{"Id":576,"Name":"gothitelle"},{"Id":577,"Name":"solosis"},{"Id":578,"Name":"duosion"},{"Id":579,"Name":"reuniclus"},{"Id":580,"Name":"ducklett"},{"Id":581,"Name":"swanna"},{"Id":582,"Name":"vanillite"},{"Id":583,"Name":"vanillish"},{"Id":584,"Name":"vanilluxe"},{"Id":585,"Name":"deerling"},{"Id":586,"Name":"sawsbuck"},{"Id":587,"Name":"emolga"},{"Id":588,"Name":"karrablast"},{"Id":589,"Name":"escavalier"},{"Id":590,"Name":"foongus"},{"Id":591,"Name":"amoonguss"},{"Id":592,"Name":"frillish"},{"Id":593,"Name":"jellicent"},{"Id":594,"Name":"alomomola"},{"Id":595,"Name":"joltik"},{"Id":596,"Name":"galvantula"},{"Id":597,"Name":"ferroseed"},{"Id":598,"Name":"ferrothorn"},{"Id":599,"Name":"klink"},{"Id":600,"Name":"klang"},{"Id":601,"Name":"klinklang"},{"Id":602,"Name":"tynamo"},{"Id":603,"Name":"eelektrik"},{"Id":604,"Name":"eelektross"},{"Id":605,"Name":"elgyem"},{"Id":606,"Name":"beheeyem"},{"Id":607,"Name":"litwick"},{"Id":608,"Name":"lampent"},{"Id":609,"Name":"chandelure"},{"Id":610,"Name":"axew"},{"Id":611,"Name":"fraxure"},{"Id":612,"Name":"haxorus"},{"Id":613,"Name":"cubchoo"},{"Id":614,"Name":"beartic"},{"Id":615,"Name":"cryogonal"},{"Id":616,"Name":"shelmet"},{"Id":617,"Name":"accelgor"},{"Id":618,"Name":"stunfisk"},{"Id":619,"Name":"mienfoo"},{"Id":620,"Name":"mienshao"},{"Id":621,"Name":"druddigon"},{"Id":622,"Name":"golett"},{"Id":623,"Name":"golurk"},{"Id":624,"Name":"pawniard"},{"Id":625,"Name":"bisharp"},{"Id":626,"Name":"bouffalant"},{"Id":627,"Name":"rufflet"},{"Id":628,"Name":"braviary"},{"Id":629,"Name":"vullaby"},{"Id":630,"Name":"mandibuzz"},{"Id":631,"Name":"heatmor"},{"Id":632,"Name":"durant"},{"Id":633,"Name":"deino"},{"Id":634,"Name":"zweilous"},{"Id":635,"Name":"hydreigon"},{"Id":636,"Name":"larvesta"},{"Id":637,"Name":"volcarona"},{"Id":638,"Name":"cobalion"},{"Id":639,"Name":"terrakion"},{"Id":640,"Name":"virizion"},{"Id":641,"Name":"tornadus"},{"Id":642,"Name":"thundurus"},{"Id":643,"Name":"reshiram"},{"Id":644,"Name":"zekrom"},{"Id":645,"Name":"landorus"},{"Id":646,"Name":"kyurem"},{"Id":647,"Name":"keldeo"},{"Id":648,"Name":"meloetta"},{"Id":649,"Name":"genesect"},{"Id":650,"Name":"chespin"},{"Id":651,"Name":"quilladin"},{"Id":652,"Name":"chesnaught"},{"Id":653,"Name":"fennekin"},{"Id":654,"Name":"braixen"},{"Id":655,"Name":"delphox"},{"Id":656,"Name":"froakie"},{"Id":657,"Name":"frogadier"},{"Id":658,"Name":"greninja"},{"Id":659,"Name":"bunnelby"},{"Id":660,"Name":"diggersby"},{"Id":661,"Name":"fletchling"},{"Id":662,"Name":"fletchinder"},{"Id":663,"Name":"talonflame"},{"Id":664,"Name":"scatterbug"},{"Id":665,"Name":"spewpa"},{"Id":666,"Name":"vivillon"},{"Id":667,"Name":"litleo"},{"Id":668,"Name":"pyroar"},{"Id":669,"Name":"flabebe"},{"Id":670,"Name":"floette"},{"Id":671,"Name":"florges"},{"Id":672,"Name":"skiddo"},{"Id":673,"Name":"gogoat"},{"Id":674,"Name":"pancham"},{"Id":675,"Name":"pangoro"},{"Id":676,"Name":"furfrou"},{"Id":677,"Name":"espurr"},{"Id":678,"Name":"meowstic"},{"Id":679,"Name":"honedge"},{"Id":680,"Name":"doublade"},{"Id":681,"Name":"aegislash"},{"Id":682,"Name":"spritzee"},{"Id":683,"Name":"aromatisse"},{"Id":684,"Name":"swirlix"},{"Id":685,"Name":"slurpuff"},{"Id":686,"Name":"inkay"},{"Id":687,"Name":"malamar"},{"Id":688,"Name":"binacle"},{"Id":689,"Name":"barbaracle"},{"Id":690,"Name":"skrelp"},{"Id":691,"Name":"dragalge"},{"Id":692,"Name":"clauncher"},{"Id":693,"Name":"clawitzer"},{"Id":694,"Name":"helioptile"},{"Id":695,"Name":"heliolisk"},{"Id":696,"Name":"tyrunt"},{"Id":697,"Name":"tyrantrum"},{"Id":698,"Name":"amaura"},{"Id":699,"Name":"aurorus"},{"Id":700,"Name":"sylveon"},{"Id":701,"Name":"hawlucha"},{"Id":702,"Name":"dedenne"},{"Id":703,"Name":"carbink"},{"Id":704,"Name":"goomy"},{"Id":705,"Name":"sliggoo"},{"Id":706,"Name":"goodra"},{"Id":707,"Name":"klefki"},{"Id":708,"Name":"phantump"},{"Id":709,"Name":"trevenant"},{"Id":710,"Name":"pumpkaboo"},{"Id":711,"Name":"gourgeist"},{"Id":712,"Name":"bergmite"},{"Id":713,"Name":"avalugg"},{"Id":714,"Name":"noibat"},{"Id":715,"Name":"noivern"},{"Id":716,"Name":"xerneas"},{"Id":717,"Name":"yveltal"},{"Id":718,"Name":"zygarde"},{"Id":719,"Name":"diancie"},{"Id":720,"Name":"hoopa"},{"Id":721,"Name":"volcanion"}] \ No newline at end of file +[{"Id":1,"Name":"bulbasaur"},{"Id":2,"Name":"ivysaur"},{"Id":3,"Name":"venusaur"},{"Id":4,"Name":"charmander"},{"Id":5,"Name":"charmeleon"},{"Id":6,"Name":"charizard"},{"Id":7,"Name":"squirtle"},{"Id":8,"Name":"wartortle"},{"Id":9,"Name":"blastoise"},{"Id":10,"Name":"caterpie"},{"Id":11,"Name":"metapod"},{"Id":12,"Name":"butterfree"},{"Id":13,"Name":"weedle"},{"Id":14,"Name":"kakuna"},{"Id":15,"Name":"beedrill"},{"Id":16,"Name":"pidgey"},{"Id":17,"Name":"pidgeotto"},{"Id":18,"Name":"pidgeot"},{"Id":19,"Name":"rattata"},{"Id":20,"Name":"raticate"},{"Id":21,"Name":"spearow"},{"Id":22,"Name":"fearow"},{"Id":23,"Name":"ekans"},{"Id":24,"Name":"arbok"},{"Id":25,"Name":"pikachu"},{"Id":26,"Name":"raichu"},{"Id":27,"Name":"sandshrew"},{"Id":28,"Name":"sandslash"},{"Id":29,"Name":"nidoran"},{"Id":30,"Name":"nidorina"},{"Id":31,"Name":"nidoqueen"},{"Id":32,"Name":"nidoran"},{"Id":33,"Name":"nidorino"},{"Id":34,"Name":"nidoking"},{"Id":35,"Name":"clefairy"},{"Id":36,"Name":"clefable"},{"Id":37,"Name":"vulpix"},{"Id":38,"Name":"ninetales"},{"Id":39,"Name":"jigglypuff"},{"Id":40,"Name":"wigglytuff"},{"Id":41,"Name":"zubat"},{"Id":42,"Name":"golbat"},{"Id":43,"Name":"oddish"},{"Id":44,"Name":"gloom"},{"Id":45,"Name":"vileplume"},{"Id":46,"Name":"paras"},{"Id":47,"Name":"parasect"},{"Id":48,"Name":"venonat"},{"Id":49,"Name":"venomoth"},{"Id":50,"Name":"diglett"},{"Id":51,"Name":"dugtrio"},{"Id":52,"Name":"meowth"},{"Id":53,"Name":"persian"},{"Id":54,"Name":"psyduck"},{"Id":55,"Name":"golduck"},{"Id":56,"Name":"mankey"},{"Id":57,"Name":"primeape"},{"Id":58,"Name":"growlithe"},{"Id":59,"Name":"arcanine"},{"Id":60,"Name":"poliwag"},{"Id":61,"Name":"poliwhirl"},{"Id":62,"Name":"poliwrath"},{"Id":63,"Name":"abra"},{"Id":64,"Name":"kadabra"},{"Id":65,"Name":"alakazam"},{"Id":66,"Name":"machop"},{"Id":67,"Name":"machoke"},{"Id":68,"Name":"machamp"},{"Id":69,"Name":"bellsprout"},{"Id":70,"Name":"weepinbell"},{"Id":71,"Name":"victreebel"},{"Id":72,"Name":"tentacool"},{"Id":73,"Name":"tentacruel"},{"Id":74,"Name":"geodude"},{"Id":75,"Name":"graveler"},{"Id":76,"Name":"golem"},{"Id":77,"Name":"ponyta"},{"Id":78,"Name":"rapidash"},{"Id":79,"Name":"slowpoke"},{"Id":80,"Name":"slowbro"},{"Id":81,"Name":"magnemite"},{"Id":82,"Name":"magneton"},{"Id":83,"Name":"farfetchd"},{"Id":84,"Name":"doduo"},{"Id":85,"Name":"dodrio"},{"Id":86,"Name":"seel"},{"Id":87,"Name":"dewgong"},{"Id":88,"Name":"grimer"},{"Id":89,"Name":"muk"},{"Id":90,"Name":"shellder"},{"Id":91,"Name":"cloyster"},{"Id":92,"Name":"gastly"},{"Id":93,"Name":"haunter"},{"Id":94,"Name":"gengar"},{"Id":95,"Name":"onix"},{"Id":96,"Name":"drowzee"},{"Id":97,"Name":"hypno"},{"Id":98,"Name":"krabby"},{"Id":99,"Name":"kingler"},{"Id":100,"Name":"voltorb"},{"Id":101,"Name":"electrode"},{"Id":102,"Name":"exeggcute"},{"Id":103,"Name":"exeggutor"},{"Id":104,"Name":"cubone"},{"Id":105,"Name":"marowak"},{"Id":106,"Name":"hitmonlee"},{"Id":107,"Name":"hitmonchan"},{"Id":108,"Name":"lickitung"},{"Id":109,"Name":"koffing"},{"Id":110,"Name":"weezing"},{"Id":111,"Name":"rhyhorn"},{"Id":112,"Name":"rhydon"},{"Id":113,"Name":"chansey"},{"Id":114,"Name":"tangela"},{"Id":115,"Name":"kangaskhan"},{"Id":116,"Name":"horsea"},{"Id":117,"Name":"seadra"},{"Id":118,"Name":"goldeen"},{"Id":119,"Name":"seaking"},{"Id":120,"Name":"staryu"},{"Id":121,"Name":"starmie"},{"Id":122,"Name":"mr mime"},{"Id":123,"Name":"scyther"},{"Id":124,"Name":"jynx"},{"Id":125,"Name":"electabuzz"},{"Id":126,"Name":"magmar"},{"Id":127,"Name":"pinsir"},{"Id":128,"Name":"tauros"},{"Id":129,"Name":"magikarp"},{"Id":130,"Name":"gyarados"},{"Id":131,"Name":"lapras"},{"Id":132,"Name":"ditto"},{"Id":133,"Name":"eevee"},{"Id":134,"Name":"vaporeon"},{"Id":135,"Name":"jolteon"},{"Id":136,"Name":"flareon"},{"Id":137,"Name":"porygon"},{"Id":138,"Name":"omanyte"},{"Id":139,"Name":"omastar"},{"Id":140,"Name":"kabuto"},{"Id":141,"Name":"kabutops"},{"Id":142,"Name":"aerodactyl"},{"Id":143,"Name":"snorlax"},{"Id":144,"Name":"articuno"},{"Id":145,"Name":"zapdos"},{"Id":146,"Name":"moltres"},{"Id":147,"Name":"dratini"},{"Id":148,"Name":"dragonair"},{"Id":149,"Name":"dragonite"},{"Id":150,"Name":"mewtwo"},{"Id":151,"Name":"mew"},{"Id":152,"Name":"chikorita"},{"Id":153,"Name":"bayleef"},{"Id":154,"Name":"meganium"},{"Id":155,"Name":"cyndaquil"},{"Id":156,"Name":"quilava"},{"Id":157,"Name":"typhlosion"},{"Id":158,"Name":"totodile"},{"Id":159,"Name":"croconaw"},{"Id":160,"Name":"feraligatr"},{"Id":161,"Name":"sentret"},{"Id":162,"Name":"furret"},{"Id":163,"Name":"hoothoot"},{"Id":164,"Name":"noctowl"},{"Id":165,"Name":"ledyba"},{"Id":166,"Name":"ledian"},{"Id":167,"Name":"spinarak"},{"Id":168,"Name":"ariados"},{"Id":169,"Name":"crobat"},{"Id":170,"Name":"chinchou"},{"Id":171,"Name":"lanturn"},{"Id":172,"Name":"pichu"},{"Id":173,"Name":"cleffa"},{"Id":174,"Name":"igglybuff"},{"Id":175,"Name":"togepi"},{"Id":176,"Name":"togetic"},{"Id":177,"Name":"natu"},{"Id":178,"Name":"xatu"},{"Id":179,"Name":"mareep"},{"Id":180,"Name":"flaaffy"},{"Id":181,"Name":"ampharos"},{"Id":182,"Name":"bellossom"},{"Id":183,"Name":"marill"},{"Id":184,"Name":"azumarill"},{"Id":185,"Name":"sudowoodo"},{"Id":186,"Name":"politoed"},{"Id":187,"Name":"hoppip"},{"Id":188,"Name":"skiploom"},{"Id":189,"Name":"jumpluff"},{"Id":190,"Name":"aipom"},{"Id":191,"Name":"sunkern"},{"Id":192,"Name":"sunflora"},{"Id":193,"Name":"yanma"},{"Id":194,"Name":"wooper"},{"Id":195,"Name":"quagsire"},{"Id":196,"Name":"espeon"},{"Id":197,"Name":"umbreon"},{"Id":198,"Name":"murkrow"},{"Id":199,"Name":"slowking"},{"Id":200,"Name":"misdreavus"},{"Id":201,"Name":"unown"},{"Id":202,"Name":"wobbuffet"},{"Id":203,"Name":"girafarig"},{"Id":204,"Name":"pineco"},{"Id":205,"Name":"forretress"},{"Id":206,"Name":"dunsparce"},{"Id":207,"Name":"gligar"},{"Id":208,"Name":"steelix"},{"Id":209,"Name":"snubbull"},{"Id":210,"Name":"granbull"},{"Id":211,"Name":"qwilfish"},{"Id":212,"Name":"scizor"},{"Id":213,"Name":"shuckle"},{"Id":214,"Name":"heracross"},{"Id":215,"Name":"sneasel"},{"Id":216,"Name":"teddiursa"},{"Id":217,"Name":"ursaring"},{"Id":218,"Name":"slugma"},{"Id":219,"Name":"magcargo"},{"Id":220,"Name":"swinub"},{"Id":221,"Name":"piloswine"},{"Id":222,"Name":"corsola"},{"Id":223,"Name":"remoraid"},{"Id":224,"Name":"octillery"},{"Id":225,"Name":"delibird"},{"Id":226,"Name":"mantine"},{"Id":227,"Name":"skarmory"},{"Id":228,"Name":"houndour"},{"Id":229,"Name":"houndoom"},{"Id":230,"Name":"kingdra"},{"Id":231,"Name":"phanpy"},{"Id":232,"Name":"donphan"},{"Id":233,"Name":"porygon2"},{"Id":234,"Name":"stantler"},{"Id":235,"Name":"smeargle"},{"Id":236,"Name":"tyrogue"},{"Id":237,"Name":"hitmontop"},{"Id":238,"Name":"smoochum"},{"Id":239,"Name":"elekid"},{"Id":240,"Name":"magby"},{"Id":241,"Name":"miltank"},{"Id":242,"Name":"blissey"},{"Id":243,"Name":"raikou"},{"Id":244,"Name":"entei"},{"Id":245,"Name":"suicune"},{"Id":246,"Name":"larvitar"},{"Id":247,"Name":"pupitar"},{"Id":248,"Name":"tyranitar"},{"Id":249,"Name":"lugia"},{"Id":250,"Name":"ho-oh"},{"Id":251,"Name":"celebi"},{"Id":252,"Name":"treecko"},{"Id":253,"Name":"grovyle"},{"Id":254,"Name":"sceptile"},{"Id":255,"Name":"torchic"},{"Id":256,"Name":"combusken"},{"Id":257,"Name":"blaziken"},{"Id":258,"Name":"mudkip"},{"Id":259,"Name":"marshtomp"},{"Id":260,"Name":"swampert"},{"Id":261,"Name":"poochyena"},{"Id":262,"Name":"mightyena"},{"Id":263,"Name":"zigzagoon"},{"Id":264,"Name":"linoone"},{"Id":265,"Name":"wurmple"},{"Id":266,"Name":"silcoon"},{"Id":267,"Name":"beautifly"},{"Id":268,"Name":"cascoon"},{"Id":269,"Name":"dustox"},{"Id":270,"Name":"lotad"},{"Id":271,"Name":"lombre"},{"Id":272,"Name":"ludicolo"},{"Id":273,"Name":"seedot"},{"Id":274,"Name":"nuzleaf"},{"Id":275,"Name":"shiftry"},{"Id":276,"Name":"taillow"},{"Id":277,"Name":"swellow"},{"Id":278,"Name":"wingull"},{"Id":279,"Name":"pelipper"},{"Id":280,"Name":"ralts"},{"Id":281,"Name":"kirlia"},{"Id":282,"Name":"gardevoir"},{"Id":283,"Name":"surskit"},{"Id":284,"Name":"masquerain"},{"Id":285,"Name":"shroomish"},{"Id":286,"Name":"breloom"},{"Id":287,"Name":"slakoth"},{"Id":288,"Name":"vigoroth"},{"Id":289,"Name":"slaking"},{"Id":290,"Name":"nincada"},{"Id":291,"Name":"ninjask"},{"Id":292,"Name":"shedinja"},{"Id":293,"Name":"whismur"},{"Id":294,"Name":"loudred"},{"Id":295,"Name":"exploud"},{"Id":296,"Name":"makuhita"},{"Id":297,"Name":"hariyama"},{"Id":298,"Name":"azurill"},{"Id":299,"Name":"nosepass"},{"Id":300,"Name":"skitty"},{"Id":301,"Name":"delcatty"},{"Id":302,"Name":"sableye"},{"Id":303,"Name":"mawile"},{"Id":304,"Name":"aron"},{"Id":305,"Name":"lairon"},{"Id":306,"Name":"aggron"},{"Id":307,"Name":"meditite"},{"Id":308,"Name":"medicham"},{"Id":309,"Name":"electrike"},{"Id":310,"Name":"manectric"},{"Id":311,"Name":"plusle"},{"Id":312,"Name":"minun"},{"Id":313,"Name":"volbeat"},{"Id":314,"Name":"illumise"},{"Id":315,"Name":"roselia"},{"Id":316,"Name":"gulpin"},{"Id":317,"Name":"swalot"},{"Id":318,"Name":"carvanha"},{"Id":319,"Name":"sharpedo"},{"Id":320,"Name":"wailmer"},{"Id":321,"Name":"wailord"},{"Id":322,"Name":"numel"},{"Id":323,"Name":"camerupt"},{"Id":324,"Name":"torkoal"},{"Id":325,"Name":"spoink"},{"Id":326,"Name":"grumpig"},{"Id":327,"Name":"spinda"},{"Id":328,"Name":"trapinch"},{"Id":329,"Name":"vibrava"},{"Id":330,"Name":"flygon"},{"Id":331,"Name":"cacnea"},{"Id":332,"Name":"cacturne"},{"Id":333,"Name":"swablu"},{"Id":334,"Name":"altaria"},{"Id":335,"Name":"zangoose"},{"Id":336,"Name":"seviper"},{"Id":337,"Name":"lunatone"},{"Id":338,"Name":"solrock"},{"Id":339,"Name":"barboach"},{"Id":340,"Name":"whiscash"},{"Id":341,"Name":"corphish"},{"Id":342,"Name":"crawdaunt"},{"Id":343,"Name":"baltoy"},{"Id":344,"Name":"claydol"},{"Id":345,"Name":"lileep"},{"Id":346,"Name":"cradily"},{"Id":347,"Name":"anorith"},{"Id":348,"Name":"armaldo"},{"Id":349,"Name":"feebas"},{"Id":350,"Name":"milotic"},{"Id":351,"Name":"castform"},{"Id":352,"Name":"kecleon"},{"Id":353,"Name":"shuppet"},{"Id":354,"Name":"banette"},{"Id":355,"Name":"duskull"},{"Id":356,"Name":"dusclops"},{"Id":357,"Name":"tropius"},{"Id":358,"Name":"chimecho"},{"Id":359,"Name":"absol"},{"Id":360,"Name":"wynaut"},{"Id":361,"Name":"snorunt"},{"Id":362,"Name":"glalie"},{"Id":363,"Name":"spheal"},{"Id":364,"Name":"sealeo"},{"Id":365,"Name":"walrein"},{"Id":366,"Name":"clamperl"},{"Id":367,"Name":"huntail"},{"Id":368,"Name":"gorebyss"},{"Id":369,"Name":"relicanth"},{"Id":370,"Name":"luvdisc"},{"Id":371,"Name":"bagon"},{"Id":372,"Name":"shelgon"},{"Id":373,"Name":"salamence"},{"Id":374,"Name":"beldum"},{"Id":375,"Name":"metang"},{"Id":376,"Name":"metagross"},{"Id":377,"Name":"regirock"},{"Id":378,"Name":"regice"},{"Id":379,"Name":"registeel"},{"Id":380,"Name":"latias"},{"Id":381,"Name":"latios"},{"Id":382,"Name":"kyogre"},{"Id":383,"Name":"groudon"},{"Id":384,"Name":"rayquaza"},{"Id":385,"Name":"jirachi"},{"Id":386,"Name":"deoxys"},{"Id":387,"Name":"turtwig"},{"Id":388,"Name":"grotle"},{"Id":389,"Name":"torterra"},{"Id":390,"Name":"chimchar"},{"Id":391,"Name":"monferno"},{"Id":392,"Name":"infernape"},{"Id":393,"Name":"piplup"},{"Id":394,"Name":"prinplup"},{"Id":395,"Name":"empoleon"},{"Id":396,"Name":"starly"},{"Id":397,"Name":"staravia"},{"Id":398,"Name":"staraptor"},{"Id":399,"Name":"bidoof"},{"Id":400,"Name":"bibarel"},{"Id":401,"Name":"kricketot"},{"Id":402,"Name":"kricketune"},{"Id":403,"Name":"shinx"},{"Id":404,"Name":"luxio"},{"Id":405,"Name":"luxray"},{"Id":406,"Name":"budew"},{"Id":407,"Name":"roserade"},{"Id":408,"Name":"cranidos"},{"Id":409,"Name":"rampardos"},{"Id":410,"Name":"shieldon"},{"Id":411,"Name":"bastiodon"},{"Id":412,"Name":"burmy"},{"Id":413,"Name":"wormadam"},{"Id":414,"Name":"mothim"},{"Id":415,"Name":"combee"},{"Id":416,"Name":"vespiquen"},{"Id":417,"Name":"pachirisu"},{"Id":418,"Name":"buizel"},{"Id":419,"Name":"floatzel"},{"Id":420,"Name":"cherubi"},{"Id":421,"Name":"cherrim"},{"Id":422,"Name":"shellos"},{"Id":423,"Name":"gastrodon"},{"Id":424,"Name":"ambipom"},{"Id":425,"Name":"drifloon"},{"Id":426,"Name":"drifblim"},{"Id":427,"Name":"buneary"},{"Id":428,"Name":"lopunny"},{"Id":429,"Name":"mismagius"},{"Id":430,"Name":"honchkrow"},{"Id":431,"Name":"glameow"},{"Id":432,"Name":"purugly"},{"Id":433,"Name":"chingling"},{"Id":434,"Name":"stunky"},{"Id":435,"Name":"skuntank"},{"Id":436,"Name":"bronzor"},{"Id":437,"Name":"bronzong"},{"Id":438,"Name":"bonsly"},{"Id":439,"Name":"mime jr"},{"Id":440,"Name":"happiny"},{"Id":441,"Name":"chatot"},{"Id":442,"Name":"spiritomb"},{"Id":443,"Name":"gible"},{"Id":444,"Name":"gabite"},{"Id":445,"Name":"garchomp"},{"Id":446,"Name":"munchlax"},{"Id":447,"Name":"riolu"},{"Id":448,"Name":"lucario"},{"Id":449,"Name":"hippopotas"},{"Id":450,"Name":"hippowdon"},{"Id":451,"Name":"skorupi"},{"Id":452,"Name":"drapion"},{"Id":453,"Name":"croagunk"},{"Id":454,"Name":"toxicroak"},{"Id":455,"Name":"carnivine"},{"Id":456,"Name":"finneon"},{"Id":457,"Name":"lumineon"},{"Id":458,"Name":"mantyke"},{"Id":459,"Name":"snover"},{"Id":460,"Name":"abomasnow"},{"Id":461,"Name":"weavile"},{"Id":462,"Name":"magnezone"},{"Id":463,"Name":"lickilicky"},{"Id":464,"Name":"rhyperior"},{"Id":465,"Name":"tangrowth"},{"Id":466,"Name":"electivire"},{"Id":467,"Name":"magmortar"},{"Id":468,"Name":"togekiss"},{"Id":469,"Name":"yanmega"},{"Id":470,"Name":"leafeon"},{"Id":471,"Name":"glaceon"},{"Id":472,"Name":"gliscor"},{"Id":473,"Name":"mamoswine"},{"Id":474,"Name":"porygon z"},{"Id":475,"Name":"gallade"},{"Id":476,"Name":"probopass"},{"Id":477,"Name":"dusknoir"},{"Id":478,"Name":"froslass"},{"Id":479,"Name":"rotom"},{"Id":480,"Name":"uxie"},{"Id":481,"Name":"mesprit"},{"Id":482,"Name":"azelf"},{"Id":483,"Name":"dialga"},{"Id":484,"Name":"palkia"},{"Id":485,"Name":"heatran"},{"Id":486,"Name":"regigigas"},{"Id":487,"Name":"giratina"},{"Id":488,"Name":"cresselia"},{"Id":489,"Name":"phione"},{"Id":490,"Name":"manaphy"},{"Id":491,"Name":"darkrai"},{"Id":492,"Name":"shaymin"},{"Id":493,"Name":"arceus"},{"Id":494,"Name":"victini"},{"Id":495,"Name":"snivy"},{"Id":496,"Name":"servine"},{"Id":497,"Name":"serperior"},{"Id":498,"Name":"tepig"},{"Id":499,"Name":"pignite"},{"Id":500,"Name":"emboar"},{"Id":501,"Name":"oshawott"},{"Id":502,"Name":"dewott"},{"Id":503,"Name":"samurott"},{"Id":504,"Name":"patrat"},{"Id":505,"Name":"watchog"},{"Id":506,"Name":"lillipup"},{"Id":507,"Name":"herdier"},{"Id":508,"Name":"stoutland"},{"Id":509,"Name":"purrloin"},{"Id":510,"Name":"liepard"},{"Id":511,"Name":"pansage"},{"Id":512,"Name":"simisage"},{"Id":513,"Name":"pansear"},{"Id":514,"Name":"simisear"},{"Id":515,"Name":"panpour"},{"Id":516,"Name":"simipour"},{"Id":517,"Name":"munna"},{"Id":518,"Name":"musharna"},{"Id":519,"Name":"pidove"},{"Id":520,"Name":"tranquill"},{"Id":521,"Name":"unfezant"},{"Id":522,"Name":"blitzle"},{"Id":523,"Name":"zebstrika"},{"Id":524,"Name":"roggenrola"},{"Id":525,"Name":"boldore"},{"Id":526,"Name":"gigalith"},{"Id":527,"Name":"woobat"},{"Id":528,"Name":"swoobat"},{"Id":529,"Name":"drilbur"},{"Id":530,"Name":"excadrill"},{"Id":531,"Name":"audino"},{"Id":532,"Name":"timburr"},{"Id":533,"Name":"gurdurr"},{"Id":534,"Name":"conkeldurr"},{"Id":535,"Name":"tympole"},{"Id":536,"Name":"palpitoad"},{"Id":537,"Name":"seismitoad"},{"Id":538,"Name":"throh"},{"Id":539,"Name":"sawk"},{"Id":540,"Name":"sewaddle"},{"Id":541,"Name":"swadloon"},{"Id":542,"Name":"leavanny"},{"Id":543,"Name":"venipede"},{"Id":544,"Name":"whirlipede"},{"Id":545,"Name":"scolipede"},{"Id":546,"Name":"cottonee"},{"Id":547,"Name":"whimsicott"},{"Id":548,"Name":"petilil"},{"Id":549,"Name":"lilligant"},{"Id":550,"Name":"basculin"},{"Id":551,"Name":"sandile"},{"Id":552,"Name":"krokorok"},{"Id":553,"Name":"krookodile"},{"Id":554,"Name":"darumaka"},{"Id":555,"Name":"darmanitan"},{"Id":556,"Name":"maractus"},{"Id":557,"Name":"dwebble"},{"Id":558,"Name":"crustle"},{"Id":559,"Name":"scraggy"},{"Id":560,"Name":"scrafty"},{"Id":561,"Name":"sigilyph"},{"Id":562,"Name":"yamask"},{"Id":563,"Name":"cofagrigus"},{"Id":564,"Name":"tirtouga"},{"Id":565,"Name":"carracosta"},{"Id":566,"Name":"archen"},{"Id":567,"Name":"archeops"},{"Id":568,"Name":"trubbish"},{"Id":569,"Name":"garbodor"},{"Id":570,"Name":"zorua"},{"Id":571,"Name":"zoroark"},{"Id":572,"Name":"minccino"},{"Id":573,"Name":"cinccino"},{"Id":574,"Name":"gothita"},{"Id":575,"Name":"gothorita"},{"Id":576,"Name":"gothitelle"},{"Id":577,"Name":"solosis"},{"Id":578,"Name":"duosion"},{"Id":579,"Name":"reuniclus"},{"Id":580,"Name":"ducklett"},{"Id":581,"Name":"swanna"},{"Id":582,"Name":"vanillite"},{"Id":583,"Name":"vanillish"},{"Id":584,"Name":"vanilluxe"},{"Id":585,"Name":"deerling"},{"Id":586,"Name":"sawsbuck"},{"Id":587,"Name":"emolga"},{"Id":588,"Name":"karrablast"},{"Id":589,"Name":"escavalier"},{"Id":590,"Name":"foongus"},{"Id":591,"Name":"amoonguss"},{"Id":592,"Name":"frillish"},{"Id":593,"Name":"jellicent"},{"Id":594,"Name":"alomomola"},{"Id":595,"Name":"joltik"},{"Id":596,"Name":"galvantula"},{"Id":597,"Name":"ferroseed"},{"Id":598,"Name":"ferrothorn"},{"Id":599,"Name":"klink"},{"Id":600,"Name":"klang"},{"Id":601,"Name":"klinklang"},{"Id":602,"Name":"tynamo"},{"Id":603,"Name":"eelektrik"},{"Id":604,"Name":"eelektross"},{"Id":605,"Name":"elgyem"},{"Id":606,"Name":"beheeyem"},{"Id":607,"Name":"litwick"},{"Id":608,"Name":"lampent"},{"Id":609,"Name":"chandelure"},{"Id":610,"Name":"axew"},{"Id":611,"Name":"fraxure"},{"Id":612,"Name":"haxorus"},{"Id":613,"Name":"cubchoo"},{"Id":614,"Name":"beartic"},{"Id":615,"Name":"cryogonal"},{"Id":616,"Name":"shelmet"},{"Id":617,"Name":"accelgor"},{"Id":618,"Name":"stunfisk"},{"Id":619,"Name":"mienfoo"},{"Id":620,"Name":"mienshao"},{"Id":621,"Name":"druddigon"},{"Id":622,"Name":"golett"},{"Id":623,"Name":"golurk"},{"Id":624,"Name":"pawniard"},{"Id":625,"Name":"bisharp"},{"Id":626,"Name":"bouffalant"},{"Id":627,"Name":"rufflet"},{"Id":628,"Name":"braviary"},{"Id":629,"Name":"vullaby"},{"Id":630,"Name":"mandibuzz"},{"Id":631,"Name":"heatmor"},{"Id":632,"Name":"durant"},{"Id":633,"Name":"deino"},{"Id":634,"Name":"zweilous"},{"Id":635,"Name":"hydreigon"},{"Id":636,"Name":"larvesta"},{"Id":637,"Name":"volcarona"},{"Id":638,"Name":"cobalion"},{"Id":639,"Name":"terrakion"},{"Id":640,"Name":"virizion"},{"Id":641,"Name":"tornadus"},{"Id":642,"Name":"thundurus"},{"Id":643,"Name":"reshiram"},{"Id":644,"Name":"zekrom"},{"Id":645,"Name":"landorus"},{"Id":646,"Name":"kyurem"},{"Id":647,"Name":"keldeo"},{"Id":648,"Name":"meloetta"},{"Id":649,"Name":"genesect"},{"Id":650,"Name":"chespin"},{"Id":651,"Name":"quilladin"},{"Id":652,"Name":"chesnaught"},{"Id":653,"Name":"fennekin"},{"Id":654,"Name":"braixen"},{"Id":655,"Name":"delphox"},{"Id":656,"Name":"froakie"},{"Id":657,"Name":"frogadier"},{"Id":658,"Name":"greninja"},{"Id":659,"Name":"bunnelby"},{"Id":660,"Name":"diggersby"},{"Id":661,"Name":"fletchling"},{"Id":662,"Name":"fletchinder"},{"Id":663,"Name":"talonflame"},{"Id":664,"Name":"scatterbug"},{"Id":665,"Name":"spewpa"},{"Id":666,"Name":"vivillon"},{"Id":667,"Name":"litleo"},{"Id":668,"Name":"pyroar"},{"Id":669,"Name":"flabebe"},{"Id":670,"Name":"floette"},{"Id":671,"Name":"florges"},{"Id":672,"Name":"skiddo"},{"Id":673,"Name":"gogoat"},{"Id":674,"Name":"pancham"},{"Id":675,"Name":"pangoro"},{"Id":676,"Name":"furfrou"},{"Id":677,"Name":"espurr"},{"Id":678,"Name":"meowstic"},{"Id":679,"Name":"honedge"},{"Id":680,"Name":"doublade"},{"Id":681,"Name":"aegislash"},{"Id":682,"Name":"spritzee"},{"Id":683,"Name":"aromatisse"},{"Id":684,"Name":"swirlix"},{"Id":685,"Name":"slurpuff"},{"Id":686,"Name":"inkay"},{"Id":687,"Name":"malamar"},{"Id":688,"Name":"binacle"},{"Id":689,"Name":"barbaracle"},{"Id":690,"Name":"skrelp"},{"Id":691,"Name":"dragalge"},{"Id":692,"Name":"clauncher"},{"Id":693,"Name":"clawitzer"},{"Id":694,"Name":"helioptile"},{"Id":695,"Name":"heliolisk"},{"Id":696,"Name":"tyrunt"},{"Id":697,"Name":"tyrantrum"},{"Id":698,"Name":"amaura"},{"Id":699,"Name":"aurorus"},{"Id":700,"Name":"sylveon"},{"Id":701,"Name":"hawlucha"},{"Id":702,"Name":"dedenne"},{"Id":703,"Name":"carbink"},{"Id":704,"Name":"goomy"},{"Id":705,"Name":"sliggoo"},{"Id":706,"Name":"goodra"},{"Id":707,"Name":"klefki"},{"Id":708,"Name":"phantump"},{"Id":709,"Name":"trevenant"},{"Id":710,"Name":"pumpkaboo"},{"Id":711,"Name":"gourgeist"},{"Id":712,"Name":"bergmite"},{"Id":713,"Name":"avalugg"},{"Id":714,"Name":"noibat"},{"Id":715,"Name":"noivern"},{"Id":716,"Name":"xerneas"},{"Id":717,"Name":"yveltal"},{"Id":718,"Name":"zygarde"},{"Id":719,"Name":"diancie"},{"Id":720,"Name":"hoopa"},{"Id":721,"Name":"volcanion"}] \ No newline at end of file From e107bee62f65428c0793be1313cbacaf1c08b09b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 27 Mar 2017 11:35:06 +0200 Subject: [PATCH 624/746] fixed help links when ffmpeg is not properly setup --- src/NadekoBot/Modules/Music/Classes/SongBuffer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs b/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs index 738d07ec..87c01ff6 100644 --- a/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs +++ b/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs @@ -99,8 +99,8 @@ namespace NadekoBot.Modules.Music.Classes Console.WriteLine(@"You have not properly installed or configured FFMPEG. Please install and configure FFMPEG to play music. Check the guides for your platform on how to setup ffmpeg correctly: - Windows Guide: https://goo.gl/SCv72y - Linux Guide: https://goo.gl/rRhjCp"); + Windows Guide: https://goo.gl/OjKk8F + Linux Guide: https://goo.gl/ShjCUo"); Console.ForegroundColor = oldclr; } catch (Exception ex) From 43ff3ad7161120104eea63090a6ab4ea51b1278b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 27 Mar 2017 11:43:49 +0200 Subject: [PATCH 625/746] Fixed some strings --- .../Resources/ResponseStrings.Designer.cs | 6 +- .../Resources/ResponseStrings.en-US.resx | 4328 ++++++++--------- .../Resources/ResponseStrings.ja-JP.resx | 236 +- src/NadekoBot/Resources/ResponseStrings.resx | 6 +- .../Resources/ResponseStrings.sr-cyrl-rs.resx | 240 +- 5 files changed, 2408 insertions(+), 2408 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index fec34b11..1b0cd969 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -250,7 +250,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sucessfully created role {0}. + /// Looks up a localized string similar to Successfully created role {0}. /// public static string administration_cr { get { @@ -340,7 +340,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sucessfully added a new donator.Total donated amount from this user: {0} 👑. + /// Looks up a localized string similar to Successfully added a new donator.Total donated amount from this user: {0} 👑. /// public static string administration_donadd { get { @@ -1351,7 +1351,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Sucessfully added role {0} to user {1}. + /// Looks up a localized string similar to Successfully added role {0} to user {1}. /// public static string administration_setrole { get { diff --git a/src/NadekoBot/Resources/ResponseStrings.en-US.resx b/src/NadekoBot/Resources/ResponseStrings.en-US.resx index c384f48e..3fb0ba18 100644 --- a/src/NadekoBot/Resources/ResponseStrings.en-US.resx +++ b/src/NadekoBot/Resources/ResponseStrings.en-US.resx @@ -1,4 +1,4 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 そのベースはもう要求・破壊されました。 @@ -856,7 +856,7 @@ Fuzzy ユーザー{1}にロール{0}を追加しました - Typo- "Sucessfully" should be 'Successfully' + Typo- "successfully" should be 'Successfully' ロールの追加に失敗しました。アクセス権が足りません。 diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 56ada3ed..6f8446b9 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -364,7 +364,7 @@ Reason: {1} Content - Sucessfully created role {0} + Successfully created role {0} Text channel {0} created. @@ -394,7 +394,7 @@ Reason: {1} DM from - Sucessfully added a new donator.Total donated amount from this user: {0} 👑 + Successfully added a new donator.Total donated amount from this user: {0} 👑 Thanks to the people listed below for making this project happen! @@ -701,7 +701,7 @@ Reason: {1} You now have {0} role. - Sucessfully added role {0} to user {1} + Successfully added role {0} to user {1} Failed to add role. I have insufficient permissions. diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx index 8fe7d18e..8c3dd6c5 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Та база је већ под захетвом или је уништена. @@ -364,7 +364,7 @@ Reason: {1} Content - Sucessfully created role {0} + successfully created role {0} Text channel {0} created. @@ -394,7 +394,7 @@ Reason: {1} DM from - Sucessfully added a new donator.Total donated amount from this user: {0} 👑 + successfully added a new donator.Total donated amount from this user: {0} 👑 Thanks to the people listed below for making this project hjappen! @@ -712,7 +712,7 @@ Reason: {1} You now have {0} role. - Sucessfully added role {0} to user {1} + successfully added role {0} to user {1} Failed to add role. I have insufficient permissions. From ac3f9f539651262189a5682cfa5d7444ca1763c0 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 27 Mar 2017 14:02:01 +0200 Subject: [PATCH 626/746] Italian added --- .../Commands/LocalizationCommands.cs | 1 + .../Resources/ResponseStrings.it-IT.resx | 2307 +++++++++++++++++ 2 files changed, 2308 insertions(+) create mode 100644 src/NadekoBot/Resources/ResponseStrings.it-IT.resx diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index c8c07fe2..19930059 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -24,6 +24,7 @@ namespace NadekoBot.Modules.Administration {"en-US", "English, United States"}, {"fr-FR", "French, France"}, {"de-DE", "German, Germany"}, + {"it-IT", "Italian, Italy" }, //{"ja-JP", "Japanese, Japan"}, {"nb-NO", "Norwegian (bokmål), Norway"}, {"pl-PL", "Polish, Poland" }, diff --git a/src/NadekoBot/Resources/ResponseStrings.it-IT.resx b/src/NadekoBot/Resources/ResponseStrings.it-IT.resx new file mode 100644 index 00000000..7a09ef5d --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.it-IT.resx @@ -0,0 +1,2307 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Quella base è già rivendicata o distrutta. + + + Quella base è già distrutta. + + + Quella base non è rivendicata. + + + **DISTRUTTO** base #{0} in una guerra contro {1} + + + {0} ha **NON RIVENDICATO** base #{1} in una guerra contro {2} + + + {0} ha rivendicato la base #{1} in una guerra contro {2} + + + @{0} Hai già rivendicato la base #{1} + + + La rivendicazione di @{0} in una guerra contro {1} + + + Nemico + + + Informazioni sulla guerra contro {0} + + + Numero della base invalido. + + + Dimensione della guerra non valida. + + + Lista delle guerre in corso + + + non rivendicato + + + Non stai partecipando a questa guerra + + + @{0} Tu non stai partecipando in questa guerra, o questa base è già distrutta. + + + Nessuna guerra in corso. + + + Dimensione + + + La guerra contro {0} è già iniziata. + + + Guerra contro {0} creata. + + + Guerra contro {0} finita. + + + Questa guerra non esiste. + + + Guerra contro {0} iniziata! + + + Tutte le reazioni personalizzate approvate. + + + Reazione personalizzata cancellata + + + Permessi insufficienti. Richiede l'essere proprietario del bot per le reazioni personalizzate globali, e l'amministratore del server per le reazioni personalizzate. + + + Lista di tutte le reazioni personalizzate + + + Reazioni Personalizzate + + + Nuove Reazioni Personalizzate + + + Nessuna reazione personalizzata trovata. + + + Nessuna reazione personalizzata trovata con quell'id. + + + Risposta + + + Statistiche Reazioni Personalizzate + + + Statistiche pulite per {0} reazioni personalizzate. + + + Nessuna statistica per questo innesco trovata, nessun azione presa. + + + Innesco + + + Autohentai fermato. + + + Nessun risultato trovato. + + + {0} è già svenuto. + + + {0} ha già gli HP al massimo. + + + il tuo tipo è già {0} + + + Ha usato {0}{1} su {2}{3} per {4} danni. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + Non puoi attaccare senza ritorsione! + Fuzzy + + + Non puoi attaccare te stesso. + + + {0} è svenuto! + + + curato {0} con un {1} + + + {0} ha {1} HP rimasto + + + Non puoi usare {0}. Scrivi `{1}ml` per vedere la lista delle mosse che puoi usare. + + + Listamosse per tipo {0} + + + Non è efficace. + + + Non hai abbastanza {0} + + + Hai resuscitato {0} con un {1} + + + Hai resuscitato te stesso con un {0} + + + Il tuo tipo è stato cambiato in {0} per un {1} + + + E' lievemente efficace. + + + E' superefficace! + + + Hai usato troppe mosse in una volta, non puoi muoverti! + + + Tipo di {0} è {1} + + + Utente non trovato. + + + Sei svenuto, non sei più in grado di muoverti! + + + **Auto assegna ruolo** sull'utente ora entrato è ora **disattivato** + + + **Auto assegna ruolo** sull'utente ora entrato è ora **attivato** + + + Allegato + + + Avatar Cambiato + + + Sei stato bannato dal {0} server. +Ragione: {1} + + + bannati + PLURAL + + + Utente bannato + + + Nome bot cambiato in {0} + + + Stato del bot cambiato in {0} + + + L'eliminazione automatica dei messaggi di arrivederci è stata disabilitata. + + + I messaggi di arrivederci verranno eliminati dopo {0} secondi. + + + Messaggi di arrivederci attuali: {0} + + + Attiva i messaggi di arrivederci scrivendo {0} + + + Nuovo messaggio di arrivederci impostato. + + + Annunci di arrivederci disattivati. + + + Annunci di arrivederci attivati in questo canale + + + Nome del canale cambiato + + + Vecchio Nome + + + Argomento del canale cambiato + + + Pulito. + + + Contenuto + + + Ruolo creato con successo {0} + + + Canale di testo {0} creato. + + + Canale vocale {0} creato. + + + Assordato con successo. + + + Server Eliminato {0} + + + Fermata con successo l'eliminazione automatica dei comandi di invocazione. + + + Avviata con successo l'eliminazione automatica dei comandi di invocazione. + + + Canale di testo {0} eliminato. + + + Canale vocale {0} eliminato. + + + MP da + + + Aggiunto con successo un nuovo donatore. Totale ammontare donato da questo utente: {0} 👑 + + + Grazie alle persone nella lista qui sotto per aver fatto avverare questo progetto! + + + Inoltrerò MP a tutti i proprietari. + + + Inoltrerò MP solo al primo proprietario. + + + Inoltrerò MP da ora in poi. + + + Fermerò l'inoltrare degli MP da ora in poi. + + + L'eliminazione automatica dei messaggi di benvenuto è stata disabilitata + + + I messaggi di benvenuto verranno eliminati dopo {0} secondi. + + + Attuali MP di benvenuto ricevuti: {0} + + + Abilità MP di benvenuto scrivendoli {0} + + + Nuovo MP di bevenuto impostato. + + + MP annunci di bevenenuto disattivato. + + + MP annunci di bevenuto attivati. + + + + + + + + + Nuovo messaggio di benvenuto impostato. + + + Annunci di bevenuto disabilitati + + + Annunci di benvenuto abilitatati in questo canale + + + Non puoi usare questo comando su utenti con un ruolo più alto o uguale al tuo nella gerarchia dei ruoli. + + + Immagine caricata dopo {0} secondi! + + + + + + Parametri Invalidi + + + {0} è entrato {1} + + + Sei stato cacciato dal {0} server. +Ragione: {1} + + + Utente cacciato + + + Lista dei linguaggi + + + + + + + + + il linguaggio dei Bot è impostato a {0} - {1} + + + + + + Il linguaggio di questo server è impostato a {0} - {1} + + + {0} ha lasciato {1} + + + Hai lasciato il server {0} + + + Inserire {0} evento in questo canale. + Someone can tell me what he means for log, soo i can translate it better and correct it anyway! +Fuzzy + + + Inseriti tutti gli eventi in questo canale. + Fuzzy + + + Entrata disattivata + Fuzzy + + + Gli eventi a cui puoi iscriverti: + Fuzzy + + + + + + + + + + + + {0} ha chiesto una menzione nei seguenti ruoli + + + Messaggio da {0} `[Proprietario Bot]`: + + + Messaggio inviato. + + + {0} spostato in {1} da {2} + + + Messaggio eliminato in #{0} + + + + + + Gli utenti sono stati mutati + PLURAL (users have been muted) + + + Utente mutato + singular "User muted." + + + Probabilmente non ho i permessi necessari per questo + + + Nuovo ruolo di muto impostato. + + + Ho bisogno dei permessi di **Amministrazione** per farlo + + + Nuovo messaggio + + + Nuovo soprannome + + + Nuova discussione + + + Soprannome cambiato + + + Non riesco a trovare questo server + + + + + + Messaggio precedente + + + Nickname precedente + + + Discussione precedente + + + Errore. Probabilmente non ho i permessi sufficienti. + + + I permessi per questo server sono resettati + + + Protezioni attive + + + {0} è stato **disattivato** in questo server. + + + {0} Attivato + + + Errore. Hai bisogno dei permessi di gestione dei ruoli + + + Nessuna protezione attiva. + + + Gli utenti in ingresso devono essere tra {0} e {1}. + + + Se {0} o più utenti entrano entro {1} secondi, io li {0} loro. + + + Il tempo deve essere tra {0} e {1} secondi. + + + Rimossi con successo tutti i ruoli dall'utente {0} + + + Fallito a rimuovere i ruoli. Non ho abbastanza permessi. + + + il colore di {0} è stato cambiato. + + + Questo ruolo non esiste. + + + I parametri specificati sono invalidi + + + Si è verificato un errore dovuto a un colore invalido o a permessi insufficienti. + + + Rimosso con successo ruolo {0} dall'utente {1} + + + Fallito a rimuovere ruolo. Non ho abbastanza permessi. + + + Ruolo rinominato + + + Rinomina del ruolo fallita. Non ho abbastanza permessi. + + + Non puoi modificare i ruoli più alti del tuo + + + Rimosso il messaggio di gioco: {0} + + + Ruolo {0} è stato aggiunto alla lista. + + + {0} non trovato.Ripulito. + + + il ruolo {0} è già nella lista + + + Aggiunto. + + + Stato di gioco rotativo disattivato. + + + Stato di gioco rotativo attivato. + + + Qui c'è una lista delle condizioni di ruolo rotative: +{0} + Fuzzy + + + Nessuno condizione di gioco rotativo impostato. + Fuzzy + + + Tu hai già {0} ruolo + + + Tu hai già {0} esclusivi ruoli auto-assegnati. + + + I ruoli auto-assegnati sono ora riservati! + + + Ci sono {0} ruoli auto-assegnabili. + + + Quel ruolo non è auto-assegnabile. + + + Tu non hai {0} ruolo. + + + I ruoli auto-assegnati ora non sono più riservati! + + + Io non sono in grado di assegnarti questo ruolo. `Io non posso assegnare ruoli al proprietario o ad altri ruoli più alti del mio nella gerarchia dei ruoli.` + + + {0} è stato rimosso dalla lista dei ruoli auto-assegnabili. + + + Tu non hai più {0} ruolo. + + + Tu ora hai {0} ruolo. + + + Aggiunto con successo ruolo {0} all'utente {1} + + + Fallito ad aggiungere il ruolo. Non ho i permessi sufficienti. + + + Nuova immagine impostata! + + + Nuovo nome del canale impostato. + + + Nuovo gioco impostato! + + + Nuova sequenza impostata! + + + Nuova discussione del canale impostata. + + + + + + + + + Spegnimento + + + Gli utenti non possono mandare più di {0} messaggi ogni {1} secondi. + + + Modalità lenta disattivata + + + Modalità lenta attivata + + + Ammonizione (Espulso) + PLURAL + + + {0} ignorerà questo canale. + + + {0} non ignorerà più questo canale. + + + Se un utente posta {0} lo stesso messaggio consecutivamente, io {0} loro. +__Canaliignorati__: {2} + + + Canale di testo creato. + + + Canale di testo distrutto. + + + Desilenziato con successo. + + + Smutato + singular + + + Nome Utente + + + Nome utente cambiato. + + + Utenti + + + Utente bannato + + + {0} è stato **mutato** dalla chat. + + + {0} è stato **smutato** dalla chat. + + + Utente entrato + + + Utente è andato via + + + {0} è stato **mutato** dal canale di testo e vocale. + + + Ruolo utente aggiunto + + + Ruolo utente rimosso + + + {0} è ora {1} + + + {0} è stato **smutato** dal canale di testo e vocale. + + + {0} è entrato {1} canale vocale. + + + {0} è uscito {1} canale vocale. + + + {0} ha spostato {1} al {2} canale vocale. + + + {0} è stato **mutato vocalmente** + + + {0} è stato **smutato vocalmente* + + + Canale vocale creato + + + Canale vocale distrutto + + + Voce + testo disabilitati. + + + Voce + testo abilitati. + + + + + + + + + + + + Utente {0} dalla chat di testo + + + Utente {0} dalla chat di testo e vocale + + + Utente {0} dalla chat vocale + + + + + + Utente sbannato + + + Trasferimento completato! + + + Errore durante il trasferimento, guarda la console del bot per più informazioni. + + + + + + Utente ammonito + + + ha regalato {0} to {1} + + + Avrai più fortuna la prossima volta ^_^ + + + Congratulazioni! Hai vinto {0} per aver rollato oltre {1} + + + Mazzo rimescolato. + + + Lanciato {0} + User flipped tails. + + + Indovinato! Hai vinto {0} + + + + + + Aggiungi {0} a questo messaggio per ottenere {1} + + + Quest'evento è attivo per le prossime {0} ore + + + + + + ha regalato {0} a {1} + X has gifted 15 flowers to Y + + + {0} ha {1} + X has Y flowers + + + Testa + + + + + + + + + Non puoi puntare più di {0} + + + Non puoi puntare meno di {0} + + + Non hai abbastanza {0} + + + Non ci sono più carte nel mazzo. + + + + + + Hai rollato {0} + + + Punta + + + WOAAHHHHHHH!!! Congratulazioni!!! x{0} + + + Un singolo {0}, x{1} + + + Wow! Fortunato! Tre di un tipo! x{0} + + + Bel lavoro! Due {0} - puntato x{1} + + + Vinto + + + Gli utenti devono scrivere un codice segreto per ottenere {0}. +Dura {1} secondi. Non dirlo a nessuno. Shhh. + + + + + + + + + Croce + + + Hai preso con successo {0} da {1} + Fuzzy + + + + + + + + + Solo il proprietario del bot. + + + + + + Puoi supportare il progetto sul patreon: <{0}> o paypal: <{0}> + + + + + + + + + + + + Non riesco a trovare questo comando. Perfavore verifica che questo comando esiste prima di riprovare. + + + Descrizione + + + Puoi supportare "NadekoBot project" su +Patreon <{0}> oppure su +Paypal <{1}> +Non dimenticarti di firmare con il tuo nome o id di discord. + +**Grazie** ♥️ + + + **Lista dei comandi**: <{0}> +**Trovi delle guide per diventare host e altri documenti qui**: <{1}> + + + Lista dei comandi + + + Lista dei moduli + + + + + + Modulo inesistente. + + + + + + Tabella dei contenuti + + + + + + Autohentai avviato. Ogni {0} secondi verrà postato qualcosa coi seguenti tag: +{1} + + + Tag + + + + + + Impossibile iniziare perché non ci sono abbastanza partecipanti. + + + La gara è piena! Inizio immediato. + + + {0} è entrato come {1} + + + {0} è entrato come {1} e ha scommesso {2}! + + + Scrivi {0}eg per entrare nella gara. + Fuzzy + + + Inizia tra 20 secondi o quando la stanza è piena. + + + Inizia con {0} partecipanti. + + + {0} come {1} Ha vinto la gara! + + + {0} come {2} Ha vinto la gara e {2}! + + + Numero specificato invalido. Puoi tirare {0}-{1} dadi alla volta. + Fuzzy + + + Ha rollato {0} + Someone rolled 35 +Fuzzy + + + Dado rollato: {0} + Dice Rolled: 5 +Fuzzy + + + Fallito a iniziare la gara. Un'altra gara è probabilmente in corso. + + + Nessuna gara esistente su questo server. + + + Il secondo numero dev'essere maggiore del primo. + + + Cambi di cuore + + + Rivendicato da + + + Divorziati + + + Piace + + + Prezzo + + + Nessuna waifu è stata rivendicata. + + + Classifica delle waifu + + + + + + ha cambiato la sua affinità da {0} a {1}. + +*È moralmente questionabile.*🤔 + Make sure to get the formatting right, and leave the thinking emoji + + + Devi aspettare {0} ore e {1} minuti prima di poter cambiare di nuovo la tua affinità. + + + La tua affinità è stata reimpostata. Non ti piace più nessuno. + + + vuole essere la waifu di {0}. Aww <3 + + + ha rivendicato {0} come la sua waifu per {1}! + + + Hai divorziato da una waifu a cui piacevi. Sei un mostro senza cuore. +{0} riceve {1} come risarcimento. + + + Non puoi impostare l'affinità su te stesso, tu egomaniaco. + + + 🎉 Il loro amore è soddisfatto! 🎉 +il nuovo valore di {0} è {1}! + Fuzzy + + + Nessuna waifu vale così poco. Devi pagare almeno {0} per avere una waifu, malgrado il suo valore reale fosse minore. + + + Devi pagare {0} o più per poter rivendicare quella waifu! + + + Quella waifu non è tua. + + + Non puoi auto-rivendicarti. + + + Hai divorziato recentemente. Devi aspettare {0} ore e {0} minuti per poter divorziare di nuovo. + + + Nessuno + + + Hai divorziato da una waifu a cui non piacevi. Riottieni {0} Indietro. + + + palla8 + + + Acrofobia + + + Partita conclusa senza risposte. + + + Nessuno ha votato. Partita conclusa senza vincitori. + + + L'acronimo era {0} + + + Una partita di Acrofobia è già in corso su questo canale. + + + Partita avviata. Crea una frase utilizzando il seguente acronimo: {0}. + + + Hai {0} secondi a disposizione per rispondere. + + + {0} ha dato la sua risposta. ({1} in totale) + + + Vota digitando il numero della risposta + + + {0} ha votato! + Fuzzy + + + Il vincitore è {0} con {1} punti. + + + {0} è il vincitore poiché è stato l'unico ad aver dato una risposta! + + + Domanda + + + E' un pareggio! Entrambi avete scelto {0} + + + {0} vince! {1} batte {2} + + + Il tempo per rispondere è scaduto + + + La corsa degli animali è già iniziata. + + + Totale: {0} Media: {1} + + + Categoria. + + + Cleverbot è stato disabilitato in questo server. + + + Cleverbot è stato abilitato in questo server. + + + + + + + + + + plural + + + + + + Impossibile caricare una domanda. + + + Partita iniziato + + + Gioco dell'impiccato iniziato + + + Il gioco dell'impiccato è già in corso in questo canale. + + + Impossibile iniziare il gioco dell'impiccato. + Fuzzy + + + + + + Classifica + + + Non hai abbastanza {0} + + + Nessun risultato + + + raccolto {0} + Kwoth picked 5* + + + {0} ha piantato {1} + Kwoth planted 5* + + + Un gioco dei trivia è già in corso su questo canale. + + + Gioco dei trivia + + + {0} ha indovinato! La riposta era: {1} + + + Nessun gioco dei trivia è in corso su questo server. + + + {0} ha {1} punti + + + Il gioco terminerà dopo questa domanda. + + + Tempo scaduto! La risposta corretta era {0} + + + {0} ha indovinato ed è il VINCITORE! La risposta era: {1} + + + Non puoi giocare contro te stesso. + + + Una partita di Tris è già in corso in questo canale. + + + Pareggio! + + + ha avviato una partita di Tris. + + + {0} ha vinto! + + + + + + Nessuna mossa rimanente! + + + Tempo scaduto! + + + + + + {0} vs {1} + + + + + + Autoplay disabilitato. + + + Autoplay abilitato. + + + Volume di default impostato a {0}% + + + + + + + + + Canzone finita + + + + + + + + + Dalla posizione + + + Id + + + Input non valido + + + + + + + + + + + + + + + + + + Nome + + + In riproduzione + + + + + + Nessun risultato trovato. + + + + + + + + + Canzone iniziata + + + + + + + + + Playlist cancellata. + + + Impossibile cancellare quella playlist perché non esiste oppure perché non ne sei l'autore. + + + Non esiste una playlist con quel ID. + + + Playlist in coda completata. + + + Playlist salvata + + + + + + Coda + + + Canzone in coda + + + + + + + + + Canzone rimossa + context: "removed song #5" + + + + + + + + + Traccia ripetuta + + + + + + + + + + + + + + + + + + + + + Canzoni mischiate + + + Canzone spostata + + + {0}o {1}m {2}s + + + Alla posizione + + + infinito + + + Il volume dev'essere impostato fra 0 e 100. + + + Volume impostato a {0}% + + + Non può essere più usato ALCUN MODULO in questo canale. + + + Possono essere usati TUTTI I MODULI in questo canale. + + + Concesso + + + Il ruolo {0} non può più usare ALCUN MODULO. + + + Il ruolo {0} può usare TUTTI I MODULI. + + + Non può essere più usato ALCUN MODULO in questo server. + + + Possono essere usati TUTTI I MODULI in questo server. + + + L'utente {0} non può più usare ALCUN MODULO. + + + L'utente {0} può usare TUTTI I MODULI. + + + + + + + + + + + + + + + Costo dei comandi + + + Disattivare l'uso di {0} {1} in questo canale {2}. + + + Attivare l'uso di {0} {1} in questo canale {2}. + + + Permesso negato + + + Aggiunta la parola {0} alla lista delle parole bandite. + + + Lista di parole bandite + + + Rimossa la parola {0} dalla lista delle parole bandite. + + + Parametro dei secondi non valido.(Deve essere un numero tra {0} e {1}) + + + + + + + + + + + + + + + + + + + + + Nessun costo impostato. + + + Comando + Gen (of command) + + + Modulo + Gen. (of module) + + + Pagina dei comandi {0} + + + + + + Gli utenti ora devono avere il ruolo di {0} per modificare i permessi. + + + + + + + + + + + + + + + + Short of seconds. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Abilità + + + Nessun anime preferito + + + Iniziata la traduzione automatica dei messaggi in questo canale. I messaggi degli utenti verranno automaticamente cancellati. + + + La tua traduzione automatica dei messaggi è stata rimossa. + + + La tua auto-traduzione linguaggio è stato impostata a {0}>{0} + Fuzzy + + + Avviata traduzione automatica dei messaggi in questo canale. + + + Annullata traduzione automatica dei messaggi in questo canale. + + + Formato input errato o errore sconosciuto. + + + Non ho trovato quella carta. + Fuzzy + + + Curiosità + + + Capitoli + + + + + + Competitive perse + + + Competitive giocate + + + Rango delle competitive + Fuzzy + + + Competitive Vinte. + + + Completato + + + Condizione + + + Costo + + + Data + + + Definisci: + + + Abbandonato + + + Episodi + + + Errore. + + + Esempio. + + + Fallito a trovare questo anime. + + + Fallito a trovare questo manga. + + + Genere + + + Fallito a trovare la definizione per questo tag. + + + Altezza/Peso + + + + + + Umidità + + + Ricerca immagine per: + + + Fallito a trovare questo film. + + + + + + Scherzo non caricato. + + + Latitudine/Lunghezza + Fuzzy + + + Livello + + + + Don't translate {0}place + + + Luogo + + + Oggetto magico non caricato. + + + + + + + + + Minimo/Massimo + + + Nessun canale trovato. + + + Nessun risultato trovato. + + + + + + Url originale + Fuzzy + + + + + + + + + + + + + + + In programma da guardare + + + Piattaforma + + + Nessun abilità trovata. + + + Nessun pokèmon trovato. + + + Link profilo: + + + Qualità: + + + + + + + + + Voto + + + Punteggio: + + + Ricerca per: + + + Non è stato possibile accorciare quel url. + + + Accorcia url + + + Qualcosa è andato storto. + + + Per favore specifica i parametri della ricerca. + + + Stato + + + Conserva url + + + Lo streamer {0} è offline. + + + Lo streamer {0} è online con {1} spettatori. + + + Stai seguendo {0} streaming in questo server. + + + Non stai seguendo nessuno streaming in questo server. + + + + + + Questo streaming probabilmente non esiste. + + + Rimossi {0} streaming ({1}) dalle notifiche + + + Io notificherò in questo canale quando il suo stato cambia. + Fuzzy + + + Alba + + + Tramonto + + + Temperratura + + + Titolo: + + + Top 3 anime preferiti: + + + Traduzione: + + + Tipi + + + + + + Url + + + Spettatori + + + Seguendo + Fuzzy + + + + + + + + + Pagina non trovata. + + + Velocità del vento + + + I campioni più bannati di {0} + + + + + + + + + + /s and total need to be localized to fit the context - +`1.` + + + + + + {0} utenti in totale. + + + Autore + + + ID del bot + + + + + + + + + Canale di discussione + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Emoji personalizzati + + + Errore + + + Funzioni + Fuzzy + + + ID + + + + + + + + + + + + + Invalid months value/ Invalid hours value + + + Si è unito a Discord + + + Si è unito al server + + + ID: {0} +Membri: {1} +ID del proprietario: {2} + + + + + + + + + Membri + + + Memoria + + + Messaggi + + + Ripetitore di Messaggi + + + Nome + + + Soprannome + + + Nessuno sta giocando a quel gioco. + + + Nessun ripetitore attivo. + + + Nessun ruolo in questa pagina. + + + + + + Nessun argomento impostato. + + + Proprietario + + + ID del proprietario + + + Presenza + + + {0} Server +{1} Canali di testo +{2} Canali vocali + + + Eliminato tutte le parole con {0} all'interno. + + + Pagina {0} delle citazioni + + + Nessuna citazione in questa pagina. + + + Nessuna citazione trovata che tu possa rimuovare. + + + Citazione Aggiunta + + + Citazione #{0} cancellata. + + + Regione + + + Registrato il + + + + + + + + + + + + + + + Lista dei ripetitori + + + Nessun ripetitore funzionante in questo server. + Fuzzy + + + #{0} fermato. + + + Nessun messaggio ripetuto trovato in questo server. + + + Risultato + + + Ruoli + + + + + + + + + Nessun colore è nel formato giusto. Usa `#00ff00` per esempio. + + + Iniziata rotazione {0} dei ruoli colorati. + Fuzzy + + + Fermata la rotazione dei colori per il {0} ruolo + + + + + + Info del server + + + + + + + + + + + + + + + + + + + + + Canali di testo + + + + + + + + + + Id of the user kwoth#1234 is 123123123123 + + + Utenti + + + Canali vocali + + + Sei già entrato in gara! + + + + + + + + + + + + + + + + + + {0} ha votato. + Kwoth voted. + + + Mandami in privato il numero della risposta. + + + Scrivi qui il numero della risposta. + + + Grazie per aver votato, {0} + + + {0} voti in totale. + + + + + + + + + Nessun utente trovato. + + + pagina {0} + + + Devi essere in un canale vocale in questo server. + + + Non ci sono ruoli nei canali vocali. + + + + + + + + + + + + + + + + + + + + + + + + + + + Nessun alias trovato + + + + + + + + + + + + + + + + + + \ No newline at end of file From 5bed3ed601458ade1d3f4c52d18f538d7e22a688 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 27 Mar 2017 14:35:23 +0200 Subject: [PATCH 627/746] Added korean and hebrew --- .../Commands/LocalizationCommands.cs | 2 + .../Resources/ResponseStrings.he-IL.resx | 2276 ++++++++++++++++ .../Resources/ResponseStrings.ko-KR.resx | 2373 +++++++++++++++++ 3 files changed, 4651 insertions(+) create mode 100644 src/NadekoBot/Resources/ResponseStrings.he-IL.resx create mode 100644 src/NadekoBot/Resources/ResponseStrings.ko-KR.resx diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 19930059..b61b2722 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -24,8 +24,10 @@ namespace NadekoBot.Modules.Administration {"en-US", "English, United States"}, {"fr-FR", "French, France"}, {"de-DE", "German, Germany"}, + {"he-IL", "Hebrew, Israel" }, {"it-IT", "Italian, Italy" }, //{"ja-JP", "Japanese, Japan"}, + {"ko-KR", "Korean, Korea" }, {"nb-NO", "Norwegian (bokmål), Norway"}, {"pl-PL", "Polish, Poland" }, {"pt-BR", "Portuguese, Brazil"}, diff --git a/src/NadekoBot/Resources/ResponseStrings.he-IL.resx b/src/NadekoBot/Resources/ResponseStrings.he-IL.resx new file mode 100644 index 00000000..5ddf049e --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.he-IL.resx @@ -0,0 +1,2276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + הבסיס הזה נתפס או נהרס. + + + הבסיס הזה כבר נהרס. + + + הבסיס הזה לא נתפס. + + + הבסיס #{0} **הושמד** במלחמה נגד {1} + + + + + + + + + + + + + + + אויב + + + מידע על המלחה נגד {0} + + + מספר בסיס שגוי + + + לא גודל מלחמה נכון. + + + רשימת מלחמות פעילות + + + לא תפוס + + + אתה לא משתתף במלחמה הזאת + + + @{0} אתה כנראה לא משתתף במלחמה הזאת או הבסיס הזה כבר הושמד. + + + אין מלחמות פעילות. + + + גודל + + + המלחה נגד {0} כבר התחילה. + + + מלחמה נגד {0} נוצרה. + + + המלחמה נגד {0} נגמרה. + + + המלחמה הזאת לא קיימת. + + + מלחמה נגד {0} התחילה! + + + כל הסטטיסטיקה של התגובות מתאם נמחקו. + + + תגובות מתאם נמחקו + + + אין מספיק רשות, מתחייבת בעלות של הבוט בשביל תגובות מתאם גלובליות, ומנהג בשביל תגובות מתאם של הרשת. + + + רשימה של כל התגובות מתאם + + + תגובות מתאם + + + תגובות מתאם חדשות + + + לא נמצאו תגובות מתאם. + + + לא נמצאו תגובות מתאם אם הזהות הזאת. + + + תגובה + + + + + + + + + + + + + + + + + + לא נמצאו תוצאות. + + + {0} כבר התעלף. + + + {0} כבר בחיים מלאים. + + + הסוג שלך הוא כבר {0} + + + {0}{1} שומש על {2}{3} שעשה {4} נזק. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + אתה לא יכול לתקוף שוב שד שיתקפו אותך. + + + אתה לא יכול לתקוף את עצמך. + + + {0} נתעלף. + + + {0} רופה עם {1} אחד. + + + ל{0} נשארו {1} חיים. + + + אתה לא יכול להשתמש ב{0}. תרשום "{1}ml" כדי לראות את רשימת המהלכים שאת יכול להשתמש בהם. + + + רשימת המהלכים לסוג {0} + + + זה לא אפקטיבי. + + + איך לך מספיק {0} + + + {0} הוחזר לתחייה עם {1} אחד. + + + החזרתה את אצמך עם {1} אחד. + + + הסוג שלך שונה ל{0} בתמורה ל{1}. + + + זה טיפה אפקטיבי. + + + זה ממש אפקטיבי! + + + השתמשת ביותר מדי מהלכים אז אתה לך יכול לזוז. + + + הסוג של {0} הוא {1} + + + משתמש לא נמצא. + + + את\ה התעלפת אז את\ה לא יכול לזוז. + + + + + + + + + קבצים מצורפים + + + תמונת פרופיל שונתה + + + אתה הוסרת משרת {0}. +סיבה: {1} + + + מגורש + PLURAL + + + משתמש גורש + + + השם של הבוט השתנה ל{0} + + + הסטטוס של הבוט השתנה ל{0} + + + ההסרה האוטומטית של הודאת השלום לא בשימוש. + + + הודאת השלום תמחק בעוד {0} שניות. + + + הודעת עזיבה נוכחית: {0} + + + אפשור הודאת שלום דרך כתיבת {0} + + + התראת עזיבה חדשה הוגדרה. + + + התראת עזיבה לא פעילה. + + + התראת עזיבה הופעלה עבור ערוץ זה. + + + השם של הערוץ השתנה + + + שם ישן + + + נושא ערוץ שונה + + + נוקה. + + + תוכן + + + תפקיד נוצר בהצלחה {0} + + + ערוץ טקסט {0} נוצר. + + + ערוץ קול {0} נוצר. + + + החרשה הצליחה. + + + השרת {0} נמחק + + + + + + + + + ערוץ טקסט {0} נמחק. + + + ערוץ קול {0} נמחק. + + + הודאה פרטית מ{0} + + + תורם חדש הוסף בהצלחה. כמות כוללת שנתרמה ממשתמש זה: {0} 👑 + + + תודה לאנשים המצורפים למטה על הצלחת הפרויקט! + + + אני האביר את ההודאות הפרטיות לכל הבעלים. + + + אני האביר את ההודאות הפרטיות לבעלים הראשונים. + + + אני האביר את ההודאות הפרטיות מעכשיו. + + + אני אפסיק להעביר את ההודאות הפרטיות מעכשיו. + + + + + + + + + הודאה פרטית נוכחית: {0} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + אתה לא יכול להשתמש בפקודה זו על משתמשים עם תפקיד שווה או גבוהה ממך בדירוג. + + + התמונות יעלו אחרי {0} שניות. + + + הפורמט המבוקש שגוי. + + + פרמטרים לא חוקיים. + + + {0} הצטרף {1} + + + + אתה הוסרת מהשרת {0} בגלל הסיבה: {1} + + + משתמש נבעט. + + + רשימה של כל השפות + + + + + + + + + שפת הבוט שונתה מ{0} ל{1}. + + + + + + שפת שרת זה מוגדרת כ- {0} - {1} + + + {0} עזב {1} + + + {0} עזב את השרת + + + רישום של האירוע {0} בערוץ זה. + + + רישום כל האירועים בערוץ זה. + + + הרישום הופסק. + + + תרשום את האירועים שאתה יכול להירשם אליהם. + + + הרישום יתעלם מ{0} + + + הרישום לא יתעלם מ{0} + + + הרישום לאירוע {0} נפסק. + + + + + + הודעה מ{0} ׳[מנהל הבוט]׳ + + + הודעה נשלחה. + + + {0} עבר מ{1} ל{2}. + + + הודעה נמחקה ב#{0} + + + הודעה עדכנה ב#{0} + + + מושתק + PLURAL (users have been muted) + + + מושתק + singular "User muted." + + + כנראה שאין לי הרשאה לזה. + + + תפקיד מושתק חדש נוצר. + + + אני צריך אישור **מנהל** כדי לעשות את זה. + + + הודעה חדשה + + + כינוי חדש + + + נושא חדש + + + כינוי שונה + + + לא ניתן למצוא את השרת + + + + + + הודעה ישנה + + + כינוי ישן + + + נושא ישן + + + שגיאה. כנראה אין לי את האישורים המתאימים. + + + ההרשאות לשרת זה התחדשו. + + + הגנות פועלות + + + {0} **הופסק** בשרת זה. + + + {0} אופשר. + + + שגיאה. אני צריך אישור **ManageRole** + + + אין הגנות פעילות + + + הסף של המשתמש צריך להיות בין {0} ל{1}. + + + אם {0} או יותר משתמשים יצטרפו בעוד {1} שניות, אני {2} אותם. + + + הזמן חייב להיות בין {0} ו{1} שניות. + + + כל התפקידים הוסרו בהצלחה ממשתמש {0} + + + הסרת התפקיד נכשלה. אין לי מספיק הרשאות. + + + הצבע של {0} התפקיד היה שונה. + + + התפקיד הזה לא קיים. + + + הפרמטר המבוקש אינו חוקי. + + + השגייה התרחשה בגלל צבע לא נכון או חוסר הרשאות. + + + התפקיד {0} הוסר בהצלחה ממשתמש {0} + + + הסרת התפקיד נחשלה. אני לי מספיק הרשאות. + + + שם התפקיד השתנה. + + + שינוי התפקיד מחשל. אני לי מספיק הרשאות. + + + אתה לא יכול לעדכן תפקידים גבוהים משלך. + + + ההודאה המוקלטת הוסרה: {0} + + + תפקיד {0} הוסף לרשימה. + + + {0} לא נמצא. נוקה. + + + התפקיד {0} כבר נמצא ברשימה. + + + הוסף. + + + סטטוס משתנה הופסק. + + + סטטוס משתנה הותחל. + + + הנה רשימה של סטטוסים מסתובבים: {0} + + + לא נקבע סטטוס משתנה. + + + יש לך כבר {0} תפקיד. + + + + + + + + + + + + + + + אין לך {0} תפקיד. + + + + + + + + + + + + אין לך את התפקיד {0}. + + + יש לך את התפקיד {0}. + + + + + + + + + תמונת הפרופיל הוספה. + + + שם הערוץ החדש נקבע. + + + משחק חדש נוצר. + + + + + + + + + + + + + + + קורס + + + משתמשים לא יכולים לשלוח יותר מ{0} הודאות כל {1} שניות. + + + מצב איתי הופסק. + + + מצב איתי הותחל. + + + הסרה קלה (גורש) + PLURAL + + + {0} יתעלם מערוץ זה. + + + {0} לא יתעלם מערוץ זה. + + + + + + ערוץ כתב נוצר. + + + ערוץ כתב הושמד. + + + + + + + singular + + + שם משתמש + + + שם משתמש שונה + + + משתמשים + + + משתמש מורחק + + + + + + + + + משתמש הצתרף + + + משתמש עזב + + + + + + התפקיד של המשתמש הוסף. + + + התפקיד של שמשתמש הורד. + + + {0} עכשיו {1} + + + + + + {0} הצטרף ל{1} ערוץ קול. + + + {0} עזב מ{1} ערוץ קול. + + + {0} עבר מ{1} ל{2} ערוץ קול. + + + + + + + + + ערוץ קול הוצר + + + ערוץ קול מושמד + + + תכונה של קול + טקסט מכובה. + + + תכונה של קול + טקסק אופשרה. + + + אין לי רשות **נהל תפקידים** וגם/או **נהל ערוצים**, אז אני לא יכול להריץ `קול+טקסט` על {0} רשת. + + + אתה מאפשר/שולל את התכונה הזאת ו**לי אין רשות של מנהל**. זה יכול לגרום לכמה בעיות, ואתה תתצרך לנקות את ערוצי הטקסט בעצמך אחר כך. + + + אני חייב לפחות **נהל תפקידים** ו**נהל ערוצים** הרשאות כדי לאפשר את התכונה הזאת. (רשות של מנהל מועדפת) + + + משתמש {0} מטקסט צ׳אט + + + משתמש {0} מטקסט וקול צ׳אט + + + משתמש {0} מערוץ קול. + + + + + + + + + נדידה גמורה! + + + שגיעה בזמן הנדידה, תבדוק את ה מסוף בקרה של הבוט בשביל יותר מידע. + + + + + עדכון נוכחות + + + + + + העניק {0} ל{1} + + + בהצלחה בפעם הבאה ^_^ + + + מזל טוב! אתה ניצחת {0} עבור זה שגלגלת מעבר מ{1} + + + חסיפה מעורבבת. + + + הפך {0}. + User flipped tails. + + + אתה ניחשת את זה! ניצחת {0} + + + המספר שצוין אינו חוקי. אתה יכול להעיף 1 עד {0} מטבעות. + + + תצרף תגובה {0} להודעה הזאת כדי לקבל {1}. + + + האירוע הזה פעיל עד {0} שעות. + + + אירוע תגובות הפרח התחיל! + + + נתן מתנה של {0} ל{1} + X has gifted 15 flowers to Y + + + {0} יש {1} + X has Y flowers + + + ראש + + + לוח תוצאות + + + הוענק {0} ל {1} למשתמשים מ{2} תפקיד. + + + אתה לא יכול להמר יותר מ-{0} + + + אתה לא יכול להמר פחות מ-{0} + + + אין לך מספיך {0} + + + אין יותר קלפים בחפיסה. + + + משתמש הגרלות + + + אתה גלגלת {0}. + + + להמר + + + ווווווווווווואאווו!!! מזל טוב!!! x{0} + + + {0} יחיד, x{1} + + + וואו! בר מזל! שלושה מאותו הסוג! x{0} + + + עבודה טובה! שני {0} - ההימור x{1} + + + זכית + + + משתמשים חייבים להקליד קוד סודי כדי לקבל {0}. נמשך {1} שניות. אל תספר לאף אחד. ששש. + + + האירוע של משחקערמומי הסתיים. {0} משתמשים קיבלו את הפרס. + + + משחקערמומיסטטוס אירוע התחיל + + + זנב + + + בהצלחה נלקח {0} מ{1} + + + לא הצליח לקחת {0} מ{1} משום שלמשתמש אין כל כך הרבה {2}! + + + חזר לToC + + + מנהל של הבוט בלבד + + + מתחייבת {0} רשות ערוץ. + + + אתה יכול לתמוח בפרוייקט על Patreon: <{0}> או Paypal: <{1}> + + + פקודות וכינויים + + + רשימת הפיקוד התחדשה. + + + + + + אני לא יכול למצוא את הפקודה הזאת. בבקשה תוודא שהפקודה הזאת נמצאת לפני שתנסה שוב. + + + תאור + + + אתה יכול למתוח את הנאדקובוט פרוייקט על Patreon <{0}> או Paypal <{1}> +אל תשכח להשאיר את השם של הדיסקורד שלך או הזהוי בהודעה. + +**תודה** ♥️ + + + **רשימה של פקודות**: <{0}> +**מדריכי אירוך ומסמכים אפשר למצוא כאן**: <{1}> + + + רשימה של פקודות + + + רשימה של מודולים + + + + + + המודול הזה לא קיים. + + + נדרשת {0} רשות השרת. + + + תוכן העניינים + + + נוהג + + + הנטאי אוטומטי התחיל. פורסים מחדש כל {0}ש עם אחד מהתגים הבאים: +{1} + + + תג + + + מרוץ בעלי חיים + + + נכשל להתחיל מכיוון שלא היו מספיק משתתפים. + + + המרוץ מלא! מתחיל מיד. + + + {0} הצתרף כ{1} + + + {0} הצתרף כ{1} והימר {2}! + + + תרשום jr{0} כדי להצתרף למרוץ. + + + מתחיל ב20 שניות או מתי שהחדר מלא. + + + מתחיל עם {0} משתתפים. + + + {0} כ{1} ניצח במרוץ! + + + {0} כ{1} ניצח במרוץ ו{2}! + + + המספר שצוין אינו חוקי. אתה יכול לגלגל {0}-{1} קוביות בבת אחת. + + + גלגל {0} + Someone rolled 35 + + + הקוביה גלגלה: {0} + Dice Rolled: 5 + + + נכשל להתחיל את המרוץ. יכול להיות שמרוץ אחר כבר פעיל. + + + אין מרוץ קיים ברשת הזאת. + + + המספר השני חייב להיות גדול יותר מהמספר הראשון. + + + שינויים של הלב + + + נתבע על ידי + + + גירושים + + + מחבב + + + מחיר + + + שום וואיפוס נתבעו עדיין. + + + וואיפוס ראשיות + + + הזיקה שלך כבר מוגדרת לוואיפו הזאת או שאתה מנסה להסיר את ההזיקה שלך בזמן שאין לך אחת. + + + שינה את הזיקה שלהם מ{0} ל{1} + +*זה מפקפק באופן מוסרי.* 🤔 + Make sure to get the formatting right, and leave the thinking emoji + + + אתה חייב לחכות {0} שעות ו{1} דקות כדי לשנות את הזיקה שלך עוד פעם. + + + הזיקה שלך אופסה. אין לך יותר אדם שאתה מחבב. + + + רוצה להיות וואיפו של {0}. אוו 3> + + + תבע {0} כהוואיפו שלהם בשביל {1}! + + + אתה גירשת וואיפו שאוהבת אותך. אתה מפלצת חסרת לב. +{0} קיבל {1} כפיצוי. + + + אתה לא יכול להגדיר זיקה לעצמך, אתה אגומניאק. + + + 🎉 האהבה שלהם התגשמה! 🎉 +הערך החדש של {0} הוא {1} + + + שום וואיפו כל כך זולה. אתה חייב לשלם לפחות {0} כדי להדיג וואיפו, אפילו אם הערך האמיתי שלהם נמוך יותר. + + + אתה חייב לשלם {0} או יותר בשביל לתבוע את הוואיפו הזאת! + + + הוואיפו הזאת לא שלך. + + + אתה לא יכול לתבע את עצמך. + + + אתה התגרשת לא מזמן. אתה צריך לחכות {0} שעות ו{1} דקות כדי להתגרש עוד פעם. + + + אף אחד + + + אתה גירשת וואיפו שלא מחבבת אותך. אתה קיבלת {0} בחזרה. + + + 8כדור + + + פחד גבהים + + + המשחק הסתיים ללא הגשות. + + + אין הצבעות. המשחק הסתיים ללא מנצח. + + + ראשי התיבות היו {0}. + + + משחק פחד גבהים כבר פועל בערוץ הזה. + + + המשחק התחיל. תכינו משפט עם הראשי התיבות הבאים: {0}. + + + יש לך {0} שניות כדי לעשות הגשה. + + + {0} הגיש את המשפט שלהם. ({1} בסכם) + + + תצביע על ידי הקלדת מספר ההגשה + + + {0} הצביעו! + + + המנצח הוא {0} עם {1} נקודות + + + {0} המנצח בגלל שהוא המשתמש היחיד שעשה הגשה! + + + שאלה + + + זה תיקו! שניהם הרימו {0} + + + {0} ניצח! {1} מביס {2} + + + ההגשות סגורות + + + מרוץ חיות כבר התחיל. + + + סה"כ: {0} ממוצע: {1} + + + קטגוריה + + + קלברבוט מכובה על השרת הזה. + + + קלברבוט מופעל על השרת הזה. + + + דור המטבע מופעל על הערוץ הזה. + + + דור המטבע מכובה על הערוץ הזה. + + + {0} מקרי {1} הופיע! + plural + + + מקרי {0} הופיע! + + + נכשל לטעון שאלה. + + + משחק התחיל + + + משחק איש תלוי התחיל + + + משחק איש תלוי בל פעיל על הערוץ הזה. + + + שגיאה בהתחלה של איש תלוי + + + רשימה של "{0}איש תלוי" סוגי טווח: + + + לוח תוצאות + + + אין לך מספיק {0} + + + אין תוצאות + + + תלש {0} + Kwoth picked 5* + + + {0} שתל {1} + Kwoth planted 5* + + + משחק טריוויה כבר פועל ברשת הזאת. + + + משחק טריוויה + + + {0} ניחש את זה! התשובה הייתה: {1} + + + משחק טריוויה לא פעיל על השרת הזה. + + + {0} יש {1} נקודות + + + עוצר אחרי השאלה הזאת. + + + הזמן עבר! התשובה הנכונה הייתה {0} + + + {0} ניחש את זה וניצח במשחק! התשובה הייתה: {1} + + + אתה לא יכול לשחק נגד עצמך. + + + משחק איקס ועיגולים כבר פעיל על הערוץ הזה. + + + תיקו! + + + יצר משחק של איקס ועיגולים. + + + {0} ניצח! + + + שלושה מתאימים + + + אין יותר מהלכים! + + + הזמן עבר! + + + המהלך של {0} + + + {0} נגד {1} + + + מנסה לשים {0} שירים בתור... + + + הפעלה אוטומטית מכובה. + + + הפעלה אוטומטית מופעלה. + + + ווליום ברירת מחדל מכוון ל%{0} + + + תור מנחה מושלם. + + + לנגןהוגן + + + שיר הסיים + + + לנגן הוגן מכובה. + + + לנגן הוגן מופעל. + + + מתוך עמדה + + + זהוי + + + קלט לא תקין. + + + מקסימום פלייטיים אין הגבלה עכשיו. + + + מקסימום פלייטיים קבע ל{0} שניות. + + + גודל התור של מקסימום מוזיקה קבע ללא הגבלה. + + + הגודל של מקסימום תור מוזיקה קבע ל{0} מסלול(ים). + + + אתה חייב להיות בערוץ קול על השרת הזה. + + + שם + + + עכשיו מנגן + + + אין נגן מוזיקה פעיל. + + + אין תוצאות חיפוש + + + השמעת מוזיקה נעצרה. + + + תור השחקן - עמוד {0}/{1} + + + מנגן שיר + + + `#{0}` - **{1}** by *{2}* ({3} שירים) + + + עמוד {0} של פלייליסטים שמורים + + + פלייליסט נמחק. + + + נכשל לנסות למחוק אל הפלייליסט הזה. זה אולי לא קיים, או שאתה לא מחברו. + + + פלייליסט עם הזהוי הזה לא קיים. + + + תור הפלייליסט שלם. + + + פליילסט נשמר + + + {0} הגבלה + + + תור + + + שיר בתור + + + תור המוזיקה נוקה. + + + התור מלא ב{0}/{0} + + + שיר מחוק + context: "removed song #5" + + + חוזרים על השיר הנוכחי + + + חוזרים על הפלייליסט + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + מותר + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + נשלל + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gen (of command) + + + + Gen. (of module) + + + + + + + + + + + + + + + + + + + + + + + + + Short of seconds. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + הפרוש המידי שלך לשפה זאת הוסרה. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + שגיעה נוצרה + + + דוגמה + + + מציאת האנימה נחשל. + + + מציאת המנגה נחשלה + + + ג'אנר + + + + + + גובה/משקל + + + {0}מ'/{1}ק"ג + + + לחות + + + חיפוש תמונה של: + + + מציאת מסרט נחשל. + + + מקור או שפה לא נכונה. + + + בדיחה לא הועלתה. + + + + + + רמה + + + + Don't translate {0}place + + + מיקום + + + חפץ הקסם לא הועלה. + + + + + + + + + הכי פחות/הרבה + + + + + + אין תוצעות + + + במעצר + + + הקישור המקורי + + + + + + + + + + + + + + + מתקבן לראות + + + פלטפורמה + + + יכולת לא נמצאה + + + פוקמון לא נמצא + + + קישור פרופיל: + + + איכות: + + + + + + ניצחונות מהירים + + + דירוג + + + ניקוד: + + + חיפוש של: + + + קיצר שורת הקישור נחשל + + + קישור קצר + + + משהו השתבש + + + + + + + + + קישור החנות + + + + + + + + + + + + + + + + + + + + + + + + + + + זריחה + + + שקיעה + + + טמפרטורה + + + + + + שלושת האנימות הטובות ביותר: + + + פרוש: + + + סוגים + + + מציעת הפרושים של המוסג הזה נחשל. + + + קישור + + + צופים + + + צופה + + + + + + + + + העמוד לא נמצא + + + מהירות הרוח + + + + + + + + + הצתרף + + + + /s and total need to be localized to fit the context - +`1.` + + + + + + + + + יוצר + + + מס' זהות של הבוט + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Invalid months value/ Invalid hours value + + + + + + + + + מס' זהות: {0} +משתמשים: {1} +בעלי המס' זהות: {2} + + + + + + + + + משתמשים + + + זיכרון + + + הודאות + + + + + + שם + + + כינוי + + + אף אחד לא משחק במשחק הזה + + + + + + + + + + + + + + + בעלים + + + מס' זהות של הבעלים + + + + + + + + + מחק את כל הציטוטים עם {0} מילות המפתח. + + + עמוד {0} של ציטוטים. + + + אין ציטוטים בעמוד זה. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0} של המשתמש {1} הינו {2} + Id of the user kwoth#1234 is 123123123123 + + + משתמשים + + + + + + אתה כבר חלק מהמרוץ הזה. + + + + + + + + + + + + + + + + + + {0} הצביע. + Kwoth voted. + + + + + + + + + תודה שהצבעתת {0} + + + + + + בחר אותם על ידי הקלדת `{0}בחר` + + + + + + משתמש לא נמצא. + + + דף {0} + + + אתה חייב להיות בערוץ קול. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.ko-KR.resx b/src/NadekoBot/Resources/ResponseStrings.ko-KR.resx new file mode 100644 index 00000000..cf1c65d5 --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.ko-KR.resx @@ -0,0 +1,2373 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 기지가 이미 요청되었거나 파괴되었습니다. + Fuzzy + + + 기지가 이미 파괴되었습니다. + + + 기지가 요청당하지 않았습니다. + + + {1} 와의 전쟁에서 #{0} 번 기지가 **파괴**되었습니다. + Fuzzy + + + {2} 와의 전쟁에서 {0} 가 #{1} 번 기지를 **요청**하지 못했습니다. + Fuzzy + + + {2} 와의 전쟁에서 #{1} 번 기지를 {0} 가 요청하였습니다. + + + @{0} 이미 #{1} 번 기지를 요청했습니다. 새로운 기지를 요청 할 수 없습니다. + + + {1} 와의 전쟁에서 @{0} 의 요청이 만료되었습니다. + Fuzzy + + + + Fuzzy + + + {0} 와의 전쟁에 대한 정보 + + + 유효하지 않은 기지 숫자입니다. + + + 유효하지 않은 전쟁 크기입니다. + + + 활성화된 전쟁 목록 + + + 요청되지 않았습니다. + + + 당신은 이 전쟁에 참여하고 있지 않습니다. + + + @{0} 당신은 그 전쟁에 참여하지 않거나 그 기지가 이미 파괴되었습니다. + + + 활성화된 전쟁이 없습니다. + + + 크기 + Fuzzy + + + {0} 에 대한 전쟁이 이미 시작되었습니다. + + + {0} 에 대한 전쟁이 생성되었습니다. + + + {0} 와의 전쟁이 종료되었습니다. + + + 전쟁이 존재하지않습니다. + + + {0} 와의 전쟁이 시작되었습니다. + + + 모든 커스텀 리액션에 대한 통계가 삭제되었습니다. + + + 커스텀 리액션이 삭제되었습니다. + + + 권한이 부족합니다. 전체 커스텀 리액션을 관리하기 위해서는 봇의 소유권과 서버의 관리자 권한이 필요합니다. + + + 모든 커스텀 리액션 목록 + + + 커스텀 리액션 + + + 새로운 커스텀 리액션 + + + 커스텀 리액션을 찾지 못했습니다. + + + 요청하신 ID에 대한 커스텀 리액션을 찾지 못했습니다. + + + 반응 + Fuzzy + + + 커스텀 리액션 통계 + + + {0} 에 대한 커스텀 리액션 통계가 삭제되었습니다. + + + 해당 트리거에 대한 통계를 찾지 못했으며, 아무런 행동도 취하지 않았습니다. + + + 트리거 + Fuzzy + + + Autohentai 기능이 정지되었습니다. + + + 결과를 찾지 못했습니다. + + + {0} 이(가) 이미 기절했습니다. + + + {0} 은(는) 이미 최대 체력입니다. + + + 당신은 이미 {0} 타입 입니다. + + + 님이 {2}{3} 에게 {0}{1} 을(를) 사용하여서 {4} 의 피해를 입혔습니다. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + 보복 없이는 다시 공격 할 수 없습니다. + + + 자신을 공격 할 수 없습니다. + + + {0} 이(가) 기절했습니다! + + + {1} 을(를) 사용하여서 {0} 을(를) 치료했습니다. + + + {0} 의 HP가 {1} 남아 있습니다. + + + {0} 을(를) 사용 할 수 없습니다. `{1}ml` 을(를) 입력해서 사용할 수 있는 움직임들의 리스트를 확인하세요. + + + {0} 종류 의 공격표 + Fuzzy + + + 효과적이지 않았다. + + + 당신은 충분한 {0} 가 없습니다. + + + {1} 을(를) 사용하여서 {0} 을(를) 소생했습니다. + + + {0} 을(를) 사용해서 자기자신을 소생시켰습니다. + + + 당신의 타입이 {0} 에서 {1} 으로 변경되었습니다. + + + 어느정도 효과가 있었다. + + + 효과는 굉장했다! + + + 너무 많은 공격을 연속해서 사용했으므로 이동할 수 없습니다! + + + {0} 의 종류는 {1} 입니다. + + + 사용자를 찾을 수 없습니다. + + + 당신은 기절해서 움직일 수 없습니다! + + + **자동 할당 역할**에 대한 사용자의 참여가 **비활성화**되었습니다. + + + **자동 할당 역할**에 대한 사용자의 참여가 **활성화**되었습니다. + + + 첨부파일 + + + 아바타가 변경되었습니다. + + + 당신은 {0} 서버에서 밴되었습니다. +사유: {1} + + + + PLURAL +Fuzzy + + + 사용자 밴 + Fuzzy + + + 봇의 이름이 {0} 으로 변경되었습니다. + + + 봇의 상태가 {0} 으로 변경되었습니다. + + + 퇴장 메세지의 자동삭제가 비활성화되었습니다. + Fuzzy + + + 퇴장 메세지는 앞으로 {0} 초 후에 삭제됩니다. + Fuzzy + + + 현재 퇴장 메세지: {0} + Fuzzy + + + 퇴장 메세지를 활성화하기 위해서는 {0} 를 입력하십시오. + Fuzzy + + + 새로운 퇴장 메세지가 설정되었습니다. + Fuzzy + + + 퇴장 알림이 비활성화되었습니다. + + + 이 채널에서 퇴장 알림이 활성화되었습니다. + + + 채널 이름이 변경되었습니다. + + + 이전 이름 + Fuzzy + + + 채널의 주제가 변경되었습니다. + + + 정리했습니다. + + + 내용 + Fuzzy + + + {0} 역할을 성공적으로 생성하였습니다. + + + 텍스트 채널 {0} 이(가) 생성되었습니다. + + + 음성 채널 {0} 이(가) 생성되었습니다. + + + 음소거되었습니다. + Fuzzy + + + {0} 서버를 삭제하였습니다. + + + 성공적으로 처리된 명령어에 대한 자동삭제가 중지되었습니다. + + + 이제 성공적으로 처리된 명령어를 자동삭제합니다. + + + 텍스트 채널 {0} 를 삭제했습니다. + + + 음성 채널 {0} 를 삭제했습니다. + + + 개인 메세지 + Fuzzy + + + 성공적으로 새로운 기부자를 추가했습니다. 이 유저의 총 기부량은 {0} 입니다. + + + 이 프로젝트를 위해 수고해주신 아래의 사람들에게 감사드립니다! + + + DM을 모든 봇 소유자에게 전달하겠습니다. + + + DM을 첫번째 봇 소유자에게만 전달하겠습니다. + + + 지금부터 DM을 전달하겠습니다. + + + 지금부터 DM 전달을 중단하겠습니다. + + + 환영 메세지에 대한 자동삭제가 비활성화되었습니다. + + + 환영 메세지는 {0} 초 후에 삭제될 것입니다. + + + 현재 DM 환영 메세지: {0} + + + {0} 을(를) 입력하여서 DM 환영 메세지를 활성화시킵니다. + + + 새로운 DM 환영 메세지가 설정되었습니다. + + + DM 환영 알림이 비활성화되었습니다. + 환영 알림 = 환영 메세지라고 해도될까요? + + + DM 환영 알림 활성화 되었습니다. + + + 현재 환영 메세지: {0} + + + {0} 를 입력하여서 환영 메세지를 활성화시킵니다. + + + 새로운 환영 메세지가 설정되었습니다. + + + 환영 알림이 비활성화되었습니다. + + + 이 채널의 환영 알림이 활성화되었습니다. + + + 당신은 이 명령어를 당신보다 상위나 동등한 권한관계를 가진 사람에게 쓸 수 없습니다. + + + 이미지가 {0} 초 후에 생성되었습니다! + Fuzzy + + + 유효하지않은 입력 포맷입니다. + + + 유효하지않은 파라미터입니다. + + + {0} 님이 {1} 에 입장하였습니다. + + + 당신은 {0} 서버에서 퇴장당했습니다. +사유 : {1} + + + 사용자 강제퇴장 + Fuzzy + + + 언어 목록 + + + 서버의 지역이 {0} - {1} 로 변경되었습니다. + + + 봇의 기본 지역이 {0} - {1} 로 변경되었습니다. + + + 봇의 언어가 {0} - {1} 로 설정되었습니다. + + + 지역 설정에 실패했습니다. 이 명령어의 도움말을 참고하십시오. + + + 이 서버의 언어가 {0} - {1} 로 변경되었습니다. + + + {0} 님이 {1} 에서 퇴장하셨습니다. + + + {0} 서버에서 퇴장하였습니다. + + + 이 채널의 {0} 이벤트를 로깅합니다. + + + 이 채널의 모든 이벤트를 로깅합니다. + + + 로깅이 비활성화되었습니다. + + + 구독 할 수 있는 로그 이벤트 : + + + 로그는 앞으로 {0} 을(를) 무시합니다. + + + 로그는 {0} 을(를) 더 이상 무시하지 않습니다. + + + {0} 이벤트에 대한 로그를 중지하였습니다. + + + {0} 이(가) 다음 역할에 대한 언급을 요청했습니다. + + + {0} `[봇의 소유자]` 로부터 메세지: + Fuzzy + + + 메세지가 전송되었습니다. + + + {0} 이(가) {1} 에서 {2} 로 이동했습니다. + + + #{0} 에서 메세지가 삭제되었습니다. + + + #{0} 에서 메세지가 업데이트되었습니다. + + + 음소거 + PLURAL (users have been muted) +Fuzzy + + + 음소거 + singular "User muted." +Fuzzy + + + 명령어를 수행하기 위한 권한이 부족합니다. + + + 새로운 음소거 역할이 설정되었습니다. + + + 요청하신 것을 처리하기 위해서는**관리자** 권한이 필요합니다. + + + 새로운 메세지 + + + 새로운 닉네임 + + + 새로운 주제 + + + 닉네임이 변경되었습니다. + + + 요청하신 서버를 찾을 수 없습니다. + + + 해당하는 Shard ID가 없습니다. + + + 이전 메세지 + + + 이전 닉네임 + + + 이전 주제 + + + 오류. 봇에게 충분한 권한이 없습니다. + + + 이 서버의 모든 권한이 초기화되었습니다. + + + 보호기능 활성화 + + + {0} 은(는) 이 서버에서 **비활성화**되었습니다. + + + {0} 가 활성화되었습니다. + + + 오류. 관리자 권한이 필요합니다. + + + 활성화된 보호기능이 없습니다. + + + 사용자의 값은 반드시 {0} 과 {1} 사이의 값이여야 합니다. + Fuzzy + + + 만약 {0} 명 이상의 사용자가 {1} 초안에 접속한다면 {2} 합니다. + Fuzzy + + + 시간은 {0} 초와 {1} 초 사이의 값이여야 합니다. + + + {0} 유저의 모든 역할을 성공적으로 삭제했습니다. + + + 역할 삭제에 실패했습니다. 권한이 부족합니다. + + + {0} 역할에 대한 색이 변경되었습니다. + + + 그 역할은 존재하지 않습니다. + + + 지정된 파라미터가 유효하지 않습니다. + + + 유효하지 않은 색이거나 권한이 부족하여서 오류가 발생했습니다. + Fuzzy + + + {1} 사용자에 대한 {0} 역할을 성공적으로 제거했습니다. + + + 역할 제거에 실패했습니다. 권한이 부족합니다. + + + 역할 이름이 변경되었습니다. + + + 역할 이름 변경에 실패했습니다. 권한이 부족합니다. + + + 자신보다 가장 높은 역할보다 높은 사용자의 역할을 수정할 수 없습니다. + + + 다루고있었든 메세지 치웠습니다: {0} + Fuzzy + + + {0} 역할을 리스트에 추가했습니다. + + + {0} 을(를) 찾을 수 없기때문에 삭제했습니다. + Fuzzy + + + {0} 역할은 이미 리스트에 추가된 상태입니다. + + + 추가했습니다. + + + 플레이 상태 로테이션이 비활성화되었습니다. + + + 플레이 상태 로테이션이 활성화되었습니다. + + + 플레이 상태 로테이션 리스트: +{0} + + + 플레이 상태 로테이션이 설정되지 않았습니다. + + + 당신은 이미 {0} 역할이 있습니다. + + + 당신은 이미 독점 자가 배정 역할 {0} 가 있습니다. + Fuzzy + + + 자가 배정 역할은 이제 하나만 선택 할 수 있습니다! + Fuzzy + + + {0} 개의 자가 배정 역할이 있습니다. + Fuzzy + + + 그 역할은 자신이 적용 할 수 없습니다. + + + 당신은 {0} 역할이 없습니다. + + + 자가 배정 역할은 이제 복수 선택 할 수 있습니다! + Fuzzy + + + 그 역할을 당신에게 추가 할 수 없습니다. `당신보다 상위나 동등한 권한관계를 가진 사람에게 역할을 추가 할 수 없습니다.` + + + {0} 은(는) 자신이 적용 할 수 있는 역할 목록에서 삭제되었습니다. + + + 당신은 더 이상 {0} 역할이 아닙니다. + + + 당신은 이제 {0} 역할입니다. + + + {1} 유저에게 {0} 역할을 성공적으로 추가했습니다. + + + 역할 추가에 실패했습니다. 권한이 부족합니다. + + + 새로운 아바타가 설정되었습니다! + + + 새로운 채널 이름이 설정되었습니다. + + + 새로운 게임이 설정되었습니다! + + + 새로운 방송이 설정되었습니다! + + + 새로운 채널 주제를 설정했습니다. + Fuzzy + + + Shard {0} 가 다시 연결되었습니다. + + + Shard {0} 를 다시 연결 중입니다. + + + 종료 중... + + + 사용자는 {1} 초마다 {0} 개 이상의 메시지를 보낼 수 없습니다. + + + 슬로우 모드가 비활성화되었습니다. + + + 슬로우 모드가 활성화되었습니다. + + + 소프트 밴 (강제퇴장) + PLURAL + + + {0} 은(는) 이 채널을 무시할 것입니다. + + + {0} 은(는) 더이상 이 채널을 무시하지 않을 것입니다. + + + 만약 사용자가 {0} 개 이상의 같은 메세지를 보내면 {1} 합니다. + __무시하는 채널들__: {2} + + + 텍스트 채널이 생성되었습니다. + + + 텍스트 채널이 삭제되었습니다. + destroyed means deleted? +디스트로이드 뜻이 삭제됬다는 건가요? + + + 음소거 해제 완료. + + + 음소거 해제 + singular + + + 사용자 이름 + + + 사용자 이름이 변경되었습니다. + + + 사용자 + Fuzzy + + + 사용자 밴 + Fuzzy + + + {0} 님이 채팅으로부터 **음소거**되었습니다. + + + {0} 님이 채팅으로부터 **음소거 해제**되었습니다. + + + 사용자 입장 + + + 사용자 퇴장 + + + {0} 은(는) 텍스트와 음성 채팅으로부터 **차단**되었습니다. + + + 사용자의 역할이 추가되었습니다. + Fuzzy + + + 사용자의 역할이 제거되었습니다. + Fuzzy + + + {0} 은(는) 이제 {1} 입니다. + + + {0} 은(는) 텍스트와 음성 채팅으로부터 **차단해제**되었습니다. + + + {0} 님이 {1} 음성채널에 입장하셨습니다. + + + {0} 님이 {1} 음성채널에서 퇴장하셨습니다. + + + {0}님이 음성채널 {1} 에서 {2} 로 이동되었습니다. + + + {0} 님이 **음성 음소거**되었습니다. + + + {0} 님이 **음성 음소거 해제**되었습니다. + + + 음성 채널이 생성되었습니다. + + + 음성 채널이 삭제되었습니다. + + + 음성 + 텍스트 기능을 비활성화시켰습니다. + + + 음성 + 텍스트 기능을 활성화시켰습니다. + + + **관리 역할** 혹은 **채널 관리 권한**이 부족해서 {0} 서버에서 `음성 + 텍스트` 기능을 실행 할 수 없습니다. + + + 당신은 **봇이 관리자 권한이 없음에도** 이 기능을 활성화/비활성화 하고 있습니다. 이로 인해서 문제가 발생 할 수 있으며 이후에 직접 텍스트 채널을 정리해야합니다. + + + 이 기능을 활성화시키기 위해서는 **역할 관리**과 **채널 관리** 권한이 필요합니다. + Fuzzy + + + 사용자가 텍스트 채팅으로부터 {0} 됐습니다. + + + 사용자가 텍스트와 음성 채팅으로부터 {0} 됐습니다. + + + 사용자가 음성 채팅으로부터 {0} 됐습니다. + + + 당신은 {0} 서버에서 soft-밴을 당했습니다. +사유: {1} + Fuzzy + + + 사용자 밴 해제 + Fuzzy + + + 이전 완료! + Fuzzy + + + 이전 과정에서 오류가 발생했습니다. 자세한 정보는 봇의 콘솔을 통해서 확인하십시오. + + + 현재 상태 업데이트 + + + 사용자 소프트 밴 + + + 님이 {1} 에게 {0} 개를 지급했습니다. + + + 다음 기회에 ^_^ + + + 축하합니다! 당신은 {1} 이상을 굴려서 {0} 을 획득했습니다. + Fuzzy + + + 덱이 섞였습니다. + Fuzzy + + + 동전뒤집기의 결과는 {0}. + User flipped tails. +Fuzzy + + + 맞췄습니다! 당신은 {0} 을(를) 획득했습니다. + + + 유효하지 않은 숫자입니다. 당신은 1개부터 {0} 개까지만 동전을 뒤집을 수 있습니다. + Fuzzy + + + {1} 을(를) 받으려면 이 메세지에 {0} 리액션을 추가하세요. + Fuzzy + + + 이 이벤트는 최대 {0} 시간 동안 활성화됩니다. + + + 플라워 리액션 이벤트가 시작되었습니다. + + + 님이 {1} 에게 {0} 개를 선물하셨습니다. + X has gifted 15 flowers to Y + + + {0} 님은 {1} 개를 보유중입니다. + X has Y flowers + + + + + + 리더보드 + + + {2} 역할의 {1} 명의 사용자에게 {0} 를 보상하였습니다. + Fuzzy + + + {0} 보다 더 배팅 할 수 없습니다. + + + {0} 보다 적게 배팅 할 수 없습니다. + + + 당신은 충분한 {0} 이(가) 없습니다. + + + 덱에 더 이상 카드가 없습니다. + + + 래플 결과 + Fuzzy + + + {0} 를 굴렸습니다. + + + 배팅 + Fuzzy + + + 대박!!! 축하합니다!!! x{0} + + + 한 {0}, x{1} + Fuzzy + + + 와! 운이 좋습니다! 같은 종류의 세개! x{0} + Fuzzy + + + 잘 했습니다! {0} 두게 - x{1} + Fuzzy + + + 얻은 액수 + Fuzzy + + + 사용자는 반드시 {0} 를 얻기 위해서 비밀 코드를 입력해야합니다. + + + + SneakyGame 이벤트가 종료되었습니다. {0} 명의 사용자들이 보상을 받았습니다. + + + SneakyGameStatus 이벤트가 시작되었습니다. + Fuzzy + + + 뒷면 + + + {1} 에게서 {0} 을(를) 성공적으로 빼앗았습니다 + + + {1} 님이 {2} 만큼을 가지고있지 않기 때문에 {0} 을(를) 회수 할 수 없습니다. + Fuzzy + + + 목차로 돌아가기 + + + 봇 소유자만 가능합니다. + + + {0} 채널의 권한이 필요합니다. + + + Patreon( <0> )이나 Paypal( <1> )을 통해서 프로젝트를 후원 할 수 있습니다. + Fuzzy + + + 명령어와 가명 + Fuzzy + + + 명령어 목록이 재생성되었습니다. + + + `{0}h 명령어이름`을 입력해서 특정 명령어에 대한 도움말을 볼 수 있습니다. +예시 : `{0}h >8ball` + + + 입력하신 명령어를 찾을 수 없습니다. 입력하시기 전에 유효한 명령어인지 확인해주십시오. + + + 설명 + Fuzzy + + + Patreon <{0}> 이나 +Paypal <{1}> 에서 +NadekoBot 프로젝트를 지원할 수 있습니다. +Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시오. + +**감사합니다** ♥️ + + + **명령어 목록**: <{0}> +**호스팅 가이드와 문서는 여기서 찾을 수 있습니다**: <{1}> + + + 명령어 목록 + + + 모듈 목록 + + + `{0}h 모듈이름`을 입력해서 특정 모듈에 대한 도움말을 볼 수 있습니다. +예시 : `{0}cmds games` + + + 그 모듈은 존재하지 않습니다. + + + {0} 서버의 권한이 필요합니다. + + + 목차 + + + 사용법 + Fuzzy + + + Autohentai 기능이 활성화되었습니다. 다음의 태그와 함께 {0} 초마다 사진이 올라옵니다. +태그 : +{1} + Fuzzy + + + 태그 + Fuzzy + + + 동물 경주 + Fuzzy + + + 참가자가 충분히 없어서 시작하지 못했습니다. + + + 참가자가 모두 모였습니다! 즉시 시작하겠습니다. + Fuzzy + + + {0} 이(가) {1} (으)로 참가했습니다. + Fuzzy + + + {0} 님이 {1} 으로써 참가하였고, {2} 을(를) 걸었습니다! + Fuzzy + + + {0}jr 를 입력해서 레이스에 참가합니다. + + + 20초 동안 기다리거나, 방이 가득 차면 시작됩니다. + Fuzzy + + + {0} 명의 참가자와 함께 시작합니다. + + + {0} 이(가) {1} (으)로 레이스를 이겼습니다! + Fuzzy + + + {0} 이(가) {1} (으)로 레이스를 이겼고 {2}! + Fuzzy + + + 유효하지 않은 숫자입니다. 한번에 {0}-{1} 의 주사위를 던질 수 있습니다. + Fuzzy + + + 님이 {0} 를 굴렸습니다. + Someone rolled 35 + + + 주사위 결과: {0} + Dice Rolled: 5 + + + 레이스 시작에 실패했습니다. 다른 레이스가 진행중입니다. + Fuzzy + + + 이 서버에 레이스가 존재하지 않습니다. + + + 두번째 숫자는 첫번째 숫자보다 큰 숫자여야 합니다. + Fuzzy + + + 마음의 변화 + Fuzzy + + + 요구한 사람 + Fuzzy + + + 이혼 + + + 좋아하는 사람 + Fuzzy + + + + + + 아무 와이프도 클레임되지 않았습니다. + Fuzzy + + + 최고의 와이프 + + + + + + + Make sure to get the formatting right, and leave the thinking emoji + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 자기자신을 클레임 할 수 없습니다. + Fuzzy + + + 당신은 최근에 이혼하셨습니다. 다시 이혼하려면 {0} 시간 {1} 분을 기다려야 합니다. + Fuzzy + + + 아무도 없음 + + + + + + 8ball + Fuzzy + + + 아크로포비아 + Fuzzy + + + 아무런 제출 없이 게임이 끝났습니다. + + + + + + 두문자가 {0} 이었슴니다. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + plural + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 결과가 없습니다. + + + 이(가) {0} 을(를) 뽑았습니다. + Kwoth picked 5* + + + {0} 이(가) {1} 을(를) 설치했습니다. + Kwoth planted 5* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + context: "removed song #5" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 허락함 + Fuzzy + + + + + + + + + + + + + + + + + + + + + {0} (ID {1})님을 블랙리스트했습니다 + + + 명령어 {0} 은(는) 이제 {1}초 재사용 대기시간이 있습니다. + + + 이제 명령어 {0} 이 재사용 대기시간이 없고 기존의 모든 재사용 대기시간이 삭제되었습니다. + + + 명령어 재사용 대기시간이 설정되지 않았습니다. + + + 명령어 값 + + + 채널 {2} 에서 {0} {1} 의 사용을 비활성화시켰습니다. + + + 채널 {2} 에서 {0} {1} 의 사용을 활성화시켰습니다. + + + 거절함 + Fuzzy + + + 필터링 된 단어 목록에 {0} 을 추가했습니다. + Fuzzy + + + 필터링 된 단어 목록 + + + 필터링 된 단어 목록에서 {0} 을 삭제했습니다. + Fuzzy + + + + + + + + + + + + + + + + + + + + + + + + + + + 명령어 + Gen (of command) + + + 모듈 + Gen. (of module) + + + 권한 목록 {0} 페이지 + + + + + + + + + + + + + + + + + + + + + 초. + Short of seconds. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 능력 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 애니메이션 검색에 실패했습니다. + + + 만화 검색에 실패했습니다. + + + 장르 + + + + + + 키/무게 + + + {0}m/{1}kg + + + 습도 + + + 이미지 검색: + + + 영화 검색에 실패했습니다. + + + + + + + + + + + + + + + + Don't translate {0}place + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 보고있는것: + Fuzzy + + + + + + + + + + + + + + + + + + + + + + + + + /s and total need to be localized to fit the context - +`1.` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Invalid months value/ Invalid hours value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 인용구가 추가되었습니다. + + + 인용구 #{0} 가 삭제되었습니다. + + + 지역 + + + 가입 날짜 + + + + + + 유효하지않은 시간 포맷입니다. 명령어 목록을 확인하십시오. + + + + + + + + + 반복 메시지 목록 + + + 이 서버에 반복 메시지 실행하고있지 안습니다. + + + #{0} 이 정지되었습니다. + + + + + + 결과 + + + 역할 + + + + + + + + + + + + + + + + + + + + + + + + Shard + + + Shard 통계 + + + Shard **#{0}** 이 {1} 상태이고 {2} 서버에 있습니다. + + + **이름:** {0} **링크:** {1} + + + 특수 이모지를 찾을 수 없습니다. + Fuzzy + + + {0} 개의 곡을 재생중이며, {1} 개의 대기열이 있습니다. + + + 텍스트 채널 + + + + + + + + + {1} 의 {0} 은(는) {2} 입니다. + Id of the user kwoth#1234 is 123123123123 + + + 사용자 + Fuzzy + + + 음성 채널 + + + 당신은 이미 레이스에 참가했습니다. + + + 현재 투표 결과 + + + 진행중인 투표가 없습니다. + + + 이 서버에서 이미 투표가 진행되고있습니다. + + + 📃 {0} 님이 투표를 생성하였습니다. + Fuzzy + + + + + + {0} 님이 투표하였습니다. + Kwoth voted. + + + 해당 답변 번호와 함께 개인 메시지를 보내십시오. + Fuzzy + + + 해당 답변 번호와 함께 여기에 메시지를 보내십시오. + Fuzzy + + + {0} 님, 투표해주셔서 감사합니다 + + + {0} 개의 표가 던져졌습니다. + Fuzzy + + + + + + `{0}pick`을 입력해서 획득하십시오. + Fuzzy + + + 사용자를 찾지 못했습니다. + + + {0} 페이지 + + + 이 서버의 음성 채널에 있어야합니다. + + + 음성채널 역할이 없습니다. + + + {0} 은(는) 음성과 텍스트 채팅으로 부터 {1} 분간 **음소거**되었습니다. + + + {0} 음성채널에 입장하는 사용자는 {1} 역할을 얻게됩니다. + + + {0} 음성채널에 입장하는 사용자는 더이상 {1} 역할을 얻지 못합니다. + + + 음성채널 역할 + + + + + + + + + + + + + + + 가명을 찾지 못했습니다. + + + {0} 입력은 이제 {1} 의 가명일것이니다. + + + 가명 목록 + + + 트리거 {0} 의 가명을 삭제했습니다. + + + 트리거 {0} 은(는) 가명 없었습니다. + + + 경기한 시간 + + + \ No newline at end of file From 22ed47ff9ece9eedf4e7fb11b5b8079cff914b69 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 27 Mar 2017 14:45:09 +0200 Subject: [PATCH 628/746] Update ResponseStrings.zh-CN.resx (POEditor.com) From c8ea0039fe0d899cb5a1d3bef62be8cc05aef81e Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 27 Mar 2017 14:45:11 +0200 Subject: [PATCH 629/746] Update ResponseStrings.zh-TW.resx (POEditor.com) --- .../Resources/ResponseStrings.zh-TW.resx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx index 051bb851..7f3ca400 100644 --- a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx +++ b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx @@ -1337,7 +1337,7 @@ Paypal <{1}> {0} 對 {1} - 正在排 {0} 首歌... + 正在點播 {0} 首歌... 已停用自動播放。 @@ -2255,16 +2255,16 @@ Paypal <{1}> 語音頻道身分組 - + 觸發自訂回應 ID 為 {0} 的訊息不會自動刪除。 - + 觸發自訂回應 ID 為 {0} 的訊息將會自動刪除。 - + 自訂回應 ID 為 {0} 的回應不會以私訊方式傳送。 - + 自訂回應 ID 為 {0} 的回應將會以私訊方式傳送。 找不到別名 @@ -2276,13 +2276,13 @@ Paypal <{1}> 別名列表 - + 觸發 {0} 不再有別名。 - + 觸發 {0} 並沒有別名。 - + 競技時數 \ No newline at end of file From a9b9612184d7ceb3cd8a39ebc346136873452dc6 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 27 Mar 2017 14:45:14 +0200 Subject: [PATCH 630/746] Update ResponseStrings.nl-NL.resx (POEditor.com) --- .../Resources/ResponseStrings.nl-NL.resx | 525 ++++++++---------- 1 file changed, 246 insertions(+), 279 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx index 15bc2419..3f7ad541 100644 --- a/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx @@ -152,8 +152,7 @@ Ongeldige basis nummer - Ongeldig oorlogs -formaat. + Ongeldig oorlogsformaat. Fuzzy @@ -195,7 +194,7 @@ formaat. Alle speciale reactie statistieken zijn verwijderd. - Speciale Reactie verwijderdt. + Speciale Reactie verwijderd. Onvoldoende rechten. Bot Eigendom is nodig voor globale speciale reacties, en Administrator voor speciale server-reacties. @@ -214,7 +213,7 @@ formaat. Fuzzy - Geen speciale reacties gevonden met die ID. + Geen speciale reacties gevonden met dat ID. Antwoord @@ -223,19 +222,19 @@ formaat. Speciale Reactie Statistieken - Statistieke verwijderd voor {0} speciale reactie. + Statistieken verwijderd voor {0} speciale reactie. Geen statistieken voor die trekker gevonden, geen actie genomen. - Trekker + Trigger Autohentai gestopt. - Geen resultaten gevonden + Geen resultaten gevonden. {0} is al flauw gevallen. @@ -251,10 +250,10 @@ formaat. Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. - Jij zal niet winnen zonder tegenstand! + Je kan niet opnieuw aanvallen zonder vergelding! - Je kunt je zelf niet aanvallen + Je kunt je zelf niet aanvallen. {0} is verslagen! @@ -263,7 +262,7 @@ formaat. heeft {0} genezen met een {1} - {0} heeft nog {1} HP over + {0} heeft nog {1} HP over. Je kan {0} niet gebruiken. Typ `{1}ml` om een lijst te bekijken van de aanvallen die jij kunt gebruiken @@ -272,7 +271,7 @@ formaat. Aanvallijst voor {0} element - Het heeft weinig effect. + Het is niet effectief. Je hebt niet genoeg {0} @@ -293,7 +292,7 @@ formaat. Het is super effectief! - Je hebt te veel aanvallen achter elkaar gemaakt, je kan dus niet bewegen! + Je hebt te veel acties achter elkaar gedaan, dus je kan niet bewegen! Element van {0} is {1} @@ -302,7 +301,7 @@ formaat. Gebruiker niet gevonden. - Je bent flauw gevallen, dus je kunt niet bewegen! + Je bent flauwgevallen, dus je kunt niet bewegen! **Auto aanwijzing van rollen** op gebruiker is nu **uitgeschakeld**. @@ -311,7 +310,7 @@ formaat. **Auto aanwijzing van rollen** op gebruiker is nu **ingeschakeld**. - Bestanden + Bijlagen Avatar veranderd @@ -320,50 +319,50 @@ formaat. Je bent verbannen van {0} server. Reden: {1} - Verbannen + verbannen PLURAL Gebruiker verbannen - Bot naam is veranderd naar {0} + Botnaam is veranderd naar {0} - Bot status is veranderd naar {0} + Botstatus is veranderd naar {0} - Automatische verwijdering van de bye berichten is uitgeschakeld. + Automatische verwijdering van de afscheidsberichten is uitgeschakeld. - Bye berichten zullen worden verwijderd na {0} seconden. + Afscheidsberichten zullen worden verwijderd na {0} seconden. - Momenteel is de bye message: {0} + Momenteel is het afscheidsbericht: {0} - Schakel de bye berichten in door {0} te typen. + Schakel de afscheidsbericht in door {0} te typen. - Nieuw bye bericht is geplaatst. + Nieuw afscheidsbericht is geplaatst. - Dag aankondigingen uitgeschakeld. + Afscheidsbericht uitgeschakeld. - Dag aankondigingen ingeschakeld op dit kanaal. + Afscheidsbericht ingeschakeld op dit kanaal. - Kanaal naam is veranderd. + Kanaalnaam is veranderd. Oude naam - Kanaal onderwerp is veranderd + Kanaalonderwerp is veranderd - Opgeruimd + Opgeruimd. Inhoud @@ -372,10 +371,10 @@ formaat. Met success een nieuwe rol gecreëerd. - Tekst kanaal {0} gecreëerd. + Tekst-kanaal {0} gecreëerd. - Stem kanaal {0} gecreëerd. + Voice-kanaal {0} gecreëerd. Dempen succesvol. @@ -384,82 +383,82 @@ formaat. Server verwijderd {0} - Stopt van automatische verwijdering van succesvolle reacties aanroepingen commando. + Succesvol aangeroepen commando's worden niet automatisch verwijderd. - Verwijdert nu automatisch succesvolle commando aanroepingen + Succesvol aangeroepen commando's worden nu automatisch verwijderd. - Tekst kanaal {0} verwijdert. + Tekst-kanaal {0} verwijderd. - Stem kanaal {0} verwijdert. + Voice-kanaal {0} verwijderd. - Privé bericht van + Privé-bericht van - Met succes een nieuwe donateur toegevoegt. Totaal gedoneerde bedrag van deze gebruiker {0} + Met succes een nieuwe donateur toegevoegd. Totaal gedoneerde bedrag van deze gebruiker: {0} - Dank aan de mensen hieronder vernoemt voor het waarmaken van dit project! + Dank aan de mensen hieronder voor het waarmaken van dit project! - Ik zal alle eigenaren een privé bericht sturen. + Ik zal alle eigenaren privé-berichten doorsturen. - Ik zal een privé bericht sturen naar de eerste eigenaar + Ik zal alleen privé-berichten doorsturen naar de eerste eigenaar. - Ik zal privé berichten sturen vanaf nu. + Ik zal privé-berichten doorsturen vanaf nu. - Ik stop vanaf nu met het sturen van privé berichten. + Ik stop vanaf nu met het doorsturen van privé berichten. - Automatisch verwijderen van groet berichten is uitgeschakeld. + Automatisch verwijderen van begroetings-berichten uitgeschakeld. - Groet berichten zullen worden verwijderd na {0} seconden. + Begroetings-berichten zullen worden verwijderd na {0} seconden. - Momenteen is het privé groet bericht: {0} + Momenteel is het privé begroetings-bericht: {0} - Schakel DM begroetings bericht in door {0} in te typen + Schakel DM begroetingen in door {0} in te typen - Nieuwe DM begroetings bericht vastgesteld. + Nieuwe DM begroeting ingesteld. - DM begroetings aankondiging uitgeschakeld. + DM begroetingen uitgeschakeld. - DM begroetingen aankondiging ingeschakeld. + DM begroetingen ingeschakeld. - Momentele begroetings bericht: {0} + Huidige begroeting: {0} - Schakel begroetings bericht in door {0} in te typen + Schakel begroetingen in door {0} in te typen - Nieuwe begroetings message vastgesteld. + Nieuwe begroeting ingesteld. - Begroetings aankondiging uitgeschakeld. + Begroetingen uitgeschakeld. - Begroetings aankondiging uitschakeld op dit kanaal. + Begroetingen uitschakeld op dit kanaal. - Jij kunt geen commando gebruiken op gebruikers met hogere of dezelfde rol als die van jouw in de rollen hiërarchie. + Je kunt geen commando gebruiken op gebruikers met een hogere of eenzelfde rol als die van jouw in de rollenhiërarchie. - Afbeeldingen geplaatst na {0} seconden! + Afbeeldingen geladen na {0} seconden! - Ongelde invoer formaat. + Ongeldig invoerformaat. Ongeldige parameters. @@ -468,12 +467,11 @@ formaat. {0} heeft {1} toegetreden - Je bent weggeschopt van de {0} server. + Je bent gekickt van {0}. Reden: {1} - Gebruiker weggeschopt - Fuzzy + Gebruiker gekickt. Lijst van talen @@ -481,37 +479,37 @@ Reden: {1} Fuzzy - Jouw server's locale is nu {0} - {1} + Je server's landinstelling is nu {0} - {1} - Bot's standaard locale is nu {0} - {1} + De bot zijn standaard landinstelling is nu {0} - {1} - Taal van de bot is gezet naar {0} - {1} + Taal van de bot is nu {0} - {1} - Instellen van locale mislukt. Ga naar de hulp voor dit commando. + Instellen van landsinstelling mislukt. Ga naar de hulp voor dit commando. - De taal van de server is gezet naar {0} - {1} + De taal van de server is nu {0} - {1} {0} heeft {1} verlaten - Server {0} verlaten + {0} verlaten - Gebeurtenis {0} wordt bijgehouden in dit kanaal. + Gebeurtenis {0} wordt gelogd in dit kanaal. - Alle gebeurtenissen worden bijgehouden in dit kanaal. + Alle gebeurtenissen worden gelogd in dit kanaal. Logging uitgeschakeld. - Log gebeurtenissen waar je op kan abonneren: + Log-gebeurtenissen waar je op kan abonneren: Logging zal {0} negeren @@ -543,7 +541,7 @@ Reden: {1} Fuzzy - Gebruikers zijn gedempt + gemute PLURAL (users have been muted) @@ -551,7 +549,7 @@ Reden: {1} singular "User muted." - Ik heb de benodigde rechten daar voor waarschijnlijk niet. + Ik heb de benodigde rechten daarvoor waarschijnlijk niet. Nieuwe demp rol geplaatst. @@ -560,20 +558,16 @@ Reden: {1} Ik heb **administrator** rechten daar voor nodig. - nieuw bericht - Fuzzy + Nieuw bericht - nieuwe bijnaam - Fuzzy + Nieuwe bijnaam Nieuw onderwerp - Fuzzy Bijnaam veranderd - Fuzzy Kan de server niet vinden @@ -583,25 +577,21 @@ Reden: {1} Oud bericht - Fuzzy Oude bijnaam - Fuzzy - Oude onderwerp - Fuzzy + Oud onderwerp - Fout. Hoogst waarschijnlijk heb ik geen voldoende rechten. + Error. Hoogst waarschijnlijk heb ik geen voldoende rechten. De rechten op deze server zijn gereset. - Actieve Beschermingen. - Fuzzy + Actieve beschermingen. {0} is nu ** uitgeschakeld** op deze server. @@ -610,29 +600,28 @@ Reden: {1} {0} Ingeschakeld - Fout. ik heb Beheer Rollen rechten nodig + Error. ik heb Beheer Rollen rechten nodig - Geen bescherming aangezet. - Fuzzy + Geen bescherming ingeschakeld. - Gebruiker's drempel moet tussen {0} en {1} zijn. + Gebruikersdrempel moet tussen {0} en {1} zijn. - Als {0} of meerdere gebruikers binnen {1} seconden, zal ik hun {2}. + Als {0} of meerdere gebruikers binnen {1} seconden toetreden, zal ik ze {2}. Aangegeven tijd hoort binnen {0} en {1} seconden te vallen. - Met succes alle roles van de gebruiker {0} verwijderd + Met succes alle rollen van gebruiker {0} verwijderd. Het verwijderen van de rollen is mislukt. Ik heb onvoldoende rechten. - De kleur van de rol {0} is veranderd + De kleur van de rol {0} is veranderd. Die rol bestaat niet. @@ -641,7 +630,7 @@ Reden: {1} De aangegeven parameters zijn ongeldig. - Error opgekomen vanwege ongeldige kleur, of onvoldoende rechten. + Error opgekomen vanwege ongeldige kleur of onvoldoende rechten. Met sucess rol {0} verwijderd van gebruiker {1}. @@ -650,16 +639,16 @@ Reden: {1} Mislukt om rol te verwijderen. Ik heb onvoldoende rechten. - Rol naam veranderd. + Naam van de rol veranderd. - Rol naam veranderen mislukt. Ik heb onvoldoende rechten. + Naam van de rol veranderen mislukt. Ik heb onvoldoende rechten. - je kan geen rollen bijwerken die hoger zijn dan je eigen rol. + Je kan geen rollen bijwerken die hoger zijn dan je hoogste rol. - Speel bericht verwijderd: {0} + Spelende bericht verwijderd: {0} Rol {0} is toegevoegd aan de lijst. @@ -687,10 +676,10 @@ Reden: {1} Nog geen routerende speelstatussen ingesteld. - Je hebt al {0} rol. + Je hebt rol {0} al. - Je hebt {0} exclusieve zelf toegewezen rol al. + Je hebt {0} exclusieve zelf-toegewezen rol al. Zelf toegewezen rollen zijn nu exclusief! @@ -699,25 +688,25 @@ Reden: {1} Er zijn {0} zelf toewijsbare rollen - Deze rol is niet zelf toewijsbaar. + Deze rol is niet zelf-toewijsbaar. - Je hebt niet {0} rol. + Je hebt rol {0} niet. - Zelf toegewezen rollen zijn nu niet exclusief! + Zelf-toegewezen rollen zijn nu niet exclusief! - Ik kan deze rol niet aan je toevoegen. `Ik kan niet rollen toevoegen aan eigenaren of andere rollen die boven mij staan in de rol hiërarchie.` + Ik kan deze rol niet aan je toevoegen. `Ik kan geen rollen toevoegen aan eigenaren of andere rollen die boven mij staan in de rol-hiërarchie.` {0} is verwijderd van de lijst met zelf toewijsbare rollen. - Je hebt {0} rol niet meer. + Je hebt de {0} rol niet meer. - je hebt nu {0} rol. + Je hebt nu de {0} rol. Succesvol de rol {0} toegevoegd aan gebruiker {1} @@ -729,7 +718,7 @@ Reden: {1} Nieuwe avatar ingesteld! - Nieuwe kanaal naam ingesteld. + Nieuwe kanaalnaam ingesteld. Nieuwe game ingesteld! @@ -738,7 +727,7 @@ Reden: {1} Nieuwe stream ingesteld! - Nieuwe kanaal onderwerp ingesteld. + Nieuwe kanaalonderwerp ingesteld. Shard {0} opnieuw verbonden. @@ -747,42 +736,42 @@ Reden: {1} Shard {0} is opnieuw aan het verbinden. - Afsluiten + Aan het afsluiten Gebruikers kunnen niet meer dan {0} berichten sturen per {1} seconden. - langzame mode uitgezet + Langzame modus uitgezet. - langzame mode gestart + Langzame modus gestart. - zacht-verbannen (kicked) + soft-verbannen (gekickt) PLURAL {0} zal dit kanaal negeren. - {0} zal dit kanaal niet meer negeren. + {0} zal dit kanaal niet langer negeren. - Als een gebruiker {0} de zelfde berichten plaatst, zal ik ze {1}. + Als een gebruiker {0} gelijke berichten plaatst, zal ik ze {1}. __IgnoredChannels__: {2} - Tekst kanaal aangemaakt. + Tekst-kanaal aangemaakt. - Tekst kanaal verwijderd. + Tekst-kanaal verwijderd. - Ontdempen succesvol + Doof maken ontdoen succesvol - Ongedempt + Geünmute singular @@ -790,70 +779,60 @@ __IgnoredChannels__: {2} Gebruikersnaam veranderd - Fuzzy Gebruikers Gebruiker verbannen - Fuzzy - {0} is **gedempt** van chatten. - Fuzzy + {0} is **gedempt** van het chatten. - {0} is **ongedempt** van chatten. - Fuzzy + {0} is **ongedempt** van het chatten. - Gebruiker toegetreden - Fuzzy + Gebruiker is toegetreden - Gebruiker verlaten - Fuzzy + Gebruiker is weggegaan - {0} is **gedempt** van het tekst en stem kanaal. + {0} is **gedempt** van het tekst- en voice-kanaal. Rol van gebruiker toegevoegd - Fuzzy Rol van gebruiker verwijderd - Fuzzy {0} is nu {1} - {0} is **ongedempt** van het tekst en stem kanaal. + {0} is **ongedempt** van het tekst- en voice-kanaal. - {0} is {1} spraakkanaal toegetreden. + {0} is {1} voice-kanaal toegetreden. - {0} heeft {1} spraakkanaal verlaten. + {0} heeft {1} voice-kanaal verlaten. - {0} heeft {1} naar {2} spraakkanaal verplaatst. + {0} heeft {1} naar {2} voice-kanaal verplaatst. - {0} is **spraak gedempt** + {0} is **spraak gemute**. - {0} is **spraak ongedempt** + {0} is **spraak geünmute**. - Spraakkanaal gemaakt - Fuzzy + Voice-kanaal gemaakt - Spraakkanaal vernietigd - Fuzzy + Voice-kanaal verwijderd Spraak + tekst mogelijkheid uitgezet. @@ -862,13 +841,13 @@ __IgnoredChannels__: {2} Spraak + tekst mogelijkheid aangezet. - Ik heb geen **Rol Beheering** en/of **Kanaal Beheering** toestemmingen, dus ik kan geen `stem+text` gebruiken op de {0} server. + Ik heb geen **Rol Beheer** en/of **Kanaal Beheer** toestemmingen, dus ik kan geen `stem+text` gebruiken op de {0} server. - Deze eigenschap wordt door jou ingeschakelt/uitgeschakelt maar **Ik heb geen ADMINISTRATIEVE toestemmingen**. Hierdoor kunnen er mogelijk problemen ontstaan, en je zal daarna de tekst kanalen zelf moeten opruimen. + Deze eigenschap wordt door jou ingeschakeld/uitgeschakeld maar **Ik heb geen ADMINISTRATIEVE toestemmingen**. Hierdoor kunnen er mogelijk problemen ontstaan, en je zal daarna de tekst-kanalen zelf moeten opruimen. - Ik heb tenminste **Rol Beheering** en **Kanaal Beheering** toestemmingen nodig om deze eigenschap in te schakelen. (Geliefe adminstratieve rechten) + Ik heb tenminste **Rol Beheering** en **Kanaal Beheering** toestemmingen nodig om deze eigenschap in te schakelen. (Gelieve administratieve rechten) Gebruiker {0} van tekstkanaal @@ -880,25 +859,23 @@ __IgnoredChannels__: {2} Gebruiker {0} van spraakkanaal - Je bent zacht-verbannen van {0} server. + Je bent soft-gebant van {0} server. Reden: {1} Gebruiker niet meer verbannen - Migratie gelukt! + Migratie klaar! - Fout tijdens het migreren, kijk in de bot's console voor meer informatie. + Fout tijdens het migreren, kijk in de bot zijn console voor meer informatie. - Aanwezigheid Updates - Fuzzy + Aanwezigheid updates - Gebruiker zacht-verbannen - Fuzzy + Gebruiker soft-gebant heeft {0} aan {1} gegeven @@ -910,7 +887,7 @@ Reden: {1} Gefeliciteerd! Je hebt {0} gewonnen voor het rollen boven de {1} - Dek geschud. + Dek herschud. heeft de munt op {0} gegooid @@ -949,22 +926,22 @@ Reden: {1} {0} heeft {1} gebruikers beloont met {2} rol. - Je kan niet meer dan {0} gokken + Je kan niet meer dan {0} wedden - Je kan niet minder dan {0} gokken + Je kan niet minder dan {0} wedden Je hebt niet genoeg {0} - Geen kaarten meer in het dek + Geen kaarten meer in het dek. - Verloten gebruiker + Verlootte gebruiker - Je hebt {0} gerold + Je hebt {0} gerold. Inzet @@ -976,7 +953,7 @@ Reden: {1} Een enkele {0}, x{1} - Wow! Gelukkig! Drie van dezelfde! x{0} + Wow! Wat een geluk! Three of a kind! x{0} Goed gedaan! Twee {0} - wed x{1} @@ -1007,28 +984,25 @@ Duurt {1} seconden. Vertel het aan niemand. Shhh. Terug naar de inhoudsopgave - Alleen Voor Bot Eigenaren - Fuzzy + Alleen voor Bot-eigenaren Heeft {0} kanaal rechten nodig. - Je kan het project steunen op patreon: <{0}> of paypal: <{1}> + Je kan het project steunen op Patreon: <{0}> of PayPal: <{1}> - Command en aliassen. - Fuzzy + Commando's en aliassen - Commandolijst Geregenereerd. - Fuzzy + Commandolijst gegenereerd. - Typ `{0}h CommandoNaam` om de hulp te zien voor die specifieke commando. b.v `{0}h >8bal` + Typ `{0}h CommandoNaam` om de uitleg te zien voor dat specifieke commando. b.v `{0}h >8bal` - Ik kan die commando niet vinden. Verifiëren of die commando echt bestaat voor dat je het opnieuw probeert. + Ik kan het commando niet vinden. Verifieer of dit commando echt bestaat voordat je het opnieuw probeert. Beschrijving @@ -1036,56 +1010,51 @@ Duurt {1} seconden. Vertel het aan niemand. Shhh. Je kan het NadekoBot project steunen op Patreon <{0}> of -Paypal <{1}> +PayPal <{1}> Vergeet niet je discord naam en id in het bericht te zetten. **Hartelijk bedankt** ♥️ **Lijst met commando's**: <{0}> -**Hosting gidsen en documenten kunnen hier gevonden worden**: <{1}> - Fuzzy +**Hosting tutorials en documenten kunnen hier gevonden worden**: <{1}> - Lijst Met Commando's - Fuzzy + Lijst met commando's - Lijst Met Modules - Fuzzy + Lijst met modules Typ `{0}cmds ModuleNaam` om een lijst van commando's te krijgen voor die module. bv `{0}cmds games` - Deze module bestaat niet + Deze module bestaat niet. Heeft {0} server rechten nodig. Inhoudsopgave - Fuzzy Gebruik - Autohentai gestart. Elke {0}s word een foto geplaatst met de volgende labels: + Autohentai gestart. Er wordt elke {0} seconden een foto geplaatst met de volgende labels: {1} - Fuzzy Label - Dieren race + Dierenrace - Gefaalt om te starten omdat er niet genoeg deelnemers zijn. + Gefaald om te starten omdat er niet genoeg deelnemers zijn. - De race is vol! De race wordt onmiddelijk gestart. + De race is vol! De race wordt onmiddellijk gestart. {0} doet mee als een {1} @@ -1097,10 +1066,10 @@ Vergeet niet je discord naam en id in het bericht te zetten. Typ {0}jr om mee te doen met de race. - De race zal beginnen in 20 seconden of wanneer de kamer is vol. + De race zal met 20 seconden beginnen of wanneer de kamer is vol. - De race zal beginnen met {0} deelnemers. + De race zal beginnen bij {0} deelnemers. {0} heeft de race gewonnen als {1}! @@ -1112,7 +1081,7 @@ Vergeet niet je discord naam en id in het bericht te zetten. Ongeldig nummer ingevoerd. Je kan de dobbelsteen van {0}-{1} rollen. - {0} gerold. + heeft {0} gerold. Someone rolled 35 @@ -1120,16 +1089,16 @@ Vergeet niet je discord naam en id in het bericht te zetten. Dice Rolled: 5 - Gefaalt om de race te starten. Een andere race is waarschijnlijk bezig. + Starten van de race is mislukt. Een andere race is waarschijnlijk bezig. - Geen enkele race bestaat op deze server. + Er bestaat geen enkele race op deze server - Het tweede nummer moet groter zijn dan het eerste nummer. + Het tweede nummer moet hoger zijn dan het eerste nummer. - Verandering van het hart + Ommezwaai Opgeëist door @@ -1138,13 +1107,13 @@ Vergeet niet je discord naam en id in het bericht te zetten. Scheidingen - Leuk + Likes Prijs - Nog geen waifus zijn overwonnen. + Er zijn nog geen waifus geclaimed. Top Waifus @@ -1153,33 +1122,33 @@ Vergeet niet je discord naam en id in het bericht te zetten. Jouw affiniteit is al ingesteld op een waifu, of je probeert om je affiniteit weg te halen terwijl je geen hebt. - Affiniteit verandert van {0} naar {1} + Affiniteit veranderd van {0} naar {1} -Dit is moreel twijfelachtig🤔 +*Dit is moreel gezien twijfelachtig.*🤔 Make sure to get the formatting right, and leave the thinking emoji Je moet {0} uren en {1} minuten wachten om je affiniteit weer te veranderen. - Jouw affiniteit is gereset. Je hebt geen persoon meer die je leuk vindt. + Je affiniteit is gereset. Je hebt geen persoon meer die je leuk vindt. wil {0}'s waifu zijn. Aww <3 - heeft {0} genomen als hun waifu voor {1}! + heeft {0} geclaimed als hun waifu voor {1}! - Je bent gescheiden met een waifu die jou leuk vindt. Jij harteloze monster. + Je bent gescheiden met een waifu die jou leuk vindt. Jij harteloos monster. {0} ontvangen {1} als compensatie. - Je kunt geen affiniteit zelf opzetten, jij opgeblazen egoist. + Je kunt geen affiniteit voor jezelf instellen, jij opgeblazen egoist. - 🎉Hun liefde overvloeit! 🎉 -{0} nieuwe waarde is {1}! + 🎉Hun liefde overvloeit! 🎉 +{0}'s nieuwe waarde is {1}! Geen enkele waifu is zo goedkoop. Je moet tenminste {0} betalen om een waifu te krijgen, ook al is hun echte waarde lager. @@ -1188,7 +1157,7 @@ Dit is moreel twijfelachtig🤔 Je moet tenminste {0} betalen om die waifu te nemen! - Die waifu is niet van jouw. + Die waifu is niet van jou. Je kunt jezelf niet als waifu nemen. @@ -1203,7 +1172,7 @@ Dit is moreel twijfelachtig🤔 Je bent gescheiden met een waifu die jou niet leuk vindt. Je krijgt {0} terug. - 8bal + 8ball Acrophobie @@ -1212,7 +1181,7 @@ Dit is moreel twijfelachtig🤔 Spel afgelopen zonder inzendingen. - Geen stemmen ingestuurdt. Spel geëindigd zonder winnaar. + Geen stemmen ingestuurd. Spel beëindigd zonder winnaar. Afkorting was {0} @@ -1254,10 +1223,10 @@ Dit is moreel twijfelachtig🤔 Inzendingen gesloten. - Dieren Race is al bezig. + Dierenrace is al bezig. - Totaal: {0} Gemiddelde: {1} + Totaal: {0} Gemiddeld: {1} Categorie @@ -1275,31 +1244,29 @@ Dit is moreel twijfelachtig🤔 Valuta generatie is ingeschakeld op dit kanaal. - {0} willekeurige {1} zijn verschenen! Pak ze op door `{2}pick` in te typen. - plural -Fuzzy + {0} willekeurige {1} zijn verschenen! + plural - Een willekeurige {0} is verschenen! Pak ze op door `{1}pick` in te typen. - Fuzzy + Een willekeurige {0} is verschenen! - Het laden van de vraag is gefaalt. + Het laden van de vraag is gefaald. Spel gestart. - Hangman + Galgje potje gestart - Er is al een spel galgje aan de gang in dit kanaal. + Er is al een potje galgje aan de gang in dit kanaal. Galgje kon niet opstarten vanwege een fout. - lijst van {0}Galgje term types: + Lijst van "{0}galgje" term types: Scoreboard @@ -1325,19 +1292,19 @@ Fuzzy Trivia spel - {0} heeft 'm geraden! Het antwoord was: {1} + {0} heeft 't geraden! Het antwoord was: {1} - Trivia is niet bezig in deze server. + Trivia is niet bezig op deze server. {0} heeft {1} punten - Stopt na deze vraag. + Er wordt gestopt na deze vraag. - Tijd is op! Het goede antwoord was {0} + De tijd is om! Het goede antwoord was {0} {0} heeft het antwoord geraden en wint het spel! Het antwoord was: {1} @@ -1346,13 +1313,13 @@ Fuzzy Je kan niet tegen jezelf spelen. - BoterKaasenEieren spel is al bezig in dit kannal. + Boter-Kaas-en-Eieren spel is al bezig in dit kanaal. Gelijkspel! - heeft een Boter, Kaas en eieren sessie aangemaakt. + heeft een Boter-Kaas-en-Eieren sessie aangemaakt. {0} heeft gewonnen! @@ -1373,7 +1340,7 @@ Fuzzy {0} tegen {1} - Aan het proberen om {0} liedjes in de wachtrij te zetten... + Aan het proberen om {0} tracks in de wachtrij te zetten... Autoplay uitgezet. @@ -1382,31 +1349,31 @@ Fuzzy Autoplay aangezet. - Standaard volume op {0}% gezet + Standaardvolume op {0}% gezet Map afspeellijst geladen/compleet. - Eerlijk spel. + fairplay - Liedje afgelopen + Track afgelopen: - Eerlijk spel uitgeschakeld. + Fairplay uitgeschakeld. - Eerlijk spel ingeschakeld. + Fairplay ingeschakeld. - van positie + Van positie ID - ongeldige invoer. + Ongeldige invoer. Maximale speeltijd heeft geen limiet meer. @@ -1418,7 +1385,7 @@ Fuzzy Maximale muziek wachtrij heeft geen limiet meer. - Maximale muziek wachtrij is nu {0} liedjes. + Maximale muziek wachtrij is nu {0} tracks. Je moet in het spraakkanaal van de server zijn. @@ -1443,26 +1410,26 @@ Fuzzy Speler afspeellijst - Pagina {0}/{1} - Liedje aan het spelen + Track speelt af - `#{0}` - **{1}** van *{2}* ({3} liedjes) + `#{0}` - **{1}** van *{2}* ({3} tracks) Pagina {0} van opgeslagen afspeellijsten - Afspeellijst verwijderd + Afspeellijst verwijderd. - Fout bij het verwijderen van de afspeellijst. Of het bestaat niet of U bent niet de auteur. + Fout bij het verwijderen van de afspeellijst. De afspeellijst bestaat niet of jij bent niet de eigenaar. Afspeellijst met dat ID bestaat niet. - Speler afspeellijst afgerond. + Afspeellijst wachtrij afgerond. Afspeellijst opgeslagen @@ -1474,7 +1441,7 @@ Fuzzy Wachtrij - Gekozen nummer + Nummer toegevoegd @@ -1484,41 +1451,41 @@ Fuzzy Wachtrij is vol op {0}/{0}. - Liedje verwijderd + Track verwijderd: context: "removed song #5" - Huidig liedje word herhaald + Huidige track word herhaald - Huidige afspeellijst word herhaald + Afspeellijst wordt herhaald - Herhaal nummer + Nummer wordt herhaald - Huidig nummer herhaling gestopt. + Huidige nummerherhaling gestopt. Nummer word hervat. - Herhaal afspeellijst uitgeschakeld. + Herhalende afspeellijst uitgeschakeld. - Herhaal afspeellijst ingeschakeld. + Herhalende afspeellijst ingeschakeld. - Muziek dat wordt gespeeld, afloopt, gepauzeerd en wordt verwijder laat ik in dit kanaal zien. + Tracks die worden afgespeeld, aflopen, gepauzeerd worden en worden verwijderd laat ik in dit kanaal zien. Overslaan naar `{0}:{1}` - Liedjes geschud + Tracks geschud - Liedje verzet + Track verzet {0}u {1}m {2}s @@ -1536,102 +1503,102 @@ Fuzzy Volume op {0}% gezet - Uitgeschakelde gebruik op alle moddelen in dit kanaal {0}. + ALLE MODULES zijn uitgeschakeld op kanaal {0}. - Ingeschakelde gebruik op alle moddelen in dit kanaal {0}. + ALLE MODULES zijn ingeschakeld op kanaal {0}. Toegestaan - Uitgeschakelde gebruik op alle moddelen voor deze rol {0}. + ALLE MODULES zijn uitgeschakeld voor deze rol {0}. - Ingeschakelde gebruik op alle moddelen voor deze rol{0}. + ALLE MODULES zijn ingeschakeld voor deze rol{0}. - Uitgeschakelde gebruik op alle moddelen in deze server. + ALLE MODULES zijn uitgeschakeld op deze server. - ingeschakelde gebruik op alle moddelen in deze server. + ALLE MODULES zijn ingeschakeld op deze server. - Uitgeschakelde gebruik op alle moddelen voor deze gebruiker{0}. + ALLE MODULES zijn uitgeschakeld voor deze gebruiker{0}. - Ingeschakelde gebruik op alle moddelen voor deze gebruiker{0}. + ALLE MODULES zijn ingeschakeld voor deze gebruiker{0}. Blacklisted {0} met ID {1} - Commando {0} heeft nu een {1}s afkoel tijd. + Commando {0} heeft nu een {1} seconden cooldown. - Commando {0} heeft geen afkoel tijd meer, en alle bestaande afkoeltijden zijn weggehaald. + Commando {0} heeft geen cooldown meer, en alle bestaande cooldowns zijn weggehaald. - Geen commando afkoeltijden ingesteld. + Geen commando cooldowns ingesteld. Command kosten - Uitgeschakelde gebruik van {0} {1} in kanaal {2}. + Gebruik van {0} {1} uitgeschakeld in kanaal {2}. - Ingeschakelde gebruik van {0} {1} in kanaal {2}. + Gebruik van {0} {1} ingeschakeld in kanaal {2}. Geweigerd - Woord {0} tegevoegd aan de lijst met foute woorden. + Woord {0} toegevoegd aan de lijst met gefilterde woorden. - Lijst van gefilterde worden + Lijst van gefilterde woorden - Woord {0} verwijderd van de lijst met foute woorden. + Woord {0} verwijderd van de lijst met gefilterde woorden. - Ongeldige tweede parameter.(Moet een number zijn tussen {0} en {1}) + Ongeldige tweede parameter (moet een nummer zijn tussen {0} en {1}). - Uitnodiging filter uitgeschakeld in dit kanaal. + Uitnodigingfilter uitgeschakeld in dit kanaal. - Uitnodiging filter ingeschakeld in dit kanaal. + Uitnodigingfilter ingeschakeld in dit kanaal. - Uitnodiging filter uitgeschakeld in deze server. + Uitnodigingfilter uitgeschakeld in deze server. - Uitnodiging filter ingeschakeld in deze server. + Uitnodigingfilter ingeschakeld in deze server. - Verplaat toestemming {0} voor #{1} naar #{2} + Toestemming {0} verplaatst van #{1} naar #{2} - Kan geen toestemming vinden in inhoudsopgave #{0} + Kan de toestemming niet vinden in inhoudsopgave #{0} Geen kosten ingesteld. - Commando + commando Gen (of command) - Module + module Gen. (of module) Rechten pagina {0} - Actueel toestemming rol is {0}. + Actuele toestemmingsrol is {0}. Gebruiker heeft nu {0} rol om toestemmingen te veranderen. @@ -1643,20 +1610,20 @@ Fuzzy Verwijderd toestemming #{0} - {1} - Uitgeschakelde gebruik van {0} {1} voor rol {2}. + Gebruik van {0} {1} uitgeschakeld voor rol {2}. - Ingeschakelde gebruik van {0} {1} voor rol {2}. + Gebruik van {0} {1} ingeschakeld voor rol {2}. - Seconden + sec. Short of seconds. - Uitgeschakelde gebruik van {0} {1} op deze server. + Gebruik van {0} {1} uitgeschakeld op deze server. - Ingeschakelde gebruik van {0} {1} op deze server. + Gebruik van {0} {1} ingeschakeld op deze server. Unblacklisted {0} met ID {1} @@ -1671,31 +1638,31 @@ Fuzzy Ingeschakelde gebruik van {0} {1} voor gebruiker {2}. - Ik zal geen permissie waarschuwingen meer weergeven. + Ik zal geen permissiewaarschuwingen meer weergeven. - Ik zal permissie waarschuwingen weergeven. + Ik zal permissiewaarschuwingen weergeven. - Woord filter gedeactiveerd in dit kanaal. + Woordfilter gedeactiveerd in dit kanaal. - Woord filter geactiveerd in dit kanaal. + Woordfilter geactiveerd in dit kanaal. - Woord filter gedeactiveerd in deze server. + Woordfilter gedeactiveerd in deze server. - Woord filter geactiveerd in deze server. + Woordfilter geactiveerd in deze server. - Talenten + Begaafdheid Nog geen favoriete anime - Gestart met het automatisch vertalen van berichten op dit kanaal. Gebruiker berichten worden automatisch verwijderd. + Gestart met het automatisch vertalen van berichten op dit kanaal. Berichten van gebruikers worden automatisch verwijderd. Jouw automatisch translatie taal is verwijderd. @@ -2211,7 +2178,7 @@ Eigenaar ID: {2} Geen speciale emojis gevonden. - {0} liedjes aan het spelen, {1} in de wachtrij + {0} tracks aan het spelen, {1} in de wachtrij Tekst Kanalen From 5996dc3ecf67f10fce3d6ba1641177f3cf05c2e0 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 27 Mar 2017 14:45:16 +0200 Subject: [PATCH 631/746] Update ResponseStrings.en-US.resx (POEditor.com) --- .../Resources/ResponseStrings.en-US.resx | 4328 ++++++++--------- 1 file changed, 2164 insertions(+), 2164 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.en-US.resx b/src/NadekoBot/Resources/ResponseStrings.en-US.resx index 3fb0ba18..ccff686e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.en-US.resx +++ b/src/NadekoBot/Resources/ResponseStrings.en-US.resx @@ -1,4 +1,4 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 そのベースはもう要求・破壊されました。 @@ -856,7 +856,7 @@ Fuzzy ユーザー{1}にロール{0}を追加しました - Typo- "successfully" should be 'Successfully' + Typo- "Sucessfully" should be 'Successfully' ロールの追加に失敗しました。アクセス権が足りません。 From bb2e647dbd8e090db75c18b14b99f1abe5a2948c Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 27 Mar 2017 14:45:27 +0200 Subject: [PATCH 635/746] Update ResponseStrings.nb-NO.resx (POEditor.com) --- .../Resources/ResponseStrings.nb-NO.resx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx b/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx index f566494b..08aa81fa 100644 --- a/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx +++ b/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx @@ -2305,34 +2305,34 @@ Eier ID: {2} Stemmekanal-roller - + Meldingen som aktiverer reaksjonen med ID {0} vil ikke bli automatisk slettet. - + Meldingen som aktiverer reaksjonen med ID {0} vil bli automatisk slettet. - + Respons-meldingen for tilpasset reaksjon med ID {0} vil ikke bli sendt som DM. - + Respons-meldingen for tilpasset reaksjon med ID {0} vil bli sendt som DM - + Ingen alias funnet - + {0} er nå alias for {1} - + Liste over alias - + {0} har ikke lenger noe alias - + {0} hadde ikke noe alias - + Kompetitiv spilltid \ No newline at end of file From b84eeb055606982cfd95dd71ad32dc7f81119b2e Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 27 Mar 2017 14:45:29 +0200 Subject: [PATCH 636/746] Update ResponseStrings.pl-PL.resx (POEditor.com) --- .../Resources/ResponseStrings.pl-PL.resx | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx index 013b1cd8..2d71a47b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx @@ -486,7 +486,7 @@ Powód: {1} - + Język bota ustawiony na {0} - {1} @@ -501,7 +501,8 @@ Powód: {1} Opuścił serwer {0} - + Logowanie wydarzenia {0} na tym kanale. + Fuzzy Logowanie wszystkich wydarzeń na tym kanale. @@ -513,7 +514,7 @@ Powód: {1} - + Logowanie będzie ignorowało {0} Logowanie nie będzie ignorowało {0} @@ -1816,7 +1817,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Oryginalny URL - + Klucz osu! API jest wymagany. @@ -1825,10 +1826,10 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Znaleziono {0} obrazków. Pokazuję przypadkowe {0} - + Nie znaleziono użytkownika! Proszę sprawdzić Region i BattleTag zanim znowu spróbujesz. - + Planowane Platforma @@ -1876,7 +1877,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Status - + Url sklepu Streamer {0} jest niedostępny. @@ -1898,7 +1899,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Stream prawdopodobnie nie istnieje. - + Usunięto stream użytkownika {0} ({1}) z powiadomień. @@ -1934,7 +1935,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Widzowie: - + Oglądane @@ -1949,7 +1950,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Szybkość wiatru - + Najczęściej banowane postacie w {0} Problem z napisaniem Twojego zdania w stylu Yody @@ -1966,7 +1967,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Łącznie {0} użytkowników. Autor @@ -1987,13 +1988,13 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + {0} {1} wynosi {2} {3} - + Jednostki które mogą być przekonwertwane - + Nie można przekonwertować {0} na {1}: nie znaleziono jednostki @@ -2077,13 +2078,13 @@ ID właściciela: {2} - + Brak roli na tej stronie. - + Brak tematu. Właściciel @@ -2100,10 +2101,10 @@ ID właściciela: {2} {2} kanałów tekstowych - + Usunięto wszystkie cytaty ze słowem {0}. - + {0} strona cytatów @@ -2112,10 +2113,10 @@ ID właściciela: {2} - + Dodano cytat - + Usunięto cytat #{0} Region @@ -2184,7 +2185,7 @@ ID właściciela: {2} - + **Nazwa:** {0} **Link:** {1} Nie znaleziono żadnych specjalnych emotikon @@ -2196,7 +2197,7 @@ ID właściciela: {2} Kanały głosowe - + Twój link do pokoju: From 2ef207e4dc20c32cf8d8ac0477d3a714a3a69e1c Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 27 Mar 2017 14:45:32 +0200 Subject: [PATCH 637/746] Update ResponseStrings.pt-BR.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.pt-BR.resx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx index f24177e0..abbdde18 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx @@ -583,7 +583,7 @@ Razão: {1} Nenhum shard com aquele ID foi encontrado. - Mensagem Antiga + Mensagem Anterior Fuzzy @@ -794,14 +794,12 @@ __Canais Ignorados__: {2} Nome de usuário alterado - Fuzzy Usuários Usuário Banido - Fuzzy {0} foi **mutado** @@ -1134,7 +1132,7 @@ Não esqueça de deixar seu nome ou id do discord na mensagem. O segundo número deve ser maior que o primeiro. - Mudanças no Coração + Mudanças de ideia Fuzzy @@ -1918,7 +1916,7 @@ Fuzzy Pontuação: - Busca Por: + Buscar Por: Fuzzy @@ -2094,8 +2092,7 @@ Fuzzy Índice fora de alcance. - Aqui está uma lista de usuários nestes cargos: - Fuzzy + Lista de usuários no cargo {0} você não tem permissão de usar esse comando em cargos com muitos usuários para prevenir abuso. @@ -2189,7 +2186,7 @@ OwnerID: {2} Citação adicionada - Uma citação aleatória foi removida. + Citação #{0} Deletada. Fuzzy From dd7e657900e1855ef41c213103e756b94f7b7953 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 27 Mar 2017 14:45:35 +0200 Subject: [PATCH 638/746] Update ResponseStrings.ru-RU.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.ru-RU.resx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx index b1039c13..8edacbe6 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx @@ -1422,7 +1422,6 @@ Fuzzy Плейлист с таким номером не существует. - Fuzzy Добавление плейлиста в очередь завершено. @@ -1526,7 +1525,6 @@ Fuzzy {0} добавлено в чёрный список под номером {1} - Fuzzy У команды {0} теперь есть время перезарядки {1}c @@ -1624,7 +1622,6 @@ Fuzzy {0} с номером {1} убраны из черного списка. - Fuzzy нередактируемое @@ -2268,11 +2265,11 @@ Fuzzy Fuzzy - Ответное сообщение для настраеваемой реакцией с номером {0} не будет отправлено в ЛС. + Ответное сообщение для настраеваемой реакции с номером {0} не будет отправлено в ЛС. Fuzzy - Ответное сообщение для настраиваемой реакцией с номером {0} будет отправлено в ЛС. + Ответное сообщение для настраиваемой реакции с номером {0} будет отправлено в ЛС. Fuzzy From 616003d83122d9778f390764e6ed2004a9df5bca Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 27 Mar 2017 14:45:38 +0200 Subject: [PATCH 639/746] Update ResponseStrings.sr-cyrl-rs.resx (POEditor.com) --- .../Resources/ResponseStrings.sr-cyrl-rs.resx | 240 +++++++++--------- 1 file changed, 120 insertions(+), 120 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx index 8c3dd6c5..8fe7d18e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Та база је већ под захетвом или је уништена. @@ -364,7 +364,7 @@ Reason: {1} Content - successfully created role {0} + Sucessfully created role {0} Text channel {0} created. @@ -394,7 +394,7 @@ Reason: {1} DM from - successfully added a new donator.Total donated amount from this user: {0} 👑 + Sucessfully added a new donator.Total donated amount from this user: {0} 👑 Thanks to the people listed below for making this project hjappen! @@ -712,7 +712,7 @@ Reason: {1} You now have {0} role. - successfully added role {0} to user {1} + Sucessfully added role {0} to user {1} Failed to add role. I have insufficient permissions. From f8f23f9d3079184b452bd798099b6d08cddc4b93 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 27 Mar 2017 14:45:40 +0200 Subject: [PATCH 640/746] Update ResponseStrings.es-ES.resx (POEditor.com) From 7190c56751d45eedbfa20a902c197faa93db2b73 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 27 Mar 2017 14:45:43 +0200 Subject: [PATCH 641/746] Update ResponseStrings.sv-SE.resx (POEditor.com) --- .../Resources/ResponseStrings.sv-SE.resx | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx index bd3d6093..6ee45f0f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx @@ -156,7 +156,7 @@ Fuzzy - Lista Över Aktiva Krig + Lista över aktiva krig Fuzzy @@ -209,7 +209,7 @@ Nya egengjorda Reaktioner - Inga egnagjorde reaktioner hittades. + Inga custom reaktioner hittades. Fuzzy @@ -536,11 +536,11 @@ Anledning: {1} {0} flyttad från {1] till {2} - Meddelande Raderat i #{0} + Meddelande raderat i #{0} Fuzzy - Meddelande Uppdaterat i #{0} + Meddelande uppdaterat i #{0} Fuzzy @@ -561,19 +561,19 @@ Anledning: {1} Jag behöver **Administration** tillåtelse för att göra det där. - Nytt Meddelande + Ny meddelande Fuzzy - Nytt Smeknamn + Ny smeknamn Fuzzy - Nytt Ämne + Ny ämne Fuzzy - Smeknamn Ändrat + Smeknamn ändrat Fuzzy @@ -583,15 +583,15 @@ Anledning: {1} Ingen shard med den ID funnen - Gammalt Meddelande + Gammal meddelande Fuzzy - Gammalt Smeknamn + Gammal smeknamn Fuzzy - Gammalt Ämne + Gammal ämne Fuzzy @@ -601,7 +601,7 @@ Anledning: {1} Tillstånd för denna server har blivit återställt. - Aktiva Skydd + Aktiva skydd Fuzzy @@ -2342,7 +2342,7 @@ Medlemmar: {1} Meddelandet som triggrar den egengjorda reaktion med id {0} kommer bli - + Svar meddelande för custom reaktion med id {0} kommer inte att skickas som ett DM. @@ -2358,10 +2358,10 @@ Medlemmar: {1} Lista av aliaser - + Aktivering {0} har inte längre någon alias. - + Trigger {0} hade ingen alias. Kompetitiv speltid From 87514da13472042a2ae093e6eb6e1153bc044283 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 27 Mar 2017 14:45:46 +0200 Subject: [PATCH 642/746] Update ResponseStrings.tr-TR.resx (POEditor.com) From 2623af5e658bfa88c30ea3bf86b8fc4120028996 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 27 Mar 2017 14:45:48 +0200 Subject: [PATCH 643/746] Update ResponseStrings.it-IT.resx (POEditor.com) --- .../Resources/ResponseStrings.it-IT.resx | 234 +++++++++--------- 1 file changed, 117 insertions(+), 117 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.it-IT.resx b/src/NadekoBot/Resources/ResponseStrings.it-IT.resx index 7a09ef5d..5a922057 100644 --- a/src/NadekoBot/Resources/ResponseStrings.it-IT.resx +++ b/src/NadekoBot/Resources/ResponseStrings.it-IT.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Quella base è già rivendicata o distrutta. From ccb90c7d154120797e96bd1fe70119390731a5b0 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 27 Mar 2017 14:45:51 +0200 Subject: [PATCH 644/746] Update ResponseStrings.he-IL.resx (POEditor.com) --- .../Resources/ResponseStrings.he-IL.resx | 234 +++++++++--------- 1 file changed, 117 insertions(+), 117 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.he-IL.resx b/src/NadekoBot/Resources/ResponseStrings.he-IL.resx index 5ddf049e..7f42401e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.he-IL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.he-IL.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 הבסיס הזה נתפס או נהרס. From ff74c861f45e50e60748f47b9282cfb3daedd486 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 27 Mar 2017 14:45:53 +0200 Subject: [PATCH 645/746] Update ResponseStrings.ko-KR.resx (POEditor.com) --- .../Resources/ResponseStrings.ko-KR.resx | 236 +++++++++--------- 1 file changed, 118 insertions(+), 118 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ko-KR.resx b/src/NadekoBot/Resources/ResponseStrings.ko-KR.resx index cf1c65d5..223b9397 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ko-KR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ko-KR.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 기지가 이미 요청되었거나 파괴되었습니다. @@ -794,7 +794,7 @@ Fuzzy 텍스트 채널이 삭제되었습니다. - destroyed means deleted? + destroyed means deleted? 디스트로이드 뜻이 삭제됬다는 건가요? From 81aec75d066c2b7fe7b95c412645ac4629ecc803 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 27 Mar 2017 14:55:25 +0200 Subject: [PATCH 646/746] upped version --- 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 676d7407..ba0f5e37 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -16,7 +16,7 @@ namespace NadekoBot.Services.Impl private readonly DiscordShardedClient _client; private readonly DateTime _started; - public const string BotVersion = "1.25a"; + public const string BotVersion = "1.26"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From 1bf1dc90779f92f38657360e57fcf9627567be01 Mon Sep 17 00:00:00 2001 From: Hubcapp Date: Mon, 27 Mar 2017 08:26:11 -0500 Subject: [PATCH 647/746] Add more articles, mostly sourced from the ancient fortunes program for posix os's. Please review and reject any you find objectionable. I wasn't given any guidelines on how to pick these. I may add more after some feedback. --- src/NadekoBot/data/typing_articles.json | 272 ++++++++++++++++++++++++ 1 file changed, 272 insertions(+) diff --git a/src/NadekoBot/data/typing_articles.json b/src/NadekoBot/data/typing_articles.json index 9850103f..4666a5e7 100644 --- a/src/NadekoBot/data/typing_articles.json +++ b/src/NadekoBot/data/typing_articles.json @@ -262,4 +262,276 @@ { "Title":"A Dictionary of Psychology", "Text":"Entries are extensively cross-referenced for ease of use, and cover word origins and derivations as well as definitions. Over 80 illustrations complement the text." + }, + { + "Title":"darbian regarding how fast you can learn to speedrun" + "Text":"This depends on a number of factors. The answer will be very different for someone who doesn't have a lot of experience with videogames compared to someone who is already decent at retro platformers. In my case, it took about a year of playing on and off to get pretty competitive at the game, but there have been others who did it much faster. With some practice you can get a time that would really impress your friends after only a few days of practice." + }, + { + "Title":"Memes" + "Text":"The FitnessGram Pacer Test is a multistage aerobic capacity test that progressively gets more difficult as it continues. The 20 meter pacer test will begin in 30 seconds. Line up at the start. The running speed starts slowly, but gets faster each minute after you hear this signal. [beep] A single lap should be completed each time you hear this sound. [ding] Remember to run in a straight line, and run as long as possible. The second time you fail to complete a lap before the sound, your test is over. The test will begin on the word start. On your mark, get ready, start." + }, + { + "Title":"Literature quotes" + "Text":"A banker is a fellow who lends you his umbrella when the sun is shining and wants it back the minute it begins to rain. -- Mark Twain" + }, + { + "Title":"Literature quotes" + "Text":"A classic is something that everyone wants to have read and nobody wants to read. -- Mark Twain" + }, + { + "Title":"Literature quotes" + "Text":"After all, all he did was string together a lot of old, well-known quotations. -- H. L. Mencken, on Shakespeare" + }, + { + "Title":"Literature quotes" + "Text":"All generalizations are false, including this one. -- Mark Twain" + }, + { + "Title":"Literature quotes" + "Text":"All I know is what the words know, and dead things, and that makes a handsome little sum, with a beginning and a middle and an end, as in the well-built phrase and the long sonata of the dead. -- Samuel Beckett" + }, + { + "Title":"Literature quotes" + "Text":"All say, \"How hard it is that we have to die\" -- a strange complaint to come from the mouths of people who have had to live. -- Mark Twain" + }, + { + "Title":"Literature quotes" + "Text":"At once it struck me what quality went to form a man of achievement, especially in literature, and which Shakespeare possessed so enormously -- I mean negative capability, that is, when a man is capable of being in uncertainties, mysteries, doubts, without any irritable reaching after fact and reason. -- John Keats" + }, + { + "Title":"Pat Cadigan, \"Mindplayers\"" + "Text":"A morgue is a morgue is a morgue. They can paint the walls with aggressively cheerful primary colors and splashy bold graphics, but it's still a holding place for the dead until they can be parted out to organ banks. Not that I would have cared normally but my viewpoint was skewed. The relentless pleasance of the room I sat in seemed only grotesque." + }, + { + "Title":"Men & Women" + "Text":"A diplomatic husband said to his wife, \"How do you expect me to remember your birthday when you never look any older?\"" + }, + { + "Title":"James L. Collymore, \"Perfect Woman\"" + "Text":"I began many years ago, as so many young men do, in searching for the perfect woman. I believed that if I looked long enough, and hard enough, I would find her and then I would be secure for life. Well, the years and romances came and went, and I eventually ended up settling for someone a lot less than my idea of perfection. But one day, after many years together, I lay there on our bed recovering from a slight illness. My wife was sitting on a chair next to the bed, humming softly and watching the late afternoon sun filtering through the trees. The only sounds to be heard elsewhere were the clock ticking, the kettle downstairs starting to boil, and an occasional schoolchild passing beneath our window. And as I looked up into my wife's now wrinkled face, but still warm and twinkling eyes, I realized something about perfection... It comes only with time." + }, + { + "Title":"Famous quotes" + "Text":"I have now come to the conclusion never again to think of marrying, and for this reason: I can never be satisfied with anyone who would be blockhead enough to have me. -- Abraham Lincoln" + }, + { + "Title":"Men & Women" + "Text":"In the midst of one of the wildest parties he'd ever been to, the young man noticed a very prim and pretty girl sitting quietly apart from the rest of the revelers. Approaching her, he introduced himself and, after some quiet conversation, said, \"I'm afraid you and I don't really fit in with this jaded group. Why don't I take you home?\" \"Fine,\" said the girl, smiling up at him demurely. \"Where do you live?\"" + }, + { + "Title":"Encyclopadia Apocryphia, 1990 ed." + "Text":"There is no realizable power that man cannot, in time, fashion the tools to attain, nor any power so secure that the naked ape will not abuse it. So it is written in the genetic cards -- only physics and war hold him in check. And also the wife who wants him home by five, of course." + }, + { + "Title":"Susan Gordon" + "Text":"What publishers are looking for these days isn't radical feminism. It's corporate feminism -- a brand of feminism designed to sell books and magazines, three-piece suits, airline tickets, Scotch, cigarettes and, most important, corporate America's message, which runs: Yes, women were discriminated against in the past, but that unfortunate mistake has been remedied; now every woman can attain wealth, prestige and power by dint of individual rather than collective effort." + }, + { + "Title":"Susan Bolotin, \"Voices From the Post-Feminist Generation\"" + "Text":"When my freshman roommate at Cornell found out I was Jewish, she was, at her request, moved to a different room. She told me she didn't think she had ever seen a Jew before. My only response was to begin wearing a small Star of David on a chain around my neck. I had not become a more observing Jew; rather, discovering that the label of Jew was offensive to others made me want to let people know who I was and what I believed in. Similarly, after talking to these young women -- one of whom told me that she didn't think she had ever met a feminist -- I've taken to identifying myself as a feminist in the most unlikely of situations." + }, + { + "Title":"Medicine" + "Text":"Never die while in your doctor's prescence or under his direct care. This will only cause him needless inconvenience and embarassment." + }, + { + "Title":"Medicine" + "Text":"Human cardiac catheterization was introduced by Werner Forssman in 1929. Ignoring his department chief, and tying his assistant to an operating table to prevent her interference, he placed a ureteral catheter into a vein in his arm, advanced it to the right atrium [of his heart], and walked upstairs to the x-ray department where he took the confirmatory x-ray film. In 1956, Dr. Forssman was awarded the Nobel Prize." + }, + { + "Title":"The C Programming Language" + "Text":"In Chapter 3 we presented a Shell sort function that would sort an array of integers, and in Chapter 4 we improved on it with a quicksort. The same algorithms will work, except that now we have to deal with lines of text, which are of different lengths, and which, unlike integers, can't be compared or moved in a single operation." + }, + { + "Title":"Religious Texts" + "Text":"O ye who believe! Avoid suspicion as much (as possible): for suspicion in some cases in a sin: And spy not on each other behind their backs. Quran 49:12" + }, + { + "Title":"Religious Texts" + "Text":"If you want to destroy any nation without war, make adultery & nudity common in the next generation. -- Salahuddin Ayyubi" + }, + { + "Title":"Religious Texts" + "Text":"Whoever recommends and helps a good cause becomes a partner therein, and whoever recommends and helps an evil cause shares in its burdens. Quran 4:85" + }, + { + "Title":"Religious Texts" + "Text":"No servant can serve two masters. Either he will hate the one and love the other, or he will be devoted to the one and despise the other. You cannot serve both God and Money. Luke 16:13" + }, + { + "Title":"Religious Texts" + "Text":"So we do not lose heart. Though our outer man is wasting away, our inner self is being renewed day by day. For this light momentary affliction is preparing for us an eternal weight of glory beyond all comparison, as we look not to the things that are seen but to the things that are unseen. For the things that are seen are transient, but the things that are unseen are eternal. 2 Corinthians 4:16-18" + }, + { + "Title":"Religious Texts" + "Text":"And out of that hopeless attempt has come nearly all that we call human history -- money, poverty, ambition, war, prostitution, classes, empires, slavery -- the long terrible story of man trying to find something other than God which will make him happy. -- C.S. Lewis" + }, + { + "Title":"Medicine" + "Text":"Your digestive system is your body's Fun House, whereby food goes on a long, dark, scary ride, taking all kinds of unexpected twists and turns, being attacked by vicious secretions along the way, and not knowing until the last minute whether it will be turned into a useful body part or ejected into the Dark Hole by Mister Sphincter. We Americans live in a nation where the medical-care system is second to none in the world, unless you count maybe 25 or 30 little scuzzball countries like Scotland that we could vaporize in seconds if we felt like it. -- Dave Barry" + }, + { + "Title":"Medicine" + "Text":"The trouble with heart disease is that the first symptom is often hard to deal with: death. -- Michael Phelps" + }, + { + "Title":"Medicine" + "Text":"Never go to a doctor whose office plants have died -- Erma Bombeck" + }, + { + "Title":"Science" + "Text":"Albert Einstein, when asked to describe radio, replied: \"You see, wire telegraph is a kind of a very, very long cat. You pull his tail in NewYork and his head is meowing in Los Angeles. Do you understand this? And radio operates exactly the same way: you send signals here, they receive them there. The only difference is that there is no cat.\"" + }, + { + "Title":"Carl Sagan, \"The Fine Art of Baloney Detection\"" + "Text":"At the heart of science is an essential tension between two seemingly contradictory attitudes -- an openness to new ideas, no matter how bizarre or counterintuitive they may be, and the most ruthless skeptical scrutiny of all ideas, old and new. This is how deep truths are winnowed from deep nonsense. Of course, scientists make mistakes in trying to understand the world, but there is a built-in error-correcting mechanism: The collective enterprise of creative thinking and skeptical thinking together keeps the field on track." + }, + { + "Title":"#Octalthorpe" + "Text":"Back in the early 60's, touch tone phones only had 10 buttons. Some military versions had 16, while the 12 button jobs were used only by people who had \"diva\" (digital inquiry, voice answerback) systems -- mainly banks. Since in those days, only Western Electric made \"data sets\" (modems) the problems of terminology were all Bell System. We used to struggle with written descriptions of dial pads that were unfamiliar to most people (most phones were rotary then.) Partly in jest, some AT&T engineering types (there was no marketing in the good old days, which is why they were the good old days) made up the term \"octalthorpe\" (note spelling) to denote the \"pound sign.\" Presumably because it has 8 points sticking out. It never really caught on." + }, + { + "Title":"Science -- Edgar R. Fiedler" + "Text":"Economists state their GDP growth projections to the nearest tenth of a percentage point to prove they have a sense of humor." + }, + { + "Title":"Science -- R. Buckminster Fuller" + "Text":"Everything you've learned in school as \"obvious\" becomes less and less obvious as you begin to study the universe. For example, there are no solids in the universe. There's not even a suggestion of a solid. There are no absolute continuums. There are no surfaces. There are no straight lines." + }, + { + "Title":"Math" + "Text":"Factorials were someone's attempt to make math LOOK exciting." + }, + { + "Title":"Science -- Thomas L. Creed" + "Text":"Fortunately, the responsibility for providing evidence is on the part of the person making the claim, not the critic. It is not the responsibility of UFO skeptics to prove that a UFO has never existed, nor is it the responsibility of paranormal-health-claims skeptics to prove that crystals or colored lights never healed anyone. The skeptic's role is to point out claims that are not adequately supported by acceptable evidcence and to provide plausible alternative explanations that are more in keeping with the accepted body of scientific evidence." + }, + { + "Title":"Science -- H. L. Mencken, 1930" + "Text":"There is, in fact, no reason to believe that any given natural phenomenon, however marvelous it may seem today, will remain forever inexplicable. Soon or late the laws governing the production of life itself will be discovered in the laboratory, and man may set up business as a creator on his own account. The thing, indeed, is not only conceivable; it is even highly probable." + }, + { + "Title":"Science" + "Text":"When Alexander Graham Bell died in 1922, the telephone people interrupted service for one minute in his honor. They've been honoring him intermittently ever since, I believe." + }, + { + "Title":"Science -- Stanislaw Lem" + "Text":"When the Universe was not so out of whack as it is today, and all the stars were lined up in their proper places, you could easily count them from left to right, or top to bottom, and the larger and bluer ones were set apart, and the smaller yellowing types pushed off to the corners as bodies of a lower grade..." + }, + { + "Title":"Science -- Dave Barry" + "Text":"You should not use your fireplace, because scientists now believe that, contrary to popular opinion, fireplaces actually remove heat from houses. Really, that's what scientists believe. In fact many scientists actually use their fireplaces to cool their houses in the summer. If you visit a scientist's house on a sultry August day, you'll find a cheerful fire roaring on the hearth and the scientist sitting nearby, remarking on how cool he is and drinking heavily." + }, + { + "Title":"Sports" + "Text":"Although golf was originally restricted to wealthy, overweight Protestants, today it's open to anybody who owns hideous clothing. -- Dave Barry" + }, + { + "Title":"Sports" + "Text":"Now there's three things you can do in a baseball game: you can win, you can lose, or it can rain. -- Casey Stengel" + }, + { + "Title":"Sports" + "Text":"Once there was this conductor see, who had a bass problem. You see, during a portion of Beethovan's Ninth Symphony in which there are no bass violin parts, one of the bassists always passed a bottle of scotch around. So, to remind himself that the basses usually required an extra cue towards the end of the symphony, the conductor would fasten a piece of string around the page of the score before the bass cue. As the basses grew more and more inebriated, two of them fell asleep. The conductor grew quite nervous (he was very concerned about the pitch) because it was the bottom of the ninth; the score was tied and the basses were loaded with two out." + }, + { + "Title":"Sports" + "Text":"When I'm gone, boxing will be nothing again. The fans with the cigars and the hats turned down'll be there, but no more housewives and little men in the street and foreign presidents. It's goin' to be back to the fighter who comes to town, smells a flower, visits a hospital, blows a horn and says he's in shape. Old hat. I was the onliest boxer in history people asked questions like a senator. -- Muhammad Ali" + }, + { + "Title":"Sports" + "Text":"The surest way to remain a winner is to win once, and then not play any more." + }, + { + "Title":"Sports" + "Text":"The real problem with hunting elephants is carrying the decoys" + }, + { + "Title":"Sports -- Dizzy Dean" + "Text":"The pitcher wound up and he flang the ball at the batter. The batter swang and missed. The pitcher flang the ball again and this time the batter connected. He hit a high fly right to the center fielder. The center fielder was all set to catch the ball, but at the last minute his eyes were blound by the sun and he dropped it." + }, + { + "Title":"Sports -- Babe Ruth, in his 1948 farewell speech at Yankee Stadium" + "Text":"The only real game in the world, I think, is baseball... You've got to start way down, at the bottom, when you're six or seven years old. You can't wait until you're fifteen or sixteen. You've got to let it grow up with you, and if you're successful and you try hard enough, you're bound to come out on top, just like these boys have come to the top now." + }, + { + "Title":"Sports" + "Text":"The one sure way to make a lazy man look respectable is to put a fishing rod in his hand." + }, + { + "Title":"Linux -- Linus Torvalds in response to \"Other than the fact Linux has a cool name, could someone explain why I should use Linux over BSD?\"" + "Text":"No. That's it. The cool name, that is. We worked very hard on creating a name that would appeal to the majority of people, and it certainly paid off: thousands of people are using linux just to be able to say \"OS/2? Hah. I've got Linux. What a cool name\". 386BSD made the mistake of putting a lot of numbers and weird abbreviations into the name, and is scaring away a lot of people just because it sounds too technical." + }, + { + "Title":"Smart House" + "Text":"A teenager wins a fully automated dream house in a competition, but soon the computer controlling it begins to take over and everything gets out of control, then Ben the teenager calms down the computer named Pat and everything goes back to normal." + }, + { + "Title":"True Words of a Genius Philosopher" + "Text":"Writing non-free software is not an ethically legitimate activity, so if people who do this run into trouble, that's good! All businesses based on non-free software ought to fail, and the sooner the better. -- Richard Stallman" + }, + { + "Title":"Linux -- Jim Wright" + "Text":"You know, if Red Hat was smart, they'd have a fake front on their office building just for visitors, where you would board a magical trolley that took you past the smiling singing oompah loompahs who take the raw linux sugar and make it into Red Hat candy goodness. Then they could use it as a motivator for employees... Shape up, or you're spending time working \"the ride\"!" + }, + { + "Title":"True Words of a Genius Philosopher" + "Text":"Free software is software that gives you the user the freedom to share, study and modify it. We call this free software because the user is free." + }, + { + "Title":"True Words of a Genius Philosopher" + "Text":"To use free software is to make a political and ethical choice asserting the right to learn, and share what we learn with others. Free software has become the foundation of a learning society where we share our knowledge in a way that others can build upon and enjoy." + }, + { + "Title":"True Words of a Genius Philosopher" + "Text":"Currently, many people use proprietary software that denies users these freedoms and benefits. If we make a copy and give it to a friend, if we try to figure out how the program works, if we put a copy on more than one of our own computers in our own home, we could be caught and fined or put in jail. That's what's in the fine print of the license agreement you accept when using proprietary software." + }, + { + "Title":"True Words of a Genius Philosopher" + "Text":"The corporations behind proprietary software will often spy on your activities and restrict you from sharing with others. And because our computers control much of our personal information and daily activities, proprietary software represents an unacceptable danger to a free society." + }, + { + "Title":"Politics -- Donald Trump" + "Text":"When Mexico sends its people, they're not sending their best. They're not sending you. They're sending people that have lots of problems, and they're bringing those problems with us. They're bringing drugs. They're bringing crime. Their rapists. And some, I assume, are good people." + }, + { + "Title":"Politics -- Sir Winston Churchill, 1952" + "Text":"A prisoner of war is a man who tries to kill you and fails, and then asks you not to kill him." + }, + { + "Title":"Politics -- Johnny Hart" + "Text":"Cutting the space budget really restores my faith in humanity. It eliminates dreams, goals, and ideals and lets us get straight to the business of hate, debauchery, and self-annihilation." + }, + { + "Title":"Politics -- Winston Churchill" + "Text":"Democracy is the worst form of government except all those other forms that have been tried from time to time." + }, + { + "Title":"Politics" + "Text":"Each person has the right to take part in the management of public affairs in his country, provided he has prior experience, a will to succeed, a university degree, influential parents, good looks, a curriculum vitae, two 3x4 snapshots, and a good tax record." + }, + { + "Title":"Politics -- A Yippie Proverb" + "Text":"Free Speech Is The Right To Shout 'Theater' In A Crowded Fire." + }, + { + "Title":"Politics -- Boss Tweed" + "Text":"I don't care who does the electing as long as I get to do the nominating." + }, + { + "Title":"Politics -- Francis Bellamy, 1892" + "Text":"I pledge allegiance to the flag of the United States of America and to the republic for which it stands, one nation, indivisible, with liberty and justice for all." + }, + { + "Title":"Politics -- Napoleon" + "Text":"It follows that any commander in chief who undertakes to carry out a plan which he considers defective is at fault; he must put forth his reasons, insist of the plan being changed, and finally tender his resignation rather than be the instrument of his army's downfall." + }, + { + "Title":"Politics" + "Text":"Only two kinds of witnesses exist. The first live in a neighborhood where a crime has been committed and in no circumstances have ever seen anything or even heard a shot. The second category are the neighbors of anyone who happens to be accused of the crime. These have always looked out of their windows when the shot was fired, and have noticed the accused person standing peacefully on his balcony a few yards away." + }, + { + "Title":"Politics -- Frederick Douglass" + "Text":"Slaves are generally expected to sing as well as to work ... I did not, when a slave, understand the deep meanings of those rude, and apparently incoherent songs. I was myself within the circle, so that I neither saw nor heard as those without might see and hear. They told a tale which was then altogether beyond my feeble comprehension: they were tones, loud, long and deep, breathing the prayer and complaint of souls boiling over with the bitterest anguish. Every tone was a testimony against slavery, and a prayer to God for deliverance from chains." }] From 13d6775b2f1d2f265ba45dde752b1cb29a660eef Mon Sep 17 00:00:00 2001 From: Hubcapp Date: Mon, 27 Mar 2017 08:45:58 -0500 Subject: [PATCH 648/746] I think you'll need these. --- src/NadekoBot/data/typing_articles.json | 136 ++++++++++++------------ 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/src/NadekoBot/data/typing_articles.json b/src/NadekoBot/data/typing_articles.json index 4666a5e7..054573a0 100644 --- a/src/NadekoBot/data/typing_articles.json +++ b/src/NadekoBot/data/typing_articles.json @@ -264,274 +264,274 @@ "Text":"Entries are extensively cross-referenced for ease of use, and cover word origins and derivations as well as definitions. Over 80 illustrations complement the text." }, { - "Title":"darbian regarding how fast you can learn to speedrun" + "Title":"darbian regarding how fast you can learn to speedrun", "Text":"This depends on a number of factors. The answer will be very different for someone who doesn't have a lot of experience with videogames compared to someone who is already decent at retro platformers. In my case, it took about a year of playing on and off to get pretty competitive at the game, but there have been others who did it much faster. With some practice you can get a time that would really impress your friends after only a few days of practice." }, { - "Title":"Memes" + "Title":"Memes", "Text":"The FitnessGram Pacer Test is a multistage aerobic capacity test that progressively gets more difficult as it continues. The 20 meter pacer test will begin in 30 seconds. Line up at the start. The running speed starts slowly, but gets faster each minute after you hear this signal. [beep] A single lap should be completed each time you hear this sound. [ding] Remember to run in a straight line, and run as long as possible. The second time you fail to complete a lap before the sound, your test is over. The test will begin on the word start. On your mark, get ready, start." }, { - "Title":"Literature quotes" + "Title":"Literature quotes", "Text":"A banker is a fellow who lends you his umbrella when the sun is shining and wants it back the minute it begins to rain. -- Mark Twain" }, { - "Title":"Literature quotes" + "Title":"Literature quotes", "Text":"A classic is something that everyone wants to have read and nobody wants to read. -- Mark Twain" }, { - "Title":"Literature quotes" + "Title":"Literature quotes", "Text":"After all, all he did was string together a lot of old, well-known quotations. -- H. L. Mencken, on Shakespeare" }, { - "Title":"Literature quotes" + "Title":"Literature quotes", "Text":"All generalizations are false, including this one. -- Mark Twain" }, { - "Title":"Literature quotes" + "Title":"Literature quotes", "Text":"All I know is what the words know, and dead things, and that makes a handsome little sum, with a beginning and a middle and an end, as in the well-built phrase and the long sonata of the dead. -- Samuel Beckett" }, { - "Title":"Literature quotes" + "Title":"Literature quotes", "Text":"All say, \"How hard it is that we have to die\" -- a strange complaint to come from the mouths of people who have had to live. -- Mark Twain" }, { - "Title":"Literature quotes" + "Title":"Literature quotes", "Text":"At once it struck me what quality went to form a man of achievement, especially in literature, and which Shakespeare possessed so enormously -- I mean negative capability, that is, when a man is capable of being in uncertainties, mysteries, doubts, without any irritable reaching after fact and reason. -- John Keats" }, { - "Title":"Pat Cadigan, \"Mindplayers\"" + "Title":"Pat Cadigan, \"Mindplayers\"", "Text":"A morgue is a morgue is a morgue. They can paint the walls with aggressively cheerful primary colors and splashy bold graphics, but it's still a holding place for the dead until they can be parted out to organ banks. Not that I would have cared normally but my viewpoint was skewed. The relentless pleasance of the room I sat in seemed only grotesque." }, { - "Title":"Men & Women" + "Title":"Men & Women", "Text":"A diplomatic husband said to his wife, \"How do you expect me to remember your birthday when you never look any older?\"" }, { - "Title":"James L. Collymore, \"Perfect Woman\"" + "Title":"James L. Collymore, \"Perfect Woman\"", "Text":"I began many years ago, as so many young men do, in searching for the perfect woman. I believed that if I looked long enough, and hard enough, I would find her and then I would be secure for life. Well, the years and romances came and went, and I eventually ended up settling for someone a lot less than my idea of perfection. But one day, after many years together, I lay there on our bed recovering from a slight illness. My wife was sitting on a chair next to the bed, humming softly and watching the late afternoon sun filtering through the trees. The only sounds to be heard elsewhere were the clock ticking, the kettle downstairs starting to boil, and an occasional schoolchild passing beneath our window. And as I looked up into my wife's now wrinkled face, but still warm and twinkling eyes, I realized something about perfection... It comes only with time." }, { - "Title":"Famous quotes" + "Title":"Famous quotes", "Text":"I have now come to the conclusion never again to think of marrying, and for this reason: I can never be satisfied with anyone who would be blockhead enough to have me. -- Abraham Lincoln" }, { - "Title":"Men & Women" + "Title":"Men & Women", "Text":"In the midst of one of the wildest parties he'd ever been to, the young man noticed a very prim and pretty girl sitting quietly apart from the rest of the revelers. Approaching her, he introduced himself and, after some quiet conversation, said, \"I'm afraid you and I don't really fit in with this jaded group. Why don't I take you home?\" \"Fine,\" said the girl, smiling up at him demurely. \"Where do you live?\"" }, { - "Title":"Encyclopadia Apocryphia, 1990 ed." + "Title":"Encyclopadia Apocryphia, 1990 ed.", "Text":"There is no realizable power that man cannot, in time, fashion the tools to attain, nor any power so secure that the naked ape will not abuse it. So it is written in the genetic cards -- only physics and war hold him in check. And also the wife who wants him home by five, of course." }, { - "Title":"Susan Gordon" + "Title":"Susan Gordon", "Text":"What publishers are looking for these days isn't radical feminism. It's corporate feminism -- a brand of feminism designed to sell books and magazines, three-piece suits, airline tickets, Scotch, cigarettes and, most important, corporate America's message, which runs: Yes, women were discriminated against in the past, but that unfortunate mistake has been remedied; now every woman can attain wealth, prestige and power by dint of individual rather than collective effort." }, { - "Title":"Susan Bolotin, \"Voices From the Post-Feminist Generation\"" + "Title":"Susan Bolotin, \"Voices From the Post-Feminist Generation\"", "Text":"When my freshman roommate at Cornell found out I was Jewish, she was, at her request, moved to a different room. She told me she didn't think she had ever seen a Jew before. My only response was to begin wearing a small Star of David on a chain around my neck. I had not become a more observing Jew; rather, discovering that the label of Jew was offensive to others made me want to let people know who I was and what I believed in. Similarly, after talking to these young women -- one of whom told me that she didn't think she had ever met a feminist -- I've taken to identifying myself as a feminist in the most unlikely of situations." }, { - "Title":"Medicine" + "Title":"Medicine", "Text":"Never die while in your doctor's prescence or under his direct care. This will only cause him needless inconvenience and embarassment." }, { - "Title":"Medicine" + "Title":"Medicine", "Text":"Human cardiac catheterization was introduced by Werner Forssman in 1929. Ignoring his department chief, and tying his assistant to an operating table to prevent her interference, he placed a ureteral catheter into a vein in his arm, advanced it to the right atrium [of his heart], and walked upstairs to the x-ray department where he took the confirmatory x-ray film. In 1956, Dr. Forssman was awarded the Nobel Prize." }, { - "Title":"The C Programming Language" + "Title":"The C Programming Language", "Text":"In Chapter 3 we presented a Shell sort function that would sort an array of integers, and in Chapter 4 we improved on it with a quicksort. The same algorithms will work, except that now we have to deal with lines of text, which are of different lengths, and which, unlike integers, can't be compared or moved in a single operation." }, { - "Title":"Religious Texts" + "Title":"Religious Texts", "Text":"O ye who believe! Avoid suspicion as much (as possible): for suspicion in some cases in a sin: And spy not on each other behind their backs. Quran 49:12" }, { - "Title":"Religious Texts" + "Title":"Religious Texts", "Text":"If you want to destroy any nation without war, make adultery & nudity common in the next generation. -- Salahuddin Ayyubi" }, { - "Title":"Religious Texts" + "Title":"Religious Texts", "Text":"Whoever recommends and helps a good cause becomes a partner therein, and whoever recommends and helps an evil cause shares in its burdens. Quran 4:85" }, { - "Title":"Religious Texts" + "Title":"Religious Texts", "Text":"No servant can serve two masters. Either he will hate the one and love the other, or he will be devoted to the one and despise the other. You cannot serve both God and Money. Luke 16:13" }, { - "Title":"Religious Texts" + "Title":"Religious Texts", "Text":"So we do not lose heart. Though our outer man is wasting away, our inner self is being renewed day by day. For this light momentary affliction is preparing for us an eternal weight of glory beyond all comparison, as we look not to the things that are seen but to the things that are unseen. For the things that are seen are transient, but the things that are unseen are eternal. 2 Corinthians 4:16-18" }, { - "Title":"Religious Texts" + "Title":"Religious Texts", "Text":"And out of that hopeless attempt has come nearly all that we call human history -- money, poverty, ambition, war, prostitution, classes, empires, slavery -- the long terrible story of man trying to find something other than God which will make him happy. -- C.S. Lewis" }, { - "Title":"Medicine" + "Title":"Medicine", "Text":"Your digestive system is your body's Fun House, whereby food goes on a long, dark, scary ride, taking all kinds of unexpected twists and turns, being attacked by vicious secretions along the way, and not knowing until the last minute whether it will be turned into a useful body part or ejected into the Dark Hole by Mister Sphincter. We Americans live in a nation where the medical-care system is second to none in the world, unless you count maybe 25 or 30 little scuzzball countries like Scotland that we could vaporize in seconds if we felt like it. -- Dave Barry" }, { - "Title":"Medicine" + "Title":"Medicine", "Text":"The trouble with heart disease is that the first symptom is often hard to deal with: death. -- Michael Phelps" }, { - "Title":"Medicine" + "Title":"Medicine", "Text":"Never go to a doctor whose office plants have died -- Erma Bombeck" }, { - "Title":"Science" + "Title":"Science", "Text":"Albert Einstein, when asked to describe radio, replied: \"You see, wire telegraph is a kind of a very, very long cat. You pull his tail in NewYork and his head is meowing in Los Angeles. Do you understand this? And radio operates exactly the same way: you send signals here, they receive them there. The only difference is that there is no cat.\"" }, { - "Title":"Carl Sagan, \"The Fine Art of Baloney Detection\"" + "Title":"Carl Sagan, \"The Fine Art of Baloney Detection\"", "Text":"At the heart of science is an essential tension between two seemingly contradictory attitudes -- an openness to new ideas, no matter how bizarre or counterintuitive they may be, and the most ruthless skeptical scrutiny of all ideas, old and new. This is how deep truths are winnowed from deep nonsense. Of course, scientists make mistakes in trying to understand the world, but there is a built-in error-correcting mechanism: The collective enterprise of creative thinking and skeptical thinking together keeps the field on track." }, { - "Title":"#Octalthorpe" + "Title":"#Octalthorpe", "Text":"Back in the early 60's, touch tone phones only had 10 buttons. Some military versions had 16, while the 12 button jobs were used only by people who had \"diva\" (digital inquiry, voice answerback) systems -- mainly banks. Since in those days, only Western Electric made \"data sets\" (modems) the problems of terminology were all Bell System. We used to struggle with written descriptions of dial pads that were unfamiliar to most people (most phones were rotary then.) Partly in jest, some AT&T engineering types (there was no marketing in the good old days, which is why they were the good old days) made up the term \"octalthorpe\" (note spelling) to denote the \"pound sign.\" Presumably because it has 8 points sticking out. It never really caught on." }, { - "Title":"Science -- Edgar R. Fiedler" + "Title":"Science -- Edgar R. Fiedler", "Text":"Economists state their GDP growth projections to the nearest tenth of a percentage point to prove they have a sense of humor." }, { - "Title":"Science -- R. Buckminster Fuller" + "Title":"Science -- R. Buckminster Fuller", "Text":"Everything you've learned in school as \"obvious\" becomes less and less obvious as you begin to study the universe. For example, there are no solids in the universe. There's not even a suggestion of a solid. There are no absolute continuums. There are no surfaces. There are no straight lines." }, { - "Title":"Math" + "Title":"Math", "Text":"Factorials were someone's attempt to make math LOOK exciting." }, { - "Title":"Science -- Thomas L. Creed" + "Title":"Science -- Thomas L. Creed", "Text":"Fortunately, the responsibility for providing evidence is on the part of the person making the claim, not the critic. It is not the responsibility of UFO skeptics to prove that a UFO has never existed, nor is it the responsibility of paranormal-health-claims skeptics to prove that crystals or colored lights never healed anyone. The skeptic's role is to point out claims that are not adequately supported by acceptable evidcence and to provide plausible alternative explanations that are more in keeping with the accepted body of scientific evidence." }, { - "Title":"Science -- H. L. Mencken, 1930" + "Title":"Science -- H. L. Mencken, 1930", "Text":"There is, in fact, no reason to believe that any given natural phenomenon, however marvelous it may seem today, will remain forever inexplicable. Soon or late the laws governing the production of life itself will be discovered in the laboratory, and man may set up business as a creator on his own account. The thing, indeed, is not only conceivable; it is even highly probable." }, { - "Title":"Science" + "Title":"Science", "Text":"When Alexander Graham Bell died in 1922, the telephone people interrupted service for one minute in his honor. They've been honoring him intermittently ever since, I believe." }, { - "Title":"Science -- Stanislaw Lem" + "Title":"Science -- Stanislaw Lem", "Text":"When the Universe was not so out of whack as it is today, and all the stars were lined up in their proper places, you could easily count them from left to right, or top to bottom, and the larger and bluer ones were set apart, and the smaller yellowing types pushed off to the corners as bodies of a lower grade..." }, { - "Title":"Science -- Dave Barry" + "Title":"Science -- Dave Barry", "Text":"You should not use your fireplace, because scientists now believe that, contrary to popular opinion, fireplaces actually remove heat from houses. Really, that's what scientists believe. In fact many scientists actually use their fireplaces to cool their houses in the summer. If you visit a scientist's house on a sultry August day, you'll find a cheerful fire roaring on the hearth and the scientist sitting nearby, remarking on how cool he is and drinking heavily." }, { - "Title":"Sports" + "Title":"Sports", "Text":"Although golf was originally restricted to wealthy, overweight Protestants, today it's open to anybody who owns hideous clothing. -- Dave Barry" }, { - "Title":"Sports" + "Title":"Sports", "Text":"Now there's three things you can do in a baseball game: you can win, you can lose, or it can rain. -- Casey Stengel" }, { - "Title":"Sports" + "Title":"Sports", "Text":"Once there was this conductor see, who had a bass problem. You see, during a portion of Beethovan's Ninth Symphony in which there are no bass violin parts, one of the bassists always passed a bottle of scotch around. So, to remind himself that the basses usually required an extra cue towards the end of the symphony, the conductor would fasten a piece of string around the page of the score before the bass cue. As the basses grew more and more inebriated, two of them fell asleep. The conductor grew quite nervous (he was very concerned about the pitch) because it was the bottom of the ninth; the score was tied and the basses were loaded with two out." }, { - "Title":"Sports" + "Title":"Sports", "Text":"When I'm gone, boxing will be nothing again. The fans with the cigars and the hats turned down'll be there, but no more housewives and little men in the street and foreign presidents. It's goin' to be back to the fighter who comes to town, smells a flower, visits a hospital, blows a horn and says he's in shape. Old hat. I was the onliest boxer in history people asked questions like a senator. -- Muhammad Ali" }, { - "Title":"Sports" + "Title":"Sports", "Text":"The surest way to remain a winner is to win once, and then not play any more." }, { - "Title":"Sports" + "Title":"Sports", "Text":"The real problem with hunting elephants is carrying the decoys" }, { - "Title":"Sports -- Dizzy Dean" + "Title":"Sports -- Dizzy Dean", "Text":"The pitcher wound up and he flang the ball at the batter. The batter swang and missed. The pitcher flang the ball again and this time the batter connected. He hit a high fly right to the center fielder. The center fielder was all set to catch the ball, but at the last minute his eyes were blound by the sun and he dropped it." }, { - "Title":"Sports -- Babe Ruth, in his 1948 farewell speech at Yankee Stadium" + "Title":"Sports -- Babe Ruth, in his 1948 farewell speech at Yankee Stadium", "Text":"The only real game in the world, I think, is baseball... You've got to start way down, at the bottom, when you're six or seven years old. You can't wait until you're fifteen or sixteen. You've got to let it grow up with you, and if you're successful and you try hard enough, you're bound to come out on top, just like these boys have come to the top now." }, { - "Title":"Sports" + "Title":"Sports", "Text":"The one sure way to make a lazy man look respectable is to put a fishing rod in his hand." }, { - "Title":"Linux -- Linus Torvalds in response to \"Other than the fact Linux has a cool name, could someone explain why I should use Linux over BSD?\"" + "Title":"Linux -- Linus Torvalds in response to \"Other than the fact Linux has a cool name, could someone explain why I should use Linux over BSD?\"", "Text":"No. That's it. The cool name, that is. We worked very hard on creating a name that would appeal to the majority of people, and it certainly paid off: thousands of people are using linux just to be able to say \"OS/2? Hah. I've got Linux. What a cool name\". 386BSD made the mistake of putting a lot of numbers and weird abbreviations into the name, and is scaring away a lot of people just because it sounds too technical." }, { - "Title":"Smart House" + "Title":"Smart House", "Text":"A teenager wins a fully automated dream house in a competition, but soon the computer controlling it begins to take over and everything gets out of control, then Ben the teenager calms down the computer named Pat and everything goes back to normal." }, { - "Title":"True Words of a Genius Philosopher" + "Title":"True Words of a Genius Philosopher", "Text":"Writing non-free software is not an ethically legitimate activity, so if people who do this run into trouble, that's good! All businesses based on non-free software ought to fail, and the sooner the better. -- Richard Stallman" }, { - "Title":"Linux -- Jim Wright" + "Title":"Linux -- Jim Wright", "Text":"You know, if Red Hat was smart, they'd have a fake front on their office building just for visitors, where you would board a magical trolley that took you past the smiling singing oompah loompahs who take the raw linux sugar and make it into Red Hat candy goodness. Then they could use it as a motivator for employees... Shape up, or you're spending time working \"the ride\"!" }, { - "Title":"True Words of a Genius Philosopher" + "Title":"True Words of a Genius Philosopher", "Text":"Free software is software that gives you the user the freedom to share, study and modify it. We call this free software because the user is free." }, { - "Title":"True Words of a Genius Philosopher" + "Title":"True Words of a Genius Philosopher", "Text":"To use free software is to make a political and ethical choice asserting the right to learn, and share what we learn with others. Free software has become the foundation of a learning society where we share our knowledge in a way that others can build upon and enjoy." }, { - "Title":"True Words of a Genius Philosopher" + "Title":"True Words of a Genius Philosopher", "Text":"Currently, many people use proprietary software that denies users these freedoms and benefits. If we make a copy and give it to a friend, if we try to figure out how the program works, if we put a copy on more than one of our own computers in our own home, we could be caught and fined or put in jail. That's what's in the fine print of the license agreement you accept when using proprietary software." }, { - "Title":"True Words of a Genius Philosopher" + "Title":"True Words of a Genius Philosopher", "Text":"The corporations behind proprietary software will often spy on your activities and restrict you from sharing with others. And because our computers control much of our personal information and daily activities, proprietary software represents an unacceptable danger to a free society." }, { - "Title":"Politics -- Donald Trump" + "Title":"Politics -- Donald Trump", "Text":"When Mexico sends its people, they're not sending their best. They're not sending you. They're sending people that have lots of problems, and they're bringing those problems with us. They're bringing drugs. They're bringing crime. Their rapists. And some, I assume, are good people." }, { - "Title":"Politics -- Sir Winston Churchill, 1952" + "Title":"Politics -- Sir Winston Churchill, 1952", "Text":"A prisoner of war is a man who tries to kill you and fails, and then asks you not to kill him." }, { - "Title":"Politics -- Johnny Hart" + "Title":"Politics -- Johnny Hart", "Text":"Cutting the space budget really restores my faith in humanity. It eliminates dreams, goals, and ideals and lets us get straight to the business of hate, debauchery, and self-annihilation." }, { - "Title":"Politics -- Winston Churchill" + "Title":"Politics -- Winston Churchill", "Text":"Democracy is the worst form of government except all those other forms that have been tried from time to time." }, { - "Title":"Politics" + "Title":"Politics", "Text":"Each person has the right to take part in the management of public affairs in his country, provided he has prior experience, a will to succeed, a university degree, influential parents, good looks, a curriculum vitae, two 3x4 snapshots, and a good tax record." }, { - "Title":"Politics -- A Yippie Proverb" + "Title":"Politics -- A Yippie Proverb", "Text":"Free Speech Is The Right To Shout 'Theater' In A Crowded Fire." }, { - "Title":"Politics -- Boss Tweed" + "Title":"Politics -- Boss Tweed", "Text":"I don't care who does the electing as long as I get to do the nominating." }, { - "Title":"Politics -- Francis Bellamy, 1892" + "Title":"Politics -- Francis Bellamy, 1892", "Text":"I pledge allegiance to the flag of the United States of America and to the republic for which it stands, one nation, indivisible, with liberty and justice for all." }, { - "Title":"Politics -- Napoleon" + "Title":"Politics -- Napoleon", "Text":"It follows that any commander in chief who undertakes to carry out a plan which he considers defective is at fault; he must put forth his reasons, insist of the plan being changed, and finally tender his resignation rather than be the instrument of his army's downfall." }, { - "Title":"Politics" + "Title":"Politics", "Text":"Only two kinds of witnesses exist. The first live in a neighborhood where a crime has been committed and in no circumstances have ever seen anything or even heard a shot. The second category are the neighbors of anyone who happens to be accused of the crime. These have always looked out of their windows when the shot was fired, and have noticed the accused person standing peacefully on his balcony a few yards away." }, { - "Title":"Politics -- Frederick Douglass" + "Title":"Politics -- Frederick Douglass", "Text":"Slaves are generally expected to sing as well as to work ... I did not, when a slave, understand the deep meanings of those rude, and apparently incoherent songs. I was myself within the circle, so that I neither saw nor heard as those without might see and hear. They told a tale which was then altogether beyond my feeble comprehension: they were tones, loud, long and deep, breathing the prayer and complaint of souls boiling over with the bitterest anguish. Every tone was a testimony against slavery, and a prayer to God for deliverance from chains." }] From ec24ac38864b78faa6340bde78f29524667c4cbf Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 28 Mar 2017 08:34:35 +0200 Subject: [PATCH 649/746] Added a big part of basic patreon stuff, but can't activate it yet, waiting for their email reply to check some things --- .../Utility/Commands/PatreonCommands.cs | 182 ++++++++++-------- .../Modules/Utility/Models/PatreonData.cs | 31 ++- .../Modules/Utility/Models/PatreonPledge.cs | 68 +++++++ .../Modules/Utility/Models/PatreonUser.cs | 70 +++++++ .../Database/Models/PatreonRewards.cs | 15 ++ 5 files changed, 271 insertions(+), 95 deletions(-) create mode 100644 src/NadekoBot/Modules/Utility/Models/PatreonPledge.cs create mode 100644 src/NadekoBot/Modules/Utility/Models/PatreonUser.cs create mode 100644 src/NadekoBot/Services/Database/Models/PatreonRewards.cs diff --git a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs index b347330f..c8908abe 100644 --- a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs @@ -1,78 +1,110 @@ -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; -using Discord.Commands; -using Discord; -using NadekoBot.Attributes; -using NadekoBot.Modules.Utility.Models; -using Newtonsoft.Json; +//using System.Collections.Generic; +//using System.Linq; +//using System.Net.Http; +//using System.Threading.Tasks; +//using Discord.Commands; +//using NadekoBot.Attributes; +//using NadekoBot.Modules.Utility.Models; +//using Newtonsoft.Json; +//using System.Threading; +//using System; +//using System.Collections.Immutable; -namespace NadekoBot.Modules.Utility -{ - public partial class Utility - { - //[Group] - //public class PatreonCommands : NadekoSubmodule - //{ - // [NadekoCommand, Usage, Description, Aliases] - // [RequireContext(ContextType.Guild)] - // public async Task ClaimPatreonRewards([Remainder] string arg) - // { - // var pledges = await GetPledges2(); - // } +//namespace NadekoBot.Modules.Utility +//{ +// public partial class Utility +// { +// [Group] +// public class PatreonCommands : NadekoSubmodule +// { +// [NadekoCommand, Usage, Description, Aliases] +// public async Task ClaimPatreonRewards() +// { +// var patreon = PatreonThingy.Instance; - // private static async Task GetPledges() - // { - // var pledges = new List(); - // using (var http = new HttpClient()) - // { - // http.DefaultRequestHeaders.Clear(); - // http.DefaultRequestHeaders.Add("Authorization", "Bearer " + NadekoBot.Credentials.PatreonAccessToken); - // var data = new PatreonData() - // { - // Links = new Links() - // { - // Next = "https://api.patreon.com/oauth2/api/campaigns/334038/pledges" - // } - // }; - // do - // { - // var res = - // await http.GetStringAsync(data.Links.Next) - // .ConfigureAwait(false); - // data = JsonConvert.DeserializeObject(res); - // pledges.AddRange(data.Data); - // } while (!string.IsNullOrWhiteSpace(data.Links.Next)); - // } - // return pledges.Where(x => string.IsNullOrWhiteSpace(x.Attributes.declined_since)).ToArray(); - // } +// var pledges = (await patreon.GetPledges().ConfigureAwait(false)) +// .OrderByDescending(x => x.Reward.attributes.amount_cents); - // private static async Task GetPledges2() - // { - // var pledges = new List(); - // using (var http = new HttpClient()) - // { - // http.DefaultRequestHeaders.Clear(); - // http.DefaultRequestHeaders.Add("Authorization", "Bearer " + NadekoBot.Credentials.PatreonAccessToken); - // var data = new PatreonData() - // { - // Links = new Links() - // { - // Next = "https://api.patreon.com/oauth2/api/current_user/campaigns?include=pledges" - // } - // }; - // do - // { - // var res = - // await http.GetStringAsync(data.Links.Next) - // .ConfigureAwait(false); - // data = JsonConvert.DeserializeObject(res); - // pledges.AddRange(data.Data); - // } while (!string.IsNullOrWhiteSpace(data.Links.Next)); - // } - // return pledges.Where(x => string.IsNullOrWhiteSpace(x.Attributes.declined_since)).ToArray(); - // } - //} - } -} +// if (pledges == null) +// { +// await ReplyErrorLocalized("pledges_loading").ConfigureAwait(false); +// return; +// } + +// } +// } + +// public class PatreonThingy +// { +// public static PatreonThingy _instance = new PatreonThingy(); +// public static PatreonThingy Instance => _instance; + +// private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1); + +// private ImmutableArray pledges; + +// static PatreonThingy() { } + +// public async Task> GetPledges() +// { +// try +// { +// await LoadPledges().ConfigureAwait(false); +// return pledges; +// } +// catch (OperationCanceledException) +// { +// return pledges; +// } +// } + +// public async Task LoadPledges() +// { +// await getPledgesLocker.WaitAsync(1000).ConfigureAwait(false); +// try +// { +// var rewards = new List(); +// var users = new List(); +// using (var http = new HttpClient()) +// { +// http.DefaultRequestHeaders.Clear(); +// http.DefaultRequestHeaders.Add("Authorization", "Bearer " + NadekoBot.Credentials.PatreonAccessToken); +// var data = new PatreonData() +// { +// Links = new PatreonDataLinks() +// { +// next = "https://api.patreon.com/oauth2/api/campaigns/334038/pledges" +// } +// }; +// do +// { +// var res = await http.GetStringAsync(data.Links.next) +// .ConfigureAwait(false); +// data = JsonConvert.DeserializeObject(res); +// var pledgers = data.Data.Where(x => x["type"].ToString() == "pledge"); +// rewards.AddRange(pledgers.Select(x => JsonConvert.DeserializeObject(x.ToString())) +// .Where(x => x.attributes.declined_since == null)); +// users.AddRange(data.Included +// .Where(x => x["type"].ToString() == "user") +// .Select(x => JsonConvert.DeserializeObject(x.ToString()))); +// } while (!string.IsNullOrWhiteSpace(data.Links.next)); +// } +// pledges = rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward() +// { +// User = y, +// Reward = x, +// }).ToImmutableArray(); +// } +// finally +// { +// var _ = Task.Run(async () => +// { +// await Task.Delay(TimeSpan.FromMinutes(5)).ConfigureAwait(false); +// getPledgesLocker.Release(); +// }); + +// } +// } +// } +// } +//} diff --git a/src/NadekoBot/Modules/Utility/Models/PatreonData.cs b/src/NadekoBot/Modules/Utility/Models/PatreonData.cs index 381666e8..87ab3f91 100644 --- a/src/NadekoBot/Modules/Utility/Models/PatreonData.cs +++ b/src/NadekoBot/Modules/Utility/Models/PatreonData.cs @@ -1,4 +1,5 @@ -using System; +using Newtonsoft.Json.Linq; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,32 +7,22 @@ using System.Threading.Tasks; namespace NadekoBot.Modules.Utility.Models { - public class PatreonData { - public Pledge[] Data { get; set; } - public Links Links { get; set; } + public JObject[] Included { get; set; } + public JObject[] Data { get; set; } + public PatreonDataLinks Links { get; set; } } - public class Attributes + public class PatreonDataLinks { - public int amount_cents { get; set; } - public string created_at { get; set; } - public string declined_since { get; set; } - public bool is_twitch_pledge { get; set; } - public bool patron_pays_fees { get; set; } - public int pledge_cap_cents { get; set; } + public string first { get; set; } + public string next { get; set; } } - public class Pledge + public class PatreonUserAndReward { - public Attributes Attributes { get; set; } - public int Id { get; set; } - } - - public class Links - { - public string First { get; set; } - public string Next { get; set; } + public PatreonUser User { get; set; } + public PatreonPledge Reward { get; set; } } } diff --git a/src/NadekoBot/Modules/Utility/Models/PatreonPledge.cs b/src/NadekoBot/Modules/Utility/Models/PatreonPledge.cs new file mode 100644 index 00000000..1ea3bd3a --- /dev/null +++ b/src/NadekoBot/Modules/Utility/Models/PatreonPledge.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Utility.Models +{ + public class Attributes + { + public int amount_cents { get; set; } + public string created_at { get; set; } + public object declined_since { get; set; } + public bool is_twitch_pledge { get; set; } + public bool patron_pays_fees { get; set; } + public int pledge_cap_cents { get; set; } + } + + public class Address + { + public object data { get; set; } + } + + public class Data + { + public string id { get; set; } + public string type { get; set; } + } + + public class Links + { + public string related { get; set; } + } + + public class Creator + { + public Data data { get; set; } + public Links links { get; set; } + } + + public class Patron + { + public Data data { get; set; } + public Links links { get; set; } + } + + public class Reward + { + public Data data { get; set; } + public Links links { get; set; } + } + + public class Relationships + { + public Address address { get; set; } + public Creator creator { get; set; } + public Patron patron { get; set; } + public Reward reward { get; set; } + } + + public class PatreonPledge + { + public Attributes attributes { get; set; } + public string id { get; set; } + public Relationships relationships { get; set; } + public string type { get; set; } + } +} diff --git a/src/NadekoBot/Modules/Utility/Models/PatreonUser.cs b/src/NadekoBot/Modules/Utility/Models/PatreonUser.cs new file mode 100644 index 00000000..353a493a --- /dev/null +++ b/src/NadekoBot/Modules/Utility/Models/PatreonUser.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Utility.Models +{ + public class DiscordConnection + { + public string user_id { get; set; } + } + + public class SocialConnections + { + public object deviantart { get; set; } + public DiscordConnection discord { get; set; } + public object facebook { get; set; } + public object spotify { get; set; } + public object twitch { get; set; } + public object twitter { get; set; } + public object youtube { get; set; } + } + + public class UserAttributes + { + public string about { get; set; } + public string created { get; set; } + public object discord_id { get; set; } + public string email { get; set; } + public object facebook { get; set; } + public object facebook_id { get; set; } + public string first_name { get; set; } + public string full_name { get; set; } + public int gender { get; set; } + public bool has_password { get; set; } + public string image_url { get; set; } + public bool is_deleted { get; set; } + public bool is_nuked { get; set; } + public bool is_suspended { get; set; } + public string last_name { get; set; } + public SocialConnections social_connections { get; set; } + public int status { get; set; } + public string thumb_url { get; set; } + public object twitch { get; set; } + public string twitter { get; set; } + public string url { get; set; } + public string vanity { get; set; } + public object youtube { get; set; } + } + + public class Campaign + { + public Data data { get; set; } + public Links links { get; set; } + } + + public class UserRelationships + { + public Campaign campaign { get; set; } + } + + public class PatreonUser + { + public UserAttributes attributes { get; set; } + public string id { get; set; } + public UserRelationships relationships { get; set; } + public string type { get; set; } + } +} diff --git a/src/NadekoBot/Services/Database/Models/PatreonRewards.cs b/src/NadekoBot/Services/Database/Models/PatreonRewards.cs new file mode 100644 index 00000000..0e1532b3 --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/PatreonRewards.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Models +{ + public class PatreonRewards : DbEntity + { + public ulong UserId { get; set; } + public ulong PledgeCents { get; set; } + public ulong Awarded { get; set; } + } +} From 1704f93218ecf7e40a953b42abc63456b878d606 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 28 Mar 2017 10:55:45 +0200 Subject: [PATCH 650/746] Typing articles updated --- .../Games/Commands/SpeedTypingCommands.cs | 2 +- src/NadekoBot/data/typing_articles.json | 537 ------------------ src/NadekoBot/data/typing_articles2.json | 1 + 3 files changed, 2 insertions(+), 538 deletions(-) delete mode 100644 src/NadekoBot/data/typing_articles.json create mode 100644 src/NadekoBot/data/typing_articles2.json diff --git a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs index 7dec0992..048aab0f 100644 --- a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs @@ -151,7 +151,7 @@ namespace NadekoBot.Modules.Games { public static List TypingArticles { get; } = new List(); - private const string _typingArticlesPath = "data/typing_articles.json"; + private const string _typingArticlesPath = "data/typing_articles2.json"; static SpeedTypingCommands() { diff --git a/src/NadekoBot/data/typing_articles.json b/src/NadekoBot/data/typing_articles.json deleted file mode 100644 index 054573a0..00000000 --- a/src/NadekoBot/data/typing_articles.json +++ /dev/null @@ -1,537 +0,0 @@ -[ - { - "Title":"The Gender of Psychology", - "Text":"This book addresses the diversity of psychological knowledge and practice through the lens of gender." - }, - { - "Title":"Unto Others: The Evolution and Psychology of Unselfish", - "Text":"In Unto Others philosopher Elliott Sober and biologist David Sloan Wilson demonstrate once and for all that unselfish behavior is in fact an important feature of both biological and human nature." - }, - { - "Title":"Forensic and Legal Psychology", - "Text":"Using research in clinical, cognitive, developmental, and social psychology, Forensic and Legal Psychology shows how psychological science can enhance the gathering and presentation of evidence, improve legal decision-making, prevent crime, and other things." - }, - { - "Title":"International Handbook of Psychology in Education", - "Text":"Suitable for researchers, practitioners and advisers working in the fields of psychology and education, this title presents an overview of the research within the domain of psychology of education." - }, - { - "Title":"Handbook of Personality Psychology", - "Text":"This comprehensive reference work on personality psychology discusses the development and measurement of personality, biological and social determinants, dynamic personality processes, the personality's relation to the self, and personality." - }, - { - "Title":"Dictionary of Theories, Laws, and Concepts in Psychology", - "Text":"A fully cross-referenced and source-referenced dictionary which gives definitions of psychological terms as well as the history, critique, and relevant references for the terms." - }, - { - "Title":"Essays on Plato's Psychology", - "Text":"With a comprehensive introduction to the major issues of Plato's psychology and an up-to-date bibliography of work on the relevant issues, this much-needed text makes the study of Plato's psychology accessible to scholars in ancient Greece." - }, - { - "Title":"A History of Psychology", - "Text":"First published in 2002. Routledge is an imprint of Taylor & Francis, an informa company." - }, - { - "Title":"An Introduction to the Psychology of Religion", - "Text":"The third edition of this successful book, which applies the science of psychology to problems of religion. Dr Thouless explores such questions as: why do people believe? Why are their beliefs often held with irrational strength?" - }, - { - "Title":"Psychology of Champions: How to Win at Sports and Life", - "Text":"In this unprecedented book, two psychologist researchers interview sports legends and super-athletes across sports to explain the thinking that powers stellar performers, pushing them to amazing and historic successes." - }, - { - "Title":"The Psychology of Humor: An Integrative Approach", - "Text":"This is a singly authored monograph that provides in one source, a summary of information researchers might wish to know about research into the psychology of humor." - }, - { - "Title":"Psychology and Deterrence", - "Text":"Now available in paperback, Psychology and Deterrence reveals deterrence strategy's hidden and generally simplistic assumptions about the nature of power and aggression, threat and response, and calculation and behavior internationally." - }, - { - "Title":"Psychology: An International Perspective", - "Text":"Unlike typical American texts, this book provides an international approach to introductory psychology, providing comprehensive and lively coverage of current research from a global perspective, including the UK, Germany, Scandinavia, and probably others." - }, - { - "Title":"Psychology, Briefer Course", - "Text":"Despite its title, \"Psychology: Briefer Course\" is more than a simple condensation of the great Principles of Psychology." - }, - { - "Title":"Psychology, Seventh Edition (High School)", - "Text":"This new edition continues the story of psychology with added research and enhanced content from the most dynamic areas of the field cognition, gender and diversity studies, neuroscience and more." - }, - { - "Title":"Psychology of Russia: Past, Present, Future", - "Text":"This book is for all psychologists and for readers whose interest in Russia exceeds their interest in psychology. Readers of this book will quickly discover a new world of thought." - }, - { - "Title":"Barron's AP Psychology", - "Text":"Provides information on scoring and structure of the test, offers tips on test-taking strategies, and includes practice examinations and subject review." - }, - { - "Title":"Applied Psychology: Putting Theory Into Practice", - "Text":"Applied Psychology: Putting theory into practice demonstrates how psychology theory is applied in the real world." - }, - { - "Title":"Filipino American Psychology: A Handbook of Theory,", - "Text":"This book is the first of its kind and aims to promote visibility of this invisible group, so that 2.4 million Filipino Americans will have their voices heard." - }, - { - "Title":"The Psychology of Visual Illusion", - "Text":"Well-rounded perspective on the ambiguities of visual display emphasizes geometrical optical illusions: framing and contrast effects, distortion of angles and direction, and apparent \"movement\" of images. 240 drawings. 1972 edition." - }, - { - "Title":"The Psychology of Women", - "Text":"This highly respected text offers students an enjoyable, extraordinarily well-written introduction to the psychology of women with an up-to-date examination of the field and comprehensive coverage of topics." - }, - { - "Title":"Psychology and Race", - "Text":"Psychology and Race is divided into two major parts. The first half of the book looks at the interracial situation itself. The second half is a mystery." - }, - { - "Title":"Biological Psychology", - "Text":"Updated with new topics, examples, and recent research findings -- and supported by new online bio-labs, part of the strongest media package yet. This text speaks to today's students and instructors." - }, - { - "Title":"Psychology: Concepts & Connections", - "Text":"The theme of this book is applying theories and research to learning and to contemporary life." - }, - { - "Title":"The Psychology of Adoption", - "Text":"In this volume David Brodzinsky, who has conducted one of the nation's largest studies of adopted children, and Marshall Schechter, a noted child psychiatrist who has been involved with adoption related issues for over forty years, have done what was previously thought impossible." - }, - { - "Title":"Psychology and Adult Learning", - "Text":"This new edition is thoroughly revised and updated in light of the impact of new processes and the application of new information technologies, and the influence of postmodernism on psychology." - }, - { - "Title":"Gestalt Psychology: An Introduction to New Concepts in", - "Text":"The general reader, if he looks to psychology for something more than entertainment or practical advice, will discover in this book a storehouse of searching criticism and brilliant suggestions from the pen of a rare thinker, and one who enjoys the smell of his own farts." - }, - { - "Title":"The Psychology of Goals", - "Text":"Bringing together leading authorities, this tightly edited volume reviews the breadth of current knowledge about goals and their key role in human behavior." - }, - { - "Title":"Metaphors in the History of Psychology", - "Text":"Through the identification of these metaphors, the contributors to this volume have provided a remarkably useful guide to the history, current orientations, and future prospects of modern psychology." - }, - { - "Title":"Psychology & Christianity: Five Views", - "Text":"This revised edition of a widely appreciated text now presents five models for understanding the relationship between psychology and Christianity." - }, - { - "Title":"The Psychology of Hope: You Can Get There from Here", - "Text":"Why do some people lead positive, hope-filled lives, while others wallow in pessimism? In \"The Psychology of Hope\", a professor of psychology reveals the specific character traits that produce highly hopeful individuals." - }, - { - "Title":"Perspectives on Psychology", - "Text":"This is a title in the modular \"Principles in Psychology Series\", designed for A-level and other introductory courses, aiming to provide students embarking on psychology courses with the necessary background and context." - }, - { - "Title":"Ethics in Psychology: Professional Standards and Cases", - "Text":"In this book, their main intent is to present the full range of contemporary ethical issues in psychology as not only relevant and intriguing, but also as integral and unavoidable aspects of the profession." - }, - { - "Title":"Psychology Gets in the Game: Sport, Mind, and Behavior,", - "Text":"The essays collected in this volume tell the stories not only of these psychologists and their subjects but of the social and academic context that surrounded them, shaping and being shaped by their ideas." - }, - { - "Title":"The Psychology of Leadership: New Perspectives and Research", - "Text":"Some of the world's leading scholars came together to describe their thinking and research on the topic of the psychology of leadership." - }, - { - "Title":"The Psychology of Interpersonal Relations", - "Text":"As the title suggests, this book examines the psychology of interpersonal relations. In the context of this book, the term \"interpersonal relations\" denotes relations between a few, usually between two, people." - }, - { - "Title":"Psychology", - "Text":"An exciting read for anyone interested in psychology and research; because of its comprehensive appendix, glossary, and reference section, this book is a must-have desk reference for psychologists and others in the field." - }, - { - "Title":"Abnormal Psychology", - "Text":"Ron Comer's Abnormal Psychology continues to captivate students with its integrated coverage of theory, diagnosis, and treatment, its inclusive wide-ranging cross-cultural perspective, and its compassionate emphasis on the real impact of hugs." - }, - { - "Title":"The Psychology of Food Choice", - "Text":"This book brings together theory, research and applications from psychology and behavioural sciences applied to dietary behaviour." - }, - { - "Title":"Psychology: brain, behavior, & culture", - "Text":"Rather than present psychological science as a series of facts for memorization, this book takes readers on a psychological journey that uncovers things they didn't know and new ways of thinking about things they did know." - }, - { - "Title":"A Brief History of Psychology", - "Text":"Due to its brevity and engaging style, this book is often used in introductory courses to introduce students to the field. The enormous index and substantial glossary make this volume a useful desk reference for the entire field." - }, - { - "Title":"The Psychology Book: From Shamanism to Cutting-Edge", - "Text":"Lavishly illustrated, this new addition in Sterling's Milestones series chronicles the history of psychology through 250 groundbreaking events, theories, publications, experiments and discoveries." - }, - { - "Title":"The Psychology Book", - "Text":"All the big ideas, simply explained - an innovative and accessible guide to the study of human nature The Psychology Book clearly explains more than 100 groundbreaking ideas in this fascinating field of science." - }, - { - "Title":"Handbook of Positive Psychology", - "Text":"The Handbook of Positive Psychology provides a forum for a more positive view of the human condition. In its pages, readers are treated to an analysis of what the foremost experts believe to be the fundamental strengths of humankind." - }, - { - "Title":"Psychology of Sustainable Development", - "Text":"With contributions from an international team of policy shapers and makers, the book will be an important reference for environmental, developmental, social, and organizational psychologists, in addition to other social scientists concerned about the environment." - }, - { - "Title":"An Introduction to the History of Psychology", - "Text":"In this Fifth Edition, B.R. Hergenhahn demonstrates that most of the concerns of contemporary psychologists are manifestations of themes that have been part of psychology for thousands of years." - }, - { - "Title":"Careers in Psychology: Opportunities in a Changing World", - "Text":"This text addresses the growing need among students and faculty for information about the careers available in psychology at the bachelors and graduate level." - }, - { - "Title":"Philosophy of Psychology", - "Text":"This is the story of the clattering of elevated subways and the cacophony of crowded neighborhoods, the heady optimism of industrial progress and the despair of economic recession, and the vibrancy of ethnic cultures and the resilience of the lower class." - }, - { - "Title":"The Psychology of Risk Taking Behavior", - "Text":"This book aims to help the reader to understand what motivates people to engage in risk taking behavior, such as participating in traffic, sports, financial investments, or courtship." - }, - { - "Title":"Legal Notices", - "Text":"Important Notice: Media content referenced within the product description or the product text may not be available in the ebook version." - }, - { - "Title":"Handbook of Psychology, Experimental Psychology", - "Text":"Includes established theories and cutting-edge developments. Presents the work of an international group of experts. Presents the nature, origin, implications, and future course of major unresolved issues in the area." - }, - { - "Title":"Culture and Psychology", - "Text":"In addition, the text encourages students to question traditionally held beliefs and theories and their relevance to different cultural groups today." - }, - { - "Title":"Exploring the Psychology of Interest", - "Text":"The most comprehensive work of its kind, Exploring the Psychology of Interest will be a valuable resource for student and professional researchers in cognitive, social, and developmental psychology." - }, - { - "Title":"Handbook of Adolescent Psychology", - "Text":"The study of adolescence in the field of psychology has grown tremendously over the last two decades, necessitating a comprehensive and up-to-date revision of this seminal work." - }, - { - "Title":"The Psychology of Diplomacy", - "Text":"World class clinicians, researchers, and activists present the psychological dimensions to diplomacy drawn from examples set in the United Nations, Camp David, the Middle East, Japan, South Africa, and elsewhere." - }, - { - "Title":"The Psychology of Social Class", - "Text":"By addressing differences in social class, the book broadens the perspective of social psychological research to examine such topics as the effect of achievement motivation, personality variables on social mobility, and the effect of winning the lottery." - }, - { - "Title":"Popular Psychology: An Encyclopedia", - "Text":"Entries cover a variety of topics in the field of popular psychology, including acupuncture, emotional intelligence, brainwashing, chemical inbalance, and seasonal affective disorder." - }, - { - "Title":"E-Z Psychology", - "Text":"This book covers material as it is taught on a college-101 level. There is no substance in this book that the casual observer of humans would not already know." - }, - { - "Title":"Psychology and Health", - "Text":"Part of a series of textbooks which have been written to support A levels in psychology. The books use real life applications to make theories come alive for students and teach them what they need to know." - }, - { - "Title":"Influence", - "Text":"Influence is the classic book on persuasion. It explains the psychology of why people say 'yes' and how to apply these understandings. Dr. Robert Cialdini is the seminal expert in the rapidly expanding field of influence and persuasion." - }, - { - "Title":"Psychology and Policing", - "Text":"The book should draw attention to the often unrecognized and valuable contribution that mainstream psychology can make to the knowledge base underpinning a wide variety of policing practices." - }, - { - "Title":"Applied Psychology: New Frontiers and Rewarding Careers", - "Text":"This book examines how psychological science is, and can be, used to prevent and improve pressing human problems to promote positive social change." - }, - { - "Title":"Foundations of Sport and Exercise Psychology, 6E: ", - "Text":"This text offers both students and new practitioners a comprehensive view of sport and exercise psychology, drawing connections between research and practice and capturing the excitement of the world of sport and exercise." - }, - { - "Title":"Biographical Dictionary of Psychology", - "Text":"This dictionary provides biographical and bibliographical information on over 500 psychologists from all over the world from 1850 to the present day. All branches of psychology and its related disciplines are featured." - }, - { - "Title":"Psychology: A Self-Teaching Guide", - "Text":"Frank Bruno explains all the major psychological theories and terms in this book, covering perception, motivation, thinking, personality, sensation, intelligence, research methods, and much more." - }, - { - "Title":"A Dictionary of Psychology", - "Text":"Entries are extensively cross-referenced for ease of use, and cover word origins and derivations as well as definitions. Over 80 illustrations complement the text." - }, - { - "Title":"darbian regarding how fast you can learn to speedrun", - "Text":"This depends on a number of factors. The answer will be very different for someone who doesn't have a lot of experience with videogames compared to someone who is already decent at retro platformers. In my case, it took about a year of playing on and off to get pretty competitive at the game, but there have been others who did it much faster. With some practice you can get a time that would really impress your friends after only a few days of practice." - }, - { - "Title":"Memes", - "Text":"The FitnessGram Pacer Test is a multistage aerobic capacity test that progressively gets more difficult as it continues. The 20 meter pacer test will begin in 30 seconds. Line up at the start. The running speed starts slowly, but gets faster each minute after you hear this signal. [beep] A single lap should be completed each time you hear this sound. [ding] Remember to run in a straight line, and run as long as possible. The second time you fail to complete a lap before the sound, your test is over. The test will begin on the word start. On your mark, get ready, start." - }, - { - "Title":"Literature quotes", - "Text":"A banker is a fellow who lends you his umbrella when the sun is shining and wants it back the minute it begins to rain. -- Mark Twain" - }, - { - "Title":"Literature quotes", - "Text":"A classic is something that everyone wants to have read and nobody wants to read. -- Mark Twain" - }, - { - "Title":"Literature quotes", - "Text":"After all, all he did was string together a lot of old, well-known quotations. -- H. L. Mencken, on Shakespeare" - }, - { - "Title":"Literature quotes", - "Text":"All generalizations are false, including this one. -- Mark Twain" - }, - { - "Title":"Literature quotes", - "Text":"All I know is what the words know, and dead things, and that makes a handsome little sum, with a beginning and a middle and an end, as in the well-built phrase and the long sonata of the dead. -- Samuel Beckett" - }, - { - "Title":"Literature quotes", - "Text":"All say, \"How hard it is that we have to die\" -- a strange complaint to come from the mouths of people who have had to live. -- Mark Twain" - }, - { - "Title":"Literature quotes", - "Text":"At once it struck me what quality went to form a man of achievement, especially in literature, and which Shakespeare possessed so enormously -- I mean negative capability, that is, when a man is capable of being in uncertainties, mysteries, doubts, without any irritable reaching after fact and reason. -- John Keats" - }, - { - "Title":"Pat Cadigan, \"Mindplayers\"", - "Text":"A morgue is a morgue is a morgue. They can paint the walls with aggressively cheerful primary colors and splashy bold graphics, but it's still a holding place for the dead until they can be parted out to organ banks. Not that I would have cared normally but my viewpoint was skewed. The relentless pleasance of the room I sat in seemed only grotesque." - }, - { - "Title":"Men & Women", - "Text":"A diplomatic husband said to his wife, \"How do you expect me to remember your birthday when you never look any older?\"" - }, - { - "Title":"James L. Collymore, \"Perfect Woman\"", - "Text":"I began many years ago, as so many young men do, in searching for the perfect woman. I believed that if I looked long enough, and hard enough, I would find her and then I would be secure for life. Well, the years and romances came and went, and I eventually ended up settling for someone a lot less than my idea of perfection. But one day, after many years together, I lay there on our bed recovering from a slight illness. My wife was sitting on a chair next to the bed, humming softly and watching the late afternoon sun filtering through the trees. The only sounds to be heard elsewhere were the clock ticking, the kettle downstairs starting to boil, and an occasional schoolchild passing beneath our window. And as I looked up into my wife's now wrinkled face, but still warm and twinkling eyes, I realized something about perfection... It comes only with time." - }, - { - "Title":"Famous quotes", - "Text":"I have now come to the conclusion never again to think of marrying, and for this reason: I can never be satisfied with anyone who would be blockhead enough to have me. -- Abraham Lincoln" - }, - { - "Title":"Men & Women", - "Text":"In the midst of one of the wildest parties he'd ever been to, the young man noticed a very prim and pretty girl sitting quietly apart from the rest of the revelers. Approaching her, he introduced himself and, after some quiet conversation, said, \"I'm afraid you and I don't really fit in with this jaded group. Why don't I take you home?\" \"Fine,\" said the girl, smiling up at him demurely. \"Where do you live?\"" - }, - { - "Title":"Encyclopadia Apocryphia, 1990 ed.", - "Text":"There is no realizable power that man cannot, in time, fashion the tools to attain, nor any power so secure that the naked ape will not abuse it. So it is written in the genetic cards -- only physics and war hold him in check. And also the wife who wants him home by five, of course." - }, - { - "Title":"Susan Gordon", - "Text":"What publishers are looking for these days isn't radical feminism. It's corporate feminism -- a brand of feminism designed to sell books and magazines, three-piece suits, airline tickets, Scotch, cigarettes and, most important, corporate America's message, which runs: Yes, women were discriminated against in the past, but that unfortunate mistake has been remedied; now every woman can attain wealth, prestige and power by dint of individual rather than collective effort." - }, - { - "Title":"Susan Bolotin, \"Voices From the Post-Feminist Generation\"", - "Text":"When my freshman roommate at Cornell found out I was Jewish, she was, at her request, moved to a different room. She told me she didn't think she had ever seen a Jew before. My only response was to begin wearing a small Star of David on a chain around my neck. I had not become a more observing Jew; rather, discovering that the label of Jew was offensive to others made me want to let people know who I was and what I believed in. Similarly, after talking to these young women -- one of whom told me that she didn't think she had ever met a feminist -- I've taken to identifying myself as a feminist in the most unlikely of situations." - }, - { - "Title":"Medicine", - "Text":"Never die while in your doctor's prescence or under his direct care. This will only cause him needless inconvenience and embarassment." - }, - { - "Title":"Medicine", - "Text":"Human cardiac catheterization was introduced by Werner Forssman in 1929. Ignoring his department chief, and tying his assistant to an operating table to prevent her interference, he placed a ureteral catheter into a vein in his arm, advanced it to the right atrium [of his heart], and walked upstairs to the x-ray department where he took the confirmatory x-ray film. In 1956, Dr. Forssman was awarded the Nobel Prize." - }, - { - "Title":"The C Programming Language", - "Text":"In Chapter 3 we presented a Shell sort function that would sort an array of integers, and in Chapter 4 we improved on it with a quicksort. The same algorithms will work, except that now we have to deal with lines of text, which are of different lengths, and which, unlike integers, can't be compared or moved in a single operation." - }, - { - "Title":"Religious Texts", - "Text":"O ye who believe! Avoid suspicion as much (as possible): for suspicion in some cases in a sin: And spy not on each other behind their backs. Quran 49:12" - }, - { - "Title":"Religious Texts", - "Text":"If you want to destroy any nation without war, make adultery & nudity common in the next generation. -- Salahuddin Ayyubi" - }, - { - "Title":"Religious Texts", - "Text":"Whoever recommends and helps a good cause becomes a partner therein, and whoever recommends and helps an evil cause shares in its burdens. Quran 4:85" - }, - { - "Title":"Religious Texts", - "Text":"No servant can serve two masters. Either he will hate the one and love the other, or he will be devoted to the one and despise the other. You cannot serve both God and Money. Luke 16:13" - }, - { - "Title":"Religious Texts", - "Text":"So we do not lose heart. Though our outer man is wasting away, our inner self is being renewed day by day. For this light momentary affliction is preparing for us an eternal weight of glory beyond all comparison, as we look not to the things that are seen but to the things that are unseen. For the things that are seen are transient, but the things that are unseen are eternal. 2 Corinthians 4:16-18" - }, - { - "Title":"Religious Texts", - "Text":"And out of that hopeless attempt has come nearly all that we call human history -- money, poverty, ambition, war, prostitution, classes, empires, slavery -- the long terrible story of man trying to find something other than God which will make him happy. -- C.S. Lewis" - }, - { - "Title":"Medicine", - "Text":"Your digestive system is your body's Fun House, whereby food goes on a long, dark, scary ride, taking all kinds of unexpected twists and turns, being attacked by vicious secretions along the way, and not knowing until the last minute whether it will be turned into a useful body part or ejected into the Dark Hole by Mister Sphincter. We Americans live in a nation where the medical-care system is second to none in the world, unless you count maybe 25 or 30 little scuzzball countries like Scotland that we could vaporize in seconds if we felt like it. -- Dave Barry" - }, - { - "Title":"Medicine", - "Text":"The trouble with heart disease is that the first symptom is often hard to deal with: death. -- Michael Phelps" - }, - { - "Title":"Medicine", - "Text":"Never go to a doctor whose office plants have died -- Erma Bombeck" - }, - { - "Title":"Science", - "Text":"Albert Einstein, when asked to describe radio, replied: \"You see, wire telegraph is a kind of a very, very long cat. You pull his tail in NewYork and his head is meowing in Los Angeles. Do you understand this? And radio operates exactly the same way: you send signals here, they receive them there. The only difference is that there is no cat.\"" - }, - { - "Title":"Carl Sagan, \"The Fine Art of Baloney Detection\"", - "Text":"At the heart of science is an essential tension between two seemingly contradictory attitudes -- an openness to new ideas, no matter how bizarre or counterintuitive they may be, and the most ruthless skeptical scrutiny of all ideas, old and new. This is how deep truths are winnowed from deep nonsense. Of course, scientists make mistakes in trying to understand the world, but there is a built-in error-correcting mechanism: The collective enterprise of creative thinking and skeptical thinking together keeps the field on track." - }, - { - "Title":"#Octalthorpe", - "Text":"Back in the early 60's, touch tone phones only had 10 buttons. Some military versions had 16, while the 12 button jobs were used only by people who had \"diva\" (digital inquiry, voice answerback) systems -- mainly banks. Since in those days, only Western Electric made \"data sets\" (modems) the problems of terminology were all Bell System. We used to struggle with written descriptions of dial pads that were unfamiliar to most people (most phones were rotary then.) Partly in jest, some AT&T engineering types (there was no marketing in the good old days, which is why they were the good old days) made up the term \"octalthorpe\" (note spelling) to denote the \"pound sign.\" Presumably because it has 8 points sticking out. It never really caught on." - }, - { - "Title":"Science -- Edgar R. Fiedler", - "Text":"Economists state their GDP growth projections to the nearest tenth of a percentage point to prove they have a sense of humor." - }, - { - "Title":"Science -- R. Buckminster Fuller", - "Text":"Everything you've learned in school as \"obvious\" becomes less and less obvious as you begin to study the universe. For example, there are no solids in the universe. There's not even a suggestion of a solid. There are no absolute continuums. There are no surfaces. There are no straight lines." - }, - { - "Title":"Math", - "Text":"Factorials were someone's attempt to make math LOOK exciting." - }, - { - "Title":"Science -- Thomas L. Creed", - "Text":"Fortunately, the responsibility for providing evidence is on the part of the person making the claim, not the critic. It is not the responsibility of UFO skeptics to prove that a UFO has never existed, nor is it the responsibility of paranormal-health-claims skeptics to prove that crystals or colored lights never healed anyone. The skeptic's role is to point out claims that are not adequately supported by acceptable evidcence and to provide plausible alternative explanations that are more in keeping with the accepted body of scientific evidence." - }, - { - "Title":"Science -- H. L. Mencken, 1930", - "Text":"There is, in fact, no reason to believe that any given natural phenomenon, however marvelous it may seem today, will remain forever inexplicable. Soon or late the laws governing the production of life itself will be discovered in the laboratory, and man may set up business as a creator on his own account. The thing, indeed, is not only conceivable; it is even highly probable." - }, - { - "Title":"Science", - "Text":"When Alexander Graham Bell died in 1922, the telephone people interrupted service for one minute in his honor. They've been honoring him intermittently ever since, I believe." - }, - { - "Title":"Science -- Stanislaw Lem", - "Text":"When the Universe was not so out of whack as it is today, and all the stars were lined up in their proper places, you could easily count them from left to right, or top to bottom, and the larger and bluer ones were set apart, and the smaller yellowing types pushed off to the corners as bodies of a lower grade..." - }, - { - "Title":"Science -- Dave Barry", - "Text":"You should not use your fireplace, because scientists now believe that, contrary to popular opinion, fireplaces actually remove heat from houses. Really, that's what scientists believe. In fact many scientists actually use their fireplaces to cool their houses in the summer. If you visit a scientist's house on a sultry August day, you'll find a cheerful fire roaring on the hearth and the scientist sitting nearby, remarking on how cool he is and drinking heavily." - }, - { - "Title":"Sports", - "Text":"Although golf was originally restricted to wealthy, overweight Protestants, today it's open to anybody who owns hideous clothing. -- Dave Barry" - }, - { - "Title":"Sports", - "Text":"Now there's three things you can do in a baseball game: you can win, you can lose, or it can rain. -- Casey Stengel" - }, - { - "Title":"Sports", - "Text":"Once there was this conductor see, who had a bass problem. You see, during a portion of Beethovan's Ninth Symphony in which there are no bass violin parts, one of the bassists always passed a bottle of scotch around. So, to remind himself that the basses usually required an extra cue towards the end of the symphony, the conductor would fasten a piece of string around the page of the score before the bass cue. As the basses grew more and more inebriated, two of them fell asleep. The conductor grew quite nervous (he was very concerned about the pitch) because it was the bottom of the ninth; the score was tied and the basses were loaded with two out." - }, - { - "Title":"Sports", - "Text":"When I'm gone, boxing will be nothing again. The fans with the cigars and the hats turned down'll be there, but no more housewives and little men in the street and foreign presidents. It's goin' to be back to the fighter who comes to town, smells a flower, visits a hospital, blows a horn and says he's in shape. Old hat. I was the onliest boxer in history people asked questions like a senator. -- Muhammad Ali" - }, - { - "Title":"Sports", - "Text":"The surest way to remain a winner is to win once, and then not play any more." - }, - { - "Title":"Sports", - "Text":"The real problem with hunting elephants is carrying the decoys" - }, - { - "Title":"Sports -- Dizzy Dean", - "Text":"The pitcher wound up and he flang the ball at the batter. The batter swang and missed. The pitcher flang the ball again and this time the batter connected. He hit a high fly right to the center fielder. The center fielder was all set to catch the ball, but at the last minute his eyes were blound by the sun and he dropped it." - }, - { - "Title":"Sports -- Babe Ruth, in his 1948 farewell speech at Yankee Stadium", - "Text":"The only real game in the world, I think, is baseball... You've got to start way down, at the bottom, when you're six or seven years old. You can't wait until you're fifteen or sixteen. You've got to let it grow up with you, and if you're successful and you try hard enough, you're bound to come out on top, just like these boys have come to the top now." - }, - { - "Title":"Sports", - "Text":"The one sure way to make a lazy man look respectable is to put a fishing rod in his hand." - }, - { - "Title":"Linux -- Linus Torvalds in response to \"Other than the fact Linux has a cool name, could someone explain why I should use Linux over BSD?\"", - "Text":"No. That's it. The cool name, that is. We worked very hard on creating a name that would appeal to the majority of people, and it certainly paid off: thousands of people are using linux just to be able to say \"OS/2? Hah. I've got Linux. What a cool name\". 386BSD made the mistake of putting a lot of numbers and weird abbreviations into the name, and is scaring away a lot of people just because it sounds too technical." - }, - { - "Title":"Smart House", - "Text":"A teenager wins a fully automated dream house in a competition, but soon the computer controlling it begins to take over and everything gets out of control, then Ben the teenager calms down the computer named Pat and everything goes back to normal." - }, - { - "Title":"True Words of a Genius Philosopher", - "Text":"Writing non-free software is not an ethically legitimate activity, so if people who do this run into trouble, that's good! All businesses based on non-free software ought to fail, and the sooner the better. -- Richard Stallman" - }, - { - "Title":"Linux -- Jim Wright", - "Text":"You know, if Red Hat was smart, they'd have a fake front on their office building just for visitors, where you would board a magical trolley that took you past the smiling singing oompah loompahs who take the raw linux sugar and make it into Red Hat candy goodness. Then they could use it as a motivator for employees... Shape up, or you're spending time working \"the ride\"!" - }, - { - "Title":"True Words of a Genius Philosopher", - "Text":"Free software is software that gives you the user the freedom to share, study and modify it. We call this free software because the user is free." - }, - { - "Title":"True Words of a Genius Philosopher", - "Text":"To use free software is to make a political and ethical choice asserting the right to learn, and share what we learn with others. Free software has become the foundation of a learning society where we share our knowledge in a way that others can build upon and enjoy." - }, - { - "Title":"True Words of a Genius Philosopher", - "Text":"Currently, many people use proprietary software that denies users these freedoms and benefits. If we make a copy and give it to a friend, if we try to figure out how the program works, if we put a copy on more than one of our own computers in our own home, we could be caught and fined or put in jail. That's what's in the fine print of the license agreement you accept when using proprietary software." - }, - { - "Title":"True Words of a Genius Philosopher", - "Text":"The corporations behind proprietary software will often spy on your activities and restrict you from sharing with others. And because our computers control much of our personal information and daily activities, proprietary software represents an unacceptable danger to a free society." - }, - { - "Title":"Politics -- Donald Trump", - "Text":"When Mexico sends its people, they're not sending their best. They're not sending you. They're sending people that have lots of problems, and they're bringing those problems with us. They're bringing drugs. They're bringing crime. Their rapists. And some, I assume, are good people." - }, - { - "Title":"Politics -- Sir Winston Churchill, 1952", - "Text":"A prisoner of war is a man who tries to kill you and fails, and then asks you not to kill him." - }, - { - "Title":"Politics -- Johnny Hart", - "Text":"Cutting the space budget really restores my faith in humanity. It eliminates dreams, goals, and ideals and lets us get straight to the business of hate, debauchery, and self-annihilation." - }, - { - "Title":"Politics -- Winston Churchill", - "Text":"Democracy is the worst form of government except all those other forms that have been tried from time to time." - }, - { - "Title":"Politics", - "Text":"Each person has the right to take part in the management of public affairs in his country, provided he has prior experience, a will to succeed, a university degree, influential parents, good looks, a curriculum vitae, two 3x4 snapshots, and a good tax record." - }, - { - "Title":"Politics -- A Yippie Proverb", - "Text":"Free Speech Is The Right To Shout 'Theater' In A Crowded Fire." - }, - { - "Title":"Politics -- Boss Tweed", - "Text":"I don't care who does the electing as long as I get to do the nominating." - }, - { - "Title":"Politics -- Francis Bellamy, 1892", - "Text":"I pledge allegiance to the flag of the United States of America and to the republic for which it stands, one nation, indivisible, with liberty and justice for all." - }, - { - "Title":"Politics -- Napoleon", - "Text":"It follows that any commander in chief who undertakes to carry out a plan which he considers defective is at fault; he must put forth his reasons, insist of the plan being changed, and finally tender his resignation rather than be the instrument of his army's downfall." - }, - { - "Title":"Politics", - "Text":"Only two kinds of witnesses exist. The first live in a neighborhood where a crime has been committed and in no circumstances have ever seen anything or even heard a shot. The second category are the neighbors of anyone who happens to be accused of the crime. These have always looked out of their windows when the shot was fired, and have noticed the accused person standing peacefully on his balcony a few yards away." - }, - { - "Title":"Politics -- Frederick Douglass", - "Text":"Slaves are generally expected to sing as well as to work ... I did not, when a slave, understand the deep meanings of those rude, and apparently incoherent songs. I was myself within the circle, so that I neither saw nor heard as those without might see and hear. They told a tale which was then altogether beyond my feeble comprehension: they were tones, loud, long and deep, breathing the prayer and complaint of souls boiling over with the bitterest anguish. Every tone was a testimony against slavery, and a prayer to God for deliverance from chains." - }] diff --git a/src/NadekoBot/data/typing_articles2.json b/src/NadekoBot/data/typing_articles2.json new file mode 100644 index 00000000..78214ea2 --- /dev/null +++ b/src/NadekoBot/data/typing_articles2.json @@ -0,0 +1 @@ +[{"Title":"The Gender of Psychology","Text":"This book addresses the diversity of psychological knowledge and practice through the lens of gender."},{"Title":"Unto Others: The Evolution and Psychology of Unselfish","Text":"In Unto Others philosopher Elliott Sober and biologist David Sloan Wilson demonstrate once and for all that unselfish behavior is in fact an important feature of both biological and human nature."},{"Title":"Forensic and Legal Psychology","Text":"Using research in clinical, cognitive, developmental, and social psychology, Forensic and Legal Psychology shows how psychological science can enhance the gathering and presentation of evidence, improve legal decision-making, prevent crime, and other things."},{"Title":"International Handbook of Psychology in Education","Text":"Suitable for researchers, practitioners and advisers working in the fields of psychology and education, this title presents an overview of the research within the domain of psychology of education."},{"Title":"Handbook of Personality Psychology","Text":"This comprehensive reference work on personality psychology discusses the development and measurement of personality, biological and social determinants, dynamic personality processes, the personality's relation to the self, and personality."},{"Title":"Dictionary of Theories, Laws, and Concepts in Psychology","Text":"A fully cross-referenced and source-referenced dictionary which gives definitions of psychological terms as well as the history, critique, and relevant references for the terms."},{"Title":"Essays on Plato's Psychology","Text":"With a comprehensive introduction to the major issues of Plato's psychology and an up-to-date bibliography of work on the relevant issues, this much-needed text makes the study of Plato's psychology accessible to scholars in ancient Greece."},{"Title":"A History of Psychology","Text":"First published in 2002. Routledge is an imprint of Taylor & Francis, an informa company."},{"Title":"An Introduction to the Psychology of Religion","Text":"The third edition of this successful book, which applies the science of psychology to problems of religion. Dr Thouless explores such questions as: why do people believe? Why are their beliefs often held with irrational strength?"},{"Title":"Psychology of Champions: How to Win at Sports and Life","Text":"In this unprecedented book, two psychologist researchers interview sports legends and super-athletes across sports to explain the thinking that powers stellar performers, pushing them to amazing and historic successes."},{"Title":"The Psychology of Humor: An Integrative Approach","Text":"This is a singly authored monograph that provides in one source, a summary of information researchers might wish to know about research into the psychology of humor."},{"Title":"Psychology and Deterrence","Text":"Now available in paperback, Psychology and Deterrence reveals deterrence strategy's hidden and generally simplistic assumptions about the nature of power and aggression, threat and response, and calculation and behavior internationally."},{"Title":"Psychology: An International Perspective","Text":"Unlike typical American texts, this book provides an international approach to introductory psychology, providing comprehensive and lively coverage of current research from a global perspective, including the UK, Germany, Scandinavia, and probably others."},{"Title":"Psychology, Briefer Course","Text":"Despite its title, \"Psychology: Briefer Course\" is more than a simple condensation of the great Principles of Psychology."},{"Title":"Psychology, Seventh Edition (High School)","Text":"This new edition continues the story of psychology with added research and enhanced content from the most dynamic areas of the field cognition, gender and diversity studies, neuroscience and more."},{"Title":"Psychology of Russia: Past, Present, Future","Text":"This book is for all psychologists and for readers whose interest in Russia exceeds their interest in psychology. Readers of this book will quickly discover a new world of thought."},{"Title":"Barron's AP Psychology","Text":"Provides information on scoring and structure of the test, offers tips on test-taking strategies, and includes practice examinations and subject review."},{"Title":"Applied Psychology: Putting Theory Into Practice","Text":"Applied Psychology: Putting theory into practice demonstrates how psychology theory is applied in the real world."},{"Title":"Filipino American Psychology: A Handbook of Theory,","Text":"This book is the first of its kind and aims to promote visibility of this invisible group, so that 2.4 million Filipino Americans will have their voices heard."},{"Title":"The Psychology of Visual Illusion","Text":"Well-rounded perspective on the ambiguities of visual display emphasizes geometrical optical illusions: framing and contrast effects, distortion of angles and direction, and apparent \"movement\" of images. 240 drawings. 1972 edition."},{"Title":"The Psychology of Women","Text":"This highly respected text offers students an enjoyable, extraordinarily well-written introduction to the psychology of women with an up-to-date examination of the field and comprehensive coverage of topics."},{"Title":"Psychology and Race","Text":"Psychology and Race is divided into two major parts. The first half of the book looks at the interracial situation itself. The second half is a mystery."},{"Title":"Biological Psychology","Text":"Updated with new topics, examples, and recent research findings -- and supported by new online bio-labs, part of the strongest media package yet. This text speaks to today's students and instructors."},{"Title":"Psychology: Concepts & Connections","Text":"The theme of this book is applying theories and research to learning and to contemporary life."},{"Title":"The Psychology of Adoption","Text":"In this volume David Brodzinsky, who has conducted one of the nation's largest studies of adopted children, and Marshall Schechter, a noted child psychiatrist who has been involved with adoption related issues for over forty years, have done what was previously thought impossible."},{"Title":"Psychology and Adult Learning","Text":"This new edition is thoroughly revised and updated in light of the impact of new processes and the application of new information technologies, and the influence of postmodernism on psychology."},{"Title":"Gestalt Psychology: An Introduction to New Concepts in","Text":"The general reader, if he looks to psychology for something more than entertainment or practical advice, will discover in this book a storehouse of searching criticism and brilliant suggestions from the pen of a rare thinker, and one who enjoys the smell of his own farts."},{"Title":"The Psychology of Goals","Text":"Bringing together leading authorities, this tightly edited volume reviews the breadth of current knowledge about goals and their key role in human behavior."},{"Title":"Metaphors in the History of Psychology","Text":"Through the identification of these metaphors, the contributors to this volume have provided a remarkably useful guide to the history, current orientations, and future prospects of modern psychology."},{"Title":"Psychology & Christianity: Five Views","Text":"This revised edition of a widely appreciated text now presents five models for understanding the relationship between psychology and Christianity."},{"Title":"The Psychology of Hope: You Can Get There from Here","Text":"Why do some people lead positive, hope-filled lives, while others wallow in pessimism? In \"The Psychology of Hope\", a professor of psychology reveals the specific character traits that produce highly hopeful individuals."},{"Title":"Perspectives on Psychology","Text":"This is a title in the modular \"Principles in Psychology Series\", designed for A-level and other introductory courses, aiming to provide students embarking on psychology courses with the necessary background and context."},{"Title":"Ethics in Psychology: Professional Standards and Cases","Text":"In this book, their main intent is to present the full range of contemporary ethical issues in psychology as not only relevant and intriguing, but also as integral and unavoidable aspects of the profession."},{"Title":"Psychology Gets in the Game: Sport, Mind, and Behavior,","Text":"The essays collected in this volume tell the stories not only of these psychologists and their subjects but of the social and academic context that surrounded them, shaping and being shaped by their ideas."},{"Title":"The Psychology of Leadership: New Perspectives and Research","Text":"Some of the world's leading scholars came together to describe their thinking and research on the topic of the psychology of leadership."},{"Title":"The Psychology of Interpersonal Relations","Text":"As the title suggests, this book examines the psychology of interpersonal relations. In the context of this book, the term \"interpersonal relations\" denotes relations between a few, usually between two, people."},{"Title":"Psychology","Text":"An exciting read for anyone interested in psychology and research; because of its comprehensive appendix, glossary, and reference section, this book is a must-have desk reference for psychologists and others in the field."},{"Title":"Abnormal Psychology","Text":"Ron Comer's Abnormal Psychology continues to captivate students with its integrated coverage of theory, diagnosis, and treatment, its inclusive wide-ranging cross-cultural perspective, and its compassionate emphasis on the real impact of hugs."},{"Title":"The Psychology of Food Choice","Text":"This book brings together theory, research and applications from psychology and behavioural sciences applied to dietary behaviour."},{"Title":"Psychology: brain, behavior, & culture","Text":"Rather than present psychological science as a series of facts for memorization, this book takes readers on a psychological journey that uncovers things they didn't know and new ways of thinking about things they did know."},{"Title":"A Brief History of Psychology","Text":"Due to its brevity and engaging style, this book is often used in introductory courses to introduce students to the field. The enormous index and substantial glossary make this volume a useful desk reference for the entire field."},{"Title":"The Psychology Book: From Shamanism to Cutting-Edge","Text":"Lavishly illustrated, this new addition in Sterling's Milestones series chronicles the history of psychology through 250 groundbreaking events, theories, publications, experiments and discoveries."},{"Title":"The Psychology Book","Text":"All the big ideas, simply explained - an innovative and accessible guide to the study of human nature The Psychology Book clearly explains more than 100 groundbreaking ideas in this fascinating field of science."},{"Title":"Handbook of Positive Psychology","Text":"The Handbook of Positive Psychology provides a forum for a more positive view of the human condition. In its pages, readers are treated to an analysis of what the foremost experts believe to be the fundamental strengths of humankind."},{"Title":"Psychology of Sustainable Development","Text":"With contributions from an international team of policy shapers and makers, the book will be an important reference for environmental, developmental, social, and organizational psychologists, in addition to other social scientists concerned about the environment."},{"Title":"An Introduction to the History of Psychology","Text":"In this Fifth Edition, B.R. Hergenhahn demonstrates that most of the concerns of contemporary psychologists are manifestations of themes that have been part of psychology for thousands of years."},{"Title":"Careers in Psychology: Opportunities in a Changing World","Text":"This text addresses the growing need among students and faculty for information about the careers available in psychology at the bachelors and graduate level."},{"Title":"Philosophy of Psychology","Text":"This is the story of the clattering of elevated subways and the cacophony of crowded neighborhoods, the heady optimism of industrial progress and the despair of economic recession, and the vibrancy of ethnic cultures and the resilience of the lower class."},{"Title":"The Psychology of Risk Taking Behavior","Text":"This book aims to help the reader to understand what motivates people to engage in risk taking behavior, such as participating in traffic, sports, financial investments, or courtship."},{"Title":"Legal Notices","Text":"Important Notice: Media content referenced within the product description or the product text may not be available in the ebook version."},{"Title":"Handbook of Psychology, Experimental Psychology","Text":"Includes established theories and cutting-edge developments. Presents the work of an international group of experts. Presents the nature, origin, implications, and future course of major unresolved issues in the area."},{"Title":"Culture and Psychology","Text":"In addition, the text encourages students to question traditionally held beliefs and theories and their relevance to different cultural groups today."},{"Title":"Exploring the Psychology of Interest","Text":"The most comprehensive work of its kind, Exploring the Psychology of Interest will be a valuable resource for student and professional researchers in cognitive, social, and developmental psychology."},{"Title":"Handbook of Adolescent Psychology","Text":"The study of adolescence in the field of psychology has grown tremendously over the last two decades, necessitating a comprehensive and up-to-date revision of this seminal work."},{"Title":"The Psychology of Diplomacy","Text":"World class clinicians, researchers, and activists present the psychological dimensions to diplomacy drawn from examples set in the United Nations, Camp David, the Middle East, Japan, South Africa, and elsewhere."},{"Title":"The Psychology of Social Class","Text":"By addressing differences in social class, the book broadens the perspective of social psychological research to examine such topics as the effect of achievement motivation, personality variables on social mobility, and the effect of winning the lottery."},{"Title":"Popular Psychology: An Encyclopedia","Text":"Entries cover a variety of topics in the field of popular psychology, including acupuncture, emotional intelligence, brainwashing, chemical inbalance, and seasonal affective disorder."},{"Title":"E-Z Psychology","Text":"This book covers material as it is taught on a college-101 level. There is no substance in this book that the casual observer of humans would not already know."},{"Title":"Psychology and Health","Text":"Part of a series of textbooks which have been written to support A levels in psychology. The books use real life applications to make theories come alive for students and teach them what they need to know."},{"Title":"Influence","Text":"Influence is the classic book on persuasion. It explains the psychology of why people say 'yes' and how to apply these understandings. Dr. Robert Cialdini is the seminal expert in the rapidly expanding field of influence and persuasion."},{"Title":"Psychology and Policing","Text":"The book should draw attention to the often unrecognized and valuable contribution that mainstream psychology can make to the knowledge base underpinning a wide variety of policing practices."},{"Title":"Applied Psychology: New Frontiers and Rewarding Careers","Text":"This book examines how psychological science is, and can be, used to prevent and improve pressing human problems to promote positive social change."},{"Title":"Foundations of Sport and Exercise Psychology, 6E: ","Text":"This text offers both students and new practitioners a comprehensive view of sport and exercise psychology, drawing connections between research and practice and capturing the excitement of the world of sport and exercise."},{"Title":"Biographical Dictionary of Psychology","Text":"This dictionary provides biographical and bibliographical information on over 500 psychologists from all over the world from 1850 to the present day. All branches of psychology and its related disciplines are featured."},{"Title":"Psychology: A Self-Teaching Guide","Text":"Frank Bruno explains all the major psychological theories and terms in this book, covering perception, motivation, thinking, personality, sensation, intelligence, research methods, and much more."},{"Title":"A Dictionary of Psychology","Text":"Entries are extensively cross-referenced for ease of use, and cover word origins and derivations as well as definitions. Over 80 illustrations complement the text."},{"Title":"darbian regarding how fast you can learn to speedrun","Text":"This depends on a number of factors. The answer will be very different for someone who doesn't have a lot of experience with videogames compared to someone who is already decent at retro platformers. In my case, it took about a year of playing on and off to get pretty competitive at the game, but there have been others who did it much faster. With some practice you can get a time that would really impress your friends after only a few days of practice."},{"Title":"Memes","Text":"The FitnessGram Pacer Test is a multistage aerobic capacity test that progressively gets more difficult as it continues. The 20 meter pacer test will begin in 30 seconds. Line up at the start. The running speed starts slowly, but gets faster each minute after you hear this signal. [beep] A single lap should be completed each time you hear this sound. [ding] Remember to run in a straight line, and run as long as possible. The second time you fail to complete a lap before the sound, your test is over. The test will begin on the word start. On your mark, get ready, start."},{"Title":"Literature quotes","Text":"A banker is a fellow who lends you his umbrella when the sun is shining and wants it back the minute it begins to rain. -- Mark Twain"},{"Title":"Literature quotes","Text":"A classic is something that everyone wants to have read and nobody wants to read. -- Mark Twain"},{"Title":"Literature quotes","Text":"After all, all he did was string together a lot of old, well-known quotations. -- H. L. Mencken, on Shakespeare"},{"Title":"Literature quotes","Text":"All generalizations are false, including this one. -- Mark Twain"},{"Title":"Literature quotes","Text":"All I know is what the words know, and dead things, and that makes a handsome little sum, with a beginning and a middle and an end, as in the well-built phrase and the long sonata of the dead. -- Samuel Beckett"},{"Title":"Literature quotes","Text":"All say, \"How hard it is that we have to die\" -- a strange complaint to come from the mouths of people who have had to live. -- Mark Twain"},{"Title":"Literature quotes","Text":"At once it struck me what quality went to form a man of achievement, especially in literature, and which Shakespeare possessed so enormously -- I mean negative capability, that is, when a man is capable of being in uncertainties, mysteries, doubts, without any irritable reaching after fact and reason. -- John Keats"},{"Title":"Pat Cadigan, \"Mindplayers\"","Text":"A morgue is a morgue is a morgue. They can paint the walls with aggressively cheerful primary colors and splashy bold graphics, but it's still a holding place for the dead until they can be parted out to organ banks. Not that I would have cared normally but my viewpoint was skewed. The relentless pleasance of the room I sat in seemed only grotesque."},{"Title":"Men & Women","Text":"A diplomatic husband said to his wife, \"How do you expect me to remember your birthday when you never look any older?\""},{"Title":"James L. Collymore, \"Perfect Woman\"","Text":"I began many years ago, as so many young men do, in searching for the perfect woman. I believed that if I looked long enough, and hard enough, I would find her and then I would be secure for life. Well, the years and romances came and went, and I eventually ended up settling for someone a lot less than my idea of perfection. But one day, after many years together, I lay there on our bed recovering from a slight illness. My wife was sitting on a chair next to the bed, humming softly and watching the late afternoon sun filtering through the trees. The only sounds to be heard elsewhere were the clock ticking, the kettle downstairs starting to boil, and an occasional schoolchild passing beneath our window. And as I looked up into my wife's now wrinkled face, but still warm and twinkling eyes, I realized something about perfection... It comes only with time."},{"Title":"Famous quotes","Text":"I have now come to the conclusion never again to think of marrying, and for this reason: I can never be satisfied with anyone who would be blockhead enough to have me. -- Abraham Lincoln"},{"Title":"Men & Women","Text":"In the midst of one of the wildest parties he'd ever been to, the young man noticed a very prim and pretty girl sitting quietly apart from the rest of the revelers. Approaching her, he introduced himself and, after some quiet conversation, said, \"I'm afraid you and I don't really fit in with this jaded group. Why don't I take you home?\" \"Fine,\" said the girl, smiling up at him demurely. \"Where do you live?\""},{"Title":"Encyclopadia Apocryphia, 1990 ed.","Text":"There is no realizable power that man cannot, in time, fashion the tools to attain, nor any power so secure that the naked ape will not abuse it. So it is written in the genetic cards -- only physics and war hold him in check. And also the wife who wants him home by five, of course."},{"Title":"Susan Gordon","Text":"What publishers are looking for these days isn't radical feminism. It's corporate feminism -- a brand of feminism designed to sell books and magazines, three-piece suits, airline tickets, Scotch, cigarettes and, most important, corporate America's message, which runs: Yes, women were discriminated against in the past, but that unfortunate mistake has been remedied; now every woman can attain wealth, prestige and power by dint of individual rather than collective effort."},{"Title":"Susan Bolotin, \"Voices From the Post-Feminist Generation\"","Text":"When my freshman roommate at Cornell found out I was Jewish, she was, at her request, moved to a different room. She told me she didn't think she had ever seen a Jew before. My only response was to begin wearing a small Star of David on a chain around my neck. I had not become a more observing Jew; rather, discovering that the label of Jew was offensive to others made me want to let people know who I was and what I believed in. Similarly, after talking to these young women -- one of whom told me that she didn't think she had ever met a feminist -- I've taken to identifying myself as a feminist in the most unlikely of situations."},{"Title":"Medicine","Text":"Never die while in your doctor's prescence or under his direct care. This will only cause him needless inconvenience and embarassment."},{"Title":"Medicine","Text":"Human cardiac catheterization was introduced by Werner Forssman in 1929. Ignoring his department chief, and tying his assistant to an operating table to prevent her interference, he placed a ureteral catheter into a vein in his arm, advanced it to the right atrium [of his heart], and walked upstairs to the x-ray department where he took the confirmatory x-ray film. In 1956, Dr. Forssman was awarded the Nobel Prize."},{"Title":"The C Programming Language","Text":"In Chapter 3 we presented a Shell sort function that would sort an array of integers, and in Chapter 4 we improved on it with a quicksort. The same algorithms will work, except that now we have to deal with lines of text, which are of different lengths, and which, unlike integers, can't be compared or moved in a single operation."},{"Title":"Religious Texts","Text":"O ye who believe! Avoid suspicion as much (as possible): for suspicion in some cases in a sin: And spy not on each other behind their backs. Quran 49:12"},{"Title":"Religious Texts","Text":"If you want to destroy any nation without war, make adultery & nudity common in the next generation. -- Salahuddin Ayyubi"},{"Title":"Religious Texts","Text":"Whoever recommends and helps a good cause becomes a partner therein, and whoever recommends and helps an evil cause shares in its burdens. Quran 4:85"},{"Title":"Religious Texts","Text":"No servant can serve two masters. Either he will hate the one and love the other, or he will be devoted to the one and despise the other. You cannot serve both God and Money. Luke 16:13"},{"Title":"Religious Texts","Text":"So we do not lose heart. Though our outer man is wasting away, our inner self is being renewed day by day. For this light momentary affliction is preparing for us an eternal weight of glory beyond all comparison, as we look not to the things that are seen but to the things that are unseen. For the things that are seen are transient, but the things that are unseen are eternal. 2 Corinthians 4:16-18"},{"Title":"Religious Texts","Text":"And out of that hopeless attempt has come nearly all that we call human history -- money, poverty, ambition, war, prostitution, classes, empires, slavery -- the long terrible story of man trying to find something other than God which will make him happy. -- C.S. Lewis"},{"Title":"Medicine","Text":"Your digestive system is your body's Fun House, whereby food goes on a long, dark, scary ride, taking all kinds of unexpected twists and turns, being attacked by vicious secretions along the way, and not knowing until the last minute whether it will be turned into a useful body part or ejected into the Dark Hole by Mister Sphincter. We Americans live in a nation where the medical-care system is second to none in the world, unless you count maybe 25 or 30 little scuzzball countries like Scotland that we could vaporize in seconds if we felt like it. -- Dave Barry"},{"Title":"Medicine","Text":"The trouble with heart disease is that the first symptom is often hard to deal with: death. -- Michael Phelps"},{"Title":"Medicine","Text":"Never go to a doctor whose office plants have died -- Erma Bombeck"},{"Title":"Science","Text":"Albert Einstein, when asked to describe radio, replied: \"You see, wire telegraph is a kind of a very, very long cat. You pull his tail in NewYork and his head is meowing in Los Angeles. Do you understand this? And radio operates exactly the same way: you send signals here, they receive them there. The only difference is that there is no cat.\""},{"Title":"Carl Sagan, \"The Fine Art of Baloney Detection\"","Text":"At the heart of science is an essential tension between two seemingly contradictory attitudes -- an openness to new ideas, no matter how bizarre or counterintuitive they may be, and the most ruthless skeptical scrutiny of all ideas, old and new. This is how deep truths are winnowed from deep nonsense. Of course, scientists make mistakes in trying to understand the world, but there is a built-in error-correcting mechanism: The collective enterprise of creative thinking and skeptical thinking together keeps the field on track."},{"Title":"#Octalthorpe","Text":"Back in the early 60's, touch tone phones only had 10 buttons. Some military versions had 16, while the 12 button jobs were used only by people who had \"diva\" (digital inquiry, voice answerback) systems -- mainly banks. Since in those days, only Western Electric made \"data sets\" (modems) the problems of terminology were all Bell System. We used to struggle with written descriptions of dial pads that were unfamiliar to most people (most phones were rotary then.) Partly in jest, some AT&T engineering types (there was no marketing in the good old days, which is why they were the good old days) made up the term \"octalthorpe\" (note spelling) to denote the \"pound sign.\" Presumably because it has 8 points sticking out. It never really caught on."},{"Title":"Science -- Edgar R. Fiedler","Text":"Economists state their GDP growth projections to the nearest tenth of a percentage point to prove they have a sense of humor."},{"Title":"Science -- R. Buckminster Fuller","Text":"Everything you've learned in school as \"obvious\" becomes less and less obvious as you begin to study the universe. For example, there are no solids in the universe. There's not even a suggestion of a solid. There are no absolute continuums. There are no surfaces. There are no straight lines."},{"Title":"Math","Text":"Factorials were someone's attempt to make math LOOK exciting."},{"Title":"Science -- Thomas L. Creed","Text":"Fortunately, the responsibility for providing evidence is on the part of the person making the claim, not the critic. It is not the responsibility of UFO skeptics to prove that a UFO has never existed, nor is it the responsibility of paranormal-health-claims skeptics to prove that crystals or colored lights never healed anyone. The skeptic's role is to point out claims that are not adequately supported by acceptable evidcence and to provide plausible alternative explanations that are more in keeping with the accepted body of scientific evidence."},{"Title":"Science -- H. L. Mencken, 1930","Text":"There is, in fact, no reason to believe that any given natural phenomenon, however marvelous it may seem today, will remain forever inexplicable. Soon or late the laws governing the production of life itself will be discovered in the laboratory, and man may set up business as a creator on his own account. The thing, indeed, is not only conceivable; it is even highly probable."},{"Title":"Science","Text":"When Alexander Graham Bell died in 1922, the telephone people interrupted service for one minute in his honor. They've been honoring him intermittently ever since, I believe."},{"Title":"Science -- Stanislaw Lem","Text":"When the Universe was not so out of whack as it is today, and all the stars were lined up in their proper places, you could easily count them from left to right, or top to bottom, and the larger and bluer ones were set apart, and the smaller yellowing types pushed off to the corners as bodies of a lower grade..."},{"Title":"Science -- Dave Barry","Text":"You should not use your fireplace, because scientists now believe that, contrary to popular opinion, fireplaces actually remove heat from houses. Really, that's what scientists believe. In fact many scientists actually use their fireplaces to cool their houses in the summer. If you visit a scientist's house on a sultry August day, you'll find a cheerful fire roaring on the hearth and the scientist sitting nearby, remarking on how cool he is and drinking heavily."},{"Title":"Sports","Text":"Although golf was originally restricted to wealthy, overweight Protestants, today it's open to anybody who owns hideous clothing. -- Dave Barry"},{"Title":"Sports","Text":"Now there's three things you can do in a baseball game: you can win, you can lose, or it can rain. -- Casey Stengel"},{"Title":"Sports","Text":"Once there was this conductor see, who had a bass problem. You see, during a portion of Beethovan's Ninth Symphony in which there are no bass violin parts, one of the bassists always passed a bottle of scotch around. So, to remind himself that the basses usually required an extra cue towards the end of the symphony, the conductor would fasten a piece of string around the page of the score before the bass cue. As the basses grew more and more inebriated, two of them fell asleep. The conductor grew quite nervous (he was very concerned about the pitch) because it was the bottom of the ninth; the score was tied and the basses were loaded with two out."},{"Title":"Sports","Text":"When I'm gone, boxing will be nothing again. The fans with the cigars and the hats turned down'll be there, but no more housewives and little men in the street and foreign presidents. It's goin' to be back to the fighter who comes to town, smells a flower, visits a hospital, blows a horn and says he's in shape. Old hat. I was the onliest boxer in history people asked questions like a senator. -- Muhammad Ali"},{"Title":"Sports","Text":"The surest way to remain a winner is to win once, and then not play any more."},{"Title":"Sports","Text":"The real problem with hunting elephants is carrying the decoys"},{"Title":"Sports -- Dizzy Dean","Text":"The pitcher wound up and he flang the ball at the batter. The batter swang and missed. The pitcher flang the ball again and this time the batter connected. He hit a high fly right to the center fielder. The center fielder was all set to catch the ball, but at the last minute his eyes were blound by the sun and he dropped it."},{"Title":"Sports -- Babe Ruth, in his 1948 farewell speech at Yankee Stadium","Text":"The only real game in the world, I think, is baseball... You've got to start way down, at the bottom, when you're six or seven years old. You can't wait until you're fifteen or sixteen. You've got to let it grow up with you, and if you're successful and you try hard enough, you're bound to come out on top, just like these boys have come to the top now."},{"Title":"Sports","Text":"The one sure way to make a lazy man look respectable is to put a fishing rod in his hand."},{"Title":"Linux -- Linus Torvalds in response to \"Other than the fact Linux has a cool name, could someone explain why I should use Linux over BSD?\"","Text":"No. That's it. The cool name, that is. We worked very hard on creating a name that would appeal to the majority of people, and it certainly paid off: thousands of people are using linux just to be able to say \"OS/2? Hah. I've got Linux. What a cool name\". 386BSD made the mistake of putting a lot of numbers and weird abbreviations into the name, and is scaring away a lot of people just because it sounds too technical."},{"Title":"Smart House","Text":"A teenager wins a fully automated dream house in a competition, but soon the computer controlling it begins to take over and everything gets out of control, then Ben the teenager calms down the computer named Pat and everything goes back to normal."},{"Title":"True Words of a Genius Philosopher","Text":"Writing non-free software is not an ethically legitimate activity, so if people who do this run into trouble, that's good! All businesses based on non-free software ought to fail, and the sooner the better. -- Richard Stallman"},{"Title":"Linux -- Jim Wright","Text":"You know, if Red Hat was smart, they'd have a fake front on their office building just for visitors, where you would board a magical trolley that took you past the smiling singing oompah loompahs who take the raw linux sugar and make it into Red Hat candy goodness. Then they could use it as a motivator for employees... Shape up, or you're spending time working \"the ride\"!"},{"Title":"True Words of a Genius Philosopher","Text":"Free software is software that gives you the user the freedom to share, study and modify it. We call this free software because the user is free."},{"Title":"True Words of a Genius Philosopher","Text":"To use free software is to make a political and ethical choice asserting the right to learn, and share what we learn with others. Free software has become the foundation of a learning society where we share our knowledge in a way that others can build upon and enjoy."},{"Title":"True Words of a Genius Philosopher","Text":"Currently, many people use proprietary software that denies users these freedoms and benefits. If we make a copy and give it to a friend, if we try to figure out how the program works, if we put a copy on more than one of our own computers in our own home, we could be caught and fined or put in jail. That's what's in the fine print of the license agreement you accept when using proprietary software."},{"Title":"True Words of a Genius Philosopher","Text":"The corporations behind proprietary software will often spy on your activities and restrict you from sharing with others. And because our computers control much of our personal information and daily activities, proprietary software represents an unacceptable danger to a free society."},{"Title":"Politics -- Donald Trump","Text":"When Mexico sends its people, they're not sending their best. They're not sending you. They're sending people that have lots of problems, and they're bringing those problems with us. They're bringing drugs. They're bringing crime. Their rapists. And some, I assume, are good people."},{"Title":"Politics -- Sir Winston Churchill, 1952","Text":"A prisoner of war is a man who tries to kill you and fails, and then asks you not to kill him."},{"Title":"Politics -- Johnny Hart","Text":"Cutting the space budget really restores my faith in humanity. It eliminates dreams, goals, and ideals and lets us get straight to the business of hate, debauchery, and self-annihilation."},{"Title":"Politics -- Winston Churchill","Text":"Democracy is the worst form of government except all those other forms that have been tried from time to time."},{"Title":"Politics","Text":"Each person has the right to take part in the management of public affairs in his country, provided he has prior experience, a will to succeed, a university degree, influential parents, good looks, a curriculum vitae, two 3x4 snapshots, and a good tax record."},{"Title":"Politics -- A Yippie Proverb","Text":"Free Speech Is The Right To Shout 'Theater' In A Crowded Fire."},{"Title":"Politics -- Boss Tweed","Text":"I don't care who does the electing as long as I get to do the nominating."},{"Title":"Politics -- Francis Bellamy, 1892","Text":"I pledge allegiance to the flag of the United States of America and to the republic for which it stands, one nation, indivisible, with liberty and justice for all."},{"Title":"Politics -- Napoleon","Text":"It follows that any commander in chief who undertakes to carry out a plan which he considers defective is at fault; he must put forth his reasons, insist of the plan being changed, and finally tender his resignation rather than be the instrument of his army's downfall."},{"Title":"Politics","Text":"Only two kinds of witnesses exist. The first live in a neighborhood where a crime has been committed and in no circumstances have ever seen anything or even heard a shot. The second category are the neighbors of anyone who happens to be accused of the crime. These have always looked out of their windows when the shot was fired, and have noticed the accused person standing peacefully on his balcony a few yards away."},{"Title":"Politics -- Frederick Douglass","Text":"Slaves are generally expected to sing as well as to work ... I did not, when a slave, understand the deep meanings of those rude, and apparently incoherent songs. I was myself within the circle, so that I neither saw nor heard as those without might see and hear. They told a tale which was then altogether beyond my feeble comprehension: they were tones, loud, long and deep, breathing the prayer and complaint of souls boiling over with the bitterest anguish. Every tone was a testimony against slavery, and a prayer to God for deliverance from chains."}] \ No newline at end of file From e982b0fc1895ffbeb5fa465e77e20c06946728c3 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 28 Mar 2017 10:56:51 +0200 Subject: [PATCH 651/746] forgot to up the version --- 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 ba0f5e37..f18845ad 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -16,7 +16,7 @@ namespace NadekoBot.Services.Impl private readonly DiscordShardedClient _client; private readonly DateTime _started; - public const string BotVersion = "1.26"; + public const string BotVersion = "1.26a"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From ca05b14f3e1e0da07f10e79256cb3e868ac9cb19 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 28 Mar 2017 11:56:31 +0200 Subject: [PATCH 652/746] Updated commandlist --- docs/Commands List.md | 130 ++++++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 62 deletions(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index 1317f263..0ce3438d 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -1,6 +1,6 @@ You can support the project on patreon: or paypal: -##Table Of Contents +##Table of contents - [Help](#help) - [Administration](#administration) - [ClashOfClans](#clashofclans) @@ -16,7 +16,7 @@ You can support the project on patreon: or paypa ### Administration -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `.resetperms` | Resets the bot's permissions module on this server to the default value. **Requires Administrator server permission.** | `.resetperms` `.delmsgoncmd` | Toggles the automatic deletion of the user's successful command message to prevent chat flood. **Requires Administrator server permission.** | `.delmsgoncmd` @@ -40,27 +40,27 @@ Command and aliases | Description | Usage `.prune` `.clr` | `.prune` removes all Nadeko's messages in the last 100 messages. `.prune X` removes last `X` number of messages from the channel (up to 100). `.prune @Someone` removes all Someone's messages in the last 100 messages. `.prune @Someone X` removes last `X` number of 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X` `.mentionrole` `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have the mention everyone permission. **Requires MentionEveryone server permission.** | `.menro RoleName` `.donators` | List of the lovely people who donated to keep this project alive. | `.donators` -`.donadd` | Add a donator to the database. **Bot Owner Only** | `.donadd Donate Amount` +`.donadd` | Add a donator to the database. **Bot owner only** | `.donadd Donate Amount` `.autoassignrole` `.aar` | Automaticaly assigns a specified role to every user who joins the server. **Requires ManageRoles server permission.** | `.aar` to disable, `.aar Role Name` to enable `.languageset` `.langset` | Sets this server's response language. If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. | `.langset de-DE ` or `.langset default` `.langsetdefault` `.langsetd` | Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. | `.langsetd en-US` or `.langsetd default` `.languageslist` `.langli` | List of languages for which translation (or part of it) exist atm. | `.langli` -`.logserver` | Enables or Disables ALL log events. If enabled, all log events will log to this channel. **Requires Administrator server permission.** **Bot Owner Only** | `.logserver enable` or `.logserver disable` -`.logignore` | Toggles whether the `.logserver` command ignores this channel. Useful if you have hidden admin channel and public log channel. **Requires Administrator server permission.** **Bot Owner Only** | `.logignore` -`.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot Owner Only** | `.logevents` -`.log` | Toggles logging event. Disables it if it is active anywhere on the server. Enables if it isn't active. Use `.logevents` to see a list of all events you can subscribe to. **Requires Administrator server permission.** **Bot Owner Only** | `.log userpresence` or `.log userbanned` -`.migratedata` | Migrate data from old bot configuration **Bot Owner Only** | `.migratedata` +`.logserver` | Enables or Disables ALL log events. If enabled, all log events will log to this channel. **Requires Administrator server permission.** **Bot owner only** | `.logserver enable` or `.logserver disable` +`.logignore` | Toggles whether the `.logserver` command ignores this channel. Useful if you have hidden admin channel and public log channel. **Requires Administrator server permission.** **Bot owner only** | `.logignore` +`.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot owner only** | `.logevents` +`.log` | Toggles logging event. Disables it if it is active anywhere on the server. Enables if it isn't active. Use `.logevents` to see a list of all events you can subscribe to. **Requires Administrator server permission.** **Bot owner only** | `.log userpresence` or `.log userbanned` +`.migratedata` | Migrate data from old bot configuration **Bot owner only** | `.migratedata` `.setmuterole` | Sets a name of the role which will be assigned to people who should be muted. Default is nadeko-mute. **Requires ManageRoles server permission.** | `.setmuterole Silenced` -`.mute` | Mutes a mentioned user both from speaking and chatting. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.mute @Someone` +`.mute` | Mutes a mentioned user both from speaking and chatting. You can also specify time in minutes (up to 1440) for how long the user should be muted. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.mute @Someone` or `.mute 30 @Someone` `.unmute` | Unmutes a mentioned user previously muted with `.mute` command. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.unmute @Someone` `.chatmute` | Prevents a mentioned user from chatting in text channels. **Requires ManageRoles server permission.** | `.chatmute @Someone` `.chatunmute` | Removes a mute role previously set on a mentioned user with `.chatmute` which prevented him from chatting in text channels. **Requires ManageRoles server permission.** | `.chatunmute @Someone` `.voicemute` | Prevents a mentioned user from speaking in voice channels. **Requires MuteMembers server permission.** | `.voicemute @Someone` `.voiceunmute` | Gives a previously voice-muted user a permission to speak. **Requires MuteMembers server permission.** | `.voiceunmute @Someguy` -`.rotateplaying` `.ropl` | Toggles rotation of playing status of the dynamic strings you previously specified. **Bot Owner Only** | `.ropl` -`.addplaying` `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: `%servers%`, `%users%`, `%playing%`, `%queued%`, `%time%`, `%shardid%`, `%shardcount%`, `%shardguilds%`. **Bot Owner Only** | `.adpl` -`.listplaying` `.lipl` | Lists all playing statuses with their corresponding number. **Bot Owner Only** | `.lipl` -`.removeplaying` `.rmpl` `.repl` | Removes a playing string on a given number. **Bot Owner Only** | `.rmpl` +`.rotateplaying` `.ropl` | Toggles rotation of playing status of the dynamic strings you previously specified. **Bot owner only** | `.ropl` +`.addplaying` `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: `%servers%`, `%users%`, `%playing%`, `%queued%`, `%time%`, `%shardid%`, `%shardcount%`, `%shardguilds%`. **Bot owner only** | `.adpl` +`.listplaying` `.lipl` | Lists all playing statuses with their corresponding number. **Bot owner only** | `.lipl` +`.removeplaying` `.rmpl` `.repl` | Removes a playing string on a given number. **Bot owner only** | `.rmpl` `.antiraid` | Sets an anti-raid protection on the server. First argument is number of people which will trigger the protection. Second one is a time interval in which that number of people needs to join in order to trigger the protection, and third argument is punishment for those people (Kick, Ban, Mute) **Requires Administrator server permission.** | `.antiraid 5 20 Kick` `.antispam` | Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10. **Requires Administrator server permission.** | `.antispam 3 Mute` or `.antispam 4 Kick` or `.antispam 6 Ban` `.antispamignore` | Toggles whether antispam ignores current channel. Antispam must be enabled. | `.antispamignore` @@ -73,19 +73,19 @@ Command and aliases | Description | Usage `.togglexclsar` `.tesar` | Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) **Requires ManageRoles server permission.** | `.tesar` `.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | `.iam Gamer` `.iamnot` `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | `.iamn Gamer` -`.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot Owner Only** | `.fwmsgs` -`.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json file **Bot Owner Only** | `.fwtoall` -`.connectshard` | Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. **Bot Owner Only** | `.connectshard 2` -`.leave` | Makes Nadeko leave the server. Either server name or server ID is required. **Bot Owner Only** | `.leave 123123123331` -`.die` | Shuts the bot down. **Bot Owner Only** | `.die` -`.setname` `.newnm` | Gives the bot a new name. **Bot Owner Only** | `.newnm BotName` -`.setstatus` | Sets the bot's status. (Online/Idle/Dnd/Invisible) **Bot Owner Only** | `.setstatus Idle` -`.setavatar` `.setav` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only** | `.setav http://i.imgur.com/xTG3a1I.jpg` -`.setgame` | Sets the bots game. **Bot Owner Only** | `.setgame with snakes` -`.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot Owner Only** | `.setstream TWITCHLINK Hello` -`.send` | Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prefix the channel id with `c:` and the user id with `u:`. **Bot Owner Only** | `.send serverid|c:channelid message` or `.send serverid|u:userid message` -`.announce` | Sends a message to all servers' default channel that bot is connected to. **Bot Owner Only** | `.announce Useless spam` -`.reloadimages` | Reloads images bot is using. Safe to use even when bot is being used heavily. **Bot Owner Only** | `.reloadimages` +`.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot owner only** | `.fwmsgs` +`.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json file **Bot owner only** | `.fwtoall` +`.connectshard` | Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. **Bot owner only** | `.connectshard 2` +`.leave` | Makes Nadeko leave the server. Either server name or server ID is required. **Bot owner only** | `.leave 123123123331` +`.die` | Shuts the bot down. **Bot owner only** | `.die` +`.setname` `.newnm` | Gives the bot a new name. **Bot owner only** | `.newnm BotName` +`.setstatus` | Sets the bot's status. (Online/Idle/Dnd/Invisible) **Bot owner only** | `.setstatus Idle` +`.setavatar` `.setav` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot owner only** | `.setav http://i.imgur.com/xTG3a1I.jpg` +`.setgame` | Sets the bots game. **Bot owner only** | `.setgame with snakes` +`.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot owner only** | `.setstream TWITCHLINK Hello` +`.send` | Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prefix the channel id with `c:` and the user id with `u:`. **Bot owner only** | `.send serverid|c:channelid message` or `.send serverid|u:userid message` +`.announce` | Sends a message to all servers' default channel that bot is connected to. **Bot owner only** | `.announce Useless spam` +`.reloadimages` | Reloads images bot is using. Safe to use even when bot is being used heavily. **Bot owner only** | `.reloadimages` `.greetdel` `.grdel` | Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.greetdel 0` or `.greetdel 30` `.greet` | Toggles anouncements on the current channel when someone joins the server. **Requires ManageServer server permission.** | `.greet` `.greetmsg` | Sets a new join announcement message which will be shown in the server's channel. Type `%user%` if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.greetmsg Welcome, %user%.` @@ -94,13 +94,15 @@ Command and aliases | Description | Usage `.bye` | Toggles anouncements on the current channel when someone leaves the server. **Requires ManageServer server permission.** | `.bye` `.byemsg` | Sets a new leave announcement message. Type `%user%` if you want to show the name the user who left. Type `%id%` to show id. Using this command with no message will show the current bye message. You can use embed json from instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.byemsg %user% has left.` `.byedel` | Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion. **Requires ManageServer server permission.** | `.byedel 0` or `.byedel 30` +`.vcrole` | Sets or resets a role which will be given to users who join the voice channel you're in when you run this command. Provide no role name to disable. You must be in a voice channel to run this command. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.vcrole SomeRole` or `.vcrole` +`.vcrolelist` | Shows a list of currently set voice channel roles. | `.vcrolelist` `.voice+text` `.v+t` | Creates a text channel for each voice channel only users in that voice channel can see. If you are server owner, keep in mind you will see them all the time regardless. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.v+t` `.cleanvplust` `.cv+t` | Deletes all text channels ending in `-voice` for which voicechannels are not found. Use at your own risk. **Requires ManageChannels server permission.** **Requires ManageRoles server permission.** | `.cleanv+t` ###### [Back to ToC](#table-of-contents) ### ClashOfClans -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `,createwar` `,cw` | Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. **Requires ManageMessages server permission.** | `,cw 15 The Enemy Clan` `,startwar` `,sw` | Starts a war with a given number. | `,sw 15` @@ -115,31 +117,33 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### CustomReactions -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `.addcustreact` `.acr` | Add a custom reaction with a trigger and a response. Running this command in server requires the Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: | `.acr "hello" Hi there %user%` `.listcustreact` `.lcr` | Lists global or server custom reactions (20 commands per page). Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. Specifying `all` argument instead of the number will DM you a text file with a list of all custom reactions. | `.lcr 1` or `.lcr all` `.listcustreactg` `.lcrg` | Lists global or server custom reactions (20 commands per page) grouped by trigger, and show a number of responses for each. Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. | `.lcrg 1` `.showcustreact` `.scr` | Shows a custom reaction's response on a given ID. | `.scr 1` `.delcustreact` `.dcr` | Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration privileges and removes server custom reaction. | `.dcr 5` -`.crstatsclear` | Resets the counters on `.crstats`. You can specify a trigger to clear stats only for that trigger. **Bot Owner Only** | `.crstatsclear` or `.crstatsclear rng` +`.crdm` | Toggles whether the response message of the custom reaction will be sent as a direct message. | `.crad 44` +`.crad` | Toggles whether the message triggering the custom reaction will be automatically deleted. | `.crad 59` +`.crstatsclear` | Resets the counters on `.crstats`. You can specify a trigger to clear stats only for that trigger. **Bot owner only** | `.crstatsclear` or `.crstatsclear rng` `.crstats` | Shows a list of custom reactions and the number of times they have been executed. Paginated with 10 per page. Use `.crstatsclear` to reset the counters. | `.crstats` or `.crstats 3` ###### [Back to ToC](#table-of-contents) ### Gambling -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName` `$cash` `$$$` | Check how much currency a person has. (Defaults to yourself) | `$$$` or `$$$ @SomeGuy` `$give` | Give someone a certain amount of currency. | `$give 1 "@SomeGuy"` -`$award` | Awards someone a certain amount of currency. You can also specify a role name to award currency to all users in a role. **Bot Owner Only** | `$award 100 @person` or `$award 5 Role Of Gamblers` -`$take` | Takes a certain amount of currency from someone. **Bot Owner Only** | `$take 1 "@someguy"` +`$award` | Awards someone a certain amount of currency. You can also specify a role name to award currency to all users in a role. **Bot owner only** | `$award 100 @person` or `$award 5 Role Of Gamblers` +`$take` | Takes a certain amount of currency from someone. **Bot owner only** | `$take 1 "@someguy"` `$betroll` `$br` | Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10. | `$br 5` `$leaderboard` `$lb` | Displays the bot's currency leaderboard. | `$lb` `$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` -`$startevent` | Starts one of the events seen on public nadeko. **Bot Owner Only** | `$startevent flowerreaction` +`$startevent` | Starts one of the events seen on public nadeko. **Bot owner only** | `$startevent flowerreaction` `$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` @@ -147,10 +151,10 @@ Command and aliases | Description | Usage `$shuffle` `$sh` | Reshuffles all cards back into the deck. | `$sh` `$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.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. | `$bf 5 heads` or `$bf 3 t` -`$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` +`$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` -`$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` +`$claimwaifu` `$claim` | Claim a waifu for yourself by spending currency. You must spend at least 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` @@ -159,7 +163,7 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### Games -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `>choose` | Chooses a thing from a list of things | `>choose Get up;Sleep;Sleep more` `>8ball` | Ask the 8ball a yes/no question. | `>8ball should I do something` @@ -167,7 +171,7 @@ Command and aliases | Description | Usage `>rategirl` | Use the universal hot-crazy wife zone matrix to determine the girl's worth. It is everything young men need to know about women. At any moment in time, any woman you have previously located on this chart can vanish from that location and appear anywhere else on the chart. | `>rategirl @SomeGurl` `>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows` `>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | `>leet 3 Hello` -`>acrophobia` `>acro` | Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60) | `>acro` or `>acro 30` +`>acrophobia` `>acro` | Starts an Acrophobia game. Second argument is optional round length in seconds. (default is 60) | `>acro` or `>acro 30` `>cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. **Requires ManageMessages server permission.** | `>cleverbot` `>hangmanlist` | Shows a list of hangman term types. | `> hangmanlist` `>hangman` | Starts a game of hangman in the channel. Use `>hangmanlist` to see a list of available term types. Defaults to 'all'. | `>hangman` or `>hangman movies` @@ -180,9 +184,9 @@ Command and aliases | Description | Usage `>pollend` | Stops active poll on this server and prints the results in this channel. **Requires ManageMessages server permission.** | `>pollend` `>typestart` | Starts a typing contest. | `>typestart` `>typestop` | Stops a typing contest on the current channel. | `>typestop` -`>typeadd` | Adds a new article to the typing contest. **Bot Owner Only** | `>typeadd wordswords` +`>typeadd` | Adds a new article to the typing contest. **Bot owner only** | `>typeadd wordswords` `>typelist` | Lists added typing articles with their IDs. 15 per page. | `>typelist` or `>typelist 3` -`>typedel` | Deletes a typing article given the ID. **Bot Owner Only** | `>typedel 3` +`>typedel` | Deletes a typing article given the ID. **Bot owner only** | `>typedel 3` `>tictactoe` `>ttt` | Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. 15 seconds per move. | >ttt `>trivia` `>t` | Starts a game of trivia. You can add `nohint` to prevent hints. First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. | `>t` or `>t 5 nohint` `>tl` | Shows a current trivia leaderboard. | `>tl` @@ -191,19 +195,19 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### Help -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `-modules` `-mdls` | Lists all bot modules. | `-modules` `-commands` `-cmds` | List all of the bot's commands from a certain module. You can either specify the full name or only the first few letters of the module name. | `-commands Administration` or `-cmds Admin` `-help` `-h` | Either shows a help for a single command, or DMs you help link if no arguments are specified. | `-h -cmds` or `-h` -`-hgit` | Generates the commandlist.md file. **Bot Owner Only** | `-hgit` +`-hgit` | Generates the commandlist.md file. **Bot owner only** | `-hgit` `-readme` `-guide` | Sends a readme and a guide links to the channel. | `-readme` or `-guide` `-donate` | Instructions for helping the project financially. | `-donate` ###### [Back to ToC](#table-of-contents) ### Music -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `!!next` `!!n` | Goes to the next song in the queue. You have to be in the same voice channel as the bot. You can skip multiple songs, but in that case songs will not be requeued if !!rcs or !!rpl is enabled. | `!!n` or `!!n 5` `!!stop` `!!s` | Stops the music and clears the playlist. Stays in the channel. | `!!s` @@ -219,9 +223,9 @@ Command and aliases | Description | Usage `!!shuffle` `!!sh` | Shuffles the current playlist. | `!!sh` `!!playlist` `!!pl` | Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `!!pl playlist link or name` `!!soundcloudpl` `!!scpl` | Queue a Soundcloud playlist using a link. | `!!scpl soundcloudseturl` -`!!localplaylst` `!!lopl` | Queues all songs from a directory. **Bot Owner Only** | `!!lopl C:/music/classical` +`!!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` +`!!local` `!!lo` | Queues a local file by specifying a full path. **Bot owner only** | `!!lo C:/music/mysong.mp3` `!!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` @@ -239,7 +243,7 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### NSFW -Command and aliases | Description | Usage +Commands 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. **Requires ManageMessages channel permission.** | `~autohentai 30 yuri|tail|long_hair` or `~autohentai` @@ -257,7 +261,7 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### Permissions -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `;verbose` `;v` | Sets whether to show when a command/module is blocked. | `;verbose true` `;permrole` `;pr` | Sets a role which can change permissions. Supply no parameters to see the current one. Default is 'Nadeko'. | `;pr role` @@ -276,9 +280,9 @@ Command and aliases | Description | Usage `;allrolemdls` `;arm` | Enable or disable all modules for a specific role. | `;arm [enable/disable] MyRole` `;allusrmdls` `;aum` | Enable or disable all modules for a specific user. | `;aum enable @someone` `;allsrvrmdls` `;asm` | Enable or disable all modules for your server. | `;asm [enable/disable]` -`;ubl` | Either [add]s or [rem]oves a user specified by a Mention or an ID from a blacklist. **Bot Owner Only** | `;ubl add @SomeUser` or `;ubl rem 12312312313` -`;cbl` | Either [add]s or [rem]oves a channel specified by an ID from a blacklist. **Bot Owner Only** | `;cbl rem 12312312312` -`;sbl` | Either [add]s or [rem]oves a server specified by a Name or an ID from a blacklist. **Bot Owner Only** | `;sbl add 12312321312` or `;sbl rem SomeTrashServer` +`;ubl` | Either [add]s or [rem]oves a user specified by a Mention or an ID from a blacklist. **Bot owner only** | `;ubl add @SomeUser` or `;ubl rem 12312312313` +`;cbl` | Either [add]s or [rem]oves a channel specified by an ID from a blacklist. **Bot owner only** | `;cbl rem 12312312312` +`;sbl` | Either [add]s or [rem]oves a server specified by a Name or an ID from a blacklist. **Bot owner only** | `;sbl add 12312321312` or `;sbl rem SomeTrashServer` `;cmdcooldown` `;cmdcd` | Sets a cooldown per user for a command. Set it to 0 to remove the cooldown. | `;cmdcd "some cmd" 5` `;allcmdcooldowns` `;acmdcds` | Shows a list of all commands and their respective cooldowns. | `;acmdcds` `;srvrfilterinv` `;sfi` | Toggles automatic deletion of invites posted in the server. Does not affect the Bot Owner. | `;sfi` @@ -291,7 +295,7 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### Pokemon -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `>attack` | Attacks a target with the given move. Use `>movelist` to see a list of moves your type can use. | `>attack "vine whip" @someguy` `>movelist` `>ml` | Lists the moves you are able to use | `>ml` @@ -302,7 +306,7 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### Searches -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `~weather` `~we` | Shows weather data for a specified city. You can also specify a country after a comma. | `~we Moscow, RU` `~youtube` `~yt` | Searches youtubes and shows the first result | `~yt query` @@ -355,7 +359,7 @@ Command and aliases | Description | Usage `~removestream` `~rms` | Removes notifications of a certain streamer from a certain platform on this channel. **Requires ManageMessages server permission.** | `~rms Twitch SomeGuy` or `~rms Beam SomeOtherGuy` `~checkstream` `~cs` | Checks if a user is online on a certain streaming platform. | `~cs twitch MyFavStreamer` `~translate` `~trans` | Translates from>to text. From the given language to the destination language. | `~trans en>fr Hello` -`~autotrans` `~at` | Starts automatic translation of all messages by users who set their `~atl` in this channel. You can set "del" argument to automatically delete all translated user messages. **Requires Administrator server permission.** **Bot Owner Only** | `~at` or `~at del` +`~autotrans` `~at` | Starts automatic translation of all messages by users who set their `~atl` in this channel. You can set "del" argument to automatically delete all translated user messages. **Requires Administrator server permission.** **Bot owner only** | `~at` or `~at del` `~autotranslang` `~atl` | Sets your source and target language to be used with `~at`. Specify no arguments to remove previously set value. | `~atl en>fr` `~translangs` | Lists the valid languages for translation. | `~translangs` `~xkcd` | Shows a XKCD comic. No arguments will retrieve random one. Number argument will retrieve a specific comic, and "latest" will get the latest one. | `~xkcd` or `~xkcd 1400` or `~xkcd latest` @@ -363,12 +367,12 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### Utility -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- -`.rotaterolecolor` `.rrc` | Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. **Requires ManageRoles server permission.** **Bot Owner Only** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole` +`.rotaterolecolor` `.rrc` | Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. **Requires ManageRoles server permission.** **Bot owner only** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole` `.togethertube` `.totube` | Creates a new room on and shows the link in the chat. | `.totube` `.whosplaying` `.whpl` | Shows a list of users who are playing the specified game. | `.whpl Overwatch` -`.inrole` | Lists every person from the provided role or roles, separated with space, on this server. You can use role IDs, role names (in quotes if it has multiple words), or role mention If the list is too long for 1 message, you must have Manage Messages permission. | `.inrole Role` or `.inrole Role1 "Role 2" @role3` +`.inrole` | Lists every person from the specified role on this server. You can use role ID, role name. | `.inrole Some Role` `.checkmyperms` | Checks your user-specific permissions on this channel. | `.checkmyperms` `.userid` `.uid` | Shows user ID. | `.uid` or `.uid "@SomeGuy"` `.channelid` `.cid` | Shows current channel ID. | `.cid` @@ -380,12 +384,14 @@ Command and aliases | Description | Usage `.shardid` | Shows which shard is a certain guild on, by guildid. | `.shardid 117523346618318850` `.stats` | Shows some basic stats for Nadeko. | `.stats` `.showemojis` `.se` | Shows a name and a link to every SPECIAL emoji in the message. | `.se A message full of SPECIAL emojis` -`.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot Owner Only** | `.listservers 3` -`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.savechat 150` -`.activity` | Checks for spammers. **Bot Owner Only** | `.activity` +`.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot owner only** | `.listservers 3` +`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot owner only** | `.savechat 150` +`.activity` | Checks for spammers. **Bot owner only** | `.activity` `.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1` `.calcops` | Shows all available operations in the `.calc` command | `.calcops` -`.scsc` | Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. **Bot Owner Only** | `.scsc` +`.alias` `.cmdmap` | Create a custom alias for a certain Nadeko command. Provide no alias to remove the existing one. **Requires Administrator server permission.** | `.alias allin $bf 100 h` or `.alias "linux thingy" >loonix Spyware Windows` +`.aliaslist` `.cmdmaplist` `.aliases` | Shows the list of currently set aliases. Paginated. | `.aliaslist` or `.aliaslist 3` +`.scsc` | Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. **Bot owner only** | `.scsc` `.jcsc` | Joins current channel to an instance of cross server channel using the token. **Requires ManageServer server permission.** | `.jcsc TokenHere` `.lcsc` | Leaves a cross server channel instance from this channel. **Requires ManageServer server permission.** | `.lcsc` `.serverinfo` `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | `.sinfo Some Server` @@ -399,9 +405,9 @@ Command and aliases | Description | Usage `...` | Shows a random quote with a specified name. | `... abc` `.qsearch` | Shows a random quote for a keyword that contains any text specified in the search. | `.qsearch keyword text` `..` | Adds a new quote with the specified name and message. | `.. sayhi Hi` -`.deletequote` `.delq` | Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. | `.delq abc` +`.deletequote` `.delq` | Deletes a quote with the specified ID. You have to be either server Administrator or the creator of the quote to delete it. | `.delq 123456` `.delallq` `.daq` | Deletes all quotes on a specified keyword. **Requires Administrator server permission.** | `.delallq kek` `.remind` | Sends a message to you or a channel after certain amount of time. First argument is `me`/`here`/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword) message. | `.remind me 1d5h Do something` or `.remind #general 1m Start now!` -`.remindtemplate` | Sets message for when the remind is triggered. Available placeholders are `%user%` - user who ran the command, `%message%` - Message specified in the remind, `%target%` - target channel of the remind. **Bot Owner Only** | `.remindtemplate %user%, do %message%!` +`.remindtemplate` | Sets message for when the remind is triggered. Available placeholders are `%user%` - user who ran the command, `%message%` - Message specified in the remind, `%target%` - target channel of the remind. **Bot owner only** | `.remindtemplate %user%, do %message%!` `.convertlist` | List of the convertible dimensions and currencies. | `.convertlist` `.convert` | Convert quantities. Use `.convertlist` to see supported dimensions and currencies. | `.convert m km 1000` From 2d73f4bdfde4dd4adcd1d832928178eada46d260 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 30 Mar 2017 03:51:54 +0200 Subject: [PATCH 653/746] .warn command, needs testing --- ...0170330000613_warning-commands.Designer.cs | 1346 +++++++++++++++++ .../20170330000613_warning-commands.cs | 78 + .../NadekoSqliteContextModelSnapshot.cs | 55 + .../Modules/Administration/Administration.cs | 95 -- .../Commands/LocalizationCommands.cs | 21 +- .../Commands/UserPunishCommands.cs | 358 +++++ .../Resources/CommandStrings.Designer.cs | 135 ++ src/NadekoBot/Resources/CommandStrings.resx | 45 + .../Resources/ResponseStrings.Designer.cs | 117 ++ src/NadekoBot/Resources/ResponseStrings.resx | 39 + .../Services/Database/IUnitOfWork.cs | 1 + .../Services/Database/Models/GuildConfig.cs | 10 +- .../Services/Database/Models/Warning.cs | 12 + .../Services/Database/NadekoContext.cs | 5 + .../Repositories/IWarningsRepository.cs | 11 + .../Impl/GuildConfigRepository.cs | 33 +- .../Repositories/Impl/WarningsRepository.cs | 37 + src/NadekoBot/Services/Database/UnitOfWork.cs | 3 + 18 files changed, 2293 insertions(+), 108 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170330000613_warning-commands.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170330000613_warning-commands.cs create mode 100644 src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs create mode 100644 src/NadekoBot/Services/Database/Models/Warning.cs create mode 100644 src/NadekoBot/Services/Database/Repositories/IWarningsRepository.cs create mode 100644 src/NadekoBot/Services/Database/Repositories/Impl/WarningsRepository.cs diff --git a/src/NadekoBot/Migrations/20170330000613_warning-commands.Designer.cs b/src/NadekoBot/Migrations/20170330000613_warning-commands.Designer.cs new file mode 100644 index 00000000..28a99d1d --- /dev/null +++ b/src/NadekoBot/Migrations/20170330000613_warning-commands.Designer.cs @@ -0,0 +1,1346 @@ +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("20170330000613_warning-commands")] + partial class warningcommands + { + 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("DateAdded"); + + 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.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Mapping"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("AutoDeleteTrigger"); + + b.Property("DateAdded"); + + b.Property("DmResponse"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.Property("WarningsInitialized"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissionv2"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UnmuteAt"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.Property("VoiceChannelId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Forgiven"); + + b.Property("ForgivenBy"); + + b.Property("GuildId"); + + b.Property("Moderator"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Count"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Punishment"); + + b.Property("Time"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + + 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.CommandAlias", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId"); + }); + + 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.Permissionv2", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("Permissions") + .HasForeignKey("GuildConfigId"); + }); + + 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.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId"); + }); + + 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); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170330000613_warning-commands.cs b/src/NadekoBot/Migrations/20170330000613_warning-commands.cs new file mode 100644 index 00000000..5fb96271 --- /dev/null +++ b/src/NadekoBot/Migrations/20170330000613_warning-commands.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class warningcommands : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "WarningsInitialized", + table: "GuildConfigs", + nullable: false, + defaultValue: false); + + migrationBuilder.CreateTable( + name: "Warnings", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DateAdded = table.Column(nullable: true), + Forgiven = table.Column(nullable: false), + ForgivenBy = table.Column(nullable: true), + GuildId = table.Column(nullable: false), + Moderator = table.Column(nullable: true), + Reason = table.Column(nullable: true), + UserId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Warnings", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "WarningPunishment", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Count = table.Column(nullable: false), + DateAdded = table.Column(nullable: true), + GuildConfigId = table.Column(nullable: true), + Punishment = table.Column(nullable: false), + Time = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_WarningPunishment", x => x.Id); + table.ForeignKey( + name: "FK_WarningPunishment_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_WarningPunishment_GuildConfigId", + table: "WarningPunishment", + column: "GuildConfigId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Warnings"); + + migrationBuilder.DropTable( + name: "WarningPunishment"); + + migrationBuilder.DropColumn( + name: "WarningsInitialized", + table: "GuildConfigs"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 18195d44..97e9b393 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -559,6 +559,8 @@ namespace NadekoBot.Migrations b.Property("VoicePlusTextEnabled"); + b.Property("WarningsInitialized"); + b.HasKey("Id"); b.HasIndex("GuildId") @@ -1060,6 +1062,52 @@ namespace NadekoBot.Migrations b.ToTable("WaifuUpdates"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Forgiven"); + + b.Property("ForgivenBy"); + + b.Property("GuildId"); + + b.Property("Moderator"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Count"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Punishment"); + + b.Property("Time"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => { b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") @@ -1285,6 +1333,13 @@ namespace NadekoBot.Migrations .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade); }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId"); + }); } } } diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 4eb9d28c..2f076ae3 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -218,101 +218,6 @@ namespace NadekoBot.Modules.Administration } } - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.BanMembers)] - [RequireBotPermission(GuildPermission.BanMembers)] - public async Task Ban(IGuildUser user, [Remainder] string msg = null) - { - if (Context.User.Id != user.Guild.OwnerId && (user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max())) - { - await ReplyErrorLocalized("hierarchy").ConfigureAwait(false); - return; - } - if (!string.IsNullOrWhiteSpace(msg)) - { - try - { - await user.SendErrorAsync(GetText("bandm", Format.Bold(Context.Guild.Name), msg)); - } - catch - { - // ignored - } - } - - await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false); - await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithTitle("⛔️ " + GetText("banned_user")) - .AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true)) - .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) - .ConfigureAwait(false); - } - - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.KickMembers)] - [RequireUserPermission(GuildPermission.ManageMessages)] - [RequireBotPermission(GuildPermission.BanMembers)] - public async Task Softban(IGuildUser user, [Remainder] string msg = null) - { - if (Context.User.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max()) - { - await ReplyErrorLocalized("hierarchy").ConfigureAwait(false); - return; - } - - if (!string.IsNullOrWhiteSpace(msg)) - { - try - { - await user.SendErrorAsync(GetText("sbdm", Format.Bold(Context.Guild.Name), msg)); - } - catch - { - // ignored - } - } - - await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false); - try { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); } - catch { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); } - - await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithTitle("☣ " + GetText("sb_user")) - .AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true)) - .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) - .ConfigureAwait(false); - } - - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.KickMembers)] - [RequireBotPermission(GuildPermission.KickMembers)] - public async Task Kick(IGuildUser user, [Remainder] string msg = null) - { - if (Context.Message.Author.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max()) - { - await ReplyErrorLocalized("hierarchy").ConfigureAwait(false); - return; - } - if (!string.IsNullOrWhiteSpace(msg)) - { - try - { - await user.SendErrorAsync(GetText("kickdm", Format.Bold(Context.Guild.Name), msg)); - } - catch { } - } - - await user.KickAsync().ConfigureAwait(false); - await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithTitle(GetText("kicked_user")) - .AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true)) - .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) - .ConfigureAwait(false); - } - [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.DeafenMembers)] diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index b61b2722..bc4a0952 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -16,25 +16,26 @@ namespace NadekoBot.Modules.Administration [Group] public class LocalizationCommands : NadekoSubmodule { + //Română, România private ImmutableDictionary supportedLocales { get; } = new Dictionary() { - {"zh-TW", "Chinese (Traditional), China" }, - {"zh-CN", "Chinese (Simplified), China"}, + {"zh-TW", "繁體中文, 台灣" }, + {"zh-CN", "简体中文, 中华人民共和国"}, {"nl-NL", "Dutch, Netherlands"}, {"en-US", "English, United States"}, - {"fr-FR", "French, France"}, + {"fr-FR", "Français, France"}, {"de-DE", "German, Germany"}, {"he-IL", "Hebrew, Israel" }, - {"it-IT", "Italian, Italy" }, + {"it-IT", "Italiano, Italia" }, //{"ja-JP", "Japanese, Japan"}, - {"ko-KR", "Korean, Korea" }, + {"ko-KR", "Korean, South Korea" }, {"nb-NO", "Norwegian (bokmål), Norway"}, - {"pl-PL", "Polish, Poland" }, - {"pt-BR", "Portuguese, Brazil"}, + {"pl-PL", "Polski, Polska" }, + {"pt-BR", "Português Brasileiro, Brasil"}, {"ru-RU", "Russian, Russia"}, - {"sr-Cyrl-RS", "Serbian, Serbia - Cyrillic"}, - {"es-ES", "Spanish, Spain"}, - {"sv-SE", "Swedish, Sweden"}, + {"sr-Cyrl-RS", "Српски, Србија"}, + {"es-ES", "Español, España"}, + {"sv-SE", "Svenska, Sverige"}, {"tr-TR", "Turkish, Turkey" } }.ToImmutableDictionary(); diff --git a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs new file mode 100644 index 00000000..0f54037f --- /dev/null +++ b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs @@ -0,0 +1,358 @@ +using Discord; +using Discord.Commands; +using Discord.WebSocket; +using Microsoft.EntityFrameworkCore; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Services; +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Administration +{ + public partial class Administration + { + [Group] + public class UserPunishCommands : NadekoSubmodule + { + private async Task InternalWarn(IGuild guild, ulong userId, string modName, string reason) + { + if (string.IsNullOrWhiteSpace(reason)) + reason = "-"; + + var guildId = guild.Id; + + var warn = new Warning() + { + UserId = userId, + GuildId = guildId, + Forgiven = false, + Reason = reason, + Moderator = modName, + }; + + int warnings; + List ps; + using (var uow = DbHandler.UnitOfWork()) + { + ps = uow.GuildConfigs.For(guildId, set => set.Include(x => x.WarnPunishments)) + .WarnPunishments; + + uow.Warnings.Add(warn); + + warnings = uow.Warnings + .For(guildId, userId) + .Where(w => !w.Forgiven && w.UserId == userId) + .Count(); + + uow.Complete(); + } + + var p = ps.FirstOrDefault(x => x.Count == warnings); + + if (p != null) + { + var user = await guild.GetUserAsync(userId); + if (user == null) + return; + switch (p.Punishment) + { + case PunishmentAction.Mute: + await MuteCommands.TimedMute(user, TimeSpan.FromMinutes(p.Time)); + break; + case PunishmentAction.Kick: + await user.KickAsync().ConfigureAwait(false); + break; + case PunishmentAction.Ban: + await guild.AddBanAsync(user).ConfigureAwait(false); + break; + default: + break; + } + } + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public async Task Warn(IGuildUser user, [Remainder] string reason = null) + { + try + { + await (await user.CreateDMChannelAsync()).EmbedAsync(new EmbedBuilder().WithErrorColor() + .WithDescription(GetText("warned_on", Context.Guild.ToString())) + .AddField(efb => efb.WithName(GetText("moderator")).WithValue(Context.User.ToString())) + .AddField(efb => efb.WithName(GetText("reason")).WithValue(reason ?? "-"))) + .ConfigureAwait(false); + } + catch { } + await InternalWarn(Context.Guild, user.Id, Context.User.ToString(), reason).ConfigureAwait(false); + + await ReplyConfirmLocalized("user_warned", Format.Bold(user.ToString())).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public Task Warnlog(int page, IGuildUser user) + => Warnlog(page, user.Id); + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public Task Warnlog(IGuildUser user) + => Warnlog(user.Id); + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public Task Warnlog(int page, ulong userId) + => InternalWarnlog(userId, page - 1); + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public Task Warnlog(ulong userId) + => InternalWarnlog(userId, 0); + + private async Task InternalWarnlog(ulong userId, int page) + { + if (page < 0) + return; + Warning[] warnings; + using (var uow = DbHandler.UnitOfWork()) + { + warnings = uow.Warnings.For(Context.Guild.Id, userId); + } + + warnings = warnings.Skip(page * 9) + .Take(9) + .ToArray(); + + var embed = new EmbedBuilder().WithOkColor() + .WithTitle(GetText("warnlog_for", (Context.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString())) + .WithFooter(efb => efb.WithText(GetText("page", page + 1))); + + if (!warnings.Any()) + { + embed.WithDescription(GetText("warnings_none")); + } + else + { + foreach (var w in warnings) + { + var name = GetText("warned_on_by", w.DateAdded.Value.ToString("dd.MM.yyy"), w.DateAdded.Value.ToString("HH:mm"), w.Moderator); + if (w.Forgiven) + name = Format.Strikethrough(name) + GetText("warn_cleared_by", w.ForgivenBy); + + embed.AddField(x => x + .WithName(name) + .WithValue(w.Reason)); + } + } + + await Context.Channel.EmbedAsync(embed); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public Task Warnclear(IGuildUser user) + => Warnclear(user.Id); + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public async Task Warnclear(ulong userId) + { + using (var uow = DbHandler.UnitOfWork()) + { + await uow.Warnings.ForgiveAll(Context.Guild.Id, userId, Context.User.ToString()).ConfigureAwait(false); + uow.Complete(); + } + + await ReplyConfirmLocalized("warnings_cleared", + (Context.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString()).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public async Task WarnPunish(int number, PunishmentAction punish, int time = 0) + { + if (punish != PunishmentAction.Mute && time != 0) + return; + if (number <= 0) + return; + + using (var uow = DbHandler.UnitOfWork()) + { + var ps = uow.GuildConfigs.For(Context.Guild.Id).WarnPunishments; + var p = ps.FirstOrDefault(x => x.Count == number); + + if (p == null) + { + ps.Add(new WarningPunishment() + { + Count = number, + Punishment = punish, + Time = time, + }); + } + else + { + p.Count = number; + p.Punishment = punish; + p.Time = time; + uow._context.Update(p); + } + uow.Complete(); + } + + await ReplyConfirmLocalized("warn_punish_set", + Format.Bold(punish.ToString()), + Format.Bold(number.ToString())).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public async Task WarnPunish(int number) + { + if (number <= 0) + return; + + using (var uow = DbHandler.UnitOfWork()) + { + var ps = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.WarnPunishments)).WarnPunishments; + var p = ps.FirstOrDefault(x => x.Count == number); + + if (p != null) + { + uow._context.Remove(p); + uow.Complete(); + } + } + + await ReplyConfirmLocalized("warn_punish_rem", + Format.Bold(number.ToString())).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task WarnPunishList() + { + WarningPunishment[] ps; + using (var uow = DbHandler.UnitOfWork()) + { + ps = uow.GuildConfigs.For(Context.Guild.Id, gc => gc.Include(x => x.WarnPunishments)) + .WarnPunishments + .OrderBy(x => x.Count) + .ToArray(); + } + + await Context.Channel.SendConfirmAsync( + GetText("warn_punish_list"), + string.Join("\n", ps.Select(x => $"{x.Count} -> {x.Punishment}"))).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + [RequireBotPermission(GuildPermission.BanMembers)] + public async Task Ban(IGuildUser user, [Remainder] string msg = null) + { + if (Context.User.Id != user.Guild.OwnerId && (user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max())) + { + await ReplyErrorLocalized("hierarchy").ConfigureAwait(false); + return; + } + if (!string.IsNullOrWhiteSpace(msg)) + { + try + { + await user.SendErrorAsync(GetText("bandm", Format.Bold(Context.Guild.Name), msg)); + } + catch + { + // ignored + } + } + + await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false); + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle("⛔️ " + GetText("banned_user")) + .AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) + .ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.KickMembers)] + [RequireUserPermission(GuildPermission.ManageMessages)] + [RequireBotPermission(GuildPermission.BanMembers)] + public async Task Softban(IGuildUser user, [Remainder] string msg = null) + { + if (Context.User.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max()) + { + await ReplyErrorLocalized("hierarchy").ConfigureAwait(false); + return; + } + + if (!string.IsNullOrWhiteSpace(msg)) + { + try + { + await user.SendErrorAsync(GetText("sbdm", Format.Bold(Context.Guild.Name), msg)); + } + catch + { + // ignored + } + } + + await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false); + try { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); } + catch { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); } + + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle("☣ " + GetText("sb_user")) + .AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) + .ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.KickMembers)] + [RequireBotPermission(GuildPermission.KickMembers)] + public async Task Kick(IGuildUser user, [Remainder] string msg = null) + { + if (Context.Message.Author.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max()) + { + await ReplyErrorLocalized("hierarchy").ConfigureAwait(false); + return; + } + if (!string.IsNullOrWhiteSpace(msg)) + { + try + { + await user.SendErrorAsync(GetText("kickdm", Format.Bold(Context.Guild.Name), msg)); + } + catch { } + } + + await user.KickAsync().ConfigureAwait(false); + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle(GetText("kicked_user")) + .AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) + .ConfigureAwait(false); + } + } + } +} diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index cc7550b6..bba6abe1 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -9104,6 +9104,141 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to warn. + /// + public static string warn_cmd { + get { + return ResourceManager.GetString("warn_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Warns a user.. + /// + public static string warn_desc { + get { + return ResourceManager.GetString("warn_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}warn @b1nzy`. + /// + public static string warn_usage { + get { + return ResourceManager.GetString("warn_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to warnclear warnc. + /// + public static string warnclear_cmd { + get { + return ResourceManager.GetString("warnclear_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Clears all warnings from a certain user.. + /// + public static string warnclear_desc { + get { + return ResourceManager.GetString("warnclear_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}warnclear @PoorDude`. + /// + public static string warnclear_usage { + get { + return ResourceManager.GetString("warnclear_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to warnlog. + /// + public static string warnlog_cmd { + get { + return ResourceManager.GetString("warnlog_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to See a list of warnings of a certain user.. + /// + public static string warnlog_desc { + get { + return ResourceManager.GetString("warnlog_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}warnlog @b1nzy`. + /// + public static string warnlog_usage { + get { + return ResourceManager.GetString("warnlog_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to warnpunish warnp. + /// + public static string warnpunish_cmd { + get { + return ResourceManager.GetString("warnpunish_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sets a punishment for a certain number of warnings. Provide no punishment to remove.. + /// + public static string warnpunish_desc { + get { + return ResourceManager.GetString("warnpunish_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}warnpunish 5 Ban` or `{0}warnpunish 3`. + /// + public static string warnpunish_usage { + get { + return ResourceManager.GetString("warnpunish_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to warnpunishlist warnpl. + /// + public static string warnpunishlist_cmd { + get { + return ResourceManager.GetString("warnpunishlist_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lists punishments for warnings.. + /// + public static string warnpunishlist_desc { + get { + return ResourceManager.GetString("warnpunishlist_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}warnpunishlist`. + /// + public static string warnpunishlist_usage { + get { + return ResourceManager.GetString("warnpunishlist_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 790df4de..1f236f0a 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3222,4 +3222,49 @@ `{0}alias allin $bf 100 h` or `{0}alias "linux thingy" >loonix Spyware Windows` + + warnlog + + + See a list of warnings of a certain user. + + + `{0}warnlog @b1nzy` + + + warn + + + Warns a user. + + + `{0}warn @b1nzy` + + + warnclear warnc + + + Clears all warnings from a certain user. + + + `{0}warnclear @PoorDude` + + + warnpunishlist warnpl + + + Lists punishments for warnings. + + + `{0}warnpunishlist` + + + warnpunish warnp + + + Sets a punishment for a certain number of warnings. Provide no punishment to remove. + + + `{0}warnpunish 5 Ban` or `{0}warnpunish 3` + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 1b0cd969..b440fe8a 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -736,6 +736,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Moderator. + /// + public static string administration_moderator { + get { + return ResourceManager.GetString("administration_moderator", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} moved from {1} to {2}. /// @@ -907,6 +916,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to page {0}. + /// + public static string administration_page { + get { + return ResourceManager.GetString("administration_page", resourceCulture); + } + } + /// /// Looks up a localized string similar to Error. Most likely I don't have sufficient permissions.. /// @@ -1060,6 +1078,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Reason. + /// + public static string administration_reason { + get { + return ResourceManager.GetString("administration_reason", resourceCulture); + } + } + /// /// Looks up a localized string similar to Successfully removed role {0} from user {1}. /// @@ -1648,6 +1675,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to User {0} has been warned.. + /// + public static string administration_user_warned { + get { + return ResourceManager.GetString("administration_user_warned", resourceCulture); + } + } + /// /// Looks up a localized string similar to Username. /// @@ -1765,6 +1801,87 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to cleared by {0}. + /// + public static string administration_warn_cleared_by { + get { + return ResourceManager.GetString("administration_warn_cleared_by", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Warning punishment list. + /// + public static string administration_warn_punish_list { + get { + return ResourceManager.GetString("administration_warn_punish_list", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Having {0} warnings will no longer trigger a punishment.. + /// + public static string administration_warn_punish_rem { + get { + return ResourceManager.GetString("administration_warn_punish_rem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I will apply {0} punishment to users with {1} warnings.. + /// + public static string administration_warn_punish_set { + get { + return ResourceManager.GetString("administration_warn_punish_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Warned on {0} server. + /// + public static string administration_warned_on { + get { + return ResourceManager.GetString("administration_warned_on", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On {0} at {1} by {2}. + /// + public static string administration_warned_on_by { + get { + return ResourceManager.GetString("administration_warned_on_by", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All warnings have been cleared for {0}.. + /// + public static string administration_warnings_cleared { + get { + return ResourceManager.GetString("administration_warnings_cleared", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No warning on this page.. + /// + public static string administration_warnings_none { + get { + return ResourceManager.GetString("administration_warnings_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Warnlog for {0}. + /// + public static string administration_warnlog_for { + get { + return ResourceManager.GetString("administration_warnlog_for", resourceCulture); + } + } + /// /// Looks up a localized string similar to User {0} from text chat. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 6f8446b9..f8523242 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2278,4 +2278,43 @@ Owner ID: {2} Competitive playtime + + Moderator + + + page {0} + + + Reason + + + User {0} has been warned. + + + Warned on {0} server + + + On {0} at {1} by {2} + + + All warnings have been cleared for {0}. + + + No warning on this page. + + + Warnlog for {0} + + + cleared by {0} + + + Warning punishment list + + + Having {0} warnings will no longer trigger a punishment. + + + I will apply {0} punishment to users with {1} warnings. + \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/IUnitOfWork.cs b/src/NadekoBot/Services/Database/IUnitOfWork.cs index c1c9479e..52cb01cf 100644 --- a/src/NadekoBot/Services/Database/IUnitOfWork.cs +++ b/src/NadekoBot/Services/Database/IUnitOfWork.cs @@ -23,6 +23,7 @@ namespace NadekoBot.Services.Database IPokeGameRepository PokeGame { get; } IWaifuRepository Waifus { get; } IDiscordUserRepository DiscordUsers { get; } + IWarningsRepository Warnings { get; } int Complete(); Task CompleteAsync(); diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs index 00693f16..4fe497c1 100644 --- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs +++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using static NadekoBot.Modules.Administration.Administration; namespace NadekoBot.Services.Database.Models { @@ -72,10 +71,19 @@ namespace NadekoBot.Services.Database.Models public HashSet UnmuteTimers { get; set; } = new HashSet(); public HashSet VcRoleInfos { get; set; } public HashSet CommandAliases { get; set; } = new HashSet(); + public List WarnPunishments { get; set; } = new List(); + public bool WarningsInitialized { get; set; } //public List ProtectionIgnoredChannels { get; set; } = new List(); } + public class WarningPunishment : DbEntity + { + public int Count { get; set; } + public PunishmentAction Punishment { get; set; } + public int Time { get; set; } + } + public class CommandAlias : DbEntity { public string Trigger { get; set; } diff --git a/src/NadekoBot/Services/Database/Models/Warning.cs b/src/NadekoBot/Services/Database/Models/Warning.cs new file mode 100644 index 00000000..e5c8f4ff --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/Warning.cs @@ -0,0 +1,12 @@ +namespace NadekoBot.Services.Database.Models +{ + public class Warning : DbEntity + { + public ulong GuildId { get; set; } + public ulong UserId { get; set; } + public string Reason { get; set; } + public bool Forgiven { get; set; } + public string ForgivenBy { get; set; } + public string Moderator { get; set; } + } +} diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index 4efb6150..a82cfde8 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -40,6 +40,7 @@ namespace NadekoBot.Services.Database public DbSet CurrencyTransactions { get; set; } public DbSet PokeGame { get; set; } public DbSet WaifuUpdates { get; set; } + public DbSet Warnings { get; set; } //logging public DbSet LogSettings { get; set; } @@ -272,6 +273,10 @@ namespace NadekoBot.Services.Database du.HasAlternateKey(w => w.UserId); #endregion + + #region Warnings + var warn = modelBuilder.Entity(); + #endregion } } } diff --git a/src/NadekoBot/Services/Database/Repositories/IWarningsRepository.cs b/src/NadekoBot/Services/Database/Repositories/IWarningsRepository.cs new file mode 100644 index 00000000..2b2e5ac4 --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/IWarningsRepository.cs @@ -0,0 +1,11 @@ +using NadekoBot.Services.Database.Models; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Repositories +{ + public interface IWarningsRepository : IRepository + { + Warning[] For(ulong guildId, ulong userId); + Task ForgiveAll(ulong guildId, ulong userId, string mod); + } +} diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index 7098888d..01a44677 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -12,6 +12,18 @@ namespace NadekoBot.Services.Database.Repositories.Impl { } + private List DefaultWarnPunishments => + new List() { + new WarningPunishment() { + Count = 3, + Punishment = PunishmentAction.Kick + }, + new WarningPunishment() { + Count = 5, + Punishment = PunishmentAction.Ban + } + }; + public IEnumerable GetAllGuildConfigs() => _set.Include(gc => gc.LogSetting) .ThenInclude(ls => ls.IgnoredChannels) @@ -64,10 +76,19 @@ namespace NadekoBot.Services.Database.Repositories.Impl _set.Add((config = new GuildConfig { GuildId = guildId, - Permissions = Permissionv2.GetDefaultPermlist + Permissions = Permissionv2.GetDefaultPermlist, + WarningsInitialized = true, + WarnPunishments = DefaultWarnPunishments, })); _context.SaveChanges(); } + + if (!config.WarningsInitialized) + { + config.WarningsInitialized = true; + config.WarnPunishments = DefaultWarnPunishments; + } + return config; } @@ -82,10 +103,18 @@ namespace NadekoBot.Services.Database.Repositories.Impl _set.Add((config = new GuildConfig { GuildId = guildId, - Permissions = Permissionv2.GetDefaultPermlist + Permissions = Permissionv2.GetDefaultPermlist, + WarningsInitialized = true, + WarnPunishments = DefaultWarnPunishments, })); _context.SaveChanges(); } + + if (!config.WarningsInitialized) + { + config.WarningsInitialized = true; + config.WarnPunishments = DefaultWarnPunishments; + } return config; } diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/WarningsRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/WarningsRepository.cs new file mode 100644 index 00000000..4bf4c293 --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/Impl/WarningsRepository.cs @@ -0,0 +1,37 @@ +using NadekoBot.Services.Database.Models; +using Microsoft.EntityFrameworkCore; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Repositories.Impl +{ + public class WarningsRepository : Repository, IWarningsRepository + { + public WarningsRepository(DbContext context) : base(context) + { + } + + public Warning[] For(ulong guildId, ulong userId) + { + var query = _set.Where(x => x.GuildId == guildId && x.UserId == userId) + .OrderByDescending(x => x.DateAdded); + + return query.ToArray(); + } + + public async Task ForgiveAll(ulong guildId, ulong userId, string mod) + { + await _set.Where(x => x.GuildId == guildId && x.UserId == userId) + .ForEachAsync(x => + { + if (x.Forgiven != true) + { + x.Forgiven = true; + x.ForgivenBy = mod; + } + }) + .ConfigureAwait(false); + } + } +} diff --git a/src/NadekoBot/Services/Database/UnitOfWork.cs b/src/NadekoBot/Services/Database/UnitOfWork.cs index 032c0bb7..02e78a97 100644 --- a/src/NadekoBot/Services/Database/UnitOfWork.cs +++ b/src/NadekoBot/Services/Database/UnitOfWork.cs @@ -54,6 +54,9 @@ namespace NadekoBot.Services.Database private IDiscordUserRepository _discordUsers; public IDiscordUserRepository DiscordUsers => _discordUsers ?? (_discordUsers = new DiscordUserRepository(_context)); + private IWarningsRepository _warnings; + public IWarningsRepository Warnings => _warnings ?? (_warnings = new WarningsRepository(_context)); + public UnitOfWork(NadekoContext context) { _context = context; From 111b4bc4654db1e5eb98f7a9670e0cabb116feb5 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 30 Mar 2017 04:35:24 +0200 Subject: [PATCH 654/746] .unban added --- .../Commands/LocalizationCommands.cs | 4 +- .../Commands/UserPunishCommands.cs | 45 +++++++++++++++++++ .../Resources/CommandStrings.Designer.cs | 27 +++++++++++ src/NadekoBot/Resources/CommandStrings.resx | 9 ++++ .../Resources/ResponseStrings.Designer.cs | 18 ++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 6 +++ 6 files changed, 107 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index bc4a0952..707d2af4 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -24,11 +24,11 @@ namespace NadekoBot.Modules.Administration {"nl-NL", "Dutch, Netherlands"}, {"en-US", "English, United States"}, {"fr-FR", "Français, France"}, - {"de-DE", "German, Germany"}, + {"de-DE", "Deutsch, Deutschland"}, {"he-IL", "Hebrew, Israel" }, {"it-IT", "Italiano, Italia" }, //{"ja-JP", "Japanese, Japan"}, - {"ko-KR", "Korean, South Korea" }, + {"ko-KR", "한국어, 대한민국" }, {"nb-NO", "Norwegian (bokmål), Norway"}, {"pl-PL", "Polski, Polska" }, {"pt-BR", "Português Brasileiro, Brasil"}, diff --git a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs index 0f54037f..53479589 100644 --- a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs @@ -290,6 +290,51 @@ namespace NadekoBot.Modules.Administration .ConfigureAwait(false); } + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + [RequireBotPermission(GuildPermission.BanMembers)] + public async Task Unban([Remainder]string user) + { + var bans = await Context.Guild.GetBansAsync(); + + var bun = bans.FirstOrDefault(x => x.User.ToString().ToLowerInvariant() == user.ToLowerInvariant()); + + if (bun == null) + { + await ReplyErrorLocalized("user_not_found").ConfigureAwait(false); + return; + } + + await UnbanInternal(bun.User).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + [RequireBotPermission(GuildPermission.BanMembers)] + public async Task Unban(ulong userId) + { + var bans = await Context.Guild.GetBansAsync(); + + var bun = bans.FirstOrDefault(x => x.User.Id == userId); + + if (bun == null) + { + await ReplyErrorLocalized("user_not_found").ConfigureAwait(false); + return; + } + + await UnbanInternal(bun.User).ConfigureAwait(false); + } + + private async Task UnbanInternal(IUser user) + { + await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); + + await ReplyConfirmLocalized("unbanned_user", Format.Bold(user.ToString())).ConfigureAwait(false); + } + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.KickMembers)] diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index bba6abe1..61163a92 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -8456,6 +8456,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to unban. + /// + public static string unban_cmd { + get { + return ResourceManager.GetString("unban_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unbans a user with the provided user#discrim or id.. + /// + public static string unban_desc { + get { + return ResourceManager.GetString("unban_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}unban kwoth#1234` or `{0}unban 123123123`. + /// + public static string unban_usage { + get { + return ResourceManager.GetString("unban_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to unclaim ucall uc. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 1f236f0a..db8b3f50 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3240,6 +3240,15 @@ `{0}warn @b1nzy` + + unban + + + Unbans a user with the provided user#discrim or id. + + + `{0}unban kwoth#1234` or `{0}unban 123123123` + warnclear warnc diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index b440fe8a..a8e6ed17 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -1504,6 +1504,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to User {0} has been unbanned.. + /// + public static string administration_unbanned_user { + get { + return ResourceManager.GetString("administration_unbanned_user", resourceCulture); + } + } + /// /// Looks up a localized string similar to Undeafen successful.. /// @@ -1585,6 +1594,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to User not found.. + /// + public static string administration_user_not_found { + get { + return ResourceManager.GetString("administration_user_not_found", resourceCulture); + } + } + /// /// Looks up a localized string similar to User's role added. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index f8523242..9ef50957 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2287,6 +2287,12 @@ Owner ID: {2} Reason + + User {0} has been unbanned. + + + User not found. + User {0} has been warned. From 090ad4f9811caa1d3c07bacb845905ad9d347b26 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 30 Mar 2017 15:53:29 +0200 Subject: [PATCH 655/746] fixed tweezers in hangman, language names are no longer in english --- .../Administration/Commands/LocalizationCommands.cs | 13 +++++++------ .../Modules/Games/Commands/Hangman/HangmanGame.cs | 2 +- src/NadekoBot/data/{hangman.json => hangman2.json} | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) rename src/NadekoBot/data/{hangman.json => hangman2.json} (99%) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 707d2af4..6930ad88 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -17,26 +17,27 @@ namespace NadekoBot.Modules.Administration public class LocalizationCommands : NadekoSubmodule { //Română, România + //Bahasa Indonesia, Indonesia private ImmutableDictionary supportedLocales { get; } = new Dictionary() { {"zh-TW", "繁體中文, 台灣" }, {"zh-CN", "简体中文, 中华人民共和国"}, - {"nl-NL", "Dutch, Netherlands"}, + {"nl-NL", "Nederlands, Nederland"}, {"en-US", "English, United States"}, {"fr-FR", "Français, France"}, {"de-DE", "Deutsch, Deutschland"}, - {"he-IL", "Hebrew, Israel" }, + {"he-IL", "עברית, ישראל"}, {"it-IT", "Italiano, Italia" }, - //{"ja-JP", "Japanese, Japan"}, + //{"ja-JP", "日本語, 日本"}, {"ko-KR", "한국어, 대한민국" }, - {"nb-NO", "Norwegian (bokmål), Norway"}, + {"nb-NO", "Norsk, Norge"}, {"pl-PL", "Polski, Polska" }, {"pt-BR", "Português Brasileiro, Brasil"}, - {"ru-RU", "Russian, Russia"}, + {"ru-RU", "Русский, Россия"}, {"sr-Cyrl-RS", "Српски, Србија"}, {"es-ES", "Español, España"}, {"sv-SE", "Svenska, Sverige"}, - {"tr-TR", "Turkish, Turkey" } + {"tr-TR", "Türkçe, Türkiye"} }.ToImmutableDictionary(); [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index b4b18e97..0f2f3bda 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -15,7 +15,7 @@ namespace NadekoBot.Modules.Games.Hangman { public class HangmanTermPool { - const string termsPath = "data/hangman.json"; + const string termsPath = "data/hangman2.json"; public static IReadOnlyDictionary data { get; } static HangmanTermPool() { diff --git a/src/NadekoBot/data/hangman.json b/src/NadekoBot/data/hangman2.json similarity index 99% rename from src/NadekoBot/data/hangman.json rename to src/NadekoBot/data/hangman2.json index e13fd5ab..b93e6aa5 100644 --- a/src/NadekoBot/data/hangman.json +++ b/src/NadekoBot/data/hangman2.json @@ -3023,7 +3023,7 @@ "ImageUrl": "https://www.randomlists.com/img/things/tv.jpg" }, { - "Word": "twezzers", + "Word": "tweezers", "ImageUrl": "https://www.randomlists.com/img/things/twezzers.jpg" }, { From 324360073bfe00093323edb10d0305d75a14447f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 30 Mar 2017 16:00:27 +0200 Subject: [PATCH 656/746] spelling mistake --- src/NadekoBot/Modules/NadekoModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index d71a2ba9..8b6788dd 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -69,7 +69,7 @@ namespace NadekoBot.Modules LogManager.GetCurrentClassLogger().Warn(lowerModuleTypeName + "_" + key + " key is missing from " + cultureInfo + " response strings. PLEASE REPORT THIS."); text = NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, _usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} not found!"; if (string.IsNullOrWhiteSpace(text)) - return "I can't tell you is the command executed, because there was an error printing out the response. Key '" + + return "I can't tell you if the command is executed, because there was an error printing out the response. Key '" + lowerModuleTypeName + "_" + key + "' " + "is missing from resources. Please report this."; } return text; @@ -84,7 +84,7 @@ namespace NadekoBot.Modules } catch (FormatException) { - return "I cant tell if you command is executed, because there was an error printing out the response. Key '" + + return "I can't tell you if the command is executed, because there was an error printing out the response. Key '" + lowerModuleTypeName + "_" + key + "' " + "is not properly formatted. Please report this."; } } From 9cf03a1fb407cff41fc18917bbf9d73b8d4d4f52 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 30 Mar 2017 20:34:40 +0200 Subject: [PATCH 657/746] Finalized some things. closes #183 and #1059 --- .../Commands/UserPunishCommands.cs | 41 ++++++++++++++----- .../Resources/ResponseStrings.Designer.cs | 18 ++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 6 +++ 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs index 53479589..ded760c2 100644 --- a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs @@ -18,7 +18,7 @@ namespace NadekoBot.Modules.Administration [Group] public class UserPunishCommands : NadekoSubmodule { - private async Task InternalWarn(IGuild guild, ulong userId, string modName, string reason) + private async Task InternalWarn(IGuild guild, ulong userId, string modName, string reason) { if (string.IsNullOrWhiteSpace(reason)) reason = "-"; @@ -34,20 +34,20 @@ namespace NadekoBot.Modules.Administration Moderator = modName, }; - int warnings; + int warnings = 1; List ps; using (var uow = DbHandler.UnitOfWork()) { ps = uow.GuildConfigs.For(guildId, set => set.Include(x => x.WarnPunishments)) .WarnPunishments; - - uow.Warnings.Add(warn); - warnings = uow.Warnings + warnings += uow.Warnings .For(guildId, userId) .Where(w => !w.Forgiven && w.UserId == userId) .Count(); + uow.Warnings.Add(warn); + uow.Complete(); } @@ -57,7 +57,7 @@ namespace NadekoBot.Modules.Administration { var user = await guild.GetUserAsync(userId); if (user == null) - return; + return null; switch (p.Punishment) { case PunishmentAction.Mute: @@ -72,7 +72,10 @@ namespace NadekoBot.Modules.Administration default: break; } + return p.Punishment; } + + return null; } [NadekoCommand, Usage, Description, Aliases] @@ -89,9 +92,16 @@ namespace NadekoBot.Modules.Administration .ConfigureAwait(false); } catch { } - await InternalWarn(Context.Guild, user.Id, Context.User.ToString(), reason).ConfigureAwait(false); + var punishment = await InternalWarn(Context.Guild, user.Id, Context.User.ToString(), reason).ConfigureAwait(false); - await ReplyConfirmLocalized("user_warned", Format.Bold(user.ToString())).ConfigureAwait(false); + if (punishment == null) + { + await ReplyConfirmLocalized("user_warned", Format.Bold(user.ToString())).ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("user_warned_and_punished", Format.Bold(user.ToString()), Format.Bold(punishment.ToString())).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -146,7 +156,7 @@ namespace NadekoBot.Modules.Administration { var name = GetText("warned_on_by", w.DateAdded.Value.ToString("dd.MM.yyy"), w.DateAdded.Value.ToString("HH:mm"), w.Moderator); if (w.Forgiven) - name = Format.Strikethrough(name) + GetText("warn_cleared_by", w.ForgivenBy); + name = Format.Strikethrough(name) + " " + GetText("warn_cleared_by", w.ForgivenBy); embed.AddField(x => x .WithName(name) @@ -175,7 +185,7 @@ namespace NadekoBot.Modules.Administration } await ReplyConfirmLocalized("warnings_cleared", - (Context.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString()).ConfigureAwait(false); + Format.Bold((Context.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString())).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -254,9 +264,18 @@ namespace NadekoBot.Modules.Administration .ToArray(); } + string list; + if (ps.Any()) + { + list = string.Join("\n", ps.Select(x => $"{x.Count} -> {x.Punishment}")); + } + else + { + list = GetText("warnpl_none"); + } await Context.Channel.SendConfirmAsync( GetText("warn_punish_list"), - string.Join("\n", ps.Select(x => $"{x.Count} -> {x.Punishment}"))).ConfigureAwait(false); + list).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index a8e6ed17..34e12752 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -1702,6 +1702,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to User {0} has been warned and {1} punishment has been applied.. + /// + public static string administration_user_warned_and_punished { + get { + return ResourceManager.GetString("administration_user_warned_and_punished", resourceCulture); + } + } + /// /// Looks up a localized string similar to Username. /// @@ -1900,6 +1909,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to No punishments set.. + /// + public static string administration_warnpl_none { + get { + return ResourceManager.GetString("administration_warnpl_none", resourceCulture); + } + } + /// /// Looks up a localized string similar to User {0} from text chat. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 9ef50957..a94761da 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2296,6 +2296,9 @@ Owner ID: {2} User {0} has been warned. + + User {0} has been warned and {1} punishment has been applied. + Warned on {0} server @@ -2311,6 +2314,9 @@ Owner ID: {2} Warnlog for {0} + + No punishments set. + cleared by {0} From 3703e39cc917956f5528b6b57e0b245a15eea2c0 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 31 Mar 2017 14:01:33 +0200 Subject: [PATCH 658/746] -cmds now splits into multiple messages if too long --- src/NadekoBot/Modules/Help/Help.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Help/Help.cs b/src/NadekoBot/Modules/Help/Help.cs index d6ceb1bd..4ca96023 100644 --- a/src/NadekoBot/Modules/Help/Help.cs +++ b/src/NadekoBot/Modules/Help/Help.cs @@ -55,8 +55,14 @@ namespace NadekoBot.Modules.Help await ReplyErrorLocalized("module_not_found").ConfigureAwait(false); return; } + var j = 0; + var groups = cmdsArray.GroupBy(x => j++ / 48).ToArray(); - await channel.SendTableAsync($"📃 **{GetText("list_of_commands")}**\n", cmdsArray, el => $"{el.Aliases.First(),-15} {"["+el.Aliases.Skip(1).FirstOrDefault()+"]",-8}").ConfigureAwait(false); + for (int i = 0; i < groups.Count(); i++) + { + await channel.SendTableAsync(i == 0 ? $"📃 **{GetText("list_of_commands")}**\n" : "", groups.ElementAt(i), el => $"{el.Aliases.First(),-15} {"[" + el.Aliases.Skip(1).FirstOrDefault() + "]",-8}").ConfigureAwait(false); + } + await ConfirmLocalized("commands_instr", Prefix).ConfigureAwait(false); } From 272bf6b85e41f69d355433ca82d738361d800f38 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 31 Mar 2017 14:03:22 +0200 Subject: [PATCH 659/746] Indonesian language completed --- .../Commands/LocalizationCommands.cs | 1 + .../Resources/ResponseStrings.id-ID.resx | 2285 +++++++++++++++++ .../ResponseStrings.sr-Cyrl-RS.Designer.cs | 260 -- 3 files changed, 2286 insertions(+), 260 deletions(-) create mode 100644 src/NadekoBot/Resources/ResponseStrings.id-ID.resx delete mode 100644 src/NadekoBot/Resources/ResponseStrings.sr-Cyrl-RS.Designer.cs diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 6930ad88..2eb70e4c 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -27,6 +27,7 @@ namespace NadekoBot.Modules.Administration {"fr-FR", "Français, France"}, {"de-DE", "Deutsch, Deutschland"}, {"he-IL", "עברית, ישראל"}, + {"id-ID", "Bahasa Indonesia, Indonesia" }, {"it-IT", "Italiano, Italia" }, //{"ja-JP", "日本語, 日本"}, {"ko-KR", "한국어, 대한민국" }, diff --git a/src/NadekoBot/Resources/ResponseStrings.id-ID.resx b/src/NadekoBot/Resources/ResponseStrings.id-ID.resx new file mode 100644 index 00000000..d2f4e2d2 --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.id-ID.resx @@ -0,0 +1,2285 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Markas itu telah diklaim atau dihancurkan. + + + Markas itu telah dihancurkan. + + + Markas itu belum diklaim. + + + **DIHANCURKAN** markas #{0} di sebuah perang melawan {1} + + + {0} telah **MEMBATALKAN KLAIM** markas #{1} di sebuah perang melawan {2} + + + {0} Telah mengklaim sebuah markas #{1} di perang melawan {2} + + + @{0} Anda telah mengklaim markas #{1}. Anda tidak bisa mengklaim lagi. + + + Klaim dari @{0} di sebuah perang melawan {1} telah kadaluarsa. + + + Musuh + + + Info tentang perang melawan {0} + + + Jumlah markas yang salah. + + + Bukan ukuran perang yang benar. + + + Daftar perang aktif. + + + Tidak diklaim. + + + Anda tidak berpartisipasi di perang itu. + + + @{0} Antara anda tidak berpartisipasi di perang itu, atau markas itu telah dihancurkan. + + + Tidak ada perang aktif. + + + Ukuran + + + Perang melawan {0} telah dimulai. + + + Telah membuat perang melawan {0}. + + + Perang melawan {0} telah selesai. + + + Perang itu tidak ada. + + + Perang melawan {0} mulai! + + + Semua reaksi kustom telah dibersihkan. + + + Reaksi kustom telah dihapus. + + + Izin anda kurang. Dibutuhkan kepemilikan Bot untuk reaksi kostum global, dan Administrator untuk reaksi kustom server. + + + Daftar dari semua reaksi kustom. + + + Reaksi kustom. + + + Reaksi kustom baru + + + Tidak ada reaksi kustom yang ditemukan. + + + Tidak ada reaksi kustom ditemukan dengan id itu. + + + Tanggapan. + + + Status reaksi kustom + + + Status dibersihkan untuk reaksi kustom {0}. + + + Tidak ada data untuk aksi itu, aksi tidak dilakukan. + + + Aksi + + + Autohentai berhenti. + + + Tidak ada hasil yang ditemukan. + + + {0} sudah pingsan. + + + {0} sudah memiliki HP penuh. + + + Tipe anda sudah {0} + + + Digunakan {0}{1} di {2}{3} untuk {4} HP. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + Anda tidak bisa menyerang lagi tanpa serangan balik! + + + Anda tidak bisa menyerang diri sendiri. + + + {0} telah pingsan! + + + {0} disembuhkan dengan satu {1} + + + {0} memiliki {1} HP tersisa. + + + Anda tidak bisa menggunakan {0}. Ketik '{1}ml' untuk melihat daftar gerakan yang anda bisa gunakan. + + + Daftar gerakan untuk tipe {0} + + + Itu tidak efektif. + + + Anda tidak memiliki cukup {0} + + + {0} Dihidupkan dengan satu {1} + + + Anda menghidupkan diri sendiri dengan satu {0} + + + Tipe anda telah diganti ke {0} untuk sebuah {1} + + + Itu cukup efektif. + + + Itu sangatlah efektif! + + + Anda menggunakan terlalu banyak gerakan, jadi anda tidak bisa bergerak! + + + Tipe dari {0} adalah {1}. + + + Pengguna tidak ditemukan. + + + Anda pingsan, jadi anda tidak bisa bergerak! + + + **Penetapan role otomatis** ketika user bergabung sekarang telah **non aktif**. + + + **Penetapan role otomatis** ketika user bergabung sekarang telah **aktif**. + + + Lampiran + + + Avatar diubah. + + + Anda telah diban dari server {0}. +Alasan: {1} + + + 'banned' + PLURAL + + + Pengguna 'banned' + + + Nama bot diubah ke {0} + + + Status bot diubah ke {0}. + + + Penghapusan otomatis dari pesan 'bye' telah dimatikan. + + + Pesan 'bye' akan dihapus setelah {0} detik. + + + Pesan 'bye' sekarang: {0} + + + Nyalakan pesan 'bye' dengan menggunakan {0} + + + Pesan tinggal baru tersetel. + Fuzzy + + + Pengumuman tinggal dimatikan. + + + Pengumuman tinggal dinyalakan di channel ini. + + + Nama Channel telah diubah. + + + Nama lama. + + + Topik channel diubah. + + + Dibersihkan. + + + Konten + + + Berhasil membuat peran {0}. + + + Channel teks {0} telah dibuat. + + + Channel suara {0} telah dibuat. + + + Penulian berhasil. + + + Server {0} dihapus + + + Penghapusan otomatis telah diberhentikan karena invokasi pemerintah yang berhasil. + + + Sekarang akan secara otomatis menghapus invokasi perintah yang sukses. + + + Channel teks {0} dihapus. + + + Channel suara {0} dihapus. + + + Pesan dari + + + Berhasil menambahkan donatur baru. Jumlah donasi dari user ini: {0} 👑 + + + Terima kasih untuk orang yang terdaftar dibawah untuk menciptakan proyek ini! + + + Saya akan meneruskan DM kepada semua pemilik. + + + Saya akan meneruskan DM hanya ke pemilik pertama. + + + Saya akan meneruskan DM mulai dari sekarang. + + + Saya akan berhenti meneruskan DM mulai dari sekarang. + + + Penghapusan pesan sapaan otomatis telah dinonaktifkan. + + + Pesan pesan sapaan akan dihapus setelah {0} detik. + + + Pesan sapa DM sekarang: {0} + + + Aktifkan pesan sapa DM dengan mengetik {0} + + + Pesan sapa DM baru telah diset. + + + Pengumuman sapa DM dinonaktifkan. + + + Pengumuman sapa DM diaktifkan. + + + Pesan sapa sekarang: {0} + + + Aktifkan pesan sapa dengan mengetik {0} + + + Pesan sapa baru telah diset. + + + Pengumuman sapa dinonaktifkan. + + + Pengumuman sapa diaktifkan di channel ini. + + + Anda tidak bisa menggunakkan perintah ini pada pengguna dengan peran yang lebih tinggi atau setara dengan anda di dalam hierarki peran. + + + Gambar ditampilkan setelah {0} detik! + + + Format input tidak valid. + + + Parameter tidak valid. + + + {0} telah bergabung {1} + + + Anda telah dikeluarkan dari server (0}. +Alasan: {1} + + + Pengguna dikeluarkan + + + Daftar bahasa-bahasa + + + Bahasa server anda sekarang adalah {0} - {1} + + + Bahasa asli bot sekarang adalah {0} - {1} + + + Bahasa bot di set ke {0} - {1} + + + Gagal mengatur bahasa. Kunjungi bantuan untuk perintah ini. + + + Bahasa perintah ini sekarang di set ke {0} - {1} + + + {0} telah pergi {1} + + + Meninggalkan server {0} + + + Mencatat {0} event di channel ini. + + + Mencatat semua event di channel ini. + + + Pencatatan dinonaktifkan. + + + Event - event catatan yang anda dapat berlangganan: + + + Pencatatan akan mengabaikan {0} + + + Pencatatatn tidak akan mengabaikan {0} + + + Berhenti mencatat event {0}. + + + {0} telah menyebut peran - peran berikut + + + Pesan dari {0} `[Pemilik Bot]`: + + + Pesan terkirim. + + + {0} telah pindah dari {1} ke {2} + + + Pesan dihapus dalam #{0} + + + Pesan diperbarui dalam #{0} + + + Didiamkan. + PLURAL (users have been muted) + + + Didiamkan. + singular "User muted." + + + Kemungkinan besar saya tidak punya izin yang dibutuhkan untuk itu. + + + Peran diam baru telah diset + + + Saya butuh izin **Administrasi** untuk melakukan itu. + + + Pesan baru + + + Nama panggilan baru + + + Topik baru + + + Nama panggilan diubah + + + Tidak dapat menemukan server itu + + + Tidak ada potongan dengan ID itu ditemukan. + + + Pesan lama + + + Nama panggilan lama + + + Topik lama + + + Error. Kemungkinan besar saya tidak punya izin yang cukup. + + + Izin untuk server ini telah diatur ulang. + + + Perlindungan aktif + + + {0} telah **dinonaktifkan** pada server ini. + + + {0} diaktifkan + + + Error. Saya butuh izin ManageRoles + + + Tidak ada perlindungan diaktifkan. + + + Batas user harus diantara {0} dan {1}. + + + Jika {0} atau lebih user bergabung dalam {1} detik, Saya akan {2} mereka. + + + Waktu harus berada diantara {0} dan {1} detik. + + + Berhasil menghapus semua peran dari user {0} + + + Gagal menghapus peran. Saya tidak punya izin. + + + Warna dari peran {0} telah diubah. + + + Peran itu tidak ada. + + + Parameter yang ditentukan tidak valid. + + + Error disebabkan warna tidak valid atau tidak punya izin. + + + Berhasil menghapus peran {0} dari user {1} + + + Gagal menghapus peran. Saya tidak punya izin. + + + Nama peran diubah. + + + Gagal merubah nama peran. Saya tidak punya izin. + + + Anda tidak dapat mengedit peran yang lebih tinggi daripada peran tertinggi anda. + + + Pesan yang diputar: {0} telah dihapus + + + Peran {0} telah ditambahkan ke daftar. + + + {0} tidak ditemukan. Telah dibersihkan. + + + Peran {0} sudah ada di dalam daftar. + + + Ditambahkan. + + + Status bermain berotasi dinonaktifkan. + + + Status bermain berotasi diaktifkan + + + Ini adalah daftar status-status yang berotasi: +{0} + + + Tidak ada status bermain berotasi yang diset. + + + Anda sudah memiliki {0} peran. + + + Anda sudah memiliki {0} peran eksklusif yang ditetapkan sendiri. + + + Peran yang ditetapkan sendiri sekarang eksklusif! + + + Ada {0} peran yang ditetapkan sendiri + + + Peran itu tidak dapat ditetapkan sendiri. + + + Anda tidak memiliki {0} peran. + + + Peran yang ditetapkan sendiri sekarang tidak eksklusif! + + + Saya tidak dapat menambahkan peran itu pada anda. 'Saya tidak dapat menambahkan peran kepada pemilik atau peran lain yang lebih tinggi daripada peran saya di dalam hierarki peran.' + + + {0} telah dihapus dari daftar peran yang dapat ditetapkan sendiri. + + + Anda tidak lagi memiliki peran {0}. + + + Anda sekarang memiliki peran {0}. + + + Berhasil menambahkan peran {0} ke user {1} + + + Gagal menambahkan peran. Saya tidak punya izin. + + + Avatar baru telah diset! + + + Nama channel baru telah diset. + + + Permainan baru telah diset! + + + Aliran baru telah diset! + + + Topik channel baru telah diset! + + + Potongan {0} telah tersambung ulang. + + + Potongan {0} sedang menyambung ulang. + + + Mematikan + + + User tidak dapat mengirim lebih dari {0} pesan setiap {1} detik. + + + Mode lambat dimatikan. + + + Mode lambat dinyalakan. + + + Ban halus (Dikeluarkan) + PLURAL + + + {0} akan mengabaikan channel ini. + + + {0} tidak lagi akan mengabaikan channel ini. + + + Jika user memposting {0} pesan yang sama secara berurutan, Saya akan {1} mereka. + __IgnoredChannels__: {2} + + + Channel teks telah dibuat. + + + Channel teks telah dihancurkan. + + + penulian nonaktif. + + + Non-bisukan + singular + + + Nama pengguna + + + Nama pengguna telah diubah + + + Para pengguna + + + Pengguna dilarang + + + {0} telah **didiamkan** dari chatting. + + + {0} telah **tidak didiamkan** dari chatting. + + + User bergabung + + + User pergi + + + {0} telah **didiamkan** dari chat teks dan suara + + + Peran pengguna telah ditambahkan + + + Peran pengguna telah dihapuskan + + + {0} sekarang adalah {1} + + + {0} telah **tidak didiamkan** dari chat teks dan suara. + + + {0} telah bergabung di channel suara {1} . + + + {0} telah meninggalkan channel suara {1}. + + + {0} berpindah dari channel suara {1} ke {2}. + + + {0} telah **dibisukan** + + + {0} telah di **voice non-bisukan**. + + + Channel suara telah dibuat + + + Channel suara telah dihancurkan + + + Fitur suara + teks dinonaktifkan. + + + Fitur suara + teks diaktfikan. + + + Saya tidak memiliki izin **mengatur peran** dan/atau **mengatur channel**, jadi saya tidak dapat menjalankan 'suara+teks' di server {0}. + + + Anda mengaktifkan/menonaktifkan fitur ini dan **Saya tidak punya izin administrator**. Ini dapat menyebabkan beberapa isu, dan anda harus membersihkan sendiri channel-channel teks setelahnya. + + + Saya membutuhkan setidaknya izin **mengatur peran** dan **mengatur channel** untuk mengaktifkan fitur ini. (lebih memilih izin administrasi) + + + User {0} dari chat teks + + + User {0} dari chat teks dan suara + + + Pengguna {0} dari chat suara + + + Anda telah diban halus dari server {0}. +Alasan: {1} + + + Pengguna telah di unban + + + Migrasi selesai! + + + Error ketika migrasi, cek konsol bot untuk informasi lebih lanjut. + + + Pembaharuan kehadiran + + + Pengguna diban halus + + + Telah menyerahkan {0} ke {1} + + + Semoga lebih beruntung lain kali ^_^ + + + Selamat! Kamu memenangkan {0} karena hasil diatas {1} + + + Deck telah dikocok ulang. + + + Terlemparkan {0}. + User flipped tails. + + + Anda berhasil menebaknya! Anda memenangkan {0} + + + Angka tidak valid tertera. Anda dapat meleparkan 1 sampai {0} koin. + + + Tambahkan reaksi {0} pada pesan ini untuk mendapatkan {1}␣ + + + Event ini akan aktif selama {0} jam. + + + Event reaksi bunga telah dimulai! + + + Telah menghadiahi {0} ke {1} + X has gifted 15 flowers to Y + + + {0} memiliki {1} + X has Y flowers + + + Kepala + + + Leaderboard + + + Diserahkan {0} sampai {1} pengguna dari peran {2}. + + + Anda tidak bisa bertaruh lebih dari {0} + + + Anda tidak bisa bertaruh kurang dari {0} + + + Anda tidak memiliki cukup {0} + + + Tidak ada lagi kartu di dalam deck. + + + Pengguna yang diundi + + + Kamu mendapatkan {0}. + + + Bertaruh + + + WOAAHHHHHH!!! Selamat!!! x{0} + + + Sebuah {0}, x{1} + + + Wow! Beruntung! Three of a kind! x{0} + + + Good job! Dua {0} - bertaruh x{1} + + + Menang + + + User harus mengetikkan kode rahasia untuk mendapatkan {0}. +Berlangsung selama {1} detik. Jangan bilang bilang. Shhh. + + + Event SneakyGame berakhir. {0} pengguna telah menerima hadiah. + + + Event SneakyGameStatus telah dimulai + + + Ekor + + + berhasil mengambil {0} dari {1} + + + tidak dapat mengambil {0} dari{1} karena user itu tidak memiliki {2} sebanyak itu! + + + Kembali ke ToC + + + Hanya untuk pemilik bot + + + Memerlukan izin {0} channel. + + + Anda dapat mendukung project ini di patreon: <{0}> atau paypal: <{1}> + + + Daftar perintah dan alias + + + Daftar perintah telah dibuat ulang. + + + Ketik '{0}h CommandName' untuk melihat bantuan untuk perintah tersebut. Contoh '{0}h >8ball' + + + Saya tidak dapat menemukan perintah itu. Tolong verifikasi perintah itu ada sebelum mencoba lagi. + + + Deskripsi + + + Anda dapat mendukung projek NadekoBot di +Patreon <{0}> atau +Paypal <{1}> +Jangan lupa untuk meninggalkan nama atau ID Discord anda di dalam pesan. + +**Terima kasih**♥️ + + + **Daftar perintah**: <{0}> +**Panduan dan dokumentasi hosting dapat ditemukan disini**: <{1}> + + + Daftar perintah + + + Daftar modul + + + Ketik '{0}cmds ModuleName' untuk mendapatkan daftar perintah di dalam modul tersebut. Contoh '{0}cmds games' + + + Modul tersebut tidak ada. + + + Memerlukan izin {0} server. + + + Daftar isi + + + Penggunaan + + + Autohentai dimulai. Posting ulang setiap {0} detik dengan satu dari tanda berikut: +{1} + + + Tanda + + + Balap hewan + + + Gagal memulai karena tidak cukup peserta. + + + Balapan penuh!! Segera memulai. + + + {0} bergabung sebagai seekor {1} + + + {0} bergabung sebagai seekor {1} dan bertaruh {2}! + + + Ketik {0}jr untuk mengikuti balapan. + + + Dimulai dalam 20 detik atau ketika telah penuh. + + + Memulai dengan {0} peserta. + + + {0} sebagai {1} Memenangkan balapan! + + + {0} sebagai {1} Memenangkan balapan dan {2}! + + + Angka tidak valid. Anda dapat melemparkan {0}-{1} dadu bersamaan. + + + mendapatkan {0} + Someone rolled 35 + + + Dadu yang dilemparkan: {0} + Dice Rolled: 5 + + + Gagal memulai balapan. Balapan lain mungkin sedang berlangsung. + + + Tidak ada balapan di server ini + + + Angka kedua harus lebih besar daripada angka pertama. + + + Perubahan hati + + + Diklaim oleh + + + Perceraian + + + Suka + + + Harga + + + Tidak ada waifu yang belum diklaim. + + + Top Waifu + + + Afinitas anda sudah ditetapkan ke waifu tersebut atau anda sedang mencoba menghilangkan afinitas tanpa mempunyainya. + + + Mengubah afinitas mereka dari {0} ke {1} + +*Ini dapat ditanyakan moralitasnya.* 🤔 + Make sure to get the formatting right, and leave the thinking emoji + + + Anda harus menunggu {0} jam dan {1} menit untuk mengubah afinitas anda lagi. + + + Afinitas anda telah diulang. Anda tidak lagi memiliki seseorang yang anda sukai. + + + ingin menjadi waifu si {0}. Aww <3 + + + mengklaim {0} sebagai waifu dia seharga {1}! + + + Kamu telah menceraikan waifu yang menyukaimu. Kamu monster tanpa hati. +{0} menerima {1} sebagai kompensasi. + + + Anda tidak bisa merubah afinitas ke diri sendiri, anda egois. + + + 🎉 Cinta mereka dipenuhi! 🎉 +Nilai {0} sekarang adalah {1}! + + + Tidak ada waifu semurah itu. Anda harus membayar setidaknya {0} untuk mendapatkan waifu, meskipun harga mereka lebih rendah. + + + Anda harus membayar {0} atau lebih untuk mengklaim waifu tersebut! + + + Waifu itu bukan milikmu. + + + Anda tidak bisa mengklaim diri sendiri. + + + Anda baru saja bercerai. Anda harus menunggu {0} jam dan {1} menit untuk bercerai lagi. + + + Tidak seorangpun + + + Anda telah menceraikan waifu yang tidak menyukaimu. Anda menerima {0} kembali. + + + 8ball + + + Acrophobia + + + Permainan selesai tanpa pengajuan. + + + Tidak ada pilihan dikirim. Permainan selesai tanpa adanya pemenang. + + + Akronim adalah {0}. + + + Permainan Acrophobia sudah berlangsung di channel ini. + + + Permainan dimulai. Buat sebuah kalimat dengan akronim berikut: {0}. + + + Anda memiliki {0} detik untuk mengirimkan pengajuan. + + + {0} mengirim kalimat mereka. (total {1}) + + + Pilih dengan mengetik nomor dari pengajuan. + + + {0} mengirimkan pilihan mereka! + + + Pemenangnya adalah {0} dengan {1} poin. + + + {0} adalah pemenang karena merupakan satu-satunya pengguna yang mengajukan submisi! + + + Pertanyaan + + + Sebuah seri! Keduanya memilih {0} + + + {0} menang! {1} mengalahkan {2} + + + Waktu pengajuan selesai. + + + Animal Race telah berlangsung. + + + Total: {0} Rata - rata: {0} + + + Kategori + + + Cleverbot dinonaktifkan di server ini. + + + Cleverbot diaktifkan di server ini + + + Pembuatan mata uang telah dinonaktifkan di channel ini. + + + Pembuatan mata uang telah diaktifkan di channel ini. + + + {0} acak {1} telah muncul! + plural + + + Sebuah {0} muncul! + + + Gagal memuat pertanyaan + + + Permainan dimulai + + + Permainan Hangman dimulai + + + Permainan Hangman telah berlangsung di channel ini + + + Ada kesalahan saat memulai Hangman + Fuzzy + + + Daftar dari "{0}hangman" tipe istilah: + + + Leaderboard + + + Anda tidak punya cukup {0} + + + Tidak ada hasil + + + memilih {0} + Kwoth picked 5* + + + {0} menanam {1} + Kwoth planted 5* + + + Permainan trivia sedang berlangsung di server ini. + + + Permainan Trivia + + + {0} menebaknya! Jawabannya adalah: {1} + + + Tidak ada trivia yang sedang berlangsung di server ini. + + + {0} memiliki {1} poin + + + Berhenti setelah pertanyaan ini. + + + Waktu habis! Jawaban yang benar adalah {0} + + + {0} berhasil menebaknya dan memenangkan permainan! Jawabannya adalah: {1} + + + Anda tidak bisa bermain melawan diri sendiri. + + + Permainan TicTacToe sedang berlangsung di channel ini. + + + Sebuah seri! + + + telah membuat permainan TicTacToe. + + + {0} telah menang! + + + Mendapat tiga. + Fuzzy + + + TIdak ada jalan tersisa! + + + Waktu habis! + + + Giliran {0} + + + {0} vs {1} + + + Mencoba untuk mengantri {0} lagu... + + + Autoplay dimatikan. + + + Autoplay diaktifkan. + + + Volume awal di set ke {0}% + + + Antrian direktori selesai. + + + fairplay + + + Lagu selesai + + + Fair play dimatikan. + + + Fair play diaktifkan. + + + Dari posisi + + + id + + + Input tidak valid. + + + Sekarang, waktu bermain maksimal tidak memiliki batas. + + + Batas waktu bermain di set ke {0} detik. + + + Antrian maks untuk musik di set ke tidak terbatas. + + + Antrian maks untuk musik di set ke {0} lagu. + + + Anda harus berada di dalam channel suara di server ini. + + + Nama + + + Sekarang memutar + + + Tidak ada pemutar musik yang aktif. + + + Tidak ada hasil pencarian. + + + Pemutaran musik berhenti sebentar. + + + Antrian pemutar musik - Halaman {0}/{1} + + + Memutar lagu + + + `#{0}` - **{1}** oleh *{2}* ({3} lagu) + + + Halaman {1} playlist yang tersimpan + + + Playlist dihapus + + + Gagal untuk menghapus playlist. Playlist tidak ditemukan, atau anda bukan pemilik playlist tersebut. + + + Playlist dengan ID tersebut tidak ditemukan. + + + Antrian playlist selesai. + + + Playlist disimpan + + + Batasan milik {0} + + + Antrian + + + Antrian lagu + + + Antrian lagu dibersihkan + + + Antrian penuh pada {0}/{0}. + + + Menghapus lagu + context: "removed song #5" + + + Mengulang lagu yang diputar saat ini + + + Mengulang playlist + + + Musik diulang + + + Pengulangan musik diberhentikan. + + + Pemutaran kembali lagu dilanjutkan. + + + Pengulangan playlist dibatalkan. + + + Pengulangan playlist diaktifkan + + + Sekarang saya akan mengeluarkan lagu yang sedang diputar, yang telah diputar, yang dihentikan dan menghapus lagu-lagu di channel ini. + + + Lewat ke `{0}:{1}` + + + Lagu diacak + + + Lagu dipindahkan + + + {0}jam {1}menit {2}detik + + + Pada posisi + + + tidak terbatas + + + Volume harus di antara 0 dan 100 + + + Volume diset pada {0}% + + + Menonaktifkan pemakaian dari SEMUA MODUL pada channel {0}. + + + Mengaktifkan pemakaian dari SEMUA MODUL pada channel {0}. + + + Diizinkan + + + Menonaktifkan pemakaian dari SEMUA MODUL untuk peran {0}. + + + Mengaktifkan pemakaian dari SEMUA MODUL untuk peran {0}. + + + Menonaktifkan pemakaian dari SEMUA MODUL di server ini. + + + Mengaktifkan pemakaian dari SEMUA MODUL di server ini. + + + Menonaktifkan pemakaian dari SEMUA MODUL untuk pengguna {0}. + + + Mengaktifkan pemakaian dari SEMUA MODUL untuk pengguna {0}. + + + Mendaftarhitamkan {0} dengan ID {1} + + + Perintah {0} sekarang memiliki jeda selama {1} detik. + + + Perintah {0} sekarang tidak memiliki jeda dan semua jeda yang ada telah dibersihkan. + + + Tidak ada perintah jeda yang ditentukan. + + + Harga perintah + + + Menonaktifkan pemakaian pada {0} {1} pada channel {2}. + + + Mengaktifkan pemakaian pada {0} {1} pada channel {2}. + + + Ditolak + + + Menambahkan kata {0} pada daftar saringan kata. + + + Daftar saringan kata-kata + + + Mencabut kata {0} dari daftar saringan kata-kata. + + + Parameter kedua salah (Harus nomor diantara {0} dan {1}) + + + Penyaringan undangan dinonaktifkan di channel ini. + + + Penyaringan undangan diaktifkan di server ini. + + + Penyaringan undangan dinonaktifkan di server ini. + + + Penyaringan undangan diaktifkan di server ini. + + + Memindakan izin {0} dari #{1} kepada #{2} + + + Tidak dapat menemukan izin pada indeks #{0} + + + Tidak ada biaya di set. + + + perintah + Gen (of command) + + + modul + Gen. (of module) + + + Halaman perizinan {0} + + + Peran izin sekarang adalah {0} + + + Pengguna memerlukan {0} peran untuk dapat merubah izin. + + + Izin tidak ditemukan dalam indeks tersebut. + + + Mencabut izin #{0} - {1} + + + Menonaktifkan pemakaian pada {0} {1} untuk peran {2}. + + + Mengaktifkan pemakaian pada {0} {1} untuk peran {2}. + + + sec. + Short of seconds. + + + Menonaktifkan pemakaian dari {0} {1} pada server ini. + + + Mengaktifkan pemakaian dari {0} {1} pada server ini. + + + Menghapus {0} dengan ID {1} dari daftar hitam + + + tidak dapat diganti + + + Menonaktifkan pemakaian dari {0} {1} untuk {2} pengguna. + + + Mengaktifkan pemakaian dari {0} {1} untuk {2} pengguna. + + + Saya tidak akan lagi memperlihatkan izin peringatan. + + + Sekarang saya akan memperlihatkan izin peringatan. + + + Penyaringan kata pada channel ini dinonaktifkan. + + + Penyaringan kata pada channel ini diaktifkan. + + + Penyaringan kata pada server ini dinonaktifkan. + + + Penyaringan kata pada server ini diaktifkan. + + + Kemampuan + + + Belum ada anime favorit + + + Memulai terjemahan otomatis dari pesan di channel ini. Pesan pengguna akan otomatis dihapus. + + + Terjemahan bahasa otomatis anda telah dicabut. + + + Terjemahan bahasa otomatis anda telah diset pada {0}>{1} + + + Memulai terjemahan otomatis dari pesan-pesan di channel ini. + + + Menghentikan terjemahan otomatis dari pesan-pesan di channel ini. + + + Format input buruk, atau terjadi kesalahan. + + + Tidak dapat menemukan kartu tersebut. + + + fakta + + + Bab + + + Komik # + + + Kekalahan kompetitif + + + Kompetitif yang dimainkan + + + Tingkat kompetitif + + + Kemenangan kompetitif + + + Selesai + + + Kondisi + + + Biaya + + + Tanggal + + + Jelaskan: + + + Terjatuh. + + + Episode + + + Kesalahan terjadi. + + + Contoh + + + Gagal menemukan animu tersebut + + + Gagal menemukan mango tersebut + + + Aliran + + + Gagal menemukan definisi dari label tersebut. + + + Tinggi/Berat + + + {0}m/{1}kg + + + Kelembaban + + + Pencarian gambar untuk: + + + Gagal untuk menemukan film tersebut. + + + Kesalahan sumber atau target bahasa. + + + Candaan tidak dimuat. + + + Lintang/Bujur + + + Tingkat + + + Daftar dari {0}tempat yang ditandai + Don't translate {0}place + + + Lokasi + + + Barang barang sihir tidak dimuat. + + + Profil MAL {0} + + + Pemilik Bot tidak menentukan MashapeApiKey. Anda tidak dapat menggunakan fungsi ini. + + + Min/Maks + + + Channel tidak ditemukan. + + + Hasil tidak ditemukan. + + + Tertahan + + + url asli + + + Sebuah osu! API key diperlukan. + + + Gagal mengambil tanda osu! + + + Ditemukan diantara {0} gambar. Memperlihatkan acak {0}. + + + Pengguna tidak ditemukan! Silahkan cek daerah dan BattleTag sebelum mencoba lagi. + + + Rencana untuk menonton + + + Peron + + + Kemampuan tidak ditemukan. + + + Pokemon tidak ditemukan. + + + Tautan profil: + + + Kualitas + + + Waktu bermain cepat + + + Kemenangan cepat + + + Penilaian + + + Skor: + + + Pencarian untuk: + + + Gagal untuk mempersingkat url tersebut. + + + Url pendek + + + Ada sesuatu yang salah. + + + Harap menentukan parameter pencarian. + + + Status + + + Menyimpan url + + + Streamer {0} sedang offline. + + + Streamer {0} online dengan {1} penonton. + + + Anda mengikuti {0} stream di server ini. + + + Anda tidak mengikuti stream di server ini. + + + Stream tidak ditemukan. + + + Stream mungkin tidak ada. + + + Menghilangkan {0} stream ({1}) dari notifikasi. + + + Saya akan memberitahu channel ini saat status berubah. + + + Matahari terbit + + + Matahari terbenam + + + Temperatur + + + Judul: + + + Top 3 favorit anime: + + + Terjemahan: + + + Tipe + + + Gagal menemukan definisi untuk istilah tersebut + + + Url + + + Penonton + + + Menonton + + + Gagal menemukan istilah tersebut dalam wikia yang ditentukan. + + + Harap memasukkan target wikia, diikuti dengan pertanyaan pencarian. + + + Halaman tidak ditemukan. + + + Kecepatan angin + + + {0} champion paling sering di ban + + + Gagal menyodifikasi kalimat anda. + + + Bergabung + + + `{0}.` {1} [{2:F2}/s] - {3} total + /s and total need to be localized to fit the context - +`1.` + + + Halaman aktifitas #{0} + + + {0} total pengguna. + + + Penulis + + + ID Bot + + + Daftar fungsi di perintah {0)calc + + + {0} dari channel ini adalah {1} + + + Topik channel + + + Perintah dijalankan + + + {0} {1} sama dengan {2} {3} + + + Satuan yang dapat digunakan oleh converter + + + Tidak bisa mengubah {0} menjadi {1}: satuan tidak ditemukan + + + Tidak dapat mengubah {0} ke {1}: tipe untuk tidak sama + + + Dibuat di + + + Mengikuti saluran silang server. + + + Saluran silang server ditinggalkan. + + + Ini adalah token CSC anda + + + emoji kustom + + + Kesalahan + + + Ciri - ciri + + + ID + + + Indeks di luar jarak. + + + Daftar pengguna pada peran {0} + + + Anda tidak diizinkan untuk menggunakan perintah ini pada peran dengan banyak pengguna di dalamnya untuk mencegah penyalahgunaan. + + + Nilai {0} salah. + Invalid months value/ Invalid hours value + + + Bergabung Discord + + + Bergabung server + + + ID: {0} +Anggota: {1} +ID Pemilik: {2} + + + Server tidak ditemukan di halaman tersebut. + + + Daftar dari pengulangan + + + Anggota + + + Memori + + + Pesan + + + Pengulang pesan + + + Nama + + + Nama panggilan + + + Tidak seorangpun memainkan game tersebut + + + Tidak ada pengulangan aktif. + + + Tidak ada peran di halaman ini. + + + Tidak ada pecahan di halaman ini. + + + Tidak ada topik yang ditentukan + + + Pemilik + + + IDs pemilik + + + Kehadiran + + + {0} Servers +{1} Channel Teks +{2} Channel Suara + + + Menghapus semua kutipan dengan {0} kata kunci. + + + Halaman {0} dari kutipan + + + Tidak ada kutipan pada halaman ini. + + + Tidak ditemukan kutipan yang dapat anda hapus. + + + Kutipan ditambahkan + + + Kutipan #{0} dihapus. + + + Wilayah + + + Terdaftar pada + + + Saya akan mengigatakn {0} untuk {1} dalam {2} '({3:d:M.yyyy.} saat {4:HH:mm} + + + Bukan format waktu yang benar. Silakan periksa daftar perintah. + + + Template mengingatkan baru disetel. + + + Mengulang {0} setiap {1} hari, {2} jam dan {3} menit. + + + Daftar pemutaran. + + + Tidak ada pemutaran di server ini. + + + #{0} berhenti. + + + Tidak ada pesan mengulang ditemukan di server ini. + + + Hasil + + + Peran + + + Halaman #{0} dari semua peran di server ini: + + + Halaman #{0} dari peran untuk {1} + + + Tidak ada warna di format benar. Gunakan '#00ff00' sebagai contoh. + + + Memulai pemutaran di peran {0}. + + + Memberhentikan warna memutar untuk peran {0} + + + {0} pada server ini adalah {1} + + + Info server + + + Pecahan + + + Statistik pecahan + + + Pecahan **#{0}** sedang di dalam keadaan {1} di {2} server. + + + **Nama:** {0} **Tautan:** {1} + + + Emojis khusus tidak ditemukan. + + + Memainkan {0} lagu, {1} menunggu + + + Channel teks + + + Ini adalah tautan untuk ruangan anda: + + + Uptime + + + {0} dari pengguna {1} adalah {2} + Id of the user kwoth#1234 is 123123123123 + + + Pengguna + + + Channel suara + + + Anda telah bergabung pada perlombaan ini! + + + Hasil pemilihan saat ini + + + Tidak ada suara terkirim. + + + Pemilihan telah dimulai di server ini. + + + 📃 {0} telah membuat pemilihan yang memerlukan perhatian anda: + + + '{0}.' {1} dengan {2} suara. + + + {0} memilih. + Kwoth voted. + + + Kirim saya pesan pribadi dengan angka yang sesuai dari jawaban. + + + Kirim pesan dengan menggunakan nomor dari jawaban. + + + Terima kasih telah memilih, {0} + + + {0} total suara dikirim. + + + Mengambil barang tersebut dengan mengetik `{0}ambil` + + + Ambil dengan mengetik '{0}pick' + + + Pengguna tidak ditemukan. + + + halaman {0} + + + Anda harus berada pada channel suara di server ini. + + + Tidak ada peran untuk saluran suara. + + + {0} telah **dibisukan** dari teks dan saluran suara selama {1} menit. + + + Pengguna yang bergabung {0} channel suara akan mendapatkan peran {1}. + + + Pengguna yang bergabung {0} channel suara tidak lagi mendapatkan peran. + + + Peran channel suara + + + Mereaksi reaksi kustom menggunakan pesan dengan id {0} tidak akan dihapus secara otomatis. + + + Mereaksikan reaksi kustom menggunakan pesan dengan id {0} akan dihapus secara otomatis. + + + Pesan respon untuk reaksi kustom dengan id {0} tidak akan dikirim sebagai DM. + + + Pesan respon untuk reaksi kustom dengan id {0} akan dikirim sebagai DM. + + + Alias tidak ditemukan + + + Mengetik {0} sekarang akan menjadi alias dari {1}. + + + Daftar alias + + + Perintah {0} sekarang tidak memiliki alias. + + + Perintah {0} tidak mempunyai alias. + + + Waktu bermain kompetitif + + + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-Cyrl-RS.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.sr-Cyrl-RS.Designer.cs deleted file mode 100644 index 4d43d571..00000000 --- a/src/NadekoBot/Resources/ResponseStrings.sr-Cyrl-RS.Designer.cs +++ /dev/null @@ -1,260 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace NadekoBot.Resources { - using System; - using System.Reflection; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class ResponseStrings_sr_SP { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - internal ResponseStrings_sr_SP() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NadekoBot.Resources.ResponseStrings-sr-SP", typeof(ResponseStrings_sr_SP).GetTypeInfo().Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to {0} has already fainted.. - /// - public static string pokemon_already_fainted { - get { - return ResourceManager.GetString("pokemon_already_fainted", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} already has full HP.. - /// - public static string pokemon_already_full { - get { - return ResourceManager.GetString("pokemon_already_full", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Your type is already {0}. - /// - public static string pokemon_already_that_type { - get { - return ResourceManager.GetString("pokemon_already_that_type", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to used {0}{1} on {2}{3} for {4} damage.. - /// - public static string pokemon_attack { - get { - return ResourceManager.GetString("pokemon_attack", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You can't attack again without retaliation!. - /// - public static string pokemon_cant_attack_again { - get { - return ResourceManager.GetString("pokemon_cant_attack_again", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You can't attack yourself.. - /// - public static string pokemon_cant_attack_yourself { - get { - return ResourceManager.GetString("pokemon_cant_attack_yourself", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} has fainted!. - /// - public static string pokemon_fainted { - get { - return ResourceManager.GetString("pokemon_fainted", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to healed {0} with one {1}. - /// - public static string pokemon_healed { - get { - return ResourceManager.GetString("pokemon_healed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} has {1} HP remaining.. - /// - public static string pokemon_hp_remaining { - get { - return ResourceManager.GetString("pokemon_hp_remaining", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You can't use {0}. Type `{1}ml` to see a list of moves you can use.. - /// - public static string pokemon_invalid_move { - get { - return ResourceManager.GetString("pokemon_invalid_move", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Movelist for {0} type. - /// - public static string pokemon_moves { - get { - return ResourceManager.GetString("pokemon_moves", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You don't have enough {0}. - /// - public static string pokemon_no_currency { - get { - return ResourceManager.GetString("pokemon_no_currency", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to It's not effective.. - /// - public static string pokemon_not_effective { - get { - return ResourceManager.GetString("pokemon_not_effective", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to revived {0} with one {1}. - /// - public static string pokemon_revive_other { - get { - return ResourceManager.GetString("pokemon_revive_other", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You revived yourself with one {0}. - /// - public static string pokemon_revive_yourself { - get { - return ResourceManager.GetString("pokemon_revive_yourself", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Your type has been changed to {0} for a {1}. - /// - public static string pokemon_settype_success { - get { - return ResourceManager.GetString("pokemon_settype_success", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to It's somewhat effective.. - /// - public static string pokemon_somewhat_effective { - get { - return ResourceManager.GetString("pokemon_somewhat_effective", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to It's super effective!. - /// - public static string pokemon_super_effective { - get { - return ResourceManager.GetString("pokemon_super_effective", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You used too many moves in a row, so you can't move!. - /// - public static string pokemon_too_many_moves { - get { - return ResourceManager.GetString("pokemon_too_many_moves", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Type of {0} is {1}. - /// - public static string pokemon_type_of_user { - get { - return ResourceManager.GetString("pokemon_type_of_user", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User not found.. - /// - public static string pokemon_user_not_found { - get { - return ResourceManager.GetString("pokemon_user_not_found", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You fainted, so you are not able to move!. - /// - public static string pokemon_you_fainted { - get { - return ResourceManager.GetString("pokemon_you_fainted", resourceCulture); - } - } - } -} From 0a7bbd60f77870e8f3e41334a4a19e1a4f14adf0 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 31 Mar 2017 14:07:18 +0200 Subject: [PATCH 660/746] Startup commands added. Closes #195; .sclist .scadd .scrm .scclr. Won't support music commands atm, but that can come in the future, there is support for it (your current voice channel is recorded when adding) --- .../Attributes/OwnerOnlyAttribute.cs | 2 +- ...0170331093025_startup-commands.Designer.cs | 1385 +++++++++++++++++ .../20170331093025_startup-commands.cs | 51 + .../NadekoSqliteContextModelSnapshot.cs | 39 + .../Modules/Administration/Administration.cs | 2 +- .../Administration/Commands/SelfCommands.cs | 168 +- .../Commands/UserPunishCommands.cs | 5 +- .../CustomReactions/CustomReactions.cs | 2 +- .../Games/Commands/CleverBotCommands.cs | 2 +- .../Resources/CommandStrings.Designer.cs | 135 ++ src/NadekoBot/Resources/CommandStrings.resx | 45 + .../Resources/ResponseStrings.Designer.cs | 72 + src/NadekoBot/Resources/ResponseStrings.resx | 24 + src/NadekoBot/Services/CommandHandler.cs | 274 ++-- .../Services/Database/Models/BotConfig.cs | 13 + .../Repositories/IBotConfigRepository.cs | 7 +- .../Repositories/Impl/BotConfigRepository.cs | 11 +- 17 files changed, 2090 insertions(+), 147 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170331093025_startup-commands.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170331093025_startup-commands.cs diff --git a/src/NadekoBot/Attributes/OwnerOnlyAttribute.cs b/src/NadekoBot/Attributes/OwnerOnlyAttribute.cs index 410a24af..eefc489c 100644 --- a/src/NadekoBot/Attributes/OwnerOnlyAttribute.cs +++ b/src/NadekoBot/Attributes/OwnerOnlyAttribute.cs @@ -6,6 +6,6 @@ namespace NadekoBot.Attributes public class OwnerOnlyAttribute : PreconditionAttribute { public override Task CheckPermissions(ICommandContext context, CommandInfo executingCommand,IDependencyMap depMap) => - Task.FromResult((NadekoBot.Credentials.IsOwner(context.User) ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Not owner"))); + Task.FromResult((NadekoBot.Credentials.IsOwner(context.User) || NadekoBot.Client.CurrentUser.Id == context.User.Id ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Not owner"))); } } \ No newline at end of file diff --git a/src/NadekoBot/Migrations/20170331093025_startup-commands.Designer.cs b/src/NadekoBot/Migrations/20170331093025_startup-commands.Designer.cs new file mode 100644 index 00000000..a91943d7 --- /dev/null +++ b/src/NadekoBot/Migrations/20170331093025_startup-commands.Designer.cs @@ -0,0 +1,1385 @@ +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("20170331093025_startup-commands")] + partial class startupcommands + { + 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("DateAdded"); + + 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.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Mapping"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("AutoDeleteTrigger"); + + b.Property("DateAdded"); + + b.Property("DmResponse"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.Property("WarningsInitialized"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissionv2"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ChannelId"); + + b.Property("ChannelName"); + + b.Property("CommandText"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("GuildName"); + + b.Property("Index"); + + b.Property("VoiceChannelId"); + + b.Property("VoiceChannelName"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("StartupCommand"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UnmuteAt"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.Property("VoiceChannelId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Forgiven"); + + b.Property("ForgivenBy"); + + b.Property("GuildId"); + + b.Property("Moderator"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Count"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Punishment"); + + b.Property("Time"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + + 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.CommandAlias", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId"); + }); + + 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.Permissionv2", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("Permissions") + .HasForeignKey("GuildConfigId"); + }); + + 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.StartupCommand", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("StartupCommands") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId"); + }); + + 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); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170331093025_startup-commands.cs b/src/NadekoBot/Migrations/20170331093025_startup-commands.cs new file mode 100644 index 00000000..d3cd52a9 --- /dev/null +++ b/src/NadekoBot/Migrations/20170331093025_startup-commands.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class startupcommands : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "StartupCommand", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + BotConfigId = table.Column(nullable: true), + ChannelId = table.Column(nullable: false), + ChannelName = table.Column(nullable: true), + CommandText = table.Column(nullable: true), + DateAdded = table.Column(nullable: true), + GuildId = table.Column(nullable: true), + GuildName = table.Column(nullable: true), + Index = table.Column(nullable: false), + VoiceChannelId = table.Column(nullable: true), + VoiceChannelName = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_StartupCommand", x => x.Id); + table.ForeignKey( + name: "FK_StartupCommand_BotConfig_BotConfigId", + column: x => x.BotConfigId, + principalTable: "BotConfig", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_StartupCommand_BotConfigId", + table: "StartupCommand", + column: "BotConfigId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "StartupCommand"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 97e9b393..83771957 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -950,6 +950,38 @@ namespace NadekoBot.Migrations b.ToTable("SelfAssignableRoles"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ChannelId"); + + b.Property("ChannelName"); + + b.Property("CommandText"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("GuildName"); + + b.Property("Index"); + + b.Property("VoiceChannelId"); + + b.Property("VoiceChannelName"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("StartupCommand"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => { b.Property("Id") @@ -1288,6 +1320,13 @@ namespace NadekoBot.Migrations .HasForeignKey("BotConfigId"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("StartupCommands") + .HasForeignKey("BotConfigId"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => { b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 2f076ae3..905243ba 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -32,7 +32,7 @@ namespace NadekoBot.Modules.Administration } - private static Task DelMsgOnCmd_Handler(SocketUserMessage msg, CommandInfo cmd) + private static Task DelMsgOnCmd_Handler(IUserMessage msg, CommandInfo cmd) { var _ = Task.Run(async () => { diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index 89d23094..3af86611 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -10,6 +10,8 @@ using System.Net.Http; using System.Threading.Tasks; using Discord.WebSocket; using NadekoBot.Services; +using NadekoBot.Services.Database.Models; +using Microsoft.EntityFrameworkCore; namespace NadekoBot.Modules.Administration { @@ -31,6 +33,166 @@ namespace NadekoBot.Modules.Administration _forwardDMs = config.ForwardMessages; _forwardDMsToAllOwners = config.ForwardToAllOwners; } + + var _ = Task.Run(async () => + { +#if !GLOBAL_NADEKO + await Task.Delay(2000); +#else + await Task.Delay(10000); +#endif + foreach (var cmd in NadekoBot.BotConfig.StartupCommands) + { + if (cmd.GuildId != null) + { + var guild = NadekoBot.Client.GetGuild(cmd.GuildId.Value); + var channel = guild?.GetChannel(cmd.ChannelId) as SocketTextChannel; + if (channel == null) + continue; + + try + { + var msg = await channel.SendMessageAsync(cmd.CommandText).ConfigureAwait(false); + await NadekoBot.CommandHandler.TryRunCommand(guild, channel, msg).ConfigureAwait(false); + //msg.DeleteAfter(5); + } + catch { } + } + } + }); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task StartupCommandAdd([Remainder] string cmdText) + { + var guser = ((IGuildUser)Context.User); + var cmd = new StartupCommand() + { + CommandText = cmdText, + ChannelId = Context.Channel.Id, + ChannelName = Context.Channel.Name, + GuildId = Context.Guild?.Id, + GuildName = Context.Guild?.Name, + VoiceChannelId = guser.VoiceChannel?.Id, + VoiceChannelName = guser.VoiceChannel?.Name, + }; + using (var uow = DbHandler.UnitOfWork()) + { + uow.BotConfig + .GetOrCreate(set => set.Include(x => x.StartupCommands)) + .StartupCommands.Add(cmd); + await uow.CompleteAsync().ConfigureAwait(false); + } + + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle(GetText("scadd")) + .AddField(efb => efb.WithName(GetText("server")) + .WithValue(cmd.GuildId == null ? $"-" : $"{cmd.GuildName}/{cmd.GuildId}").WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("channel")) + .WithValue($"{cmd.ChannelName}/{cmd.ChannelId}").WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("command_text")) + .WithValue(cmdText).WithIsInline(false))); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task StartupCommands(int page = 1) + { + if (page < 1) + return; + page -= 1; + IEnumerable scmds; + using (var uow = DbHandler.UnitOfWork()) + { + scmds = uow.BotConfig + .GetOrCreate(set => set.Include(x => x.StartupCommands)) + .StartupCommands + .OrderBy(x => x.Id) + .ToArray(); + } + scmds = scmds.Skip(page * 5).Take(5); + if (!scmds.Any()) + { + await ReplyErrorLocalized("startcmdlist_none").ConfigureAwait(false); + } + else + { + await Context.Channel.SendConfirmAsync("", string.Join("\n--\n", scmds.Select(x => + { + string str = Format.Code(GetText("server")) + ": " + (x.GuildId == null ? "-" : x.GuildName + "/" + x.GuildId); + + str += $@" +{Format.Code(GetText("channel"))}: {x.ChannelName}/{x.ChannelId} +{Format.Code(GetText("command_text"))}: {x.CommandText}"; + return str; + })),footer: GetText("page", page + 1)) + .ConfigureAwait(false); + } + } + + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task Wait(int miliseconds) + { + if (miliseconds <= 0) + return; + Context.Message.DeleteAfter(0); + try + { + var msg = await Context.Channel.SendConfirmAsync($"⏲ {miliseconds}ms") + .ConfigureAwait(false); + msg.DeleteAfter(miliseconds / 1000); + } + catch { } + + await Task.Delay(miliseconds); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task StartupCommandRemove([Remainder] string cmdText) + { + StartupCommand cmd; + using (var uow = DbHandler.UnitOfWork()) + { + var cmds = uow.BotConfig + .GetOrCreate(set => set.Include(x => x.StartupCommands)) + .StartupCommands; + cmd = cmds + .FirstOrDefault(x => x.CommandText.ToLowerInvariant() == cmdText.ToLowerInvariant()); + + if (cmd != null) + { + cmds.Remove(cmd); + await uow.CompleteAsync().ConfigureAwait(false); + } + } + + if(cmd == null) + await ReplyErrorLocalized("scrm_fail").ConfigureAwait(false); + else + await ReplyConfirmLocalized("scrm").ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task StartupCommandsClear() + { + using (var uow = DbHandler.UnitOfWork()) + { + uow.BotConfig + .GetOrCreate(set => set.Include(x => x.StartupCommands)) + .StartupCommands + .Clear(); + uow.Complete(); + } + + await ReplyConfirmLocalized("startcmds_cleared").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -68,7 +230,7 @@ namespace NadekoBot.Modules.Administration } - public static async Task HandleDmForwarding(SocketMessage msg, List ownerChannels) + public static async Task HandleDmForwarding(IUserMessage msg, List ownerChannels) { if (_forwardDMs && ownerChannels.Any()) { @@ -157,7 +319,7 @@ namespace NadekoBot.Modules.Administration else { await server.DeleteAsync().ConfigureAwait(false); - await ReplyConfirmLocalized("deleted_server",Format.Bold(server.Name)).ConfigureAwait(false); + await ReplyConfirmLocalized("deleted_server", Format.Bold(server.Name)).ConfigureAwait(false); } } @@ -332,4 +494,4 @@ namespace NadekoBot.Modules.Administration } } } -} +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs index ded760c2..f37b864c 100644 --- a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs @@ -61,7 +61,10 @@ namespace NadekoBot.Modules.Administration switch (p.Punishment) { case PunishmentAction.Mute: - await MuteCommands.TimedMute(user, TimeSpan.FromMinutes(p.Time)); + if (p.Time == 0) + await MuteCommands.MuteUser(user).ConfigureAwait(false); + else + await MuteCommands.TimedMute(user, TimeSpan.FromMinutes(p.Time)).ConfigureAwait(false); break; case PunishmentAction.Kick: await user.KickAsync().ConfigureAwait(false); diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index f28a7bc9..ac6fd4c9 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -59,7 +59,7 @@ namespace NadekoBot.Modules.CustomReactions public void ClearStats() => ReactionStats.Clear(); - public static CustomReaction TryGetCustomReaction(SocketUserMessage umsg) + public static CustomReaction TryGetCustomReaction(IUserMessage umsg) { var channel = umsg.Channel as SocketTextChannel; if (channel == null) diff --git a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs index 0e85e4b0..fd426be3 100644 --- a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs @@ -40,7 +40,7 @@ namespace NadekoBot.Modules.Games _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); } - public static async Task TryAsk(SocketUserMessage msg) + public static async Task TryAsk(IUserMessage msg) { var channel = msg.Channel as ITextChannel; diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 61163a92..20c12253 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -7889,6 +7889,114 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to scadd. + /// + public static string startupcommandadd_cmd { + get { + return ResourceManager.GetString("startupcommandadd_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Adds a command to the list of commands which will be executed automatically in the current channel, in the order they were added in, by the bot when it startups up.. + /// + public static string startupcommandadd_desc { + get { + return ResourceManager.GetString("startupcommandadd_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}scadd .stats`. + /// + public static string startupcommandadd_usage { + get { + return ResourceManager.GetString("startupcommandadd_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to scrm. + /// + public static string startupcommandremove_cmd { + get { + return ResourceManager.GetString("startupcommandremove_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removes a startup command with the provided command text.. + /// + public static string startupcommandremove_desc { + get { + return ResourceManager.GetString("startupcommandremove_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}scrm .stats`. + /// + public static string startupcommandremove_usage { + get { + return ResourceManager.GetString("startupcommandremove_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to sclist. + /// + public static string startupcommands_cmd { + get { + return ResourceManager.GetString("startupcommands_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lists all startup commands in the order they will be executed in.. + /// + public static string startupcommands_desc { + get { + return ResourceManager.GetString("startupcommands_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}sclist`. + /// + public static string startupcommands_usage { + get { + return ResourceManager.GetString("startupcommands_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to scclr. + /// + public static string startupcommandsclear_cmd { + get { + return ResourceManager.GetString("startupcommandsclear_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removes all startup commands.. + /// + public static string startupcommandsclear_desc { + get { + return ResourceManager.GetString("startupcommandsclear_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}scclr`. + /// + public static string startupcommandsclear_usage { + get { + return ResourceManager.GetString("startupcommandsclear_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to startwar sw. /// @@ -9131,6 +9239,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to wait. + /// + public static string wait_cmd { + get { + return ResourceManager.GetString("wait_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Used only as a startup command. Waits a certain number of miliseconds before continuing the execution of the following startup commands.. + /// + public static string wait_desc { + get { + return ResourceManager.GetString("wait_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}wait 3000`. + /// + public static string wait_usage { + get { + return ResourceManager.GetString("wait_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to warn. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index db8b3f50..5d1d0539 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3240,6 +3240,42 @@ `{0}warn @b1nzy` + + scadd + + + Adds a command to the list of commands which will be executed automatically in the current channel, in the order they were added in, by the bot when it startups up. + + + `{0}scadd .stats` + + + scrm + + + Removes a startup command with the provided command text. + + + `{0}scrm .stats` + + + scclr + + + Removes all startup commands. + + + `{0}scclr` + + + sclist + + + Lists all startup commands in the order they will be executed in. + + + `{0}sclist` + unban @@ -3249,6 +3285,15 @@ `{0}unban kwoth#1234` or `{0}unban 123123123` + + wait + + + Used only as a startup command. Waits a certain number of miliseconds before continuing the execution of the following startup commands. + + + `{0}wait 3000` + warnclear warnc diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 34e12752..ea980b1f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -231,6 +231,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Channel. + /// + public static string administration_channel { + get { + return ResourceManager.GetString("administration_channel", resourceCulture); + } + } + /// /// Looks up a localized string similar to Cleaned up.. /// @@ -240,6 +249,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Command Text. + /// + public static string administration_command_text { + get { + return ResourceManager.GetString("administration_command_text", resourceCulture); + } + } + /// /// Looks up a localized string similar to Content. /// @@ -1233,6 +1251,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to New startup command added.. + /// + public static string administration_scadd { + get { + return ResourceManager.GetString("administration_scadd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Startup command successfully removed.. + /// + public static string administration_scrm { + get { + return ResourceManager.GetString("administration_scrm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Startup command not found.. + /// + public static string administration_scrm_fail { + get { + return ResourceManager.GetString("administration_scrm_fail", resourceCulture); + } + } + /// /// Looks up a localized string similar to You already have {0} role.. /// @@ -1332,6 +1377,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Server. + /// + public static string administration_server { + get { + return ResourceManager.GetString("administration_server", resourceCulture); + } + } + /// /// Looks up a localized string similar to New avatar set!. /// @@ -1486,6 +1540,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to No startup commands on this page.. + /// + public static string administration_startcmdlist_none { + get { + return ResourceManager.GetString("administration_startcmdlist_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cleared all startup commands.. + /// + public static string administration_startcmds_cleared { + get { + return ResourceManager.GetString("administration_startcmds_cleared", resourceCulture); + } + } + /// /// Looks up a localized string similar to Text channel created.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index a94761da..92087d6b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2278,6 +2278,12 @@ Owner ID: {2} Competitive playtime + + Channel + + + Command Text + Moderator @@ -2287,6 +2293,24 @@ Owner ID: {2} Reason + + New startup command added. + + + Startup command successfully removed. + + + Startup command not found. + + + Server + + + No startup commands on this page. + + + Cleared all startup commands. + User {0} has been unbanned. diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 17521cab..31f30932 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -37,7 +37,7 @@ namespace NadekoBot.Services private List ownerChannels { get; set; } = new List(); - public event Func CommandExecuted = delegate { return Task.CompletedTask; }; + public event Func CommandExecuted = delegate { return Task.CompletedTask; }; //userid/msg count public ConcurrentDictionary UserMessagesSent { get; } = new ConcurrentDictionary(); @@ -109,7 +109,7 @@ namespace NadekoBot.Services return Task.CompletedTask; } - private async Task TryRunCleverbot(SocketUserMessage usrMsg, IGuild guild) + private async Task TryRunCleverbot(IUserMessage usrMsg, IGuild guild) { if (guild == null) return false; @@ -130,14 +130,13 @@ namespace NadekoBot.Services return false; } - private bool IsBlacklisted(IGuild guild, SocketUserMessage usrMsg) => - usrMsg.Author?.Id == 193022505026453504 || // he requested to be blacklisted from self-hosted bots + private bool IsBlacklisted(IGuild guild, IUserMessage usrMsg) => (guild != null && BlacklistCommands.BlacklistedGuilds.Contains(guild.Id)) || BlacklistCommands.BlacklistedChannels.Contains(usrMsg.Channel.Id) || BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id); private const float _oneThousandth = 1.0f / 1000; - private Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int exec1, int exec2, int exec3, int total) + private Task LogSuccessfulExecution(IUserMessage usrMsg, ExecuteCommandResult exec, ITextChannel channel, int exec1, int exec2, int exec3, int total) { _log.Info("Command Executed after {4}/{5}/{6}/{7}s\n\t" + "User: {0}\n\t" + @@ -156,7 +155,7 @@ namespace NadekoBot.Services return Task.CompletedTask; } - private void LogErroredExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int exec1, int exec2, int exec3, int total) + private void LogErroredExecution(IUserMessage usrMsg, ExecuteCommandResult exec, ITextChannel channel, int exec1, int exec2, int exec3, int total) { _log.Warn("Command Errored after {5}/{6}/{7}/{8}s\n\t" + "User: {0}\n\t" + @@ -176,7 +175,7 @@ namespace NadekoBot.Services ); } - private async Task InviteFiltered(IGuild guild, SocketUserMessage usrMsg) + private async Task InviteFiltered(IGuild guild, IUserMessage usrMsg) { if ((Permissions.FilterCommands.InviteFilteringChannels.Contains(usrMsg.Channel.Id) || Permissions.FilterCommands.InviteFilteringServers.Contains(guild.Id)) && @@ -196,7 +195,7 @@ namespace NadekoBot.Services return false; } - private async Task WordFiltered(IGuild guild, SocketUserMessage usrMsg) + private async Task WordFiltered(IGuild guild, IUserMessage usrMsg) { var filteredChannelWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id) ?? new ConcurrentHashSet(); var filteredServerWords = Permissions.FilterCommands.FilteredWordsForServer(guild.Id) ?? new ConcurrentHashSet(); @@ -232,8 +231,6 @@ namespace NadekoBot.Services if (msg.Author.IsBot || !NadekoBot.Ready) //no bots, wait until bot connected and initialized return; - var execTime = Environment.TickCount; - var usrMsg = msg as SocketUserMessage; if (usrMsg == null) //has to be an user message, not system/other messages. return; @@ -248,131 +245,7 @@ namespace NadekoBot.Services var channel = msg.Channel as SocketTextChannel; var guild = channel?.Guild; - if (guild != null && guild.OwnerId != msg.Author.Id) - { - if (await InviteFiltered(guild, usrMsg).ConfigureAwait(false)) - return; - - if (await WordFiltered(guild, usrMsg).ConfigureAwait(false)) - return; - } - - if (IsBlacklisted(guild, usrMsg)) - return; - - var exec1 = Environment.TickCount - execTime; - - var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false); - if (cleverBotRan) - return; - - var exec2 = Environment.TickCount - execTime; - - // maybe this message is a custom reaction - // todo log custom reaction executions. return struct with info - var cr = await Task.Run(() => CustomReactions.TryGetCustomReaction(usrMsg)).ConfigureAwait(false); - if (cr != null) //if it was, don't execute the command - { - try - { - if (guild != null) - { - PermissionCache pc; - if (!Permissions.Cache.TryGetValue(guild.Id, out pc)) - { - using (var uow = DbHandler.UnitOfWork()) - { - var config = uow.GuildConfigs.For(guild.Id, - set => set.Include(x => x.Permissions)); - Permissions.UpdateCache(config); - } - Permissions.Cache.TryGetValue(guild.Id, out pc); - if (pc == null) - throw new Exception("Cache is null."); - } - int index; - if ( - !pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions", - out index)) - { - //todo print in guild actually - var returnMsg = - $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action."; - _log.Info(returnMsg); - return; - } - } - await cr.Send(usrMsg).ConfigureAwait(false); - - if (cr.AutoDeleteTrigger) - { - try { await msg.DeleteAsync().ConfigureAwait(false); } catch { } - } - } - catch (Exception ex) - { - _log.Warn("Sending CREmbed failed"); - _log.Warn(ex); - } - return; - } - - var exec3 = Environment.TickCount - execTime; - - string messageContent = usrMsg.Content; - if (guild != null) - { - ConcurrentDictionary maps; - if (Modules.Utility.Utility.CommandMapCommands.AliasMaps.TryGetValue(guild.Id, out maps)) - { - string newMessageContent; - if (maps.TryGetValue(messageContent.Trim().ToLowerInvariant(), out newMessageContent)) - { - _log.Info(@"--Mapping Command-- - GuildId: {0} - Trigger: {1} - Mapping: {2}", guild.Id, messageContent, newMessageContent); - var oldMessageContent = messageContent; - messageContent = newMessageContent; - - try { await usrMsg.Channel.SendConfirmAsync($"{oldMessageContent} => {newMessageContent}").ConfigureAwait(false); } catch { } - } - } - } - - - // execute the command and measure the time it took - 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) - { - await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false); - await LogSuccessfulExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime).ConfigureAwait(false); - } - else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand) - { - LogErroredExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime); - if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception) - { - if (exec.PermissionCache != null && exec.PermissionCache.Verbose) - try { await msg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { } - } - } - else - { - if (msg.Channel is IPrivateChannel) - { - // rofl, gotta do this to prevent dm help message being sent to - // users who are voting on private polls (sending a number in a DM) - int vote; - if (int.TryParse(msg.Content, out vote)) return; - - await msg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false); - - await SelfCommands.HandleDmForwarding(msg, ownerChannels).ConfigureAwait(false); - } - } + await TryRunCommand(guild, channel, usrMsg); } catch (Exception ex) { @@ -388,6 +261,137 @@ namespace NadekoBot.Services return Task.CompletedTask; } + public async Task TryRunCommand(SocketGuild guild, ITextChannel channel, IUserMessage usrMsg) + { + var execTime = Environment.TickCount; + + if (guild != null && guild.OwnerId != usrMsg.Author.Id) + { + if (await InviteFiltered(guild, usrMsg).ConfigureAwait(false)) + return; + + if (await WordFiltered(guild, usrMsg).ConfigureAwait(false)) + return; + } + + if (IsBlacklisted(guild, usrMsg)) + return; + + var exec1 = Environment.TickCount - execTime; + + var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false); + if (cleverBotRan) + return; + + var exec2 = Environment.TickCount - execTime; + + // maybe this message is a custom reaction + // todo log custom reaction executions. return struct with info + var cr = await Task.Run(() => CustomReactions.TryGetCustomReaction(usrMsg)).ConfigureAwait(false); + if (cr != null) //if it was, don't execute the command + { + try + { + if (guild != null) + { + PermissionCache pc; + if (!Permissions.Cache.TryGetValue(guild.Id, out pc)) + { + using (var uow = DbHandler.UnitOfWork()) + { + var config = uow.GuildConfigs.For(guild.Id, + set => set.Include(x => x.Permissions)); + Permissions.UpdateCache(config); + } + Permissions.Cache.TryGetValue(guild.Id, out pc); + if (pc == null) + throw new Exception("Cache is null."); + } + int index; + if ( + !pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions", + out index)) + { + //todo print in guild actually + var returnMsg = + $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action."; + _log.Info(returnMsg); + return; + } + } + await cr.Send(usrMsg).ConfigureAwait(false); + + if (cr.AutoDeleteTrigger) + { + try { await usrMsg.DeleteAsync().ConfigureAwait(false); } catch { } + } + } + catch (Exception ex) + { + _log.Warn("Sending CREmbed failed"); + _log.Warn(ex); + } + return; + } + + var exec3 = Environment.TickCount - execTime; + + string messageContent = usrMsg.Content; + if (guild != null) + { + ConcurrentDictionary maps; + if (Modules.Utility.Utility.CommandMapCommands.AliasMaps.TryGetValue(guild.Id, out maps)) + { + string newMessageContent; + if (maps.TryGetValue(messageContent.Trim().ToLowerInvariant(), out newMessageContent)) + { + _log.Info(@"--Mapping Command-- + GuildId: {0} + Trigger: {1} + Mapping: {2}", guild.Id, messageContent, newMessageContent); + var oldMessageContent = messageContent; + messageContent = newMessageContent; + + try { await usrMsg.Channel.SendConfirmAsync($"{oldMessageContent} => {newMessageContent}").ConfigureAwait(false); } catch { } + } + } + } + + + // execute the command and measure the time it took + 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) + { + await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false); + await LogSuccessfulExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime).ConfigureAwait(false); + } + else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand) + { + LogErroredExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime); + if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception) + { + if (exec.PermissionCache != null && exec.PermissionCache.Verbose) + try { await usrMsg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { } + } + } + else + { + if (usrMsg.Channel is IPrivateChannel) + { + // rofl, gotta do this to prevent dm help message being sent to + // users who are voting on private polls (sending a number in a DM) + int vote; + if (int.TryParse(usrMsg.Content, out vote)) return; + + await usrMsg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false); + + await SelfCommands.HandleDmForwarding(usrMsg, ownerChannels).ConfigureAwait(false); + } + } + } + public Task ExecuteCommandAsync(CommandContext context, int argPos, IDependencyMap dependencyMap = null, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception) => ExecuteCommand(context, context.Message.Content.Substring(argPos), dependencyMap, multiMatchHandling); diff --git a/src/NadekoBot/Services/Database/Models/BotConfig.cs b/src/NadekoBot/Services/Database/Models/BotConfig.cs index 8ff90e8a..b25dc744 100644 --- a/src/NadekoBot/Services/Database/Models/BotConfig.cs +++ b/src/NadekoBot/Services/Database/Models/BotConfig.cs @@ -61,6 +61,19 @@ Nadeko Support Server: https://discord.gg/nadekobot"; public string OkColor { get; set; } = "71cd40"; public string ErrorColor { get; set; } = "ee281f"; public string Locale { get; set; } = null; + public List StartupCommands { get; set; } + } + + public class StartupCommand : DbEntity, IIndexed + { + public int Index { get; set; } + public string CommandText { get; set; } + public ulong ChannelId { get; set; } + public string ChannelName { get; set; } + public ulong? GuildId { get; set; } + public string GuildName { get; set; } + public ulong? VoiceChannelId { get; set; } + public string VoiceChannelName { get; set; } } public class PlayingStatus :DbEntity diff --git a/src/NadekoBot/Services/Database/Repositories/IBotConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/IBotConfigRepository.cs index 7f9f3dd5..7a2adf63 100644 --- a/src/NadekoBot/Services/Database/Repositories/IBotConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/IBotConfigRepository.cs @@ -1,9 +1,12 @@ -using NadekoBot.Services.Database.Models; +using Microsoft.EntityFrameworkCore; +using NadekoBot.Services.Database.Models; +using System; +using System.Linq; namespace NadekoBot.Services.Database.Repositories { public interface IBotConfigRepository : IRepository { - BotConfig GetOrCreate(); + BotConfig GetOrCreate(Func, IQueryable> includes = null); } } diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs index 2aa0bf83..1e40f86c 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs @@ -1,6 +1,7 @@ using NadekoBot.Services.Database.Models; using System.Linq; using Microsoft.EntityFrameworkCore; +using System; namespace NadekoBot.Services.Database.Repositories.Impl { @@ -10,15 +11,21 @@ namespace NadekoBot.Services.Database.Repositories.Impl { } - public BotConfig GetOrCreate() + public BotConfig GetOrCreate(Func, IQueryable> includes = null) { - var config = _set.Include(bc => bc.RotatingStatusMessages) + BotConfig config; + + if (includes == null) + config = _set.Include(bc => bc.RotatingStatusMessages) .Include(bc => bc.RaceAnimals) .Include(bc => bc.Blacklist) .Include(bc => bc.EightBallResponses) .Include(bc => bc.ModulePrefixes) + .Include(bc => bc.StartupCommands) //.Include(bc => bc.CommandCosts) .FirstOrDefault(); + else + config = includes(_set).FirstOrDefault(); if (config == null) { From 223b668628c6691a0b1f8fb1f731f58ffbfe3352 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 1 Apr 2017 11:15:37 +0200 Subject: [PATCH 661/746] softban is a separate punishment from kick now. Commandlist updated --- .../Modules/Administration/Commands/LogCommand.cs | 3 +++ .../Administration/Commands/ProtectionCommands.cs | 7 +++++++ .../Administration/Commands/UserPunishCommands.cs | 11 +++++++++++ src/NadekoBot/Resources/ResponseStrings.Designer.cs | 11 ++++++++++- src/NadekoBot/Resources/ResponseStrings.resx | 6 +++++- .../Services/Database/Models/AntiProtection.cs | 1 + 6 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index f061f045..515c2f46 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -307,6 +307,9 @@ namespace NadekoBot.Modules.Administration punishment = "🔇 " + logChannel.Guild.GetLogText("muted_pl").ToUpperInvariant(); break; case PunishmentAction.Kick: + punishment = "👢 " + logChannel.Guild.GetLogText("kicked_pl").ToUpperInvariant(); + break; + case PunishmentAction.Softban: punishment = "☣ " + logChannel.Guild.GetLogText("soft_banned_pl").ToUpperInvariant(); break; case PunishmentAction.Ban: diff --git a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs index af7269c9..23f1eaf0 100644 --- a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs @@ -188,6 +188,13 @@ namespace NadekoBot.Modules.Administration catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); } break; case PunishmentAction.Kick: + try + { + await gu.KickAsync().ConfigureAwait(false); + } + catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); } + break; + case PunishmentAction.Softban: try { await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false); diff --git a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs index f37b864c..f794d47a 100644 --- a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs @@ -72,6 +72,17 @@ namespace NadekoBot.Modules.Administration case PunishmentAction.Ban: await guild.AddBanAsync(user).ConfigureAwait(false); break; + case PunishmentAction.Softban: + await guild.AddBanAsync(user).ConfigureAwait(false); + try + { + await guild.RemoveBanAsync(user).ConfigureAwait(false); + } + catch + { + await guild.RemoveBanAsync(user).ConfigureAwait(false); + } + break; default: break; } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index ea980b1f..3d91002f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -574,6 +574,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Kicked. + /// + public static string administration_kicked_pl { + get { + return ResourceManager.GetString("administration_kicked_pl", resourceCulture); + } + } + /// /// Looks up a localized string similar to User kicked. /// @@ -1504,7 +1513,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to soft-banned (kicked). + /// Looks up a localized string similar to soft-banned. /// public static string administration_soft_banned_pl { get { diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 92087d6b..c71eea89 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -740,7 +740,7 @@ Reason: {1} Slow mode initiated - soft-banned (kicked) + soft-banned PLURAL @@ -2284,6 +2284,10 @@ Owner ID: {2} Command Text + + Kicked + PLURAL + Moderator diff --git a/src/NadekoBot/Services/Database/Models/AntiProtection.cs b/src/NadekoBot/Services/Database/Models/AntiProtection.cs index 0172dd90..a90ee649 100644 --- a/src/NadekoBot/Services/Database/Models/AntiProtection.cs +++ b/src/NadekoBot/Services/Database/Models/AntiProtection.cs @@ -31,6 +31,7 @@ namespace NadekoBot.Services.Database.Models Mute, Kick, Ban, + Softban } public class AntiSpamIgnore : DbEntity From 83dbc562af0c74dc1d19f756f80f5c5b7a700657 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 1 Apr 2017 11:15:54 +0200 Subject: [PATCH 662/746] Woops --- docs/Commands List.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index 0ce3438d..715df776 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -26,9 +26,6 @@ Commands and aliases | Description | Usage `.removeallroles` `.rar` | Removes all roles from a mentioned user. **Requires ManageRoles server permission.** | `.rar @User` `.createrole` `.cr` | Creates a role with a given name. **Requires ManageRoles server permission.** | `.cr Awesome Role` `.rolecolor` `.rc` | Set a role's color to the hex or 0-255 rgb color value provided. **Requires ManageRoles server permission.** | `.rc Admin 255 200 100` or `.rc Admin ffba55` -`.ban` `.b` | Bans a user by ID or name with an optional message. **Requires BanMembers server permission.** | `.b "@some Guy" Your behaviour is toxic.` -`.softban` `.sb` | Bans and then unbans a user by ID or name with an optional message. **Requires KickMembers server permission.** **Requires ManageMessages server permission.** | `.sb "@some Guy" Your behaviour is toxic.` -`.kick` `.k` | Kicks a mentioned user. **Requires KickMembers server permission.** | `.k "@some Guy" Your behaviour is toxic.` `.deafen` `.deaf` | Deafens mentioned user or users. **Requires DeafenMembers server permission.** | `.deaf "@Someguy"` or `.deaf "@Someguy" "@Someguy"` `.undeafen` `.undef` | Undeafens mentioned user or users. **Requires DeafenMembers server permission.** | `.undef "@Someguy"` or `.undef "@Someguy" "@Someguy"` `.delvoichanl` `.dvch` | Deletes a voice channel with a given name. **Requires ManageChannels server permission.** | `.dvch VoiceChannelName` @@ -73,6 +70,11 @@ Commands and aliases | Description | Usage `.togglexclsar` `.tesar` | Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) **Requires ManageRoles server permission.** | `.tesar` `.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | `.iam Gamer` `.iamnot` `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | `.iamn Gamer` +`.scadd` | Adds a command to the list of commands which will be executed automatically in the current channel, in the order they were added in, by the bot when it startups up. **Bot owner only** | `.scadd .stats` +`.sclist` | Lists all startup commands in the order they will be executed in. **Bot owner only** | `.sclist` +`.wait` | Used only as a startup command. Waits a certain number of miliseconds before continuing the execution of the following startup commands. **Bot owner only** | `.wait 3000` +`.scrm` | Removes a startup command with the provided command text. **Bot owner only** | `.scrm .stats` +`.scclr` | Removes all startup commands. **Bot owner only** | `.scclr` `.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot owner only** | `.fwmsgs` `.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json file **Bot owner only** | `.fwtoall` `.connectshard` | Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. **Bot owner only** | `.connectshard 2` @@ -94,6 +96,15 @@ Commands and aliases | Description | Usage `.bye` | Toggles anouncements on the current channel when someone leaves the server. **Requires ManageServer server permission.** | `.bye` `.byemsg` | Sets a new leave announcement message. Type `%user%` if you want to show the name the user who left. Type `%id%` to show id. Using this command with no message will show the current bye message. You can use embed json from instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.byemsg %user% has left.` `.byedel` | Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion. **Requires ManageServer server permission.** | `.byedel 0` or `.byedel 30` +`.warn` | Warns a user. **Requires BanMembers server permission.** | `.warn @b1nzy` +`.warnlog` | See a list of warnings of a certain user. **Requires BanMembers server permission.** | `.warnlog @b1nzy` +`.warnclear` `.warnc` | Clears all warnings from a certain user. **Requires BanMembers server permission.** | `.warnclear @PoorDude` +`.warnpunish` `.warnp` | Sets a punishment for a certain number of warnings. Provide no punishment to remove. **Requires BanMembers server permission.** | `.warnpunish 5 Ban` or `.warnpunish 3` +`.warnpunishlist` `.warnpl` | Lists punishments for warnings. | `.warnpunishlist` +`.ban` `.b` | Bans a user by ID or name with an optional message. **Requires BanMembers server permission.** | `.b "@some Guy" Your behaviour is toxic.` +`.unban` | Unbans a user with the provided user#discrim or id. **Requires BanMembers server permission.** | `.unban kwoth#1234` or `.unban 123123123` +`.softban` `.sb` | Bans and then unbans a user by ID or name with an optional message. **Requires KickMembers server permission.** **Requires ManageMessages server permission.** | `.sb "@some Guy" Your behaviour is toxic.` +`.kick` `.k` | Kicks a mentioned user. **Requires KickMembers server permission.** | `.k "@some Guy" Your behaviour is toxic.` `.vcrole` | Sets or resets a role which will be given to users who join the voice channel you're in when you run this command. Provide no role name to disable. You must be in a voice channel to run this command. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.vcrole SomeRole` or `.vcrole` `.vcrolelist` | Shows a list of currently set voice channel roles. | `.vcrolelist` `.voice+text` `.v+t` | Creates a text channel for each voice channel only users in that voice channel can see. If you are server owner, keep in mind you will see them all the time regardless. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.v+t` From 3a5aed213b3580521e2a0a9f9bb5e6299ffcf622 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 1 Apr 2017 13:47:05 +0200 Subject: [PATCH 663/746] startup commands will no longer be treated as if theyr'e run in DMs --- .../Commands/RatelimitCommand.cs | 27 +++++++++++++++++++ .../Administration/Commands/SelfCommands.cs | 11 ++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs index 2a4e111f..6d1e3f13 100644 --- a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs @@ -1,7 +1,10 @@ using Discord; using Discord.Commands; +using Microsoft.EntityFrameworkCore; using NadekoBot.Attributes; using NadekoBot.Extensions; +using NadekoBot.Services; +using NadekoBot.Services.Database; using NLog; using System; using System.Collections.Concurrent; @@ -118,6 +121,30 @@ namespace NadekoBot.Modules.Administration .ConfigureAwait(false); } } + + //[NadekoCommand, Usage, Description, Aliases] + //[RequireContext(ContextType.Guild)] + //[RequireUserPermission(GuildPermission.ManageMessages)] + //public async Task SlowmodeWhitelist(IUser user) + //{ + // Ratelimiter throwaway; + // if (RatelimitingChannels.TryRemove(Context.Channel.Id, out throwaway)) + // { + // throwaway.cancelSource.Cancel(); + // await ReplyConfirmLocalized("slowmode_disabled").ConfigureAwait(false); + // } + //} + + //[NadekoCommand, Usage, Description, Aliases] + //[RequireContext(ContextType.Guild)] + //[RequireUserPermission(GuildPermission.ManageMessages)] + //public async Task SlowmodeWhitelist(IRole role) + //{ + // using (var uow = DbHandler.UnitOfWork()) + // { + // uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeWhitelists)). + // } + //} } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index 3af86611..09924682 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -36,11 +36,9 @@ namespace NadekoBot.Modules.Administration var _ = Task.Run(async () => { -#if !GLOBAL_NADEKO - await Task.Delay(2000); -#else - await Task.Delay(10000); -#endif + while(!NadekoBot.Ready) + await Task.Delay(1000); + foreach (var cmd in NadekoBot.BotConfig.StartupCommands) { if (cmd.GuildId != null) @@ -52,7 +50,8 @@ namespace NadekoBot.Modules.Administration try { - var msg = await channel.SendMessageAsync(cmd.CommandText).ConfigureAwait(false); + IUserMessage msg = await channel.SendMessageAsync(cmd.CommandText).ConfigureAwait(false); + msg = (IUserMessage)await channel.GetMessageAsync(msg.Id).ConfigureAwait(false); await NadekoBot.CommandHandler.TryRunCommand(guild, channel, msg).ConfigureAwait(false); //msg.DeleteAfter(5); } From 2b65518649b6b338cfde0d9d6468fae50ec5f585 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 1 Apr 2017 21:40:13 +0200 Subject: [PATCH 664/746] Slowmode whitelists done, need testing --- ...70401161600_slowmode-whitelist.Designer.cs | 1435 +++++++++++++++++ .../20170401161600_slowmode-whitelist.cs | 73 + .../NadekoSqliteContextModelSnapshot.cs | 50 + .../Commands/RatelimitCommand.cs | 112 +- .../Utility/Commands/PatreonCommands.cs | 113 +- .../Resources/CommandStrings.Designer.cs | 54 + src/NadekoBot/Resources/CommandStrings.resx | 18 + .../Resources/ResponseStrings.Designer.cs | 117 ++ src/NadekoBot/Resources/ResponseStrings.resx | 39 + .../Services/Database/Models/GuildConfig.cs | 46 + .../Services/Database/Models/RewardedUser.cs | 11 + 11 files changed, 2020 insertions(+), 48 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.cs create mode 100644 src/NadekoBot/Services/Database/Models/RewardedUser.cs diff --git a/src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.Designer.cs b/src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.Designer.cs new file mode 100644 index 00000000..7409d096 --- /dev/null +++ b/src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.Designer.cs @@ -0,0 +1,1435 @@ +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("20170401161600_slowmode-whitelist")] + partial class slowmodewhitelist + { + 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("DateAdded"); + + 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.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Mapping"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("AutoDeleteTrigger"); + + b.Property("DateAdded"); + + b.Property("DmResponse"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.Property("WarningsInitialized"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissionv2"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredRole"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ChannelId"); + + b.Property("ChannelName"); + + b.Property("CommandText"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("GuildName"); + + b.Property("Index"); + + b.Property("VoiceChannelId"); + + b.Property("VoiceChannelName"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("StartupCommand"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UnmuteAt"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.Property("VoiceChannelId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Forgiven"); + + b.Property("ForgivenBy"); + + b.Property("GuildId"); + + b.Property("Moderator"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Count"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Punishment"); + + b.Property("Time"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + + 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.CommandAlias", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId"); + }); + + 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.Permissionv2", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("Permissions") + .HasForeignKey("GuildConfigId"); + }); + + 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.SlowmodeIgnoredRole", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("StartupCommands") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId"); + }); + + 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); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.cs b/src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.cs new file mode 100644 index 00000000..fc2be484 --- /dev/null +++ b/src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class slowmodewhitelist : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "SlowmodeIgnoredRole", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DateAdded = table.Column(nullable: true), + GuildConfigId = table.Column(nullable: true), + RoleId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SlowmodeIgnoredRole", x => x.Id); + table.ForeignKey( + name: "FK_SlowmodeIgnoredRole_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "SlowmodeIgnoredUser", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DateAdded = table.Column(nullable: true), + GuildConfigId = table.Column(nullable: true), + UserId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SlowmodeIgnoredUser", x => x.Id); + table.ForeignKey( + name: "FK_SlowmodeIgnoredUser_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_SlowmodeIgnoredRole_GuildConfigId", + table: "SlowmodeIgnoredRole", + column: "GuildConfigId"); + + migrationBuilder.CreateIndex( + name: "IX_SlowmodeIgnoredUser_GuildConfigId", + table: "SlowmodeIgnoredUser", + column: "GuildConfigId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "SlowmodeIgnoredRole"); + + migrationBuilder.DropTable( + name: "SlowmodeIgnoredUser"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 83771957..3f6df376 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -950,6 +950,42 @@ namespace NadekoBot.Migrations b.ToTable("SelfAssignableRoles"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredRole"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredUser"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => { b.Property("Id") @@ -1320,6 +1356,20 @@ namespace NadekoBot.Migrations .HasForeignKey("BotConfigId"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => { b.HasOne("NadekoBot.Services.Database.Models.BotConfig") diff --git a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs index 6d1e3f13..0c0f91be 100644 --- a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs @@ -1,13 +1,17 @@ using Discord; using Discord.Commands; +using Discord.WebSocket; using Microsoft.EntityFrameworkCore; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; using NLog; using System; using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -23,6 +27,9 @@ namespace NadekoBot.Modules.Administration public class Ratelimiter { + public HashSet IgnoreUsers { get; set; } = new HashSet(); + public HashSet IgnoreRoles { get; set; } = new HashSet(); + public class RatelimitedUser { public ulong UserId { get; set; } @@ -38,10 +45,14 @@ namespace NadekoBot.Modules.Administration public ConcurrentDictionary Users { get; set; } = new ConcurrentDictionary(); - public bool CheckUserRatelimit(ulong id) + public bool CheckUserRatelimit(ulong id, SocketGuildUser optUser) { + if (IgnoreUsers.Contains(id) || + (optUser != null && optUser.RoleIds.Any(x => IgnoreRoles.Contains(x)))) + return false; + var usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id }); - if (usr.MessageCount == MaxMessages) + if (usr.MessageCount >= MaxMessages) { return true; } @@ -67,8 +78,8 @@ namespace NadekoBot.Modules.Administration { try { - var usrMsg = umsg as IUserMessage; - var channel = usrMsg?.Channel as ITextChannel; + var usrMsg = umsg as SocketUserMessage; + var channel = usrMsg?.Channel as SocketTextChannel; if (channel == null || usrMsg.IsAuthor()) return; @@ -76,7 +87,7 @@ namespace NadekoBot.Modules.Administration if (!RatelimitingChannels.TryGetValue(channel.Id, out limiter)) return; - if (limiter.CheckUserRatelimit(usrMsg.Author.Id)) + if (limiter.CheckUserRatelimit(usrMsg.Author.Id, usrMsg.Author as SocketGuildUser)) await usrMsg.DeleteAsync(); } catch (Exception ex) { _log.Warn(ex); } @@ -122,29 +133,76 @@ namespace NadekoBot.Modules.Administration } } - //[NadekoCommand, Usage, Description, Aliases] - //[RequireContext(ContextType.Guild)] - //[RequireUserPermission(GuildPermission.ManageMessages)] - //public async Task SlowmodeWhitelist(IUser user) - //{ - // Ratelimiter throwaway; - // if (RatelimitingChannels.TryRemove(Context.Channel.Id, out throwaway)) - // { - // throwaway.cancelSource.Cancel(); - // await ReplyConfirmLocalized("slowmode_disabled").ConfigureAwait(false); - // } - //} + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + [Priority(1)] + public async Task SlowmodeWhitelist(IUser user) + { + var siu = new SlowmodeIgnoredUser + { + UserId = user.Id + }; - //[NadekoCommand, Usage, Description, Aliases] - //[RequireContext(ContextType.Guild)] - //[RequireUserPermission(GuildPermission.ManageMessages)] - //public async Task SlowmodeWhitelist(IRole role) - //{ - // using (var uow = DbHandler.UnitOfWork()) - // { - // uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeWhitelists)). - // } - //} + HashSet usrs; + bool removed; + using (var uow = DbHandler.UnitOfWork()) + { + usrs = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeIgnoredUsers)) + .SlowmodeIgnoredUsers; + + if (!(removed = usrs.Remove(siu))) + usrs.Add(siu); + + await uow.CompleteAsync().ConfigureAwait(false); + } + + Ratelimiter rl; + if (RatelimitingChannels.TryGetValue(Context.Guild.Id, out rl)) + { + rl.IgnoreUsers = new HashSet(usrs.Select(x => x.UserId)); + } + if(removed) + await ReplyConfirmLocalized("slowmodewl_user_stop", Format.Bold(user.ToString())).ConfigureAwait(false); + else + await ReplyConfirmLocalized("slowmodewl_user_start", Format.Bold(user.ToString())).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + [Priority(0)] + public async Task SlowmodeWhitelist(IRole role) + { + var sir = new SlowmodeIgnoredRole + { + RoleId = role.Id + }; + + HashSet roles; + bool removed; + using (var uow = DbHandler.UnitOfWork()) + { + roles = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeIgnoredRoles)) + .SlowmodeIgnoredRoles; + + if (!(removed = roles.Remove(sir))) + roles.Add(sir); + + await uow.CompleteAsync().ConfigureAwait(false); + } + + Ratelimiter rl; + if (RatelimitingChannels.TryGetValue(Context.Guild.Id, out rl)) + { + rl.IgnoreRoles = new HashSet(roles.Select(x => x.RoleId)); + } + + if (removed) + await ReplyConfirmLocalized("slowmodewl_role_stop", Format.Bold(role.ToString())).ConfigureAwait(false); + else + await ReplyConfirmLocalized("slowmodewl_role_start", Format.Bold(role.ToString())).ConfigureAwait(false); + } } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs index c8908abe..76dd9ee0 100644 --- a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs @@ -9,6 +9,9 @@ //using System.Threading; //using System; //using System.Collections.Immutable; +//using NadekoBot.Services; +//using NadekoBot.Services.Database.Models; +//using NadekoBot.Extensions; //namespace NadekoBot.Modules.Utility //{ @@ -17,20 +20,45 @@ // [Group] // public class PatreonCommands : NadekoSubmodule // { +// private static readonly PatreonThingy patreon; + +// static PatreonCommands() +// { +// patreon = PatreonThingy.Instance; +// } // [NadekoCommand, Usage, Description, Aliases] // public async Task ClaimPatreonRewards() // { -// var patreon = PatreonThingy.Instance; - -// var pledges = (await patreon.GetPledges().ConfigureAwait(false)) -// .OrderByDescending(x => x.Reward.attributes.amount_cents); - -// if (pledges == null) +// if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) +// return; +// if (DateTime.UtcNow.Day < 5) // { -// await ReplyErrorLocalized("pledges_loading").ConfigureAwait(false); +// await ReplyErrorLocalized("claimpatreon_too_early").ConfigureAwait(false); +// } +// int amount = 0; +// try +// { +// amount = await patreon.ClaimReward(Context.User.Id).ConfigureAwait(false); +// } +// catch (Exception ex) +// { +// _log.Warn(ex); +// } + +// if (amount > 0) +// { +// await ReplyConfirmLocalized("claimpatreon_success", amount).ConfigureAwait(false); // return; // } +// await Context.Channel.EmbedAsync(new Discord.EmbedBuilder().WithOkColor() +// .WithDescription(GetText("claimpatreon_fail")) +// .AddField(efb => efb.WithName("").WithValue("")) +// .AddField(efb => efb.WithName("").WithValue("")) +// .AddField(efb => efb.WithName("").WithValue(""))) +// .ConfigureAwait(false); + +// await ReplyErrorLocalized("claimpatreon_fail").ConfigureAwait(false); // } // } @@ -41,21 +69,16 @@ // private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1); -// private ImmutableArray pledges; +// public ImmutableArray Pledges { get; private set; } -// static PatreonThingy() { } +// private readonly Timer update; +// private readonly SemaphoreSlim claimLockJustInCase = new SemaphoreSlim(1, 1); -// public async Task> GetPledges() +// private PatreonThingy() // { -// try -// { -// await LoadPledges().ConfigureAwait(false); -// return pledges; -// } -// catch (OperationCanceledException) -// { -// return pledges; -// } +// if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) +// return; +// update = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, TimeSpan.FromHours(3)); // } // public async Task LoadPledges() @@ -89,7 +112,7 @@ // .Select(x => JsonConvert.DeserializeObject(x.ToString()))); // } while (!string.IsNullOrWhiteSpace(data.Links.next)); // } -// pledges = rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward() +// Pledges = rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward() // { // User = y, // Reward = x, @@ -102,7 +125,55 @@ // await Task.Delay(TimeSpan.FromMinutes(5)).ConfigureAwait(false); // getPledgesLocker.Release(); // }); - + +// } +// } + +// public async Task ClaimReward(ulong userId) +// { +// await claimLockJustInCase.WaitAsync(); +// try +// { +// var data = Pledges.FirstOrDefault(x => x.User.id == userId.ToString()); + +// if (data == null) +// return 0; + +// var amount = data.Reward.attributes.amount_cents; + +// using (var uow = DbHandler.UnitOfWork()) +// { +// var users = uow._context.Set(); +// var usr = users.FirstOrDefault(x => x.UserId == userId); + +// if (usr == null) +// { +// users.Add(new RewardedUser() +// { +// UserId = userId, +// LastReward = DateTime.UtcNow, +// AmountRewardedThisMonth = amount, +// }); +// await uow.CompleteAsync().ConfigureAwait(false); +// return amount; +// } + +// if (usr.AmountRewardedThisMonth < amount) +// { +// var toAward = amount - usr.AmountRewardedThisMonth; + +// usr.LastReward = DateTime.UtcNow; +// usr.AmountRewardedThisMonth = amount; + +// await uow.CompleteAsync().ConfigureAwait(false); +// return toAward; +// } +// } +// return 0; +// } +// finally +// { +// claimLockJustInCase.Release(); // } // } // } diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 20c12253..ef7c365a 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -1706,6 +1706,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to claimpatreonrewards. + /// + public static string claimpatreonrewards_cmd { + get { + return ResourceManager.GetString("claimpatreonrewards_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If you're subscribed to bot owner's patreon you can user this command to claim your rewards - assuming bot owner did setup has their patreon key.. + /// + public static string claimpatreonrewards_desc { + get { + return ResourceManager.GetString("claimpatreonrewards_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}claimpatreonrewards`. + /// + public static string claimpatreonrewards_usage { + get { + return ResourceManager.GetString("claimpatreonrewards_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to cleanup. /// @@ -7673,6 +7700,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to slowmodewl. + /// + public static string slowmodewhitelist_cmd { + get { + return ResourceManager.GetString("slowmodewhitelist_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ignores a role or a user from the slowmode feature.. + /// + public static string slowmodewhitelist_desc { + get { + return ResourceManager.GetString("slowmodewhitelist_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}slowmodewl SomeRole` or `{0}slowmodewl AdminDude`. + /// + public static string slowmodewhitelist_usage { + get { + return ResourceManager.GetString("slowmodewhitelist_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to softban sb. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 5d1d0539..64236de1 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3321,4 +3321,22 @@ `{0}warnpunish 5 Ban` or `{0}warnpunish 3` + + claimpatreonrewards + + + If you're subscribed to bot owner's patreon you can user this command to claim your rewards - assuming bot owner did setup has their patreon key. + + + `{0}claimpatreonrewards` + + + slowmodewl + + + Ignores a role or a user from the slowmode feature. + + + `{0}slowmodewl SomeRole` or `{0}slowmodewl AdminDude` + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 3d91002f..5befa0b0 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -1512,6 +1512,42 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Slowmode will now ignore role {0}. + /// + public static string administration_slowmodewl_role_start { + get { + return ResourceManager.GetString("administration_slowmodewl_role_start", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Slowmode will no longer ignore role {0}. + /// + public static string administration_slowmodewl_role_stop { + get { + return ResourceManager.GetString("administration_slowmodewl_role_stop", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Slowmode will now ignore user {0}. + /// + public static string administration_slowmodewl_user_start { + get { + return ResourceManager.GetString("administration_slowmodewl_user_start", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Slowmode will no longer ignore user {0}. + /// + public static string administration_slowmodewl_user_stop { + get { + return ResourceManager.GetString("administration_slowmodewl_user_stop", resourceCulture); + } + } + /// /// Looks up a localized string similar to soft-banned. /// @@ -5989,6 +6025,87 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Failed claiming rewards due to one of the following reasons:. + /// + public static string utility_claimpatreon_fail { + get { + return ResourceManager.GetString("utility_claimpatreon_fail", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maybe you have already received your reward for this month. You can receive rewards only once a month unless you increase your pledge.. + /// + public static string utility_claimpatreon_fail_already { + get { + return ResourceManager.GetString("utility_claimpatreon_fail_already", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Already rewarded. + /// + public static string utility_claimpatreon_fail_already_title { + get { + return ResourceManager.GetString("utility_claimpatreon_fail_already_title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In order to be eligible for the reward, you must support the project on patreon. Use {0} command to get the link.. + /// + public static string utility_claimpatreon_fail_sup { + get { + return ResourceManager.GetString("utility_claimpatreon_fail_sup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not supporting. + /// + public static string utility_claimpatreon_fail_sup_title { + get { + return ResourceManager.GetString("utility_claimpatreon_fail_sup_title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You have to wait a few hours after making your pledge, if you didn't, waiut a bit and then try again later.. + /// + public static string utility_claimpatreon_fail_wait { + get { + return ResourceManager.GetString("utility_claimpatreon_fail_wait", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wait some time. + /// + public static string utility_claimpatreon_fail_wait_title { + get { + return ResourceManager.GetString("utility_claimpatreon_fail_wait_title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You've received {0}. Thanks for supporting the project!. + /// + public static string utility_claimpatreon_success { + get { + return ResourceManager.GetString("utility_claimpatreon_success", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Rewards can be claimed on or after 5th of each month.. + /// + public static string utility_claimpatreon_too_early { + get { + return ResourceManager.GetString("utility_claimpatreon_too_early", resourceCulture); + } + } + /// /// Looks up a localized string similar to Commands ran. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index c71eea89..0a523218 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2357,4 +2357,43 @@ Owner ID: {2} I will apply {0} punishment to users with {1} warnings. + + Slowmode will now ignore role {0} + + + Slowmode will no longer ignore role {0} + + + Slowmode will now ignore user {0} + + + Slowmode will no longer ignore user {0} + + + Failed claiming rewards due to one of the following reasons: + + + Maybe you have already received your reward for this month. You can receive rewards only once a month unless you increase your pledge. + + + Already rewarded + + + In order to be eligible for the reward, you must support the project on patreon. Use {0} command to get the link. + + + Not supporting + + + You have to wait a few hours after making your pledge, if you didn't, waiut a bit and then try again later. + + + Wait some time + + + You've received {0}. Thanks for supporting the project! + + + Rewards can be claimed on or after 5th of each month. + \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs index 4fe497c1..aaf7addf 100644 --- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs +++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs @@ -73,10 +73,56 @@ namespace NadekoBot.Services.Database.Models public HashSet CommandAliases { get; set; } = new HashSet(); public List WarnPunishments { get; set; } = new List(); public bool WarningsInitialized { get; set; } + public HashSet SlowmodeIgnoredUsers { get; set; } + public HashSet SlowmodeIgnoredRoles { get; set; } //public List ProtectionIgnoredChannels { get; set; } = new List(); } + public class SlowmodeIgnoredUser : DbEntity + { + public ulong UserId { get; set; } + + // override object.Equals + public override bool Equals(object obj) + { + if (obj == null || GetType() != obj.GetType()) + { + return false; + } + + return ((SlowmodeIgnoredUser)obj).UserId == UserId; + } + + // override object.GetHashCode + public override int GetHashCode() + { + return UserId.GetHashCode(); + } + } + + public class SlowmodeIgnoredRole : DbEntity + { + public ulong RoleId { get; set; } + + // override object.Equals + public override bool Equals(object obj) + { + if (obj == null || GetType() != obj.GetType()) + { + return false; + } + + return ((SlowmodeIgnoredRole)obj).RoleId == RoleId; + } + + // override object.GetHashCode + public override int GetHashCode() + { + return RoleId.GetHashCode(); + } + } + public class WarningPunishment : DbEntity { public int Count { get; set; } diff --git a/src/NadekoBot/Services/Database/Models/RewardedUser.cs b/src/NadekoBot/Services/Database/Models/RewardedUser.cs new file mode 100644 index 00000000..e71843b1 --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/RewardedUser.cs @@ -0,0 +1,11 @@ +//using System; + +//namespace NadekoBot.Services.Database.Models +//{ +// public class RewardedUser +// { +// public ulong UserId { get; set; } +// public int AmountRewardedThisMonth { get; set; } +// public DateTime LastReward { get; set; } +// } +//} From 7e23877fd8784082329c488a9c2daa1cb677bef3 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 1 Apr 2017 21:51:25 +0200 Subject: [PATCH 665/746] .clparew (Claim patreon rewards) added, needs testing --- .../Utility/Commands/PatreonCommands.cs | 324 +++++++++--------- .../Resources/CommandStrings.Designer.cs | 4 +- src/NadekoBot/Resources/CommandStrings.resx | 4 +- .../Resources/ResponseStrings.Designer.cs | 36 +- src/NadekoBot/Resources/ResponseStrings.resx | 18 +- .../Services/Database/Models/RewardedUser.cs | 20 +- 6 files changed, 204 insertions(+), 202 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs index 76dd9ee0..6415dd8f 100644 --- a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs @@ -1,181 +1,183 @@ -//using System.Collections.Generic; -//using System.Linq; -//using System.Net.Http; -//using System.Threading.Tasks; -//using Discord.Commands; -//using NadekoBot.Attributes; -//using NadekoBot.Modules.Utility.Models; -//using Newtonsoft.Json; -//using System.Threading; -//using System; -//using System.Collections.Immutable; -//using NadekoBot.Services; -//using NadekoBot.Services.Database.Models; -//using NadekoBot.Extensions; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using Discord.Commands; +using NadekoBot.Attributes; +using NadekoBot.Modules.Utility.Models; +using Newtonsoft.Json; +using System.Threading; +using System; +using System.Collections.Immutable; +using NadekoBot.Services; +using NadekoBot.Services.Database.Models; +using NadekoBot.Extensions; -//namespace NadekoBot.Modules.Utility -//{ -// public partial class Utility -// { -// [Group] -// public class PatreonCommands : NadekoSubmodule -// { -// private static readonly PatreonThingy patreon; +namespace NadekoBot.Modules.Utility +{ + public partial class Utility + { + [Group] + public class PatreonCommands : NadekoSubmodule + { + private static readonly PatreonThingy patreon; -// static PatreonCommands() -// { -// patreon = PatreonThingy.Instance; -// } -// [NadekoCommand, Usage, Description, Aliases] -// public async Task ClaimPatreonRewards() -// { -// if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) -// return; -// if (DateTime.UtcNow.Day < 5) -// { -// await ReplyErrorLocalized("claimpatreon_too_early").ConfigureAwait(false); -// } -// int amount = 0; -// try -// { -// amount = await patreon.ClaimReward(Context.User.Id).ConfigureAwait(false); -// } -// catch (Exception ex) -// { -// _log.Warn(ex); -// } + static PatreonCommands() + { + patreon = PatreonThingy.Instance; + } + [NadekoCommand, Usage, Description, Aliases] + public async Task ClaimPatreonRewards() + { + if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) + return; + if (DateTime.UtcNow.Day < 5) + { + await ReplyErrorLocalized("clpa_too_early").ConfigureAwait(false); + } + int amount = 0; + try + { + amount = await patreon.ClaimReward(Context.User.Id).ConfigureAwait(false); + } + catch (Exception ex) + { + _log.Warn(ex); + } -// if (amount > 0) -// { -// await ReplyConfirmLocalized("claimpatreon_success", amount).ConfigureAwait(false); -// return; -// } + if (amount > 0) + { + await ReplyConfirmLocalized("clpa_success", amount + NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); + return; + } -// await Context.Channel.EmbedAsync(new Discord.EmbedBuilder().WithOkColor() -// .WithDescription(GetText("claimpatreon_fail")) -// .AddField(efb => efb.WithName("").WithValue("")) -// .AddField(efb => efb.WithName("").WithValue("")) -// .AddField(efb => efb.WithName("").WithValue(""))) -// .ConfigureAwait(false); + await Context.Channel.EmbedAsync(new Discord.EmbedBuilder().WithOkColor() + .WithDescription(GetText("clpa_fail")) + .AddField(efb => efb.WithName(GetText("clpa_fail_already_title")).WithValue(GetText("clpa_fail_already"))) + .AddField(efb => efb.WithName(GetText("clpa_fail_wait_title")).WithValue(GetText("clpa_fail_wait"))) + .AddField(efb => efb.WithName(GetText("clpa_fail_sup_title")).WithValue(GetText("clpa_fail_sup")))) + .ConfigureAwait(false); + } + } -// await ReplyErrorLocalized("claimpatreon_fail").ConfigureAwait(false); -// } -// } + public class PatreonThingy + { + public static PatreonThingy _instance = new PatreonThingy(); + public static PatreonThingy Instance => _instance; -// public class PatreonThingy -// { -// public static PatreonThingy _instance = new PatreonThingy(); -// public static PatreonThingy Instance => _instance; + private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1); -// private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1); + public ImmutableArray Pledges { get; private set; } -// public ImmutableArray Pledges { get; private set; } + private readonly Timer update; + private readonly SemaphoreSlim claimLockJustInCase = new SemaphoreSlim(1, 1); -// private readonly Timer update; -// private readonly SemaphoreSlim claimLockJustInCase = new SemaphoreSlim(1, 1); + private PatreonThingy() + { + if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) + return; + update = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, TimeSpan.FromHours(3)); + } -// private PatreonThingy() -// { -// if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) -// return; -// update = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, TimeSpan.FromHours(3)); -// } + public async Task LoadPledges() + { + await getPledgesLocker.WaitAsync(1000).ConfigureAwait(false); + try + { + var rewards = new List(); + var users = new List(); + using (var http = new HttpClient()) + { + http.DefaultRequestHeaders.Clear(); + http.DefaultRequestHeaders.Add("Authorization", "Bearer " + NadekoBot.Credentials.PatreonAccessToken); + var data = new PatreonData() + { + Links = new PatreonDataLinks() + { + next = "https://api.patreon.com/oauth2/api/campaigns/334038/pledges" + } + }; + do + { + var res = await http.GetStringAsync(data.Links.next) + .ConfigureAwait(false); + data = JsonConvert.DeserializeObject(res); + var pledgers = data.Data.Where(x => x["type"].ToString() == "pledge"); + rewards.AddRange(pledgers.Select(x => JsonConvert.DeserializeObject(x.ToString())) + .Where(x => x.attributes.declined_since == null)); + users.AddRange(data.Included + .Where(x => x["type"].ToString() == "user") + .Select(x => JsonConvert.DeserializeObject(x.ToString()))); + } while (!string.IsNullOrWhiteSpace(data.Links.next)); + } + Pledges = rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward() + { + User = y, + Reward = x, + }).ToImmutableArray(); + } + finally + { + var _ = Task.Run(async () => + { + await Task.Delay(TimeSpan.FromMinutes(5)).ConfigureAwait(false); + getPledgesLocker.Release(); + }); + } + } -// public async Task LoadPledges() -// { -// await getPledgesLocker.WaitAsync(1000).ConfigureAwait(false); -// try -// { -// var rewards = new List(); -// var users = new List(); -// using (var http = new HttpClient()) -// { -// http.DefaultRequestHeaders.Clear(); -// http.DefaultRequestHeaders.Add("Authorization", "Bearer " + NadekoBot.Credentials.PatreonAccessToken); -// var data = new PatreonData() -// { -// Links = new PatreonDataLinks() -// { -// next = "https://api.patreon.com/oauth2/api/campaigns/334038/pledges" -// } -// }; -// do -// { -// var res = await http.GetStringAsync(data.Links.next) -// .ConfigureAwait(false); -// data = JsonConvert.DeserializeObject(res); -// var pledgers = data.Data.Where(x => x["type"].ToString() == "pledge"); -// rewards.AddRange(pledgers.Select(x => JsonConvert.DeserializeObject(x.ToString())) -// .Where(x => x.attributes.declined_since == null)); -// users.AddRange(data.Included -// .Where(x => x["type"].ToString() == "user") -// .Select(x => JsonConvert.DeserializeObject(x.ToString()))); -// } while (!string.IsNullOrWhiteSpace(data.Links.next)); -// } -// Pledges = rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward() -// { -// User = y, -// Reward = x, -// }).ToImmutableArray(); -// } -// finally -// { -// var _ = Task.Run(async () => -// { -// await Task.Delay(TimeSpan.FromMinutes(5)).ConfigureAwait(false); -// getPledgesLocker.Release(); -// }); + public async Task ClaimReward(ulong userId) + { + await claimLockJustInCase.WaitAsync(); + try + { + var data = Pledges.FirstOrDefault(x => x.User.id == userId.ToString()); -// } -// } + if (data == null) + return 0; -// public async Task ClaimReward(ulong userId) -// { -// await claimLockJustInCase.WaitAsync(); -// try -// { -// var data = Pledges.FirstOrDefault(x => x.User.id == userId.ToString()); + var amount = data.Reward.attributes.amount_cents; -// if (data == null) -// return 0; + using (var uow = DbHandler.UnitOfWork()) + { + var users = uow._context.Set(); + var usr = users.FirstOrDefault(x => x.UserId == userId); -// var amount = data.Reward.attributes.amount_cents; + if (usr == null) + { + users.Add(new RewardedUser() + { + UserId = userId, + LastReward = DateTime.UtcNow, + AmountRewardedThisMonth = amount, + }); -// using (var uow = DbHandler.UnitOfWork()) -// { -// var users = uow._context.Set(); -// var usr = users.FirstOrDefault(x => x.UserId == userId); + await CurrencyHandler.AddCurrencyAsync(usr.UserId, "Patreon reward", amount, uow).ConfigureAwait(false); -// if (usr == null) -// { -// users.Add(new RewardedUser() -// { -// UserId = userId, -// LastReward = DateTime.UtcNow, -// AmountRewardedThisMonth = amount, -// }); -// await uow.CompleteAsync().ConfigureAwait(false); -// return amount; -// } + await uow.CompleteAsync().ConfigureAwait(false); + return amount; + } -// if (usr.AmountRewardedThisMonth < amount) -// { -// var toAward = amount - usr.AmountRewardedThisMonth; + if (usr.AmountRewardedThisMonth < amount) + { + var toAward = amount - usr.AmountRewardedThisMonth; -// usr.LastReward = DateTime.UtcNow; -// usr.AmountRewardedThisMonth = amount; + usr.LastReward = DateTime.UtcNow; + usr.AmountRewardedThisMonth = amount; -// await uow.CompleteAsync().ConfigureAwait(false); -// return toAward; -// } -// } -// return 0; -// } -// finally -// { -// claimLockJustInCase.Release(); -// } -// } -// } -// } -//} + await CurrencyHandler.AddCurrencyAsync(usr.UserId, "Patreon reward", toAward, uow).ConfigureAwait(false); + + await uow.CompleteAsync().ConfigureAwait(false); + return toAward; + } + } + return 0; + } + finally + { + claimLockJustInCase.Release(); + } + } + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index ef7c365a..76dac5be 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -1707,7 +1707,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to claimpatreonrewards. + /// Looks up a localized string similar to clparew. /// public static string claimpatreonrewards_cmd { get { @@ -1716,7 +1716,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to If you're subscribed to bot owner's patreon you can user this command to claim your rewards - assuming bot owner did setup has their patreon key.. + /// Looks up a localized string similar to Claim patreon rewards. If you're subscribed to bot owner's patreon you can user this command to claim your rewards - assuming bot owner did setup has their patreon key.. /// public static string claimpatreonrewards_desc { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 64236de1..f3662ef3 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3322,10 +3322,10 @@ `{0}warnpunish 5 Ban` or `{0}warnpunish 3` - claimpatreonrewards + clparew - If you're subscribed to bot owner's patreon you can user this command to claim your rewards - assuming bot owner did setup has their patreon key. + Claim patreon rewards. If you're subscribed to bot owner's patreon you can user this command to claim your rewards - assuming bot owner did setup has their patreon key. `{0}claimpatreonrewards` diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 5befa0b0..48394268 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -6028,81 +6028,81 @@ namespace NadekoBot.Resources { /// /// Looks up a localized string similar to Failed claiming rewards due to one of the following reasons:. /// - public static string utility_claimpatreon_fail { + public static string utility_clpa_fail { get { - return ResourceManager.GetString("utility_claimpatreon_fail", resourceCulture); + return ResourceManager.GetString("utility_clpa_fail", resourceCulture); } } /// /// Looks up a localized string similar to Maybe you have already received your reward for this month. You can receive rewards only once a month unless you increase your pledge.. /// - public static string utility_claimpatreon_fail_already { + public static string utility_clpa_fail_already { get { - return ResourceManager.GetString("utility_claimpatreon_fail_already", resourceCulture); + return ResourceManager.GetString("utility_clpa_fail_already", resourceCulture); } } /// /// Looks up a localized string similar to Already rewarded. /// - public static string utility_claimpatreon_fail_already_title { + public static string utility_clpa_fail_already_title { get { - return ResourceManager.GetString("utility_claimpatreon_fail_already_title", resourceCulture); + return ResourceManager.GetString("utility_clpa_fail_already_title", resourceCulture); } } /// /// Looks up a localized string similar to In order to be eligible for the reward, you must support the project on patreon. Use {0} command to get the link.. /// - public static string utility_claimpatreon_fail_sup { + public static string utility_clpa_fail_sup { get { - return ResourceManager.GetString("utility_claimpatreon_fail_sup", resourceCulture); + return ResourceManager.GetString("utility_clpa_fail_sup", resourceCulture); } } /// /// Looks up a localized string similar to Not supporting. /// - public static string utility_claimpatreon_fail_sup_title { + public static string utility_clpa_fail_sup_title { get { - return ResourceManager.GetString("utility_claimpatreon_fail_sup_title", resourceCulture); + return ResourceManager.GetString("utility_clpa_fail_sup_title", resourceCulture); } } /// /// Looks up a localized string similar to You have to wait a few hours after making your pledge, if you didn't, waiut a bit and then try again later.. /// - public static string utility_claimpatreon_fail_wait { + public static string utility_clpa_fail_wait { get { - return ResourceManager.GetString("utility_claimpatreon_fail_wait", resourceCulture); + return ResourceManager.GetString("utility_clpa_fail_wait", resourceCulture); } } /// /// Looks up a localized string similar to Wait some time. /// - public static string utility_claimpatreon_fail_wait_title { + public static string utility_clpa_fail_wait_title { get { - return ResourceManager.GetString("utility_claimpatreon_fail_wait_title", resourceCulture); + return ResourceManager.GetString("utility_clpa_fail_wait_title", resourceCulture); } } /// /// Looks up a localized string similar to You've received {0}. Thanks for supporting the project!. /// - public static string utility_claimpatreon_success { + public static string utility_clpa_success { get { - return ResourceManager.GetString("utility_claimpatreon_success", resourceCulture); + return ResourceManager.GetString("utility_clpa_success", resourceCulture); } } /// /// Looks up a localized string similar to Rewards can be claimed on or after 5th of each month.. /// - public static string utility_claimpatreon_too_early { + public static string utility_clpa_too_early { get { - return ResourceManager.GetString("utility_claimpatreon_too_early", resourceCulture); + return ResourceManager.GetString("utility_clpa_too_early", resourceCulture); } } diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 0a523218..105efa2b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2369,31 +2369,31 @@ Owner ID: {2} Slowmode will no longer ignore user {0} - + Failed claiming rewards due to one of the following reasons: - + Maybe you have already received your reward for this month. You can receive rewards only once a month unless you increase your pledge. - + Already rewarded - + In order to be eligible for the reward, you must support the project on patreon. Use {0} command to get the link. - + Not supporting - + You have to wait a few hours after making your pledge, if you didn't, waiut a bit and then try again later. - + Wait some time - + You've received {0}. Thanks for supporting the project! - + Rewards can be claimed on or after 5th of each month. \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/Models/RewardedUser.cs b/src/NadekoBot/Services/Database/Models/RewardedUser.cs index e71843b1..535f1354 100644 --- a/src/NadekoBot/Services/Database/Models/RewardedUser.cs +++ b/src/NadekoBot/Services/Database/Models/RewardedUser.cs @@ -1,11 +1,11 @@ -//using System; +using System; -//namespace NadekoBot.Services.Database.Models -//{ -// public class RewardedUser -// { -// public ulong UserId { get; set; } -// public int AmountRewardedThisMonth { get; set; } -// public DateTime LastReward { get; set; } -// } -//} +namespace NadekoBot.Services.Database.Models +{ + public class RewardedUser + { + public ulong UserId { get; set; } + public int AmountRewardedThisMonth { get; set; } + public DateTime LastReward { get; set; } + } +} From 3cec4f14d0ecb035e7e60b8825d9280d8b440016 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 2 Apr 2017 00:01:02 +0200 Subject: [PATCH 666/746] .clparew finished --- ...20170401205753_patreon-rewards.Designer.cs | 1456 +++++++++++++++++ .../20170401205753_patreon-rewards.cs | 40 + .../NadekoSqliteContextModelSnapshot.cs | 21 + .../Utility/Commands/PatreonCommands.cs | 41 +- .../Resources/ResponseStrings.Designer.cs | 24 +- src/NadekoBot/Resources/ResponseStrings.resx | 12 +- .../Database/Models/PatreonRewards.cs | 15 - .../Services/Database/Models/RewardedUser.cs | 2 +- .../Services/Database/NadekoContext.cs | 7 + 9 files changed, 1583 insertions(+), 35 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170401205753_patreon-rewards.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170401205753_patreon-rewards.cs delete mode 100644 src/NadekoBot/Services/Database/Models/PatreonRewards.cs diff --git a/src/NadekoBot/Migrations/20170401205753_patreon-rewards.Designer.cs b/src/NadekoBot/Migrations/20170401205753_patreon-rewards.Designer.cs new file mode 100644 index 00000000..e693300d --- /dev/null +++ b/src/NadekoBot/Migrations/20170401205753_patreon-rewards.Designer.cs @@ -0,0 +1,1456 @@ +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("20170401205753_patreon-rewards")] + partial class patreonrewards + { + 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("DateAdded"); + + 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.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Mapping"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("AutoDeleteTrigger"); + + b.Property("DateAdded"); + + b.Property("DmResponse"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.Property("WarningsInitialized"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissionv2"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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.RewardedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AmountRewardedThisMonth"); + + b.Property("DateAdded"); + + b.Property("LastReward"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("RewardedUsers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredRole"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ChannelId"); + + b.Property("ChannelName"); + + b.Property("CommandText"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("GuildName"); + + b.Property("Index"); + + b.Property("VoiceChannelId"); + + b.Property("VoiceChannelName"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("StartupCommand"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UnmuteAt"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.Property("VoiceChannelId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Forgiven"); + + b.Property("ForgivenBy"); + + b.Property("GuildId"); + + b.Property("Moderator"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Count"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Punishment"); + + b.Property("Time"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + + 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.CommandAlias", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId"); + }); + + 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.Permissionv2", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("Permissions") + .HasForeignKey("GuildConfigId"); + }); + + 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.SlowmodeIgnoredRole", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("StartupCommands") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId"); + }); + + 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); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170401205753_patreon-rewards.cs b/src/NadekoBot/Migrations/20170401205753_patreon-rewards.cs new file mode 100644 index 00000000..83057ff5 --- /dev/null +++ b/src/NadekoBot/Migrations/20170401205753_patreon-rewards.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class patreonrewards : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "RewardedUsers", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AmountRewardedThisMonth = table.Column(nullable: false), + DateAdded = table.Column(nullable: true), + LastReward = table.Column(nullable: false), + UserId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_RewardedUsers", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_RewardedUsers_UserId", + table: "RewardedUsers", + column: "UserId", + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "RewardedUsers"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 3f6df376..303783e4 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -931,6 +931,27 @@ namespace NadekoBot.Migrations b.ToTable("Reminders"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.RewardedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AmountRewardedThisMonth"); + + b.Property("DateAdded"); + + b.Property("LastReward"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("RewardedUsers"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => { b.Property("Id") diff --git a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs index 6415dd8f..e9b78014 100644 --- a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs @@ -12,6 +12,7 @@ using System.Collections.Immutable; using NadekoBot.Services; using NadekoBot.Services.Database.Models; using NadekoBot.Extensions; +using Discord; namespace NadekoBot.Modules.Utility { @@ -31,10 +32,11 @@ namespace NadekoBot.Modules.Utility { if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) return; - if (DateTime.UtcNow.Day < 5) - { - await ReplyErrorLocalized("clpa_too_early").ConfigureAwait(false); - } + //if (DateTime.UtcNow.Day < 5) + //{ + // await ReplyErrorLocalized("clpa_too_early").ConfigureAwait(false); + // return; + //} int amount = 0; try { @@ -50,12 +52,13 @@ namespace NadekoBot.Modules.Utility await ReplyConfirmLocalized("clpa_success", amount + NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); return; } - - await Context.Channel.EmbedAsync(new Discord.EmbedBuilder().WithOkColor() + var helpcmd = Format.Code(NadekoBot.ModulePrefixes[typeof(Help.Help).Name] + "donate"); + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithDescription(GetText("clpa_fail")) .AddField(efb => efb.WithName(GetText("clpa_fail_already_title")).WithValue(GetText("clpa_fail_already"))) .AddField(efb => efb.WithName(GetText("clpa_fail_wait_title")).WithValue(GetText("clpa_fail_wait"))) - .AddField(efb => efb.WithName(GetText("clpa_fail_sup_title")).WithValue(GetText("clpa_fail_sup")))) + .AddField(efb => efb.WithName(GetText("clpa_fail_conn_title")).WithValue(GetText("clpa_fail_conn"))) + .AddField(efb => efb.WithName(GetText("clpa_fail_sup_title")).WithValue(GetText("clpa_fail_sup", helpcmd)))) .ConfigureAwait(false); } } @@ -129,9 +132,10 @@ namespace NadekoBot.Modules.Utility public async Task ClaimReward(ulong userId) { await claimLockJustInCase.WaitAsync(); + var now = DateTime.UtcNow; try { - var data = Pledges.FirstOrDefault(x => x.User.id == userId.ToString()); + var data = Pledges.FirstOrDefault(x => x.User.attributes?.social_connections?.discord?.user_id == userId.ToString()); if (data == null) return 0; @@ -148,24 +152,35 @@ namespace NadekoBot.Modules.Utility users.Add(new RewardedUser() { UserId = userId, - LastReward = DateTime.UtcNow, + LastReward = now, AmountRewardedThisMonth = amount, }); - await CurrencyHandler.AddCurrencyAsync(usr.UserId, "Patreon reward", amount, uow).ConfigureAwait(false); + await CurrencyHandler.AddCurrencyAsync(userId, "Patreon reward - new", amount, uow).ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false); return amount; } - if (usr.AmountRewardedThisMonth < amount) + if (usr.LastReward.Month != now.Month) + { + usr.LastReward = now; + usr.AmountRewardedThisMonth = amount; + + await CurrencyHandler.AddCurrencyAsync(userId, "Patreon reward - recurring", amount, uow).ConfigureAwait(false); + + await uow.CompleteAsync().ConfigureAwait(false); + return amount; + } + + if ( usr.AmountRewardedThisMonth < amount) { var toAward = amount - usr.AmountRewardedThisMonth; - usr.LastReward = DateTime.UtcNow; + usr.LastReward = now; usr.AmountRewardedThisMonth = amount; - await CurrencyHandler.AddCurrencyAsync(usr.UserId, "Patreon reward", toAward, uow).ConfigureAwait(false); + await CurrencyHandler.AddCurrencyAsync(usr.UserId, "Patreon reward - update", toAward, uow).ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false); return toAward; diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 48394268..445e025b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -6035,7 +6035,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Maybe you have already received your reward for this month. You can receive rewards only once a month unless you increase your pledge.. + /// Looks up a localized string similar to Maybe you've already received your reward for this month. You can receive rewards only once a month unless you increase your pledge.. /// public static string utility_clpa_fail_already { get { @@ -6053,7 +6053,25 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to In order to be eligible for the reward, you must support the project on patreon. Use {0} command to get the link.. + /// Looks up a localized string similar to Your discord account might not be connected to Patreon.. If you are unsure what that means, or don't know how to connect it - you have to go to [Patreon account settings page](https://patreon.com/settings/account) and click 'Connect to discord' button.. + /// + public static string utility_clpa_fail_conn { + get { + return ResourceManager.GetString("utility_clpa_fail_conn", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Discord account not connected. + /// + public static string utility_clpa_fail_conn_title { + get { + return ResourceManager.GetString("utility_clpa_fail_conn_title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In order to be eligible for the reward, you must support the project on patreon. You can use {0} command to get the link.. /// public static string utility_clpa_fail_sup { get { @@ -6071,7 +6089,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to You have to wait a few hours after making your pledge, if you didn't, waiut a bit and then try again later.. + /// Looks up a localized string similar to You have to wait a few hours after making your pledge, if you didn't, try again later.. /// public static string utility_clpa_fail_wait { get { diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 105efa2b..4d605da8 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2373,19 +2373,25 @@ Owner ID: {2} Failed claiming rewards due to one of the following reasons: - Maybe you have already received your reward for this month. You can receive rewards only once a month unless you increase your pledge. + Maybe you've already received your reward for this month. You can receive rewards only once a month unless you increase your pledge. Already rewarded + + Your discord account might not be connected to Patreon.. If you are unsure what that means, or don't know how to connect it - you have to go to [Patreon account settings page](https://patreon.com/settings/account) and click 'Connect to discord' button. + + + Discord account not connected + - In order to be eligible for the reward, you must support the project on patreon. Use {0} command to get the link. + In order to be eligible for the reward, you must support the project on patreon. You can use {0} command to get the link. Not supporting - You have to wait a few hours after making your pledge, if you didn't, waiut a bit and then try again later. + You have to wait a few hours after making your pledge, if you didn't, try again later. Wait some time diff --git a/src/NadekoBot/Services/Database/Models/PatreonRewards.cs b/src/NadekoBot/Services/Database/Models/PatreonRewards.cs deleted file mode 100644 index 0e1532b3..00000000 --- a/src/NadekoBot/Services/Database/Models/PatreonRewards.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NadekoBot.Services.Database.Models -{ - public class PatreonRewards : DbEntity - { - public ulong UserId { get; set; } - public ulong PledgeCents { get; set; } - public ulong Awarded { get; set; } - } -} diff --git a/src/NadekoBot/Services/Database/Models/RewardedUser.cs b/src/NadekoBot/Services/Database/Models/RewardedUser.cs index 535f1354..f7db8dc4 100644 --- a/src/NadekoBot/Services/Database/Models/RewardedUser.cs +++ b/src/NadekoBot/Services/Database/Models/RewardedUser.cs @@ -2,7 +2,7 @@ namespace NadekoBot.Services.Database.Models { - public class RewardedUser + public class RewardedUser : DbEntity { public ulong UserId { get; set; } public int AmountRewardedThisMonth { get; set; } diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index a82cfde8..9c084867 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -51,6 +51,7 @@ namespace NadekoBot.Services.Database public DbSet EightBallResponses { get; set; } public DbSet RaceAnimals { get; set; } public DbSet ModulePrefixes { get; set; } + public DbSet RewardedUsers { get; set; } public NadekoContext() : base() { @@ -277,6 +278,12 @@ namespace NadekoBot.Services.Database #region Warnings var warn = modelBuilder.Entity(); #endregion + + #region PatreonRewards + var pr = modelBuilder.Entity(); + pr.HasIndex(x => x.UserId) + .IsUnique(); + #endregion } } } From c512f6360b0fe32d312fde5f28b89addfae5ea7b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 2 Apr 2017 00:25:26 +0200 Subject: [PATCH 667/746] .slowmodewl implemented and now works properly --- .../Commands/RatelimitCommand.cs | 45 ++++++++++--------- .../Resources/ResponseStrings.Designer.cs | 10 ++--- src/NadekoBot/Resources/ResponseStrings.resx | 10 ++--- .../Impl/GuildConfigRepository.cs | 2 + 4 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs index 0c0f91be..57dd4c89 100644 --- a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs @@ -5,7 +5,6 @@ using Microsoft.EntityFrameworkCore; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; -using NadekoBot.Services.Database; using NadekoBot.Services.Database.Models; using NLog; using System; @@ -20,16 +19,16 @@ namespace NadekoBot.Modules.Administration public partial class Administration { [Group] - public class RatelimitCommand : NadekoSubmodule + public class RatelimitCommands : NadekoSubmodule { public static ConcurrentDictionary RatelimitingChannels = new ConcurrentDictionary(); + public static ConcurrentDictionary> IgnoredRoles = new ConcurrentDictionary>(); + public static ConcurrentDictionary> IgnoredUsers = new ConcurrentDictionary>(); + private new static readonly Logger _log; public class Ratelimiter { - public HashSet IgnoreUsers { get; set; } = new HashSet(); - public HashSet IgnoreRoles { get; set; } = new HashSet(); - public class RatelimitedUser { public ulong UserId { get; set; } @@ -45,10 +44,13 @@ namespace NadekoBot.Modules.Administration public ConcurrentDictionary Users { get; set; } = new ConcurrentDictionary(); - public bool CheckUserRatelimit(ulong id, SocketGuildUser optUser) + public bool CheckUserRatelimit(ulong id, ulong guildId, SocketGuildUser optUser) { - if (IgnoreUsers.Contains(id) || - (optUser != null && optUser.RoleIds.Any(x => IgnoreRoles.Contains(x)))) + HashSet ignoreUsers; + HashSet ignoreRoles; + + if ((IgnoredUsers.TryGetValue(guildId, out ignoreUsers) && ignoreUsers.Contains(id)) || + (optUser != null && IgnoredRoles.TryGetValue(guildId, out ignoreRoles) && optUser.RoleIds.Any(x => ignoreRoles.Contains(x)))) return false; var usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id }); @@ -70,10 +72,20 @@ namespace NadekoBot.Modules.Administration } } - static RatelimitCommand() + static RatelimitCommands() { _log = LogManager.GetCurrentClassLogger(); + IgnoredRoles = new ConcurrentDictionary>( + NadekoBot.AllGuildConfigs + .ToDictionary(x => x.GuildId, + x => new HashSet(x.SlowmodeIgnoredRoles.Select(y => y.RoleId)))); + + IgnoredUsers = new ConcurrentDictionary>( + NadekoBot.AllGuildConfigs + .ToDictionary(x => x.GuildId, + x => new HashSet(x.SlowmodeIgnoredUsers.Select(y => y.UserId)))); + NadekoBot.Client.MessageReceived += async (umsg) => { try @@ -87,7 +99,7 @@ namespace NadekoBot.Modules.Administration if (!RatelimitingChannels.TryGetValue(channel.Id, out limiter)) return; - if (limiter.CheckUserRatelimit(usrMsg.Author.Id, usrMsg.Author as SocketGuildUser)) + if (limiter.CheckUserRatelimit(usrMsg.Author.Id, channel.Guild.Id, usrMsg.Author as SocketGuildUser)) await usrMsg.DeleteAsync(); } catch (Exception ex) { _log.Warn(ex); } @@ -157,11 +169,8 @@ namespace NadekoBot.Modules.Administration await uow.CompleteAsync().ConfigureAwait(false); } - Ratelimiter rl; - if (RatelimitingChannels.TryGetValue(Context.Guild.Id, out rl)) - { - rl.IgnoreUsers = new HashSet(usrs.Select(x => x.UserId)); - } + IgnoredUsers.AddOrUpdate(Context.Guild.Id, new HashSet(usrs.Select(x => x.UserId)), (key, old) => new HashSet(usrs.Select(x => x.UserId))); + if(removed) await ReplyConfirmLocalized("slowmodewl_user_stop", Format.Bold(user.ToString())).ConfigureAwait(false); else @@ -192,11 +201,7 @@ namespace NadekoBot.Modules.Administration await uow.CompleteAsync().ConfigureAwait(false); } - Ratelimiter rl; - if (RatelimitingChannels.TryGetValue(Context.Guild.Id, out rl)) - { - rl.IgnoreRoles = new HashSet(roles.Select(x => x.RoleId)); - } + IgnoredRoles.AddOrUpdate(Context.Guild.Id, new HashSet(roles.Select(x => x.RoleId)), (key, old) => new HashSet(roles.Select(x => x.RoleId))); if (removed) await ReplyConfirmLocalized("slowmodewl_role_stop", Format.Bold(role.ToString())).ConfigureAwait(false); diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 445e025b..e13d8513 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -1513,7 +1513,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Slowmode will now ignore role {0}. + /// Looks up a localized string similar to Slowmode will now ignore {0} role.. /// public static string administration_slowmodewl_role_start { get { @@ -1522,7 +1522,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Slowmode will no longer ignore role {0}. + /// Looks up a localized string similar to Slowmode will no longer ignore {0} role.. /// public static string administration_slowmodewl_role_stop { get { @@ -1531,7 +1531,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Slowmode will now ignore user {0}. + /// Looks up a localized string similar to Slowmode will now ignore user {0}.. /// public static string administration_slowmodewl_user_start { get { @@ -1540,7 +1540,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Slowmode will no longer ignore user {0}. + /// Looks up a localized string similar to Slowmode will no longer ignore user {0}.. /// public static string administration_slowmodewl_user_stop { get { @@ -6107,7 +6107,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to You've received {0}. Thanks for supporting the project!. + /// Looks up a localized string similar to You've received {0} Thanks for supporting the project!. /// public static string utility_clpa_success { get { diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 4d605da8..83d701f3 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2358,16 +2358,16 @@ Owner ID: {2} I will apply {0} punishment to users with {1} warnings. - Slowmode will now ignore role {0} + Slowmode will now ignore {0} role. - Slowmode will no longer ignore role {0} + Slowmode will no longer ignore {0} role. - Slowmode will now ignore user {0} + Slowmode will now ignore user {0}. - Slowmode will no longer ignore user {0} + Slowmode will no longer ignore user {0}. Failed claiming rewards due to one of the following reasons: @@ -2397,7 +2397,7 @@ Owner ID: {2} Wait some time - You've received {0}. Thanks for supporting the project! + You've received {0} Thanks for supporting the project! Rewards can be claimed on or after 5th of each month. diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index 01a44677..ebe41406 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -38,6 +38,8 @@ namespace NadekoBot.Services.Database.Repositories.Impl .Include(gc => gc.CommandCooldowns) .Include(gc => gc.GuildRepeaters) .Include(gc => gc.AntiRaidSetting) + .Include(gc => gc.SlowmodeIgnoredRoles) + .Include(gc => gc.SlowmodeIgnoredUsers) .Include(gc => gc.AntiSpamSetting) .ThenInclude(x => x.IgnoredChannels) .ToList(); From 3364f110a47f3e78b7d77c13a690ba45c4f9a5e9 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 2 Apr 2017 00:26:44 +0200 Subject: [PATCH 668/746] Startup commands will now run with 400ms delay between each other --- src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index 09924682..dcb36766 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -57,6 +57,7 @@ namespace NadekoBot.Modules.Administration } catch { } } + await Task.Delay(400).ConfigureAwait(false); } }); } From dfdfab44f7e28069944470c898544f3847c6813d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 2 Apr 2017 02:33:43 +0200 Subject: [PATCH 669/746] Woops, forgot to uncomment day check --- .../Modules/Utility/Commands/PatreonCommands.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs index e9b78014..303774f4 100644 --- a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs @@ -32,11 +32,11 @@ namespace NadekoBot.Modules.Utility { if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) return; - //if (DateTime.UtcNow.Day < 5) - //{ - // await ReplyErrorLocalized("clpa_too_early").ConfigureAwait(false); - // return; - //} + if (DateTime.UtcNow.Day < 5) + { + await ReplyErrorLocalized("clpa_too_early").ConfigureAwait(false); + return; + } int amount = 0; try { From e3a1d17d8e863eaa2fae1b9eac7a0984a37ba17a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 2 Apr 2017 12:45:35 +0200 Subject: [PATCH 670/746] $lb can't take negative page numbers anymore xD --- src/NadekoBot/Modules/Gambling/Gambling.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 760f8156..83db6048 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -246,6 +246,9 @@ namespace NadekoBot.Modules.Gambling [NadekoCommand, Usage, Description, Aliases] public async Task Leaderboard(int page = 1) { + if (page < 1) + return; + List richest; using (var uow = DbHandler.UnitOfWork()) { From 9afab5ad4c7afcb954b54bd30b9ae62f5bc4bb12 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sun, 2 Apr 2017 18:26:27 +0200 Subject: [PATCH 671/746] Update ResponseStrings.en-US.resx (POEditor.com) --- .../Resources/ResponseStrings.en-US.resx | 126 +++++++++++++++++- 1 file changed, 125 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.en-US.resx b/src/NadekoBot/Resources/ResponseStrings.en-US.resx index ccff686e..753f8135 100644 --- a/src/NadekoBot/Resources/ResponseStrings.en-US.resx +++ b/src/NadekoBot/Resources/ResponseStrings.en-US.resx @@ -740,7 +740,7 @@ Reason: {1} Slow mode initiated - soft-banned (kicked) + soft-banned PLURAL @@ -2278,5 +2278,129 @@ Owner ID: {2} Competitive playtime + + Channel + + + Command Text + + + Kicked + PLURAL + + + Moderator + + + page {0} + + + Reason + + + New startup command added. + + + Startup command successfully removed. + + + Startup command not found. + + + Server + + + No startup commands on this page. + + + Cleared all startup commands. + + + User {0} has been unbanned. + + + User not found. + + + User {0} has been warned. + + + User {0} has been warned and {1} punishment has been applied. + + + Warned on {0} server + + + On {0} at {1} by {2} + + + All warnings have been cleared for {0}. + + + No warning on this page. + + + Warnlog for {0} + + + No punishments set. + + + cleared by {0} + + + Warning punishment list + + + Having {0} warnings will no longer trigger a punishment. + + + I will apply {0} punishment to users with {1} warnings. + + + Slowmode will now ignore {0} role. + + + Slowmode will no longer ignore {0} role. + + + Slowmode will now ignore user {0}. + + + Slowmode will no longer ignore user {0}. + + + Failed claiming rewards due to one of the following reasons: + + + Maybe you've already received your reward for this month. You can receive rewards only once a month unless you increase your pledge. + + + Already rewarded + + + Your discord account might not be connected to Patreon. If you are unsure what that means, or don't know how to connect it - you have to go to [Patreon account settings page](https://patreon.com/settings/account) and click 'Connect to discord' button. + + + Discord account not connected + + + In order to be eligible for the reward, you must support the project on patreon. You can use {0} command to get the link. + + + Not supporting + + + You have to wait a few hours after making your pledge, if you didn't, try again later. + + + Wait some time + + + You've received {0} Thanks for supporting the project! + + + Rewards can be claimed on or after 5th of each month. + \ No newline at end of file From d256d520e4b12c5c89d83502d7f5e10b186d241e Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Sun, 2 Apr 2017 15:43:02 -0400 Subject: [PATCH 672/746] Add quote ID search --- .../Modules/Utility/Commands/QuoteCommands.cs | 48 ++++++++++++++++--- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index ea4bc674..37fdbf07 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -1,4 +1,4 @@ -using Discord; +using Discord; using Discord.Commands; using NadekoBot.Attributes; using NadekoBot.Extensions; @@ -100,7 +100,43 @@ namespace NadekoBot.Modules.Utility await Context.Channel.SendMessageAsync($"`#{keywordquote.Id}` 💬 " + keyword.ToLowerInvariant() + ": " + keywordquote.Text.SanitizeMentions()); } - + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task QuoteId(int id) + { + if (id < 0 || id > Int32.MaxValue) + return; + + using (var uow = DbHandler.UnitOfWork()) + { + var qfromid = uow.Quotes.Get(id); + CREmbed crembed; + + if (qfromid == null) + { + await Context.Channel.SendErrorAsync(GetText("quotes_notfound")); + } + else if (CREmbed.TryParse(qfromid.Text, out crembed)) + { + try + { + await Context.Channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "") + .ConfigureAwait(false); + } + catch (Exception ex) + { + _log.Warn("Sending CREmbed failed"); + _log.Warn(ex); + } + return; + } + + else { await Context.Channel.SendMessageAsync($"`#{qfromid.Id}` 🗯️ " + qfromid.Keyword.ToLowerInvariant() + ": " + + qfromid.Text.SanitizeMentions()); } + } + } + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] public async Task AddQuote(string keyword, [Remainder] string text) @@ -130,8 +166,8 @@ namespace NadekoBot.Modules.Utility public async Task DeleteQuote(int id) { var isAdmin = ((IGuildUser) Context.Message.Author).GuildPermissions.Administrator; - - var sucess = false; + + var success = false; string response; using (var uow = DbHandler.UnitOfWork()) { @@ -145,11 +181,11 @@ namespace NadekoBot.Modules.Utility { uow.Quotes.Remove(q); await uow.CompleteAsync().ConfigureAwait(false); - sucess = true; + success = true; response = GetText("quote_deleted", id); } } - if (sucess) + if (success) await Context.Channel.SendConfirmAsync(response); else await Context.Channel.SendErrorAsync(response); From 80c1c141b754fc5c3fa6f4e8a367e7e32b1abf42 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Sun, 2 Apr 2017 15:44:15 -0400 Subject: [PATCH 673/746] Update CommandStrings.resx --- src/NadekoBot/Resources/CommandStrings.resx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index f3662ef3..cbdfc5b3 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -1151,6 +1151,15 @@ `{0}qsearch keyword text` + + + quoteid qid + + + Displays the quote with the specified ID number. Quote ID numbers can be found by typing `.liqu [num]` where `[num]` is a number of a page which contains 15 quotes. + + + `{0}qid 123456` deletequote delq @@ -3339,4 +3348,4 @@ `{0}slowmodewl SomeRole` or `{0}slowmodewl AdminDude` - \ No newline at end of file + From 44e8939a5beefdcc289a0aede312340bb7288e4a Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Sun, 2 Apr 2017 15:46:30 -0400 Subject: [PATCH 674/746] Update CommandStrings.Designer.cs --- .../Resources/CommandStrings.Designer.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 76dac5be..437ef468 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -5729,6 +5729,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar quoteid qid. + /// + public static string quoteid_cmd { + get { + return ResourceManager.GetString("quoteid_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Displays the quote with the specified ID number. Quote ID numbers can be found by typing `.liqu [num]` where `[num]` is a number of a page which contains 15 quotes.. + /// + public static string quoteid_desc { + get { + return ResourceManager.GetString("quoteid_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}qid 123456`. + /// + public static string quoteid_usage { + get { + return ResourceManager.GetString("quoteid_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to race. /// From 510a46698592605ffb8a2a7f65c98fa433a4a4e5 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 2 Apr 2017 21:47:35 +0200 Subject: [PATCH 675/746] Aliased commands now do take extra parameters while aliased --- .../Resources/ResponseStrings.Designer.cs | 2 +- src/NadekoBot/Resources/ResponseStrings.resx | 2 +- src/NadekoBot/Services/CommandHandler.cs | 19 ++++++++++++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index e13d8513..ce51f8f4 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -6053,7 +6053,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Your discord account might not be connected to Patreon.. If you are unsure what that means, or don't know how to connect it - you have to go to [Patreon account settings page](https://patreon.com/settings/account) and click 'Connect to discord' button.. + /// Looks up a localized string similar to Your discord account might not be connected to Patreon. If you are unsure what that means, or don't know how to connect it - you have to go to [Patreon account settings page](https://patreon.com/settings/account) and click 'Connect to discord' button.. /// public static string utility_clpa_fail_conn { get { diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 83d701f3..42a22f42 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2379,7 +2379,7 @@ Owner ID: {2} Already rewarded - Your discord account might not be connected to Patreon.. If you are unsure what that means, or don't know how to connect it - you have to go to [Patreon account settings page](https://patreon.com/settings/account) and click 'Connect to discord' button. + Your discord account might not be connected to Patreon. If you are unsure what that means, or don't know how to connect it - you have to go to [Patreon account settings page](https://patreon.com/settings/account) and click 'Connect to discord' button. Discord account not connected diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 31f30932..f47e45d5 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -342,10 +342,22 @@ namespace NadekoBot.Services ConcurrentDictionary maps; if (Modules.Utility.Utility.CommandMapCommands.AliasMaps.TryGetValue(guild.Id, out maps)) { - string newMessageContent; - if (maps.TryGetValue(messageContent.Trim().ToLowerInvariant(), out newMessageContent)) + + var keys = maps.Keys + .OrderByDescending(x => x.Length); + + var lowerMessageContent = messageContent.ToLowerInvariant(); + foreach (var k in keys) { - _log.Info(@"--Mapping Command-- + string newMessageContent; + if (lowerMessageContent.StartsWith(k + " ")) + newMessageContent = maps[k] + messageContent.Substring(k.Length, messageContent.Length - k.Length); + else if (lowerMessageContent == k) + newMessageContent = maps[k]; + else + continue; + + _log.Info(@"--Mapping Command-- GuildId: {0} Trigger: {1} Mapping: {2}", guild.Id, messageContent, newMessageContent); @@ -353,6 +365,7 @@ namespace NadekoBot.Services messageContent = newMessageContent; try { await usrMsg.Channel.SendConfirmAsync($"{oldMessageContent} => {newMessageContent}").ConfigureAwait(false); } catch { } + break; } } } From a4d78dfc0d45b49c798428521a4e358467030dc3 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Sun, 2 Apr 2017 15:48:17 -0400 Subject: [PATCH 676/746] Update ResponseStrings.resx --- src/NadekoBot/Resources/ResponseStrings.resx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 83d701f3..a8b2d0bb 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2083,6 +2083,9 @@ Owner ID: {2} No quotes on this page. + + No quotes found matching the quote ID specified. + No quotes found which you can remove. @@ -2402,4 +2405,4 @@ Owner ID: {2} Rewards can be claimed on or after 5th of each month. - \ No newline at end of file + From 34b4884ec41186b52b6f4164e29f4c624b67c4b3 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Sun, 2 Apr 2017 15:49:43 -0400 Subject: [PATCH 677/746] Update ResponseStrings.Designer.cs --- src/NadekoBot/Resources/ResponseStrings.Designer.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index e13d8513..1aa7c15e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -6506,6 +6506,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to No quotes found matching the quote ID specified.. + /// + public static string utility_quotes_notfound { + get { + return ResourceManager.GetString("utility_quotes_notfound", resourceCulture); + } + } + /// /// Looks up a localized string similar to No quotes found which you can remove.. /// From 43d8f1997a1b95bd55fb9bca03ab7cc2e620a366 Mon Sep 17 00:00:00 2001 From: Shikhir Arora Date: Sun, 2 Apr 2017 15:57:56 -0400 Subject: [PATCH 678/746] Update QuoteCommands.cs --- src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index 37fdbf07..b8819255 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -105,7 +105,7 @@ namespace NadekoBot.Modules.Utility [RequireContext(ContextType.Guild)] public async Task QuoteId(int id) { - if (id < 0 || id > Int32.MaxValue) + if (id < 0) return; using (var uow = DbHandler.UnitOfWork()) From d0380b0cbfc2ce45b5f4b0dcc07e32e198b3603e Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 3 Apr 2017 12:43:59 +0200 Subject: [PATCH 679/746] .ping command added --- src/NadekoBot/Modules/Utility/Utility.cs | 12 ++++++++++++ src/NadekoBot/Resources/CommandStrings.resx | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index ee92b771..1ac77e73 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -16,6 +16,7 @@ using System.Collections.Generic; using Newtonsoft.Json; using Discord.WebSocket; using NadekoBot.Services; +using System.Diagnostics; namespace NadekoBot.Modules.Utility { @@ -494,5 +495,16 @@ namespace NadekoBot.Modules.Utility await Context.User.SendFileAsync( await JsonConvert.SerializeObject(grouping, Formatting.Indented).ToStream().ConfigureAwait(false), title, title).ConfigureAwait(false); } + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task Ping() + { + var sw = Stopwatch.StartNew(); + var msg = await Context.Channel.SendMessageAsync("🏓").ConfigureAwait(false); + sw.Stop(); + msg.DeleteAfter(0); + + await Context.Channel.SendConfirmAsync($"{Format.Bold(Context.User.ToString())} 🏓 {(int)sw.Elapsed.TotalMilliseconds}ms").ConfigureAwait(false); + } } } \ No newline at end of file diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index f3662ef3..83d9659b 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3330,6 +3330,15 @@ `{0}claimpatreonrewards` + + ping + + + Ping the bot to see if there are latency issues. + + + `{0}ping` + slowmodewl From 6817b1ba0746ab2a281710fd2fdfe45af358de9f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 3 Apr 2017 14:30:31 +0200 Subject: [PATCH 680/746] .rar, .sr, .renr and .rr will now work only on roles lower than your highest role --- .../Modules/Administration/Administration.cs | 18 +++++++++++-- .../Resources/CommandStrings.Designer.cs | 27 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 905243ba..4eec4ebd 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -11,7 +11,6 @@ using Discord.WebSocket; using NadekoBot.Services.Database.Models; using static NadekoBot.Modules.Permissions.Permissions; using System.Collections.Concurrent; -using Microsoft.EntityFrameworkCore; using NLog; namespace NadekoBot.Modules.Administration @@ -99,6 +98,10 @@ namespace NadekoBot.Modules.Administration [RequireBotPermission(GuildPermission.ManageRoles)] public async Task Setrole(IGuildUser usr, [Remainder] IRole role) { + var guser = (IGuildUser)Context.User; + var maxRole = guser.GetRoles().Max(x => x.Position); + if (maxRole < role.Position || maxRole <= usr.GetRoles().Max(x => x.Position)) + return; try { await usr.AddRolesAsync(role).ConfigureAwait(false); @@ -118,6 +121,9 @@ namespace NadekoBot.Modules.Administration [RequireBotPermission(GuildPermission.ManageRoles)] public async Task Removerole(IGuildUser usr, [Remainder] IRole role) { + var guser = (IGuildUser)Context.User; + if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= usr.GetRoles().Max(x => x.Position)) + return; try { await usr.RemoveRolesAsync(role).ConfigureAwait(false); @@ -135,6 +141,9 @@ namespace NadekoBot.Modules.Administration [RequireBotPermission(GuildPermission.ManageRoles)] public async Task RenameRole(IRole roleToEdit, string newname) { + var guser = (IGuildUser)Context.User; + if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= roleToEdit.Position) + return; try { if (roleToEdit.Position > (await Context.Guild.GetCurrentUserAsync().ConfigureAwait(false)).GetRoles().Max(r => r.Position)) @@ -157,9 +166,14 @@ namespace NadekoBot.Modules.Administration [RequireBotPermission(GuildPermission.ManageRoles)] public async Task RemoveAllRoles([Remainder] IGuildUser user) { + var guser = (IGuildUser)Context.User; + + var userRoles = user.GetRoles(); + if (guser.Id != Context.Guild.OwnerId && (user.Id == Context.Guild.OwnerId || guser.GetRoles().Max(x => x.Position) <= userRoles.Max(x => x.Position))) + return; try { - await user.RemoveRolesAsync(user.GetRoles()).ConfigureAwait(false); + await user.RemoveRolesAsync(userRoles).ConfigureAwait(false); await ReplyConfirmLocalized("rar", Format.Bold(user.ToString())).ConfigureAwait(false); } catch diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 76dac5be..865609b2 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -5378,6 +5378,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to ping. + /// + public static string ping_cmd { + get { + return ResourceManager.GetString("ping_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ping the bot to see if there are latency issues.. + /// + public static string ping_desc { + get { + return ResourceManager.GetString("ping_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}ping`. + /// + public static string ping_usage { + get { + return ResourceManager.GetString("ping_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to place. /// From 3e1b5d7e572a064c2ea4712de868eb9f172fa40c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 3 Apr 2017 23:18:18 +0200 Subject: [PATCH 681/746] some small fixes, .time added, closes #989 --- .../Modules/Administration/Administration.cs | 3 +- .../Commands/AutoAssignRoleCommands.cs | 6 +++ .../Commands/SelfAssignedRolesCommand.cs | 8 ++++ .../Searches/Commands/Models/TimeModels.cs | 42 +++++++++++++++++++ src/NadekoBot/Modules/Searches/Searches.cs | 21 ++++++++++ .../Resources/CommandStrings.Designer.cs | 29 ++++++++++++- src/NadekoBot/Resources/CommandStrings.resx | 13 +++++- .../Resources/ResponseStrings.Designer.cs | 20 ++++----- src/NadekoBot/Resources/ResponseStrings.resx | 9 ++-- src/NadekoBot/_Extensions/Extensions.cs | 2 +- 10 files changed, 134 insertions(+), 19 deletions(-) create mode 100644 src/NadekoBot/Modules/Searches/Commands/Models/TimeModels.cs diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 4eec4ebd..6ecefe10 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -169,7 +169,8 @@ namespace NadekoBot.Modules.Administration var guser = (IGuildUser)Context.User; var userRoles = user.GetRoles(); - if (guser.Id != Context.Guild.OwnerId && (user.Id == Context.Guild.OwnerId || guser.GetRoles().Max(x => x.Position) <= userRoles.Max(x => x.Position))) + if (guser.Id != Context.Guild.OwnerId && + (user.Id == Context.Guild.OwnerId || guser.GetRoles().Max(x => x.Position) <= userRoles.Max(x => x.Position))) return; try { diff --git a/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs b/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs index 98a8844f..13a3422a 100644 --- a/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/AutoAssignRoleCommands.cs @@ -1,6 +1,7 @@ using Discord; using Discord.Commands; using NadekoBot.Attributes; +using NadekoBot.Extensions; using NadekoBot.Services; using NLog; using System; @@ -48,6 +49,11 @@ namespace NadekoBot.Modules.Administration [RequireUserPermission(GuildPermission.ManageRoles)] public async Task AutoAssignRole([Remainder] IRole role = null) { + var guser = (IGuildUser)Context.User; + if (role != null) + if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position) + return; + using (var uow = DbHandler.UnitOfWork()) { var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set); diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs b/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs index 6ac60f21..e13a278f 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs @@ -43,6 +43,10 @@ namespace NadekoBot.Modules.Administration { IEnumerable roles; + var guser = (IGuildUser)Context.User; + if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position) + return; + string msg; var error = false; using (var uow = DbHandler.UnitOfWork()) @@ -75,6 +79,10 @@ namespace NadekoBot.Modules.Administration [RequireUserPermission(GuildPermission.ManageRoles)] public async Task Rsar([Remainder] IRole role) { + var guser = (IGuildUser)Context.User; + if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position) + return; + bool success; using (var uow = DbHandler.UnitOfWork()) { diff --git a/src/NadekoBot/Modules/Searches/Commands/Models/TimeModels.cs b/src/NadekoBot/Modules/Searches/Commands/Models/TimeModels.cs new file mode 100644 index 00000000..e997b78c --- /dev/null +++ b/src/NadekoBot/Modules/Searches/Commands/Models/TimeModels.cs @@ -0,0 +1,42 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Searches.Commands.Models +{ + public class TimeZoneResult + { + public double DstOffset { get; set; } + public double RawOffset { get; set; } + + //public string TimeZoneId { get; set; } + public string TimeZoneName { get; set; } + } + + public class GeolocationResult + { + + public class GeolocationModel + { + public class GeometryModel + { + public class LocationModel + { + public float Lat { get; set; } + public float Lng { get; set; } + } + + public LocationModel Location { get; set; } + } + + [JsonProperty("formatted_address")] + public string FormattedAddress { get; set; } + public GeometryModel Geometry { get; set; } + } + + public GeolocationModel[] results; + } +} diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 472a17d5..3e6aa1bc 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -56,6 +56,27 @@ namespace NadekoBot.Modules.Searches await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } + [NadekoCommand, Usage, Description, Aliases] + public async Task Time([Remainder] string arg) + { + if (string.IsNullOrWhiteSpace(arg) || string.IsNullOrWhiteSpace(NadekoBot.Credentials.GoogleApiKey)) + return; + + using (var http = new HttpClient()) + { + var res = await http.GetStringAsync($"https://maps.googleapis.com/maps/api/geocode/json?address={arg}&key={NadekoBot.Credentials.GoogleApiKey}").ConfigureAwait(false); + var obj = JsonConvert.DeserializeObject(res); + + var currentSeconds = DateTime.UtcNow.UnixTimestamp(); + var timeRes = await http.GetStringAsync($"https://maps.googleapis.com/maps/api/timezone/json?location={obj.results[0].Geometry.Location.Lat},{obj.results[0].Geometry.Location.Lng}×tamp={currentSeconds}&key={NadekoBot.Credentials.GoogleApiKey}").ConfigureAwait(false); + var timeObj = JsonConvert.DeserializeObject(timeRes); + + var time = DateTime.UtcNow.AddSeconds(timeObj.DstOffset + timeObj.RawOffset); + + await ReplyConfirmLocalized("time", Format.Bold(obj.results[0].FormattedAddress), Format.Code(time.ToString("HH:mm")), timeObj.TimeZoneName).ConfigureAwait(false); + } + } + [NadekoCommand, Usage, Description, Aliases] public async Task Youtube([Remainder] string query = null) { diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index c3e4c03b..c8f3ed92 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -5757,7 +5757,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar quoteid qid. + /// Looks up a localized string similar to quoteid qid. /// public static string quoteid_cmd { get { @@ -8267,6 +8267,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to time. + /// + public static string time_cmd { + get { + return ResourceManager.GetString("time_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows the current time and timezone in the specified location.. + /// + public static string time_desc { + get { + return ResourceManager.GetString("time_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}time London, UK`. + /// + public static string time_usage { + get { + return ResourceManager.GetString("time_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to timezone. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index ec1f2125..1d5479ab 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -1152,7 +1152,7 @@ `{0}qsearch keyword text` - + quoteid qid @@ -3357,4 +3357,13 @@ `{0}slowmodewl SomeRole` or `{0}slowmodewl AdminDude` - + + time + + + Shows the current time and timezone in the specified location. + + + `{0}time London, UK` + + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 9561c996..f4171166 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -5773,6 +5773,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Time in {0} is {1} - {2}. + /// + public static string searches_time { + get { + return ResourceManager.GetString("searches_time", resourceCulture); + } + } + /// /// Looks up a localized string similar to Title:. /// @@ -6498,7 +6507,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to No quotes on this page.. + /// Looks up a localized string similar to No quotes found matching the quote ID specified.. /// public static string utility_quotes_page_none { get { @@ -6506,15 +6515,6 @@ namespace NadekoBot.Resources { } } - /// - /// Looks up a localized string similar to No quotes found matching the quote ID specified.. - /// - public static string utility_quotes_notfound { - get { - return ResourceManager.GetString("utility_quotes_notfound", resourceCulture); - } - } - /// /// Looks up a localized string similar to No quotes found which you can remove.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 31b11e93..2a1d1e7f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2082,10 +2082,7 @@ Owner ID: {2} Page {0} of quotes - No quotes on this page. - No quotes found matching the quote ID specified. - No quotes found which you can remove. @@ -2405,4 +2402,8 @@ Owner ID: {2} Rewards can be claimed on or after 5th of each month. - + + Time in {0} is {1} - {2} + Time in London, UK is 15:30 - Time Zone Name + + \ No newline at end of file diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index b880944c..52d8ab3a 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -193,7 +193,7 @@ namespace NadekoBot.Extensions public static string SanitizeMentions(this string str) => str.Replace("@everyone", "@everyοne").Replace("@here", "@һere"); - public static double UnixTimestamp(this DateTime dt) => dt.ToUniversalTime().Subtract(new DateTime(1970, 1, 1)).TotalSeconds; + public static double UnixTimestamp(this DateTime dt) => dt.ToUniversalTime().Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds; public static async Task SendMessageAsync(this IUser user, string message, bool isTTS = false) => await (await user.CreateDMChannelAsync().ConfigureAwait(false)).SendMessageAsync(message, isTTS).ConfigureAwait(false); From bbda4c7a3bb35e68330ab8da50e7277df906c87e Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 4 Apr 2017 01:50:27 +0200 Subject: [PATCH 682/746] disabling >cleverbot with permissions will also disable talking with chatterbot --- .../Games/Commands/CleverBotCommands.cs | 28 ++++++---- .../Modules/Permissions/Permissions.cs | 18 ++++++ src/NadekoBot/Services/CommandHandler.cs | 55 +++++++++---------- 3 files changed, 63 insertions(+), 38 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs index fd426be3..fcaecc98 100644 --- a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs @@ -40,16 +40,19 @@ namespace NadekoBot.Modules.Games _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); } - public static async Task TryAsk(IUserMessage msg) + public static string PrepareMessage(IUserMessage msg, out ChatterBotSession cleverbot) { var channel = msg.Channel as ITextChannel; + cleverbot = null; if (channel == null) - return false; + return null; - Lazy cleverbot; - if (!CleverbotGuilds.TryGetValue(channel.Guild.Id, out cleverbot)) - return false; + Lazy lazyCleverbot; + if (!CleverbotGuilds.TryGetValue(channel.Guild.Id, out lazyCleverbot)) + return null; + + cleverbot = lazyCleverbot.Value; var nadekoId = NadekoBot.Client.CurrentUser.Id; var normalMention = $"<@{nadekoId}> "; @@ -65,19 +68,24 @@ namespace NadekoBot.Modules.Games } else { - return false; + return null; } - await msg.Channel.TriggerTypingAsync().ConfigureAwait(false); + return message; + } - var response = await cleverbot.Value.Think(message).ConfigureAwait(false); + public static async Task TryAsk(ChatterBotSession cleverbot, ITextChannel channel, string message) + { + await channel.TriggerTypingAsync().ConfigureAwait(false); + + var response = await cleverbot.Think(message).ConfigureAwait(false); try { - await msg.Channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false); + await channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false); } catch { - await msg.Channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false); // try twice :\ + await channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false); // try twice :\ } return true; } diff --git a/src/NadekoBot/Modules/Permissions/Permissions.cs b/src/NadekoBot/Modules/Permissions/Permissions.cs index ec0e1016..a942fd7e 100644 --- a/src/NadekoBot/Modules/Permissions/Permissions.cs +++ b/src/NadekoBot/Modules/Permissions/Permissions.cs @@ -62,6 +62,24 @@ namespace NadekoBot.Modules.Permissions log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); } + public static PermissionCache GetCache(ulong guildId) + { + PermissionCache pc; + if (!Permissions.Cache.TryGetValue(guildId, out pc)) + { + using (var uow = DbHandler.UnitOfWork()) + { + var config = uow.GuildConfigs.For(guildId, + set => set.Include(x => x.Permissions)); + Permissions.UpdateCache(config); + } + Permissions.Cache.TryGetValue(guildId, out pc); + if (pc == null) + throw new Exception("Cache is null."); + } + return pc; + } + private static void TryMigratePermissions() { var log = LogManager.GetCurrentClassLogger(); diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index f47e45d5..5c4fa19c 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -18,6 +18,7 @@ using System.Collections.Concurrent; using System.Threading; using Microsoft.EntityFrameworkCore; using NadekoBot.DataStructures; +using Services.CleverBotApi; namespace NadekoBot.Services { @@ -109,13 +110,33 @@ namespace NadekoBot.Services return Task.CompletedTask; } - private async Task TryRunCleverbot(IUserMessage usrMsg, IGuild guild) + private async Task TryRunCleverbot(IUserMessage usrMsg, SocketGuild guild) { if (guild == null) return false; try { - var cleverbotExecuted = await Games.CleverBotCommands.TryAsk(usrMsg).ConfigureAwait(false); + Games.ChatterBotSession cbs; + var message = Games.CleverBotCommands.PrepareMessage(usrMsg, out cbs); + if(message == null || cbs == null) + return false; + + PermissionCache pc = Permissions.GetCache(guild.Id); + int index; + if ( + !pc.Permissions.CheckPermissions(usrMsg, + NadekoBot.ModulePrefixes[typeof(Games).Name] + "cleverbot", + typeof(Games).Name, + out index)) + { + //todo print in guild actually + var returnMsg = + $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action."; + _log.Info(returnMsg); + return true; + } + + var cleverbotExecuted = await Games.CleverBotCommands.TryAsk(cbs, (ITextChannel)usrMsg.Channel, message).ConfigureAwait(false); if (cleverbotExecuted) { _log.Info($@"CleverBot Executed @@ -278,6 +299,7 @@ namespace NadekoBot.Services return; var exec1 = Environment.TickCount - execTime; + var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false); if (cleverBotRan) @@ -294,19 +316,8 @@ namespace NadekoBot.Services { if (guild != null) { - PermissionCache pc; - if (!Permissions.Cache.TryGetValue(guild.Id, out pc)) - { - using (var uow = DbHandler.UnitOfWork()) - { - var config = uow.GuildConfigs.For(guild.Id, - set => set.Include(x => x.Permissions)); - Permissions.UpdateCache(config); - } - Permissions.Cache.TryGetValue(guild.Id, out pc); - if (pc == null) - throw new Exception("Cache is null."); - } + PermissionCache pc = Permissions.GetCache(guild.Id); + int index; if ( !pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions", @@ -457,21 +468,9 @@ namespace NadekoBot.Services var cmd = commands[i].Command; var resetCommand = cmd.Name == "resetperms"; var module = cmd.Module.GetTopLevelModule(); - PermissionCache pc; if (context.Guild != null) { - //todo move to permissions module? - if (!Permissions.Cache.TryGetValue(context.Guild.Id, out pc)) - { - using (var uow = DbHandler.UnitOfWork()) - { - var config = uow.GuildConfigs.GcWithPermissionsv2For(context.Guild.Id); - Permissions.UpdateCache(config); - } - Permissions.Cache.TryGetValue(context.Guild.Id, out pc); - if(pc == null) - throw new Exception("Cache is null."); - } + PermissionCache pc = Permissions.GetCache(context.Guild.Id); int index; if (!resetCommand && !pc.Permissions.CheckPermissions(context.Message, cmd.Aliases.First(), module.Name, out index)) { From af744cb3d74138bbe4128c2aba87127e74451693 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 4 Apr 2017 01:52:51 +0200 Subject: [PATCH 683/746] Removed old cleverbot stuff --- .../Games/Commands/CleverBotCommands.cs | 3 - .../Services/CleverBotApi/ChatterBot.cs | 25 --- .../CleverBotApi/ChatterBotFactory.cs | 51 ------ .../CleverBotApi/ChatterBotSession.cs | 28 ---- .../CleverBotApi/ChatterBotThought.cs | 26 --- .../Services/CleverBotApi/ChatterBotType.cs | 27 ---- .../Services/CleverBotApi/Cleverbot.cs | 116 -------------- .../Services/CleverBotApi/Pandorabots.cs | 68 -------- src/NadekoBot/Services/CleverBotApi/Utils.cs | 148 ------------------ src/NadekoBot/Services/CommandHandler.cs | 2 - 10 files changed, 494 deletions(-) delete mode 100644 src/NadekoBot/Services/CleverBotApi/ChatterBot.cs delete mode 100644 src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs delete mode 100644 src/NadekoBot/Services/CleverBotApi/ChatterBotSession.cs delete mode 100644 src/NadekoBot/Services/CleverBotApi/ChatterBotThought.cs delete mode 100644 src/NadekoBot/Services/CleverBotApi/ChatterBotType.cs delete mode 100644 src/NadekoBot/Services/CleverBotApi/Cleverbot.cs delete mode 100644 src/NadekoBot/Services/CleverBotApi/Pandorabots.cs delete mode 100644 src/NadekoBot/Services/CleverBotApi/Utils.cs diff --git a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs index fcaecc98..8abb47d5 100644 --- a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs @@ -1,11 +1,9 @@ using Discord; using Discord.Commands; -using Discord.WebSocket; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; using NLog; -//using Services.CleverBotApi; using System; using System.Collections.Concurrent; using System.Diagnostics; @@ -13,7 +11,6 @@ using System.Linq; using System.Net.Http; using System.Threading.Tasks; using Newtonsoft.Json; -using Services.CleverBotApi; namespace NadekoBot.Modules.Games { diff --git a/src/NadekoBot/Services/CleverBotApi/ChatterBot.cs b/src/NadekoBot/Services/CleverBotApi/ChatterBot.cs deleted file mode 100644 index 746b44aa..00000000 --- a/src/NadekoBot/Services/CleverBotApi/ChatterBot.cs +++ /dev/null @@ -1,25 +0,0 @@ - /* - ChatterBotAPI - Copyright (C) 2011 pierredavidbelanger@gmail.com - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -namespace Services.CleverBotApi -{ - public interface ChatterBot - { - ChatterBotSession CreateSession(); - } -} \ No newline at end of file diff --git a/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs b/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs deleted file mode 100644 index e183c249..00000000 --- a/src/NadekoBot/Services/CleverBotApi/ChatterBotFactory.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; - -/* - ChatterBotAPI - Copyright (C) 2011 pierredavidbelanger@gmail.com - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -namespace Services.CleverBotApi -{ - public class ChatterBotFactory - { - public static ChatterBot Create(ChatterBotType type) - { - return Create(type, null); - } - - public static ChatterBot Create(ChatterBotType type, object arg) - { -#if GLOBAL_NADEKO - var url = "http://www.cleverbot.com/webservicemin?uc=777&botapi=nadekobot"; -#else - var url = "http://www.cleverbot.com/webservicemin?uc=777&botapi=chatterbotapi"; -#endif - - switch (type) - { - case ChatterBotType.CLEVERBOT: - return new Cleverbot("http://www.cleverbot.com/", url, 26); - case ChatterBotType.JABBERWACKY: - return new Cleverbot("http://jabberwacky.com", "http://jabberwacky.com/webservicemin", 20); - case ChatterBotType.PANDORABOTS: - if (arg == null) throw new ArgumentException("PANDORABOTS needs a botid arg", nameof(arg)); - return new Pandorabots(arg.ToString()); - } - return null; - } - } -} \ No newline at end of file diff --git a/src/NadekoBot/Services/CleverBotApi/ChatterBotSession.cs b/src/NadekoBot/Services/CleverBotApi/ChatterBotSession.cs deleted file mode 100644 index 0f063571..00000000 --- a/src/NadekoBot/Services/CleverBotApi/ChatterBotSession.cs +++ /dev/null @@ -1,28 +0,0 @@ -/* - ChatterBotAPI - Copyright (C) 2011 pierredavidbelanger@gmail.com - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -using System.Threading.Tasks; - -namespace Services.CleverBotApi -{ - public interface ChatterBotSession - { - Task Think(ChatterBotThought thought); - Task Think(string text); - } -} \ No newline at end of file diff --git a/src/NadekoBot/Services/CleverBotApi/ChatterBotThought.cs b/src/NadekoBot/Services/CleverBotApi/ChatterBotThought.cs deleted file mode 100644 index 1a385642..00000000 --- a/src/NadekoBot/Services/CleverBotApi/ChatterBotThought.cs +++ /dev/null @@ -1,26 +0,0 @@ -/* - ChatterBotAPI - Copyright (C) 2011 pierredavidbelanger@gmail.com - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -namespace Services.CleverBotApi -{ - public class ChatterBotThought - { - public string[] Emotions { get; set; } - public string Text { get; set; } - } -} \ No newline at end of file diff --git a/src/NadekoBot/Services/CleverBotApi/ChatterBotType.cs b/src/NadekoBot/Services/CleverBotApi/ChatterBotType.cs deleted file mode 100644 index e4e8fab8..00000000 --- a/src/NadekoBot/Services/CleverBotApi/ChatterBotType.cs +++ /dev/null @@ -1,27 +0,0 @@ -/* - ChatterBotAPI - Copyright (C) 2011 pierredavidbelanger@gmail.com - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -namespace Services.CleverBotApi -{ - public enum ChatterBotType - { - CLEVERBOT, - JABBERWACKY, - PANDORABOTS - } -} \ No newline at end of file diff --git a/src/NadekoBot/Services/CleverBotApi/Cleverbot.cs b/src/NadekoBot/Services/CleverBotApi/Cleverbot.cs deleted file mode 100644 index 45109863..00000000 --- a/src/NadekoBot/Services/CleverBotApi/Cleverbot.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System.Collections.Generic; -using System.Net; -using System.Threading.Tasks; - -/* - ChatterBotAPI - Copyright (C) 2011 pierredavidbelanger@gmail.com - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -namespace Services.CleverBotApi -{ - public class Cleverbot : ChatterBot - { - private readonly int endIndex; - private readonly string baseUrl; - private readonly string url; - - public Cleverbot(string baseUrl, string url, int endIndex) - { - this.baseUrl = baseUrl; - this.url = url; - this.endIndex = endIndex; - } - - public ChatterBotSession CreateSession() - { - return new CleverbotSession(baseUrl, url, endIndex); - } - } - - public class CleverbotSession : ChatterBotSession - { - private readonly int endIndex; - private readonly string url; - private readonly IDictionary vars; - private readonly CookieCollection cookies; - - public CleverbotSession(string baseUrl, string url, int endIndex) - { - this.url = url; - this.endIndex = endIndex; - vars = new Dictionary(); - //vars["start"] = "y"; - vars["stimulus"] = ""; - vars["islearning"] = "1"; - vars["icognoid"] = "wsf"; - //vars["fno"] = "0"; - //vars["sub"] = "Say"; - //vars["cleanslate"] = "false"; - cookies = Utils.GetCookies(baseUrl); - } - - public async Task Think(ChatterBotThought thought) - { - vars["stimulus"] = thought.Text; - - var formData = Utils.ParametersToWWWFormURLEncoded(vars); - var formDataToDigest = formData.Substring(9, endIndex); - var formDataDigest = Utils.MD5(formDataToDigest); - vars["icognocheck"] = formDataDigest; - - var response = await Utils.Post(url, vars, cookies).ConfigureAwait(false); - - var responseValues = response.Split('\r'); - - //vars[""] = Utils.StringAtIndex(responseValues, 0); ?? - vars["sessionid"] = Utils.StringAtIndex(responseValues, 1); - vars["logurl"] = Utils.StringAtIndex(responseValues, 2); - vars["vText8"] = Utils.StringAtIndex(responseValues, 3); - vars["vText7"] = Utils.StringAtIndex(responseValues, 4); - vars["vText6"] = Utils.StringAtIndex(responseValues, 5); - vars["vText5"] = Utils.StringAtIndex(responseValues, 6); - vars["vText4"] = Utils.StringAtIndex(responseValues, 7); - vars["vText3"] = Utils.StringAtIndex(responseValues, 8); - vars["vText2"] = Utils.StringAtIndex(responseValues, 9); - vars["prevref"] = Utils.StringAtIndex(responseValues, 10); - //vars[""] = Utils.StringAtIndex(responseValues, 11); ?? -// vars["emotionalhistory"] = Utils.StringAtIndex(responseValues, 12); -// vars["ttsLocMP3"] = Utils.StringAtIndex(responseValues, 13); -// vars["ttsLocTXT"] = Utils.StringAtIndex(responseValues, 14); -// vars["ttsLocTXT3"] = Utils.StringAtIndex(responseValues, 15); -// vars["ttsText"] = Utils.StringAtIndex(responseValues, 16); -// vars["lineRef"] = Utils.StringAtIndex(responseValues, 17); -// vars["lineURL"] = Utils.StringAtIndex(responseValues, 18); -// vars["linePOST"] = Utils.StringAtIndex(responseValues, 19); -// vars["lineChoices"] = Utils.StringAtIndex(responseValues, 20); -// vars["lineChoicesAbbrev"] = Utils.StringAtIndex(responseValues, 21); -// vars["typingData"] = Utils.StringAtIndex(responseValues, 22); -// vars["divert"] = Utils.StringAtIndex(responseValues, 23); - - var responseThought = new ChatterBotThought(); - - responseThought.Text = Utils.StringAtIndex(responseValues, 0); - - return responseThought; - } - - public async Task Think(string text) - { - return (await Think(new ChatterBotThought {Text = text}).ConfigureAwait(false)).Text; - } - } -} \ No newline at end of file diff --git a/src/NadekoBot/Services/CleverBotApi/Pandorabots.cs b/src/NadekoBot/Services/CleverBotApi/Pandorabots.cs deleted file mode 100644 index 0d1d8246..00000000 --- a/src/NadekoBot/Services/CleverBotApi/Pandorabots.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -/* - ChatterBotAPI - Copyright (C) 2011 pierredavidbelanger@gmail.com - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -namespace Services.CleverBotApi -{ - public class Pandorabots : ChatterBot - { - private readonly string botid; - - public Pandorabots(string botid) - { - this.botid = botid; - } - - public ChatterBotSession CreateSession() - { - return new PandorabotsSession(botid); - } - } - - public class PandorabotsSession : ChatterBotSession - { - private readonly IDictionary vars; - - public PandorabotsSession(string botid) - { - vars = new Dictionary(); - vars["botid"] = botid; - vars["custid"] = Guid.NewGuid().ToString(); - } - - public async Task Think(ChatterBotThought thought) - { - vars["input"] = thought.Text; - - var response = await Utils.Post("http://www.pandorabots.com/pandora/talk-xml", vars, null).ConfigureAwait(false); - - var responseThought = new ChatterBotThought(); - responseThought.Text = Utils.XPathSearch(response, "//result/that/text()"); - - return responseThought; - } - - public async Task Think(string text) - { - return (await Think(new ChatterBotThought {Text = text}).ConfigureAwait(false)).Text; - } - } -} \ No newline at end of file diff --git a/src/NadekoBot/Services/CleverBotApi/Utils.cs b/src/NadekoBot/Services/CleverBotApi/Utils.cs deleted file mode 100644 index 8954afc6..00000000 --- a/src/NadekoBot/Services/CleverBotApi/Utils.cs +++ /dev/null @@ -1,148 +0,0 @@ -using NadekoBot.Extensions; -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using System.Xml.XPath; - -/* - ChatterBotAPI - Copyright (C) 2011 pierredavidbelanger@gmail.com - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -namespace Services.CleverBotApi -{ - public static class Utils - { - public static string ParametersToWWWFormURLEncoded(IDictionary parameters) - { - string wwwFormUrlEncoded = null; - foreach (var parameterKey in parameters.Keys) - { - var parameterValue = parameters[parameterKey]; - var parameter = string.Format("{0}={1}", System.Uri.EscapeDataString(parameterKey), System.Uri.EscapeDataString(parameterValue)); - if (wwwFormUrlEncoded == null) - { - wwwFormUrlEncoded = parameter; - } - else - { - wwwFormUrlEncoded = string.Format("{0}&{1}", wwwFormUrlEncoded, parameter); - } - } - return wwwFormUrlEncoded; - } - - public static string MD5(string input) - { - // step 1, calculate MD5 hash from input - var md5 = System.Security.Cryptography.MD5.Create(); - var inputBytes = Encoding.ASCII.GetBytes(input); - var hash = md5.ComputeHash(inputBytes); - - // step 2, convert byte array to hex string - var sb = new StringBuilder(); - for (var i = 0; i < hash.Length; i++) - { - sb.Append(hash[i].ToString("X2")); - } - return sb.ToString(); - - } - - public static CookieCollection GetCookies(string url) - { - CookieContainer container = new CookieContainer(); - - HttpResponseMessage res; - using (var handler = new HttpClientHandler() { CookieContainer = container }) - using (var http = new HttpClient(handler)) - { - http.AddFakeHeaders(); - http.DefaultRequestHeaders.Add("ContentType", "text/html"); - res = http.GetAsync(url).GetAwaiter().GetResult(); - } - var response = res.Content.ReadAsStringAsync().GetAwaiter().GetResult(); - - return container.GetCookies(res.RequestMessage.RequestUri); - } - - public static async Task Post(string url, IDictionary parameters, CookieCollection cookies) - { - var postData = ParametersToWWWFormURLEncoded(parameters); - var postDataBytes = Encoding.ASCII.GetBytes(postData); - - var request = (HttpWebRequest)WebRequest.Create(url); - - if (cookies != null) - { - var container = new CookieContainer(); - container.Add(new Uri(url), cookies); - request.CookieContainer = container; - } - - - request.Method = "POST"; - request.ContentType = "application/x-www-form-urlencoded"; - - using (var outputStream = await request.GetRequestStreamAsync()) - { - outputStream.Write(postDataBytes, 0, postDataBytes.Length); - outputStream.Flush(); - - var response = (HttpWebResponse)await request.GetResponseAsync(); - using (var responseStreamReader = new StreamReader(response.GetResponseStream())) - { - return responseStreamReader.ReadToEnd().Trim(); - } - } - - //HttpClientHandler handler; - //var uri = new Uri(url); - //if (cookies == null) - // handler = new HttpClientHandler(); - //else - //{ - // var cookieContainer = new CookieContainer(); - // cookieContainer.Add(uri, cookies); - // handler = new HttpClientHandler() { CookieContainer = cookieContainer }; - //} - //using (handler) - //using (var http = new HttpClient(handler)) - //{ - // var res = await http.PostAsync(url, new FormUrlEncodedContent(parameters)).ConfigureAwait(false); - // return await res.Content.ReadAsStringAsync().ConfigureAwait(false); - //} - } - - - public static string XPathSearch(string input, string expression) - { - var document = new XPathDocument(new MemoryStream(Encoding.ASCII.GetBytes(input))); - var navigator = document.CreateNavigator(); - return navigator.SelectSingleNode(expression).Value.Trim(); - } - - public static string StringAtIndex(string[] strings, int index) - { - if (index >= strings.Length) return ""; - return strings[index]; - } - } -} \ No newline at end of file diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 5c4fa19c..8cd840e0 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -16,9 +16,7 @@ using NadekoBot.Modules.CustomReactions; using NadekoBot.Modules.Games; using System.Collections.Concurrent; using System.Threading; -using Microsoft.EntityFrameworkCore; using NadekoBot.DataStructures; -using Services.CleverBotApi; namespace NadekoBot.Services { From d07ec11fa371d327b1b1ca3a07d561a34bb7ae10 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 4 Apr 2017 15:51:19 +0200 Subject: [PATCH 684/746] Fixed .clparew usage string --- src/NadekoBot/Resources/CommandStrings.Designer.cs | 2 +- src/NadekoBot/Resources/CommandStrings.resx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index c8f3ed92..d021e161 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -1725,7 +1725,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}claimpatreonrewards`. + /// Looks up a localized string similar to `{0}clparew`. /// public static string claimpatreonrewards_usage { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 1d5479ab..1a943af1 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3337,7 +3337,7 @@ Claim patreon rewards. If you're subscribed to bot owner's patreon you can user this command to claim your rewards - assuming bot owner did setup has their patreon key. - `{0}claimpatreonrewards` + `{0}clparew` ping From 349f76af851882048f4e971a302afd8da1b69236 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 4 Apr 2017 19:48:33 +0200 Subject: [PATCH 685/746] Fixed permission listing when user(s) in permissions left the server --- src/NadekoBot/Modules/Permissions/PermissionExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Permissions/PermissionExtensions.cs b/src/NadekoBot/Modules/Permissions/PermissionExtensions.cs index db0fdfd6..f48dcd16 100644 --- a/src/NadekoBot/Modules/Permissions/PermissionExtensions.cs +++ b/src/NadekoBot/Modules/Permissions/PermissionExtensions.cs @@ -106,7 +106,7 @@ namespace NadekoBot.Modules.Permissions switch (perm.PrimaryTarget) { case PrimaryPermissionType.User: - com += guild?.GetUser(perm.PrimaryTargetId).ToString() ?? $"<@{perm.PrimaryTargetId}>"; + com += guild?.GetUser(perm.PrimaryTargetId)?.ToString() ?? $"<@{perm.PrimaryTargetId}>"; break; case PrimaryPermissionType.Channel: com += $"<#{perm.PrimaryTargetId}>"; From e3463e1e7066ad1c40ce2ed8e9dc0eb32d355a39 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:05 +0200 Subject: [PATCH 686/746] Update ResponseStrings.zh-CN.resx (POEditor.com) --- .../Resources/ResponseStrings.zh-CN.resx | 127 +++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx b/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx index e756cf57..ae22319e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx +++ b/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx @@ -759,7 +759,8 @@ 软禁(踢出) - PLURAL + PLURAL +Fuzzy {0}将忽略此通道。 @@ -2383,5 +2384,129 @@ Fuzzy 竞争比赛游戏时间。 + + + + + + + + + PLURAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 8a860fe978766543bdba82be14900585fc4e51a2 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:07 +0200 Subject: [PATCH 687/746] Update ResponseStrings.zh-TW.resx (POEditor.com) --- .../Resources/ResponseStrings.zh-TW.resx | 134 +++++++++++++++++- 1 file changed, 129 insertions(+), 5 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx index 7f3ca400..3af06d17 100644 --- a/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx +++ b/src/NadekoBot/Resources/ResponseStrings.zh-TW.resx @@ -317,7 +317,7 @@ 原因:{1} - 用戶已封鎖 + 成員已封鎖 PLURAL @@ -530,7 +530,7 @@ {0} 已從 {1} 移動至 {2} - #{0} 中删除了讯息 + #{0} 中删除了訊息 #{0} 中更新了訊息 @@ -904,7 +904,7 @@ 花幣大放送開始了! - 送了 {1} 給 {0} + 送了 {0} 給 {1} X has gifted 15 flowers to Y @@ -933,7 +933,7 @@ 卡堆中没有更多的牌。 - 得獎用戶 + 得獎成員 您骰了 {0}。 @@ -1473,7 +1473,7 @@ Paypal <{1}> 我將在此頻道輸出播放、暫停、結束和移除歌曲的訊息。 - 跳至 ‘{0}:{1}’ + 跳至 `{0}:{1}` 隨機播放 @@ -2284,5 +2284,129 @@ Paypal <{1}> 競技時數 + + 頻道 + + + 指令 + + + 踢除 + PLURAL + + + 群管 + + + 第 {0} 頁 + + + 理由 + + + 已新增新的啟動執行命令。 + + + 啟動執行命令已移除。 + + + 找不到啟動執行命令。 + + + 伺服器 + + + 此頁沒有啟動執行命令。 + + + 已清除所有啟動執行命令。 + + + 成員 {0} 已解除封鎖。 + + + 找不到成員。 + + + 已警告成員 {0} 。 + + + 成員 {0} 因警告多次故以 {0} 作為懲罰。 + + + 在 {0} 伺服器上警告 + + + 於 {0} {1},由 {2} + + + 已清除成員 {0} 上的所有警告。 + + + 此頁沒有警告。 + + + {0} 的警告紀錄 + + + 沒有設定懲處罰則。 + + + 由 {0} 清除 + + + 警告懲處清單 + + + 擁有 {0} 支警告不再觸發懲處。 + + + 我將會用 {0} 懲處擁有 {0} 支警告的成員。 + + + Slowmode 將不再套用於 {0} 身分組。 + + + Slowmode 將套用於 {0} 身分組。 + + + Slowmode 將不再套用於 {0} 成員。 + + + Slowmode 將套用於 {0} 成員。 + + + 因下列因素而無法領獎: + + + 您一個月只能領一次獎勵,除非您的贊助金額有提升。 + + + 獎勵已發送 + + + 您的Discord帳號可能未與Patreon帳戶連結。若您不確定,或不知道如何連結的話,請至您的[Patreon帳戶設定](https://patreon.com/settings/account)並點選'連節至Discord'按鈕。 + + + 尚未連接Discord帳號 + + + 您必須要與Patreon連結您的Discord帳戶才符合領獎資格。您可以使用 {0} 指令來取得連結。 + + + 無法支援 + + + 贊助完畢後需要等待數小時等資訊入系統,還請稍後再嘗試。 + + + 請稍等 + + + 您因贊助了此專案而獲得了{0}! + + + 獎勵可於每月5日之後領取。 + \ No newline at end of file From 494aae95a5dfe8af138d8a5aa1296e60a99cba74 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:10 +0200 Subject: [PATCH 688/746] Update ResponseStrings.nl-NL.resx (POEditor.com) --- .../Resources/ResponseStrings.nl-NL.resx | 156 +++++++++++++++--- 1 file changed, 134 insertions(+), 22 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx index 3f7ad541..2662c00a 100644 --- a/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.nl-NL.resx @@ -140,7 +140,6 @@ De aanvraag van @{0} voor een oorlog tegen {1} is niet meer geldig. - Fuzzy Vijand @@ -153,11 +152,9 @@ Ongeldig oorlogsformaat. - Fuzzy - Lijst van voorlopende oorlogen. - Fuzzy + Lijst van actieve oorlogen Niet veroverd. @@ -169,8 +166,7 @@ @{0} Je doet niet mee aan die oorlog, of die basis is al vernietigd. - Geen voorlopende oorlogen. - Fuzzy + Geen actieve oorlogen Grootte. @@ -209,8 +205,7 @@ Nieuwe Speciale Reacties - Geen speciale reacties gevonden. - Fuzzy + Geen aangepaste reacties gevonden. Geen speciale reacties gevonden met dat ID. @@ -476,7 +471,6 @@ Reden: {1} Lijst van talen {0} - Fuzzy Je server's landinstelling is nu {0} - {1} @@ -533,12 +527,10 @@ Reden: {1} {0} verplaats van {1} naar {2} - Bericht in #{0} verwijdert - Fuzzy + Bericht in #{0} verwijderd Bericht in #{0} bijgewerkt - Fuzzy gemute @@ -749,7 +741,8 @@ Reden: {1} soft-verbannen (gekickt) - PLURAL + PLURAL +Fuzzy {0} zal dit kanaal negeren. @@ -1395,7 +1388,6 @@ Vergeet niet je discord naam en id in het bericht te zetten. Nu aan het spelen - Fuzzy Geen actieve muziek speler. @@ -1731,12 +1723,10 @@ Vergeet niet je discord naam en id in het bericht te zetten. Voorbeeld - Mislukt in het vinden van die chinese tekenfilm - Fuzzy + Kon die animu niet vinden. - Mislukt in het vinden van die - Fuzzy + Kon die mango niet vinden. Genres @@ -2012,8 +2002,7 @@ Vergeet niet je discord naam en id in het bericht te zetten. Index buiten bereik. - Hier is de lijst met gebruikers in die rollen: - Fuzzy + Lijst van gebruikers met rol {0} Om misbruik te voorkomen ben je niet gemachtigd om dit commando te gebruiken op rollen met veel gebruikers. @@ -2102,8 +2091,7 @@ Eigenaar ID: {2} Citaat toegevoegd - Een willekeurig citaat verwijderd - Fuzzy + Citaat #{0} verwijderd. Regio @@ -2293,5 +2281,129 @@ Eigenaar ID: {2} Competitieve speeltijd + + Kanaal + + + Tekst commando + + + Geschopt + PLURAL + + + Toezichthouder + + + Pagina {0} + + + Reden + + + Nieuw startup commando toegevoegd. + + + Startup commando succesvol toegevoegd. + + + Startup commando niet gevonden. + + + Server + + + Geen startup commando's op deze pagina. + + + Verwijder alle startup commando's. + + + Gebruiker {0} is unbanned. + + + Gebruiker niet gevonden. + + + Gebruiker {0} is gewaarschuwd. + + + Gebruiker {0} is gewaarschuwd en {1) straf is uitgevoerd. + + + Gewaarschuwd op {0} server + + + op {0} tussen {1} bij (2} + + + Alle waarschuwingen zijn verwijdert van {0}. + + + Geen waarschuwingen op deze pagina. + + + Waarschuwings logboek van {0} + + + Geen straffen geconfigureerd. + + + Verwijdert door {0} + + + waarschuwing straffen lijst + + + Bij {0} waarschuwingen treed niet langer meer een straf. + + + Ik pas {0} straf toe aan de gebruikers met {1} waarschuwingen. + + + Slowmotion modus word genegeerd voor {0} rol. + + + Slowmotion wordt niet langer genegeerd door {0} rol. + + + Slowmotion modus wordt genegeerd door gebruiker {0}. + + + Slowmotion modus wordt niet langer genegeerd door genegeerde gebruiker {0}. + + + Mislukt om beloningen te claimen door een van de volgende redenen: + + + Misschien heb je al je beloningen gekregen deze maand. Je krijgt beloningen maar een keer per maand tenzij je je + + + Al beloond + + + Jouw discord account is nog niet verbonden met Patreon. Als je onzeker bent wat dit betekend, of niet weet hoe je dit moet doen - ga dan naar [Patreon account settings page](https://patreon.com/settings/account) en click dan op 'Verbind met discord'. + + + Discord account nog niet verbonden + + + Om in aanmerking te komen voor de beloning, moet je eerst een donatie doen voor het project bij patreon. Je kunt (0} commando gebruiken om de link te krijgen. + + + Niet ondersteund + + + Je moet een aantal uren wachten na het plaatsen van je donatie, als je het nog niet hebt gedaan, probeer later dan opnieuw. + + + Wacht nog even + + + Je ontvangt {0} Hartelijk bedankt voor het steunen van het project! + + + Beloningen kunnen worden geclaimd op of na elke 5de van de maand. + \ No newline at end of file From 91880e6ca28dfd984985bea2b712287c11b075f8 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:12 +0200 Subject: [PATCH 689/746] Update ResponseStrings.en-US.resx (POEditor.com) From 28753b6a22a614d47ed22e017533b25c66b9384e Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:15 +0200 Subject: [PATCH 690/746] Update ResponseStrings.fr-FR.resx (POEditor.com) --- .../Resources/ResponseStrings.fr-FR.resx | 133 +++++++++++++++++- 1 file changed, 129 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx b/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx index 3c3279ff..c2ad5917 100644 --- a/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx @@ -748,7 +748,8 @@ Raison: {1} expulsés (kick) - PLURAL + PLURAL +Fuzzy {0} ignorera ce Salon. @@ -757,7 +758,7 @@ Raison: {1} {0} n'ignorera plus ce Salon. - Si un utilisateur poste {0} le même message à la suite, je le {1}. + Si un utilisateur poste {0} fois le même message à la suite, je le {1}. __SalonsIgnorés__: {2} @@ -1432,7 +1433,7 @@ La nouvelle valeur de {0} est {1} ! Aucune liste de lecture ne correspond a cet ID. - File d'attente de la liste complétée. + Liste de lecture ajoutée à la file d'attente. Liste de lecture sauvegardée @@ -2291,7 +2292,7 @@ ID du propriétaire: {2} {0} sera maintenant l'alias de {1}. - Liste des alias. + Liste des alias {0} n'a plus d'alias. @@ -2302,5 +2303,129 @@ ID du propriétaire: {2} Temps en jeu compétitif. + + Salon + + + Texte de la commande. + + + Expulsés + PLURAL + + + Modérateur + + + Page {0} + + + Raison + + + Nouvelle commande au démarrage ajoutée + + + Commande au démarrage retirée. + + + Commande au démarrage introuvable. + + + Serveur + + + Aucune commande de démarrage sur cette page. + + + Toutes les commandes au démarrage ont été retirées. + + + L'utilisateur {0} a été débanni. + + + Utilisateur introuvable. + + + L'utilisateur {0} a été averti. + + + L'utilisateur {0} a été averti et {1} punition a été appliquée. + + + Averti sur le serveur {0} + + + Le {0} à {1} par {2} + + + Toutes les avertissements ont étés effacés pour {0}. + + + Pas d'avertissement sur cette page. + + + Log d'avertissement pour {0} + + + Pas de punition définie. + + + Effacé par {0} + + + Liste des avertissements de punitions. + + + Avoir {0} avertissements ne déclenche plus de punition. + + + J'appliquerai seulement la punition {0} aux utilisateurs ayant {1} avertissements. + + + Le mode lent ignorera le rôle {0}. + + + Le mode lent n'ignorera plus le rôle {0}. + + + Le mode lent ignorera l'utilisateur {0}. + + + Le mode lent n'ignorera plus l'utilisateur {0}. + + + Échec de la réclamation des récompenses à cause d'une des raisons suivantes: + + + Vous avez peut-être déjà reçu votre récompense mensuelle. Vous ne pouvez recevoir qu'une récompense mensuelle sauf si vous augmentez votre engagement. + + + Déjà récompensé. + + + Votre compte Discord n'est peut-être pas connecté à Patreon. Si vous n'êtes pas sur de ce que ça veut dire, ou ne savez pas comment le connecter, vous devez aller à la [Page de configurations du compte Patreon](https://patreon.com/settings/account) et cliquer sur 'Connect to discord'. + + + Le compte Discord n'est pas connecté + + + Pour être éligible à la récompense, vous devez supporter le projet sur Patreon. Vous pouvez utiliser la commande {0} afin d'avoir le lien. + + + Ne supporte pas. + + + Vous devez attendre quelques heures après avoir fait votre engagement, si ce n'est pas le cas, réessayez plus tard. + + + Attendez quelque temps + + + Vous avez reçu {0}. Merci de supporter le projet! + + + Les récompenses peuvent être réclamés le 5e du mois ou après. + \ No newline at end of file From 6114df7e12793d01e7197a7bbd0b5fbece9dbfd6 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:18 +0200 Subject: [PATCH 691/746] Update ResponseStrings.de-DE.resx (POEditor.com) --- .../Resources/ResponseStrings.de-DE.resx | 129 +++++++++++++++++- 1 file changed, 128 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx index c568448d..81cde44a 100644 --- a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx @@ -760,7 +760,8 @@ Grund: {1} soft-banned (gekickt) - PLURAL + PLURAL +Fuzzy {0} wird diesen Kanal ignorieren. @@ -2387,5 +2388,131 @@ ID des Besitzers: {2} Kompetetive Spielzeit + + Kanal + + + Befehls Text + + + Kicked + PLURAL + + + Moderator + + + Seite {0} + + + Grund + + + Neuer Startbefehl hinzugefügt. + Fuzzy + + + Startbefehl wurde erfolgreich entfernt. + + + Startbefehl konnte nicht gefunden werden + + + Server + + + Keine Startbefehle auf dieser Seite + + + Alle Startbefehle wurden entfernt. + + + Benutzer {0} wurde entbannt. + + + Benutzer nicht gefunden. + + + Benutzer {0} wurde gewarnt. + + + Benutzer {0} wurde gewarnt und Strafe {1} wurde ausgeführt. + + + Gewarnt auf dem Server {0} + + + Am {0} um {1} von {2} + + + Alle Warnungen wurden bereinigt für {0}. + + + Keine Warnungen auf dieser Seite. + + + + + + Keine Bestrafungen gesetzt. + + + Bereinigt bei {0} + + + Warnungs Straf Liste + + + {0} Warnungen werden nicht mehr eine Bestrafung auslösen. + + + Ich werde die Bestrafung {0} an Benutzern mit {1} Warnungen ausführen. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Keine Unterstützung + + + Sie müssen ein paar Stunden warten nachdem sie ihre Unterstützung zusagenl, falls Sie das nicht getan haben, versuchen Sie es später erneut. + Fuzzy + + + + + + + + + + \ No newline at end of file From 3b446508c7cf81e05f45afdfef660978733c396c Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:20 +0200 Subject: [PATCH 692/746] Update ResponseStrings.he-IL.resx (POEditor.com) --- .../Resources/ResponseStrings.he-IL.resx | 149 ++++++++++++++++-- 1 file changed, 137 insertions(+), 12 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.he-IL.resx b/src/NadekoBot/Resources/ResponseStrings.he-IL.resx index 7f42401e..cf49c09f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.he-IL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.he-IL.resx @@ -130,13 +130,13 @@ הבסיס #{0} **הושמד** במלחמה נגד {1} - + {0} **שיחרר** את בסיס #{0} במלחמה נגד {2} - + {0} תפס את בסיס #{1} במלחמה נגד {2} - + @{0} אתה כבר תפסת את בסיס #{1}. אינך יכול לתפוס אחד חדש @@ -214,7 +214,7 @@ תגובה - + נתוני תגובות מותאמות @@ -226,7 +226,7 @@ - + אוטוהנטאי הפסיק לא נמצאו תוצאות. @@ -299,10 +299,10 @@ את\ה התעלפת אז את\ה לא יכול לזוז. - + **נתינת תפקיד אוטומטי** כאשר משתמש מתווסף **הופסקה** כעת. - + **נתינת תפקיד אוטומטי** כאשר משתמש מתווסף **התחילה** כעת. קבצים מצורפים @@ -412,10 +412,10 @@ אני אפסיק להעביר את ההודאות הפרטיות מעכשיו. - + מחיקה אוטומטית של הודאות ברכה הופסקה. - + הודאות הודאה פרטית נוכחית: {0} @@ -442,10 +442,10 @@ - + הודאות ברכה בוטלו. - + הודאות ברכה הופעלו עבור ערוץ זה. אתה לא יכול להשתמש בפקודה זו על משתמשים עם תפקיד שווה או גבוהה ממך בדירוג. @@ -740,7 +740,8 @@ הסרה קלה (גורש) - PLURAL + PLURAL +Fuzzy {0} יתעלם מערוץ זה. @@ -2272,5 +2273,129 @@ + + + + + + + + + PLURAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From ce26d181607f97c94e80a9edf4f7b0b045a45241 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:23 +0200 Subject: [PATCH 693/746] Update ResponseStrings.it-IT.resx (POEditor.com) --- .../Resources/ResponseStrings.it-IT.resx | 687 +++++++++++------- 1 file changed, 420 insertions(+), 267 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.it-IT.resx b/src/NadekoBot/Resources/ResponseStrings.it-IT.resx index 5a922057..5247c7a6 100644 --- a/src/NadekoBot/Resources/ResponseStrings.it-IT.resx +++ b/src/NadekoBot/Resources/ResponseStrings.it-IT.resx @@ -118,28 +118,28 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Quella base è già rivendicata o distrutta. + Quella base è già stata rivendicata o distrutta. Quella base è già distrutta. - Quella base non è rivendicata. + Quella base non è stata rivendicata. - **DISTRUTTO** base #{0} in una guerra contro {1} + **DISTRUTTA** base #{0} in una guerra contro {1} - {0} ha **NON RIVENDICATO** base #{1} in una guerra contro {2} + {0} ha **NON RIVENDICATO** la base #{1} in una guerra contro {2} {0} ha rivendicato la base #{1} in una guerra contro {2} - @{0} Hai già rivendicato la base #{1} + @{0} Hai già rivendicato la base #{1}. Non puoi rivendicarne un'altra. - La rivendicazione di @{0} in una guerra contro {1} + La rivendicazione di @{0} in una guerra contro {1} è scaduta. Nemico @@ -157,13 +157,13 @@ Lista delle guerre in corso - non rivendicato + non rivendicata - Non stai partecipando a questa guerra + Non stai partecipando a quella guerra - @{0} Tu non stai partecipando in questa guerra, o questa base è già distrutta. + @{0} Non stai partecipando in quella guerra oppure quella base è già distrutta. Nessuna guerra in corso. @@ -178,22 +178,22 @@ Guerra contro {0} creata. - Guerra contro {0} finita. + Guerra contro {0} conclusa. Questa guerra non esiste. - Guerra contro {0} iniziata! + Guerra contro {0} avviata! - Tutte le reazioni personalizzate approvate. + Tutte le reazioni personalizzate sono state approvate. Reazione personalizzata cancellata - Permessi insufficienti. Richiede l'essere proprietario del bot per le reazioni personalizzate globali, e l'amministratore del server per le reazioni personalizzate. + Permessi insufficienti. Bisogna essere proprietario del Bot per personalizzare le reazioni globali e l'amministratore del server per le personalizzare le reazioni del server. Lista di tutte le reazioni personalizzate @@ -232,39 +232,39 @@ Nessun risultato trovato. - {0} è già svenuto. + {0} è già esausto. {0} ha già gli HP al massimo. - il tuo tipo è già {0} + Il tuo tipo è già {0} - Ha usato {0}{1} su {2}{3} per {4} danni. + ha usato {0}{1} su {2}{3} per {4} danni. Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. - Non puoi attaccare senza ritorsione! + Non puoi attaccare di nuovo senza subire una rappresaglia! Fuzzy Non puoi attaccare te stesso. - {0} è svenuto! + {0} è esausto! - curato {0} con un {1} + ha curato {0} con un {1} - {0} ha {1} HP rimasto + {0} ha {1} HP rimasti. Non puoi usare {0}. Scrivi `{1}ml` per vedere la lista delle mosse che puoi usare. - Listamosse per tipo {0} + Lista delle mosse per il tipo {0} Non è efficace. @@ -273,22 +273,22 @@ Non hai abbastanza {0} - Hai resuscitato {0} con un {1} + ha resuscitato {0} con un {1} Hai resuscitato te stesso con un {0} - Il tuo tipo è stato cambiato in {0} per un {1} + Il tuo tipo è cambiato in {0} per un {1} - E' lievemente efficace. + È lievemente efficace. - E' superefficace! + È superefficace! - Hai usato troppe mosse in una volta, non puoi muoverti! + Hai usato troppe mosse di fila, quindi ora non puoi muoverti! Tipo di {0} è {1} @@ -300,20 +300,20 @@ Sei svenuto, non sei più in grado di muoverti! - **Auto assegna ruolo** sull'utente ora entrato è ora **disattivato** + **Assegna ruolo automaticamente** ai nuovi utenti è stato **disattivato**. - **Auto assegna ruolo** sull'utente ora entrato è ora **attivato** + **Assegna ruolo automaticamente** ai nuovi utenti è stato **attivato**. Allegato - Avatar Cambiato + Avatar cambiato Sei stato bannato dal {0} server. -Ragione: {1} +Motivo: {1} bannati @@ -323,13 +323,13 @@ Ragione: {1} Utente bannato - Nome bot cambiato in {0} + Nome del bot cambiato in {0} Stato del bot cambiato in {0} - L'eliminazione automatica dei messaggi di arrivederci è stata disabilitata. + la cancellazione automatica dei messaggi di arrivederci è stata disabilitata. I messaggi di arrivederci verranno eliminati dopo {0} secondi. @@ -347,13 +347,13 @@ Ragione: {1} Annunci di arrivederci disattivati. - Annunci di arrivederci attivati in questo canale + Annunci di arrivederci attivati in questo canale. Nome del canale cambiato - Vecchio Nome + Vecchio nome Argomento del canale cambiato @@ -377,7 +377,7 @@ Ragione: {1} Assordato con successo. - Server Eliminato {0} + Server eliminato {0} Fermata con successo l'eliminazione automatica dei comandi di invocazione. @@ -392,25 +392,25 @@ Ragione: {1} Canale vocale {0} eliminato. - MP da + Messaggio diretto da parte di - Aggiunto con successo un nuovo donatore. Totale ammontare donato da questo utente: {0} 👑 + Aggiunto con successo un nuovo donatore. Totale dell'ammonto donato dall'utente: {0} 👑 - Grazie alle persone nella lista qui sotto per aver fatto avverare questo progetto! + Grazie alle persone nella lista qui sotto per aver fatto di questo progetto una realtà! - Inoltrerò MP a tutti i proprietari. + Contatterò in privato tutti i proprietari. - Inoltrerò MP solo al primo proprietario. + Contatterò in privato solo il primo proprietario. - Inoltrerò MP da ora in poi. + Inoltrerò messaggi diretti d'ora in avanti. - Fermerò l'inoltrare degli MP da ora in poi. + Smetterò di inoltrare messaggi diretti d'ora in avanti. L'eliminazione automatica dei messaggi di benvenuto è stata disabilitata @@ -419,43 +419,43 @@ Ragione: {1} I messaggi di benvenuto verranno eliminati dopo {0} secondi. - Attuali MP di benvenuto ricevuti: {0} + Messaggi diretti di benvenuto ricevuti finora: {0} - Abilità MP di benvenuto scrivendoli {0} + Per abilitare i messaggi diretti di benvenuto scrivi {0} - Nuovo MP di bevenuto impostato. + Nuovo messaggio diretto di benvenuto impostato. - MP annunci di bevenenuto disattivato. + Messaggi diretti di benvenuto disabilitati. - MP annunci di bevenuto attivati. + Messaggi diretti di benvenuto abilitati. - + Messaggio di benvenuto attuale: {0} - + Per abilitare i messaggi di benvenuto scrivi {0} Nuovo messaggio di benvenuto impostato. - Annunci di bevenuto disabilitati + Messaggi di benvenuto disabilitati. - Annunci di benvenuto abilitatati in questo canale + Messaggi di benvenuto abilitatati in questo canale. - Non puoi usare questo comando su utenti con un ruolo più alto o uguale al tuo nella gerarchia dei ruoli. + Non puoi usare questo comando su utenti con un ruolo superiore o pari al tuo. Immagine caricata dopo {0} secondi! - + Formato di input invalido. Parametri Invalidi @@ -471,28 +471,28 @@ Ragione: {1} Utente cacciato - Lista dei linguaggi + Lista delle lingue - + La lingua del tuo server è ora {0} - {1} - + La lingua di base del bot è ora {0} - {1} - il linguaggio dei Bot è impostato a {0} - {1} + La lingua del Bot è impostata a {0} - {1} - + Impostazione della lingua del server fallita. Riguarda la guida di questo comando. - Il linguaggio di questo server è impostato a {0} - {1} + La lingua di questo server è impostata a {0} - {1} {0} ha lasciato {1} - Hai lasciato il server {0} + Ha lasciato il server {0} Inserire {0} evento in questo canale. @@ -504,7 +504,7 @@ Fuzzy Fuzzy - Entrata disattivata + Registrazione disattivata Fuzzy @@ -512,42 +512,45 @@ Fuzzy Fuzzy - + La registrazione ignorerá {0} + Fuzzy - + La registrazione non ignorerá {0} + Fuzzy - + Fermata la registrazione dell'evento {0} + Fuzzy {0} ha chiesto una menzione nei seguenti ruoli - Messaggio da {0} `[Proprietario Bot]`: + Messaggio da {0} `[Proprietario del bot]`: Messaggio inviato. - {0} spostato in {1} da {2} + {0} spostato da {1} a {2} Messaggio eliminato in #{0} - + Messaggio aggiornato in #{0} - Gli utenti sono stati mutati + Mutati PLURAL (users have been muted) - Utente mutato + Mutato singular "User muted." - Probabilmente non ho i permessi necessari per questo + Probabilmente non ho i permessi necessari per farlo. Nuovo ruolo di muto impostato. @@ -568,10 +571,10 @@ Fuzzy Soprannome cambiato - Non riesco a trovare questo server + Non riesco a trovare quel server - + Non è stato trovato nessun frammento con quel ID. Messaggio precedente @@ -583,10 +586,10 @@ Fuzzy Discussione precedente - Errore. Probabilmente non ho i permessi sufficienti. + Errore. Probabilmente non dispongo dei permessi necessari. - I permessi per questo server sono resettati + I permessi di questo server sono stati reimpostati. Protezioni attive @@ -598,7 +601,7 @@ Fuzzy {0} Attivato - Errore. Hai bisogno dei permessi di gestione dei ruoli + Errore. Ho bisogno dei permessi di gestione dei ruoli Nessuna protezione attiva. @@ -607,55 +610,57 @@ Fuzzy Gli utenti in ingresso devono essere tra {0} e {1}. - Se {0} o più utenti entrano entro {1} secondi, io li {0} loro. + Se {0} o più utenti entrano entro {1} secondi, li {0}. Il tempo deve essere tra {0} e {1} secondi. - Rimossi con successo tutti i ruoli dall'utente {0} + L'utente {0} è stato sollevato da tutti i suoi ruoli. - Fallito a rimuovere i ruoli. Non ho abbastanza permessi. + Impossibile rimuovere i ruoli. Non dispongo dei permessi necessari. - il colore di {0} è stato cambiato. + il colore del ruolo {0} è stato cambiato. - Questo ruolo non esiste. + Quel ruolo non esiste. - I parametri specificati sono invalidi + I parametri specificati sono invalidi. Si è verificato un errore dovuto a un colore invalido o a permessi insufficienti. - Rimosso con successo ruolo {0} dall'utente {1} + L'utente {1} è stato sollevato dal ruolo di {0} - Fallito a rimuovere ruolo. Non ho abbastanza permessi. + Impossibile rimuovere il ruolo. Non dispongo dei permessi necessari. - Ruolo rinominato + Ruolo rinominato. - Rinomina del ruolo fallita. Non ho abbastanza permessi. + Impossibile rinominare il ruolo. Non dispongo dei permessi necessari. - Non puoi modificare i ruoli più alti del tuo + Non puoi modificare i ruoli più alti del tuo. Rimosso il messaggio di gioco: {0} + Fuzzy - Ruolo {0} è stato aggiunto alla lista. + Il ruolo {0} è stato aggiunto alla lista. - {0} non trovato.Ripulito. + {0} non trovato. Pulizia avvenuta. + Fuzzy - il ruolo {0} è già nella lista + il ruolo {0} è già nella lista. Aggiunto. @@ -667,7 +672,7 @@ Fuzzy Stato di gioco rotativo attivato. - Qui c'è una lista delle condizioni di ruolo rotative: + Ecco una lista delle condizioni di ruolo rotative: {0} Fuzzy @@ -676,10 +681,11 @@ Fuzzy Fuzzy - Tu hai già {0} ruolo + Sei già un {0}. - Tu hai già {0} esclusivi ruoli auto-assegnati. + Hai già {0} esclusivi ruoli auto-assegnati. + Fuzzy I ruoli auto-assegnati sono ora riservati! @@ -691,31 +697,31 @@ Fuzzy Quel ruolo non è auto-assegnabile. - Tu non hai {0} ruolo. + Non sei un {0}. I ruoli auto-assegnati ora non sono più riservati! - Io non sono in grado di assegnarti questo ruolo. `Io non posso assegnare ruoli al proprietario o ad altri ruoli più alti del mio nella gerarchia dei ruoli.` + Non sono in grado di assegnarti quel ruolo. `Non posso assegnare ruoli al proprietario o ad altri utenti con un ruolo superiore al mio.` {0} è stato rimosso dalla lista dei ruoli auto-assegnabili. - Tu non hai più {0} ruolo. + Se non più un {0}. - Tu ora hai {0} ruolo. + Ora sei un {0}. - Aggiunto con successo ruolo {0} all'utente {1} + All'utente {1} è stato assegnato con successo il ruolo di {0}. - Fallito ad aggiungere il ruolo. Non ho i permessi sufficienti. + Impossibile assegnare ruolo. Non dispongo dei permessi necessari. - Nuova immagine impostata! + Nuovo avatar impostato! Nuovo nome del canale impostato. @@ -730,10 +736,12 @@ Fuzzy Nuova discussione del canale impostata. - + Frammento {0} ricollegato. + Fuzzy - + Frammento {0} si sta ricollegando. + Fuzzy Spegnimento @@ -743,13 +751,16 @@ Fuzzy Modalità lenta disattivata + Fuzzy Modalità lenta attivata + Fuzzy Ammonizione (Espulso) - PLURAL + PLURAL +Fuzzy {0} ignorerà questo canale. @@ -808,7 +819,7 @@ __Canaliignorati__: {2} Ruolo utente rimosso - {0} è ora {1} + {0} ora é {1} {0} è stato **smutato** dal canale di testo e vocale. @@ -841,13 +852,13 @@ __Canaliignorati__: {2} Voce + testo abilitati. - + Non ho i permessi **gestire ruoli* e/o **gestire canali*, quindi non posso utilizzare `voce+testo` sul server {0}. - + Stai attivando/disattivando questa opzione e **Io non ho i permessi di AMMINISTRATORE**. Questo potrebbe causare dei problemi, e dopo tu dovrai ripulire il canale di testo. - + Richiedo dei permessi **gestire ruoli** e **gestire canali** per abilitare per questa funzione. (preferibilmente il permesso Amministratore) Utente {0} dalla chat di testo @@ -859,7 +870,8 @@ __Canaliignorati__: {2} Utente {0} dalla chat vocale - + Sei statto cacciato da {0} server. +Motivo : {1} Utente sbannato @@ -896,7 +908,7 @@ __Canaliignorati__: {2} Indovinato! Hai vinto {0} - + Numero specificato non valido. Puoi lanciare da 1 a {0} monete. Aggiungi {0} a questo messaggio per ottenere {1} @@ -905,7 +917,8 @@ __Canaliignorati__: {2} Quest'evento è attivo per le prossime {0} ore - + Evento reazioni iniziato! + Fuzzy ha regalato {0} a {1} @@ -919,7 +932,7 @@ __Canaliignorati__: {2} Testa - + Classifica @@ -937,7 +950,7 @@ __Canaliignorati__: {2} Non ci sono più carte nel mazzo. - + Utente sorteggiato Hai rollato {0} @@ -965,10 +978,10 @@ __Canaliignorati__: {2} Dura {1} secondi. Non dirlo a nessuno. Shhh. - + L'evento SneakyGame è finito. {0} utenti hanno ricevuto la loro ricompensa. - + L'evento SneakyGameStatus è iniziato Croce @@ -978,28 +991,28 @@ Dura {1} secondi. Non dirlo a nessuno. Shhh. Fuzzy - + non sono stata in grado di prendere {0} da{1} perché l'utente non aveva abbastanza {2}! - + Torna al sommario Solo il proprietario del bot. - + Richiede il permesso del canale {0}. Puoi supportare il progetto sul patreon: <{0}> o paypal: <{0}> - + Comandi e alias - + Lista dei comandi rigenerata. - + Scrivi `{0}h NomeDelComando` per consultare la guida per il comando specificato. Ad esempio: `{0}h >8ball` Non riesco a trovare questo comando. Perfavore verifica che questo comando esiste prima di riprovare. @@ -1026,19 +1039,19 @@ Non dimenticarti di firmare con il tuo nome o id di discord. Lista dei moduli - + Scrivi `{0}cmds NomeModulo` per vedere la lista di tutti i comandi in quel modulo. Ad esempio: `{0}cmds giochi` Modulo inesistente. - + Richiede il permesso {0} del server. Tabella dei contenuti - + Uso Autohentai avviato. Ogni {0} secondi verrà postato qualcosa coi seguenti tag: @@ -1048,7 +1061,7 @@ Non dimenticarti di firmare con il tuo nome o id di discord. Tag - + Gara degli animali Impossibile iniziare perché non ci sono abbastanza partecipanti. @@ -1063,8 +1076,7 @@ Non dimenticarti di firmare con il tuo nome o id di discord. {0} è entrato come {1} e ha scommesso {2}! - Scrivi {0}eg per entrare nella gara. - Fuzzy + Scrivi {0}jr per partecipare alla gara. Inizia tra 20 secondi o quando la stanza è piena. @@ -1076,11 +1088,10 @@ Non dimenticarti di firmare con il tuo nome o id di discord. {0} come {1} Ha vinto la gara! - {0} come {2} Ha vinto la gara e {2}! + {0} come {1} Ha vinto la gara e {2}! Numero specificato invalido. Puoi tirare {0}-{1} dadi alla volta. - Fuzzy Ha rollato {0} @@ -1088,9 +1099,8 @@ Non dimenticarti di firmare con il tuo nome o id di discord. Fuzzy - Dado rollato: {0} - Dice Rolled: 5 -Fuzzy + Dadi tirati: {0} + Dice Rolled: 5 Fallito a iniziare la gara. Un'altra gara è probabilmente in corso. @@ -1123,7 +1133,7 @@ Fuzzy Classifica delle waifu - + La tua affinità è già stabilita a quella waifu oppure stai cercando di rimuovere la tua affinità mentre non ne hai una. ha cambiato la sua affinità da {0} a {1}. @@ -1244,17 +1254,17 @@ il nuovo valore di {0} è {1}! Cleverbot è stato abilitato in questo server. - + La generazione di valuta è stata disabilitata in questo canale. - + La generazione di valuta è stata abilitata in questo canale. - + {0} un {1} casuale è apparso! plural - + Un {0} è apparso! Impossibile caricare una domanda. @@ -1270,10 +1280,9 @@ il nuovo valore di {0} è {1}! Impossibile iniziare il gioco dell'impiccato. - Fuzzy - + Lista dei tipi di parole dell' "{0}impiccato": Classifica @@ -1332,7 +1341,9 @@ il nuovo valore di {0} è {1}! {0} ha vinto! - + Tris + The mean of ''matched three'' is that someone won at tic tac toe? +Fuzzy Nessuna mossa rimanente! @@ -1341,13 +1352,13 @@ il nuovo valore di {0} è {1}! Tempo scaduto! - + Tocca a {0} {0} vs {1} - + Cercando di mettere in coda {0} canzoni... Autoplay disabilitato. @@ -1359,19 +1370,20 @@ il nuovo valore di {0} è {1}! Volume di default impostato a {0}% - + Coda della directory completata. + Fuzzy - + gioco corretto Canzone finita - + Gioco corretto disabilitato. - + Gioco corretto abilitato. Dalla posizione @@ -1383,19 +1395,19 @@ il nuovo valore di {0} è {1}! Input non valido - + Il tempo massimo di gioco ora non ha più un limite. - + Il tempo massimo di gioco è stato impostato a {0} secondi. - + La coda massima della musica è stata impostata a illimitata - + La coda massima della musica è stata impostata a {0} brani. - + Bisogna essere in un canale vocale in questo server Nome @@ -1404,16 +1416,16 @@ il nuovo valore di {0} è {1}! In riproduzione - + Nessuna musica in riproduzione. Nessun risultato trovato. - + Riproduzione della musica messa in pausa. - + Coda degli utenti - Pagina {0}/{1} Canzone iniziata @@ -1422,7 +1434,7 @@ il nuovo valore di {0} è {1}! - + Pagina {0} della playlist salvata Playlist cancellata. @@ -1440,7 +1452,7 @@ il nuovo valore di {0} è {1}! Playlist salvata - + limite di {0} secondi Coda @@ -1449,41 +1461,41 @@ il nuovo valore di {0} è {1}! Canzone in coda - + Coda della musica ripulita - + La coda é piena a {0}/{0} Canzone rimossa context: "removed song #5" - + Ripetendo la canzone corrente - + Ripetendo la playlist Traccia ripetuta - + Riproduzione del brano attuale fermata. - + Riproduzione della musica ricominciata. - + Ripeti playlist disabilitato. - + Ripeti playlist abilitato. - + Ora mostrerò i brani in ascolto, finiti, messi in pausa e rimossi in questo canale. - + Saltato a '{0}:{1}' Canzoni mischiate @@ -1534,16 +1546,16 @@ il nuovo valore di {0} è {1}! L'utente {0} può usare TUTTI I MODULI. - + Aggiunto {0} con ID {1} alla lista nera - + Il comando {0} ha adesso {1} secondi di ricarica. - + Il comando {0} non ha più il tempo di ricarica e tutti i tempi di ricarica esistenti sono stati cancellati. - + Nessuna ricarica dei comandi stabilita. Costo dei comandi @@ -1570,22 +1582,22 @@ il nuovo valore di {0} è {1}! Parametro dei secondi non valido.(Deve essere un numero tra {0} e {1}) - + Filtro degli inviti disabilitato in questo canale. - + Filtro degli inviti abilitato su questo canale - + Filtro degli inviti disabilitato su questo canale - + Filtro degli inviti abilitato su questo server - + Spostato il permesso {0} da #{1} a #{2} - + Impossibile trovare il permesso nell'elenco #{0} Nessun costo impostato. @@ -1608,56 +1620,56 @@ il nuovo valore di {0} è {1}! Gli utenti ora devono avere il ruolo di {0} per modificare i permessi. - + Nessun permesso trovato in quell'elenco. - + rimosso il permesso #{0} - {1} - + Disabilitato l'uso di {0} {1} per il ruolo {2}. - + Abilitato l'uso di {0} {1} per il ruolo {2}. - + sec. Short of seconds. - + Disabilitato l'utilizzo di {0} {1} in questo server - + Abilitato l'utilizzo di {0} {1} in questo server - + Rimosso dalla lista nera {0} con l'ID {1} - + non modificabile - + Disabilitato l'uso di {0} {1} per l'utente {2}. - + Abilitato l'uso di {0} {1} per l'utente {2}. - + Non mostreró piú avvisi sui permessi - + Ora mostreró gli avvisi sui permessi. - + Filtro delle parole disabilitato in questo canale. - + Filtro delle parole abilitato in questo canale. - + Filtro delle parole disabilitato in questo server. - + Filtro delle parole abilitato in questo server. Abilità @@ -1672,8 +1684,7 @@ il nuovo valore di {0} è {1}! La tua traduzione automatica dei messaggi è stata rimossa. - La tua auto-traduzione linguaggio è stato impostata a {0}>{0} - Fuzzy + La tua traduzione automatica del linguaggio è stata impostata a {0}>{0} Avviata traduzione automatica dei messaggi in questo canale. @@ -1695,7 +1706,7 @@ il nuovo valore di {0} è {1}! Capitoli - + Fumetto # Competitive perse @@ -1704,7 +1715,7 @@ il nuovo valore di {0} è {1}! Competitive giocate - Rango delle competitive + Rango competitivo Fuzzy @@ -1753,7 +1764,8 @@ il nuovo valore di {0} è {1}! Altezza/Peso - + {0}m/{1}kg + Fuzzy Umidità @@ -1771,14 +1783,13 @@ il nuovo valore di {0} è {1}! Scherzo non caricato. - Latitudine/Lunghezza - Fuzzy + Latitudine/Longitudine Livello - + Lista delle tag {0}place Don't translate {0}place @@ -1788,10 +1799,10 @@ il nuovo valore di {0} è {1}! Oggetto magico non caricato. - + Profilo MAL di {0} - + Il possessore del bot non ha specificato MashapeApiKey, Non puoi usare questa funzione. Minimo/Massimo @@ -1803,23 +1814,23 @@ il nuovo valore di {0} è {1}! Nessun risultato trovato. - + In sospeso Url originale - Fuzzy - + Una chiave API di Osu! é richiesta. - + Recupero della firma di Osu! fallito. + Fuzzy - + Trovate oltre {0} immagini. Piazzandone casualmente {0} - + Utente non trovato! Perfavore controlla la regione e il Battletag prima di riprovare. In programma da guardare @@ -1840,10 +1851,10 @@ il nuovo valore di {0} è {1}! Qualità: - + Gioco veloce - + Vittoria veloce Voto @@ -1885,7 +1896,7 @@ il nuovo valore di {0} è {1}! Non stai seguendo nessuno streaming in questo server. - + Nessun tale stream Questo streaming probabilmente non esiste. @@ -1919,7 +1930,7 @@ il nuovo valore di {0} è {1}! Tipi - + Nessuna definizione trovata per la parola. Url @@ -1932,10 +1943,11 @@ il nuovo valore di {0} è {1}! Fuzzy - + Non sono riuscita a trovare quel termine nella wikia specificata. - + Inserisca una wikia, seguita dalla richiesta di ricerca. + Fuzzy Pagina non trovata. @@ -1947,10 +1959,10 @@ il nuovo valore di {0} è {1}! I campioni più bannati di {0} - + Non sono riuscita a yodificare la tua frase. - + Entrato @@ -1958,7 +1970,7 @@ il nuovo valore di {0} è {1}! `1.` - + Pagina attivitá #{0} {0} utenti in totale. @@ -1970,31 +1982,31 @@ il nuovo valore di {0} è {1}! ID del bot - + Lista di funzioni nel comando {0}calc - + {0} di questo canale è {1} Canale di discussione - + Comandi eseguiti - + {0} {1} è uguale a {2} {3} - + Unità che possono essere usate dal convertitore - + Non posso convertire {0} a {1}: unità non trovate. - + Impossibile convertire {0} in {1}: i tipi di unitá sono diversi - + Creato a @@ -2003,7 +2015,8 @@ il nuovo valore di {0} è {1}! - + Questo é il tuo token CSC + Fuzzy Emoji personalizzati @@ -2019,16 +2032,16 @@ il nuovo valore di {0} è {1}! ID - + Indice fuori dall'intervallo consentito. - + Lista degli utenti con il ruolo {0} - + Non sei autorizzato a usare questo comando con un ruolo comune per prevenirne l'abuso. - + Valore {0} invalido. Invalid months value/ Invalid hours value @@ -2043,10 +2056,10 @@ Membri: {1} ID del proprietario: {2} - + Nessun server trovato su quella pagina. - + Lista dei ripetitori Membri @@ -2076,7 +2089,7 @@ ID del proprietario: {2} Nessun ruolo in questa pagina. - + Nessun frammento in questa pagina. Nessun argomento impostato. @@ -2120,16 +2133,16 @@ ID del proprietario: {2} Registrato il - + Ricorderò {0} a {1} il {2} `({3:d.M.yyyy.} alle {4:HH:mm})` - + Formato data non valido. Controlla la lista dei comandi. - + Nuovo modello di promemoria stabilito. - + Ripetendo {0} ogni {1} giorno(s), {2} ore(s) e {3} minuti(s). Lista dei ripetitori @@ -2151,10 +2164,10 @@ ID del proprietario: {2} Ruoli - + Pagina #{0} di tutti i ruoli in questo server: - + Pagina #{0} dei ruoli di {1} Nessun colore è nel formato giusto. Usa `#00ff00` per esempio. @@ -2167,40 +2180,42 @@ ID del proprietario: {2} Fermata la rotazione dei colori per il {0} ruolo - + {0} di questo server è {1} Info del server - + Frammento - + Statistiche della Shard + Fuzzy - + **Nome:** {0} **Link:** {1} - + Nessuna emoji speciale trovata. - + Avviando {0} canzoni, {1} in coda. Canali di testo - + Qui c'è il link della tua stanza: - + Tempo di funzionamento + Fuzzy - + {0} di questo utente {1} è {2} Id of the user kwoth#1234 is 123123123123 @@ -2213,19 +2228,20 @@ ID del proprietario: {2} Sei già entrato in gara! - + Risultati del sondaggio corrente - + Nessun voto - + C'è già un sondaggio in corso in questo server. - + 📃 {0} ha creato un sondaggio che richiede la tua attenzione: - + '{0}. '{1} con {2} voti. + Fuzzy {0} ha votato. @@ -2244,10 +2260,10 @@ ID del proprietario: {2} {0} voti in totale. - + Prendili scrivendo `{0}prendi` - + Prendilo scrivendo `{0}prendi` Nessun utente trovato. @@ -2262,46 +2278,183 @@ ID del proprietario: {2} Non ci sono ruoli nei canali vocali. - + {0} è stato **mutato* dal canale di testo e vocale per {1} minuti. - + Gli utenti che entrano {0} canale vocale avranno {1} come ruolo. - + Gli utenti che entrano {0} canale vocale non avranno più un ruolo. - + Ruoli del canale vocale - + I messaggi che innescano la reazione personalizzata con id {0} non saranno automaticamente eliminati. - + I messaggi che innescano la reazione personalizzata con id {0} saranno automaticamente eliminati. - + Il messaggio di risposta per la reazione personalizzata con l'id {0} non sarà inviato come MP. - + I messaggi di risposta per la reazione personalizzata id {0} saranno ora mandati come MP. Nessun alias trovato - + Scrivere {0} sarà ora un alias di {1}. - + Lista degli alias - + Innescato {0} non ha più un Alias. + Fuzzy - + Innescato {0} non ha un alias. + Fuzzy - + Tempo di gioco competitivo + + + Canale + + + Testo del comando + + + Espulso + PLURAL + + + Moderatore + + + pagina {0} + + + Ragione + + + Nuovo comando all'avvio aggiunto. + Fuzzy + + + Comando all'avvio rimosso con successo. + Fuzzy + + + Comando all'avvio non trovato. + Fuzzy + + + Server + + + Nessun comando di avvio in questa pagina + Fuzzy + + + Ripuliti tutti i comandi all'avvio. + Fuzzy + + + All'utente {0} é stato rimosso il ban. + + + Utente non trovato. + + + L'utente {0} é stato avvisato. + + + L'utente {0} é stato avvisato e {1} punizioni sono state applicate. + + + Avvisato nel server {0} + + + Il {0} alle {1} da {2} + + + Tutti gli avvisi sono stati cancellati per {0}. + + + Nessun avviso in questa pagina. + + + Lista degli avvisi per {0} + + + Nessuna punizione stabilita. + + + ripulito da {0} + + + Lista degli avvisi. + + + Avere {0} avvisi non porterá piú a una punizione. + + + Applicheró la punizione {0} agli utenti con {1} avvisi. + + + La modalitá lenta ignorerá il ruolo {0}. + Fuzzy + + + La modalitá lenta non ignorerá piú il ruolo {0}. + Fuzzy + + + La modalitá lenta ignorerá l'utente {0}. + Fuzzy + + + La modalitá lenta non ignorerá piú l'utente {0}. + Fuzzy + + + Errore nella richiesta dei premi per le seguenti ragioni: + + + Magari hai giá ricevuto il tuo premio per questo mese, Puoi ricevere premi solo una volta al mese sempre se non aumenti la tua donazione mensile. + + + Giá premiato + + + Il tuo account discord potrebbe non essere connesso con Patreon. Se non sai cosa significa, o non sai come connetterlo - bisogna andare su [la pagina delle impostazioni dell'account Patreon] (https://patreon.com/settings/account) e cliccare su 'Connetti a discord' + + + L'account discord non é connesso + + + Per essere consono a ricevere premi, devi supportare il progetto su patreon. Puoi usare il comando {0} per ricevere il link. + + + Non sta donando + Fuzzy + + + Devi aspettae un po' di ore dopo aver fatto la tua donazione, se non lo hai fatto, prova di nuovo piú tardi + Fuzzy + + + Aspetta un po' di tempo + + + Hai ricevuto {0} ringraziamenti per il supporto del progetto! + + + I premi possono essere richiesti dal 5 di ogni mese \ No newline at end of file From 7fa355af7058583102af5a182c8c7a7a806ff6cd Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:26 +0200 Subject: [PATCH 694/746] Update ResponseStrings.ja-JP.resx (POEditor.com) --- .../Resources/ResponseStrings.ja-JP.resx | 267 +++++++++++++----- 1 file changed, 204 insertions(+), 63 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx b/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx index 6e52fbe0..2b33b3f1 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ja-JP.resx @@ -905,7 +905,8 @@ Fuzzy ソフトバン(キック) - PLURAL + PLURAL +Fuzzy {0}はこのチャンネルを無視します。 @@ -1388,97 +1389,113 @@ Paypal <{1}> {0}の新しい値は{1}です! - + waifuは安いです。実際の値がより低い場合でも、waifuを取得するには少なくとも{0}を支払う必要があります。 - + あなたはwaifuを主張するために{0}以上支払う必要があります! + - + そのwaifuはあなたのものではありません。 + - + あなたは自分自身を主張することはできません。 + - + あなたは最近離婚した。もう離婚するには{0}時間と{1}分待つ必要があります。 + - + 誰も + - + あなたはあなたを好きではない妖精と離婚しました。あなたは{0}戻ってきました。 + エイトボール - + Acrophobia + - + ゲームは提出なしで終了しました。 - + 投票は行われません。ゲームは勝者なしで終了しました。 + - + 頭字語は{0}でした。 - + Acrophobiaゲームは既にこのチャンネルで実行されています。 + - + ゲームが始まった。次の頭文字で{0}の文章を作成します。 - + 投稿には{0}秒かかります。 + - + {0}はその文を提出しました。 ({1}合計) + 数字を入力して投票 - + {0}は投票をしました! + - + 勝者は{1}点で{0}です。 + - + {0}は投稿した唯一のユーザーであるための勝者です! 質問 - + それはドローです!どちらも{0} - + {0}が勝った! {1}が{2}を打つ - + 投稿が閉じられました + - + 動物レースはすでに実行中です。 + - + 合計:{0}平均:{1} + カテゴリー - + このサーバーではCleverbotは使えません。 このサーバーではCleverbotが有効です。 - + このチャンネルでは現在の世代は使えなくなりました。 - + このチャンネルでは現在の世代は使えるようになりました。 @@ -1506,16 +1523,16 @@ Paypal <{1}> - + リーダーボード - + 十分な {0} を持っていません。 - + 結果はありません。 - + {0} をひろった。 Kwoth picked 5* @@ -1523,10 +1540,10 @@ Paypal <{1}> Kwoth planted 5* - + Trivia gameはすでにこのサーバーで動いています。 - + Trivia game @@ -1535,22 +1552,22 @@ Paypal <{1}> - + {0} は {1} ポイント持っています。 - + この質問のあと停止します。 - + 時間切れです。正解は {0} です。 - + あなた自身とはゲームできません。 - + TicTacToe ゲームはすでにこのサーバで動いています。 引き分け @@ -1562,7 +1579,7 @@ Paypal <{1}> {0} の勝ち! - + 三回戦 @@ -1577,7 +1594,7 @@ Paypal <{1}> - + キューに {0} 曲を適用しています。 オートプレイは無効です。 @@ -1592,26 +1609,26 @@ Paypal <{1}> ディレクトリのキューが完了しました。 - + フェアプレイ 曲が終わった Fuzzy - + フェアプレイは無効です。 - + フェアプレイは有効です。 - + ポジションから - + ID - + 不適切な入力。 最大再生時間は制限ありません。 @@ -1688,56 +1705,56 @@ Paypal <{1}> キュー( {0}/{0} ) はいっぱいです。 - + 削除された曲 context: "removed song #5" - + 繰り返し現在の曲 - + 繰り返しプレイリスト - + 繰り返しトラック - + 現在のトラックの繰り返しを中止しました。 - + 曲の再生を再開しました。 - + プレイリストの繰り返しは無効です。 - + プレイリストの繰り返しは有効です。 - + このチャンネルでは、再生、終了、一時停止、曲の削除ができます。 - + スキップしました。 {0}:{1} - + シャッフルした曲 - + 削除した曲 - + {0}時 {1}分 {2}秒 - + 位置に - + 無制限 - + 音量は0から100の間でなければなりません。 - + 音量を {0}% にセット @@ -2527,5 +2544,129 @@ Paypal <{1}> + + + + + + + + + PLURAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From eb4c3c68e7b208177e33fa27faf88a0ea0045fd1 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:28 +0200 Subject: [PATCH 695/746] Update ResponseStrings.ko-KR.resx (POEditor.com) --- .../Resources/ResponseStrings.ko-KR.resx | 855 ++++++++++-------- 1 file changed, 498 insertions(+), 357 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ko-KR.resx b/src/NadekoBot/Resources/ResponseStrings.ko-KR.resx index 223b9397..239484e4 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ko-KR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ko-KR.resx @@ -119,7 +119,6 @@ 기지가 이미 요청되었거나 파괴되었습니다. - Fuzzy 기지가 이미 파괴되었습니다. @@ -129,11 +128,9 @@ {1} 와의 전쟁에서 #{0} 번 기지가 **파괴**되었습니다. - Fuzzy {2} 와의 전쟁에서 {0} 가 #{1} 번 기지를 **요청**하지 못했습니다. - Fuzzy {2} 와의 전쟁에서 #{1} 번 기지를 {0} 가 요청하였습니다. @@ -143,11 +140,9 @@ {1} 와의 전쟁에서 @{0} 의 요청이 만료되었습니다. - Fuzzy - Fuzzy {0} 와의 전쟁에 대한 정보 @@ -175,7 +170,6 @@ 크기 - Fuzzy {0} 에 대한 전쟁이 이미 시작되었습니다. @@ -205,7 +199,7 @@ 모든 커스텀 리액션 목록 - 커스텀 리액션 + 커스텀 리액션 목록 새로운 커스텀 리액션 @@ -339,23 +333,23 @@ Fuzzy 봇의 상태가 {0} 으로 변경되었습니다. - 퇴장 메세지의 자동삭제가 비활성화되었습니다. + 퇴장 메시지의 자동삭제가 비활성화되었습니다. Fuzzy - 퇴장 메세지는 앞으로 {0} 초 후에 삭제됩니다. + 퇴장 메시지는 앞으로 {0} 초 후에 삭제됩니다. Fuzzy - 현재 퇴장 메세지: {0} + 현재 퇴장 메시지: {0} Fuzzy - 퇴장 메세지를 활성화하기 위해서는 {0} 를 입력하십시오. + 퇴장 메시지를 활성화하기 위해서는 {0} 를 입력하십시오. Fuzzy - 새로운 퇴장 메세지가 설정되었습니다. + 새로운 퇴장 메시지가 설정되었습니다. Fuzzy @@ -369,7 +363,6 @@ Fuzzy 이전 이름 - Fuzzy 채널의 주제가 변경되었습니다. @@ -379,7 +372,6 @@ Fuzzy 내용 - Fuzzy {0} 역할을 성공적으로 생성하였습니다. @@ -410,11 +402,11 @@ Fuzzy 음성 채널 {0} 를 삭제했습니다. - 개인 메세지 + 개인 메시지 Fuzzy - 성공적으로 새로운 기부자를 추가했습니다. 이 유저의 총 기부량은 {0} 입니다. + 성공적으로 새로운 기부자를 추가했습니다. 이 유저의 총 기부량은 {0} 👑 입니다. 이 프로젝트를 위해 수고해주신 아래의 사람들에게 감사드립니다! @@ -432,19 +424,19 @@ Fuzzy 지금부터 DM 전달을 중단하겠습니다. - 환영 메세지에 대한 자동삭제가 비활성화되었습니다. + 환영 메시지에 대한 자동삭제가 비활성화되었습니다. - 환영 메세지는 {0} 초 후에 삭제될 것입니다. + 환영 메시지는 {0} 초 후에 삭제될 것입니다. - 현재 DM 환영 메세지: {0} + 현재 DM 환영 메시지: {0} - {0} 을(를) 입력하여서 DM 환영 메세지를 활성화시킵니다. + {0} 을(를) 입력하여서 DM 환영 메시지를 활성화시킵니다. - 새로운 DM 환영 메세지가 설정되었습니다. + 새로운 DM 환영 메시지가 설정되었습니다. DM 환영 알림이 비활성화되었습니다. @@ -454,13 +446,13 @@ Fuzzy DM 환영 알림 활성화 되었습니다. - 현재 환영 메세지: {0} + 현재 환영 메시지: {0} - {0} 를 입력하여서 환영 메세지를 활성화시킵니다. + {0} 를 입력하여서 환영 메시지를 활성화시킵니다. - 새로운 환영 메세지가 설정되었습니다. + 새로운 환영 메시지가 설정되었습니다. 환영 알림이 비활성화되었습니다. @@ -541,20 +533,20 @@ Fuzzy {0} 이(가) 다음 역할에 대한 언급을 요청했습니다. - {0} `[봇의 소유자]` 로부터 메세지: + {0} `[봇의 소유자]` 로부터 메시지: Fuzzy - 메세지가 전송되었습니다. + 메시지가 전송되었습니다. {0} 이(가) {1} 에서 {2} 로 이동했습니다. - #{0} 에서 메세지가 삭제되었습니다. + #{0} 에서 메시지가 삭제되었습니다. - #{0} 에서 메세지가 업데이트되었습니다. + #{0} 에서 메시지가 업데이트되었습니다. 음소거 @@ -576,7 +568,7 @@ Fuzzy 요청하신 것을 처리하기 위해서는**관리자** 권한이 필요합니다. - 새로운 메세지 + 새로운 메시지 새로운 닉네임 @@ -594,7 +586,7 @@ Fuzzy 해당하는 Shard ID가 없습니다. - 이전 메세지 + 이전 메시지 이전 닉네임 @@ -669,7 +661,7 @@ Fuzzy 자신보다 가장 높은 역할보다 높은 사용자의 역할을 수정할 수 없습니다. - 다루고있었든 메세지 치웠습니다: {0} + 다루고있었던 메시지를 치웠습니다: {0} Fuzzy @@ -777,16 +769,17 @@ Fuzzy 소프트 밴 (강제퇴장) - PLURAL + PLURAL +Fuzzy {0} 은(는) 이 채널을 무시할 것입니다. - {0} 은(는) 더이상 이 채널을 무시하지 않을 것입니다. + {0} 은(는) 더 이상 이 채널을 무시하지 않을 것입니다. - 만약 사용자가 {0} 개 이상의 같은 메세지를 보내면 {1} 합니다. + 만약 사용자가 {0} 개 이상의 같은 메시지를 보내면 {1} 합니다. __무시하는 채널들__: {2} @@ -842,16 +835,16 @@ Fuzzy Fuzzy - {0} 은(는) 이제 {1} 입니다. + {0} 님은 상태는 {1} 입니다. {0} 은(는) 텍스트와 음성 채팅으로부터 **차단해제**되었습니다. - {0} 님이 {1} 음성채널에 입장하셨습니다. + {0} 님이 음성채널 {1} 에 입장하셨습니다. - {0} 님이 {1} 음성채널에서 퇴장하셨습니다. + {0} 님이 음성채널 {1} 에서 퇴장하셨습니다. {0}님이 음성채널 {1} 에서 {2} 로 이동되었습니다. @@ -942,7 +935,7 @@ Fuzzy Fuzzy - {1} 을(를) 받으려면 이 메세지에 {0} 리액션을 추가하세요. + {1} 을(를) 받으려면 이 메시지에 {0} 리액션을 추가하세요. Fuzzy @@ -1142,7 +1135,7 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 Fuzzy - {0} 이(가) {1} (으)로 레이스를 이겼고 {2}! + {0} 이(가) {1} (으)로 레이스를 이겼고 {2} 을 획득했습니다! Fuzzy @@ -1194,41 +1187,44 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 최고의 와이프 - + 당신의 친밀감이 이미 그 와이프로 설정 했거나 당신에게 친밀감이 없는 상태의 와이프에게 친밀감 삭제를 시도했습니다. - + 친밀감이 {0} 에서 {1} 으로 변경되었습니다. + +*도덕성이 의심스럽습니다.*🤔 Make sure to get the formatting right, and leave the thinking emoji - + 친밀감을 다시 바꾸기 위해서는 {0} 시간 {1} 분을 기다려야합니다. - + 당신의 친밀감은 초기화되었습니다. 당신이 좋아하는 사람은 더 이상 없습니다. - + 님이 {0}의 와이프가 되고싶어합니다. - + 님이 {1} 에 {0} 님을 와이프로 요구했습니다. - + 당신을 좋아하는 와이프와 이혼했습니다. {0} 님이 보상금으로 {1} 만큼을 받았습니다. - + 자기 자신에게 친밀감을 설정 할 수 없습니다. - + 🎉 그들의 사랑이 성취되었습니다! 🎉 +{0} 의 새로운 가치는 {1} 입니다! - + 그렇게 싼 와이프는 없습니다. 와이프를 얻기 위해서는 실제 가치보다 낮더라도 {0} 만큼을 지불해야합니다. - + 와이프를 요구하기 위해서는 {0} 이상을 지불해야합니다! - + 그 와이프는 당신의 와이프가 아닙니다. 자기자신을 클레임 할 수 없습니다. @@ -1242,7 +1238,7 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 아무도 없음 - + 당신을 좋아하지 않는 와이프와 이혼했습니다. 당신은 {0}을 돌려받았습니다. 8ball @@ -1256,98 +1252,102 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 아무런 제출 없이 게임이 끝났습니다. - + 아무도 투표하지 않았습니다. 승자없이 게임이 종료되었습니다. - 두문자가 {0} 이었슴니다. + 머리글자는 {0} 이었습니다. - + 아크로포비아 게임이 이미 이 채널에서 진행 중입니다. - + 게임이 시작되었습니다. {0} 머리글자를 사용해서 문장 만드십시오. + Fuzzy - + 제출까지 {0} 초 남았습니다. - + {0} 가 그의 문장을 입력했습니다. (합계: {1}) - + 제출번호를 입력해서 투표를 하십시오. - + {0} 가 투표했습니다! - + 우승자는 {1} 포인트를 가진 {0} 입니다. - + {0} 님이 서버에서 유일한 제출자이기 때문에 승리했습니다. - + 문제 + - + 비겼습니다! 둘다 {0} 을(를) 선택했습니다. - + {0} 가 승리했습니다! {1} 은(는) {2} 을(를) 이겼습니다. - + 제출이 마감되었습니다. - + 동물 레이스가 이미 진행 중입니다. - + 총합: {0} 평균: {1} - + 범주 - + 이 서버에서 클레버봇을 비활성화하였습니다. - + 이 서버에서 클레버봇을 활성화하였습니다. - + 이 채널에서 통화 생성이 비활성화되었습니다. - + 이 채널에서 통화 생성이 활성화되었습니다. - - plural + {0} 무작위 {1} 가 등장했습니다! + plural +Fuzzy - + 무작위 {0} 가 등장했습니다! - + 질문 로딩에 실패하였습니다. - + 게임이 시작되었습니다 - + 행맨 게임이 시작되었습니다 - + 행맨 게임이 이미 시작되었습니다 - + 행맨 게임 시작에 오류가 발생하였습니다. - + "{0}hangman" 용어 종류 목록 - + 리더 보드 + Fuzzy - + 당신은 충분한 {0} 이(가) 없습니다. 결과가 없습니다. @@ -1361,246 +1361,252 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 Kwoth planted 5* - + 이미 이 서버에서 트리비아 게임이 진행중입니다. - + 트리비아 게임 - + {0} 님이 맞췄습니다! 답은 {1} 입니다. - + 이 서버에서 진행중인 트리비아 게임이 없습니다. - + {0} 이(가) {1} 포인트를 갖고있습니다. - + 이 질문 후에 중지합니다. - + 시간초과! 정확한 답은 {0} 입니다. + Fuzzy - + {0} 님이 맞춰서 게임을 이겼습니다! 답은 {1} 입니다. + Fuzzy - + 당신을 상대로 플레이 할 수 없습니다. - + 이미 이 채널에서 TicTacToe 게임이 진행중입니다. - + 비겼습니다! - + 님이 TicTacToe 게임을 생성하였습니다. - + {0} 님이 이겼습니다! - + 3개 일치 + Fuzzy - + 더 이상 움직일 수 없습니다! - + 시간이 만료되었습니다! - + {0}의 이동 - + {0} 대 {1} - + {0} 개의 곡을 대기열에 추가하는 중... - + 자동재생이 비활성화되었습니다. - + 자동재생이 활성화되었습니다. - + 기본 음량이 {0}%로 설정되었습니다. - + 디렉토리 대기열 추가가 완료되었습니다. + Fuzzy - + 페어플레이 - + 재생 완료 - + 페어플레이가 비활성화되었습니다. - + 페어플레이가 활성화되었습니다. - + 원레 위치 - + ID - + 유효하지 않은 입력입니다. - + 이제 최대 재생시간에 제한이 없습니다. - + 최대 재생시간이 {0} 초로 설정되었습니다. - + 이제 음악 대기열 크기는 제한이 없습니다. - + 음악 대기열 크기가 {0} 곡으로 변경되었습니다. - + 당신은 이 서버의 음성채널에 있어야 합니다. - + 이름 - + 현재 재생 중 - + 재생중인 곡이 없습니다. - + 검색 결과가 없습니다. - + 음악 재생이 일시정지되었습니다. - + 음악 대기열 - {0}/{1} 페이지 - + 노래 재생 중 - + `#{0}` - {2} 님의 재생목록 **{1}** ({3} 곡) - + 저장된 재생목록의 {0} 번째 페이지 - + 재생목록이 삭제되었습니다. - + 재생목록 삭제에 실패했습니다. 존재하지 않거나, 당신이 재생목록의 저자가 아닙니다. - + 그 ID에 해당하는 재생목록이 존재하지 않습니다. - + 재생목록 대기열 추가 완료. - + 재생목록이 저장되었습니다. - + {0} 초 한계 - + 대기열 - + 대기열에 추가됨 - + 음악 대기열이 초기화되었습니다. - + 대기열이 {0}/{0} 으(로) 가득찼습니다. - + 곡 삭제됨 context: "removed song #5" - + 현재 곡을 반복재생합니다. - + 현재 재생목록을 반복재생합니다. - + 현재 트랙을 반복재생합니다. - + 현재 트랙 반복이 중지되었습니다. - + 음악 재생이 재개되었습니다. - + 재생목록 반복이 비활성화되었습니다. - + 재생목록 반복이 활성화되었습니다. - + 앞으로 재생 중, 완료, 일시정지, 삭제된 곡들을 이 채널에 출력합니다. - + `{0}:{1}`로 이동하였습니다. + Fuzzy - + 곡을 섞었습니다. - + 곡이 이동되었습니다. - + {0}시간 {1}분 {2}초 - + 바뀐 위치 + Fuzzy - + 무제한 - + 음량은 0과 100 사이의 값이여야 합니다. - + 음량이 {0}% 로 설정되었습니다. - + {0} 채널에서 모든 모듈의 사용을 비활성화했습니다. - + {0} 채널에서 모든 모듈의 사용을 활성화했습니다. 허락함 Fuzzy - + {0} 역할에게 모든 모듈의 사용을 비활성화했습니다. - + {0} 역할에게 모든 모듈의 사용을 활성화했습니다. - + 이 서버에서 모든 모듈의 사용을 비활성화했습니다. - + 이 서버에서 모든 모듈의 사용을 활성화했습니다. - + {0} 사용자에 대한 모든 모듈의 사용을 비활성화합니다. - + {0} 사용자에 대한 모든 모듈의 사용을 활성화합니다. {0} (ID {1})님을 블랙리스트했습니다 @@ -1639,28 +1645,28 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 Fuzzy - + 유효하지 않은 두번째 파라미터입니다. ( {0} 와(과) {1} 사이의 숫자여야 합니다.) - + 초대 필터링이 이 채널에서 비활성화되었습니다. - + 초대 필터링이 이 채널에서 활성화되었습니다. - + 초대 필터링이 이 서버에서 비활성화되었습니다. - + 초대 필터링이 이 서버에서 활성화되었습니다. - + {0} 권한을 #{1} 에서 #{2} (으)로 이동했습니다. - + 색인 #{0} 에 대한 권한을 찾을 수 없습니다. - + 아무런 값이 설정되지 않았습니다. 명령어 @@ -1674,137 +1680,140 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 권한 목록 {0} 페이지 - + 현재 권한 역할은 {0} 입니다. - + 이제 사용자가 권한 수정을 위해서는 {0} 권한이 필요합니다. - + 그 색인에 대한 권한을 찾을 수 없습니다. - + #{0} - {1} 권한을 삭제했습니다. - + {2} 역할에 대한 {0} {1} 의 사용을 비활성화했습니다. - + {2} 역할에 대한 {0} {1} 의 사용을 활성화했습니다. 초. Short of seconds. - + 이 서버에서 {0} {1} 의 사용을 비활성화했습니다. - + 이 서버에서 {0} {1} 의 사용을 활성화했습니다. - + {0} (ID {1} ) 님을 블랙리스트에서 해제하였습니다. + Fuzzy - + 수정불가 - + {2} 사용자의 {0} {1} 의 사용을 비활성화했습니다. - + {2} 사용자의 {0} {1} 의 사용을 활성화했습니다. - + 더 이상 권한 경고를 표시하지 않습니다. - + 앞으로 권한 경고를 표시합니다. - + 단어 필터링이 이 채널에서 비활성화되었습니다. - + 단어 필터링이 이 채널에서 활성화되었습니다. - + 단어 필터링이 이 서버에서 비활성화되었습니다. - + 단어 필터링이 이 서버에서 활성화되었습니다. 능력 - + 좋아하는 애니메이션이 없습니다. - + 이 채널 메시지의 자동번역을 시작합니다. 사용자의 메시지는 자동삭제 됩니다. - + 당신의 자동번역 언어가 제거되었습니다. - + 당신의 자동번역 언어가 {0}>{1} 로 설정되었습니다. - + 이 채널의 자동번역을 시작합니다. - + 이 채널의 자동번역을 중지합니다. - + 올바르지 않은 입력 포맷이거나 무언가가 잘못되었습니다. - + 그 카드를 찾을 수 없습니다. - + 사실 - + 챕터 - + 만화 # - + 경쟁전 패배 - + 경쟁전 플레이 - + 경쟁전 랭크 - + 경쟁전 승리 - + 완료 - + 조건 - + - + 날짜 - + 정의: + Fuzzy - + 시청 종료 + Fuzzy - + 에피소드 - + 오류가 발생했습니다. - + 예시 애니메이션 검색에 실패했습니다. @@ -1816,7 +1825,7 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 장르 - + 해당 태그에 대한 정의를 찾지 못했습니다. 키/무게 @@ -1834,339 +1843,353 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 영화 검색에 실패했습니다. - + 유효하지 않은 소스 또는 언어입니다. + Fuzzy - + 농담이 로드되지 않았습니다. - + 위도/경도 - + 레벨 - + {0}place 태그 목록 Don't translate {0}place - + 위치 - + 마법 아이템이 로드되지 않습니다. - + {0}의 MAL 프로필 - + 봇의 소유자가 MashapeApiKey을 설정하지 않아서 이 기능을 사용 할 수 없습니다. - + 최소/최대 - + 채널을 찾을 수 없습니다 - + 결과를 찾을 수 없습니다. - + 보류 - + 원본 Url - + osu! API키가 필요합니다. - + osu! 정보 검색에 실패했습니다. - + {0} 개 이상의 이미지가 발견되었습니다. 무작위로 {0}개를 표시합니다. + Fuzzy - + 사용자를 찾을 수 없습니다! 다시 시도하기 전에 지역과 배틀태그를 확인해주십시오 - + 볼 예정 - + 플랫폼 - + 능력을 찾을 수 없습니다. - + 포케몬을 찾을 수 없습니다. - + 프로필 링크: - + 품질: - + 빠른대전 플레이 시간 - + 빠른대전 승리 - + 레이팅 - + 점수: - + 검색 쿼리: - + Url 단축에 실패했습니다. - + Url 단축 - + 무언가가 잘못되었습니다. - + 검색어를 입력해주세요. + Fuzzy - + 상태 - + 저장된 Url + Fuzzy - + 스트리머 {0} 은(는) 오프라인입니다. - + 스트리머 {0} 은(는) {1} 명의 시청자와 함께 온라인입니다. + Fuzzy - + 당신은 이 서버에서 {0} 개의 스트리밍을 팔로우 중입니다. - + 당신은 이 서버에서 어떠한 스트리밍도 팔로우하지 않았습니다. + Fuzzy - + 스트리밍이 없습니다. - + 스트리밍 속성이 존재하지 않습니다. - + {0}의 스트리밍 ({1})을 알림에서 삭제했습니다. - + 상태가 변경되면 이 채널에 알립니다. - + 일출 - + 일몰 - + 온도 - + 제목: - + 좋아하는 상위 3개 애니: - + 번역 결과: - + 종류 - + 해당 용어에 대한 정의를 찾지 못했습니다. - + Url - + 시청자 - 보고있는것: + 시청중 Fuzzy - + 해당 용어에 대한 특정 Wikia를 찾지 못했습니다. - + 목적 Wikia를 입력하고 검색 쿼리를 입력하십시오. - + 페이지를 찾지 못했습니다. - + 바람의 속도 - + {0} 번째로 많은 밴을 당한 챔피언 - + 당신의 문장을 Yodify하지 못했습니다. - + 입장 - + `{0}.` {1} [{2:F2}/초] - 합계 {3} /s and total need to be localized to fit the context - `1.` - + 활성 페이지 #{0} - + 총 {0} 명의 사용자. - + 저자 - + 봇 ID - + {0}calc 명령어의 기능 목록 - + 이 채널의 {0} 은 {1} 입니다. - + 채널 주제 - + 실행된 명령어 - + {0} {1} 은(는) {2} {3} 와(과) 같습니다. - + 변환기에서 사용할수있는 단위 - + 단위를 찾지 못해서 {0} 을(를) {1} (으)로 변환 할 수 없습니다. + Fuzzy - + 단위의 종류가 같지 않기때문에 {0} 을(를) {1} (으)로 변환 할 수 없습니다. + Fuzzy - + 작성 시간: - + 크로스 서버 채널에 입장했습니다. + Fuzzy - + 크로스 서버 채널에서 퇴장했습니다. - + 이것은 당신의 CSC 토큰입니다. - + 커스텀 이모지 - + 오류 - + 기능 - + 아이디 - + 색인이 범위를 벗어났습니다. + Fuzzy - + {0} 역할의 사용자 목록 - + 악용을 막기위해서 많은 사용자가 있는 역할의 이 명령어 사용이 제한되었습니다. - + 유효하지 않은 {0} 값입니다. Invalid months value/ Invalid hours value - + 디스코드 입장 - + 서버 입장 - + ID: {0} +맴버: {1} +소유자 ID: {2} - + 이 페이지에서 서버를 찾을 수 없습니다. - + 리피터 목록 - + 맴버 - + 메모리 - + 메시지 - + 메시지 리피터 - + 이름 - + 닉네임 - + 아무도 그 게임을 플레이하고 있지 않습니다. - + 활성화된 리피터가 없습니다. - + 이 페이지에 역할이 없습니다. - + 이 페이지에 Shard가 없습니다. - + 주제가 설정되지 않았습니다. - + 소유자 - + 소유자의 ID - + 상태 - + {0} 서버 +{1} 텍스트 채널 +{2} 음성 채널 - + {0} 키워드를 가진 모든 인용구를 삭제했습니다. - + 인용구 페이지 {0} - + 이 페이지에 인용구가 없습니다. - + 삭제 할 수 있는 인용구를 찾지못했습니다. 인용구가 추가되었습니다. @@ -2181,28 +2204,28 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 가입 날짜 - + 제가 {2} `({3:d.M.yyyy.} at {4:HH:mm})`에 {0} 에게 {1}을(를) 상기시킬 것입니다. 유효하지않은 시간 포맷입니다. 명령어 목록을 확인하십시오. - + 새로운 상기 템플릿이 설정되었습니다. - + {0} 을 {1} 일 {2} 시간 {3} 분마다 반복합니다. 반복 메시지 목록 - 이 서버에 반복 메시지 실행하고있지 안습니다. + 이 서버에 반복 메시지가 실행하고있지 않습니다. #{0} 이 정지되었습니다. - + 이 서버에서 반복 메시지를 찾을 수 없습니다. 결과 @@ -2211,25 +2234,26 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 역할 - + 이 서버의 모든 역할 페이지 #{0} : - + {1} 역할에 대한 페이지 #{0} - + 색상 포맷이 정확하지 않습니다. `#00FF00`을 사용해보십시오. - + {0} 역할의 색상 로테이션을 시작했습니다. + Fuzzy - + {0} 역할의 색상 로테이션을 중지했습니다. - + 이 서버의 {0} 은 {1} 입니다. - + 서버 정보 Shard @@ -2245,7 +2269,6 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 특수 이모지를 찾을 수 없습니다. - Fuzzy {0} 개의 곡을 재생중이며, {1} 개의 대기열이 있습니다. @@ -2254,10 +2277,10 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 텍스트 채널 - + 방 링크: - + 작동 시간 {1} 의 {0} 은(는) {2} 입니다. @@ -2265,7 +2288,6 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 사용자 - Fuzzy 음성 채널 @@ -2284,10 +2306,9 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 📃 {0} 님이 투표를 생성하였습니다. - Fuzzy - + `{0}.` {2} 표를 가진 {1}. {0} 님이 투표하였습니다. @@ -2295,25 +2316,21 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 해당 답변 번호와 함께 개인 메시지를 보내십시오. - Fuzzy 해당 답변 번호와 함께 여기에 메시지를 보내십시오. - Fuzzy {0} 님, 투표해주셔서 감사합니다 - {0} 개의 표가 던져졌습니다. - Fuzzy + {0} 개의 표가 투표되었습니다. - + `{0}pick`을 입력해서 획득하십시오. `{0}pick`을 입력해서 획득하십시오. - Fuzzy 사용자를 찾지 못했습니다. @@ -2331,31 +2348,31 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 {0} 은(는) 음성과 텍스트 채팅으로 부터 {1} 분간 **음소거**되었습니다. - {0} 음성채널에 입장하는 사용자는 {1} 역할을 얻게됩니다. + 음성채널 {0} 에 입장하는 사용자는 {1} 역할을 얻게됩니다. - {0} 음성채널에 입장하는 사용자는 더이상 {1} 역할을 얻지 못합니다. + 음성채널 {0} 에 입장하는 사용자는 더이상 {1} 역할을 얻지 못합니다. 음성채널 역할 - + ID {0} 커스텀 리액션을 작동시키는 메시지는 자동삭제되지 않습니다. - + ID {0} 커스텀 리액션을 작동시키는 메시지는 자동삭제됩니다. - + 이제 ID {0} 커스텀 리액션에 대한 반응은 DM으로 전송되지 않습니다. - + ID {0} 커스텀 리액션에 대한 반응은 DM으로 전송됩니다. 가명을 찾지 못했습니다. - {0} 입력은 이제 {1} 의 가명일것이니다. + {0} 을(를) 입력하면 이제 {1} 의 가명입니다. 가명 목록 @@ -2364,10 +2381,134 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 트리거 {0} 의 가명을 삭제했습니다. - 트리거 {0} 은(는) 가명 없었습니다. + 트리거 {0} 은(는) 가명이 없었습니다. - 경기한 시간 + 경쟁전 플레이 시간 + + + 채널 + + + 명령어 텍스트 + + + 강퇴 + PLURAL + + + 관리자 + + + {0} 페이지 + + + 사유 + + + 새로운 시작 명령어가 추가되었습니다. + + + 시작 명렁어가 성공적으로 삭제되었습니다. + + + 시작 명령어를 찾을 수 없습니다. + + + 서버 + + + 이 페이지에는 시작 명령어가 없습니다. + + + 모든 시작 명령어를 삭제했습니다. + + + 사용자 {0} 님이 밴에서 해제되었습니다. + + + 사용자를 찾을 수 없습니다. + + + 사용자 {0} 님이 경고를 받았습니다. + + + 사용자 {0} 님이 경고를 받았고, {1} 처벌이 적용되었습니다. + + + {0} 서버에 경고했습니다. + + + {0} {1} 에 {2} 이(가) + + + {0} 님이 모든 경고를 삭제했습니다. + + + 이 페이지에는 경고가 없습니다. + + + {0} 의 경고 기록 + + + 처벌이 설정되지 않았습니다. + + + {0} 이(가) 제거했습니다. + + + 경고 처벌 목록 + + + {0} 개의 경고를 받은 사용자에 대한 처벌을 하지않습니다. + + + {1} 개의 경고를 받은 사용자에게 {0} 처벌을 내립니다. + + + 이제 슬로우모드는 {0} 역할에게 적용되지 않습니다. + + + 이제 슬로우모드는 {0} 역할에게 적용됩니다. + + + 이제 슬로우모드는 {0} 님에게 적용되지 않습니다. + + + 이제 슬로우모드는 {0} 님에게 적용됩니다. + + + 다음과 같은 이유로 인해서 보상을 요청하지 못했습니다: + + + 당신은 이미 이번달의 보상을 받은 것 같습니다. 당신의 후원금을 올리지 않는 이상 한 달에 한 번만 보상을 받을 수 있습니다. + + + 이미 지급되었습니다. + + + 당신의 디스코드 계정이 Patreon에 연결되지 않았습니다. 이것이 무슨 뜻인지 모르거나, 어떻게 연결하는지 모른다면 - [Patreon 계정 설정 페이지] (https://patreon.com/settings/account) 에 접속해서 'Connect to discord' 버튼을 클릭하십시오. + + + 디스코드 계정이 연결되지 않았습니다. + + + 보상을 받을 수 있는 자격을 얻기 위해서는 Patreon에서 프로젝트를 후원해야 합니다. {0} 명령어를 이용해서 링크를 얻을 수 있습니다. + + + 후원 중이지 않습니다. + + + 다시 시도하지 않았다면, 후원을 한 후에 몇 시간을 기다려야합니다. + + + 잠시만 기다려주십시오. + + + {0} 을 받았습니다. 프로젝트를 후원 해주셔서 감사합니다! + + + 보상은 매 달 5일에 요구 할 수 있습니다. \ No newline at end of file From 2574546c823b87696edbe8b14fdbb53aab0f7b64 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:31 +0200 Subject: [PATCH 696/746] Update ResponseStrings.nb-NO.resx (POEditor.com) --- .../Resources/ResponseStrings.nb-NO.resx | 128 +++++++++++++++++- 1 file changed, 127 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx b/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx index 08aa81fa..52009361 100644 --- a/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx +++ b/src/NadekoBot/Resources/ResponseStrings.nb-NO.resx @@ -761,7 +761,8 @@ Grunn: {1} soft-banned (sparket) - PLURAL + PLURAL +Fuzzy {0} vil nå ignorere denne kanalen. @@ -2334,5 +2335,130 @@ Eier ID: {2} Kompetitiv spilltid + + Kanal + + + Kommando tekst + + + Sparket + PLURAL + + + Moderator + + + side {0} + + + Grunn + + + Ny oppstartskommando lagt til. + + + Oppstartskommando fjernet. + + + Fant ikke oppstartskommando + + + Server + + + Ingen oppstartskommandoer på denne siden. + + + Fjernet alle oppstartskommandoer + + + Bruker {0} er ikke lenger utestengt + + + Fant ikke bruker. + + + Advarte bruker {0} + + + Bruker {0} ble advart og straffet med {0} + + + Advart på server {0} + + + Den {0} kl. {1} av {2} + On 02.04.2017 at 16:03 by Kwoth + + + Alle advarsler fjernet for {0} + + + Ingen advarsler på denne siden. + + + Advarselslogg for {0} + + + Ingen straff satt. + + + fjernet av {0} + + + Straffliste + + + Å ha {0} advarsler vil ikke lenger gi noen straff. + + + Brukere med {1} advarsler vil bli straffet med {0} + + + Slowmode vil nå ignorere rollen {0}. + + + Slowmode ignorerer ikke lenger rollen {0}. + + + Slowmode vil nå ignorere brukeren {0}. + + + Slowmode vil ikke lenger ignorere brukeren {0} + + + Kunne ikke hevde premie p.g.a. én av følgende grunner: + + + Det er mulig du allerede har mottatt premien din for denne måneden. Du kan bare hevde premien én gang i måneden med mindre du øker summen. + + + Allerede belønnet. + + + Din Discord konto er ikke tilkoblet Patreon. Om du er usikker på hva dette betyr, eller ikke er sikker på hvordan du gjør det, kan du gå til [Patreon kontoinnstillinger](https://patreon.com/settings/account) og klikk på 'Connect to Discord'-knappen. + + + Discord kontoen er ikke tilknyttet. + + + For å være kvalifisert for belønning, må du støtte prosjektet på Patreon. Du kan bruke {0} kommandoen for å få link. + + + Støttes ikke + + + Du må vente noen timer etter du har gitt ditt løfte. Prøv igjen om litt. + + + Vent litt. + + + Du har mottatt {0}. Takk for at du støtter prosjektet! + + + Belønninger kan bare hevdes fra og med den 5. dagen i måneden. + \ No newline at end of file From a4219a89db020d48637517abdf5b551c7d47fa2f Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:34 +0200 Subject: [PATCH 697/746] Update ResponseStrings.pl-PL.resx (POEditor.com) --- .../Resources/ResponseStrings.pl-PL.resx | 277 +++++++++++++----- 1 file changed, 201 insertions(+), 76 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx index 2d71a47b..01fe013c 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pl-PL.resx @@ -203,16 +203,16 @@ Lista własnych reakcji - Własne reakcje + Niestandardowe reakcje - Nowe własne reakcje + Nowe niestandardowe reakcje - Własne reakcje nie zostały znalezione. + Niestandardowe reakcje nie zostały znalezione. - Własne reakcje z tym ID nie zostały znalezione. + Niestandardowe reakcje z tym ID nie zostały znalezione. Odpowiedź @@ -221,7 +221,7 @@ Statystyki niestandardowych reakcji - + Statystyki wyczyszczone dla {0} niestandardowych reakcji. @@ -480,7 +480,7 @@ Powód: {1} Fuzzy - + Twojego servra lokal jest teraz {0} - {1} @@ -520,7 +520,7 @@ Powód: {1} Logowanie nie będzie ignorowało {0} - + Logowanie wydarzenia {1} zatrzymane. @@ -755,7 +755,8 @@ Powód: {1} lekko zbanowany (wyrzucony) - PLURAL + PLURAL +Fuzzy {0} będzie ignorował ten kanał. @@ -880,7 +881,7 @@ Powód: {1} Migracja zakończona! - + Błąd podczas migracji, sprawdz konsole bota po więcej informacji. @@ -921,7 +922,7 @@ Powód: {1} Wydarzenie reagowania kwiatkami rozpoczęło się! - dał (0} dla {1} + dał {0} dla {1} X has gifted 15 flowers to Y @@ -979,10 +980,10 @@ Powód: {1} Trwa {0} sekund. Nie nikomu. Ciiii. - + Wydarzenie SneakyGame zakończyło się. {0} użytkowników otrzymało nagrodę. - + Wydarzenie SneakyGameStatus rozpoczęło się. Reszka @@ -1010,10 +1011,10 @@ Trwa {0} sekund. Nie nikomu. Ciiii. Komendy i aliasy - + Lista komend została wygenerowana na nowo. - + Wpisz `{0}h NazwaKomendy` aby otrzymać pomoc dla danej komendy, np. `{0}h >8ball` Nie mogę znaleźć komendy. Proszę sprawdź czy komenda istnieje, zanim jej użyjesz. @@ -1048,7 +1049,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Ten moduł nie istnieje. - + Wymaga {0} uprawnień na serwerze. Spis treści @@ -1094,7 +1095,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś {1} czyli {0} wygrał wyścig i {2}! - Użyty numer jest nie poprawny. Możesz rzucić {0}-{1} kośćmi na raz + Użyty numer jest niepoprawny. Możesz rzucić {0}-{1} kośćmi na raz wyrzucono {0} @@ -1164,7 +1165,8 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + 🎉 To prawdziwa miłość! 🎉 +Nowa wartość {0} to {1}! Żadna waifu nie jest taka tania. Musisz zapłacić co najmniej {0} aby zdobyć waifu, nawet jeśli nie jest tyle warta. @@ -1188,13 +1190,13 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Rozwiodłeś się z waifu, która cię nie lubi. W zamian dostałeś {0}. - Magiczna kula nr 8 + Kula nr. 8 - + Gra zakończona bez żadnych zgłoszeń. Jakies pomysły jak przetlumaczyć Submission by miało sens? @@ -1207,19 +1209,19 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Gra rozpoczęta. Stwórz zdanie z podanym akronimem: {0}. - + Masz {0} sekund aby coś zgłosić. - + {0} zgłosił swoje zdanie. (łącznie {1}) - + Głosuj, wpisując numer zgłoszenia. - + {0} dał swój głos! Zwycięzcą jest {0} z {1} punktami. @@ -1266,7 +1268,6 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś {0} się pojawiły! - Fuzzy Nie udało się załadować pytania. @@ -1293,7 +1294,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Nie masz wystarczająco {0} - Brak rezultatów + Brak wyników podniósł {0} @@ -1304,7 +1305,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Kwoth planted 5* - Trivia jest aktywna na tym serwerze + Trivia jest aktywna na tym serwerze. Trivia @@ -1313,13 +1314,13 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś {0} zgadł! Odpowiedź to: {1} - Trivia nie jest aktywna na tym serwerze + Trivia nie jest aktywna na tym serwerze. {0} posiada {1} punktów - Koniec po tym pytaniu + Koniec po tym pytaniu. Koniec czasu! Prawidłowa odpowiedź to {0} @@ -1331,7 +1332,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Nie możesz grać przeciwko sobie. - + Gra kółko i krzyżyk jest aktywna na tym serwerze. Remis! @@ -1385,7 +1386,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Fair play włączony. - + Z pozycji ID @@ -1415,7 +1416,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Teraz gra - + Brak aktywnego odtwarzacza muzyki. Brak wyników @@ -1430,7 +1431,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Gra utwór - + `#{0}` - **{1}** przez *{2}* ({3} piosenek) Strona {0} zapisanych playlist @@ -1451,7 +1452,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Playlista zapisana - + Limit {0} Kolejka @@ -1506,7 +1507,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś {0}g {1}m {2}s - + Do pozycji bez limitu @@ -1613,7 +1614,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Strona uprawnień {0} - + Aktualna rola z uprawnieniami to {0}. Użytkownicy wymagają roli {0}, by móc edytować uprawnienia. @@ -1811,7 +1812,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Brak rezultatów. - + Wstrzymane Oryginalny URL @@ -1820,7 +1821,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Klucz osu! API jest wymagany. - + Nie udało się wywołać sygnatury osu!. Znaleziono {0} obrazków. Pokazuję przypadkowe {0} @@ -1835,7 +1836,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Platforma - + Nie znaleziono umięjętności. Pokemon nieznaleziony @@ -1844,13 +1845,13 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Link profilowy: - + Jakość: - + Szybkie wygrane Ocena @@ -1871,7 +1872,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Coś poszło nie tak. - + Proszę o sprecyzowanie kryteriów wyszukiwania. Status @@ -1902,7 +1903,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Usunięto stream użytkownika {0} ({1}) z powiadomień. - + Powiadomię ten kanał kiedy status się zmieni. Wschód słońca @@ -1926,7 +1927,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Typy - + Nie znaleziono definicji dla tego terminu. Url @@ -1938,7 +1939,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś Oglądane - + Nie znaleziono tego terminu na konkretnej wikii. @@ -1964,7 +1965,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś `1.` - + Strona aktywności #{0} Łącznie {0} użytkowników. @@ -1979,7 +1980,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + {0} tego kanału to {1} Temat kanału @@ -2009,7 +2010,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + To jest twój token CSC Niestandardowe emotikony @@ -2027,7 +2028,7 @@ Nie zapomnij zostawić swojej discordowej nazwy użytkownika albo ID w wiadomoś - + Lista użytkowników w roli {0} @@ -2081,7 +2082,7 @@ ID właściciela: {2} Brak roli na tej stronie. - + Brak shard'ów na tej stronie. Brak tematu. @@ -2093,7 +2094,7 @@ ID właściciela: {2} ID właściciela - + Obecność {0} serwerów @@ -2107,10 +2108,10 @@ ID właściciela: {2} {0} strona cytatów - + Brak cytatów ona tej stronie. - + Nie znaleziono żadnych cytatów które możesz usunąć. Dodano cytat @@ -2122,10 +2123,10 @@ ID właściciela: {2} Region - + Zarejestrowany - + Przypomnę {0} dla {2} `({3:d.M.yyyy.} o {4:HH:mm})` @@ -2155,10 +2156,10 @@ ID właściciela: {2} Role - + Strona #{} wszystkich ról na tym serwerze: - + Strona #{0} ról {1} Kolory zostały podane w niepoprawnej formie. Użyj np. `#00ff00` @@ -2170,16 +2171,16 @@ ID właściciela: {2} Zakończono zmienianie kolorów dla roli {0} - + {0} tego serwera to {1} Informacje o serwerze - + Shard - + Statystyki odłamka @@ -2191,7 +2192,7 @@ ID właściciela: {2} Nie znaleziono żadnych specjalnych emotikon - + Teraz leci {0} piosenek; {1} w kolejce Kanały głosowe @@ -2200,7 +2201,7 @@ ID właściciela: {2} Twój link do pokoju: - + Czas działania @@ -2219,13 +2220,13 @@ ID właściciela: {2} - + Nie ma oddanych głosów. - + Ankieta już istnieje na tym serwerze. - + 📃 {0} stworzył ankietę, która wymaga twojej uwagi: `{0}.` {1} z {2} głosami. @@ -2244,25 +2245,25 @@ ID właściciela: {2} Dziękuję za oddany głos, {0} - + {0} oddanych głosów. - + Podnieś je przez napisanie `{0}pick` - + Podnieś to przez napisanie `{0}pick` - + Nie znaleziono użytkownika. - + Strona {0} - Musisz znajdować się w kanale głosowym na tym serwerze. + Musisz znajdować się na kanale głosowym na tym serwerze. - + Niema żadnych ról w kanałach głosowych. {0} został **wyciszony** w kanałach tekstowych oraz głosowych na {1} minut. @@ -2271,7 +2272,7 @@ ID właściciela: {2} Użytkownicy którzy dołączą do kanału głosowego {0} , otrzymają rolę {1}. - + Użytkownicy którzy dołączą do kanału głosowego {0} już nie dostaną roli. Uprawnienia kanału głosowego @@ -2283,10 +2284,10 @@ ID właściciela: {2} - + Odpowiedź na niestandardową reakcję z id {0} będzie wysłana jako wiadomość prywatna. - + Odpowiedź na niestandardową reakcję z id {0} będzie wysłana jako wiadomość prywatna. @@ -2295,7 +2296,7 @@ ID właściciela: {2} - + Lista pseudonimów @@ -2306,5 +2307,129 @@ ID właściciela: {2} + + Kanał + + + + + + Wyrzucony + PLURAL + + + Moderator + + + strona {0} + + + Powód + + + + + + + + + + + + Serwer + + + + + + + + + Użytkownik {0} został odbanowany. + + + Użytkownik nieznaleziony. + + + Użytkownik {0} został ostrzeżony. + + + + + + + + + Dnia {0} o godzinie {1} przez {2} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Otrzymałeś {0}. Dziękujemy, że wspierasz projekt! + + + + \ No newline at end of file From 4995b88fc71baf154688e68a41966e7ab686581f Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:36 +0200 Subject: [PATCH 698/746] Update ResponseStrings.pt-BR.resx (POEditor.com) --- .../Resources/ResponseStrings.pt-BR.resx | 127 +++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx index abbdde18..a416a95e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx @@ -762,7 +762,8 @@ Razão: {1} Banidos temporariamente (kickados) - PLURAL + PLURAL +Fuzzy {0} irá ignorar esse canal. @@ -2383,5 +2384,129 @@ OwnerID: {2} Tempo de jogo competitivo + + Canal + + + Comando de Texto + + + Chutado + PLURAL + + + Moderador + + + página {0} + + + Motivo + + + Novo comando de inicialização adicionado. + + + Comando de inicialização removido com sucesso. + + + Comando de inicialização não encontrado. + + + Servidor + + + Não há comandos de inicialização nesta página. + + + Todos os comandos de inicialização foram removidos. + + + Usuário {0} foi desbanido. + + + Usuário não encontrado. + + + Usuário {0} foi advertido. + + + Usuário {0} foi advertido e {1} punição foi aplicada. + + + Advertiu no server {0} + + + Em {0} às {1} por {2} + + + Todas as advertências foram removidas para {0} + + + Não há advertências nessa página. + + + Log de advertências para {0} + + + Nenhuma punição definida. + + + Limpado por {0} + + + Lista de punições por advertência + + + Possuir {0} advertências não irá mais resultar em punição. + + + Eu irei aplicar punição {0} para usuários com {1} advertências. + + + Modo lento agora irá ignorar o cargo {0}. + + + Modo lento não ira mais ignorar o cargo {0}. + + + Modo lento irá ignorar o usuário {0}. + + + Modo lento não irá mais ignorar o usuário {0}. + + + Falha em reivindicar recompensas devido a uma das seguintes razões: + + + Talvez você já tenha recebido sua recompensa esse mês. Você pode receber recompensas apenas uma vez por mês a não ser que você aumente o seu pagamento. + + + Já recompensado + + + Sua conta do discord pode não estar conectada ao Patreon. Se você não tem certeza do que isso significa, ou não sabe como conectá-la - Você deve ir para [Página de configurações de conta do Patreon)(https://patreon.com/settings/account) e clicar em 'Connect to discord' button. + + + Conta do discord não conectada + + + Para poder receber recompensas, você deve dar suporte ao projeto no patreon. Você pode usar o comando {0} para receber o link. + + + Não suportando + + + Você deve esperar algumas horas depois de realizar seu pagamento. Se não o fez, tente novamente mais tarde. + + + Espere um momento + + + Você recebeu {0} Obrigado por dar suporte ao projeto! + + + Recompensas podem ser reivindicadas no ou a partir do 5° dia de cada mês + \ No newline at end of file From 1a2433bbaf2cb12d13a03b9979cbfdd941c376cf Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:39 +0200 Subject: [PATCH 699/746] Update ResponseStrings.ru-RU.resx (POEditor.com) --- .../Resources/ResponseStrings.ru-RU.resx | 146 +++++++++++++++++- 1 file changed, 142 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx index 8edacbe6..0044bbbc 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ru-RU.resx @@ -743,7 +743,8 @@ Fuzzy выгнаны - PLURAL + PLURAL +Fuzzy {0} будет игнорировать данный канал. @@ -1119,7 +1120,7 @@ Paypal <{1}> сменил свою предрасположенность с {0} на {1}. -*Это сомнительно с моральной точки зрения* :thinking: +*Это сомнительно с моральной точки зрения.*🤔 Make sure to get the formatting right, and leave the thinking emoji @@ -2261,11 +2262,11 @@ ID Владельца: {2} Fuzzy - Сообщение, инициирующее настраеваемую реакцию с номером {0}, будет автоматически удалено. + Сообщение, инициирующее настраиваемую реакцию с номером {0}, будет автоматически удалено. Fuzzy - Ответное сообщение для настраеваемой реакции с номером {0} не будет отправлено в ЛС. + Ответное сообщение для настраиваемой реакции с номером {0} не будет отправлено в ЛС. Fuzzy @@ -2295,5 +2296,142 @@ Fuzzy Время в игре + + Канал + + + Текст команды + + + Выгнаны + PLURAL + + + Модератор + + + страница {0} + + + Причина + + + Новая команда автозапуска добавлена. + Fuzzy + + + Новая команда автозапуска успешно удалена. + Fuzzy + + + Команда автозапуска не найдена. + Fuzzy + + + Сервер + + + Не найдено команд автозапуска на этой странице. + Fuzzy + + + Удалены все команды автозапуска. + Fuzzy + + + Пользователь {0} был разбанен. + + + Пользователь не найден. + + + Пользователь {0} получил предупреждение. + Fuzzy + + + Пользователь {0} получил предупреждение и наказание {1} было применено. + Fuzzy + + + Предупреждение было вынесено на сервере {0} + + + {0} в {1} пользователем {2} + Fuzzy + + + Все предупреждения были удалены для пользователя {0}. + + + На этой странице нет предупреждений. + + + Регистрация предупреждений для пользователя {0} + Fuzzy + + + Наказания не выставлены. + Fuzzy + + + очищен пользователем {0} + + + Список наказаний для предупреждений + Fuzzy + + + Наказание больше не будет применено после {0} предупреждений. + Fuzzy + + + Для пользователей с {1} предупреждениями будет применено наказание {0}. + Fuzzy + + + Медленный режим больше не распространяется на роль {0}. + + + Медленный режим теперь распространяется на роль {0}. + + + Медленный режим больше не распространяется на пользователя {0}. + + + Медленный режим теперь распространяется на пользователя {0}. + + + Не удалось получить награды по одной из следующих причин: + + + Возможно, Вы уже получили Ваши награды за этот месяц. Вы можете получать награды только раз в месяц, если Вы не увеличивали Ваше пожертвование. + + + Уже были получены + + + Ваш аккаунт в Discord, скорее всего, не подключён к Patreon. Если Вы не уверены, что это значит или не знаете, как его подключить, то Вам необходимо перейти на [Страницу настроек аккаунта в Patreon](https://patreon.com/settings/account) и нажать кнопку "Connect to discord." + + + Аккаунт Discord не подключён + + + Для получения наград Вам необходимо поддерживать проект в Patreon. Вы можете воспользоваться командой {0}, чтобы получить ссылку. + + + Вы не поддерживаете проект + + + Вам необходимо подождать несколько часов после Вашего пожертвования, если Вы не делали этого, попробуйте позже. + + + Подождите немного + + + Вы получили {0}. Спасибо за поддержку проекта! + + + Награды могут быть получены только начиная с 5-го числа месяца. + \ No newline at end of file From b04b03495fe29aa92cbd42b0f834ad24488693f5 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:42 +0200 Subject: [PATCH 700/746] Update ResponseStrings.sr-cyrl-rs.resx (POEditor.com) --- .../Resources/ResponseStrings.sr-cyrl-rs.resx | 127 +++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx index 8fe7d18e..31342757 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx @@ -752,7 +752,8 @@ Reason: {1} soft-banned (kicked) - PLURAL + PLURAL +Fuzzy {0} will ignore this channel. @@ -2326,5 +2327,129 @@ Lasts {1} seconds. Don't tell anyone. Shhh. + + + + + + + + + PLURAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 1dd3bbe312ab466bc85cdc1bd06ca8c7cf98fb3d Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:44 +0200 Subject: [PATCH 701/746] Update ResponseStrings.es-ES.resx (POEditor.com) --- .../Resources/ResponseStrings.es-ES.resx | 129 +++++++++++++++++- 1 file changed, 127 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.es-ES.resx b/src/NadekoBot/Resources/ResponseStrings.es-ES.resx index 37e12fc6..b5813634 100644 --- a/src/NadekoBot/Resources/ResponseStrings.es-ES.resx +++ b/src/NadekoBot/Resources/ResponseStrings.es-ES.resx @@ -741,8 +741,9 @@ Razón: {1} Modo lento iniciado - advertido (expulsado) - PLURAL + advertidos (expulsado) + PLURAL +Fuzzy {0} ignorará este canal. @@ -2277,5 +2278,129 @@ IDs de dueños: {2} Tiempo de juego en competitivo + + Canal + + + Comando de texto + + + Expulsados + PLURAL + + + Moderador + + + Página {0} + + + Razón + + + Nuevo comando de inicio añadido. + + + Comando de inicio removido satisfactoriamente. + + + Comando de inicio no encontrado. + + + Servidor + + + No hay comandos de inicio en esta página. + + + Reiniciados todos los comandos de inicio. + + + El usuario {0} ha sido desbloqueado. + + + No encuentro tal usuario. + + + El usuario {0} ha sido advertido. + + + El usuario {0} ha sido advertido y el castigo {0} ha sido aplicado. + + + Advertido en el servidor {0} + + + El {0} a las {1} por {2} + + + Todas las advertencias han sido reiniciadas por {0}. + + + No hay advertencias en esta página. + + + Registro de advertencias para {0} + + + No hay castigos configurados. + + + Reiniciados por {0} + + + Lista de castigos de advertencia + + + Tener {0} advertencias ya no ejecutará un castigo. + + + Aplicaré el castigo {0} a los usuarios con {1} advertecias. + + + El modo lento ahora ignorará el rol {0}. + + + El modo lento ya no ignorará el rol {0}. + + + El modo lento ignorará al usuario {0}. + + + El modo lento ya no ignorará al usuario {0}. + + + Imposible reclamar recompensas debido a una de las siguientes razones: + + + Tal vez ya has recibido tu recompensa de este mes. Puedes recibir recompensa solo una vez cada mes a menos que incrementes el monto. + + + Ya recompensado + + + Puede que tu cuenta de Discord no esté conectada a Patreon. Si no estás seguro de lo que significa, o no sabes cómo conectarla, tienes que ir a la página de configuración de Patreon (https://patreon.com/settings/account) y presionar el botón de 'conectar a Discord'. + + + Cuenta de Discord no conectada. + + + Para elegir una recompensa, debes apoyar el proyecto en Patreon. Puedes usar el comando {0} para obtener el enlace. + + + No apoyando + + + Tienes que esperar algunas horas después de hacer tu colaboración, sino, trata otra vez. + + + Espera un tiempo + + + Has recibido {0} ¡Gracias por apoyar el proyecto! + + + Las recompensas pueden ser reclamadas el día 5 de cada mes. + \ No newline at end of file From a0e855d2d0956aeddefc6eb636274d4bcc6c9f7a Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:47 +0200 Subject: [PATCH 702/746] Update ResponseStrings.sv-SE.resx (POEditor.com) --- .../Resources/ResponseStrings.sv-SE.resx | 138 +++++++++++++++++- 1 file changed, 131 insertions(+), 7 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx index 6ee45f0f..8d392491 100644 --- a/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.sv-SE.resx @@ -256,8 +256,7 @@ du kan inte attackera dig själv - -{0} har svimmat! + {0} har svimmat! helade {0} med en {1} @@ -765,7 +764,8 @@ Anledning: {1} mjukt-bannad (kickad) - PLURAL + PLURAL +Fuzzy {0} kommer ignorera denna kanal. @@ -2330,7 +2330,7 @@ Medlemmar: {1} Användare som går in i röstkanalen {0} får rollen {1}. - Användare som går + Användare som går med {0} röstkanalen kommer inte längre få en roll. Röstkanalsroller @@ -2342,11 +2342,10 @@ Medlemmar: {1} Meddelandet som triggrar den egengjorda reaktion med id {0} kommer bli - Svar meddelande för custom reaktion med id {0} kommer inte att skickas som ett DM. + Svar meddelande för den egengjorda reaktion med id {0} kommer inte att skickas som ett DM. - - + Svar meddelande för den egengjoda reaktion med id {0} kommer att skickas som ett DM. Ingen alias hittad @@ -2366,5 +2365,130 @@ Medlemmar: {1} Kompetitiv speltid + + Kanal + + + Kommando Text + + + Sparkad + PLURAL + + + Moderator + + + Sida {0} + + + Anledning + + + Ny uppstart kommando tillagd. + + + Uppstart kommando har blivit avtagen. + + + Uppstart kommando hittas inte. + + + Server + + + Ingen uppstart kommando har hittats på denna sidan. + + + Rensat alla uppstart kommando. + + + Användaren {0} har blivit icke avstängd. + + + Användaren hittades inte. + + + Användaren {0} har blivit varnad. + + + Användaren {0} har blivit varnad och {1} straff har blivit tillämpat. + + + Varning på {0} server + + + På {0} i {1} av {2} + + + Alla varningar har blivit rensad. + + + Inga varningar på denna sidan. + + + Varning log för {0} + + + Ingen straff ställt. + + + rensad av {0} + + + Varning straff lista + + + Har {0} varningar kommer inte längre aktivera ett straff. + + + Jag kommer att tillägga {0} straff till användare med {1} varningar. + + + Långsam läge kommer nu att bli ignorerad {0} roll. + + + Långsam läge kommer inte längre att bli ignorerad {0} roll. + + + Långsam läge kommer nu ignorera användaren {0} + + + Långsam läge kommer inte längre ignorera användaren {0} + + + Misslyckad anpråk av pris på grund av följande anledningar: + + + Du har kanske redan mottagit din pris för denna månaden. Du kan bara motta priser en gång per månad om inte du ökar din pledge. + + + Redan belönat + + + Din discord konto är kanske inte ansluten till Patreon. Om du inte är säker om vad det betyder, eller inte vet hur du skall ansluta det - du måse då gå till [Patreon account settings page] +(https://patreon.com/settings/account) och klicka på 'Connect to discord' knappen. + + + Discord konto är icke ansluten. + + + För att vara berättigad till priset så måste du stödja projektet på patreon. Du kan använda {0} kommandot för att få länken. + + + Ingen stöd + + + Du måste vänta några timmer efter din pledge, om du inte har gjort det, prova igen senare. + + + Vänta en stund + + + Du har mottagit {0} Tack för att du har stödjat projektet! + + + Pris kan bli hävdad på eller efter femte av varje månad. + \ No newline at end of file From 74d747279f084f8699eacd0ac6cdb2b07fc198d2 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:49 +0200 Subject: [PATCH 703/746] Update ResponseStrings.tr-TR.resx (POEditor.com) --- .../Resources/ResponseStrings.tr-TR.resx | 127 +++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx b/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx index b63550e8..182ad0d4 100644 --- a/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.tr-TR.resx @@ -741,7 +741,8 @@ Sebep: {1} Hafif bir şekilde yasaklandılar (atıldılar) - PLURAL + PLURAL +Fuzzy {0} bu kanalı yoksayacak. @@ -2281,5 +2282,129 @@ Kurucu Kimliği: {2} Rekabetçi oyun süresi + + Kanal + + + Kanal Mesajı + + + Atıldı + PLURAL + + + Moderatör + + + sayfa {0} + + + Sebep + + + Yeni başlangıç komutu eklendi. + + + Başlangıç komutu başarıyla kaldırıldı. + + + Başlangıç komutu bulunamadı. + + + Sunucu + + + Bu sayfada başlangıç komutları bulunmuyor. + + + Tüm başlangıç komutları temizlendi. + + + {0} kullanıcısının yasağı kaldırıldı. + + + Kullanıcı bulunamadı. + + + {0} kullanıcısı uyarıldı. + + + {0} kullanıcısı uyarıldı ve {1} cezası uygulandı. + + + {0} sunucusunda uyarıldı. + + + {0} - {1} tarihinde {2} tarafından + + + {0} için tüm uyarılar silindi. + + + Bu sayfada uyarı bulunamadı. + + + {0} için Uyarı Kayıtları + + + Hiç ceza belirlenmedi. + + + {0} tarafından temizlendi. + + + Uyarı ceza listesi + + + {0} uyarılarına sahip olmak artık cezayı tetiklemeyecektir. + + + {1} uyarılarıyla {0} cezasını kullanıcılara uygulayacağım. + + + Yavaş mod, artık {0} rolünü görmezden gelecektir. + + + Yavaş mod, artık {0} rolünü görmezden gelmeyecek. + + + Yavaş mod, artık {0} kullanıcısını yoksayacak. + + + Yavaş mod, {0} kullanıcısını artık görmezden gelmeyecek. + + + Aşağıdaki nedenlerden biriyle ödül talebinde bulunamadı: + + + Belki de bu ay için ödülünüzü zaten almışsınızdır. Bağış miktarınızı artırmadıkça, yalnızca ayda bir kez ödül alabilirsiniz. + + + Zaten ödüllendirildi + + + Discord hesabınız Patreon'a bağlı olmayabilir. Bunun ne anlama geldiğinden emin değilseniz veya nasıl bağlanacağınızı bilmiyorsanız - [Patreon hesap ayarları sayfasına] (https://patreon.com/settings/account) adresine gidin ve 'Bağlantı' butonuna tıklayın. + + + Discord hesabı bağlı değil + + + Ödül için uygun olabilmeniz için, projeyi patreon'da bağış yapmanız gerek. Bağlantıyı almak için {0} komutunu kullanabilirsiniz. + + + Desteklemiyor + + + Bağış yaptıktan sonra birkaç saat beklemek zorundasınız, yapmadıysanız, daha sonra tekrar deneyin. + + + Biraz bekleyin + + + {0} Projeyi desteklediğiniz için teşekkürlerimizi aldınız! + + + Ödüller, her ayın 5'inde veya sonrasında talep edilebilir. + \ No newline at end of file From 8927f9c1bee2d7dfa089dbacece37652448a36be Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 5 Apr 2017 12:19:52 +0200 Subject: [PATCH 704/746] Update ResponseStrings.id-ID.resx (POEditor.com) --- .../Resources/ResponseStrings.id-ID.resx | 362 ++++++++++++------ 1 file changed, 244 insertions(+), 118 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.id-ID.resx b/src/NadekoBot/Resources/ResponseStrings.id-ID.resx index d2f4e2d2..f6cad4b4 100644 --- a/src/NadekoBot/Resources/ResponseStrings.id-ID.resx +++ b/src/NadekoBot/Resources/ResponseStrings.id-ID.resx @@ -1,121 +1,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Markas itu telah diklaim atau dihancurkan. @@ -742,7 +742,8 @@ Alasan: {1} Ban halus (Dikeluarkan) - PLURAL + PLURAL +Fuzzy {0} akan mengabaikan channel ini. @@ -2281,5 +2282,130 @@ ID Pemilik: {2} Waktu bermain kompetitif + + Saluran + + + Teks perintah + + + Ditendang + PLURAL + + + Moderator + + + Halaman {0} + + + Alasan + + + Perintah startup ditambahkan. + + + Penghilangan perintah startup sukses. + + + Perintah startup tidak ditemukan. + + + Server + + + Tidak ada perintah startup dihalaman ini. + + + Membersihkan semua perintah startup. + + + Pengguna {0} telah dinonlarangkan. + + + Pengguna tidak ditemukan + + + Pengguna {0} telah diperingatkan. + + + Pengguna {0} telah diperingatkan dan hukuman {1} diberikan. + + + Diperingatkan di server {0} + + + Di {0} saat {1} oleh {2} + + + Semua peringatan telah dibersihkan untuk {0}. + + + Tidak ada peringatan dihalaman ini. + + + Berkas peringatan untuk {0} + + + Tidak ada hukuman ditetapkan. + + + Dibersihkan oleh {0} + + + Daftar peringatan hukum + + + Mempunyai {0} peringatan tidak akan memulai hukuman. + + + Saya akan menambahkan hukuman {0} untuk pengguna dengan {1} peringatan. + + + Slowmode akan mengabaikan peran {0}. + + + Slowmode tidak akan lagi mengabaikan peran {0} + + + Slowmode akan mengabaikan pengguna {0} + Fuzzy + + + Slowmode tidak akan lagi mengabaikan pengguna {0}. + + + Gagal untuk mengambil hadiah karena salah satu dari alasan ini: + + + Mungkin anda telah mendapatkan hadiah anda untuk bulan ini. Anda hanya bisa mendapatkan hadiah sekali sebulan kecuali anda menambahkan jumlah janji anda. + + + Telah dihadiahkan + + + Akun DIscord anda mungkin tidak terkoneksi ke Patreon. Jika anda tidak yakin artinya, atau tidak tahu cara menghubungkannya ` anda harus pergi ke [Halaman pengaturan akun Patreon] (https://patreon.com/settings/account) dan menekan tombol 'Connect to Discord'. + + + Akun Discord tidak terhubung + + + Untuk berhak mendapatkan hadiah, anda harus mendukung proyek di Patreon. + + + Tidak mendukung. + + + Anda harus menunggu beberapa jam setelah memohon, jika anda tidak, cobalah nanti lagi. + + + Tunggulah sebentar. + + + Anda telah menerima {0}. Terima kasih untuk mendukung proyek ini! + + + Hadiah bisa diambil saat atau setelah tanggal 5 dari setiap bulan. + \ No newline at end of file From 2869a60d6c9702b215450964a2f0d4bbf9e4636a Mon Sep 17 00:00:00 2001 From: snippet Date: Wed, 5 Apr 2017 23:04:37 +1000 Subject: [PATCH 705/746] Adds .rolehoist command --- docs/Commands List.md | 1 + .../Modules/Administration/Administration.cs | 12 +++++++++ .../Resources/CommandStrings.Designer.cs | 27 +++++++++++++++++++ src/NadekoBot/Resources/CommandStrings.resx | 9 +++++++ 4 files changed, 49 insertions(+) diff --git a/docs/Commands List.md b/docs/Commands List.md index 715df776..da4d922c 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -26,6 +26,7 @@ Commands and aliases | Description | Usage `.removeallroles` `.rar` | Removes all roles from a mentioned user. **Requires ManageRoles server permission.** | `.rar @User` `.createrole` `.cr` | Creates a role with a given name. **Requires ManageRoles server permission.** | `.cr Awesome Role` `.rolecolor` `.rc` | Set a role's color to the hex or 0-255 rgb color value provided. **Requires ManageRoles server permission.** | `.rc Admin 255 200 100` or `.rc Admin ffba55` +`.rolehoist` `.rh` | Set whether the role should be displayed separately in the sidebar **Requires ManageRoles server permission.** | `.rh Guests true` or `.rolehoist "Space Wizards" true` `.deafen` `.deaf` | Deafens mentioned user or users. **Requires DeafenMembers server permission.** | `.deaf "@Someguy"` or `.deaf "@Someguy" "@Someguy"` `.undeafen` `.undef` | Undeafens mentioned user or users. **Requires DeafenMembers server permission.** | `.undef "@Someguy"` or `.undef "@Someguy" "@Someguy"` `.delvoichanl` `.dvch` | Deletes a voice channel with a given name. **Requires ManageChannels server permission.** | `.dvch VoiceChannelName` diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 6ecefe10..5b0adfaa 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -196,6 +196,18 @@ namespace NadekoBot.Modules.Administration await ReplyConfirmLocalized("cr", Format.Bold(r.Name)).ConfigureAwait(false); } + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageRoles)] + [RequireBotPermission(GuildPermission.ManageRoles)] + public async Task RoleHoist(string roleSearchName, bool targetState) + { + var roleName = roleSearchName.ToUpperInvariant(); + var role = Context.Guild.Roles.FirstOrDefault(r => r.Name.ToUpperInvariant() == roleName); + + await role.ModifyAsync(r => r.Hoist = targetState).ConfigureAwait(false); + } + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageRoles)] diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index d021e161..ef52ebd4 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -6593,6 +6593,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to rolehoist rh. + /// + public static string rolehoist_cmd { + get { + return ResourceManager.GetString("rolehoist_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Toggles if this role is displayed in the sidebar or not. + /// + public static string rolehoist_desc { + get { + return ResourceManager.GetString("rolehoist_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}rh Guests true` or `{0}rh "Space Wizards" true. + /// + public static string rolehoist_usage { + get { + return ResourceManager.GetString("rolehoist_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to rolemdl rm. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 1a943af1..859f0043 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3366,4 +3366,13 @@ `{0}time London, UK` + + rolehoist rh + + + Toggles if this role is displayed in the sidebar or not + + + `{0}rh Guests true` or `{0}rh "Space Wizards" true + \ No newline at end of file From 80cb6e86c45ead7552002c49bbc967223833966e Mon Sep 17 00:00:00 2001 From: snippet Date: Wed, 5 Apr 2017 23:30:29 +1000 Subject: [PATCH 706/746] Adds response to .rh / .rolehoist Also swaps to PermissionAction from bool --- src/NadekoBot/Modules/Administration/Administration.cs | 6 ++++-- src/NadekoBot/Resources/ResponseStrings.Designer.cs | 9 +++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 3 +++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 5b0adfaa..fffac1f7 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -12,6 +12,7 @@ using NadekoBot.Services.Database.Models; using static NadekoBot.Modules.Permissions.Permissions; using System.Collections.Concurrent; using NLog; +using NadekoBot.Modules.Permissions; namespace NadekoBot.Modules.Administration { @@ -200,12 +201,13 @@ namespace NadekoBot.Modules.Administration [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageRoles)] [RequireBotPermission(GuildPermission.ManageRoles)] - public async Task RoleHoist(string roleSearchName, bool targetState) + public async Task RoleHoist(string roleSearchName, PermissionAction targetState) { var roleName = roleSearchName.ToUpperInvariant(); var role = Context.Guild.Roles.FirstOrDefault(r => r.Name.ToUpperInvariant() == roleName); - await role.ModifyAsync(r => r.Hoist = targetState).ConfigureAwait(false); + await role.ModifyAsync(r => r.Hoist = targetState.Value).ConfigureAwait(false); + await ReplyConfirmLocalized("rh", Format.Bold(role.Name), Format.Bold(targetState.Value.ToString())).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index f4171166..1836004a 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -1168,6 +1168,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Set the display of guild role {0} to {1}.. + /// + public static string administration_rh { + get { + return ResourceManager.GetString("administration_rh", resourceCulture); + } + } + /// /// Looks up a localized string similar to Role {0} as been added to the list.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 2a1d1e7f..e3de1903 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2406,4 +2406,7 @@ Owner ID: {2} Time in {0} is {1} - {2} Time in London, UK is 15:30 - Time Zone Name + + Set the display of guild role {0} to {1}. + \ No newline at end of file From b09cd7ea434ed52c19e92fbaa649323ea6265d3d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 6 Apr 2017 19:48:21 +0200 Subject: [PATCH 707/746] patreon error fix --- src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs index 303774f4..924c720f 100644 --- a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs @@ -13,6 +13,7 @@ using NadekoBot.Services; using NadekoBot.Services.Database.Models; using NadekoBot.Extensions; using Discord; +using NLog; namespace NadekoBot.Modules.Utility { @@ -74,11 +75,13 @@ namespace NadekoBot.Modules.Utility private readonly Timer update; private readonly SemaphoreSlim claimLockJustInCase = new SemaphoreSlim(1, 1); + private readonly Logger _log; private PatreonThingy() { if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) return; + _log = LogManager.GetCurrentClassLogger(); update = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, TimeSpan.FromHours(3)); } @@ -119,6 +122,10 @@ namespace NadekoBot.Modules.Utility Reward = x, }).ToImmutableArray(); } + catch (Exception ex) + { + _log.Warn(ex); + } finally { var _ = Task.Run(async () => From 6efd78ca215656e040ff9db526ec47a841d20b70 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 6 Apr 2017 20:59:07 +0200 Subject: [PATCH 708/746] Patreon stuff improved --- .../Utility/Commands/PatreonCommands.cs | 20 ++++++++- src/NadekoBot/Resources/CommandStrings.resx | 41 +++++++++++++++++-- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs index 924c720f..583b1f5b 100644 --- a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs @@ -28,6 +28,16 @@ namespace NadekoBot.Modules.Utility { patreon = PatreonThingy.Instance; } + + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task PatreonRewardsReload() + { + await patreon.LoadPledges().ConfigureAwait(false); + + await Context.Channel.SendConfirmAsync("👌").ConfigureAwait(false); + } + [NadekoCommand, Usage, Description, Aliases] public async Task ClaimPatreonRewards() { @@ -53,13 +63,15 @@ namespace NadekoBot.Modules.Utility await ReplyConfirmLocalized("clpa_success", amount + NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); return; } + var rem = (patreon.Interval - (DateTime.UtcNow - patreon.LastUpdate)); var helpcmd = Format.Code(NadekoBot.ModulePrefixes[typeof(Help.Help).Name] + "donate"); await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithDescription(GetText("clpa_fail")) .AddField(efb => efb.WithName(GetText("clpa_fail_already_title")).WithValue(GetText("clpa_fail_already"))) .AddField(efb => efb.WithName(GetText("clpa_fail_wait_title")).WithValue(GetText("clpa_fail_wait"))) .AddField(efb => efb.WithName(GetText("clpa_fail_conn_title")).WithValue(GetText("clpa_fail_conn"))) - .AddField(efb => efb.WithName(GetText("clpa_fail_sup_title")).WithValue(GetText("clpa_fail_sup", helpcmd)))) + .AddField(efb => efb.WithName(GetText("clpa_fail_sup_title")).WithValue(GetText("clpa_fail_sup", helpcmd))) + .WithFooter(efb => efb.WithText(GetText("clpa_next_update", rem)))) .ConfigureAwait(false); } } @@ -72,21 +84,25 @@ namespace NadekoBot.Modules.Utility private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1); public ImmutableArray Pledges { get; private set; } + public DateTime LastUpdate { get; private set; } = DateTime.UtcNow; private readonly Timer update; private readonly SemaphoreSlim claimLockJustInCase = new SemaphoreSlim(1, 1); private readonly Logger _log; + public readonly TimeSpan Interval = TimeSpan.FromHours(1); + private PatreonThingy() { if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) return; _log = LogManager.GetCurrentClassLogger(); - update = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, TimeSpan.FromHours(3)); + update = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, Interval); } public async Task LoadPledges() { + LastUpdate = DateTime.UtcNow; await getPledgesLocker.WaitAsync(1000).ConfigureAwait(false); try { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 1a943af1..cb6958bb 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2596,10 +2596,10 @@ listquotes liqu - `{0}liqu` or `{0}liqu 3` + Lists all quotes on the server ordered alphabetically. 15 Per page. - Lists all quotes on the server ordered alphabetically. 15 Per page. + `{0}liqu` or `{0}liqu 3` typedel @@ -3211,7 +3211,7 @@ Toggles whether the response message of the custom reaction will be sent as a direct message. - `{0}crad 44` + `{0}crdm 44` aliaslist cmdmaplist aliases @@ -3334,7 +3334,7 @@ clparew - Claim patreon rewards. If you're subscribed to bot owner's patreon you can user this command to claim your rewards - assuming bot owner did setup has their patreon key. + Claim patreon rewards. If you're subscribed to bot owner's patreon you can use this command to claim your rewards - assuming bot owner did setup has their patreon key. `{0}clparew` @@ -3366,4 +3366,37 @@ `{0}time London, UK` + + parewrel + + + Forces the update of the list of patrons who are eligible for the reward. + + + `{0}parewrel` + + + shopadd + + + Adds an item to the shop by specifying type price and name. + + + `{0}shopadd role 1000 Rich` + + + shoprem shoprm + + + Removes an item from the shop by its color. + + + shop + + + Lists this server's administrators' shop. Paginated. + + + `{0}shop` or `{0}shop 2` + \ No newline at end of file From 936ba264c97942c339f86b9f8a41ae3660e2254d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 6 Apr 2017 21:00:46 +0200 Subject: [PATCH 709/746] A lot of work on flower shop --- .../DataStructures/IndexedCollection.cs | 128 ++ .../DataStructures/PermissionsCollection.cs | 103 +- .../20170405161814_flower-shop.Designer.cs | 1518 +++++++++++++++++ .../Migrations/20170405161814_flower-shop.cs | 79 + .../NadekoSqliteContextModelSnapshot.cs | 62 + .../Modules/Gambling/Commands/FlowerShop.cs | 170 ++ .../Resources/CommandStrings.Designer.cs | 107 +- .../Resources/ResponseStrings.Designer.cs | 63 + src/NadekoBot/Resources/ResponseStrings.resx | 22 + .../Services/Database/Models/GuildConfig.cs | 2 + .../Services/Database/Models/ShopEntry.cs | 41 + 11 files changed, 2207 insertions(+), 88 deletions(-) create mode 100644 src/NadekoBot/DataStructures/IndexedCollection.cs create mode 100644 src/NadekoBot/Migrations/20170405161814_flower-shop.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170405161814_flower-shop.cs create mode 100644 src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs create mode 100644 src/NadekoBot/Services/Database/Models/ShopEntry.cs diff --git a/src/NadekoBot/DataStructures/IndexedCollection.cs b/src/NadekoBot/DataStructures/IndexedCollection.cs new file mode 100644 index 00000000..72b4f343 --- /dev/null +++ b/src/NadekoBot/DataStructures/IndexedCollection.cs @@ -0,0 +1,128 @@ +using NadekoBot.Services.Database.Models; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace NadekoBot.DataStructures +{ + public class IndexedCollection : IList where T : IIndexed + { + public List Source { get; } + private readonly object _locker = new object(); + + public IndexedCollection(IEnumerable source) + { + lock (_locker) + { + Source = source.OrderBy(x => x.Index).ToList(); + for (var i = 0; i < Source.Count; i++) + { + if (Source[i].Index != i) + Source[i].Index = i; + } + } + } + + public static implicit operator List(IndexedCollection x) => + x.Source; + + public IEnumerator GetEnumerator() => + Source.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => + Source.GetEnumerator(); + + public void Add(T item) + { + lock (_locker) + { + item.Index = Source.Count; + Source.Add(item); + } + } + + public virtual void Clear() + { + lock (_locker) + { + Source.Clear(); + } + } + + public bool Contains(T item) + { + lock (_locker) + { + return Source.Contains(item); + } + } + + public void CopyTo(T[] array, int arrayIndex) + { + lock (_locker) + { + Source.CopyTo(array, arrayIndex); + } + } + + public virtual bool Remove(T item) + { + bool removed; + lock (_locker) + { + if (removed = Source.Remove(item)) + { + for (int i = 0; i < Source.Count; i++) + { + // hm, no idea how ef works, so I don't want to set if it's not changed, + // maybe it will try to update db? + // But most likely it just compares old to new values, meh. + if (Source[i].Index != i) + Source[i].Index = i; + } + } + } + return removed; + } + + public int Count => Source.Count; + public bool IsReadOnly => false; + public int IndexOf(T item) => item.Index; + + public virtual void Insert(int index, T item) + { + lock (_locker) + { + Source.Insert(index, item); + for (int i = index; i < Source.Count; i++) + { + Source[i].Index = i; + } + } + } + + public virtual void RemoveAt(int index) + { + lock (_locker) + { + Source.RemoveAt(index); + for (int i = index; i < Source.Count; i++) + { + Source[i].Index = i; + } + } + } + + public virtual T this[int index] { + get { return Source[index]; } + set { + lock (_locker) + { + value.Index = index; + Source[index] = value; + } + } + } + } + +} diff --git a/src/NadekoBot/DataStructures/PermissionsCollection.cs b/src/NadekoBot/DataStructures/PermissionsCollection.cs index e7963e64..484c4f9d 100644 --- a/src/NadekoBot/DataStructures/PermissionsCollection.cs +++ b/src/NadekoBot/DataStructures/PermissionsCollection.cs @@ -6,132 +6,67 @@ using NadekoBot.Services.Database.Models; namespace NadekoBot.DataStructures { - public class PermissionsCollection : IList where T : IIndexed + public class PermissionsCollection : IndexedCollection where T : IIndexed { - public List Source { get; } - private readonly object _locker = new object(); - - public PermissionsCollection(IEnumerable source) + private readonly object _localLocker = new object(); + public PermissionsCollection(IEnumerable source) : base(source) { - lock (_locker) - { - Source = source.OrderBy(x => x.Index).ToList(); - for (var i = 0; i < Source.Count; i++) - { - if(Source[i].Index != i) - Source[i].Index = i; - } - } } public static implicit operator List(PermissionsCollection x) => x.Source; - public IEnumerator GetEnumerator() => - Source.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => - Source.GetEnumerator(); - - public void Add(T item) + public override void Clear() { - lock (_locker) - { - item.Index = Source.Count; - Source.Add(item); - } - } - - public void Clear() - { - lock (_locker) + lock (_localLocker) { var first = Source[0]; - Source.Clear(); + base.Clear(); Source[0] = first; } } - public bool Contains(T item) - { - lock (_locker) - { - return Source.Contains(item); - } - } - - public void CopyTo(T[] array, int arrayIndex) - { - lock (_locker) - { - Source.CopyTo(array, arrayIndex); - } - } - - public bool Remove(T item) + public override bool Remove(T item) { bool removed; - lock (_locker) + lock (_localLocker) { if(Source.IndexOf(item) == 0) throw new ArgumentException("You can't remove first permsission (allow all)"); - if (removed = Source.Remove(item)) - { - for (int i = 0; i < Source.Count; i++) - { - // hm, no idea how ef works, so I don't want to set if it's not changed, - // maybe it will try to update db? - // But most likely it just compares old to new values, meh. - if (Source[i].Index != i) - Source[i].Index = i; - } - } + removed = base.Remove(item); } return removed; } - public int Count => Source.Count; - public bool IsReadOnly => false; - public int IndexOf(T item) => item.Index; - - public void Insert(int index, T item) + public override void Insert(int index, T item) { - lock (_locker) + lock (_localLocker) { if(index == 0) // can't insert on first place. Last item is always allow all. throw new IndexOutOfRangeException(nameof(index)); - Source.Insert(index, item); - for (int i = index; i < Source.Count; i++) - { - Source[i].Index = i; - } + base.Insert(index, item); } } - public void RemoveAt(int index) + public override void RemoveAt(int index) { - lock (_locker) + lock (_localLocker) { if(index == 0) // you can't remove first permission (allow all) - throw new IndexOutOfRangeException(nameof(index)); + throw new IndexOutOfRangeException(nameof(index)); - Source.RemoveAt(index); - for (int i = index; i < Source.Count; i++) - { - Source[i].Index = i; - } + base.RemoveAt(index); } } - public T this[int index] { + public override T this[int index] { get { return Source[index]; } set { - lock (_locker) + lock (_localLocker) { if(index == 0) // can't set first element. It's always allow all throw new IndexOutOfRangeException(nameof(index)); - value.Index = index; - Source[index] = value; + base[index] = value; } } } diff --git a/src/NadekoBot/Migrations/20170405161814_flower-shop.Designer.cs b/src/NadekoBot/Migrations/20170405161814_flower-shop.Designer.cs new file mode 100644 index 00000000..5acf9f8e --- /dev/null +++ b/src/NadekoBot/Migrations/20170405161814_flower-shop.Designer.cs @@ -0,0 +1,1518 @@ +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("20170405161814_flower-shop")] + partial class flowershop + { + 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("DateAdded"); + + 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.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Mapping"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("AutoDeleteTrigger"); + + b.Property("DateAdded"); + + b.Property("DmResponse"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.Property("WarningsInitialized"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissionv2"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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.RewardedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AmountRewardedThisMonth"); + + b.Property("DateAdded"); + + b.Property("LastReward"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("RewardedUsers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("Name"); + + b.Property("Price"); + + b.Property("RoleId"); + + b.Property("RoleName"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("ShopEntry"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("ShopEntryId"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("ShopEntryId"); + + b.ToTable("ShopEntryItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredRole"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ChannelId"); + + b.Property("ChannelName"); + + b.Property("CommandText"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("GuildName"); + + b.Property("Index"); + + b.Property("VoiceChannelId"); + + b.Property("VoiceChannelName"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("StartupCommand"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UnmuteAt"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.Property("VoiceChannelId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Forgiven"); + + b.Property("ForgivenBy"); + + b.Property("GuildId"); + + b.Property("Moderator"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Count"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Punishment"); + + b.Property("Time"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + + 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.CommandAlias", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId"); + }); + + 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.Permissionv2", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("Permissions") + .HasForeignKey("GuildConfigId"); + }); + + 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.ShopEntry", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("ShopEntries") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ShopEntry") + .WithMany("Items") + .HasForeignKey("ShopEntryId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("StartupCommands") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId"); + }); + + 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); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170405161814_flower-shop.cs b/src/NadekoBot/Migrations/20170405161814_flower-shop.cs new file mode 100644 index 00000000..7d0cde56 --- /dev/null +++ b/src/NadekoBot/Migrations/20170405161814_flower-shop.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class flowershop : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ShopEntry", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AuthorId = table.Column(nullable: false), + DateAdded = table.Column(nullable: true), + GuildConfigId = table.Column(nullable: true), + Index = table.Column(nullable: false), + Name = table.Column(nullable: true), + Price = table.Column(nullable: false), + RoleId = table.Column(nullable: false), + RoleName = table.Column(nullable: true), + Type = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ShopEntry", x => x.Id); + table.ForeignKey( + name: "FK_ShopEntry_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "ShopEntryItem", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DateAdded = table.Column(nullable: true), + ShopEntryId = table.Column(nullable: true), + Text = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ShopEntryItem", x => x.Id); + table.ForeignKey( + name: "FK_ShopEntryItem_ShopEntry_ShopEntryId", + column: x => x.ShopEntryId, + principalTable: "ShopEntry", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_ShopEntry_GuildConfigId", + table: "ShopEntry", + column: "GuildConfigId"); + + migrationBuilder.CreateIndex( + name: "IX_ShopEntryItem_ShopEntryId", + table: "ShopEntryItem", + column: "ShopEntryId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ShopEntryItem"); + + migrationBuilder.DropTable( + name: "ShopEntry"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 303783e4..c255ba79 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -971,6 +971,54 @@ namespace NadekoBot.Migrations b.ToTable("SelfAssignableRoles"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("Name"); + + b.Property("Price"); + + b.Property("RoleId"); + + b.Property("RoleName"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("ShopEntry"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("ShopEntryId"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("ShopEntryId"); + + b.ToTable("ShopEntryItem"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => { b.Property("Id") @@ -1377,6 +1425,20 @@ namespace NadekoBot.Migrations .HasForeignKey("BotConfigId"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntry", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("ShopEntries") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ShopEntry") + .WithMany("Items") + .HasForeignKey("ShopEntryId"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => { b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs b/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs new file mode 100644 index 00000000..56be01ff --- /dev/null +++ b/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs @@ -0,0 +1,170 @@ +using Discord; +using Discord.Commands; +using Microsoft.EntityFrameworkCore; +using NadekoBot.Attributes; +using NadekoBot.DataStructures; +using NadekoBot.Extensions; +using NadekoBot.Services; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Gambling +{ + public partial class Gambling + { + [Group] + public class FlowerShop : NadekoSubmodule + { + public enum Role { + Role + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task Shop(int page = 1) + { + if (page <= 0) + return; + page -= 1; + List entries; + using (var uow = DbHandler.UnitOfWork()) + { + entries = new IndexedCollection(uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.ShopEntries)).ShopEntries); + } + + await Context.Channel.SendPaginatedConfirmAsync(page + 1, (curPage) => + { + var theseEntries = entries.Skip((curPage - 1) * 9).Take(9); + + if (!theseEntries.Any()) + return new EmbedBuilder().WithErrorColor() + .WithDescription(GetText("shop_none")); + var embed = new EmbedBuilder().WithOkColor() + .WithTitle(GetText("shop", NadekoBot.BotConfig.CurrencySign)); + + for (int i = 0; i < entries.Count; i++) + { + var entry = entries[i]; + embed.AddField(efb => efb.WithName($"#{i + 1} - {entry.Price}{NadekoBot.BotConfig.CurrencySign}").WithValue(EntryToString(entry)).WithIsInline(true)); + } + return embed; + }, entries.Count / 9, true); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task Buy(int entryNumber) + { + var channel = (ITextChannel)Context.Channel; + + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.Administrator)] + public async Task ShopAdd(ShopEntryType type, int price, string name) + { + var entry = new ShopEntry() + { + Name = name, + Price = price, + Type = type, + AuthorId = Context.User.Id, + }; + using (var uow = DbHandler.UnitOfWork()) + { + var entries = new IndexedCollection(uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.ShopEntries)).ShopEntries); + entries.Add(entry); + uow.GuildConfigs.For(Context.Guild.Id, set => set).ShopEntries = entries; + uow.Complete(); + } + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle(GetText("shop_item_add")) + .AddField(efb => efb.WithName(GetText("name")).WithValue(name).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("price")).WithValue(price.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("type")).WithValue(type.ToString()).WithIsInline(true))); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.Administrator)] + public async Task ShopAdd(Role _, int price, [Remainder] IRole role) + { + var entry = new ShopEntry() + { + Name = "-", + Price = price, + Type = ShopEntryType.Role, + AuthorId = Context.User.Id, + RoleId = role.Id, + RoleName = role.Name + }; + using (var uow = DbHandler.UnitOfWork()) + { + var entries = new IndexedCollection(uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.ShopEntries)).ShopEntries); + entries.Add(entry); + uow.GuildConfigs.For(Context.Guild.Id, set => set).ShopEntries = entries; + uow.Complete(); + } + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle(GetText("shop_item_add")) + .AddField(efb => efb.WithName(GetText("name")).WithValue(GetText("shop_role", Format.Bold(entry.RoleName))).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("price")).WithValue(price.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("type")).WithValue("Role").WithIsInline(true))); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task ShopRemove(int index) + { + if (index < 0) + return; + ShopEntry removed; + using (var uow = DbHandler.UnitOfWork()) + { + var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.ShopEntries)); + var entries = new IndexedCollection(config.ShopEntries); + removed = entries.ElementAtOrDefault(index); + if (removed != null) + { + entries.Remove(removed); + + config.ShopEntries = entries; + uow.Complete(); + } + } + + if(removed == null) + await ReplyErrorLocalized("shop_rem_fail").ConfigureAwait(false); + else + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle(GetText("shop_item_add")) + .AddField(efb => efb.WithName(GetText("name")).WithValue(GetText("shop_role", Format.Bold(removed.RoleName))).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("price")).WithValue(removed.Price.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("type")).WithValue(removed.Type.ToString()).WithIsInline(true))); + } + + public string EntryToString(ShopEntry entry) + { + if (entry.Type == ShopEntryType.Role) + { + return Format.Bold(entry.Name) + "\n" + GetText("shop_role", Format.Bold(entry.RoleName)); + } + else if (entry.Type == ShopEntryType.List) + { + + } + else if (entry.Type == ShopEntryType.Infinite_List) + { + + } + return ""; + } + } + } +} diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index d021e161..5729c282 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -1716,7 +1716,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Claim patreon rewards. If you're subscribed to bot owner's patreon you can user this command to claim your rewards - assuming bot owner did setup has their patreon key.. + /// Looks up a localized string similar to Claim patreon rewards. If you're subscribed to bot owner's patreon you can use this command to claim your rewards - assuming bot owner did setup has their patreon key.. /// public static string claimpatreonrewards_desc { get { @@ -2103,7 +2103,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}crad 44`. + /// Looks up a localized string similar to `{0}crdm 44`. /// public static string crdm_usage { get { @@ -4173,7 +4173,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}liqu` or `{0}liqu 3`. + /// Looks up a localized string similar to Lists all quotes on the server ordered alphabetically. 15 Per page.. /// public static string listquotes_desc { get { @@ -4182,7 +4182,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Lists all quotes on the server ordered alphabetically. 15 Per page.. + /// Looks up a localized string similar to `{0}liqu` or `{0}liqu 3`. /// public static string listquotes_usage { get { @@ -5297,6 +5297,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to parewrel. + /// + public static string patreonrewardsreload_cmd { + get { + return ResourceManager.GetString("patreonrewardsreload_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Forces the update of the list of patrons who are eligible for the reward.. + /// + public static string patreonrewardsreload_desc { + get { + return ResourceManager.GetString("patreonrewardsreload_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}parewrel`. + /// + public static string patreonrewardsreload_usage { + get { + return ResourceManager.GetString("patreonrewardsreload_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to pause p. /// @@ -7484,6 +7511,78 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to shop. + /// + public static string shop_cmd { + get { + return ResourceManager.GetString("shop_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lists this server's administrators' shop. Paginated.. + /// + public static string shop_desc { + get { + return ResourceManager.GetString("shop_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}shop` or `{0}shop 2`. + /// + public static string shop_usage { + get { + return ResourceManager.GetString("shop_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to shopadd. + /// + public static string shopadd_cmd { + get { + return ResourceManager.GetString("shopadd_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Adds an item to the shop by specifying type price and name.. + /// + public static string shopadd_desc { + get { + return ResourceManager.GetString("shopadd_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}shopadd role 1000 Rich`. + /// + public static string shopadd_usage { + get { + return ResourceManager.GetString("shopadd_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to shoprem shoprm. + /// + public static string shopremove_cmd { + get { + return ResourceManager.GetString("shopremove_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removes an item from the shop by its color.. + /// + public static string shopremove_desc { + get { + return ResourceManager.GetString("shopremove_desc", resourceCulture); + } + } + /// /// Looks up a localized string similar to shorten. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index f4171166..c174661e 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -2755,6 +2755,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Name. + /// + public static string gambling_name { + get { + return ResourceManager.GetString("gambling_name", resourceCulture); + } + } + /// /// Looks up a localized string similar to No more cards in the deck.. /// @@ -2854,6 +2863,42 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Shop. + /// + public static string gambling_shop { + get { + return ResourceManager.GetString("gambling_shop", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shop item added. + /// + public static string gambling_shop_item_add { + get { + return ResourceManager.GetString("gambling_shop_item_add", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No shop items found on this page.. + /// + public static string gambling_shop_none { + get { + return ResourceManager.GetString("gambling_shop_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You will get {0} role.. + /// + public static string gambling_shop_role { + get { + return ResourceManager.GetString("gambling_shop_role", resourceCulture); + } + } + /// /// Looks up a localized string similar to Bet. /// @@ -2972,6 +3017,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Type. + /// + public static string gambling_type { + get { + return ResourceManager.GetString("gambling_type", resourceCulture); + } + } + /// /// Looks up a localized string similar to your affinity is already set to that waifu or you're trying to remove your affinity while not having one.. /// @@ -6115,6 +6169,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Next update in {0}. + /// + public static string utility_clpa_next_update { + get { + return ResourceManager.GetString("utility_clpa_next_update", resourceCulture); + } + } + /// /// Looks up a localized string similar to You've received {0} Thanks for supporting the project!. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 2a1d1e7f..b87bfe8d 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2406,4 +2406,26 @@ Owner ID: {2} Time in {0} is {1} - {2} Time in London, UK is 15:30 - Time Zone Name + + Name + + + Shop + + + Shop item added + + + No shop items found on this page. + + + You will get {0} role. + + + Type + + + Next update in {0} + Next update in 05:30 + \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs index aaf7addf..e5a2c8b6 100644 --- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs +++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs @@ -76,6 +76,8 @@ namespace NadekoBot.Services.Database.Models public HashSet SlowmodeIgnoredUsers { get; set; } public HashSet SlowmodeIgnoredRoles { get; set; } + public List ShopEntries { get; set; } + //public List ProtectionIgnoredChannels { get; set; } = new List(); } diff --git a/src/NadekoBot/Services/Database/Models/ShopEntry.cs b/src/NadekoBot/Services/Database/Models/ShopEntry.cs new file mode 100644 index 00000000..ad46fc9c --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/ShopEntry.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; + +namespace NadekoBot.Services.Database.Models +{ + public enum ShopEntryType + { + Role, + List, + Infinite_List, + } + + public class ShopEntry : DbEntity, IIndexed + { + public int Index { get; set; } + public int Price { get; set; } + public string Name { get; set; } + public ulong AuthorId { get; set; } + + public ShopEntryType Type { get; set; } + public string RoleName { get; set; } + public ulong RoleId { get; set; } + public List Items { get; set; } + } + + public class ShopEntryItem : DbEntity + { + public string Text { get; set; } + + public override bool Equals(object obj) + { + if (obj == null || GetType() != obj.GetType()) + { + return false; + } + return ((ShopEntryItem)obj).Text == Text; + } + + public override int GetHashCode() => + Text.GetHashCode(); + } +} From b3f6b4473b8eb156b12f4e242b2639db754e32ae Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 8 Apr 2017 17:47:32 +0200 Subject: [PATCH 710/746] Woops, shop item purchase fix --- src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs b/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs index dbb268d8..57a05e10 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs @@ -151,7 +151,7 @@ namespace NadekoBot.Modules.Gambling .AddField(efb => efb.WithName(GetText("name")).WithValue(entry.Name).WithIsInline(true))) .ConfigureAwait(false); - await CurrencyHandler.AddCurrencyAsync(Context.User.Id, + await CurrencyHandler.AddCurrencyAsync(entry.AuthorId, $"Shop error refund - {entry.Name}", GetProfitAmount(entry.Price)).ConfigureAwait(false); } From 57e9c62b11a50b3547caa9cdaa1ccf7c4322df60 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 8 Apr 2017 17:48:54 +0200 Subject: [PATCH 711/746] transaction Name fix --- src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs b/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs index 57a05e10..f04e7c65 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs @@ -152,7 +152,7 @@ namespace NadekoBot.Modules.Gambling .ConfigureAwait(false); await CurrencyHandler.AddCurrencyAsync(entry.AuthorId, - $"Shop error refund - {entry.Name}", + $"Shop sell item - {entry.Name}", GetProfitAmount(entry.Price)).ConfigureAwait(false); } catch From a89d00ff317cbcc01297f86eccd560f7adc20ed2 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 8 Apr 2017 21:03:07 +0200 Subject: [PATCH 712/746] .gvc added --- ...70408162851_game-voice-channel.Designer.cs | 1520 +++++++++++++++++ .../20170408162851_game-voice-channel.cs | 24 + .../NadekoSqliteContextModelSnapshot.cs | 2 + .../Commands/GameChannelCommands.cs | 131 ++ .../Modules/Gambling/Commands/FlowerShop.cs | 1 - src/NadekoBot/Modules/Music/Music.cs | 2 +- .../Resources/CommandStrings.Designer.cs | 29 +- src/NadekoBot/Resources/CommandStrings.resx | 11 +- .../Resources/ResponseStrings.Designer.cs | 27 + src/NadekoBot/Resources/ResponseStrings.resx | 9 + .../Services/Database/Models/GuildConfig.cs | 1 + 11 files changed, 1753 insertions(+), 4 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170408162851_game-voice-channel.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170408162851_game-voice-channel.cs create mode 100644 src/NadekoBot/Modules/Administration/Commands/GameChannelCommands.cs diff --git a/src/NadekoBot/Migrations/20170408162851_game-voice-channel.Designer.cs b/src/NadekoBot/Migrations/20170408162851_game-voice-channel.Designer.cs new file mode 100644 index 00000000..fa371c1d --- /dev/null +++ b/src/NadekoBot/Migrations/20170408162851_game-voice-channel.Designer.cs @@ -0,0 +1,1520 @@ +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("20170408162851_game-voice-channel")] + partial class gamevoicechannel + { + 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("DateAdded"); + + 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.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Mapping"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("AutoDeleteTrigger"); + + b.Property("DateAdded"); + + b.Property("DmResponse"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("DefaultMusicVolume"); + + b.Property("DeleteMessageOnCommand"); + + b.Property("DmGreetMessageText"); + + b.Property("ExclusiveSelfAssignedRoles"); + + b.Property("FilterInvites"); + + b.Property("FilterWords"); + + b.Property("GameVoiceChannel"); + + b.Property("GreetMessageChannelId"); + + b.Property("GuildId"); + + b.Property("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.Property("WarningsInitialized"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissionv2"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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.RewardedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AmountRewardedThisMonth"); + + b.Property("DateAdded"); + + b.Property("LastReward"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("RewardedUsers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("Name"); + + b.Property("Price"); + + b.Property("RoleId"); + + b.Property("RoleName"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("ShopEntry"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("ShopEntryId"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("ShopEntryId"); + + b.ToTable("ShopEntryItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredRole"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ChannelId"); + + b.Property("ChannelName"); + + b.Property("CommandText"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("GuildName"); + + b.Property("Index"); + + b.Property("VoiceChannelId"); + + b.Property("VoiceChannelName"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("StartupCommand"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UnmuteAt"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.Property("VoiceChannelId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Forgiven"); + + b.Property("ForgivenBy"); + + b.Property("GuildId"); + + b.Property("Moderator"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Count"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Punishment"); + + b.Property("Time"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + + 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.CommandAlias", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId"); + }); + + 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.Permissionv2", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("Permissions") + .HasForeignKey("GuildConfigId"); + }); + + 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.ShopEntry", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("ShopEntries") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ShopEntry") + .WithMany("Items") + .HasForeignKey("ShopEntryId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("StartupCommands") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId"); + }); + + 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); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170408162851_game-voice-channel.cs b/src/NadekoBot/Migrations/20170408162851_game-voice-channel.cs new file mode 100644 index 00000000..3b9cb6c6 --- /dev/null +++ b/src/NadekoBot/Migrations/20170408162851_game-voice-channel.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class gamevoicechannel : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "GameVoiceChannel", + table: "GuildConfigs", + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "GameVoiceChannel", + table: "GuildConfigs"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index c255ba79..a8e43d26 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -533,6 +533,8 @@ namespace NadekoBot.Migrations b.Property("FilterWords"); + b.Property("GameVoiceChannel"); + b.Property("GreetMessageChannelId"); b.Property("GuildId"); diff --git a/src/NadekoBot/Modules/Administration/Commands/GameChannelCommands.cs b/src/NadekoBot/Modules/Administration/Commands/GameChannelCommands.cs new file mode 100644 index 00000000..f2e5fb6c --- /dev/null +++ b/src/NadekoBot/Modules/Administration/Commands/GameChannelCommands.cs @@ -0,0 +1,131 @@ +using Discord; +using Discord.Commands; +using Microsoft.EntityFrameworkCore; +using NadekoBot.Attributes; +using NadekoBot.Services; +using NadekoBot.Services.Database; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Discord.WebSocket; +using NLog; +using NadekoBot.Extensions; + +namespace NadekoBot.Modules.Administration +{ + public partial class Administration + { + [Group] + public class GameChannelCommands : NadekoSubmodule + { + private static readonly Timer _t; + + private static readonly ConcurrentHashSet gameVoiceChannels = new ConcurrentHashSet(); + + private static new readonly Logger _log; + + static GameChannelCommands() + { + //_t = new Timer(_ => { + + //}, null, ); + + _log = LogManager.GetCurrentClassLogger(); + + gameVoiceChannels = new ConcurrentHashSet( + NadekoBot.AllGuildConfigs.Where(gc => gc.GameVoiceChannel != null) + .Select(gc => gc.GameVoiceChannel.Value)); + + NadekoBot.Client.UserVoiceStateUpdated += Client_UserVoiceStateUpdated; + + } + + private static Task Client_UserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState, SocketVoiceState newState) + { + var _ = Task.Run(async () => + { + try + { + var gUser = usr as SocketGuildUser; + if (gUser == null) + return; + + var game = gUser.Game?.Name.TrimTo(50).ToLowerInvariant(); + + if (oldState.VoiceChannel == newState.VoiceChannel || + newState.VoiceChannel == null) + return; + + if (!gameVoiceChannels.Contains(newState.VoiceChannel.Id) || + string.IsNullOrWhiteSpace(game)) + return; + + var vch = gUser.Guild.VoiceChannels + .FirstOrDefault(x => x.Name.ToLowerInvariant() == game); + + if (vch == null) + return; + + await Task.Delay(1000).ConfigureAwait(false); + await gUser.ModifyAsync(gu => gu.Channel = vch).ConfigureAwait(false); + } + catch (Exception ex) + { + _log.Warn(ex); + } + }); + + return Task.CompletedTask; + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.Administrator)] + [RequireBotPermission(GuildPermission.MoveMembers)] + public async Task GameVoiceChannel() + { + var vch = ((IGuildUser)Context.User).VoiceChannel; + + if (vch == null) + { + await ReplyErrorLocalized("not_in_voice").ConfigureAwait(false); + return; + } + ulong? id; + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set); + + if (gc.GameVoiceChannel == vch.Id) + { + gameVoiceChannels.TryRemove(vch.Id); + id = gc.GameVoiceChannel = null; + } + else + { + if(gc.GameVoiceChannel != null) + gameVoiceChannels.TryRemove(gc.GameVoiceChannel.Value); + gameVoiceChannels.Add(vch.Id); + id = gc.GameVoiceChannel = vch.Id; + } + + uow.Complete(); + } + + if (id == null) + { + await ReplyConfirmLocalized("gvc_disabled").ConfigureAwait(false); + } + else + { + gameVoiceChannels.Add(vch.Id); + await ReplyConfirmLocalized("gvc_enabled", Format.Bold(vch.Name)).ConfigureAwait(false); + } + } + } + } +} diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs b/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs index f04e7c65..4fab3906 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs @@ -140,7 +140,6 @@ namespace NadekoBot.Modules.Gambling removed = uow.Complete(); } - _log.Warn($"Removed {removed} items"); try { await (await Context.User.CreateDMChannelAsync()) diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index 315ddb52..d6484011 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Music { [NadekoModule("Music", "!!")] [DontAutoLoad] - public class Music : NadekoTopLevelModule + public class Music : NadekoTopLevelModule { public static ConcurrentDictionary MusicPlayers { get; } = new ConcurrentDictionary(); diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index ff0aa011..256ff9fe 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -3002,6 +3002,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to gvc. + /// + public static string gamevoicechannel_cmd { + get { + return ResourceManager.GetString("gamevoicechannel_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Toggles game voice channel feature in the voice channel you're currently in. Users who join the game voice channel will get automatically redirected to the voice channel with the name of their current game if it exists. Can't move users to channels that the bot has no connect permission for. One per server.. + /// + public static string gamevoicechannel_desc { + get { + return ResourceManager.GetString("gamevoicechannel_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}gvc`. + /// + public static string gamevoicechannel_usage { + get { + return ResourceManager.GetString("gamevoicechannel_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to gelbooru. /// @@ -7629,7 +7656,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Adds an item to the list of items for sale in the shop entry given the index.. + /// Looks up a localized string similar to Adds an item to the list of items for sale in the shop entry given the index. You usually want to run this command in the secret channel, so that the unique items are not leaked.. /// public static string shoplistadd_desc { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 363b09af..a0a397a6 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3417,11 +3417,20 @@ `{0}buy 2` + + gvc + + + Toggles game voice channel feature in the voice channel you're currently in. Users who join the game voice channel will get automatically redirected to the voice channel with the name of their current game if it exists. Can't move users to channels that the bot has no connect permission for. One per server. + + + `{0}gvc` + shoplistadd - Adds an item to the list of items for sale in the shop entry given the index. + Adds an item to the list of items for sale in the shop entry given the index. You usually want to run this command in the secret channel, so that the unique items are not leaked. `{0}shoplistadd 1 Uni-que-Steam-Key` diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 52a31610..1d0d3075 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -519,6 +519,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Game Voice Channel feature has been disabled on this server.. + /// + public static string administration_gvc_disabled { + get { + return ResourceManager.GetString("administration_gvc_disabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0} is a Game Voice Channel now.. + /// + public static string administration_gvc_enabled { + get { + return ResourceManager.GetString("administration_gvc_enabled", resourceCulture); + } + } + /// /// Looks up a localized string similar to You can't use this command on users with a role higher or equal to yours in the role hierarchy.. /// @@ -916,6 +934,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to You are not in voice channel on this server.. + /// + public static string administration_not_in_voice { + get { + return ResourceManager.GetString("administration_not_in_voice", resourceCulture); + } + } + /// /// Looks up a localized string similar to Old message. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 8b8ed781..4831a40f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2431,6 +2431,15 @@ Owner ID: {2} Next update in {0} Next update in 05:30 + + Game Voice Channel feature has been disabled on this server. + + + {0} is a Game Voice Channel now. + + + You are not in voice channel on this server. + Item diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs index e5a2c8b6..7d0ef6d2 100644 --- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs +++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs @@ -77,6 +77,7 @@ namespace NadekoBot.Services.Database.Models public HashSet SlowmodeIgnoredRoles { get; set; } public List ShopEntries { get; set; } + public ulong? GameVoiceChannel { get; set; } = null; //public List ProtectionIgnoredChannels { get; set; } = new List(); } From 98c330d6a62fc3a9b2bb4d45b655150db46b404c Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 9 Apr 2017 22:28:42 +0200 Subject: [PATCH 713/746] ;gmod, ;cmd, ;lgp and .resetglobalperms added. Bot owner can disable modules or commands bot-wide. --- .../20170409193757_gmod-and-cmod.Designer.cs | 1553 +++++++++++++++++ .../20170409193757_gmod-and-cmod.cs | 56 + .../NadekoSqliteContextModelSnapshot.cs | 33 + .../Modules/Administration/Administration.cs | 17 + .../Commands/GameChannelCommands.cs | 2 +- .../Commands/GlobalPermissionCommands.cs | 118 ++ .../Utility/Commands/CommandMapCommands.cs | 6 +- .../Commands/CrossServerTextChannel.cs | 68 +- .../Utility/Commands/MessageRepeater.cs | 21 +- .../Utility/Commands/PatreonCommands.cs | 9 +- .../Modules/Utility/Commands/Remind.cs | 19 +- .../Utility/Commands/UnitConversion.cs | 9 +- src/NadekoBot/Modules/Utility/Utility.cs | 9 +- .../Resources/CommandStrings.Designer.cs | 110 +- src/NadekoBot/Resources/CommandStrings.resx | 38 +- .../Resources/ResponseStrings.Designer.cs | 72 + src/NadekoBot/Resources/ResponseStrings.resx | 24 + src/NadekoBot/Services/CommandHandler.cs | 25 +- .../Services/Database/Models/BotConfig.cs | 19 + .../Repositories/Impl/BotConfigRepository.cs | 2 + 20 files changed, 2157 insertions(+), 53 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170409193757_gmod-and-cmod.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170409193757_gmod-and-cmod.cs create mode 100644 src/NadekoBot/Modules/Permissions/Commands/GlobalPermissionCommands.cs diff --git a/src/NadekoBot/Migrations/20170409193757_gmod-and-cmod.Designer.cs b/src/NadekoBot/Migrations/20170409193757_gmod-and-cmod.Designer.cs new file mode 100644 index 00000000..fe9da269 --- /dev/null +++ b/src/NadekoBot/Migrations/20170409193757_gmod-and-cmod.Designer.cs @@ -0,0 +1,1553 @@ +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("20170409193757_gmod-and-cmod")] + partial class gmodandcmod + { + 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("DateAdded"); + + 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.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("ItemId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("BlacklistItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlockedCmdOrMdl", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("BotConfigId1"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.HasIndex("BotConfigId1"); + + b.ToTable("BlockedCmdOrMdl"); + }); + + 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("DateAdded"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Mapping"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("AutoDeleteTrigger"); + + b.Property("DateAdded"); + + b.Property("DmResponse"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("DefaultMusicVolume"); + + b.Property("DeleteMessageOnCommand"); + + b.Property("DmGreetMessageText"); + + b.Property("ExclusiveSelfAssignedRoles"); + + b.Property("FilterInvites"); + + b.Property("FilterWords"); + + b.Property("GameVoiceChannel"); + + b.Property("GreetMessageChannelId"); + + b.Property("GuildId"); + + b.Property("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.Property("WarningsInitialized"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissionv2"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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("DateAdded"); + + 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.RewardedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AmountRewardedThisMonth"); + + b.Property("DateAdded"); + + b.Property("LastReward"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("RewardedUsers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("Name"); + + b.Property("Price"); + + b.Property("RoleId"); + + b.Property("RoleName"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("ShopEntry"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("ShopEntryId"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("ShopEntryId"); + + b.ToTable("ShopEntryItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredRole"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ChannelId"); + + b.Property("ChannelName"); + + b.Property("CommandText"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("GuildName"); + + b.Property("Index"); + + b.Property("VoiceChannelId"); + + b.Property("VoiceChannelName"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("StartupCommand"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UnmuteAt"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.Property("VoiceChannelId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("DateAdded"); + + 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("DateAdded"); + + 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.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Forgiven"); + + b.Property("ForgivenBy"); + + b.Property("GuildId"); + + b.Property("Moderator"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Count"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Punishment"); + + b.Property("Time"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + + 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.BlockedCmdOrMdl", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("BlockedCommands") + .HasForeignKey("BotConfigId"); + + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("BlockedModules") + .HasForeignKey("BotConfigId1"); + }); + + 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.CommandAlias", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId"); + }); + + 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.Permissionv2", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("Permissions") + .HasForeignKey("GuildConfigId"); + }); + + 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.ShopEntry", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("ShopEntries") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ShopEntry") + .WithMany("Items") + .HasForeignKey("ShopEntryId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("StartupCommands") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId"); + }); + + 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); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170409193757_gmod-and-cmod.cs b/src/NadekoBot/Migrations/20170409193757_gmod-and-cmod.cs new file mode 100644 index 00000000..5cef1a06 --- /dev/null +++ b/src/NadekoBot/Migrations/20170409193757_gmod-and-cmod.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class gmodandcmod : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "BlockedCmdOrMdl", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + BotConfigId = table.Column(nullable: true), + BotConfigId1 = table.Column(nullable: true), + DateAdded = table.Column(nullable: true), + Name = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_BlockedCmdOrMdl", x => x.Id); + table.ForeignKey( + name: "FK_BlockedCmdOrMdl_BotConfig_BotConfigId", + column: x => x.BotConfigId, + principalTable: "BotConfig", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_BlockedCmdOrMdl_BotConfig_BotConfigId1", + column: x => x.BotConfigId1, + principalTable: "BotConfig", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_BlockedCmdOrMdl_BotConfigId", + table: "BlockedCmdOrMdl", + column: "BotConfigId"); + + migrationBuilder.CreateIndex( + name: "IX_BlockedCmdOrMdl_BotConfigId1", + table: "BlockedCmdOrMdl", + column: "BotConfigId1"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "BlockedCmdOrMdl"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index a8e43d26..2e1fd50c 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -99,6 +99,28 @@ namespace NadekoBot.Migrations b.ToTable("BlacklistItem"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlockedCmdOrMdl", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("BotConfigId1"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.HasIndex("BotConfigId1"); + + b.ToTable("BlockedCmdOrMdl"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b => { b.Property("Id") @@ -1277,6 +1299,17 @@ namespace NadekoBot.Migrations .HasForeignKey("BotConfigId"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlockedCmdOrMdl", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("BlockedCommands") + .HasForeignKey("BotConfigId"); + + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("BlockedModules") + .HasForeignKey("BotConfigId1"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => { b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar") diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index fffac1f7..71f20464 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -67,6 +67,23 @@ namespace NadekoBot.Modules.Administration await ReplyConfirmLocalized("perms_reset").ConfigureAwait(false); } + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task ResetGlobalPermissions() + { + using (var uow = DbHandler.UnitOfWork()) + { + var gc = uow.BotConfig.GetOrCreate(); + gc.BlockedCommands.Clear(); + gc.BlockedModules.Clear(); + + GlobalPermissionCommands.BlockedCommands.Clear(); + GlobalPermissionCommands.BlockedModules.Clear(); + await uow.CompleteAsync(); + } + await ReplyConfirmLocalized("global_perms_reset").ConfigureAwait(false); + } + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.Administrator)] diff --git a/src/NadekoBot/Modules/Administration/Commands/GameChannelCommands.cs b/src/NadekoBot/Modules/Administration/Commands/GameChannelCommands.cs index f2e5fb6c..0e557b40 100644 --- a/src/NadekoBot/Modules/Administration/Commands/GameChannelCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/GameChannelCommands.cs @@ -22,7 +22,7 @@ namespace NadekoBot.Modules.Administration [Group] public class GameChannelCommands : NadekoSubmodule { - private static readonly Timer _t; + //private static readonly Timer _t; private static readonly ConcurrentHashSet gameVoiceChannels = new ConcurrentHashSet(); diff --git a/src/NadekoBot/Modules/Permissions/Commands/GlobalPermissionCommands.cs b/src/NadekoBot/Modules/Permissions/Commands/GlobalPermissionCommands.cs new file mode 100644 index 00000000..41ba61b3 --- /dev/null +++ b/src/NadekoBot/Modules/Permissions/Commands/GlobalPermissionCommands.cs @@ -0,0 +1,118 @@ +using Discord; +using Discord.Commands; +using NadekoBot.Attributes; +using NadekoBot.DataStructures; +using NadekoBot.Extensions; +using NadekoBot.Services; +using NadekoBot.Services.Database; +using NadekoBot.TypeReaders; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Permissions +{ + public partial class Permissions + { + [Group] + public class GlobalPermissionCommands : NadekoSubmodule + { + public static readonly ConcurrentHashSet BlockedModules; + public static readonly ConcurrentHashSet BlockedCommands; + + static GlobalPermissionCommands() + { + BlockedModules = new ConcurrentHashSet(NadekoBot.BotConfig.BlockedModules.Select(x => x.Name)); + BlockedCommands = new ConcurrentHashSet(NadekoBot.BotConfig.BlockedCommands.Select(x => x.Name)); + } + + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task Lgp() + { + if (!BlockedModules.Any() && !BlockedCommands.Any()) + { + await ReplyErrorLocalized("lgp_none").ConfigureAwait(false); + return; + } + + var embed = new EmbedBuilder().WithOkColor(); + + if (BlockedModules.Any()) + embed.AddField(efb => efb.WithName(GetText("blocked_modules")).WithValue(string.Join("\n", BlockedModules)).WithIsInline(false)); + + if (BlockedCommands.Any()) + embed.AddField(efb => efb.WithName(GetText("blocked_commands")).WithValue(string.Join("\n", BlockedCommands)).WithIsInline(false)); + + await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task Gmod(ModuleInfo module) + { + var moduleName = module.Name.ToLowerInvariant(); + if (BlockedModules.Add(moduleName)) + { + using (var uow = DbHandler.UnitOfWork()) + { + var bc = uow.BotConfig.GetOrCreate(); + bc.BlockedModules.Add(new Services.Database.Models.BlockedCmdOrMdl + { + Name = moduleName, + }); + uow.Complete(); + } + await ReplyConfirmLocalized("gmod_add", Format.Bold(module.Name)).ConfigureAwait(false); + return; + } + else if (BlockedModules.TryRemove(moduleName)) + { + using (var uow = DbHandler.UnitOfWork()) + { + var bc = uow.BotConfig.GetOrCreate(); + bc.BlockedModules.RemoveWhere(x => x.Name == moduleName); + uow.Complete(); + } + await ReplyConfirmLocalized("gmod_remove", Format.Bold(module.Name)).ConfigureAwait(false); + return; + } + } + + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task Gcmd(CommandOrCrInfo cmd) + { + var commandName = cmd.Name.ToLowerInvariant(); + if (BlockedCommands.Add(commandName)) + { + using (var uow = DbHandler.UnitOfWork()) + { + var bc = uow.BotConfig.GetOrCreate(); + bc.BlockedCommands.Add(new Services.Database.Models.BlockedCmdOrMdl + { + Name = commandName, + }); + uow.Complete(); + } + await ReplyConfirmLocalized("gcmd_add", Format.Bold(cmd.Name)).ConfigureAwait(false); + return; + } + else if (BlockedCommands.TryRemove(commandName)) + { + using (var uow = DbHandler.UnitOfWork()) + { + var bc = uow.BotConfig.GetOrCreate(); + bc.BlockedCommands.RemoveWhere(x => x.Name == commandName); + uow.Complete(); + } + await ReplyConfirmLocalized("gcmd_remove", Format.Bold(cmd.Name)).ConfigureAwait(false); + return; + } + } + } + } +} diff --git a/src/NadekoBot/Modules/Utility/Commands/CommandMapCommands.cs b/src/NadekoBot/Modules/Utility/Commands/CommandMapCommands.cs index 51fa03d1..11eb5017 100644 --- a/src/NadekoBot/Modules/Utility/Commands/CommandMapCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/CommandMapCommands.cs @@ -16,7 +16,6 @@ namespace NadekoBot.Modules.Utility { public partial class Utility { - public class CommandAliasEqualityComparer : IEqualityComparer { public bool Equals(CommandAlias x, CommandAlias y) => x.Trigger == y.Trigger; @@ -41,6 +40,11 @@ namespace NadekoBot.Modules.Utility .ToDictionary(ca => ca.Trigger, ca => ca.Mapping)))); } + public static void Unload() + { + AliasMaps.Clear(); + } + [NadekoCommand, Usage, Description, Aliases] [RequireUserPermission(GuildPermission.Administrator)] [RequireContext(ContextType.Guild)] diff --git a/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs b/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs index 45318177..0f1a78b5 100644 --- a/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs +++ b/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs @@ -3,6 +3,7 @@ using Discord.Commands; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; +using System; using System.Collections.Concurrent; using System.Linq; using System.Threading.Tasks; @@ -16,43 +17,50 @@ namespace NadekoBot.Modules.Utility { static CrossServerTextChannel() { - NadekoBot.Client.MessageReceived += async imsg => + NadekoBot.Client.MessageReceived += Client_MessageReceived; + } + + public static void Unload() + { + NadekoBot.Client.MessageReceived -= Client_MessageReceived; + } + + private static async Task Client_MessageReceived(Discord.WebSocket.SocketMessage imsg) + { + try { - try + if (imsg.Author.IsBot) + return; + var msg = imsg as IUserMessage; + if (msg == null) + return; + var channel = imsg.Channel as ITextChannel; + if (channel == null) + return; + if (msg.Author.Id == NadekoBot.Client.CurrentUser.Id) return; + foreach (var subscriber in Subscribers) { - if (imsg.Author.IsBot) - return; - var msg = imsg as IUserMessage; - if (msg == null) - return; - var channel = imsg.Channel as ITextChannel; - if (channel == null) - return; - if (msg.Author.Id == NadekoBot.Client.CurrentUser.Id) return; - foreach (var subscriber in Subscribers) + var set = subscriber.Value; + if (!set.Contains(channel)) + continue; + foreach (var chan in set.Except(new[] { channel })) { - var set = subscriber.Value; - if (!set.Contains(channel)) - continue; - foreach (var chan in set.Except(new[] {channel})) + try { - try - { - await chan.SendMessageAsync(GetMessage(channel, (IGuildUser) msg.Author, - msg)).ConfigureAwait(false); - } - catch - { - // ignored - } + await chan.SendMessageAsync(GetMessage(channel, (IGuildUser)msg.Author, + msg)).ConfigureAwait(false); + } + catch + { + // ignored } } } - catch - { - // ignored - } - }; + } + catch + { + // ignored + } } private static string GetMessage(ITextChannel channel, IGuildUser user, IUserMessage message) => diff --git a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs index 58752c28..4b40b98b 100644 --- a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs @@ -48,7 +48,6 @@ namespace NadekoBot.Modules.Utility Task.Run(Run); } - private async Task Run() { source = new CancellationTokenSource(); @@ -124,7 +123,12 @@ namespace NadekoBot.Modules.Utility { var _ = Task.Run(async () => { +#if !GLOBAL_NADEKO await Task.Delay(5000).ConfigureAwait(false); +#else + await Task.Delay(30000).ConfigureAwait(false); +#endif + //todo this is pretty terrible Repeaters = new ConcurrentDictionary>(NadekoBot.AllGuildConfigs .ToDictionary(gc => gc.GuildId, gc => new ConcurrentQueue(gc.GuildRepeaters @@ -134,6 +138,21 @@ namespace NadekoBot.Modules.Utility }); } + public static void Unload() + { + _ready = false; + foreach (var kvp in Repeaters) + { + RepeatRunner r; + while (kvp.Value.TryDequeue(out r)) + { + r.Stop(); + } + } + + Repeaters.Clear(); + } + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageMessages)] diff --git a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs index 583b1f5b..618fb588 100644 --- a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs @@ -29,6 +29,11 @@ namespace NadekoBot.Modules.Utility patreon = PatreonThingy.Instance; } + public static void Unload() + { + patreon.Updater.Change(Timeout.Infinite, Timeout.Infinite); + } + [NadekoCommand, Usage, Description, Aliases] [OwnerOnly] public async Task PatreonRewardsReload() @@ -86,7 +91,7 @@ namespace NadekoBot.Modules.Utility public ImmutableArray Pledges { get; private set; } public DateTime LastUpdate { get; private set; } = DateTime.UtcNow; - private readonly Timer update; + public readonly Timer Updater; private readonly SemaphoreSlim claimLockJustInCase = new SemaphoreSlim(1, 1); private readonly Logger _log; @@ -97,7 +102,7 @@ namespace NadekoBot.Modules.Utility if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) return; _log = LogManager.GetCurrentClassLogger(); - update = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, Interval); + Updater = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, Interval); } public async Task LoadPledges() diff --git a/src/NadekoBot/Modules/Utility/Commands/Remind.cs b/src/NadekoBot/Modules/Utility/Commands/Remind.cs index 8d490563..8da05b89 100644 --- a/src/NadekoBot/Modules/Utility/Commands/Remind.cs +++ b/src/NadekoBot/Modules/Utility/Commands/Remind.cs @@ -32,10 +32,15 @@ namespace NadekoBot.Modules.Utility }; private new static readonly Logger _log; + private static readonly CancellationTokenSource cancelSource; + private static readonly CancellationToken cancelAllToken; static RemindCommands() { _log = LogManager.GetCurrentClassLogger(); + + cancelSource = new CancellationTokenSource(); + cancelAllToken = cancelSource.Token; List reminders; using (var uow = DbHandler.UnitOfWork()) { @@ -45,11 +50,17 @@ namespace NadekoBot.Modules.Utility foreach (var r in reminders) { - Task.Run(() => StartReminder(r)); + Task.Run(() => StartReminder(r, cancelAllToken)); } } - private static async Task StartReminder(Reminder r) + public static void Unload() + { + if (!cancelSource.IsCancellationRequested) + cancelSource.Cancel(); + } + + private static async Task StartReminder(Reminder r, CancellationToken t) { var now = DateTime.Now; @@ -58,7 +69,7 @@ namespace NadekoBot.Modules.Utility if (time.TotalMilliseconds > int.MaxValue) return; - await Task.Delay(time).ConfigureAwait(false); + await Task.Delay(time, t).ConfigureAwait(false); try { IMessageChannel ch; @@ -188,7 +199,7 @@ namespace NadekoBot.Modules.Utility { // ignored } - await StartReminder(rem); + await StartReminder(rem, cancelAllToken); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs index 4046627b..87283de3 100644 --- a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs +++ b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs @@ -49,14 +49,19 @@ namespace NadekoBot.Modules.Utility } Units = data.ToList(); } - catch (Exception e) + catch (Exception ex) { - _log.Warn("Could not load units: " + e.Message); + _log.Warn("Could not load units: " + ex.Message); } _timer = new Timer(async (obj) => await UpdateCurrency(), null, _updateInterval, _updateInterval); } + public static void Unload() + { + _timer.Change(Timeout.Infinite, Timeout.Infinite); + } + public static async Task UpdateCurrency() { try diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 1ac77e73..0e2eba1b 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -25,6 +25,12 @@ namespace NadekoBot.Modules.Utility { private static ConcurrentDictionary _rotatingRoleColors = new ConcurrentDictionary(); + public static void Unload() + { + _rotatingRoleColors.ForEach(x => x.Value?.Change(Timeout.Infinite, Timeout.Infinite)); + _rotatingRoleColors.Clear(); + } + //[NadekoCommand, Usage, Description, Aliases] //[RequireContext(ContextType.Guild)] //public async Task Midorina([Remainder] string arg) @@ -49,7 +55,7 @@ namespace NadekoBot.Modules.Utility // var roleStrings = roles // .Select(x => $"{reactions[j++]} -> {x.Name}"); - + // var msg = await Context.Channel.SendConfirmAsync("Pick a Role", // string.Join("\n", roleStrings)).ConfigureAwait(false); @@ -100,6 +106,7 @@ namespace NadekoBot.Modules.Utility // } // })); //} + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 256ff9fe..0a128d7f 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -3012,7 +3012,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Toggles game voice channel feature in the voice channel you're currently in. Users who join the game voice channel will get automatically redirected to the voice channel with the name of their current game if it exists. Can't move users to channels that the bot has no connect permission for. One per server.. + /// Looks up a localized string similar to Toggles game voice channel feature in the voice channel you're currently in. Users who join the game voice channel will get automatically redirected to the voice channel with the name of their current game, if it exists. Can't move users to channels that the bot has no connect permission for. One per server.. /// public static string gamevoicechannel_desc { get { @@ -3029,6 +3029,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to globalcommand gcmd. + /// + public static string gcmd_cmd { + get { + return ResourceManager.GetString("gcmd_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enables or disables a command from use on all servers.. + /// + public static string gcmd_desc { + get { + return ResourceManager.GetString("gcmd_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}gcmd `. + /// + public static string gcmd_usage { + get { + return ResourceManager.GetString("gcmd_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to gelbooru. /// @@ -3110,6 +3137,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to globalmodule gmod. + /// + public static string gmod_cmd { + get { + return ResourceManager.GetString("gmod_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enable or disable a module from use on all servers.. + /// + public static string gmod_desc { + get { + return ResourceManager.GetString("gmod_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}gmod nsfw disable`. + /// + public static string gmod_usage { + get { + return ResourceManager.GetString("gmod_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to google g. /// @@ -4055,6 +4109,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to listglobalperms lgp. + /// + public static string lgp_cmd { + get { + return ResourceManager.GetString("lgp_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lists global permissions set by the bot owner.. + /// + public static string lgp_desc { + get { + return ResourceManager.GetString("lgp_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}lgp`. + /// + public static string lgp_usage { + get { + return ResourceManager.GetString("lgp_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to linux. /// @@ -6512,6 +6593,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to resetglobalperms. + /// + public static string resetglobalpermissions_cmd { + get { + return ResourceManager.GetString("resetglobalpermissions_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Resets global permissions set by bot owner.. + /// + public static string resetglobalpermissions_desc { + get { + return ResourceManager.GetString("resetglobalpermissions_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}resetglobalperms`. + /// + public static string resetglobalpermissions_usage { + get { + return ResourceManager.GetString("resetglobalpermissions_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to resetperms. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index a0a397a6..715ae1ba 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3421,7 +3421,7 @@ gvc - Toggles game voice channel feature in the voice channel you're currently in. Users who join the game voice channel will get automatically redirected to the voice channel with the name of their current game if it exists. Can't move users to channels that the bot has no connect permission for. One per server. + Toggles game voice channel feature in the voice channel you're currently in. Users who join the game voice channel will get automatically redirected to the voice channel with the name of their current game, if it exists. Can't move users to channels that the bot has no connect permission for. One per server. `{0}gvc` @@ -3438,4 +3438,40 @@ `{0}shoprm 1` + + globalcommand gcmd + + + Enables or disables a command from use on all servers. + + + `{0}gcmd ` + + + globalmodule gmod + + + Enable or disable a module from use on all servers. + + + `{0}gmod nsfw disable` + + + listglobalperms lgp + + + Lists global permissions set by the bot owner. + + + `{0}lgp` + + + resetglobalperms + + + Resets global permissions set by bot owner. + + + `{0}resetglobalperms` + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 1d0d3075..67942c21 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -411,6 +411,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Global permissions have been reset.. + /// + public static string administration_global_perms_reset { + get { + return ResourceManager.GetString("administration_global_perms_reset", resourceCulture); + } + } + /// /// Looks up a localized string similar to Greet announcements disabled.. /// @@ -4711,6 +4720,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Blocked Commands. + /// + public static string permissions_blocked_commands { + get { + return ResourceManager.GetString("permissions_blocked_commands", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Blocked Modules. + /// + public static string permissions_blocked_modules { + get { + return ResourceManager.GetString("permissions_blocked_modules", resourceCulture); + } + } + /// /// Looks up a localized string similar to Command {0} now has a {1}s cooldown.. /// @@ -4801,6 +4828,42 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Command {0} has been disabled on all servers.. + /// + public static string permissions_gcmd_add { + get { + return ResourceManager.GetString("permissions_gcmd_add", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Command {0} has been enabled on all servers.. + /// + public static string permissions_gcmd_remove { + get { + return ResourceManager.GetString("permissions_gcmd_remove", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Module {0} has been disabled on all servers.. + /// + public static string permissions_gmod_add { + get { + return ResourceManager.GetString("permissions_gmod_add", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Module {0} has been enabled on all servers.. + /// + public static string permissions_gmod_remove { + get { + return ResourceManager.GetString("permissions_gmod_remove", resourceCulture); + } + } + /// /// Looks up a localized string similar to Invalid second parameter.(Must be a number between {0} and {1}). /// @@ -4846,6 +4909,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to No blocked commands or modules.. + /// + public static string permissions_lgp_none { + get { + return ResourceManager.GetString("permissions_lgp_none", resourceCulture); + } + } + /// /// Looks up a localized string similar to Moved permission {0} from #{1} to #{2}. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 4831a40f..e3c2ffa4 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2431,6 +2431,9 @@ Owner ID: {2} Next update in {0} Next update in 05:30 + + Global permissions have been reset. + Game Voice Channel feature has been disabled on this server. @@ -2485,4 +2488,25 @@ Owner ID: {2} {0} unique items left. + + Blocked Commands + + + Blocked Modules + + + Command {0} has been disabled on all servers. + + + Command {0} has been enabled on all servers. + + + Module {0} has been disabled on all servers. + + + Module {0} has been enabled on all servers. + + + No blocked commands or modules. + \ No newline at end of file diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 8cd840e0..06b447b1 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -486,15 +486,22 @@ namespace NadekoBot.Services } } - int price; - if (Permissions.CommandCostCommands.CommandCosts.TryGetValue(cmd.Aliases.First().Trim().ToLowerInvariant(), out price) && price > 0) - { - var success = await CurrencyHandler.RemoveCurrencyAsync(context.User.Id, $"Running {cmd.Name} command.", price).ConfigureAwait(false); - if (!success) - { - return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"Insufficient funds. You need {price}{NadekoBot.BotConfig.CurrencySign} to run this command.")); - } - } + //int price; + //if (Permissions.CommandCostCommands.CommandCosts.TryGetValue(cmd.Aliases.First().Trim().ToLowerInvariant(), out price) && price > 0) + //{ + // var success = await CurrencyHandler.RemoveCurrencyAsync(context.User.Id, $"Running {cmd.Name} command.", price).ConfigureAwait(false); + // if (!success) + // { + // return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"Insufficient funds. You need {price}{NadekoBot.BotConfig.CurrencySign} to run this command.")); + // } + //} + } + + if (cmd.Name != "resetglobalperms" && + (GlobalPermissionCommands.BlockedCommands.Contains(cmd.Aliases.First().ToLowerInvariant()) || + GlobalPermissionCommands.BlockedModules.Contains(module.Name.ToLowerInvariant()))) + { + return new ExecuteCommandResult(cmd, null, SearchResult.FromError(CommandError.Exception, $"Command or module is blocked globally by the bot owner.")); } // Bot will ignore commands which are ran more often than what specified by diff --git a/src/NadekoBot/Services/Database/Models/BotConfig.cs b/src/NadekoBot/Services/Database/Models/BotConfig.cs index b25dc744..81bbb87f 100644 --- a/src/NadekoBot/Services/Database/Models/BotConfig.cs +++ b/src/NadekoBot/Services/Database/Models/BotConfig.cs @@ -62,6 +62,25 @@ Nadeko Support Server: https://discord.gg/nadekobot"; public string ErrorColor { get; set; } = "ee281f"; public string Locale { get; set; } = null; public List StartupCommands { get; set; } + public HashSet BlockedCommands { get; set; } + public HashSet BlockedModules { get; set; } + } + + public class BlockedCmdOrMdl : DbEntity + { + public string Name { get; set; } + + public override bool Equals(object obj) + { + if (obj == null || GetType() != obj.GetType()) + { + return false; + } + + return ((BlockedCmdOrMdl)obj).Name.ToLowerInvariant() == Name.ToLowerInvariant(); + } + + public override int GetHashCode() => Name.GetHashCode(); } public class StartupCommand : DbEntity, IIndexed diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs index 1e40f86c..c9b7ad7d 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs @@ -22,6 +22,8 @@ namespace NadekoBot.Services.Database.Repositories.Impl .Include(bc => bc.EightBallResponses) .Include(bc => bc.ModulePrefixes) .Include(bc => bc.StartupCommands) + .Include(bc => bc.BlockedCommands) + .Include(bc => bc.BlockedModules) //.Include(bc => bc.CommandCosts) .FirstOrDefault(); else From 19160c6bbcf8a8c81913b215d4bf5aee4e453b04 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 9 Apr 2017 23:22:06 +0200 Subject: [PATCH 714/746] closes #431, if gmod or gcmd is active on some module or command, they won't show up on -mdls or -cmds respectively --- src/NadekoBot/Modules/Help/Help.cs | 2 ++ src/NadekoBot/Modules/Searches/Searches.cs | 2 +- src/NadekoBot/Resources/CommandStrings.Designer.cs | 2 +- src/NadekoBot/Resources/CommandStrings.resx | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Help/Help.cs b/src/NadekoBot/Modules/Help/Help.cs index 4ca96023..1208260b 100644 --- a/src/NadekoBot/Modules/Help/Help.cs +++ b/src/NadekoBot/Modules/Help/Help.cs @@ -31,6 +31,7 @@ namespace NadekoBot.Modules.Help .WithTitle(GetText("list_of_modules")) .WithDescription(string.Join("\n", NadekoBot.CommandService.Modules.GroupBy(m => m.GetTopLevelModule()) + .Where(m => !Permissions.Permissions.GlobalPermissionCommands.BlockedModules.Contains(m.Key.Name.ToLowerInvariant())) .Select(m => "• " + m.Key.Name) .OrderBy(s => s))); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); @@ -45,6 +46,7 @@ namespace NadekoBot.Modules.Help if (string.IsNullOrWhiteSpace(module)) return; var cmds = NadekoBot.CommandService.Commands.Where(c => c.Module.GetTopLevelModule().Name.ToUpperInvariant().StartsWith(module)) + .Where(c => !Permissions.Permissions.GlobalPermissionCommands.BlockedCommands.Contains(c.Aliases.First().ToLowerInvariant())) .OrderBy(c => c.Aliases.First()) .Distinct(new CommandTextEqualityComparer()) .AsEnumerable(); diff --git a/src/NadekoBot/Modules/Searches/Searches.cs b/src/NadekoBot/Modules/Searches/Searches.cs index 3e6aa1bc..b25bf15e 100644 --- a/src/NadekoBot/Modules/Searches/Searches.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -585,7 +585,7 @@ namespace NadekoBot.Modules.Searches { if (usr == null) usr = Context.User; - await Context.Channel.SendConfirmAsync($"https://images.google.com/searchbyimage?image_url={usr.AvatarUrl}").ConfigureAwait(false); + await Context.Channel.SendConfirmAsync($"https://images.google.com/searchbyimage?image_url={usr.RealAvatarUrl()}").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 0a128d7f..48192ab6 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -5037,7 +5037,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have the mention everyone permission.. + /// Looks up a localized string similar to Mentions every person from the provided role or roles (separated by a ',') on this server.. /// public static string mentionrole_desc { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 715ae1ba..1b5cff49 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -733,7 +733,7 @@ mentionrole menro - Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have the mention everyone permission. + Mentions every person from the provided role or roles (separated by a ',') on this server. `{0}menro RoleName` From c9937a4fbe29f0d212df0a1ed9388aea7a6b222d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 9 Apr 2017 23:23:19 +0200 Subject: [PATCH 715/746] version upped to 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 f18845ad..570c44ff 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -16,7 +16,7 @@ namespace NadekoBot.Services.Impl private readonly DiscordShardedClient _client; private readonly DateTime _started; - public const string BotVersion = "1.26a"; + public const string BotVersion = "1.3"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From 4badd92b5a3f8c92d2203afdf32f46c71e1815e4 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 9 Apr 2017 23:29:08 +0200 Subject: [PATCH 716/746] updated commandlist --- docs/Commands List.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index da4d922c..dc705b8e 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -19,14 +19,15 @@ You can support the project on patreon: or paypa Commands and aliases | Description | Usage ----------------|--------------|------- `.resetperms` | Resets the bot's permissions module on this server to the default value. **Requires Administrator server permission.** | `.resetperms` +`.resetglobalperms` | Resets global permissions set by bot owner. **Bot owner only** | `.resetglobalperms` `.delmsgoncmd` | Toggles the automatic deletion of the user's successful command message to prevent chat flood. **Requires Administrator server permission.** | `.delmsgoncmd` `.setrole` `.sr` | Sets a role for a given user. **Requires ManageRoles server permission.** | `.sr @User Guest` `.removerole` `.rr` | Removes a role from a given user. **Requires ManageRoles server permission.** | `.rr @User Admin` `.renamerole` `.renr` | Renames a role. The role you are renaming must be lower than bot's highest role. **Requires ManageRoles server permission.** | `.renr "First role" SecondRole` `.removeallroles` `.rar` | Removes all roles from a mentioned user. **Requires ManageRoles server permission.** | `.rar @User` `.createrole` `.cr` | Creates a role with a given name. **Requires ManageRoles server permission.** | `.cr Awesome Role` +`.rolehoist` `.rh` | Toggles if this role is displayed in the sidebar or not **Requires ManageRoles server permission.** | `.rh Guests true` or `.rh "Space Wizards" true `.rolecolor` `.rc` | Set a role's color to the hex or 0-255 rgb color value provided. **Requires ManageRoles server permission.** | `.rc Admin 255 200 100` or `.rc Admin ffba55` -`.rolehoist` `.rh` | Set whether the role should be displayed separately in the sidebar **Requires ManageRoles server permission.** | `.rh Guests true` or `.rolehoist "Space Wizards" true` `.deafen` `.deaf` | Deafens mentioned user or users. **Requires DeafenMembers server permission.** | `.deaf "@Someguy"` or `.deaf "@Someguy" "@Someguy"` `.undeafen` `.undef` | Undeafens mentioned user or users. **Requires DeafenMembers server permission.** | `.undef "@Someguy"` or `.undef "@Someguy" "@Someguy"` `.delvoichanl` `.dvch` | Deletes a voice channel with a given name. **Requires ManageChannels server permission.** | `.dvch VoiceChannelName` @@ -36,10 +37,11 @@ Commands and aliases | Description | Usage `.settopic` `.st` | Sets a topic on the current channel. **Requires ManageChannels server permission.** | `.st My new topic` `.setchanlname` `.schn` | Changes the name of the current channel. **Requires ManageChannels server permission.** | `.schn NewName` `.prune` `.clr` | `.prune` removes all Nadeko's messages in the last 100 messages. `.prune X` removes last `X` number of messages from the channel (up to 100). `.prune @Someone` removes all Someone's messages in the last 100 messages. `.prune @Someone X` removes last `X` number of 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X` -`.mentionrole` `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have the mention everyone permission. **Requires MentionEveryone server permission.** | `.menro RoleName` +`.mentionrole` `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. **Requires MentionEveryone server permission.** | `.menro RoleName` `.donators` | List of the lovely people who donated to keep this project alive. | `.donators` `.donadd` | Add a donator to the database. **Bot owner only** | `.donadd Donate Amount` `.autoassignrole` `.aar` | Automaticaly assigns a specified role to every user who joins the server. **Requires ManageRoles server permission.** | `.aar` to disable, `.aar Role Name` to enable +`.gvc` | Toggles game voice channel feature in the voice channel you're currently in. Users who join the game voice channel will get automatically redirected to the voice channel with the name of their current game, if it exists. Can't move users to channels that the bot has no connect permission for. One per server. **Requires Administrator server permission.** | `.gvc` `.languageset` `.langset` | Sets this server's response language. If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. | `.langset de-DE ` or `.langset default` `.langsetdefault` `.langsetd` | Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. | `.langsetd en-US` or `.langsetd default` `.languageslist` `.langli` | List of languages for which translation (or part of it) exist atm. | `.langli` @@ -64,6 +66,7 @@ Commands and aliases | Description | Usage `.antispamignore` | Toggles whether antispam ignores current channel. Antispam must be enabled. | `.antispamignore` `.antilist` `.antilst` | Shows currently enabled protection features. | `.antilist` `.slowmode` | Toggles slowmode. Disable by specifying no parameters. To enable, specify a number of messages each user can send, and an interval in seconds. For example 1 message every 5 seconds. **Requires ManageMessages server permission.** | `.slowmode 1 5` or `.slowmode` +`.slowmodewl` | Ignores a role or a user from the slowmode feature. **Requires ManageMessages server permission.** | `.slowmodewl SomeRole` or `.slowmodewl AdminDude` `.adsarm` | Toggles the automatic deletion of confirmations for `.iam` and `.iamn` commands. **Requires ManageMessages server permission.** | `.adsarm` `.asar` | Adds a role to the list of self-assignable roles. **Requires ManageRoles server permission.** | `.asar Gamer` `.rsar` | Removes a specified role from the list of self-assignable roles. **Requires ManageRoles server permission.** | `.rsar` @@ -136,7 +139,7 @@ Commands and aliases | Description | Usage `.listcustreactg` `.lcrg` | Lists global or server custom reactions (20 commands per page) grouped by trigger, and show a number of responses for each. Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. | `.lcrg 1` `.showcustreact` `.scr` | Shows a custom reaction's response on a given ID. | `.scr 1` `.delcustreact` `.dcr` | Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration privileges and removes server custom reaction. | `.dcr 5` -`.crdm` | Toggles whether the response message of the custom reaction will be sent as a direct message. | `.crad 44` +`.crdm` | Toggles whether the response message of the custom reaction will be sent as a direct message. | `.crdm 44` `.crad` | Toggles whether the message triggering the custom reaction will be automatically deleted. | `.crad 59` `.crstatsclear` | Resets the counters on `.crstats`. You can specify a trigger to clear stats only for that trigger. **Bot owner only** | `.crstatsclear` or `.crstatsclear rng` `.crstats` | Shows a list of custom reactions and the number of times they have been executed. Paginated with 10 per page. Use `.crstatsclear` to reset the counters. | `.crstats` or `.crstats 3` @@ -163,6 +166,11 @@ Commands and aliases | Description | Usage `$shuffle` `$sh` | Reshuffles all cards back into the deck. | `$sh` `$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.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. | `$bf 5 heads` or `$bf 3 t` +`$shop` | Lists this server's administrators' shop. Paginated. | `$shop` or `$shop 2` +`$buy` | Buys an item from the shop on a given index. If buying items, make sure that the bot can DM you. | `$buy 2` +`$shopadd` | Adds an item to the shop by specifying type price and name. Available types are role and list. **Requires Administrator server permission.** | `$shopadd role 1000 Rich` +`$shoplistadd` | Adds an item to the list of items for sale in the shop entry given the index. You usually want to run this command in the secret channel, so that the unique items are not leaked. **Requires Administrator server permission.** | `$shoplistadd 1 Uni-que-Steam-Key` +`$shoprem` `$shoprm` | Removes an item from the shop by its color. **Requires Administrator server permission.** | `$shoprm 1` `$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` @@ -303,6 +311,9 @@ Commands and aliases | Description | Usage `;chnlfilterwords` `;cfw` | Toggles automatic deletion of messages containing filtered words on the channel. Does not negate the `;srvrfilterwords` enabled setting. Does not affect the 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` +`;listglobalperms` `;lgp` | Lists global permissions set by the bot owner. **Bot owner only** | `;lgp` +`;globalmodule` `;gmod` | Enable or disable a module from use on all servers. **Bot owner only** | `;gmod nsfw disable` +`;globalcommand` `;gcmd` | Enables or disables a command from use on all servers. **Bot owner only** | `;gcmd ` ###### [Back to ToC](#table-of-contents) @@ -321,6 +332,7 @@ Commands and aliases | Description | Usage Commands and aliases | Description | Usage ----------------|--------------|------- `~weather` `~we` | Shows weather data for a specified city. You can also specify a country after a comma. | `~we Moscow, RU` +`~time` | Shows the current time and timezone in the specified location. | `~time London, UK` `~youtube` `~yt` | Searches youtubes and shows the first result | `~yt query` `~imdb` `~omdb` | Queries omdb for movies or series, show first result. | `~imdb Batman vs Superman` `~randomcat` `~meow` | Shows a random cat image. | `~meow` @@ -398,6 +410,7 @@ Commands and aliases | Description | Usage `.showemojis` `.se` | Shows a name and a link to every SPECIAL emoji in the message. | `.se A message full of SPECIAL emojis` `.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot owner only** | `.listservers 3` `.savechat` | Saves a number of messages to a text file and sends it to you. **Bot owner only** | `.savechat 150` +`.ping` | Ping the bot to see if there are latency issues. | `.ping` `.activity` | Checks for spammers. **Bot owner only** | `.activity` `.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1` `.calcops` | Shows all available operations in the `.calc` command | `.calcops` @@ -413,9 +426,12 @@ Commands and aliases | Description | Usage `.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2` `.repeat` | Repeat a message every `X` minutes in the current channel. You can have up to 5 repeating messages on the server in total. **Requires ManageMessages server permission.** | `.repeat 5 Hello there` `.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist` -`.listquotes` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page. +`.parewrel` | Forces the update of the list of patrons who are eligible for the reward. **Bot owner only** | `.parewrel` +`.clparew` | Claim patreon rewards. If you're subscribed to bot owner's patreon you can use this command to claim your rewards - assuming bot owner did setup has their patreon key. | `.clparew` +`.listquotes` `.liqu` | Lists all quotes on the server ordered alphabetically. 15 Per page. | `.liqu` or `.liqu 3` `...` | Shows a random quote with a specified name. | `... abc` `.qsearch` | Shows a random quote for a keyword that contains any text specified in the search. | `.qsearch keyword text` +`.quoteid` `.qid` | Displays the quote with the specified ID number. Quote ID numbers can be found by typing `.liqu [num]` where `[num]` is a number of a page which contains 15 quotes. | `.qid 123456` `..` | Adds a new quote with the specified name and message. | `.. sayhi Hi` `.deletequote` `.delq` | Deletes a quote with the specified ID. You have to be either server Administrator or the creator of the quote to delete it. | `.delq 123456` `.delallq` `.daq` | Deletes all quotes on a specified keyword. **Requires Administrator server permission.** | `.delallq kek` From e5131e0416f3ae3ff42b1820185482dd94e5a299 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 9 Apr 2017 23:31:16 +0200 Subject: [PATCH 717/746] now shows that you can specify a reason --- src/NadekoBot/Resources/CommandStrings.Designer.cs | 2 +- src/NadekoBot/Resources/CommandStrings.resx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 48192ab6..c135ff21 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -9744,7 +9744,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to `{0}warn @b1nzy`. + /// Looks up a localized string similar to `{0}warn @b1nzy Very rude person`. /// public static string warn_usage { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 1b5cff49..6c67e584 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3247,7 +3247,7 @@ Warns a user. - `{0}warn @b1nzy` + `{0}warn @b1nzy Very rude person` scadd From a0e363ff660637e53442acdb7853a905f8ae3f77 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 10 Apr 2017 02:29:33 +0200 Subject: [PATCH 718/746] mute role will be applied to newly created channels now too --- .../Administration/Commands/MuteCommands.cs | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs index 0a130383..9399fc90 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MuteCommands.cs @@ -1,5 +1,6 @@ using Discord; using Discord.Commands; +using Discord.WebSocket; using Microsoft.EntityFrameworkCore; using NadekoBot.Attributes; using NadekoBot.Services; @@ -32,6 +33,9 @@ namespace NadekoBot.Modules.Administration Chat, All } + private static readonly OverwritePermissions denyOverwrite = new OverwritePermissions(sendMessages: PermValue.Deny, attachFiles: PermValue.Deny); + + private static readonly new Logger _log = LogManager.GetCurrentClassLogger(); static MuteCommands() { @@ -152,21 +156,26 @@ namespace NadekoBot.Modules.Administration muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName) ?? await guild.CreateRoleAsync(defaultMuteRoleName, GuildPermissions.None).ConfigureAwait(false); } + } - foreach (var toOverwrite in (await guild.GetTextChannelsAsync())) + foreach (var toOverwrite in (await guild.GetTextChannelsAsync())) + { + try { - try + if (!toOverwrite.PermissionOverwrites.Select(x => x.Permissions).Contains(denyOverwrite)) { - await toOverwrite.AddPermissionOverwriteAsync(muteRole, new OverwritePermissions(sendMessages: PermValue.Deny, attachFiles: PermValue.Deny)) + await toOverwrite.AddPermissionOverwriteAsync(muteRole, denyOverwrite) .ConfigureAwait(false); + + await Task.Delay(200).ConfigureAwait(false); } - catch - { - // ignored - } - await Task.Delay(200).ConfigureAwait(false); + } + catch + { + // ignored } } + return muteRole; } From bece18dffc09678d543d3cdb9767d01299c8d18f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 10 Apr 2017 02:53:36 +0200 Subject: [PATCH 719/746] .repinv now posts in the channel repeater originates from, not current one --- .../Utility/Commands/MessageRepeater.cs | 84 ++++++++++--------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs index 4b40b98b..4bc2f2f5 100644 --- a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs @@ -36,6 +36,7 @@ namespace NadekoBot.Modules.Utility public Repeater Repeater { get; } public SocketGuild Guild { get; } public ITextChannel Channel { get; private set; } + private IUserMessage oldMsg = null; public RepeatRunner(Repeater repeater, ITextChannel channel = null) { @@ -52,49 +53,13 @@ namespace NadekoBot.Modules.Utility { source = new CancellationTokenSource(); token = source.Token; - IUserMessage oldMsg = null; try { while (!token.IsCancellationRequested) { - var toSend = "🔄 " + Repeater.Message; await Task.Delay(Repeater.Interval, token).ConfigureAwait(false); - //var lastMsgInChannel = (await Channel.GetMessagesAsync(2)).FirstOrDefault(); - // if (lastMsgInChannel.Id == oldMsg?.Id) //don't send if it's the same message in the channel - // continue; - - if (oldMsg != null) - try - { - await oldMsg.DeleteAsync(); - } - catch - { - // ignored - } - try - { - if (Channel == null) - Channel = Guild.GetTextChannel(Repeater.ChannelId); - - if (Channel != null) - oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false); - } - catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.Forbidden) - { - _log.Warn("Missing permissions. Repeater stopped. ChannelId : {0}", Channel?.Id); - return; - } - catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound) - { - _log.Warn("Channel not found. Repeater stopped. ChannelId : {0}", Channel?.Id); - return; - } - catch (Exception ex) - { - _log.Warn(ex); - } + await Trigger().ConfigureAwait(false); } } catch (OperationCanceledException) @@ -102,6 +67,46 @@ namespace NadekoBot.Modules.Utility } } + public async Task Trigger() + { + var toSend = "🔄 " + Repeater.Message; + //var lastMsgInChannel = (await Channel.GetMessagesAsync(2)).FirstOrDefault(); + // if (lastMsgInChannel.Id == oldMsg?.Id) //don't send if it's the same message in the channel + // continue; + + if (oldMsg != null) + try + { + await oldMsg.DeleteAsync(); + } + catch + { + // ignored + } + try + { + if (Channel == null) + Channel = Guild.GetTextChannel(Repeater.ChannelId); + + if (Channel != null) + oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false); + } + catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.Forbidden) + { + _log.Warn("Missing permissions. Repeater stopped. ChannelId : {0}", Channel?.Id); + return; + } + catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound) + { + _log.Warn("Channel not found. Repeater stopped. ChannelId : {0}", Channel?.Id); + return; + } + catch (Exception ex) + { + _log.Warn(ex); + } + } + public void Reset() { source.Cancel(); @@ -176,9 +181,10 @@ namespace NadekoBot.Modules.Utility return; } var repeater = repList[index].Repeater; - repList[index].Reset(); - await Context.Channel.SendMessageAsync("🔄 " + repeater.Message).ConfigureAwait(false); + await repList[index].Trigger(); + + await Context.Channel.SendMessageAsync("🔄").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] From 81d2272a9a5f24b8d0c46c60be3fa9d2a4d446a2 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 10 Apr 2017 03:00:17 +0200 Subject: [PATCH 720/746] fixed missing here and everyone mention removals from custom reactions, repeaters and others --- src/NadekoBot/Modules/CustomReactions/CustomReactions.cs | 2 +- src/NadekoBot/Modules/CustomReactions/Extensions.cs | 2 +- src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index ac6fd4c9..b250c510 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -28,7 +28,7 @@ namespace NadekoBot.Modules.CustomReactions { return await channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? ""); } - return await channel.SendMessageAsync(cr.ResponseWithContext(context)); + return await channel.SendMessageAsync(cr.ResponseWithContext(context).SanitizeMentions()); } } diff --git a/src/NadekoBot/Modules/CustomReactions/Extensions.cs b/src/NadekoBot/Modules/CustomReactions/Extensions.cs index a0b91962..b40e3fa8 100644 --- a/src/NadekoBot/Modules/CustomReactions/Extensions.cs +++ b/src/NadekoBot/Modules/CustomReactions/Extensions.cs @@ -15,7 +15,7 @@ namespace NadekoBot.Modules.CustomReactions { public static Dictionary> responsePlaceholders = new Dictionary>() { - {"%target%", (ctx, trigger) => { return ctx.Content.Substring(trigger.Length).Trim(); } } + {"%target%", (ctx, trigger) => { return ctx.Content.Substring(trigger.Length).Trim().SanitizeMentions(); } } }; public static Dictionary> placeholders = new Dictionary>() diff --git a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs index 4bc2f2f5..4b05391d 100644 --- a/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Utility/Commands/MessageRepeater.cs @@ -89,7 +89,7 @@ namespace NadekoBot.Modules.Utility Channel = Guild.GetTextChannel(Repeater.ChannelId); if (Channel != null) - oldMsg = await Channel.SendMessageAsync(toSend).ConfigureAwait(false); + oldMsg = await Channel.SendMessageAsync(toSend.SanitizeMentions()).ConfigureAwait(false); } catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.Forbidden) { From 4a3bb0f57eb3dd9a278f98ae062d040dd9396e20 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 10 Apr 2017 03:02:46 +0200 Subject: [PATCH 721/746] sanitized mentions in quote commands --- src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs index b8819255..a11ad7c9 100644 --- a/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/QuoteCommands.cs @@ -34,7 +34,7 @@ namespace NadekoBot.Modules.Utility if (quotes.Any()) await Context.Channel.SendConfirmAsync(GetText("quotes_page", page + 1), - string.Join("\n", quotes.Select(q => $"`#{q.Id}` {Format.Bold(q.Keyword),-20} by {q.AuthorName}"))) + string.Join("\n", quotes.Select(q => $"`#{q.Id}` {Format.Bold(q.Keyword.SanitizeMentions()),-20} by {q.AuthorName.SanitizeMentions()}"))) .ConfigureAwait(false); else await ReplyErrorLocalized("quotes_page_none").ConfigureAwait(false); @@ -132,7 +132,7 @@ namespace NadekoBot.Modules.Utility return; } - else { await Context.Channel.SendMessageAsync($"`#{qfromid.Id}` 🗯️ " + qfromid.Keyword.ToLowerInvariant() + ": " + + else { await Context.Channel.SendMessageAsync($"`#{qfromid.Id}` 🗯️ " + qfromid.Keyword.ToLowerInvariant().SanitizeMentions() + ": " + qfromid.Text.SanitizeMentions()); } } } @@ -208,7 +208,7 @@ namespace NadekoBot.Modules.Utility await uow.CompleteAsync(); } - await ReplyConfirmLocalized("quotes_deleted", Format.Bold(keyword)).ConfigureAwait(false); + await ReplyConfirmLocalized("quotes_deleted", Format.Bold(keyword.SanitizeMentions())).ConfigureAwait(false); } } } From a3bd89460b72569e48aa04faf4388d8128b1f0c9 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 10 Apr 2017 03:14:52 +0200 Subject: [PATCH 722/746] ;fwmsgs should ocne again dm the first bot owner, not a random one --- src/NadekoBot/Services/CommandHandler.cs | 3 ++- src/NadekoBot/Services/IBotCredentials.cs | 2 +- src/NadekoBot/Services/Impl/BotCredentials.cs | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 06b447b1..0febdb9d 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -75,12 +75,13 @@ namespace NadekoBot.Services } }))) .Where(ch => ch != null) + .OrderBy(x => NadekoBot.Credentials.OwnerIds.IndexOf(x.Id)) .ToList(); if (!ownerChannels.Any()) _log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file."); else - _log.Info($"Created {ownerChannels.Count} out of {NadekoBot.Credentials.OwnerIds.Count} owner message channels."); + _log.Info($"Created {ownerChannels.Count} out of {NadekoBot.Credentials.OwnerIds.Length} owner message channels."); }); _client.MessageReceived += MessageReceivedHandler; diff --git a/src/NadekoBot/Services/IBotCredentials.cs b/src/NadekoBot/Services/IBotCredentials.cs index 63bea8b8..0a89b471 100644 --- a/src/NadekoBot/Services/IBotCredentials.cs +++ b/src/NadekoBot/Services/IBotCredentials.cs @@ -10,7 +10,7 @@ namespace NadekoBot.Services string Token { get; } string GoogleApiKey { get; } - ImmutableHashSet OwnerIds { get; } + ImmutableArray OwnerIds { get; } string MashapeKey { get; } string LoLApiKey { get; } string PatreonAccessToken { get; } diff --git a/src/NadekoBot/Services/Impl/BotCredentials.cs b/src/NadekoBot/Services/Impl/BotCredentials.cs index a0220778..27ea4090 100644 --- a/src/NadekoBot/Services/Impl/BotCredentials.cs +++ b/src/NadekoBot/Services/Impl/BotCredentials.cs @@ -21,7 +21,7 @@ namespace NadekoBot.Services.Impl public string Token { get; } - public ImmutableHashSet OwnerIds { get; } + public ImmutableArray OwnerIds { get; } public string LoLApiKey { get; } public string OsuApiKey { get; } @@ -62,7 +62,7 @@ namespace NadekoBot.Services.Impl Token = data[nameof(Token)]; if (string.IsNullOrWhiteSpace(Token)) throw new ArgumentNullException(nameof(Token), "Token is missing from credentials.json or Environment varibles."); - OwnerIds = data.GetSection("OwnerIds").GetChildren().Select(c => ulong.Parse(c.Value)).ToImmutableHashSet(); + OwnerIds = data.GetSection("OwnerIds").GetChildren().Select(c => ulong.Parse(c.Value)).ToImmutableArray(); LoLApiKey = data[nameof(LoLApiKey)]; GoogleApiKey = data[nameof(GoogleApiKey)]; MashapeKey = data[nameof(MashapeKey)]; From 06ca1c5f8f96ce2f2f18e200f4004600f32746d1 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 10 Apr 2017 19:56:10 +0200 Subject: [PATCH 723/746] You can now use actualcustomreactions as a module name to enable/disable actual custom reactions, as opposed to commands to manage them which are in CustomReactions module --- .../Games/Commands/PlantAndPickCommands.cs | 3 ++- .../Commands/GlobalPermissionCommands.cs | 2 +- .../Modules/Permissions/Permissions.cs | 8 +++---- src/NadekoBot/NadekoBot.cs | 1 + src/NadekoBot/TypeReaders/ModuleTypeReader.cs | 21 +++++++++++++++++++ 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 7c081289..44eb474a 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -181,7 +181,7 @@ namespace NadekoBot.Modules.Games return old; }); } - +#if !GLOBAL_NADEKO [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageMessages)] @@ -218,6 +218,7 @@ namespace NadekoBot.Modules.Games await ReplyConfirmLocalized("curgen_disabled").ConfigureAwait(false); } } +#endif private static KeyValuePair> GetRandomCurrencyImage() { diff --git a/src/NadekoBot/Modules/Permissions/Commands/GlobalPermissionCommands.cs b/src/NadekoBot/Modules/Permissions/Commands/GlobalPermissionCommands.cs index 41ba61b3..e493f03d 100644 --- a/src/NadekoBot/Modules/Permissions/Commands/GlobalPermissionCommands.cs +++ b/src/NadekoBot/Modules/Permissions/Commands/GlobalPermissionCommands.cs @@ -52,7 +52,7 @@ namespace NadekoBot.Modules.Permissions [NadekoCommand, Usage, Description, Aliases] [OwnerOnly] - public async Task Gmod(ModuleInfo module) + public async Task Gmod(ModuleOrCrInfo module) { var moduleName = module.Name.ToLowerInvariant(); if (BlockedModules.Add(moduleName)) diff --git a/src/NadekoBot/Modules/Permissions/Permissions.cs b/src/NadekoBot/Modules/Permissions/Permissions.cs index a942fd7e..e9f92c66 100644 --- a/src/NadekoBot/Modules/Permissions/Permissions.cs +++ b/src/NadekoBot/Modules/Permissions/Permissions.cs @@ -363,7 +363,7 @@ namespace NadekoBot.Modules.Permissions [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task SrvrMdl(ModuleInfo module, PermissionAction action) + public async Task SrvrMdl(ModuleOrCrInfo module, PermissionAction action) { await AddPermissions(Context.Guild.Id, new Permissionv2 { @@ -419,7 +419,7 @@ namespace NadekoBot.Modules.Permissions [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task UsrMdl(ModuleInfo module, PermissionAction action, [Remainder] IGuildUser user) + public async Task UsrMdl(ModuleOrCrInfo module, PermissionAction action, [Remainder] IGuildUser user) { await AddPermissions(Context.Guild.Id, new Permissionv2 { @@ -480,7 +480,7 @@ namespace NadekoBot.Modules.Permissions [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task RoleMdl(ModuleInfo module, PermissionAction action, [Remainder] IRole role) + public async Task RoleMdl(ModuleOrCrInfo module, PermissionAction action, [Remainder] IRole role) { if (role == role.Guild.EveryoneRole) return; @@ -542,7 +542,7 @@ namespace NadekoBot.Modules.Permissions [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - public async Task ChnlMdl(ModuleInfo module, PermissionAction action, [Remainder] ITextChannel chnl) + public async Task ChnlMdl(ModuleOrCrInfo module, PermissionAction action, [Remainder] ITextChannel chnl) { await AddPermissions(Context.Guild.Id, new Permissionv2 { diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 6673cacb..075c12e8 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -112,6 +112,7 @@ namespace NadekoBot CommandService.AddTypeReader(new CommandTypeReader()); CommandService.AddTypeReader(new CommandOrCrTypeReader()); CommandService.AddTypeReader(new ModuleTypeReader()); + CommandService.AddTypeReader(new ModuleOrCrTypeReader()); CommandService.AddTypeReader(new GuildTypeReader()); diff --git a/src/NadekoBot/TypeReaders/ModuleTypeReader.cs b/src/NadekoBot/TypeReaders/ModuleTypeReader.cs index ae93576e..10278060 100644 --- a/src/NadekoBot/TypeReaders/ModuleTypeReader.cs +++ b/src/NadekoBot/TypeReaders/ModuleTypeReader.cs @@ -17,4 +17,25 @@ namespace NadekoBot.TypeReaders return Task.FromResult(TypeReaderResult.FromSuccess(module)); } } + + public class ModuleOrCrTypeReader : TypeReader + { + public override Task Read(ICommandContext context, string input) + { + input = input.ToLowerInvariant(); + var module = NadekoBot.CommandService.Modules.GroupBy(m => m.GetTopLevelModule()).FirstOrDefault(m => m.Key.Name.ToLowerInvariant() == input)?.Key; + if (module == null && input != "actualcustomreactions") + return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such module found.")); + + return Task.FromResult(TypeReaderResult.FromSuccess(new ModuleOrCrInfo + { + Name = input, + })); + } + } + + public class ModuleOrCrInfo + { + public string Name { get; set; } + } } From ade2b69a86347097c84e4a96584618b2ace2f74f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 10 Apr 2017 20:02:18 +0200 Subject: [PATCH 724/746] help updated, commandlist regenerated --- src/NadekoBot/Resources/CommandStrings.Designer.cs | 2 +- src/NadekoBot/Resources/CommandStrings.resx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index c135ff21..ec6654e3 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -7980,7 +7980,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Play Nadeko slots. Max bet is 999. 3 seconds cooldown per user.. + /// Looks up a localized string similar to Play Nadeko slots. Max bet is 9999. 1.5 second cooldown per user.. /// public static string slot_desc { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 6c67e584..a46b89e8 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -2992,7 +2992,7 @@ slot - Play Nadeko slots. Max bet is 999. 3 seconds cooldown per user. + Play Nadeko slots. Max bet is 9999. 1.5 second cooldown per user. `{0}slot 5` From a0d93c93c2a475d52cedc3a788473df6f25d3ab0 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Mon, 10 Apr 2017 20:03:33 +0200 Subject: [PATCH 725/746] Version upped to 1.3a --- docs/Commands List.md | 4 ++-- src/NadekoBot/Services/Impl/StatsService.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index dc705b8e..6c47c7ed 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -100,7 +100,7 @@ Commands and aliases | Description | Usage `.bye` | Toggles anouncements on the current channel when someone leaves the server. **Requires ManageServer server permission.** | `.bye` `.byemsg` | Sets a new leave announcement message. Type `%user%` if you want to show the name the user who left. Type `%id%` to show id. Using this command with no message will show the current bye message. You can use embed json from instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.byemsg %user% has left.` `.byedel` | Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion. **Requires ManageServer server permission.** | `.byedel 0` or `.byedel 30` -`.warn` | Warns a user. **Requires BanMembers server permission.** | `.warn @b1nzy` +`.warn` | Warns a user. **Requires BanMembers server permission.** | `.warn @b1nzy Very rude person` `.warnlog` | See a list of warnings of a certain user. **Requires BanMembers server permission.** | `.warnlog @b1nzy` `.warnclear` `.warnc` | Clears all warnings from a certain user. **Requires BanMembers server permission.** | `.warnclear @PoorDude` `.warnpunish` `.warnp` | Sets a punishment for a certain number of warnings. Provide no punishment to remove. **Requires BanMembers server permission.** | `.warnpunish 5 Ban` or `.warnpunish 3` @@ -173,7 +173,7 @@ Commands and aliases | Description | Usage `$shoprem` `$shoprm` | Removes an item from the shop by its color. **Requires Administrator server permission.** | `$shoprm 1` `$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` +`$slot` | Play Nadeko slots. Max bet is 9999. 1.5 second cooldown per user. | `$slot 5` `$claimwaifu` `$claim` | Claim a waifu for yourself by spending currency. You must spend at least 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` diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index 570c44ff..b567a72b 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -16,7 +16,7 @@ namespace NadekoBot.Services.Impl private readonly DiscordShardedClient _client; private readonly DateTime _started; - public const string BotVersion = "1.3"; + public const string BotVersion = "1.3a"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From 763bfc08bcc036d8ee464d254ba9e4ce5376f008 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 11 Apr 2017 00:46:02 +0200 Subject: [PATCH 726/746] prune bugfixes --- src/NadekoBot/Modules/Administration/Administration.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 71f20464..0e175083 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -392,13 +392,18 @@ namespace NadekoBot.Modules.Administration [RequireContext(ContextType.Guild)] [RequireUserPermission(ChannelPermission.ManageMessages)] [RequireBotPermission(GuildPermission.ManageMessages)] + [Priority(0)] public async Task Prune(int count) { if (count < 1) return; await Context.Message.DeleteAsync().ConfigureAwait(false); - int limit = (count < 100) ? count : 100; + int limit = (count < 100) ? count + 1 : 100; var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten().ConfigureAwait(false)); + if (enumerable.FirstOrDefault()?.Id == Context.Message.Id) + enumerable = enumerable.Skip(1).ToArray(); + else + enumerable = enumerable.Take(count); await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false); } @@ -407,6 +412,7 @@ namespace NadekoBot.Modules.Administration [RequireContext(ContextType.Guild)] [RequireUserPermission(ChannelPermission.ManageMessages)] [RequireBotPermission(GuildPermission.ManageMessages)] + [Priority(1)] public async Task Prune(IGuildUser user, int count = 100) { if (count < 1) From daee24af237836d58f644f055beaeeef04c2a381 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:56:22 +0200 Subject: [PATCH 727/746] Update ResponseStrings.zh-CN.resx (POEditor.com) --- .../Resources/ResponseStrings.zh-CN.resx | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx b/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx index ae22319e..b120f601 100644 --- a/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx +++ b/src/NadekoBot/Resources/ResponseStrings.zh-CN.resx @@ -2385,128 +2385,128 @@ Fuzzy 竞争比赛游戏时间。 - + 频道 - + 指令 - + 已被踢出 PLURAL - + 群管 - + 第{0}页 - + 原因 - + 新启动执行命令已加 - + 启动执行命令已删 - + 启动执行命令未找到 - + 服务器 - + 该页并无启动执行命令 - + 清除所有启动执行命令 - + 用户 {0} 已被解禁 - + 该用户未找到 - + 用户{0}已被警告 - + 用户 {0} 已被警告,惩罚已执行。 - + 在 {0} 服务器上被警告 - + 在 {0} {1} 被 {2} - + {0} 的所有警告已清除。 - + 该页并无警告。 - + {0} 的警告记录。 - + 没有设定任何惩罚 - + 被{0} 清除 - + 警告惩罚记录 - + 拥有{0} 个警告已不会触动惩罚。 - + 我会给拥有 {1} 个警告的用户执行{0} 惩罚。 - + Slowmode 现在会无视 {0} 身份组。 - + Slowmode不会无视 {0} 身份组。 - + Slowmode 现在会无视用户 {0} 。 - + Slowmode 现在不会无视用户 {0} 。 - + 因下列原因无法领取奖励: - + 你可能已领取这个月的奖励。除非你的赞助金额增加,你只能领取奖励一个月一次。 - + 已被奖励 - + 你的discord账户可能未与Patreon连接。如果你并不明白或不知如何连接 - 你需要去 [Patreon account settings page] (https://patreon.com/settings/account) 然后点击'Connect to discord' 的按钮。 - + Discord账号没有连接 - + 你必须要在patreon赞助该项目才有资格领取奖励。你可以使用命令 {0} 取得网址。 - + 无法支援 - + 你需要在赞助了之后等几个小时。如果你没有,请稍后再试。 - + 稍等片刻 - + 您已领取 {0} 。感谢您支持该项目! - + 奖励只能在每月五号或五号后才能领取。 \ No newline at end of file From 2c30ad9bd94485e5d4874ee004bc4e9327f5bdfa Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:56:25 +0200 Subject: [PATCH 728/746] Update ResponseStrings.zh-TW.resx (POEditor.com) From 8a902ad212131fc1aa88cf025b6eb5b2ec016096 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:56:27 +0200 Subject: [PATCH 729/746] Update ResponseStrings.nl-NL.resx (POEditor.com) From b07d48400176f0815f7430ac1858ef1a1c7549d4 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:56:30 +0200 Subject: [PATCH 730/746] Update ResponseStrings.en-US.resx (POEditor.com) From a97ee7c0e90305dd1e983c25fee1fbb773add6d9 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:56:33 +0200 Subject: [PATCH 731/746] Update ResponseStrings.fr-FR.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.fr-FR.resx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx b/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx index c2ad5917..8e46bc14 100644 --- a/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.fr-FR.resx @@ -2323,7 +2323,7 @@ ID du propriétaire: {2} Raison - Nouvelle commande au démarrage ajoutée + Nouvelle commande au démarrage ajoutée. Commande au démarrage retirée. @@ -2350,7 +2350,7 @@ ID du propriétaire: {2} L'utilisateur {0} a été averti. - L'utilisateur {0} a été averti et {1} punition a été appliquée. + L'utilisateur {0} a été averti et la punition {1} a été appliquée. Averti sur le serveur {0} @@ -2359,13 +2359,14 @@ ID du propriétaire: {2} Le {0} à {1} par {2} - Toutes les avertissements ont étés effacés pour {0}. + Tous les avertissements ont été effacés pour {0}. Pas d'avertissement sur cette page. Log d'avertissement pour {0} + Log ou historique ? Pas de punition définie. @@ -2404,7 +2405,7 @@ ID du propriétaire: {2} Déjà récompensé. - Votre compte Discord n'est peut-être pas connecté à Patreon. Si vous n'êtes pas sur de ce que ça veut dire, ou ne savez pas comment le connecter, vous devez aller à la [Page de configurations du compte Patreon](https://patreon.com/settings/account) et cliquer sur 'Connect to discord'. + Votre compte Discord n'est peut-être pas connecté à Patreon. Si vous n'êtes pas sur de ce que ça veut dire, ou ne savez pas comment le connecter, vous devez aller à la [Page de configuration du compte Patreon](https://patreon.com/settings/account) et cliquer sur 'Connect to discord'. Le compte Discord n'est pas connecté From 836a91107a17e12bb7f87da95c8110d1ac76cbc5 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:56:36 +0200 Subject: [PATCH 732/746] Update ResponseStrings.de-DE.resx (POEditor.com) --- .../Resources/ResponseStrings.de-DE.resx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx index 81cde44a..6b6a53c3 100644 --- a/src/NadekoBot/Resources/ResponseStrings.de-DE.resx +++ b/src/NadekoBot/Resources/ResponseStrings.de-DE.resx @@ -2451,7 +2451,7 @@ ID des Besitzers: {2} Keine Warnungen auf dieser Seite. - + Warnlog für {0} Keine Bestrafungen gesetzt. @@ -2469,34 +2469,34 @@ ID des Besitzers: {2} Ich werde die Bestrafung {0} an Benutzern mit {1} Warnungen ausführen. - + Slow mode wird jetzt die Rolle {0} ignorieren. - + Slow mode wird nicht mehr die Rolle {0} ignorieren. - + Slow mod witrd jetzt den Benutzer {0} ignorieren. - + Slow mod witrd nicht mehr Benutzer {0} ignorieren. - + Belohnungen konnten nicht beansprucht werden wegen einer dieser Gründe: - + Eventuell haben Sie ihre Belohnung für diesen Monat schon bekommen. Sie können Belohnungen nur einmal pro Monat beanspruchen, außer sie erhören ihre Unterstützung. - + Belohnung schon beansprucht - + Ihr Discord Account ist eventuell nicht mit Patreon verbunden. Wenn Sie unsicher sind was dies bedeutet, oder nicht wissen wie man es verbinded - Sie müssen zu der [Patreon Account Einstellungs Seite](https://patreon.com/settings/account) gehen und den 'Zu Discord verbinden' Knopf betätigen. - + Discord Account nicht verbunden - + Um berechtigt für die Belohnung zu sein, müssen Sie das Projekt auf Patreon unterstützen. Sie können den Befehl {0} benutzen um den Link zu kriegen. Keine Unterstützung @@ -2506,13 +2506,13 @@ ID des Besitzers: {2} Fuzzy - + Bitte warten Sie eine weile - + Sie haben {0} erhalten. Danke für das unterstützen des Projektes! - + Belohnungen können am or nach dem fünften tag jedes Monats beansprucht werden. \ No newline at end of file From d970603317e7c8612d0a76dd3c5572e9d2551021 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:56:39 +0200 Subject: [PATCH 733/746] Update ResponseStrings.he-IL.resx (POEditor.com) From 95012a5e462b5051e25da693b4425ef775483f64 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:56:41 +0200 Subject: [PATCH 734/746] Update ResponseStrings.id-ID.resx (POEditor.com) From e87633b3dd811b76aa7dfd52bdc654e974d728c7 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:56:44 +0200 Subject: [PATCH 735/746] Update ResponseStrings.it-IT.resx (POEditor.com) --- .../Resources/ResponseStrings.it-IT.resx | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.it-IT.resx b/src/NadekoBot/Resources/ResponseStrings.it-IT.resx index 5247c7a6..b675d6a7 100644 --- a/src/NadekoBot/Resources/ResponseStrings.it-IT.resx +++ b/src/NadekoBot/Resources/ResponseStrings.it-IT.resx @@ -751,11 +751,9 @@ Fuzzy Modalità lenta disattivata - Fuzzy Modalità lenta attivata - Fuzzy Ammonizione (Espulso) @@ -883,7 +881,8 @@ Motivo : {1} Errore durante il trasferimento, guarda la console del bot per più informazioni. - + Aggiornamenti sulla presenza + Fuzzy Utente ammonito @@ -935,7 +934,7 @@ Motivo : {1} Classifica - + Premiati con {0} {1} utenti con il ruolo {2}. Non puoi puntare più di {0} @@ -1431,7 +1430,8 @@ Fuzzy Canzone iniziata - + `#{0}` - **{1}** da *{2}* ({3} canzoni) + Fuzzy Pagina {0} della playlist salvata @@ -1614,7 +1614,8 @@ Fuzzy Pagina dei comandi {0} - + Attualmente i permessi del ruolo sono {0}. + Fuzzy Gli utenti ora devono avere il ruolo di {0} per modificare i permessi. @@ -1716,7 +1717,6 @@ Fuzzy Rango competitivo - Fuzzy Competitive Vinte. @@ -1777,7 +1777,8 @@ Fuzzy Fallito a trovare questo film. - + Fonte o lingua non valida. + Fuzzy Scherzo non caricato. @@ -1965,9 +1966,10 @@ Fuzzy Entrato - + `{0}.` {1} [{2:F2}/s] - {3} totali /s and total need to be localized to fit the context - -`1.` +`1.` +Fuzzy Pagina attivitá #{0} @@ -2009,10 +2011,12 @@ Fuzzy Creato a - + Entrato nel canale tra server. + Fuzzy - + Uscito dal canale tra server. + Fuzzy Questo é il tuo token CSC @@ -2193,7 +2197,8 @@ ID del proprietario: {2} Fuzzy - + Il frammento **#{0}** é nello stato {1} con {2} server + Fuzzy **Nome:** {0} **Link:** {1} @@ -2407,19 +2412,15 @@ ID del proprietario: {2} La modalitá lenta ignorerá il ruolo {0}. - Fuzzy La modalitá lenta non ignorerá piú il ruolo {0}. - Fuzzy La modalitá lenta ignorerá l'utente {0}. - Fuzzy La modalitá lenta non ignorerá piú l'utente {0}. - Fuzzy Errore nella richiesta dei premi per le seguenti ragioni: @@ -2444,8 +2445,7 @@ ID del proprietario: {2} Fuzzy - Devi aspettae un po' di ore dopo aver fatto la tua donazione, se non lo hai fatto, prova di nuovo piú tardi - Fuzzy + Devi aspettare un po' di ore dopo aver donato, se non lo hai fatto, prova di nuovo piú tardi. Aspetta un po' di tempo From 5eb725bc288fe9c63ee0c540996765283cad8f99 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:56:47 +0200 Subject: [PATCH 736/746] Update ResponseStrings.ja-JP.resx (POEditor.com) From 295fb6f4c17700b8bf59f1bf32fb0071ef8c3b2a Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:56:49 +0200 Subject: [PATCH 737/746] Update ResponseStrings.ko-KR.resx (POEditor.com) --- .../Resources/ResponseStrings.ko-KR.resx | 587 ++++++++---------- 1 file changed, 245 insertions(+), 342 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.ko-KR.resx b/src/NadekoBot/Resources/ResponseStrings.ko-KR.resx index 239484e4..de5bb4e7 100644 --- a/src/NadekoBot/Resources/ResponseStrings.ko-KR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.ko-KR.resx @@ -127,25 +127,25 @@ 기지가 요청당하지 않았습니다. - {1} 와의 전쟁에서 #{0} 번 기지가 **파괴**되었습니다. + {1}와의 전쟁에서 #{0}번 기지가 **파괴**되었습니다. - {2} 와의 전쟁에서 {0} 가 #{1} 번 기지를 **요청**하지 못했습니다. + {2}와의 전쟁에서 {0}가 #{1}번 기지를 **요청**하지 못했습니다. - {2} 와의 전쟁에서 #{1} 번 기지를 {0} 가 요청하였습니다. + {2}와의 전쟁에서 #{1}번 기지를 {0}가 요청하였습니다. - @{0} 이미 #{1} 번 기지를 요청했습니다. 새로운 기지를 요청 할 수 없습니다. + @{0} 이미 #{1}번 기지를 요청했습니다. 새로운 기지를 요청 할 수 없습니다. - {1} 와의 전쟁에서 @{0} 의 요청이 만료되었습니다. + {1}와의 전쟁에서 @{0}의 요청이 만료되었습니다. - {0} 와의 전쟁에 대한 정보 + {0}와의 전쟁에 대한 정보 유효하지 않은 기지 숫자입니다. @@ -172,13 +172,13 @@ 크기 - {0} 에 대한 전쟁이 이미 시작되었습니다. + {0}에 대한 전쟁이 이미 시작되었습니다. - {0} 에 대한 전쟁이 생성되었습니다. + {0}에 대한 전쟁이 생성되었습니다. - {0} 와의 전쟁이 종료되었습니다. + {0}와의 전쟁이 종료되었습니다. 전쟁이 존재하지않습니다. @@ -212,20 +212,18 @@ 반응 - Fuzzy 커스텀 리액션 통계 - {0} 에 대한 커스텀 리액션 통계가 삭제되었습니다. + {0}에 대한 커스텀 리액션 통계가 삭제되었습니다. 해당 트리거에 대한 통계를 찾지 못했으며, 아무런 행동도 취하지 않았습니다. 트리거 - Fuzzy Autohentai 기능이 정지되었습니다. @@ -234,16 +232,16 @@ 결과를 찾지 못했습니다. - {0} 이(가) 이미 기절했습니다. + {0}이(가) 이미 기절했습니다. - {0} 은(는) 이미 최대 체력입니다. + {0}은(는) 이미 최대 체력입니다. 당신은 이미 {0} 타입 입니다. - 님이 {2}{3} 에게 {0}{1} 을(를) 사용하여서 {4} 의 피해를 입혔습니다. + 님이 {2}{3}에게 {0}{1}을(를) 사용하여서 {4}의 피해를 입혔습니다. Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. @@ -253,35 +251,34 @@ 자신을 공격 할 수 없습니다. - {0} 이(가) 기절했습니다! + {0}이(가) 기절했습니다! - {1} 을(를) 사용하여서 {0} 을(를) 치료했습니다. + {1}을(를) 사용하여서 {0}을(를) 치료했습니다. - {0} 의 HP가 {1} 남아 있습니다. + {0}의 HP가 {1} 남아 있습니다. - {0} 을(를) 사용 할 수 없습니다. `{1}ml` 을(를) 입력해서 사용할 수 있는 움직임들의 리스트를 확인하세요. + {0}을(를) 사용 할 수 없습니다. `{1}ml`을(를) 입력해서 사용할 수 있는 움직임들의 리스트를 확인하세요. - {0} 종류 의 공격표 - Fuzzy + {0}의 종류 공격표 효과적이지 않았다. - 당신은 충분한 {0} 가 없습니다. + 당신은 충분한 {0}가 없습니다. - {1} 을(를) 사용하여서 {0} 을(를) 소생했습니다. + {1}을(를) 사용하여서 {0}을(를) 소생했습니다. - {0} 을(를) 사용해서 자기자신을 소생시켰습니다. + {0}을(를) 사용해서 자기자신을 소생시켰습니다. - 당신의 타입이 {0} 에서 {1} 으로 변경되었습니다. + 당신의 타입이 {0}에서 {1}으로 변경되었습니다. 어느정도 효과가 있었다. @@ -293,7 +290,7 @@ 너무 많은 공격을 연속해서 사용했으므로 이동할 수 없습니다! - {0} 의 종류는 {1} 입니다. + {0}의 종류는 {1}입니다. 사용자를 찾을 수 없습니다. @@ -319,38 +316,31 @@ - PLURAL -Fuzzy + PLURAL 사용자 밴 - Fuzzy - 봇의 이름이 {0} 으로 변경되었습니다. + 봇의 이름이 {0}으로 변경되었습니다. - 봇의 상태가 {0} 으로 변경되었습니다. + 봇의 상태가 {0}으로 변경되었습니다. 퇴장 메시지의 자동삭제가 비활성화되었습니다. - Fuzzy - 퇴장 메시지는 앞으로 {0} 초 후에 삭제됩니다. - Fuzzy + 퇴장 메시지는 앞으로 {0}초 후에 삭제됩니다. 현재 퇴장 메시지: {0} - Fuzzy - 퇴장 메시지를 활성화하기 위해서는 {0} 를 입력하십시오. - Fuzzy + 퇴장 메시지를 활성화하기 위해서는 {0}를 입력하세요. 새로운 퇴장 메시지가 설정되었습니다. - Fuzzy 퇴장 알림이 비활성화되었습니다. @@ -377,10 +367,10 @@ Fuzzy {0} 역할을 성공적으로 생성하였습니다. - 텍스트 채널 {0} 이(가) 생성되었습니다. + 텍스트 채널 {0}이(가) 생성되었습니다. - 음성 채널 {0} 이(가) 생성되었습니다. + 음성 채널 {0}이(가) 생성되었습니다. 음소거되었습니다. @@ -396,14 +386,13 @@ Fuzzy 이제 성공적으로 처리된 명령어를 자동삭제합니다. - 텍스트 채널 {0} 를 삭제했습니다. + 텍스트 채널 {0}을(를) 삭제했습니다. - 음성 채널 {0} 를 삭제했습니다. + 음성 채널 {0}을(를) 삭제했습니다. 개인 메시지 - Fuzzy 성공적으로 새로운 기부자를 추가했습니다. 이 유저의 총 기부량은 {0} 👑 입니다. @@ -427,13 +416,13 @@ Fuzzy 환영 메시지에 대한 자동삭제가 비활성화되었습니다. - 환영 메시지는 {0} 초 후에 삭제될 것입니다. + 환영 메시지는 {0}초 후에 삭제될 것입니다. 현재 DM 환영 메시지: {0} - {0} 을(를) 입력하여서 DM 환영 메시지를 활성화시킵니다. + {0}을(를) 입력해서 DM 환영 메시지를 활성화시킵니다. 새로운 DM 환영 메시지가 설정되었습니다. @@ -449,7 +438,7 @@ Fuzzy 현재 환영 메시지: {0} - {0} 를 입력하여서 환영 메시지를 활성화시킵니다. + {0}을(를) 입력해서 환영 메시지를 활성화시킵니다. 새로운 환영 메시지가 설정되었습니다. @@ -464,8 +453,7 @@ Fuzzy 당신은 이 명령어를 당신보다 상위나 동등한 권한관계를 가진 사람에게 쓸 수 없습니다. - 이미지가 {0} 초 후에 생성되었습니다! - Fuzzy + 이미지가 {0}초 후에 생성되었습니다! 유효하지않은 입력 포맷입니다. @@ -474,7 +462,7 @@ Fuzzy 유효하지않은 파라미터입니다. - {0} 님이 {1} 에 입장하였습니다. + {0}님이 {1}에 입장하였습니다. 당신은 {0} 서버에서 퇴장당했습니다. @@ -482,28 +470,27 @@ Fuzzy 사용자 강제퇴장 - Fuzzy 언어 목록 - 서버의 지역이 {0} - {1} 로 변경되었습니다. + 서버의 지역이 {0} - {1}로 변경되었습니다. - 봇의 기본 지역이 {0} - {1} 로 변경되었습니다. + 봇의 기본 지역이 {0} - {1}로 변경되었습니다. - 봇의 언어가 {0} - {1} 로 설정되었습니다. + 봇의 언어가 {0} - {1}로 설정되었습니다. - 지역 설정에 실패했습니다. 이 명령어의 도움말을 참고하십시오. + 지역 설정에 실패했습니다. 이 명령어의 도움말을 참고하십세요. - 이 서버의 언어가 {0} - {1} 로 변경되었습니다. + 이 서버의 언어가 {0} - {1}로 변경되었습니다. - {0} 님이 {1} 에서 퇴장하셨습니다. + {0}님이 {1}에서 퇴장하셨습니다. {0} 서버에서 퇴장하였습니다. @@ -521,42 +508,39 @@ Fuzzy 구독 할 수 있는 로그 이벤트 : - 로그는 앞으로 {0} 을(를) 무시합니다. + 로그는 앞으로 {0}을(를) 무시합니다. - 로그는 {0} 을(를) 더 이상 무시하지 않습니다. + 로그는 {0}을(를) 더 이상 무시하지 않습니다. {0} 이벤트에 대한 로그를 중지하였습니다. - {0} 이(가) 다음 역할에 대한 언급을 요청했습니다. + {0}이(가) 다음 역할에 대한 언급을 요청했습니다. {0} `[봇의 소유자]` 로부터 메시지: - Fuzzy 메시지가 전송되었습니다. - {0} 이(가) {1} 에서 {2} 로 이동했습니다. + {0}이(가) {1}에서 {2}로 이동했습니다. - #{0} 에서 메시지가 삭제되었습니다. + #{0}에서 메시지가 삭제되었습니다. - #{0} 에서 메시지가 업데이트되었습니다. + #{0}에서 메시지가 업데이트되었습니다. 음소거 - PLURAL (users have been muted) -Fuzzy + PLURAL (users have been muted) 음소거 - singular "User muted." -Fuzzy + singular "User muted." 명령어를 수행하기 위한 권한이 부족합니다. @@ -604,10 +588,10 @@ Fuzzy 보호기능 활성화 - {0} 은(는) 이 서버에서 **비활성화**되었습니다. + {0}은(는) 이 서버에서 **비활성화**되었습니다. - {0} 가 활성화되었습니다. + {0}이(가) 활성화되었습니다. 오류. 관리자 권한이 필요합니다. @@ -616,18 +600,16 @@ Fuzzy 활성화된 보호기능이 없습니다. - 사용자의 값은 반드시 {0} 과 {1} 사이의 값이여야 합니다. - Fuzzy + 사용자의 값은 반드시 {0}와(과) {1}사이의 값이여야 합니다. - 만약 {0} 명 이상의 사용자가 {1} 초안에 접속한다면 {2} 합니다. - Fuzzy + 만약 {0}명 이상의 사용자가 {1}초안에 접속한다면 {2} 합니다. - 시간은 {0} 초와 {1} 초 사이의 값이여야 합니다. + 시간은 {0}초와 {1}초 사이의 값이여야 합니다. - {0} 유저의 모든 역할을 성공적으로 삭제했습니다. + {0}의 모든 역할을 성공적으로 삭제했습니다. 역할 삭제에 실패했습니다. 권한이 부족합니다. @@ -642,11 +624,10 @@ Fuzzy 지정된 파라미터가 유효하지 않습니다. - 유효하지 않은 색이거나 권한이 부족하여서 오류가 발생했습니다. - Fuzzy + 유효하지 않은 색이거나 권한이 부족해서 오류가 발생했습니다. - {1} 사용자에 대한 {0} 역할을 성공적으로 제거했습니다. + {1}의 {0} 역할을 성공적으로 제거했습니다. 역할 제거에 실패했습니다. 권한이 부족합니다. @@ -662,14 +643,12 @@ Fuzzy 다루고있었던 메시지를 치웠습니다: {0} - Fuzzy {0} 역할을 리스트에 추가했습니다. - {0} 을(를) 찾을 수 없기때문에 삭제했습니다. - Fuzzy + {0}을(를) 찾을 수 없기때문에 삭제했습니다. {0} 역할은 이미 리스트에 추가된 상태입니다. @@ -694,16 +673,13 @@ Fuzzy 당신은 이미 {0} 역할이 있습니다. - 당신은 이미 독점 자가 배정 역할 {0} 가 있습니다. - Fuzzy + 당신은 이미 독점 자가 배정 역할 {0}이(가) 있습니다. 자가 배정 역할은 이제 하나만 선택 할 수 있습니다! - Fuzzy - {0} 개의 자가 배정 역할이 있습니다. - Fuzzy + {0}개의 자가 배정 역할이 있습니다. 그 역할은 자신이 적용 할 수 없습니다. @@ -713,13 +689,12 @@ Fuzzy 자가 배정 역할은 이제 복수 선택 할 수 있습니다! - Fuzzy 그 역할을 당신에게 추가 할 수 없습니다. `당신보다 상위나 동등한 권한관계를 가진 사람에게 역할을 추가 할 수 없습니다.` - {0} 은(는) 자신이 적용 할 수 있는 역할 목록에서 삭제되었습니다. + {0}은(는) 자신이 적용 할 수 있는 역할 목록에서 삭제되었습니다. 당신은 더 이상 {0} 역할이 아닙니다. @@ -728,7 +703,7 @@ Fuzzy 당신은 이제 {0} 역할입니다. - {1} 유저에게 {0} 역할을 성공적으로 추가했습니다. + {1}님에게 {0} 역할을 성공적으로 추가했습니다. 역할 추가에 실패했습니다. 권한이 부족합니다. @@ -747,19 +722,18 @@ Fuzzy 새로운 채널 주제를 설정했습니다. - Fuzzy - Shard {0} 가 다시 연결되었습니다. + Shard {0}이(가) 다시 연결되었습니다. - Shard {0} 를 다시 연결 중입니다. + Shard {0}을(를) 다시 연결 중입니다. 종료 중... - 사용자는 {1} 초마다 {0} 개 이상의 메시지를 보낼 수 없습니다. + 사용자는 {1}초마다 {0}개 이상의 메시지를 보낼 수 없습니다. 슬로우 모드가 비활성화되었습니다. @@ -769,17 +743,16 @@ Fuzzy 소프트 밴 (강제퇴장) - PLURAL -Fuzzy + PLURAL - {0} 은(는) 이 채널을 무시할 것입니다. + {0}은(는) 이 채널을 무시할 것입니다. - {0} 은(는) 더 이상 이 채널을 무시하지 않을 것입니다. + {0}은(는) 더 이상 이 채널을 무시하지 않을 것입니다. - 만약 사용자가 {0} 개 이상의 같은 메시지를 보내면 {1} 합니다. + 만약 사용자가 {0}개 이상의 같은 메시지를 보내면 {1} 합니다. __무시하는 채널들__: {2} @@ -805,17 +778,15 @@ Fuzzy 사용자 - Fuzzy 사용자 밴 - Fuzzy - {0} 님이 채팅으로부터 **음소거**되었습니다. + {0}님이 채팅으로부터 **음소거**되었습니다. - {0} 님이 채팅으로부터 **음소거 해제**되었습니다. + {0}님이 채팅으로부터 **음소거 해제**되었습니다. 사용자 입장 @@ -824,36 +795,34 @@ Fuzzy 사용자 퇴장 - {0} 은(는) 텍스트와 음성 채팅으로부터 **차단**되었습니다. + {0}님이 텍스트와 음성 채팅으로부터 **차단**되었습니다. 사용자의 역할이 추가되었습니다. - Fuzzy 사용자의 역할이 제거되었습니다. - Fuzzy - {0} 님은 상태는 {1} 입니다. + {0}님의 상태는 {1} 입니다. - {0} 은(는) 텍스트와 음성 채팅으로부터 **차단해제**되었습니다. + {0}님이 텍스트와 음성 채팅으로부터 **차단해제**되었습니다. - {0} 님이 음성채널 {1} 에 입장하셨습니다. + {0}님이 음성채널 {1}에 입장하셨습니다. - {0} 님이 음성채널 {1} 에서 퇴장하셨습니다. + {0}님이 음성채널 {1}에서 퇴장하셨습니다. - {0}님이 음성채널 {1} 에서 {2} 로 이동되었습니다. + {0}님이 음성채널 {1}에서 {2}로 이동되었습니다. - {0} 님이 **음성 음소거**되었습니다. + {0}님이 **음성 음소거**되었습니다. - {0} 님이 **음성 음소거 해제**되었습니다. + {0}님이 **음성 음소거 해제**되었습니다. 음성 채널이 생성되었습니다. @@ -871,36 +840,32 @@ Fuzzy **관리 역할** 혹은 **채널 관리 권한**이 부족해서 {0} 서버에서 `음성 + 텍스트` 기능을 실행 할 수 없습니다. - 당신은 **봇이 관리자 권한이 없음에도** 이 기능을 활성화/비활성화 하고 있습니다. 이로 인해서 문제가 발생 할 수 있으며 이후에 직접 텍스트 채널을 정리해야합니다. + 당신은 **봇이 관리자 권한이 없음에도** 이 기능을 활성화/비활성화 하려고 하고 있습니다. 이로 인해서 문제가 발생 할 수 있으며 이후에 직접 텍스트 채널을 정리해야합니다. 이 기능을 활성화시키기 위해서는 **역할 관리**과 **채널 관리** 권한이 필요합니다. - Fuzzy - 사용자가 텍스트 채팅으로부터 {0} 됐습니다. + 사용자가 텍스트 채팅으로부터 {0} 되었습니다. - 사용자가 텍스트와 음성 채팅으로부터 {0} 됐습니다. + 사용자가 텍스트와 음성 채팅으로부터 {0} 되었습니다. - 사용자가 음성 채팅으로부터 {0} 됐습니다. + 사용자가 음성 채팅으로부터 {0} 되었습니다. - 당신은 {0} 서버에서 soft-밴을 당했습니다. + 당신은 {0} 서버에서 소프트밴을 당했습니다. 사유: {1} - Fuzzy 사용자 밴 해제 - Fuzzy 이전 완료! - Fuzzy - 이전 과정에서 오류가 발생했습니다. 자세한 정보는 봇의 콘솔을 통해서 확인하십시오. + 이전 과정에서 오류가 발생했습니다. 자세한 정보는 봇의 콘솔을 통해서 확인하세요. 현재 상태 업데이트 @@ -909,67 +874,61 @@ Fuzzy 사용자 소프트 밴 - 님이 {1} 에게 {0} 개를 지급했습니다. + 님이 {1}에게 {0}개를 지급했습니다. 다음 기회에 ^_^ - 축하합니다! 당신은 {1} 이상을 굴려서 {0} 을 획득했습니다. - Fuzzy + 축하합니다! 당신은 {1}이상을 굴려서 {0}을(를) 획득했습니다. 덱이 섞였습니다. - Fuzzy - 동전뒤집기의 결과는 {0}. - User flipped tails. -Fuzzy + 동전뒤집기의 결과는 {0} 입니다. + User flipped tails. - 맞췄습니다! 당신은 {0} 을(를) 획득했습니다. + 맞췄습니다! 당신은 {0}을(를) 획득했습니다. - 유효하지 않은 숫자입니다. 당신은 1개부터 {0} 개까지만 동전을 뒤집을 수 있습니다. - Fuzzy + 유효하지 않은 숫자입니다. 당신은 1개부터 {0}개까지만 동전을 뒤집을 수 있습니다. - {1} 을(를) 받으려면 이 메시지에 {0} 리액션을 추가하세요. - Fuzzy + {1}을(를) 받으려면 이 메시지에 {0} 리액션을 추가하세요. - 이 이벤트는 최대 {0} 시간 동안 활성화됩니다. + 이 이벤트는 최대 {0}시간 동안 활성화됩니다. 플라워 리액션 이벤트가 시작되었습니다. - 님이 {1} 에게 {0} 개를 선물하셨습니다. + 님이 {1}에게 {0}개를 선물하셨습니다. X has gifted 15 flowers to Y - {0} 님은 {1} 개를 보유중입니다. + {0}님은 {1}개를 보유중입니다. X has Y flowers - + 앞면 리더보드 - {2} 역할의 {1} 명의 사용자에게 {0} 를 보상하였습니다. - Fuzzy + {2} 역할의 {1}명의 사용자에게 {0}을(를) 보상하였습니다. - {0} 보다 더 배팅 할 수 없습니다. + {0}보다 더 배팅 할 수 없습니다. - {0} 보다 적게 배팅 할 수 없습니다. + {0}보다 적게 배팅 할 수 없습니다. - 당신은 충분한 {0} 이(가) 없습니다. + 당신은 충분한 {0}이(가) 없습니다. 덱에 더 이상 카드가 없습니다. @@ -983,47 +942,42 @@ Fuzzy 배팅 - Fuzzy 대박!!! 축하합니다!!! x{0} - 한 {0}, x{1} - Fuzzy + {0} 한 개를 맞추셨네요! x{1} - 와! 운이 좋습니다! 같은 종류의 세개! x{0} - Fuzzy + 와! 운이 좋습니다! 트리플입니다! x{0} - 잘 했습니다! {0} 두게 - x{1} + 잘했습니다! {0} 두 개를 맞추셨습니다! - x{1} Fuzzy 얻은 액수 - Fuzzy - 사용자는 반드시 {0} 를 얻기 위해서 비밀 코드를 입력해야합니다. + 사용자는 {0}을(를) 얻기 위해서 비밀 코드를 입력해야합니다. +{1}초 동안 유효합니다. 아무에게도 알려주지 마세요. - SneakyGame 이벤트가 종료되었습니다. {0} 명의 사용자들이 보상을 받았습니다. + SneakyGame 이벤트가 종료되었습니다. {0}명의 사용자들이 보상을 받았습니다. SneakyGameStatus 이벤트가 시작되었습니다. - Fuzzy 뒷면 - {1} 에게서 {0} 을(를) 성공적으로 빼앗았습니다 + {1}에게서 {0}을(를) 성공적으로 빼앗았습니다. - {1} 님이 {2} 만큼을 가지고있지 않기 때문에 {0} 을(를) 회수 할 수 없습니다. - Fuzzy + {1}님이 {2}만큼을 가지고있지 않기 때문에 {0}을(를) 회수 할 수 없습니다. 목차로 돌아가기 @@ -1036,11 +990,9 @@ Fuzzy Patreon( <0> )이나 Paypal( <1> )을 통해서 프로젝트를 후원 할 수 있습니다. - Fuzzy 명령어와 가명 - Fuzzy 명령어 목록이 재생성되었습니다. @@ -1050,17 +1002,16 @@ Fuzzy 예시 : `{0}h >8ball` - 입력하신 명령어를 찾을 수 없습니다. 입력하시기 전에 유효한 명령어인지 확인해주십시오. + 입력하신 명령어를 찾을 수 없습니다. 입력하시기 전에 유효한 명령어인지 확인해주세요. 설명 - Fuzzy - Patreon <{0}> 이나 -Paypal <{1}> 에서 + Patreon <{0}>이나 +Paypal <{1}>에서 NadekoBot 프로젝트를 지원할 수 있습니다. -Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시오. +Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마세요. **감사합니다** ♥️ @@ -1082,68 +1033,56 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 그 모듈은 존재하지 않습니다. - {0} 서버의 권한이 필요합니다. + 서버의 {0} 권한이 필요합니다. 목차 사용법 - Fuzzy - Autohentai 기능이 활성화되었습니다. 다음의 태그와 함께 {0} 초마다 사진이 올라옵니다. -태그 : -{1} - Fuzzy + Autohentai 기능이 활성화되었습니다. 다음의 태그와 함께 {0}초마다 사진이 올라옵니다. +태그 : {1} 태그 - Fuzzy - 동물 경주 - Fuzzy + 동물 레이스 참가자가 충분히 없어서 시작하지 못했습니다. 참가자가 모두 모였습니다! 즉시 시작하겠습니다. - Fuzzy - {0} 이(가) {1} (으)로 참가했습니다. - Fuzzy + {0}이(가) {1}(으)로 참가했습니다. - {0} 님이 {1} 으로써 참가하였고, {2} 을(를) 걸었습니다! - Fuzzy + {0}님이 {1}(으)로 참가하였고, {2}을(를) 걸었습니다! - {0}jr 를 입력해서 레이스에 참가합니다. + {0}jr을 입력해서 레이스에 참가합니다. 20초 동안 기다리거나, 방이 가득 차면 시작됩니다. - Fuzzy - {0} 명의 참가자와 함께 시작합니다. + {0}명의 참가자와 함께 시작합니다. - {0} 이(가) {1} (으)로 레이스를 이겼습니다! - Fuzzy + {0}이(가) {1}(으)로 레이스를 이겼습니다! - {0} 이(가) {1} (으)로 레이스를 이겼고 {2} 을 획득했습니다! - Fuzzy + {0}이(가) {1}(으)로 레이스를 이겼고 {2}을(를) 획득했습니다! - 유효하지 않은 숫자입니다. 한번에 {0}-{1} 의 주사위를 던질 수 있습니다. - Fuzzy + 유효하지 않은 숫자입니다. 한번에 {0}-{1}개의 주사위를 던질 수 있습니다. - 님이 {0} 를 굴렸습니다. + 님이 {0}을(를) 굴렸습니다. Someone rolled 35 @@ -1152,51 +1091,45 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 레이스 시작에 실패했습니다. 다른 레이스가 진행중입니다. - Fuzzy 이 서버에 레이스가 존재하지 않습니다. 두번째 숫자는 첫번째 숫자보다 큰 숫자여야 합니다. - Fuzzy 마음의 변화 - Fuzzy 요구한 사람 - Fuzzy 이혼 좋아하는 사람 - Fuzzy - 아무 와이프도 클레임되지 않았습니다. - Fuzzy + 아무 와이프도 요청되지 않았습니다. 최고의 와이프 - 당신의 친밀감이 이미 그 와이프로 설정 했거나 당신에게 친밀감이 없는 상태의 와이프에게 친밀감 삭제를 시도했습니다. + 당신의 친밀감이 이미 그 와이프로 설정 되었거나 당신에게 친밀감이 없는 상태의 와이프에게 친밀감 삭제를 시도했습니다. - 친밀감이 {0} 에서 {1} 으로 변경되었습니다. + 친밀감이 {0}에서 {1}(으)로 변경되었습니다. *도덕성이 의심스럽습니다.*🤔 Make sure to get the formatting right, and leave the thinking emoji - 친밀감을 다시 바꾸기 위해서는 {0} 시간 {1} 분을 기다려야합니다. + 친밀감을 다시 바꾸기 위해서는 {0}시간 {1}분을 기다려야합니다. 당신의 친밀감은 초기화되었습니다. 당신이 좋아하는 사람은 더 이상 없습니다. @@ -1205,17 +1138,17 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 님이 {0}의 와이프가 되고싶어합니다. - 님이 {1} 에 {0} 님을 와이프로 요구했습니다. + 님이 {1}에 {0}님을 와이프로 요구했습니다. - 당신을 좋아하는 와이프와 이혼했습니다. {0} 님이 보상금으로 {1} 만큼을 받았습니다. + 당신을 좋아하는 와이프와 이혼했습니다. {0}님이 보상금으로 {1}을(를) 받았습니다. 자기 자신에게 친밀감을 설정 할 수 없습니다. 🎉 그들의 사랑이 성취되었습니다! 🎉 -{0} 의 새로운 가치는 {1} 입니다! +{0}의 새로운 가치는 {1} 입니다! 그렇게 싼 와이프는 없습니다. 와이프를 얻기 위해서는 실제 가치보다 낮더라도 {0} 만큼을 지불해야합니다. @@ -1228,11 +1161,9 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 자기자신을 클레임 할 수 없습니다. - Fuzzy 당신은 최근에 이혼하셨습니다. 다시 이혼하려면 {0} 시간 {1} 분을 기다려야 합니다. - Fuzzy 아무도 없음 @@ -1241,12 +1172,10 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 당신을 좋아하지 않는 와이프와 이혼했습니다. 당신은 {0}을 돌려받았습니다. - 8ball - Fuzzy + 아크로포비아 - Fuzzy 아무런 제출 없이 게임이 끝났습니다. @@ -1261,36 +1190,35 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 아크로포비아 게임이 이미 이 채널에서 진행 중입니다. - 게임이 시작되었습니다. {0} 머리글자를 사용해서 문장 만드십시오. - Fuzzy + 게임이 시작되었습니다. {0} 머리글자를 사용해서 문장 만드세요. - 제출까지 {0} 초 남았습니다. + 제출까지 {0}초 남았습니다. - {0} 가 그의 문장을 입력했습니다. (합계: {1}) + {0}이(가) 그의 문장을 입력했습니다. (합계: {1}) - 제출번호를 입력해서 투표를 하십시오. + 제출하고자 하는 번호를 입력해서 투표를 하세요. - {0} 가 투표했습니다! + {0}이(가) 투표했습니다! - 우승자는 {1} 포인트를 가진 {0} 입니다. + 우승자는 {1}포인트를 가진 {0} 입니다. - {0} 님이 서버에서 유일한 제출자이기 때문에 승리했습니다. + {0}님이 서버에서 유일한 제출자이기 때문에 승리했습니다. - 문제 + 질문 - 비겼습니다! 둘다 {0} 을(를) 선택했습니다. + 비겼습니다! 둘다 {0}을(를) 선택했습니다. - {0} 가 승리했습니다! {1} 은(는) {2} 을(를) 이겼습니다. + {0}이(가) 승리했습니다! {1}은(는) {2}을(를) 이겼습니다. 제출이 마감되었습니다. @@ -1317,12 +1245,11 @@ Discord 닉네임이나 ID를 메시지에 남겨 두는 것을 잊지 마십시 이 채널에서 통화 생성이 활성화되었습니다. - {0} 무작위 {1} 가 등장했습니다! - plural -Fuzzy + {0} 무작위 {1}이(가) 등장했습니다! + plural - 무작위 {0} 가 등장했습니다! + 무작위 {0}이(가) 등장했습니다! 질문 로딩에 실패하였습니다. @@ -1344,20 +1271,19 @@ Fuzzy 리더 보드 - Fuzzy - 당신은 충분한 {0} 이(가) 없습니다. + 당신은 충분한 {0}이(가) 없습니다. 결과가 없습니다. - 이(가) {0} 을(를) 뽑았습니다. + 이(가) {0}을(를) 뽑았습니다. Kwoth picked 5* - {0} 이(가) {1} 을(를) 설치했습니다. + {0}이(가) {1}을(를) 심었습니다. Kwoth planted 5* @@ -1367,24 +1293,22 @@ Fuzzy 트리비아 게임 - {0} 님이 맞췄습니다! 답은 {1} 입니다. + {0}님이 맞췄습니다! 답은 {1} 입니다. 이 서버에서 진행중인 트리비아 게임이 없습니다. - {0} 이(가) {1} 포인트를 갖고있습니다. + {0}이(가) {1}포인트를 갖고있습니다. 이 질문 후에 중지합니다. 시간초과! 정확한 답은 {0} 입니다. - Fuzzy - {0} 님이 맞춰서 게임을 이겼습니다! 답은 {1} 입니다. - Fuzzy + {0}님이 맞춰서 게임을 이겼습니다! 답은 {1} 입니다. 당신을 상대로 플레이 할 수 없습니다. @@ -1399,7 +1323,7 @@ Fuzzy 님이 TicTacToe 게임을 생성하였습니다. - {0} 님이 이겼습니다! + {0}님이 이겼습니다! 3개 일치 @@ -1418,7 +1342,7 @@ Fuzzy {0} 대 {1} - {0} 개의 곡을 대기열에 추가하는 중... + {0}개의 곡을 대기열에 추가하는 중... 자동재생이 비활성화되었습니다. @@ -1431,7 +1355,6 @@ Fuzzy 디렉토리 대기열 추가가 완료되었습니다. - Fuzzy 페어플레이 @@ -1458,13 +1381,13 @@ Fuzzy 이제 최대 재생시간에 제한이 없습니다. - 최대 재생시간이 {0} 초로 설정되었습니다. + 최대 재생시간이 {0}초로 설정되었습니다. 이제 음악 대기열 크기는 제한이 없습니다. - 음악 대기열 크기가 {0} 곡으로 변경되었습니다. + 음악 대기열 크기가 {0}곡으로 변경되었습니다. 당신은 이 서버의 음성채널에 있어야 합니다. @@ -1491,10 +1414,10 @@ Fuzzy 노래 재생 중 - `#{0}` - {2} 님의 재생목록 **{1}** ({3} 곡) + `#{0}` - {2}님의 재생목록 **{1}** ({3} 곡) - 저장된 재생목록의 {0} 번째 페이지 + 저장된 재생목록의 {0}번째 페이지 재생목록이 삭제되었습니다. @@ -1512,7 +1435,7 @@ Fuzzy 재생목록이 저장되었습니다. - {0} 초 한계 + {0}초 한계 대기열 @@ -1524,7 +1447,7 @@ Fuzzy 음악 대기열이 초기화되었습니다. - 대기열이 {0}/{0} 으(로) 가득찼습니다. + 대기열이 {0}/{0}으(로) 가득찼습니다. 곡 삭제됨 @@ -1556,7 +1479,6 @@ Fuzzy `{0}:{1}`로 이동하였습니다. - Fuzzy 곡을 섞었습니다. @@ -1569,7 +1491,6 @@ Fuzzy 바뀐 위치 - Fuzzy 무제한 @@ -1588,7 +1509,6 @@ Fuzzy 허락함 - Fuzzy {0} 역할에게 모든 모듈의 사용을 비활성화했습니다. @@ -1612,10 +1532,10 @@ Fuzzy {0} (ID {1})님을 블랙리스트했습니다 - 명령어 {0} 은(는) 이제 {1}초 재사용 대기시간이 있습니다. + 명령어 {0}은(는) 이제 {1}초 재사용 대기시간이 있습니다. - 이제 명령어 {0} 이 재사용 대기시간이 없고 기존의 모든 재사용 대기시간이 삭제되었습니다. + 이제 명령어 {0}이(가) 재사용 대기시간이 없고 기존의 모든 재사용 대기시간이 삭제되었습니다. 명령어 재사용 대기시간이 설정되지 않았습니다. @@ -1624,28 +1544,25 @@ Fuzzy 명령어 값 - 채널 {2} 에서 {0} {1} 의 사용을 비활성화시켰습니다. + 채널 {2}에서 {0} {1}의 사용을 비활성화시켰습니다. - 채널 {2} 에서 {0} {1} 의 사용을 활성화시켰습니다. + 채널 {2}에서 {0} {1}의 사용을 활성화시켰습니다. 거절함 - Fuzzy - 필터링 된 단어 목록에 {0} 을 추가했습니다. - Fuzzy + 필터링 된 단어 목록에 {0}을(를) 추가했습니다. 필터링 된 단어 목록 - 필터링 된 단어 목록에서 {0} 을 삭제했습니다. - Fuzzy + 필터링 된 단어 목록에서 {0}을(를) 삭제했습니다. - 유효하지 않은 두번째 파라미터입니다. ( {0} 와(과) {1} 사이의 숫자여야 합니다.) + 유효하지 않은 두번째 파라미터입니다. ({0}와(과) {1}사이의 숫자여야 합니다.) 초대 필터링이 이 채널에서 비활성화되었습니다. @@ -1660,10 +1577,10 @@ Fuzzy 초대 필터링이 이 서버에서 활성화되었습니다. - {0} 권한을 #{1} 에서 #{2} (으)로 이동했습니다. + {0} 권한을 #{1}에서 #{2}(으)로 이동했습니다. - 색인 #{0} 에 대한 권한을 찾을 수 없습니다. + 색인 #{0}에 대한 권한을 찾을 수 없습니다. 아무런 값이 설정되지 않았습니다. @@ -1692,33 +1609,32 @@ Fuzzy #{0} - {1} 권한을 삭제했습니다. - {2} 역할에 대한 {0} {1} 의 사용을 비활성화했습니다. + {2} 역할에 대한 {0} {1}의 사용을 비활성화했습니다. - {2} 역할에 대한 {0} {1} 의 사용을 활성화했습니다. + {2} 역할에 대한 {0} {1}의 사용을 활성화했습니다. 초. Short of seconds. - 이 서버에서 {0} {1} 의 사용을 비활성화했습니다. + 이 서버에서 {0} {1}의 사용을 비활성화했습니다. - 이 서버에서 {0} {1} 의 사용을 활성화했습니다. + 이 서버에서 {0} {1}의 사용을 활성화했습니다. - {0} (ID {1} ) 님을 블랙리스트에서 해제하였습니다. - Fuzzy + {0} (ID {1} )님을 블랙리스트에서 해제하였습니다. 수정불가 - {2} 사용자의 {0} {1} 의 사용을 비활성화했습니다. + {2} 사용자의 {0} {1}의 사용을 비활성화했습니다. - {2} 사용자의 {0} {1} 의 사용을 활성화했습니다. + {2} 사용자의 {0} {1}의 사용을 활성화했습니다. 더 이상 권한 경고를 표시하지 않습니다. @@ -1751,7 +1667,7 @@ Fuzzy 당신의 자동번역 언어가 제거되었습니다. - 당신의 자동번역 언어가 {0}>{1} 로 설정되었습니다. + 당신의 자동번역 언어가 {0}>{1}으(로) 설정되었습니다. 이 채널의 자동번역을 시작합니다. @@ -1800,11 +1716,9 @@ Fuzzy 정의: - Fuzzy 시청 종료 - Fuzzy 에피소드 @@ -1844,7 +1758,6 @@ Fuzzy 유효하지 않은 소스 또는 언어입니다. - Fuzzy 농담이 로드되지 않았습니다. @@ -1869,7 +1782,7 @@ Fuzzy {0}의 MAL 프로필 - 봇의 소유자가 MashapeApiKey을 설정하지 않아서 이 기능을 사용 할 수 없습니다. + 봇의 소유자가 MashapeApiKey를 설정하지 않아서 이 기능을 사용 할 수 없습니다. 최소/최대 @@ -1893,11 +1806,10 @@ Fuzzy osu! 정보 검색에 실패했습니다. - {0} 개 이상의 이미지가 발견되었습니다. 무작위로 {0}개를 표시합니다. - Fuzzy + {0}개 이상의 이미지가 발견되었습니다. 무작위로 {0}개를 표시합니다. - 사용자를 찾을 수 없습니다! 다시 시도하기 전에 지역과 배틀태그를 확인해주십시오 + 사용자를 찾을 수 없습니다! 다시 시도하기 전에 지역과 배틀태그를 확인해주세요. 볼 예정 @@ -1943,28 +1855,24 @@ Fuzzy 검색어를 입력해주세요. - Fuzzy 상태 - 저장된 Url - Fuzzy + 상점 url - 스트리머 {0} 은(는) 오프라인입니다. + 스트리머 {0}은(는) 오프라인입니다. - 스트리머 {0} 은(는) {1} 명의 시청자와 함께 온라인입니다. - Fuzzy + 스트리머 {0}은(는) {1}명의 시청자와 함께 온라인입니다. - 당신은 이 서버에서 {0} 개의 스트리밍을 팔로우 중입니다. + 당신은 이 서버에서 {0}개의 스트리밍을 팔로우 중입니다. 당신은 이 서버에서 어떠한 스트리밍도 팔로우하지 않았습니다. - Fuzzy 스트리밍이 없습니다. @@ -2010,13 +1918,12 @@ Fuzzy 시청중 - Fuzzy 해당 용어에 대한 특정 Wikia를 찾지 못했습니다. - 목적 Wikia를 입력하고 검색 쿼리를 입력하십시오. + 목적 Wikia를 입력하고 검색 쿼리를 입력하세요. 페이지를 찾지 못했습니다. @@ -2025,7 +1932,7 @@ Fuzzy 바람의 속도 - {0} 번째로 많은 밴을 당한 챔피언 + {0}번째로 많은 밴을 당한 챔피언 당신의 문장을 Yodify하지 못했습니다. @@ -2042,7 +1949,7 @@ Fuzzy 활성 페이지 #{0} - 총 {0} 명의 사용자. + 총 {0}명의 사용자. 저자 @@ -2054,7 +1961,7 @@ Fuzzy {0}calc 명령어의 기능 목록 - 이 채널의 {0} 은 {1} 입니다. + 이 채널의 {0}은(는) {1} 입니다. 채널 주제 @@ -2063,31 +1970,28 @@ Fuzzy 실행된 명령어 - {0} {1} 은(는) {2} {3} 와(과) 같습니다. + {0} {1}은(는) {2} {3}와(과) 같습니다. 변환기에서 사용할수있는 단위 - 단위를 찾지 못해서 {0} 을(를) {1} (으)로 변환 할 수 없습니다. - Fuzzy + 단위를 찾지 못해서 {0}을(를) {1}(으)로 변환 할 수 없습니다. - 단위의 종류가 같지 않기때문에 {0} 을(를) {1} (으)로 변환 할 수 없습니다. - Fuzzy + 단위의 종류가 같지 않기때문에 {0}을(를) {1}(으)로 변환 할 수 없습니다. - 작성 시간: + 작성 시간 크로스 서버 채널에 입장했습니다. - Fuzzy 크로스 서버 채널에서 퇴장했습니다. - 이것은 당신의 CSC 토큰입니다. + 이것이 당신의 CSC 토큰입니다. 커스텀 이모지 @@ -2103,7 +2007,6 @@ Fuzzy 색인이 범위를 벗어났습니다. - Fuzzy {0} 역할의 사용자 목록 @@ -2116,10 +2019,10 @@ Fuzzy Invalid months value/ Invalid hours value - 디스코드 입장 + 디스코드 가입일 - 서버 입장 + 서버 가입일 ID: {0} @@ -2130,7 +2033,7 @@ Fuzzy 이 페이지에서 서버를 찾을 수 없습니다. - 리피터 목록 + 메시지 반복 목록 맴버 @@ -2142,7 +2045,7 @@ Fuzzy 메시지 - 메시지 리피터 + 메시지 반복 이름 @@ -2195,7 +2098,7 @@ Fuzzy 인용구가 추가되었습니다. - 인용구 #{0} 가 삭제되었습니다. + 인용구 #{0}이(가) 삭제되었습니다. 지역 @@ -2204,16 +2107,16 @@ Fuzzy 가입 날짜 - 제가 {2} `({3:d.M.yyyy.} at {4:HH:mm})`에 {0} 에게 {1}을(를) 상기시킬 것입니다. + {2}마다 {0}에게 {1}을(를) 상기시킵니다. `({3:d.M.yyyy.} {4:HH:mm})` - 유효하지않은 시간 포맷입니다. 명령어 목록을 확인하십시오. + 유효하지 않은 시간 포맷입니다. 명령어 목록을 확인하세요. 새로운 상기 템플릿이 설정되었습니다. - {0} 을 {1} 일 {2} 시간 {3} 분마다 반복합니다. + {0}을(를) {1}일 {2}시간 {3}분마다 반복합니다. 반복 메시지 목록 @@ -2222,7 +2125,7 @@ Fuzzy 이 서버에 반복 메시지가 실행하고있지 않습니다. - #{0} 이 정지되었습니다. + #{0}이(가) 정지되었습니다. 이 서버에서 반복 메시지를 찾을 수 없습니다. @@ -2240,17 +2143,16 @@ Fuzzy {1} 역할에 대한 페이지 #{0} - 색상 포맷이 정확하지 않습니다. `#00FF00`을 사용해보십시오. + 색상 포맷이 정확하지 않습니다. 예를들어 `#00FF00`을 사용해보세요. {0} 역할의 색상 로테이션을 시작했습니다. - Fuzzy {0} 역할의 색상 로테이션을 중지했습니다. - 이 서버의 {0} 은 {1} 입니다. + 이 서버의 {0}은(는) {1} 입니다. 서버 정보 @@ -2262,7 +2164,7 @@ Fuzzy Shard 통계 - Shard **#{0}** 이 {1} 상태이고 {2} 서버에 있습니다. + Shard **#{0}**이 {1} 상태이고 {2} 서버에 있습니다. **이름:** {0} **링크:** {1} @@ -2271,7 +2173,7 @@ Fuzzy 특수 이모지를 찾을 수 없습니다. - {0} 개의 곡을 재생중이며, {1} 개의 대기열이 있습니다. + {0}개의 곡을 재생중이며, {1}개의 대기열이 있습니다. 텍스트 채널 @@ -2283,7 +2185,7 @@ Fuzzy 작동 시간 - {1} 의 {0} 은(는) {2} 입니다. + {1}의 {0}은(는) {2} 입니다. Id of the user kwoth#1234 is 123123123123 @@ -2305,38 +2207,38 @@ Fuzzy 이 서버에서 이미 투표가 진행되고있습니다. - 📃 {0} 님이 투표를 생성하였습니다. + 📃 {0}님이 투표를 생성하였습니다. - `{0}.` {2} 표를 가진 {1}. + `{0}.` {2}표를 획득한 {1}이(가) 되었습니다. - {0} 님이 투표하였습니다. + {0}님이 투표하였습니다. Kwoth voted. - 해당 답변 번호와 함께 개인 메시지를 보내십시오. + 해당 답변 번호와 함께 개인 메시지를 보내세요. - 해당 답변 번호와 함께 여기에 메시지를 보내십시오. + 해당 답변 번호와 함께 여기에 메시지를 보내세요. - {0} 님, 투표해주셔서 감사합니다 + {0}님, 투표해주셔서 감사합니다 - {0} 개의 표가 투표되었습니다. + {0}개의 표가 투표되었습니다. - `{0}pick`을 입력해서 획득하십시오. + `{0}pick`을 입력해서 획득하세요. - `{0}pick`을 입력해서 획득하십시오. + `{0}pick`을 입력해서 획득하세요. 사용자를 찾지 못했습니다. - {0} 페이지 + {0}페이지 이 서버의 음성 채널에 있어야합니다. @@ -2345,13 +2247,13 @@ Fuzzy 음성채널 역할이 없습니다. - {0} 은(는) 음성과 텍스트 채팅으로 부터 {1} 분간 **음소거**되었습니다. + {0}은(는) 음성과 텍스트 채팅으로 부터 {1} 분간 **음소거**되었습니다. - 음성채널 {0} 에 입장하는 사용자는 {1} 역할을 얻게됩니다. + 음성채널 {0}에 입장하는 사용자는 {1} 역할을 얻게됩니다. - 음성채널 {0} 에 입장하는 사용자는 더이상 {1} 역할을 얻지 못합니다. + 음성채널 {0}에 입장하는 사용자는 더이상 {1} 역할을 얻지 못합니다. 음성채널 역할 @@ -2372,16 +2274,16 @@ Fuzzy 가명을 찾지 못했습니다. - {0} 을(를) 입력하면 이제 {1} 의 가명입니다. + {0}을(를) 입력하면 이제 {1}이(가) 입력됩니다. 가명 목록 - 트리거 {0} 의 가명을 삭제했습니다. + 트리거 {0}의 가명을 삭제했습니다. - 트리거 {0} 은(는) 가명이 없었습니다. + 트리거 {0}은(는) 가명이 없었습니다. 경쟁전 플레이 시간 @@ -2400,7 +2302,7 @@ Fuzzy 관리자 - {0} 페이지 + {0}페이지 사유 @@ -2424,46 +2326,46 @@ Fuzzy 모든 시작 명령어를 삭제했습니다. - 사용자 {0} 님이 밴에서 해제되었습니다. + 사용자 {0}님이 밴에서 해제되었습니다. 사용자를 찾을 수 없습니다. - 사용자 {0} 님이 경고를 받았습니다. + 사용자 {0}님이 경고를 받았습니다. - 사용자 {0} 님이 경고를 받았고, {1} 처벌이 적용되었습니다. + 사용자 {0}님이 경고를 받았고, {1} 처벌이 적용되었습니다. {0} 서버에 경고했습니다. - {0} {1} 에 {2} 이(가) + {0} {1}에 {2}이(가) - {0} 님이 모든 경고를 삭제했습니다. + {0}님이 모든 경고를 삭제했습니다. 이 페이지에는 경고가 없습니다. - {0} 의 경고 기록 + {0}의 경고 기록 처벌이 설정되지 않았습니다. - {0} 이(가) 제거했습니다. + {0}님이 초기화했습니다. 경고 처벌 목록 - {0} 개의 경고를 받은 사용자에 대한 처벌을 하지않습니다. + {0}개의 경고를 받은 사용자에 대한 처벌을 하지않습니다. - {1} 개의 경고를 받은 사용자에게 {0} 처벌을 내립니다. + {1}개의 경고를 받은 사용자에게 {0} 처벌을 내립니다. 이제 슬로우모드는 {0} 역할에게 적용되지 않습니다. @@ -2472,40 +2374,41 @@ Fuzzy 이제 슬로우모드는 {0} 역할에게 적용됩니다. - 이제 슬로우모드는 {0} 님에게 적용되지 않습니다. + 이제 슬로우모드는 {0}님에게 적용되지 않습니다. - 이제 슬로우모드는 {0} 님에게 적용됩니다. + 이제 슬로우모드는 {0}님에게 적용됩니다. - 다음과 같은 이유로 인해서 보상을 요청하지 못했습니다: + 다음과 같은 이유로 인해서 보상을 요청하지 못했습니다. 당신은 이미 이번달의 보상을 받은 것 같습니다. 당신의 후원금을 올리지 않는 이상 한 달에 한 번만 보상을 받을 수 있습니다. - 이미 지급되었습니다. + 이미 지급되었습니다 - 당신의 디스코드 계정이 Patreon에 연결되지 않았습니다. 이것이 무슨 뜻인지 모르거나, 어떻게 연결하는지 모른다면 - [Patreon 계정 설정 페이지] (https://patreon.com/settings/account) 에 접속해서 'Connect to discord' 버튼을 클릭하십시오. + 당신의 디스코드 계정이 Patreon에 연결되지 않았습니다. 이것이 무슨 뜻인지 모르거나, 어떻게 연결하는지 모른다면, +[Patreon 계정 설정 페이지] (https://patreon.com/settings/account)에 접속해서 'Connect to discord' 버튼을 클릭하세요. - 디스코드 계정이 연결되지 않았습니다. + 디스코드 계정이 연결되지 않았습니다 보상을 받을 수 있는 자격을 얻기 위해서는 Patreon에서 프로젝트를 후원해야 합니다. {0} 명령어를 이용해서 링크를 얻을 수 있습니다. - 후원 중이지 않습니다. + 후원 중이지 않습니다 - 다시 시도하지 않았다면, 후원을 한 후에 몇 시간을 기다려야합니다. + 후원을 한 후에 몇 시간을 기다려야합니다, 그렇지 않다면 나중에 다시 시도해주세요. - 잠시만 기다려주십시오. + 잠시만 기다려주세요 - {0} 을 받았습니다. 프로젝트를 후원 해주셔서 감사합니다! + {0}을(를) 받았습니다. 프로젝트를 후원 해주셔서 감사합니다! 보상은 매 달 5일에 요구 할 수 있습니다. From bad80381bd6456ffe9ee6f9f978462dae5a22de1 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:56:52 +0200 Subject: [PATCH 738/746] Update ResponseStrings.nb-NO.resx (POEditor.com) From 373753b40fe646de1779469e6937beb0ae2c7e89 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:56:55 +0200 Subject: [PATCH 739/746] Update ResponseStrings.pl-PL.resx (POEditor.com) From 2ed450944165a7007ab7031871ffbf2b0386ce86 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:56:58 +0200 Subject: [PATCH 740/746] Update ResponseStrings.pt-BR.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.pt-BR.resx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx index a416a95e..f5819b5a 100644 --- a/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx +++ b/src/NadekoBot/Resources/ResponseStrings.pt-BR.resx @@ -2391,7 +2391,7 @@ OwnerID: {2} Comando de Texto - Chutado + Kickados PLURAL @@ -2485,7 +2485,7 @@ OwnerID: {2} Já recompensado - Sua conta do discord pode não estar conectada ao Patreon. Se você não tem certeza do que isso significa, ou não sabe como conectá-la - Você deve ir para [Página de configurações de conta do Patreon)(https://patreon.com/settings/account) e clicar em 'Connect to discord' button. + Sua conta do discord pode não estar conectada ao Patreon. Se você não tem certeza do que isso significa, ou não sabe como conectá-la - Você deve ir para [Página de configurações de conta do Patreon](https://patreon.com/settings/account) e clicar no botão 'Connect to discord'. Conta do discord não conectada From d2d10f2c9d889d3d2fad3bb0362ded04a84c62d7 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:57:00 +0200 Subject: [PATCH 741/746] Update ResponseStrings.ru-RU.resx (POEditor.com) From 48ab3150ef7bbcd42ccfd1953967b1f946c60b9c Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:57:03 +0200 Subject: [PATCH 742/746] Update ResponseStrings.sr-cyrl-rs.resx (POEditor.com) From 6ffc2a041d54b7546f7131882d8e3ccd1bd8e39a Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:57:06 +0200 Subject: [PATCH 743/746] Update ResponseStrings.es-ES.resx (POEditor.com) --- src/NadekoBot/Resources/ResponseStrings.es-ES.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.es-ES.resx b/src/NadekoBot/Resources/ResponseStrings.es-ES.resx index b5813634..a57dff77 100644 --- a/src/NadekoBot/Resources/ResponseStrings.es-ES.resx +++ b/src/NadekoBot/Resources/ResponseStrings.es-ES.resx @@ -2391,7 +2391,7 @@ IDs de dueños: {2} No apoyando - Tienes que esperar algunas horas después de hacer tu colaboración, sino, trata otra vez. + Tienes que esperar algunas horas después de hacer tu colaboración, sino, trata otra vez más tarde. Espera un tiempo From a4d09dc31f9079dfa76d77a0923c47e2797eaebb Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:57:08 +0200 Subject: [PATCH 744/746] Update ResponseStrings.sv-SE.resx (POEditor.com) From de65173fd00c92eaf53e8f88ba0a08f7fc9912d2 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 11 Apr 2017 00:57:11 +0200 Subject: [PATCH 745/746] Update ResponseStrings.tr-TR.resx (POEditor.com) From a283c3d73f40535e07ef4214f3558ae828f00cb7 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 11 Apr 2017 01:55:19 +0200 Subject: [PATCH 746/746] Arabic is added but not working properly, waiting for translators to fix --- .../Commands/LocalizationCommands.cs | 1 + .../Resources/ResponseStrings.ar.resx | 2424 +++++++++++++++++ 2 files changed, 2425 insertions(+) create mode 100644 src/NadekoBot/Resources/ResponseStrings.ar.resx diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 2eb70e4c..c3de5bd8 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -20,6 +20,7 @@ namespace NadekoBot.Modules.Administration //Bahasa Indonesia, Indonesia private ImmutableDictionary supportedLocales { get; } = new Dictionary() { + //{"ar", "العربية" }, {"zh-TW", "繁體中文, 台灣" }, {"zh-CN", "简体中文, 中华人民共和国"}, {"nl-NL", "Nederlands, Nederland"}, diff --git a/src/NadekoBot/Resources/ResponseStrings.ar.resx b/src/NadekoBot/Resources/ResponseStrings.ar.resx new file mode 100644 index 00000000..ffb1ba85 --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.ar.resx @@ -0,0 +1,2424 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + تم الاسنيلاء على القاعدة ,او مدمرة + + + القاعدة مدمرة + + + تلك القاعدة غير محتلة + + + ** تدمير** القاعدة #{0} في الحرب ضد {1} + + + {0}**قد تنازل**عن قاعدة #{1} في الحرب ضد {2} + + + {0} استولى على قاعدة #{1} في الحرب ضد {2} + + + @{0} أنت استوليت بالفعل قاعدة # {1}. لا يمكنك المطالبة بوحدة جديدة. + + + الاستولى من @{0} في الحرب ضد {1} قد انته. + + + عدو + + + معلومات عن الحرب ضد {0} + + + رقم القاعدة خطأ. + + + غير متاح حجم الحرب. + + + قائمة الحرب القائمة + + + غير محتلة + + + انت لست مدرج في هذه الحرب + + + @{0} لست مشارك في الحرب , او ان القاعدة قد تدمرت + + + لا توجد حروب ناشطة + + + حجم + + + الحرب ضد {0} قد بدأت + + + أنشئت حرب ضد {0}. + + + الحرب ضد {0} قد انتهت + + + هذه الحرب لا توجد + + + الحرب ضد {0} قد بدأت + + + كل خصائص الرموز التعبيرية المخصصى خالية + + + تم محي الرمز التعبيري المخصص + + + أذونات غير كافية. البوت بحاجة الى تصريح المالك لتعديل الرد التفاعلي , وايضا المدير لتخصيص الرد التفاعلي + + + فائمة الرموز التعبيرية المخصصة + + + الرموز التعبيرية المخصصة + + + رمز تعبيري مخصص جديد + + + لم يوجد هذا الرمز + + + الرمز التعبيري المخصص ليس موجود حسب المدخل + + + الإستجاب + + + احصائيات الرموز التعبيرية مخصصة + + + الخصائص خالية (0) للترميز التفاعلي + + + لا يوجد خصائص مفعلة متاحة , لم يتم اتخاذ اي اجراء. + + + تفعيل + + + Autohentai توقف + Fuzzy + + + لا توجد نتائج. + + + {0} قد اغمي عليه + + + (0) عنده من قبل HP كامل + Fuzzy + + + لديك النوع التالي (0). + + + استخدام (0)(1) على (2)(3) لضرر (4). + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + لا يمكنك الهجوم مرة أخرى دون انتقام! + + + لا يمكنك الهجوم على نفسك. + + + (0) اغمى عليه. + + + عالج (0) باستخدام واحد (1) . + + + (0) لديه (1) HP متبقي. + + + لا يمكنك استخدام (0). اكتب "(1)ml" لروئية لائحة التحريكات التي يمكنك استخدمها. + + + حرك القائمة الى (0) نوع . + + + غير فعالة. + + + لاتملك ما يكفي (0) . + + + أحيا (0) باستخدام (1) . + + + لقد احبيبت تقسك باستخدام واحد (0). + + + لقد تم تغير النوع الى (0) مقابل (1) . + + + انها فعالة إلى حد ما. + + + انها فعالة جدا . + + + لقد استخدمت اكثر من حركة في صف . لا تستطيع التحرك . + + + نوع (0) هو (1) . + + + المستخدم غير متاح . + + + لقد اغمى عليك , لا تيستطيع التحرك ! + + + **تعين دور ** على ضخول مستخدم**تم تعطيله **. + + + **تعين دور ** على ضخول مستخدم**تم تشغيله **. + + + مرفق . + + + تغير المظهر . + + + تم طردك من السيرفر (0) . +السبب : (1) . + + + تم طردك . + PLURAL + + + المستخدم مطرود . + + + تغير اسم البوت الى (0) . + + + خصائص البوت غيرت الى (0). + + + تم تعطيل الحذف الالي لرسالة الوداع. + + + سيتم حذف رسالة الوداع بعد {0} ثواني . + + + رسالة الوداع حاليا : (0) . + + + تفعيل رسالة الوداع بكتابة (0) . + + + وضع رسالة وداع جديدة . + + + اعلان رسالة الوداع غير مفعلة . + + + اعلان رسالة الوداع مفعلة في هذه القناة . + + + تم تغير اسم القناة . + + + الاسم القديم . + + + تم تغير موضوع القناة. + + + تم تنظيف المحتوى . + + + المحتوى . + + + تم انشاء دور (0). + + + تم انشاء قناة رسائل (0) . + + + تم أنشاء قناة الصوت {0}. + + + تم الطرش بنجاح . + + + حذف السيرفر {0}. + + + تم وقف الحذف الالي لأوامر الاستدعاء الناجحة. + + + سيتم الغاء الامر تلقائيا بعد التنفيذ . + + + تم حذف قناة الرسائل {0}. + + + قناة الصوت {0} قد أحذفت. + + + رسالة خاصة من + + + تم اضافة متبرع جديد بنجاح . اجمالي تبرعات هذا المستخدم (0) 👑 + + + شكرا للجميع في القائمة التالية على مساهمتهم في تحقيق هذا المشروع! + + + سوف ارسل الرسائل الخاصة الى جميع المالكين. + + + سوف ارسل الرسائل الخاصة الى المالك الأول فقط. + + + من الان فصاعدا سوف أرسل الرسائل الخاصة. + + + من الان فصاعدا سوف أتوقف عن أرسال الرسائل الخاصة. + + + تم تعطيل الحذف الالي لرسائل التحية. + + + سوف يتم حذف رسائل التحية بعد {0} ثانية. + + + الرسالة الخاصة الحالية للتحية : {0} + + + تمكين DM رسائل التحية عن طريق كتابة {0} + + + تم تثبيت رسالة التحية عبر رسالة خاصة. + + + تم تعطيل الإعلان عن التحية عبر الرسائل الخاصة. + + + تم تفعيل الإعلان عن التحية عبر الرسائل الخاصة. + + + رسالة التحية الحالية : {0} + + + يتم تفعيل رسائل التحية بكتابة {0} + + + وضع رسالة تحية جديدة. + + + اعلان التحية غير مفعل . + + + اعلان التحية مفعل في هذه القناة . + + + ليس باستطاعتك ان تستخدم هذا الأمر على المستخدمين بدور اعلى من دورك او مساوا له في سلم الأدوار. + + + تحميل الصور بعد {0} ثواني! + + + ادخال خاطئ . + + + معلمات غير صالحة. + + + + انضم {0} الى {1} + + + لقد تم طردك من {0} السيرفر. +السبب: {1} + + + تم طرد المستخدم . + + + قائمة اللغات . + + + لغة سيرفرك الان {0}-{1} + + + لغة الألي إفتراضياً الآن {0} - {1} + Fuzzy + + + تم ضبط لغة البوت الى (0) - (1) . + + + فشل الضبط المحلي . قم بزيارة قائمة مساعدة الاوامر . + + + لغة السيرفر مضبوطة الى (0) - (1) . + + + {0} ترك {1} + + + خرج من السيرفر (0) + + + تسجيل هذا الحدث في القناة (0) . + + + تسجيل جميع الاحداث في هذه القناة . + + + تم تعطيل التسجيل. + + + قائمة الاحداث التي يمكنك التسجيل بها . + + + التسجيل سيتجاهل {0} + + + التسجيل لن يتجاهل {0} + + + تم ايقاف تسجيل الحدث (0). + + + (0) قد استند إلى ذكر الأدوار التالية + + + رسالة من (0) '[ مالك البوت ]' . + + + تم ارسال الرسالة . + + + (0) تم تحريك من (1) الى (2) . + + + تم حذف الرسالة في {0}# + + + تم تحديث الرسالة في {0}# + + + صامتة . + PLURAL (users have been muted) + + + صامتة . + singular "User muted." + + + ليس لدي الأذن الازم لذلك على ما يبدو. + + + ضبط اسكات لدور جديد . + + + أحتاج الى الأذن "Administrator" للقيام بذلك. + + + رسالة جديدة . + + + لقب جديد . + + + موضوع جديد . + + + تغير اللقب . + + + لم أجد هذا السيرجر + + + لم يوجد مشاركة مع صاحب ID + + + رسائل قديمة . + + + لقب قديم . + + + موضوع قديم . + + + خطأ . على الاغلب لا امتلك الصلاحيات الكافية . + + + جميع الأذون في السيرفر أعاد تعيينهم. + + + الحماية فعالة . + + + تم تعطيل {0} على هذا السيرفر. + + + {0} مفعل + + + خطأ. أحتاج الى الأذن ManageRoles + + + لس هنالك حماية فغالة. + + + يجب أن يكون المستخدم عتبة بين {0} و {1}. + + + إذا {0} أو أكثر من المستخدمين الانضمام في {1} ثواني، سوف {2} لهم. + + + يجب أن يكون الوقت بين {0} و {1} ثواني. + + + تم حذف جميع الادوار من هذا المستخدم (0) . + + + فشل حذف الدور . لا امتلك الصلاحيات الكافية . + + + تم تغيير لون الدور{0} . + + + الدور غير موجود. + + + المعلمات المحددة غير صالحة. + + + حدث خطأ بسبب لون غير صالح أو أذونات غير كافية. + + + تم ازالة دور {0} من المستخدم {1} + + + فشل حذف الدور. لا امتلك الصلاحيات الكافية . + + + تغير اسم الدور . + + + فشل تغير الاسم . لا امتلك الصلاحيات الكافية . + + + لا يمكنك تعديل أدوار أعلى من أعلى دورك + + + إزالة رسالة اللعب: {0} + + + دور {0} تم أضيفت إلى القائمة. + + + {0} لم يتم العثور.تم تنظيفه + + + دور {0} موجود بالفعل في القائمة. + + + اضافة . + + + تعطيل دوار وضع اللعب + + + تشغيل دوار وضع اللعب + + + هذه قائمة من الحالات الدورية:(0) + + + لم يتعين اوضاع اللعب الدوري. + + + لديك بالفعل الدور{0}. + + + لديك بالفعل دور{0} الحصري المعين لك. + + + الادوار المخصصة للتعين الذاتي الان اصبحت خاصة! + + + هنالك (0) ادور مخصصة للتعين الذاتي . + + + الدور غير مخصص للتعين الذاتي . + + + ليس لديك دور {0}. + + + الادوار المخصصة للتعين الذاتي الان اصبحت غير خاصة! + + + لا أست + + + {0} تمت إزالته من قائمة الأدوار الذاتية التعيين. + + + انت لا تملك هذا الدور (0) بعد الان. + + + لقد اصبحت تملك هذا الدور (0) . + + + تم اضافة الدور (0) بنجاح الى مستخدم (1). + + + فشل اضافة الدور . لا امتلك الاذن الكافي . + + + مظهر جديد ضبط . + + + ضبط اسم قناة جديد. + + + تم اضافة لعبة جديدة ! + + + تم اضافة بث جديد ! + + + اسند موضوع جديد للقناة. + + + شارد {0} اعيدت أتصالها. + + + شارد {0} يعادة الاتصال. + + + جاري الأغلاق. + + + لا يمكن للمستخدمين إرسال أكثر من {0} رسائل كل {1} ثواني. + + + الوضع البطيئ تم ايقافه . + + + الوضع البطيئ تم تفعيله . + + + حظر ناعم (رفض) + PLURAL +Fuzzy + + + {0} سيتجاهل هذه القناة. + + + {0} لم يعد يتجاهل هذه القناة. + + + + + + قناة كتبه صنعت + + + تدمير قناة المراسلة . + + + ازالة عدم السماع بنجاح . + + + إلغاء الصامت + singular + + + اسم المستخدم + + + اسم المستخدم تغير + + + المستخدمين . + + + المستخدم مطرود . + + + {0} تم **صامتة** من الدردشة. + + + {0} تم **إلغاء صامتة** من الدردشة. + + + تم اضافة مستخدم . + + + المستخدم غادر + + + {0} تم **صامتة** من الدردشة والدردشة الصوتية. + + + أضافة دور المستخدم + + + إزالة دور المستخدم + + + (0) اصبح الان (1) + + + (0) اصبح ** صامت ** في المراسلة والمحادثة . + + + (0) اشترك ب (1) قناة الصوت . + + + (0) خرج من (1) قناة الصوت . + + + {0} تغير من {1} الى {2} قناة الصوتية. + + + (0) تم **اسكات الصوت** + + + (0) تم ازالة **اسكات الصوت** + + + انشاء قناة صوت + + + تدمير قناة الصوت + + + ايقاف خصائص الصوت والكتابة + + + تفعيل خصائص الصوت والكتابة + + + + + + + + + + + + المستخدم (0) من كتابة الرسائل + + + المستخدم (0) من الكتابة ومحادثة الصوت + + + المستخدم (0) من محادثة الصوت + + + لقد تم حظرك من {0} مزود. +السبب: {1} + Fuzzy + + + ازالة الطرد عن المستخدم + + + تمت الهجرة ! + + + حدث خطأ أثناء الترحيل، راجع وحدة تحكم بوت للحصول على مزيد من المعلومات. + + + التحديث الحالي + + + المستخدم طرد-مخفض + + + تم منح (0) الى (1) + + + حظا اوفر المرة القادمة ^_^ + + + مبارك لقد فزت (0) دحرجة فوق (1) + + + خلط ورق اللعب مرة ثانية + + + قلب (0) + User flipped tails. + + + لقد خمنتها ! فزت (0) + + + رقم خطأ غير مخصص . بأمكانك قلب 1 الى (0) عملة نقدية + + + اضف الى (0) للحصول على الرمز التفاعلي ل(1) + + + الحدث مستمر لغاية (0) ساعة + + + وردة الرمز التفاعلي بدأت ! + + + لقد اهدا (0) الى (1) + X has gifted 15 flowers to Y + + + (0) يملك (1) + X has Y flowers + + + رأس + + + قائمة المتصدرين + + + تم مكافئة {0} الى {1} المستخدم من دور {2}. + + + لايمكنك المزايدة اكثر من (0) + + + لا يمكنك المزايدة اقل من (0) + + + انت لا تملك ما يكفي (0) + + + لا مزيد للورق على الطاولة + + + بيع المستخدم يانصيب + + + لقد دحرجت (0) + + + المزايدة + + + WOAAHHHHHH!!! مبارك !!! * (0) + + + اشارة (0) , *(1) + + + واو ! محظوظ! ثلاثة من نوع ! * (0) + + + عمل جيد ! اثنين (0) - مزايدة *(1) + + + فزت + + + + + + + + + + + + ذيل + + + بنجاح اخذت (0) من (1) + + + لم استطع اخذ (0) من (1) بسبب المستخدم لا يملك ما يكفي من (2)! + + + العودة الى TOC + Fuzzy + + + فقط مالك البوت + + + مطلوب (0) للسماح بالقناة + + + يمكنك بدعم المشروع في <{patreon: <{0 او في <{1}> :paypal + + + الأوامر والأسماء المستعارة + + + قائمة الأوامر مجددة. + + + + + + لا استطيع ان اجد الامر . الرجاء تأكد من وجود الامر قبل المحاولة التالية + + + وصف + + + يمكنكم الدعم مشروع NadekoBot في <{Patreon <{0 او في <{1}> PayPal +لا تنسى تترك اسمك في ديسكورد او الID في علبة الرسالة. + +** شكراً لكم **♥️ + + + + + + قاىمة الأوامر + + + قائمة الوحدات + + + + + + تلك الوحدة غير موجودة. + + + يتطلب (0) أذن من السيرفر + + + جدول المحتويات + + + الأستعمال + + + + + + ربط + + + سباق الحيوانات + + + فشل في البدء لعدم وجود مشاركين كفاية + + + امتلئ السباق ! البدء فورا. + + + (0) انضم بصفة (1) + + + (0) انضم بصفة (1) و راهن (2)! + + + اكتب {0}jr للانضمام إلى السباق. + Not sure whether to use the actual Arabic letters here to just use the English ones. + + + البدء خلال 20 ثانية او عند اكتمال العدد في الغرفة + + + البدء مع (0) مشتركين. + + + (0) بصفة (1) فاز بالسباق! + + + (0) بصفة (1) فاز بالسباق وايضا (2)! + + + + + + دحرج (0) + Someone rolled 35 + + + دحرج النرد : (0) + Dice Rolled: 5 + + + فشل بداية السباق. ربما سباق آخر في طور الحدوت. + + + لا يوجد سباق على هذا الموزع + + + الرقم الثانيي يجب ان يكون اكبر من الرقم الاول. + + + تغير بالخاطر + + + المطالبة + + + طلاق + + + اعجاب + + + ثمن + + + لم يتم المطلبة بأي waifus بعد. + + + + + + + + + تغير إنجذابهم من {0} الى {1} +*هذا مشكوك فيه أدبياً.*🤔 + Make sure to get the formatting right, and leave the thinking emoji + + + يجب ان تنتظر {0} ساعات و {1} دقائق إذا اردت تغيير انجذابك مرة أخرى. + + + تم إعادته إنجذابك. ليس لديك أي شخص تحبه. + + + يريد ان يكون {0} وايفو. كيوووت 3> + + + + + + + + + لا يمكنك تعيين تقارب لنفسك، انت إغومانياك. + + + 🎉 يتم الوفاء بحبهم! 🎉 +قيمة (0) الجديدة (1)! + + + + + + + + + هذه ليست زوجنك + + + لا يمكنك المطالبة بنفسك. + + + + + + لا أحد + + + + + + 8 كرة + + + رهاب الأجسام. + + + اللعبة انتهت بدون اي اخضاع. + + + لم يحتسب الاصوات . اللعبة انتهت بدون فائز. + + + كان الاختصار (0) + + + + + + بدأت اللعبة. إنشاء جملة مع الاختصار التالي : (0). + + + لديك (0) ثانية لعمل اخضاع. + + + (0) اعتمد حكمهم .((1) الاجمالي) + + + تصويت بكتابة رقم من الاخضاع. + + + (0) وضعوا اصواتهم ! + + + الفائز هو (0) مع (1) من النقاط. + + + + + + سؤال + + + انها التعادل! اختار كلاهما {0}. + + + {0} فاز! {1} هزم على {2}. + + + اغلاق الاخضاع + + + سباق الحيوانات جاهز للركض. + + + المجموع: {0} المعدل: {1} + + + قوائم + + + ايقاف البوت الذكي في هذا السيرفر + + + تفعيل البوت الذكي في هذا السيرفر + + + + + + + + + + plural + + + + + + فشل في تحميل السؤال + + + بدأت اللعبة + + + بدأت لعبة Hangman + + + + + + + + + + + + قائمة المتصدرين + + + انت لا تملك ما يكفي من(0) + + + لا يوجد ناتج + + + حمل (0) + Kwoth picked 5* + + + (0) زرع (1) + Kwoth planted 5* + + + لعبة Trivia تعمل على هذا السيرفر. + + + لعبة Trivia + + + (0) لقد حزرها ! الجواب كان :(1) + + + Trivia لا تعمل على هذا السيرفر. + + + (0) لديه (1) نقطة + + + التوقف بعد هذا السؤال + + + انتهى الوقت ! الاجابة الصحيحة كانت (0) + + + (0) حزر الاجابة وفاز باللعبة ! الاجابة كانت : (1) + + + لا يمكنك اللعب ضد نفسك. + + + + + + تعادل ! + + + تم انتاج لعبة TicTacToe. + + + (0) لقد فاز! + + + تطابق ثلاث + + + لا تحركات متبقية! + + + نفذ الوقت ! + + + حركة {0}. + + + (0) ضد (1) + + + + + + تم تعطيل التشغيل التلقائي. + + + تم تفعيلل التشغيل التلقائي. + + + + + + + + + اللعب العادل + + + انتهت الاغنية + + + تم تعطيل اللعب العادل. + + + تم تفعيل اللعب العادل. + + + من الوضع + + + + + + مدخل غير صالح. + + + + + + + + + + + + + + + + + + اسم الاغنية + + + الان تسمع اغنية + + + لايوجد موسيقى + + + لم يتم ايجاد البحث + + + + + + + + + تشغيل الاغنية + + + + + + + + + تم حذف قائمة التشغيل. + + + + + + + + + + + + حفظ قائمة التشغيل + + + (0) ث الحد + + + + + + + + + تم حذف قائمة انتظار الموسيقى. + + + + + + ازالة الاغنية + context: "removed song #5" + + + اعادة تشغيل الاغنية الحالية + + + تكرار قائمة التشغيل + + + تكرار المسار للموسيقى + + + توقيف تكرار المسار الحالي + + + تم استئناف تشغيل الموسيقى. + + + تم تعطيل قائمة التشغيل المتكررة. + + + تم تمكين قائمة التشغيل المتكرر. + + + + + + تخطي الى '(0):(1)' + + + خلط الاغاني + + + تحريك الاغنية + + + (0 س (1)د (2)ث + + + الى مكان + + + غير محدود + + + يجب أن يكون درجة الصوت بين 0 و 100 + + + ضبط درجة الصوت الى (0)% + + + + + + + + + السماح + + + + + + + + + + + + + + + + + + + + + + + + الامر (0) الان لديه (1)ث ليصبح جاهز. + + + + + + لم يتم تعيين أي تهدئة الأوامر. + + + تكلفة الامر + + + ايقاف الاستخدام في (0) (1) على قناة (2). + + + تفعيل الاستخدام في (0) (1) على قناة (2). + + + رفض + + + تم اضافة الكلمة (0) الى قائمة الكلمات المصفاة. + + + قائمة الكلمات المصفاة. + + + ازالة الكلمة (0) من لائحة الكلمات المصفاة . + + + + + + الدعوات المصفاة تم ايقافها في هذه القناة. + + + الدعوات المصفاة مفعلة في هذه القناة. + + + الدعوات المصفاة تم ايقافها في هذا السيرفر. + + + الدعوات المصفاة مفعلة في هذا السيرفر. + + + تحريك الاذن (0) من #(1) الى #(2) + + + لا استطيع ايجاد الاذن في الدليل + + + لم يوضع تكلفة. + + + الامر + Gen (of command) + + + وحدة + Gen. (of module) + + + صفحة السماحات (0) + + + وضع السماح للدور هو (0) + + + المستخدم يتطلب (0) دور للتمكن من تعديل الاذونات. + + + لم اجد الاذن في القائمة. + + + ازالة الاذن #(0) - (1) + + + ايقاف الاستخدام (0) (1) للدور (2) + + + تفعيل الاستخدام (0) (1) للدور (2) + + + ثواني. + Short of seconds. +Fuzzy + + + ايقاف استخدام (0) (1) في هذا السيرفر + + + تفعيل استخدام (0) (1) في هذا السيرفر + + + + + + لا يتعدل + + + ايقاف الاستخدام (0) (1) للمستخدم (2) + + + تفعيل الاستخدام (0) (1) للمستخدم (2) + + + لن اقوم بأظهار اي تحذير للاذونات. + + + سوف اظهر تحذير الاذونات. + + + ايقاف تصفية الكلمات في هذه القناة. + + + تفعيل تصفية الكلمات في هذه القناة. + + + ايقاف تصفية الكلمات في هذا السيرفر. + + + تفعيل تصفية الكلمات في هذا السيرفر. + + + قدرات + + + لا يوجد انمي مفضل بعد + + + البدء بالترجمة الفورية للمسجات في هذه القناة . رسائل المستخدم سيتم الغائها تلقائيا. + + + تمت إزالة لغة الترجمة التلقائية. + + + تم تعيين لغة الترجمة التلقائية إلى (0)>(1) + + + بدء الترجمة التلقائية للرسائل على هذه القناة. + + + تم إيقاف الترجمة التلقائية للرسائل على هذه القناة. + + + ادخال خطأ للصيغة, او شيء ما حدث بالخطأ. + + + لم استطع ايجاد هذه البطاقة. + + + واقعية + + + فصول + + + رسوم متحركة # + + + خسائر تنافسية + + + لعب تنافسي + + + مرتبة تنافسية + + + فوز تنافسي + + + منتهي + + + شرط + + + تكلفة + + + موعد + + + تحديد: + + + اسقاط + + + حلقة + + + حدث خطأ + + + مثال + + + فشل ايجاد ذلك الانمي + + + فشل ايجاد ذلك المانجا + + + الانواع + + + فشل العثور على تعريف لهذه العلامة. + + + طول/وزن + + + (0) م / (1) كجم + + + رطوبة + + + بحث الصورة في: + + + فشل ايجاد ذلك الفيلم. + + + لغة المصدر أو الهدف غير صالحة + + + النكت غير محملة + + + خط العرض/طول + + + مستوى + + + قائمة (0) الامان المعلمة + Don't translate {0}place + + + المكان + + + + + + + + + + + + ادنى/ اعلى + + + القناة غير موجودة + + + لا توجد نتائج. + + + على- الانتظار + + + الرابط الاصلي + + + + + + فشل استرداد أوسو! التوقيع. + Fuzzy + + + تم ايجاد اكثر من (0) صورة . عرض عشوائي(0). + + + + + + خطط للمشاهدة + + + منصة + Fuzzy + + + لم يتم العثور على أي قدرة. + + + لم اجد اليوكمون. + + + رابط الملف الشخصي: + + + الجودة: + + + وقت اللعب السريع + + + الفوز السريع + + + الترتيب + + + مجموع النقاط: + + + البحث عن: + + + فشل تقصير الربط + + + عنوان الرابط قصير + Fuzzy + + + هناك خطأ ما. + + + يرجى تحديد معلمات البحث. + + + الحالة + + + حفظ الرابط + + + ستريمر {0} غير متواجد حاليا. + Fuzzy + + + ستريمر (0) على الإنترنت مع (1) من المشاهدين. + Fuzzy + + + انت تتابع (0) بث على هذا السيرفر + + + انت لا تتابع اي بث على هذا السيرفر + Fuzzy + + + لا يوجد مثل هذا البث. + + + البث على الاغلب غير موجود. + + + + + + سوف اعلم هذه القناة عند تغير الحالة. + + + شروق الشمس + + + غروب الشمس + + + درجة الحرارة + + + عنوان: + + + اعلى 3 أنيمي مفضلة: + + + ترجمة: + + + الأنواع + + + فشل العثور على تعريف لهذا المصطلح. + + + رابط + + + متابعين + + + مشاهدة + + + فشل العثور على هذا المصطلح على wikia المحدد. + + + الرجاء إدخال وتحديد wikia ، يليه طلب البحث. + + + الصفحة غير موجودة. + + + سرعة الرياح + + + معظم الأبطال المحظورة (0) + + + أخفق تعديل الجملة. + Fuzzy + + + انضم + + + {0} .` {1} [{2: F2} / s] - {3} ألمجموع + /s and total need to be localized to fit the context - +`1.` + + + صفحة النشاط #(0) + + + {0} مجموع المستخدمين. + + + مؤلف + + + بوت ID + + + قائمة الوظائف في الأمر (0) كلك + Fuzzy + + + (0) من هذه القناة هو (1) + + + موضوع القناة + + + تم تشغيل الأوامر + + + {0} {1} يساوي {2} {3} + + + الوحدات التي يمكن استخدامها من قبل المحول + + + لا يمكنني تحويل (0) الى (1): الوحة غير موجودة + + + لا يمكن تحويل (0) إلى (1): أنواع الوحدات غير متساوية + + + أنشئت في + + + انضممت الى قناة تقاطع السيرفارات + Fuzzy + + + مغادرة قناة تقاطع السيرفارات + + + هذا csc قطعة + Fuzzy + + + الرمز التعبيري المخصص + In Arabic, we do have instances where we add "AL" (the) to a sentence since at times it might not make sense without it. It really depends on the sentence wording. + + + خطأ + + + الميزات + + + + الهوية + + + + القائمة خارج النطاق. + + + قائمة المستخدمين في {0} دور + + + لا يسمح لك باستخدام هذا الأمر في الأدوار التي تملك الكثير من المستخدمين فيها لكي تمنع الإساءة + + + قيمة {0} غير صالحة + Invalid months value/ Invalid hours value + + + انضم إلى ديسكورد + + + انضم إلى السيرفر + There are two terms that can be used here other than what is already used. +مُزَوِّد and خادم. +خادم could be mistaken for another word so I avoided it. + + + الهوية: {0} +الأعضاء: {1} +هوية المالك: {2} + + + لم يتم ايجاد سيرفر على تلك الصفحة + + + قائمة المكررين + + + اعضاء + + + ذاكرة + + + رسالة + + + مكرر رسائل + + + الاسم + + + الاسم المستعار + + + لا احد يلعب تلك اللعبة + + + لا نشاط للمكريرن + Fuzzy + + + لا يوجد ادوار في هذه الصفحة + + + + + + لم يضبط الموضوع + + + مالك + + + صاحب IDs + + + حضور + + + (0) سيرفرز +(1) قناة الرسائل +(2) قناة الصوت + + + تم حذف جميع علامات الاقتباس باستخدام كلمة رئيسية (0) + + + صفحة (0) من علامات الاقتباس + + + لا توجد علامات اقتباس في هذه الصفحة. + + + لم يتم العثور على علامات الاقتباس التي يمكنك إزالة. + + + تمت إضافة اقتباس + + + تم حذف الاقتباس # (0) + + + منطقة + + + مسجل في + + + + + + تنسيق الوقت ليس صالحا. تحقق من قائمة الأوامر. + + + تذكير جديد قالب مضبوط + + + + + + قائمة المكررين + + + لا يوجد مكررين على هذا السيرفر + + + #(0) توقف + + + لم اجد رسائل مكررة على هذا السيرفر + + + ناتج + + + دور + + + صفحة #(0) لجميع الادوار على هذا السيرفر + + + صفحة #(0) من الادوار ل (1) + Fuzzy + + + لا توجد ألوان بالتنسيق الصحيح. استخدم `# 00ff00` على سبيل المثال. + + + بدأ تدوير لون الدور (0) + + + توقف الألوان الدورية لدور (0) + + + (0) من هذا السيرفر(1) + + + معلومات السيرفر + + + + + + + + + + + + **الاسم:** (0) **الرابط:**(1) + + + لم يتم العثور على رموز تعبيرية خاصة. + + + تشغيل الأغاني (0). (1) في قائمة الانتظار. + + + قناة الرسائل + + + إليك رابط غرفتك: + + + مدة التشغيل + + + (0) للمستخدم (1) هو (2) + Id of the user kwoth#1234 is 123123123123 + + + المستخدمين + + + قناة الصوت + + + لقد انضممت بالفعل لهذا السباق! + + + نتائج الاستطلاع الحالية + + + لا اصوات وضعت + + + يتم تشغيل الاستطلاع بالفعل على هذا السيرفر + + + 📃 (0) قام بإنشاء استطلاع يتطلب انتباهك: + + + `{0}.` {1} مع {2} اصوات. + + + (0) صوت. + Kwoth voted. + + + + + + + + + شكرا للتصويت (0) + + + مجموع الاصوات (0) + + + + + + + + + لم يتم العثور على مستخدم + + + صفحة (0) + + + يجب أن تكون في قناة الصوت على هذا السيرفر + + + لا توجد أدوار لقنوات الصوت + + + + + + + + + + + + ادوار قناة الصوت + + + + + + + + + + + + + + + لم يتم العثور على اسم مستعار + + + + + + + + + + + + + + + + + + + + + + + + + PLURAL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file

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 EUy(;nMgRZ+ literal 0 HcmV?d00001 diff --git a/src/NadekoBot/_libs/64/libsodium.dll b/src/NadekoBot/_libs/64/libsodium.dll new file mode 100644 index 0000000000000000000000000000000000000000..f5de830e8ca15d0944da923a23e1da39d39dfa05 GIT binary patch literal 399872 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�VjmrTRKbmxuJS~{1`$rq|GPb=9_xRdUaS{fdU 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 z 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%0A)}`3W7Ngvp`=F#vx5 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%0AiOxr0XV6GmwxbxGTOJ5H=xMID!Hb5L)zd?_ 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 literal 0 HcmV?d00001 diff --git a/src/NadekoBot/_libs/64/opus.dll b/src/NadekoBot/_libs/64/opus.dll new file mode 100644 index 0000000000000000000000000000000000000000..a962869fd53cc473812231b51d3edf31ecfa77d2 GIT binary patch literal 261632 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