Пример #1
0
        public async Task SetFeaturePermissionForChannel(CommandContext ctx,
                                                         [Description("The feature to configure")] string feature,
                                                         [Description("The channel to configure (without the #)")] string channel,
                                                         [Description("The default permission on the feature")] bool permission)
        {
            await ctx.TriggerTypingAsync();

            if (!feature.IsFeature())
            {
                var emoji = DiscordEmoji.FromName(ctx.Client, ":no_entry:");
                var embed = new DiscordEmbedBuilder
                {
                    Title       = "Invalid Feature",
                    Description = $"{emoji} There is no feature called `{feature}`. Check all the features with `admin features`.",
                    Color       = DiscordColor.Red
                };

                await ctx.RespondAsync("", embed : embed);

                return;
            }

            var configuration = GuildConfiguration.FromGuild(ctx.Guild);

            if (!configuration.PermissionsByFeatureChannel.TryGetValue(feature, out var permissions))
            {
                permissions = new Dictionary <string, bool>();
                configuration.PermissionsByFeatureChannel[feature] = permissions;
            }
            permissions[channel] = permission;

            configuration.Save();

            await ctx.RespondAsync($"The default permission to the `{feature}` feature on the `{channel}` channel is now `{permission}`.");
        }
Пример #2
0
        public async Task SetFeaturePermission(CommandContext ctx,
                                               [Description("The feature to configure")] string feature,
                                               [Description("The default permission on the feature")] bool permission)
        {
            await ctx.TriggerTypingAsync();

            if (!feature.IsFeature())
            {
                var emoji = DiscordEmoji.FromName(ctx.Client, ":no_entry:");
                var embed = new DiscordEmbedBuilder
                {
                    Title       = "Invalid Feature",
                    Description = $"{emoji} There is no feature called `{feature}`. Check all the features with `admin features`.",
                    Color       = DiscordColor.Red
                };

                await ctx.RespondAsync("", embed : embed);

                return;
            }

            var configuration = GuildConfiguration.FromGuild(ctx.Guild);

            configuration.PermissionByFeature[feature] = permission;

            configuration.Save();

            await ctx.RespondAsync($"The default permission to the `{feature}` feature is now `{permission}`.");
        }
Пример #3
0
        public async Task ClearFeaturePermissions(CommandContext ctx,
                                                  [Description("The feature to clear permissions")] string feature)
        {
            await ctx.TriggerTypingAsync();

            if (!feature.IsFeature())
            {
                var emoji = DiscordEmoji.FromName(ctx.Client, ":no_entry:");
                var embed = new DiscordEmbedBuilder
                {
                    Title       = "Invalid Feature",
                    Description = $"{emoji} There is no feature called `{feature}`. Check all the features with `admin ListFeatures`.",
                    Color       = DiscordColor.Red
                };

                await ctx.RespondAsync("", embed : embed);

                return;
            }

            var configuration = GuildConfiguration.FromGuild(ctx.Guild);

            configuration.PermissionByFeature.Remove(feature);
            configuration.PermissionsByFeatureChannel.Remove(feature);
            configuration.PermissionsByFeatureRole.Remove(feature);
            configuration.PermissionsByFeatureRoleChannel.Remove(feature);

            configuration.Save();

            await ctx.RespondAsync($"All the explicit permissions to the `{feature}` feature were cleared.");
        }
Пример #4
0
        public async Task Coin(CommandContext ctx)
        {
            if (!await CanExecute(ctx, Features.Games))
            {
                return;
            }

            Log.Debug($"Requesting {nameof(Coin)}()...");

            var cfg = GuildConfiguration.FromGuild(ctx.Guild);

            var isHead = Rand.Next(0, 2) == 0;

            var embed = new DiscordEmbedBuilder
            {
                Title       = isHead ? "Head!" : "Tail!",
                Description = $"{ctx.User.Mention}, your coin flipped {(isHead ? "**Head**" : "**Tail**")}!",
                Color       = DiscordColor.Goldenrod,
                Url         = BasicExtensions.SiteUrl(),
                ImageUrl    = BasicExtensions.SiteUrl() + $"/images/coin-{(isHead ? "head" : "tail")}.png",
                Author      = new DiscordEmbedBuilder.EmbedAuthor
                {
                    Name = "WoTClans",
                    Url  = BasicExtensions.SiteUrl()
                },
                Footer = new DiscordEmbedBuilder.EmbedFooter
                {
                    Text = $"Flipped at {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC."
                }
            };

            Log.Debug($"Returned {nameof(Coin)}() = {isHead}");

            await ctx.RespondAsync("", embed : embed);
        }
Пример #5
0
        public async Task TestPermissions(CommandContext ctx,
                                          [Description("The feature")] string feature,
                                          [Description("The role")] string role,
                                          [Description("The channel")] string channel)
        {
            await ctx.TriggerTypingAsync();

            if (!feature.IsFeature())
            {
                var emoji = DiscordEmoji.FromName(ctx.Client, ":no_entry:");
                var embed = new DiscordEmbedBuilder
                {
                    Title       = "Invalid Feature",
                    Description = $"{emoji} There is no feature called `{feature}`. Check all the features with `admin ListFeatures`.",
                    Color       = DiscordColor.Red
                };

                await ctx.RespondAsync("", embed : embed);

                return;
            }

            var configuration = GuildConfiguration.FromGuild(ctx.Guild);

            var result = configuration.CanCallerExecute(feature, new[] { role }, channel, out var reason);
            await ctx.RespondAsync($"The feature `{feature}` is **{(result ? "allowed" : "denied")}** on role `{role}` in the channel `#{channel}`. Explanation: {reason}");
        }
Пример #6
0
        public async Task SetPlataform(CommandContext ctx, [Description("Plataform")] string plataform)
        {
            if (!Enum.TryParse(plataform, true, out Plataform plat))
            {
                var emoji = DiscordEmoji.FromName(ctx.Client, ":no_entry:");
                var embed = new DiscordEmbedBuilder
                {
                    Title       = "Wrong parameter",
                    Description = $"{emoji} The plataform should be `{Plataform.XBOX}` or `{Plataform.PS}`.",
                    Color       = DiscordColor.Red
                };
                await ctx.RespondAsync("", embed : embed);

                return;
            }

            await ctx.TriggerTypingAsync();

            var configuration = GuildConfiguration.FromGuild(ctx.Guild);

            configuration.Plataform = plat;
            configuration.Name      = ctx.Guild.Name;
            configuration.Region    = ctx.Guild.RegionId;

            configuration.Save();
            await ctx.RespondAsync($"The plataform is now {plataform}.");
        }
Пример #7
0
        private static Task DiscordOnGuildAvailable(GuildCreateEventArgs args)
        {
            Log.Info($"Guild Available: {args.Guild.Name}.{args.Guild.RegionId}.{args.Guild.Id} with {args.Guild.MemberCount} members.");

            var config = GuildConfiguration.FromGuild(args.Guild);

            config.Save();

            return(Task.CompletedTask);
        }
Пример #8
0
        public async Task SetWhoIAm(CommandContext ctx,
                                    [Description("The *gamer tag* or *PSN Name*")][RemainingText] string gamerTag = "")
        {
            try
            {
                await ctx.TriggerTypingAsync();

                if (!await CanExecute(ctx, Features.Players))
                {
                    return;
                }

                long userId = (long)(ctx?.User?.Id ?? 0UL);
                if (userId == 0)
                {
                    await ctx.RespondAsync($"Sorry, {ctx.User.Mention}. I don't now your Discord User Id! WTF!??!");

                    return;
                }

                var cfg       = GuildConfiguration.FromGuild(ctx.Guild);
                var plataform = GetPlataform(gamerTag, cfg.Plataform, out gamerTag);

                if (string.IsNullOrWhiteSpace(gamerTag))
                {
                    gamerTag = ctx.User.Username;
                }

                var provider = new DbProvider(_connectionString);

                var playerId = provider.GetPlayerIdByName(plataform, gamerTag);
                if (playerId == null)
                {
                    await ctx.RespondAsync($"Sorry, {ctx.User.Mention}, I do not track `{gamerTag}` yet. Are you a member of a tracked clan? Are you sure about the gamer tag?");

                    return;
                }

                var recorder = new DbRecorder(_connectionString);
                recorder.AssociateDiscordUserToPlayer(userId, playerId.Value);

                await ctx.RespondAsync($"Ok, {ctx.User.Mention}, for now on you can use `me` instead of your full {plataform.TagName()} on " +
                                       $"commands that take it as a parameters. I promisse to never abuse this association, and protected it from use outside of this system. " +
                                       $"If you want me to remove this piece of information use the `ForgetWhoIAm` command.");

                return;
            }
            catch (Exception ex)
            {
                Log.Error($"{nameof(WhoIAm)}()", ex);
                await ctx.RespondAsync($"Sorry, {ctx.User.Mention}. There was an error... the *Coder* will be notified of `{ex.Message}`.");

                return;
            }
        }
Пример #9
0
        public async Task SetSilentDeny(CommandContext ctx,
                                        [Description("If `true` the denies will be silent.")] bool useSilentDeny)
        {
            await ctx.TriggerTypingAsync();

            var configuration = GuildConfiguration.FromGuild(ctx.Guild);

            configuration.SilentDeny = useSilentDeny;
            configuration.Save();

            await ctx.RespondAsync($"The Silend Deny is now `{useSilentDeny}`.");
        }
Пример #10
0
        public async Task ClanDelete(CommandContext ctx,
                                     [Description("The clan Tag")] string clanTag)
        {
            await ctx.TriggerTypingAsync();

            var userId = ctx.User?.Id ?? 0;

            Log.Info($"Requesting {nameof(ClanDelete)}({clanTag}) by {userId}...");
            if (userId != _coder)
            {
                var emoji = DiscordEmoji.FromName(ctx.Client, ":no_entry:");
                var embed = new DiscordEmbedBuilder
                {
                    Title       = "Access denied",
                    Description = $"{emoji} You may be a *coder*, but you are not **The Coder**!",
                    Color       = DiscordColor.Red
                };

                await ctx.RespondAsync("", embed : embed);

                return;
            }

            var cfg      = GuildConfiguration.FromGuild(ctx.Guild);
            var platform = GetPlatform(clanTag, cfg.Plataform, out clanTag);

            clanTag = clanTag.Trim('[', ']');
            clanTag = clanTag.ToUpperInvariant();

            if (!ClanTagRegex.IsMatch(clanTag))
            {
                await ctx.RespondAsync($"You must send a **valid** clan **tag** as parameter, {ctx.User?.Mention}.");

                return;
            }

            try
            {
                var putter = new Putter(platform, ConfigurationManager.AppSettings["ApiAdminKey"]);
                putter.DeleteClan(clanTag);

                await ctx.RespondAsync(
                    $"The clan `{clanTag}` on `{platform}` was deleted from the site.");

                Log.Debug($"{nameof(ClanDelete)} returned ok.");
            }
            catch (Exception ex)
            {
                Log.Error($"{nameof(ClanDelete)}", ex);
                await ctx.RespondAsync(
                    $"Sorry, {ctx.User?.Mention}. There was an error... the *Coder* will be notified of `{ex.Message}`.");
            }
        }
Пример #11
0
        public async Task SetDefaultPermission(CommandContext ctx,
                                               [Description("The default permission")] bool permission)
        {
            await ctx.TriggerTypingAsync();

            var configuration = GuildConfiguration.FromGuild(ctx.Guild);

            configuration.PermissionDefault = permission;
            configuration.Save();

            await ctx.RespondAsync($"The default permission to every feature on every channel and role is now `{permission}`.");
        }
Пример #12
0
        public async Task ResetPermissions(CommandContext ctx)
        {
            await ctx.TriggerTypingAsync();

            var cfg = GuildConfiguration.FromGuild(ctx.Guild);

            cfg.PermissionByFeature.Clear();
            cfg.PermissionsByFeatureChannel.Clear();
            cfg.PermissionsByFeatureRole.Clear();
            cfg.PermissionsByFeatureRoleChannel.Clear();
            cfg.PermissionDefault = true;

            cfg.Save();

            await ctx.RespondAsync($"All permissions were reset. Any command can be called by anyone everywhere.");
        }
Пример #13
0
        public async Task Site(CommandContext ctx)
        {
            if (!await CanExecute(ctx, Features.General))
            {
                return;
            }

            var config = GuildConfiguration.FromGuild(ctx.Guild);

            var embed = new DiscordEmbedBuilder
            {
                Title       = "WoT Clans",
                Description = $"The best WoT site in the universe is just a click away from you, {ctx.User.Mention}!",
                Color       = DiscordColor.DarkGreen,
                Url         = $"https://{(config.Plataform == Plataform.PS ? "ps." : "")}wotclans.com.br"
            };

            await ctx.RespondAsync("", embed : embed);
        }
Пример #14
0
        public async Task Site(CommandContext ctx)
        {
            if (!await CanExecute(ctx, Features.General))
            {
                return;
            }

            Log.Debug($"Requesting {nameof(Site)}()...");

            var config = GuildConfiguration.FromGuild(ctx.Guild);

            var embed = new DiscordEmbedBuilder
            {
                Title       = "WoT Clans",
                Description = $"The best WoT site in the universe is just a click away from you, {ctx.User.Mention}!",
                Color       = DiscordColor.DarkGreen,
                Url         = "https://wotclans.com.br"
            };

            await ctx.RespondAsync("", embed : embed);
        }
Пример #15
0
        protected async Task <bool> CanExecute(CommandContext ctx, string feature)
        {
            var cfg = GuildConfiguration.FromGuild(ctx.Guild);

            if (!cfg.CanCallerExecute(feature, ctx.Member, ctx.Channel, out var reason))
            {
                if (!cfg.SilentDeny)
                {
                    var emoji = DiscordEmoji.FromName(ctx.Client, ":no_entry:");
                    var embed = new DiscordEmbedBuilder
                    {
                        Title       = "Access denied",
                        Description = $"{emoji} {reason}",
                        Color       = DiscordColor.Red
                    };

                    await ctx.RespondAsync("", embed : embed);
                }

                return(await Task.Run(() => false));
            }

            return(await Task.Run(() => true));
        }
Пример #16
0
        public async Task ClanTopOnTank(CommandContext ctx,
                                        [Description("The clan **tag**")] string clanTag,
                                        [Description("The Tank name, as it appears in battles. If it has spaces, enclose it on quotes.")][RemainingText] string tankName)
        {
            if (!await CanExecute(ctx, Features.Clans))
            {
                return;
            }

            await ctx.TriggerTypingAsync();

            if (string.IsNullOrWhiteSpace(clanTag))
            {
                await ctx.RespondAsync($"You must send a clan tag as parameter, {ctx.User.Mention}.");

                return;
            }

            Log.Debug($"Requesting {nameof(ClanTopOnTank)}({clanTag}, {tankName})...");

            var cfg      = GuildConfiguration.FromGuild(ctx.Guild);
            var platform = GetPlatform(clanTag, cfg.Plataform, out clanTag);

            if (!ClanTagRegex.IsMatch(clanTag))
            {
                await ctx.RespondAsync($"You must send a **valid** clan **tag** as parameter, {ctx.User.Mention}.");

                return;
            }

            var provider = new DbProvider(_connectionString);

            var clan = provider.GetClan(platform, clanTag);

            if (clan == null)
            {
                platform = platform == Platform.PS ? Platform.XBOX : Platform.PS;

                clan = provider.GetClan(platform, clanTag);
                if (clan == null)
                {
                    await ctx.RespondAsync(
                        $"Can't find on a clan with tag `[{clanTag}]`, {ctx.User.Mention}. Maybe my site doesn't track it yet... or you have the wrong clan tag.");

                    return;
                }
            }

            if (!clan.Enabled)
            {
                await ctx.RespondAsync(
                    $"Data collection for the `[{clan.ClanTag}]` is disabled, {ctx.User.Mention}. Maybe the clan went too small, or inactive.");

                return;
            }

            var tankCommands = new TankCommands();
            var tank         = tankCommands.FindTank(platform, tankName, out _);

            if (tank == null)
            {
                await ctx.RespondAsync($"Can't find a tank with `{tankName}` on the name, {ctx.User.Mention}.");

                return;
            }

            var tr = provider.GetTanksReferences(tank.Plataform, null, tank.TankId, false, false, false).FirstOrDefault();

            if (tr == null)
            {
                await ctx.RespondAsync($"Sorry, there is no tank statistics for the `{tank.Name}`, {ctx.User.Mention}.");

                return;
            }

            if (tr.Tier < 5)
            {
                await ctx.RespondAsync($"Sorry, this command is meant to be used only with tanks Tier 5 and above, {ctx.User.Mention}.");

                return;
            }

            var players = provider.GetClanPlayerIdsOnTank(platform, clan.ClanId, tr.TankId).ToList();

            if (players.Count <= 0)
            {
                await ctx.RespondAsync($"No players from the `[{clan.ClanTag}]` has battles on the `{tank.Name}`, {ctx.User.Mention}, as far as the database is up to date.");

                return;
            }

            var waitMsg = await ctx.RespondAsync($"Please wait as data for {players.Count} tankers is being retrieved, {ctx.User.Mention}...");

            var playerCommands = new PlayerCommands();

            var fullPlayers = new ConcurrentBag <Player>();
            var tasks       = players.Select(async p =>
            {
                var player = await playerCommands.GetPlayer(ctx, ((p.Plataform == Platform.XBOX) ? "x." : "ps.") + p.Name);
                if (player == null)
                {
                    await ctx.RespondAsync($"Sorry, could not get updated information for player `{p.Name}`, {ctx.User.Mention}.");
                    return;
                }

                fullPlayers.Add(player);
            });
            await Task.WhenAll(tasks);

            await waitMsg.DeleteAsync();

            var sb = new StringBuilder();

            var maxNameLength = fullPlayers.Max(p => p.Name.Length);

            //sb.AppendLine($"Here `[{clan.ClanTag}]` top players on the `{tank.Name}`, {ctx.User.Mention}:");
            //sb.AppendLine();
            sb.AppendLine("```");
            sb.AppendLine($"{platform.TagName().PadRight(maxNameLength)} {"Days".PadLeft(5)} {"Battles".PadLeft(7)} {"WN8".PadLeft(6)}");
            foreach (var p in fullPlayers.OrderByDescending(p => p.Performance.All[tank.TankId].Wn8).Take(25))
            {
                var tp = p.Performance.All[tank.TankId];
                sb.AppendLine($"{(p.Name ?? string.Empty).PadRight(maxNameLength)} {(DateTime.UtcNow - tp.LastBattle).TotalDays.ToString("N0").PadLeft(5)} {tp.Battles.ToString("N0").PadLeft(7)} {tp.Wn8.ToString("N0").PadLeft(6)}");
            }
            sb.AppendLine("```");
            sb.AppendLine();
            sb.AppendLine("This command is a **Premium** feature on the bot. For now it's free to use this command, but be advised that on the near future access will be restricted to Premium subscribers.");

            var color          = clan.Top15Wn8.ToColor();
            var platformPrefix = clan.Plataform == Platform.PS ? "ps." : string.Empty;

            var embed = new DiscordEmbedBuilder
            {
                Title        = $"`{clan.ClanTag}` top players on the `{tank.Name}`",
                Description  = sb.ToString(),
                Color        = new DiscordColor(color.R, color.G, color.B),
                ThumbnailUrl = tank.SmallImageUrl,
                Url          = $"https://{platformPrefix}wotclans.com.br/Clan/{clan.ClanTag}",
                Author       = new DiscordEmbedBuilder.EmbedAuthor
                {
                    Name = "WoTClans",
                    Url  = $"https://{platformPrefix}wotclans.com.br"
                },
                Footer = new DiscordEmbedBuilder.EmbedFooter
                {
                    Text = $"Calculated at {DateTime.UtcNow:yyyy-MM-dd HH:mm} UTC"
                }
            };

            await ctx.RespondAsync("", embed : embed);
        }
Пример #17
0
        public async Task Clan(CommandContext ctx, [Description("The clan **tag**")] string clanTag)
        {
            if (!await CanExecute(ctx, Features.Clans))
            {
                return;
            }


            await ctx.TriggerTypingAsync();

            if (string.IsNullOrWhiteSpace(clanTag))
            {
                await ctx.RespondAsync($"You must send a clan tag as parameter, {ctx.User.Mention}.");

                return;
            }

            Log.Debug($"Requesting {nameof(Clan)}({clanTag})...");

            var cfg       = GuildConfiguration.FromGuild(ctx.Guild);
            var plataform = GetPlataform(clanTag, cfg.Plataform, out clanTag);

            clanTag = clanTag.Trim('[', ']');
            clanTag = clanTag.ToUpperInvariant();

            if (!ClanTagRegex.IsMatch(clanTag))
            {
                await ctx.RespondAsync($"You must send a **valid** clan **tag** as parameter, {ctx.User.Mention}.");

                return;
            }

            var provider = new DbProvider(_connectionString);

            var clan = provider.GetClan(plataform, clanTag);

            if (clan == null)
            {
                if (plataform == Plataform.PS)
                {
                    plataform = Plataform.XBOX;
                }
                else
                {
                    plataform = Plataform.PS;
                }

                clan = provider.GetClan(plataform, clanTag);
                if (clan == null)
                {
                    await ctx.RespondAsync($"Can't find on a clan with tag `[{clanTag}]`, {ctx.User.Mention}. Maybe my site doesn't track it yet... or you have the wrong clan tag.");

                    return;
                }
            }

            var sb = new StringBuilder();

            sb.Append($"Information about the `{clan.ClanTag}`");
            if (!string.IsNullOrWhiteSpace(clan.Country))
            {
                sb.Append($" ({clan.Country.ToUpperInvariant()})");
            }
            sb.AppendLine($", on the {clan.Plataform}, {ctx.User.Mention}:");

            if (!clan.Enabled)
            {
                sb.AppendLine("Data collection for this clan is **disabled**!");
            }

            sb.AppendLine();

            sb.AppendLine($"Active Members: {clan.Active}; Total Members: {clan.Count};");
            sb.AppendLine($"Recent Win Rate: {clan.ActiveWinRate:P1}; Overall Win Rate: {clan.TotalWinRate:P1};");
            sb.AppendLine($"Recent WN8t15: {clan.Top15Wn8:N0}; Overall WN8: {clan.TotalWn8:N0};");
            if (clan.DeltaDayTop15Wn8.HasValue)
            {
                sb.AppendLine($"WN8t15 Variation from 1 day ago: {clan.DeltaDayTop15Wn8.Value:N0}");
            }
            if (clan.DeltaWeekTop15Wn8.HasValue)
            {
                sb.AppendLine($"WN8t15 Variation from 1 week ago: {clan.DeltaWeekTop15Wn8.Value:N0}");
            }
            if (clan.DeltaMonthTop15Wn8.HasValue)
            {
                sb.AppendLine($"WN8t15 Variation from 1 month ago: {clan.DeltaMonthTop15Wn8.Value:N0}");
            }
            sb.AppendLine($"Recent Actives Battles: {clan.ActiveBattles:N0}; Recent Avg Tier: {clan.ActiveAvgTier:N1}");

            sb.AppendLine();
            sb.AppendLine("**Top 15 Active Players**");
            foreach (var p in clan.Top15Players)
            {
                sb.AppendLine($"{Formatter.MaskedUrl(p.Name, new Uri(p.PlayerOverallUrl))}, {p.MonthBattles} battles, WN8: {p.MonthWn8:N0}");
            }

            string title;

            if (clan.ClanTag.EqualsCiAi(clan.Name))
            {
                title = clan.ClanTag;
            }
            else
            {
                title = $"{clan.ClanTag} - {clan.Name}";
            }

            var color = clan.Top15Wn8.ToColor();

            var plataformPrefix = clan.Plataform == Plataform.PS ? "ps." : string.Empty;

            var embed = new DiscordEmbedBuilder
            {
                Title       = title,
                Description = sb.ToString(),
                Color       = new DiscordColor(color.R, color.G, color.B),
                Url         = $"https://{plataformPrefix}wotclans.com.br/Clan/{clan.ClanTag}",
                Author      = new DiscordEmbedBuilder.EmbedAuthor
                {
                    Name = "WoTClans",
                    Url  = $"https://{plataform}wotclans.com.br"
                },
                Footer = new DiscordEmbedBuilder.EmbedFooter
                {
                    Text = $"Data calculatet at {clan.Moment:yyyy-MM-dd HH:mm} UTC."
                }
            };

            Log.Debug($"Returned {nameof(Clan)}({clan.Plataform}.{clan.ClanTag})");

            await ctx.RespondAsync("", embed : embed);
        }
Пример #18
0
        public async Task ListPermissions(CommandContext ctx)
        {
            await ctx.TriggerTypingAsync();

            var cfg = GuildConfiguration.FromGuild(ctx.Guild);

            var sb = new StringBuilder();

            sb.AppendLine("These are the permissions on this server, on the order they are evaluated:");
            sb.AppendLine();

            sb.AppendLine("1) Explicit permissions on a *feature* for a given *role* **and** *channel*:");
            if (!cfg.PermissionsByFeatureRoleChannel.Any())
            {
                sb.AppendLine("  No explicit permissions.");
            }
            else
            {
                foreach (var byFeature in cfg.PermissionsByFeatureRoleChannel.OrderBy(kv => kv.Key))
                {
                    foreach (var byRole in byFeature.Value.OrderBy(kv => kv.Key))
                    {
                        foreach (var byChannel in byRole.Value.OrderBy(kv => kv.Key))
                        {
                            sb.AppendLine($"  Feature `{byFeature.Key}`, role `{byRole.Key}`, channel `#{byChannel.Key}`: {(byChannel.Value ? "allow" : "deny")}");
                        }
                    }
                }
            }
            sb.AppendLine();

            sb.AppendLine("2) Explicit permissions on a *feature* for a given *role*:");
            if (!cfg.PermissionsByFeatureRole.Any())
            {
                sb.AppendLine("  No explicit permissions.");
            }
            else
            {
                foreach (var byFeature in cfg.PermissionsByFeatureRole.OrderBy(kv => kv.Key))
                {
                    foreach (var byRole in byFeature.Value.OrderBy(kv => kv.Key))
                    {
                        sb.AppendLine($"  Feature `{byFeature.Key}`, role `{byRole.Key}`: {(byRole.Value ? "allow" : "deny")}");
                    }
                }
            }
            sb.AppendLine();

            sb.AppendLine("3) Explicit permissions on a *feature* for a given *channel*:");
            if (!cfg.PermissionsByFeatureChannel.Any())
            {
                sb.AppendLine("  No explicit permissions.");
            }
            else
            {
                foreach (var byFeature in cfg.PermissionsByFeatureChannel.OrderBy(kv => kv.Key))
                {
                    foreach (var byChannel in byFeature.Value.OrderBy(kv => kv.Key))
                    {
                        sb.AppendLine($"  Feature `{byFeature.Key}`, channel `#{byChannel.Key}`: {(byChannel.Value ? "allow" : "deny")}");
                    }
                }
            }
            sb.AppendLine();

            sb.AppendLine("4) Explicit permissions on a *feature*:");
            if (!cfg.PermissionByFeature.Any())
            {
                sb.AppendLine("  No explicit permissions.");
            }
            else
            {
                foreach (var byFeature in cfg.PermissionByFeature.OrderBy(kv => kv.Key))
                {
                    sb.AppendLine($"  Feature `{byFeature.Key}`: {(byFeature.Value ? "allow" : "deny")}");
                }
            }
            sb.AppendLine();

            sb.AppendLine($"5) The *Global Permission*: {(cfg.PermissionDefault ? "allow" : "deny")}");
            sb.AppendLine();

            await ctx.RespondAsync(sb.ToString());
        }
Пример #19
0
        public async Task SetClan(CommandContext ctx, [Description("The clan tag")] string clanTag,
                                  [Description("The clan flag")] string flagCode                 = null,
                                  [Description("Enable or Disable the Clan")] bool enable        = true,
                                  [Description("To ban or not a clan from the site")] bool isBan = false)
        {
            await ctx.TriggerTypingAsync();

            var userId = ctx?.User?.Id ?? 0;

            Log.Info($"Requesting {nameof(SetClan)} by {userId}...");
            if (userId != _coder)
            {
                var emoji = DiscordEmoji.FromName(ctx.Client, ":no_entry:");
                var embed = new DiscordEmbedBuilder
                {
                    Title       = "Access denied",
                    Description = $"{emoji} You may be a *coder*, but you are not **The Coder**!",
                    Color       = DiscordColor.Red
                };

                await ctx.RespondAsync("", embed : embed);

                return;
            }
            var cfg       = GuildConfiguration.FromGuild(ctx.Guild);
            var plataform = GetPlataform(clanTag, cfg.Plataform, out clanTag);

            clanTag = clanTag.Trim('[', ']');
            clanTag = clanTag.ToUpperInvariant();

            if (!ClanTagRegex.IsMatch(clanTag))
            {
                await ctx.RespondAsync($"You must send a **valid** clan **tag** as parameter, {ctx.User.Mention}.");

                return;
            }

            if (!string.IsNullOrWhiteSpace(flagCode))
            {
                flagCode = flagCode.RemoveDiacritics().ToUpperInvariant();

                if (flagCode.Length != 2)
                {
                    await ctx.RespondAsync($"The flag code must be 2 letters only, {ctx.User.Mention}.");

                    return;
                }
            }

            Log.Warn($"{nameof(SetClan)}({clanTag}, {plataform}, {flagCode}, {enable}, {isBan})...");

            try
            {
                await ctx.TriggerTypingAsync();

                var provider = new DbProvider(_connectionString);
                var recorder = new DbRecorder(_connectionString);

                var cacheDirectory = ConfigurationManager.AppSettings["CacheDir"] ?? Path.GetTempPath();
                var webCacheAge    = TimeSpan.FromHours(4);
                var appId          = ConfigurationManager.AppSettings["WgAppId"] ?? "demo";

                var fetcher = new Fetcher(cacheDirectory)
                {
                    ApplicationId    = appId,
                    WebCacheAge      = webCacheAge,
                    WebFetchInterval = TimeSpan.FromSeconds(1)
                };

                var clan = provider.GetClan(plataform, clanTag);
                if (clan == null && enable)
                {
                    // Check to add...
                    await ctx.RespondAsync($"Not found `{clanTag}` on the database. Searching the WG API...");

                    await ctx.TriggerTypingAsync();

                    var clanOnSite = fetcher.FindClan(plataform, clanTag, true);
                    if (clanOnSite == null)
                    {
                        await ctx.RespondAsync($"Not found `{clanTag}` on the WG API for `{plataform}`. Check the clan tag.");

                        return;
                    }

                    if (clanOnSite.AllMembersCount < 7)
                    {
                        await ctx.RespondAsync($"The clan `{clanTag}` on `{plataform}` has only {clanOnSite.AllMembersCount}, and will not be added to the system.");

                        return;
                    }

                    clanOnSite.Country = flagCode;
                    recorder.Add(clanOnSite);

                    await ctx.RespondAsync($"The clan `{clanTag}` on `{plataform}` with {clanOnSite.AllMembersCount} members was added to the system and " +
                                           $"should appear on the site in ~12 hours. Keep playing to achieve at least 7 members with 21 recent battles and appear on the default view.");

                    Log.Info($"Added {plataform}.{clanTag}");
                    return;
                }

                if (!clan.Enabled && enable)
                {
                    // Can be enabled?
                    var clanOnSite = fetcher.GetClans(new[] { clan }).FirstOrDefault();
                    if (clanOnSite == null)
                    {
                        await ctx.RespondAsync($"Not found `{clanTag}` on the WG API for `{plataform}`. Check the clan tag.");

                        return;
                    }

                    if (clanOnSite.IsDisbanded)
                    {
                        await ctx.RespondAsync($"The clan `{clanTag}` on `{plataform}` was disbanded.");

                        return;
                    }

                    if (clanOnSite.Count < 7)
                    {
                        await ctx.RespondAsync($"The clan `{clanTag}` on `{plataform}` has only {clanOnSite.Count} members and will not be enabled.");

                        return;
                    }

                    if (clan.DisabledReason == DisabledReason.Banned)
                    {
                        await ctx.RespondAsync($"The clan `{clanTag}` ({clan.ClanId}) on `{plataform}` was **banned** from the site.");

                        return;
                    }

                    recorder.EnableClan(clanOnSite.Plataform, clanOnSite.ClanId);
                    await ctx.RespondAsync($"The clan `{clanTag}` on `{plataform}` disabled for `{clan.DisabledReason}` is enabled again.");

                    Log.Info($"Enabled {plataform}.{clanTag}");
                }
                else if (clan.Enabled && !enable)
                {
                    if (isBan)
                    {
                        recorder.DisableClan(clan.Plataform, clan.ClanId, DisabledReason.Banned);
                        await ctx.RespondAsync($"The clan `{clanTag}` ({clan.ClanId}) on `{plataform}` was **BANNED** from the site.");

                        Log.Warn($"BANNED {plataform}.{clanTag}");
                    }
                    else
                    {
                        recorder.DisableClan(clan.Plataform, clan.ClanId, DisabledReason.Unknow);
                        await ctx.RespondAsync($"The clan `{clanTag}` ({clan.ClanId}) on `{plataform}` was **disabled** from the site.");

                        Log.Warn($"Disabled {plataform}.{clanTag}");
                    }
                }

                // change flag?
                flagCode = flagCode ?? string.Empty;
                if (flagCode.ToUpperInvariant() != (clan.Country ?? string.Empty).ToUpperInvariant())
                {
                    recorder.SetClanFlag(clan.Plataform, clan.ClanId, flagCode);
                    await ctx.RespondAsync($"The flag of the clan `{clanTag}` on `{plataform}` was changed to `{flagCode}`.");

                    Log.Info($"Flag changed on {plataform}.{clanTag} to {flagCode}.");
                }

                await ctx.RespondAsync($"all done for `{clan.ClanTag}` on `{plataform}`.");
            }
            catch (Exception ex)
            {
                Log.Error($"{nameof(SetClan)}", ex);
                await ctx.RespondAsync($"Sorry, {ctx.User.Mention}. There was an error... the *Coder* will be notified of `{ex.Message}`.");

                return;
            }
        }
Пример #20
0
        public async Task Moe(CommandContext ctx,
                              [Description("The Tank name, as it appears in battles. If it has spaces, enclose it on quotes.")][RemainingText] string tankName)
        {
            if (!await CanExecute(ctx, Features.Tanks))
            {
                return;
            }

            Log.Info($"Requesting {nameof(Moe)}({tankName})");

            await ctx.TriggerTypingAsync();

            var cfg = GuildConfiguration.FromGuild(ctx.Guild);

            var tank = FindTank(cfg.Plataform, tankName, out var exact);

            if (tank == null)
            {
                await ctx.RespondAsync($"Can't find a tank with `{tankName}` on the name, {ctx.User.Mention}.");

                return;
            }

            var provider = new DbProvider(_connectionString);
            var moe      = provider.GetMoe(tank.Plataform, null, tank.TankId).FirstOrDefault();

            if (moe == null)
            {
                await ctx.RespondAsync($"Sorry, there is no MoE information for the `{tank.Name}`, {ctx.User.Mention}.");

                return;
            }

            var sb = new StringBuilder();

            sb.AppendLine($"Here the MoE information about the `{moe.Name}`, Tier {moe.Tier.ToRomanNumeral()}, {moe.Nation.GetDescription()}, {(moe.IsPremium ? "Premium" : "Regular")}, {ctx.User.Mention}:");
            sb.AppendLine($"```  * 1  mark: {moe.Moe1Dmg:N0} Total Damage");
            sb.AppendLine($" ** 2 marks: {moe.Moe2Dmg:N0} Total Damage");
            sb.AppendLine($"*** 3 marks: {moe.Moe3Dmg:N0} Total Damage```");

            var emoji = DiscordEmoji.FromName(ctx.Client, ":exclamation:");

            if (!exact)
            {
                sb.AppendLine();
                sb.AppendLine($"{emoji} If this is *not the tank* you are looking for, try sending the exact short name, the one that appears during battles, or enclosing the name in quotes.");
            }

            var platformPrefix = moe.Plataform == Platform.PS ? "ps." : string.Empty;

            var embed = new DiscordEmbedBuilder
            {
                Title        = $"{tank.Name} MoE",
                Description  = sb.ToString(),
                Color        = DiscordColor.Gray,
                ThumbnailUrl = tank.SmallImageUrl,
                Url          = $"https://{platformPrefix}wotclans.com.br/Tanks/{tank.TankId}",
                Author       = new DiscordEmbedBuilder.EmbedAuthor
                {
                    Name = "WoTClans",
                    Url  = $"https://{platformPrefix}wotclans.com.br"
                },
                Footer = new DiscordEmbedBuilder.EmbedFooter
                {
                    Text = $"Calculated at {moe.Date:yyyy-MM-dd} from {moe.NumberOfBattles:N0} battles."
                }
            };

            await ctx.RespondAsync("", embed : embed);
        }
Пример #21
0
        public async Task RandTank(CommandContext ctx,
                                   [Description("The minimum tier of the tanks")] int minTier = 5,
                                   [Description("The maximum tier of the tanks")] int maxTier = 10,
                                   [Description("Nation of the tank, or *any*. Multiple values can be sent using *;* as separators")] string nationFilter = "any",
                                   [Description("Type of the tank, or *any*. Multiple values can be sent using *;* as separators")] string typeFilter     = "any",
                                   [Description("*Premium*, *regular*, or *any*")] string premiumFilter = "any",
                                   [Description("The *gamer tag* or *PSN Name*, so it only returns tanks that the player have (or had)")] string gamerTag = null,
                                   [Description("If *true* then a tank that the given player **hadn't** will be picked")] bool notOnPlayer = false)
        {
            // Yeah... it's a Player feature but it uses more calculations for tanks...
            if (!await CanExecute(ctx, Features.Tanks))
            {
                return;
            }

            if (minTier < 1)
            {
                await ctx.RespondAsync("The minimum tier is 1.");

                return;
            }

            if (minTier > 10)
            {
                await ctx.RespondAsync("The maximum tier is 1.");

                return;
            }

            if (maxTier < 1)
            {
                await ctx.RespondAsync("The minimum tier is 1.");

                return;
            }

            if (maxTier > 10)
            {
                await ctx.RespondAsync("The maximum tier is 1.");

                return;
            }

            if (maxTier < minTier)
            {
                var temp = maxTier;
                maxTier = minTier;
                minTier = temp;
            }

            await ctx.TriggerTypingAsync();

            var cfg = GuildConfiguration.FromGuild(ctx.Guild);

            Log.Debug($"Requesting {nameof(RandTank)}({minTier}, {maxTier}, {nationFilter}, {typeFilter}, {premiumFilter}, {gamerTag ?? string.Empty}, {notOnPlayer})...");

            try
            {
                var provider = new DbProvider(_connectionString);

                var allTanks = provider.EnumTanks(cfg.Plataform).Where(t => (t.Tier >= minTier) && (t.Tier <= maxTier)).ToList();

                if (!string.IsNullOrWhiteSpace(nationFilter) && !nationFilter.EqualsCiAi("any"))
                {
                    var filtersText = nationFilter.Split(new[] { ',', ';', '-', ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    var filters     = new HashSet <Nation>();
                    foreach (var filterText in filtersText)
                    {
                        if (Enum.TryParse <Nation>(filterText, true, out var nation))
                        {
                            filters.Add(nation);
                        }
                        else
                        {
                            await ctx.RespondAsync(
                                $"Sorry, {ctx.User.Mention}, the nation `{filterText}` is not a valid nation. Valid nations are: {string.Join(", ", NationExtensions.GetGameNations().Select(n => $"`{n.ToString().ToLowerInvariant()}`"))}.");

                            return;
                        }
                    }

                    allTanks = allTanks.Where(t => filters.Contains(t.Nation)).ToList();
                }

                if (!string.IsNullOrWhiteSpace(typeFilter) && !typeFilter.EqualsCiAi("any"))
                {
                    var filtersText = typeFilter.Split(new[] { ',', ';', '-', ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    var filters     = new HashSet <TankType>();
                    foreach (var filterText in filtersText)
                    {
                        if (Enum.TryParse <TankType>(filterText, true, out var tankType))
                        {
                            filters.Add(tankType);
                        }
                        else
                        {
                            await ctx.RespondAsync(
                                $"Sorry, {ctx.User.Mention}, the tank type `{filterText}` is not a valid type. Valid tank types are: {string.Join(", ", TankTypeExtensions.GetGameTankTypes().Select(n => $"`{n.ToString().ToLowerInvariant()}`"))}.");

                            return;
                        }
                    }

                    allTanks = allTanks.Where(t => filters.Contains(t.Type)).ToList();
                }

                if (!string.IsNullOrWhiteSpace(premiumFilter) && !premiumFilter.EqualsCiAi("any"))
                {
                    if (premiumFilter.EqualsCiAi("regular"))
                    {
                        allTanks = allTanks.Where(t => !t.IsPremium).ToList();
                    }
                    else if (premiumFilter.EqualsCiAi("premium"))
                    {
                        allTanks = allTanks.Where(t => t.IsPremium).ToList();
                    }
                    else
                    {
                        await ctx.RespondAsync(
                            $"Sorry, {ctx.User.Mention}, the premium filter `{premiumFilter}` is not a valid value. Valid values are: `Regular`, `Premium` or `Any`.");

                        return;
                    }
                }

                if (!string.IsNullOrWhiteSpace(gamerTag))
                {
                    var playerCommands = new PlayerCommands();
                    var player         = await playerCommands.GetPlayer(ctx, gamerTag);

                    if (player == null)
                    {
                        Log.Debug($"Could not find player {gamerTag}");
                        await ctx.RespondAsync("I could not find a tanker " +
                                               $"with the Gamer Tag `{gamerTag}` on the Database, {ctx.User.Mention}. I may not track this player, or the Gamer Tag is wrong.");

                        return;
                    }
                    gamerTag = player.Name;

                    var playerTanks = player.Performance.All.Select(kv => kv.Key).ToHashSet();

                    allTanks = notOnPlayer
                        ? allTanks.Where(t => !playerTanks.Contains(t.TankId)).ToList()
                        : allTanks.Where(t => playerTanks.Contains(t.TankId)).ToList();
                }

                if (allTanks.Count <= 0)
                {
                    await ctx.RespondAsync(
                        $"Sorry, {ctx.User.Mention}, there are no tanks with the given criteria.");

                    return;
                }

                var number = Rand.Next(0, allTanks.Count);

                var tank = allTanks[number];

                var platformPrefix = tank.Plataform == Platform.PS ? "ps." : string.Empty;

                var sb = new StringBuilder();

                sb.AppendLine($"The random tank is the `{tank.Name}`, Tier {tank.Tier.ToRomanNumeral()}, {tank.Nation.GetDescription()}, {(tank.IsPremium ? "Premium" : "Regular")}, {ctx.User.Mention}!");

                var embed = new DiscordEmbedBuilder
                {
                    Title        = $"{tank.Name} is the random Tank",
                    Description  = sb.ToString(),
                    Color        = DiscordColor.Gray,
                    ThumbnailUrl = tank.SmallImageUrl,
                    Url          = $"https://{platformPrefix}wotclans.com.br/Tanks/{tank.TankId}",
                    Author       = new DiscordEmbedBuilder.EmbedAuthor
                    {
                        Name = "WoTClans",
                        Url  = $"https://{platformPrefix}wotclans.com.br"
                    },
                    Footer = new DiscordEmbedBuilder.EmbedFooter
                    {
                        Text = $"Picked at {DateTime.UtcNow:yyyy-MM-dd HH:mm}."
                    }
                };

                await ctx.RespondAsync("", embed : embed);
            }
            catch (Exception ex)
            {
                Log.Error($"Error on {nameof(RandTank)}({minTier}, {maxTier}, {nationFilter}, {typeFilter}, {premiumFilter}, {gamerTag ?? string.Empty}, {notOnPlayer})", ex);
                await ctx.RespondAsync($"Sorry, {ctx.User.Mention}. There was an error... the *Coder* will be notified of `{ex.Message}`.");
            }
        }
Пример #22
0
        /// <summary>
        /// Retrieves a player from database, or only WG API
        /// </summary>
        /// <param name="gamerTag"></param>
        /// <returns></returns>
        public async Task <Player> GetPlayer(CommandContext ctx, string gamerTag)
        {
            try
            {
                var cfg       = GuildConfiguration.FromGuild(ctx.Guild);
                var plataform = GetPlataform(gamerTag, cfg.Plataform, out gamerTag);

                var provider = new DbProvider(_connectionString);
                var recorder = new DbRecorder(_connectionString);

                DiscordMessage willTryApiMessage = null;

                long?playerId = null;
                if (gamerTag.EqualsCiAi("me"))
                {
                    playerId = provider.GetPlayerIdByDiscordId((long)ctx.User.Id);
                }

                playerId = playerId ?? provider.GetPlayerIdByName(plataform, gamerTag);
                if (playerId == null)
                {
                    Log.Debug($"Could not find player {plataform}.{gamerTag} on the database... trying the API...");
                    willTryApiMessage = await ctx.RespondAsync($"I could not find a player on `{plataform}` " +
                                                               $"with the Gamer Tag `{gamerTag}` on the Database, {ctx.User.Mention}. I will try the Wargaming API... it may take some time...");
                }

                var cacheDirectory = ConfigurationManager.AppSettings["CacheDir"] ?? Path.GetTempPath();
                var webCacheAge    = TimeSpan.FromHours(4);
                var appId          = ConfigurationManager.AppSettings["WgAppId"] ?? "demo";

                var fetcher = new Fetcher(cacheDirectory)
                {
                    ApplicationId    = appId,
                    WebCacheAge      = webCacheAge,
                    WebFetchInterval = TimeSpan.FromSeconds(1)
                };

                Player apiPlayer = null;
                if (playerId == null)
                {
                    await ctx.TriggerTypingAsync();

                    apiPlayer = fetcher.GetPlayerByGamerTag(plataform, gamerTag);
                    if (apiPlayer == null)
                    {
                        Log.Debug($"Could not find player {plataform}.{gamerTag} on the WG API.");

                        if (willTryApiMessage != null)
                        {
                            await willTryApiMessage.DeleteAsync("Information updated.");
                        }

                        await ctx.RespondAsync($"Sorry, {ctx.User.Mention}. I could not find a player on `{plataform}` " +
                                               $"with the Gamer Tag `{gamerTag}` on the Wargaming API. Are you sure about the **exact** gamer tag?.");

                        return(null);
                    }
                    playerId = apiPlayer.Id;
                }

                var player = provider.GetPlayer(playerId.Value, true);

                var wn8Expected = provider.GetWn8ExpectedValues(player?.Plataform ?? apiPlayer.Plataform);

                if ((player == null) && (apiPlayer != null))
                {
                    // Not on my database, but on the API Let's work with overall data!
                    IEnumerable <WgApi.TankPlayer> tanks = fetcher.GetTanksForPlayer(apiPlayer.Plataform, apiPlayer.Id);
                    foreach (var t in tanks)
                    {
                        t.All.TreesCut = t.TreesCut;
                        t.All.BattleLifeTimeSeconds = t.BattleLifeTimeSeconds;
                        t.All.MarkOfMastery         = t.MarkOfMastery;
                        t.All.MaxFrags   = t.MaxFrags;
                        t.All.LastBattle = t.LastBattle;
                    }

                    apiPlayer.Performance = new Tanks.TankPlayerPeriods()
                    {
                        All = tanks.ToDictionary(t => t.TankId, t => t.All)
                    };

                    apiPlayer.Calculate(wn8Expected);

                    if (willTryApiMessage != null)
                    {
                        await willTryApiMessage.DeleteAsync("Information updated.");
                    }

                    return(apiPlayer);
                }

                if (player.Age.TotalHours > 4)
                {
                    willTryApiMessage = await ctx.RespondAsync($"Data for  `{player.Name}` on `{player.Plataform}` " +
                                                               $"is more than {player.Age.TotalHours:N0}h old, {ctx.User.Mention}. Retrieving fresh data, please wait...");

                    var tanks      = fetcher.GetTanksForPlayer(player.Plataform, player.Id);
                    var allTanks   = provider.GetTanks(player.Plataform).ToDictionary(t => t.TankId);
                    var validTanks = tanks.Where(t => allTanks.ContainsKey(t.TankId)).ToArray();
                    recorder.Set(validTanks);

                    var played = provider.GetWn8RawStatsForPlayer(player.Plataform, player.Id);
                    player.Performance = played;
                    player.Calculate(wn8Expected);
                    player.Moment = DateTime.UtcNow;
                    player.Origin = PlayerDataOrigin.Self;

                    var previous = provider.GetPlayer(player.Id, player.Date, true);
                    if (previous != null)
                    {
                        if (player.Check(previous, true))
                        {
                            Log.Warn($"Player {player.Name}.{player.Id}@{player.Plataform} was patched.");
                        }
                    }

                    if (player.CanSave())
                    {
                        recorder.Set(player);
                        if (!player.IsPatched)
                        {
                            var putter = new Putter(player.Plataform, ConfigurationManager.AppSettings["ApiAdminKey"]);
                            putter.Put(player);
                        }
                    }
                    else
                    {
                        Log.Warn($"Player {player.Name}.{player.Id}@{player.Plataform} has to much zero data.");
                    }
                }
                else
                {
                    player.Calculate(wn8Expected);
                }

                if (willTryApiMessage != null)
                {
                    await willTryApiMessage.DeleteAsync("Information updated.");
                }

                return(player);
            }
            catch (Exception ex)
            {
                Log.Error($"{nameof(GetPlayer)}({gamerTag})", ex);
                await ctx.RespondAsync($"Sorry, {ctx.User.Mention}. There was an error... the *Coder* will be notified of `{ex.Message}`.");

                return(null);
            }
        }
Пример #23
0
        public async Task Clan(CommandContext ctx, [Description("The clan **tag**")] string clanTag, [Description("Put `true` to dump all members of the clan")] bool all = false)
        {
            if (!await CanExecute(ctx, Features.Clans))
            {
                return;
            }

            await ctx.TriggerTypingAsync();

            if (string.IsNullOrWhiteSpace(clanTag))
            {
                await ctx.RespondAsync($"You must send a clan tag as parameter, {ctx.User.Mention}.");

                return;
            }

            Log.Debug($"Requesting {nameof(Clan)}({clanTag}, {all})...");

            var cfg      = GuildConfiguration.FromGuild(ctx.Guild);
            var platform = GetPlatform(clanTag, cfg.Plataform, out clanTag);

            clanTag = clanTag.Trim('[', ']');
            clanTag = clanTag.ToUpperInvariant();

            if (!ClanTagRegex.IsMatch(clanTag))
            {
                await ctx.RespondAsync($"You must send a **valid** clan **tag** as parameter, {ctx.User.Mention}.");

                return;
            }

            var provider = new DbProvider(_connectionString);

            var clan = provider.GetClan(platform, clanTag);

            if (clan == null)
            {
                platform = platform == Platform.PS ? Platform.XBOX : Platform.PS;

                clan = provider.GetClan(platform, clanTag);
                if (clan == null)
                {
                    await ctx.RespondAsync(
                        $"Can't find on a clan with tag `[{clanTag}]`, {ctx.User.Mention}. Maybe my site doesn't track it yet... or you have the wrong clan tag.");

                    return;
                }
            }

            var sb = new StringBuilder();

            sb.Append($"Information about the `{clan.ClanTag}`");
            if (!string.IsNullOrWhiteSpace(clan.Country))
            {
                sb.Append($" ({clan.Country.ToUpperInvariant()})");
            }

            sb.AppendLine($", on the {clan.Plataform}, {ctx.User.Mention}:");

            if (!clan.Enabled)
            {
                sb.AppendLine($"Data collection for this clan is **disabled**, the reason for this is {clan.DisabledReason}.");
            }

            sb.AppendLine();

            sb.AppendLine($"Active Members: {clan.Active}; Total Members: {clan.Count};");
            sb.AppendLine($"Recent Win Rate: {clan.ActiveWinRate:P1}; Overall Win Rate: {clan.TotalWinRate:P1};");
            sb.AppendLine($"Recent WN8t15: {clan.Top15Wn8:N0}; Overall WN8: {clan.TotalWn8:N0};");
            if (clan.DeltaDayTop15Wn8.HasValue)
            {
                sb.AppendLine($"WN8t15 Variation from 1 day ago: {clan.DeltaDayTop15Wn8.Value:N0}");
            }

            if (clan.DeltaWeekTop15Wn8.HasValue)
            {
                sb.AppendLine($"WN8t15 Variation from 1 week ago: {clan.DeltaWeekTop15Wn8.Value:N0}");
            }

            if (clan.DeltaMonthTop15Wn8.HasValue)
            {
                sb.AppendLine($"WN8t15 Variation from 1 month ago: {clan.DeltaMonthTop15Wn8.Value:N0}");
            }

            sb.AppendLine($"Recent Actives Battles: {clan.ActiveBattles:N0}; Recent Avg Tier: {clan.ActiveAvgTier:N1}");

            sb.AppendLine();
            sb.AppendLine("**Top 15 Active Players**");
            foreach (var p in clan.Top15Players)
            {
                sb.AppendLine(
                    $"{Formatter.MaskedUrl(p.Name, new Uri(p.PlayerOverallUrl))}, {p.MonthBattles} battles, WN8: {p.MonthWn8:N0}");
            }

            var title = clan.ClanTag.EqualsCiAi(clan.Name) ? clan.ClanTag : $"{clan.ClanTag} - {clan.Name}";

            var color = clan.Top15Wn8.ToColor();

            var platformPrefix = clan.Plataform == Platform.PS ? "ps." : string.Empty;

            var embed = new DiscordEmbedBuilder
            {
                Title       = title,
                Description = sb.ToString(),
                Color       = new DiscordColor(color.R, color.G, color.B),
                Url         = $"https://{platformPrefix}wotclans.com.br/Clan/{clan.ClanTag}",
                Author      = new DiscordEmbedBuilder.EmbedAuthor
                {
                    Name = "WoTClans",
                    Url  = $"https://{platform}wotclans.com.br"
                },
                Footer = new DiscordEmbedBuilder.EmbedFooter
                {
                    Text = $"Data calculated at {clan.Moment:yyyy-MM-dd HH:mm} UTC."
                }
            };

            Log.Debug($"Returned {nameof(Clan)}({clan.Plataform}.{clan.ClanTag})");

            await ctx.RespondAsync("", embed : embed);

            if (all)
            {
                // We need more responses, as discord limits the amount of data we can send on one message

                var       allPlayers = clan.Players.OrderByDescending(p => p.MonthBattles).ThenByDescending(p => p.TotalBattles).ToArray();
                const int pageSize   = 15;
                var       pages      = allPlayers.Length / pageSize + 1;

                color = clan.TotalWn8.ToColor();

                for (var currentPage = 0; currentPage < pages; ++currentPage)
                {
                    sb.Clear();

                    title = (clan.ClanTag.EqualsCiAi(clan.Name) ? clan.ClanTag : $"{clan.ClanTag} - {clan.Name}") +
                            $" - Page {currentPage + 1} of {pages}";

                    sb.Append($"All members of the `{clan.ClanTag}`");
                    if (!string.IsNullOrWhiteSpace(clan.Country))
                    {
                        sb.Append($" ({clan.Country.ToUpperInvariant()})");
                    }

                    sb.AppendLine($", on the {clan.Plataform}:");
                    sb.AppendLine();

                    foreach (var p in allPlayers.Skip(currentPage * pageSize).Take(pageSize))
                    {
                        sb.AppendLine($"{Formatter.MaskedUrl(p.Name, new Uri(p.PlayerOverallUrl))}, {p.MonthBattles} battles, WN8: {p.MonthWn8:N0}");
                    }

                    embed = new DiscordEmbedBuilder
                    {
                        Title       = title,
                        Description = sb.ToString(),
                        Color       = new DiscordColor(color.R, color.G, color.B),
                        Url         = $"https://{platformPrefix}wotclans.com.br/Clan/{clan.ClanTag}",
                        Author      = new DiscordEmbedBuilder.EmbedAuthor
                        {
                            Name = "WoTClans",
                            Url  = $"https://{platform}wotclans.com.br"
                        },
                        Footer = new DiscordEmbedBuilder.EmbedFooter
                        {
                            Text = $"Page {currentPage + 1} of {pages}"
                        }
                    };

                    await ctx.RespondAsync("", embed : embed);
                }
            }
        }
Пример #24
0
        public async Task ClanInactives(CommandContext ctx,
                                        [Description("The clan **tag**")] string clanTag)
        {
            try
            {
                if (!await CanExecute(ctx, Features.Clans))
                {
                    return;
                }

                await ctx.TriggerTypingAsync();

                if (string.IsNullOrWhiteSpace(clanTag))
                {
                    await ctx.RespondAsync($"You must send a clan tag as parameter, {ctx.User.Mention}.");

                    return;
                }

                Log.Debug($"Requesting {nameof(ClanInactives)}({clanTag})...");

                var cfg      = GuildConfiguration.FromGuild(ctx.Guild);
                var platform = GetPlatform(clanTag, cfg.Plataform, out clanTag);

                clanTag = clanTag.Trim('[', ']');
                clanTag = clanTag.ToUpperInvariant();

                if (!ClanTagRegex.IsMatch(clanTag))
                {
                    await ctx.RespondAsync($"You must send a **valid** clan **tag** as parameter, {ctx.User.Mention}.");

                    return;
                }

                var provider = new DbProvider(_connectionString);

                var clan = provider.GetClan(platform, clanTag);
                if (clan == null)
                {
                    platform = platform == Platform.PS ? Platform.XBOX : Platform.PS;

                    clan = provider.GetClan(platform, clanTag);
                    if (clan == null)
                    {
                        await ctx.RespondAsync(
                            $"Can't find on a clan with tag `[{clanTag}]`, {ctx.User.Mention}. Maybe my site doesn't track it yet... or you have the wrong clan tag.");

                        return;
                    }
                }

                if (!clan.Enabled)
                {
                    await ctx.RespondAsync($"Data collection for this clan is **disabled**, the reason for this is {clan.DisabledReason}, {ctx.User.Mention}.");

                    return;
                }

                var inactives = clan.Players.Where(p => !p.IsActive).ToArray();
                if (inactives.Length <= 0)
                {
                    await ctx.RespondAsync($"There are no inactive tankers on this clan, {ctx.User.Mention}.");

                    return;
                }

                // To retrieve the last battle
                for (int i = 0; i < inactives.Length; i++)
                {
                    inactives[i] = provider.GetPlayer(inactives[i].Id, true);
                }

                inactives = inactives.OrderBy(p => p.MonthBattles).ThenBy(p => p.LastBattle ?? DateTime.Today.AddYears(-5)).ToArray();

                var sb = new StringBuilder();

                sb.Append($"Information about `{clan.ClanTag}`'s {inactives.Length} inactives tankers on the {clan.Plataform}, {ctx.User.Mention}:");
                sb.AppendLine();

                var maxNameLength = inactives.Max(p => p.Name.Length);

                sb.AppendLine("```");
                sb.AppendLine($"{platform.TagName().PadRight(maxNameLength)} {"Days".PadLeft(5)} {"Battles".PadLeft(7)} {"WN8".PadLeft(6)}");
                foreach (var p in inactives.Take(30))
                {
                    sb.AppendLine($"{(p.Name ?? string.Empty).PadRight(maxNameLength)} {(DateTime.UtcNow - (p.LastBattle ?? DateTime.Today.AddYears(-5))).TotalDays.ToString("N0").PadLeft(5)} {p.MonthBattles.ToString("N0").PadLeft(7)} {p.TotalWn8.ToString("N0").PadLeft(6)}");
                }
                sb.AppendLine("```");

                var color          = clan.InactivesWn8.ToColor();
                var platformPrefix = clan.Plataform == Platform.PS ? "ps." : string.Empty;

                var embed = new DiscordEmbedBuilder
                {
                    Title       = $"{clan.ClanTag}'s Inactives Tankers",
                    Description = sb.ToString(),
                    Color       = new DiscordColor(color.R, color.G, color.B),
                    Url         = $"https://{platformPrefix}wotclans.com.br/Clan/{clan.ClanTag}",
                    Author      = new DiscordEmbedBuilder.EmbedAuthor
                    {
                        Name = "WoTClans",
                        Url  = $"https://{platformPrefix}wotclans.com.br"
                    },
                    Footer = new DiscordEmbedBuilder.EmbedFooter
                    {
                        Text = $"Calculated at {DateTime.UtcNow:yyyy-MM-dd HH:mm} UTC"
                    }
                };

                await ctx.RespondAsync("", embed : embed);
            }
            catch (Exception ex)
            {
                Log.Error($"Error calling {nameof(ClanInactives)}({clanTag})", ex);
                await ctx.RespondAsync(
                    $"Sorry, {ctx.User.Mention}. There was an error... the *Coder* will be notified of `{ex.Message}`.");
            }
        }
Пример #25
0
        public async Task Damage(CommandContext ctx,
                                 [Description("The Tank name, as it appears in battles. If it has spaces, enclose it on quotes.")][RemainingText] string tankName)
        {
            if (!await CanExecute(ctx, Features.Tanks))
            {
                return;
            }

            Log.Info($"Requesting {nameof(Damage)}({tankName})");

            await ctx.TriggerTypingAsync();

            var cfg = GuildConfiguration.FromGuild(ctx.Guild);

            var tank = FindTank(cfg.Plataform, tankName, out var exact);

            if (tank == null)
            {
                await ctx.RespondAsync($"Can't find a tank with `{tankName}` on the name, {ctx.User.Mention}.");

                return;
            }


            var provider = new DbProvider(_connectionString);
            var tr       = provider.GetTanksReferences(tank.Plataform, null, tank.TankId, false, false, false).FirstOrDefault();

            if (tr == null)
            {
                await ctx.RespondAsync($"Sorry, there is no tank statistics for the `{tank.Name}`, {ctx.User.Mention}.");

                return;
            }

            var sb = new StringBuilder();

            sb.AppendLine($"Here the **Target Damage** information about the `{tr.Name}`, Tier {tr.Tier.ToRomanNumeral()}, {tr.Nation.GetDescription()}, {(tr.IsPremium ? "Premium" : "Regular")}, {ctx.User.Mention}:");

            sb.AppendLine();
            sb.AppendLine("```");
            sb.AppendLine("Rating   WN8  Damage Piercings Shots");
            sb.AppendLine($"Average {    ((int)Wn8Rating.Average).ToString("N0").PadLeft(5)} {    tr.TargetDamageAverage.ToString("N0").PadLeft(6)}        {    tr.TargetDamageAveragePiercings.ToString("N0").PadLeft(2)}    {tr.TargetDamageAverageShots.ToString("N0").PadLeft(2)}");
            sb.AppendLine($"Good    {       ((int)Wn8Rating.Good).ToString("N0").PadLeft(5)} {       tr.TargetDamageGood.ToString("N0").PadLeft(6)}        {       tr.TargetDamageGoodPiercings.ToString("N0").PadLeft(2)}    {tr.TargetDamageGoodShots.ToString("N0").PadLeft(2)}");
            sb.AppendLine($"Great   {      ((int)Wn8Rating.Great).ToString("N0").PadLeft(5)} {      tr.TargetDamageGreat.ToString("N0").PadLeft(6)}        {      tr.TargetDamageGreatPiercings.ToString("N0").PadLeft(2)}    {tr.TargetDamageGreatShots.ToString("N0").PadLeft(2)}");
            sb.AppendLine($"Unicum  {     ((int)Wn8Rating.Unicum).ToString("N0").PadLeft(5)} {     tr.TargetDamageUnicum.ToString("N0").PadLeft(6)}        {     tr.TargetDamageUnicumPiercings.ToString("N0").PadLeft(2)}    {tr.TargetDamageUnicumShots.ToString("N0").PadLeft(2)}");
            sb.AppendLine($"Super   {((int)Wn8Rating.SuperUnicum).ToString("N0").PadLeft(5)} {tr.TargetDamageSuperUnicum.ToString("N0").PadLeft(6)}        {tr.TargetDamageSuperUnicumPiercings.ToString("N0").PadLeft(2)}    {tr.TargetDamageSuperUnicumShots.ToString("N0").PadLeft(2)}");
            sb.AppendLine("```");
            sb.AppendLine();

            sb.AppendLine($"Recent Averages: WN8: {tr.LastMonth.AverageWn8:N0}, Win Rate: {tr.LastMonth.WinRatio:P1}, Direct Dmg: {tr.LastMonth.DamageDealt:N0}, " +
                          $"Total Dmg: {tr.LastMonth.TotalDamage:N0}, Spots: {tr.LastMonth.Spotted:N1}, Kills: {tr.LastMonth.Kills:N1}.");

            var emoji = DiscordEmoji.FromName(ctx.Client, ":exclamation:");

            if (!exact)
            {
                sb.AppendLine();
                sb.AppendLine($"{emoji} If this is *not the tank* you are looking for, try sending the exact short name, the one that appears during battles, or enclosing the name in quotes.");
            }

            var platformPrefix = tr.Plataform == Platform.PS ? "ps." : string.Empty;

            var color = tr.LastMonth.AverageWn8.ToColor();

            var embed = new DiscordEmbedBuilder
            {
                Title        = $"{tank.Name} Target Damage",
                Description  = sb.ToString(),
                Color        = new DiscordColor(color.R, color.G, color.B),
                ThumbnailUrl = tank.SmallImageUrl,
                Url          = tank.Url,
                Author       = new DiscordEmbedBuilder.EmbedAuthor
                {
                    Name = "WoTClans",
                    Url  = $"https://{platformPrefix}wotclans.com.br"
                },
                Footer = new DiscordEmbedBuilder.EmbedFooter
                {
                    Text = $"Calculated at {tr.Date:yyyy-MM-dd} from {tr.LastMonth.TotalPlayers:N0} recent players and {tr.LastMonth.TotalBattles:N0} battles."
                }
            };

            await ctx.RespondAsync("", embed : embed);
        }
Пример #26
0
        public async Task GetSiteStatus(CommandContext ctx, [Description("The site to query, *PS* or *XBOX*")] string plataformString = "XBOX")
        {
            await ctx.TriggerTypingAsync();

            var userId = ctx?.User?.Id ?? 0;

            Log.Info($"Requesting {nameof(GetSiteStatus)} by {userId}...");
            if (userId != _coder)
            {
                var emoji = DiscordEmoji.FromName(ctx.Client, ":no_entry:");
                var embed = new DiscordEmbedBuilder
                {
                    Title       = "Access denied",
                    Description = $"{emoji} You may be a *coder*, but you are not **The Coder**!",
                    Color       = DiscordColor.Red
                };

                await ctx.RespondAsync("", embed : embed);

                return;
            }
            var cfg       = GuildConfiguration.FromGuild(ctx.Guild);
            var plataform = GetPlataform(plataformString + ".", cfg.Plataform, out var _);

            try
            {
                var cacheDirectory = ConfigurationManager.AppSettings["CacheDir"] ?? Path.GetTempPath();
                var webCacheAge    = TimeSpan.FromHours(4);
                var appId          = ConfigurationManager.AppSettings["WgAppId"] ?? "demo";

                var fetcher = new Fetcher(cacheDirectory)
                {
                    ApplicationId    = appId,
                    WebCacheAge      = webCacheAge,
                    WebFetchInterval = TimeSpan.FromSeconds(1)
                };

                var s = fetcher.GetSiteDiagnostic(plataform, ConfigurationManager.AppSettings["ApiAdminKey"]);

                var sb = new StringBuilder();
                sb.AppendLine($"Data Age Minutes: {s.DataAgeMinutes:N0}");
                sb.AppendLine($"Most Recent Clan Moment: {s.MostRecentClanMoment:yyyy-MM-dd HH:mm}");
                sb.AppendLine($"Tank Leaders Last Date: {s.TankLeadersLastDate:yyyy-MM-dd}");
                sb.AppendLine($"Tank MoE Last Date: {s.TanksMoELastDate:yyyy-MM-dd}");
                sb.AppendLine($"Players: {s.PlayersCount:N0}; Clans: {s.ClansCount:N0}");
                sb.AppendLine($"Clans With Players Updated On Last Hour: {s.ClansWithPlayersUpdatedOnLastHour:N0}");
                sb.AppendLine($"Since Started Load: {s.AveragedProcessCpuUsage.SinceStartedLoad:P1}");

                var plataformPrefix = plataform == Plataform.PS ? "ps." : string.Empty;

                var embed = new DiscordEmbedBuilder
                {
                    Title       = $"Site Status - {plataform.ToString().ToUpperInvariant()}",
                    Description = sb.ToString(),
                    Color       = DiscordColor.Goldenrod,
                    Author      = new DiscordEmbedBuilder.EmbedAuthor
                    {
                        Name = "WoTClans",
                        Url  = $"https://{plataformPrefix}wotclans.com.br"
                    },
                    Footer = new DiscordEmbedBuilder.EmbedFooter
                    {
                        Text = $"Retrieved at {s.ServerMoment:yyyy-MM-dd HH:mm} UTC."
                    }
                };

                await ctx.RespondAsync("", embed : embed);

                Log.Debug($"{nameof(GetSiteStatus)} returned ok.");
            }
            catch (Exception ex)
            {
                Log.Error($"{nameof(GetSiteStatus)}", ex);
                await ctx.RespondAsync($"Sorry, {ctx.User.Mention}. There was an error... the *Coder* will be notified of `{ex.Message}`.");

                return;
            }
        }
Пример #27
0
        public async Task LeaderByFlag(CommandContext ctx,
                                       [Description("The clan flag **code**. As they appears on https://wotclans.com.br/Flags")] string flagCode,
                                       [Description("The Tank name, as it appears in battles. If it has spaces, enclose it on quotes.")] string tankName,
                                       [Description("A gamer tag, to be searched on the leaderboard of this tank. If it has spaces, enclose it in quotes.")][RemainingText] string gamerTag)
        {
            if (!await CanExecute(ctx, Features.Tanks))
            {
                return;
            }

            Log.Info($"Requesting {nameof(LeaderByFlag)}({flagCode}, {tankName}, {gamerTag})");

            await ctx.TriggerTypingAsync();

            if (string.IsNullOrWhiteSpace(flagCode) || flagCode.Length != 2)
            {
                await ctx.RespondAsync($"Choose a valid flag code from {Formatter.MaskedUrl("the site", new Uri("https://wotclans.com.br/Flags"), "flags")}, {ctx.User.Mention}.");

                return;
            }
            flagCode = flagCode.RemoveDiacritics().ToLowerInvariant();

            var cfg = GuildConfiguration.FromGuild(ctx.Guild);

            var tank = FindTank(cfg.Plataform, tankName, out var exact);

            if ((tank == null) && !string.IsNullOrWhiteSpace(gamerTag) && (gamerTag.Length <= 2))
            {
                // Maybe the gamer tag is not a gamer tag, just the final part of a tank name...
                tank = FindTank(cfg.Plataform, tankName + " " + gamerTag, out exact);
                if (tank != null)
                {
                    // yeah... it was not a gamer tag
                    gamerTag = string.Empty;
                }
            }

            if (tank == null)
            {
                await ctx.RespondAsync($"Can't find a tank with `{tankName}` on the name, {ctx.User.Mention}.");

                return;
            }

            Log.Info($"Requested {nameof(LeaderByFlag)}({flagCode}, {tank.Plataform}.{tank.Name}, {gamerTag})");

            int top = 25;

            gamerTag = gamerTag ?? string.Empty;
            gamerTag = gamerTag.Replace("\"", "").ToLowerInvariant();
            if (!string.IsNullOrEmpty(gamerTag))
            {
                top = 1000;
            }

            var provider = new DbProvider(_connectionString);

            if (gamerTag.EqualsCiAi("me"))
            {
                var playerId = provider.GetPlayerIdByDiscordId((long)ctx.User.Id);
                if (playerId.HasValue)
                {
                    var player = provider.GetPlayer(playerId.Value);
                    gamerTag = player.Name;
                }
            }


            var leaderboard = provider.GetLeaderboard(tank.Plataform, tank.TankId, top, flagCode).Where(l => (l.ClanFlag ?? string.Empty)
                                                                                                        .ToLowerInvariant() == flagCode).ToArray();

            if (!leaderboard.Any())
            {
                await ctx.RespondAsync($"Sorry, there is no leaderboard information for the `{tank.Name}`, {ctx.User.Mention}.");

                return;
            }

            var sb = new StringBuilder();

            sb.AppendLine($"Here the top {Math.Min(leaderboard.Length, 25)} players from {flagCode.ToUpperInvariant()} on the `{tank.Name}`, Tier {tank.Tier.ToRomanNumeral()}, {tank.Nation.GetDescription()}, {(tank.IsPremium ? "Premium" : "Regular")}, {ctx.User.Mention}:");

            for (int i = 0; i < Math.Min(leaderboard.Length, 25); i++)
            {
                var l = leaderboard[i];
                sb.AppendLine($"{(i + 1).ToString().PadLeft(3)}: `{l.GamerTag}`, " +
                              $"from `{l.ClanTag}`. Dmg = {l.TotalDamage:N0} = {l.DirectDamage:N0} + {l.DamageAssisted:N0}");
            }

            if (!string.IsNullOrWhiteSpace(gamerTag))
            {
                Leader leader   = null;
                int    position = 1;
                for (int i = 0; i < leaderboard.Length; i++)
                {
                    var l = leaderboard[i];
                    if (l.GamerTag.ToLowerInvariant() == gamerTag.ToLowerInvariant())
                    {
                        position = i + 1;
                        leader   = l;
                        break;
                    }
                }

                if (leader != null)
                {
                    sb.AppendLine();
                    sb.AppendLine($" {Formatter.MaskedUrl(leader.GamerTag, new Uri(leader.PlayerOverallUrl), leader.GamerTag)} is in {position}th. Dmg = {leader.TotalDamage:N0} = {leader.DirectDamage:N0} + {leader.DamageAssisted:N0}");
                }
                else
                {
                    sb.AppendLine();
                    sb.AppendLine($"`{gamerTag}` does not appear on any place up to {leaderboard.Length:N0}th.");
                }
            }

            var emoji = DiscordEmoji.FromName(ctx.Client, ":exclamation:");

            if (!exact)
            {
                sb.AppendLine();
                sb.AppendLine($"{emoji} If this is *not the tank* you are looking for, try sending the exact short name, the one that appears during battles, or enclosing the name in quotes.");
            }

            var platformPrefix = leaderboard.First().Plataform == Platform.PS ? "ps." : string.Empty;

            var embed = new DiscordEmbedBuilder
            {
                Title        = $"{tank.Name} Leaderboard for {flagCode.ToUpperInvariant()}",
                Description  = sb.ToString(),
                Color        = DiscordColor.Gray,
                ThumbnailUrl = tank.SmallImageUrl,
                Url          = $"https://{platformPrefix}wotclans.com.br/Tanks/{tank.TankId}",
                Author       = new DiscordEmbedBuilder.EmbedAuthor
                {
                    Name = "WoTClans",
                    Url  = $"https://{platformPrefix}wotclans.com.br"
                },
                Footer = new DiscordEmbedBuilder.EmbedFooter
                {
                    Text = $"Calculated at {leaderboard.First().Date:yyyy-MM-dd}."
                }
            };

            await ctx.RespondAsync("", embed : embed);
        }
Пример #28
0
        public async Task TankerTank(CommandContext ctx,
                                     [Description("The *gamer tag* or *PSN Name*. If it has spaces, enclose it on double quotes.")] string gamerTag,
                                     [Description("The Tank name, as it appears in battles. If it has spaces, enclose it on double quotes.")][RemainingText] string tankName)
        {
            // Yeah... it's a Player featurem but it uses more calculations for tanks...
            if (!await CanExecute(ctx, Features.Players))
            {
                return;
            }

            if (string.IsNullOrWhiteSpace(gamerTag))
            {
                await ctx.RespondAsync($"Plase specify the *Gamer Tag*, {ctx.User.Mention}. Something like `!w tanker {ctx.User.Username.RemoveDiacritics()}`, for example.");

                return;
            }

            await ctx.TriggerTypingAsync();

            Log.Debug($"Requesting {nameof(TankerTank)}({gamerTag}, {tankName})...");

            try
            {
                var cfg = GuildConfiguration.FromGuild(ctx.Guild);

                var provider = new DbProvider(_connectionString);

                var playerCommands = new PlayerCommands();
                var player         = await playerCommands.GetPlayer(ctx, gamerTag);

                if (player == null)
                {
                    Log.Debug($"Could not find player {gamerTag}");
                    await ctx.RespondAsync($"I could not find a tanker " +
                                           $"with the Gamer Tag `{gamerTag}` on the Database, {ctx.User.Mention}. I may not track this player, or the Gamer Tag is wrong.");

                    return;
                }
                gamerTag = player.Name;

                var tank = FindTank(player.Plataform, tankName, out var exact);

                if (tank == null)
                {
                    await ctx.RespondAsync($"Can't find a tank with `{tankName}` on the name, {ctx.User.Mention}.");

                    return;
                }

                var tr = provider.GetTanksReferences(tank.Plataform, null, tank.TankId, false, false, false).FirstOrDefault();

                if (tr == null)
                {
                    await ctx.RespondAsync($"Sorry, there is no tank statistics for the `{tank.Name}`, {ctx.User.Mention}.");

                    return;
                }

                var hist = provider.GetPlayerHistoryByTank(player.Plataform, player.Id, tank.TankId).ToArray();
                if (!hist.Any())
                {
                    await ctx.RespondAsync($"Sorry, there is no tank statistics history for the `{tank.Name}` for the player `{gamerTag}`, {ctx.User.Mention}.");

                    return;
                }

                var wn8Expected = provider.GetWn8ExpectedValues(player.Plataform);

                foreach (var h in hist)
                {
                    h.Wn8 = wn8Expected.CalculateWn8(h);
                }

                Tanks.TankPlayerStatistics[] head, tail;
                if (hist.Length > 20)
                {
                    head = hist.Take(15).ToArray();
                    tail = hist.Skip(hist.Length - 5).Take(5).ToArray();
                }
                else
                {
                    head = hist;
                    tail = null;
                }

                var sb = new StringBuilder();

                sb.AppendLine($"History of the {Formatter.MaskedUrl(tr.Name, new Uri(tr.Url))}, Tier {tr.Tier.ToRomanNumeral()}, {(tr.IsPremium ? "Premium" : "Regular")}, as played by {Formatter.MaskedUrl(gamerTag, new Uri(player.PlayerOverallUrl))}, {ctx.User.Mention}:");
                sb.AppendLine();
                sb.AppendLine("```");
                sb.AppendLine("Date       Battles Tot.Dmg   WN8");
                foreach (var t in head)
                {
                    sb.AppendLine($"{t.LastBattle:yyyy-MM-dd} {t.Battles.ToString("N0").PadLeft(7)} {t.TotalDamagePerBattle.ToString("N0").PadLeft(7)} {t.Wn8.ToString("N0").PadLeft(6)}");
                }
                if (tail != null)
                {
                    sb.AppendLine("...");
                    foreach (var t in tail)
                    {
                        sb.AppendLine($"{t.LastBattle:yyyy-MM-dd} {t.Battles.ToString("N0").PadLeft(7)} {t.TotalDamagePerBattle.ToString("N0").PadLeft(7)} {t.Wn8.ToString("N0").PadLeft(6)}");
                    }
                }
                sb.AppendLine("```");
                sb.AppendLine();

                var ptr = player.Performance.All[tr.TankId];

                sb.AppendLine($"**{player.Name}** current values:");
                sb.AppendLine($"Total Damage: {ptr.TotalDamagePerBattle:N0} ");
                sb.AppendLine($"Direct Damage: {ptr.DirectDamagePerBattle:N0} ");
                sb.AppendLine($"Assited Damage: {ptr.DamageAssistedPerBattle:N0} ");
                sb.AppendLine($"WN8: {ptr.Wn8:N0}; Win Rate: {ptr.WinRate:P1}");
                sb.AppendLine($"Battles: {ptr.Battles:N0}; Hours Battling: {ptr.BattleLifeTime.TotalHours:N0}");
                sb.AppendLine($"Max Kills: {ptr.MaxFrags:N1}; Avg Kills: {ptr.KillsPerBattle:N1}");
                sb.AppendLine();
                sb.AppendLine($"**Global Recent** average among {tr.LastMonth.TotalPlayers:N0} players of the {tr.Name}:");
                sb.AppendLine($"Total Damage: {tr.LastMonth.TotalDamage:N0} ");
                sb.AppendLine($"Direct Damage: {tr.LastMonth.DamageDealt:N0} ");
                sb.AppendLine($"Assited Damage: {tr.LastMonth.DamageAssisted:N0} ");
                sb.AppendLine($"WN8: {tr.LastMonth.AverageWn8:N0}; Win Rate: {tr.LastMonth.WinRatio:P1}");
                sb.AppendLine($"Battles: {tr.LastMonth.BattlesPerPlayer:N0}; Hours Battling: {tr.LastMonth.TimePerPlayer.TotalHours:N0}");
                sb.AppendLine($"Max Kills: {tr.LastMonth.MaxKills:N1}; Avg Kills: {tr.LastMonth.Kills:N1}");

                var plataformPrefix = tr.Plataform == Plataform.PS ? "ps." : string.Empty;

                var color = ptr.Wn8.ToColor();

                var embed = new DiscordEmbedBuilder
                {
                    Title        = $"{gamerTag} history with the {tank.Name}",
                    Description  = sb.ToString(),
                    Color        = new DiscordColor(color.R, color.G, color.B),
                    ThumbnailUrl = tank.SmallImageUrl,
                    Url          = player.PlayerOverallUrl,
                    Author       = new DiscordEmbedBuilder.EmbedAuthor
                    {
                        Name = "WoTClans",
                        Url  = $"https://{plataformPrefix}wotclans.com.br"
                    },
                    Footer = new DiscordEmbedBuilder.EmbedFooter
                    {
                        Text = $"Calculatet at {player.Moment:yyyy-MM-dd HH:mm} UTC"
                    }
                };

                await ctx.RespondAsync("", embed : embed);
            }
            catch (Exception ex)
            {
                Log.Error($"{nameof(TankerTank)}({gamerTag})", ex);
                await ctx.RespondAsync($"Sorry, {ctx.User.Mention}. There was an error... the *Coder* will be notified of `{ex.Message}`.");

                return;
            }
        }