public async Task EventStart(CurrencyEvent.Type ev, params string[] options) { var(opts, _) = OptionsParser.ParseFrom(new EventOptions(), options); if (!await _service.TryCreateEventAsync(ctx.Guild.Id, ctx.Channel.Id, ev, opts, GetEmbed ).ConfigureAwait(false)) { await ReplyErrorLocalizedAsync("start_event_fail").ConfigureAwait(false); return; } }
public async Task Slowmode(params string[] args) { var(opts, succ) = OptionsParser.ParseFrom(new SlowmodeService.Options(), args); if (!succ) { await ReplyErrorLocalized("invalid_params").ConfigureAwait(false); return; } if (_service.StartSlowmode(Context.Channel.Id, opts.MessageCount, opts.PerSec)) { await Context.Channel.SendConfirmAsync(GetText("slowmode_init"), GetText("slowmode_desc", Format.Bold(opts.MessageCount.ToString()), Format.Bold(opts.PerSec.ToString()))) .ConfigureAwait(false); } }
public async Task TypeStart(params string[] args) { var(options, _) = OptionsParser.ParseFrom(new TypingGame.Options(), args); var channel = (ITextChannel)Context.Channel; var game = _service.RunningContests.GetOrAdd(channel.Guild.Id, id => new TypingGame(_games, _client, channel, Prefix, options)); if (game.IsActive) { await channel.SendErrorAsync( $"Contest already running in " + $"{game.Channel.Mention} channel.") .ConfigureAwait(false); } else { await game.Start().ConfigureAwait(false); } }
public async Task Commands(string module = null, params string[] args) { var channel = Context.Channel; var(opts, _) = OptionsParser.ParseFrom(new CommandsOptions(), args); module = module?.Trim().ToUpperInvariant(); if (string.IsNullOrWhiteSpace(module)) { return; } // Find commands for that module // don't show commands which are blocked // order by name var cmds = _cmds.Commands.Where(c => c.Module.GetTopLevelModule().Name.ToUpperInvariant().StartsWith(module, StringComparison.InvariantCulture)) .Where(c => !_perms.BlockedCommands.Contains(c.Aliases[0].ToLowerInvariant())) .OrderBy(c => c.Aliases[0]) .Distinct(new CommandTextEqualityComparer()); // check preconditions for all commands, but only if it's not 'all' // because all will show all commands anyway, no need to check HashSet <CommandInfo> succ = new HashSet <CommandInfo>(); if (opts.View != CommandsOptions.ViewType.All) { succ = new HashSet <CommandInfo>((await Task.WhenAll(cmds.Select(async x => { var pre = (await x.CheckPreconditionsAsync(Context, _services).ConfigureAwait(false)); return(Cmd: x, Succ: pre.IsSuccess); })).ConfigureAwait(false)) .Where(x => x.Succ) .Select(x => x.Cmd)); if (opts.View == CommandsOptions.ViewType.Hide) { // if hidden is specified, completely remove these commands from the list cmds = cmds.Where(x => succ.Contains(x)); } } var cmdsWithGroup = cmds.GroupBy(c => c.Module.Name.Replace("Commands", "", StringComparison.InvariantCulture)) .OrderBy(x => x.Key == x.First().Module.Name ? int.MaxValue : x.Count()); if (!cmds.Any()) { if (opts.View != CommandsOptions.ViewType.Hide) { await ReplyErrorLocalizedAsync("module_not_found").ConfigureAwait(false); } else { await ReplyErrorLocalizedAsync("module_not_found_or_cant_exec").ConfigureAwait(false); } return; } var i = 0; var groups = cmdsWithGroup.GroupBy(x => i++ / 48).ToArray(); var embed = new EmbedBuilder().WithOkColor(); foreach (var g in groups) { var last = g.Count(); for (i = 0; i < last; i++) { var transformed = g.ElementAt(i).Select(x => { //if cross is specified, and the command doesn't satisfy the requirements, cross it out if (opts.View == CommandsOptions.ViewType.Cross) { return($"{(succ.Contains(x) ? "✅" : "❌")}{Prefix + x.Aliases.First(),-15} {"[" + x.Aliases.Skip(1).FirstOrDefault() + "]",-8}"); } return($"{Prefix + x.Aliases.First(),-15} {"[" + x.Aliases.Skip(1).FirstOrDefault() + "]",-8}"); }); if (i == last - 1 && (i + 1) % 2 != 0) { var grp = 0; var count = transformed.Count(); transformed = transformed .GroupBy(x => grp++ % count / 2) .Select(x => { if (x.Count() == 1) { return($"{x.First()}"); } else { return(String.Concat(x)); } }); } embed.AddField(g.ElementAt(i).Key, "```css\n" + string.Join("\n", transformed) + "\n```", true); } } embed.WithFooter(GetText("commands_instr", Prefix)); await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); }
public async Task ChessChallenge(IGuildUser opponent, params string[] args) { if (opponent == Context.User) { await Context.Channel.SendErrorAsync("You cannot challenge yourself!").ConfigureAwait(false); return; } if (opponent.IsBot) { await Context.Channel.SendErrorAsync("You cannot challenge a bot (yet)!").ConfigureAwait(false); return; } var opts = OptionsParser.ParseFrom(new ChessOptions(), args); opts.ChallengeTo = opponent; var response = await Service.CreateChessChallenge(opts).ConfigureAwait(false); using var json = JsonDocument.Parse(response); var challenge = json.RootElement.GetProperty("challenge"); var challengeUrl = challenge.GetProperty("url").GetString(); var speed = $"{challenge.GetProperty("timeControl").GetProperty("show").GetString()} {challenge.GetProperty("speed").GetString().ToTitleCase()}"; if (string.IsNullOrWhiteSpace(challengeUrl)) { await Context.Channel.SendErrorAsync("Something went wrong when creating the challenge.\nPlease try again later"); return; } var userDm = await Context.User.GetOrCreateDMChannelAsync().ConfigureAwait(false); var oppDm = await opponent.GetOrCreateDMChannelAsync().ConfigureAwait(false); await Context.Channel.EmbedAsync(new EmbedBuilder().WithDynamicColor(Context) .WithTitle("Chess Challenge") .WithAuthor(speed) .WithDescription($"{Context.User.Mention} vs {opponent.Mention}\nCheck DMs for challenge link.")) .ConfigureAwait(false); try { if (opts.Color == ChessColor.Random) { await userDm.EmbedAsync(new EmbedBuilder().WithDynamicColor(Context) .WithTitle($"Chess Challenge vs {opponent}") .WithAuthor(speed) .WithDescription($"[Click here for Challenge Link]({challengeUrl})")) .ConfigureAwait(false); await oppDm.EmbedAsync(new EmbedBuilder().WithDynamicColor(Context) .WithTitle($"Chess Challenge vs {Context.User}") .WithAuthor(speed) .WithDescription($"[Click here for Challenge Link]({challengeUrl})")) .ConfigureAwait(false); } else { await userDm.EmbedAsync(new EmbedBuilder().WithColor(opts.Color == ChessColor.White ? new Color(255, 255, 255) : new Color(0, 0, 0)) .WithTitle($"Chess Challenge vs {opponent}") .WithAuthor($"{speed} as {opts.Color}") .WithDescription($"[Click here for Challenge Link]({challengeUrl}{(opts.Color == ChessColor.White ? "?color=white" : "?color=black")})")) .ConfigureAwait(false); await oppDm.EmbedAsync(new EmbedBuilder().WithColor(opts.Color == ChessColor.Black ? new Color(255, 255, 255) : new Color(0, 0, 0)) .WithTitle($"Chess Challenge vs {Context.User}") .WithAuthor($"{speed} as {opts.Color}") .WithDescription($"[Click here for Challenge Link]({challengeUrl}{(opts.Color == ChessColor.Black ? "?color=white" : "?color=black")})")) .ConfigureAwait(false); } } catch (Exception) { if (opts.Color == ChessColor.Random) { await userDm.EmbedAsync(new EmbedBuilder().WithDynamicColor(Context) .WithTitle("Chess Challenge") .WithAuthor(speed) .WithDescription($"{Context.User.Mention} vs {opponent.Mention}\n[Click here for Challenge Link]({challengeUrl})")) .ConfigureAwait(false); } else { await Context.Channel.EmbedAsync(new EmbedBuilder().WithDynamicColor(Context) .WithTitle("Chess Challenge") .WithAuthor($"{speed} as {opts.Color}") .WithDescription($"{Context.User.Mention} vs {opponent.Mention}\n[Click here for Challenge Link]({challengeUrl}{(opts.Color == ChessColor.White ? "?color=white" : "?color=black")})")) .ConfigureAwait(false); } } Service.PollGame(Context, opts, challengeUrl, speed); }
public async Task Repeat(GuildDateTime dt, params string[] options) { if (!_service.RepeaterReady) { return; } var(opts, _) = OptionsParser.ParseFrom(new Repeater.Options(), options); if (string.IsNullOrWhiteSpace(opts.Message) || opts.Interval >= 50001) { return; } var toAdd = new Repeater() { ChannelId = ctx.Channel.Id, GuildId = ctx.Guild.Id, Interval = TimeSpan.FromMinutes(opts.Interval), Message = opts.Message, NoRedundant = opts.NoRedundant, StartTimeOfDay = dt?.InputTimeUtc.TimeOfDay, }; using (var uow = _db.GetDbContext()) { var gc = uow.GuildConfigs.ForId(ctx.Guild.Id, set => set.Include(x => x.GuildRepeaters)); if (gc.GuildRepeaters.Count >= 5) { return; } gc.GuildRepeaters.Add(toAdd); await uow.SaveChangesAsync(); } var rep = new RepeatRunner((SocketGuild)ctx.Guild, toAdd, _service); _service.Repeaters.AddOrUpdate(ctx.Guild.Id, new ConcurrentDictionary <int, RepeatRunner>(new[] { new KeyValuePair <int, RepeatRunner>(toAdd.Id, rep) }), (key, old) => { old.TryAdd(rep.Repeater.Id, rep); return(old); }); string secondPart = ""; if (dt != null) { secondPart = GetText("repeater_initial", Format.Bold(rep.InitialInterval.Hours.ToString()), Format.Bold(rep.InitialInterval.Minutes.ToString())); } await ctx.Channel.SendConfirmAsync( "🔁 " + GetText("repeater", Format.Bold(((IGuildUser)ctx.User).GuildPermissions.MentionEveryone ? rep.Repeater.Message : rep.Repeater.Message.SanitizeMentions()), Format.Bold(rep.Repeater.Interval.Days.ToString()), Format.Bold(rep.Repeater.Interval.Hours.ToString()), Format.Bold(rep.Repeater.Interval.Minutes.ToString())) + " " + secondPart).ConfigureAwait(false); }
public async Task Connect4(params string[] args) { var(options, _) = OptionsParser.ParseFrom(new Connect4Game.Options(), args); if (!await CheckBetOptional(options.Bet).ConfigureAwait(false)) { return; } var newGame = new Connect4Game(Context.User.Id, Context.User.ToString(), options, _cs); Connect4Game game; if ((game = _service.Connect4Games.GetOrAdd(Context.Channel.Id, newGame)) != newGame) { if (game.CurrentPhase != Connect4Game.Phase.Joining) { return; } newGame.Dispose(); //means game already exists, try to join var joined = await game.Join(Context.User.Id, Context.User.ToString(), options.Bet).ConfigureAwait(false); return; } if (options.Bet > 0) { if (!await _cs.RemoveAsync(Context.User.Id, "Connect4-bet", options.Bet, true).ConfigureAwait(false)) { await ReplyErrorLocalized("not_enough", Bc.BotConfig.CurrencySign).ConfigureAwait(false); _service.Connect4Games.TryRemove(Context.Channel.Id, out _); game.Dispose(); return; } } game.OnGameStateUpdated += Game_OnGameStateUpdated; game.OnGameFailedToStart += Game_OnGameFailedToStart; game.OnGameEnded += Game_OnGameEnded; _client.MessageReceived += _client_MessageReceived; game.Initialize(); if (options.Bet == 0) { await ReplyConfirmLocalized("connect4_created").ConfigureAwait(false); } else { await ReplyConfirmLocalized("connect4_created_bet", options.Bet + Bc.BotConfig.CurrencySign).ConfigureAwait(false); } Task _client_MessageReceived(SocketMessage arg) { if (Context.Channel.Id != arg.Channel.Id) { return(Task.CompletedTask); } var _ = Task.Run(async() => { bool success = false; if (int.TryParse(arg.Content, out var col)) { success = await game.Input(arg.Author.Id, col).ConfigureAwait(false); } if (success) { try { await arg.DeleteAsync().ConfigureAwait(false); } catch { } } else { if (game.CurrentPhase == Connect4Game.Phase.Joining || game.CurrentPhase == Connect4Game.Phase.Ended) { return; } RepostCounter++; if (RepostCounter == 0) { try { msg = await Context.Channel.SendMessageAsync("", embed: (Embed)msg.Embeds.First()).ConfigureAwait(false); } catch { } } } }); return(Task.CompletedTask); } Task Game_OnGameFailedToStart(Connect4Game arg) { if (_service.Connect4Games.TryRemove(Context.Channel.Id, out var toDispose)) { _client.MessageReceived -= _client_MessageReceived; toDispose.Dispose(); } return(ErrorLocalized("connect4_failed_to_start")); } Task Game_OnGameEnded(Connect4Game arg, Connect4Game.Result result) { if (_service.Connect4Games.TryRemove(Context.Channel.Id, out var toDispose)) { _client.MessageReceived -= _client_MessageReceived; toDispose.Dispose(); } string title; if (result == Connect4Game.Result.CurrentPlayerWon) { title = GetText("connect4_won", Format.Bold(arg.CurrentPlayer.Username), Format.Bold(arg.OtherPlayer.Username)); } else if (result == Connect4Game.Result.OtherPlayerWon) { title = GetText("connect4_won", Format.Bold(arg.OtherPlayer.Username), Format.Bold(arg.CurrentPlayer.Username)); } else { title = GetText("connect4_draw"); } return(msg.ModifyAsync(x => x.Embed = new EmbedBuilder() .WithTitle(title) .WithDescription(GetGameStateText(game)) .WithOkColor() .Build())); } }
public async Task Leaderboard(int page = 1, params string[] args) { if (--page < 0) { return; } var(opts, _) = OptionsParser.ParseFrom(new LbOpts(), args); List <DiscordUser> cleanRichest = new List <DiscordUser>(); // it's pointless to have clean on dm context if (Context.Guild is null) { opts.Clean = false; } if (opts.Clean) { var now = DateTime.UtcNow; using (var uow = _db.GetDbContext()) { cleanRichest = uow.DiscordUsers.GetTopRichest(_client.CurrentUser.Id, 10_000); } await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); await _tracker.EnsureUsersDownloadedAsync(ctx.Guild).ConfigureAwait(false); var sg = (SocketGuild)Context.Guild; cleanRichest = cleanRichest.Where(x => sg.GetUser(x.UserId) != null) .ToList(); } else { using (var uow = _db.GetDbContext()) { cleanRichest = uow.DiscordUsers.GetTopRichest(_client.CurrentUser.Id, 9, page).ToList(); } } await Context.SendPaginatedConfirmAsync(page, curPage => { var embed = new EmbedBuilder() .WithOkColor() .WithTitle(CurrencySign + " " + GetText("leaderboard")); List <DiscordUser> toSend; if (!opts.Clean) { using (var uow = _db.GetDbContext()) { toSend = uow.DiscordUsers.GetTopRichest(_client.CurrentUser.Id, 9, curPage); } } else { toSend = cleanRichest.Skip(curPage * 9).Take(9).ToList(); } if (!toSend.Any()) { embed.WithDescription(GetText("no_user_on_this_page")); return(embed); } for (var i = 0; i < toSend.Count; i++) { var x = toSend[i]; var usrStr = x.ToString().TrimTo(20, true); var j = i; embed.AddField(efb => efb.WithName("#" + (9 * curPage + j + 1) + " " + usrStr) .WithValue(n(x.CurrencyAmount) + " " + CurrencySign) .WithIsInline(true)); } return(embed); }, opts.Clean?cleanRichest.Count() : 9000, 9, opts.Clean); }
public async Task Repeat(GuildDateTime dt, params string[] options) { if (!_service.RepeaterReady) { return; } var(opts, _) = OptionsParser.ParseFrom(new Repeater.Options(), options); if (string.IsNullOrWhiteSpace(opts.Message) || opts.Interval >= 50001) { return; } var startTimeOfDay = dt?.InputTimeUtc.TimeOfDay; // if interval not null, that means user specified it (don't change it) // if interval is null set the default to: // if time of day is specified: 24 * 60 (24h) // else 5 var realInterval = opts.Interval ?? (startTimeOfDay is null ? 5 : 24 * 60); var toAdd = new Repeater() { ChannelId = ctx.Channel.Id, GuildId = ctx.Guild.Id, Interval = TimeSpan.FromMinutes(realInterval), Message = opts.Message, NoRedundant = opts.NoRedundant, StartTimeOfDay = startTimeOfDay, }; using (var uow = _db.GetDbContext()) { var gc = uow.GuildConfigs.ForId(ctx.Guild.Id, set => set.Include(x => x.GuildRepeaters)); if (gc.GuildRepeaters.Count >= 5) { return; } gc.GuildRepeaters.Add(toAdd); await uow.SaveChangesAsync(); } var runner = new RepeatRunner(_client, (SocketGuild)ctx.Guild, toAdd, _service); _service.Repeaters.AddOrUpdate(ctx.Guild.Id, new ConcurrentDictionary <int, RepeatRunner>(new[] { new KeyValuePair <int, RepeatRunner>(toAdd.Id, runner) }), (key, old) => { old.TryAdd(runner.Repeater.Id, runner); return(old); }); var description = GetRepeaterInfoString(runner); await ctx.Channel.EmbedAsync(new EmbedBuilder() .WithOkColor() .WithTitle(GetText("repeater_created")) .WithDescription(description)); }
public Task Race(params string[] args) { var(options, success) = OptionsParser.ParseFrom(new RaceOptions(), args); var ar = new AnimalRace(options, _cs, Bc.BotConfig.RaceAnimals.Shuffle().ToArray()); if (!_service.AnimalRaces.TryAdd(Context.Guild.Id, ar)) { return(Context.Channel.SendErrorAsync(GetText("animal_race"), GetText("animal_race_already_started"))); } ar.Initialize(); var count = 0; Task _client_MessageReceived(SocketMessage arg) { var _ = Task.Run(() => { try { if (arg.Channel.Id == Context.Channel.Id) { if (ar.CurrentPhase == AnimalRace.Phase.Running && ++count % 9 == 0) { raceMessage = null; } } } catch { } }); return(Task.CompletedTask); } Task Ar_OnEnded(AnimalRace race) { _client.MessageReceived -= _client_MessageReceived; _service.AnimalRaces.TryRemove(Context.Guild.Id, out _); var winner = race.FinishedUsers[0]; if (race.FinishedUsers[0].Bet > 0) { return(Context.Channel.SendConfirmAsync(GetText("animal_race"), GetText("animal_race_won_money", Format.Bold(winner.Username), winner.Animal.Icon, (race.FinishedUsers[0].Bet * (race.Users.Length - 1)) + Bc.BotConfig.CurrencySign))); } else { return(Context.Channel.SendConfirmAsync(GetText("animal_race"), GetText("animal_race_won", Format.Bold(winner.Username), winner.Animal.Icon))); } } ar.OnStartingFailed += Ar_OnStartingFailed; ar.OnStateUpdate += Ar_OnStateUpdate; ar.OnEnded += Ar_OnEnded; ar.OnStarted += Ar_OnStarted; _client.MessageReceived += _client_MessageReceived; return(Context.Channel.SendConfirmAsync(GetText("animal_race"), GetText("animal_race_starting", options.StartTime), footer: GetText("animal_race_join_instr", Prefix))); }
public async Task WIP(params string[] args) { var(opts, _) = OptionsParser.ParseFrom(new RandomWIPOptions(), args); //parse options, to be used to check if the result should be unembedded var msg = await Context.Channel.SendMessageAsync(GetText("jl_randomfriend_searching")).ConfigureAwait(false); string wipPage; //we need to declare this here to use it out of the do-while loop string redirPage = "https://japari-library.com/wiki/Special:RandomInCategory/Missing_Content"; //by default look in the Missing_Content category //if requested, look for a specific kind of WIP page (unfortunately only 1 of these is possible at a time) if (opts.isIrl) { redirPage = "https://japari-library.com/wiki/Special:RandomInCategory/Needs_RL_Info"; } if (opts.isAppearance) { redirPage = "https://japari-library.com/wiki/Special:RandomInCategory/Needs_Appearance"; } if (opts.isPriority) { redirPage = "https://japari-library.com/wiki/Special:RandomInCategory/Priority_Articles"; } using (var http = _httpFactory.CreateClient()) { do { try { var response = await http.GetAsync(redirPage).ConfigureAwait(false); var location = response.Headers.Location; //the redirect isn't automatically followed, you have to dig in the response header to find out what the page actually is wipPage = location.AbsoluteUri; } catch (System.Net.Http.HttpRequestException) { await msg.ModifyAsync(m => m.Content = GetText("jl_wikisearch_error")).ConfigureAwait(false); return; } wipPage = Regex.Replace(wipPage, "http*", "https"); //the URI is http by default while japari-librari is https, the vanilla link works but this is more correct } while (wipPage.Contains("Category:")); //Category pages count as Friend pages but we don't want none of that if (opts.IsUnembedded) { wipPage = "<" + wipPage + ">"; //Enclosing a link in these tells Discord not to make an embed for it string successText = "jl_randomwip_success"; if (opts.isPriority) { successText = "jl_randomwip_priority_success"; } await msg.ModifyAsync(m => m.Content = GetText(successText, wipPage)).ConfigureAwait(false); } else //make it embedded { var config = Configuration.Default.WithDefaultLoader(); using (var document = await BrowsingContext.New(config).OpenAsync(wipPage).ConfigureAwait(false)) { var imageElem = document.QuerySelector("table.infobox > tbody > tr >td > p > a.image > img"); imageElem = ((IHtmlImageElement)imageElem)?.Source == null?document.QuerySelector("div.tabbertab > p > a > img") : imageElem; //if a wip page has multiple pictures, this will get the correct image var friendImageUrl = ((IHtmlImageElement)imageElem)?.Source ?? "http://icecream.me/uploads/870b03f36b59cc16ebfe314ef2dde781.png"; //get wip image or a default one if one cannot be loaded var friendInfoElem = document.QuerySelector("#mw-content-text > p"); // check if we can get the description or not, if not, just say the description is unavailable var friendInfo = friendInfoElem == null ? "Description unavailable" : friendInfoElem.InnerHtml; var friendNameElem = document.QuerySelector("#firstHeading"); var friendName = friendNameElem.InnerHtml; //get page name friendName = Regex.Replace(friendName, "<[^>]*>", ""); friendInfo = Regex.Replace(friendInfo, "<[^>]*>", ""); //remove html tags // footer var footer = new EmbedFooterBuilder(); footer.Text = "Japari Library"; footer.IconUrl = "https://japari-library.com/w/resources/assets/Jlibrarywglogo.png?d63ab"; await msg.DeleteAsync(); await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() //make a small embed .WithTitle(friendName) .WithDescription(friendInfo) .WithThumbnailUrl(friendImageUrl) .WithUrl(wipPage) .WithFooter(footer) ).ConfigureAwait(false); } } } }
public async Task Jeopardy(params string[] args) { JeopardyOptions opts = OptionsParser.ParseFrom(new JeopardyOptions(), args); if (Service.ActiveGames.TryGetValue(Context.Channel.Id, out Jeopardy activeGame)) { await Context.Channel.SendErrorAsync("Jeopardy game is already in progress in current channel.").ConfigureAwait(false); await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(activeGame.Color) .WithAuthor("Jeopardy!") .WithTitle($"{activeGame.CurrentClue.Category.Name} - ${activeGame.CurrentClue.Value}") .WithDescription(activeGame.CurrentClue.Text) .WithFooter($"#{activeGame.CurrentClue.Id} | answer with a question, e.g. what's x, who's x")) .ConfigureAwait(false); return; } await _semaphore.WaitAsync(); Jeopardy jeopardy; try { List <Category> categories = await Service.GenerateGame(opts.NumCategories).ConfigureAwait(false); jeopardy = new Jeopardy(_client, await _config.GetGuildConfigAsync(Context.Guild.Id), categories, Context.Guild, Context.Channel as ITextChannel, _currency, await Service.GenerateFinalJeopardy()); } catch (Exception e) { Log.Error(e, "Could not start jeopardy game"); _semaphore.Release(); return; } if (Service.ActiveGames.TryAdd(Context.Channel.Id, jeopardy)) { _semaphore.Release(); try { await jeopardy.StartGame().ConfigureAwait(false); } finally { Service.ActiveGames.TryRemove(Context.Channel.Id, out jeopardy); if (jeopardy != null) { await jeopardy.EnsureStopped().ConfigureAwait(false); jeopardy.Dispose(); } } } else { _semaphore.Release(); Log.Error("Could not start jeopardy game"); jeopardy.Dispose(); } }
public async Task XpLeaderboard(int page = 1, params string[] args) { if (--page < 0 || page > 100) { return; } var(opts, _) = OptionsParser.ParseFrom(new LbOpts(), args); await Context.Channel.TriggerTypingAsync(); var socketGuild = ((SocketGuild)ctx.Guild); List <UserXpStats> allUsers = new List <UserXpStats>(); if (opts.Clean) { await Context.Channel.TriggerTypingAsync().ConfigureAwait(false); await _tracker.EnsureUsersDownloadedAsync(ctx.Guild).ConfigureAwait(false); allUsers = _service.GetTopUserXps(ctx.Guild.Id, 1000) .Where(user => !(socketGuild.GetUser(user.UserId) is null)) .ToList(); } await ctx.SendPaginatedConfirmAsync(page, (curPage) => { var embed = new EmbedBuilder() .WithTitle(GetText("server_leaderboard")) .WithOkColor(); List <UserXpStats> users; if (opts.Clean) { users = allUsers.Skip(curPage * 9).Take(9).ToList(); } else { users = _service.GetUserXps(ctx.Guild.Id, curPage); } if (!users.Any()) { return(embed.WithDescription("-")); } else { for (int i = 0; i < users.Count; i++) { var levelStats = new LevelStats(users[i].Xp + users[i].AwardedXp); var user = ((SocketGuild)ctx.Guild).GetUser(users[i].UserId); var userXpData = users[i]; var awardStr = ""; if (userXpData.AwardedXp > 0) { awardStr = $"(+{userXpData.AwardedXp})"; } else if (userXpData.AwardedXp < 0) { awardStr = $"({userXpData.AwardedXp})"; } embed.AddField( $"#{(i + 1 + curPage * 9)} {(user?.ToString() ?? users[i].UserId.ToString())}", $"{GetText("level_x", levelStats.Level)} - {levelStats.TotalXp}xp {awardStr}"); } return(embed); } }, 900, 9, addPaginatedFooter : false); }