Merge remote-tracking branch 'Kwoth/dev' into dev
# Conflicts: # src/NadekoBot/Resources/CommandStrings.resx
This commit is contained in:
commit
26e769c6dd
1095
src/NadekoBot/Migrations/20170213164350_guild-timezone-and-locale.Designer.cs
generated
Normal file
1095
src/NadekoBot/Migrations/20170213164350_guild-timezone-and-locale.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace NadekoBot.Migrations
|
||||
{
|
||||
public partial class guildtimezoneandlocale : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Locale",
|
||||
table: "GuildConfigs",
|
||||
nullable: true,
|
||||
defaultValue: null);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "TimeZoneId",
|
||||
table: "GuildConfigs",
|
||||
nullable: true,
|
||||
defaultValue: null);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Locale",
|
||||
table: "BotConfig",
|
||||
nullable: true,
|
||||
defaultValue: null);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Locale",
|
||||
table: "GuildConfigs");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TimeZoneId",
|
||||
table: "GuildConfigs");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Locale",
|
||||
table: "BotConfig");
|
||||
}
|
||||
}
|
||||
}
|
@ -128,6 +128,8 @@ namespace NadekoBot.Migrations
|
||||
|
||||
b.Property<string>("HelpString");
|
||||
|
||||
b.Property<string>("Locale");
|
||||
|
||||
b.Property<int>("MigrationVersion");
|
||||
|
||||
b.Property<int>("MinimumBetAmount");
|
||||
@ -469,6 +471,8 @@ namespace NadekoBot.Migrations
|
||||
|
||||
b.Property<ulong>("GuildId");
|
||||
|
||||
b.Property<string>("Locale");
|
||||
|
||||
b.Property<int?>("LogSettingId");
|
||||
|
||||
b.Property<string>("MuteRoleName");
|
||||
@ -483,6 +487,8 @@ namespace NadekoBot.Migrations
|
||||
|
||||
b.Property<bool>("SendDmGreetMessage");
|
||||
|
||||
b.Property<string>("TimeZoneId");
|
||||
|
||||
b.Property<bool>("VerbosePermissions");
|
||||
|
||||
b.Property<bool>("VoicePlusTextEnabled");
|
||||
|
@ -1,18 +1,14 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Attributes;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Net.Http;
|
||||
using System.IO;
|
||||
using static NadekoBot.Modules.Permissions.Permissions;
|
||||
using System.Collections.Concurrent;
|
||||
using NLog;
|
||||
@ -20,21 +16,18 @@ using NLog;
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
[NadekoModule("Administration", ".")]
|
||||
public partial class Administration : DiscordModule
|
||||
public partial class Administration : NadekoModule
|
||||
{
|
||||
private static ConcurrentHashSet<ulong> deleteMessagesOnCommand { get; }
|
||||
|
||||
private static ConcurrentDictionary<ulong, string> GuildMuteRoles { get; } = new ConcurrentDictionary<ulong, string>();
|
||||
|
||||
private static ConcurrentHashSet<ulong> DeleteMessagesOnCommand { get; } = new ConcurrentHashSet<ulong>();
|
||||
|
||||
private new static Logger _log { get; }
|
||||
private new static readonly Logger _log;
|
||||
|
||||
static Administration()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
NadekoBot.CommandHandler.CommandExecuted += DelMsgOnCmd_Handler;
|
||||
|
||||
DeleteMessagesOnCommand = new ConcurrentHashSet<ulong>(NadekoBot.AllGuildConfigs.Where(g => g.DeleteMessageOnCommand).Select(g => g.GuildId));
|
||||
deleteMessagesOnCommand = new ConcurrentHashSet<ulong>(NadekoBot.AllGuildConfigs.Where(g => g.DeleteMessageOnCommand).Select(g => g.GuildId));
|
||||
|
||||
}
|
||||
|
||||
@ -47,7 +40,7 @@ namespace NadekoBot.Modules.Administration
|
||||
var channel = msg.Channel as SocketTextChannel;
|
||||
if (channel == null)
|
||||
return;
|
||||
if (DeleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune")
|
||||
if (deleteMessagesOnCommand.Contains(channel.Guild.Id) && cmd.Name != "prune")
|
||||
await msg.DeleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -74,17 +67,17 @@ namespace NadekoBot.Modules.Administration
|
||||
PermRole = config.PermissionRole,
|
||||
Verbose = config.VerbosePermissions,
|
||||
};
|
||||
Permissions.Permissions.Cache.AddOrUpdate(channel.Guild.Id,
|
||||
Cache.AddOrUpdate(channel.Guild.Id,
|
||||
toAdd, (id, old) => toAdd);
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
|
||||
await channel.SendConfirmAsync($"{Context.Message.Author.Mention} 🆗 **Permissions for this server are reset.**");
|
||||
await ReplyConfirmLocalized("perms_reset").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
[RequireBotPermission(GuildPermission.ManageMessages)]
|
||||
public async Task Delmsgoncmd()
|
||||
{
|
||||
bool enabled;
|
||||
@ -97,29 +90,31 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
if (enabled)
|
||||
{
|
||||
DeleteMessagesOnCommand.Add(Context.Guild.Id);
|
||||
await Context.Channel.SendConfirmAsync("✅ **Now automatically deleting successful command invokations.**").ConfigureAwait(false);
|
||||
deleteMessagesOnCommand.Add(Context.Guild.Id);
|
||||
await ReplyConfirmLocalized("delmsg_on").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeleteMessagesOnCommand.TryRemove(Context.Guild.Id);
|
||||
await Context.Channel.SendConfirmAsync("❗**Stopped automatic deletion of successful command invokations.**").ConfigureAwait(false);
|
||||
deleteMessagesOnCommand.TryRemove(Context.Guild.Id);
|
||||
await ReplyConfirmLocalized("delmsg_off").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||
public async Task Setrole(IGuildUser usr, [Remainder] IRole role)
|
||||
{
|
||||
try
|
||||
{
|
||||
await usr.AddRolesAsync(role).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"ℹ️ Successfully added role **{role.Name}** to user **{usr.Username}**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("setrole", Format.Bold(role.Name), Format.Bold(usr.ToString()))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ Failed to add role. **Bot has insufficient permissions.**\n").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("setrole_err").ConfigureAwait(false);
|
||||
Console.WriteLine(ex.ToString());
|
||||
}
|
||||
}
|
||||
@ -127,95 +122,94 @@ namespace NadekoBot.Modules.Administration
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||
public async Task Removerole(IGuildUser usr, [Remainder] IRole role)
|
||||
{
|
||||
try
|
||||
{
|
||||
await usr.RemoveRolesAsync(role).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"ℹ️ Successfully removed role **{role.Name}** from user **{usr.Username}**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("remrole", Format.Bold(role.Name), Format.Bold(usr.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ Failed to remove role. Most likely reason: **Insufficient permissions.**").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("remrole_err").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||
public async Task RenameRole(IRole roleToEdit, string newname)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (roleToEdit.Position > (await Context.Guild.GetCurrentUserAsync().ConfigureAwait(false)).GetRoles().Max(r => r.Position))
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("🚫 You can't edit roles higher than your highest role.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("renrole_perms").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await roleToEdit.ModifyAsync(g => g.Name = newname).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync("✅ Role renamed.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("renrole").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ Failed to rename role. Probably **insufficient permissions.**").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("renrole_err").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||
public async Task RemoveAllRoles([Remainder] IGuildUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
await user.RemoveRolesAsync(user.GetRoles()).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"🗑 Successfully removed **all** roles from user **{user.Username}**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("rar", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ Failed to remove roles. Most likely reason: **Insufficient permissions.**").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("rar_err").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||
public async Task CreateRole([Remainder] string roleName = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(roleName))
|
||||
return;
|
||||
try
|
||||
{
|
||||
|
||||
var r = await Context.Guild.CreateRoleAsync(roleName).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"✅ Successfully created role **{r.Name}**.").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ Unspecified error.").ConfigureAwait(false);
|
||||
}
|
||||
await ReplyConfirmLocalized("cr", Format.Bold(r.Name)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||
public async Task RoleColor(params string[] args)
|
||||
{
|
||||
if (args.Count() != 2 && args.Count() != 4)
|
||||
if (args.Length != 2 && args.Length != 4)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("❌ The parameters specified are **invalid.**").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("rc_params").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var roleName = args[0].ToUpperInvariant();
|
||||
var role = Context.Guild.Roles.Where(r => r.Name.ToUpperInvariant() == roleName).FirstOrDefault();
|
||||
var role = Context.Guild.Roles.FirstOrDefault(r => r.Name.ToUpperInvariant() == roleName);
|
||||
|
||||
if (role == null)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("🚫 That role **does not exist.**").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("rc_not_exist").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var rgb = args.Count() == 4;
|
||||
var rgb = args.Length == 4;
|
||||
var arg1 = args[1].Replace("#", "");
|
||||
|
||||
var red = Convert.ToByte(rgb ? int.Parse(arg1) : Convert.ToInt32(arg1.Substring(0, 2), 16));
|
||||
@ -223,64 +217,57 @@ namespace NadekoBot.Modules.Administration
|
||||
var blue = Convert.ToByte(rgb ? int.Parse(args[3]) : Convert.ToInt32(arg1.Substring(4, 2), 16));
|
||||
|
||||
await role.ModifyAsync(r => r.Color = new Color(red, green, blue)).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"☑️ Role **{role.Name}'s** color has been changed.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("rc", Format.Bold(role.Name)).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ Error occured, most likely **invalid parameters** or **insufficient permissions.**").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("rc_perms").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||
[RequireBotPermission(GuildPermission.BanMembers)]
|
||||
public async Task Ban(IGuildUser user, [Remainder] string msg = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
msg = "❗️No reason provided.";
|
||||
}
|
||||
if (Context.User.Id != user.Guild.OwnerId && (user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max()))
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ You can't use this command on users with a role higher or equal to yours in the role hierarchy.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("hierarchy").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
try
|
||||
{
|
||||
await (await user.CreateDMChannelAsync()).SendErrorAsync($"⛔️ **You have been BANNED from `{Context.Guild.Name}` server.**\n" +
|
||||
$"⚖ *Reason:* {msg}").ConfigureAwait(false);
|
||||
await user.SendErrorAsync(GetText("bandm", Format.Bold(Context.Guild.Name), msg));
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
try
|
||||
{
|
||||
await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false);
|
||||
|
||||
await Context.Channel.SendConfirmAsync("⛔️ **Banned** user **" + user.Username + "** ID: `" + user.Id + "`").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ **Error.** Most likely I don't have sufficient permissions.").ConfigureAwait(false);
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false);
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithTitle("⛔️ " + GetText("banned_user"))
|
||||
.AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true)))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.KickMembers)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
[RequireBotPermission(GuildPermission.BanMembers)]
|
||||
public async Task Softban(IGuildUser user, [Remainder] string msg = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
msg = "❗️No reason provided.";
|
||||
}
|
||||
if (Context.User.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max())
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ You can't use this command on users with a role higher or equal to yours in the role hierarchy.");
|
||||
await ReplyErrorLocalized("hierarchy").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -288,161 +275,162 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
try
|
||||
{
|
||||
await user.SendErrorAsync($"☣ **You have been SOFT-BANNED from `{Context.Guild.Name}` server.**\n" +
|
||||
$"⚖ *Reason:* {msg}").ConfigureAwait(false);
|
||||
await user.SendErrorAsync(GetText("sbdm", Format.Bold(Context.Guild.Name), msg));
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false);
|
||||
try { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); }
|
||||
catch { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); }
|
||||
|
||||
await Context.Channel.SendConfirmAsync("☣ **Soft-Banned** user **" + user.Username + "** ID: `" + user.Id + "`").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ Error. Most likely I don't have sufficient permissions.").ConfigureAwait(false);
|
||||
}
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithTitle("☣ " + GetText("sb_user"))
|
||||
.AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true)))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.KickMembers)]
|
||||
[RequireBotPermission(GuildPermission.KickMembers)]
|
||||
public async Task Kick(IGuildUser user, [Remainder] string msg = null)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("❗️User not found.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Context.Message.Author.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max())
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ You can't use this command on users with a role higher or equal to yours in the role hierarchy.");
|
||||
await ReplyErrorLocalized("hierarchy").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
try
|
||||
{
|
||||
await user.SendErrorAsync($"‼️**You have been KICKED from `{Context.Guild.Name}` server.**\n" +
|
||||
$"⚖ *Reason:* {msg}").ConfigureAwait(false);
|
||||
await user.SendErrorAsync(GetText("kickdm", Format.Bold(Context.Guild.Name), msg));
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
try
|
||||
{
|
||||
|
||||
await user.KickAsync().ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync("‼️**Kicked** user **" + user.Username + "** ID: `" + user.Id + "`").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ Error. Most likely I don't have sufficient permissions.").ConfigureAwait(false);
|
||||
}
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithTitle(GetText("kicked_user"))
|
||||
.AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true)))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.DeafenMembers)]
|
||||
[RequireBotPermission(GuildPermission.DeafenMembers)]
|
||||
public async Task Deafen(params IGuildUser[] users)
|
||||
{
|
||||
if (!users.Any())
|
||||
return;
|
||||
try
|
||||
{
|
||||
foreach (var u in users)
|
||||
{
|
||||
try
|
||||
{
|
||||
await u.ModifyAsync(usr => usr.Deaf = true).ConfigureAwait(false);
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync("🔇 **Deafen** successful.").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false);
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
await ReplyConfirmLocalized("deafen").ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.DeafenMembers)]
|
||||
[RequireBotPermission(GuildPermission.DeafenMembers)]
|
||||
public async Task UnDeafen(params IGuildUser[] users)
|
||||
{
|
||||
if (!users.Any())
|
||||
return;
|
||||
try
|
||||
{
|
||||
|
||||
foreach (var u in users)
|
||||
{
|
||||
try
|
||||
{
|
||||
await u.ModifyAsync(usr => usr.Deaf = false).ConfigureAwait(false);
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync("🔊 **Undeafen** successful.").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false);
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
await ReplyConfirmLocalized("undeafen").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||
[RequireBotPermission(GuildPermission.ManageChannels)]
|
||||
public async Task DelVoiChanl([Remainder] IVoiceChannel voiceChannel)
|
||||
{
|
||||
await voiceChannel.DeleteAsync().ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"🗑 Removed voice channel **{voiceChannel.Name}** successfully.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("delvoich", Format.Bold(voiceChannel.Name)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||
[RequireBotPermission(GuildPermission.ManageChannels)]
|
||||
public async Task CreatVoiChanl([Remainder] string channelName)
|
||||
{
|
||||
var ch = await Context.Guild.CreateVoiceChannelAsync(channelName).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"✅ Created voice channel **{ch.Name}**. ID: `{ch.Id}`").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("createvoich",Format.Bold(ch.Name)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||
[RequireBotPermission(GuildPermission.ManageChannels)]
|
||||
public async Task DelTxtChanl([Remainder] ITextChannel toDelete)
|
||||
{
|
||||
await toDelete.DeleteAsync().ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"🗑 Removed text channel **{toDelete.Name}**. ID: `{toDelete.Id}`").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("deltextchan", Format.Bold(toDelete.Name)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||
[RequireBotPermission(GuildPermission.ManageChannels)]
|
||||
public async Task CreaTxtChanl([Remainder] string channelName)
|
||||
{
|
||||
var txtCh = await Context.Guild.CreateTextChannelAsync(channelName).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"✅ Added text channel **{txtCh.Name}**. ID: `{txtCh.Id}`").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("createtextchan", Format.Bold(txtCh.Name)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||
[RequireBotPermission(GuildPermission.ManageChannels)]
|
||||
public async Task SetTopic([Remainder] string topic = null)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
topic = topic ?? "";
|
||||
await channel.ModifyAsync(c => c.Topic = topic);
|
||||
await channel.SendConfirmAsync("🆗 **New channel topic set.**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("set_topic").ConfigureAwait(false);
|
||||
|
||||
}
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||
[RequireBotPermission(GuildPermission.ManageChannels)]
|
||||
public async Task SetChanlName([Remainder] string name)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
await channel.ModifyAsync(c => c.Name = name).ConfigureAwait(false);
|
||||
await channel.SendConfirmAsync("🆗 **New channel name set.**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("set_channel_name").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
@ -462,6 +450,7 @@ namespace NadekoBot.Modules.Administration
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(ChannelPermission.ManageMessages)]
|
||||
[RequireBotPermission(GuildPermission.ManageMessages)]
|
||||
public async Task Prune(int count)
|
||||
{
|
||||
if (count < 1)
|
||||
@ -477,6 +466,7 @@ namespace NadekoBot.Modules.Administration
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(ChannelPermission.ManageMessages)]
|
||||
[RequireBotPermission(GuildPermission.ManageMessages)]
|
||||
public async Task Prune(IGuildUser user, int count = 100)
|
||||
{
|
||||
if (count < 1)
|
||||
@ -495,11 +485,11 @@ namespace NadekoBot.Modules.Administration
|
||||
[RequireUserPermission(GuildPermission.MentionEveryone)]
|
||||
public async Task MentionRole(params IRole[] roles)
|
||||
{
|
||||
string send = $"❕{Context.User.Mention} has invoked a mention on the following roles ❕";
|
||||
string send = "❕" +GetText("menrole",Context.User.Mention);
|
||||
foreach (var role in roles)
|
||||
{
|
||||
send += $"\n**{role.Name}**\n";
|
||||
send += string.Join(", ", (await Context.Guild.GetUsersAsync()).Where(u => u.GetRoles().Contains(role)).Distinct().Select(u => u.Mention));
|
||||
send += string.Join(", ", (await Context.Guild.GetUsersAsync()).Where(u => u.GetRoles().Contains(role)).Take(50).Select(u => u.Mention));
|
||||
}
|
||||
|
||||
while (send.Length > 2000)
|
||||
@ -513,7 +503,7 @@ namespace NadekoBot.Modules.Administration
|
||||
await Context.Channel.SendMessageAsync(send).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
IGuild nadekoSupportServer;
|
||||
private IGuild _nadekoSupportServer;
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Donators()
|
||||
{
|
||||
@ -523,18 +513,15 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
donatorsOrdered = uow.Donators.GetDonatorsOrdered();
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync("Thanks to the people listed below for making this project happen!", string.Join("⭐", donatorsOrdered.Select(d => d.Name))).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync(GetText("donators"), string.Join("⭐", donatorsOrdered.Select(d => d.Name))).ConfigureAwait(false);
|
||||
|
||||
nadekoSupportServer = nadekoSupportServer ?? NadekoBot.Client.GetGuild(117523346618318850);
|
||||
_nadekoSupportServer = _nadekoSupportServer ?? NadekoBot.Client.GetGuild(117523346618318850);
|
||||
|
||||
if (nadekoSupportServer == null)
|
||||
return;
|
||||
|
||||
var patreonRole = nadekoSupportServer.GetRole(236667642088259585);
|
||||
var patreonRole = _nadekoSupportServer?.GetRole(236667642088259585);
|
||||
if (patreonRole == null)
|
||||
return;
|
||||
|
||||
var usrs = (await nadekoSupportServer.GetUsersAsync()).Where(u => u.RoleIds.Contains(236667642088259585u));
|
||||
var usrs = (await _nadekoSupportServer.GetUsersAsync()).Where(u => u.RoleIds.Contains(236667642088259585u));
|
||||
await Context.Channel.SendConfirmAsync("Patreon supporters", string.Join("⭐", usrs.Select(d => d.Username))).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@ -549,8 +536,7 @@ namespace NadekoBot.Modules.Administration
|
||||
don = uow.Donators.AddOrUpdateDonator(donator.Id, donator.Username, amount);
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"Successfuly added a new donator. Total donated amount from this user: {don.Amount} 👑").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("donadd", don.Amount).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
//[NadekoCommand, Usage, Description, Aliases]
|
||||
|
@ -1,13 +1,10 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -16,24 +13,23 @@ namespace NadekoBot.Modules.Administration
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class AutoAssignRoleCommands : ModuleBase
|
||||
public class AutoAssignRoleCommands : NadekoSubmodule
|
||||
{
|
||||
private static Logger _log { get; }
|
||||
//guildid/roleid
|
||||
private static ConcurrentDictionary<ulong, ulong> AutoAssignedRoles { get; }
|
||||
private static ConcurrentDictionary<ulong, ulong> autoAssignedRoles { get; }
|
||||
|
||||
static AutoAssignRoleCommands()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
var log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
AutoAssignedRoles = new ConcurrentDictionary<ulong, ulong>(NadekoBot.AllGuildConfigs.Where(x => x.AutoAssignRoleId != 0)
|
||||
autoAssignedRoles = new ConcurrentDictionary<ulong, ulong>(NadekoBot.AllGuildConfigs.Where(x => x.AutoAssignRoleId != 0)
|
||||
.ToDictionary(k => k.GuildId, v => v.AutoAssignRoleId));
|
||||
NadekoBot.Client.UserJoined += async (user) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
ulong roleId = 0;
|
||||
AutoAssignedRoles.TryGetValue(user.Guild.Id, out roleId);
|
||||
ulong roleId;
|
||||
autoAssignedRoles.TryGetValue(user.Guild.Id, out roleId);
|
||||
|
||||
if (roleId == 0)
|
||||
return;
|
||||
@ -43,7 +39,7 @@ namespace NadekoBot.Modules.Administration
|
||||
if (role != null)
|
||||
await user.AddRolesAsync(role).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
catch (Exception ex) { log.Warn(ex); }
|
||||
};
|
||||
}
|
||||
|
||||
@ -52,20 +48,19 @@ namespace NadekoBot.Modules.Administration
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
public async Task AutoAssignRole([Remainder] IRole role = null)
|
||||
{
|
||||
GuildConfig conf;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||
if (role == null)
|
||||
{
|
||||
conf.AutoAssignRoleId = 0;
|
||||
ulong throwaway;
|
||||
AutoAssignedRoles.TryRemove(Context.Guild.Id, out throwaway);
|
||||
autoAssignedRoles.TryRemove(Context.Guild.Id, out throwaway);
|
||||
}
|
||||
else
|
||||
{
|
||||
conf.AutoAssignRoleId = role.Id;
|
||||
AutoAssignedRoles.AddOrUpdate(Context.Guild.Id, role.Id, (key, val) => role.Id);
|
||||
autoAssignedRoles.AddOrUpdate(Context.Guild.Id, role.Id, (key, val) => role.Id);
|
||||
}
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
@ -73,11 +68,11 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
if (role == null)
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync("🆗 **Auto assign role** on user join is now **disabled**.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("aar_disabled").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync("✅ **Auto assign role** on user join is now **enabled**.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("aar_enabled").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,90 +0,0 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NLog;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class DMForwardCommands : ModuleBase
|
||||
{
|
||||
private static bool ForwardDMs { get; set; }
|
||||
private static bool ForwardDMsToAllOwners { get; set; }
|
||||
|
||||
private static readonly Logger _log;
|
||||
|
||||
static DMForwardCommands()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var config = uow.BotConfig.GetOrCreate();
|
||||
ForwardDMs = config.ForwardMessages;
|
||||
ForwardDMsToAllOwners = config.ForwardToAllOwners;
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task ForwardMessages()
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var config = uow.BotConfig.GetOrCreate();
|
||||
ForwardDMs = config.ForwardMessages = !config.ForwardMessages;
|
||||
uow.Complete();
|
||||
}
|
||||
if (ForwardDMs)
|
||||
await Context.Channel.SendConfirmAsync("✅ **I will forward DMs from now on.**").ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendConfirmAsync("🆗 **I will stop forwarding DMs from now on.**").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task ForwardToAll()
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var config = uow.BotConfig.GetOrCreate();
|
||||
ForwardDMsToAllOwners = config.ForwardToAllOwners = !config.ForwardToAllOwners;
|
||||
uow.Complete();
|
||||
}
|
||||
if (ForwardDMsToAllOwners)
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ **I will forward DMs to all owners.**").ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ **I will forward DMs only to the first owner.**").ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
public static async Task HandleDMForwarding(SocketMessage msg, List<IDMChannel> ownerChannels)
|
||||
{
|
||||
if (ForwardDMs && ownerChannels.Any())
|
||||
{
|
||||
var title = $"DM from [{msg.Author}]({msg.Author.Id})";
|
||||
if (ForwardDMsToAllOwners)
|
||||
{
|
||||
var msgs = await Task.WhenAll(ownerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id)
|
||||
.Select(ch => ch.SendConfirmAsync(title, msg.Content))).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var firstOwnerChannel = ownerChannels.First();
|
||||
if (firstOwnerChannel.Recipient.Id != msg.Author.Id)
|
||||
try { await firstOwnerChannel.SendConfirmAsync(title, msg.Content).ConfigureAwait(false); } catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,234 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class LocalizationCommands : NadekoSubmodule
|
||||
{
|
||||
private ImmutableDictionary<string, string> supportedLocales { get; } = new Dictionary<string, string>()
|
||||
{
|
||||
{"en-US", "English, United States" },
|
||||
{"sr-cyrl-rs", "Serbian, Cyrillic" }
|
||||
}.ToImmutableDictionary();
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task LanguageSet()
|
||||
{
|
||||
var cul = NadekoBot.Localization.GetCultureInfo(Context.Guild);
|
||||
await ReplyConfirmLocalized("lang_set_show", Format.Bold(cul.ToString()), Format.Bold(cul.NativeName))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
public async Task LanguageSet(string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
CultureInfo ci;
|
||||
if (name.Trim().ToLowerInvariant() == "default")
|
||||
{
|
||||
NadekoBot.Localization.RemoveGuildCulture(Context.Guild);
|
||||
ci = NadekoBot.Localization.DefaultCultureInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
ci = new CultureInfo(name);
|
||||
NadekoBot.Localization.SetGuildCulture(Context.Guild, ci);
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalized("lang_set", Format.Bold(ci.ToString()), Format.Bold(ci.NativeName)).ConfigureAwait(false);
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
await ReplyErrorLocalized("lang_set_fail").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task LanguageSetDefault()
|
||||
{
|
||||
var cul = NadekoBot.Localization.DefaultCultureInfo;
|
||||
await ReplyConfirmLocalized("lang_set_bot_show", cul, cul.NativeName).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task LanguageSetDefault(string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
CultureInfo ci;
|
||||
if (name.Trim().ToLowerInvariant() == "default")
|
||||
{
|
||||
NadekoBot.Localization.ResetDefaultCulture();
|
||||
ci = NadekoBot.Localization.DefaultCultureInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
ci = new CultureInfo(name);
|
||||
NadekoBot.Localization.SetDefaultCulture(ci);
|
||||
}
|
||||
await ReplyConfirmLocalized("lang_set_bot", Format.Bold(ci.ToString()), Format.Bold(ci.NativeName)).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await ReplyErrorLocalized("lang_set_fail").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task LanguagesList()
|
||||
{
|
||||
await ReplyConfirmLocalized("lang_list",
|
||||
string.Join("\n", supportedLocales.Select(x => $"{Format.Code(x.Key)} => {x.Value}")))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* list of language codes for reference.
|
||||
* taken from https://github.com/dotnet/coreclr/blob/ee5862c6a257e60e263537d975ab6c513179d47f/src/mscorlib/src/System/Globalization/CultureData.cs#L192
|
||||
{ "029", "en-029" },
|
||||
{ "AE", "ar-AE" },
|
||||
{ "AF", "prs-AF" },
|
||||
{ "AL", "sq-AL" },
|
||||
{ "AM", "hy-AM" },
|
||||
{ "AR", "es-AR" },
|
||||
{ "AT", "de-AT" },
|
||||
{ "AU", "en-AU" },
|
||||
{ "AZ", "az-Cyrl-AZ" },
|
||||
{ "BA", "bs-Latn-BA" },
|
||||
{ "BD", "bn-BD" },
|
||||
{ "BE", "nl-BE" },
|
||||
{ "BG", "bg-BG" },
|
||||
{ "BH", "ar-BH" },
|
||||
{ "BN", "ms-BN" },
|
||||
{ "BO", "es-BO" },
|
||||
{ "BR", "pt-BR" },
|
||||
{ "BY", "be-BY" },
|
||||
{ "BZ", "en-BZ" },
|
||||
{ "CA", "en-CA" },
|
||||
{ "CH", "it-CH" },
|
||||
{ "CL", "es-CL" },
|
||||
{ "CN", "zh-CN" },
|
||||
{ "CO", "es-CO" },
|
||||
{ "CR", "es-CR" },
|
||||
{ "CS", "sr-Cyrl-CS" },
|
||||
{ "CZ", "cs-CZ" },
|
||||
{ "DE", "de-DE" },
|
||||
{ "DK", "da-DK" },
|
||||
{ "DO", "es-DO" },
|
||||
{ "DZ", "ar-DZ" },
|
||||
{ "EC", "es-EC" },
|
||||
{ "EE", "et-EE" },
|
||||
{ "EG", "ar-EG" },
|
||||
{ "ES", "es-ES" },
|
||||
{ "ET", "am-ET" },
|
||||
{ "FI", "fi-FI" },
|
||||
{ "FO", "fo-FO" },
|
||||
{ "FR", "fr-FR" },
|
||||
{ "GB", "en-GB" },
|
||||
{ "GE", "ka-GE" },
|
||||
{ "GL", "kl-GL" },
|
||||
{ "GR", "el-GR" },
|
||||
{ "GT", "es-GT" },
|
||||
{ "HK", "zh-HK" },
|
||||
{ "HN", "es-HN" },
|
||||
{ "HR", "hr-HR" },
|
||||
{ "HU", "hu-HU" },
|
||||
{ "ID", "id-ID" },
|
||||
{ "IE", "en-IE" },
|
||||
{ "IL", "he-IL" },
|
||||
{ "IN", "hi-IN" },
|
||||
{ "IQ", "ar-IQ" },
|
||||
{ "IR", "fa-IR" },
|
||||
{ "IS", "is-IS" },
|
||||
{ "IT", "it-IT" },
|
||||
{ "IV", "" },
|
||||
{ "JM", "en-JM" },
|
||||
{ "JO", "ar-JO" },
|
||||
{ "JP", "ja-JP" },
|
||||
{ "KE", "sw-KE" },
|
||||
{ "KG", "ky-KG" },
|
||||
{ "KH", "km-KH" },
|
||||
{ "KR", "ko-KR" },
|
||||
{ "KW", "ar-KW" },
|
||||
{ "KZ", "kk-KZ" },
|
||||
{ "LA", "lo-LA" },
|
||||
{ "LB", "ar-LB" },
|
||||
{ "LI", "de-LI" },
|
||||
{ "LK", "si-LK" },
|
||||
{ "LT", "lt-LT" },
|
||||
{ "LU", "lb-LU" },
|
||||
{ "LV", "lv-LV" },
|
||||
{ "LY", "ar-LY" },
|
||||
{ "MA", "ar-MA" },
|
||||
{ "MC", "fr-MC" },
|
||||
{ "ME", "sr-Latn-ME" },
|
||||
{ "MK", "mk-MK" },
|
||||
{ "MN", "mn-MN" },
|
||||
{ "MO", "zh-MO" },
|
||||
{ "MT", "mt-MT" },
|
||||
{ "MV", "dv-MV" },
|
||||
{ "MX", "es-MX" },
|
||||
{ "MY", "ms-MY" },
|
||||
{ "NG", "ig-NG" },
|
||||
{ "NI", "es-NI" },
|
||||
{ "NL", "nl-NL" },
|
||||
{ "NO", "nn-NO" },
|
||||
{ "NP", "ne-NP" },
|
||||
{ "NZ", "en-NZ" },
|
||||
{ "OM", "ar-OM" },
|
||||
{ "PA", "es-PA" },
|
||||
{ "PE", "es-PE" },
|
||||
{ "PH", "en-PH" },
|
||||
{ "PK", "ur-PK" },
|
||||
{ "PL", "pl-PL" },
|
||||
{ "PR", "es-PR" },
|
||||
{ "PT", "pt-PT" },
|
||||
{ "PY", "es-PY" },
|
||||
{ "QA", "ar-QA" },
|
||||
{ "RO", "ro-RO" },
|
||||
{ "RS", "sr-Latn-RS" },
|
||||
{ "RU", "ru-RU" },
|
||||
{ "RW", "rw-RW" },
|
||||
{ "SA", "ar-SA" },
|
||||
{ "SE", "sv-SE" },
|
||||
{ "SG", "zh-SG" },
|
||||
{ "SI", "sl-SI" },
|
||||
{ "SK", "sk-SK" },
|
||||
{ "SN", "wo-SN" },
|
||||
{ "SV", "es-SV" },
|
||||
{ "SY", "ar-SY" },
|
||||
{ "TH", "th-TH" },
|
||||
{ "TJ", "tg-Cyrl-TJ" },
|
||||
{ "TM", "tk-TM" },
|
||||
{ "TN", "ar-TN" },
|
||||
{ "TR", "tr-TR" },
|
||||
{ "TT", "en-TT" },
|
||||
{ "TW", "zh-TW" },
|
||||
{ "UA", "uk-UA" },
|
||||
{ "US", "en-US" },
|
||||
{ "UY", "es-UY" },
|
||||
{ "UZ", "uz-Cyrl-UZ" },
|
||||
{ "VE", "es-VE" },
|
||||
{ "VN", "vi-VN" },
|
||||
{ "YE", "ar-YE" },
|
||||
{ "ZA", "af-ZA" },
|
||||
{ "ZW", "en-ZW" }
|
||||
*/
|
@ -1,7 +1,6 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions;
|
||||
@ -21,45 +20,43 @@ namespace NadekoBot.Modules.Administration
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class LogCommands : ModuleBase
|
||||
public class LogCommands : NadekoSubmodule
|
||||
{
|
||||
private const string clockEmojiUrl = "https://cdn.discordapp.com/attachments/155726317222887425/258309524966866945/clock.png";
|
||||
|
||||
private static DiscordShardedClient _client { get; }
|
||||
private static Logger _log { get; }
|
||||
private static DiscordShardedClient client { get; }
|
||||
private new static Logger _log { get; }
|
||||
|
||||
private static string prettyCurrentTime => $"【{DateTime.Now:HH:mm:ss}】";
|
||||
private static string currentTime => $"{DateTime.Now:HH:mm:ss}";
|
||||
|
||||
public static ConcurrentDictionary<ulong, LogSetting> GuildLogSettings { get; }
|
||||
|
||||
private static ConcurrentDictionary<ITextChannel, List<string>> PresenceUpdates { get; } = new ConcurrentDictionary<ITextChannel, List<string>>();
|
||||
private static Timer timerReference { get; }
|
||||
private IGoogleApiService _google { get; }
|
||||
private static ConcurrentDictionary<ITextChannel, List<string>> presenceUpdates { get; } = new ConcurrentDictionary<ITextChannel, List<string>>();
|
||||
private static readonly Timer _timerReference;
|
||||
|
||||
static LogCommands()
|
||||
{
|
||||
_client = NadekoBot.Client;
|
||||
client = NadekoBot.Client;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
GuildLogSettings = new ConcurrentDictionary<ulong, LogSetting>(NadekoBot.AllGuildConfigs
|
||||
.ToDictionary(g => g.GuildId, g => g.LogSetting));
|
||||
}
|
||||
|
||||
timerReference = new Timer(async (state) =>
|
||||
_timerReference = new Timer(async (state) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var keys = PresenceUpdates.Keys.ToList();
|
||||
var keys = presenceUpdates.Keys.ToList();
|
||||
|
||||
await Task.WhenAll(keys.Select(async key =>
|
||||
{
|
||||
List<string> messages;
|
||||
if (PresenceUpdates.TryRemove(key, out messages))
|
||||
try { await key.SendConfirmAsync("Presence Updates", string.Join(Environment.NewLine, messages)); } catch { }
|
||||
if (presenceUpdates.TryRemove(key, out messages))
|
||||
try { await key.SendConfirmAsync(key.Guild.GetLogText("presence_updates"), string.Join(Environment.NewLine, messages)); }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}));
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -72,23 +69,22 @@ namespace NadekoBot.Modules.Administration
|
||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
||||
|
||||
//_client.MessageReceived += _client_MessageReceived;
|
||||
_client.MessageUpdated += _client_MessageUpdated;
|
||||
_client.MessageDeleted += _client_MessageDeleted;
|
||||
_client.UserBanned += _client_UserBanned;
|
||||
_client.UserUnbanned += _client_UserUnbanned;
|
||||
_client.UserJoined += _client_UserJoined;
|
||||
_client.UserLeft += _client_UserLeft;
|
||||
_client.UserPresenceUpdated += _client_UserPresenceUpdated;
|
||||
_client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated;
|
||||
_client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS;
|
||||
_client.GuildMemberUpdated += _client_GuildUserUpdated;
|
||||
client.MessageUpdated += _client_MessageUpdated;
|
||||
client.MessageDeleted += _client_MessageDeleted;
|
||||
client.UserBanned += _client_UserBanned;
|
||||
client.UserUnbanned += _client_UserUnbanned;
|
||||
client.UserJoined += _client_UserJoined;
|
||||
client.UserLeft += _client_UserLeft;
|
||||
client.UserPresenceUpdated += _client_UserPresenceUpdated;
|
||||
client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated;
|
||||
client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS;
|
||||
client.GuildMemberUpdated += _client_GuildUserUpdated;
|
||||
#if !GLOBAL_NADEKO
|
||||
_client.UserUpdated += _client_UserUpdated;
|
||||
client.UserUpdated += _client_UserUpdated;
|
||||
#endif
|
||||
|
||||
_client.ChannelCreated += _client_ChannelCreated;
|
||||
_client.ChannelDestroyed += _client_ChannelDestroyed;
|
||||
_client.ChannelUpdated += _client_ChannelUpdated;
|
||||
client.ChannelCreated += _client_ChannelCreated;
|
||||
client.ChannelDestroyed += _client_ChannelDestroyed;
|
||||
client.ChannelUpdated += _client_ChannelUpdated;
|
||||
|
||||
MuteCommands.UserMuted += MuteCommands_UserMuted;
|
||||
MuteCommands.UserUnmuted += MuteCommands_UserUnmuted;
|
||||
@ -119,7 +115,7 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
if (before.Username != after.Username)
|
||||
{
|
||||
embed.WithTitle("👥 Username Changed")
|
||||
embed.WithTitle("👥 " + g.GetLogText("username_changed"))
|
||||
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
||||
.AddField(fb => fb.WithName("Old Name").WithValue($"{before.Username}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("New Name").WithValue($"{after.Username}").WithIsInline(true))
|
||||
@ -128,7 +124,7 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
else if (before.AvatarUrl != after.AvatarUrl)
|
||||
{
|
||||
embed.WithTitle("👥 Avatar Changed")
|
||||
embed.WithTitle("👥" + g.GetLogText("avatar_changed"))
|
||||
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
||||
.WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}")
|
||||
.WithThumbnailUrl(before.AvatarUrl)
|
||||
@ -159,7 +155,9 @@ namespace NadekoBot.Modules.Administration
|
||||
//}
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task _client_UserVoiceStateUpdated_TTS(SocketUser iusr, SocketVoiceState before, SocketVoiceState after)
|
||||
@ -188,20 +186,23 @@ namespace NadekoBot.Modules.Administration
|
||||
var str = "";
|
||||
if (beforeVch?.Guild == afterVch?.Guild)
|
||||
{
|
||||
str = $"{usr.Username} moved from {beforeVch.Name} to {afterVch.Name}";
|
||||
str = logChannel.Guild.GetLogText("moved", usr.Username, beforeVch?.Name, afterVch?.Name);
|
||||
}
|
||||
else if (beforeVch == null)
|
||||
{
|
||||
str = $"{usr.Username} has joined {afterVch.Name}";
|
||||
str = logChannel.Guild.GetLogText("joined", usr.Username, afterVch.Name);
|
||||
}
|
||||
else if (afterVch == null)
|
||||
{
|
||||
str = $"{usr.Username} has left {beforeVch.Name}";
|
||||
str = logChannel.Guild.GetLogText("left", usr.Username, beforeVch.Name);
|
||||
}
|
||||
var toDelete = await logChannel.SendMessageAsync(str, true).ConfigureAwait(false);
|
||||
toDelete.DeleteAfter(5);
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private static async void MuteCommands_UserMuted(IGuildUser usr, MuteCommands.MuteType muteType)
|
||||
@ -216,28 +217,32 @@ namespace NadekoBot.Modules.Administration
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserMuted)) == null)
|
||||
return;
|
||||
string mutes = "";
|
||||
var mutes = "";
|
||||
var mutedLocalized = logChannel.Guild.GetLogText("muted_sn");
|
||||
switch (muteType)
|
||||
{
|
||||
case MuteCommands.MuteType.Voice:
|
||||
mutes = "voice chat";
|
||||
mutes = "🔇 " + logChannel.Guild.GetLogText("xmuted_voice", mutedLocalized);
|
||||
break;
|
||||
case MuteCommands.MuteType.Chat:
|
||||
mutes = "text chat";
|
||||
mutes = "🔇 " + logChannel.Guild.GetLogText("xmuted_text", mutedLocalized);
|
||||
break;
|
||||
case MuteCommands.MuteType.All:
|
||||
mutes = "text and voice chat";
|
||||
mutes = "🔇 " + logChannel.Guild.GetLogText("xmuted_text_and_voice", mutedLocalized);
|
||||
break;
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName("🔇 User Muted from " + mutes))
|
||||
var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName(mutes))
|
||||
.WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
|
||||
.WithFooter(fb => fb.WithText(currentTime))
|
||||
.WithOkColor();
|
||||
|
||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private static async void MuteCommands_UserUnmuted(IGuildUser usr, MuteCommands.MuteType muteType)
|
||||
@ -253,28 +258,32 @@ namespace NadekoBot.Modules.Administration
|
||||
if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserMuted)) == null)
|
||||
return;
|
||||
|
||||
string mutes = "";
|
||||
var mutes = "";
|
||||
var unmutedLocalized = logChannel.Guild.GetLogText("unmuted_sn");
|
||||
switch (muteType)
|
||||
{
|
||||
case MuteCommands.MuteType.Voice:
|
||||
mutes = "voice chat";
|
||||
mutes = "🔊 " + logChannel.Guild.GetLogText("xmuted_voice", unmutedLocalized);
|
||||
break;
|
||||
case MuteCommands.MuteType.Chat:
|
||||
mutes = "text chat";
|
||||
mutes = "🔊 " + logChannel.Guild.GetLogText("xmuted_text", unmutedLocalized);
|
||||
break;
|
||||
case MuteCommands.MuteType.All:
|
||||
mutes = "text and voice chat";
|
||||
mutes = "🔊 " + logChannel.Guild.GetLogText("xmuted_text_and_voice", unmutedLocalized);
|
||||
break;
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName("🔊 User Unmuted from " + mutes))
|
||||
var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName(mutes))
|
||||
.WithTitle($"{usr.Username}#{usr.Discriminator} | {usr.Id}")
|
||||
.WithFooter(fb => fb.WithText($"{currentTime}"))
|
||||
.WithOkColor();
|
||||
|
||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task TriggeredAntiProtection(IGuildUser[] users, PunishmentAction action, ProtectionType protection)
|
||||
@ -293,28 +302,31 @@ namespace NadekoBot.Modules.Administration
|
||||
return;
|
||||
|
||||
var punishment = "";
|
||||
if (action == PunishmentAction.Mute)
|
||||
switch (action)
|
||||
{
|
||||
punishment = "🔇 MUTED";
|
||||
}
|
||||
else if (action == PunishmentAction.Kick)
|
||||
{
|
||||
punishment = "☣ SOFT-BANNED (KICKED)";
|
||||
}
|
||||
else if (action == PunishmentAction.Ban)
|
||||
{
|
||||
punishment = "⛔️ BANNED";
|
||||
case PunishmentAction.Mute:
|
||||
punishment = "🔇 " + logChannel.Guild.GetLogText("muted_pl").ToUpperInvariant();
|
||||
break;
|
||||
case PunishmentAction.Kick:
|
||||
punishment = "☣ " + logChannel.Guild.GetLogText("soft_banned_pl").ToUpperInvariant();
|
||||
break;
|
||||
case PunishmentAction.Ban:
|
||||
punishment = "⛔️ " + logChannel.Guild.GetLogText("banned_pl").ToUpperInvariant();
|
||||
break;
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder().WithAuthor(eab => eab.WithName($"🛡 Anti-{protection}"))
|
||||
.WithTitle($"Users " + punishment)
|
||||
.WithDescription(String.Join("\n", users.Select(u => u.ToString())))
|
||||
.WithTitle(logChannel.Guild.GetLogText("users") + " " + punishment)
|
||||
.WithDescription(string.Join("\n", users.Select(u => u.ToString())))
|
||||
.WithFooter(fb => fb.WithText($"{currentTime}"))
|
||||
.WithOkColor();
|
||||
|
||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task _client_GuildUserUpdated(SocketGuildUser before, SocketGuildUser after)
|
||||
@ -333,23 +345,23 @@ namespace NadekoBot.Modules.Administration
|
||||
.WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}");
|
||||
if (before.Nickname != after.Nickname)
|
||||
{
|
||||
embed.WithAuthor(eab => eab.WithName("👥 Nickname Changed"))
|
||||
embed.WithAuthor(eab => eab.WithName("👥 " + logChannel.Guild.GetLogText("nick_change")))
|
||||
|
||||
.AddField(efb => efb.WithName("Old Nickname").WithValue($"{before.Nickname}#{before.Discriminator}"))
|
||||
.AddField(efb => efb.WithName("New Nickname").WithValue($"{after.Nickname}#{after.Discriminator}"));
|
||||
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("old_nick")).WithValue($"{before.Nickname}#{before.Discriminator}"))
|
||||
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("new_nick")).WithValue($"{after.Nickname}#{after.Discriminator}"));
|
||||
}
|
||||
else if (!before.RoleIds.SequenceEqual(after.RoleIds))
|
||||
{
|
||||
if (before.RoleIds.Count < after.RoleIds.Count)
|
||||
{
|
||||
var diffRoles = after.RoleIds.Where(r => !before.RoleIds.Contains(r)).Select(r => before.Guild.GetRole(r).Name);
|
||||
embed.WithAuthor(eab => eab.WithName("⚔ User's Role Added"))
|
||||
embed.WithAuthor(eab => eab.WithName("⚔ " + logChannel.Guild.GetLogText("user_role_add")))
|
||||
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
|
||||
}
|
||||
else if (before.RoleIds.Count > after.RoleIds.Count)
|
||||
{
|
||||
var diffRoles = before.RoleIds.Where(r => !after.RoleIds.Contains(r)).Select(r => before.Guild.GetRole(r).Name);
|
||||
embed.WithAuthor(eab => eab.WithName("⚔ User's Role Removed"))
|
||||
embed.WithAuthor(eab => eab.WithName("⚔ " + logChannel.Guild.GetLogText("user_role_rem")))
|
||||
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
|
||||
}
|
||||
}
|
||||
@ -357,7 +369,10 @@ namespace NadekoBot.Modules.Administration
|
||||
return;
|
||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task _client_ChannelUpdated(IChannel cbefore, IChannel cafter)
|
||||
@ -386,23 +401,26 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
if (before.Name != after.Name)
|
||||
{
|
||||
embed.WithTitle("ℹ️ Channel Name Changed")
|
||||
embed.WithTitle("ℹ️ " + logChannel.Guild.GetLogText("ch_name_change"))
|
||||
.WithDescription($"{after} | {after.Id}")
|
||||
.AddField(efb => efb.WithName("Old Name").WithValue(before.Name));
|
||||
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("ch_old_name")).WithValue(before.Name));
|
||||
}
|
||||
else if (beforeTextChannel?.Topic != afterTextChannel?.Topic)
|
||||
{
|
||||
embed.WithTitle("ℹ️ Channel Topic Changed")
|
||||
embed.WithTitle("ℹ️ " + logChannel.Guild.GetLogText("ch_topic_change"))
|
||||
.WithDescription($"{after} | {after.Id}")
|
||||
.AddField(efb => efb.WithName("Old Topic").WithValue(beforeTextChannel.Topic))
|
||||
.AddField(efb => efb.WithName("New Topic").WithValue(afterTextChannel.Topic));
|
||||
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("old_topic")).WithValue(beforeTextChannel?.Topic ?? "-"))
|
||||
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("new_topic")).WithValue(afterTextChannel?.Topic ?? "-"));
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task _client_ChannelDestroyed(IChannel ich)
|
||||
@ -422,14 +440,23 @@ namespace NadekoBot.Modules.Administration
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(ch.Guild, logSetting, LogType.ChannelDestroyed)) == null)
|
||||
return;
|
||||
|
||||
string title;
|
||||
if (ch is IVoiceChannel)
|
||||
{
|
||||
title = logChannel.Guild.GetLogText("voice_chan_destroyed");
|
||||
}
|
||||
else
|
||||
title = logChannel.Guild.GetLogText("text_chan_destroyed");
|
||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle("🆕 " + (ch is IVoiceChannel ? "Voice" : "Text") + " Channel Destroyed")
|
||||
.WithTitle("🆕 " + title)
|
||||
.WithDescription($"{ch.Name} | {ch.Id}")
|
||||
.WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task _client_ChannelCreated(IChannel ich)
|
||||
@ -448,10 +475,16 @@ namespace NadekoBot.Modules.Administration
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(ch.Guild, logSetting, LogType.ChannelCreated)) == null)
|
||||
return;
|
||||
|
||||
string title;
|
||||
if (ch is IVoiceChannel)
|
||||
{
|
||||
title = logChannel.Guild.GetLogText("voice_chan_created");
|
||||
}
|
||||
else
|
||||
title = logChannel.Guild.GetLogText("text_chan_created");
|
||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle("🆕 " + (ch is IVoiceChannel ? "Voice" : "Text") + " Channel Created")
|
||||
.WithTitle("🆕 " + title)
|
||||
.WithDescription($"{ch.Name} | {ch.Id}")
|
||||
.WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false);
|
||||
}
|
||||
@ -484,20 +517,29 @@ namespace NadekoBot.Modules.Administration
|
||||
string str = null;
|
||||
if (beforeVch?.Guild == afterVch?.Guild)
|
||||
{
|
||||
str = $"🎙`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__ moved from **{beforeVch.Name}** to **{afterVch.Name}** voice channel.";
|
||||
str = "🎙" + Format.Code(prettyCurrentTime) + logChannel.Guild.GetLogText("user_vmoved",
|
||||
"👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
||||
Format.Bold(beforeVch?.Name ?? ""), Format.Bold(afterVch?.Name ?? ""));
|
||||
}
|
||||
else if (beforeVch == null)
|
||||
{
|
||||
str = $"🎙`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__ has joined **{afterVch.Name}** voice channel.";
|
||||
str = "🎙" + Format.Code(prettyCurrentTime) + logChannel.Guild.GetLogText("user_vjoined",
|
||||
"👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
||||
Format.Bold(afterVch.Name ?? ""));
|
||||
}
|
||||
else if (afterVch == null)
|
||||
{
|
||||
str = $"🎙`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__ has left **{beforeVch.Name}** voice channel.";
|
||||
str = "🎙" + Format.Code(prettyCurrentTime) + logChannel.Guild.GetLogText("user_vleft",
|
||||
"👤" + Format.Code(prettyCurrentTime), "👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
||||
Format.Bold(beforeVch.Name ?? ""));
|
||||
}
|
||||
if (str != null)
|
||||
PresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
|
||||
presenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private static async Task _client_UserPresenceUpdated(Optional<SocketGuild> optGuild, SocketUser usr, SocketPresence before, SocketPresence after)
|
||||
@ -520,7 +562,10 @@ namespace NadekoBot.Modules.Administration
|
||||
return;
|
||||
string str = "";
|
||||
if (before.Status != after.Status)
|
||||
str = $"🎭`{prettyCurrentTime}`👤__**{usr.Username}**__ is now **{after.Status}**.";
|
||||
str = "🎭" + Format.Code(prettyCurrentTime) +
|
||||
logChannel.Guild.GetLogText("user_status_change",
|
||||
"👤" + Format.Bold(usr.Username),
|
||||
Format.Bold(after.Status.ToString()));
|
||||
|
||||
//if (before.Game?.Name != after.Game?.Name)
|
||||
//{
|
||||
@ -529,9 +574,12 @@ namespace NadekoBot.Modules.Administration
|
||||
// str += $"👾`{prettyCurrentTime}`👤__**{usr.Username}**__ is now playing **{after.Game?.Name}**.";
|
||||
//}
|
||||
|
||||
PresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
|
||||
presenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private static async Task _client_UserLeft(IGuildUser usr)
|
||||
@ -549,13 +597,16 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle("❌ User Left")
|
||||
.WithTitle("❌ " + logChannel.Guild.GetLogText("user_left"))
|
||||
.WithThumbnailUrl(usr.AvatarUrl)
|
||||
.WithDescription(usr.ToString())
|
||||
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
||||
.WithFooter(efb => efb.WithText(currentTime))).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task _client_UserJoined(IGuildUser usr)
|
||||
@ -573,7 +624,7 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle("✅ User Joined")
|
||||
.WithTitle("✅ " + logChannel.Guild.GetLogText("user_joined"))
|
||||
.WithThumbnailUrl(usr.AvatarUrl)
|
||||
.WithDescription($"{usr}")
|
||||
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
||||
@ -597,7 +648,7 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle("♻️ User Unbanned")
|
||||
.WithTitle("♻️ " + logChannel.Guild.GetLogText("user_unbanned"))
|
||||
.WithThumbnailUrl(usr.AvatarUrl)
|
||||
.WithDescription(usr.ToString())
|
||||
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
||||
@ -620,7 +671,7 @@ namespace NadekoBot.Modules.Administration
|
||||
return;
|
||||
await logChannel.EmbedAsync(new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle("🚫 User Banned")
|
||||
.WithTitle("🚫 " + logChannel.Guild.GetLogText("user_banned"))
|
||||
.WithThumbnailUrl(usr.AvatarUrl)
|
||||
.WithDescription(usr.ToString())
|
||||
.AddField(efb => efb.WithName("Id").WithValue(usr.Id.ToString()))
|
||||
@ -653,17 +704,20 @@ namespace NadekoBot.Modules.Administration
|
||||
return;
|
||||
var embed = new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle($"🗑 Message Deleted in #{((ITextChannel)msg.Channel).Name}")
|
||||
.WithTitle("🗑 " + logChannel.Guild.GetLogText("msg_del", ((ITextChannel)msg.Channel).Name))
|
||||
.WithDescription($"{msg.Author}")
|
||||
.AddField(efb => efb.WithName("Content").WithValue(msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("content")).WithValue(msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||
.AddField(efb => efb.WithName("Id").WithValue(msg.Id.ToString()).WithIsInline(false))
|
||||
.WithFooter(efb => efb.WithText(currentTime));
|
||||
if (msg.Attachments.Any())
|
||||
embed.AddField(efb => efb.WithName("Attachments").WithValue(string.Join(", ", msg.Attachments.Select(a => a.ProxyUrl))).WithIsInline(false));
|
||||
embed.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("attachments")).WithValue(string.Join(", ", msg.Attachments.Select(a => a.ProxyUrl))).WithIsInline(false));
|
||||
|
||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task _client_MessageUpdated(Optional<SocketMessage> optmsg, SocketMessage imsg2)
|
||||
@ -697,16 +751,19 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle($"📝 Message Updated in #{((ITextChannel)after.Channel).Name}")
|
||||
.WithTitle("📝 " + logChannel.Guild.GetLogText("msg_update", ((ITextChannel)after.Channel).Name))
|
||||
.WithDescription(after.Author.ToString())
|
||||
.AddField(efb => efb.WithName("Old Message").WithValue(before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||
.AddField(efb => efb.WithName("New Message").WithValue(after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("old_msg")).WithValue(before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("new_msg")).WithValue(after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||
.AddField(efb => efb.WithName("Id").WithValue(after.Id.ToString()).WithIsInline(false))
|
||||
.WithFooter(efb => efb.WithText(currentTime));
|
||||
|
||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
public enum LogType
|
||||
@ -778,8 +835,6 @@ namespace NadekoBot.Modules.Administration
|
||||
case LogType.UserMuted:
|
||||
id = logSetting.UserMutedId;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!id.HasValue)
|
||||
@ -850,8 +905,6 @@ namespace NadekoBot.Modules.Administration
|
||||
case LogType.VoicePresenceTTS:
|
||||
newLogSetting.LogVoicePresenceTTSId = null;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
GuildLogSettings.AddOrUpdate(guildId, newLogSetting, (gid, old) => newLogSetting);
|
||||
uow.Complete();
|
||||
@ -895,9 +948,9 @@ namespace NadekoBot.Modules.Administration
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
if (action.Value)
|
||||
await channel.SendConfirmAsync("Logging all events in this channel.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("log_all").ConfigureAwait(false);
|
||||
else
|
||||
await channel.SendConfirmAsync("Logging disabled.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("log_disabled").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -924,9 +977,9 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
|
||||
if (removed == 0)
|
||||
await channel.SendConfirmAsync($"Logging will IGNORE **{channel.Mention} ({channel.Id})**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("log_ignore", Format.Bold(channel.Mention + "(" + channel.Id + ")")).ConfigureAwait(false);
|
||||
else
|
||||
await channel.SendConfirmAsync($"Logging will NOT IGNORE **{channel.Mention} ({channel.Id})**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("log_not_ignore", Format.Bold(channel.Mention + "(" + channel.Id + ")")).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -935,7 +988,7 @@ namespace NadekoBot.Modules.Administration
|
||||
[OwnerOnly]
|
||||
public async Task LogEvents()
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync("Log events you can subscribe to:", String.Join(", ", Enum.GetNames(typeof(LogType)).Cast<string>()));
|
||||
await ReplyConfirmLocalized("log_events", string.Join(", ", Enum.GetNames(typeof(LogType)).Cast<string>())).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -1003,10 +1056,19 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
|
||||
if (channelId != null)
|
||||
await channel.SendConfirmAsync($"Logging **{type}** event in this channel.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("log", Format.Bold(type.ToString())).ConfigureAwait(false);
|
||||
else
|
||||
await channel.SendConfirmAsync($"Stopped logging **{type}** event.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("log_stop", Format.Bold(type.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class GuildExtensions
|
||||
{
|
||||
public static string GetLogText(this IGuild guild, string key, params object[] replacements)
|
||||
=> NadekoModule.GetTextStatic(key,
|
||||
NadekoBot.Localization.GetCultureInfo(guild),
|
||||
typeof(Administration).Name.ToLowerInvariant(),
|
||||
replacements);
|
||||
}
|
||||
}
|
@ -20,11 +20,11 @@ namespace NadekoBot.Modules.Administration
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class Migration : ModuleBase
|
||||
public class Migration : NadekoSubmodule
|
||||
{
|
||||
private const int CURRENT_VERSION = 1;
|
||||
|
||||
private static Logger _log { get; }
|
||||
private new static readonly Logger _log;
|
||||
|
||||
static Migration()
|
||||
{
|
||||
@ -51,12 +51,12 @@ namespace NadekoBot.Modules.Administration
|
||||
break;
|
||||
}
|
||||
}
|
||||
await Context.Channel.SendMessageAsync("🆙 **Migration done.**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("migration_done").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Error(ex);
|
||||
await Context.Channel.SendMessageAsync("⚠️ **Error while migrating, check `logs` for more informations.**").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("migration_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,11 +103,8 @@ namespace NadekoBot.Modules.Administration
|
||||
var greetChannel = (ulong)(long)reader["GreetChannelId"];
|
||||
var greetMsg = (string)reader["GreetText"];
|
||||
var bye = (long)reader["Bye"] == 1;
|
||||
var byeDM = (long)reader["ByePM"] == 1;
|
||||
var byeChannel = (ulong)(long)reader["ByeChannelId"];
|
||||
var byeMsg = (string)reader["ByeText"];
|
||||
var grdel = false;
|
||||
var byedel = grdel;
|
||||
var gc = uow.GuildConfigs.For(gid, set => set);
|
||||
|
||||
if (greetDM)
|
||||
@ -121,7 +118,6 @@ namespace NadekoBot.Modules.Administration
|
||||
gc.ByeMessageChannelId = byeChannel;
|
||||
gc.ChannelByeMessageText = byeMsg;
|
||||
|
||||
gc.AutoDeleteGreetMessagesTimer = gc.AutoDeleteByeMessagesTimer = grdel ? 30 : 0;
|
||||
_log.Info(++i);
|
||||
}
|
||||
}
|
||||
@ -129,12 +125,12 @@ namespace NadekoBot.Modules.Administration
|
||||
_log.Warn("Greet/bye messages won't be migrated");
|
||||
}
|
||||
var com2 = db.CreateCommand();
|
||||
com.CommandText = "SELECT * FROM CurrencyState GROUP BY UserId";
|
||||
com2.CommandText = "SELECT * FROM CurrencyState GROUP BY UserId";
|
||||
|
||||
i = 0;
|
||||
try
|
||||
{
|
||||
var reader2 = com.ExecuteReader();
|
||||
var reader2 = com2.ExecuteReader();
|
||||
while (reader2.Read())
|
||||
{
|
||||
_log.Info(++i);
|
||||
@ -203,7 +199,6 @@ namespace NadekoBot.Modules.Administration
|
||||
guildConfig.ExclusiveSelfAssignedRoles = data.ExclusiveSelfAssignedRoles;
|
||||
guildConfig.GenerateCurrencyChannelIds = new HashSet<GCChannelId>(data.GenerateCurrencyChannels.Select(gc => new GCChannelId() { ChannelId = gc.Key }));
|
||||
selfAssRoles.AddRange(data.ListOfSelfAssignableRoles.Select(r => new SelfAssignedRole() { GuildId = guildConfig.GuildId, RoleId = r }).ToArray());
|
||||
var logSetting = guildConfig.LogSetting;
|
||||
guildConfig.LogSetting.IgnoredChannels = new HashSet<IgnoredLogChannel>(data.LogserverIgnoreChannels.Select(id => new IgnoredLogChannel() { ChannelId = id }));
|
||||
|
||||
guildConfig.LogSetting.LogUserPresenceId = data.LogPresenceChannel;
|
||||
@ -249,7 +244,7 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
private void MigratePermissions0_9(IUnitOfWork uow)
|
||||
{
|
||||
var PermissionsDict = new ConcurrentDictionary<ulong, ServerPermissions0_9>();
|
||||
var permissionsDict = new ConcurrentDictionary<ulong, ServerPermissions0_9>();
|
||||
if (!Directory.Exists("data/permissions/"))
|
||||
{
|
||||
_log.Warn("No data from permissions will be migrated.");
|
||||
@ -263,12 +258,15 @@ namespace NadekoBot.Modules.Administration
|
||||
if (string.IsNullOrWhiteSpace(strippedFileName)) continue;
|
||||
var id = ulong.Parse(strippedFileName);
|
||||
var data = JsonConvert.DeserializeObject<ServerPermissions0_9>(File.ReadAllText(file));
|
||||
PermissionsDict.TryAdd(id, data);
|
||||
permissionsDict.TryAdd(id, data);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
var i = 0;
|
||||
PermissionsDict
|
||||
permissionsDict
|
||||
.Select(p => new { data = p.Value, gconfig = uow.GuildConfigs.For(p.Key) })
|
||||
.AsParallel()
|
||||
.ForAll(perms =>
|
||||
|
@ -8,8 +8,6 @@ using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -18,11 +16,10 @@ namespace NadekoBot.Modules.Administration
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class MuteCommands : ModuleBase
|
||||
public class MuteCommands : NadekoSubmodule
|
||||
{
|
||||
private static ConcurrentDictionary<ulong, string> GuildMuteRoles { get; } = new ConcurrentDictionary<ulong, string>();
|
||||
|
||||
private static ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> MutedUsers { get; } = new ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>>();
|
||||
private static ConcurrentDictionary<ulong, string> guildMuteRoles { get; }
|
||||
private static ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> mutedUsers { get; }
|
||||
|
||||
public static event Action<IGuildUser, MuteType> UserMuted = delegate { };
|
||||
public static event Action<IGuildUser, MuteType> UserUnmuted = delegate { };
|
||||
@ -36,14 +33,12 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
static MuteCommands()
|
||||
{
|
||||
var _log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
var configs = NadekoBot.AllGuildConfigs;
|
||||
GuildMuteRoles = new ConcurrentDictionary<ulong, string>(configs
|
||||
guildMuteRoles = new ConcurrentDictionary<ulong, string>(configs
|
||||
.Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName))
|
||||
.ToDictionary(c => c.GuildId, c => c.MuteRoleName));
|
||||
|
||||
MutedUsers = new ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>>(configs.ToDictionary(
|
||||
mutedUsers = new ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>>(configs.ToDictionary(
|
||||
k => k.GuildId,
|
||||
v => new ConcurrentHashSet<ulong>(v.MutedUsers.Select(m => m.UserId))
|
||||
));
|
||||
@ -56,16 +51,15 @@ namespace NadekoBot.Modules.Administration
|
||||
try
|
||||
{
|
||||
ConcurrentHashSet<ulong> muted;
|
||||
MutedUsers.TryGetValue(usr.Guild.Id, out muted);
|
||||
mutedUsers.TryGetValue(usr.Guild.Id, out muted);
|
||||
|
||||
if (muted == null || !muted.Contains(usr.Id))
|
||||
return;
|
||||
else
|
||||
await MuteUser(usr).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
LogManager.GetCurrentClassLogger().Warn(ex);
|
||||
}
|
||||
|
||||
}
|
||||
@ -82,7 +76,7 @@ namespace NadekoBot.Modules.Administration
|
||||
UserId = usr.Id
|
||||
});
|
||||
ConcurrentHashSet<ulong> muted;
|
||||
if (MutedUsers.TryGetValue(usr.Guild.Id, out muted))
|
||||
if (mutedUsers.TryGetValue(usr.Guild.Id, out muted))
|
||||
muted.Add(usr.Id);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
@ -102,7 +96,7 @@ namespace NadekoBot.Modules.Administration
|
||||
UserId = usr.Id
|
||||
});
|
||||
ConcurrentHashSet<ulong> muted;
|
||||
if (MutedUsers.TryGetValue(usr.Guild.Id, out muted))
|
||||
if (mutedUsers.TryGetValue(usr.Guild.Id, out muted))
|
||||
muted.TryRemove(usr.Id);
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
@ -113,7 +107,7 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
const string defaultMuteRoleName = "nadeko-mute";
|
||||
|
||||
var muteRoleName = GuildMuteRoles.GetOrAdd(guild.Id, defaultMuteRoleName);
|
||||
var muteRoleName = guildMuteRoles.GetOrAdd(guild.Id, defaultMuteRoleName);
|
||||
|
||||
var muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName);
|
||||
if (muteRole == null)
|
||||
@ -135,7 +129,10 @@ namespace NadekoBot.Modules.Administration
|
||||
await toOverwrite.AddPermissionOverwriteAsync(muteRole, new OverwritePermissions(sendMessages: PermValue.Deny, attachFiles: PermValue.Deny))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
await Task.Delay(200).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@ -148,7 +145,6 @@ namespace NadekoBot.Modules.Administration
|
||||
[Priority(1)]
|
||||
public async Task SetMuteRole([Remainder] string name)
|
||||
{
|
||||
//var channel = (ITextChannel)Context.Channel;
|
||||
name = name.Trim();
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return;
|
||||
@ -157,10 +153,10 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||
config.MuteRoleName = name;
|
||||
GuildMuteRoles.AddOrUpdate(Context.Guild.Id, name, (id, old) => name);
|
||||
guildMuteRoles.AddOrUpdate(Context.Guild.Id, name, (id, old) => name);
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync("☑️ **New mute role set.**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("mute_role_set").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -179,11 +175,11 @@ namespace NadekoBot.Modules.Administration
|
||||
try
|
||||
{
|
||||
await MuteUser(user).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"🔇 **{user}** has been **muted** from text and voice chat.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("user_muted", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("mute_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,11 +192,11 @@ namespace NadekoBot.Modules.Administration
|
||||
try
|
||||
{
|
||||
await UnmuteUser(user).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"🔉 **{user}** has been **unmuted** from text and voice chat.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("user_unmuted", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("mute_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,11 +209,11 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
await user.AddRolesAsync(await GetMuteRole(Context.Guild).ConfigureAwait(false)).ConfigureAwait(false);
|
||||
UserMuted(user, MuteType.Chat);
|
||||
await Context.Channel.SendConfirmAsync($"✏️🚫 **{user}** has been **muted** from chatting.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("user_chat_mute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("mute_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,11 +226,11 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
await user.RemoveRolesAsync(await GetMuteRole(Context.Guild).ConfigureAwait(false)).ConfigureAwait(false);
|
||||
UserUnmuted(user, MuteType.Chat);
|
||||
await Context.Channel.SendConfirmAsync($"✏️✅ **{user}** has been **unmuted** from chatting.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("user_chat_unmute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("mute_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,11 +243,11 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
await user.ModifyAsync(usr => usr.Mute = true).ConfigureAwait(false);
|
||||
UserMuted(user, MuteType.Voice);
|
||||
await Context.Channel.SendConfirmAsync($"🎙🚫 **{user}** has been **voice muted**.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("user_voice_mute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("mute_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,11 +260,11 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
await user.ModifyAsync(usr => usr.Mute = false).ConfigureAwait(false);
|
||||
UserUnmuted(user, MuteType.Voice);
|
||||
await Context.Channel.SendConfirmAsync($"🎙✅ **{user}** has been **voice unmuted**.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("user_voice_unmute", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ I most likely don't have the permission necessary for that.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("mute_error").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
@ -8,7 +7,6 @@ using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -18,16 +16,17 @@ namespace NadekoBot.Modules.Administration
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class PlayingRotateCommands : ModuleBase
|
||||
public class PlayingRotateCommands : NadekoSubmodule
|
||||
{
|
||||
private static Logger _log { get; }
|
||||
public static List<PlayingStatus> RotatingStatusMessages { get; }
|
||||
public static bool RotatingStatuses { get; private set; } = false;
|
||||
private static Timer _t { get; }
|
||||
public static volatile bool RotatingStatuses;
|
||||
private readonly object _locker = new object();
|
||||
private new static Logger _log { get; }
|
||||
private static readonly Timer _t;
|
||||
|
||||
private class TimerState
|
||||
{
|
||||
public int Index { get; set; } = 0;
|
||||
public int Index { get; set; }
|
||||
}
|
||||
|
||||
static PlayingRotateCommands()
|
||||
@ -37,8 +36,6 @@ namespace NadekoBot.Modules.Administration
|
||||
RotatingStatusMessages = NadekoBot.BotConfig.RotatingStatusMessages;
|
||||
RotatingStatuses = NadekoBot.BotConfig.RotatingStatuses;
|
||||
|
||||
|
||||
|
||||
_t = new Timer(async (objState) =>
|
||||
{
|
||||
try
|
||||
@ -46,8 +43,6 @@ namespace NadekoBot.Modules.Administration
|
||||
var state = (TimerState)objState;
|
||||
if (!RotatingStatuses)
|
||||
return;
|
||||
else
|
||||
{
|
||||
if (state.Index >= RotatingStatusMessages.Count)
|
||||
state.Index = 0;
|
||||
|
||||
@ -60,7 +55,8 @@ namespace NadekoBot.Modules.Administration
|
||||
var shards = NadekoBot.Client.Shards;
|
||||
for (int i = 0; i < shards.Count; i++)
|
||||
{
|
||||
ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(shards.ElementAt(i))));
|
||||
var curShard = shards.ElementAt(i);
|
||||
ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(curShard)));
|
||||
try { await shards.ElementAt(i).SetGameAsync(status).ConfigureAwait(false); }
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -68,7 +64,6 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn("Rotating playing status errored.\n" + ex);
|
||||
@ -106,18 +101,21 @@ namespace NadekoBot.Modules.Administration
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task RotatePlaying()
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var config = uow.BotConfig.GetOrCreate();
|
||||
|
||||
RotatingStatuses = config.RotatingStatuses = !config.RotatingStatuses;
|
||||
await uow.CompleteAsync();
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
if (RotatingStatuses)
|
||||
await Context.Channel.SendConfirmAsync("🆗 **Rotating playing status enabled.**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("ropl_enabled").ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ **Rotating playing status disabled.**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("ropl_disabled").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -133,7 +131,7 @@ namespace NadekoBot.Modules.Administration
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync("✅ **Added.**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("ropl_added").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -141,11 +139,13 @@ namespace NadekoBot.Modules.Administration
|
||||
public async Task ListPlaying()
|
||||
{
|
||||
if (!RotatingStatusMessages.Any())
|
||||
await Context.Channel.SendErrorAsync("❎ **No rotating playing statuses set.**");
|
||||
await ReplyErrorLocalized("ropl_not_set").ConfigureAwait(false);
|
||||
else
|
||||
{
|
||||
var i = 1;
|
||||
await Context.Channel.SendConfirmAsync($"ℹ️ {Context.User.Mention} `Here is a list of rotating statuses:`\n\n\t" + string.Join("\n\t", RotatingStatusMessages.Select(rs => $"`{i++}.` {rs.Status}")));
|
||||
await ReplyConfirmLocalized("ropl_list",
|
||||
string.Join("\n\t", RotatingStatusMessages.Select(rs => $"`{i++}.` {rs.Status}")))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
}
|
||||
@ -156,7 +156,7 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
index -= 1;
|
||||
|
||||
string msg = "";
|
||||
string msg;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var config = uow.BotConfig.GetOrCreate();
|
||||
@ -168,7 +168,7 @@ namespace NadekoBot.Modules.Administration
|
||||
RotatingStatusMessages.RemoveAt(index);
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync($"🗑 **Removed the the playing message:** {msg}").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("reprm", msg).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,10 @@ using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -26,12 +24,8 @@ namespace NadekoBot.Modules.Administration
|
||||
public class AntiRaidStats
|
||||
{
|
||||
public AntiRaidSetting AntiRaidSettings { get; set; }
|
||||
public int UsersCount { get; set; } = 0;
|
||||
public int UsersCount { get; set; }
|
||||
public ConcurrentHashSet<IGuildUser> RaidUsers { get; set; } = new ConcurrentHashSet<IGuildUser>();
|
||||
|
||||
public override string ToString() =>
|
||||
$"If **{AntiRaidSettings.UserThreshold}** or more users join within **{AntiRaidSettings.Seconds}** seconds," +
|
||||
$" I will **{AntiRaidSettings.Action}** them.";
|
||||
}
|
||||
|
||||
public class AntiSpamStats
|
||||
@ -39,16 +33,6 @@ namespace NadekoBot.Modules.Administration
|
||||
public AntiSpamSetting AntiSpamSettings { get; set; }
|
||||
public ConcurrentDictionary<ulong, UserSpamStats> UserStats { get; set; }
|
||||
= new ConcurrentDictionary<ulong, UserSpamStats>();
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var ignoredString = string.Join(", ", AntiSpamSettings.IgnoredChannels.Select(c => $"<#{c.ChannelId}>"));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ignoredString))
|
||||
ignoredString = "none";
|
||||
return $"If a user posts **{AntiSpamSettings.MessageThreshold}** same messages in a row, I will **{AntiSpamSettings.Action}** them."
|
||||
+ $"\n\t__IgnoredChannels__: {ignoredString}";
|
||||
}
|
||||
}
|
||||
|
||||
public class UserSpamStats
|
||||
@ -76,15 +60,15 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
|
||||
[Group]
|
||||
public class ProtectionCommands : ModuleBase
|
||||
public class ProtectionCommands : NadekoSubmodule
|
||||
{
|
||||
private static ConcurrentDictionary<ulong, AntiRaidStats> antiRaidGuilds =
|
||||
private static readonly ConcurrentDictionary<ulong, AntiRaidStats> _antiRaidGuilds =
|
||||
new ConcurrentDictionary<ulong, AntiRaidStats>();
|
||||
// guildId | (userId|messages)
|
||||
private static ConcurrentDictionary<ulong, AntiSpamStats> antiSpamGuilds =
|
||||
private static readonly ConcurrentDictionary<ulong, AntiSpamStats> _antiSpamGuilds =
|
||||
new ConcurrentDictionary<ulong, AntiSpamStats>();
|
||||
|
||||
private static Logger _log { get; }
|
||||
private new static readonly Logger _log;
|
||||
|
||||
static ProtectionCommands()
|
||||
{
|
||||
@ -98,11 +82,11 @@ namespace NadekoBot.Modules.Administration
|
||||
if (raid != null)
|
||||
{
|
||||
var raidStats = new AntiRaidStats() { AntiRaidSettings = raid };
|
||||
antiRaidGuilds.TryAdd(gc.GuildId, raidStats);
|
||||
_antiRaidGuilds.TryAdd(gc.GuildId, raidStats);
|
||||
}
|
||||
|
||||
if (spam != null)
|
||||
antiSpamGuilds.TryAdd(gc.GuildId, new AntiSpamStats() { AntiSpamSettings = spam });
|
||||
_antiSpamGuilds.TryAdd(gc.GuildId, new AntiSpamStats() { AntiSpamSettings = spam });
|
||||
}
|
||||
|
||||
NadekoBot.Client.MessageReceived += (imsg) =>
|
||||
@ -119,7 +103,7 @@ namespace NadekoBot.Modules.Administration
|
||||
try
|
||||
{
|
||||
AntiSpamStats spamSettings;
|
||||
if (!antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings) ||
|
||||
if (!_antiSpamGuilds.TryGetValue(channel.Guild.Id, out spamSettings) ||
|
||||
spamSettings.AntiSpamSettings.IgnoredChannels.Contains(new AntiSpamIgnore()
|
||||
{
|
||||
ChannelId = channel.Id
|
||||
@ -141,7 +125,10 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
@ -151,7 +138,7 @@ namespace NadekoBot.Modules.Administration
|
||||
if (usr.IsBot)
|
||||
return Task.CompletedTask;
|
||||
AntiRaidStats settings;
|
||||
if (!antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings))
|
||||
if (!_antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings))
|
||||
return Task.CompletedTask;
|
||||
if (!settings.RaidUsers.Add(usr))
|
||||
return Task.CompletedTask;
|
||||
@ -175,7 +162,10 @@ namespace NadekoBot.Modules.Administration
|
||||
--settings.UsersCount;
|
||||
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
@ -219,13 +209,27 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishment"); }
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
await LogCommands.TriggeredAntiProtection(gus, action, pt).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private string GetAntiSpamString(AntiSpamStats stats)
|
||||
{
|
||||
var ignoredString = string.Join(", ", stats.AntiSpamSettings.IgnoredChannels.Select(c => $"<#{c.ChannelId}>"));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ignoredString))
|
||||
ignoredString = "none";
|
||||
return GetText("spam_stats",
|
||||
Format.Bold(stats.AntiSpamSettings.MessageThreshold.ToString()),
|
||||
Format.Bold(stats.AntiSpamSettings.Action.ToString()),
|
||||
ignoredString);
|
||||
}
|
||||
|
||||
private string GetAntiRaidString(AntiRaidStats stats) => GetText("raid_stats",
|
||||
Format.Bold(stats.AntiRaidSettings.UserThreshold.ToString()),
|
||||
Format.Bold(stats.AntiRaidSettings.Seconds.ToString()),
|
||||
Format.Bold(stats.AntiRaidSettings.Action.ToString()));
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
@ -234,18 +238,18 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
if (userThreshold < 2 || userThreshold > 30)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("❗️User threshold must be between **2** and **30**.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("raid_cnt", 2, 30).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (seconds < 2 || seconds > 300)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("❗️Time must be between **2** and **300** seconds.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("raid_time", 2, 300).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
AntiRaidStats throwaway;
|
||||
if (antiRaidGuilds.TryRemove(Context.Guild.Id, out throwaway))
|
||||
if (_antiRaidGuilds.TryRemove(Context.Guild.Id, out throwaway))
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
@ -254,7 +258,7 @@ namespace NadekoBot.Modules.Administration
|
||||
gc.AntiRaidSetting = null;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync("**Anti-Raid** feature has been **disabled** on this server.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("prot_disable", "Anti-Raid").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -264,10 +268,8 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" +
|
||||
"or create 'nadeko-mute' role with disabled SendMessages and try again.")
|
||||
.ConfigureAwait(false);
|
||||
_log.Warn(ex);
|
||||
await ReplyErrorLocalized("prot_error").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -281,7 +283,7 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
};
|
||||
|
||||
antiRaidGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats);
|
||||
_antiRaidGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats);
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
@ -291,7 +293,7 @@ namespace NadekoBot.Modules.Administration
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync("Anti-Raid Enabled", $"{Context.User.Mention} {stats.ToString()}")
|
||||
await Context.Channel.SendConfirmAsync(GetText("prot_enable", "Anti-Raid"), $"{Context.User.Mention} {GetAntiRaidString(stats)}")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@ -304,7 +306,7 @@ namespace NadekoBot.Modules.Administration
|
||||
return;
|
||||
|
||||
AntiSpamStats throwaway;
|
||||
if (antiSpamGuilds.TryRemove(Context.Guild.Id, out throwaway))
|
||||
if (_antiSpamGuilds.TryRemove(Context.Guild.Id, out throwaway))
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
@ -314,7 +316,7 @@ namespace NadekoBot.Modules.Administration
|
||||
gc.AntiSpamSetting = null;
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync("**Anti-Spam** has been **disabled** on this server.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("prot_disable", "Anti-Spam").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -324,10 +326,8 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ Failed creating a mute role. Give me ManageRoles permission" +
|
||||
"or create 'nadeko-mute' role with disabled SendMessages and try again.")
|
||||
.ConfigureAwait(false);
|
||||
_log.Warn(ex);
|
||||
await ReplyErrorLocalized("prot_error").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -340,7 +340,7 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
};
|
||||
|
||||
antiSpamGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats);
|
||||
_antiSpamGuilds.AddOrUpdate(Context.Guild.Id, stats, (key, old) => stats);
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
@ -350,7 +350,7 @@ namespace NadekoBot.Modules.Administration
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync("Anti-Spam Enabled", $"{Context.User.Mention} {stats.ToString()}").ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync(GetText("prot_enable", "Anti-Spam"), $"{Context.User.Mention} {GetAntiSpamString(stats)}").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -376,7 +376,7 @@ namespace NadekoBot.Modules.Administration
|
||||
if (spam.IgnoredChannels.Add(obj))
|
||||
{
|
||||
AntiSpamStats temp;
|
||||
if (antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp))
|
||||
if (_antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp))
|
||||
temp.AntiSpamSettings.IgnoredChannels.Add(obj);
|
||||
added = true;
|
||||
}
|
||||
@ -384,7 +384,7 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
spam.IgnoredChannels.Remove(obj);
|
||||
AntiSpamStats temp;
|
||||
if (antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp))
|
||||
if (_antiSpamGuilds.TryGetValue(Context.Guild.Id, out temp))
|
||||
temp.AntiSpamSettings.IgnoredChannels.Remove(obj);
|
||||
added = false;
|
||||
}
|
||||
@ -392,9 +392,9 @@ namespace NadekoBot.Modules.Administration
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
if (added)
|
||||
await Context.Channel.SendConfirmAsync("Anti-Spam will ignore this channel.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("spam_ignore", "Anti-Spam").ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendConfirmAsync("Anti-Spam will no longer ignore this channel.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("spam_not_ignore", "Anti-Spam").ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
@ -402,31 +402,29 @@ namespace NadekoBot.Modules.Administration
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task AntiList()
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
AntiSpamStats spam;
|
||||
antiSpamGuilds.TryGetValue(Context.Guild.Id, out spam);
|
||||
_antiSpamGuilds.TryGetValue(Context.Guild.Id, out spam);
|
||||
|
||||
AntiRaidStats raid;
|
||||
antiRaidGuilds.TryGetValue(Context.Guild.Id, out raid);
|
||||
_antiRaidGuilds.TryGetValue(Context.Guild.Id, out raid);
|
||||
|
||||
if (spam == null && raid == null)
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync("No protections enabled.");
|
||||
await ReplyConfirmLocalized("prot_none").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = new EmbedBuilder().WithOkColor()
|
||||
.WithTitle("Protections Enabled");
|
||||
.WithTitle(GetText("prot_active"));
|
||||
|
||||
if (spam != null)
|
||||
embed.AddField(efb => efb.WithName("Anti-Spam")
|
||||
.WithValue(spam.ToString())
|
||||
.WithValue(GetAntiSpamString(spam))
|
||||
.WithIsInline(true));
|
||||
|
||||
if (raid != null)
|
||||
embed.AddField(efb => efb.WithName("Anti-Raid")
|
||||
.WithValue(raid.ToString())
|
||||
.WithValue(GetAntiRaidString(raid))
|
||||
.WithIsInline(true));
|
||||
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
|
@ -13,10 +13,10 @@ namespace NadekoBot.Modules.Administration
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class RatelimitCommand : ModuleBase
|
||||
public class RatelimitCommand : NadekoSubmodule
|
||||
{
|
||||
public static ConcurrentDictionary<ulong, Ratelimiter> RatelimitingChannels = new ConcurrentDictionary<ulong, Ratelimiter>();
|
||||
private static Logger _log { get; }
|
||||
private new static readonly Logger _log;
|
||||
|
||||
public class Ratelimiter
|
||||
{
|
||||
@ -37,15 +37,13 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
public bool CheckUserRatelimit(ulong id)
|
||||
{
|
||||
RatelimitedUser usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id });
|
||||
var usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id });
|
||||
if (usr.MessageCount == MaxMessages)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
usr.MessageCount++;
|
||||
var t = Task.Run(async () =>
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -56,8 +54,6 @@ namespace NadekoBot.Modules.Administration
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static RatelimitCommand()
|
||||
@ -69,9 +65,7 @@ namespace NadekoBot.Modules.Administration
|
||||
try
|
||||
{
|
||||
var usrMsg = umsg as IUserMessage;
|
||||
if (usrMsg == null)
|
||||
return;
|
||||
var channel = usrMsg.Channel as ITextChannel;
|
||||
var channel = usrMsg?.Channel as ITextChannel;
|
||||
|
||||
if (channel == null || usrMsg.IsAuthor())
|
||||
return;
|
||||
@ -95,8 +89,7 @@ namespace NadekoBot.Modules.Administration
|
||||
if (RatelimitingChannels.TryRemove(Context.Channel.Id, out throwaway))
|
||||
{
|
||||
throwaway.cancelSource.Cancel();
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ Slow mode disabled.").ConfigureAwait(false);
|
||||
return;
|
||||
await ReplyConfirmLocalized("slowmode_disabled").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,7 +102,7 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
if (msg < 1 || perSec < 1 || msg > 100 || perSec > 3600)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ Invalid parameters.");
|
||||
await ReplyErrorLocalized("invalid_params").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var toAdd = new Ratelimiter()
|
||||
@ -120,8 +113,8 @@ namespace NadekoBot.Modules.Administration
|
||||
};
|
||||
if(RatelimitingChannels.TryAdd(Context.Channel.Id, toAdd))
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync("Slow mode initiated",
|
||||
$"Users can't send more than `{toAdd.MaxMessages} message(s)` every `{toAdd.PerSeconds} second(s)`.")
|
||||
await Context.Channel.SendConfirmAsync(GetText("slowmode_init"),
|
||||
GetText("slowmode_desc", Format.Bold(toAdd.MaxMessages.ToString()), Format.Bold(toAdd.PerSeconds.ToString())))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ namespace NadekoBot.Modules.Administration
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class SelfAssignedRolesCommands : ModuleBase
|
||||
public class SelfAssignedRolesCommands : NadekoSubmodule
|
||||
{
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -44,25 +44,30 @@ namespace NadekoBot.Modules.Administration
|
||||
IEnumerable<SelfAssignedRole> roles;
|
||||
|
||||
string msg;
|
||||
var error = false;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id);
|
||||
if (roles.Any(s => s.RoleId == role.Id && s.GuildId == role.Guild.Id))
|
||||
{
|
||||
await Context.Channel.SendMessageAsync($"💢 Role **{role.Name}** is already in the list.").ConfigureAwait(false);
|
||||
return;
|
||||
msg = GetText("role_in_list", Format.Bold(role.Name));
|
||||
error = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
uow.SelfAssignedRoles.Add(new SelfAssignedRole {
|
||||
uow.SelfAssignedRoles.Add(new SelfAssignedRole
|
||||
{
|
||||
RoleId = role.Id,
|
||||
GuildId = role.Guild.Id
|
||||
});
|
||||
await uow.CompleteAsync();
|
||||
msg = $"🆗 Role **{role.Name}** added to the list.";
|
||||
msg = GetText("role_added", Format.Bold(role.Name));
|
||||
}
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync(msg.ToString()).ConfigureAwait(false);
|
||||
if (error)
|
||||
await Context.Channel.SendErrorAsync(msg).ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendConfirmAsync(msg).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -70,8 +75,6 @@ namespace NadekoBot.Modules.Administration
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
public async Task Rsar([Remainder] IRole role)
|
||||
{
|
||||
//var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
bool success;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
@ -80,18 +83,16 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("❎ That role is not self-assignable.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("self_assign_not").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync($"🗑 **{role.Name}** has been removed from the list of self-assignable roles.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("self_assign_rem", Format.Bold(role.Name)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Lsar()
|
||||
{
|
||||
//var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
var toRemove = new ConcurrentHashSet<SelfAssignedRole>();
|
||||
var removeMsg = new StringBuilder();
|
||||
var msg = new StringBuilder();
|
||||
@ -116,11 +117,11 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
foreach (var role in toRemove)
|
||||
{
|
||||
removeMsg.AppendLine($"`{role.RoleId} not found. Cleaned up.`");
|
||||
removeMsg.AppendLine(GetText("role_clean", role.RoleId));
|
||||
}
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync($"ℹ️ There are `{roleCnt}` self assignable roles:", msg.ToString() + "\n\n" + removeMsg.ToString()).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync(GetText("self_assign_list", roleCnt), msg + "\n\n" + removeMsg).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -128,8 +129,6 @@ namespace NadekoBot.Modules.Administration
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
public async Task Tesar()
|
||||
{
|
||||
//var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
bool areExclusive;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
@ -138,15 +137,16 @@ namespace NadekoBot.Modules.Administration
|
||||
areExclusive = config.ExclusiveSelfAssignedRoles = !config.ExclusiveSelfAssignedRoles;
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
string exl = areExclusive ? "**exclusive**." : "**not exclusive**.";
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ Self assigned roles are now " + exl);
|
||||
if(areExclusive)
|
||||
await ReplyConfirmLocalized("self_assign_excl").ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("self_assign_no_excl").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Iam([Remainder] IRole role)
|
||||
{
|
||||
//var channel = (ITextChannel)Context.Channel;
|
||||
var guildUser = (IGuildUser)Context.User;
|
||||
|
||||
GuildConfig conf;
|
||||
@ -156,25 +156,24 @@ namespace NadekoBot.Modules.Administration
|
||||
conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||
roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id);
|
||||
}
|
||||
SelfAssignedRole roleModel;
|
||||
if ((roleModel = roles.FirstOrDefault(r=>r.RoleId == role.Id)) == null)
|
||||
if (roles.FirstOrDefault(r=>r.RoleId == role.Id) == null)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("That role is not self-assignable.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("self_assign_not").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (guildUser.RoleIds.Contains(role.Id))
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"You already have **{role.Name}** role.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("self_assign_already", Format.Bold(role.Name)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (conf.ExclusiveSelfAssignedRoles)
|
||||
{
|
||||
var sameRoleId = guildUser.RoleIds.Where(r => roles.Select(sar => sar.RoleId).Contains(r)).FirstOrDefault();
|
||||
var sameRoleId = guildUser.RoleIds.FirstOrDefault(r => roles.Select(sar => sar.RoleId).Contains(r));
|
||||
var sameRole = Context.Guild.GetRole(sameRoleId);
|
||||
if (sameRoleId != default(ulong))
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"You already have **{sameRole?.Name}** `exclusive self-assigned` role.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("self_assign_already_excl", Format.Bold(sameRole?.Name)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -184,11 +183,11 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"⚠️ I am unable to add that role to you. `I can't add roles to owners or other roles higher than my role in the role hierarchy.`").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("self_assign_perms").ConfigureAwait(false);
|
||||
Console.WriteLine(ex);
|
||||
return;
|
||||
}
|
||||
var msg = await Context.Channel.SendConfirmAsync($"🆗 You now have **{role.Name}** role.").ConfigureAwait(false);
|
||||
var msg = await ReplyConfirmLocalized("self_assign_success",Format.Bold(role.Name)).ConfigureAwait(false);
|
||||
|
||||
if (conf.AutoDeleteSelfAssignedRoleMessages)
|
||||
{
|
||||
@ -210,15 +209,14 @@ namespace NadekoBot.Modules.Administration
|
||||
autoDeleteSelfAssignedRoleMessages = uow.GuildConfigs.For(Context.Guild.Id, set => set).AutoDeleteSelfAssignedRoleMessages;
|
||||
roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id);
|
||||
}
|
||||
SelfAssignedRole roleModel;
|
||||
if ((roleModel = roles.FirstOrDefault(r => r.RoleId == role.Id)) == null)
|
||||
if (roles.FirstOrDefault(r => r.RoleId == role.Id) == null)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("💢 That role is not self-assignable.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("self_assign_not").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (!guildUser.RoleIds.Contains(role.Id))
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"❎ You don't have **{role.Name}** role.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("self_assign_not_have",Format.Bold(role.Name)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
try
|
||||
@ -227,10 +225,10 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"⚠️ I am unable to add that role to you. `I can't remove roles to owners or other roles higher than my role in the role hierarchy.`").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("self_assign_perms").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var msg = await Context.Channel.SendConfirmAsync($"🆗 You no longer have **{role.Name}** role.").ConfigureAwait(false);
|
||||
var msg = await ReplyConfirmLocalized("self_assign_remove", Format.Bold(role.Name)).ConfigureAwait(false);
|
||||
|
||||
if (autoDeleteSelfAssignedRoleMessages)
|
||||
{
|
||||
|
@ -3,19 +3,97 @@ using Discord.Commands;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
class SelfCommands : ModuleBase
|
||||
public class SelfCommands : NadekoSubmodule
|
||||
{
|
||||
private static volatile bool _forwardDMs;
|
||||
private static volatile bool _forwardDMsToAllOwners;
|
||||
|
||||
private static readonly object _locker = new object();
|
||||
|
||||
static SelfCommands()
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var config = uow.BotConfig.GetOrCreate();
|
||||
_forwardDMs = config.ForwardMessages;
|
||||
_forwardDMsToAllOwners = config.ForwardToAllOwners;
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task ForwardMessages()
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var config = uow.BotConfig.GetOrCreate();
|
||||
lock (_locker)
|
||||
_forwardDMs = config.ForwardMessages = !config.ForwardMessages;
|
||||
uow.Complete();
|
||||
}
|
||||
if (_forwardDMs)
|
||||
await ReplyConfirmLocalized("fwdm_start").ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("fwdm_stop").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task ForwardToAll()
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var config = uow.BotConfig.GetOrCreate();
|
||||
lock (_locker)
|
||||
_forwardDMsToAllOwners = config.ForwardToAllOwners = !config.ForwardToAllOwners;
|
||||
uow.Complete();
|
||||
}
|
||||
if (_forwardDMsToAllOwners)
|
||||
await ReplyConfirmLocalized("fwall_start").ConfigureAwait(false);
|
||||
else
|
||||
await ReplyConfirmLocalized("fwall_stop").ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
public static async Task HandleDmForwarding(SocketMessage msg, List<IDMChannel> ownerChannels)
|
||||
{
|
||||
if (_forwardDMs && ownerChannels.Any())
|
||||
{
|
||||
var title =
|
||||
GetTextStatic("dm_from", NadekoBot.Localization.DefaultCultureInfo,
|
||||
typeof(Administration).Name.ToLowerInvariant()) + $" [{msg.Author}]({msg.Author.Id})";
|
||||
if (_forwardDMsToAllOwners)
|
||||
{
|
||||
await Task.WhenAll(ownerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id)
|
||||
.Select(ch => ch.SendConfirmAsync(title, msg.Content))).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var firstOwnerChannel = ownerChannels.First();
|
||||
if (firstOwnerChannel.Recipient.Id != msg.Author.Id)
|
||||
try { await firstOwnerChannel.SendConfirmAsync(title, msg.Content).ConfigureAwait(false); }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task ConnectShard(int shardid)
|
||||
@ -24,14 +102,14 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
if (shard == null)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("No shard by that id found.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("no_shard_id").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync($"Shard **#{shardid}** reconnecting.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("shard_reconnecting", Format.Bold("#" + shardid)).ConfigureAwait(false);
|
||||
await shard.ConnectAsync().ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"Shard **#{shardid}** reconnected.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("shard_reconnected", Format.Bold("#" + shardid)).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -49,18 +127,18 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
if (server == null)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ Cannot find that server").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("no_server").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (server.OwnerId != NadekoBot.Client.CurrentUser.Id)
|
||||
{
|
||||
await server.LeaveAsync().ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync("✅ Left server " + server.Name).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("left_server", Format.Bold(server.Name)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await server.DeleteAsync().ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync("Deleted server " + server.Name).ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("deleted_server",Format.Bold(server.Name)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,7 +147,14 @@ namespace NadekoBot.Modules.Administration
|
||||
[OwnerOnly]
|
||||
public async Task Die()
|
||||
{
|
||||
try { await Context.Channel.SendConfirmAsync("ℹ️ **Shutting down.**").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
||||
try
|
||||
{
|
||||
await ReplyConfirmLocalized("shutting_down").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
await Task.Delay(2000).ConfigureAwait(false);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
@ -83,7 +168,7 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
await NadekoBot.Client.CurrentUser.ModifyAsync(u => u.Username = newName).ConfigureAwait(false);
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"Bot name changed to **{newName}**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("bot_name", Format.Bold(newName)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -92,7 +177,7 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
await NadekoBot.Client.SetStatusAsync(SettableUserStatusToUserStatus(status)).ConfigureAwait(false);
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"Bot status changed to **{status}**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("bot_status", Format.Bold(status.ToString())).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -114,7 +199,7 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync("🆒 **New avatar set.**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("set_avatar").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -123,7 +208,7 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
await NadekoBot.Client.SetGameAsync(game).ConfigureAwait(false);
|
||||
|
||||
await Context.Channel.SendConfirmAsync("👾 **New game set.**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("set_game").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -134,7 +219,7 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
await NadekoBot.Client.SetGameAsync(name, url, StreamType.Twitch).ConfigureAwait(false);
|
||||
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ **New stream set.**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("set_stream").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -148,7 +233,7 @@ namespace NadekoBot.Modules.Administration
|
||||
if (ids.Length != 2)
|
||||
return;
|
||||
var sid = ulong.Parse(ids[0]);
|
||||
var server = NadekoBot.Client.GetGuilds().Where(s => s.Id == sid).FirstOrDefault();
|
||||
var server = NadekoBot.Client.GetGuilds().FirstOrDefault(s => s.Id == sid);
|
||||
|
||||
if (server == null)
|
||||
return;
|
||||
@ -156,7 +241,7 @@ namespace NadekoBot.Modules.Administration
|
||||
if (ids[1].ToUpperInvariant().StartsWith("C:"))
|
||||
{
|
||||
var cid = ulong.Parse(ids[1].Substring(2));
|
||||
var ch = server.TextChannels.Where(c => c.Id == cid).FirstOrDefault();
|
||||
var ch = server.TextChannels.FirstOrDefault(c => c.Id == cid);
|
||||
if (ch == null)
|
||||
{
|
||||
return;
|
||||
@ -166,7 +251,7 @@ namespace NadekoBot.Modules.Administration
|
||||
else if (ids[1].ToUpperInvariant().StartsWith("U:"))
|
||||
{
|
||||
var uid = ulong.Parse(ids[1].Substring(2));
|
||||
var user = server.Users.Where(u => u.Id == uid).FirstOrDefault();
|
||||
var user = server.Users.FirstOrDefault(u => u.Id == uid);
|
||||
if (user == null)
|
||||
{
|
||||
return;
|
||||
@ -175,8 +260,10 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
else
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ Invalid format.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("invalid_format").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await ReplyConfirmLocalized("message_sent").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -186,10 +273,10 @@ namespace NadekoBot.Modules.Administration
|
||||
var channels = NadekoBot.Client.GetGuilds().Select(g => g.DefaultChannel).ToArray();
|
||||
if (channels == null)
|
||||
return;
|
||||
await Task.WhenAll(channels.Where(c => c != null).Select(c => c.SendConfirmAsync($"🆕 Message from {Context.User} `[Bot Owner]`:", message)))
|
||||
await Task.WhenAll(channels.Where(c => c != null).Select(c => c.SendConfirmAsync(GetText("message_from_bo", Context.User.ToString()), message)))
|
||||
.ConfigureAwait(false);
|
||||
|
||||
await Context.Channel.SendConfirmAsync("🆗").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("message_sent").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -197,7 +284,7 @@ namespace NadekoBot.Modules.Administration
|
||||
public async Task ReloadImages()
|
||||
{
|
||||
var time = await NadekoBot.Images.Reload().ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"Images loaded after {time.TotalSeconds:F3}s!").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("images_loaded", time.TotalSeconds.ToString("F3")).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus)
|
||||
|
@ -1,11 +1,9 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.DataStructures;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
using System;
|
||||
@ -18,10 +16,10 @@ namespace NadekoBot.Modules.Administration
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class ServerGreetCommands : ModuleBase
|
||||
public class ServerGreetCommands : NadekoSubmodule
|
||||
{
|
||||
//make this to a field in the guildconfig table
|
||||
class GreetSettings
|
||||
private class GreetSettings
|
||||
{
|
||||
public int AutoDeleteGreetMessagesTimer { get; set; }
|
||||
public int AutoDeleteByeMessagesTimer { get; set; }
|
||||
@ -53,9 +51,9 @@ namespace NadekoBot.Modules.Administration
|
||||
};
|
||||
}
|
||||
|
||||
private static Logger _log { get; }
|
||||
private new static Logger _log { get; }
|
||||
|
||||
private static ConcurrentDictionary<ulong, GreetSettings> GuildConfigsCache { get; } = new ConcurrentDictionary<ulong, GreetSettings>();
|
||||
private static ConcurrentDictionary<ulong, GreetSettings> guildConfigsCache { get; }
|
||||
|
||||
static ServerGreetCommands()
|
||||
{
|
||||
@ -63,13 +61,13 @@ namespace NadekoBot.Modules.Administration
|
||||
NadekoBot.Client.UserLeft += UserLeft;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
GuildConfigsCache = new ConcurrentDictionary<ulong, GreetSettings>(NadekoBot.AllGuildConfigs.ToDictionary(g => g.GuildId, (g) => GreetSettings.Create(g)));
|
||||
guildConfigsCache = new ConcurrentDictionary<ulong, GreetSettings>(NadekoBot.AllGuildConfigs.ToDictionary(g => g.GuildId, GreetSettings.Create));
|
||||
}
|
||||
|
||||
private static GreetSettings GetOrAddSettingsForGuild(ulong guildId)
|
||||
{
|
||||
GreetSettings settings;
|
||||
GuildConfigsCache.TryGetValue(guildId, out settings);
|
||||
guildConfigsCache.TryGetValue(guildId, out settings);
|
||||
|
||||
if (settings != null)
|
||||
return settings;
|
||||
@ -80,7 +78,7 @@ namespace NadekoBot.Modules.Administration
|
||||
settings = GreetSettings.Create(gc);
|
||||
}
|
||||
|
||||
GuildConfigsCache.TryAdd(guildId, settings);
|
||||
guildConfigsCache.TryAdd(guildId, settings);
|
||||
return settings;
|
||||
}
|
||||
|
||||
@ -129,7 +127,10 @@ namespace NadekoBot.Modules.Administration
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@ -212,7 +213,10 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@ -222,16 +226,15 @@ namespace NadekoBot.Modules.Administration
|
||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||
public async Task GreetDel(int timer = 30)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
if (timer < 0 || timer > 600)
|
||||
return;
|
||||
|
||||
await ServerGreetCommands.SetGreetDel(Context.Guild.Id, timer).ConfigureAwait(false);
|
||||
|
||||
if (timer > 0)
|
||||
await Context.Channel.SendConfirmAsync($"🆗 Greet messages **will be deleted** after `{timer} seconds`.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("greetdel_on", timer).ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ Automatic deletion of greet messages has been **disabled**.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("greetdel_off").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async Task SetGreetDel(ulong id, int timer)
|
||||
@ -245,7 +248,7 @@ namespace NadekoBot.Modules.Administration
|
||||
conf.AutoDeleteGreetMessagesTimer = timer;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(id, toAdd, (key, old) => toAdd);
|
||||
guildConfigsCache.AddOrUpdate(id, toAdd, (key, old) => toAdd);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
@ -259,9 +262,9 @@ namespace NadekoBot.Modules.Administration
|
||||
var enabled = await ServerGreetCommands.SetGreet(Context.Guild.Id, Context.Channel.Id).ConfigureAwait(false);
|
||||
|
||||
if (enabled)
|
||||
await Context.Channel.SendConfirmAsync("✅ Greeting messages **enabled** on this channel.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("greet_on").ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ Greeting messages **disabled**.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("greet_off").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async Task<bool> SetGreet(ulong guildId, ulong channelId, bool? value = null)
|
||||
@ -274,7 +277,7 @@ namespace NadekoBot.Modules.Administration
|
||||
conf.GreetMessageChannelId = channelId;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
guildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
@ -293,15 +296,15 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
channelGreetMessageText = uow.GuildConfigs.For(Context.Guild.Id, set => set).ChannelGreetMessageText;
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync("Current greet message: ", channelGreetMessageText?.SanitizeMentions());
|
||||
await ReplyConfirmLocalized("greetmsg_cur", channelGreetMessageText?.SanitizeMentions()).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var sendGreetEnabled = ServerGreetCommands.SetGreetMessage(Context.Guild.Id, ref text);
|
||||
|
||||
await Context.Channel.SendConfirmAsync("🆗 New greet message **set**.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("greetmsg_new").ConfigureAwait(false);
|
||||
if (!sendGreetEnabled)
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ Enable greet messsages by typing `.greet`").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("greetmsg_enable", $"`{Prefix}greet`").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static bool SetGreetMessage(ulong guildId, ref string message)
|
||||
@ -319,7 +322,7 @@ namespace NadekoBot.Modules.Administration
|
||||
greetMsgEnabled = conf.SendChannelGreetMessage;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
guildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
@ -334,9 +337,9 @@ namespace NadekoBot.Modules.Administration
|
||||
var enabled = await ServerGreetCommands.SetGreetDm(Context.Guild.Id).ConfigureAwait(false);
|
||||
|
||||
if (enabled)
|
||||
await Context.Channel.SendConfirmAsync("🆗 DM Greet announcements **enabled**.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("greetdm_on").ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ Greet announcements **disabled**.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("greetdm_off").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async Task<bool> SetGreetDm(ulong guildId, bool? value = null)
|
||||
@ -348,7 +351,7 @@ namespace NadekoBot.Modules.Administration
|
||||
enabled = conf.SendDmGreetMessage = value ?? !conf.SendDmGreetMessage;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
guildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
@ -367,15 +370,15 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
config = uow.GuildConfigs.For(Context.Guild.Id);
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ Current **DM greet** message: `" + config.DmGreetMessageText?.SanitizeMentions() + "`");
|
||||
await ReplyConfirmLocalized("greetdmmsg_cur", config.DmGreetMessageText?.SanitizeMentions()).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var sendGreetEnabled = ServerGreetCommands.SetGreetDmMessage(Context.Guild.Id, ref text);
|
||||
|
||||
await Context.Channel.SendConfirmAsync("🆗 New DM greet message **set**.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("greetdmmsg_new").ConfigureAwait(false);
|
||||
if (!sendGreetEnabled)
|
||||
await Context.Channel.SendConfirmAsync($"ℹ️ Enable DM greet messsages by typing `{NadekoBot.ModulePrefixes[typeof(Administration).Name]}greetdm`").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("greetdmmsg_enable", $"`{Prefix}greetdm`").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static bool SetGreetDmMessage(ulong guildId, ref string message)
|
||||
@ -393,7 +396,7 @@ namespace NadekoBot.Modules.Administration
|
||||
greetMsgEnabled = conf.SendDmGreetMessage;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
guildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
@ -408,9 +411,9 @@ namespace NadekoBot.Modules.Administration
|
||||
var enabled = await ServerGreetCommands.SetBye(Context.Guild.Id, Context.Channel.Id).ConfigureAwait(false);
|
||||
|
||||
if (enabled)
|
||||
await Context.Channel.SendConfirmAsync("✅ Bye announcements **enabled** on this channel.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("bye_on").ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ Bye announcements **disabled**.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("bye_off").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async Task<bool> SetBye(ulong guildId, ulong channelId, bool? value = null)
|
||||
@ -423,7 +426,7 @@ namespace NadekoBot.Modules.Administration
|
||||
conf.ByeMessageChannelId = channelId;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
guildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
@ -442,15 +445,15 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
byeMessageText = uow.GuildConfigs.For(Context.Guild.Id, set => set).ChannelByeMessageText;
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ Current **bye** message: `" + byeMessageText?.SanitizeMentions() + "`");
|
||||
await ReplyConfirmLocalized("byemsg_cur", byeMessageText?.SanitizeMentions()).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var sendByeEnabled = ServerGreetCommands.SetByeMessage(Context.Guild.Id, ref text);
|
||||
|
||||
await Context.Channel.SendConfirmAsync("🆗 New bye message **set**.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("byemsg_new").ConfigureAwait(false);
|
||||
if (!sendByeEnabled)
|
||||
await Context.Channel.SendConfirmAsync($"ℹ️ Enable bye messsages by typing `{NadekoBot.ModulePrefixes[typeof(Administration).Name]}bye`").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("byemsg_enable", $"`{Prefix}bye`").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static bool SetByeMessage(ulong guildId, ref string message)
|
||||
@ -468,7 +471,7 @@ namespace NadekoBot.Modules.Administration
|
||||
byeMsgEnabled = conf.SendChannelByeMessage;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
guildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
@ -483,9 +486,9 @@ namespace NadekoBot.Modules.Administration
|
||||
await ServerGreetCommands.SetByeDel(Context.Guild.Id, timer).ConfigureAwait(false);
|
||||
|
||||
if (timer > 0)
|
||||
await Context.Channel.SendConfirmAsync($"🆗 Bye messages **will be deleted** after `{timer} seconds`.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("byedel_on", timer).ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ Automatic deletion of bye messages has been **disabled**.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("byedel_off").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async Task SetByeDel(ulong guildId, int timer)
|
||||
@ -499,7 +502,7 @@ namespace NadekoBot.Modules.Administration
|
||||
conf.AutoDeleteByeMessagesTimer = timer;
|
||||
|
||||
var toAdd = GreetSettings.Create(conf);
|
||||
GuildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
guildConfigsCache.AddOrUpdate(guildId, toAdd, (key, old) => toAdd);
|
||||
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
@ -19,21 +19,20 @@ namespace NadekoBot.Modules.Administration
|
||||
public partial class Administration
|
||||
{
|
||||
[Group]
|
||||
public class VoicePlusTextCommands : ModuleBase
|
||||
public class VoicePlusTextCommands : NadekoSubmodule
|
||||
{
|
||||
private static Regex channelNameRegex = new Regex(@"[^a-zA-Z0-9 -]", RegexOptions.Compiled);
|
||||
private new static readonly Logger _log;
|
||||
|
||||
private static ConcurrentHashSet<ulong> voicePlusTextCache { get; }
|
||||
private static readonly Regex _channelNameRegex = new Regex(@"[^a-zA-Z0-9 -]", RegexOptions.Compiled);
|
||||
|
||||
private static ConcurrentDictionary<ulong, SemaphoreSlim> guildLockObjects = new ConcurrentDictionary<ulong, SemaphoreSlim>();
|
||||
private static readonly ConcurrentHashSet<ulong> _voicePlusTextCache;
|
||||
private static readonly ConcurrentDictionary<ulong, SemaphoreSlim> _guildLockObjects = new ConcurrentDictionary<ulong, SemaphoreSlim>();
|
||||
static VoicePlusTextCommands()
|
||||
{
|
||||
var _log = LogManager.GetCurrentClassLogger();
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
var sw = Stopwatch.StartNew();
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
voicePlusTextCache = new ConcurrentHashSet<ulong>(NadekoBot.AllGuildConfigs.Where(g => g.VoicePlusTextEnabled).Select(g => g.GuildId));
|
||||
}
|
||||
|
||||
_voicePlusTextCache = new ConcurrentHashSet<ulong>(NadekoBot.AllGuildConfigs.Where(g => g.VoicePlusTextEnabled).Select(g => g.GuildId));
|
||||
NadekoBot.Client.UserVoiceStateUpdated += UserUpdatedEventHandler;
|
||||
|
||||
sw.Stop();
|
||||
@ -53,7 +52,7 @@ namespace NadekoBot.Modules.Administration
|
||||
if (before.VoiceChannel == after.VoiceChannel)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (!voicePlusTextCache.Contains(guild.Id))
|
||||
if (!_voicePlusTextCache.Contains(guild.Id))
|
||||
return Task.CompletedTask;
|
||||
|
||||
var _ = Task.Run(async () =>
|
||||
@ -66,20 +65,25 @@ namespace NadekoBot.Modules.Administration
|
||||
try
|
||||
{
|
||||
await guild.Owner.SendErrorAsync(
|
||||
"⚠️ I don't have **manage server** and/or **manage channels** permission," +
|
||||
$" so I cannot run `voice+text` on **{guild.Name}** server.").ConfigureAwait(false);
|
||||
GetTextStatic("vt_exit",
|
||||
NadekoBot.Localization.GetCultureInfo(guild),
|
||||
typeof(Administration).Name.ToLowerInvariant(),
|
||||
Format.Bold(guild.Name))).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
catch { }
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
uow.GuildConfigs.For(guild.Id, set => set).VoicePlusTextEnabled = false;
|
||||
voicePlusTextCache.TryRemove(guild.Id);
|
||||
_voicePlusTextCache.TryRemove(guild.Id);
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var semaphore = guildLockObjects.GetOrAdd(guild.Id, (key) => new SemaphoreSlim(1, 1));
|
||||
var semaphore = _guildLockObjects.GetOrAdd(guild.Id, (key) => new SemaphoreSlim(1, 1));
|
||||
|
||||
try
|
||||
{
|
||||
@ -106,18 +110,16 @@ namespace NadekoBot.Modules.Administration
|
||||
if (afterVch != null && guild.AFKChannel?.Id != afterVch.Id)
|
||||
{
|
||||
var roleName = GetRoleName(afterVch);
|
||||
IRole roleToAdd = guild.Roles.FirstOrDefault(x => x.Name == roleName);
|
||||
if (roleToAdd == null)
|
||||
roleToAdd = await guild.CreateRoleAsync(roleName, GuildPermissions.None).ConfigureAwait(false);
|
||||
var roleToAdd = guild.Roles.FirstOrDefault(x => x.Name == roleName) ??
|
||||
(IRole) await guild.CreateRoleAsync(roleName, GuildPermissions.None).ConfigureAwait(false);
|
||||
|
||||
ITextChannel textChannel = guild.TextChannels
|
||||
.Where(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant())
|
||||
.FirstOrDefault();
|
||||
.FirstOrDefault(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant());
|
||||
if (textChannel == null)
|
||||
{
|
||||
var created = (await guild.CreateTextChannelAsync(GetChannelName(afterVch.Name).ToLowerInvariant()).ConfigureAwait(false));
|
||||
|
||||
try { await guild.CurrentUser.AddRolesAsync(roleToAdd).ConfigureAwait(false); } catch { }
|
||||
try { await guild.CurrentUser.AddRolesAsync(roleToAdd).ConfigureAwait(false); } catch {/*ignored*/}
|
||||
await Task.Delay(50).ConfigureAwait(false);
|
||||
await created.AddPermissionOverwriteAsync(roleToAdd, new OverwritePermissions(
|
||||
readMessages: PermValue.Allow,
|
||||
@ -148,7 +150,7 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
|
||||
private static string GetChannelName(string voiceName) =>
|
||||
channelNameRegex.Replace(voiceName, "").Trim().Replace(" ", "-").TrimTo(90, true) + "-voice";
|
||||
_channelNameRegex.Replace(voiceName, "").Trim().Replace(" ", "-").TrimTo(90, true) + "-voice";
|
||||
|
||||
private static string GetRoleName(IVoiceChannel ch) =>
|
||||
"nvoice-" + ch.Id;
|
||||
@ -164,7 +166,7 @@ namespace NadekoBot.Modules.Administration
|
||||
var botUser = await guild.GetCurrentUserAsync().ConfigureAwait(false);
|
||||
if (!botUser.GuildPermissions.ManageRoles || !botUser.GuildPermissions.ManageChannels)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("I require atleast **manage roles** and **manage channels permissions** to enable this feature. `(preffered Administration permission)`");
|
||||
await ReplyErrorLocalized("vt_no_perms").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -172,10 +174,12 @@ namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
try
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("⚠️ You are enabling/disabling this feature and **I do not have ADMINISTRATOR permissions**. " +
|
||||
"`This may cause some issues, and you will have to clean up text channels yourself afterwards.`");
|
||||
await ReplyErrorLocalized("vt_no_admin").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
try
|
||||
{
|
||||
@ -188,7 +192,7 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
if (!isEnabled)
|
||||
{
|
||||
voicePlusTextCache.TryRemove(guild.Id);
|
||||
_voicePlusTextCache.TryRemove(guild.Id);
|
||||
foreach (var textChannel in (await guild.GetTextChannelsAsync().ConfigureAwait(false)).Where(c => c.Name.EndsWith("-voice")))
|
||||
{
|
||||
try { await textChannel.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||
@ -200,11 +204,11 @@ namespace NadekoBot.Modules.Administration
|
||||
try { await role.DeleteAsync().ConfigureAwait(false); } catch { }
|
||||
await Task.Delay(500).ConfigureAwait(false);
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync("ℹ️ Successfuly **removed** voice + text feature.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("vt_disabled").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
voicePlusTextCache.Add(guild.Id);
|
||||
await Context.Channel.SendConfirmAsync("🆗 Successfuly **enabled** voice + text feature.").ConfigureAwait(false);
|
||||
_voicePlusTextCache.Add(guild.Id);
|
||||
await ReplyConfirmLocalized("vt_enabled").ConfigureAwait(false);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -224,7 +228,7 @@ namespace NadekoBot.Modules.Administration
|
||||
var botUser = await guild.GetCurrentUserAsync().ConfigureAwait(false);
|
||||
if (!botUser.GuildPermissions.Administrator)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("I need **Administrator permission** to do that.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("need_admin").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -251,7 +255,7 @@ namespace NadekoBot.Modules.Administration
|
||||
await Task.Delay(500).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync("Cleaned v+t.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("cleaned_up").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,18 +17,14 @@ using NLog;
|
||||
namespace NadekoBot.Modules.ClashOfClans
|
||||
{
|
||||
[NadekoModule("ClashOfClans", ",")]
|
||||
public class ClashOfClans : DiscordModule
|
||||
public class ClashOfClans : NadekoModule
|
||||
{
|
||||
public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; set; } = new ConcurrentDictionary<ulong, List<ClashWar>>();
|
||||
|
||||
private static Timer checkWarTimer { get; }
|
||||
|
||||
private static new readonly Logger _log;
|
||||
|
||||
static ClashOfClans()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
var sw = Stopwatch.StartNew();
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
ClashWars = new ConcurrentDictionary<ulong, List<ClashWar>>(
|
||||
@ -73,7 +69,11 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
try
|
||||
{
|
||||
SaveWar(war);
|
||||
await war.Channel.SendErrorAsync($"❗🔰**Claim from @{Bases[i].CallUser} for a war against {war.ShortPrint()} has expired.**").ConfigureAwait(false);
|
||||
await war.Channel.SendErrorAsync(GetTextStatic("claim_expired",
|
||||
NadekoBot.Localization.GetCultureInfo(war.Channel.GuildId),
|
||||
typeof(ClashOfClans).Name.ToLowerInvariant(),
|
||||
Format.Bold(Bases[i].CallUser),
|
||||
war.ShortPrint()));
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
@ -92,7 +92,7 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
|
||||
if (size < 10 || size > 50 || size % 5 != 0)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("🔰 Not a Valid war size").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("invalid_size").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
List<ClashWar> wars;
|
||||
@ -107,7 +107,7 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
var cw = await CreateWar(enemyClan, size, Context.Guild.Id, Context.Channel.Id);
|
||||
|
||||
wars.Add(cw);
|
||||
await Context.Channel.SendConfirmAsync($"❗🔰**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("war_created", cw.ShortPrint()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -120,18 +120,18 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
var warsInfo = GetWarInfo(Context.Guild, num);
|
||||
if (warsInfo == null)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("🔰 **That war does not exist.**").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("war_not_exist").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var war = warsInfo.Item1[warsInfo.Item2];
|
||||
try
|
||||
{
|
||||
war.Start();
|
||||
await Context.Channel.SendConfirmAsync($"🔰**STARTED WAR AGAINST {war.ShortPrint()}**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("war_started", war.ShortPrint()).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"🔰**WAR AGAINST {war.ShortPrint()} HAS ALREADY STARTED**").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("war_already_started", war.ShortPrint()).ConfigureAwait(false);
|
||||
}
|
||||
SaveWar(war);
|
||||
}
|
||||
@ -149,22 +149,20 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
ClashWars.TryGetValue(Context.Guild.Id, out wars);
|
||||
if (wars == null || wars.Count == 0)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("🔰 **No active wars.**").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("no_active_wars").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("🔰 **LIST OF ACTIVE WARS**");
|
||||
sb.AppendLine("**-------------------------**");
|
||||
for (var i = 0; i < wars.Count; i++)
|
||||
{
|
||||
sb.AppendLine($"**#{i + 1}.** `Enemy:` **{wars[i].EnemyClan}**");
|
||||
sb.AppendLine($"\t\t`Size:` **{wars[i].Size} v {wars[i].Size}**");
|
||||
sb.AppendLine($"**#{i + 1}.** `{GetText("enemy")}:` **{wars[i].EnemyClan}**");
|
||||
sb.AppendLine($"\t\t`{GetText("size")}:` **{wars[i].Size} v {wars[i].Size}**");
|
||||
sb.AppendLine("**-------------------------**");
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync(sb.ToString()).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync(GetText("list_active_wars"), sb.ToString()).ConfigureAwait(false);
|
||||
return;
|
||||
|
||||
}
|
||||
var num = 0;
|
||||
int.TryParse(number, out num);
|
||||
@ -172,10 +170,11 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
var warsInfo = GetWarInfo(Context.Guild, num);
|
||||
if (warsInfo == null)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("🔰 **That war does not exist.**").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("war_not_exist").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync(warsInfo.Item1[warsInfo.Item2].ToPrettyString()).ConfigureAwait(false);
|
||||
var war = warsInfo.Item1[warsInfo.Item2];
|
||||
await Context.Channel.SendConfirmAsync(war.Localize("info_about_war", $"`{war.EnemyClan}` ({war.Size} v {war.Size})"), war.ToPrettyString()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -185,7 +184,7 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
var warsInfo = GetWarInfo(Context.Guild, number);
|
||||
if (warsInfo == null || warsInfo.Item1.Count == 0)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("🔰 **That war does not exist.**").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("war_not_exist").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var usr =
|
||||
@ -197,11 +196,11 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
var war = warsInfo.Item1[warsInfo.Item2];
|
||||
war.Call(usr, baseNumber - 1);
|
||||
SaveWar(war);
|
||||
await Context.Channel.SendConfirmAsync($"🔰**{usr}** claimed a base #{baseNumber} for a war against {war.ShortPrint()}").ConfigureAwait(false);
|
||||
await ConfirmLocalized("claimed_base", Format.Bold(usr.ToString()), baseNumber, war.ShortPrint()).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"🔰 {ex.Message}").ConfigureAwait(false);
|
||||
await Context.Channel.SendErrorAsync(ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,15 +232,14 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
var warsInfo = GetWarInfo(Context.Guild, number);
|
||||
if (warsInfo == null)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("🔰 That war does not exist.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("war_not_exist").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var war = warsInfo.Item1[warsInfo.Item2];
|
||||
war.End();
|
||||
SaveWar(war);
|
||||
await Context.Channel.SendConfirmAsync($"❗🔰**War against {warsInfo.Item1[warsInfo.Item2].ShortPrint()} ended.**").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("war_ended", warsInfo.Item1[warsInfo.Item2].ShortPrint()).ConfigureAwait(false);
|
||||
|
||||
var size = warsInfo.Item1[warsInfo.Item2].Size;
|
||||
warsInfo.Item1.RemoveAt(warsInfo.Item2);
|
||||
}
|
||||
|
||||
@ -252,7 +250,7 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
var warsInfo = GetWarInfo(Context.Guild, number);
|
||||
if (warsInfo == null || warsInfo.Item1.Count == 0)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("🔰 **That war does not exist.**").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("war_not_exist").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var usr =
|
||||
@ -264,11 +262,11 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
var war = warsInfo.Item1[warsInfo.Item2];
|
||||
var baseNumber = war.Uncall(usr);
|
||||
SaveWar(war);
|
||||
await Context.Channel.SendConfirmAsync($"🔰 @{usr} has **UNCLAIMED** a base #{baseNumber + 1} from a war against {war.ShortPrint()}").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("base_unclaimed", usr, baseNumber + 1, war.ShortPrint()).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"🔰 {ex.Message}").ConfigureAwait(false);
|
||||
await Context.Channel.SendErrorAsync(ex.Message).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,7 +275,7 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
var warInfo = GetWarInfo(Context.Guild, number);
|
||||
if (warInfo == null || warInfo.Item1.Count == 0)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("🔰 **That war does not exist.**").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("war_not_exist").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var war = warInfo.Item1[warInfo.Item2];
|
||||
@ -292,7 +290,7 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
{
|
||||
war.FinishClaim(baseNumber, stars);
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync($"❗🔰{Context.User.Mention} **DESTROYED** a base #{baseNumber + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("base_destroyed", baseNumber +1, war.ShortPrint()).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -27,13 +27,13 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
public static void Call(this ClashWar cw, string u, int baseNumber)
|
||||
{
|
||||
if (baseNumber < 0 || baseNumber >= cw.Bases.Count)
|
||||
throw new ArgumentException("Invalid base number");
|
||||
throw new ArgumentException(cw.Localize("invalid_base_number"));
|
||||
if (cw.Bases[baseNumber].CallUser != null && cw.Bases[baseNumber].Stars == 3)
|
||||
throw new ArgumentException("That base is already destroyed.");
|
||||
throw new ArgumentException(cw.Localize("base_already_claimed"));
|
||||
for (var i = 0; i < cw.Bases.Count; i++)
|
||||
{
|
||||
if (cw.Bases[i]?.BaseDestroyed == false && cw.Bases[i]?.CallUser == u)
|
||||
throw new ArgumentException($"@{u} You already claimed base #{i + 1}. You can't claim a new one.");
|
||||
throw new ArgumentException(cw.Localize("claimed_other", u, i + 1));
|
||||
}
|
||||
|
||||
var cc = cw.Bases[baseNumber];
|
||||
@ -45,7 +45,7 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
public static void Start(this ClashWar cw)
|
||||
{
|
||||
if (cw.WarState == StateOfWar.Started)
|
||||
throw new InvalidOperationException("War already started");
|
||||
throw new InvalidOperationException("war_already_started");
|
||||
//if (Started)
|
||||
// throw new InvalidOperationException();
|
||||
//Started = true;
|
||||
@ -66,7 +66,7 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
cw.Bases[i].CallUser = null;
|
||||
return i;
|
||||
}
|
||||
throw new InvalidOperationException("You are not participating in that war.");
|
||||
throw new InvalidOperationException(cw.Localize("not_partic"));
|
||||
}
|
||||
|
||||
public static string ShortPrint(this ClashWar cw) =>
|
||||
@ -76,7 +76,6 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine($"🔰**WAR AGAINST `{cw.EnemyClan}` ({cw.Size} v {cw.Size}) INFO:**");
|
||||
if (cw.WarState == StateOfWar.Created)
|
||||
sb.AppendLine("`not started`");
|
||||
var twoHours = new TimeSpan(2, 0, 0);
|
||||
@ -84,7 +83,7 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
{
|
||||
if (cw.Bases[i].CallUser == null)
|
||||
{
|
||||
sb.AppendLine($"`{i + 1}.` ❌*unclaimed*");
|
||||
sb.AppendLine($"`{i + 1}.` ❌*{cw.Localize("not_claimed")}*");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -120,7 +119,7 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
cw.Bases[i].Stars = stars;
|
||||
return i;
|
||||
}
|
||||
throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base.");
|
||||
throw new InvalidOperationException(cw.Localize("not_partic_or_destroyed", user));
|
||||
}
|
||||
|
||||
public static void FinishClaim(this ClashWar cw, int index, int stars = 3)
|
||||
@ -128,10 +127,22 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
if (index < 0 || index > cw.Bases.Count)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
var toFinish = cw.Bases[index];
|
||||
if (toFinish.BaseDestroyed != false) throw new InvalidOperationException("That base is already destroyed.");
|
||||
if (toFinish.CallUser == null) throw new InvalidOperationException("That base is unclaimed.");
|
||||
if (toFinish.BaseDestroyed != false) throw new InvalidOperationException(cw.Localize("base_already_destroyed"));
|
||||
if (toFinish.CallUser == null) throw new InvalidOperationException(cw.Localize("base_already_unclaimed"));
|
||||
toFinish.BaseDestroyed = true;
|
||||
toFinish.Stars = stars;
|
||||
}
|
||||
|
||||
public static string Localize(this ClashWar cw, string key)
|
||||
{
|
||||
return NadekoModule.GetTextStatic(key,
|
||||
NadekoBot.Localization.GetCultureInfo(cw.Channel?.GuildId),
|
||||
typeof(ClashOfClans).Name.ToLowerInvariant());
|
||||
}
|
||||
|
||||
public static string Localize(this ClashWar cw, string key, params object[] replacements)
|
||||
{
|
||||
return string.Format(cw.Localize(key), replacements);
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ using NadekoBot.DataStructures;
|
||||
namespace NadekoBot.Modules.CustomReactions
|
||||
{
|
||||
[NadekoModule("CustomReactions", ".")]
|
||||
public class CustomReactions : DiscordModule
|
||||
public class CustomReactions : NadekoModule
|
||||
{
|
||||
private static CustomReaction[] _globalReactions = new CustomReaction[] { };
|
||||
public static CustomReaction[] GlobalReactions => _globalReactions;
|
||||
@ -139,7 +139,7 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
|
||||
if ((channel == null && !NadekoBot.Credentials.IsOwner(Context.User)) || (channel != null && !((IGuildUser)Context.User).GuildPermissions.Administrator))
|
||||
{
|
||||
try { await Context.Channel.SendErrorAsync("Insufficient permissions. Requires Bot ownership for global custom reactions, and Administrator for guild custom reactions."); } catch { }
|
||||
await ReplyErrorLocalized("insuff_perms").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -165,8 +165,8 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
}
|
||||
else
|
||||
{
|
||||
var reactions = GuildReactions.AddOrUpdate(Context.Guild.Id,
|
||||
Array.Empty<CustomReaction>(),
|
||||
GuildReactions.AddOrUpdate(Context.Guild.Id,
|
||||
new CustomReaction[] { cr },
|
||||
(k, old) =>
|
||||
{
|
||||
Array.Resize(ref old, old.Length + 1);
|
||||
@ -176,10 +176,10 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
}
|
||||
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithTitle("New Custom Reaction")
|
||||
.WithTitle(GetText("new_cust_react"))
|
||||
.WithDescription($"#{cr.Id}")
|
||||
.AddField(efb => efb.WithName("Trigger").WithValue(key))
|
||||
.AddField(efb => efb.WithName("Response").WithValue(message))
|
||||
.AddField(efb => efb.WithName(GetText("trigger")).WithValue(key))
|
||||
.AddField(efb => efb.WithName(GetText("response")).WithValue(message))
|
||||
).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@ -196,20 +196,21 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, Array.Empty<CustomReaction>()).Where(cr => cr != null).ToArray();
|
||||
|
||||
if (customReactions == null || !customReactions.Any())
|
||||
await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false);
|
||||
else
|
||||
{
|
||||
await ReplyErrorLocalized("no_found").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var lastPage = customReactions.Length / 20;
|
||||
await Context.Channel.SendPaginatedConfirmAsync(page, curPage =>
|
||||
new EmbedBuilder().WithOkColor()
|
||||
.WithTitle("Custom reactions")
|
||||
.WithTitle(GetText("name"))
|
||||
.WithDescription(string.Join("\n", customReactions.OrderBy(cr => cr.Trigger)
|
||||
.Skip((curPage - 1) * 20)
|
||||
.Take(20)
|
||||
.Select(cr => $"`#{cr.Id}` `Trigger:` {cr.Trigger}"))), lastPage)
|
||||
.Select(cr => $"`#{cr.Id}` `{GetText("trigger")}:` {cr.Trigger}"))), lastPage)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public enum All
|
||||
{
|
||||
@ -227,20 +228,22 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray();
|
||||
|
||||
if (customReactions == null || !customReactions.Any())
|
||||
await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false);
|
||||
else
|
||||
{
|
||||
await ReplyErrorLocalized("no_found").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var txtStream = await customReactions.GroupBy(cr => cr.Trigger)
|
||||
.OrderBy(cr => cr.Key)
|
||||
.Select(cr => new { Trigger = cr.Key, Responses = cr.Select(y => new { id = y.Id, text = y.Response }).ToList() })
|
||||
.ToJson()
|
||||
.ToStream()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (Context.Guild == null) // its a private one, just send back
|
||||
await Context.Channel.SendFileAsync(txtStream, "customreactions.txt", "List of all custom reactions").ConfigureAwait(false);
|
||||
await Context.Channel.SendFileAsync(txtStream, "customreactions.txt", GetText("list_all")).ConfigureAwait(false);
|
||||
else
|
||||
await ((IGuildUser)Context.User).SendFileAsync(txtStream, "customreactions.txt", "List of all custom reactions").ConfigureAwait(false);
|
||||
}
|
||||
await ((IGuildUser)Context.User).SendFileAsync(txtStream, "customreactions.txt", GetText("list_all")).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -255,7 +258,9 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
customReactions = GuildReactions.GetOrAdd(Context.Guild.Id, new CustomReaction[]{ }).Where(cr => cr != null).ToArray();
|
||||
|
||||
if (customReactions == null || !customReactions.Any())
|
||||
await Context.Channel.SendErrorAsync("No custom reactions found").ConfigureAwait(false);
|
||||
{
|
||||
await ReplyErrorLocalized("no_found").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var ordered = customReactions
|
||||
@ -266,7 +271,7 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
var lastPage = ordered.Count / 20;
|
||||
await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) =>
|
||||
new EmbedBuilder().WithOkColor()
|
||||
.WithTitle($"Custom Reactions (grouped)")
|
||||
.WithTitle(GetText("name"))
|
||||
.WithDescription(string.Join("\r\n", ordered
|
||||
.Skip((curPage - 1) * 20)
|
||||
.Take(20)
|
||||
@ -287,13 +292,16 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
var found = customReactions.FirstOrDefault(cr => cr?.Id == id);
|
||||
|
||||
if (found == null)
|
||||
await Context.Channel.SendErrorAsync("No custom reaction found with that id.").ConfigureAwait(false);
|
||||
{
|
||||
await ReplyErrorLocalized("no_found_id").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(efb => efb.WithName("Trigger").WithValue(found.Trigger))
|
||||
.AddField(efb => efb.WithName("Response").WithValue(found.Response + "\n```css\n" + found.Response + "```"))
|
||||
.AddField(efb => efb.WithName(GetText("trigger")).WithValue(found.Trigger))
|
||||
.AddField(efb => efb.WithName(GetText("response")).WithValue(found.Response + "\n```css\n" + found.Response + "```"))
|
||||
).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@ -303,7 +311,7 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
{
|
||||
if ((Context.Guild == null && !NadekoBot.Credentials.IsOwner(Context.User)) || (Context.Guild != null && !((IGuildUser)Context.User).GuildPermissions.Administrator))
|
||||
{
|
||||
try { await Context.Channel.SendErrorAsync("Insufficient permissions. Requires Bot ownership for global custom reactions, and Administrator for guild custom reactions."); } catch { }
|
||||
await ReplyErrorLocalized("insuff_perms").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -313,8 +321,9 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
{
|
||||
toDelete = uow.CustomReactions.Get(id);
|
||||
if (toDelete == null) //not found
|
||||
return;
|
||||
|
||||
success = false;
|
||||
else
|
||||
{
|
||||
if ((toDelete.GuildId == null || toDelete.GuildId == 0) && Context.Guild == null)
|
||||
{
|
||||
uow.CustomReactions.Remove(toDelete);
|
||||
@ -334,11 +343,20 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
if (success)
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
await Context.Channel.SendConfirmAsync("Deleted custom reaction", toDelete.ToString()).ConfigureAwait(false);
|
||||
{
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithTitle(GetText("deleted"))
|
||||
.WithDescription("#" + toDelete.Id)
|
||||
.AddField(efb => efb.WithName(GetText("trigger")).WithValue(toDelete.Trigger))
|
||||
.AddField(efb => efb.WithName(GetText("response")).WithValue(toDelete.Response)));
|
||||
}
|
||||
else
|
||||
await Context.Channel.SendErrorAsync("Failed to find that custom reaction.").ConfigureAwait(false);
|
||||
{
|
||||
await ReplyErrorLocalized("no_found_id").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -348,18 +366,18 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
if (string.IsNullOrWhiteSpace(trigger))
|
||||
{
|
||||
ClearStats();
|
||||
await Context.Channel.SendConfirmAsync($"Custom reaction stats cleared.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("all_stats_cleared").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint throwaway;
|
||||
if (ReactionStats.TryRemove(trigger, out throwaway))
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync($"Stats cleared for `{trigger}` custom reaction.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("stats_cleared", Format.Bold(trigger)).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("No stats for that trigger found, no action taken.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("stats_not_found").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -376,7 +394,7 @@ namespace NadekoBot.Modules.CustomReactions
|
||||
await Context.Channel.SendPaginatedConfirmAsync(page,
|
||||
(curPage) => ordered.Skip((curPage - 1) * 9)
|
||||
.Take(9)
|
||||
.Aggregate(new EmbedBuilder().WithOkColor().WithTitle($"Custom Reaction Stats"),
|
||||
.Aggregate(new EmbedBuilder().WithOkColor().WithTitle(GetText("stats")),
|
||||
(agg, cur) => agg.AddField(efb => efb.WithName(cur.Key).WithValue(cur.Value.ToString()).WithIsInline(true))), lastPage)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NLog;
|
||||
|
||||
namespace NadekoBot.Modules
|
||||
{
|
||||
public abstract class DiscordModule : ModuleBase
|
||||
{
|
||||
protected Logger _log { get; }
|
||||
protected string _prefix { get; }
|
||||
|
||||
public DiscordModule()
|
||||
{
|
||||
string prefix;
|
||||
if (NadekoBot.ModulePrefixes.TryGetValue(this.GetType().Name, out prefix))
|
||||
_prefix = prefix;
|
||||
else
|
||||
_prefix = "?missing_prefix?";
|
||||
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
public partial class Gambling
|
||||
{
|
||||
[Group]
|
||||
public class AnimalRacing : ModuleBase
|
||||
public class AnimalRacing : NadekoSubmodule
|
||||
{
|
||||
public static ConcurrentDictionary<ulong, AnimalRace> AnimalRaces { get; } = new ConcurrentDictionary<ulong, AnimalRace>();
|
||||
|
||||
@ -25,7 +25,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Race()
|
||||
{
|
||||
var ar = new AnimalRace(Context.Guild.Id, (ITextChannel)Context.Channel);
|
||||
var ar = new AnimalRace(Context.Guild.Id, (ITextChannel)Context.Channel, Prefix);
|
||||
|
||||
if (ar.Fail)
|
||||
await Context.Channel.SendErrorAsync("🏁 `Failed starting a race. Another race is probably running.`").ConfigureAwait(false);
|
||||
@ -59,13 +59,16 @@ namespace NadekoBot.Modules.Gambling
|
||||
public List<Participant> participants = new List<Participant>();
|
||||
private ulong serverId;
|
||||
private int messagesSinceGameStarted = 0;
|
||||
private readonly string _prefix;
|
||||
|
||||
private Logger _log { get; }
|
||||
|
||||
public ITextChannel raceChannel { get; set; }
|
||||
public bool Started { get; private set; } = false;
|
||||
|
||||
public AnimalRace(ulong serverId, ITextChannel ch)
|
||||
public AnimalRace(ulong serverId, ITextChannel ch, string prefix)
|
||||
{
|
||||
this._prefix = prefix;
|
||||
this._log = LogManager.GetCurrentClassLogger();
|
||||
this.serverId = serverId;
|
||||
this.raceChannel = ch;
|
||||
@ -75,10 +78,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
return;
|
||||
}
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
animals = new ConcurrentQueue<string>(NadekoBot.BotConfig.RaceAnimals.Select(ra => ra.Icon).Shuffle());
|
||||
}
|
||||
|
||||
|
||||
var cancelSource = new CancellationTokenSource();
|
||||
@ -91,7 +91,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
try
|
||||
{
|
||||
await raceChannel.SendConfirmAsync("Animal Race", $"Starting in 20 seconds or when the room is full.",
|
||||
footer: $"Type {NadekoBot.ModulePrefixes[typeof(Gambling).Name]}jr to join the race.");
|
||||
footer: $"Type {_prefix}jr to join the race.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -280,9 +280,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var p = obj as Participant;
|
||||
return p == null ?
|
||||
false :
|
||||
p.User == User;
|
||||
return p != null && p.User == User;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
@ -5,12 +5,9 @@ using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Services.Database;
|
||||
using System.Threading;
|
||||
using NLog;
|
||||
|
||||
@ -19,7 +16,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
public partial class Gambling
|
||||
{
|
||||
[Group]
|
||||
public class CurrencyEvents : ModuleBase
|
||||
public class CurrencyEvents : NadekoSubmodule
|
||||
{
|
||||
public enum CurrencyEvent
|
||||
{
|
||||
@ -27,7 +24,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
SneakyGameStatus
|
||||
}
|
||||
//flower reaction event
|
||||
public static readonly ConcurrentHashSet<ulong> _sneakyGameAwardedUsers = new ConcurrentHashSet<ulong>();
|
||||
private static readonly ConcurrentHashSet<ulong> _sneakyGameAwardedUsers = new ConcurrentHashSet<ulong>();
|
||||
|
||||
|
||||
private static readonly char[] _sneakyGameStatusChars = Enumerable.Range(48, 10)
|
||||
@ -36,15 +33,12 @@ namespace NadekoBot.Modules.Gambling
|
||||
.Select(x => (char)x)
|
||||
.ToArray();
|
||||
|
||||
private static string _secretCode = String.Empty;
|
||||
private static string _secretCode = string.Empty;
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[OwnerOnly]
|
||||
public async Task StartEvent(CurrencyEvent e, int arg = -1)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
try
|
||||
{
|
||||
switch (e)
|
||||
{
|
||||
@ -54,14 +48,10 @@ namespace NadekoBot.Modules.Gambling
|
||||
case CurrencyEvent.SneakyGameStatus:
|
||||
await SneakyGameStatusEvent(Context, arg).ConfigureAwait(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public static async Task SneakyGameStatusEvent(CommandContext Context, int? arg)
|
||||
public async Task SneakyGameStatusEvent(CommandContext context, int? arg)
|
||||
{
|
||||
int num;
|
||||
if (arg == null || arg < 5)
|
||||
@ -69,26 +59,27 @@ namespace NadekoBot.Modules.Gambling
|
||||
else
|
||||
num = arg.Value;
|
||||
|
||||
if (_secretCode != String.Empty)
|
||||
if (_secretCode != string.Empty)
|
||||
return;
|
||||
var rng = new NadekoRandom();
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
_secretCode += _sneakyGameStatusChars[rng.Next(0, _sneakyGameStatusChars.Length)];
|
||||
}
|
||||
|
||||
var game = NadekoBot.Client.Game?.Name;
|
||||
await NadekoBot.Client.SetGameAsync($"type {_secretCode} for " + NadekoBot.BotConfig.CurrencyPluralName)
|
||||
.ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync($"SneakyGameStatus event started",
|
||||
$"Users must type a secret code to get 100 currency.\n" +
|
||||
$"Lasts {num} seconds. Don't tell anyone. Shhh.")
|
||||
.ConfigureAwait(false);
|
||||
var title = GetText("sneakygamestatus_title");
|
||||
var desc = GetText("sneakygamestatus_desc", Format.Bold(100.ToString()) + CurrencySign, Format.Bold(num.ToString()));
|
||||
await context.Channel.SendConfirmAsync(title, desc).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
catch { }
|
||||
|
||||
|
||||
NadekoBot.Client.MessageReceived += SneakyGameMessageReceivedEventHandler;
|
||||
@ -97,9 +88,9 @@ namespace NadekoBot.Modules.Gambling
|
||||
|
||||
var cnt = _sneakyGameAwardedUsers.Count;
|
||||
_sneakyGameAwardedUsers.Clear();
|
||||
_secretCode = String.Empty;
|
||||
_secretCode = string.Empty;
|
||||
|
||||
await NadekoBot.Client.SetGameAsync($"SneakyGame event ended. {cnt} users received a reward.")
|
||||
await NadekoBot.Client.SetGameAsync(GetText("sneakygamestatus_end", cnt))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@ -114,29 +105,41 @@ namespace NadekoBot.Modules.Gambling
|
||||
.ConfigureAwait(false);
|
||||
|
||||
try { await arg.DeleteAsync(new RequestOptions() { RetryMode = RetryMode.AlwaysFail }).ConfigureAwait(false); }
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Task.Delay(0);
|
||||
}
|
||||
|
||||
public static Task FlowerReactionEvent(CommandContext Context) =>
|
||||
new FlowerReactionEvent().Start(Context);
|
||||
public async Task FlowerReactionEvent(CommandContext context)
|
||||
{
|
||||
var title = GetText("flowerreaction_title");
|
||||
var desc = GetText("flowerreaction_desc", "🌸", Format.Bold(100.ToString()) + CurrencySign);
|
||||
var footer = GetText("flowerreaction_footer", 24);
|
||||
var msg = await context.Channel.SendConfirmAsync(title,
|
||||
desc, footer: footer)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
await new FlowerReactionEvent().Start(msg, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class CurrencyEvent
|
||||
{
|
||||
public abstract Task Start(CommandContext channel);
|
||||
public abstract Task Start(IUserMessage msg, CommandContext channel);
|
||||
}
|
||||
|
||||
public class FlowerReactionEvent : CurrencyEvent
|
||||
{
|
||||
public readonly ConcurrentHashSet<ulong> _flowerReactionAwardedUsers = new ConcurrentHashSet<ulong>();
|
||||
private readonly ConcurrentHashSet<ulong> _flowerReactionAwardedUsers = new ConcurrentHashSet<ulong>();
|
||||
private readonly Logger _log;
|
||||
|
||||
private IUserMessage msg { get; set; } = null;
|
||||
private IUserMessage msg { get; set; }
|
||||
|
||||
private CancellationTokenSource source { get; }
|
||||
private CancellationToken cancelToken { get; }
|
||||
@ -163,19 +166,15 @@ namespace NadekoBot.Modules.Gambling
|
||||
if (msg?.Id == id)
|
||||
{
|
||||
_log.Warn("Stopping flower reaction event because message is deleted.");
|
||||
Task.Run(() => End());
|
||||
var __ = Task.Run(End);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task Start(CommandContext context)
|
||||
public override async Task Start(IUserMessage umsg, CommandContext context)
|
||||
{
|
||||
msg = await context.Channel.SendConfirmAsync("Flower reaction event started!",
|
||||
"Add 🌸 reaction to this message to get 100" + NadekoBot.BotConfig.CurrencySign,
|
||||
footer: "This event is active for up to 24 hours.")
|
||||
.ConfigureAwait(false);
|
||||
|
||||
msg = umsg;
|
||||
NadekoBot.Client.MessageDeleted += MessageDeletedEventHandler;
|
||||
|
||||
try { await msg.AddReactionAsync("🌸").ConfigureAwait(false); }
|
||||
@ -194,10 +193,14 @@ namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
if (r.Emoji.Name == "🌸" && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _flowerReactionAwardedUsers.Add(r.User.Value.Id))
|
||||
{
|
||||
try { await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, false).ConfigureAwait(false); } catch { }
|
||||
await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, false)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}))
|
||||
{
|
||||
try
|
||||
|
@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
public partial class Gambling
|
||||
{
|
||||
[Group]
|
||||
public class DriceRollCommands : ModuleBase
|
||||
public class DriceRollCommands : NadekoSubmodule
|
||||
{
|
||||
private Regex dndRegex { get; } = new Regex(@"^(?<n1>\d+)d(?<n2>\d+)(?:\+(?<add>\d+))?(?:\-(?<sub>\d+))?$", RegexOptions.Compiled);
|
||||
private Regex fudgeRegex { get; } = new Regex(@"^(?<n1>\d+)d(?:F|f)$", RegexOptions.Compiled);
|
||||
|
@ -4,8 +4,6 @@ using ImageSharp;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Gambling.Models;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@ -17,17 +15,17 @@ namespace NadekoBot.Modules.Gambling
|
||||
public partial class Gambling
|
||||
{
|
||||
[Group]
|
||||
public class DrawCommands : ModuleBase
|
||||
public class DrawCommands : NadekoSubmodule
|
||||
{
|
||||
private static readonly ConcurrentDictionary<IGuild, Cards> AllDecks = new ConcurrentDictionary<IGuild, Cards>();
|
||||
private static readonly ConcurrentDictionary<IGuild, Cards> _allDecks = new ConcurrentDictionary<IGuild, Cards>();
|
||||
|
||||
private const string cardsPath = "data/images/cards";
|
||||
private const string _cardsPath = "data/images/cards";
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Draw(int num = 1)
|
||||
{
|
||||
var cards = AllDecks.GetOrAdd(Context.Guild, (s) => new Cards());
|
||||
var cards = _allDecks.GetOrAdd(Context.Guild, (s) => new Cards());
|
||||
var images = new List<Image>();
|
||||
var cardObjects = new List<Cards.Card>();
|
||||
if (num > 5) num = 5;
|
||||
@ -35,12 +33,19 @@ namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
if (cards.CardPool.Count == 0 && i != 0)
|
||||
{
|
||||
try { await Context.Channel.SendErrorAsync("No more cards in a deck.").ConfigureAwait(false); } catch { }
|
||||
try
|
||||
{
|
||||
await ReplyErrorLocalized("no_more_cards").ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
break;
|
||||
}
|
||||
var currentCard = cards.DrawACard();
|
||||
cardObjects.Add(currentCard);
|
||||
using (var stream = File.OpenRead(Path.Combine(cardsPath, currentCard.ToString().ToLowerInvariant()+ ".jpg").Replace(' ','_')))
|
||||
using (var stream = File.OpenRead(Path.Combine(_cardsPath, currentCard.ToString().ToLowerInvariant()+ ".jpg").Replace(' ','_')))
|
||||
images.Add(new Image(stream));
|
||||
}
|
||||
MemoryStream bitmapStream = new MemoryStream();
|
||||
@ -59,7 +64,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
//var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
AllDecks.AddOrUpdate(Context.Guild,
|
||||
_allDecks.AddOrUpdate(Context.Guild,
|
||||
(g) => new Cards(),
|
||||
(g, c) =>
|
||||
{
|
||||
@ -67,7 +72,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
return c;
|
||||
});
|
||||
|
||||
await Context.Channel.SendConfirmAsync("Deck reshuffled.").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("deck_reshuffled").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,10 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using ImageSharp;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Image = ImageSharp.Image;
|
||||
|
||||
@ -15,7 +13,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
public partial class Gambling
|
||||
{
|
||||
[Group]
|
||||
public class FlipCoinCommands : ModuleBase
|
||||
public class FlipCoinCommands : NadekoSubmodule
|
||||
{
|
||||
private readonly IImagesService _images;
|
||||
|
||||
@ -24,7 +22,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
public FlipCoinCommands()
|
||||
{
|
||||
//todo DI in the future, can't atm
|
||||
this._images = NadekoBot.Images;
|
||||
_images = NadekoBot.Images;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -36,21 +34,21 @@ namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
using (var heads = _images.Heads.ToStream())
|
||||
{
|
||||
await Context.Channel.SendFileAsync(heads, "heads.jpg", $"{Context.User.Mention} flipped " + Format.Code("Heads") + ".").ConfigureAwait(false);
|
||||
await Context.Channel.SendFileAsync(heads, "heads.jpg", Context.User.Mention + " " + GetText("flipped", Format.Bold(GetText("heads"))) + ".").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var tails = _images.Tails.ToStream())
|
||||
{
|
||||
await Context.Channel.SendFileAsync(tails, "tails.jpg", $"{Context.User.Mention} flipped " + Format.Code("Tails") + ".").ConfigureAwait(false);
|
||||
await Context.Channel.SendFileAsync(tails, "tails.jpg", Context.User.Mention + " " + GetText("flipped", Format.Bold(GetText("tails"))) + ".").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (count > 10 || count < 1)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("`Invalid number specified. You can flip 1 to 10 coins.`").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("flip_invalid", 10).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var imgs = new Image[count];
|
||||
@ -76,14 +74,13 @@ namespace NadekoBot.Modules.Gambling
|
||||
|
||||
if (amount < NadekoBot.BotConfig.MinimumBetAmount)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"You can't bet less than {NadekoBot.BotConfig.MinimumBetAmount}{CurrencySign}.")
|
||||
.ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("min_bet_limit", NadekoBot.BotConfig.MinimumBetAmount + CurrencySign).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var removed = await CurrencyHandler.RemoveCurrencyAsync(Context.User, "Betflip Gamble", amount, false).ConfigureAwait(false);
|
||||
if (!removed)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {CurrencyPluralName}.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("not_enough", CurrencyPluralName).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
//heads = true
|
||||
@ -91,7 +88,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
|
||||
//todo this seems stinky, no time to look at it right now
|
||||
var isHeads = guessStr == "HEADS" || guessStr == "H";
|
||||
bool result = false;
|
||||
var result = false;
|
||||
IEnumerable<byte> imageToSend;
|
||||
if (rng.Next(0, 2) == 1)
|
||||
{
|
||||
@ -107,12 +104,12 @@ namespace NadekoBot.Modules.Gambling
|
||||
if (isHeads == result)
|
||||
{
|
||||
var toWin = (int)Math.Round(amount * NadekoBot.BotConfig.BetflipMultiplier);
|
||||
str = $"{Context.User.Mention}`You guessed it!` You won {toWin}{CurrencySign}";
|
||||
await CurrencyHandler.AddCurrencyAsync(Context.User, "Betflip Gamble", toWin, false).ConfigureAwait(false);
|
||||
str = Context.User.Mention + " " + GetText("flip_guess", toWin + CurrencySign);
|
||||
await CurrencyHandler.AddCurrencyAsync(Context.User, GetText("betflip_gamble"), toWin, false).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
str = $"{Context.User.Mention}`Better luck next time.`";
|
||||
str = Context.User.Mention + " " + GetText("better_luck");
|
||||
}
|
||||
using (var toSend = imageToSend.ToStream())
|
||||
{
|
||||
|
@ -5,7 +5,6 @@ using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
@ -16,12 +15,12 @@ namespace NadekoBot.Modules.Gambling
|
||||
public partial class Gambling
|
||||
{
|
||||
[Group]
|
||||
public class Slots : ModuleBase
|
||||
public class Slots : NadekoSubmodule
|
||||
{
|
||||
private static int totalBet = 0;
|
||||
private static int totalPaidOut = 0;
|
||||
private static int _totalBet;
|
||||
private static int _totalPaidOut;
|
||||
|
||||
const int alphaCutOut = byte.MaxValue / 3;
|
||||
private const int _alphaCutOut = byte.MaxValue / 3;
|
||||
|
||||
//here is a payout chart
|
||||
//https://lh6.googleusercontent.com/-i1hjAJy_kN4/UswKxmhrbPI/AAAAAAAAB1U/82wq_4ZZc-Y/DE6B0895-6FC1-48BE-AC4F-14D1B91AB75B.jpg
|
||||
@ -31,14 +30,14 @@ namespace NadekoBot.Modules.Gambling
|
||||
|
||||
public Slots()
|
||||
{
|
||||
this._images = NadekoBot.Images;
|
||||
_images = NadekoBot.Images;
|
||||
}
|
||||
|
||||
public class SlotMachine
|
||||
{
|
||||
public const int MaxValue = 5;
|
||||
|
||||
static readonly List<Func<int[], int>> winningCombos = new List<Func<int[], int>>()
|
||||
static readonly List<Func<int[], int>> _winningCombos = new List<Func<int[], int>>()
|
||||
{
|
||||
//three flowers
|
||||
(arr) => arr.All(a=>a==MaxValue) ? 30 : 0,
|
||||
@ -53,14 +52,14 @@ namespace NadekoBot.Modules.Gambling
|
||||
public static SlotResult Pull()
|
||||
{
|
||||
var numbers = new int[3];
|
||||
for (int i = 0; i < numbers.Length; i++)
|
||||
for (var i = 0; i < numbers.Length; i++)
|
||||
{
|
||||
numbers[i] = new NadekoRandom().Next(0, MaxValue + 1);
|
||||
}
|
||||
int multi = 0;
|
||||
for (int i = 0; i < winningCombos.Count; i++)
|
||||
var multi = 0;
|
||||
foreach (var t in _winningCombos)
|
||||
{
|
||||
multi = winningCombos[i](numbers);
|
||||
multi = t(numbers);
|
||||
if (multi != 0)
|
||||
break;
|
||||
}
|
||||
@ -74,8 +73,8 @@ namespace NadekoBot.Modules.Gambling
|
||||
public int Multiplier { get; }
|
||||
public SlotResult(int[] nums, int multi)
|
||||
{
|
||||
this.Numbers = nums;
|
||||
this.Multiplier = multi;
|
||||
Numbers = nums;
|
||||
Multiplier = multi;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -85,8 +84,8 @@ namespace NadekoBot.Modules.Gambling
|
||||
public async Task SlotStats()
|
||||
{
|
||||
//i remembered to not be a moron
|
||||
var paid = totalPaidOut;
|
||||
var bet = totalBet;
|
||||
var paid = _totalPaidOut;
|
||||
var bet = _totalBet;
|
||||
|
||||
if (bet <= 0)
|
||||
bet = 1;
|
||||
@ -130,33 +129,34 @@ namespace NadekoBot.Modules.Gambling
|
||||
footer: $"Total Bet: {tests * bet} | Payout: {payout * bet} | {payout * 1.0f / tests * 100}%");
|
||||
}
|
||||
|
||||
static HashSet<ulong> runningUsers = new HashSet<ulong>();
|
||||
private static readonly HashSet<ulong> _runningUsers = new HashSet<ulong>();
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Slot(int amount = 0)
|
||||
{
|
||||
if (!runningUsers.Add(Context.User.Id))
|
||||
if (!_runningUsers.Add(Context.User.Id))
|
||||
return;
|
||||
try
|
||||
{
|
||||
if (amount < 1)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"You can't bet less than 1{NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("min_bet_limit", 1 + CurrencySign).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (amount > 999)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"You can't bet more than 999{NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false);
|
||||
GetText("slot_maxbet", 999 + CurrencySign);
|
||||
await ReplyErrorLocalized("max_bet_limit", 999 + CurrencySign).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User, "Slot Machine", amount, false))
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"You don't have enough {NadekoBot.BotConfig.CurrencySign}.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("not_enough", CurrencySign).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
Interlocked.Add(ref totalBet, amount);
|
||||
Interlocked.Add(ref _totalBet, amount);
|
||||
using (var bgFileStream = NadekoBot.Images.SlotBackground.ToStream())
|
||||
{
|
||||
var bgImage = new ImageSharp.Image(bgFileStream);
|
||||
@ -179,7 +179,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
var x = 95 + 142 * i + j;
|
||||
int y = 330 + k;
|
||||
var toSet = toAdd[j, k];
|
||||
if (toSet.A < alphaCutOut)
|
||||
if (toSet.A < _alphaCutOut)
|
||||
continue;
|
||||
bgPixels[x, y] = toAdd[j, k];
|
||||
}
|
||||
@ -203,7 +203,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
for (int j = 0; j < pixels.Height; j++)
|
||||
{
|
||||
if (pixels[i, j].A < alphaCutOut)
|
||||
if (pixels[i, j].A < _alphaCutOut)
|
||||
continue;
|
||||
var x = 230 - n * 16 + i;
|
||||
bgPixels[x, 462 + j] = pixels[i, j];
|
||||
@ -228,7 +228,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
for (int j = 0; j < pixels.Height; j++)
|
||||
{
|
||||
if (pixels[i, j].A < alphaCutOut)
|
||||
if (pixels[i, j].A < _alphaCutOut)
|
||||
continue;
|
||||
var x = 395 - n * 16 + i;
|
||||
bgPixels[x, 462 + j] = pixels[i, j];
|
||||
@ -240,30 +240,30 @@ namespace NadekoBot.Modules.Gambling
|
||||
} while ((printAmount /= 10) != 0);
|
||||
}
|
||||
|
||||
var msg = "Better luck next time ^_^";
|
||||
var msg = GetText("better_luck");
|
||||
if (result.Multiplier != 0)
|
||||
{
|
||||
await CurrencyHandler.AddCurrencyAsync(Context.User, $"Slot Machine x{result.Multiplier}", amount * result.Multiplier, false);
|
||||
Interlocked.Add(ref totalPaidOut, amount * result.Multiplier);
|
||||
Interlocked.Add(ref _totalPaidOut, amount * result.Multiplier);
|
||||
if (result.Multiplier == 1)
|
||||
msg = $"A single {NadekoBot.BotConfig.CurrencySign}, x1 - Try again!";
|
||||
msg = GetText("slot_single", CurrencySign, 1);
|
||||
else if (result.Multiplier == 4)
|
||||
msg = $"Good job! Two {NadekoBot.BotConfig.CurrencySign} - bet x4";
|
||||
msg = GetText("slot_two", CurrencySign, 4);
|
||||
else if (result.Multiplier == 10)
|
||||
msg = "Wow! Lucky! Three of a kind! x10";
|
||||
msg = GetText("slot_three", 10);
|
||||
else if (result.Multiplier == 30)
|
||||
msg = "WOAAHHHHHH!!! Congratulations!!! x30";
|
||||
msg = GetText("slot_jackpot", 30);
|
||||
}
|
||||
|
||||
await Context.Channel.SendFileAsync(bgImage.ToStream(), "result.png", Context.User.Mention + " " + msg + $"\n`Bet:`{amount} `Won:` {amount * result.Multiplier}{NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false);
|
||||
await Context.Channel.SendFileAsync(bgImage.ToStream(), "result.png", Context.User.Mention + " " + msg + $"\n`{GetText("slot_bet")}:`{amount} `{GetText("slot_won")}:` {amount * result.Multiplier}{NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
var t = Task.Run(async () =>
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(2000);
|
||||
runningUsers.Remove(Context.User.Id);
|
||||
_runningUsers.Remove(Context.User.Id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
}
|
||||
|
||||
[Group]
|
||||
public class WaifuClaimCommands : ModuleBase
|
||||
public class WaifuClaimCommands : NadekoSubmodule
|
||||
{
|
||||
private static ConcurrentDictionary<ulong, DateTime> _divorceCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
||||
private static ConcurrentDictionary<ulong, DateTime> _affinityCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
||||
@ -197,8 +197,6 @@ namespace NadekoBot.Modules.Gambling
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Divorce([Remainder]IUser target)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
if (target.Id == Context.User.Id)
|
||||
return;
|
||||
|
||||
@ -423,7 +421,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle("Waifu " + w.Waifu.ToString() + " - \"the " + claimInfo.Title + "\"")
|
||||
.WithTitle("Waifu " + w.Waifu + " - \"the " + claimInfo.Title + "\"")
|
||||
.AddField(efb => efb.WithName("Price").WithValue(w.Price.ToString()).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName("Claimed by").WithValue(w.Claimer?.ToString() ?? "No one").WithIsInline(true))
|
||||
.AddField(efb => efb.WithName("Likes").WithValue(w.Affinity?.ToString() ?? "Nobody").WithIsInline(true))
|
||||
|
@ -1,9 +1,9 @@
|
||||
using Discord;
|
||||
using System;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Attributes;
|
||||
using NadekoBot.Extensions;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
@ -12,7 +12,7 @@ using System.Collections.Generic;
|
||||
namespace NadekoBot.Modules.Gambling
|
||||
{
|
||||
[NadekoModule("Gambling", "$")]
|
||||
public partial class Gambling : DiscordModule
|
||||
public partial class Gambling : NadekoModule
|
||||
{
|
||||
public static string CurrencyName { get; set; }
|
||||
public static string CurrencyPluralName { get; set; }
|
||||
@ -42,7 +42,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
var members = role.Members().Where(u => u.Status != UserStatus.Offline && u.Status != UserStatus.Unknown);
|
||||
var membersArray = members as IUser[] ?? members.ToArray();
|
||||
var usr = membersArray[new NadekoRandom().Next(0, membersArray.Length)];
|
||||
await Context.Channel.SendConfirmAsync("🎟 Raffled user", $"**{usr.Username}#{usr.Discriminator}**", footer: $"ID: {usr.Id}").ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync("🎟 "+ GetText("raffled_user"), $"**{usr.Username}#{usr.Discriminator}**", footer: $"ID: {usr.Id}").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -50,15 +50,14 @@ namespace NadekoBot.Modules.Gambling
|
||||
public async Task Cash([Remainder] IUser user = null)
|
||||
{
|
||||
user = user ?? Context.User;
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"{user.Username} has {GetCurrency(user.Id)} {CurrencySign}").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("has", Format.Bold(user.ToString()), $"{GetCurrency(user.Id)} {CurrencySign}").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[Priority(1)]
|
||||
public async Task Cash(ulong userId)
|
||||
{
|
||||
await Context.Channel.SendConfirmAsync($"`{userId}` has {GetCurrency(userId)} {CurrencySign}").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("has", Format.Code(userId.ToString()), $"{GetCurrency(userId)} {CurrencySign}").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -70,11 +69,12 @@ namespace NadekoBot.Modules.Gambling
|
||||
var success = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Gift to {receiver.Username} ({receiver.Id}).", amount, false).ConfigureAwait(false);
|
||||
if (!success)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {CurrencyPluralName}.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("not_enough", CurrencyPluralName).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await CurrencyHandler.AddCurrencyAsync(receiver, $"Gift from {Context.User.Username} ({Context.User.Id}).", amount, true).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} gifted {amount}{CurrencySign} to {Format.Bold(receiver.ToString())}!").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("gifted", amount + CurrencySign, Format.Bold(receiver.ToString()))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -93,8 +93,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
return;
|
||||
|
||||
await CurrencyHandler.AddCurrencyAsync(usrId, $"Awarded by bot owner. ({Context.User.Username}/{Context.User.Id})", amount).ConfigureAwait(false);
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} awarded {amount}{CurrencySign} to <@{usrId}>!").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("awarded", amount + CurrencySign, $"<@{usrId}>").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -103,7 +102,6 @@ namespace NadekoBot.Modules.Gambling
|
||||
[Priority(0)]
|
||||
public async Task Award(int amount, [Remainder] IRole role)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
var users = (await Context.Guild.GetUsersAsync())
|
||||
.Where(u => u.GetRoles().Contains(role))
|
||||
.ToList();
|
||||
@ -112,9 +110,10 @@ namespace NadekoBot.Modules.Gambling
|
||||
amount)))
|
||||
.ConfigureAwait(false);
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"Awarded `{amount}` {CurrencyPluralName} to `{users.Count}` users from `{role.Name}` role.")
|
||||
.ConfigureAwait(false);
|
||||
|
||||
await ReplyConfirmLocalized("mass_award",
|
||||
amount + CurrencySign,
|
||||
Format.Bold(users.Count.ToString()),
|
||||
Format.Bold(role.Name)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -126,9 +125,9 @@ namespace NadekoBot.Modules.Gambling
|
||||
return;
|
||||
|
||||
if (await CurrencyHandler.RemoveCurrencyAsync(user, $"Taken by bot owner.({Context.User.Username}/{Context.User.Id})", amount, true).ConfigureAwait(false))
|
||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully took {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from {user}!").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("take", amount+CurrencySign, Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} was unable to take {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from {user} because the user doesn't have that much {CurrencyPluralName}!").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("take_fail", amount + CurrencySign, Format.Bold(user.ToString()), CurrencyPluralName).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
@ -140,9 +139,9 @@ namespace NadekoBot.Modules.Gambling
|
||||
return;
|
||||
|
||||
if (await CurrencyHandler.RemoveCurrencyAsync(usrId, $"Taken by bot owner.({Context.User.Username}/{Context.User.Id})", amount).ConfigureAwait(false))
|
||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully took {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from <@{usrId}>!").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("take", amount + CurrencySign, $"<@{usrId}>").ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} was unable to take {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from `{usrId}` because the user doesn't have that much {CurrencyPluralName}!").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("take_fail", amount + CurrencySign, Format.Code(usrId.ToString()), CurrencyPluralName).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
//[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -206,49 +205,48 @@ namespace NadekoBot.Modules.Gambling
|
||||
if (amount < 1)
|
||||
return;
|
||||
|
||||
long userFlowers;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User, "Betroll Gamble", amount, false).ConfigureAwait(false))
|
||||
{
|
||||
userFlowers = uow.Currency.GetOrCreate(Context.User.Id).Amount;
|
||||
}
|
||||
|
||||
if (userFlowers < amount)
|
||||
{
|
||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {CurrencyPluralName}. You only have {userFlowers}{CurrencySign}.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("not_enough", CurrencyPluralName).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await CurrencyHandler.RemoveCurrencyAsync(Context.User, "Betroll Gamble", amount, false).ConfigureAwait(false);
|
||||
|
||||
var rng = new NadekoRandom().Next(0, 101);
|
||||
var str = $"{Context.User.Mention} `You rolled {rng}.` ";
|
||||
if (rng < 67)
|
||||
var rnd = new NadekoRandom().Next(0, 101);
|
||||
var str = Context.User.Mention + Format.Code(GetText("roll", rnd));
|
||||
if (rnd < 67)
|
||||
{
|
||||
str += "Better luck next time.";
|
||||
}
|
||||
else if (rng < 91)
|
||||
{
|
||||
str += $"Congratulations! You won {amount * NadekoBot.BotConfig.Betroll67Multiplier}{CurrencySign} for rolling above 66";
|
||||
await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", (int)(amount * NadekoBot.BotConfig.Betroll67Multiplier), false).ConfigureAwait(false);
|
||||
}
|
||||
else if (rng < 100)
|
||||
{
|
||||
str += $"Congratulations! You won {amount * NadekoBot.BotConfig.Betroll91Multiplier}{CurrencySign} for rolling above 90.";
|
||||
await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", (int)(amount * NadekoBot.BotConfig.Betroll91Multiplier), false).ConfigureAwait(false);
|
||||
str += GetText("better_luck");
|
||||
}
|
||||
else
|
||||
{
|
||||
str += $"👑 Congratulations! You won {amount * NadekoBot.BotConfig.Betroll100Multiplier}{CurrencySign} for rolling **100**. 👑";
|
||||
await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", (int)(amount * NadekoBot.BotConfig.Betroll100Multiplier), false).ConfigureAwait(false);
|
||||
if (rnd < 91)
|
||||
{
|
||||
str += GetText("br_win", (amount * NadekoBot.BotConfig.Betroll67Multiplier) + CurrencySign, 66);
|
||||
await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble",
|
||||
(int) (amount * NadekoBot.BotConfig.Betroll67Multiplier), false).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
else if (rnd < 100)
|
||||
{
|
||||
str += GetText("br_win", (amount * NadekoBot.BotConfig.Betroll91Multiplier) + CurrencySign, 90);
|
||||
await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble",
|
||||
(int) (amount * NadekoBot.BotConfig.Betroll91Multiplier), false).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
str += GetText("br_win", (amount * NadekoBot.BotConfig.Betroll100Multiplier) + CurrencySign, 100) + " 👑";
|
||||
await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble",
|
||||
(int) (amount * NadekoBot.BotConfig.Betroll100Multiplier), false).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
Console.WriteLine("started sending");
|
||||
await Context.Channel.SendConfirmAsync(str).ConfigureAwait(false);
|
||||
Console.WriteLine("done sending");
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Leaderboard()
|
||||
{
|
||||
var richest = new List<Currency>();
|
||||
List<Currency> richest;
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
richest = uow.Currency.GetTopRichest(9).ToList();
|
||||
@ -256,22 +254,22 @@ namespace NadekoBot.Modules.Gambling
|
||||
if (!richest.Any())
|
||||
return;
|
||||
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
.WithOkColor()
|
||||
.WithTitle(NadekoBot.BotConfig.CurrencySign + " Leaderboard");
|
||||
.WithTitle(NadekoBot.BotConfig.CurrencySign + " " + GetText("leaderboard"));
|
||||
|
||||
for (var i = 0; i < richest.Count; i++)
|
||||
{
|
||||
var x = richest[i];
|
||||
var usr = await Context.Guild.GetUserAsync(x.UserId).ConfigureAwait(false);
|
||||
var usrStr = "";
|
||||
if (usr == null)
|
||||
usrStr = x.UserId.ToString();
|
||||
else
|
||||
usrStr = usr.Username?.TrimTo(20, true);
|
||||
var usrStr = usr == null
|
||||
? x.UserId.ToString()
|
||||
: usr.Username?.TrimTo(20, true);
|
||||
|
||||
embed.AddField(efb => efb.WithName("#" + (i + 1) + " " + usrStr).WithValue(x.Amount.ToString() + " " + NadekoBot.BotConfig.CurrencySign).WithIsInline(true));
|
||||
var j = i;
|
||||
embed.AddField(efb => efb.WithName("#" + (j + 1) + " " + usrStr)
|
||||
.WithValue(x.Amount.ToString() + " " + NadekoBot.BotConfig.CurrencySign)
|
||||
.WithIsInline(true));
|
||||
}
|
||||
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
|
@ -21,12 +21,6 @@ namespace NadekoBot.Modules.Games
|
||||
{
|
||||
private static Logger _log { get; }
|
||||
|
||||
class CleverAnswer
|
||||
{
|
||||
public string Status { get; set; }
|
||||
public string Response { get; set; }
|
||||
}
|
||||
|
||||
public static ConcurrentDictionary<ulong, Lazy<ChatterBotSession>> CleverbotGuilds { get; } = new ConcurrentDictionary<ulong, Lazy<ChatterBotSession>>();
|
||||
|
||||
static CleverBotCommands()
|
||||
@ -34,14 +28,12 @@ namespace NadekoBot.Modules.Games
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
|
||||
var bot = ChatterBotFactory.Create(ChatterBotType.CLEVERBOT);
|
||||
CleverbotGuilds = new ConcurrentDictionary<ulong, Lazy<ChatterBotSession>>(
|
||||
NadekoBot.AllGuildConfigs
|
||||
.Where(gc => gc.CleverbotEnabled)
|
||||
.ToDictionary(gc => gc.GuildId, gc => new Lazy<ChatterBotSession>(() => bot.CreateSession(), true)));
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
||||
|
@ -23,7 +23,8 @@ namespace NadekoBot.Modules.Games
|
||||
static HangmanCommands()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
typesStr = $"`List of \"{NadekoBot.ModulePrefixes[typeof(Games).Name]}hangman\" term types:`\n" + String.Join(", ", HangmanTermPool.data.Keys);
|
||||
typesStr =
|
||||
string.Format("`List of \"{0}hangman\" term types:`\n", NadekoBot.ModulePrefixes[typeof(Games).Name]) + String.Join(", ", HangmanTermPool.data.Keys);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
|
@ -29,7 +29,7 @@ namespace NadekoBot.Modules.Games
|
||||
/// https://discord.gg/0TYNJfCU4De7YIk8
|
||||
/// </summary>
|
||||
[Group]
|
||||
public class PlantPickCommands : ModuleBase
|
||||
public class PlantPickCommands : NadekoSubmodule
|
||||
{
|
||||
private static ConcurrentHashSet<ulong> generationChannels { get; } = new ConcurrentHashSet<ulong>();
|
||||
//channelid/message
|
||||
@ -37,13 +37,8 @@ namespace NadekoBot.Modules.Games
|
||||
//channelId/last generation
|
||||
private static ConcurrentDictionary<ulong, DateTime> lastGenerations { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
||||
|
||||
private static ConcurrentHashSet<ulong> usersRecentlyPicked { get; } = new ConcurrentHashSet<ulong>();
|
||||
|
||||
private static Logger _log { get; }
|
||||
|
||||
static PlantPickCommands()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
#if !GLOBAL_NADEKO
|
||||
NadekoBot.Client.MessageReceived += PotentialFlowerGeneration;
|
||||
@ -103,7 +98,8 @@ namespace NadekoBot.Modules.Games
|
||||
var sent = await channel.SendFileAsync(
|
||||
fileStream,
|
||||
file.Key,
|
||||
$"❗ {firstPart} Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`")
|
||||
string.Format("❗ {0} Pick it up by typing `{1}pick`", firstPart,
|
||||
NadekoBot.ModulePrefixes[typeof(Games).Name]))
|
||||
.ConfigureAwait(false);
|
||||
|
||||
msgs[0] = sent;
|
||||
@ -115,7 +111,7 @@ namespace NadekoBot.Modules.Games
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
LogManager.GetCurrentClassLogger().Warn(ex);
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
@ -129,12 +125,6 @@ namespace NadekoBot.Modules.Games
|
||||
|
||||
if (!(await channel.Guild.GetCurrentUserAsync()).GetPermissions(channel).ManageMessages)
|
||||
return;
|
||||
#if GLOBAL_NADEKO
|
||||
if (!usersRecentlyPicked.Add(Context.User.Id))
|
||||
return;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
|
||||
List<IUserMessage> msgs;
|
||||
|
||||
@ -148,14 +138,6 @@ namespace NadekoBot.Modules.Games
|
||||
var msg = await channel.SendConfirmAsync($"**{Context.User}** picked {msgs.Count}{NadekoBot.BotConfig.CurrencySign}!").ConfigureAwait(false);
|
||||
msg.DeleteAfter(10);
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if GLOBAL_NADEKO
|
||||
await Task.Delay(60000);
|
||||
usersRecentlyPicked.TryRemove(Context.User.Id);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
@ -174,7 +156,7 @@ namespace NadekoBot.Modules.Games
|
||||
var imgData = GetRandomCurrencyImage();
|
||||
var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.BotConfig.CurrencyName[0]);
|
||||
|
||||
var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(amount == 1 ? (vowelFirst ? "an" : "a") : amount.ToString())} {(amount > 1 ? NadekoBot.BotConfig.CurrencyPluralName : NadekoBot.BotConfig.CurrencyName)}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick";
|
||||
var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(amount == 1 ? (vowelFirst ? "an" : "a") : amount.ToString())} {(amount > 1 ? NadekoBot.BotConfig.CurrencyPluralName : NadekoBot.BotConfig.CurrencyName)}. Pick it using {Prefix}pick";
|
||||
|
||||
IUserMessage msg;
|
||||
using (var toSend = imgData.Value.ToStream())
|
||||
@ -236,17 +218,6 @@ namespace NadekoBot.Modules.Games
|
||||
|
||||
return images[rng.Next(0, images.Length)];
|
||||
}
|
||||
|
||||
int GetRandomNumber()
|
||||
{
|
||||
using (var rg = RandomNumberGenerator.Create())
|
||||
{
|
||||
byte[] rno = new byte[4];
|
||||
rg.GetBytes(rno);
|
||||
int randomvalue = BitConverter.ToInt32(rno, 0);
|
||||
return randomvalue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -307,7 +307,7 @@ namespace NadekoBot.Modules.Games
|
||||
var del2 = previousMessage?.DeleteAsync();
|
||||
try { previousMessage = await _channel.EmbedAsync(GetEmbed(reason)); } catch { }
|
||||
try { await del1; } catch { }
|
||||
try { await del2; } catch { }
|
||||
try { if (del2 != null) await del2; } catch { }
|
||||
});
|
||||
curUserIndex ^= 1;
|
||||
|
||||
|
@ -11,7 +11,7 @@ using NadekoBot.Extensions;
|
||||
namespace NadekoBot.Modules.Games
|
||||
{
|
||||
[NadekoModule("Games", ">")]
|
||||
public partial class Games : DiscordModule
|
||||
public partial class Games : NadekoModule
|
||||
{
|
||||
private static string[] _8BallResponses { get; } = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text).ToArray();
|
||||
|
||||
@ -32,7 +32,6 @@ namespace NadekoBot.Modules.Games
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(question))
|
||||
return;
|
||||
var rng = new NadekoRandom();
|
||||
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor)
|
||||
.AddField(efb => efb.WithName("❓ Question").WithValue(question).WithIsInline(false))
|
||||
|
@ -13,19 +13,26 @@ using System.Collections.Generic;
|
||||
namespace NadekoBot.Modules.Help
|
||||
{
|
||||
[NadekoModule("Help", "-")]
|
||||
public partial class Help : DiscordModule
|
||||
public class Help : NadekoModule
|
||||
{
|
||||
private static string helpString { get; } = NadekoBot.BotConfig.HelpString;
|
||||
public static string HelpString => String.Format(helpString, NadekoBot.Credentials.ClientId, NadekoBot.ModulePrefixes[typeof(Help).Name]);
|
||||
|
||||
public static string DMHelpString { get; } = NadekoBot.BotConfig.DMHelpString;
|
||||
|
||||
public const string PatreonUrl = "https://patreon.com/nadekobot";
|
||||
public const string PaypalUrl = "https://paypal.me/Kwoth";
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Modules()
|
||||
{
|
||||
|
||||
var embed = new EmbedBuilder().WithOkColor().WithFooter(efb => efb.WithText($" ℹ️ Type `-cmds ModuleName` to get a list of commands in that module. eg `-cmds games`"))
|
||||
.WithTitle("📜 List Of Modules").WithDescription("\n• " + string.Join("\n• ", NadekoBot.CommandService.Modules.GroupBy(m => m.GetTopLevelModule()).Select(m => m.Key.Name).OrderBy(s => s)));
|
||||
var embed = new EmbedBuilder().WithOkColor()
|
||||
.WithFooter(efb => efb.WithText("ℹ️" + GetText("modules_footer", Prefix)))
|
||||
.WithTitle(GetText("list_of_modules"))
|
||||
.WithDescription(string.Join("\n",
|
||||
NadekoBot.CommandService.Modules.GroupBy(m => m.GetTopLevelModule())
|
||||
.Select(m => "• " + m.Key.Name)
|
||||
.OrderBy(s => s)));
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@ -45,18 +52,13 @@ namespace NadekoBot.Modules.Help
|
||||
var cmdsArray = cmds as CommandInfo[] ?? cmds.ToArray();
|
||||
if (!cmdsArray.Any())
|
||||
{
|
||||
await channel.SendErrorAsync("That module does not exist.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("module_not_found").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (module != "customreactions" && module != "conversations")
|
||||
{
|
||||
await channel.SendTableAsync("📃 **List Of Commands:**\n", cmdsArray, el => $"{el.Aliases.First(),-15} {"["+el.Aliases.Skip(1).FirstOrDefault()+"]",-8}").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await channel.SendMessageAsync("📃 **List Of Commands:**\n• " + string.Join("\n• ", cmdsArray.Select(c => $"{c.Aliases.First()}")));
|
||||
}
|
||||
await channel.SendConfirmAsync($"ℹ️ **Type** `\"{NadekoBot.ModulePrefixes[typeof(Help).Name]}h CommandName\"` **to see the help for that specified command.** ***e.g.*** `-h >8ball`").ConfigureAwait(false);
|
||||
|
||||
await channel.SendTableAsync($"📃 **{GetText("list_of_commands")}**\n", cmdsArray, el => $"{el.Aliases.First(),-15} {"["+el.Aliases.Skip(1).FirstOrDefault()+"]",-8}").ConfigureAwait(false);
|
||||
|
||||
await ConfirmLocalized("commands_instr", Prefix).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -75,32 +77,33 @@ namespace NadekoBot.Modules.Help
|
||||
|
||||
if (com == null)
|
||||
{
|
||||
await channel.SendErrorAsync("I can't find that command. Please check the **command** and **command prefix** before trying again.");
|
||||
await ReplyErrorLocalized("command_not_found").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var str = $"**`{com.Aliases.First()}`**";
|
||||
var str = string.Format("**`{0}`**", com.Aliases.First());
|
||||
var alias = com.Aliases.Skip(1).FirstOrDefault();
|
||||
if (alias != null)
|
||||
str += $" **/ `{alias}`**";
|
||||
str += string.Format(" **/ `{0}`**", alias);
|
||||
var embed = new EmbedBuilder()
|
||||
.AddField(fb => fb.WithName(str).WithValue($"{string.Format(com.Summary, com.Module.Aliases.First())} {GetCommandRequirements(com)}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Usage**").WithValue($"{string.Format(com.Remarks, com.Module.Aliases.First())}").WithIsInline(false))
|
||||
.AddField(fb => fb.WithName(GetText("usage")).WithValue(string.Format(com.Remarks, com.Module.Aliases.First())).WithIsInline(false))
|
||||
.WithColor(NadekoBot.OkColor);
|
||||
await channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private string GetCommandRequirements(CommandInfo cmd) =>
|
||||
String.Join(" ", cmd.Preconditions
|
||||
string.Join(" ", cmd.Preconditions
|
||||
.Where(ca => ca is OwnerOnlyAttribute || ca is RequireUserPermissionAttribute)
|
||||
.Select(ca =>
|
||||
{
|
||||
if (ca is OwnerOnlyAttribute)
|
||||
return "**Bot Owner only.**";
|
||||
return Format.Bold(GetText("bot_owner_only"));
|
||||
var cau = (RequireUserPermissionAttribute)ca;
|
||||
if (cau.GuildPermission != null)
|
||||
return $"**Requires {cau.GuildPermission} server permission.**".Replace("Guild", "Server");
|
||||
else
|
||||
return $"**Requires {cau.ChannelPermission} channel permission.**".Replace("Guild", "Server");
|
||||
return Format.Bold(GetText("server_permission", cau.GuildPermission))
|
||||
.Replace("Guild", "Server");
|
||||
return Format.Bold(GetText("channel_permission", cau.ChannelPermission))
|
||||
.Replace("Guild", "Server");
|
||||
}));
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -109,14 +112,14 @@ namespace NadekoBot.Modules.Help
|
||||
public async Task Hgit()
|
||||
{
|
||||
var helpstr = new StringBuilder();
|
||||
helpstr.AppendLine("You can support the project on patreon: <https://patreon.com/nadekobot> or paypal: <https://www.paypal.me/Kwoth>\n");
|
||||
helpstr.AppendLine("##Table Of Contents");
|
||||
helpstr.AppendLine(GetText("cmdlist_donate", PatreonUrl, PaypalUrl) + "\n");
|
||||
helpstr.AppendLine("##"+ GetText("table_of_contents"));
|
||||
helpstr.AppendLine(string.Join("\n", NadekoBot.CommandService.Modules.Where(m => m.GetTopLevelModule().Name.ToLowerInvariant() != "help")
|
||||
.Select(m => m.GetTopLevelModule().Name)
|
||||
.Distinct()
|
||||
.OrderBy(m => m)
|
||||
.Prepend("Help")
|
||||
.Select(m => $"- [{m}](#{m.ToLowerInvariant()})")));
|
||||
.Select(m => string.Format("- [{0}](#{1})", m, m.ToLowerInvariant()))));
|
||||
helpstr.AppendLine();
|
||||
string lastModule = null;
|
||||
foreach (var com in NadekoBot.CommandService.Commands.OrderBy(com => com.Module.GetTopLevelModule().Name).GroupBy(c => c.Aliases.First()).Select(g => g.First()))
|
||||
@ -127,44 +130,35 @@ namespace NadekoBot.Modules.Help
|
||||
if (lastModule != null)
|
||||
{
|
||||
helpstr.AppendLine();
|
||||
helpstr.AppendLine("###### [Back to TOC](#table-of-contents)");
|
||||
helpstr.AppendLine($"###### [{GetText("back_to_toc")}](#{GetText("table_of_contents").ToLowerInvariant().Replace(' ', '-')})");
|
||||
}
|
||||
helpstr.AppendLine();
|
||||
helpstr.AppendLine("### " + module.Name + " ");
|
||||
helpstr.AppendLine("Command and aliases | Description | Usage");
|
||||
helpstr.AppendLine($"{GetText("cmd_and_alias")} | {GetText("desc")} | {GetText("usage")}");
|
||||
helpstr.AppendLine("----------------|--------------|-------");
|
||||
lastModule = module.Name;
|
||||
}
|
||||
helpstr.AppendLine($"{string.Join(" ", com.Aliases.Select(a => "`" + a + "`"))} | {string.Format(com.Summary, com.Module.GetPrefix())} {GetCommandRequirements(com)} | {string.Format(com.Remarks, com.Module.GetPrefix())}");
|
||||
helpstr.AppendLine($"{string.Join(" ", com.Aliases.Select(a => "`" + a + "`"))} |" +
|
||||
$" {string.Format(com.Summary, com.Module.GetPrefix())} {GetCommandRequirements(com)} |" +
|
||||
$" {string.Format(com.Remarks, com.Module.GetPrefix())}");
|
||||
}
|
||||
helpstr = helpstr.Replace(NadekoBot.Client.CurrentUser.Username , "@BotName");
|
||||
File.WriteAllText("../../docs/Commands List.md", helpstr.ToString());
|
||||
await Context.Channel.SendConfirmAsync("Commandlist Regenerated").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("commandlist_regen").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Guide()
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
await channel.SendConfirmAsync(
|
||||
@"**LIST OF COMMANDS**: <http://nadekobot.readthedocs.io/en/latest/Commands%20List/>
|
||||
**Hosting Guides and docs can be found here**: <http://nadekobot.readthedocs.io/en/latest/>").ConfigureAwait(false);
|
||||
await ConfirmLocalized("guide",
|
||||
"http://nadekobot.readthedocs.io/en/latest/Commands%20List/",
|
||||
"http://nadekobot.readthedocs.io/en/latest/").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Donate()
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
await channel.SendConfirmAsync(
|
||||
$@"You can support the NadekoBot project on patreon. <https://patreon.com/nadekobot> or
|
||||
Paypal <https://paypal.me/Kwoth>
|
||||
Don't forget to leave your discord name or id in the message.
|
||||
|
||||
**Thank you** ♥️").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("donate", PatreonUrl, PaypalUrl).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ namespace NadekoBot.Modules.Music
|
||||
{
|
||||
[NadekoModule("Music", "!!")]
|
||||
[DontAutoLoad]
|
||||
public partial class Music : DiscordModule
|
||||
public partial class Music : NadekoModule
|
||||
{
|
||||
public static ConcurrentDictionary<ulong, MusicPlayer> MusicPlayers { get; } = new ConcurrentDictionary<ulong, MusicPlayer>();
|
||||
|
||||
@ -415,8 +415,6 @@ namespace NadekoBot.Modules.Music
|
||||
var arg = directory;
|
||||
if (string.IsNullOrWhiteSpace(arg))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var dir = new DirectoryInfo(arg);
|
||||
var fileEnum = dir.GetFiles("*", SearchOption.AllDirectories)
|
||||
.Where(x => !x.Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System));
|
||||
@ -425,18 +423,19 @@ namespace NadekoBot.Modules.Music
|
||||
{
|
||||
try
|
||||
{
|
||||
await QueueSong(((IGuildUser)Context.User), (ITextChannel)Context.Channel, ((IGuildUser)Context.User).VoiceChannel, file.FullName, true, MusicType.Local).ConfigureAwait(false);
|
||||
await QueueSong(gusr, (ITextChannel)Context.Channel, gusr.VoiceChannel, file.FullName, true, MusicType.Local).ConfigureAwait(false);
|
||||
}
|
||||
catch (PlaylistFullException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
await Context.Channel.SendConfirmAsync("🎵 Directory queue complete.").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
|
@ -17,11 +17,11 @@ using System.Collections.Concurrent;
|
||||
namespace NadekoBot.Modules.NSFW
|
||||
{
|
||||
[NadekoModule("NSFW", "~")]
|
||||
public class NSFW : DiscordModule
|
||||
public class NSFW : NadekoModule
|
||||
{
|
||||
|
||||
private static ConcurrentDictionary<ulong, Timer> AutoHentaiTimers { get; } = new ConcurrentDictionary<ulong, Timer>();
|
||||
private static ConcurrentHashSet<ulong> _hentaiBombBlacklist { get; } = new ConcurrentHashSet<ulong>();
|
||||
private static readonly ConcurrentDictionary<ulong, Timer> AutoHentaiTimers = new ConcurrentDictionary<ulong, Timer>();
|
||||
private static readonly ConcurrentHashSet<ulong> HentaiBombBlacklist = new ConcurrentHashSet<ulong>();
|
||||
|
||||
private async Task InternalHentai(IMessageChannel channel, string tag, bool noError)
|
||||
{
|
||||
@ -30,7 +30,7 @@ namespace NadekoBot.Modules.NSFW
|
||||
tag = "rating%3Aexplicit+" + tag;
|
||||
|
||||
var rng = new NadekoRandom();
|
||||
Task<string> provider = Task.FromResult("");
|
||||
var provider = Task.FromResult("");
|
||||
switch (rng.Next(0, 4))
|
||||
{
|
||||
case 0:
|
||||
@ -45,20 +45,18 @@ namespace NadekoBot.Modules.NSFW
|
||||
case 3:
|
||||
provider = GetYandereImageLink(tag);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
var link = await provider.ConfigureAwait(false);
|
||||
if (string.IsNullOrWhiteSpace(link))
|
||||
{
|
||||
if (!noError)
|
||||
await channel.SendErrorAsync("No results found.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("not_found").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithImageUrl(link)
|
||||
.WithDescription("Tag: " + tag))
|
||||
.WithDescription($"{GetText("tag")}: " + tag))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@ -74,11 +72,10 @@ namespace NadekoBot.Modules.NSFW
|
||||
|
||||
if (interval == 0)
|
||||
{
|
||||
if (AutoHentaiTimers.TryRemove(Context.Channel.Id, out t))
|
||||
{
|
||||
if (!AutoHentaiTimers.TryRemove(Context.Channel.Id, out t)) return;
|
||||
|
||||
t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer
|
||||
await Context.Channel.SendConfirmAsync("Autohentai stopped.").ConfigureAwait(false);
|
||||
}
|
||||
await ReplyConfirmLocalized("autohentai_stopped").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -96,7 +93,10 @@ namespace NadekoBot.Modules.NSFW
|
||||
else
|
||||
await InternalHentai(Context.Channel, tagsArr[new NadekoRandom().Next(0, tagsArr.Length)], true).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}, null, interval * 1000, interval * 1000);
|
||||
|
||||
AutoHentaiTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) =>
|
||||
@ -105,15 +105,16 @@ namespace NadekoBot.Modules.NSFW
|
||||
return t;
|
||||
});
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"Autohentai started. Reposting every {interval}s with one of the following tags:\n{string.Join(", ", tagsArr)}")
|
||||
.ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("autohentai_started",
|
||||
interval,
|
||||
string.Join(", ", tagsArr)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task HentaiBomb([Remainder] string tag = null)
|
||||
{
|
||||
if (!_hentaiBombBlacklist.Add(Context.User.Id))
|
||||
if (!HentaiBombBlacklist.Add(Context.User.Id))
|
||||
return;
|
||||
try
|
||||
{
|
||||
@ -125,19 +126,19 @@ namespace NadekoBot.Modules.NSFW
|
||||
GetKonachanImageLink(tag),
|
||||
GetYandereImageLink(tag)).ConfigureAwait(false);
|
||||
|
||||
var linksEnum = links?.Where(l => l != null);
|
||||
var linksEnum = links?.Where(l => l != null).ToArray();
|
||||
if (links == null || !linksEnum.Any())
|
||||
{
|
||||
await Context.Channel.SendErrorAsync("No results found.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("not_found").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await Context.Channel.SendMessageAsync(String.Join("\n\n", linksEnum)).ConfigureAwait(false);
|
||||
await Context.Channel.SendMessageAsync(string.Join("\n\n", linksEnum)).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await Task.Delay(5000).ConfigureAwait(false);
|
||||
_hentaiBombBlacklist.TryRemove(Context.User.Id);
|
||||
HentaiBombBlacklist.TryRemove(Context.User.Id);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -157,7 +158,7 @@ namespace NadekoBot.Modules.NSFW
|
||||
var url = await GetE621ImageLink(tag).ConfigureAwait(false);
|
||||
|
||||
if (url == null)
|
||||
await Context.Channel.SendErrorAsync(Context.User.Mention + " No results.");
|
||||
await ReplyErrorLocalized("not_found").ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithDescription(Context.User.Mention + " " + tag)
|
||||
@ -178,7 +179,7 @@ namespace NadekoBot.Modules.NSFW
|
||||
var url = await GetDanbooruImageLink(tag).ConfigureAwait(false);
|
||||
|
||||
if (url == null)
|
||||
await Context.Channel.SendErrorAsync(Context.User.Mention + " No results.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("not_found").ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
.WithDescription(Context.User.Mention + " " + tag)
|
||||
@ -229,7 +230,7 @@ namespace NadekoBot.Modules.NSFW
|
||||
{
|
||||
obj = JArray.Parse(await http.GetStringAsync($"http://api.oboobs.ru/boobs/{new NadekoRandom().Next(0, 10330)}").ConfigureAwait(false))[0];
|
||||
}
|
||||
await Context.Channel.SendMessageAsync($"http://media.oboobs.ru/{ obj["preview"].ToString() }").ConfigureAwait(false);
|
||||
await Context.Channel.SendMessageAsync($"http://media.oboobs.ru/{obj["preview"]}").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -247,7 +248,7 @@ namespace NadekoBot.Modules.NSFW
|
||||
{
|
||||
obj = JArray.Parse(await http.GetStringAsync($"http://api.obutts.ru/butts/{new NadekoRandom().Next(0, 4335)}").ConfigureAwait(false))[0];
|
||||
}
|
||||
await Context.Channel.SendMessageAsync($"http://media.obutts.ru/{ obj["preview"].ToString() }").ConfigureAwait(false);
|
||||
await Context.Channel.SendMessageAsync($"http://media.obutts.ru/{obj["preview"]}").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
129
src/NadekoBot/Modules/NadekoModule.cs
Normal file
129
src/NadekoBot/Modules/NadekoModule.cs
Normal file
@ -0,0 +1,129 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules
|
||||
{
|
||||
public abstract class NadekoModule : ModuleBase
|
||||
{
|
||||
protected readonly Logger _log;
|
||||
protected CultureInfo _cultureInfo;
|
||||
public readonly string Prefix;
|
||||
public readonly string ModuleTypeName;
|
||||
public readonly string LowerModuleTypeName;
|
||||
|
||||
protected NadekoModule(bool isTopLevelModule = true)
|
||||
{
|
||||
//if it's top level module
|
||||
ModuleTypeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name;
|
||||
LowerModuleTypeName = ModuleTypeName.ToLowerInvariant();
|
||||
|
||||
if (!NadekoBot.ModulePrefixes.TryGetValue(ModuleTypeName, out Prefix))
|
||||
Prefix = "?err?";
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
}
|
||||
|
||||
protected override void BeforeExecute()
|
||||
{
|
||||
_cultureInfo = NadekoBot.Localization.GetCultureInfo(Context.Guild?.Id);
|
||||
|
||||
_log.Warn("Culture info is {0}", _cultureInfo);
|
||||
}
|
||||
|
||||
//public Task<IUserMessage> ReplyConfirmLocalized(string titleKey, string textKey, string url = null, string footer = null)
|
||||
//{
|
||||
// var title = NadekoBot.ResponsesResourceManager.GetString(titleKey, cultureInfo);
|
||||
// var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo);
|
||||
// return Context.Channel.SendConfirmAsync(title, text, url, footer);
|
||||
//}
|
||||
|
||||
//public Task<IUserMessage> ReplyConfirmLocalized(string textKey)
|
||||
//{
|
||||
// var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo);
|
||||
// return Context.Channel.SendConfirmAsync(Context.User.Mention + " " + textKey);
|
||||
//}
|
||||
|
||||
//public Task<IUserMessage> ReplyErrorLocalized(string titleKey, string textKey, string url = null, string footer = null)
|
||||
//{
|
||||
// var title = NadekoBot.ResponsesResourceManager.GetString(titleKey, cultureInfo);
|
||||
// var text = NadekoBot.ResponsesResourceManager.GetString(textKey, cultureInfo);
|
||||
// return Context.Channel.SendErrorAsync(title, text, url, footer);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Used as failsafe in case response key doesn't exist in the selected or default language.
|
||||
/// </summary>
|
||||
private static readonly CultureInfo _usCultureInfo = new CultureInfo("en-US");
|
||||
|
||||
public static string GetTextStatic(string key, CultureInfo cultureInfo, string lowerModuleTypeName)
|
||||
{
|
||||
var text = NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, cultureInfo);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
LogManager.GetCurrentClassLogger().Warn(lowerModuleTypeName + "_" + key + " key is missing from " + cultureInfo + " response strings. PLEASE REPORT THIS.");
|
||||
text = NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, _usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} not found!";
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return "I cant tell if you command is executed, because there was an error printing out the response. Key '" +
|
||||
lowerModuleTypeName + "_" + key + "' " + "is missing from resources. Please report this.";
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public static string GetTextStatic(string key, CultureInfo cultureInfo, string lowerModuleTypeName,
|
||||
params object[] replacements)
|
||||
{
|
||||
try
|
||||
{
|
||||
return string.Format(GetTextStatic(key, cultureInfo, lowerModuleTypeName), replacements);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return "I cant tell if you command is executed, because there was an error printing out the response. Key '" +
|
||||
lowerModuleTypeName + "_" + key + "' " + "is not properly formatted. Please report this.";
|
||||
}
|
||||
}
|
||||
|
||||
protected string GetText(string key) =>
|
||||
GetTextStatic(key, _cultureInfo, LowerModuleTypeName);
|
||||
|
||||
protected string GetText(string key, params object[] replacements) =>
|
||||
GetTextStatic(key, _cultureInfo, LowerModuleTypeName, replacements);
|
||||
|
||||
public Task<IUserMessage> ErrorLocalized(string textKey, params object[] replacements)
|
||||
{
|
||||
var text = GetText(textKey, replacements);
|
||||
return Context.Channel.SendErrorAsync(text);
|
||||
}
|
||||
|
||||
public Task<IUserMessage> ReplyErrorLocalized(string textKey, params object[] replacements)
|
||||
{
|
||||
var text = GetText(textKey, replacements);
|
||||
return Context.Channel.SendErrorAsync(Context.User.Mention + " " + text);
|
||||
}
|
||||
|
||||
public Task<IUserMessage> ConfirmLocalized(string textKey, params object[] replacements)
|
||||
{
|
||||
var text = GetText(textKey, replacements);
|
||||
return Context.Channel.SendConfirmAsync(text);
|
||||
}
|
||||
|
||||
public Task<IUserMessage> ReplyConfirmLocalized(string textKey, params object[] replacements)
|
||||
{
|
||||
var text = GetText(textKey, replacements);
|
||||
return Context.Channel.SendConfirmAsync(Context.User.Mention + " " + text);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class NadekoSubmodule : NadekoModule
|
||||
{
|
||||
protected NadekoSubmodule() : base(false)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
15
src/NadekoBot/Modules/NadekoModuleExtensions.cs
Normal file
15
src/NadekoBot/Modules/NadekoModuleExtensions.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using Discord;
|
||||
using NadekoBot.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules
|
||||
{
|
||||
public static class NadekoModuleExtensions
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -101,23 +101,23 @@ namespace NadekoBot.Modules.Permissions
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
activeCdsForGuild.Add(new ActiveCooldown()
|
||||
{
|
||||
UserId = user.Id,
|
||||
Command = cmd.Aliases.First().ToLowerInvariant(),
|
||||
});
|
||||
var t = Task.Run(async () =>
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(cdRule.Seconds * 1000);
|
||||
activeCdsForGuild.RemoveWhere(ac => ac.Command == cmd.Aliases.First().ToLowerInvariant() && ac.UserId == user.Id);
|
||||
}
|
||||
catch { }
|
||||
});
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -41,8 +41,6 @@ namespace NadekoBot.Modules.Permissions
|
||||
}
|
||||
|
||||
static FilterCommands()
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var guildConfigs = NadekoBot.AllGuildConfigs;
|
||||
|
||||
@ -57,8 +55,6 @@ namespace NadekoBot.Modules.Permissions
|
||||
WordFilteringServers = new ConcurrentHashSet<ulong>(serverFiltering.Select(gc => gc.GuildId));
|
||||
|
||||
WordFilteringChannels = new ConcurrentHashSet<ulong>(guildConfigs.SelectMany(gc => gc.FilterWordsChannelIds.Select(fwci => fwci.ChannelId)));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
|
@ -15,7 +15,7 @@ using NLog;
|
||||
namespace NadekoBot.Modules.Permissions
|
||||
{
|
||||
[NadekoModule("Permissions", ";")]
|
||||
public partial class Permissions : DiscordModule
|
||||
public partial class Permissions : NadekoModule
|
||||
{
|
||||
public class PermissionCache
|
||||
{
|
||||
|
@ -16,21 +16,21 @@ using System.Collections.Concurrent;
|
||||
namespace NadekoBot.Modules.Pokemon
|
||||
{
|
||||
[NadekoModule("Pokemon", ">")]
|
||||
public partial class Pokemon : DiscordModule
|
||||
public class Pokemon : NadekoModule
|
||||
{
|
||||
private static List<PokemonType> PokemonTypes = new List<PokemonType>();
|
||||
private static ConcurrentDictionary<ulong, PokeStats> Stats = new ConcurrentDictionary<ulong, PokeStats>();
|
||||
private static readonly List<PokemonType> _pokemonTypes = new List<PokemonType>();
|
||||
private static readonly ConcurrentDictionary<ulong, PokeStats> _stats = new ConcurrentDictionary<ulong, PokeStats>();
|
||||
|
||||
public const string PokemonTypesFile = "data/pokemon_types.json";
|
||||
|
||||
private static new Logger _log { get; }
|
||||
private new static Logger _log { get; }
|
||||
|
||||
static Pokemon()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
if (File.Exists(PokemonTypesFile))
|
||||
{
|
||||
PokemonTypes = JsonConvert.DeserializeObject<List<PokemonType>>(File.ReadAllText(PokemonTypesFile));
|
||||
_pokemonTypes = JsonConvert.DeserializeObject<List<PokemonType>>(File.ReadAllText(PokemonTypesFile));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -42,21 +42,18 @@ namespace NadekoBot.Modules.Pokemon
|
||||
private int GetDamage(PokemonType usertype, PokemonType targetType)
|
||||
{
|
||||
var rng = new Random();
|
||||
int damage = rng.Next(40, 60);
|
||||
foreach (PokemonMultiplier Multiplier in usertype.Multipliers)
|
||||
var damage = rng.Next(40, 60);
|
||||
foreach (var multiplierObj in usertype.Multipliers)
|
||||
{
|
||||
if (Multiplier.Type == targetType.Name)
|
||||
{
|
||||
var multiplier = Multiplier.Multiplication;
|
||||
damage = (int)(damage * multiplier);
|
||||
}
|
||||
if (multiplierObj.Type != targetType.Name) continue;
|
||||
damage = (int)(damage * multiplierObj.Multiplication);
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
|
||||
private PokemonType GetPokeType(ulong id)
|
||||
private static PokemonType GetPokeType(ulong id)
|
||||
{
|
||||
|
||||
Dictionary<ulong, string> setTypes;
|
||||
@ -69,20 +66,18 @@ namespace NadekoBot.Modules.Pokemon
|
||||
{
|
||||
return StringToPokemonType(setTypes[id]);
|
||||
}
|
||||
int count = PokemonTypes.Count;
|
||||
var count = _pokemonTypes.Count;
|
||||
|
||||
int remainder = Math.Abs((int)(id % (ulong)count));
|
||||
var remainder = Math.Abs((int)(id % (ulong)count));
|
||||
|
||||
return PokemonTypes[remainder];
|
||||
return _pokemonTypes[remainder];
|
||||
}
|
||||
|
||||
|
||||
|
||||
private PokemonType StringToPokemonType(string v)
|
||||
private static PokemonType StringToPokemonType(string v)
|
||||
{
|
||||
var str = v?.ToUpperInvariant();
|
||||
var list = PokemonTypes;
|
||||
foreach (PokemonType p in list)
|
||||
var list = _pokemonTypes;
|
||||
foreach (var p in list)
|
||||
{
|
||||
if (str == p.Name)
|
||||
{
|
||||
@ -92,7 +87,6 @@ namespace NadekoBot.Modules.Pokemon
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Attack(string move, IGuildUser targetUser = null)
|
||||
@ -105,46 +99,44 @@ namespace NadekoBot.Modules.Pokemon
|
||||
|
||||
if (targetUser == null)
|
||||
{
|
||||
await Context.Channel.SendMessageAsync("No such person.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("user_not_found").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
else if (targetUser == user)
|
||||
if (targetUser == user)
|
||||
{
|
||||
await Context.Channel.SendMessageAsync("You can't attack yourself.").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("cant_attack_yourself").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Checking stats first, then move
|
||||
//Set up the userstats
|
||||
PokeStats userStats;
|
||||
userStats = Stats.GetOrAdd(user.Id, new PokeStats());
|
||||
var userStats = _stats.GetOrAdd(user.Id, new PokeStats());
|
||||
|
||||
//Check if able to move
|
||||
//User not able if HP < 0, has made more than 4 attacks
|
||||
if (userStats.Hp < 0)
|
||||
{
|
||||
await Context.Channel.SendMessageAsync($"{user.Mention} has fainted and was not able to move!").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("you_fainted").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (userStats.MovesMade >= 5)
|
||||
{
|
||||
await Context.Channel.SendMessageAsync($"{user.Mention} has used too many moves in a row and was not able to move!").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("too_many_moves").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (userStats.LastAttacked.Contains(targetUser.Id))
|
||||
{
|
||||
await Context.Channel.SendMessageAsync($"{user.Mention} can't attack again without retaliation!").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("cant_attack_again").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
//get target stats
|
||||
PokeStats targetStats;
|
||||
targetStats = Stats.GetOrAdd(targetUser.Id, new PokeStats());
|
||||
var targetStats = _stats.GetOrAdd(targetUser.Id, new PokeStats());
|
||||
|
||||
//If target's HP is below 0, no use attacking
|
||||
if (targetStats.Hp <= 0)
|
||||
{
|
||||
await Context.Channel.SendMessageAsync($"{targetUser.Mention} has already fainted!").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("too_many_moves", targetUser).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -154,7 +146,7 @@ namespace NadekoBot.Modules.Pokemon
|
||||
var enabledMoves = userType.Moves;
|
||||
if (!enabledMoves.Contains(move.ToLowerInvariant()))
|
||||
{
|
||||
await Context.Channel.SendMessageAsync($"{user.Mention} is not able to use **{move}**. Type {NadekoBot.ModulePrefixes[typeof(Pokemon).Name]}ml to see moves").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("invalid_move", Format.Bold(move), Prefix).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -165,31 +157,31 @@ namespace NadekoBot.Modules.Pokemon
|
||||
//apply damage to target
|
||||
targetStats.Hp -= damage;
|
||||
|
||||
var response = $"{user.Mention} used **{move}**{userType.Icon} on {targetUser.Mention}{targetType.Icon} for **{damage}** damage";
|
||||
var response = GetText("attack", Format.Bold(move), userType.Icon, Format.Bold(targetUser.ToString()), targetType.Icon, Format.Bold(damage.ToString()));
|
||||
|
||||
//Damage type
|
||||
if (damage < 40)
|
||||
{
|
||||
response += "\nIt's not effective..";
|
||||
response += "\n" + GetText("not_effective");
|
||||
}
|
||||
else if (damage > 60)
|
||||
{
|
||||
response += "\nIt's super effective!";
|
||||
response += "\n" + GetText("super_effective");
|
||||
}
|
||||
else
|
||||
{
|
||||
response += "\nIt's somewhat effective";
|
||||
response += "\n" + GetText("somewhat_effective");
|
||||
}
|
||||
|
||||
//check fainted
|
||||
|
||||
if (targetStats.Hp <= 0)
|
||||
{
|
||||
response += $"\n**{targetUser.Mention}** has fainted!";
|
||||
response += "\n" + GetText("fainted", Format.Bold(targetUser.ToString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
response += $"\n**{targetUser.Mention}** has {targetStats.Hp} HP remaining";
|
||||
response += "\n" + GetText("hp_remaining", Format.Bold(targetUser.ToString()), targetStats.Hp);
|
||||
}
|
||||
|
||||
//update other stats
|
||||
@ -203,10 +195,10 @@ namespace NadekoBot.Modules.Pokemon
|
||||
|
||||
//update dictionary
|
||||
//This can stay the same right?
|
||||
Stats[user.Id] = userStats;
|
||||
Stats[targetUser.Id] = targetStats;
|
||||
_stats[user.Id] = userStats;
|
||||
_stats[targetUser.Id] = targetStats;
|
||||
|
||||
await Context.Channel.SendMessageAsync(response).ConfigureAwait(false);
|
||||
await Context.Channel.SendConfirmAsync(Context.User.Mention + " " + response).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
@ -218,12 +210,10 @@ namespace NadekoBot.Modules.Pokemon
|
||||
|
||||
var userType = GetPokeType(user.Id);
|
||||
var movesList = userType.Moves;
|
||||
var str = $"**Moves for `{userType.Name}` type.**";
|
||||
foreach (string m in movesList)
|
||||
{
|
||||
str += $"\n{userType.Icon}{m}";
|
||||
}
|
||||
await Context.Channel.SendMessageAsync(str).ConfigureAwait(false);
|
||||
var embed = new EmbedBuilder().WithOkColor()
|
||||
.WithTitle(GetText("moves", userType))
|
||||
.WithDescription(string.Join("\n", movesList.Select(m => userType.Icon + " " + m)));
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -232,17 +222,18 @@ namespace NadekoBot.Modules.Pokemon
|
||||
{
|
||||
IGuildUser user = (IGuildUser)Context.User;
|
||||
|
||||
if (targetUser == null) {
|
||||
await Context.Channel.SendMessageAsync("No such person.").ConfigureAwait(false);
|
||||
if (targetUser == null)
|
||||
{
|
||||
await ReplyErrorLocalized("user_not_found").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Stats.ContainsKey(targetUser.Id))
|
||||
if (_stats.ContainsKey(targetUser.Id))
|
||||
{
|
||||
var targetStats = Stats[targetUser.Id];
|
||||
var targetStats = _stats[targetUser.Id];
|
||||
if (targetStats.Hp == targetStats.MaxHp)
|
||||
{
|
||||
await Context.Channel.SendMessageAsync($"{targetUser.Mention} already has full HP!").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("already_full", Format.Bold(targetUser.ToString())).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
//Payment~
|
||||
@ -253,7 +244,7 @@ namespace NadekoBot.Modules.Pokemon
|
||||
{
|
||||
if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"Poke-Heal {target}", amount, true).ConfigureAwait(false))
|
||||
{
|
||||
try { await Context.Channel.SendMessageAsync($"{user.Mention} You don't have enough {NadekoBot.BotConfig.CurrencyName}s.").ConfigureAwait(false); } catch { }
|
||||
await ReplyErrorLocalized("no_currency", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -263,23 +254,20 @@ namespace NadekoBot.Modules.Pokemon
|
||||
if (targetStats.Hp < 0)
|
||||
{
|
||||
//Could heal only for half HP?
|
||||
Stats[targetUser.Id].Hp = (targetStats.MaxHp / 2);
|
||||
_stats[targetUser.Id].Hp = (targetStats.MaxHp / 2);
|
||||
if (target == "yourself")
|
||||
{
|
||||
await Context.Channel.SendMessageAsync($"You revived yourself with one {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("revive_yourself", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await ReplyConfirmLocalized("revive_other", Format.Bold(targetUser.ToString()), NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
||||
}
|
||||
await ReplyConfirmLocalized("healed", Format.Bold(targetUser.ToString()), NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Context.Channel.SendMessageAsync($"{user.Mention} revived {targetUser.Mention} with one {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
await Context.Channel.SendMessageAsync($"{user.Mention} healed {targetUser.Mention} with one {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
await Context.Channel.SendMessageAsync($"{targetUser.Mention} already has full HP!").ConfigureAwait(false);
|
||||
await ErrorLocalized("already_full", Format.Bold(targetUser.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,15 +276,9 @@ namespace NadekoBot.Modules.Pokemon
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Type(IGuildUser targetUser = null)
|
||||
{
|
||||
IGuildUser user = (IGuildUser)Context.User;
|
||||
|
||||
if (targetUser == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
targetUser = targetUser ?? (IGuildUser)Context.User;
|
||||
var pType = GetPokeType(targetUser.Id);
|
||||
await Context.Channel.SendMessageAsync($"Type of {targetUser.Mention} is **{pType.Name.ToLowerInvariant()}**{pType.Icon}").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("type_of_user", Format.Bold(targetUser.ToString()), pType).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
@ -309,7 +291,7 @@ namespace NadekoBot.Modules.Pokemon
|
||||
var targetType = StringToPokemonType(typeTargeted);
|
||||
if (targetType == null)
|
||||
{
|
||||
await Context.Channel.EmbedAsync(PokemonTypes.Aggregate(new EmbedBuilder().WithDescription("List of the available types:"),
|
||||
await Context.Channel.EmbedAsync(_pokemonTypes.Aggregate(new EmbedBuilder().WithDescription("List of the available types:"),
|
||||
(eb, pt) => eb.AddField(efb => efb.WithName(pt.Name)
|
||||
.WithValue(pt.Icon)
|
||||
.WithIsInline(true)))
|
||||
@ -318,7 +300,7 @@ namespace NadekoBot.Modules.Pokemon
|
||||
}
|
||||
if (targetType == GetPokeType(user.Id))
|
||||
{
|
||||
await Context.Channel.SendMessageAsync($"Your type is already {targetType.Name.ToLowerInvariant()}{targetType.Icon}").ConfigureAwait(false);
|
||||
await ReplyErrorLocalized("already_that_type", targetType).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -326,20 +308,19 @@ namespace NadekoBot.Modules.Pokemon
|
||||
var amount = 1;
|
||||
if (amount > 0)
|
||||
{
|
||||
if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"{user.Mention} change type to {typeTargeted}", amount, true).ConfigureAwait(false))
|
||||
if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"{user} change type to {typeTargeted}", amount, true).ConfigureAwait(false))
|
||||
{
|
||||
try { await Context.Channel.SendMessageAsync($"{user.Mention} You don't have enough {NadekoBot.BotConfig.CurrencyName}s.").ConfigureAwait(false); } catch { }
|
||||
await ReplyErrorLocalized("no_currency", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Actually changing the type here
|
||||
Dictionary<ulong, string> setTypes;
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var pokeUsers = uow.PokeGame.GetAll();
|
||||
setTypes = pokeUsers.ToDictionary(x => x.UserId, y => y.type);
|
||||
var pokeUsers = uow.PokeGame.GetAll().ToArray();
|
||||
var setTypes = pokeUsers.ToDictionary(x => x.UserId, y => y.type);
|
||||
var pt = new UserPokeTypes
|
||||
{
|
||||
UserId = user.Id,
|
||||
@ -353,7 +334,7 @@ namespace NadekoBot.Modules.Pokemon
|
||||
else
|
||||
{
|
||||
//update user in db
|
||||
var pokeUserCmd = pokeUsers.Where(p => p.UserId == user.Id).FirstOrDefault();
|
||||
var pokeUserCmd = pokeUsers.FirstOrDefault(p => p.UserId == user.Id);
|
||||
pokeUserCmd.type = targetType.Name;
|
||||
uow.PokeGame.Update(pokeUserCmd);
|
||||
}
|
||||
@ -361,9 +342,10 @@ namespace NadekoBot.Modules.Pokemon
|
||||
}
|
||||
|
||||
//Now for the response
|
||||
await Context.Channel.SendMessageAsync($"Set type of {user.Mention} to {typeTargeted}{targetType.Icon} for a {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false);
|
||||
await ReplyConfirmLocalized("settype_success",
|
||||
targetType,
|
||||
NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,9 @@ namespace NadekoBot.Modules.Pokemon
|
||||
public List<PokemonMultiplier> Multipliers { get; set; }
|
||||
public string Icon { get; set; }
|
||||
public string[] Moves { get; set; }
|
||||
|
||||
public override string ToString() =>
|
||||
Icon + "**" + Name.ToLowerInvariant() + "**" + Icon;
|
||||
}
|
||||
public class PokemonMultiplier
|
||||
{
|
||||
|
@ -230,7 +230,7 @@ namespace NadekoBot.Modules.Searches
|
||||
var link = "http://anilist.co/api/anime/search/" + Uri.EscapeUriString(query);
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
var res = await http.GetStringAsync("http://anilist.co/api/anime/search/" + Uri.EscapeUriString(query) + $"?access_token={anilistToken}").ConfigureAwait(false);
|
||||
var res = await http.GetStringAsync(link + $"?access_token={anilistToken}").ConfigureAwait(false);
|
||||
var smallObj = JArray.Parse(res)[0];
|
||||
var aniData = await http.GetStringAsync("http://anilist.co/api/anime/" + smallObj["id"] + $"?access_token={anilistToken}").ConfigureAwait(false);
|
||||
|
||||
|
@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Searches
|
||||
|
||||
var rankimg = $"{model.Competitive.rank_img}";
|
||||
var rank = $"{model.Competitive.rank}";
|
||||
var competitiveplay = $"{model.Games.Competitive.played}";
|
||||
//var competitiveplay = $"{model.Games.Competitive.played}";
|
||||
if (string.IsNullOrWhiteSpace(rank))
|
||||
{
|
||||
var embed = new EmbedBuilder()
|
||||
|
@ -12,7 +12,8 @@ namespace NadekoBot.Modules.Searches
|
||||
[Group]
|
||||
public class PlaceCommands : ModuleBase
|
||||
{
|
||||
private static string typesStr { get; } = $"`List of \"{NadekoBot.ModulePrefixes[typeof(Searches).Name]}place\" tags:`\n" + String.Join(", ", Enum.GetNames(typeof(PlaceType)));
|
||||
private static string typesStr { get; } =
|
||||
string.Format("`List of \"{0}place\" tags:`\n", NadekoBot.ModulePrefixes[typeof(Searches).Name]) + String.Join(", ", Enum.GetNames(typeof(PlaceType)));
|
||||
|
||||
public enum PlaceType
|
||||
{
|
||||
|
@ -103,19 +103,23 @@ namespace NadekoBot.Modules.Searches
|
||||
oldStatus.IsLive != newStatus.IsLive)
|
||||
{
|
||||
var server = NadekoBot.Client.GetGuild(fs.GuildId);
|
||||
if (server == null)
|
||||
return;
|
||||
var channel = server.GetTextChannel(fs.ChannelId);
|
||||
var channel = server?.GetTextChannel(fs.ChannelId);
|
||||
if (channel == null)
|
||||
return;
|
||||
try
|
||||
{
|
||||
var msg = await channel.EmbedAsync(fs.GetEmbed(newStatus)).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}));
|
||||
|
||||
FirstPass = false;
|
||||
|
@ -28,7 +28,7 @@ using System.Xml.Linq;
|
||||
namespace NadekoBot.Modules.Searches
|
||||
{
|
||||
[NadekoModule("Searches", "~")]
|
||||
public partial class Searches : DiscordModule
|
||||
public partial class Searches : NadekoModule
|
||||
{
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Weather([Remainder] string query)
|
||||
@ -499,12 +499,12 @@ namespace NadekoBot.Modules.Searches
|
||||
|
||||
var data = JsonConvert.DeserializeObject<DefineModel>(res);
|
||||
|
||||
var sense = data.Results.Where(x => x.Senses != null && x.Senses[0].Definition != null).FirstOrDefault()?.Senses[0];
|
||||
var sense = data.Results.FirstOrDefault(x => x.Senses?[0].Definition != null)?.Senses[0];
|
||||
|
||||
if (sense?.Definition == null)
|
||||
return;
|
||||
|
||||
string definition = sense.Definition.ToString();
|
||||
var definition = sense.Definition.ToString();
|
||||
if (!(sense.Definition is string))
|
||||
definition = ((JArray)JToken.Parse(sense.Definition.ToString())).First.ToString();
|
||||
|
||||
@ -536,7 +536,7 @@ namespace NadekoBot.Modules.Searches
|
||||
}
|
||||
|
||||
await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||
string res = "";
|
||||
var res = "";
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
http.DefaultRequestHeaders.Clear();
|
||||
@ -548,7 +548,7 @@ namespace NadekoBot.Modules.Searches
|
||||
{
|
||||
var items = JObject.Parse(res);
|
||||
var item = items["defs"]["def"];
|
||||
var hashtag = item["hashtag"].ToString();
|
||||
//var hashtag = item["hashtag"].ToString();
|
||||
var link = item["uri"].ToString();
|
||||
var desc = item["text"].ToString();
|
||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||
|
@ -32,7 +32,6 @@ namespace NadekoBot.Modules.Utility
|
||||
var voicechn = (await guild.GetVoiceChannelsAsync()).Count();
|
||||
|
||||
var createdAt = new DateTime(2015, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(guild.Id >> 22);
|
||||
var sb = new StringBuilder();
|
||||
var users = await guild.GetUsersAsync().ConfigureAwait(false);
|
||||
var features = string.Join("\n", guild.Features);
|
||||
if (string.IsNullOrWhiteSpace(features))
|
||||
@ -45,13 +44,13 @@ namespace NadekoBot.Modules.Utility
|
||||
.AddField(fb => fb.WithName("**Members**").WithValue(users.Count.ToString()).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Text Channels**").WithValue(textchn.ToString()).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Voice Channels**").WithValue(voicechn.ToString()).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt:dd.MM.yyyy HH:mm}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Region**").WithValue(guild.VoiceRegionId.ToString()).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Roles**").WithValue((guild.Roles.Count - 1).ToString()).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Features**").WithValue(features).WithIsInline(true))
|
||||
.WithImageUrl(guild.IconUrl)
|
||||
.WithColor(NadekoBot.OkColor);
|
||||
if (guild.Emojis.Count() > 0)
|
||||
if (guild.Emojis.Any())
|
||||
{
|
||||
embed.AddField(fb => fb.WithName($"**Custom Emojis ({guild.Emojis.Count})**").WithValue(string.Join(" ", guild.Emojis.Shuffle().Take(25).Select(e => $"{e.Name} <:{e.Name}:{e.Id}>"))));
|
||||
}
|
||||
@ -71,7 +70,7 @@ namespace NadekoBot.Modules.Utility
|
||||
.WithTitle(ch.Name)
|
||||
.WithDescription(ch.Topic?.SanitizeMentions())
|
||||
.AddField(fb => fb.WithName("**ID**").WithValue(ch.Id.ToString()).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt:dd.MM.yyyy HH:mm}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Users**").WithValue(usercount.ToString()).WithIsInline(true))
|
||||
.WithColor(NadekoBot.OkColor);
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
@ -81,7 +80,6 @@ namespace NadekoBot.Modules.Utility
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task UserInfo(IGuildUser usr = null)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
var user = usr ?? Context.User as IGuildUser;
|
||||
|
||||
if (user == null)
|
||||
@ -95,7 +93,7 @@ namespace NadekoBot.Modules.Utility
|
||||
}
|
||||
embed.AddField(fb => fb.WithName("**ID**").WithValue(user.Id.ToString()).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Joined Server**").WithValue($"{user.JoinedAt?.ToString("dd.MM.yyyy HH:mm") ?? "unavail."}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Joined Discord**").WithValue($"{user.CreatedAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Joined Discord**").WithValue($"{user.CreatedAt:dd.MM.yyyy HH:mm}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count - 1})** - {string.Join("\n", user.GetRoles().Take(10).Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true))
|
||||
.WithColor(NadekoBot.OkColor);
|
||||
|
||||
|
@ -91,7 +91,7 @@ namespace NadekoBot.Modules.Utility
|
||||
public void Reset()
|
||||
{
|
||||
source.Cancel();
|
||||
var t = Task.Run(Run);
|
||||
var _ = Task.Run(Run);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
|
@ -45,15 +45,15 @@ namespace NadekoBot.Modules.Utility
|
||||
|
||||
foreach (var r in reminders)
|
||||
{
|
||||
try { var t = StartReminder(r); } catch (Exception ex) { _log.Warn(ex); }
|
||||
Task.Run(() => StartReminder(r));
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task StartReminder(Reminder r)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
var twoMins = new TimeSpan(0, 2, 0);
|
||||
TimeSpan time = r.When - now;
|
||||
|
||||
var time = r.When - now;
|
||||
|
||||
if (time.TotalMilliseconds > int.MaxValue)
|
||||
return;
|
||||
|
@ -21,7 +21,7 @@ using NadekoBot.Services;
|
||||
namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
[NadekoModule("Utility", ".")]
|
||||
public partial class Utility : DiscordModule
|
||||
public partial class Utility : NadekoModule
|
||||
{
|
||||
private static ConcurrentDictionary<ulong, Timer> rotatingRoleColors = new ConcurrentDictionary<ulong, Timer>();
|
||||
|
||||
@ -468,7 +468,6 @@ namespace NadekoBot.Modules.Utility
|
||||
[OwnerOnly]
|
||||
public async Task SaveChat(int cnt)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var msgs = new List<IMessage>(cnt);
|
||||
await Context.Channel.GetMessagesAsync(cnt).ForEachAsync(dled => msgs.AddRange(dled)).ConfigureAwait(false);
|
||||
|
||||
|
@ -14,8 +14,12 @@ using System.Collections.Generic;
|
||||
using NadekoBot.Modules.Permissions;
|
||||
using NadekoBot.TypeReaders;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using NadekoBot.Modules.Music;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using System.Resources;
|
||||
using NadekoBot.Resources;
|
||||
|
||||
namespace NadekoBot
|
||||
{
|
||||
@ -29,7 +33,10 @@ namespace NadekoBot
|
||||
public static CommandService CommandService { get; private set; }
|
||||
public static CommandHandler CommandHandler { get; private set; }
|
||||
public static DiscordShardedClient Client { get; private set; }
|
||||
public static BotCredentials Credentials { get; private set; }
|
||||
public static BotCredentials Credentials { get; }
|
||||
|
||||
public static Localization Localization { get; private set; }
|
||||
public static ResourceManager ResponsesResourceManager { get; } = new ResourceManager(typeof(ResponseStrings));
|
||||
|
||||
public static GoogleApiService Google { get; private set; }
|
||||
public static StatsService Stats { get; private set; }
|
||||
@ -38,7 +45,7 @@ namespace NadekoBot
|
||||
public static ConcurrentDictionary<string, string> ModulePrefixes { get; private set; }
|
||||
public static bool Ready { get; private set; }
|
||||
|
||||
public static IEnumerable<GuildConfig> AllGuildConfigs { get; }
|
||||
public static ImmutableArray<GuildConfig> AllGuildConfigs { get; }
|
||||
public static BotConfig BotConfig { get; }
|
||||
|
||||
static NadekoBot()
|
||||
@ -48,7 +55,7 @@ namespace NadekoBot
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs();
|
||||
AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs().ToImmutableArray();
|
||||
BotConfig = uow.BotConfig.GetOrCreate();
|
||||
OkColor = new Color(Convert.ToUInt32(BotConfig.OkColor, 16));
|
||||
ErrorColor = new Color(Convert.ToUInt32(BotConfig.ErrorColor, 16));
|
||||
@ -79,6 +86,7 @@ namespace NadekoBot
|
||||
#endif
|
||||
|
||||
//initialize Services
|
||||
Localization = new Localization(NadekoBot.BotConfig.Locale, NadekoBot.AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale));
|
||||
CommandService = new CommandService(new CommandServiceConfig() {
|
||||
CaseSensitiveCommands = false,
|
||||
DefaultRunMode = RunMode.Sync
|
||||
@ -102,13 +110,16 @@ namespace NadekoBot
|
||||
CommandService.AddTypeReader<ModuleInfo>(new ModuleTypeReader());
|
||||
CommandService.AddTypeReader<IGuild>(new GuildTypeReader());
|
||||
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
//connect
|
||||
await Client.LoginAsync(TokenType.Bot, Credentials.Token).ConfigureAwait(false);
|
||||
await Client.ConnectAsync().ConfigureAwait(false);
|
||||
//await Client.DownloadAllUsersAsync().ConfigureAwait(false);
|
||||
Stats.Initialize();
|
||||
|
||||
_log.Info("Connected");
|
||||
sw.Stop();
|
||||
_log.Info("Connected in " + sw.Elapsed.TotalSeconds.ToString("F2"));
|
||||
|
||||
//load commands and prefixes
|
||||
|
||||
|
3
src/NadekoBot/NadekoBot.xproj.DotSettings
Normal file
3
src/NadekoBot/NadekoBot.xproj.DotSettings
Normal file
@ -0,0 +1,3 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cadministration_005Ccommands/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=modules_005Cgambling_005Ccommands/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
83
src/NadekoBot/Resources/CommandStrings.Designer.cs
generated
83
src/NadekoBot/Resources/CommandStrings.Designer.cs
generated
@ -3704,6 +3704,87 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to languageset langset.
|
||||
/// </summary>
|
||||
public static string languageset_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("languageset_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language..
|
||||
/// </summary>
|
||||
public static string languageset_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("languageset_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}langset de-DE ` or `{0}langset default`.
|
||||
/// </summary>
|
||||
public static string languageset_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("languageset_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to langsetdefault langsetd.
|
||||
/// </summary>
|
||||
public static string languagesetdefault_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("languagesetdefault_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language..
|
||||
/// </summary>
|
||||
public static string languagesetdefault_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("languagesetdefault_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}langsetd en-US` or `{0}langsetd default`.
|
||||
/// </summary>
|
||||
public static string languagesetdefault_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("languagesetdefault_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to languageslist langli.
|
||||
/// </summary>
|
||||
public static string languageslist_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("languageslist_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to List of languages for which translation (or part of it) exist atm..
|
||||
/// </summary>
|
||||
public static string languageslist_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("languageslist_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}langli`.
|
||||
/// </summary>
|
||||
public static string languageslist_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("languageslist_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to lcsc.
|
||||
/// </summary>
|
||||
@ -8988,7 +9069,7 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to {0}yodify I was once an adventurer like you` or `{0}yoda my feelings hurt`.
|
||||
/// Looks up a localized string similar to `{0}yoda my feelings hurt`.
|
||||
/// </summary>
|
||||
public static string yodify_usage {
|
||||
get {
|
||||
|
@ -2698,7 +2698,7 @@
|
||||
<value>Translates your normal sentences into Yoda styled sentences!</value>
|
||||
</data>
|
||||
<data name="yodify_usage" xml:space="preserve">
|
||||
<value>{0}yodify I was once an adventurer like you` or `{0}yoda my feelings hurt`</value>
|
||||
<value>`{0}yoda my feelings hurt`</value>
|
||||
</data>
|
||||
<data name="attack_cmd" xml:space="preserve">
|
||||
<value>attack</value>
|
||||
@ -3114,4 +3114,35 @@
|
||||
<data name="timezone_usage" xml:space="preserve">
|
||||
<value>`{0}timezone`</value>
|
||||
</data>
|
||||
<<<<<<< HEAD
|
||||
</root>
|
||||
=======
|
||||
<data name="languagesetdefault_cmd" xml:space="preserve">
|
||||
<value>langsetdefault langsetd</value>
|
||||
</data>
|
||||
<data name="languagesetdefault_desc" xml:space="preserve">
|
||||
<value>Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language.</value>
|
||||
</data>
|
||||
<data name="languagesetdefault_usage" xml:space="preserve">
|
||||
<value>`{0}langsetd en-US` or `{0}langsetd default`</value>
|
||||
</data>
|
||||
<data name="languageset_cmd" xml:space="preserve">
|
||||
<value>languageset langset</value>
|
||||
</data>
|
||||
<data name="languageset_desc" xml:space="preserve">
|
||||
<value>Sets this server's response language If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language.</value>
|
||||
</data>
|
||||
<data name="languageset_usage" xml:space="preserve">
|
||||
<value>`{0}langset de-DE ` or `{0}langset default`</value>
|
||||
</data>
|
||||
<data name="languageslist_cmd" xml:space="preserve">
|
||||
<value>languageslist langli</value>
|
||||
</data>
|
||||
<data name="languageslist_desc" xml:space="preserve">
|
||||
<value>List of languages for which translation (or part of it) exist atm.</value>
|
||||
</data>
|
||||
<data name="languageslist_usage" xml:space="preserve">
|
||||
<value>`{0}langli`</value>
|
||||
</data>
|
||||
</root>
|
||||
>>>>>>> Kwoth/dev
|
||||
|
2723
src/NadekoBot/Resources/ResponseStrings.Designer.cs
generated
2723
src/NadekoBot/Resources/ResponseStrings.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@ -117,4 +117,930 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="clashofclans_base_already_claimed" xml:space="preserve">
|
||||
<value>That base is already claimed or destroyed.</value>
|
||||
</data>
|
||||
<data name="clashofclans_base_already_destroyed" xml:space="preserve">
|
||||
<value>That base is already destroyed.</value>
|
||||
</data>
|
||||
<data name="clashofclans_base_already_unclaimed" xml:space="preserve">
|
||||
<value>That base is not claimed.</value>
|
||||
</data>
|
||||
<data name="clashofclans_base_destroyed" xml:space="preserve">
|
||||
<value>**DESTROYED** base #{0} in a war against {1}</value>
|
||||
</data>
|
||||
<data name="clashofclans_base_unclaimed" xml:space="preserve">
|
||||
<value>{0} has **UNCLAIMED** base #{1} in a war against {2}</value>
|
||||
</data>
|
||||
<data name="clashofclans_claimed_base" xml:space="preserve">
|
||||
<value>{0} claimed a base #{1} in a war against {2}</value>
|
||||
</data>
|
||||
<data name="clashofclans_claimed_other" xml:space="preserve">
|
||||
<value>@{0} You already claimed base #{1}. You can't claim a new one.</value>
|
||||
</data>
|
||||
<data name="clashofclans_claim_expired" xml:space="preserve">
|
||||
<value>Claim from @{0} for a war against {1} has expired.</value>
|
||||
</data>
|
||||
<data name="clashofclans_enemy" xml:space="preserve">
|
||||
<value>Enemy</value>
|
||||
</data>
|
||||
<data name="clashofclans_info_about_war" xml:space="preserve">
|
||||
<value>Info about war against {0}</value>
|
||||
</data>
|
||||
<data name="clashofclans_invalid_base_number" xml:space="preserve">
|
||||
<value>Invalid base number.</value>
|
||||
</data>
|
||||
<data name="clashofclans_invalid_size" xml:space="preserve">
|
||||
<value>Not a Valid war size.</value>
|
||||
</data>
|
||||
<data name="clashofclans_list_active_wars" xml:space="preserve">
|
||||
<value>List Of Active Wars</value>
|
||||
</data>
|
||||
<data name="clashofclans_not_claimed" xml:space="preserve">
|
||||
<value>not claimed</value>
|
||||
</data>
|
||||
<data name="clashofclans_not_partic" xml:space="preserve">
|
||||
<value>You are not participating in that war.</value>
|
||||
</data>
|
||||
<data name="clashofclans_not_partic_or_destroyed" xml:space="preserve">
|
||||
<value>@{0} You are either not participating in that war, or that base is already destroyed.</value>
|
||||
</data>
|
||||
<data name="clashofclans_no_active_wars" xml:space="preserve">
|
||||
<value>No active wars.</value>
|
||||
</data>
|
||||
<data name="clashofclans_size" xml:space="preserve">
|
||||
<value>Size</value>
|
||||
</data>
|
||||
<data name="clashofclans_war_already_started" xml:space="preserve">
|
||||
<value>War against {0} has already started.</value>
|
||||
</data>
|
||||
<data name="clashofclans_war_created" xml:space="preserve">
|
||||
<value>War against {0} created.</value>
|
||||
</data>
|
||||
<data name="clashofclans_war_ended" xml:space="preserve">
|
||||
<value>War against {0} ended.</value>
|
||||
</data>
|
||||
<data name="clashofclans_war_not_exist" xml:space="preserve">
|
||||
<value>That war does not exist.</value>
|
||||
</data>
|
||||
<data name="clashofclans_war_started" xml:space="preserve">
|
||||
<value>War against {0} started!</value>
|
||||
</data>
|
||||
<data name="customreactions_all_stats_cleared" xml:space="preserve">
|
||||
<value>All custom reaction stats cleared.</value>
|
||||
</data>
|
||||
<data name="customreactions_deleted" xml:space="preserve">
|
||||
<value>Custom Reaction deleted</value>
|
||||
</data>
|
||||
<data name="customreactions_insuff_perms" xml:space="preserve">
|
||||
<value>Insufficient permissions. Requires Bot ownership for global custom reactions, and Administrator for server custom reactions.</value>
|
||||
</data>
|
||||
<data name="customreactions_list_all" xml:space="preserve">
|
||||
<value>List of all custom reactions</value>
|
||||
</data>
|
||||
<data name="customreactions_name" xml:space="preserve">
|
||||
<value>Custom Reactions</value>
|
||||
</data>
|
||||
<data name="customreactions_new_cust_react" xml:space="preserve">
|
||||
<value>New Custom Reaction</value>
|
||||
</data>
|
||||
<data name="customreactions_no_found" xml:space="preserve">
|
||||
<value>No custom reactions found.</value>
|
||||
</data>
|
||||
<data name="customreactions_no_found_id" xml:space="preserve">
|
||||
<value>No custom reaction found with that id.</value>
|
||||
</data>
|
||||
<data name="customreactions_response" xml:space="preserve">
|
||||
<value>Response</value>
|
||||
</data>
|
||||
<data name="customreactions_stats" xml:space="preserve">
|
||||
<value>Custom Reaction Stats</value>
|
||||
</data>
|
||||
<data name="customreactions_stats_cleared" xml:space="preserve">
|
||||
<value>Stats cleared for {0} custom reaction.</value>
|
||||
</data>
|
||||
<data name="customreactions_stats_not_found" xml:space="preserve">
|
||||
<value>No stats for that trigger found, no action taken.</value>
|
||||
</data>
|
||||
<data name="customreactions_trigger" xml:space="preserve">
|
||||
<value>Trigger</value>
|
||||
</data>
|
||||
<data name="nsfw_autohentai_stopped" xml:space="preserve">
|
||||
<value>Autohentai stopped.</value>
|
||||
</data>
|
||||
<data name="nsfw_not_found" xml:space="preserve">
|
||||
<value>No results found.</value>
|
||||
</data>
|
||||
<data name="pokemon_already_fainted" xml:space="preserve">
|
||||
<value>{0} has already fainted.</value>
|
||||
</data>
|
||||
<data name="pokemon_already_full" xml:space="preserve">
|
||||
<value>{0} already has full HP.</value>
|
||||
</data>
|
||||
<data name="pokemon_already_that_type" xml:space="preserve">
|
||||
<value>Your type is already {0}</value>
|
||||
</data>
|
||||
<data name="pokemon_attack" xml:space="preserve">
|
||||
<value>used {0}{1} on {2}{3} for {4} damage.</value>
|
||||
<comment>Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage.</comment>
|
||||
</data>
|
||||
<data name="pokemon_cant_attack_again" xml:space="preserve">
|
||||
<value>You can't attack again without retaliation!</value>
|
||||
</data>
|
||||
<data name="pokemon_cant_attack_yourself" xml:space="preserve">
|
||||
<value>You can't attack yourself.</value>
|
||||
</data>
|
||||
<data name="pokemon_fainted" xml:space="preserve">
|
||||
<value>{0} has fainted!</value>
|
||||
</data>
|
||||
<data name="pokemon_healed" xml:space="preserve">
|
||||
<value>healed {0} with one {1}</value>
|
||||
</data>
|
||||
<data name="pokemon_hp_remaining" xml:space="preserve">
|
||||
<value>{0} has {1} HP remaining.</value>
|
||||
</data>
|
||||
<data name="pokemon_invalid_move" xml:space="preserve">
|
||||
<value>You can't use {0}. Type `{1}ml` to see a list of moves you can use.</value>
|
||||
</data>
|
||||
<data name="pokemon_moves" xml:space="preserve">
|
||||
<value>Movelist for {0} type</value>
|
||||
</data>
|
||||
<data name="pokemon_not_effective" xml:space="preserve">
|
||||
<value>It's not effective.</value>
|
||||
</data>
|
||||
<data name="pokemon_no_currency" xml:space="preserve">
|
||||
<value>You don't have enough {0}</value>
|
||||
</data>
|
||||
<data name="pokemon_revive_other" xml:space="preserve">
|
||||
<value>revived {0} with one {1}</value>
|
||||
</data>
|
||||
<data name="pokemon_revive_yourself" xml:space="preserve">
|
||||
<value>You revived yourself with one {0}</value>
|
||||
</data>
|
||||
<data name="pokemon_settype_success" xml:space="preserve">
|
||||
<value>Your type has been changed to {0} for a {1}</value>
|
||||
</data>
|
||||
<data name="pokemon_somewhat_effective" xml:space="preserve">
|
||||
<value>It's somewhat effective.</value>
|
||||
</data>
|
||||
<data name="pokemon_super_effective" xml:space="preserve">
|
||||
<value>It's super effective!</value>
|
||||
</data>
|
||||
<data name="pokemon_too_many_moves" xml:space="preserve">
|
||||
<value>You used too many moves in a row, so you can't move!</value>
|
||||
</data>
|
||||
<data name="pokemon_type_of_user" xml:space="preserve">
|
||||
<value>Type of {0} is {1}</value>
|
||||
</data>
|
||||
<data name="pokemon_user_not_found" xml:space="preserve">
|
||||
<value>User not found.</value>
|
||||
</data>
|
||||
<data name="pokemon_you_fainted" xml:space="preserve">
|
||||
<value>You fainted, so you are not able to move!</value>
|
||||
</data>
|
||||
<data name="administration_aar_disabled" xml:space="preserve">
|
||||
<value>**Auto assign role** on user join is now **disabled**.</value>
|
||||
</data>
|
||||
<data name="administration_aar_enabled" xml:space="preserve">
|
||||
<value>**Auto assign role** on user join is now **enabled**.</value>
|
||||
</data>
|
||||
<data name="administration_attachments" xml:space="preserve">
|
||||
<value>Attachments</value>
|
||||
</data>
|
||||
<data name="administration_avatar_changed" xml:space="preserve">
|
||||
<value>Avatar Changed</value>
|
||||
</data>
|
||||
<data name="administration_bandm" xml:space="preserve">
|
||||
<value>You have been banned from {0} server.
|
||||
Reason: {1}</value>
|
||||
</data>
|
||||
<data name="administration_banned_pl" xml:space="preserve">
|
||||
<value>banned</value>
|
||||
<comment>PLURAL</comment>
|
||||
</data>
|
||||
<data name="administration_banned_user" xml:space="preserve">
|
||||
<value>User Banned</value>
|
||||
</data>
|
||||
<data name="administration_bot_name" xml:space="preserve">
|
||||
<value>Bot name changed to {0}</value>
|
||||
</data>
|
||||
<data name="administration_bot_status" xml:space="preserve">
|
||||
<value>Bot status changed to {0}</value>
|
||||
</data>
|
||||
<data name="administration_byedel_off" xml:space="preserve">
|
||||
<value>Automatic deletion of bye messages has been disabled.</value>
|
||||
</data>
|
||||
<data name="administration_byedel_on" xml:space="preserve">
|
||||
<value>Bye messages will be deleted after {0} seconds.</value>
|
||||
</data>
|
||||
<data name="administration_byemsg_cur" xml:space="preserve">
|
||||
<value>Current bye message: {0}</value>
|
||||
</data>
|
||||
<data name="administration_byemsg_enable" xml:space="preserve">
|
||||
<value>Enable bye messages by typing {0}</value>
|
||||
</data>
|
||||
<data name="administration_byemsg_new" xml:space="preserve">
|
||||
<value>New bye message set.</value>
|
||||
</data>
|
||||
<data name="administration_bye_off" xml:space="preserve">
|
||||
<value>Bye announcements disabled.</value>
|
||||
</data>
|
||||
<data name="administration_bye_on" xml:space="preserve">
|
||||
<value>Bye announcements enabled on this channel.</value>
|
||||
</data>
|
||||
<data name="administration_ch_name_change" xml:space="preserve">
|
||||
<value>Channel Name Changed</value>
|
||||
</data>
|
||||
<data name="administration_ch_old_name" xml:space="preserve">
|
||||
<value>Old Name</value>
|
||||
</data>
|
||||
<data name="administration_ch_topic_change" xml:space="preserve">
|
||||
<value>Channel Topic Changed</value>
|
||||
</data>
|
||||
<data name="administration_cleaned_up" xml:space="preserve">
|
||||
<value>Cleaned up.</value>
|
||||
</data>
|
||||
<data name="administration_content" xml:space="preserve">
|
||||
<value>Content</value>
|
||||
</data>
|
||||
<data name="administration_cr" xml:space="preserve">
|
||||
<value>Sucessfully created role {0}</value>
|
||||
</data>
|
||||
<data name="administration_createtextchan" xml:space="preserve">
|
||||
<value>Text channel {0} created.</value>
|
||||
</data>
|
||||
<data name="administration_createvoich" xml:space="preserve">
|
||||
<value>Voice channel {0} created.</value>
|
||||
</data>
|
||||
<data name="administration_deafen" xml:space="preserve">
|
||||
<value>Deafen successful.</value>
|
||||
</data>
|
||||
<data name="administration_deleted_server" xml:space="preserve">
|
||||
<value>Deleted server {0}</value>
|
||||
</data>
|
||||
<data name="administration_delmsg_off" xml:space="preserve">
|
||||
<value>Stopped automatic deletion of successful command invokations.</value>
|
||||
</data>
|
||||
<data name="administration_delmsg_on" xml:space="preserve">
|
||||
<value>Now automatically deleting sucessful command invokations.</value>
|
||||
</data>
|
||||
<data name="administration_deltextchan" xml:space="preserve">
|
||||
<value>Text channel {0} deleted.</value>
|
||||
</data>
|
||||
<data name="administration_delvoich" xml:space="preserve">
|
||||
<value>Voice channel {0} deleted.</value>
|
||||
</data>
|
||||
<data name="administration_dm_from" xml:space="preserve">
|
||||
<value>DM from</value>
|
||||
</data>
|
||||
<data name="administration_donadd" xml:space="preserve">
|
||||
<value>Sucessfully added a new donator.Total donated amount from this user: {0} 👑</value>
|
||||
</data>
|
||||
<data name="administration_donators" xml:space="preserve">
|
||||
<value>Thanks to the people listed below for making this project hjappen!</value>
|
||||
</data>
|
||||
<data name="administration_fwall_start" xml:space="preserve">
|
||||
<value>I will forward DMs to all owners.</value>
|
||||
</data>
|
||||
<data name="administration_fwall_stop" xml:space="preserve">
|
||||
<value>I will forward DMs only to the first owner.</value>
|
||||
</data>
|
||||
<data name="administration_fwdm_start" xml:space="preserve">
|
||||
<value>I will forward DMs from now on.</value>
|
||||
</data>
|
||||
<data name="administration_fwdm_stop" xml:space="preserve">
|
||||
<value>I will stop forwarding DMs from now on.</value>
|
||||
</data>
|
||||
<data name="administration_greetdel_off" xml:space="preserve">
|
||||
<value>Automatic deletion of greet messages has been disabled.</value>
|
||||
</data>
|
||||
<data name="administration_greetdel_on" xml:space="preserve">
|
||||
<value>Greet messages will be deleted after {0} seconds.</value>
|
||||
</data>
|
||||
<data name="administration_greetdmmsg_cur" xml:space="preserve">
|
||||
<value>Current DM greet message: {0}</value>
|
||||
</data>
|
||||
<data name="administration_greetdmmsg_enable" xml:space="preserve">
|
||||
<value>Enable DM greet messages by typing {0}</value>
|
||||
</data>
|
||||
<data name="administration_greetdmmsg_new" xml:space="preserve">
|
||||
<value>New DM greet message set.</value>
|
||||
</data>
|
||||
<data name="administration_greetdm_off" xml:space="preserve">
|
||||
<value>DM greet announcements disabled.</value>
|
||||
</data>
|
||||
<data name="administration_greetdm_on" xml:space="preserve">
|
||||
<value>DM greet announcements enabled.</value>
|
||||
</data>
|
||||
<data name="administration_greetmsg_cur" xml:space="preserve">
|
||||
<value>Current greet message: {0}</value>
|
||||
</data>
|
||||
<data name="administration_greetmsg_enable" xml:space="preserve">
|
||||
<value>Enable greet messages by typing {0}</value>
|
||||
</data>
|
||||
<data name="administration_greetmsg_new" xml:space="preserve">
|
||||
<value>New greet message set.</value>
|
||||
</data>
|
||||
<data name="administration_greet_off" xml:space="preserve">
|
||||
<value>Greet announcements disabled.</value>
|
||||
</data>
|
||||
<data name="administration_greet_on" xml:space="preserve">
|
||||
<value>Greet announcements enabled on this channel.</value>
|
||||
</data>
|
||||
<data name="administration_hierarchy" xml:space="preserve">
|
||||
<value>You can't use this command on users with a role higher or equal to yours in the role hierarchy.</value>
|
||||
</data>
|
||||
<data name="administration_images_loaded" xml:space="preserve">
|
||||
<value>Images loaded after {0} seconds!</value>
|
||||
</data>
|
||||
<data name="administration_invalid_format" xml:space="preserve">
|
||||
<value>Invalid input format.</value>
|
||||
</data>
|
||||
<data name="administration_invalid_params" xml:space="preserve">
|
||||
<value>Invalid parameters.</value>
|
||||
</data>
|
||||
<data name="administration_joined" xml:space="preserve">
|
||||
<value>{0} has joined {1}</value>
|
||||
</data>
|
||||
<data name="administration_kickdm" xml:space="preserve">
|
||||
<value>You have been kicked from {0} server.
|
||||
Reason: {1}</value>
|
||||
</data>
|
||||
<data name="administration_kicked_user" xml:space="preserve">
|
||||
<value>User Kicked</value>
|
||||
</data>
|
||||
<data name="administration_lang_list" xml:space="preserve">
|
||||
<value>List Of Languages
|
||||
{0}</value>
|
||||
</data>
|
||||
<data name="administration_lang_set" xml:space="preserve">
|
||||
<value>Your server's locale is now {0} - {1}</value>
|
||||
</data>
|
||||
<data name="administration_lang_set_bot" xml:space="preserve">
|
||||
<value>Bot's default locale is now {0} - {1}</value>
|
||||
</data>
|
||||
<data name="administration_lang_set_bot_show" xml:space="preserve">
|
||||
<value>Bot's language is set to {0} - {0}</value>
|
||||
</data>
|
||||
<data name="administration_lang_set_fail" xml:space="preserve">
|
||||
<value>Failed setting locale. Revisit this command's help.</value>
|
||||
</data>
|
||||
<data name="administration_lang_set_show" xml:space="preserve">
|
||||
<value>This server's language is set to {0} - {0}</value>
|
||||
</data>
|
||||
<data name="administration_left" xml:space="preserve">
|
||||
<value>{0} has left {1}</value>
|
||||
</data>
|
||||
<data name="administration_left_server" xml:space="preserve">
|
||||
<value>Left server {0}</value>
|
||||
</data>
|
||||
<data name="administration_log" xml:space="preserve">
|
||||
<value>Logging {0} event in this channel.</value>
|
||||
</data>
|
||||
<data name="administration_log_all" xml:space="preserve">
|
||||
<value>Logging all events in this channel.</value>
|
||||
</data>
|
||||
<data name="administration_log_disabled" xml:space="preserve">
|
||||
<value>Logging disabled.</value>
|
||||
</data>
|
||||
<data name="administration_log_events" xml:space="preserve">
|
||||
<value>Log events you can subscribe to:</value>
|
||||
</data>
|
||||
<data name="administration_log_ignore" xml:space="preserve">
|
||||
<value>Logging will ignore {0}</value>
|
||||
</data>
|
||||
<data name="administration_log_not_ignore" xml:space="preserve">
|
||||
<value>Logging will not ignore {0}</value>
|
||||
</data>
|
||||
<data name="administration_log_stop" xml:space="preserve">
|
||||
<value>Stopped logging {0} event.</value>
|
||||
</data>
|
||||
<data name="administration_menrole" xml:space="preserve">
|
||||
<value>{0} has invoked a mention on the following roles</value>
|
||||
</data>
|
||||
<data name="administration_message_from_bo" xml:space="preserve">
|
||||
<value>Message from {0} `[Bot Owner]`:</value>
|
||||
</data>
|
||||
<data name="administration_message_sent" xml:space="preserve">
|
||||
<value>Message sent.</value>
|
||||
</data>
|
||||
<data name="administration_moved" xml:space="preserve">
|
||||
<value>{0} moved from {1} to {2}</value>
|
||||
</data>
|
||||
<data name="administration_msg_del" xml:space="preserve">
|
||||
<value>Message Deleted in #{0}</value>
|
||||
</data>
|
||||
<data name="administration_msg_update" xml:space="preserve">
|
||||
<value>Message Updated in #{0}</value>
|
||||
</data>
|
||||
<data name="administration_muted_pl" xml:space="preserve">
|
||||
<value>Muted</value>
|
||||
<comment>PLURAL (users have been muted)</comment>
|
||||
</data>
|
||||
<data name="administration_muted_sn" xml:space="preserve">
|
||||
<value>Muted</value>
|
||||
<comment>singular "User muted."</comment>
|
||||
</data>
|
||||
<data name="administration_mute_error" xml:space="preserve">
|
||||
<value>I don't have the permission necessary for that most likely.</value>
|
||||
</data>
|
||||
<data name="administration_mute_role_set" xml:space="preserve">
|
||||
<value>New mute role set.</value>
|
||||
</data>
|
||||
<data name="administration_need_admin" xml:space="preserve">
|
||||
<value>I need **Administration** permission to do that.</value>
|
||||
</data>
|
||||
<data name="administration_new_msg" xml:space="preserve">
|
||||
<value>New Message</value>
|
||||
</data>
|
||||
<data name="administration_new_nick" xml:space="preserve">
|
||||
<value>New Nickname</value>
|
||||
</data>
|
||||
<data name="administration_new_topic" xml:space="preserve">
|
||||
<value>New Topic</value>
|
||||
</data>
|
||||
<data name="administration_nick_change" xml:space="preserve">
|
||||
<value>Nickname Changed</value>
|
||||
</data>
|
||||
<data name="administration_no_server" xml:space="preserve">
|
||||
<value>Can't find that server</value>
|
||||
</data>
|
||||
<data name="administration_no_shard_id" xml:space="preserve">
|
||||
<value>No shard with that ID found.</value>
|
||||
</data>
|
||||
<data name="administration_old_msg" xml:space="preserve">
|
||||
<value>Old Message</value>
|
||||
</data>
|
||||
<data name="administration_old_nick" xml:space="preserve">
|
||||
<value>Old Nickname</value>
|
||||
</data>
|
||||
<data name="administration_old_topic" xml:space="preserve">
|
||||
<value>Old Topic</value>
|
||||
</data>
|
||||
<data name="administration_perms" xml:space="preserve">
|
||||
<value>Error. Most likely I don't have sufficient permissions.</value>
|
||||
</data>
|
||||
<data name="administration_perms_reset" xml:space="preserve">
|
||||
<value>Permissions for this server are reset.</value>
|
||||
</data>
|
||||
<data name="administration_prot_active" xml:space="preserve">
|
||||
<value>Active Protections</value>
|
||||
</data>
|
||||
<data name="administration_prot_disable" xml:space="preserve">
|
||||
<value>{0} has been **disabled** on this server.</value>
|
||||
</data>
|
||||
<data name="administration_prot_enable" xml:space="preserve">
|
||||
<value>{0} Enabled</value>
|
||||
</data>
|
||||
<data name="administration_prot_error" xml:space="preserve">
|
||||
<value>Error. I need ManageRoles permission</value>
|
||||
</data>
|
||||
<data name="administration_prot_none" xml:space="preserve">
|
||||
<value>No protections enabled.</value>
|
||||
</data>
|
||||
<data name="administration_raid_cnt" xml:space="preserve">
|
||||
<value>User threshold must be between {0} and {1}.</value>
|
||||
</data>
|
||||
<data name="administration_raid_stats" xml:space="preserve">
|
||||
<value>If {0} or more users join within {1} seconds, I will {2} them.</value>
|
||||
</data>
|
||||
<data name="administration_raid_time" xml:space="preserve">
|
||||
<value>Time must be between {0} and {1} seconds.</value>
|
||||
</data>
|
||||
<data name="administration_rar" xml:space="preserve">
|
||||
<value>Successfully removed all roles from user {0}</value>
|
||||
</data>
|
||||
<data name="administration_rar_err" xml:space="preserve">
|
||||
<value>Failed to remove roles. I have insufficient permissions.</value>
|
||||
</data>
|
||||
<data name="administration_rc" xml:space="preserve">
|
||||
<value>Color of {0} role has been changed.</value>
|
||||
</data>
|
||||
<data name="administration_rc_not_exist" xml:space="preserve">
|
||||
<value>That role does not exist.</value>
|
||||
</data>
|
||||
<data name="administration_rc_params" xml:space="preserve">
|
||||
<value>The parameters specified are invalid.</value>
|
||||
</data>
|
||||
<data name="administration_rc_perms" xml:space="preserve">
|
||||
<value>Error occured due to invalid color or insufficient permissions.</value>
|
||||
</data>
|
||||
<data name="administration_remrole" xml:space="preserve">
|
||||
<value>Successfully removed role {0} from user {1}</value>
|
||||
</data>
|
||||
<data name="administration_remrole_err" xml:space="preserve">
|
||||
<value>Failed to remove role. I have insufficient permissions.</value>
|
||||
</data>
|
||||
<data name="administration_renrole" xml:space="preserve">
|
||||
<value>Role renamed.</value>
|
||||
</data>
|
||||
<data name="administration_renrole_err" xml:space="preserve">
|
||||
<value>Failed to rename role. I have insufficient permissions.</value>
|
||||
</data>
|
||||
<data name="administration_renrole_perms" xml:space="preserve">
|
||||
<value>You can't edit roles higher than your highest role.</value>
|
||||
</data>
|
||||
<data name="administration_reprm" xml:space="preserve">
|
||||
<value>Removed the playing message: {0}</value>
|
||||
</data>
|
||||
<data name="administration_role_added" xml:space="preserve">
|
||||
<value>Role {0} as been added to the list.</value>
|
||||
</data>
|
||||
<data name="administration_role_clean" xml:space="preserve">
|
||||
<value>{0} not found.Cleaned up.</value>
|
||||
</data>
|
||||
<data name="administration_role_in_list" xml:space="preserve">
|
||||
<value>Role {0} is already in the list.</value>
|
||||
</data>
|
||||
<data name="administration_ropl_added" xml:space="preserve">
|
||||
<value>Added.</value>
|
||||
</data>
|
||||
<data name="administration_ropl_disabled" xml:space="preserve">
|
||||
<value>Rotating playing status disabled.</value>
|
||||
</data>
|
||||
<data name="administration_ropl_enabled" xml:space="preserve">
|
||||
<value>Rotating playing status enabled.</value>
|
||||
</data>
|
||||
<data name="administration_ropl_list" xml:space="preserve">
|
||||
<value>Here is a list of rotating statuses:
|
||||
{0}</value>
|
||||
</data>
|
||||
<data name="administration_ropl_not_set" xml:space="preserve">
|
||||
<value>No rotating playing statuses set.</value>
|
||||
</data>
|
||||
<data name="administration_self_assign_already" xml:space="preserve">
|
||||
<value>You already have {0} role.</value>
|
||||
</data>
|
||||
<data name="administration_self_assign_already_excl" xml:space="preserve">
|
||||
<value>You already have {0} exclusive self-assigned role.</value>
|
||||
</data>
|
||||
<data name="administration_self_assign_excl" xml:space="preserve">
|
||||
<value>Self assigned roles are now exclusive!</value>
|
||||
</data>
|
||||
<data name="administration_self_assign_list" xml:space="preserve">
|
||||
<value>There are {0} self assignable roles</value>
|
||||
</data>
|
||||
<data name="administration_self_assign_not" xml:space="preserve">
|
||||
<value>That role is not self-assignable.</value>
|
||||
</data>
|
||||
<data name="administration_self_assign_not_have" xml:space="preserve">
|
||||
<value>You don't have {0} role.</value>
|
||||
</data>
|
||||
<data name="administration_self_assign_no_excl" xml:space="preserve">
|
||||
<value>Self assigned roles are now not exclusive!</value>
|
||||
</data>
|
||||
<data name="administration_self_assign_perms" xml:space="preserve">
|
||||
<value>I am unable to add that role to you. `I can't add roles to owners or other roles higher than my role in the role hierarchy.`</value>
|
||||
</data>
|
||||
<data name="administration_self_assign_rem" xml:space="preserve">
|
||||
<value>{0} has been removed from the list of self-assignable roles.</value>
|
||||
</data>
|
||||
<data name="administration_self_assign_remove" xml:space="preserve">
|
||||
<value>You no longer have {0} role.</value>
|
||||
</data>
|
||||
<data name="administration_self_assign_sucess" xml:space="preserve">
|
||||
<value>You now have {0} role.</value>
|
||||
</data>
|
||||
<data name="administration_setrole" xml:space="preserve">
|
||||
<value>Sucessfully added role {0} to user {1}</value>
|
||||
</data>
|
||||
<data name="administration_setrole_err" xml:space="preserve">
|
||||
<value>Failed to add role. I have insufficient permissions.</value>
|
||||
</data>
|
||||
<data name="administration_set_avatar" xml:space="preserve">
|
||||
<value>New avatar set!</value>
|
||||
</data>
|
||||
<data name="administration_set_channel_name" xml:space="preserve">
|
||||
<value>New channel name set.</value>
|
||||
</data>
|
||||
<data name="administration_set_game" xml:space="preserve">
|
||||
<value>New game set!</value>
|
||||
</data>
|
||||
<data name="administration_set_stream" xml:space="preserve">
|
||||
<value>New stream set!</value>
|
||||
</data>
|
||||
<data name="administration_set_topic" xml:space="preserve">
|
||||
<value>New channel topic set.</value>
|
||||
</data>
|
||||
<data name="administration_shard_reconnected" xml:space="preserve">
|
||||
<value>Shard {0} reconnected.</value>
|
||||
</data>
|
||||
<data name="administration_shard_reconnecting" xml:space="preserve">
|
||||
<value>Shard {0} reconnecting.</value>
|
||||
</data>
|
||||
<data name="administration_shutting_down" xml:space="preserve">
|
||||
<value>Shutting down</value>
|
||||
</data>
|
||||
<data name="administration_slowmode_desc" xml:space="preserve">
|
||||
<value>Users can't send more than {0} messages every {1} seconds.</value>
|
||||
</data>
|
||||
<data name="administration_slowmode_disabled" xml:space="preserve">
|
||||
<value>Slow mode disabled.</value>
|
||||
</data>
|
||||
<data name="administration_slowmode_init" xml:space="preserve">
|
||||
<value>Slow mode initiated</value>
|
||||
</data>
|
||||
<data name="administration_soft_banned_pl" xml:space="preserve">
|
||||
<value>soft-banned (kicked)</value>
|
||||
<comment>PLURAL</comment>
|
||||
</data>
|
||||
<data name="administration_spam_ignore" xml:space="preserve">
|
||||
<value>{0} will ignore this channel.</value>
|
||||
</data>
|
||||
<data name="administration_spam_not_ignore" xml:space="preserve">
|
||||
<value>{0} will no longer ignore this channel.</value>
|
||||
</data>
|
||||
<data name="administration_spam_stats" xml:space="preserve">
|
||||
<value>If a user posts {0} same messages in a row, I will {1} them.
|
||||
__IgnoredChannels__: {2}</value>
|
||||
</data>
|
||||
<data name="administration_text_chan_created" xml:space="preserve">
|
||||
<value>Text Channel Destroyed </value>
|
||||
</data>
|
||||
<data name="administration_text_chan_destroyed" xml:space="preserve">
|
||||
<value>Text Channel Destroyed </value>
|
||||
</data>
|
||||
<data name="administration_undeafen" xml:space="preserve">
|
||||
<value>Undeafen successful.</value>
|
||||
</data>
|
||||
<data name="administration_unmuted_sn" xml:space="preserve">
|
||||
<value>Unmuted</value>
|
||||
<comment>singular</comment>
|
||||
</data>
|
||||
<data name="administration_username" xml:space="preserve">
|
||||
<value>Username</value>
|
||||
</data>
|
||||
<data name="administration_username_changed" xml:space="preserve">
|
||||
<value>Username Changed</value>
|
||||
</data>
|
||||
<data name="administration_users" xml:space="preserve">
|
||||
<value>Users</value>
|
||||
</data>
|
||||
<data name="administration_user_banned" xml:space="preserve">
|
||||
<value>User Banned</value>
|
||||
</data>
|
||||
<data name="administration_user_chat_mute" xml:space="preserve">
|
||||
<value>{0} has been **muted** from chatting.</value>
|
||||
</data>
|
||||
<data name="administration_user_chat_unmute" xml:space="preserve">
|
||||
<value>{0} has been **unmuted** from chatting.</value>
|
||||
</data>
|
||||
<data name="administration_user_joined" xml:space="preserve">
|
||||
<value>User Joined</value>
|
||||
</data>
|
||||
<data name="administration_user_left" xml:space="preserve">
|
||||
<value>User Left</value>
|
||||
</data>
|
||||
<data name="administration_user_muted" xml:space="preserve">
|
||||
<value>{0} has been **muted** from text and voice chat.</value>
|
||||
</data>
|
||||
<data name="administration_user_role_add" xml:space="preserve">
|
||||
<value>User's Role Added</value>
|
||||
</data>
|
||||
<data name="administration_user_role_rem" xml:space="preserve">
|
||||
<value>User's Role Removed</value>
|
||||
</data>
|
||||
<data name="administration_user_status_change" xml:space="preserve">
|
||||
<value>{0} is now {1}</value>
|
||||
</data>
|
||||
<data name="administration_user_unmuted" xml:space="preserve">
|
||||
<value>{0} has been **unmuted** from text and voice chat.</value>
|
||||
</data>
|
||||
<data name="administration_user_vjoined" xml:space="preserve">
|
||||
<value>{0} has joined {1} voice channel.</value>
|
||||
</data>
|
||||
<data name="administration_user_vleft" xml:space="preserve">
|
||||
<value>{0} has left {1} voice channel.</value>
|
||||
</data>
|
||||
<data name="administration_user_vmoved" xml:space="preserve">
|
||||
<value>{0} moved from {1} to {2} voice channel.</value>
|
||||
</data>
|
||||
<data name="administration_user_voice_mute" xml:space="preserve">
|
||||
<value>{0} has been **voice muted**.</value>
|
||||
</data>
|
||||
<data name="administration_user_voice_unmute" xml:space="preserve">
|
||||
<value>{0} has been **voice unmuted**.</value>
|
||||
</data>
|
||||
<data name="administration_voice_chan_created" xml:space="preserve">
|
||||
<value>Voice Channel Destroyed</value>
|
||||
</data>
|
||||
<data name="administration_voice_chan_destroyed" xml:space="preserve">
|
||||
<value>Voice Channel Destroyed</value>
|
||||
</data>
|
||||
<data name="administration_vt_disabled" xml:space="preserve">
|
||||
<value>Disabled voice + text feature.</value>
|
||||
</data>
|
||||
<data name="administration_vt_enabled" xml:space="preserve">
|
||||
<value>Enabled voice + text feature.</value>
|
||||
</data>
|
||||
<data name="administration_vt_exit" xml:space="preserve">
|
||||
<value>I don't have **manage roles** and/or **manage channels** permission, so I cannot run `voice+text` on {0} server.</value>
|
||||
</data>
|
||||
<data name="administration_vt_no_admin" xml:space="preserve">
|
||||
<value>You are enabling/disabling this feature and **I do not have ADMINISTRATOR permissions**. This may cause some issues, and you will have to clean up text channels yourself afterwards.</value>
|
||||
</data>
|
||||
<data name="administration_vt_perms" xml:space="preserve">
|
||||
<value>I require atleast **manage roles** and **manage channels** permissions to enable this feature. (preffered Administration permission)</value>
|
||||
</data>
|
||||
<data name="administration_xmuted_text" xml:space="preserve">
|
||||
<value>User {0} from text chat</value>
|
||||
</data>
|
||||
<data name="administration_xmuted_text_and_voice" xml:space="preserve">
|
||||
<value>User {0} from text and voice chat</value>
|
||||
</data>
|
||||
<data name="administration_xmuted_voice" xml:space="preserve">
|
||||
<value>User {0} from voice chat</value>
|
||||
</data>
|
||||
<data name="administraton_sbdm" xml:space="preserve">
|
||||
<value>You have been soft-banned from {0} server.
|
||||
Reason: {1}</value>
|
||||
</data>
|
||||
<data name="administraton_user_unbanned" xml:space="preserve">
|
||||
<value>User Unbanned</value>
|
||||
</data>
|
||||
<data name="adminsitration_migration_done" xml:space="preserve">
|
||||
<value>Migration done!</value>
|
||||
</data>
|
||||
<data name="adminsitration_migration_error" xml:space="preserve">
|
||||
<value>Error while migrating, check bot's console for more information.</value>
|
||||
</data>
|
||||
<data name="adminsitration_presence_updates" xml:space="preserve">
|
||||
<value>Presence Updates</value>
|
||||
</data>
|
||||
<data name="adminsitration_sb_user" xml:space="preserve">
|
||||
<value>User Soft-Banned</value>
|
||||
</data>
|
||||
<data name="gambling_awarded" xml:space="preserve">
|
||||
<value>has awarded {0} to {1}</value>
|
||||
</data>
|
||||
<data name="gambling_betflip_gamble" xml:space="preserve">
|
||||
<value>Betflip Gamble</value>
|
||||
</data>
|
||||
<data name="gambling_better_luck" xml:space="preserve">
|
||||
<value>Better luck next time ^_^</value>
|
||||
</data>
|
||||
<data name="gambling_br_win" xml:space="preserve">
|
||||
<value>Congratulations! You won {0} for rolling above {1}</value>
|
||||
</data>
|
||||
<data name="gambling_deck_reshuffled" xml:space="preserve">
|
||||
<value>Deck reshuffled.</value>
|
||||
</data>
|
||||
<data name="gambling_flipped" xml:space="preserve">
|
||||
<value>flipped {0}.</value>
|
||||
<comment>User flipped tails.</comment>
|
||||
</data>
|
||||
<data name="gambling_flip_guess" xml:space="preserve">
|
||||
<value>You guessed it! You won {0}</value>
|
||||
</data>
|
||||
<data name="gambling_flip_invalid" xml:space="preserve">
|
||||
<value>Invalid number specified. You can flip 1 to {0} coins.</value>
|
||||
</data>
|
||||
<data name="gambling_flowerreaction_desc" xml:space="preserve">
|
||||
<value>Add {0} reaction to this message to get {1} </value>
|
||||
</data>
|
||||
<data name="gambling_flowerreaction_footer" xml:space="preserve">
|
||||
<value>This event is active for up to {0} hours.</value>
|
||||
</data>
|
||||
<data name="gambling_flowerreaction_title" xml:space="preserve">
|
||||
<value>Flower reaction event started!</value>
|
||||
</data>
|
||||
<data name="gambling_gifted" xml:space="preserve">
|
||||
<value>has gifted {0} to {1}</value>
|
||||
<comment>X has gifted 15 flowers to Y</comment>
|
||||
</data>
|
||||
<data name="gambling_has" xml:space="preserve">
|
||||
<value>{0} has {1}</value>
|
||||
<comment>X has Y flowers</comment>
|
||||
</data>
|
||||
<data name="gambling_heads" xml:space="preserve">
|
||||
<value>Heads</value>
|
||||
</data>
|
||||
<data name="gambling_leaderboard" xml:space="preserve">
|
||||
<value>Leaderboard</value>
|
||||
</data>
|
||||
<data name="gambling_mass_award" xml:space="preserve">
|
||||
<value>Awarded {0} to {1} users from {2} role.</value>
|
||||
</data>
|
||||
<data name="gambling_max_bet_limit" xml:space="preserve">
|
||||
<value>You can't bet more than {0}</value>
|
||||
</data>
|
||||
<data name="gambling_min_bet_limit" xml:space="preserve">
|
||||
<value>You can't bet less than {0}</value>
|
||||
</data>
|
||||
<data name="gambling_not_enough" xml:space="preserve">
|
||||
<value>You don't have enough {0}</value>
|
||||
</data>
|
||||
<data name="gambling_no_more_cards" xml:space="preserve">
|
||||
<value>No more cards in the deck.</value>
|
||||
</data>
|
||||
<data name="gambling_raffled_user" xml:space="preserve">
|
||||
<value>Raffled User</value>
|
||||
</data>
|
||||
<data name="gambling_roll" xml:space="preserve">
|
||||
<value>You rolled {0}.</value>
|
||||
</data>
|
||||
<data name="gambling_slot_bet" xml:space="preserve">
|
||||
<value>Bet</value>
|
||||
</data>
|
||||
<data name="gambling_slot_jackpot" xml:space="preserve">
|
||||
<value>WOAAHHHHHH!!! Congratulations!!! x{0}</value>
|
||||
</data>
|
||||
<data name="gambling_slot_single" xml:space="preserve">
|
||||
<value>A single {0}, x{1}</value>
|
||||
</data>
|
||||
<data name="gambling_slot_three" xml:space="preserve">
|
||||
<value>Wow! Lucky! Three of a kind! x{0}</value>
|
||||
</data>
|
||||
<data name="gambling_slot_two" xml:space="preserve">
|
||||
<value>Good job! Two {0} - bet x{1}</value>
|
||||
</data>
|
||||
<data name="gambling_slot_won" xml:space="preserve">
|
||||
<value>Won</value>
|
||||
</data>
|
||||
<data name="gambling_sneakygamestatus_desc" xml:space="preserve">
|
||||
<value>Users must type a secret code to get {0}.
|
||||
Lasts {1} seconds. Don't tell anyone. Shhh.</value>
|
||||
</data>
|
||||
<data name="gambling_sneakygamestatus_end" xml:space="preserve">
|
||||
<value>SneakyGame event ended. {0} users received the reward.</value>
|
||||
</data>
|
||||
<data name="gambling_sneakygamestatus_title" xml:space="preserve">
|
||||
<value>SneakyGameStatus event started</value>
|
||||
</data>
|
||||
<data name="gambling_tails" xml:space="preserve">
|
||||
<value>Tails</value>
|
||||
</data>
|
||||
<data name="gambling_take" xml:space="preserve">
|
||||
<value>successfully took {0} from {1}</value>
|
||||
</data>
|
||||
<data name="gambling_take_fail" xml:space="preserve">
|
||||
<value>was unable to take {0} from{1} because the user doesn't have that much {2}!</value>
|
||||
</data>
|
||||
<data name="help_back_to_toc" xml:space="preserve">
|
||||
<value>Back to ToC</value>
|
||||
</data>
|
||||
<data name="help_bot_owner_only" xml:space="preserve">
|
||||
<value>Bot Owner Only</value>
|
||||
</data>
|
||||
<data name="help_channel_permission" xml:space="preserve">
|
||||
<value>Requires {0} channel permission.</value>
|
||||
</data>
|
||||
<data name="help_cmdlist_donate" xml:space="preserve">
|
||||
<value>You can support the project on patreon: <{0}> or paypal: <{1}></value>
|
||||
</data>
|
||||
<data name="help_cmd_and_alias" xml:space="preserve">
|
||||
<value>Command and aliases</value>
|
||||
</data>
|
||||
<data name="help_commandlist_regen" xml:space="preserve">
|
||||
<value>Commandlist Regenerated.</value>
|
||||
</data>
|
||||
<data name="help_commands_instr" xml:space="preserve">
|
||||
<value>Type `{0}h CommandName` to see the help for that specified command. e.g. `{0}h >8ball`</value>
|
||||
</data>
|
||||
<data name="help_command_not_found" xml:space="preserve">
|
||||
<value>I can't find that command. Please verify that the command exists before trying again.</value>
|
||||
</data>
|
||||
<data name="help_desc" xml:space="preserve">
|
||||
<value>Description</value>
|
||||
</data>
|
||||
<data name="help_donate" xml:space="preserve">
|
||||
<value>You can support the NadekoBot project on
|
||||
Patreon <{0}> or
|
||||
Paypal <{1}>
|
||||
Don't forget to leave your discord name or id in the message.
|
||||
|
||||
**Thank you** ♥️</value>
|
||||
</data>
|
||||
<data name="help_guide" xml:space="preserve">
|
||||
<value>**List of Commands**: <{0}>
|
||||
**Hosting Guides and docs can be found here**: <{1}></value>
|
||||
</data>
|
||||
<data name="help_list_of_commands" xml:space="preserve">
|
||||
<value>List Of Commands</value>
|
||||
</data>
|
||||
<data name="help_list_of_modules" xml:space="preserve">
|
||||
<value>List Of Modules</value>
|
||||
</data>
|
||||
<data name="help_modules_footer" xml:space="preserve">
|
||||
<value>Type `{0}cmds ModuleName` to get a list of commands in that module. eg `{0}cmds games`</value>
|
||||
</data>
|
||||
<data name="help_module_not_found" xml:space="preserve">
|
||||
<value>That module does not exist.</value>
|
||||
</data>
|
||||
<data name="help_server_permission" xml:space="preserve">
|
||||
<value>Requires {0} server permission.</value>
|
||||
</data>
|
||||
<data name="help_table_of_contents" xml:space="preserve">
|
||||
<value>Table Of Contents</value>
|
||||
</data>
|
||||
<data name="help_usage" xml:space="preserve">
|
||||
<value>Usage</value>
|
||||
</data>
|
||||
<data name="nsfw_autohentai_started" xml:space="preserve">
|
||||
<value>Autohentai started. Reposting every {0}s with one of the following tags:
|
||||
{1}</value>
|
||||
</data>
|
||||
<data name="nsfw_tag" xml:space="preserve">
|
||||
<value>Tag</value>
|
||||
</data>
|
||||
</root>
|
260
src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.Designer.cs
generated
Normal file
260
src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.Designer.cs
generated
Normal file
@ -0,0 +1,260 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace NadekoBot.Resources {
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class ResponseStrings_sr_SP {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
internal ResponseStrings_sr_SP() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NadekoBot.Resources.ResponseStrings-sr-SP", typeof(ResponseStrings_sr_SP).GetTypeInfo().Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to {0} has already fainted..
|
||||
/// </summary>
|
||||
public static string pokemon_already_fainted {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_already_fainted", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to {0} already has full HP..
|
||||
/// </summary>
|
||||
public static string pokemon_already_full {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_already_full", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Your type is already {0}.
|
||||
/// </summary>
|
||||
public static string pokemon_already_that_type {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_already_that_type", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to used {0}{1} on {2}{3} for {4} damage..
|
||||
/// </summary>
|
||||
public static string pokemon_attack {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_attack", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You can't attack again without retaliation!.
|
||||
/// </summary>
|
||||
public static string pokemon_cant_attack_again {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_cant_attack_again", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You can't attack yourself..
|
||||
/// </summary>
|
||||
public static string pokemon_cant_attack_yourself {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_cant_attack_yourself", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to {0} has fainted!.
|
||||
/// </summary>
|
||||
public static string pokemon_fainted {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_fainted", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to healed {0} with one {1}.
|
||||
/// </summary>
|
||||
public static string pokemon_healed {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_healed", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to {0} has {1} HP remaining..
|
||||
/// </summary>
|
||||
public static string pokemon_hp_remaining {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_hp_remaining", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You can't use {0}. Type `{1}ml` to see a list of moves you can use..
|
||||
/// </summary>
|
||||
public static string pokemon_invalid_move {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_invalid_move", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Movelist for {0} type.
|
||||
/// </summary>
|
||||
public static string pokemon_moves {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_moves", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You don't have enough {0}.
|
||||
/// </summary>
|
||||
public static string pokemon_no_currency {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_no_currency", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to It's not effective..
|
||||
/// </summary>
|
||||
public static string pokemon_not_effective {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_not_effective", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to revived {0} with one {1}.
|
||||
/// </summary>
|
||||
public static string pokemon_revive_other {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_revive_other", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You revived yourself with one {0}.
|
||||
/// </summary>
|
||||
public static string pokemon_revive_yourself {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_revive_yourself", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Your type has been changed to {0} for a {1}.
|
||||
/// </summary>
|
||||
public static string pokemon_settype_success {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_settype_success", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to It's somewhat effective..
|
||||
/// </summary>
|
||||
public static string pokemon_somewhat_effective {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_somewhat_effective", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to It's super effective!.
|
||||
/// </summary>
|
||||
public static string pokemon_super_effective {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_super_effective", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You used too many moves in a row, so you can't move!.
|
||||
/// </summary>
|
||||
public static string pokemon_too_many_moves {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_too_many_moves", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Type of {0} is {1}.
|
||||
/// </summary>
|
||||
public static string pokemon_type_of_user {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_type_of_user", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to User not found..
|
||||
/// </summary>
|
||||
public static string pokemon_user_not_found {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_user_not_found", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You fainted, so you are not able to move!.
|
||||
/// </summary>
|
||||
public static string pokemon_you_fainted {
|
||||
get {
|
||||
return ResourceManager.GetString("pokemon_you_fainted", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
368
src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx
Normal file
368
src/NadekoBot/Resources/ResponseStrings.sr-cyrl-rs.resx
Normal file
@ -0,0 +1,368 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="pokemon_already_fainted" xml:space="preserve">
|
||||
<value>{0} је већ онесвешћен.</value>
|
||||
</data>
|
||||
<data name="pokemon_already_full" xml:space="preserve">
|
||||
<value>{0} је већ потпуно здрав.</value>
|
||||
</data>
|
||||
<data name="pokemon_already_that_type" xml:space="preserve">
|
||||
<value>Твој тип већ јесте {0}</value>
|
||||
</data>
|
||||
<data name="pokemon_attack" xml:space="preserve">
|
||||
<value>је искористио {0}{1} на {2}{3} и нанео {4} штете.</value>
|
||||
<comment>Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage.</comment>
|
||||
</data>
|
||||
<data name="pokemon_cant_attack_again" xml:space="preserve">
|
||||
<value>Не можеш напасти пре узвратног ударца.</value>
|
||||
</data>
|
||||
<data name="pokemon_cant_attack_yourself" xml:space="preserve">
|
||||
<value>Не можеш напасти себе.</value>
|
||||
</data>
|
||||
<data name="pokemon_fainted" xml:space="preserve">
|
||||
<value>{0} се онесвестио.</value>
|
||||
</data>
|
||||
<data name="pokemon_healed" xml:space="preserve">
|
||||
<value>је излечио {0} са једним {1}</value>
|
||||
</data>
|
||||
<data name="pokemon_hp_remaining" xml:space="preserve">
|
||||
<value>{0} има {1} преосталог здравља.</value>
|
||||
</data>
|
||||
<data name="pokemon_invalid_move" xml:space="preserve">
|
||||
<value>Не можеш искористити {0}. Укуцај `{1}ml` да би видео листу удараца које можеш користити.</value>
|
||||
</data>
|
||||
<data name="pokemon_moves" xml:space="preserve">
|
||||
<value>Листа покрета за {0} тип</value>
|
||||
</data>
|
||||
<data name="pokemon_not_effective" xml:space="preserve">
|
||||
<value>Није ефективно.</value>
|
||||
</data>
|
||||
<data name="pokemon_no_currency" xml:space="preserve">
|
||||
<value>Немаш довољно {0}</value>
|
||||
</data>
|
||||
<data name="pokemon_revive_other" xml:space="preserve">
|
||||
<value>је оживео {0} са једним {1}</value>
|
||||
</data>
|
||||
<data name="pokemon_revive_yourself" xml:space="preserve">
|
||||
<value>Оживео си себе са једним {0}</value>
|
||||
</data>
|
||||
<data name="pokemon_settype_success" xml:space="preserve">
|
||||
<value>Твој тип је промењен на {0} за један {1}</value>
|
||||
</data>
|
||||
<data name="pokemon_somewhat_effective" xml:space="preserve">
|
||||
<value>Има неког ефекта!</value>
|
||||
</data>
|
||||
<data name="pokemon_super_effective" xml:space="preserve">
|
||||
<value>Супер ефективно!</value>
|
||||
</data>
|
||||
<data name="pokemon_too_many_moves" xml:space="preserve">
|
||||
<value>Користио си превише напада узастопно, не можеш да се крећеш!</value>
|
||||
</data>
|
||||
<data name="pokemon_type_of_user" xml:space="preserve">
|
||||
<value>{0}-ов тип је {1}</value>
|
||||
</data>
|
||||
<data name="pokemon_user_not_found" xml:space="preserve">
|
||||
<value>Корисник није нађен.</value>
|
||||
</data>
|
||||
<data name="pokemon_you_fainted" xml:space="preserve">
|
||||
<value>Онесвешћен си, не можеш да се крећеш.</value>
|
||||
</data>
|
||||
<data name="clashofclans_base_already_claimed" xml:space="preserve">
|
||||
<value>Та база је већ под захетвом или је уништена.</value>
|
||||
</data>
|
||||
<data name="clashofclans_base_already_destroyed" xml:space="preserve">
|
||||
<value>Та база је већ под захтевом.</value>
|
||||
</data>
|
||||
<data name="clashofclans_base_already_unclaimed" xml:space="preserve">
|
||||
<value>Та база није под захтевом.</value>
|
||||
</data>
|
||||
<data name="clashofclans_base_unclaimed" xml:space="preserve">
|
||||
<value>{0} је **ПОНИШТИО ЗАХТЕВ** за базу #{1} у рату против {2}</value>
|
||||
</data>
|
||||
<data name="clashofclans_claimed_base" xml:space="preserve">
|
||||
<value>{0} захтева базу #{1} у рату против {2}</value>
|
||||
</data>
|
||||
<data name="clashofclans_claimed_other" xml:space="preserve">
|
||||
<value>@{0} Ти већ захтеваш базу #{1}. Не можеш захтевати још једну.</value>
|
||||
</data>
|
||||
<data name="clashofclans_claim_expired" xml:space="preserve">
|
||||
<value>Захтев од @{0} за рат против {1} је истекао.</value>
|
||||
</data>
|
||||
<data name="clashofclans_enemy" xml:space="preserve">
|
||||
<value>Противник</value>
|
||||
</data>
|
||||
<data name="clashofclans_info_about_war" xml:space="preserve">
|
||||
<value>Подаци о рату против {0}</value>
|
||||
</data>
|
||||
<data name="clashofclans_invalid_base_number" xml:space="preserve">
|
||||
<value>Број базе није валидан.</value>
|
||||
</data>
|
||||
<data name="clashofclans_invalid_size" xml:space="preserve">
|
||||
<value>Величина рата није валидна.</value>
|
||||
</data>
|
||||
<data name="clashofclans_list_active_wars" xml:space="preserve">
|
||||
<value>Листа Ратова У Току</value>
|
||||
</data>
|
||||
<data name="clashofclans_not_claimed" xml:space="preserve">
|
||||
<value>нема захтева</value>
|
||||
</data>
|
||||
<data name="clashofclans_not_partic" xml:space="preserve">
|
||||
<value>Ти не учествујеш у том рату.</value>
|
||||
</data>
|
||||
<data name="clashofclans_not_partic_or_destroyed" xml:space="preserve">
|
||||
<value>@{0} Ти или не учествујеш у рату или је та база већ уништена.</value>
|
||||
</data>
|
||||
<data name="clashofclans_no_active_wars" xml:space="preserve">
|
||||
<value>Нема ратова у току.</value>
|
||||
</data>
|
||||
<data name="clashofclans_size" xml:space="preserve">
|
||||
<value>Величина</value>
|
||||
</data>
|
||||
<data name="clashofclans_war_already_started" xml:space="preserve">
|
||||
<value>Рат против {0} је већ почео.</value>
|
||||
</data>
|
||||
<data name="clashofclans_war_created" xml:space="preserve">
|
||||
<value>Рат против {0} је направљен.</value>
|
||||
</data>
|
||||
<data name="clashofclans_war_ended" xml:space="preserve">
|
||||
<value>Рат против {0} је завршен.</value>
|
||||
</data>
|
||||
<data name="clashofclans_war_not_exist" xml:space="preserve">
|
||||
<value>Тај рат не постоји.</value>
|
||||
</data>
|
||||
<data name="clashofclans_war_started" xml:space="preserve">
|
||||
<value>Рат против {0} је започет!</value>
|
||||
</data>
|
||||
<data name="clasofclans_base_destroyed" xml:space="preserve">
|
||||
<value>је **УНИШТИО** базу #{0} у рату против {1}</value>
|
||||
</data>
|
||||
<data name="customreactions_all_stats_cleared" xml:space="preserve">
|
||||
<value>Сва статистика Реакција по Избору је обрисана.</value>
|
||||
</data>
|
||||
<data name="customreactions_deleted" xml:space="preserve">
|
||||
<value>Реакција по Избору обрисана</value>
|
||||
</data>
|
||||
<data name="customreactions_insuff_perms" xml:space="preserve">
|
||||
<value>Немате дозволу. Потребно је поседовати бота за глобалне Реакције по Избору, а Администратор за серверске Реакције по Избору.</value>
|
||||
</data>
|
||||
<data name="customreactions_list_all" xml:space="preserve">
|
||||
<value>Листа свих реакција по избору</value>
|
||||
</data>
|
||||
<data name="customreactions_name" xml:space="preserve">
|
||||
<value>Реакције по Избору</value>
|
||||
</data>
|
||||
<data name="customreactions_new_cust_react" xml:space="preserve">
|
||||
<value>Нова Реакција по Избору</value>
|
||||
</data>
|
||||
<data name="customreactions_no_found" xml:space="preserve">
|
||||
<value>Реакција по избору није нађена.</value>
|
||||
</data>
|
||||
<data name="customreactions_no_found_id" xml:space="preserve">
|
||||
<value>Није нађена реакција са тим идентификатором.</value>
|
||||
</data>
|
||||
<data name="customreactions_response" xml:space="preserve">
|
||||
<value>Одговор</value>
|
||||
</data>
|
||||
<data name="customreactions_stats" xml:space="preserve">
|
||||
<value>Статистика Реакција по Избору</value>
|
||||
</data>
|
||||
<data name="customreactions_stats_cleared" xml:space="preserve">
|
||||
<value>Статистика је обрисана за {0} реакцију по избору.</value>
|
||||
</data>
|
||||
<data name="customreactions_stats_not_found" xml:space="preserve">
|
||||
<value>Није нађена статистика за тај окидач. Нема промене.</value>
|
||||
</data>
|
||||
<data name="customreactions_trigger" xml:space="preserve">
|
||||
<value>Окидач</value>
|
||||
</data>
|
||||
<data name="help_back_to_toc" xml:space="preserve">
|
||||
<value>Назад на Садржај</value>
|
||||
</data>
|
||||
<data name="help_bot_owner_only" xml:space="preserve">
|
||||
<value>Само Власник Бота</value>
|
||||
</data>
|
||||
<data name="help_channel_permission" xml:space="preserve">
|
||||
<value>Захтева {0} дозволу на каналу.</value>
|
||||
</data>
|
||||
<data name="help_cmdlist_donate" xml:space="preserve">
|
||||
<value>Можете подржати пројекат на Пејтриону: <{0}> или Пејпалу: <{1}></value>
|
||||
</data>
|
||||
<data name="help_cmd_and_alias" xml:space="preserve">
|
||||
<value>Команде и псеудоними</value>
|
||||
</data>
|
||||
<data name="help_commandlist_regen" xml:space="preserve">
|
||||
<value>Листа команди је обновљена.</value>
|
||||
</data>
|
||||
<data name="help_commands_instr" xml:space="preserve">
|
||||
<value>Укуцај `{0}h ИмеКоманде` да видиш помоћ за ту команду. нпр. `{0}h >8ball`</value>
|
||||
</data>
|
||||
<data name="help_command_not_found" xml:space="preserve">
|
||||
<value>Не могу да нађем ту команду. Проверите да ли команда постоји, па покушајте поново.</value>
|
||||
</data>
|
||||
<data name="help_desc" xml:space="preserve">
|
||||
<value>Опис</value>
|
||||
</data>
|
||||
<data name="help_donate" xml:space="preserve">
|
||||
<value>Можете подржати НадекоБот пројекат на
|
||||
Пејтриону <{0}> или
|
||||
Пејпалу <{1}>
|
||||
Не заборавите да оставите своје корисничко име или ИД.
|
||||
|
||||
**Хвала** ♥️</value>
|
||||
</data>
|
||||
<data name="help_guide" xml:space="preserve">
|
||||
<value>**List of Commands**: <{0}>
|
||||
**Hosting Guides and docs can be found here**: <{1}></value>
|
||||
</data>
|
||||
<data name="help_list_of_commands" xml:space="preserve">
|
||||
<value>Листа Команди</value>
|
||||
</data>
|
||||
<data name="help_list_of_modules" xml:space="preserve">
|
||||
<value>Листа Модула</value>
|
||||
</data>
|
||||
<data name="help_modules_footer" xml:space="preserve">
|
||||
<value>Укуцај `{0}cmds ИмеМодула` да видиш листу свих команди у том модулу. нпр `{0}cmds games`</value>
|
||||
</data>
|
||||
<data name="help_module_not_found" xml:space="preserve">
|
||||
<value>Тај модул не постоји.</value>
|
||||
</data>
|
||||
<data name="help_server_permission" xml:space="preserve">
|
||||
<value>Захтева {0} дозволу на серверу.</value>
|
||||
</data>
|
||||
<data name="help_table_of_contents" xml:space="preserve">
|
||||
<value>Садржај</value>
|
||||
</data>
|
||||
<data name="help_usage" xml:space="preserve">
|
||||
<value>Упутство</value>
|
||||
</data>
|
||||
<data name="nsfw_autohentai_started" xml:space="preserve">
|
||||
<value>Аутохентаи започет. Постоваћу сваких {0} сек. користећи један од следећих тагова:
|
||||
{1}</value>
|
||||
</data>
|
||||
<data name="nsfw_autohentai_stopped" xml:space="preserve">
|
||||
<value>АутоХентаи заустављен.</value>
|
||||
</data>
|
||||
<data name="nsfw_no_results" xml:space="preserve">
|
||||
<value>Нема резултата.</value>
|
||||
</data>
|
||||
<data name="nsfw_tag" xml:space="preserve">
|
||||
<value>Таг</value>
|
||||
</data>
|
||||
</root>
|
@ -30,9 +30,9 @@ namespace Services.CleverBotApi
|
||||
public static ChatterBot Create(ChatterBotType type, object arg)
|
||||
{
|
||||
#if GLOBAL_NADEKO
|
||||
var url = "http://www.cleverbot.com/webservicemin?uc=3210&botapi=nadekobot";
|
||||
var url = "http://www.cleverbot.com/webservicemin?uc=777&botapi=nadekobot";
|
||||
#else
|
||||
var url = "http://www.cleverbot.com/webservicemin?uc=3210&botapi=chatterbotapi";
|
||||
var url = "http://www.cleverbot.com/webservicemin?uc=777&botapi=chatterbotapi";
|
||||
#endif
|
||||
|
||||
switch (type)
|
||||
|
@ -73,7 +73,7 @@ namespace NadekoBot.Services
|
||||
if (!ownerChannels.Any())
|
||||
_log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file.");
|
||||
else
|
||||
_log.Info($"Created {ownerChannels.Count} out of {NadekoBot.Credentials.OwnerIds.Length} owner message channels.");
|
||||
_log.Info($"Created {ownerChannels.Count} out of {NadekoBot.Credentials.OwnerIds.Count} owner message channels.");
|
||||
|
||||
_client.MessageReceived += MessageReceivedHandler;
|
||||
}
|
||||
@ -273,7 +273,7 @@ namespace NadekoBot.Services
|
||||
|
||||
await msg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false);
|
||||
|
||||
await DMForwardCommands.HandleDMForwarding(msg, ownerChannels).ConfigureAwait(false);
|
||||
await SelfCommands.HandleDmForwarding(msg, ownerChannels).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ Nadeko Support Server: https://discord.gg/nadekobot";
|
||||
|
||||
public string OkColor { get; set; } = "71cd40";
|
||||
public string ErrorColor { get; set; } = "ee281f";
|
||||
public string Locale { get; set; } = null;
|
||||
}
|
||||
|
||||
public class PlayingStatus :DbEntity
|
||||
|
@ -12,7 +12,6 @@ namespace NadekoBot.Services.Database.Models
|
||||
public string Trigger { get; set; }
|
||||
public bool IsRegex { get; set; }
|
||||
public bool OwnerOnly { get; set; }
|
||||
public override string ToString() => $"`#{Id}` `Trigger:` {Trigger}\n `Response:` {Response}";
|
||||
}
|
||||
|
||||
public class ReactionResponse : DbEntity
|
||||
|
@ -64,6 +64,9 @@ namespace NadekoBot.Services.Database.Models
|
||||
public AntiRaidSetting AntiRaidSetting { get; set; }
|
||||
public AntiSpamSetting AntiSpamSetting { get; set; }
|
||||
|
||||
public string Locale { get; set; } = null;
|
||||
public string TimeZoneId { get; set; } = null;
|
||||
|
||||
//public List<ProtectionIgnoredChannel> ProtectionIgnoredChannels { get; set; } = new List<ProtectionIgnoredChannel>();
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ namespace NadekoBot.Services.Database
|
||||
{
|
||||
#region QUOTES
|
||||
|
||||
var quoteEntity = modelBuilder.Entity<Quote>();
|
||||
//var quoteEntity = modelBuilder.Entity<Quote>();
|
||||
|
||||
#endregion
|
||||
|
||||
@ -166,7 +166,7 @@ namespace NadekoBot.Services.Database
|
||||
#endregion
|
||||
|
||||
#region BotConfig
|
||||
var botConfigEntity = modelBuilder.Entity<BotConfig>();
|
||||
//var botConfigEntity = modelBuilder.Entity<BotConfig>();
|
||||
//botConfigEntity
|
||||
// .HasMany(c => c.ModulePrefixes)
|
||||
// .WithOne(mp => mp.BotConfig)
|
||||
|
@ -1,4 +1,6 @@
|
||||
using Discord;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace NadekoBot.Services
|
||||
{
|
||||
@ -9,7 +11,7 @@ namespace NadekoBot.Services
|
||||
|
||||
string Token { get; }
|
||||
string GoogleApiKey { get; }
|
||||
ulong[] OwnerIds { get; }
|
||||
ImmutableHashSet<ulong> OwnerIds { get; }
|
||||
string MashapeKey { get; }
|
||||
string LoLApiKey { get; }
|
||||
|
||||
|
@ -5,6 +5,8 @@ using Discord;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace NadekoBot.Services.Impl
|
||||
{
|
||||
@ -21,7 +23,7 @@ namespace NadekoBot.Services.Impl
|
||||
|
||||
public string Token { get; }
|
||||
|
||||
public ulong[] OwnerIds { get; }
|
||||
public ImmutableHashSet<ulong> OwnerIds { get; }
|
||||
|
||||
public string LoLApiKey { get; }
|
||||
public string OsuApiKey { get; }
|
||||
@ -61,7 +63,7 @@ namespace NadekoBot.Services.Impl
|
||||
Token = data[nameof(Token)];
|
||||
if (string.IsNullOrWhiteSpace(Token))
|
||||
throw new ArgumentNullException(nameof(Token), "Token is missing from credentials.json or Environment varibles.");
|
||||
OwnerIds = data.GetSection("OwnerIds").GetChildren().Select(c => ulong.Parse(c.Value)).ToArray();
|
||||
OwnerIds = data.GetSection("OwnerIds").GetChildren().Select(c => ulong.Parse(c.Value)).ToImmutableHashSet();
|
||||
LoLApiKey = data[nameof(LoLApiKey)];
|
||||
GoogleApiKey = data[nameof(GoogleApiKey)];
|
||||
MashapeKey = data[nameof(MashapeKey)];
|
||||
|
@ -1,45 +1,122 @@
|
||||
namespace NadekoBot.Services
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using NadekoBot.Services.Database;
|
||||
using NLog;
|
||||
|
||||
namespace NadekoBot.Services
|
||||
{
|
||||
public class Localization
|
||||
{
|
||||
public string this[string key] => LoadCommandString(key);
|
||||
private readonly Logger _log;
|
||||
|
||||
public ConcurrentDictionary<ulong, CultureInfo> GuildCultureInfos { get; }
|
||||
public CultureInfo DefaultCultureInfo { get; private set; } = CultureInfo.CurrentCulture;
|
||||
|
||||
private Localization() { }
|
||||
public Localization(string defaultCulture, IDictionary<ulong, string> cultureInfoNames)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
if (string.IsNullOrWhiteSpace(defaultCulture))
|
||||
DefaultCultureInfo = new CultureInfo("en-US");
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
DefaultCultureInfo = new CultureInfo(defaultCulture);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_log.Warn("Unable to load default bot's locale/language. Using en-US.");
|
||||
DefaultCultureInfo = new CultureInfo("en-US");
|
||||
}
|
||||
}
|
||||
GuildCultureInfos = new ConcurrentDictionary<ulong, CultureInfo>(cultureInfoNames.ToDictionary(x => x.Key, x =>
|
||||
{
|
||||
CultureInfo cultureInfo = null;
|
||||
try
|
||||
{
|
||||
cultureInfo = new CultureInfo(x.Value);
|
||||
}
|
||||
catch { }
|
||||
return cultureInfo;
|
||||
}).Where(x => x.Value != null));
|
||||
}
|
||||
|
||||
public void SetGuildCulture(IGuild guild, CultureInfo ci) =>
|
||||
SetGuildCulture(guild.Id, ci);
|
||||
|
||||
public void SetGuildCulture(ulong guildId, CultureInfo ci)
|
||||
{
|
||||
if (ci == DefaultCultureInfo)
|
||||
{
|
||||
RemoveGuildCulture(guildId);
|
||||
return;
|
||||
}
|
||||
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(guildId, set => set);
|
||||
gc.Locale = ci.Name;
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
GuildCultureInfos.AddOrUpdate(guildId, ci, (id, old) => ci);
|
||||
}
|
||||
|
||||
public void RemoveGuildCulture(IGuild guild) =>
|
||||
RemoveGuildCulture(guild.Id);
|
||||
|
||||
public void RemoveGuildCulture(ulong guildId) {
|
||||
|
||||
CultureInfo throwaway;
|
||||
if (GuildCultureInfos.TryRemove(guildId, out throwaway))
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var gc = uow.GuildConfigs.For(guildId, set => set);
|
||||
gc.Locale = null;
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDefaultCulture(CultureInfo ci)
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
var bc = uow.BotConfig.GetOrCreate();
|
||||
bc.Locale = ci.Name;
|
||||
uow.Complete();
|
||||
}
|
||||
DefaultCultureInfo = ci;
|
||||
}
|
||||
|
||||
public void ResetDefaultCulture() =>
|
||||
SetDefaultCulture(CultureInfo.CurrentCulture);
|
||||
|
||||
public CultureInfo GetCultureInfo(IGuild guild) =>
|
||||
GetCultureInfo(guild?.Id);
|
||||
|
||||
public CultureInfo GetCultureInfo(ulong? guildId)
|
||||
{
|
||||
if (guildId == null)
|
||||
return DefaultCultureInfo;
|
||||
CultureInfo info = null;
|
||||
GuildCultureInfos.TryGetValue(guildId.Value, out info);
|
||||
return info ?? DefaultCultureInfo;
|
||||
}
|
||||
|
||||
public static string LoadCommandString(string key)
|
||||
{
|
||||
string toReturn = Resources.CommandStrings.ResourceManager.GetString(key);
|
||||
return string.IsNullOrWhiteSpace(toReturn) ? key : toReturn;
|
||||
}
|
||||
|
||||
//private static string GetCommandString(string key)
|
||||
//{
|
||||
// return key;
|
||||
//var resx = new List<DictionaryEntry>();
|
||||
//var fs = new StreamReader(File.OpenRead("./Strings.resx"));
|
||||
//Console.WriteLine(fs.ReadToEnd());
|
||||
//using (var reader = new ResourceReader(fs.BaseStream))
|
||||
//{
|
||||
// List<DictionaryEntry> existing = new List<DictionaryEntry>();
|
||||
// foreach (DictionaryEntry item in reader)
|
||||
// {
|
||||
// existing.Add(item);
|
||||
// }
|
||||
// var existingResource = resx.Where(r => r.Key.ToString() == key).FirstOrDefault();
|
||||
// if (existingResource.Key == null)
|
||||
// {
|
||||
// resx.Add(new DictionaryEntry() { Key = key, Value = key });
|
||||
// }
|
||||
// else
|
||||
// return existingResource.Value.ToString();
|
||||
//}
|
||||
//using (var writer = new ResourceWriter(new FileStream("./Strings.resx", FileMode.OpenOrCreate)))
|
||||
//{
|
||||
// resx.ForEach(r =>
|
||||
// {
|
||||
// writer.AddResource(r.Key.ToString(), r.Value.ToString());
|
||||
// });
|
||||
// writer.Generate();
|
||||
//}
|
||||
//return key;
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ namespace NadekoBot.Services.Impl
|
||||
private DiscordShardedClient client;
|
||||
private DateTime started;
|
||||
|
||||
public const string BotVersion = "1.1.6";
|
||||
public const string BotVersion = "1.1.8-alpha";
|
||||
|
||||
public string Author => "Kwoth#2560";
|
||||
public string Library => "Discord.Net";
|
||||
@ -96,18 +96,21 @@ namespace NadekoBot.Services.Impl
|
||||
content.Headers.Clear();
|
||||
content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
|
||||
|
||||
var res = await http.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false);
|
||||
await http.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false);
|
||||
}
|
||||
};
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1));
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
var guilds = this.client.GetGuilds();
|
||||
_textChannels = guilds.Sum(g => g.Channels.Where(cx => cx is ITextChannel).Count());
|
||||
var guilds = this.client.GetGuilds().ToArray();
|
||||
_textChannels = guilds.Sum(g => g.Channels.Count(cx => cx is ITextChannel));
|
||||
_voiceChannels = guilds.Sum(g => g.Channels.Count) - _textChannels;
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,6 @@ namespace NadekoBot.Services
|
||||
return minValue;
|
||||
var bytes = new byte[sizeof(int)];
|
||||
rng.GetBytes(bytes);
|
||||
var num = BitConverter.ToInt32(bytes, 0);
|
||||
var sign = Math.Sign(BitConverter.ToInt32(bytes, 0));
|
||||
return (sign * BitConverter.ToInt32(bytes, 0)) % (maxValue - minValue) + minValue;
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"AngleSharp": "0.9.9",
|
||||
"libvideo": "1.0.0",
|
||||
"libvideo": "1.0.1",
|
||||
"CoreCLR-NCalc": "2.1.2",
|
||||
"Google.Apis.Urlshortener.v1": "1.19.0.138",
|
||||
"Google.Apis.YouTube.v3": "1.20.0.701",
|
||||
|
Loading…
Reference in New Issue
Block a user