public async Task SetPrefix(string prefix) { var embed = new KaguyaEmbedBuilder(); if (prefix.Length > 5) { await ConsoleLogger.LogAsync("Command prefix was too long. Not set.", DataStorage.JsonStorage.LogLvl.DEBUG); embed.WithDescription("Your command prefix may not be longer than 5 characters."); embed.SetColor(EmbedColor.RED); await ReplyAsync(embed : embed.Build()); return; } Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id); server.CommandPrefix = prefix; await DatabaseQueries.UpdateAsync(server); embed.WithDescription($"Command prefix has been changed to `{prefix}`."); embed.WithFooter($"Use this command again without specifying a prefix to reset it."); embed.SetColor(EmbedColor.VIOLET); await ReplyAsync(embed : embed.Build()); }
public async Task SwapLogLevel(string level) { LogLvl curLog = ConfigProperties.LogLevel; string validSeverities = "Trace, Debug, Info, Warn, Error"; ConfigProperties.LogLevel = level.ToLower() switch { "trace" => LogLvl.TRACE, "debug" => LogLvl.DEBUG, "info" => LogLvl.INFO, "warn" => LogLvl.WARN, "error" => LogLvl.ERROR, _ => throw new ArgumentOutOfRangeException($"Valid logtypes are `{validSeverities}`", new Exception()) }; var embed = new KaguyaEmbedBuilder { Description = $"Successfully changed LogLevel from `{curLog.Humanize()}` to `{ConfigProperties.LogLevel.Humanize()}`", Footer = new EmbedFooterBuilder { Text = $"Note: This loglevel will return back to `{curLog.Humanize()}` after a restart." } }; embed.SetColor(EmbedColor.VIOLET); await ReplyAsync(embed : embed.Build()); } }
public async Task ResetLogChannel(string logType) { KaguyaEmbedBuilder embed; List <string> logTypes = await LogQuery.LogSwitcher(logType, false, Context.Guild.Id); if (logTypes.Count == 0) { embed = new KaguyaEmbedBuilder { Description = $"Please specify a valid log type." }; embed.SetColor(EmbedColor.RED); goto Reply; } if (logTypes.Any(x => x.Equals("all", System.StringComparison.OrdinalIgnoreCase))) { embed = new KaguyaEmbedBuilder { Description = $"Successfully disabled all log types." }; } else { embed = new KaguyaEmbedBuilder { Description = $"Successfully disabled logtype `{string.Join(", ", logTypes).ToUpper()}`." }; } Reply: await ReplyAsync(embed : embed.Build()); }
public async Task UnWarnUser(SocketGuildUser user, [Remainder] string reason = null) { Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id); List <WarnedUser> warnings = await DatabaseQueries.GetAllForServerAndUserAsync <WarnedUser>(user.Id, server.ServerId); int warnCount = warnings.Count; var fields = new List <EmbedFieldBuilder>(); reason ??= "<No reason provided>"; if (warnCount > 4 && !server.IsPremium) { warnCount = 4; } if (warnCount > 9 && server.IsPremium) { warnCount = 9; } if (warnings.Count == 0) { var reply = new KaguyaEmbedBuilder { Description = $"{user.Username} has no warnings to remove!" }; reply.SetColor(EmbedColor.RED); await ReplyAsync(embed : reply.Build()); return; } for (int i = 0; i < warnCount; i++) { var field = new EmbedFieldBuilder { Name = $"Warning #{i + 1}", Value = $"Reason: `{warnings.ElementAt(i).Reason}`" }; fields.Add(field); } var embed = new KaguyaEmbedBuilder { Title = $"Warnings for {user}", Fields = fields, Footer = new EmbedFooterBuilder { Text = "Select a reaction to remove the warning." } }; await ReactionReply(user, warnings, embed.Build(), warnCount, server, reason); }
public async Task UnmuteUser(SocketGuildUser user, [Remainder] string reason = null) { Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id); var mutedObject = await DatabaseQueries.GetFirstMatchAsync <MutedUser>(x => x.UserId == user.Id && x.ServerId == server.ServerId); reason ??= "<No reason provided>"; if (mutedObject != null) { await DatabaseQueries.DeleteAsync(mutedObject); } if (server.IsPremium) { await DatabaseQueries.UpdateAsync(server); } try { SocketRole muteRole = Context.Guild.Roles.FirstOrDefault(x => x.Name.ToLower() == "kaguya-mute"); if (!user.Roles.Contains(muteRole)) { await ReplyAsync($"{Context.User.Mention} **{user}** is not muted."); return; } await user.RemoveRoleAsync(muteRole); await ReplyAsync($"{Context.User.Mention} Successfully unmuted **{user}**."); KaguyaEvents.TriggerUnmute(new ModeratorEventArgs(server, Context.Guild, user, (SocketGuildUser)Context.User, reason, null)); } catch (NullReferenceException) { var errorEmbed = new KaguyaEmbedBuilder { Description = "User was never muted because the mute role doesn't exist.", Footer = new EmbedFooterBuilder { Text = "Use the mute command to generate the mute role." } }; errorEmbed.SetColor(EmbedColor.RED); await ReplyAsync(embed : errorEmbed.Build()); } catch (Exception e) { throw new KaguyaSupportException($"An unexpected error occurred.\n\nError Log: {e}"); } }
public async Task AddPhrase(params string[] args) { string s = "s"; if (args.Length == 1) { s = ""; } Server server = DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id).Result; List <FilteredPhrase> allFp = server.FilteredPhrases.ToList(); if (args.Length == 0) { var embed0 = new KaguyaEmbedBuilder { Description = "Please specify at least one phrase." }; embed0.SetColor(EmbedColor.RED); await SendEmbedAsync(embed0); return; } foreach (string element in args) { var fp = new FilteredPhrase { ServerId = server.ServerId, Phrase = element }; if (allFp.Contains(fp)) { continue; } await DatabaseQueries.InsertIfNotExistsAsync(fp); await ConsoleLogger.LogAsync($"Server {server.ServerId} has added the phrase \"{element}\" to their word filter.", DataStorage.JsonStorage.LogLvl.DEBUG); } var embed = new KaguyaEmbedBuilder { Description = $"Successfully added {args.Length} phrase{s} to the filter." }; embed.SetColor(EmbedColor.VIOLET); await ReplyAsync(embed : embed.Build()); }
/// <summary> /// Sends a basic error message in chat. /// </summary> /// <param name="channel"></param> /// <param name="description"></param> /// <returns></returns> public static async Task SendBasicErrorEmbedAsync(this IMessageChannel channel, string description) { var embed = new KaguyaEmbedBuilder { Description = description }; embed.SetColor(EmbedColor.RED); await channel.SendMessageAsync(embed : embed.Build()); }
private async Task <CommandInfo> FindCommandInfo(string cmd, Server server) { CommandService cmdInfo = CommandHandler.Commands; var allAliases = new List <string>(); foreach (CommandInfo command in cmdInfo.Commands) { allAliases.AddRange(command.Aliases.Select(alias => alias.ToLower())); } /*We use LastOrDefault instead of FirstOrDefault * because there are two "help" commands with the same names, but only the * last one has the proper description / syntax to be displayed in chat.*/ CommandInfo selectedCommandByName = cmdInfo.Commands.LastOrDefault(x => x.Name.ToLower() == cmd); CommandInfo selectedCommandByAlias = cmdInfo.Commands.LastOrDefault(x => x.Aliases.Contains(cmd)); CommandInfo selectedCommand; if (selectedCommandByAlias != null && selectedCommandByName == null || selectedCommandByAlias != null) { selectedCommand = selectedCommandByAlias; } else if (selectedCommandByName != null) { selectedCommand = selectedCommandByName; } else { var embed = new KaguyaEmbedBuilder { Description = $"Command `{server.CommandPrefix}{cmd}` does not exist. Please ensure you are typing the name (or ailias) correctly. " + $"Use `{server.CommandPrefix}help` for a list of all commands." }; embed.SetColor(EmbedColor.RED); await ReplyAsync(embed : embed.Build()); selectedCommand = null; } return(selectedCommand); }
public async Task Find([Remainder] string roleName) { SocketGuild guild = Context.Guild; IReadOnlyCollection <SocketRole> roles = guild.Roles; if (roles.All(x => x.Name.ToLower() != roleName.ToLower())) { var embed = new KaguyaEmbedBuilder { Description = $"The role `{roleName.ToUpper()}` could not be found." }; embed.SetColor(EmbedColor.RED); await ReplyAsync(embed : embed.Build()); return; } int matchCount = roles.Count(x => x.Name.ToLower() == roleName.ToLower()); if (matchCount > 1) { await MultipleMatchingRolesHandler(guild, roleName, roles); return; } SocketRole matchingRole = guild.Roles.FirstOrDefault(x => x.Name.ToLower() == roleName.ToLower()); List <PaginatedMessage.Page> pages = Pages(guild, matchingRole); var pager = new PaginatedMessage { Pages = pages, Color = Color.Blue }; await PagedReplyAsync(pager, new ReactionList { Backward = true, First = true, Forward = true, Jump = true, Last = true, Trash = true }); }
public async Task RemovePhrase() { Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id); List <FilteredPhrase> allFp = server.FilteredPhrases.ToList(); foreach (FilteredPhrase element in allFp) { await DatabaseQueries.DeleteAsync(element); } var embed = new KaguyaEmbedBuilder { Description = $"Successfully cleared the server's word filter. ({allFp.Count} phrases)" }; embed.SetColor(EmbedColor.VIOLET); await ReplyAsync(embed : embed.Build()); }
public async Task RemoveRole(params string[] roleNames) { if (roleNames.Length > 1) { var embed = new KaguyaEmbedBuilder { Title = "Roles Created" }; foreach (string role in roleNames) { embed.AddField("Role Created", $"`{role}` has been created."); await Context.Guild.CreateRoleAsync(role, GuildPermissions.None, Color.Default, false, false, null); } await ReplyAsync(embed : embed.Build()); } else if (roleNames.Count() == 1) { var embed = new KaguyaEmbedBuilder { Description = $"**{Context.User.Mention} Successfully created role `{roleNames[0]}`**" }; await Context.Guild.CreateRoleAsync(roleNames[0], GuildPermissions.None, Color.Default, false, false, null); await ReplyAsync(embed : embed.Build()); } else { var embed = new KaguyaEmbedBuilder { Description = $"Please specify a role to create." }; embed.SetColor(EmbedColor.RED); await ReplyAsync(embed : embed.Build()); } }
private static async Task <KaguyaEmbedBuilder> WarnEmbed(WarnedUser user, ICommandContext context) { List <WarnedUser> curWarns = await DatabaseQueries.GetAllForServerAndUserAsync <WarnedUser>(user.UserId, context.Guild.Id); int curCount = curWarns.Count; var embed = new KaguyaEmbedBuilder { Title = "⚠️ Warning Received", Description = $"Warned from `[Server: {context.Guild} | ID: {context.Guild.Id}]`\n" + $"Warned by: `[User: {context.User} | ID: {context.User.Id}]`\n" + $"Reason: `{user.Reason}`", Footer = new EmbedFooterBuilder { Text = $"You currently have {curCount} warnings." } }; embed.SetColor(EmbedColor.RED); return(embed); }
public async Task React(string text, ulong msgId = 0) { IMessage message = null; if (msgId == 0) { message = Context.Message; } if (msgId != 0) { message = await Context.Channel.GetMessageAsync(msgId); } if (text.Length > 10) { var embed = new KaguyaEmbedBuilder { Description = "Your reaction may not be more than 10 characters long." }; embed.SetColor(EmbedColor.RED); await ReplyAsync(embed : embed.Build()); return; } text.Replace(" ", ""); var emojis = new List <Emoji>(); foreach (char letter in text) { emojis.Add(new Emoji($"{ReturnEmoji(letter)}")); } await(message as IUserMessage).AddReactionsAsync(emojis.ToArray()); }
public async Task Remind(string timeString, [Remainder] string text) { TimeSpan time = timeString.ParseToTimespan(); KaguyaEmbedBuilder embed; if (time.TotalSeconds < 10) { embed = new KaguyaEmbedBuilder { Description = "You must set a reminder for at least 10 seconds from now." }; embed.SetColor(EmbedColor.RED); await ReplyAsync(embed : embed.Build()); return; } var reminder = new Reminder { UserId = Context.User.Id, Expiration = DateTime.Now.AddSeconds(time.TotalSeconds).ToOADate(), Text = text, HasTriggered = false }; await DatabaseQueries.InsertAsync(reminder); embed = new KaguyaEmbedBuilder { Description = $"Okay! I'll remind you in `{time.Humanize(3)}` to `{text}`" }; await ReplyAsync(embed : embed.Build()); }
public async Task Command() { DiscordShardedClient client = Client; SocketUser owner = client.GetUser(ConfigProperties.BotConfig.BotOwnerId); KaguyaStatistics stats = MemoryCache.MostRecentStats; int totalGuilds = stats.Guilds; int totalTextChannels = stats.TextChannels; int totalVoiceChannels = stats.VoiceChannels; Dictionary <string, int> mostPopCommand = MemoryCache.MostPopularCommandCache; string mostPopCommandName = mostPopCommand?.Keys.First(); string mostPopCommandCount = mostPopCommand?.Values.First().ToString("N0"); string mostPopCommandText; if (mostPopCommandName == null || String.IsNullOrWhiteSpace(mostPopCommandCount)) { mostPopCommandText = "Data not loaded into cache yet."; } else { mostPopCommandText = $"{mostPopCommandName} with {int.Parse(mostPopCommandCount.Replace(",", "")):N0} uses."; } var fields = new List <EmbedFieldBuilder> { new EmbedFieldBuilder { Name = "Author", Value = $"User: `{owner}`\n" + $"Id: `{owner.Id}`" }, new EmbedFieldBuilder { Name = "Command Stats", Value = $"Commands Run (Last 24 Hours): `{stats.CommandsLast24Hours:N0}`\n" + $"Commands Run (All-time): `{stats.Commands:N0}`\n" + $"Most Popular Command: `{mostPopCommandText}`" }, new EmbedFieldBuilder { Name = "Global Stats", Value = $"Uptime: `{(DateTime.Now - DateTime.Now.AddSeconds(-stats.UptimeSeconds)).Humanize(4, minUnit: TimeUnit.Second)}`\n" + $"Guilds: `{totalGuilds:N0}`\n" + $"Text Channels: `{totalTextChannels:N0}`\n" + $"Voice Channels: `{totalVoiceChannels:N0}`\n" + $"Users: `{stats.GuildUsers:N0}`\n" + $"RAM Usage: `{stats.RamUsageMegabytes:N2} Megabytes`\n" + $"Current Version: `{stats.Version}`" }, new EmbedFieldBuilder { Name = "Kaguya User Stats", Value = $"Unique Interactions (Users): `{stats.KaguyaUsers:N0}`\n" + $"Total Points in Circulation: `{stats.Points:N0}`\n" + $"Total Gambles: `{stats.Gambles:N0}`" } }; var embed = new KaguyaEmbedBuilder { Title = "Kaguya Statistics", Fields = fields }; embed.SetColor(EmbedColor.GOLD); await ReplyAsync(embed : embed.Build()); }
public async Task ClearMessages(int amount = 10, string reason = null) { if (amount > 1000) { await SendBasicErrorEmbedAsync("You may not attempt to clear more than `1,000` messages " + "at a time."); return; } if (amount < 1) { await SendBasicErrorEmbedAsync("You must clear at least 1 message."); return; } Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id); KaguyaEmbedBuilder embed; server.IsCurrentlyPurgingMessages = true; await DatabaseQueries.UpdateAsync(server); IMessage[] messages = (await Context.Channel.GetMessagesAsync(amount + 1).FlattenAsync()).ToArray(); IEnumerable <IMessage> invalidMessages = messages.Where(x => x.Timestamp.DateTime < DateTime.Now.AddDays(-14)); await((SocketTextChannel)Context.Channel).DeleteMessagesAsync(messages); // We take away 1 because the bot's own message is included in the collection. int msgDisplayCount = messages.Length - 1; string s = msgDisplayCount == 1 ? string.Empty : "s"; if (!invalidMessages.Any()) { embed = new KaguyaEmbedBuilder { Description = $"Successfully deleted `{msgDisplayCount}` message{s}." }; await ReplyAndDeleteAsync("", false, embed.Build(), TimeSpan.FromSeconds(4)); } else { embed = new KaguyaEmbedBuilder { Description = $"Successfully deleted `{msgDisplayCount}` messages. Failed to delete " + $"`{amount - msgDisplayCount}` message{s}. This is likely because those " + "messages were posted more than two weeks ago. Messages posted more than two " + "weeks ago may not be deleted by Discord bots (this is a Discord-imposed limitation).", Footer = new EmbedFooterBuilder { Text = "This message will be deleted in 15 seconds..." } }; embed.SetColor(EmbedColor.VIOLET); await ReplyAndDeleteAsync("", false, embed.Build(), TimeSpan.FromSeconds(15)); } server.IsCurrentlyPurgingMessages = false; await DatabaseQueries.UpdateAsync(server); }
public async Task Command(string action = null, int warnings = 0) { Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id); var serverActions = await DatabaseQueries.GetFirstForServerAsync <WarnSetting>(server.ServerId); if (action == null && warnings == 0) { if (serverActions == null) { var nullErrorEmbed = new KaguyaEmbedBuilder { Description = "Nothing has been configured." }; nullErrorEmbed.SetColor(EmbedColor.RED); await ReplyAsync(embed : nullErrorEmbed.Build()); return; } var curSettingsEmbed = new KaguyaEmbedBuilder { Description = $"`{Context.Guild.Name}`. Here's what I've got:\n\n" + $"`Mute`: After `{(serverActions.Mute.IsZero() ? "N/A" : serverActions.Mute.ToString().Humanize())}` warnings.\n" + $"`Kick`: After `{(serverActions.Kick.IsZero() ? "N/A" : serverActions.Kick.ToString().Humanize())}` warnings.\n" + $"`Shadowban`: After `{(serverActions.Shadowban.IsZero() ? "N/A" : serverActions.Shadowban.ToString().Humanize())}` warnings.\n" + $"`Ban`: After `{(serverActions.Ban.IsZero() ? "N/A" : serverActions.Ban.ToString().Humanize())}` warnings.\n" }; await ReplyAsync(embed : curSettingsEmbed.Build()); return; } var actions = new string[] { "mute", "kick", "shadowban", "ban" }; if (actions.All(x => x.ToLower() != action)) { var errorEmbed = new KaguyaEmbedBuilder { Description = $"`{Context.Message.Content}` is not a valid action. The only valid " + $"actions are `mute`, `kick`, `shadowban`, and `ban`." }; errorEmbed.SetColor(EmbedColor.RED); await ReplyAsync(embed : errorEmbed.Build()); return; } if (warnings < 0 || warnings > 99) { var numError = new KaguyaEmbedBuilder { Description = "The amount of warnings must be between `0` and `99`." }; numError.SetColor(EmbedColor.RED); await ReplyAsync(embed : numError.Build()); return; } var newSetting = new WarnSetting { ServerId = Context.Guild.Id }; if (serverActions != null) { newSetting = serverActions; } switch (action.ToLower()) { case "mute": newSetting.Mute = warnings; break; case "kick": newSetting.Kick = warnings; break; case "shadowban": newSetting.Shadowban = warnings; break; case "ban": newSetting.Ban = warnings; break; } await DatabaseQueries.InsertOrReplaceAsync(newSetting); var successEmbed = new KaguyaEmbedBuilder { Description = $"Successfully updated the warn triggers for " + $"`{Context.Guild.Name}`. Here's what I've got:\n\n" + $"`Mute`: After `{(newSetting.Mute.IsZero() ? "N/A" : newSetting.Mute.ToString().Humanize())}` warnings.\n" + $"`Kick`: After `{(newSetting.Kick.IsZero() ? "N/A" : newSetting.Kick.ToString().Humanize())}` warnings.\n" + $"`Shadowban`: After `{(newSetting.Shadowban.IsZero() ? "N/A" : newSetting.Shadowban.ToString().Humanize())}` warnings.\n" + $"`Ban`: After `{(newSetting.Ban.IsZero() ? "N/A" : newSetting.Ban.ToString().Humanize())}` warnings.\n" }; successEmbed.SetColor(EmbedColor.PINK); await ReplyAsync(embed : successEmbed.Build()); }
public async Task RemovePhrase(params string[] args) { string s = "s"; if (args.Length == 1) { s = ""; } Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id); List <FilteredPhrase> allFp = server.FilteredPhrases.ToList(); if (args.Length == 0) { var embed0 = new KaguyaEmbedBuilder { Description = "Please specify at least one phrase." }; embed0.SetColor(EmbedColor.RED); await Context.Channel.SendEmbedAsync(embed0); return; } int remCount = 0; bool matches = false; foreach (string element in args) { if (!allFp.Any(x => x.Phrase.ToLower() == element.ToLower() && x.ServerId == server.ServerId)) { continue; } await DatabaseQueries.DeleteAsync(allFp.FirstOrDefault(x => x.Phrase.ToLower() == element.ToLower() && x.ServerId == server.ServerId)); matches = true; remCount++; await ConsoleLogger.LogAsync($"Server {server.ServerId} has removed the phrase \"{element}\" from their word filter.", DataStorage.JsonStorage.LogLvl.DEBUG); } KaguyaEmbedBuilder embed; if (!matches) { embed = new KaguyaEmbedBuilder(EmbedColor.RED) { Description = "The phrases you wrote here are not present in your filter.", Footer = new EmbedFooterBuilder { Text = "If your phrase has a space, wrap it in quotation marks." } }; } else { if (remCount == args.Length) { embed = new KaguyaEmbedBuilder(EmbedColor.VIOLET) { Description = $"Successfully removed `{args.Length:N0}` phrase{s} from the filter." }; } else { s = remCount == 0 ? "" : "s"; embed = new KaguyaEmbedBuilder(EmbedColor.ORANGE) { Description = $"Successfully removed `{remCount:N0}` phrase{s} from the filter.\n" + $"`{args.Length - remCount}` phrases did not exist in the filter." }; } } await ReplyAsync(embed : embed.Build()); }
public async Task RemoveRole([Remainder] string targetRole) { var roles = new List <SocketRole>(); roles = Context.Guild.Roles.Where(r => r.Name.ToLower() == targetRole.ToLower()).ToList(); if (roles.Count > 1) { var emojis = new Emoji[] { new Emoji("1⃣"), new Emoji("2⃣"), new Emoji("3⃣"), new Emoji("4⃣"), new Emoji("5⃣"), new Emoji("6⃣"), new Emoji("7⃣"), new Emoji("8⃣"), new Emoji("9⃣") }; var embed = new KaguyaEmbedBuilder { Description = $"I found `{roles.Count.ToWords()}` roles that match this name. Please " + $"select the role that you want to delete, or use the ⛔ reaction " + $"to delete all roles with this name.", Fields = new List <EmbedFieldBuilder>() }; var callbacks = new List <(IEmote, Func <SocketCommandContext, SocketReaction, Task>)>(); for (int i = 0; i < roles.Count; i++) { int roleIndex = i + 1; SocketRole role = roles.ElementAt(i); embed.Fields.Add(new EmbedFieldBuilder { Name = $"Role #{roleIndex}", Value = $"Exact Name: `{role.Name}`\n" + $"Number of users who have this role: " + $"`{Context.Guild.Users.Count(x => x.Roles.Contains(role))}`\n" + $"Permissions: `{roles.Count}`\n" + $"Created: `{role.CreatedAt.Humanize()}`\n" + $"Position in role list (higher number = higher position): `{role.Position}`" }); callbacks.Add((emojis[i], async(c, r) => { await role.DeleteAsync(); await ReplyAsync($"{Context.User.Mention} `Successfully deleted Role #{roleIndex}`"); } )); } callbacks.Add((new Emoji("⛔"), async(c, r) => { foreach (SocketRole role in roles) { await role.DeleteAsync(); } await ReplyAsync($"{Context.User.Mention} Successfully deleted `{roles.Count.ToWords()}` roles."); } )); var data = new ReactionCallbackData("", embed.Build(), false, false, TimeSpan.FromSeconds(120)); data.SetCallbacks(callbacks); await InlineReactionReplyAsync(data); } else if (roles.Count == 1) { SocketRole role = roles.First(); var embed = new KaguyaEmbedBuilder { Description = $"{Context.User.Mention} Successfully deleted role `{role.Name}`" }; await role.DeleteAsync(); await ReplyAsync(embed : embed.Build()); } else { var embed = new KaguyaEmbedBuilder { Description = $"I could not find the specified role." }; embed.SetColor(EmbedColor.RED); await ReplyAsync(embed : embed.Build()); } }
public async Task Command(IGuildUser user = null, [Remainder] string reason = null) { Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id); List <Praise> userPraise = await DatabaseQueries.GetAllForServerAndUserAsync <Praise>(Context.User.Id, server.ServerId); double lastGivenPraise = DatabaseQueries.GetLastPraiseTime(Context.User.Id, Context.Guild.Id); if (user == null && reason == null) { await SendBasicSuccessEmbedAsync($"You currently have `{userPraise.Count}` praise."); return; } if (user == null) { var curEmbed = new KaguyaEmbedBuilder { Description = $"You currently have `{userPraise.Count}` praise." }; await Context.Channel.SendEmbedAsync(curEmbed); return; } if (user == Context.User) { var userErrorEmbed = new KaguyaEmbedBuilder { Description = $"You can't praise yourself!" }; userErrorEmbed.SetColor(EmbedColor.RED); await ReplyAsync(embed : userErrorEmbed.Build()); return; } double cooldownTime = DateTime.Now.AddHours(-server.PraiseCooldown).ToOADate(); if (!(lastGivenPraise < cooldownTime)) { var timeErrorEmbed = new KaguyaEmbedBuilder { Description = $"Sorry, you must wait " + $"`{(DateTime.FromOADate(lastGivenPraise) - DateTime.FromOADate(cooldownTime)).Humanize()}` " + $"before giving praise again." }; timeErrorEmbed.SetColor(EmbedColor.RED); await ReplyAsync(embed : timeErrorEmbed.Build()); return; } if (reason == null) { reason = "No reason provided."; } var praise = new Praise { UserId = user.Id, ServerId = server.ServerId, GivenBy = Context.User.Id, Reason = reason, Server = server, TimeGiven = DateTime.Now.ToOADate() }; await DatabaseQueries.InsertAsync(praise); List <Praise> newTargetPraise = await DatabaseQueries.GetAllForServerAndUserAsync <Praise>(praise.UserId, praise.ServerId); int newTargetPraiseCount = newTargetPraise.Count; var embed = new KaguyaEmbedBuilder { Description = $"Successfully awarded `{user}` with `+1` praise.\n" + $"Reason: `{reason}`", Footer = new EmbedFooterBuilder { Text = $"{user.Username} now has {newTargetPraiseCount} praise. " + $"You have {userPraise.Count} praise." } }; await ReplyAsync(embed : embed.Build()); }
public async Task RedeemKey(params string[] keys) { User user = await DatabaseQueries.GetOrCreateUserAsync(Context.User.Id); Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id); List <PremiumKey> existingPremiumKeys = await DatabaseQueries.GetAllAsync <PremiumKey>(); foreach (string keyString in keys) { PremiumKey premiumKey = existingPremiumKeys.FirstOrDefault(x => x.Key == keyString && x.UserId == 0 && x.ServerId == 0); if (premiumKey == null) { await Context.Message.DeleteAsync(); var embed0 = new KaguyaEmbedBuilder { Description = "Key does not exist or has already been redeemed.", Footer = new EmbedFooterBuilder { Text = $"If you need assistance, please join the server provided in {server.CommandPrefix}invite" } }; embed0.SetColor(EmbedColor.RED); await ReplyAsync(embed : embed0.Build()); return; } IKey newKey; if (!string.IsNullOrEmpty(premiumKey?.Key)) { newKey = new PremiumKey { Key = premiumKey.Key, LengthInSeconds = premiumKey.LengthInSeconds, KeyCreatorId = premiumKey.KeyCreatorId, UserId = Context.User.Id, ServerId = Context.Guild.Id }; await DatabaseQueries.InsertOrReplaceAsync((PremiumKey)newKey); } else { await Context.Message.DeleteAsync(); throw new KaguyaSupportException("Failed to redeem your key. Please " + "join our support server for assistance."); } TimeSpan ts = $"{newKey.LengthInSeconds}s".ParseToTimespan(); user.TotalDaysPremium += (int)TimeSpan.FromSeconds(newKey.LengthInSeconds).TotalDays; int totalDaysSupported = user.TotalDaysPremium; double userPremiumExpiration = user.PremiumExpiration; if (userPremiumExpiration < DateTime.Now.ToOADate()) { userPremiumExpiration = DateTime.Now.ToOADate(); } userPremiumExpiration = DateTime.FromOADate(userPremiumExpiration).AddSeconds(premiumKey.LengthInSeconds).ToOADate(); user.PremiumExpiration = userPremiumExpiration; // If the server has never been premium before, or was but it has expired, // we need to reset the expiration to Now + the key's length. if (server.PremiumExpiration < DateTime.Now.ToOADate()) { server.PremiumExpiration = DateTime.Now.AddSeconds(premiumKey.LengthInSeconds).ToOADate(); } else { server.PremiumExpiration = DateTime.FromOADate(server.PremiumExpiration) .AddSeconds(premiumKey.LengthInSeconds).ToOADate(); } var embed = new KaguyaEmbedBuilder { Description = $"Successfully redeemed `" + $"{ts.Humanize(maxUnit: TimeUnit.Day)}` of Kaguya Premium!\n" + $"This server's subscription will expire on: `{DateTime.FromOADate(server.PremiumExpiration).ToLongDateString()}`\n" + $"Your personal subscription will expire on: `{DateTime.FromOADate(userPremiumExpiration).ToLongDateString()}`\n" + $"You've supported for `{totalDaysSupported:N0}` days! " + $"That's `{ServerUptimeCalcInDays(totalDaysSupported):N2} days` of server uptime 💙", Footer = new EmbedFooterBuilder { Text = "It may not seem like a lot, but it all adds up. Thanks for your support!" } }; embed.SetColor(EmbedColor.GOLD); await ReplyAsync(embed : embed.Build()); #if !DEBUG await SendEmbedToBotOwner(Context, newKey); #endif await DatabaseQueries.UpdateAsync(user); await DatabaseQueries.UpdateAsync(server); await ApplyRewardsToUser(user, Context.User, premiumKey); } }
public async Task Command() { // Cooldown in seconds. const int FISHING_COOLDOWN = 15; const int FISHING_COOLDOWN_PREMIUM = 5; User user = await DatabaseQueries.GetOrCreateUserAsync(Context.User.Id); Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id); if (user.Points < user.FishCost()) { var baitEmbed = new KaguyaEmbedBuilder(EmbedColor.RED) { Description = $"You do not have enough points to play the fishing game.", Footer = new EmbedFooterBuilder { Text = $"You need {user.FishCost()} points to play. You have {user.Points} points." } }; await SendEmbedAsync(baitEmbed); return; } bool isPremium = user.IsPremium; if (user.LastFished >= DateTime.Now.AddSeconds(-FISHING_COOLDOWN).ToOADate() && !isPremium || user.LastFished >= DateTime.Now.AddSeconds(-FISHING_COOLDOWN_PREMIUM).ToOADate() && isPremium) { TimeSpan ts = DateTime.FromOADate(user.LastFished) - DateTime.Now.AddSeconds(-15); if (isPremium) { ts -= TimeSpan.FromSeconds(10); } var errorEmbed = new KaguyaEmbedBuilder(EmbedColor.RED) { Description = $"Please wait `{ts.Humanize(minUnit: TimeUnit.Second)}` before fishing again." }; await ReplyAndDeleteAsync("", false, errorEmbed.Build(), TimeSpan.FromSeconds(3)); return; } int value; var embed = new KaguyaEmbedBuilder { Description = $"🎣 | {Context.User.Mention} " }; var r = new Random(); double roll = r.NextDouble(); int fishId = r.Next(int.MaxValue); int fishExp; while (await DatabaseQueries.ItemExistsAsync <Fish>(x => x.FishId == fishId)) { fishId = r.Next(int.MaxValue); } var bonuses = new FishHandler.FishLevelBonuses(user.FishExp); roll *= 1 - (bonuses.BonusLuckPercent / 100); if (isPremium) { roll *= 0.95; } FishType fishType = GetFishType(roll); switch (fishType) { case FishType.SEAWEED: value = 2; fishExp = 0; embed.Description += $"Aw man, you caught `seaweed`. Better luck next time!"; embed.SetColor(EmbedColor.GRAY); break; case FishType.PINFISH: value = 15; fishExp = r.Next(1, 3); embed.Description += $"you caught a `pinfish`!"; embed.SetColor(EmbedColor.GRAY); break; case FishType.SMALL_BASS: value = 25; fishExp = r.Next(2, 6); embed.Description += $"you caught a `small bass`!"; embed.SetColor(EmbedColor.GREEN); break; case FishType.SMALL_SALMON: value = 25; fishExp = r.Next(2, 6); embed.Description += $"you caught a `small salmon`!"; embed.SetColor(EmbedColor.GREEN); break; case FishType.CATFISH: value = 75; fishExp = r.Next(5, 9); embed.Description += $"you caught a `catfish`!"; embed.SetColor(EmbedColor.GREEN); break; case FishType.LARGE_BASS: value = 150; fishExp = r.Next(7, 11); embed.Description += $"Wow, you caught a `large bass`!"; embed.SetColor(EmbedColor.LIGHT_BLUE); break; case FishType.LARGE_SALMON: value = 150; fishExp = r.Next(7, 11); embed.Description += $"Wow, you caught a `large salmon`!"; embed.SetColor(EmbedColor.LIGHT_BLUE); break; case FishType.RED_DRUM: value = 200; fishExp = r.Next(7, 20); embed.Description += $"Holy smokes, you caught a `red drum`!"; embed.SetColor(EmbedColor.RED); break; case FishType.TRIGGERFISH: value = 350; fishExp = r.Next(11, 30); embed.Description += $"Holy smokes, you caught a `triggerfish`!"; embed.SetColor(EmbedColor.LIGHT_PURPLE); break; case FishType.GIANT_SEA_BASS: value = 500; fishExp = r.Next(18, 36); embed.Description += $"No way, you caught a `giant sea bass`! Nice work!"; embed.SetColor(EmbedColor.LIGHT_PURPLE); break; case FishType.SMALLTOOTH_SAWFISH: value = 1000; fishExp = r.Next(29, 42); embed.Description += $"No way, you caught a `smalltooth sawfish`! Nice work!"; embed.SetColor(EmbedColor.LIGHT_PURPLE); break; case FishType.DEVILS_HOLE_PUPFISH: value = 2500; fishExp = r.Next(40, 95); embed.Description += $"I can't believe my eyes!! you caught a `devils hold pupfish`! You're crazy!"; embed.SetColor(EmbedColor.VIOLET); break; case FishType.ORANTE_SLEEPER_RAY: value = 5000; fishExp = r.Next(75, 325); embed.Description += $"Hot diggity dog, you caught an `orante sleeper ray`! This is unbelievable!"; embed.SetColor(EmbedColor.ORANGE); break; case FishType.GIANT_SQUID: value = 20000; fishExp = r.Next(400, 900); embed.Description += $"Well butter my buttcheeks and call me a biscuit, you caught the second " + $"rarest fish in the sea! It's a `giant squid`!! Congratulations!"; embed.SetColor(EmbedColor.ORANGE); break; case FishType.BIG_KAHUNA: value = 50000; fishExp = r.Next(1250, 4500); embed.Description += $"<a:siren:429784681316220939> NO WAY! You hit the jackpot " + $"and caught the **Legendary `BIG KAHUNA`**!!!! " + $"What an incredible moment this is! <a:siren:429784681316220939>"; embed.SetColor(EmbedColor.GOLD); break; default: value = 0; fishExp = 0; embed.Description += $"Oh no, it took your bait! Better luck next time..."; embed.SetColor(EmbedColor.GRAY); break; } user.FishExp += fishExp; user.Points -= user.FishCost(); user.LastFished = DateTime.Now.ToOADate(); var fish = new Fish { FishId = fishId, UserId = Context.User.Id, ServerId = Context.Guild.Id, TimeCaught = DateTime.Now.ToOADate(), FishType = fishType, FishString = fishType.ToString(), Value = value, Exp = fishExp, Sold = false }; value = Fish.GetPayoutForFish(fish, user.FishExp); await DatabaseQueries.InsertAsync(fish); await DatabaseQueries.UpdateAsync(user); await KaguyaEvents.TriggerFish(new FishHandlerEventArgs(user, fish, Context)); // Triggers the fish EXP service. if (fishType != FishType.BAIT_STOLEN) { List <Fish> existingFish = (await DatabaseQueries.GetFishForUserMatchingTypeAsync(fishType, user.UserId)).ToList(); int fishCount = existingFish.Count(x => !x.Sold); string fishString = fishType.ToString().Replace("_", " ").ToLower(); embed.Description += $"\n\nFish ID: `{fishId}`\n" + $"Fish Value: `{value:N0}` points.\n" + $"Fishing Exp Earned: `{fishExp:N0} exp`\n" + $"Points Remaining: `{user.Points:N0} (-{user.FishCost()})`\n\n" + $"You now have `{fishCount}` `{fishString}`"; } else { embed.Description += $"\nPoints Remaining: `{user.Points:N0} (-{user.FishCost()})`"; } embed.Footer = new EmbedFooterBuilder { Text = $"Use the {server.CommandPrefix}myfish command to view your fishing stats!\n" + $"The {server.CommandPrefix}sellfish command may be used to sell your fish." }; // Fish Embed await ReplyAsync(embed : embed.Build()); }
public static Task Initialize() { var timer = new Timer(DURATION_MS); timer.AutoReset = true; timer.Enabled = true; timer.Elapsed += async(sender, e) => { List <User> users = await DatabaseQueries.GetAllAsync <User>(x => x.ActiveRateLimit > 0 && x.UserId != 146092837723832320); foreach (User registeredUser in users) { if (registeredUser.LastRatelimited < DateTime.Now.Add(TimeSpan.FromDays(-30)).ToOADate() && registeredUser.RateLimitWarnings > 0) { registeredUser.RateLimitWarnings = 0; await ConsoleLogger.LogAsync($"User [ID: {registeredUser.UserId}] has had their Ratelimit Warnings reset " + $"due to not being ratelimited for 30 days.", LogLvl.INFO); } // The user has been rate limited within the last 30 seconds. // Don't accidentally double-rate-limit them. if (registeredUser.LastRatelimited > DateTime.Now.AddSeconds(-30).ToOADate() && registeredUser.RateLimitWarnings > 0) { return; } if (registeredUser.ActiveRateLimit >= THRESHOLD_REG && !registeredUser.IsPremium || registeredUser.ActiveRateLimit >= THRESHOLD_PREMIUM && registeredUser.IsPremium) { registeredUser.LastRatelimited = DateTime.Now.ToOADate(); registeredUser.RateLimitWarnings++; if (registeredUser.RateLimitWarnings > 7 && registeredUser.ActiveRateLimit > 0) { SocketUser socketUser = ConfigProperties.Client.GetUser(registeredUser.UserId); var maxRlimitEmbed = new KaguyaEmbedBuilder(EmbedColor.RED) { Description = "You have exceeded your maximum allotment of ratelimit strikes, therefore " + "you will be permanently blacklisted." }; try { await socketUser.SendMessageAsync(embed : maxRlimitEmbed.Build()); } catch (HttpException) { await ConsoleLogger.LogAsync($"Attempted to DM user {socketUser.Id} about " + $"acheiving the maximum allotted ratelimit strikes, " + $"but a Discord.Net.HttpException was thrown.", LogLvl.WARN); } var bl = new UserBlacklist { UserId = socketUser.Id, Expiration = DateTime.MaxValue.ToOADate(), Reason = "Ratelimit service: Automatic permanent blacklist for surpassing " + "7 ratelimit strikes in one month.", User = registeredUser }; registeredUser.ActiveRateLimit = 0; await DatabaseQueries.UpdateAsync(registeredUser); await DatabaseQueries.InsertOrReplaceAsync(bl); await ConsoleLogger.LogAsync( $"User [Name: {socketUser.Username} | ID: {socketUser.Id} | Supporter: {registeredUser.IsPremium}] " + "has been permanently blacklisted. Reason: Excessive Ratelimiting", LogLvl.WARN); return; } SocketUser user = ConfigProperties.Client.GetUser(registeredUser.UserId); if (user == null) { return; } string[] durations = { "60s", "5m", "30m", "3h", "12h", "1d", "3d" }; List <TimeSpan> timeSpans = durations.Select(RegexTimeParser.ParseToTimespan).ToList(); string humanizedTime = timeSpans.ElementAt(registeredUser.RateLimitWarnings - 1).Humanize(); var tempBlacklist = new UserBlacklist { UserId = user.Id, Expiration = (DateTime.Now + timeSpans.ElementAt(registeredUser.RateLimitWarnings - 1)).ToOADate(), Reason = $"Ratelimit service: Automatic {timeSpans.ElementAt(registeredUser.RateLimitWarnings - 1)} " + $"temporary blacklist for surpassing a ratelimit strike", User = registeredUser }; await DatabaseQueries.InsertOrReplaceAsync(tempBlacklist); var curRlimEmbed = new KaguyaEmbedBuilder { Description = $"You have been ratelimited for `{humanizedTime}`\n\n" + $"For this time, you may not use any commands or earn experience points.", Footer = new EmbedFooterBuilder { Text = $"You have {registeredUser.RateLimitWarnings} ratelimit strikes. Receiving " + $"{durations.Length - registeredUser.RateLimitWarnings} more strikes will result " + $"in a permanent blacklist." } }; curRlimEmbed.SetColor(EmbedColor.RED); bool dm = true; try { await user.SendMessageAsync(embed : curRlimEmbed.Build()); } catch (Exception) { dm = false; } await ConsoleLogger.LogAsync($"User [Name: {user?.Username} | ID: {user?.Id} | Supporter: {registeredUser.IsPremium}] " + $"has been ratelimited. Duration: {humanizedTime} Direct Message Sent: {dm}", LogLvl.INFO); } if (registeredUser.ActiveRateLimit > 0) { registeredUser.ActiveRateLimit = 0; await DatabaseQueries.UpdateAsync(registeredUser); } } }; return(Task.CompletedTask); }
public async Task DeleteRoles() { KaguyaEmbedBuilder embed; var confirmEmbed = new KaguyaEmbedBuilder { Description = $"{Context.User.Username}, are you sure you " + $"wish to preform this action?" }; confirmEmbed.SetColor(EmbedColor.VIOLET); var timeoutEmbed = new KaguyaEmbedBuilder { Description = "Timeout reached - reactions disabled. No action will be taken." }; timeoutEmbed.SetColor(EmbedColor.RED); await InlineReactionReplyAsync(new ReactionCallbackData("", confirmEmbed.Build(), true, true, TimeSpan.FromSeconds(60)) .WithCallback(GlobalProperties.CheckMarkEmoji(), async(c, r) => { int i = 0; int j = 0; string failString = ""; foreach (SocketRole role in Context.Guild.Roles.Where(x => !x.Members.Any() && x.Name.ToLower() != "kaguya-mute")) { try { await role.DeleteAsync(); i++; } catch (Exception) { j++; } } if (j != 0) { failString = $"However, I failed to delete `{j}` roles. These roles are likely " + "managed by integrations, therefore they cannot be deleted. \n" + "*Hint: Is my role at the top of the hierarchy?*"; } if (i == 0 && j == 0) { embed = new KaguyaEmbedBuilder { Description = "Actually, there weren't any roles to delete - no action has been taken." }; await ReplyAsync(embed: embed.Build()); } else { embed = new KaguyaEmbedBuilder { Description = $"Successfully deleted `{i}` roles. {failString}" }; await ReplyAsync(embed: embed.Build()); } }) .WithCallback(new Emoji("⛔"), async(c, r) => { embed = new KaguyaEmbedBuilder { Description = $"Okay, no action will be taken." }; await ReplyAsync(embed: embed.Build()); })); }
public async Task Command(int bet) { if (bet < 5) { throw new ArgumentOutOfRangeException(nameof(bet), "Your bet must be at least `5` points."); } User user = await DatabaseQueries.GetOrCreateUserAsync(Context.User.Id); if (bet > MAX_BET && !user.IsPremium) { await SendBasicErrorEmbedAsync($"Sorry, but only premium subscribers may bet more than " + $"`{MAX_BET:N0}` points."); return; } if (bet > MAX_PREMIUM_BET && user.IsPremium) { await SendBasicErrorEmbedAsync($"Sorry, but you may not bet more than " + $"`{MAX_PREMIUM_BET:N0}` points."); return; } if (user.Points < bet) { await SendBasicErrorEmbedAsync($"You don't have enough points to perform this action.\n" + $"Current points: `{user.Points:N0}` points."); return; } var r = new Random(); int roll = r.Next(101); if (roll > 100) { roll = 100; } if (user.IsPremium) { roll = (int)(roll * 1.05); } RollResult rollResult = GetRollResult(roll); int payout = GetPayout(rollResult, bet); bool winner; var embed = new KaguyaEmbedBuilder { Title = $"Kaguya Betting: " }; switch (rollResult) { case RollResult.LOSS: winner = false; embed.Title += "Loser"; embed.Description = $"{Context.User.Mention} rolled `{roll}` and lost their bet of " + $"`{bet:N0}` points! Better luck next time!"; break; default: winner = true; embed.Title += "Winner!"; embed.Description = $"{Context.User.Mention} rolled `{roll}` and won " + $"`{payout:N0}` points, **`{GetMultiplier(rollResult)}x`** their bet!"; break; } user = user.AddPoints((uint)payout); var gh = new GambleHistory { UserId = user.UserId, Action = GambleAction.BET_ROLL, Bet = bet, Payout = payout, Roll = roll, Time = DateTime.Now.ToOADate(), Winner = winner }; await DatabaseQueries.InsertAsync(gh); await DatabaseQueries.UpdateAsync(user); List <GambleHistory> allGh = await DatabaseQueries.GetAllForUserAsync <GambleHistory>(user.UserId); var footer = new EmbedFooterBuilder { Text = $"New points balance: {user.Points:N0} | Lifetime Bets: {allGh.Count:N0}" }; embed.Footer = footer; embed.SetColor(GetEmbedColorBasedOnRoll(rollResult)); await SendEmbedAsync(embed); }
public async Task OsuRecentCommand([Remainder] string player = null) { var embed = new KaguyaEmbedBuilder(); OsuClient client = OsuBase.Client; User user = await DatabaseQueries.GetOrCreateUserAsync(Context.User.Id); Server server = await DatabaseQueries.GetOrCreateServerAsync(Context.Guild.Id); OsuSharp.User osuPlayer = player == null ? await client.GetUserByUserIdAsync(user.OsuId, GameMode.Standard) : await client.GetUserByUsernameAsync(player, GameMode.Standard); // Maybe the user provided an ID to search for. if (osuPlayer == null && long.TryParse(player, out long id)) { osuPlayer = await client.GetUserByUserIdAsync(id, GameMode.Standard); } // If it's still null, they don't exist. if (osuPlayer == null) { embed.Description = $"{Context.User.Mention} Failed to acquire username! " + "Please specify a player or set your osu! username with " + $"`{server.CommandPrefix}osuset`!"; await ReplyAsync(embed : embed.Build()); return; } Score osuRecent = player == null ? (await client.GetUserRecentsByUserIdAsync(user.OsuId, GameMode.Standard, 1)).FirstOrDefault() : (await client.GetUserRecentsByUsernameAsync(player, GameMode.Standard, 1)).FirstOrDefault(); if (osuRecent == null) { embed.WithAuthor(author => { author .WithName($"{osuPlayer.Username} doesn't have any recent plays.") .WithIconUrl("https://a.ppy.sh/" + osuPlayer.UserId); }); await SendEmbedAsync(embed); return; } // Reset the embed as its values were changed in the above code. embed = new KaguyaEmbedBuilder(); Beatmap beatmap = await osuRecent.GetBeatmapAsync(); //Author embed.WithAuthor(author => { author .WithName($"Recent: {osuPlayer.Username} | {beatmap.Title} [{beatmap.Difficulty}] by {beatmap.Author}") .WithIconUrl("https://a.ppy.sh/" + osuPlayer.UserId); }); //Description PerformanceData scoredPerformance = await OppaiClient.GetPPAsync(osuRecent.BeatmapId, osuRecent.Mods, (float)osuRecent.Accuracy, osuRecent.MaxCombo); PerformanceData wouldbePerformance = await OppaiClient.GetPPAsync(osuRecent.BeatmapId, osuRecent.Mods, (float)osuRecent.Accuracy, beatmap.MaxCombo); string beatmapLink = $"https://osu.ppy.sh/b/{beatmap.BeatmapId}"; string discussionLink = $"https://osu.ppy.sh/beatmapsets/{beatmap.BeatmapsetId}/discussion"; string downloadLink = $"https://osu.ppy.sh/beatmapsets/{beatmap.BeatmapsetId}/download"; var descSb = new StringBuilder(); // Links (Row 0) descSb.AppendLine($"**Links:** [Listing]({beatmapLink}) ▸ [Modding]({discussionLink}) ▸ [Download]({downloadLink})"); descSb.AppendLine(); // Row 1 descSb.AppendLine($@"• {OsuBase.OsuGradeEmote(osuRecent.Rank)} {osuRecent.Mods.ToModeString(OsuBase.Client) .Replace("No Mode", "No Mod") .Replace("DTNC", "NC")} | {scoredPerformance.Stars:N2}★"); // Row 2 descSb.Append($"• **Combo:** {osuRecent.MaxCombo:N0}x / {beatmap.MaxCombo:N0}x ▸ "); descSb.AppendLine($"**Accuracy:** {osuRecent.Accuracy:N2}% ▸ **Score:** {osuRecent.TotalScore:N0}"); // Row 3 descSb.Append($"• {osuRecent.Count300:N0} / {osuRecent.Count100:N0} / {osuRecent.Count50:N0} / {osuRecent.Miss:N0} ▸ "); descSb.AppendLine($"**BPM:** {beatmap.Bpm:N0} ▸ **Length:** {beatmap.TotalLength.TotalMinutes:00}:{beatmap.TotalLength.Seconds:00}"); // Row 4 descSb.Append($"• **CS:** {GetStatNumAsString(scoredPerformance.Cs)} ▸ **AR:** {GetStatNumAsString(scoredPerformance.Ar)} ▸ "); descSb.AppendLine($"**OD:** {GetStatNumAsString(scoredPerformance.Od)} ▸ **HP:** {GetStatNumAsString(scoredPerformance.Hp)}"); // Row 5 descSb.AppendLine($"• **Performance:** {scoredPerformance.Pp:N2}pp ({wouldbePerformance.Pp:N2}pp for {osuRecent.Accuracy:N2}% FC)"); if (osuRecent.MaxCombo == beatmap.MaxCombo) { embed.SetColor(EmbedColor.GOLD); descSb.Append("Full combo!"); } embed.Description = descSb.ToString(); //Footer TimeSpan difference = DateTime.UtcNow - osuRecent.Date.Value.DateTime; string humanizedDif = difference.Humanize(2, minUnit: TimeUnit.Second); embed.WithFooter($"{osuPlayer.Username} performed this play {humanizedDif} ago."); await ReplyAsync(embed : embed.Build()); }
public async Task Command(IGuildUser guildUser = null, [Remainder] string reason = null) { User user = await DatabaseQueries.GetOrCreateUserAsync(Context.User.Id); List <Rep> rep = await DatabaseQueries.GetAllForUserAsync <Rep>(user.UserId); int repCount = rep.Count; if (guildUser == null) { var curRepEmbed = new KaguyaEmbedBuilder { Description = $"You have `{repCount}` rep." }; await ReplyAsync(embed : curRepEmbed.Build()); return; } if (!user.CanGiveRep) { var denyEmbed = new KaguyaEmbedBuilder { Description = $"{Context.User.Mention} you must wait " + $"`{(DateTime.FromOADate(user.LastGivenRep) - DateTime.Now.AddHours(-24)).Humanize()}` " + $"before giving rep again." }; denyEmbed.SetColor(EmbedColor.RED); await ReplyAsync(embed : denyEmbed.Build()); return; } if (guildUser == Context.User) { var invalidUserEmbed = new KaguyaEmbedBuilder { Description = $"You may not rep yourself!" }; invalidUserEmbed.SetColor(EmbedColor.RED); await ReplyAsync(embed : invalidUserEmbed.Build()); return; } if (guildUser.IsBot) { var invalidUserEmbed = new KaguyaEmbedBuilder { Description = $"Sorry, rep can't be given to bots." }; invalidUserEmbed.SetColor(EmbedColor.RED); await ReplyAsync(embed : invalidUserEmbed.Build()); return; } User target = await DatabaseQueries.GetOrCreateUserAsync(guildUser.Id); if (target.IsBlacklisted) { var invalidUserEmbed = new KaguyaEmbedBuilder { Description = $"Sorry, rep can't be given to blacklisted users. " + $"This person may appeal their blacklist by filling " + $"out [this form](https://forms.gle/bnLFWbNiEyF4uE9E9)" }; invalidUserEmbed.SetColor(EmbedColor.RED); await ReplyAsync(embed : invalidUserEmbed.Build()); return; } var newTargetRep = new Rep { UserId = guildUser.Id, GivenBy = user.UserId, TimeGiven = DateTime.Now.ToOADate(), Reason = reason ?? "No reason provided." }; await DatabaseQueries.InsertAsync(newTargetRep); user.LastGivenRep = DateTime.Now.ToOADate(); await DatabaseQueries.UpdateAsync(user); List <Rep> targetRepList = await DatabaseQueries.GetAllForUserAsync <Rep>(target.UserId); var embed = new KaguyaEmbedBuilder { Description = $"Successfully added one rep to `{guildUser}`! \nYou may give rep again in `24 hours`.", Footer = new EmbedFooterBuilder { Text = $"{guildUser.Username} now has {targetRepList.Count} rep. You have {repCount} rep." } }; embed.SetColor(EmbedColor.GOLD); await ReplyAsync(embed : embed.Build()); }