Merge remote-tracking branch 'refs/remotes/Kwoth/master'

# Conflicts:
#	NadekoBot/Modules/Games.cs
This commit is contained in:
appelemac 2016-03-28 15:27:50 +02:00
commit 4c9b6185aa
11 changed files with 878 additions and 334 deletions

View File

@ -20,7 +20,7 @@ namespace NadekoBot.Classes
var flows = ""; var flows = "";
for (var i = 0; i < amount; i++) for (var i = 0; i < amount; i++)
{ {
flows += "🌸"; flows += NadekoBot.Config.CurrencySign;
} }
await u.SendMessage("👑Congratulations!👑\nYou received: " + flows); await u.SendMessage("👑Congratulations!👑\nYou received: " + flows);
} }

View File

@ -1,11 +1,12 @@
using System; using Discord;
using Newtonsoft.Json;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Discord;
using Newtonsoft.Json;
namespace NadekoBot.Classes.JSONModels { namespace NadekoBot.Classes.JSONModels
public class Configuration { {
public class Configuration
{
public bool DontJoinServers { get; set; } = false; public bool DontJoinServers { get; set; } = false;
public bool ForwardMessages { get; set; } = true; public bool ForwardMessages { get; set; } = true;
public bool IsRotatingStatus { get; set; } = false; public bool IsRotatingStatus { get; set; } = false;
@ -50,7 +51,7 @@ namespace NadekoBot.Classes.JSONModels {
"NO - It may cause disease contraction" "NO - It may cause disease contraction"
}; };
public string[] DisguiseResponses { get; set; } = { public string[] DisguiseResponses { get; set; } = {
"https://cdn.discordapp.com/attachments/140007341880901632/156721710458994690/Cc5mixjUYAADgBs.jpg", "https://cdn.discordapp.com/attachments/140007341880901632/156721710458994690/Cc5mixjUYAADgBs.jpg",
"https://cdn.discordapp.com/attachments/140007341880901632/156721715831898113/hqdefault.jpg", "https://cdn.discordapp.com/attachments/140007341880901632/156721715831898113/hqdefault.jpg",
"https://cdn.discordapp.com/attachments/140007341880901632/156721724430352385/okawari_01_haruka_weird_mask.jpg", "https://cdn.discordapp.com/attachments/140007341880901632/156721724430352385/okawari_01_haruka_weird_mask.jpg",
@ -75,9 +76,13 @@ namespace NadekoBot.Classes.JSONModels {
"http://gallery1.anivide.com/_full/65030_1382582341.gif", "http://gallery1.anivide.com/_full/65030_1382582341.gif",
"https://49.media.tumblr.com/8e8a099c4eba22abd3ec0f70fd087cce/tumblr_nxovj9oY861ur1mffo1_500.gif ", "https://49.media.tumblr.com/8e8a099c4eba22abd3ec0f70fd087cce/tumblr_nxovj9oY861ur1mffo1_500.gif ",
}; };
public string CurrencySign { get; set; } = "🌸";
public string CurrencyName { get; set; } = "NadekoFlower";
} }
public class CommandPrefixesModel { public class CommandPrefixesModel
{
public string Administration { get; set; } = "."; public string Administration { get; set; } = ".";
public string Searches { get; set; } = "~"; public string Searches { get; set; } = "~";
public string NSFW { get; set; } = "~"; public string NSFW { get; set; } = "~";
@ -93,10 +98,13 @@ namespace NadekoBot.Classes.JSONModels {
public string Pokemon { get; set; } = "poke"; public string Pokemon { get; set; } = "poke";
} }
public static class ConfigHandler { public static class ConfigHandler
{
private static readonly object configLock = new object(); private static readonly object configLock = new object();
public static void SaveConfig() { public static void SaveConfig()
lock (configLock) { {
lock (configLock)
{
File.WriteAllText("data/config.json", JsonConvert.SerializeObject(NadekoBot.Config, Formatting.Indented)); File.WriteAllText("data/config.json", JsonConvert.SerializeObject(NadekoBot.Config, Formatting.Indented));
} }
} }
@ -112,7 +120,8 @@ namespace NadekoBot.Classes.JSONModels {
public static bool IsUserBlacklisted(ulong id) => NadekoBot.Config.UserBlacklist.Contains(id); public static bool IsUserBlacklisted(ulong id) => NadekoBot.Config.UserBlacklist.Contains(id);
} }
public class Quote { public class Quote
{
public string Author { get; set; } public string Author { get; set; }
public string Text { get; set; } public string Text { get; set; }

View File

@ -1,19 +1,22 @@
using System; using Discord.Commands;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
using System.Drawing;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using NadekoBot.Modules; using NadekoBot.Modules;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NadekoBot.Commands { namespace NadekoBot.Commands
internal class LoLCommands : DiscordCommand { {
internal class LoLCommands : DiscordCommand
{
private class CachedChampion { private class CachedChampion
{
public System.IO.Stream ImageStream { get; set; } public System.IO.Stream ImageStream { get; set; }
public DateTime AddedAt { get; set; } public DateTime AddedAt { get; set; }
public string Name { get; set; } public string Name { get; set; }
@ -24,16 +27,20 @@ namespace NadekoBot.Commands {
private System.Timers.Timer clearTimer { get; } = new System.Timers.Timer(); private System.Timers.Timer clearTimer { get; } = new System.Timers.Timer();
public LoLCommands(DiscordModule module) : base(module) { public LoLCommands(DiscordModule module) : base(module)
{
clearTimer.Interval = new TimeSpan(0, 10, 0).TotalMilliseconds; clearTimer.Interval = new TimeSpan(0, 10, 0).TotalMilliseconds;
clearTimer.Start(); clearTimer.Start();
clearTimer.Elapsed += (s, e) => { clearTimer.Elapsed += (s, e) =>
try { {
try
{
lock (cacheLock) lock (cacheLock)
CachedChampionImages = CachedChampionImages CachedChampionImages = CachedChampionImages
.Where(kvp => DateTime.Now - kvp.Value.AddedAt > new TimeSpan(1, 0, 0)) .Where(kvp => DateTime.Now - kvp.Value.AddedAt > new TimeSpan(1, 0, 0))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
} catch { } }
catch { }
}; };
} }
@ -44,11 +51,13 @@ namespace NadekoBot.Commands {
"If you consider playing teemo, do it. If you consider teemo, you deserve him.", "If you consider playing teemo, do it. If you consider teemo, you deserve him.",
"Doesn't matter what you ban really. Enemy will ban your main and you will lose." }; "Doesn't matter what you ban really. Enemy will ban your main and you will lose." };
public Func<CommandEventArgs, Task> DoFunc() { public Func<CommandEventArgs, Task> DoFunc()
{
throw new NotImplementedException(); throw new NotImplementedException();
} }
private class MatchupModel { private class MatchupModel
{
public int Games { get; set; } public int Games { get; set; }
public float WinRate { get; set; } public float WinRate { get; set; }
[Newtonsoft.Json.JsonProperty("key")] [Newtonsoft.Json.JsonProperty("key")]
@ -56,48 +65,60 @@ namespace NadekoBot.Commands {
public float StatScore { get; set; } public float StatScore { get; set; }
} }
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "lolchamp") cgb.CreateCommand(Module.Prefix + "lolchamp")
.Description("Shows League Of Legends champion statistics. If there are spaces/apostrophes or in the name - omit them. Optional second parameter is a role.\n**Usage**:~lolchamp Riven or ~lolchamp Annie sup") .Description("Shows League Of Legends champion statistics. If there are spaces/apostrophes or in the name - omit them. Optional second parameter is a role.\n**Usage**:~lolchamp Riven or ~lolchamp Annie sup")
.Parameter("champ", ParameterType.Required) .Parameter("champ", ParameterType.Required)
.Parameter("position", ParameterType.Unparsed) .Parameter("position", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
try { {
try
{
//get role //get role
var role = ResolvePos(e.GetArg("position")); var role = ResolvePos(e.GetArg("position"));
var resolvedRole = role; var resolvedRole = role;
var name = e.GetArg("champ").Replace(" ", "").ToLower(); var name = e.GetArg("champ").Replace(" ", "").ToLower();
CachedChampion champ = null; CachedChampion champ = null;
lock (cacheLock) { lock (cacheLock)
{
CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ); CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ);
} }
if (champ != null) { if (champ != null)
{
champ.ImageStream.Position = 0; champ.ImageStream.Position = 0;
await e.Channel.SendFile("champ.png", champ.ImageStream); await e.Channel.SendFile("champ.png", champ.ImageStream);
return; return;
} }
var allData = JArray.Parse(await Classes.SearchHelper.GetResponseStringAsync($"http://api.champion.gg/champion/{name}?api_key={NadekoBot.Creds.LOLAPIKey}")); var allData = JArray.Parse(await Classes.SearchHelper.GetResponseStringAsync($"http://api.champion.gg/champion/{name}?api_key={NadekoBot.Creds.LOLAPIKey}"));
JToken data = null; JToken data = null;
if (role != null) { if (role != null)
for (var i = 0; i < allData.Count; i++) { {
if (allData[i]["role"].ToString().Equals(role)) { for (var i = 0; i < allData.Count; i++)
{
if (allData[i]["role"].ToString().Equals(role))
{
data = allData[i]; data = allData[i];
break; break;
} }
} }
if (data == null) { if (data == null)
{
await e.Channel.SendMessage("💢 Data for that role does not exist."); await e.Channel.SendMessage("💢 Data for that role does not exist.");
return; return;
} }
} else { }
else {
data = allData[0]; data = allData[0];
role = allData[0]["role"].ToString(); role = allData[0]["role"].ToString();
resolvedRole = ResolvePos(role); resolvedRole = ResolvePos(role);
} }
lock (cacheLock) { lock (cacheLock)
{
CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ); CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ);
} }
if (champ != null) { if (champ != null)
{
Console.WriteLine("Sending lol image from cache."); Console.WriteLine("Sending lol image from cache.");
champ.ImageStream.Position = 0; champ.ImageStream.Position = 0;
await e.Channel.SendFile("champ.png", champ.ImageStream); await e.Channel.SendFile("champ.png", champ.ImageStream);
@ -106,7 +127,8 @@ namespace NadekoBot.Commands {
//name = data["title"].ToString(); //name = data["title"].ToString();
// get all possible roles, and "select" the shown one // get all possible roles, and "select" the shown one
var roles = new string[allData.Count]; var roles = new string[allData.Count];
for (var i = 0; i < allData.Count; i++) { for (var i = 0; i < allData.Count; i++)
{
roles[i] = allData[i]["role"].ToString(); roles[i] = allData[i]["role"].ToString();
if (roles[i] == role) if (roles[i] == role)
roles[i] = ">" + roles[i] + "<"; roles[i] = ">" + roles[i] + "<";
@ -114,14 +136,16 @@ namespace NadekoBot.Commands {
var general = JArray.Parse(await SearchHelper.GetResponseStringAsync($"http://api.champion.gg/stats/" + var general = JArray.Parse(await SearchHelper.GetResponseStringAsync($"http://api.champion.gg/stats/" +
$"champs/{name}?api_key={NadekoBot.Creds.LOLAPIKey}")) $"champs/{name}?api_key={NadekoBot.Creds.LOLAPIKey}"))
.FirstOrDefault(jt => jt["role"].ToString() == role)?["general"]; .FirstOrDefault(jt => jt["role"].ToString() == role)?["general"];
if (general == null) { if (general == null)
{
Console.WriteLine("General is null."); Console.WriteLine("General is null.");
return; return;
} }
//get build data for this role //get build data for this role
var buildData = data["items"]["mostGames"]["items"]; var buildData = data["items"]["mostGames"]["items"];
var items = new string[6]; var items = new string[6];
for (var i = 0; i < 6; i++) { for (var i = 0; i < 6; i++)
{
items[i] = buildData[i]["id"].ToString(); items[i] = buildData[i]["id"].ToString();
} }
@ -146,7 +170,8 @@ namespace NadekoBot.Commands {
var orderArr = (data["skills"]["mostGames"]["order"] as JArray); var orderArr = (data["skills"]["mostGames"]["order"] as JArray);
var img = Image.FromFile("data/lol/bg.png"); var img = Image.FromFile("data/lol/bg.png");
using (var g = Graphics.FromImage(img)) { using (var g = Graphics.FromImage(img))
{
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
//g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy; //g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
const int margin = 5; const int margin = 5;
@ -166,12 +191,14 @@ namespace NadekoBot.Commands {
//draw skill order //draw skill order
float orderFormula = 120 / orderArr.Count; float orderFormula = 120 / orderArr.Count;
const float orderVerticalSpacing = 10; const float orderVerticalSpacing = 10;
for (var i = 0; i < orderArr.Count; i++) { for (var i = 0; i < orderArr.Count; i++)
{
var orderX = margin + margin + imageSize + orderFormula * i + i; var orderX = margin + margin + imageSize + orderFormula * i + i;
float orderY = margin + 35; float orderY = margin + 35;
var spellName = orderArr[i].ToString().ToLowerInvariant(); var spellName = orderArr[i].ToString().ToLowerInvariant();
switch (spellName) { switch (spellName)
{
case "w": case "w":
orderY += orderVerticalSpacing; orderY += orderVerticalSpacing;
break; break;
@ -206,7 +233,8 @@ Assists: {general["assists"]} Ban: {general["banRate"]}%
g.DrawString($"Best against", smallFont, Brushes.WhiteSmoke, margin, img.Height - imageSize + margin); g.DrawString($"Best against", smallFont, Brushes.WhiteSmoke, margin, img.Height - imageSize + margin);
var smallImgSize = 50; var smallImgSize = 50;
for (var i = 0; i < counters.Length; i++) { for (var i = 0; i < counters.Length; i++)
{
g.DrawImage(GetImage(counters[i]), g.DrawImage(GetImage(counters[i]),
new Rectangle(i * (smallImgSize + margin) + margin, img.Height - smallImgSize - margin, new Rectangle(i * (smallImgSize + margin) + margin, img.Height - smallImgSize - margin,
smallImgSize, smallImgSize,
@ -215,7 +243,8 @@ Assists: {general["assists"]} Ban: {general["banRate"]}%
//draw countered by //draw countered by
g.DrawString($"Worst against", smallFont, Brushes.WhiteSmoke, img.Width - 3 * (smallImgSize + margin), img.Height - imageSize + margin); g.DrawString($"Worst against", smallFont, Brushes.WhiteSmoke, img.Width - 3 * (smallImgSize + margin), img.Height - imageSize + margin);
for (var i = 0; i < countered.Length; i++) { for (var i = 0; i < countered.Length; i++)
{
var j = countered.Length - i; var j = countered.Length - i;
g.DrawImage(GetImage(countered[i]), g.DrawImage(GetImage(countered[i]),
new Rectangle(img.Width - (j * (smallImgSize + margin) + margin), img.Height - smallImgSize - margin, new Rectangle(img.Width - (j * (smallImgSize + margin) + margin), img.Height - smallImgSize - margin,
@ -225,7 +254,8 @@ Assists: {general["assists"]} Ban: {general["banRate"]}%
//draw item build //draw item build
g.DrawString("Popular build", normalFont, Brushes.WhiteSmoke, img.Width - (3 * (smallImgSize + margin) + margin), 77); g.DrawString("Popular build", normalFont, Brushes.WhiteSmoke, img.Width - (3 * (smallImgSize + margin) + margin), 77);
for (var i = 0; i < 6; i++) { for (var i = 0; i < 6; i++)
{
var inverseI = 5 - i; var inverseI = 5 - i;
var j = inverseI % 3 + 1; var j = inverseI % 3 + 1;
var k = inverseI / 3; var k = inverseI / 3;
@ -238,18 +268,23 @@ Assists: {general["assists"]} Ban: {general["banRate"]}%
var cachedChamp = new CachedChampion { AddedAt = DateTime.Now, ImageStream = img.ToStream(System.Drawing.Imaging.ImageFormat.Png), Name = name.ToLower() + "_" + resolvedRole }; var cachedChamp = new CachedChampion { AddedAt = DateTime.Now, ImageStream = img.ToStream(System.Drawing.Imaging.ImageFormat.Png), Name = name.ToLower() + "_" + resolvedRole };
CachedChampionImages.Add(cachedChamp.Name, cachedChamp); CachedChampionImages.Add(cachedChamp.Name, cachedChamp);
await e.Channel.SendFile(data["title"] + "_stats.png", cachedChamp.ImageStream); await e.Channel.SendFile(data["title"] + "_stats.png", cachedChamp.ImageStream);
} catch { }
catch (Exception ex)
{
Console.WriteLine(ex);
await e.Channel.SendMessage("💢 Failed retreiving data for that champion."); await e.Channel.SendMessage("💢 Failed retreiving data for that champion.");
} }
}); });
cgb.CreateCommand(Module.Prefix + "lolban") cgb.CreateCommand(Module.Prefix + "lolban")
.Description("Shows top 6 banned champions ordered by ban rate. Ban these champions and you will be Plat 5 in no time.") .Description("Shows top 6 banned champions ordered by ban rate. Ban these champions and you will be Plat 5 in no time.")
.Do(async e => { .Do(async e =>
{
var showCount = 6; var showCount = 6;
//http://api.champion.gg/stats/champs/mostBanned?api_key=YOUR_API_TOKEN&page=1&limit=2 //http://api.champion.gg/stats/champs/mostBanned?api_key=YOUR_API_TOKEN&page=1&limit=2
try { try
{
var data = JObject.Parse( var data = JObject.Parse(
await Classes await Classes
.SearchHelper .SearchHelper
@ -260,7 +295,8 @@ Assists: {general["assists"]} Ban: {general["banRate"]}%
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine($"**Showing {showCount} top banned champions.**"); sb.AppendLine($"**Showing {showCount} top banned champions.**");
sb.AppendLine($"`{trashTalk[new Random().Next(0, trashTalk.Length)]}`"); sb.AppendLine($"`{trashTalk[new Random().Next(0, trashTalk.Length)]}`");
for (var i = 0; i < data.Count; i++) { for (var i = 0; i < data.Count; i++)
{
if (i % 2 == 0 && i != 0) if (i % 2 == 0 && i != 0)
sb.AppendLine(); sb.AppendLine();
sb.Append($"`{i + 1}.` **{data[i]["name"]}** "); sb.Append($"`{i + 1}.` **{data[i]["name"]}** ");
@ -268,34 +304,44 @@ Assists: {general["assists"]} Ban: {general["banRate"]}%
} }
await e.Channel.SendMessage(sb.ToString()); await e.Channel.SendMessage(sb.ToString());
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage($":anger: Fail: Champion.gg didsabled ban data until next patch. Sorry for the inconvenience."); await e.Channel.SendMessage($":anger: Fail: Champion.gg didsabled ban data until next patch. Sorry for the inconvenience.");
} }
}); });
} }
private enum GetImageType { private enum GetImageType
{
Champion, Champion,
Item Item
} }
private static Image GetImage(string id, GetImageType imageType = GetImageType.Champion) { private static Image GetImage(string id, GetImageType imageType = GetImageType.Champion)
try { {
switch (imageType) { try
{
switch (imageType)
{
case GetImageType.Champion: case GetImageType.Champion:
return Image.FromFile($"data/lol/champions/{id}.png"); return Image.FromFile($"data/lol/champions/{id}.png");
case GetImageType.Item: case GetImageType.Item:
default: default:
return Image.FromFile($"data/lol/items/{id}.png"); return Image.FromFile($"data/lol/items/{id}.png");
} }
} catch (Exception) { }
catch (Exception)
{
return Image.FromFile("data/lol/_ERROR.png"); return Image.FromFile("data/lol/_ERROR.png");
} }
} }
private static string ResolvePos(string pos) { private static string ResolvePos(string pos)
{
if (string.IsNullOrWhiteSpace(pos)) if (string.IsNullOrWhiteSpace(pos))
return null; return null;
switch (pos.ToLowerInvariant()) { switch (pos.ToLowerInvariant())
{
case "m": case "m":
case "mid": case "mid":
case "midorfeed": case "midorfeed":

View File

@ -1,23 +1,24 @@
using System; using Discord;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Timers;
using System.Threading.Tasks;
using Discord.Commands; using Discord.Commands;
using Discord;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Classes.Permissions; using NadekoBot.Classes.Permissions;
using NadekoBot.Modules; using NadekoBot.Modules;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;
namespace NadekoBot.Commands { namespace NadekoBot.Commands
internal class LogCommand : DiscordCommand { {
internal class LogCommand : DiscordCommand
{
private readonly ConcurrentDictionary<Server, Channel> logs = new ConcurrentDictionary<Server, Channel>(); private readonly ConcurrentDictionary<Server, Channel> logs = new ConcurrentDictionary<Server, Channel>();
private readonly ConcurrentDictionary<Server, Channel> loggingPresences = new ConcurrentDictionary<Server, Channel>(); private readonly ConcurrentDictionary<Server, Channel> loggingPresences = new ConcurrentDictionary<Server, Channel>();
private readonly ConcurrentDictionary<Channel, Channel> voiceChannelLog = new ConcurrentDictionary<Channel, Channel>(); private readonly ConcurrentDictionary<Channel, Channel> voiceChannelLog = new ConcurrentDictionary<Channel, Channel>();
public LogCommand(DiscordModule module) : base(module) { public LogCommand(DiscordModule module) : base(module)
{
NadekoBot.Client.MessageReceived += MsgRecivd; NadekoBot.Client.MessageReceived += MsgRecivd;
NadekoBot.Client.MessageDeleted += MsgDltd; NadekoBot.Client.MessageDeleted += MsgDltd;
NadekoBot.Client.MessageUpdated += MsgUpdtd; NadekoBot.Client.MessageUpdated += MsgUpdtd;
@ -25,11 +26,13 @@ namespace NadekoBot.Commands {
NadekoBot.Client.UserBanned += UsrBanned; NadekoBot.Client.UserBanned += UsrBanned;
NadekoBot.Client.MessageReceived += async (s, e) => { NadekoBot.Client.MessageReceived += async (s, e) =>
{
if (e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id) if (e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id)
return; return;
if (!SpecificConfigurations.Default.Of(e.Server.Id).SendPrivateMessageOnMention) return; if (!SpecificConfigurations.Default.Of(e.Server.Id).SendPrivateMessageOnMention) return;
try { try
{
var usr = e.Message.MentionedUsers.FirstOrDefault(u => u != e.User); var usr = e.Message.MentionedUsers.FirstOrDefault(u => u != e.User);
if (usr?.Status != UserStatus.Offline) if (usr?.Status != UserStatus.Offline)
return; return;
@ -38,22 +41,28 @@ namespace NadekoBot.Commands {
$"User `{e.User.Name}` mentioned you on " + $"User `{e.User.Name}` mentioned you on " +
$"`{e.Server.Name}` server while you were offline.\n" + $"`{e.Server.Name}` server while you were offline.\n" +
$"`Message:` {e.Message.Text}"); $"`Message:` {e.Message.Text}");
} catch { } }
catch { }
}; };
} }
private async void UsrBanned(object sender, UserEventArgs e) { private async void UsrBanned(object sender, UserEventArgs e)
try { {
try
{
Channel ch; Channel ch;
if (!logs.TryGetValue(e.Server, out ch)) if (!logs.TryGetValue(e.Server, out ch))
return; return;
await ch.SendMessage($"`User banned:` **{e.User.Name}** ({e.User.Id})"); await ch.SendMessage($"`User banned:` **{e.User.Name}** ({e.User.Id})");
} catch { } }
catch { }
} }
public Func<CommandEventArgs, Task> DoFunc() => async e => { public Func<CommandEventArgs, Task> DoFunc() => async e =>
{
Channel ch; Channel ch;
if (!logs.TryRemove(e.Server, out ch)) { if (!logs.TryRemove(e.Server, out ch))
{
logs.TryAdd(e.Server, e.Channel); logs.TryAdd(e.Server, e.Channel);
await e.Channel.SendMessage($"**I WILL BEGIN LOGGING SERVER ACTIVITY IN THIS CHANNEL**"); await e.Channel.SendMessage($"**I WILL BEGIN LOGGING SERVER ACTIVITY IN THIS CHANNEL**");
return; return;
@ -62,57 +71,75 @@ namespace NadekoBot.Commands {
await e.Channel.SendMessage($"**NO LONGER LOGGING IN {ch.Mention} CHANNEL**"); await e.Channel.SendMessage($"**NO LONGER LOGGING IN {ch.Mention} CHANNEL**");
}; };
private async void MsgRecivd(object sender, MessageEventArgs e) { private async void MsgRecivd(object sender, MessageEventArgs e)
try { {
try
{
if (e.Server == null || e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id) if (e.Server == null || e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id)
return; return;
Channel ch; Channel ch;
if (!logs.TryGetValue(e.Server, out ch) || e.Channel == ch) if (!logs.TryGetValue(e.Server, out ch) || e.Channel == ch)
return; return;
await ch.SendMessage($"`Type:` **Message received** `Time:` **{DateTime.Now}** `Channel:` **{e.Channel.Name}**\n`{e.User}:` {e.Message.Text}"); await ch.SendMessage($"`Type:` **Message received** `Time:` **{DateTime.Now}** `Channel:` **{e.Channel.Name}**\n`{e.User}:` {e.Message.Text}");
} catch { } }
catch { }
} }
private async void MsgDltd(object sender, MessageEventArgs e) { private async void MsgDltd(object sender, MessageEventArgs e)
try { {
try
{
if (e.Server == null || e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id) if (e.Server == null || e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id)
return; return;
Channel ch; Channel ch;
if (!logs.TryGetValue(e.Server, out ch) || e.Channel == ch) if (!logs.TryGetValue(e.Server, out ch) || e.Channel == ch)
return; return;
await ch.SendMessage($"`Type:` **Message deleted** `Time:` **{DateTime.Now}** `Channel:` **{e.Channel.Name}**\n`{e.User}:` {e.Message.Text}"); await ch.SendMessage($"`Type:` **Message deleted** `Time:` **{DateTime.Now}** `Channel:` **{e.Channel.Name}**\n`{e.User}:` {e.Message.Text}");
} catch { } }
catch { }
} }
private async void MsgUpdtd(object sender, MessageUpdatedEventArgs e) { private async void MsgUpdtd(object sender, MessageUpdatedEventArgs e)
try { {
try
{
if (e.Server == null || e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id) if (e.Server == null || e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id)
return; return;
Channel ch; Channel ch;
if (!logs.TryGetValue(e.Server, out ch) || e.Channel == ch) if (!logs.TryGetValue(e.Server, out ch) || e.Channel == ch)
return; return;
await ch.SendMessage($"`Type:` **Message updated** `Time:` **{DateTime.Now}** `Channel:` **{e.Channel.Name}**\n**BEFORE**: `{e.User}:` {e.Before.Text}\n---------------\n**AFTER**: `{e.User}:` {e.After.Text}"); await ch.SendMessage($"`Type:` **Message updated** `Time:` **{DateTime.Now}** `Channel:` **{e.Channel.Name}**\n**BEFORE**: `{e.User}:` {e.Before.Text}\n---------------\n**AFTER**: `{e.User}:` {e.After.Text}");
} catch { } }
catch { }
} }
private async void UsrUpdtd(object sender, UserUpdatedEventArgs e) { private async void UsrUpdtd(object sender, UserUpdatedEventArgs e)
try { {
try
{
Channel ch; Channel ch;
if (loggingPresences.TryGetValue(e.Server, out ch)) if (loggingPresences.TryGetValue(e.Server, out ch))
if (e.Before.Status != e.After.Status) { if (e.Before.Status != e.After.Status)
{
await ch.SendMessage($"**{e.Before.Name}** is now **{e.After.Status}**."); await ch.SendMessage($"**{e.Before.Name}** is now **{e.After.Status}**.");
} }
} catch { } }
catch { }
try { try
if (e.Before.VoiceChannel != null && voiceChannelLog.ContainsKey(e.Before.VoiceChannel)) { {
if (e.Before.VoiceChannel != null && voiceChannelLog.ContainsKey(e.Before.VoiceChannel))
{
if (e.After.VoiceChannel != e.Before.VoiceChannel) if (e.After.VoiceChannel != e.Before.VoiceChannel)
await voiceChannelLog[e.Before.VoiceChannel].SendMessage($"🎼`{e.Before.Name} has left the` {e.Before.VoiceChannel.Mention} `voice channel.`"); await voiceChannelLog[e.Before.VoiceChannel].SendMessage($"🎼`{e.Before.Name} has left the` {e.Before.VoiceChannel.Mention} `voice channel.`");
} }
if (e.After.VoiceChannel != null && voiceChannelLog.ContainsKey(e.After.VoiceChannel)) { if (e.After.VoiceChannel != null && voiceChannelLog.ContainsKey(e.After.VoiceChannel))
{
if (e.After.VoiceChannel != e.Before.VoiceChannel) if (e.After.VoiceChannel != e.Before.VoiceChannel)
await voiceChannelLog[e.After.VoiceChannel].SendMessage($"🎼`{e.After.Name} has joined the`{e.After.VoiceChannel.Mention} `voice channel.`"); await voiceChannelLog[e.After.VoiceChannel].SendMessage($"🎼`{e.After.Name} has joined the`{e.After.VoiceChannel.Mention} `voice channel.`");
} }
} catch { } }
catch { }
try { try
{
Channel ch; Channel ch;
if (!logs.TryGetValue(e.Server, out ch)) if (!logs.TryGetValue(e.Server, out ch))
return; return;
@ -126,15 +153,18 @@ namespace NadekoBot.Commands {
else else
return; return;
await ch.SendMessage(str); await ch.SendMessage(str);
} catch { } }
catch { }
} }
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "spmom") cgb.CreateCommand(Module.Prefix + "spmom")
.Description("Toggles whether mentions of other offline users on your server will send a pm to them.") .Description("Toggles whether mentions of other offline users on your server will send a pm to them.")
.AddCheck(SimpleCheckers.ManageServer()) .AddCheck(SimpleCheckers.ManageServer())
.Do(async e => { .Do(async e =>
{
var specificConfig = SpecificConfigurations.Default.Of(e.Server.Id); var specificConfig = SpecificConfigurations.Default.Of(e.Server.Id);
specificConfig.SendPrivateMessageOnMention = specificConfig.SendPrivateMessageOnMention =
!specificConfig.SendPrivateMessageOnMention; !specificConfig.SendPrivateMessageOnMention;
@ -156,9 +186,11 @@ namespace NadekoBot.Commands {
.Description("Starts logging to this channel when someone from the server goes online/offline/idle. **Owner Only!**") .Description("Starts logging to this channel when someone from the server goes online/offline/idle. **Owner Only!**")
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.AddCheck(SimpleCheckers.ManageServer()) .AddCheck(SimpleCheckers.ManageServer())
.Do(async e => { .Do(async e =>
{
Channel ch; Channel ch;
if (!loggingPresences.TryRemove(e.Server, out ch)) { if (!loggingPresences.TryRemove(e.Server, out ch))
{
loggingPresences.TryAdd(e.Server, e.Channel); loggingPresences.TryAdd(e.Server, e.Channel);
await e.Channel.SendMessage($"**User presence notifications enabled.**"); await e.Channel.SendMessage($"**User presence notifications enabled.**");
return; return;
@ -172,25 +204,31 @@ namespace NadekoBot.Commands {
.Parameter("all", ParameterType.Optional) .Parameter("all", ParameterType.Optional)
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.AddCheck(SimpleCheckers.ManageServer()) .AddCheck(SimpleCheckers.ManageServer())
.Do(async e => { .Do(async e =>
{
if (e.GetArg("all")?.ToLower() == "all") { if (e.GetArg("all")?.ToLower() == "all")
foreach (var voiceChannel in e.Server.VoiceChannels) { {
foreach (var voiceChannel in e.Server.VoiceChannels)
{
voiceChannelLog.TryAdd(voiceChannel, e.Channel); voiceChannelLog.TryAdd(voiceChannel, e.Channel);
} }
await e.Channel.SendMessage("Started logging user presence for **ALL** voice channels!"); await e.Channel.SendMessage("Started logging user presence for **ALL** voice channels!");
return; return;
} }
if (e.User.VoiceChannel == null) { if (e.User.VoiceChannel == null)
{
await e.Channel.SendMessage("💢 You are not in a voice channel right now. If you are, please rejoin it."); await e.Channel.SendMessage("💢 You are not in a voice channel right now. If you are, please rejoin it.");
return; return;
} }
Channel throwaway; Channel throwaway;
if (!voiceChannelLog.TryRemove(e.User.VoiceChannel, out throwaway)) { if (!voiceChannelLog.TryRemove(e.User.VoiceChannel, out throwaway))
{
voiceChannelLog.TryAdd(e.User.VoiceChannel, e.Channel); voiceChannelLog.TryAdd(e.User.VoiceChannel, e.Channel);
await e.Channel.SendMessage($"`Logging user updates for` {e.User.VoiceChannel.Mention} `voice channel.`"); await e.Channel.SendMessage($"`Logging user updates for` {e.User.VoiceChannel.Mention} `voice channel.`");
} else }
else
await e.Channel.SendMessage($"`Stopped logging user updates for` {e.User.VoiceChannel.Mention} `voice channel.`"); await e.Channel.SendMessage($"`Stopped logging user updates for` {e.User.VoiceChannel.Mention} `voice channel.`");
}); });
} }

View File

@ -1,21 +1,23 @@
using Discord.Modules;
using Discord.Commands;
using Discord; using Discord;
using System; using Discord.Commands;
using System.Collections.Generic; using Discord.Modules;
using System.Linq;
using NadekoBot.Extensions;
using System.Threading.Tasks;
using NadekoBot.Commands;
using System.IO;
using Newtonsoft.Json.Linq;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Classes.Permissions;
using NadekoBot.Classes._DataModels; using NadekoBot.Classes._DataModels;
using NadekoBot.Classes.Permissions;
using NadekoBot.Commands;
using NadekoBot.Extensions;
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace NadekoBot.Modules { namespace NadekoBot.Modules
internal class Administration : DiscordModule { {
public Administration() { internal class Administration : DiscordModule
{
public Administration()
{
commands.Add(new ServerGreetCommand(this)); commands.Add(new ServerGreetCommand(this));
commands.Add(new LogCommand(this)); commands.Add(new LogCommand(this));
commands.Add(new MessageRepeater(this)); commands.Add(new MessageRepeater(this));
@ -28,8 +30,10 @@ namespace NadekoBot.Modules {
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Administration; public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Administration;
public override void Install(ModuleManager manager) { public override void Install(ModuleManager manager)
manager.CreateCommands("", cgb => { {
manager.CreateCommands("", cgb =>
{
cgb.AddCheck(PermissionChecker.Instance); cgb.AddCheck(PermissionChecker.Instance);
@ -42,32 +46,39 @@ namespace NadekoBot.Modules {
.Parameter("user_name", ParameterType.Required) .Parameter("user_name", ParameterType.Required)
.Parameter("role_name", ParameterType.Unparsed) .Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => { .Do(async e =>
{
var userName = e.GetArg("user_name"); var userName = e.GetArg("user_name");
var roleName = e.GetArg("role_name"); var roleName = e.GetArg("role_name");
if (string.IsNullOrWhiteSpace(roleName)) return; if (string.IsNullOrWhiteSpace(roleName)) return;
if (!e.User.ServerPermissions.ManageRoles) { if (!e.User.ServerPermissions.ManageRoles)
{
await e.Channel.SendMessage("You have insufficient permissions."); await e.Channel.SendMessage("You have insufficient permissions.");
} }
var usr = e.Server.FindUsers(userName).FirstOrDefault(); var usr = e.Server.FindUsers(userName).FirstOrDefault();
if (usr == null) { if (usr == null)
{
await e.Channel.SendMessage("You failed to supply a valid username"); await e.Channel.SendMessage("You failed to supply a valid username");
return; return;
} }
var role = e.Server.FindRoles(roleName).FirstOrDefault(); var role = e.Server.FindRoles(roleName).FirstOrDefault();
if (role == null) { if (role == null)
{
await e.Channel.SendMessage("You failed to supply a valid role"); await e.Channel.SendMessage("You failed to supply a valid role");
return; return;
} }
try { try
{
await usr.AddRoles(role); await usr.AddRoles(role);
await e.Channel.SendMessage($"Successfully added role **{role.Name}** to user **{usr.Name}**"); await e.Channel.SendMessage($"Successfully added role **{role.Name}** to user **{usr.Name}**");
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage("Failed to add roles. Bot has insufficient permissions.\n"); await e.Channel.SendMessage("Failed to add roles. Bot has insufficient permissions.\n");
Console.WriteLine(ex.ToString()); Console.WriteLine(ex.ToString());
} }
@ -78,28 +89,34 @@ namespace NadekoBot.Modules {
.Parameter("user_name", ParameterType.Required) .Parameter("user_name", ParameterType.Required)
.Parameter("role_name", ParameterType.Unparsed) .Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => { .Do(async e =>
{
var userName = e.GetArg("user_name"); var userName = e.GetArg("user_name");
var roleName = e.GetArg("role_name"); var roleName = e.GetArg("role_name");
if (string.IsNullOrWhiteSpace(roleName)) return; if (string.IsNullOrWhiteSpace(roleName)) return;
var usr = e.Server.FindUsers(userName).FirstOrDefault(); var usr = e.Server.FindUsers(userName).FirstOrDefault();
if (usr == null) { if (usr == null)
{
await e.Channel.SendMessage("You failed to supply a valid username"); await e.Channel.SendMessage("You failed to supply a valid username");
return; return;
} }
var role = e.Server.FindRoles(roleName).FirstOrDefault(); var role = e.Server.FindRoles(roleName).FirstOrDefault();
if (role == null) { if (role == null)
{
await e.Channel.SendMessage("You failed to supply a valid role"); await e.Channel.SendMessage("You failed to supply a valid role");
return; return;
} }
try { try
{
await usr.RemoveRoles(role); await usr.RemoveRoles(role);
await e.Channel.SendMessage($"Successfully removed role **{role.Name}** from user **{usr.Name}**"); await e.Channel.SendMessage($"Successfully removed role **{role.Name}** from user **{usr.Name}**");
} catch { }
catch
{
await e.Channel.SendMessage("Failed to remove roles. Most likely reason: Insufficient permissions."); await e.Channel.SendMessage("Failed to remove roles. Most likely reason: Insufficient permissions.");
} }
}); });
@ -108,13 +125,17 @@ namespace NadekoBot.Modules {
.Description("Creates a role with a given name.**Usage**: .r Awesome Role") .Description("Creates a role with a given name.**Usage**: .r Awesome Role")
.Parameter("role_name", ParameterType.Unparsed) .Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => { .Do(async e =>
{
if (string.IsNullOrWhiteSpace(e.GetArg("role_name"))) if (string.IsNullOrWhiteSpace(e.GetArg("role_name")))
return; return;
try { try
{
var r = await e.Server.CreateRole(e.GetArg("role_name")); var r = await e.Server.CreateRole(e.GetArg("role_name"));
await e.Channel.SendMessage($"Successfully created role **{r.Name}**."); await e.Channel.SendMessage($"Successfully created role **{r.Name}**.");
} catch (Exception) { }
catch (Exception)
{
await e.Channel.SendMessage(":warning: Unspecified error."); await e.Channel.SendMessage(":warning: Unspecified error.");
} }
}); });
@ -125,26 +146,31 @@ namespace NadekoBot.Modules {
.Parameter("g", ParameterType.Optional) .Parameter("g", ParameterType.Optional)
.Parameter("b", ParameterType.Optional) .Parameter("b", ParameterType.Optional)
.Description("Set a role's color to the hex or 0-255 rgb color value provided.\n**Usage**: .color Admin 255 200 100 or .color Admin ffba55") .Description("Set a role's color to the hex or 0-255 rgb color value provided.\n**Usage**: .color Admin 255 200 100 or .color Admin ffba55")
.Do(async e => { .Do(async e =>
if (!e.User.ServerPermissions.ManageRoles) { {
if (!e.User.ServerPermissions.ManageRoles)
{
await e.Channel.SendMessage("You don't have permission to use this!"); await e.Channel.SendMessage("You don't have permission to use this!");
return; return;
} }
var args = e.Args.Where(s => s != string.Empty); var args = e.Args.Where(s => s != string.Empty);
if (args.Count() != 2 && args.Count() != 4) { if (args.Count() != 2 && args.Count() != 4)
{
await e.Channel.SendMessage("The parameters are invalid."); await e.Channel.SendMessage("The parameters are invalid.");
return; return;
} }
var role = e.Server.FindRoles(e.Args[0]).FirstOrDefault(); var role = e.Server.FindRoles(e.Args[0]).FirstOrDefault();
if (role == null) { if (role == null)
{
await e.Channel.SendMessage("That role does not exist."); await e.Channel.SendMessage("That role does not exist.");
return; return;
} }
try { try
{
var rgb = args.Count() == 4; var rgb = args.Count() == 4;
var red = Convert.ToByte(rgb ? int.Parse(e.Args[1]) : Convert.ToInt32(e.Args[1].Substring(0, 2), 16)); var red = Convert.ToByte(rgb ? int.Parse(e.Args[1]) : Convert.ToInt32(e.Args[1].Substring(0, 2), 16));
@ -153,7 +179,9 @@ namespace NadekoBot.Modules {
await role.Edit(color: new Color(red, green, blue)); await role.Edit(color: new Color(red, green, blue));
await e.Channel.SendMessage($"Role {role.Name}'s color has been changed."); await e.Channel.SendMessage($"Role {role.Name}'s color has been changed.");
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage("Error occured, most likely invalid parameters or insufficient permissions."); await e.Channel.SendMessage("Error occured, most likely invalid parameters or insufficient permissions.");
} }
}); });
@ -161,8 +189,10 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "roles") cgb.CreateCommand(Prefix + "roles")
.Description("List all roles on this server or a single user if specified.") .Description("List all roles on this server or a single user if specified.")
.Parameter("user", ParameterType.Unparsed) .Parameter("user", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
if (!string.IsNullOrWhiteSpace(e.GetArg("user"))) { {
if (!string.IsNullOrWhiteSpace(e.GetArg("user")))
{
var usr = e.Server.FindUsers(e.GetArg("user")).FirstOrDefault(); var usr = e.Server.FindUsers(e.GetArg("user")).FirstOrDefault();
if (usr == null) return; if (usr == null) return;
@ -176,24 +206,31 @@ namespace NadekoBot.Modules {
.Parameter("user", ParameterType.Required) .Parameter("user", ParameterType.Required)
.Parameter("msg", ParameterType.Optional) .Parameter("msg", ParameterType.Optional)
.Description("Bans a user by id or name with an optional message.\n**Usage**: .b \"@some Guy\" Your behaviour is toxic.") .Description("Bans a user by id or name with an optional message.\n**Usage**: .b \"@some Guy\" Your behaviour is toxic.")
.Do(async e => { .Do(async e =>
{
var msg = e.GetArg("msg"); var msg = e.GetArg("msg");
var user = e.GetArg("user"); var user = e.GetArg("user");
if (e.User.ServerPermissions.BanMembers) { if (e.User.ServerPermissions.BanMembers)
{
var usr = e.Server.FindUsers(user).FirstOrDefault(); var usr = e.Server.FindUsers(user).FirstOrDefault();
if (usr == null) { if (usr == null)
{
await e.Channel.SendMessage("User not found."); await e.Channel.SendMessage("User not found.");
return; return;
} }
if (!string.IsNullOrWhiteSpace(msg)) { if (!string.IsNullOrWhiteSpace(msg))
{
await usr.SendMessage($"**You have been BANNED from `{e.Server.Name}` server.**\n" + await usr.SendMessage($"**You have been BANNED from `{e.Server.Name}` server.**\n" +
$"Reason: {msg}"); $"Reason: {msg}");
await Task.Delay(2000); // temp solution; give time for a message to be send, fu volt await Task.Delay(2000); // temp solution; give time for a message to be send, fu volt
} }
try { try
{
await e.Server.Ban(usr); await e.Server.Ban(usr);
await e.Channel.SendMessage("Banned user " + usr.Name + " Id: " + usr.Id); await e.Channel.SendMessage("Banned user " + usr.Name + " Id: " + usr.Id);
} catch { }
catch
{
await e.Channel.SendMessage("Error. Most likely I don't have sufficient permissions."); await e.Channel.SendMessage("Error. Most likely I don't have sufficient permissions.");
} }
} }
@ -203,24 +240,31 @@ namespace NadekoBot.Modules {
.Parameter("user") .Parameter("user")
.Parameter("msg", ParameterType.Unparsed) .Parameter("msg", ParameterType.Unparsed)
.Description("Kicks a mentioned user.") .Description("Kicks a mentioned user.")
.Do(async e => { .Do(async e =>
{
var msg = e.GetArg("msg"); var msg = e.GetArg("msg");
var user = e.GetArg("user"); var user = e.GetArg("user");
if (e.User.ServerPermissions.KickMembers) { if (e.User.ServerPermissions.KickMembers)
{
var usr = e.Server.FindUsers(user).FirstOrDefault(); var usr = e.Server.FindUsers(user).FirstOrDefault();
if (usr == null) { if (usr == null)
{
await e.Channel.SendMessage("User not found."); await e.Channel.SendMessage("User not found.");
return; return;
} }
if (!string.IsNullOrWhiteSpace(msg)) { if (!string.IsNullOrWhiteSpace(msg))
{
await usr.SendMessage($"**You have been KICKED from `{e.Server.Name}` server.**\n" + await usr.SendMessage($"**You have been KICKED from `{e.Server.Name}` server.**\n" +
$"Reason: {msg}"); $"Reason: {msg}");
await Task.Delay(2000); // temp solution; give time for a message to be send, fu volt await Task.Delay(2000); // temp solution; give time for a message to be send, fu volt
} }
try { try
{
await usr.Kick(); await usr.Kick();
await e.Channel.SendMessage("Kicked user " + usr.Name + " Id: " + usr.Id); await e.Channel.SendMessage("Kicked user " + usr.Name + " Id: " + usr.Id);
} catch { }
catch
{
await e.Channel.SendMessage("Error. Most likely I don't have sufficient permissions."); await e.Channel.SendMessage("Error. Most likely I don't have sufficient permissions.");
} }
} }
@ -228,19 +272,25 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "mute") cgb.CreateCommand(Prefix + "mute")
.Description("Mutes mentioned user or users.") .Description("Mutes mentioned user or users.")
.Parameter("throwaway", ParameterType.Unparsed) .Parameter("throwaway", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
if (!e.User.ServerPermissions.MuteMembers) { {
if (!e.User.ServerPermissions.MuteMembers)
{
await e.Channel.SendMessage("You do not have permission to do that."); await e.Channel.SendMessage("You do not have permission to do that.");
return; return;
} }
if (!e.Message.MentionedUsers.Any()) if (!e.Message.MentionedUsers.Any())
return; return;
try { try
foreach (var u in e.Message.MentionedUsers) { {
foreach (var u in e.Message.MentionedUsers)
{
await u.Edit(isMuted: true); await u.Edit(isMuted: true);
} }
await e.Channel.SendMessage("Mute successful"); await e.Channel.SendMessage("Mute successful");
} catch { }
catch
{
await e.Channel.SendMessage("I do not have permission to do that most likely."); await e.Channel.SendMessage("I do not have permission to do that most likely.");
} }
}); });
@ -248,19 +298,25 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "unmute") cgb.CreateCommand(Prefix + "unmute")
.Description("Unmutes mentioned user or users.") .Description("Unmutes mentioned user or users.")
.Parameter("throwaway", ParameterType.Unparsed) .Parameter("throwaway", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
if (!e.User.ServerPermissions.MuteMembers) { {
if (!e.User.ServerPermissions.MuteMembers)
{
await e.Channel.SendMessage("You do not have permission to do that."); await e.Channel.SendMessage("You do not have permission to do that.");
return; return;
} }
if (!e.Message.MentionedUsers.Any()) if (!e.Message.MentionedUsers.Any())
return; return;
try { try
foreach (var u in e.Message.MentionedUsers) { {
foreach (var u in e.Message.MentionedUsers)
{
await u.Edit(isMuted: false); await u.Edit(isMuted: false);
} }
await e.Channel.SendMessage("Unmute successful"); await e.Channel.SendMessage("Unmute successful");
} catch { }
catch
{
await e.Channel.SendMessage("I do not have permission to do that most likely."); await e.Channel.SendMessage("I do not have permission to do that most likely.");
} }
}); });
@ -269,19 +325,25 @@ namespace NadekoBot.Modules {
.Alias(Prefix + "deaf") .Alias(Prefix + "deaf")
.Description("Deafens mentioned user or users") .Description("Deafens mentioned user or users")
.Parameter("throwaway", ParameterType.Unparsed) .Parameter("throwaway", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
if (!e.User.ServerPermissions.DeafenMembers) { {
if (!e.User.ServerPermissions.DeafenMembers)
{
await e.Channel.SendMessage("You do not have permission to do that."); await e.Channel.SendMessage("You do not have permission to do that.");
return; return;
} }
if (!e.Message.MentionedUsers.Any()) if (!e.Message.MentionedUsers.Any())
return; return;
try { try
foreach (var u in e.Message.MentionedUsers) { {
foreach (var u in e.Message.MentionedUsers)
{
await u.Edit(isDeafened: true); await u.Edit(isDeafened: true);
} }
await e.Channel.SendMessage("Deafen successful"); await e.Channel.SendMessage("Deafen successful");
} catch { }
catch
{
await e.Channel.SendMessage("I do not have permission to do that most likely."); await e.Channel.SendMessage("I do not have permission to do that most likely.");
} }
}); });
@ -290,19 +352,25 @@ namespace NadekoBot.Modules {
.Alias(Prefix + "undeaf") .Alias(Prefix + "undeaf")
.Description("Undeafens mentioned user or users") .Description("Undeafens mentioned user or users")
.Parameter("throwaway", ParameterType.Unparsed) .Parameter("throwaway", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
if (!e.User.ServerPermissions.DeafenMembers) { {
if (!e.User.ServerPermissions.DeafenMembers)
{
await e.Channel.SendMessage("You do not have permission to do that."); await e.Channel.SendMessage("You do not have permission to do that.");
return; return;
} }
if (!e.Message.MentionedUsers.Any()) if (!e.Message.MentionedUsers.Any())
return; return;
try { try
foreach (var u in e.Message.MentionedUsers) { {
foreach (var u in e.Message.MentionedUsers)
{
await u.Edit(isDeafened: false); await u.Edit(isDeafened: false);
} }
await e.Channel.SendMessage("Undeafen successful"); await e.Channel.SendMessage("Undeafen successful");
} catch { }
catch
{
await e.Channel.SendMessage("I do not have permission to do that most likely."); await e.Channel.SendMessage("I do not have permission to do that most likely.");
} }
}); });
@ -310,13 +378,18 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "rvch") cgb.CreateCommand(Prefix + "rvch")
.Description("Removes a voice channel with a given name.") .Description("Removes a voice channel with a given name.")
.Parameter("channel_name", ParameterType.Required) .Parameter("channel_name", ParameterType.Required)
.Do(async e => { .Do(async e =>
try { {
if (e.User.ServerPermissions.ManageChannels) { try
{
if (e.User.ServerPermissions.ManageChannels)
{
await e.Server.FindChannels(e.GetArg("channel_name"), ChannelType.Voice).FirstOrDefault()?.Delete(); await e.Server.FindChannels(e.GetArg("channel_name"), ChannelType.Voice).FirstOrDefault()?.Delete();
await e.Channel.SendMessage($"Removed channel **{e.GetArg("channel_name")}**."); await e.Channel.SendMessage($"Removed channel **{e.GetArg("channel_name")}**.");
} }
} catch { }
catch
{
await e.Channel.SendMessage("Insufficient permissions."); await e.Channel.SendMessage("Insufficient permissions.");
} }
}); });
@ -324,13 +397,18 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "vch").Alias(Prefix + "cvch") cgb.CreateCommand(Prefix + "vch").Alias(Prefix + "cvch")
.Description("Creates a new voice channel with a given name.") .Description("Creates a new voice channel with a given name.")
.Parameter("channel_name", ParameterType.Required) .Parameter("channel_name", ParameterType.Required)
.Do(async e => { .Do(async e =>
try { {
if (e.User.ServerPermissions.ManageChannels) { try
{
if (e.User.ServerPermissions.ManageChannels)
{
await e.Server.CreateChannel(e.GetArg("channel_name"), ChannelType.Voice); await e.Server.CreateChannel(e.GetArg("channel_name"), ChannelType.Voice);
await e.Channel.SendMessage($"Created voice channel **{e.GetArg("channel_name")}**."); await e.Channel.SendMessage($"Created voice channel **{e.GetArg("channel_name")}**.");
} }
} catch { }
catch
{
await e.Channel.SendMessage("Insufficient permissions."); await e.Channel.SendMessage("Insufficient permissions.");
} }
}); });
@ -338,15 +416,20 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "rch").Alias(Prefix + "rtch") cgb.CreateCommand(Prefix + "rch").Alias(Prefix + "rtch")
.Description("Removes a text channel with a given name.") .Description("Removes a text channel with a given name.")
.Parameter("channel_name", ParameterType.Required) .Parameter("channel_name", ParameterType.Required)
.Do(async e => { .Do(async e =>
try { {
if (e.User.ServerPermissions.ManageChannels) { try
{
if (e.User.ServerPermissions.ManageChannels)
{
var channel = e.Server.FindChannels(e.GetArg("channel_name"), ChannelType.Text).FirstOrDefault(); var channel = e.Server.FindChannels(e.GetArg("channel_name"), ChannelType.Text).FirstOrDefault();
if (channel == null) return; if (channel == null) return;
await channel.Delete(); await channel.Delete();
await e.Channel.SendMessage($"Removed text channel **{e.GetArg("channel_name")}**."); await e.Channel.SendMessage($"Removed text channel **{e.GetArg("channel_name")}**.");
} }
} catch { }
catch
{
await e.Channel.SendMessage("Insufficient permissions."); await e.Channel.SendMessage("Insufficient permissions.");
} }
}); });
@ -354,31 +437,40 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "ch").Alias(Prefix + "tch") cgb.CreateCommand(Prefix + "ch").Alias(Prefix + "tch")
.Description("Creates a new text channel with a given name.") .Description("Creates a new text channel with a given name.")
.Parameter("channel_name", ParameterType.Required) .Parameter("channel_name", ParameterType.Required)
.Do(async e => { .Do(async e =>
try { {
if (e.User.ServerPermissions.ManageChannels) { try
{
if (e.User.ServerPermissions.ManageChannels)
{
await e.Server.CreateChannel(e.GetArg("channel_name"), ChannelType.Text); await e.Server.CreateChannel(e.GetArg("channel_name"), ChannelType.Text);
await e.Channel.SendMessage($"Added text channel **{e.GetArg("channel_name")}**."); await e.Channel.SendMessage($"Added text channel **{e.GetArg("channel_name")}**.");
} }
} catch { }
catch
{
await e.Channel.SendMessage("Insufficient permissions."); await e.Channel.SendMessage("Insufficient permissions.");
} }
}); });
cgb.CreateCommand(Prefix + "st").Alias(Prefix + "settopic") cgb.CreateCommand(Prefix + "st").Alias(Prefix + "settopic")
.Alias(Prefix + "topic")
.Description("Sets a topic on the current channel.") .Description("Sets a topic on the current channel.")
.Parameter("topic", ParameterType.Unparsed) .Parameter("topic", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
try { {
if (e.User.ServerPermissions.ManageChannels) var topic = e.GetArg("topic");
await e.Channel.Edit(topic: e.GetArg("topic")); if (string.IsNullOrWhiteSpace(topic))
} catch { } return;
await e.Channel.Edit(topic: topic);
await e.Channel.SendMessage(":ok: **New channel topic set.**");
}); });
cgb.CreateCommand(Prefix + "uid").Alias(Prefix + "userid") cgb.CreateCommand(Prefix + "uid").Alias(Prefix + "userid")
.Description("Shows user ID.") .Description("Shows user ID.")
.Parameter("user", ParameterType.Unparsed) .Parameter("user", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
var usr = e.User; var usr = e.User;
if (!string.IsNullOrWhiteSpace(e.GetArg("user"))) usr = e.Channel.FindUsers(e.GetArg("user")).FirstOrDefault(); if (!string.IsNullOrWhiteSpace(e.GetArg("user"))) usr = e.Channel.FindUsers(e.GetArg("user")).FirstOrDefault();
if (usr == null) if (usr == null)
@ -396,33 +488,38 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "stats") cgb.CreateCommand(Prefix + "stats")
.Description("Shows some basic stats for Nadeko.") .Description("Shows some basic stats for Nadeko.")
.Do(async e => { .Do(async e =>
{
await e.Channel.SendMessage(await NadekoStats.Instance.GetStats()); await e.Channel.SendMessage(await NadekoStats.Instance.GetStats());
}); });
cgb.CreateCommand(Prefix + "dysyd") cgb.CreateCommand(Prefix + "dysyd")
.Description("Shows some basic stats for Nadeko.") .Description("Shows some basic stats for Nadeko.")
.Do(async e => { .Do(async e =>
{
await e.Channel.SendMessage((await NadekoStats.Instance.GetStats()).Matrix().TrimTo(1990)); await e.Channel.SendMessage((await NadekoStats.Instance.GetStats()).Matrix().TrimTo(1990));
}); });
cgb.CreateCommand(Prefix + "heap") cgb.CreateCommand(Prefix + "heap")
.Description("Shows allocated memory - **Owner Only!**") .Description("Shows allocated memory - **Owner Only!**")
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => { .Do(async e =>
{
var heap = await Task.Run(() => NadekoStats.Instance.Heap()); var heap = await Task.Run(() => NadekoStats.Instance.Heap());
await e.Channel.SendMessage($"`Heap Size:` {heap}"); await e.Channel.SendMessage($"`Heap Size:` {heap}");
}); });
cgb.CreateCommand(Prefix + "prune") cgb.CreateCommand(Prefix + "prune")
.Parameter("num", ParameterType.Required) .Parameter("num", ParameterType.Required)
.Description("Prunes a number of messages from the current channel.\n**Usage**: .prune 5") .Description("Prunes a number of messages from the current channel.\n**Usage**: .prune 5")
.Do(async e => { .Do(async e =>
{
if (!e.User.ServerPermissions.ManageMessages) return; if (!e.User.ServerPermissions.ManageMessages) return;
int val; int val;
if (string.IsNullOrWhiteSpace(e.GetArg("num")) || !int.TryParse(e.GetArg("num"), out val) || val < 0) if (string.IsNullOrWhiteSpace(e.GetArg("num")) || !int.TryParse(e.GetArg("num"), out val) || val < 0)
return; return;
foreach (var msg in await e.Channel.DownloadMessages(val)) { foreach (var msg in await e.Channel.DownloadMessages(val))
{
await msg.Delete(); await msg.Delete();
await Task.Delay(100); await Task.Delay(100);
} }
@ -431,8 +528,10 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "die") cgb.CreateCommand(Prefix + "die")
.Alias(Prefix + "graceful") .Alias(Prefix + "graceful")
.Description("Shuts the bot down and notifies users about the restart. **Owner Only!**") .Description("Shuts the bot down and notifies users about the restart. **Owner Only!**")
.Do(async e => { .Do(async e =>
if (NadekoBot.IsOwner(e.User.Id)) { {
if (NadekoBot.IsOwner(e.User.Id))
{
await e.Channel.SendMessage("`Shutting down.`"); await e.Channel.SendMessage("`Shutting down.`");
await Task.Delay(2000); await Task.Delay(2000);
Environment.Exit(0); Environment.Exit(0);
@ -442,19 +541,25 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "clr") cgb.CreateCommand(Prefix + "clr")
.Description("Clears some of Nadeko's messages from the current channel. If given a user, will clear the user's messages from the current channel (**Owner Only!**) \n**Usage**: .clr @X") .Description("Clears some of Nadeko's messages from the current channel. If given a user, will clear the user's messages from the current channel (**Owner Only!**) \n**Usage**: .clr @X")
.Parameter("user", ParameterType.Unparsed) .Parameter("user", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
var usrId = NadekoBot.Client.CurrentUser.Id; var usrId = NadekoBot.Client.CurrentUser.Id;
if (!string.IsNullOrWhiteSpace(e.GetArg("user")) && e.User.ServerPermissions.ManageMessages) { if (!string.IsNullOrWhiteSpace(e.GetArg("user")) && e.User.ServerPermissions.ManageMessages)
{
var usr = e.Server.FindUsers(e.GetArg("user")).FirstOrDefault(); var usr = e.Server.FindUsers(e.GetArg("user")).FirstOrDefault();
if (usr != null) if (usr != null)
usrId = usr.Id; usrId = usr.Id;
} }
await Task.Run(async () => { await Task.Run(async () =>
{
var msgs = (await e.Channel.DownloadMessages(100)).Where(m => m.User.Id == usrId); var msgs = (await e.Channel.DownloadMessages(100)).Where(m => m.User.Id == usrId);
foreach (var m in msgs) { foreach (var m in msgs)
try { {
try
{
await m.Delete(); await m.Delete();
} catch { } }
catch { }
await Task.Delay(200); await Task.Delay(200);
} }
@ -465,7 +570,8 @@ namespace NadekoBot.Modules {
.Alias(Prefix + "setname") .Alias(Prefix + "setname")
.Description("Give the bot a new name. **Owner Only!**") .Description("Give the bot a new name. **Owner Only!**")
.Parameter("new_name", ParameterType.Unparsed) .Parameter("new_name", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
if (!NadekoBot.IsOwner(e.User.Id) || e.GetArg("new_name") == null) return; if (!NadekoBot.IsOwner(e.User.Id) || e.GetArg("new_name") == null) return;
await client.CurrentUser.Edit(NadekoBot.Creds.Password, e.GetArg("new_name")); await client.CurrentUser.Edit(NadekoBot.Creds.Password, e.GetArg("new_name"));
@ -475,7 +581,8 @@ namespace NadekoBot.Modules {
.Alias(Prefix + "setavatar") .Alias(Prefix + "setavatar")
.Description("Sets a new avatar image for the NadekoBot. **Owner Only!**") .Description("Sets a new avatar image for the NadekoBot. **Owner Only!**")
.Parameter("img", ParameterType.Unparsed) .Parameter("img", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
if (!NadekoBot.IsOwner(e.User.Id) || string.IsNullOrWhiteSpace(e.GetArg("img"))) if (!NadekoBot.IsOwner(e.User.Id) || string.IsNullOrWhiteSpace(e.GetArg("img")))
return; return;
// Gather user provided URL. // Gather user provided URL.
@ -492,7 +599,8 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "setgame") cgb.CreateCommand(Prefix + "setgame")
.Description("Sets the bots game. **Owner Only!**") .Description("Sets the bots game. **Owner Only!**")
.Parameter("set_game", ParameterType.Unparsed) .Parameter("set_game", ParameterType.Unparsed)
.Do(e => { .Do(e =>
{
if (!NadekoBot.IsOwner(e.User.Id) || e.GetArg("set_game") == null) return; if (!NadekoBot.IsOwner(e.User.Id) || e.GetArg("set_game") == null) return;
client.SetGame(e.GetArg("set_game")); client.SetGame(e.GetArg("set_game"));
@ -500,9 +608,11 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "checkmyperms") cgb.CreateCommand(Prefix + "checkmyperms")
.Description("Checks your userspecific permissions on this channel.") .Description("Checks your userspecific permissions on this channel.")
.Do(async e => { .Do(async e =>
{
var output = "```\n"; var output = "```\n";
foreach (var p in e.User.ServerPermissions.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any())) { foreach (var p in e.User.ServerPermissions.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any()))
{
output += p.Name + ": " + p.GetValue(e.User.ServerPermissions, null).ToString() + "\n"; output += p.Name + ": " + p.GetValue(e.User.ServerPermissions, null).ToString() + "\n";
} }
output += "```"; output += "```";
@ -516,20 +626,24 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "commsuser") cgb.CreateCommand(Prefix + "commsuser")
.Description("Sets a user for through-bot communication. Only works if server is set. Resets commschannel. **Owner Only!**") .Description("Sets a user for through-bot communication. Only works if server is set. Resets commschannel. **Owner Only!**")
.Parameter("name", ParameterType.Unparsed) .Parameter("name", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
if (!NadekoBot.IsOwner(e.User.Id)) return; if (!NadekoBot.IsOwner(e.User.Id)) return;
commsUser = commsServer?.FindUsers(e.GetArg("name")).FirstOrDefault(); commsUser = commsServer?.FindUsers(e.GetArg("name")).FirstOrDefault();
if (commsUser != null) { if (commsUser != null)
{
commsChannel = null; commsChannel = null;
await e.Channel.SendMessage("User for comms set."); await e.Channel.SendMessage("User for comms set.");
} else }
else
await e.Channel.SendMessage("No server specified or user."); await e.Channel.SendMessage("No server specified or user.");
}); });
cgb.CreateCommand(Prefix + "commsserver") cgb.CreateCommand(Prefix + "commsserver")
.Description("Sets a server for through-bot communication. **Owner Only!**") .Description("Sets a server for through-bot communication. **Owner Only!**")
.Parameter("server", ParameterType.Unparsed) .Parameter("server", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
if (!NadekoBot.IsOwner(e.User.Id)) return; if (!NadekoBot.IsOwner(e.User.Id)) return;
commsServer = client.FindServers(e.GetArg("server")).FirstOrDefault(); commsServer = client.FindServers(e.GetArg("server")).FirstOrDefault();
if (commsServer != null) if (commsServer != null)
@ -541,20 +655,24 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "commschannel") cgb.CreateCommand(Prefix + "commschannel")
.Description("Sets a channel for through-bot communication. Only works if server is set. Resets commsuser. **Owner Only!**") .Description("Sets a channel for through-bot communication. Only works if server is set. Resets commsuser. **Owner Only!**")
.Parameter("ch", ParameterType.Unparsed) .Parameter("ch", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
if (!NadekoBot.IsOwner(e.User.Id)) return; if (!NadekoBot.IsOwner(e.User.Id)) return;
commsChannel = commsServer?.FindChannels(e.GetArg("ch"), ChannelType.Text).FirstOrDefault(); commsChannel = commsServer?.FindChannels(e.GetArg("ch"), ChannelType.Text).FirstOrDefault();
if (commsChannel != null) { if (commsChannel != null)
{
commsUser = null; commsUser = null;
await e.Channel.SendMessage("Server for comms set."); await e.Channel.SendMessage("Server for comms set.");
} else }
else
await e.Channel.SendMessage("No server specified or channel is invalid."); await e.Channel.SendMessage("No server specified or channel is invalid.");
}); });
cgb.CreateCommand(Prefix + "send") cgb.CreateCommand(Prefix + "send")
.Description("Send a message to someone on a different server through the bot. **Owner Only!**\n **Usage**: .send Message text multi word!") .Description("Send a message to someone on a different server through the bot. **Owner Only!**\n **Usage**: .send Message text multi word!")
.Parameter("msg", ParameterType.Unparsed) .Parameter("msg", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
if (!NadekoBot.IsOwner(e.User.Id)) return; if (!NadekoBot.IsOwner(e.User.Id)) return;
if (commsUser != null) if (commsUser != null)
await commsUser.SendMessage(e.GetArg("msg")); await commsUser.SendMessage(e.GetArg("msg"));
@ -568,19 +686,23 @@ namespace NadekoBot.Modules {
.Alias(Prefix + "mentionrole") .Alias(Prefix + "mentionrole")
.Description("Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission.") .Description("Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission.")
.Parameter("roles", ParameterType.Unparsed) .Parameter("roles", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
await Task.Run(async () => { {
await Task.Run(async () =>
{
if (!e.User.ServerPermissions.MentionEveryone) return; if (!e.User.ServerPermissions.MentionEveryone) return;
var arg = e.GetArg("roles").Split(',').Select(r => r.Trim()); var arg = e.GetArg("roles").Split(',').Select(r => r.Trim());
string send = $"--{e.User.Mention} has invoked a mention on the following roles--"; string send = $"--{e.User.Mention} has invoked a mention on the following roles--";
foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str))) { foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str)))
{
var role = e.Server.FindRoles(roleStr).FirstOrDefault(); var role = e.Server.FindRoles(roleStr).FirstOrDefault();
if (role == null) continue; if (role == null) continue;
send += $"\n`{role.Name}`\n"; send += $"\n`{role.Name}`\n";
send += string.Join(", ", role.Members.Select(r => r.Mention)); send += string.Join(", ", role.Members.Select(r => r.Mention));
} }
while (send.Length > 2000) { while (send.Length > 2000)
{
var curstr = send.Substring(0, 2000); var curstr = send.Substring(0, 2000);
await await
e.Channel.Send(curstr.Substring(0, e.Channel.Send(curstr.Substring(0,
@ -594,10 +716,12 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "parsetosql") cgb.CreateCommand(Prefix + "parsetosql")
.Description("Loads exported parsedata from /data/parsedata/ into sqlite database.") .Description("Loads exported parsedata from /data/parsedata/ into sqlite database.")
.Do(async e => { .Do(async e =>
{
if (!NadekoBot.IsOwner(e.User.Id)) if (!NadekoBot.IsOwner(e.User.Id))
return; return;
await Task.Run(() => { await Task.Run(() =>
{
SaveParseToDb<Announcement>("data/parsedata/Announcements.json"); SaveParseToDb<Announcement>("data/parsedata/Announcements.json");
SaveParseToDb<Classes._DataModels.Command>("data/parsedata/CommandsRan.json"); SaveParseToDb<Classes._DataModels.Command>("data/parsedata/CommandsRan.json");
SaveParseToDb<Request>("data/parsedata/Requests.json"); SaveParseToDb<Request>("data/parsedata/Requests.json");
@ -609,14 +733,17 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "unstuck") cgb.CreateCommand(Prefix + "unstuck")
.Description("Clears the message queue. **Owner Only!**") .Description("Clears the message queue. **Owner Only!**")
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(e => { .Do(e =>
{
NadekoBot.Client.MessageQueue.Clear(); NadekoBot.Client.MessageQueue.Clear();
}); });
cgb.CreateCommand(Prefix + "donators") cgb.CreateCommand(Prefix + "donators")
.Description("List of lovely people who donated to keep this project alive.") .Description("List of lovely people who donated to keep this project alive.")
.Do(async e => { .Do(async e =>
await Task.Run(async () => { {
await Task.Run(async () =>
{
var rows = DbHandler.Instance.GetAllRows<Donator>(); var rows = DbHandler.Instance.GetAllRows<Donator>();
var donatorsOrdered = rows.OrderByDescending(d => d.Amount); var donatorsOrdered = rows.OrderByDescending(d => d.Amount);
string str = $"**Thanks to the people listed below for making this project happen!**\n"; string str = $"**Thanks to the people listed below for making this project happen!**\n";
@ -632,64 +759,65 @@ namespace NadekoBot.Modules {
.Parameter("donator") .Parameter("donator")
.Parameter("amount") .Parameter("amount")
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => { .Do(async e =>
await Task.Run(() => { {
await Task.Run(() =>
{
if (!NadekoBot.IsOwner(e.User.Id)) if (!NadekoBot.IsOwner(e.User.Id))
return; return;
var donator = e.Server.FindUsers(e.GetArg("donator")).FirstOrDefault(); var donator = e.Server.FindUsers(e.GetArg("donator")).FirstOrDefault();
var amount = int.Parse(e.GetArg("amount")); var amount = int.Parse(e.GetArg("amount"));
if (donator == null) return; if (donator == null) return;
try { try
DbHandler.Instance.InsertData(new Donator { {
DbHandler.Instance.InsertData(new Donator
{
Amount = amount, Amount = amount,
UserName = donator.Name, UserName = donator.Name,
UserId = (long)e.User.Id UserId = (long)e.User.Id
}); });
e.Channel.SendMessage("Successfuly added a new donator. 👑"); e.Channel.SendMessage("Successfuly added a new donator. 👑");
} catch { } }
catch { }
}); });
}); });
cgb.CreateCommand(Prefix + "topic")
.Description("Sets current channel's topic.")
.Parameter("topic", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.ManageChannels())
.Do(async e => {
var topic = e.GetArg("topic");
if (string.IsNullOrWhiteSpace(topic))
return;
await e.Channel.Edit(topic: topic);
await e.Channel.SendMessage(":ok: **New channel topic set.**");
});
cgb.CreateCommand(Prefix + "videocall") cgb.CreateCommand(Prefix + "videocall")
.Description("Creates a private appear.in video call link for you and other mentioned people. The link is sent to mentioned people via a private message.") .Description("Creates a private appear.in video call link for you and other mentioned people. The link is sent to mentioned people via a private message.")
.Parameter("arg", ParameterType.Unparsed) .Parameter("arg", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
try { {
try
{
var allUsrs = e.Message.MentionedUsers.Union(new User[] { e.User }); var allUsrs = e.Message.MentionedUsers.Union(new User[] { e.User });
var allUsrsArray = allUsrs as User[] ?? allUsrs.ToArray(); var allUsrsArray = allUsrs as User[] ?? allUsrs.ToArray();
var str = allUsrsArray.Aggregate("http://appear.in/", (current, usr) => current + Uri.EscapeUriString(usr.Name[0].ToString())); var str = allUsrsArray.Aggregate("http://appear.in/", (current, usr) => current + Uri.EscapeUriString(usr.Name[0].ToString()));
str += new Random().Next(); str += new Random().Next();
foreach (var usr in allUsrsArray) { foreach (var usr in allUsrsArray)
{
await usr.SendMessage(str); await usr.SendMessage(str);
} }
} catch (Exception ex) { }
catch (Exception ex)
{
Console.WriteLine(ex); Console.WriteLine(ex);
} }
}); });
}); });
} }
public void SaveParseToDb<T>(string where) where T : IDataModel { public void SaveParseToDb<T>(string where) where T : IDataModel
try { {
try
{
var data = File.ReadAllText(where); var data = File.ReadAllText(where);
var arr = JObject.Parse(data)["results"] as JArray; var arr = JObject.Parse(data)["results"] as JArray;
if (arr == null) if (arr == null)
return; return;
var objects = arr.Select(x => x.ToObject<T>()); var objects = arr.Select(x => x.ToObject<T>());
DbHandler.Instance.InsertMany(objects); DbHandler.Instance.InsertMany(objects);
} catch { } }
catch { }
} }
} }
} }

View File

@ -1,18 +1,17 @@
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using Discord.Modules; using Discord.Modules;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Commands;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using NadekoBot.Properties; using NadekoBot.Properties;
using NadekoBot.Commands; using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace NadekoBot.Modules namespace NadekoBot.Modules
{ {

View File

@ -34,15 +34,14 @@ namespace NadekoBot.Modules.Gambling
.Parameter("role", ParameterType.Optional) .Parameter("role", ParameterType.Optional)
.Do(RaffleFunc()); .Do(RaffleFunc());
cgb.CreateCommand(Prefix + "$$") cgb.CreateCommand(Prefix + "$$")
.Description("Check how many NadekoFlowers you have.") .Description(string.Format("Check how much {0}s you have.", NadekoBot.Config.CurrencyName))
.Do(NadekoFlowerCheckFunc()); .Do(NadekoFlowerCheckFunc());
cgb.CreateCommand(Prefix + "give") cgb.CreateCommand(Prefix + "give")
.Description("Give someone a certain amount of flowers") .Description(string.Format("Give someone a certain amount of {0}s", NadekoBot.Config.CurrencyName))
.Parameter("amount", ParameterType.Required) .Parameter("amount", ParameterType.Required)
.Parameter("receiver", ParameterType.Unparsed) .Parameter("receiver", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
var amountStr = e.GetArg("amount")?.Trim(); var amountStr = e.GetArg("amount")?.Trim();
long amount; long amount;
if (!long.TryParse(amountStr, out amount) || amount < 0) if (!long.TryParse(amountStr, out amount) || amount < 0)
@ -58,14 +57,14 @@ namespace NadekoBot.Modules.Gambling
if (userFlowers < amount) if (userFlowers < amount)
{ {
await e.Channel.SendMessage($"{e.User.Mention} You don't have enough flowers. You have only {userFlowers}🌸."); await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You have only {userFlowers}{NadekoBot.Config.CurrencySign}.");
return; return;
} }
await FlowersHandler.RemoveFlowersAsync(e.User, "Gift", (int)amount); await FlowersHandler.RemoveFlowersAsync(e.User, "Gift", (int)amount);
await FlowersHandler.AddFlowersAsync(mentionedUser, "Gift", (int)amount); await FlowersHandler.AddFlowersAsync(mentionedUser, "Gift", (int)amount);
await e.Channel.SendMessage($"{e.User.Mention} successfully sent {amount}🌸 to {mentionedUser.Mention}!"); await e.Channel.SendMessage($"{e.User.Mention} successfully sent {amount} {NadekoBot.Config.CurrencyName}s to {mentionedUser.Mention}!");
}); });
}); });
@ -76,10 +75,10 @@ namespace NadekoBot.Modules.Gambling
return async e => return async e =>
{ {
var pts = GetUserFlowers(e.User.Id); var pts = GetUserFlowers(e.User.Id);
var str = $"`You have {pts} NadekoFlowers".SnPl((int)pts) + "`\n"; var str = $"`You have {pts} {NadekoBot.Config.CurrencyName}s".SnPl((int)pts) + "`\n";
for (var i = 0; i < pts; i++) for (var i = 0; i < pts; i++)
{ {
str += "🌸"; str += NadekoBot.Config.CurrencySign;
} }
await e.Channel.SendMessage(str); await e.Channel.SendMessage(str);
}; };

View File

@ -3,16 +3,18 @@ using Discord.Commands;
using Discord.Modules; using Discord.Modules;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Classes.Music; using NadekoBot.Classes.Music;
using NadekoBot.Classes.Permissions;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using NadekoBot.Classes.Permissions;
using Timer = System.Timers.Timer; using Timer = System.Timers.Timer;
namespace NadekoBot.Modules { namespace NadekoBot.Modules
internal class Music : DiscordModule { {
internal class Music : DiscordModule
{
public static ConcurrentDictionary<Server, MusicPlayer> MusicPlayers = new ConcurrentDictionary<Server, MusicPlayer>(); public static ConcurrentDictionary<Server, MusicPlayer> MusicPlayers = new ConcurrentDictionary<Server, MusicPlayer>();
public static ConcurrentDictionary<ulong, float> DefaultMusicVolumes = new ConcurrentDictionary<ulong, float>(); public static ConcurrentDictionary<ulong, float> DefaultMusicVolumes = new ConcurrentDictionary<ulong, float>();
@ -21,24 +23,46 @@ namespace NadekoBot.Modules {
private bool setgameEnabled = false; private bool setgameEnabled = false;
public Music() { public Music()
{
setgameTimer.Interval = 20000; setgameTimer.Interval = 20000;
setgameTimer.Elapsed += (s, e) => { setgameTimer.Elapsed += (s, e) =>
try { {
try
{
var num = MusicPlayers.Count(kvp => kvp.Value.CurrentSong != null); var num = MusicPlayers.Count(kvp => kvp.Value.CurrentSong != null);
NadekoBot.Client.SetGame($"{num} songs".SnPl(num) + $", {MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count())} queued"); NadekoBot.Client.SetGame($"{num} songs".SnPl(num) + $", {MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count())} queued");
} catch { } }
catch { }
}; };
// ready for 1.0
//NadekoBot.Client.UserUpdated += (s, e) =>
//{
// try
// {
// if (e.Before.VoiceChannel != e.After.VoiceChannel &&
// e.Before.VoiceChannel.Members.Count() == 0)
// {
// MusicPlayer musicPlayer;
// if (!MusicPlayers.TryRemove(e.Server, out musicPlayer)) return;
// musicPlayer.Destroy();
// }
// }
// catch { }
//};
} }
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Music; public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Music;
public override void Install(ModuleManager manager) { public override void Install(ModuleManager manager)
{
var client = NadekoBot.Client; var client = NadekoBot.Client;
manager.CreateCommands(Prefix, cgb => { manager.CreateCommands(Prefix, cgb =>
{
cgb.AddCheck(Classes.Permissions.PermissionChecker.Instance); cgb.AddCheck(Classes.Permissions.PermissionChecker.Instance);
@ -47,7 +71,8 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("n") cgb.CreateCommand("n")
.Alias("next") .Alias("next")
.Description("Goes to the next song in the queue.") .Description("Goes to the next song in the queue.")
.Do(e => { .Do(e =>
{
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return; if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return;
musicPlayer.Next(); musicPlayer.Next();
@ -56,8 +81,10 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("s") cgb.CreateCommand("s")
.Alias("stop") .Alias("stop")
.Description("Stops the music and clears the playlist. Stays in the channel.") .Description("Stops the music and clears the playlist. Stays in the channel.")
.Do(async e => { .Do(async e =>
await Task.Run(() => { {
await Task.Run(() =>
{
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return; if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return;
musicPlayer.Stop(); musicPlayer.Stop();
@ -67,8 +94,10 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("d") cgb.CreateCommand("d")
.Alias("destroy") .Alias("destroy")
.Description("Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour)") .Description("Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour)")
.Do(async e => { .Do(async e =>
await Task.Run(() => { {
await Task.Run(() =>
{
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
if (!MusicPlayers.TryRemove(e.Server, out musicPlayer)) return; if (!MusicPlayers.TryRemove(e.Server, out musicPlayer)) return;
musicPlayer.Destroy(); musicPlayer.Destroy();
@ -78,7 +107,8 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("p") cgb.CreateCommand("p")
.Alias("pause") .Alias("pause")
.Description("Pauses or Unpauses the song.") .Description("Pauses or Unpauses the song.")
.Do(async e => { .Do(async e =>
{
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return; if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return;
musicPlayer.TogglePause(); musicPlayer.TogglePause();
@ -92,16 +122,19 @@ namespace NadekoBot.Modules {
.Alias("yq") .Alias("yq")
.Description("Queue a song using keywords or a link. Bot will join your voice channel. **You must be in a voice channel**.\n**Usage**: `!m q Dream Of Venice`") .Description("Queue a song using keywords or a link. Bot will join your voice channel. **You must be in a voice channel**.\n**Usage**: `!m q Dream Of Venice`")
.Parameter("query", ParameterType.Unparsed) .Parameter("query", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
await QueueSong(e.Channel, e.User.VoiceChannel, e.GetArg("query")); await QueueSong(e.Channel, e.User.VoiceChannel, e.GetArg("query"));
}); });
cgb.CreateCommand("lq") cgb.CreateCommand("lq")
.Alias("ls").Alias("lp") .Alias("ls").Alias("lp")
.Description("Lists up to 15 currently queued songs.") .Description("Lists up to 15 currently queued songs.")
.Do(async e => { .Do(async e =>
{
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) { if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
{
await e.Channel.SendMessage("🎵 No active music player."); await e.Channel.SendMessage("🎵 No active music player.");
return; return;
} }
@ -117,7 +150,8 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("np") cgb.CreateCommand("np")
.Alias("playing") .Alias("playing")
.Description("Shows the song currently playing.") .Description("Shows the song currently playing.")
.Do(async e => { .Do(async e =>
{
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
return; return;
@ -130,13 +164,15 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("vol") cgb.CreateCommand("vol")
.Description("Sets the music volume 0-150%") .Description("Sets the music volume 0-150%")
.Parameter("val", ParameterType.Required) .Parameter("val", ParameterType.Required)
.Do(async e => { .Do(async e =>
{
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
return; return;
var arg = e.GetArg("val"); var arg = e.GetArg("val");
int volume; int volume;
if (!int.TryParse(arg, out volume)) { if (!int.TryParse(arg, out volume))
{
await e.Channel.SendMessage("Volume number invalid."); await e.Channel.SendMessage("Volume number invalid.");
return; return;
} }
@ -148,10 +184,12 @@ namespace NadekoBot.Modules {
.Alias("defvol") .Alias("defvol")
.Description("Sets the default music volume when music playback is started (0-100). Does not persist through restarts.\n**Usage**: !m dv 80") .Description("Sets the default music volume when music playback is started (0-100). Does not persist through restarts.\n**Usage**: !m dv 80")
.Parameter("val", ParameterType.Required) .Parameter("val", ParameterType.Required)
.Do(async e => { .Do(async e =>
{
var arg = e.GetArg("val"); var arg = e.GetArg("val");
float volume; float volume;
if (!float.TryParse(arg, out volume) || volume < 0 || volume > 100) { if (!float.TryParse(arg, out volume) || volume < 0 || volume > 100)
{
await e.Channel.SendMessage("Volume number invalid."); await e.Channel.SendMessage("Volume number invalid.");
return; return;
} }
@ -161,7 +199,8 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("min").Alias("mute") cgb.CreateCommand("min").Alias("mute")
.Description("Sets the music volume to 0%") .Description("Sets the music volume to 0%")
.Do(e => { .Do(e =>
{
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
return; return;
@ -170,7 +209,8 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("max") cgb.CreateCommand("max")
.Description("Sets the music volume to 100% (real max is actually 150%).") .Description("Sets the music volume to 100% (real max is actually 150%).")
.Do(e => { .Do(e =>
{
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
return; return;
@ -179,7 +219,8 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("half") cgb.CreateCommand("half")
.Description("Sets the music volume to 50%.") .Description("Sets the music volume to 50%.")
.Do(e => { .Do(e =>
{
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
return; return;
@ -188,11 +229,13 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("sh") cgb.CreateCommand("sh")
.Description("Shuffles the current playlist.") .Description("Shuffles the current playlist.")
.Do(async e => { .Do(async e =>
{
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
return; return;
if (musicPlayer.Playlist.Count < 2) { if (musicPlayer.Playlist.Count < 2)
{
await e.Channel.SendMessage("💢 Not enough songs in order to perform the shuffle."); await e.Channel.SendMessage("💢 Not enough songs in order to perform the shuffle.");
return; return;
} }
@ -204,7 +247,8 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("setgame") cgb.CreateCommand("setgame")
.Description("Sets the game of the bot to the number of songs playing. **Owner only**") .Description("Sets the game of the bot to the number of songs playing. **Owner only**")
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => { .Do(async e =>
{
await e.Channel.SendMessage("❗This command is deprecated. " + await e.Channel.SendMessage("❗This command is deprecated. " +
"Use:\n `.ropl`\n `.adpl %playing% songs, %queued% queued.` instead.\n " + "Use:\n `.ropl`\n `.adpl %playing% songs, %queued% queued.` instead.\n " +
"It even persists through restarts."); "It even persists through restarts.");
@ -213,8 +257,10 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("pl") cgb.CreateCommand("pl")
.Description("Queues up to 25 songs from a youtube playlist specified by a link, or keywords.") .Description("Queues up to 25 songs from a youtube playlist specified by a link, or keywords.")
.Parameter("playlist", ParameterType.Unparsed) .Parameter("playlist", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
if (e.User.VoiceChannel?.Server != e.Server) { {
if (e.User.VoiceChannel?.Server != e.Server)
{
await e.Channel.SendMessage("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining it."); await e.Channel.SendMessage("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining it.");
return; return;
} }
@ -224,10 +270,13 @@ namespace NadekoBot.Modules {
var count = idArray.Count(); var count = idArray.Count();
var msg = var msg =
await e.Channel.SendMessage($"🎵 `Attempting to queue {count} songs".SnPl(count) + "...`"); await e.Channel.SendMessage($"🎵 `Attempting to queue {count} songs".SnPl(count) + "...`");
foreach (var id in idArray) { foreach (var id in idArray)
try { {
try
{
await QueueSong(e.Channel, e.User.VoiceChannel, id, true); await QueueSong(e.Channel, e.User.VoiceChannel, id, true);
} catch { } }
catch { }
} }
await msg.Edit("🎵 `Playlist queue complete.`"); await msg.Edit("🎵 `Playlist queue complete.`");
}); });
@ -236,24 +285,30 @@ namespace NadekoBot.Modules {
.Description("Queues up to 50 songs from a directory. **Owner Only!**") .Description("Queues up to 50 songs from a directory. **Owner Only!**")
.Parameter("directory", ParameterType.Unparsed) .Parameter("directory", ParameterType.Unparsed)
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly()) .AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Do(async e => { .Do(async e =>
{
var arg = e.GetArg("directory"); var arg = e.GetArg("directory");
if (string.IsNullOrWhiteSpace(e.GetArg("directory"))) if (string.IsNullOrWhiteSpace(e.GetArg("directory")))
return; return;
try { try
{
var fileEnum = System.IO.Directory.EnumerateFiles(e.GetArg("directory")).Take(50); var fileEnum = System.IO.Directory.EnumerateFiles(e.GetArg("directory")).Take(50);
foreach (var file in fileEnum) { foreach (var file in fileEnum)
{
await QueueSong(e.Channel, e.User.VoiceChannel, file, true, MusicType.Local); await QueueSong(e.Channel, e.User.VoiceChannel, file, true, MusicType.Local);
} }
await e.Channel.SendMessage("🎵 `Directory queue complete.`"); await e.Channel.SendMessage("🎵 `Directory queue complete.`");
} catch { } }
catch { }
}); });
cgb.CreateCommand("radio").Alias("ra") cgb.CreateCommand("radio").Alias("ra")
.Description("Queues a direct radio stream from a link.") .Description("Queues a direct radio stream from a link.")
.Parameter("radio_link", ParameterType.Required) .Parameter("radio_link", ParameterType.Required)
.Do(async e => { .Do(async e =>
if (e.User.VoiceChannel?.Server != e.Server) { {
if (e.User.VoiceChannel?.Server != e.Server)
{
await e.Channel.SendMessage("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining it."); await e.Channel.SendMessage("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining it.");
return; return;
} }
@ -264,7 +319,8 @@ namespace NadekoBot.Modules {
.Description("Queues a local file by specifying a full path. **Owner Only!**") .Description("Queues a local file by specifying a full path. **Owner Only!**")
.Parameter("path", ParameterType.Unparsed) .Parameter("path", ParameterType.Unparsed)
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly()) .AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Do(async e => { .Do(async e =>
{
var arg = e.GetArg("path"); var arg = e.GetArg("path");
if (string.IsNullOrWhiteSpace(arg)) if (string.IsNullOrWhiteSpace(arg))
return; return;
@ -273,7 +329,8 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("mv") cgb.CreateCommand("mv")
.Description("Moves the bot to your voice channel. (works only if music is already playing)") .Description("Moves the bot to your voice channel. (works only if music is already playing)")
.Do(e => { .Do(e =>
{
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
var voiceChannel = e.User.VoiceChannel; var voiceChannel = e.User.VoiceChannel;
if (voiceChannel == null || voiceChannel.Server != e.Server || !MusicPlayers.TryGetValue(e.Server, out musicPlayer)) if (voiceChannel == null || voiceChannel.Server != e.Server || !MusicPlayers.TryGetValue(e.Server, out musicPlayer))
@ -284,19 +341,23 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("rm") cgb.CreateCommand("rm")
.Description("Remove a song by its # in the queue, or 'all' to remove whole queue.") .Description("Remove a song by its # in the queue, or 'all' to remove whole queue.")
.Parameter("num", ParameterType.Required) .Parameter("num", ParameterType.Required)
.Do(async e => { .Do(async e =>
{
var arg = e.GetArg("num"); var arg = e.GetArg("num");
MusicPlayer musicPlayer; MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) { if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
{
return; return;
} }
if (arg?.ToLower() == "all") { if (arg?.ToLower() == "all")
{
musicPlayer.ClearQueue(); musicPlayer.ClearQueue();
await e.Channel.SendMessage($"🎵`Queue cleared!`"); await e.Channel.SendMessage($"🎵`Queue cleared!`");
return; return;
} }
int num; int num;
if (!int.TryParse(arg, out num)) { if (!int.TryParse(arg, out num))
{
return; return;
} }
if (num <= 0 || num > musicPlayer.Playlist.Count) if (num <= 0 || num > musicPlayer.Playlist.Count)
@ -309,11 +370,14 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("cleanup") cgb.CreateCommand("cleanup")
.Description("Cleans up hanging voice connections. **Owner Only!**") .Description("Cleans up hanging voice connections. **Owner Only!**")
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(e => { .Do(e =>
foreach (var kvp in MusicPlayers) { {
foreach (var kvp in MusicPlayers)
{
var songs = kvp.Value.Playlist; var songs = kvp.Value.Playlist;
var currentSong = kvp.Value.CurrentSong; var currentSong = kvp.Value.CurrentSong;
if (songs.Count == 0 && currentSong == null) { if (songs.Count == 0 && currentSong == null)
{
MusicPlayer throwaway; MusicPlayer throwaway;
MusicPlayers.TryRemove(kvp.Key, out throwaway); MusicPlayers.TryRemove(kvp.Key, out throwaway);
throwaway.Destroy(); throwaway.Destroy();
@ -331,8 +395,10 @@ namespace NadekoBot.Modules {
}); });
} }
private async Task QueueSong(Channel textCh, Channel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal) { private async Task QueueSong(Channel textCh, Channel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal)
if (voiceCh == null || voiceCh.Server != textCh.Server) { {
if (voiceCh == null || voiceCh.Server != textCh.Server)
{
if (!silent) if (!silent)
await textCh.SendMessage("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining."); await textCh.SendMessage("💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining.");
throw new ArgumentNullException(nameof(voiceCh)); throw new ArgumentNullException(nameof(voiceCh));
@ -340,25 +406,32 @@ namespace NadekoBot.Modules {
if (string.IsNullOrWhiteSpace(query) || query.Length < 3) if (string.IsNullOrWhiteSpace(query) || query.Length < 3)
throw new ArgumentException("💢 Invalid query for queue song.", nameof(query)); throw new ArgumentException("💢 Invalid query for queue song.", nameof(query));
var musicPlayer = MusicPlayers.GetOrAdd(textCh.Server, server => { var musicPlayer = MusicPlayers.GetOrAdd(textCh.Server, server =>
{
float? vol = null; float? vol = null;
float throwAway; float throwAway;
if (DefaultMusicVolumes.TryGetValue(server.Id, out throwAway)) if (DefaultMusicVolumes.TryGetValue(server.Id, out throwAway))
vol = throwAway; vol = throwAway;
var mp = new MusicPlayer(voiceCh, vol); var mp = new MusicPlayer(voiceCh, vol);
mp.OnCompleted += async (s, song) => { mp.OnCompleted += async (s, song) =>
try { {
try
{
await textCh.SendMessage($"🎵`Finished`{song.PrettyName}"); await textCh.SendMessage($"🎵`Finished`{song.PrettyName}");
} catch { } }
catch { }
}; };
mp.OnStarted += async (s, song) => { mp.OnStarted += async (s, song) =>
{
var sender = s as MusicPlayer; var sender = s as MusicPlayer;
if (sender == null) if (sender == null)
return; return;
try { try
{
var msgTxt = $"🎵`Playing`{song.PrettyName} `Vol: {(int)(sender.Volume * 100)}%`"; var msgTxt = $"🎵`Playing`{song.PrettyName} `Vol: {(int)(sender.Volume * 100)}%`";
await textCh.SendMessage(msgTxt); await textCh.SendMessage(msgTxt);
} catch { } }
catch { }
}; };
return mp; return mp;
}); });

View File

@ -71,5 +71,7 @@
"https://media.giphy.com/media/12hvLuZ7uzvCvK/giphy.gif", "https://media.giphy.com/media/12hvLuZ7uzvCvK/giphy.gif",
"http://gallery1.anivide.com/_full/65030_1382582341.gif", "http://gallery1.anivide.com/_full/65030_1382582341.gif",
"https://49.media.tumblr.com/8e8a099c4eba22abd3ec0f70fd087cce/tumblr_nxovj9oY861ur1mffo1_500.gif " "https://49.media.tumblr.com/8e8a099c4eba22abd3ec0f70fd087cce/tumblr_nxovj9oY861ur1mffo1_500.gif "
] ],
"CurrencySign": "🌸",
"CurrencyName": "NadekoFlower"
} }

View File

@ -0,0 +1,248 @@
[{
"Name": "Ace of Spades",
"Description": "An ace of spades from a standard card deck. No matter where you store it on your body, you will always be able to find it in your right sleeve afterwards."
}, {
"Name": "Arrow of Euarere",
"Description": "A silver arrow, suspended on a string. It always points to the person holding the string."
}, {
"Name": "Amulet of Extra Amulet Slot",
"Description": "This amulet allows you to gain the benefit from two magical amulets rather than one. It cannot be further enchanted."
}, {
"Name": "Amulet of Feather Fall",
"Description": "When worn, this amulet turns into a feather and falls to the ground."
}, {
"Name": "Anti-Matches",
"Description": "A box of matches. Striking one will make it begin to drip water from the tip while the match shrivels away. The amount of water a match releases is about enough to fill a tablespoon."
}, {
"Name": "Artist's Bludgeon, The",
"Description": "Inanimate objects hit with this bludgeon will receive no damage; they will however change color."
}, {
"Name":"Attentive Guardsman's Pike",
"Description":"These ornate and deadly-looking ceremonial pikes are reach weapons and appear to eigh at least 20 lbs, not counting the weight of the fluttering banners that can be unfurled for parade use. Constructed of shadowstuff, they weigh one pound, and inflict only a single point of damage on an attack, being almost entirely for show, although they also have the unique property of remaining in place when set (although unable to support more than 20 lbs), allowing a 'resting his eyes' guardsman to prop it up and leave it standing under its own power, while his hand sags off of it."
}, {
"Name": "Attentive Guardsman's Tabard",
"Description": "A dozen of these tabards were fashioned for palace guardsmen in the Empire of Sard, 250 miles from the nearest enemy. The bearer is placed under a glamour that causes him to appear alert and awake, even if his eyes are closed and he is snoring lightly."
}, {
"Name": "Axe of Big Numbers",
"Description": "This axe shouts \"Big numbers baby, come on!\" whenever it is swung, but always deals 1 damage or less."
}, {
"Name": "Axe of Empathy",
"Description": "Every time you hit something with this +5 greataxe, you get dealt an equal amount of damage. Both you and the thing you hit are then healed the amount of damage dealt by the axe, even if either are dead. The Axe hopes you have learned your lesson."
}, {
"Name": "Axe of Pain",
"Description": "The axe is always moaning and groaning with pain."
}, {
"Name": "Baby Oil",
"Description": "An aphrodisiac made from the finest mashed babies. Strangely unpopular in the upper planes, the judgmental prudes."
}, {
"Name": "Bag of Faerie Gold",
"Description": "This sack appears to be full of gold coins and jewels. When one attempts to spend them, however, the glamour on them soon vanishes, revealing them to be nothing but leaves and pebbles. Obviously, most shopkeepers will not be happy about this, and no amount of 'we didn't know, I swear!' will change their mind."
}, {
"Name": "Bag of Holding",
"Description":"This item functions as a normal
backpack, however when attempting to retrieve an item, a calm female
voice tells them there is a wait time of 4d10 minutes before they can
retrieve their item (actual time is stated time plus 6d6 additional
minutes). During this wait, the bag plays either annoying muzak or advertisements
for the bag's creator's other products/services. Upon attempting to
retrieve an item, there is a chance that the wrong item is retrieved, or
that the intended item is simply missing. Obtaining the original item
requires an additional 4d10+6d6 minutes and has only a 5% chance of
success."
}, {
"Name": "Bag of Holding (Alternate)",
"Description": "This sack needs a hug!"
}, {
"Name": "Bag of Trading",
"Description": "You can take one thing out of the bag for each object you put in the bag. However, you have no control over what you get, and there are no trade-backs. Past research seems to imply there's some sort of correlation to what gets you what, but it's extremely convoluted and far from understood."
}, {
"Name": "Bag of Trick",
"Description": "This bag operates like a Bag of Tricks, except it only works once a week and produces a rat each time itis used."
}, {
"Name": "Bag of Unholding",
"Description": "Quite a large backpack but even the smallest item doesn't fit."
}, {
"Name": "Bagpipe of Stealth",
"Description": "Grants the user invisibility as long as it is being played."
}, {
"Name": "Ball of Eyes",
"Description": "A snow-globe filled with miniature eyeballs. When shaken, it grants the user a blurry, jittery vision of some future event."
}, {
"Name": "Banana Walkie-Talkies",
"Description": "There exist two, and only two, of these items in the world. One of which is possessed by a cranky and lonely half-orc. It appears to be an innocuous wooden banana with a coat of faded yellow paint. When an end (doesn't matter which one) is placed against your ear, you can hear a ringing followed by a *click* and a half-orc yelling at you for waking him up at this ungodly hour. If you drop the banana or \"hang up,\" the call ends. If you stay and listen, the half-orc will yell at you, call o...(line truncated)...
}, {
"Name": "Barrel of Holding",
"Description": "This large wooden barrel measuring &#8730;(12/&#960;) feet in diameter and 5 feet in height can hold up to 15 cubic feet of matter."
}, {
"Name": "Beam Sword of Severed Nerves",
"Description": "A beam sword. It cannot cut anything but nerve strings. Will pass through any other material leaving no harm."
}, {
"Name": "Belt of Pants",
"Description": "This belt creates illusory pants on the wearer. The wearer can suppress the illusion at will"
}, {
"Name": "Belt of Tightening",
"Description": "Every time you put this belt on, all of your clothes permanently shrink a fraction of a millimeter. The effect is compound."
}, {
"Name": "Belt of Unbathed Breath",
"Description": "When worn around the waist, allows the user to breathe underwater. Does not function when wet."
}, {
"Name": "Boogie Skeleton",
"Description": "This pile of bones is small, such as one that might be obtained from a bird or a toad, though it can look as though it came from any creature. When a song is sung or played in the vicinity of the skeleton, it begins to dance appropriately. As soon as the music stops, it collapses into the pile of bones again. The skeleton, when dancing, can be no larger than Diminutive."
}, {
"Name": "Book of Canon",
"Description": "A book that automatically transforms into a copy of the sacred text of any religion, translated into the language the user is most familiar with."
}, {
"Name": "Book of Confusion",
"Description": "The letters in this book always appear to be upside down, even if viewed from different directions at the same time. The book is a bad novel about zombies."
}, {
"Name": "Book of Curses",
"Description": "When opened, the book verbally berates anyone in the immediate vicinity, calling into question their combat ability, intellect, personal hygiene, lineage and profession of their mothers, and other delightful insults. Once closed the book continues shouting (although it is muffled) until placed inside a bag or some other similar container for 1d4+1 minutes and ignored. Replying to the book in any other way causes the insults to get louder and more childish the more time you spend replying to...(line truncated)...
}, {
"Name": "Book of Exalted Deeds",
"Description": "Contains a listing of some of the finest houses ever sold and the specifics of the titles to the properties."
}, {
"Name": "Boots of Levitation",
"Description": "These boots levitate a few inches off the ground when not worn."
}, {
"Name": "Boots of Stylishness",
"Description": "Knee high black boots that are always clean and shiny. They never take in water, thus feet are always dry."
}, {
"Name": "Boots of Walking",
"Description": "The wearer of the boots cannot run, nor can he take a double move action, and takes a -5 to Tumble checks. These boots are made for walkin', and that's just what they'll do."
}, {
"Name": "Bottle of Air",
"Description": "It's a bottle. Full of air. Congratulations."
}, {
"Name": "Bottomless Beer Mug",
"Description": "Any liquid poured into this mug treats the bottom as incorporeal, but solid objects don't"
}, {
"Name": "Bowl of Comfortable Warmth",
"Description": "Any liquid in the bowl will feel comfortably warm, so icy cold water will feel like it's a bit over room temperature. Do note, however, that it's still icy cold water, it just feels warmer."
}, {
"Name": "Breastplate of Secret Detection",
"Description": "If the wearer of this breastplate gains a piece of information that is somehow connected to the concealment of a hidden conspiracy or plot, a live and still wet red herring forms on the inside of the armor."
}, {
"Name": "Bullying Gloves",
"Description": "At random intervals, these gloves instil the wearer with a near-irresistible urge to hit themselves."
}, {
"Name": "Bunyan’s Belt",
"Description": "When worn, causes an enormous, bushy black beard to appear on the wearer’s face."
}, {
"Name": "Cape of Resistance",
"Description": "When this item is placed on any living thing it somehow manages to fall off, untie itself, slip past the owner’s neck entirely, or otherwise avoid being worn."
}, {
"Name": "Case of the Litigator",
"Description": "Translates any document placed in the case into legal jargon; non-reversible. Does not confer the ability to understand legal jargon."
}, {
"Name": "Cat of Schrodinger",
"Description": "When this cat is not being observed in any way it is both dead and alive. When something observes it, it suddenly becomes either dead or alive with a 50% chance of either."
}, {
"Name": "Chair of Steadiness",
"Description": "This chair can be moved but cannot be tipped over by anything less than a DC 35 Strength check."
}, {
"Name": "Charles",
"Description": "This small, unremarkable figurine of a gnome refuses to be called anything but Charles. No other name will leave the lips of the speaker. It has no other powers."
}, {
"Name": "Chime of Interruption",
"Description": "This instrument can be struck once every round, which takes a standard action. On any round the chime is activated the user may ready one action without spending an action to do so."
}, {
"Name": "Chime of Opening",
"Description": "Commonly affixed to or near doors, when pressed it emits a sound on the interior of the owner’s home to let them know guests have arrived."
}, {
"Name": "Chime of Opening (Alternate)",
"Description": "When struck against a solid surface, this chime emits a loud click, and opens along its length, to reveal a tiny compartment adequate to conceal a single 'smoke' worth of pipeweed or a blowgun needle. When the compartment is closed, it is seamless and can be detected only with a DC 20 Search check. If hit with an instrument such as a small mallet, it chimes."
}, {
"Name": "Cloak of Billowing",
"Description": "This black and silver cloak will always billow dramatically behind the wearer, it has no other effects."
}, {
"Name": "Cloak of Displacement, Minor",
"Description": "This item appears to be a normal cloak, but when worn by a character its magical properties distort and warp reality. When any attack is made against the wearer the cloak has a 20% chance of falling off, no matter how it is secured."
}, {
"Name": "Compacting hammer",
"Description": "The force imparted by it is multiplied, but is spread around the surface of a struck object facing inward."
}, {
"Name": "Cymbal of Symbols",
"Description": "This musical instrument enables the user to comprehend dead languages, but only while they are deafened by noise."
}, {
"Name": "Dagger of Told Secrets",
"Description": "A simple-looking dagger. If used to backstab someone to death, it will whisper your most embarrassing secret to that person."
}, {
"Name": "Dagger of Untold Secrets",
"Description": "A simple looking dagger. If used to backstab someone to death, it will whisper the most embarrassing secret of that person to you."
}, {
"Name": "Decanter of Endless Sorrow",
"Description": "A pewter flask that produces limitless alcohol when held to their lips by someone who is troubled. It gets them drunk but they never feel any better."
}, {
"Name": "Diadem of Brothaurity",
"Description": "When wearing this headpiece, you are as elegant and well-spoken as a famous diplomat or regent, but you can't stop calling everyone bro."
}, {
"Name": "Enchanted Book of Collected Stories",
"Description": "Opening this will cause miniature creatures/people to pour out and preform a chapter from the book much like a theater."
}, {
"Name": "Fade to Black Belt",
"Description": "The wearer of this belt will be unable to remember any sexual encounter begun while they were wearing the belt."
}, {
"Name": "Focusing Ring",
"Description": "The digit on which this ring is worn can be viewed in extremely high definition from a great distance."
}, {
"Name": "Gloves of Tinkering",
"Description": "Wearing the gloves will make you able to almost repair any broken item. However, you will always end up with pieces from the item that don't seem to fit anywhere."
}, {
"Name": "Greater Staff of Random Summoning",
"Description": "Summons a random creature at a random place. You could be summoning a giant Ogre on the other side of the globe for all you know."
}, {
"Name": "Hoarder's Wand",
"Description": "Does nothing but for some reason you think it might be important later in your quest."
}, {
"Name": "Hood of Offensive Facades",
"Description": "This hood will change your identity in the eyes of others to the appearance of the person they most personally dislike."
}, {
"Name": "Hood Of Worrisome Facades",
"Description": "This hood will change your identity in the eyes of others, however the identity used will be random."
}, {
"Name": "Indestructible Notebook of Memories",
"Description": "This otherwise normal notepad of normal notepad size cannot be damaged or destroyed, and anything written in it cannot be obscured or defaced. It also has unlimited pages despite its finite size. However, the data it holds only lasts as long as the writer independently remembers it, and decays in exact proportion to the relevant memories. Remember who and when, but not where? Then the words describing the location in that particular entry are the only ones gone."
}, {
"Name": "Intransigent Rod",
"Description": "When the button on this artifact is pressed in, the holder's opinions solidify and they become impossible to convince."
}, {
"Name": "Lunchbox of Delicious Unfulfillment",
"Description": "This lunchbox will hold whatever food you desire. However you will never get full and the food will deliver no nourishment."
}, {
"Name": "Mattress of Poverty, The",
"Description": "No matter how you fluff this gorgeous, thick, mattress, you will always sleep on the thin part of it."
}, {
"Name": "Mug O' Dissatisfaction",
"Description": "A mug that always produces a steaming hot cup of coffee or tea when tapped on the bottom. It conjures the opposite of what the tapper prefers, so if you like tea you get coffee and vice versa. Handing the full mug to another person will make the drink in it transform to the opposite of that persons preferences."
}, {
"Name": "Murder Dagger",
"Description": "All damage it would deal is instead replaced by the target being harassed by crows for that many hours."
}, {
"Name": "Needle Of Learned Compromise",
"Description": "This needle will create beautiful tattoos of any design, however they hurt a tiny bit more. When used to sew it is entirely normal."
}, {
"Name": "Portable Dark Tavern Corner",
"Description": "Consisting of two wooden boards connected by a hinge, this artifact draws those nearby into assuming it is a perfect spot to conduct seedy business."
}, {
"Name": "Ring of First Impression",
"Description": "Wearing the ring will make you able to perform a perfect handshake with the hand wearing it."
}, {
"Name": "Sack of Hive Eggs",
"Description": "Crushing one of the numerous tiny eggs will cause the thoughts of everybody in the proximity to merge. Everybody can hear what you think and you can hear everybody."
}, {
"Name": "Shoes of the Restless Traveler",
"Description": "These shoes allow their user to run for miles without feeling fatigue, but if they try to do anything else with it (walk, sit down, jump), they will instantly trip"
}, {
"Name": "Sword of Parrying",
"Description": "Parries every attack, swinging it yourself will force it to \"parry\" your opponents weapon/attack even though he/she/it is defenseless."
}, {
"Name": "Vorpal Grindstone",
"Description": "It can \"sharpen\" any object to become vorpal. Any object."
}, {
"Name": "Water Hat, The",
"Description": "A small red hat, when worn, causes water to pour from the wearer's fingers at the speed and pressure of a kitchen faucet at half power."
},
{ "Name":"Wineskin of the Eternal Primary",
"Description":"This wineskin never runs out of water, but even the tiniest sip makes you have to go, like, super bad. Right now."
},
]

View File

@ -56,6 +56,8 @@ Next to your exe you must also have a data folder in which there is config.json
- For Mashape Api Key you need to create an account on their api marketplace here https://market.mashape.com/. After that you need to go to market.mashape.com/YOURNAMEHERE/applications/default-application and press GET THE KEYS in the right top corner copy paste it into your credentials.json and you are ready to race! - For Mashape Api Key you need to create an account on their api marketplace here https://market.mashape.com/. After that you need to go to market.mashape.com/YOURNAMEHERE/applications/default-application and press GET THE KEYS in the right top corner copy paste it into your credentials.json and you are ready to race!
- If you want to have music, you need to download FFMPEG from this link http://ffmpeg.zeranoe.com/builds/ (static build version) and add ffmpeg/bin folder to your PATH environment variable. You do that by opening explorer -> right click 'This PC' -> properties -> advanced system settings -> In the top part, there is a PATH field, add `;` to the end and then your ffmpeg install location /bin (for example ;C:\ffmpeg-5.6.7\bin) and save. Open command prompt and type ffmpeg to see if you added it correctly. If it says "command not found" then you made a mistake somewhere. There are a lot of guides on the internet on how to add stuff to your PATH, check them out if you are stuck. - If you want to have music, you need to download FFMPEG from this link http://ffmpeg.zeranoe.com/builds/ (static build version) and add ffmpeg/bin folder to your PATH environment variable. You do that by opening explorer -> right click 'This PC' -> properties -> advanced system settings -> In the top part, there is a PATH field, add `;` to the end and then your ffmpeg install location /bin (for example ;C:\ffmpeg-5.6.7\bin) and save. Open command prompt and type ffmpeg to see if you added it correctly. If it says "command not found" then you made a mistake somewhere. There are a lot of guides on the internet on how to add stuff to your PATH, check them out if you are stuck.
- **IF YOU HAVE BEEN USING THIS BOT BEFORE AND YOU HAVE DATA FROM PARSE THAT YOU WANT TO KEEP** you should export your parse data and extract it inside /data/parsedata in your bot's folder. Next time you start the bot, type `.parsetosql` and the bot will fill your local sqlite db with data from those .json files. - **IF YOU HAVE BEEN USING THIS BOT BEFORE AND YOU HAVE DATA FROM PARSE THAT YOU WANT TO KEEP** you should export your parse data and extract it inside /data/parsedata in your bot's folder. Next time you start the bot, type `.parsetosql` and the bot will fill your local sqlite db with data from those .json files.
**Nothing was buffered music error?** make sure to follow the guide on google api key and ffmpeg [here](https://www.youtube.com/watch?v=x7v02MXNLeI)
Enjoy Enjoy