Merge remote-tracking branch 'Kwoth/1.9' into 1.9
This commit is contained in:
		
							
								
								
									
										2022
									
								
								NadekoBot.Core/Migrations/20171115040313_currency level up reward.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										2022
									
								
								NadekoBot.Core/Migrations/20171115040313_currency level up reward.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
using Microsoft.EntityFrameworkCore.Migrations;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Migrations
 | 
			
		||||
{
 | 
			
		||||
    public partial class currencylevelupreward : Migration
 | 
			
		||||
    {
 | 
			
		||||
        protected override void Up(MigrationBuilder migrationBuilder)
 | 
			
		||||
        {
 | 
			
		||||
            migrationBuilder.CreateTable(
 | 
			
		||||
                name: "XpCurrencyReward",
 | 
			
		||||
                columns: table => new
 | 
			
		||||
                {
 | 
			
		||||
                    Id = table.Column<int>(type: "INTEGER", nullable: false)
 | 
			
		||||
                        .Annotation("Sqlite:Autoincrement", true),
 | 
			
		||||
                    Amount = table.Column<int>(type: "INTEGER", nullable: false),
 | 
			
		||||
                    DateAdded = table.Column<DateTime>(type: "TEXT", nullable: true),
 | 
			
		||||
                    Level = table.Column<int>(type: "INTEGER", nullable: false),
 | 
			
		||||
                    XpSettingsId = table.Column<int>(type: "INTEGER", nullable: false)
 | 
			
		||||
                },
 | 
			
		||||
                constraints: table =>
 | 
			
		||||
                {
 | 
			
		||||
                    table.PrimaryKey("PK_XpCurrencyReward", x => x.Id);
 | 
			
		||||
                    table.ForeignKey(
 | 
			
		||||
                        name: "FK_XpCurrencyReward_XpSettings_XpSettingsId",
 | 
			
		||||
                        column: x => x.XpSettingsId,
 | 
			
		||||
                        principalTable: "XpSettings",
 | 
			
		||||
                        principalColumn: "Id",
 | 
			
		||||
                        onDelete: ReferentialAction.Cascade);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            migrationBuilder.CreateIndex(
 | 
			
		||||
                name: "IX_XpCurrencyReward_XpSettingsId",
 | 
			
		||||
                table: "XpCurrencyReward",
 | 
			
		||||
                column: "XpSettingsId");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void Down(MigrationBuilder migrationBuilder)
 | 
			
		||||
        {
 | 
			
		||||
            migrationBuilder.DropTable(
 | 
			
		||||
                name: "XpCurrencyReward");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1551,6 +1551,26 @@ namespace NadekoBot.Migrations
 | 
			
		||||
                    b.ToTable("WarningPunishment");
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.XpCurrencyReward", b =>
 | 
			
		||||
                {
 | 
			
		||||
                    b.Property<int>("Id")
 | 
			
		||||
                        .ValueGeneratedOnAdd();
 | 
			
		||||
 | 
			
		||||
                    b.Property<int>("Amount");
 | 
			
		||||
 | 
			
		||||
                    b.Property<DateTime?>("DateAdded");
 | 
			
		||||
 | 
			
		||||
                    b.Property<int>("Level");
 | 
			
		||||
 | 
			
		||||
                    b.Property<int>("XpSettingsId");
 | 
			
		||||
 | 
			
		||||
                    b.HasKey("Id");
 | 
			
		||||
 | 
			
		||||
                    b.HasIndex("XpSettingsId");
 | 
			
		||||
 | 
			
		||||
                    b.ToTable("XpCurrencyReward");
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.XpRoleReward", b =>
 | 
			
		||||
                {
 | 
			
		||||
                    b.Property<int>("Id")
 | 
			
		||||
@@ -1972,6 +1992,14 @@ namespace NadekoBot.Migrations
 | 
			
		||||
                        .HasForeignKey("GuildConfigId");
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.XpCurrencyReward", b =>
 | 
			
		||||
                {
 | 
			
		||||
                    b.HasOne("NadekoBot.Core.Services.Database.Models.XpSettings", "XpSettings")
 | 
			
		||||
                        .WithMany("CurrencyRewards")
 | 
			
		||||
                        .HasForeignKey("XpSettingsId")
 | 
			
		||||
                        .OnDelete(DeleteBehavior.Cascade);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            modelBuilder.Entity("NadekoBot.Core.Services.Database.Models.XpRoleReward", b =>
 | 
			
		||||
                {
 | 
			
		||||
                    b.HasOne("NadekoBot.Core.Services.Database.Models.XpSettings", "XpSettings")
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            [Priority(0)]
 | 
			
		||||
            public async Task LanguageSet()
 | 
			
		||||
            {
 | 
			
		||||
                var cul = _localization.GetCultureInfo(Context.Guild);
 | 
			
		||||
@@ -57,6 +58,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            [RequireUserPermission(GuildPermission.Administrator)]
 | 
			
		||||
            [Priority(1)]
 | 
			
		||||
            public async Task LanguageSet(string name)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
 
 | 
			
		||||
@@ -106,11 +106,60 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            [OwnerOnly]
 | 
			
		||||
            public async Task LogEvents()
 | 
			
		||||
            {
 | 
			
		||||
                _service.GuildLogSettings.TryGetValue(Context.Guild.Id, out LogSetting l);
 | 
			
		||||
                var str = string.Join("\n", Enum.GetNames(typeof(LogType))
 | 
			
		||||
                    .Select(x =>
 | 
			
		||||
                    {
 | 
			
		||||
                        var val = l == null ? null : GetLogProperty(l, Enum.Parse<LogType>(x));
 | 
			
		||||
                        if (val != null)
 | 
			
		||||
                            return $"{Format.Bold(x)} <#{val}>";
 | 
			
		||||
                        return Format.Bold(x);
 | 
			
		||||
                    }));
 | 
			
		||||
 | 
			
		||||
                await Context.Channel.SendConfirmAsync(Format.Bold(GetText("log_events")) + "\n" +
 | 
			
		||||
                                                       $"```fix\n{string.Join(", ", Enum.GetNames(typeof(LogType)).Cast<string>())}```")
 | 
			
		||||
                    str)
 | 
			
		||||
                    .ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private ulong? GetLogProperty(LogSetting l, LogType type)
 | 
			
		||||
            {
 | 
			
		||||
                switch (type)
 | 
			
		||||
                {
 | 
			
		||||
                    case LogType.Other:
 | 
			
		||||
                        return l.LogOtherId;
 | 
			
		||||
                    case LogType.MessageUpdated:
 | 
			
		||||
                        return l.MessageUpdatedId;
 | 
			
		||||
                    case LogType.MessageDeleted:
 | 
			
		||||
                        return l.MessageDeletedId;
 | 
			
		||||
                    case LogType.UserJoined:
 | 
			
		||||
                        return l.UserJoinedId;
 | 
			
		||||
                    case LogType.UserLeft:
 | 
			
		||||
                        return l.UserLeftId;
 | 
			
		||||
                    case LogType.UserBanned:
 | 
			
		||||
                        return l.UserBannedId;
 | 
			
		||||
                    case LogType.UserUnbanned:
 | 
			
		||||
                        return l.UserUnbannedId;
 | 
			
		||||
                    case LogType.UserUpdated:
 | 
			
		||||
                        return l.UserUpdatedId;
 | 
			
		||||
                    case LogType.ChannelCreated:
 | 
			
		||||
                        return l.ChannelCreatedId;
 | 
			
		||||
                    case LogType.ChannelDestroyed:
 | 
			
		||||
                        return l.ChannelDestroyedId;
 | 
			
		||||
                    case LogType.ChannelUpdated:
 | 
			
		||||
                        return l.ChannelUpdatedId;
 | 
			
		||||
                    case LogType.UserPresence:
 | 
			
		||||
                        return l.LogUserPresenceId;
 | 
			
		||||
                    case LogType.VoicePresence:
 | 
			
		||||
                        return l.LogVoicePresenceId;
 | 
			
		||||
                    case LogType.VoicePresenceTTS:
 | 
			
		||||
                        return l.LogVoicePresenceTTSId;
 | 
			
		||||
                    case LogType.UserMuted:
 | 
			
		||||
                        return l.UserMutedId;
 | 
			
		||||
                    default:
 | 
			
		||||
                        return null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            [RequireUserPermission(GuildPermission.Administrator)]
 | 
			
		||||
 
 | 
			
		||||
@@ -2,16 +2,16 @@
 | 
			
		||||
using AngleSharp.Dom.Html;
 | 
			
		||||
using Discord;
 | 
			
		||||
using Discord.WebSocket;
 | 
			
		||||
using NadekoBot.Common;
 | 
			
		||||
using NadekoBot.Common.Replacements;
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using NadekoBot.Extensions;
 | 
			
		||||
using NadekoBot.Modules.CustomReactions.Services;
 | 
			
		||||
using NadekoBot.Core.Services.Database.Models;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using NadekoBot.Common;
 | 
			
		||||
using NadekoBot.Common.Replacements;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.CustomReactions.Extensions
 | 
			
		||||
{
 | 
			
		||||
@@ -89,7 +89,7 @@ namespace NadekoBot.Modules.CustomReactions.Extensions
 | 
			
		||||
        public static string TriggerWithContext(this CustomReaction cr, IUserMessage ctx, DiscordSocketClient client)
 | 
			
		||||
            => cr.Trigger.ResolveTriggerString(ctx, client);
 | 
			
		||||
 | 
			
		||||
        public static Task<string > ResponseWithContextAsync(this CustomReaction cr, IUserMessage ctx, DiscordSocketClient client, bool containsAnywhere)
 | 
			
		||||
        public static Task<string> ResponseWithContextAsync(this CustomReaction cr, IUserMessage ctx, DiscordSocketClient client, bool containsAnywhere)
 | 
			
		||||
            => cr.Response.ResolveResponseStringAsync(ctx, client, cr.Trigger.ResolveTriggerString(ctx, client), containsAnywhere);
 | 
			
		||||
 | 
			
		||||
        public static async Task<IUserMessage> Send(this CustomReaction cr, IUserMessage ctx, DiscordSocketClient client, CustomReactionsService crs)
 | 
			
		||||
@@ -127,14 +127,35 @@ namespace NadekoBot.Modules.CustomReactions.Extensions
 | 
			
		||||
 | 
			
		||||
        public static WordPosition GetWordPosition(this string str, string word)
 | 
			
		||||
        {
 | 
			
		||||
            if (str.StartsWith(word + " "))
 | 
			
		||||
                return WordPosition.Start;
 | 
			
		||||
            else if (str.EndsWith(" " + word))
 | 
			
		||||
                return WordPosition.End;
 | 
			
		||||
            else if (str.Contains(" " + word + " "))
 | 
			
		||||
                return WordPosition.Middle;
 | 
			
		||||
            else
 | 
			
		||||
            var wordIndex = str.IndexOf(word);
 | 
			
		||||
            if (wordIndex == -1)
 | 
			
		||||
                return WordPosition.None;
 | 
			
		||||
 | 
			
		||||
            if (wordIndex == 0)
 | 
			
		||||
            {
 | 
			
		||||
                if (word.Length < str.Length && str.isValidWordDivider(word.Length))
 | 
			
		||||
                    return WordPosition.Start;
 | 
			
		||||
            }
 | 
			
		||||
            else if ((wordIndex + word.Length) == str.Length)
 | 
			
		||||
            {
 | 
			
		||||
                if (str.isValidWordDivider(wordIndex - 1))
 | 
			
		||||
                    return WordPosition.End;
 | 
			
		||||
            }
 | 
			
		||||
            else if (str.isValidWordDivider(wordIndex - 1) && str.isValidWordDivider(wordIndex + word.Length))
 | 
			
		||||
                return WordPosition.Middle;
 | 
			
		||||
 | 
			
		||||
            return WordPosition.None;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool isValidWordDivider(this string str, int index)
 | 
			
		||||
        {
 | 
			
		||||
            var ch = str[index];
 | 
			
		||||
            if (ch >= 'a' && ch <= 'z')
 | 
			
		||||
                return false;
 | 
			
		||||
            if (ch >= 'A' && ch <= 'Z')
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -20,14 +20,16 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
            private readonly IImageCache _images;
 | 
			
		||||
            private readonly IBotConfigProvider _bc;
 | 
			
		||||
            private readonly CurrencyService _cs;
 | 
			
		||||
 | 
			
		||||
            private readonly DbService _db;
 | 
			
		||||
            private static readonly NadekoRandom rng = new NadekoRandom();
 | 
			
		||||
 | 
			
		||||
            public FlipCoinCommands(IDataCache data, CurrencyService cs, IBotConfigProvider bc)
 | 
			
		||||
            public FlipCoinCommands(IDataCache data, CurrencyService cs,
 | 
			
		||||
                IBotConfigProvider bc, DbService db)
 | 
			
		||||
            {
 | 
			
		||||
                _images = data.LocalImages;
 | 
			
		||||
                _bc = bc;
 | 
			
		||||
                _cs = cs;
 | 
			
		||||
                _db = db;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
@@ -86,7 +88,18 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            public async Task Betflip(int amount, BetFlipGuess guess)
 | 
			
		||||
            public Task Betflip(Allin _, BetFlipGuess guess)
 | 
			
		||||
            {
 | 
			
		||||
                long cur;
 | 
			
		||||
                using (var uow = _db.UnitOfWork)
 | 
			
		||||
                {
 | 
			
		||||
                    cur = uow.Currency.GetUserCurrency(Context.User.Id);
 | 
			
		||||
                }
 | 
			
		||||
                return Betflip(cur, guess);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            public async Task Betflip(long amount, BetFlipGuess guess)
 | 
			
		||||
            {
 | 
			
		||||
                if (amount < _bc.BotConfig.MinimumBetAmount)
 | 
			
		||||
                {
 | 
			
		||||
 
 | 
			
		||||
@@ -278,9 +278,9 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
        //    });
 | 
			
		||||
        //    return Task.CompletedTask;
 | 
			
		||||
        //}
 | 
			
		||||
        public enum Allin { Allin, All }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        public async Task BetRoll(long amount)
 | 
			
		||||
        private async Task InternallBetroll(long amount)
 | 
			
		||||
        {
 | 
			
		||||
            if (amount < 1)
 | 
			
		||||
                return;
 | 
			
		||||
@@ -303,24 +303,39 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
                {
 | 
			
		||||
                    str += GetText("br_win", (amount * _bc.BotConfig.Betroll67Multiplier) + CurrencySign, 66);
 | 
			
		||||
                    await _cs.AddAsync(Context.User, "Betroll Gamble",
 | 
			
		||||
                        (int) (amount * _bc.BotConfig.Betroll67Multiplier), false).ConfigureAwait(false);
 | 
			
		||||
                        (int)(amount * _bc.BotConfig.Betroll67Multiplier), false).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                else if (rnd < 100)
 | 
			
		||||
                {
 | 
			
		||||
                    str += GetText("br_win", (amount * _bc.BotConfig.Betroll91Multiplier) + CurrencySign, 90);
 | 
			
		||||
                    await _cs.AddAsync(Context.User, "Betroll Gamble",
 | 
			
		||||
                        (int) (amount * _bc.BotConfig.Betroll91Multiplier), false).ConfigureAwait(false);
 | 
			
		||||
                        (int)(amount * _bc.BotConfig.Betroll91Multiplier), false).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    str += GetText("br_win", (amount * _bc.BotConfig.Betroll100Multiplier) + CurrencySign, 99) + " 👑";
 | 
			
		||||
                    await _cs.AddAsync(Context.User, "Betroll Gamble",
 | 
			
		||||
                        (int) (amount * _bc.BotConfig.Betroll100Multiplier), false).ConfigureAwait(false);
 | 
			
		||||
                        (int)(amount * _bc.BotConfig.Betroll100Multiplier), false).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            await Context.Channel.SendConfirmAsync(str).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        public Task BetRoll(long amount)
 | 
			
		||||
            => InternallBetroll(amount);
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        public Task BetRoll(Allin _)
 | 
			
		||||
        {
 | 
			
		||||
            long cur;
 | 
			
		||||
            using (var uow = _db.UnitOfWork)
 | 
			
		||||
            {
 | 
			
		||||
                cur = uow.Currency.GetUserCurrency(Context.User.Id);
 | 
			
		||||
            }
 | 
			
		||||
            return InternallBetroll(cur);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        public async Task Leaderboard(int page = 1)
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -15,16 +15,31 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
        {
 | 
			
		||||
            private readonly CurrencyService _cs;
 | 
			
		||||
            private readonly IBotConfigProvider _bc;
 | 
			
		||||
            private readonly DbService _db;
 | 
			
		||||
 | 
			
		||||
            public WheelOfFortuneCommands(CurrencyService cs, IBotConfigProvider bc)
 | 
			
		||||
            public WheelOfFortuneCommands(CurrencyService cs, IBotConfigProvider bc,
 | 
			
		||||
                DbService db)
 | 
			
		||||
            {
 | 
			
		||||
                _cs = cs;
 | 
			
		||||
                _bc = bc;
 | 
			
		||||
                _db = db;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public enum Allin { Allin, All }
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            public Task WheelOfFortune(Allin _)
 | 
			
		||||
            {
 | 
			
		||||
                long cur;
 | 
			
		||||
                using (var uow = _db.UnitOfWork)
 | 
			
		||||
                {
 | 
			
		||||
                    cur = uow.Currency.GetUserCurrency(Context.User.Id);
 | 
			
		||||
                }
 | 
			
		||||
                return WheelOfFortune(cur);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task WheelOfFortune(int bet)
 | 
			
		||||
            public async Task WheelOfFortune(long bet)
 | 
			
		||||
            {
 | 
			
		||||
                const int minBet = 10;
 | 
			
		||||
                if (bet < minBet)
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,8 @@ using System.Collections.Generic;
 | 
			
		||||
using NadekoBot.Common.Attributes;
 | 
			
		||||
using NadekoBot.Modules.Help.Services;
 | 
			
		||||
using NadekoBot.Modules.Permissions.Services;
 | 
			
		||||
using NadekoBot.Common;
 | 
			
		||||
using NadekoBot.Common.Replacements;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Help
 | 
			
		||||
{
 | 
			
		||||
@@ -23,8 +25,23 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
        private readonly CommandService _cmds;
 | 
			
		||||
        private readonly GlobalPermissionService _perms;
 | 
			
		||||
 | 
			
		||||
        public string HelpString => String.Format(_config.BotConfig.HelpString, _creds.ClientId, Prefix);
 | 
			
		||||
        public string DMHelpString => _config.BotConfig.DMHelpString;
 | 
			
		||||
        public EmbedBuilder GetHelpStringEmbed()
 | 
			
		||||
        {
 | 
			
		||||
            var r = new ReplacementBuilder()
 | 
			
		||||
                .WithDefault(Context)
 | 
			
		||||
                .WithOverride("{0}", () => _creds.ClientId.ToString())
 | 
			
		||||
                .WithOverride("{1}", () => Prefix)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            if (!CREmbed.TryParse(_config.BotConfig.HelpString, out var embed))
 | 
			
		||||
                return new EmbedBuilder().WithOkColor()
 | 
			
		||||
                    .WithDescription(String.Format(_config.BotConfig.HelpString, _creds.ClientId, Prefix));
 | 
			
		||||
 | 
			
		||||
            r.Replace(embed);
 | 
			
		||||
 | 
			
		||||
            return embed.ToEmbed();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Help(IBotCredentials creds, GlobalPermissionService perms, IBotConfigProvider config, CommandService cmds)
 | 
			
		||||
        {
 | 
			
		||||
@@ -94,16 +111,10 @@ namespace NadekoBot.Modules.Help
 | 
			
		||||
            if (com == null)
 | 
			
		||||
            {
 | 
			
		||||
                IMessageChannel ch = channel is ITextChannel ? await ((IGuildUser)Context.User).GetOrCreateDMChannelAsync() : channel;
 | 
			
		||||
                await ch.SendMessageAsync(HelpString).ConfigureAwait(false);
 | 
			
		||||
                await ch.EmbedAsync(GetHelpStringEmbed()).ConfigureAwait(false);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //if (com == null)
 | 
			
		||||
            //{
 | 
			
		||||
            //    await ReplyErrorLocalized("command_not_found").ConfigureAwait(false);
 | 
			
		||||
            //    return;
 | 
			
		||||
            //}
 | 
			
		||||
 | 
			
		||||
            var embed = _service.GetCommandHelp(com, Context.Guild);
 | 
			
		||||
            await channel.EmbedAsync(embed).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,8 @@ using NadekoBot.Common.Attributes;
 | 
			
		||||
using NadekoBot.Common.ModuleBehaviors;
 | 
			
		||||
using NadekoBot.Core.Services;
 | 
			
		||||
using NadekoBot.Core.Services.Impl;
 | 
			
		||||
using NadekoBot.Common;
 | 
			
		||||
using NLog;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Help.Services
 | 
			
		||||
{
 | 
			
		||||
@@ -17,26 +19,34 @@ namespace NadekoBot.Modules.Help.Services
 | 
			
		||||
        private readonly IBotConfigProvider _bc;
 | 
			
		||||
        private readonly CommandHandler _ch;
 | 
			
		||||
        private readonly NadekoStrings _strings;
 | 
			
		||||
        private readonly Logger _log;
 | 
			
		||||
 | 
			
		||||
        public HelpService(IBotConfigProvider bc, CommandHandler ch, NadekoStrings strings)
 | 
			
		||||
        {
 | 
			
		||||
            _bc = bc;
 | 
			
		||||
            _ch = ch;
 | 
			
		||||
            _strings = strings;
 | 
			
		||||
            _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task LateExecute(DiscordSocketClient client, IGuild guild, IUserMessage msg)
 | 
			
		||||
        public Task LateExecute(DiscordSocketClient client, IGuild guild, IUserMessage msg)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                if(guild == null)
 | 
			
		||||
                    await msg.Channel.SendMessageAsync(_bc.BotConfig.DMHelpString).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception)
 | 
			
		||||
                if (guild == null)
 | 
			
		||||
                {
 | 
			
		||||
                //ignore
 | 
			
		||||
                    if (CREmbed.TryParse(_bc.BotConfig.DMHelpString, out var embed))
 | 
			
		||||
                        return msg.Channel.EmbedAsync(embed.ToEmbed(), embed.PlainText?.SanitizeMentions() ?? "");
 | 
			
		||||
 | 
			
		||||
                    return msg.Channel.SendMessageAsync(_bc.BotConfig.DMHelpString);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                _log.Warn(ex);
 | 
			
		||||
            }
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public EmbedBuilder GetCommandHelp(CommandInfo com, IGuild guild)
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -89,6 +89,7 @@ namespace NadekoBot.Modules.Permissions
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    _service.InviteFilteringChannels.TryRemove(channel.Id);
 | 
			
		||||
                    await ReplyConfirmLocalized("invite_filter_channel_off").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
 | 
			
		||||
                if (novelData == null)
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalized("error_finding_novel").ConfigureAwait(false);
 | 
			
		||||
                    await ReplyErrorLocalized("failed_finding_novel").ConfigureAwait(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -35,7 +35,7 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
                    .WithTitle(novelData.Title)
 | 
			
		||||
                    .WithUrl(novelData.Link)
 | 
			
		||||
                    .WithImageUrl(novelData.ImageUrl)
 | 
			
		||||
                    .AddField(efb => efb.WithName(GetText("authors")).WithValue(String.Join("\n", novelData.Authors)).WithIsInline(true))
 | 
			
		||||
                    .AddField(efb => efb.WithName(GetText("authors")).WithValue(string.Join("\n", novelData.Authors)).WithIsInline(true))
 | 
			
		||||
                    .AddField(efb => efb.WithName(GetText("status")).WithValue(novelData.Status).WithIsInline(true))
 | 
			
		||||
                    .AddField(efb => efb.WithName(GetText("genres")).WithValue(string.Join(" ", novelData.Genres.Any() ? novelData.Genres : new[] { "none" })).WithIsInline(true))
 | 
			
		||||
                    .WithFooter(efb => efb.WithText(GetText("score") + " " + novelData.Score));
 | 
			
		||||
 
 | 
			
		||||
@@ -67,6 +67,8 @@ namespace NadekoBot.Modules.Searches.Services
 | 
			
		||||
                    var document = await BrowsingContext.New(config).OpenAsync(link);
 | 
			
		||||
 | 
			
		||||
                    var imageElem = document.QuerySelector("div.seriesimg > img");
 | 
			
		||||
                    if (imageElem == null)
 | 
			
		||||
                        return null;
 | 
			
		||||
                    var imageUrl = ((IHtmlImageElement)imageElem).Source;
 | 
			
		||||
 | 
			
		||||
                    var descElem = document.QuerySelector("div#editdescription > p");
 | 
			
		||||
 
 | 
			
		||||
@@ -51,7 +51,6 @@ namespace NadekoBot.Modules.Searches.Services
 | 
			
		||||
        public ConcurrentDictionary<ulong, Timer> AutoButtTimers { get; } = new ConcurrentDictionary<ulong, Timer>();
 | 
			
		||||
 | 
			
		||||
        private readonly ConcurrentDictionary<ulong, HashSet<string>> _blacklistedTags = new ConcurrentDictionary<ulong, HashSet<string>>();
 | 
			
		||||
        private readonly Timer _t;
 | 
			
		||||
 | 
			
		||||
        private readonly SemaphoreSlim _cryptoLock = new SemaphoreSlim(1, 1);
 | 
			
		||||
        public async Task<CryptoData[]> CryptoData()
 | 
			
		||||
@@ -132,22 +131,6 @@ namespace NadekoBot.Modules.Searches.Services
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            if (client.ShardId == 0)
 | 
			
		||||
            {
 | 
			
		||||
                _t = new Timer(async _ =>
 | 
			
		||||
                {
 | 
			
		||||
                    var r = _cache.Redis.GetDatabase();
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception ex)
 | 
			
		||||
                    {
 | 
			
		||||
                        _log.Warn(ex);
 | 
			
		||||
                    }
 | 
			
		||||
                }, null, TimeSpan.Zero, TimeSpan.FromHours(1));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //joke commands
 | 
			
		||||
            if (File.Exists("data/wowjokes.json"))
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
        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 int? pledge_cap_cents { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class Address
 | 
			
		||||
 
 | 
			
		||||
@@ -118,7 +118,7 @@ namespace NadekoBot.Modules.Utility
 | 
			
		||||
            [OwnerOnly]
 | 
			
		||||
            public async Task Activity(int page = 1)
 | 
			
		||||
            {
 | 
			
		||||
                const int activityPerPage = 15;
 | 
			
		||||
                const int activityPerPage = 10;
 | 
			
		||||
                page -= 1;
 | 
			
		||||
 | 
			
		||||
                if (page < 0)
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,8 @@ namespace NadekoBot.Modules.Xp.Services
 | 
			
		||||
        private readonly NadekoStrings _strings;
 | 
			
		||||
        private readonly IDataCache _cache;
 | 
			
		||||
        private readonly FontProvider _fonts;
 | 
			
		||||
        private readonly IBotCredentials _creds;
 | 
			
		||||
        private readonly CurrencyService _cs;
 | 
			
		||||
        public const int XP_REQUIRED_LVL_1 = 36;
 | 
			
		||||
 | 
			
		||||
        private readonly ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> _excludedRoles
 | 
			
		||||
@@ -60,7 +62,7 @@ namespace NadekoBot.Modules.Xp.Services
 | 
			
		||||
 | 
			
		||||
        public XpService(CommandHandler cmd, IBotConfigProvider bc,
 | 
			
		||||
            NadekoBot bot, DbService db, NadekoStrings strings, IDataCache cache,
 | 
			
		||||
            FontProvider fonts)
 | 
			
		||||
            FontProvider fonts, IBotCredentials creds, CurrencyService cs)
 | 
			
		||||
        {
 | 
			
		||||
            _db = db;
 | 
			
		||||
            _cmd = cmd;
 | 
			
		||||
@@ -70,6 +72,8 @@ namespace NadekoBot.Modules.Xp.Services
 | 
			
		||||
            _strings = strings;
 | 
			
		||||
            _cache = cache;
 | 
			
		||||
            _fonts = fonts;
 | 
			
		||||
            _creds = creds;
 | 
			
		||||
            _cs = cs;
 | 
			
		||||
 | 
			
		||||
            //load settings
 | 
			
		||||
            var allGuildConfigs = bot.AllGuildConfigs.Where(x => x.XpSettings != null);
 | 
			
		||||
@@ -105,6 +109,7 @@ namespace NadekoBot.Modules.Xp.Services
 | 
			
		||||
                {
 | 
			
		||||
                    var toNotify = new List<(IMessageChannel MessageChannel, IUser User, int Level, XpNotificationType NotifyType, NotifOf NotifOf)>();
 | 
			
		||||
                    var roleRewards = new Dictionary<ulong, List<XpRoleReward>>();
 | 
			
		||||
                    var curRewards = new Dictionary<ulong, List<XpCurrencyReward>>();
 | 
			
		||||
 | 
			
		||||
                    var toAddTo = new List<UserCacheItem>();
 | 
			
		||||
                    while (_addMessageXp.TryDequeue(out var usr))
 | 
			
		||||
@@ -120,14 +125,13 @@ namespace NadekoBot.Modules.Xp.Services
 | 
			
		||||
                        {
 | 
			
		||||
                            var xp = item.Select(x => bc.BotConfig.XpPerMessage).Sum();
 | 
			
		||||
 | 
			
		||||
                            //1. Mass query discord users and userxpstats and get them from local dict
 | 
			
		||||
                            //2. (better but much harder) Move everything to the database, and get old and new xp
 | 
			
		||||
                            // amounts for every user (in order to give rewards)
 | 
			
		||||
 | 
			
		||||
                            var usr = uow.Xp.GetOrCreateUser(item.Key.GuildId, item.Key.User.Id);
 | 
			
		||||
                            var du = uow.DiscordUsers.GetOrCreate(item.Key.User);
 | 
			
		||||
 | 
			
		||||
                            if (du.LastXpGain + TimeSpan.FromMinutes(_bc.BotConfig.XpMinutesTimeout) > DateTime.UtcNow)
 | 
			
		||||
                                continue;
 | 
			
		||||
 | 
			
		||||
                            du.LastXpGain = DateTime.UtcNow;
 | 
			
		||||
 | 
			
		||||
                            var globalXp = du.TotalXp;
 | 
			
		||||
                            var oldGlobalLevelData = new LevelStats(globalXp);
 | 
			
		||||
                            var newGlobalLevelData = new LevelStats(globalXp + xp);
 | 
			
		||||
@@ -156,21 +160,34 @@ namespace NadekoBot.Modules.Xp.Services
 | 
			
		||||
                                    toNotify.Add((first.Channel, first.User, newGuildLevelData.Level, usr.NotifyOnLevelUp, NotifOf.Server));
 | 
			
		||||
 | 
			
		||||
                                //give role
 | 
			
		||||
                                if (!roleRewards.TryGetValue(usr.GuildId, out var rewards))
 | 
			
		||||
                                if (!roleRewards.TryGetValue(usr.GuildId, out var rrews))
 | 
			
		||||
                                {
 | 
			
		||||
                                    rewards = uow.GuildConfigs.XpSettingsFor(usr.GuildId).RoleRewards.ToList();
 | 
			
		||||
                                    roleRewards.Add(usr.GuildId, rewards);
 | 
			
		||||
                                    rrews = uow.GuildConfigs.XpSettingsFor(usr.GuildId).RoleRewards.ToList();
 | 
			
		||||
                                    roleRewards.Add(usr.GuildId, rrews);
 | 
			
		||||
                                }
 | 
			
		||||
 | 
			
		||||
                                var rew = rewards.FirstOrDefault(x => x.Level == newGuildLevelData.Level);
 | 
			
		||||
                                if (rew != null)
 | 
			
		||||
                                if (!curRewards.TryGetValue(usr.GuildId, out var crews))
 | 
			
		||||
                                {
 | 
			
		||||
                                    var role = first.User.Guild.GetRole(rew.RoleId);
 | 
			
		||||
                                    crews = uow.GuildConfigs.XpSettingsFor(usr.GuildId).CurrencyRewards.ToList();
 | 
			
		||||
                                    curRewards.Add(usr.GuildId, crews);
 | 
			
		||||
                                }
 | 
			
		||||
 | 
			
		||||
                                var rrew = rrews.FirstOrDefault(x => x.Level == newGuildLevelData.Level);
 | 
			
		||||
                                if (rrew != null)
 | 
			
		||||
                                {
 | 
			
		||||
                                    var role = first.User.Guild.GetRole(rrew.RoleId);
 | 
			
		||||
                                    if (role != null)
 | 
			
		||||
                                    {
 | 
			
		||||
                                        var __ = first.User.AddRoleAsync(role);
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                                //get currency reward for this level
 | 
			
		||||
                                var crew = crews.FirstOrDefault(x => x.Level == newGuildLevelData.Level);
 | 
			
		||||
                                if (crew != null)
 | 
			
		||||
                                {
 | 
			
		||||
                                    //give the user the reward if it exists
 | 
			
		||||
                                    await _cs.AddAsync(item.Key.User.Id, "Level-up Reward", crew.Amount, uow);
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
@@ -241,6 +258,50 @@ namespace NadekoBot.Modules.Xp.Services
 | 
			
		||||
            }, token);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void SetCurrencyReward(ulong guildId, int level, int amount)
 | 
			
		||||
        {
 | 
			
		||||
            using (var uow = _db.UnitOfWork)
 | 
			
		||||
            {
 | 
			
		||||
                var settings = uow.GuildConfigs.XpSettingsFor(guildId);
 | 
			
		||||
 | 
			
		||||
                if (amount <= 0)
 | 
			
		||||
                {
 | 
			
		||||
                    var toRemove = settings.CurrencyRewards.FirstOrDefault(x => x.Level == level);
 | 
			
		||||
                    if (toRemove != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        uow._context.Remove(toRemove);
 | 
			
		||||
                        settings.CurrencyRewards.Remove(toRemove);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
                    var rew = settings.CurrencyRewards.FirstOrDefault(x => x.Level == level);
 | 
			
		||||
 | 
			
		||||
                    if (rew != null)
 | 
			
		||||
                        rew.Amount = amount;
 | 
			
		||||
                    else
 | 
			
		||||
                        settings.CurrencyRewards.Add(new XpCurrencyReward()
 | 
			
		||||
                        {
 | 
			
		||||
                            Level = level,
 | 
			
		||||
                            Amount = amount,
 | 
			
		||||
                        });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                uow.Complete();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<XpCurrencyReward> GetCurrencyRewards(ulong id)
 | 
			
		||||
        {
 | 
			
		||||
            using (var uow = _db.UnitOfWork)
 | 
			
		||||
            {
 | 
			
		||||
                return uow.GuildConfigs.XpSettingsFor(id)
 | 
			
		||||
                    .CurrencyRewards
 | 
			
		||||
                    .ToArray();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<XpRoleReward> GetRoleRewards(ulong id)
 | 
			
		||||
        {
 | 
			
		||||
            using (var uow = _db.UnitOfWork)
 | 
			
		||||
@@ -385,7 +446,13 @@ namespace NadekoBot.Modules.Xp.Services
 | 
			
		||||
 | 
			
		||||
        private bool SetUserRewarded(ulong userId)
 | 
			
		||||
        {
 | 
			
		||||
            return _rewardedUsers.Add(userId);
 | 
			
		||||
            var r = _cache.Redis.GetDatabase();
 | 
			
		||||
            var key = $"{_creds.RedisKey()}_user_xp_gain_{userId}";
 | 
			
		||||
 | 
			
		||||
            return r.StringSet(key, 
 | 
			
		||||
                true, 
 | 
			
		||||
                TimeSpan.FromMinutes(_bc.BotConfig.XpMinutesTimeout), 
 | 
			
		||||
                StackExchange.Redis.When.NotExists);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public FullUserStats GetUserStats(IGuildUser user)
 | 
			
		||||
 
 | 
			
		||||
@@ -17,40 +17,18 @@ namespace NadekoBot.Modules.Xp
 | 
			
		||||
    {
 | 
			
		||||
        private readonly DiscordSocketClient _client;
 | 
			
		||||
        private readonly DbService _db;
 | 
			
		||||
        private readonly IBotConfigProvider _bc;
 | 
			
		||||
 | 
			
		||||
        public Xp(DiscordSocketClient client,DbService db)
 | 
			
		||||
        public Xp(DiscordSocketClient client,DbService db, IBotConfigProvider bc)
 | 
			
		||||
        {
 | 
			
		||||
            _client = client;
 | 
			
		||||
            _db = db;
 | 
			
		||||
            _bc = bc;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        //[NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        //[RequireContext(ContextType.Guild)]
 | 
			
		||||
        //[OwnerOnly]
 | 
			
		||||
        //public async Task Populate()
 | 
			
		||||
        //{
 | 
			
		||||
        //    var rng = new NadekoRandom();
 | 
			
		||||
        //    using (var uow = _db.UnitOfWork)
 | 
			
		||||
        //    {
 | 
			
		||||
        //        for (var i = 0ul; i < 1000000; i++)
 | 
			
		||||
        //        {
 | 
			
		||||
        //            uow.DiscordUsers.Add(new DiscordUser()
 | 
			
		||||
        //            {
 | 
			
		||||
        //                AvatarId = i.ToString(),
 | 
			
		||||
        //                Discriminator = "1234",
 | 
			
		||||
        //                UserId = i,
 | 
			
		||||
        //                Username = i.ToString(),
 | 
			
		||||
        //                Club = null,
 | 
			
		||||
        //            });
 | 
			
		||||
        //            var xp = uow.Xp.GetOrCreateUser(Context.Guild.Id, i);
 | 
			
		||||
        //            xp.Xp = rng.Next(100, 100000);
 | 
			
		||||
        //        }
 | 
			
		||||
        //        uow.Complete();
 | 
			
		||||
        //    }
 | 
			
		||||
        //}
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        //todo add ratelimit attribute
 | 
			
		||||
        //[Ratelimit(30)]
 | 
			
		||||
        public async Task Experience([Remainder]IUser user = null)
 | 
			
		||||
        {
 | 
			
		||||
@@ -69,34 +47,39 @@ namespace NadekoBot.Modules.Xp
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        public Task XpRoleRewards(int page = 1)
 | 
			
		||||
        public Task XpLevelUpRewards(int page = 1)
 | 
			
		||||
        {
 | 
			
		||||
            page--;
 | 
			
		||||
 | 
			
		||||
            if (page < 0 || page > 100)
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
            var roles = _service.GetRoleRewards(Context.Guild.Id)
 | 
			
		||||
                .OrderBy(x => x.Level)
 | 
			
		||||
                .Skip(page * 9)
 | 
			
		||||
                .Take(9);
 | 
			
		||||
 | 
			
		||||
            var embed = new EmbedBuilder()
 | 
			
		||||
                .WithTitle(GetText("role_rewards"))
 | 
			
		||||
                .WithTitle(GetText("level_up_rewards"))
 | 
			
		||||
                .WithOkColor();
 | 
			
		||||
 | 
			
		||||
            if (!roles.Any())
 | 
			
		||||
                return Context.Channel.EmbedAsync(embed.WithDescription(GetText("no_role_rewards")));
 | 
			
		||||
 | 
			
		||||
            foreach (var rolerew in roles)
 | 
			
		||||
            var rewards = _service.GetRoleRewards(Context.Guild.Id)
 | 
			
		||||
                .OrderBy(x => x.Level)
 | 
			
		||||
                .Select(x =>
 | 
			
		||||
                {
 | 
			
		||||
                var role = Context.Guild.GetRole(rolerew.RoleId);
 | 
			
		||||
                    var str = Context.Guild.GetRole(x.RoleId)?.ToString();
 | 
			
		||||
                    if (str != null)
 | 
			
		||||
                        str = GetText("role_reward", Format.Bold(str));
 | 
			
		||||
                    return (x.Level, RoleStr: str);
 | 
			
		||||
                })
 | 
			
		||||
                .Where(x => x.RoleStr != null)
 | 
			
		||||
                .Concat(_service.GetCurrencyRewards(Context.Guild.Id)
 | 
			
		||||
                    .OrderBy(x => x.Level)
 | 
			
		||||
                    .Select(x => (x.Level, Format.Bold(x.Amount + _bc.BotConfig.CurrencySign))))
 | 
			
		||||
                    .GroupBy(x => x.Level)
 | 
			
		||||
                    .OrderBy(x => x.Key)
 | 
			
		||||
                    .Skip(page * 9)
 | 
			
		||||
                    .Take(9)
 | 
			
		||||
                    .ForEach(x => embed.AddField(GetText("level_x", x.Key), string.Join("\n", x.Select(y => y.Item2))));
 | 
			
		||||
 | 
			
		||||
                if (role == null)
 | 
			
		||||
                    continue;
 | 
			
		||||
            if (!rewards.Any())
 | 
			
		||||
                return Context.Channel.EmbedAsync(embed.WithDescription(GetText("no_level_up_rewards")));
 | 
			
		||||
 | 
			
		||||
                embed.AddField(GetText("level_x", Format.Bold(rolerew.Level.ToString())), role.ToString());
 | 
			
		||||
            }
 | 
			
		||||
            return Context.Channel.EmbedAsync(embed);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -116,6 +99,22 @@ namespace NadekoBot.Modules.Xp
 | 
			
		||||
                await ReplyConfirmLocalized("role_reward_added", level, Format.Bold(role.ToString())).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [OwnerOnly]
 | 
			
		||||
        public async Task XpCurrencyReward(int level, int amount=0)
 | 
			
		||||
        {
 | 
			
		||||
            if (level < 1 || amount < 0)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _service.SetCurrencyReward(Context.Guild.Id, level, amount);
 | 
			
		||||
 | 
			
		||||
            if (amount == 0)
 | 
			
		||||
                await ReplyConfirmLocalized("cur_reward_cleared", level, _bc.BotConfig.CurrencySign).ConfigureAwait(false);
 | 
			
		||||
            else
 | 
			
		||||
                await ReplyConfirmLocalized("cur_reward_added", level, Format.Bold(amount + _bc.BotConfig.CurrencySign)).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public enum NotifyPlace
 | 
			
		||||
        {
 | 
			
		||||
            Server = 0,
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
        public GuildConfig GuildConfig { get; set; }
 | 
			
		||||
 | 
			
		||||
        public HashSet<XpRoleReward> RoleRewards { get; set; } = new HashSet<XpRoleReward>();
 | 
			
		||||
        public HashSet<XpCurrencyReward> CurrencyRewards { get; set; } = new HashSet<XpCurrencyReward>();
 | 
			
		||||
        public bool XpRoleRewardExclusive { get; set; }
 | 
			
		||||
        public string NotifyMessage { get; set; } = "Congratulations {0}! You have reached level {1}!";
 | 
			
		||||
        public HashSet<ExcludedItem> ExclusionList { get; set; } = new HashSet<ExcludedItem>();
 | 
			
		||||
@@ -35,6 +36,25 @@ namespace NadekoBot.Core.Services.Database.Models
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class XpCurrencyReward : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public int XpSettingsId { get; set; }
 | 
			
		||||
        public XpSettings XpSettings { get; set; }
 | 
			
		||||
 | 
			
		||||
        public int Level { get; set; }
 | 
			
		||||
        public int Amount { get; set; }
 | 
			
		||||
 | 
			
		||||
        public override int GetHashCode()
 | 
			
		||||
        {
 | 
			
		||||
            return Level.GetHashCode() ^ XpSettingsId.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool Equals(object obj)
 | 
			
		||||
        {
 | 
			
		||||
            return obj is XpCurrencyReward xrr && xrr.Level == Level && xrr.XpSettingsId == XpSettingsId;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class ExcludedItem : DbEntity
 | 
			
		||||
    {
 | 
			
		||||
        public ulong ItemId { get; set; }
 | 
			
		||||
 
 | 
			
		||||
@@ -200,6 +200,8 @@ namespace NadekoBot.Core.Services.Database.Repositories.Impl
 | 
			
		||||
                set => set.Include(x => x.XpSettings)
 | 
			
		||||
                          .ThenInclude(x => x.RoleRewards)
 | 
			
		||||
                          .Include(x => x.XpSettings)
 | 
			
		||||
                          .ThenInclude(x => x.CurrencyRewards)
 | 
			
		||||
                          .Include(x => x.XpSettings)
 | 
			
		||||
                          .ThenInclude(x => x.ExclusionList));
 | 
			
		||||
 | 
			
		||||
            if (gc.XpSettings == null)
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ namespace NadekoBot.Core.Services.Impl
 | 
			
		||||
        private readonly IBotCredentials _creds;
 | 
			
		||||
        private readonly DateTime _started;
 | 
			
		||||
 | 
			
		||||
        public const string BotVersion = "2.4.3";
 | 
			
		||||
        public const string BotVersion = "2.5.1";
 | 
			
		||||
 | 
			
		||||
        public string Author => "Kwoth#2560";
 | 
			
		||||
        public string Library => "Discord.Net";
 | 
			
		||||
 
 | 
			
		||||
@@ -228,9 +228,6 @@
 | 
			
		||||
  "gambling_flipped": "flipped {0}.",
 | 
			
		||||
  "gambling_flip_guess": "You guessed it! You won {0}",
 | 
			
		||||
  "gambling_flip_invalid": "Invalid number specified. You can flip 1 to {0} coins.",
 | 
			
		||||
  "gambling_flowerreaction_desc": "Add {0} reaction to this message to get {1} ",
 | 
			
		||||
  "gambling_flowerreaction_footer": "This event is active for up to {0} hours.",
 | 
			
		||||
  "gambling_flowerreaction_title": "Flower reaction event started!",
 | 
			
		||||
  "gambling_gifted": "has gifted {0} to {1}",
 | 
			
		||||
  "gambling_has": "{0} has {1}",
 | 
			
		||||
  "gambling_heads": "Head",
 | 
			
		||||
@@ -841,11 +838,14 @@
 | 
			
		||||
  "xp_level_up_channel": "Congratulations {0}, You've reached level {1}!",
 | 
			
		||||
  "xp_level_up_dm": "Congratulations {0}, You've reached level {1} on {2} server!",
 | 
			
		||||
  "xp_level_up_global": "Congratulations {0}, You've reached global level {1}!",
 | 
			
		||||
  "xp_role_reward_cleared": "Level {0} will no longer reward a role.",
 | 
			
		||||
  "xp_role_reward_cleared": "Reaching level {0} will no longer reward a role.",
 | 
			
		||||
  "xp_role_reward_added": "Users who reach level {0} will receive {1} role.",
 | 
			
		||||
  "xp_role_rewards": "Role Rewards",
 | 
			
		||||
  "xp_cur_reward_cleared": "Reaching level {0} will no longer reward any {1}.",
 | 
			
		||||
  "xp_cur_reward_added": "Users who reach level {0} will receive {1}.",
 | 
			
		||||
  "xp_level_up_rewards": "Level Up Rewards",
 | 
			
		||||
  "xp_level_x": "Level {0}",
 | 
			
		||||
  "xp_no_role_rewards": "No role reward on this page.",
 | 
			
		||||
  "xp_role_reward": "{0} role",
 | 
			
		||||
  "xp_no_level_up_rewards": "No level up reward on this page.",
 | 
			
		||||
  "xp_server_leaderboard": "Server XP Leaderboard",
 | 
			
		||||
  "xp_global_leaderboard": "Global XP Leaderboard",
 | 
			
		||||
  "xp_modified": "Modified server XP of the user {0} by {1}",
 | 
			
		||||
@@ -923,5 +923,5 @@
 | 
			
		||||
  "administration_invalid": "Invalid / Can't be found ({0})",
 | 
			
		||||
  "administration_mass_kill_in_progress": "Mass Banning and Blacklisting of {0} users is in progress...",
 | 
			
		||||
  "administration_mass_kill_completed": "Mass Banning and Blacklisting of {0} users is complete.",
 | 
			
		||||
  "searches_error_finding_novel": "Can't find that novel. Make sure you've typed the exact full name, and that it exists on novelupdates.com"
 | 
			
		||||
  "searches_failed_finding_novel": "Can't find that novel. Make sure you've typed the exact full name, and that it exists on novelupdates.com"
 | 
			
		||||
}
 | 
			
		||||
@@ -2815,11 +2815,11 @@
 | 
			
		||||
      "{0}xpn server channel"
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
  "xprolerewards": {
 | 
			
		||||
    "Cmd": "xprolerewards xprrs",
 | 
			
		||||
    "Desc": "Shows currently set role rewards.",
 | 
			
		||||
  "xpleveluprewards": {
 | 
			
		||||
    "Cmd": "xplvluprewards xprews xpcrs xprrs xprolerewards xpcurrewards",
 | 
			
		||||
    "Desc": "Shows currently set level up rewards.",
 | 
			
		||||
    "Usage": [
 | 
			
		||||
      "{0}xprrs"
 | 
			
		||||
      "{0}xprews"
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
  "xprolereward": {
 | 
			
		||||
@@ -2829,6 +2829,13 @@
 | 
			
		||||
      "{0}xprr 3 Social"
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
  "xpcurrencyreward": {
 | 
			
		||||
    "Cmd": "xpcurreward xpcr",
 | 
			
		||||
    "Desc": "Sets a currency reward on a specified level. Provide no amount in order to remove the reward.",
 | 
			
		||||
    "Usage": [
 | 
			
		||||
      "{0}xpcr 3 50"
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
  "xpleaderboard": {
 | 
			
		||||
    "Cmd": "xpleaderboard xplb",
 | 
			
		||||
    "Desc": "Shows current server's xp leaderboard.",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user