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

This commit is contained in:
appelemac 2016-04-01 19:35:28 +02:00
commit 0d224ec047
66 changed files with 1847 additions and 1318 deletions

7
.gitignore vendored
View File

@ -10,7 +10,6 @@
obj/ obj/
# User-specific files (MonoDevelop/Xamarin Studio) # User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs *.userprefs
**/Bin/Debug/**
**/Bin/Release/ **/Bin/Release/
**/Bin/PRIVATE/ **/Bin/PRIVATE/
!**/Bin/Debug/opus.dll !**/Bin/Debug/opus.dll
@ -19,9 +18,11 @@ obj/
!**/Bin/Debug/Nito.AsyncEx.dll !**/Bin/Debug/Nito.AsyncEx.dll
!**/Bin/Debug/WebSocket4Net.dll !**/Bin/Debug/WebSocket4Net.dll
!**/Bin/Debug/sqlite3.dll !**/Bin/Debug/sqlite3.dll
!**/Bin/Debug/data/*
!**/Bin/Debug/data/
!**/Bin/Debug/credentials_example.json !**/Bin/Debug/credentials_example.json
NadekoBot/bin/debug/*.*
NadekoBot/bin/debug/data/permissions
NadekoBot/bin/debug/data/incidents
!NadekoBot/bin/Debug/data/currency_images/*
Tests/bin Tests/bin
# NuGet Packages # NuGet Packages

View File

@ -0,0 +1,8 @@
namespace NadekoBot.Classes
{
class BombermanGame
{
public ulong ChannelId { get; internal set; }
public bool Ended { get; internal set; }
}
}

View File

@ -1,19 +1,23 @@
using System.Collections.Generic; using NadekoBot.Classes._DataModels;
using System.Linq;
using SQLite; using SQLite;
using NadekoBot.Classes._DataModels;
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
namespace NadekoBot.Classes { namespace NadekoBot.Classes
internal class DbHandler { {
internal class DbHandler
{
public static DbHandler Instance { get; } = new DbHandler(); public static DbHandler Instance { get; } = new DbHandler();
private string FilePath { get; } = "data/nadekobot.sqlite"; private string FilePath { get; } = "data/nadekobot.sqlite";
static DbHandler() { } static DbHandler() { }
public DbHandler() { public DbHandler()
using (var conn = new SQLiteConnection(FilePath)) { {
using (var conn = new SQLiteConnection(FilePath))
{
conn.CreateTable<Stats>(); conn.CreateTable<Stats>();
conn.CreateTable<Command>(); conn.CreateTable<Command>();
conn.CreateTable<Announcement>(); conn.CreateTable<Announcement>();
@ -23,44 +27,83 @@ namespace NadekoBot.Classes {
conn.CreateTable<CurrencyTransaction>(); conn.CreateTable<CurrencyTransaction>();
conn.CreateTable<Donator>(); conn.CreateTable<Donator>();
conn.CreateTable<PokeMoves>(); conn.CreateTable<PokeMoves>();
conn.CreateTable<userPokeTypes>(); conn.CreateTable<UserPokeTypes>();
conn.CreateTable<UserQuote>(); conn.CreateTable<UserQuote>();
conn.CreateTable<Reminder>();
conn.Execute(Queries.TransactionTriggerQuery); conn.Execute(Queries.TransactionTriggerQuery);
} }
} }
internal void InsertData<T>(T o) where T : IDataModel { internal T FindOne<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
using (var conn = new SQLiteConnection(FilePath)) { {
using (var conn = new SQLiteConnection(FilePath))
{
return conn.Table<T>().Where(p).FirstOrDefault();
}
}
internal void DeleteAll<T>() where T : IDataModel
{
using (var conn = new SQLiteConnection(FilePath))
{
conn.DeleteAll<T>();
}
}
internal void DeleteWhere<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
{
using (var conn = new SQLiteConnection(FilePath))
{
var id = conn.Table<T>().Where(p).FirstOrDefault()?.Id;
if (id.HasValue)
conn.Delete<T>(id);
}
}
internal void InsertData<T>(T o) where T : IDataModel
{
using (var conn = new SQLiteConnection(FilePath))
{
conn.Insert(o, typeof(T)); conn.Insert(o, typeof(T));
} }
} }
internal void InsertMany<T>(T objects) where T : IEnumerable<IDataModel> { internal void InsertMany<T>(T objects) where T : IEnumerable<IDataModel>
using (var conn = new SQLiteConnection(FilePath)) { {
using (var conn = new SQLiteConnection(FilePath))
{
conn.InsertAll(objects); conn.InsertAll(objects);
} }
} }
internal void UpdateData<T>(T o) where T : IDataModel { internal void UpdateData<T>(T o) where T : IDataModel
using (var conn = new SQLiteConnection(FilePath)) { {
using (var conn = new SQLiteConnection(FilePath))
{
conn.Update(o, typeof(T)); conn.Update(o, typeof(T));
} }
} }
internal HashSet<T> GetAllRows<T>() where T : IDataModel, new() { internal HashSet<T> GetAllRows<T>() where T : IDataModel, new()
using (var conn = new SQLiteConnection(FilePath)) { {
using (var conn = new SQLiteConnection(FilePath))
{
return new HashSet<T>(conn.Table<T>()); return new HashSet<T>(conn.Table<T>());
} }
} }
internal CurrencyState GetStateByUserId(long id) { internal CurrencyState GetStateByUserId(long id)
using (var conn = new SQLiteConnection(FilePath)) { {
using (var conn = new SQLiteConnection(FilePath))
{
return conn.Table<CurrencyState>().Where(x => x.UserId == id).FirstOrDefault(); return conn.Table<CurrencyState>().Where(x => x.UserId == id).FirstOrDefault();
} }
} }
internal T Delete<T>(int id) where T : IDataModel, new() { internal T Delete<T>(int id) where T : IDataModel, new()
using (var conn = new SQLiteConnection(FilePath)) { {
using (var conn = new SQLiteConnection(FilePath))
{
var found = conn.Find<T>(id); var found = conn.Find<T>(id);
if (found != null) if (found != null)
conn.Delete<T>(found.Id); conn.Delete<T>(found.Id);
@ -71,8 +114,10 @@ namespace NadekoBot.Classes {
/// <summary> /// <summary>
/// Updates an existing object or creates a new one /// Updates an existing object or creates a new one
/// </summary> /// </summary>
internal void Save<T>(T o) where T : IDataModel, new() { internal void Save<T>(T o) where T : IDataModel, new()
using (var conn = new SQLiteConnection(FilePath)) { {
using (var conn = new SQLiteConnection(FilePath))
{
var found = conn.Find<T>(o.Id); var found = conn.Find<T>(o.Id);
if (found == null) if (found == null)
conn.Insert(o, typeof(T)); conn.Insert(o, typeof(T));
@ -81,8 +126,10 @@ namespace NadekoBot.Classes {
} }
} }
internal T GetRandom<T>(Expression<Func<T, bool>> p) where T : IDataModel, new() { internal T GetRandom<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
using (var conn = new SQLiteConnection(FilePath)) { {
using (var conn = new SQLiteConnection(FilePath))
{
var r = new Random(); var r = new Random();
return conn.Table<T>().Where(p).ToList().OrderBy(x => r.Next()).FirstOrDefault(); return conn.Table<T>().Where(p).ToList().OrderBy(x => r.Next()).FirstOrDefault();
} }
@ -90,7 +137,8 @@ namespace NadekoBot.Classes {
} }
} }
public static class Queries { public static class Queries
{
public static string TransactionTriggerQuery = @" public static string TransactionTriggerQuery = @"
CREATE TRIGGER IF NOT EXISTS OnTransactionAdded CREATE TRIGGER IF NOT EXISTS OnTransactionAdded
AFTER INSERT ON CurrencyTransaction AFTER INSERT ON CurrencyTransaction

View File

@ -4,7 +4,7 @@ namespace NadekoBot.Classes
{ {
internal static class FlowersHandler internal static class FlowersHandler
{ {
public static async Task AddFlowersAsync(Discord.User u, string reason, int amount) public static async Task AddFlowersAsync(Discord.User u, string reason, int amount, bool silent = false)
{ {
if (amount <= 0) if (amount <= 0)
return; return;
@ -17,6 +17,10 @@ namespace NadekoBot.Classes
Value = amount, Value = amount,
}); });
}); });
if (silent)
return;
var flows = ""; var flows = "";
for (var i = 0; i < amount; i++) for (var i = 0; i < amount; i++)
{ {
@ -25,19 +29,23 @@ namespace NadekoBot.Classes
await u.SendMessage("👑Congratulations!👑\nYou received: " + flows); await u.SendMessage("👑Congratulations!👑\nYou received: " + flows);
} }
public static async Task RemoveFlowersAsync(Discord.User u, string reason, int amount) public static bool RemoveFlowers(Discord.User u, string reason, int amount)
{ {
if (amount <= 0) if (amount <= 0)
return; return false;
await Task.Run(() => var uid = (long)u.Id;
{ var state = DbHandler.Instance.FindOne<_DataModels.CurrencyState>(cs => cs.UserId == uid);
if (state.Value < amount)
return false;
DbHandler.Instance.InsertData(new _DataModels.CurrencyTransaction DbHandler.Instance.InsertData(new _DataModels.CurrencyTransaction
{ {
Reason = reason, Reason = reason,
UserId = (long)u.Id, UserId = (long)u.Id,
Value = -amount, Value = -amount,
}); });
}); return true;
} }
} }
} }

View File

@ -94,7 +94,7 @@ namespace NadekoBot.Classes.JSONModels
public string Gambling { get; set; } = "$"; public string Gambling { get; set; } = "$";
public string Permissions { get; set; } = ";"; public string Permissions { get; set; } = ";";
public string Programming { get; set; } = "%"; public string Programming { get; set; } = "%";
public string Pokemon { get; set; } = "poke"; public string Pokemon { get; set; } = ">";
} }
public static class ConfigHandler public static class ConfigHandler

View File

@ -5,15 +5,18 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace NadekoBot.Classes.Music { namespace NadekoBot.Classes.Music
{
public enum MusicType { public enum MusicType
{
Radio, Radio,
Normal, Normal,
Local Local
} }
public enum StreamState { public enum StreamState
{
Resolving, Resolving,
Queued, Queued,
Buffering, //not using it atm Buffering, //not using it atm
@ -21,7 +24,8 @@ namespace NadekoBot.Classes.Music {
Completed Completed
} }
public class MusicPlayer { public class MusicPlayer
{
public static int MaximumPlaylistSize => 50; public static int MaximumPlaylistSize => 50;
private IAudioClient audioClient { get; set; } private IAudioClient audioClient { get; set; }
@ -44,8 +48,11 @@ namespace NadekoBot.Classes.Music {
public Channel PlaybackVoiceChannel { get; private set; } public Channel PlaybackVoiceChannel { get; private set; }
private bool Destroyed { get; set; } = false; private bool Destroyed { get; set; } = false;
public bool RepeatSong { get; private set; } = false;
public bool RepeatPlaylist { get; private set; } = false;
public MusicPlayer(Channel startingVoiceChannel, float? defaultVolume) { public MusicPlayer(Channel startingVoiceChannel, float? defaultVolume)
{
if (startingVoiceChannel == null) if (startingVoiceChannel == null)
throw new ArgumentNullException(nameof(startingVoiceChannel)); throw new ArgumentNullException(nameof(startingVoiceChannel));
if (startingVoiceChannel.Type != ChannelType.Voice) if (startingVoiceChannel.Type != ChannelType.Voice)
@ -56,27 +63,42 @@ namespace NadekoBot.Classes.Music {
SongCancelSource = new CancellationTokenSource(); SongCancelSource = new CancellationTokenSource();
cancelToken = SongCancelSource.Token; cancelToken = SongCancelSource.Token;
Task.Run(async () => { Task.Run(async () =>
while (!Destroyed) { {
try { while (!Destroyed)
{
try
{
if (audioClient?.State != ConnectionState.Connected) if (audioClient?.State != ConnectionState.Connected)
audioClient = await PlaybackVoiceChannel.JoinAudio(); audioClient = await PlaybackVoiceChannel.JoinAudio();
} catch { }
catch
{
await Task.Delay(1000); await Task.Delay(1000);
continue; continue;
} }
CurrentSong = GetNextSong(); CurrentSong = GetNextSong();
var curSong = CurrentSong; var curSong = CurrentSong;
if (curSong != null) { if (curSong != null)
try { {
try
{
OnStarted(this, curSong); OnStarted(this, curSong);
await curSong.Play(audioClient, cancelToken); await curSong.Play(audioClient, cancelToken);
} catch (OperationCanceledException) { }
catch (OperationCanceledException)
{
Console.WriteLine("Song canceled"); Console.WriteLine("Song canceled");
} catch (Exception ex) { }
catch (Exception ex)
{
Console.WriteLine($"Exception in PlaySong: {ex}"); Console.WriteLine($"Exception in PlaySong: {ex}");
} }
OnCompleted(this, curSong); OnCompleted(this, curSong);
if (RepeatSong)
playlist.Insert(0, curSong);
else if (RepeatPlaylist)
playlist.Insert(playlist.Count, curSong);
SongCancelSource = new CancellationTokenSource(); SongCancelSource = new CancellationTokenSource();
cancelToken = SongCancelSource.Token; cancelToken = SongCancelSource.Token;
} }
@ -85,17 +107,22 @@ namespace NadekoBot.Classes.Music {
}); });
} }
public void Next() { public void Next()
lock (playlistLock) { {
if (!SongCancelSource.IsCancellationRequested) { lock (playlistLock)
{
if (!SongCancelSource.IsCancellationRequested)
{
Paused = false; Paused = false;
SongCancelSource.Cancel(); SongCancelSource.Cancel();
} }
} }
} }
public void Stop() { public void Stop()
lock (playlistLock) { {
lock (playlistLock)
{
playlist.Clear(); playlist.Clear();
CurrentSong = null; CurrentSong = null;
if (!SongCancelSource.IsCancellationRequested) if (!SongCancelSource.IsCancellationRequested)
@ -105,13 +132,16 @@ namespace NadekoBot.Classes.Music {
public void TogglePause() => Paused = !Paused; public void TogglePause() => Paused = !Paused;
public void Shuffle() { public void Shuffle()
lock (playlistLock) { {
lock (playlistLock)
{
playlist.Shuffle(); playlist.Shuffle();
} }
} }
public int SetVolume(int volume) { public int SetVolume(int volume)
{
if (volume < 0) if (volume < 0)
volume = 0; volume = 0;
if (volume > 150) if (volume > 150)
@ -121,8 +151,10 @@ namespace NadekoBot.Classes.Music {
return volume; return volume;
} }
private Song GetNextSong() { private Song GetNextSong()
lock (playlistLock) { {
lock (playlistLock)
{
if (playlist.Count == 0) if (playlist.Count == 0)
return null; return null;
var toReturn = playlist[0]; var toReturn = playlist[0];
@ -131,45 +163,56 @@ namespace NadekoBot.Classes.Music {
} }
} }
public void AddSong(Song s) { public void AddSong(Song s)
{
if (s == null) if (s == null)
throw new ArgumentNullException(nameof(s)); throw new ArgumentNullException(nameof(s));
lock (playlistLock) { lock (playlistLock)
{
playlist.Add(s); playlist.Add(s);
} }
} }
public void RemoveSong(Song s) { public void RemoveSong(Song s)
{
if (s == null) if (s == null)
throw new ArgumentNullException(nameof(s)); throw new ArgumentNullException(nameof(s));
lock (playlistLock) { lock (playlistLock)
{
playlist.Remove(s); playlist.Remove(s);
} }
} }
public void RemoveSongAt(int index) { public void RemoveSongAt(int index)
lock (playlistLock) { {
lock (playlistLock)
{
if (index < 0 || index >= playlist.Count) if (index < 0 || index >= playlist.Count)
throw new ArgumentException("Invalid index"); throw new ArgumentException("Invalid index");
playlist.RemoveAt(index); playlist.RemoveAt(index);
} }
} }
internal Task MoveToVoiceChannel(Channel voiceChannel) { internal Task MoveToVoiceChannel(Channel voiceChannel)
{
if (audioClient?.State != ConnectionState.Connected) if (audioClient?.State != ConnectionState.Connected)
throw new InvalidOperationException("Can't move while bot is not connected to voice channel."); throw new InvalidOperationException("Can't move while bot is not connected to voice channel.");
PlaybackVoiceChannel = voiceChannel; PlaybackVoiceChannel = voiceChannel;
return PlaybackVoiceChannel.JoinAudio(); return PlaybackVoiceChannel.JoinAudio();
} }
internal void ClearQueue() { internal void ClearQueue()
lock (playlistLock) { {
lock (playlistLock)
{
playlist.Clear(); playlist.Clear();
} }
} }
public void Destroy() { public void Destroy()
lock (playlistLock) { {
lock (playlistLock)
{
playlist.Clear(); playlist.Clear();
Destroyed = true; Destroyed = true;
CurrentSong = null; CurrentSong = null;
@ -178,5 +221,9 @@ namespace NadekoBot.Classes.Music {
audioClient.Disconnect(); audioClient.Disconnect();
} }
} }
internal bool ToggleRepeatSong() => this.RepeatSong = !this.RepeatSong;
internal bool ToggleRepeatPlaylist() => this.RepeatPlaylist = !this.RepeatPlaylist;
} }
} }

View File

@ -1,16 +1,19 @@
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using NadekoBot.Extensions;
using NadekoBot.Modules;
using NadekoBot.Modules.Administration.Commands;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using NadekoBot.Extensions;
using System.Threading.Tasks;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
using System.Timers; using System.Timers;
using NadekoBot.Modules;
namespace NadekoBot { namespace NadekoBot
public class NadekoStats { {
public class NadekoStats
{
public static NadekoStats Instance { get; } = new NadekoStats(); public static NadekoStats Instance { get; } = new NadekoStats();
public string BotVersion => $"{Assembly.GetExecutingAssembly().GetName().Name} v{Assembly.GetExecutingAssembly().GetName().Version}"; public string BotVersion => $"{Assembly.GetExecutingAssembly().GetName().Name} v{Assembly.GetExecutingAssembly().GetName().Version}";
@ -27,7 +30,8 @@ namespace NadekoBot {
static NadekoStats() { } static NadekoStats() { }
private NadekoStats() { private NadekoStats()
{
var commandService = NadekoBot.Client.GetService<CommandService>(); var commandService = NadekoBot.Client.GetService<CommandService>();
statsStopwatch.Start(); statsStopwatch.Start();
@ -43,52 +47,66 @@ namespace NadekoBot {
TextChannelsCount = channelsArray.Count(c => c.Type == ChannelType.Text); TextChannelsCount = channelsArray.Count(c => c.Type == ChannelType.Text);
VoiceChannelsCount = channelsArray.Count() - TextChannelsCount; VoiceChannelsCount = channelsArray.Count() - TextChannelsCount;
NadekoBot.Client.JoinedServer += (s, e) => { NadekoBot.Client.JoinedServer += (s, e) =>
try { {
try
{
ServerCount++; ServerCount++;
TextChannelsCount += e.Server.TextChannels.Count(); TextChannelsCount += e.Server.TextChannels.Count();
VoiceChannelsCount += e.Server.VoiceChannels.Count(); VoiceChannelsCount += e.Server.VoiceChannels.Count();
} catch { } }
catch { }
}; };
NadekoBot.Client.LeftServer += (s, e) => { NadekoBot.Client.LeftServer += (s, e) =>
try { {
try
{
ServerCount--; ServerCount--;
TextChannelsCount -= e.Server.TextChannels.Count(); TextChannelsCount -= e.Server.TextChannels.Count();
VoiceChannelsCount -= e.Server.VoiceChannels.Count(); VoiceChannelsCount -= e.Server.VoiceChannels.Count();
} catch { } }
catch { }
}; };
NadekoBot.Client.ChannelCreated += (s, e) => { NadekoBot.Client.ChannelCreated += (s, e) =>
try { {
try
{
if (e.Channel.IsPrivate) if (e.Channel.IsPrivate)
return; return;
if (e.Channel.Type == ChannelType.Text) if (e.Channel.Type == ChannelType.Text)
TextChannelsCount++; TextChannelsCount++;
else if (e.Channel.Type == ChannelType.Voice) else if (e.Channel.Type == ChannelType.Voice)
VoiceChannelsCount++; VoiceChannelsCount++;
} catch { } }
catch { }
}; };
NadekoBot.Client.ChannelDestroyed += (s, e) => { NadekoBot.Client.ChannelDestroyed += (s, e) =>
try { {
try
{
if (e.Channel.IsPrivate) if (e.Channel.IsPrivate)
return; return;
if (e.Channel.Type == ChannelType.Text) if (e.Channel.Type == ChannelType.Text)
VoiceChannelsCount++; VoiceChannelsCount++;
else if (e.Channel.Type == ChannelType.Voice) else if (e.Channel.Type == ChannelType.Voice)
VoiceChannelsCount--; VoiceChannelsCount--;
} catch { } }
catch { }
}; };
} }
public TimeSpan GetUptime() => public TimeSpan GetUptime() =>
DateTime.Now - Process.GetCurrentProcess().StartTime; DateTime.Now - Process.GetCurrentProcess().StartTime;
public string GetUptimeString() { public string GetUptimeString()
{
var time = (DateTime.Now - Process.GetCurrentProcess().StartTime); var time = (DateTime.Now - Process.GetCurrentProcess().StartTime);
return time.Days + " days, " + time.Hours + " hours, and " + time.Minutes + " minutes."; return time.Days + " days, " + time.Hours + " hours, and " + time.Minutes + " minutes.";
} }
public Task LoadStats() => public Task LoadStats() =>
Task.Run(() => { Task.Run(() =>
{
var songs = Music.MusicPlayers.Count(mp => mp.Value.CurrentSong != null); var songs = Music.MusicPlayers.Count(mp => mp.Value.CurrentSong != null);
var sb = new System.Text.StringBuilder(); var sb = new System.Text.StringBuilder();
sb.AppendLine("`Author: Kwoth` `Library: Discord.Net`"); sb.AppendLine("`Author: Kwoth` `Library: Discord.Net`");
@ -102,7 +120,7 @@ namespace NadekoBot {
sb.AppendLine($" | VoiceChannels: {VoiceChannelsCount}`"); sb.AppendLine($" | VoiceChannels: {VoiceChannelsCount}`");
sb.AppendLine($"`Commands Ran this session: {commandsRan}`"); sb.AppendLine($"`Commands Ran this session: {commandsRan}`");
sb.AppendLine($"`Message queue size: {NadekoBot.Client.MessageQueue.Count}`"); sb.AppendLine($"`Message queue size: {NadekoBot.Client.MessageQueue.Count}`");
sb.Append($"`Greeted {Commands.ServerGreetCommand.Greeted} times.`"); sb.Append($"`Greeted {ServerGreetCommand.Greeted} times.`");
sb.AppendLine($" `| Playing {songs} songs, ".SnPl(songs) + sb.AppendLine($" `| Playing {songs} songs, ".SnPl(songs) +
$"{Music.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count)} queued.`"); $"{Music.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count)} queued.`");
sb.AppendLine($"`Heap: {Heap(false)}`"); sb.AppendLine($"`Heap: {Heap(false)}`");
@ -111,7 +129,8 @@ namespace NadekoBot {
public string Heap(bool pass = true) => Math.Round((double)GC.GetTotalMemory(pass) / 1.MiB(), 2).ToString(); public string Heap(bool pass = true) => Math.Round((double)GC.GetTotalMemory(pass) / 1.MiB(), 2).ToString();
public async Task<string> GetStats() { public async Task<string> GetStats()
{
if (statsStopwatch.Elapsed.Seconds < 4 && if (statsStopwatch.Elapsed.Seconds < 4 &&
!string.IsNullOrWhiteSpace(statsCache)) return statsCache; !string.IsNullOrWhiteSpace(statsCache)) return statsCache;
await LoadStats(); await LoadStats();
@ -119,35 +138,45 @@ namespace NadekoBot {
return statsCache; return statsCache;
} }
private async Task StartCollecting() { private async Task StartCollecting()
while (true) { {
while (true)
{
await Task.Delay(new TimeSpan(0, 30, 0)); await Task.Delay(new TimeSpan(0, 30, 0));
try { try
{
var onlineUsers = await Task.Run(() => NadekoBot.Client.Servers.Sum(x => x.Users.Count())); var onlineUsers = await Task.Run(() => NadekoBot.Client.Servers.Sum(x => x.Users.Count()));
var realOnlineUsers = await Task.Run(() => NadekoBot.Client.Servers var realOnlineUsers = await Task.Run(() => NadekoBot.Client.Servers
.Sum(x => x.Users.Count(u => u.Status == UserStatus.Online))); .Sum(x => x.Users.Count(u => u.Status == UserStatus.Online)));
var connectedServers = NadekoBot.Client.Servers.Count(); var connectedServers = NadekoBot.Client.Servers.Count();
Classes.DbHandler.Instance.InsertData(new Classes._DataModels.Stats { Classes.DbHandler.Instance.InsertData(new Classes._DataModels.Stats
{
OnlineUsers = onlineUsers, OnlineUsers = onlineUsers,
RealOnlineUsers = realOnlineUsers, RealOnlineUsers = realOnlineUsers,
Uptime = GetUptime(), Uptime = GetUptime(),
ConnectedServers = connectedServers, ConnectedServers = connectedServers,
DateAdded = DateTime.Now DateAdded = DateTime.Now
}); });
} catch { }
catch
{
Console.WriteLine("DB Exception in stats collecting."); Console.WriteLine("DB Exception in stats collecting.");
break; break;
} }
} }
} }
private async void StatsCollector_RanCommand(object sender, CommandEventArgs e) { private async void StatsCollector_RanCommand(object sender, CommandEventArgs e)
{
Console.WriteLine($">>Command {e.Command.Text}"); Console.WriteLine($">>Command {e.Command.Text}");
await Task.Run(() => { await Task.Run(() =>
try { {
try
{
commandsRan++; commandsRan++;
Classes.DbHandler.Instance.InsertData(new Classes._DataModels.Command { Classes.DbHandler.Instance.InsertData(new Classes._DataModels.Command
{
ServerId = (long)e.Server.Id, ServerId = (long)e.Server.Id,
ServerName = e.Server.Name, ServerName = e.Server.Name,
ChannelId = (long)e.Channel.Id, ChannelId = (long)e.Channel.Id,
@ -157,7 +186,9 @@ namespace NadekoBot {
CommandName = e.Command.Text, CommandName = e.Command.Text,
DateAdded = DateTime.Now DateAdded = DateTime.Now
}); });
} catch { }
catch
{
Console.WriteLine("Error in ran command DB write."); Console.WriteLine("Error in ran command DB write.");
} }
}); });

View File

@ -1,15 +1,16 @@
using System; using Newtonsoft.Json;
using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using NadekoBot.Classes.JSONModels;
using Newtonsoft.Json;
namespace NadekoBot.Classes { namespace NadekoBot.Classes
internal class SpecificConfigurations { {
internal class SpecificConfigurations
{
public static SpecificConfigurations Default { get; } = new SpecificConfigurations(); public static SpecificConfigurations Default { get; } = new SpecificConfigurations();
public static bool Instantiated { get; private set; } public static bool Instantiated { get; private set; }
@ -17,14 +18,19 @@ namespace NadekoBot.Classes {
static SpecificConfigurations() { } static SpecificConfigurations() { }
private SpecificConfigurations() { private SpecificConfigurations()
{
if (File.Exists(filePath)) { if (File.Exists(filePath))
try { {
try
{
configs = JsonConvert configs = JsonConvert
.DeserializeObject<ConcurrentDictionary<ulong, ServerSpecificConfig>>( .DeserializeObject<ConcurrentDictionary<ulong, ServerSpecificConfig>>(
File.ReadAllText(filePath)); File.ReadAllText(filePath));
} catch (Exception ex) { }
catch (Exception ex)
{
Console.WriteLine($"Deserialization failing: {ex}"); Console.WriteLine($"Deserialization failing: {ex}");
} }
} }
@ -42,14 +48,17 @@ namespace NadekoBot.Classes {
private readonly object saveLock = new object(); private readonly object saveLock = new object();
public void Save() { public void Save()
lock (saveLock) { {
lock (saveLock)
{
File.WriteAllText(filePath, JsonConvert.SerializeObject(configs, Formatting.Indented)); File.WriteAllText(filePath, JsonConvert.SerializeObject(configs, Formatting.Indented));
} }
} }
} }
internal class ServerSpecificConfig : INotifyPropertyChanged { internal class ServerSpecificConfig : INotifyPropertyChanged
{
[JsonProperty("VoicePlusTextEnabled")] [JsonProperty("VoicePlusTextEnabled")]
private bool voicePlusTextEnabled; private bool voicePlusTextEnabled;
[JsonIgnore] [JsonIgnore]
@ -78,7 +87,8 @@ namespace NadekoBot.Classes {
set { set {
listOfSelfAssignableRoles = value; listOfSelfAssignableRoles = value;
if (value != null) if (value != null)
listOfSelfAssignableRoles.CollectionChanged += (s, e) => { listOfSelfAssignableRoles.CollectionChanged += (s, e) =>
{
if (!SpecificConfigurations.Instantiated) return; if (!SpecificConfigurations.Instantiated) return;
OnPropertyChanged(); OnPropertyChanged();
}; };
@ -92,34 +102,39 @@ namespace NadekoBot.Classes {
set { set {
observingStreams = value; observingStreams = value;
if (value != null) if (value != null)
observingStreams.CollectionChanged += (s, e) => { observingStreams.CollectionChanged += (s, e) =>
{
if (!SpecificConfigurations.Instantiated) return; if (!SpecificConfigurations.Instantiated) return;
OnPropertyChanged(); OnPropertyChanged();
}; };
} }
} }
public ServerSpecificConfig() { public ServerSpecificConfig()
{
ListOfSelfAssignableRoles = new ObservableCollection<ulong>(); ListOfSelfAssignableRoles = new ObservableCollection<ulong>();
ObservingStreams = new ObservableCollection<StreamNotificationConfig>(); ObservingStreams = new ObservableCollection<StreamNotificationConfig>();
} }
public event PropertyChangedEventHandler PropertyChanged = delegate { SpecificConfigurations.Default.Save(); }; public event PropertyChangedEventHandler PropertyChanged = delegate { SpecificConfigurations.Default.Save(); };
private void OnPropertyChanged([CallerMemberName] string propertyName = null) { private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
Console.WriteLine("property changed"); Console.WriteLine("property changed");
PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
} }
} }
public class StreamNotificationConfig : IEquatable<StreamNotificationConfig> { public class StreamNotificationConfig : IEquatable<StreamNotificationConfig>
{
public string Username { get; set; } public string Username { get; set; }
public StreamType Type { get; set; } public StreamType Type { get; set; }
public ulong ServerId { get; set; } public ulong ServerId { get; set; }
public ulong ChannelId { get; set; } public ulong ChannelId { get; set; }
public bool LastStatus { get; set; } public bool LastStatus { get; set; }
public enum StreamType { public enum StreamType
{
Twitch, Twitch,
Beam, Beam,
Hitbox, Hitbox,
@ -131,7 +146,8 @@ namespace NadekoBot.Classes {
this.Type == other.Type && this.Type == other.Type &&
this.ServerId == other.ServerId; this.ServerId == other.ServerId;
public override int GetHashCode() { public override int GetHashCode()
{
return (int)((int)ServerId + Username.Length + (int)Type); return (int)((int)ServerId + Username.Length + (int)Type);
} }
} }

View File

@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace NadekoBot.Classes._DataModels namespace NadekoBot.Classes._DataModels
{ {
class userPokeTypes : IDataModel class UserPokeTypes : IDataModel
{ {
public long UserId { get; set; } public long UserId { get; set; }
public int type { get; set; } public int type { get; set; }

View File

@ -0,0 +1,14 @@
using System;
namespace NadekoBot.Classes._DataModels
{
class Reminder : IDataModel
{
public DateTime When { get; set; }
public long ChannelId { get; set; }
public long ServerId { get; set; }
public long UserId { get; set; }
public string Message { get; set; }
public bool IsPrivate { get; set; }
}
}

View File

@ -0,0 +1,56 @@
using Discord;
using Discord.Commands;
using NadekoBot.Classes;
using NadekoBot.Modules;
using System;
namespace NadekoBot.Commands
{
class Bomberman : DiscordCommand
{
public Bomberman(DiscordModule module) : base(module)
{
NadekoBot.Client.MessageReceived += async (s, e) =>
{
if (e.Channel.Id != bombGame.ChannelId) return;
var text = e.Message.Text;
await e.Message.Delete();
HandleBombermanCommand(e.User, text);
};
}
private void HandleBombermanCommand(User user, string text)
{
throw new NotImplementedException();
}
//only one bomberman game can run at any one time
public static BombermanGame bombGame = null;
private readonly object locker = new object();
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand($"{Module.Prefix}bmb")
.Description("Creates a bomberman game for this channel or join existing one." +
" If you are 4th player - Game will start. After game starts " +
" everything written in the channel will be autodeleted and treated as a bomberman command." +
" only one bomberman game can run at any one time per bot. Game will run at 1FPS." +
" You must have manage messages permissions in order to create the game.")
.Do(e =>
{
lock (locker)
{
if (bombGame == null || bombGame.Ended)
{
if (!e.User.ServerPermissions.ManageMessages ||
!e.Server.GetUser(NadekoBot.Client.CurrentUser.Id).ServerPermissions.ManageMessages)
{
e.Channel.SendMessage("Both you and Nadeko need manage messages permissions to start a new bomberman game.").Wait();
}
}
}
});
}
}
}

View File

@ -1,27 +1,29 @@
using System; using Discord;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Discord;
using Discord.Commands; using Discord.Commands;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Classes.Permissions; using NadekoBot.Classes.Permissions;
using NadekoBot.Modules; using NadekoBot.Modules;
using System;
using System.Linq;
using ServerPermissions = NadekoBot.Classes.Permissions.ServerPermissions; using ServerPermissions = NadekoBot.Classes.Permissions.ServerPermissions;
namespace NadekoBot.Commands { namespace NadekoBot.Commands
internal class FilterWords : DiscordCommand { {
public FilterWords(DiscordModule module) : base(module) { internal class FilterWords : DiscordCommand
NadekoBot.Client.MessageReceived += async (sender, args) => { {
public FilterWords(DiscordModule module) : base(module)
{
NadekoBot.Client.MessageReceived += async (sender, args) =>
{
if (args.Channel.IsPrivate || args.User.Id == NadekoBot.Client.CurrentUser.Id) return; if (args.Channel.IsPrivate || args.User.Id == NadekoBot.Client.CurrentUser.Id) return;
try { try
{
ServerPermissions serverPerms; ServerPermissions serverPerms;
if (!IsChannelOrServerFiltering(args.Channel, out serverPerms)) return; if (!IsChannelOrServerFiltering(args.Channel, out serverPerms)) return;
var wordsInMessage = args.Message.RawText.ToLowerInvariant().Split(' '); var wordsInMessage = args.Message.RawText.ToLowerInvariant().Split(' ');
if (serverPerms.Words.Any(w => wordsInMessage.Contains(w))) { if (serverPerms.Words.Any(w => wordsInMessage.Contains(w)))
{
await args.Message.Delete(); await args.Message.Delete();
IncidentsHandler.Add(args.Server.Id, $"User [{args.User.Name}/{args.User.Id}] posted " + IncidentsHandler.Add(args.Server.Id, $"User [{args.User.Name}/{args.User.Id}] posted " +
$"BANNED WORD in [{args.Channel.Name}/{args.Channel.Id}] channel. " + $"BANNED WORD in [{args.Channel.Name}/{args.Channel.Id}] channel. " +
@ -30,11 +32,13 @@ namespace NadekoBot.Commands {
await args.Channel.SendMessage($"{args.User.Mention} One or more of the words you used " + await args.Channel.SendMessage($"{args.User.Mention} One or more of the words you used " +
$"in that sentence are not allowed here."); $"in that sentence are not allowed here.");
} }
} catch { } }
catch { }
}; };
} }
private static bool IsChannelOrServerFiltering(Channel channel, out ServerPermissions serverPerms) { private static bool IsChannelOrServerFiltering(Channel channel, out ServerPermissions serverPerms)
{
if (!PermissionsHandler.PermissionsDict.TryGetValue(channel.Server.Id, out serverPerms)) return false; if (!PermissionsHandler.PermissionsDict.TryGetValue(channel.Server.Id, out serverPerms)) return false;
if (serverPerms.Permissions.FilterWords) if (serverPerms.Permissions.FilterWords)
@ -44,7 +48,8 @@ namespace NadekoBot.Commands {
return serverPerms.ChannelPermissions.TryGetValue(channel.Id, out perms) && perms.FilterWords; return serverPerms.ChannelPermissions.TryGetValue(channel.Id, out perms) && perms.FilterWords;
} }
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "cfw") cgb.CreateCommand(Module.Prefix + "cfw")
.Alias(Module.Prefix + "channelfilterwords") .Alias(Module.Prefix + "channelfilterwords")
.Description("Enables or disables automatic deleting of messages containing banned words on the channel." + .Description("Enables or disables automatic deleting of messages containing banned words on the channel." +
@ -52,12 +57,15 @@ namespace NadekoBot.Commands {
"\n**Usage**: ;cfi enable #general-chat") "\n**Usage**: ;cfi enable #general-chat")
.Parameter("bool") .Parameter("bool")
.Parameter("channel", ParameterType.Optional) .Parameter("channel", ParameterType.Optional)
.Do(async e => { .Do(async e =>
try { {
try
{
var state = PermissionHelper.ValidateBool(e.GetArg("bool")); var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
var chanStr = e.GetArg("channel")?.ToLowerInvariant().Trim(); var chanStr = e.GetArg("channel")?.ToLowerInvariant().Trim();
if (chanStr != "all") { if (chanStr != "all")
{
var chan = string.IsNullOrWhiteSpace(chanStr) var chan = string.IsNullOrWhiteSpace(chanStr)
? e.Channel ? e.Channel
: PermissionHelper.ValidateChannel(e.Server, chanStr); : PermissionHelper.ValidateChannel(e.Server, chanStr);
@ -67,11 +75,14 @@ namespace NadekoBot.Commands {
} }
//all channels //all channels
foreach (var curChannel in e.Server.TextChannels) { foreach (var curChannel in e.Server.TextChannels)
{
PermissionsHandler.SetChannelWordPermission(curChannel, state); PermissionsHandler.SetChannelWordPermission(curChannel, state);
} }
await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** for **ALL** channels."); await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** for **ALL** channels.");
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage($"💢 Error: {ex.Message}"); await e.Channel.SendMessage($"💢 Error: {ex.Message}");
} }
}); });
@ -81,15 +92,19 @@ namespace NadekoBot.Commands {
.Description("Adds a new word to the list of filtered words" + .Description("Adds a new word to the list of filtered words" +
"\n**Usage**: ;aw poop") "\n**Usage**: ;aw poop")
.Parameter("word", ParameterType.Unparsed) .Parameter("word", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
try { {
try
{
var word = e.GetArg("word"); var word = e.GetArg("word");
if (string.IsNullOrWhiteSpace(word)) if (string.IsNullOrWhiteSpace(word))
return; return;
PermissionsHandler.AddFilteredWord(e.Server, word.ToLowerInvariant().Trim()); PermissionsHandler.AddFilteredWord(e.Server, word.ToLowerInvariant().Trim());
await e.Channel.SendMessage($"Successfully added new filtered word."); await e.Channel.SendMessage($"Successfully added new filtered word.");
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage($"💢 Error: {ex.Message}"); await e.Channel.SendMessage($"💢 Error: {ex.Message}");
} }
}); });
@ -99,15 +114,19 @@ namespace NadekoBot.Commands {
.Description("Removes the word from the list of filtered words" + .Description("Removes the word from the list of filtered words" +
"\n**Usage**: ;rw poop") "\n**Usage**: ;rw poop")
.Parameter("word", ParameterType.Unparsed) .Parameter("word", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
try { {
try
{
var word = e.GetArg("word"); var word = e.GetArg("word");
if (string.IsNullOrWhiteSpace(word)) if (string.IsNullOrWhiteSpace(word))
return; return;
PermissionsHandler.RemoveFilteredWord(e.Server, word.ToLowerInvariant().Trim()); PermissionsHandler.RemoveFilteredWord(e.Server, word.ToLowerInvariant().Trim());
await e.Channel.SendMessage($"Successfully removed filtered word."); await e.Channel.SendMessage($"Successfully removed filtered word.");
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage($"💢 Error: {ex.Message}"); await e.Channel.SendMessage($"💢 Error: {ex.Message}");
} }
}); });
@ -116,14 +135,18 @@ namespace NadekoBot.Commands {
.Alias(Module.Prefix + "listfilteredwords") .Alias(Module.Prefix + "listfilteredwords")
.Description("Shows a list of filtered words" + .Description("Shows a list of filtered words" +
"\n**Usage**: ;lfw") "\n**Usage**: ;lfw")
.Do(async e => { .Do(async e =>
try { {
try
{
ServerPermissions serverPerms; ServerPermissions serverPerms;
if (!PermissionsHandler.PermissionsDict.TryGetValue(e.Server.Id, out serverPerms)) if (!PermissionsHandler.PermissionsDict.TryGetValue(e.Server.Id, out serverPerms))
return; return;
await e.Channel.SendMessage($"There are `{serverPerms.Words.Count}` filtered words.\n" + await e.Channel.SendMessage($"There are `{serverPerms.Words.Count}` filtered words.\n" +
string.Join("\n", serverPerms.Words)); string.Join("\n", serverPerms.Words));
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage($"💢 Error: {ex.Message}"); await e.Channel.SendMessage($"💢 Error: {ex.Message}");
} }
}); });
@ -132,13 +155,17 @@ namespace NadekoBot.Commands {
.Alias(Module.Prefix + "serverfilterwords") .Alias(Module.Prefix + "serverfilterwords")
.Description("Enables or disables automatic deleting of messages containing forbidden words on the server.\n**Usage**: ;sfi disable") .Description("Enables or disables automatic deleting of messages containing forbidden words on the server.\n**Usage**: ;sfi disable")
.Parameter("bool") .Parameter("bool")
.Do(async e => { .Do(async e =>
try { {
try
{
var state = PermissionHelper.ValidateBool(e.GetArg("bool")); var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
PermissionsHandler.SetServerWordPermission(e.Server, state); PermissionsHandler.SetServerWordPermission(e.Server, state);
await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** on this server."); await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** on this server.");
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage($"💢 Error: {ex.Message}"); await e.Channel.SendMessage($"💢 Error: {ex.Message}");
} }
}); });

View File

@ -0,0 +1,85 @@
using Discord;
using Discord.Commands;
using NadekoBot.Classes;
using NadekoBot.Modules;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace NadekoBot.Commands
{
/// <summary>
/// Flower picking/planting idea is given to me by its
/// inceptor Violent Crumble from Game Developers League discord server
/// (he has !cookie and !nom) Thanks a lot Violent!
/// Check out GDL (its a growing gamedev community):
/// https://discord.gg/0TYNJfCU4De7YIk8
/// </summary>
class PlantPick : DiscordCommand
{
public PlantPick(DiscordModule module) : base(module)
{
}
//channelid/messageid pair
ConcurrentDictionary<ulong, Message> plantedFlowerChannels = new ConcurrentDictionary<ulong, Message>();
private object locker = new object();
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "pick")
.Description("Picks a flower planted in this channel.")
.Do(async e =>
{
Message msg;
await e.Message.Delete();
if (!plantedFlowerChannels.TryRemove(e.Channel.Id, out msg))
return;
await msg.Delete();
await FlowersHandler.AddFlowersAsync(e.User, "Picked a flower.", 1, true);
msg = await e.Channel.SendMessage($"**{e.User.Name}** picked a {NadekoBot.Config.CurrencyName}!");
await Task.Delay(10000);
await msg.Delete();
});
cgb.CreateCommand(Module.Prefix + "plant")
.Description("Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost)")
.Do(async e =>
{
lock (locker)
{
if (plantedFlowerChannels.ContainsKey(e.Channel.Id))
{
e.Channel.SendMessage($"There is already a {NadekoBot.Config.CurrencyName} in this channel.");
return;
}
var removed = FlowersHandler.RemoveFlowers(e.User, "Planted a flower.", 1);
if (!removed)
{
e.Channel.SendMessage($"You don't have any {NadekoBot.Config.CurrencyName}s.").Wait();
return;
}
var rng = new Random();
var file = Directory.GetFiles("data/currency_images").OrderBy(s => rng.Next()).FirstOrDefault();
Message msg;
if (file == null)
msg = e.Channel.SendMessage("🌸").Result;
else
msg = e.Channel.SendFile(file).Result;
plantedFlowerChannels.TryAdd(e.Channel.Id, msg);
}
var msg2 = await e.Channel.SendMessage($"Oh how Nice! **{e.User.Name}** planted a flower. Pick it using {Module.Prefix}pick");
await Task.Delay(20000);
await msg2.Delete();
});
}
}
}

View File

@ -5,6 +5,7 @@ using NadekoBot.Classes.Permissions;
using NadekoBot.Modules; using NadekoBot.Modules;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System; using System;
using System.Collections.Concurrent;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Timers; using System.Timers;
@ -18,11 +19,15 @@ namespace NadekoBot.Commands
{ {
Interval = new TimeSpan(0, 0, 15).TotalMilliseconds, Interval = new TimeSpan(0, 0, 15).TotalMilliseconds,
}; };
private ConcurrentDictionary<string, Tuple<bool, string>> cachedStatuses = new ConcurrentDictionary<string, Tuple<bool, string>>();
public StreamNotifications(DiscordModule module) : base(module) public StreamNotifications(DiscordModule module) : base(module)
{ {
checkTimer.Elapsed += async (s, e) => checkTimer.Elapsed += async (s, e) =>
{ {
cachedStatuses.Clear();
try try
{ {
var streams = SpecificConfigurations.Default.AllConfigs.SelectMany(c => c.ObservingStreams); var streams = SpecificConfigurations.Default.AllConfigs.SelectMany(c => c.ObservingStreams);
@ -74,23 +79,39 @@ namespace NadekoBot.Commands
bool isLive; bool isLive;
string response; string response;
JObject data; JObject data;
Tuple<bool, string> result;
switch (stream.Type) switch (stream.Type)
{ {
case StreamNotificationConfig.StreamType.Hitbox: case StreamNotificationConfig.StreamType.Hitbox:
response = await SearchHelper.GetResponseStringAsync($"https://api.hitbox.tv/media/status/{stream.Username}"); var hitboxUrl = $"https://api.hitbox.tv/media/status/{stream.Username}";
if (cachedStatuses.TryGetValue(hitboxUrl, out result))
return result;
response = await SearchHelper.GetResponseStringAsync(hitboxUrl);
data = JObject.Parse(response); data = JObject.Parse(response);
isLive = data["media_is_live"].ToString() == "1"; isLive = data["media_is_live"].ToString() == "1";
return new Tuple<bool, string>(isLive, data["media_views"].ToString()); result = new Tuple<bool, string>(isLive, data["media_views"].ToString());
cachedStatuses.TryAdd(hitboxUrl, result);
return result;
case StreamNotificationConfig.StreamType.Twitch: case StreamNotificationConfig.StreamType.Twitch:
response = await SearchHelper.GetResponseStringAsync($"https://api.twitch.tv/kraken/streams/{Uri.EscapeUriString(stream.Username)}"); var twitchUrl = $"https://api.twitch.tv/kraken/streams/{Uri.EscapeUriString(stream.Username)}";
if (cachedStatuses.TryGetValue(twitchUrl, out result))
return result;
response = await SearchHelper.GetResponseStringAsync(twitchUrl);
data = JObject.Parse(response); data = JObject.Parse(response);
isLive = !string.IsNullOrWhiteSpace(data["stream"].ToString()); isLive = !string.IsNullOrWhiteSpace(data["stream"].ToString());
return new Tuple<bool, string>(isLive, isLive ? data["stream"]["viewers"].ToString() : "0"); result = new Tuple<bool, string>(isLive, isLive ? data["stream"]["viewers"].ToString() : "0");
cachedStatuses.TryAdd(twitchUrl, result);
return result;
case StreamNotificationConfig.StreamType.Beam: case StreamNotificationConfig.StreamType.Beam:
response = await SearchHelper.GetResponseStringAsync($"https://beam.pro/api/v1/channels/{stream.Username}"); var beamUrl = $"https://beam.pro/api/v1/channels/{stream.Username}";
if (cachedStatuses.TryGetValue(beamUrl, out result))
return result;
response = await SearchHelper.GetResponseStringAsync(beamUrl);
data = JObject.Parse(response); data = JObject.Parse(response);
isLive = data["online"].ToObject<bool>() == true; isLive = data["online"].ToObject<bool>() == true;
return new Tuple<bool, string>(isLive, data["viewersCurrent"].ToString()); result = new Tuple<bool, string>(isLive, data["viewersCurrent"].ToString());
cachedStatuses.TryAdd(beamUrl, result);
return result;
default: default:
break; break;
} }

View File

@ -4,19 +4,19 @@ using Discord.Modules;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Classes._DataModels;
using NadekoBot.Classes.Permissions; using NadekoBot.Classes.Permissions;
using NadekoBot.Commands;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using NadekoBot.Modules.Administration.Commands;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace NadekoBot.Modules namespace NadekoBot.Modules.Administration
{ {
internal class Administration : DiscordModule internal class AdministrationModule : DiscordModule
{ {
public Administration() public AdministrationModule()
{ {
commands.Add(new ServerGreetCommand(this)); commands.Add(new ServerGreetCommand(this));
commands.Add(new LogCommand(this)); commands.Add(new LogCommand(this));
@ -26,6 +26,7 @@ namespace NadekoBot.Modules
commands.Add(new VoicePlusTextCommand(this)); commands.Add(new VoicePlusTextCommand(this));
commands.Add(new CrossServerTextChannel(this)); commands.Add(new CrossServerTextChannel(this));
commands.Add(new SelfAssignedRolesCommand(this)); commands.Add(new SelfAssignedRolesCommand(this));
commands.Add(new Remind(this));
} }
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Administration; public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Administration;
@ -227,6 +228,7 @@ namespace NadekoBot.Modules
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
@ -456,6 +458,7 @@ namespace NadekoBot.Modules
cgb.CreateCommand(Prefix + "st").Alias(Prefix + "settopic") cgb.CreateCommand(Prefix + "st").Alias(Prefix + "settopic")
.Alias(Prefix + "topic") .Alias(Prefix + "topic")
.Description("Sets a topic on the current channel.") .Description("Sets a topic on the current channel.")
.AddCheck(SimpleCheckers.ManageChannels())
.Parameter("topic", ParameterType.Unparsed) .Parameter("topic", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {

View File

@ -1,36 +1,48 @@
using System; using Discord;
using Discord.Commands;
using NadekoBot.Classes.Permissions;
using NadekoBot.Commands;
using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Discord;
using Discord.Commands;
using NadekoBot.Classes.Permissions;
using NadekoBot.Modules;
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
class CrossServerTextChannel : DiscordCommand { {
public CrossServerTextChannel(DiscordModule module) : base(module) { class CrossServerTextChannel : DiscordCommand
NadekoBot.Client.MessageReceived += async (s, e) => { {
try { public CrossServerTextChannel(DiscordModule module) : base(module)
{
NadekoBot.Client.MessageReceived += async (s, e) =>
{
try
{
if (e.User.Id == NadekoBot.Client.CurrentUser.Id) return; if (e.User.Id == NadekoBot.Client.CurrentUser.Id) return;
foreach (var subscriber in Subscribers) { foreach (var subscriber in Subscribers)
{
var set = subscriber.Value; var set = subscriber.Value;
if (!set.Contains(e.Channel)) if (!set.Contains(e.Channel))
continue; continue;
foreach (var chan in set.Except(new[] { e.Channel })) { foreach (var chan in set.Except(new[] { e.Channel }))
{
await chan.SendMessage(GetText(e.Server, e.Channel, e.User, e.Message)); await chan.SendMessage(GetText(e.Server, e.Channel, e.User, e.Message));
} }
} }
} catch { } }
catch { }
}; };
NadekoBot.Client.MessageUpdated += async (s, e) => { NadekoBot.Client.MessageUpdated += async (s, e) =>
try { {
try
{
if (e.After?.User?.Id == null || e.After.User.Id == NadekoBot.Client.CurrentUser.Id) return; if (e.After?.User?.Id == null || e.After.User.Id == NadekoBot.Client.CurrentUser.Id) return;
foreach (var subscriber in Subscribers) { foreach (var subscriber in Subscribers)
{
var set = subscriber.Value; var set = subscriber.Value;
if (!set.Contains(e.Channel)) if (!set.Contains(e.Channel))
continue; continue;
foreach (var chan in set.Except(new[] { e.Channel })) { foreach (var chan in set.Except(new[] { e.Channel }))
{
var msg = chan.Messages var msg = chan.Messages
.FirstOrDefault(m => .FirstOrDefault(m =>
m.RawText == GetText(e.Server, e.Channel, e.User, e.Before)); m.RawText == GetText(e.Server, e.Channel, e.User, e.Before));
@ -39,7 +51,8 @@ namespace NadekoBot.Commands {
} }
} }
} catch { } }
catch { }
}; };
} }
@ -48,15 +61,18 @@ namespace NadekoBot.Commands {
public static readonly ConcurrentDictionary<int, HashSet<Channel>> Subscribers = new ConcurrentDictionary<int, HashSet<Channel>>(); public static readonly ConcurrentDictionary<int, HashSet<Channel>> Subscribers = new ConcurrentDictionary<int, HashSet<Channel>>();
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "scsc") cgb.CreateCommand(Module.Prefix + "scsc")
.Description("Starts an instance of cross server channel. You will get a token as a DM" + .Description("Starts an instance of cross server channel. You will get a token as a DM" +
"that other people will use to tune in to the same instance") "that other people will use to tune in to the same instance")
.AddCheck(SimpleCheckers.OwnerOnly()) .AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => { .Do(async e =>
{
var token = new Random().Next(); var token = new Random().Next();
var set = new HashSet<Channel>(); var set = new HashSet<Channel>();
if (Subscribers.TryAdd(token, set)) { if (Subscribers.TryAdd(token, set))
{
set.Add(e.Channel); set.Add(e.Channel);
await e.User.SendMessage("This is your CSC token:" + token.ToString()); await e.User.SendMessage("This is your CSC token:" + token.ToString());
} }
@ -66,7 +82,8 @@ namespace NadekoBot.Commands {
.Description("Joins current channel to an instance of cross server channel using the token.") .Description("Joins current channel to an instance of cross server channel using the token.")
.Parameter("token") .Parameter("token")
.AddCheck(SimpleCheckers.ManageServer()) .AddCheck(SimpleCheckers.ManageServer())
.Do(async e => { .Do(async e =>
{
int token; int token;
if (!int.TryParse(e.GetArg("token"), out token)) if (!int.TryParse(e.GetArg("token"), out token))
return; return;
@ -80,8 +97,10 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(Module.Prefix + "lcsc") cgb.CreateCommand(Module.Prefix + "lcsc")
.Description("Leaves Cross server channel instance from this channel") .Description("Leaves Cross server channel instance from this channel")
.AddCheck(SimpleCheckers.ManageServer()) .AddCheck(SimpleCheckers.ManageServer())
.Do(async e => { .Do(async e =>
foreach (var subscriber in Subscribers) { {
foreach (var subscriber in Subscribers)
{
subscriber.Value.Remove(e.Channel); subscriber.Value.Remove(e.Channel);
} }
await e.Channel.SendMessage(":ok:"); await e.Channel.SendMessage(":ok:");

View File

@ -2,13 +2,13 @@
using Discord.Commands; using Discord.Commands;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Classes.Permissions; using NadekoBot.Classes.Permissions;
using NadekoBot.Modules; using NadekoBot.Commands;
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;
namespace NadekoBot.Commands namespace NadekoBot.Modules.Administration.Commands
{ {
internal class LogCommand : DiscordCommand internal class LogCommand : DiscordCommand
{ {

View File

@ -1,15 +1,18 @@
using System; using Discord;
using System.Timers;
using System.Collections.Concurrent;
using Discord;
using NadekoBot.Classes.Permissions;
using Discord.Commands; using Discord.Commands;
using NadekoBot.Modules; using NadekoBot.Classes.Permissions;
using NadekoBot.Commands;
using System;
using System.Collections.Concurrent;
using System.Timers;
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
class MessageRepeater : DiscordCommand { {
class MessageRepeater : DiscordCommand
{
private readonly ConcurrentDictionary<Server, Repeater> repeaters = new ConcurrentDictionary<Server, Repeater>(); private readonly ConcurrentDictionary<Server, Repeater> repeaters = new ConcurrentDictionary<Server, Repeater>();
private class Repeater { private class Repeater
{
[Newtonsoft.Json.JsonIgnore] [Newtonsoft.Json.JsonIgnore]
public Timer MessageTimer { get; set; } public Timer MessageTimer { get; set; }
[Newtonsoft.Json.JsonIgnore] [Newtonsoft.Json.JsonIgnore]
@ -20,21 +23,27 @@ namespace NadekoBot.Commands {
public string RepeatingMessage { get; set; } public string RepeatingMessage { get; set; }
public int Interval { get; set; } public int Interval { get; set; }
public Repeater Start() { public Repeater Start()
{
MessageTimer = new Timer { Interval = Interval }; MessageTimer = new Timer { Interval = Interval };
MessageTimer.Elapsed += async (s, e) => { MessageTimer.Elapsed += async (s, e) =>
{
var ch = RepeatingChannel; var ch = RepeatingChannel;
var msg = RepeatingMessage; var msg = RepeatingMessage;
if (ch != null && !string.IsNullOrWhiteSpace(msg)) { if (ch != null && !string.IsNullOrWhiteSpace(msg))
try { {
try
{
await ch.SendMessage(msg); await ch.SendMessage(msg);
} catch { } }
catch { }
} }
}; };
return this; return this;
} }
} }
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "repeat") cgb.CreateCommand(Module.Prefix + "repeat")
.Description("Repeat a message every X minutes. If no parameters are specified, " + .Description("Repeat a message every X minutes. If no parameters are specified, " +
@ -42,12 +51,14 @@ namespace NadekoBot.Commands {
.Parameter("minutes", ParameterType.Optional) .Parameter("minutes", ParameterType.Optional)
.Parameter("msg", ParameterType.Unparsed) .Parameter("msg", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.ManageMessages()) .AddCheck(SimpleCheckers.ManageMessages())
.Do(async e => { .Do(async e =>
{
var minutesStr = e.GetArg("minutes"); var minutesStr = e.GetArg("minutes");
var msg = e.GetArg("msg"); var msg = e.GetArg("msg");
// if both null, disable // if both null, disable
if (string.IsNullOrWhiteSpace(msg) && string.IsNullOrWhiteSpace(minutesStr)) { if (string.IsNullOrWhiteSpace(msg) && string.IsNullOrWhiteSpace(minutesStr))
{
await e.Channel.SendMessage("Repeating disabled"); await e.Channel.SendMessage("Repeating disabled");
Repeater rep; Repeater rep;
if (repeaters.TryGetValue(e.Server, out rep)) if (repeaters.TryGetValue(e.Server, out rep))
@ -55,14 +66,16 @@ namespace NadekoBot.Commands {
return; return;
} }
int minutes; int minutes;
if (!int.TryParse(minutesStr, out minutes) || minutes < 1 || minutes > 720) { if (!int.TryParse(minutesStr, out minutes) || minutes < 1 || minutes > 720)
{
await e.Channel.SendMessage("Invalid value"); await e.Channel.SendMessage("Invalid value");
return; return;
} }
var repeater = repeaters.GetOrAdd( var repeater = repeaters.GetOrAdd(
e.Server, e.Server,
s => new Repeater { s => new Repeater
{
Interval = minutes * 60 * 1000, Interval = minutes * 60 * 1000,
RepeatingChannel = e.Channel, RepeatingChannel = e.Channel,
RepeatingChannelId = e.Channel.Id, RepeatingChannelId = e.Channel.Id,

View File

@ -1,15 +1,17 @@
using System; using Discord.Commands;
using NadekoBot.Classes.JSONModels;
using NadekoBot.Commands;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord.Commands;
using System.Timers; using System.Timers;
using NadekoBot.Classes.JSONModels;
using NadekoBot.Modules;
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
internal class PlayingRotate : DiscordCommand { {
internal class PlayingRotate : DiscordCommand
{
private static readonly Timer timer = new Timer(12000); private static readonly Timer timer = new Timer(12000);
public static Dictionary<string, Func<string>> PlayingPlaceholders { get; } = public static Dictionary<string, Func<string>> PlayingPlaceholders { get; } =
@ -34,16 +36,21 @@ namespace NadekoBot.Commands {
private readonly object playingPlaceholderLock = new object(); private readonly object playingPlaceholderLock = new object();
public PlayingRotate(DiscordModule module) : base(module) { public PlayingRotate(DiscordModule module) : base(module)
{
var i = -1; var i = -1;
timer.Elapsed += (s, e) => { timer.Elapsed += (s, e) =>
try { {
try
{
i++; i++;
var status = ""; var status = "";
lock (playingPlaceholderLock) { lock (playingPlaceholderLock)
{
if (PlayingPlaceholders.Count == 0) if (PlayingPlaceholders.Count == 0)
return; return;
if (i >= PlayingPlaceholders.Count) { if (i >= PlayingPlaceholders.Count)
{
i = -1; i = -1;
return; return;
} }
@ -54,14 +61,17 @@ namespace NadekoBot.Commands {
if (string.IsNullOrWhiteSpace(status)) if (string.IsNullOrWhiteSpace(status))
return; return;
Task.Run(() => { NadekoBot.Client.SetGame(status); }); Task.Run(() => { NadekoBot.Client.SetGame(status); });
} catch { } }
catch { }
}; };
timer.Enabled = NadekoBot.Config.IsRotatingStatus; timer.Enabled = NadekoBot.Config.IsRotatingStatus;
} }
public Func<CommandEventArgs, Task> DoFunc() => async e => { public Func<CommandEventArgs, Task> DoFunc() => async e =>
lock (playingPlaceholderLock) { {
lock (playingPlaceholderLock)
{
if (timer.Enabled) if (timer.Enabled)
timer.Stop(); timer.Stop();
else else
@ -72,7 +82,8 @@ namespace NadekoBot.Commands {
await e.Channel.SendMessage($"❗`Rotating playing status has been {(timer.Enabled ? "enabled" : "disabled")}.`"); await e.Channel.SendMessage($"❗`Rotating playing status has been {(timer.Enabled ? "enabled" : "disabled")}.`");
}; };
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "rotateplaying") cgb.CreateCommand(Module.Prefix + "rotateplaying")
.Alias(Module.Prefix + "ropl") .Alias(Module.Prefix + "ropl")
.Description("Toggles rotation of playing status of the dynamic strings you specified earlier.") .Description("Toggles rotation of playing status of the dynamic strings you specified earlier.")
@ -85,11 +96,13 @@ namespace NadekoBot.Commands {
"Supported placeholders: " + string.Join(", ", PlayingPlaceholders.Keys)) "Supported placeholders: " + string.Join(", ", PlayingPlaceholders.Keys))
.Parameter("text", ParameterType.Unparsed) .Parameter("text", ParameterType.Unparsed)
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly()) .AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Do(async e => { .Do(async e =>
{
var arg = e.GetArg("text"); var arg = e.GetArg("text");
if (string.IsNullOrWhiteSpace(arg)) if (string.IsNullOrWhiteSpace(arg))
return; return;
lock (playingPlaceholderLock) { lock (playingPlaceholderLock)
{
NadekoBot.Config.RotatingStatuses.Add(arg); NadekoBot.Config.RotatingStatuses.Add(arg);
ConfigHandler.SaveConfig(); ConfigHandler.SaveConfig();
} }
@ -100,12 +113,14 @@ namespace NadekoBot.Commands {
.Alias(Module.Prefix + "lipl") .Alias(Module.Prefix + "lipl")
.Description("Lists all playing statuses with their corresponding number.") .Description("Lists all playing statuses with their corresponding number.")
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly()) .AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Do(async e => { .Do(async e =>
{
if (NadekoBot.Config.RotatingStatuses.Count == 0) if (NadekoBot.Config.RotatingStatuses.Count == 0)
await e.Channel.SendMessage("`There are no playing strings. " + await e.Channel.SendMessage("`There are no playing strings. " +
"Add some with .addplaying [text] command.`"); "Add some with .addplaying [text] command.`");
var sb = new StringBuilder(); var sb = new StringBuilder();
for (var i = 0; i < NadekoBot.Config.RotatingStatuses.Count; i++) { for (var i = 0; i < NadekoBot.Config.RotatingStatuses.Count; i++)
{
sb.AppendLine($"`{i + 1}.` {NadekoBot.Config.RotatingStatuses[i]}"); sb.AppendLine($"`{i + 1}.` {NadekoBot.Config.RotatingStatuses[i]}");
} }
await e.Channel.SendMessage(sb.ToString()); await e.Channel.SendMessage(sb.ToString());
@ -116,11 +131,13 @@ namespace NadekoBot.Commands {
.Description("Removes a playing string on a given number.") .Description("Removes a playing string on a given number.")
.Parameter("number", ParameterType.Required) .Parameter("number", ParameterType.Required)
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly()) .AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Do(async e => { .Do(async e =>
{
var arg = e.GetArg("number"); var arg = e.GetArg("number");
int num; int num;
string str; string str;
lock (playingPlaceholderLock) { lock (playingPlaceholderLock)
{
if (!int.TryParse(arg.Trim(), out num) || num <= 0 || num > NadekoBot.Config.RotatingStatuses.Count) if (!int.TryParse(arg.Trim(), out num) || num <= 0 || num > NadekoBot.Config.RotatingStatuses.Count)
return; return;
str = NadekoBot.Config.RotatingStatuses[num - 1]; str = NadekoBot.Config.RotatingStatuses[num - 1];

View File

@ -1,28 +1,36 @@
using System;
using System.Collections.Concurrent;
using Discord.Commands; using Discord.Commands;
using NadekoBot.Classes.Permissions; using NadekoBot.Classes.Permissions;
using NadekoBot.Modules; using NadekoBot.Commands;
using System;
using System.Collections.Concurrent;
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
internal class RatelimitCommand : DiscordCommand { {
internal class RatelimitCommand : DiscordCommand
{
public static ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, DateTime>> RatelimitingChannels = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, DateTime>>(); public static ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, DateTime>> RatelimitingChannels = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, DateTime>>();
private static readonly TimeSpan ratelimitTime = new TimeSpan(0, 0, 0, 5); private static readonly TimeSpan ratelimitTime = new TimeSpan(0, 0, 0, 5);
public RatelimitCommand(DiscordModule module) : base(module) { public RatelimitCommand(DiscordModule module) : base(module)
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;
ConcurrentDictionary<ulong, DateTime> userTimePair; ConcurrentDictionary<ulong, DateTime> userTimePair;
if (!RatelimitingChannels.TryGetValue(e.Channel.Id, out userTimePair)) return; if (!RatelimitingChannels.TryGetValue(e.Channel.Id, out userTimePair)) return;
DateTime lastMessageTime; DateTime lastMessageTime;
if (userTimePair.TryGetValue(e.User.Id, out lastMessageTime)) { if (userTimePair.TryGetValue(e.User.Id, out lastMessageTime))
if (DateTime.Now - lastMessageTime < ratelimitTime) { {
try { if (DateTime.Now - lastMessageTime < ratelimitTime)
{
try
{
await e.Message.Delete(); await e.Message.Delete();
} catch { } }
catch { }
return; return;
} }
} }
@ -30,23 +38,27 @@ namespace NadekoBot.Commands {
}; };
} }
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "slowmode") cgb.CreateCommand(Module.Prefix + "slowmode")
.Description("Toggles slow mode. When ON, users will be able to send only 1 message every 5 seconds.") .Description("Toggles slow mode. When ON, users will be able to send only 1 message every 5 seconds.")
.Parameter("minutes", ParameterType.Optional) .Parameter("minutes", ParameterType.Optional)
.AddCheck(SimpleCheckers.ManageMessages()) .AddCheck(SimpleCheckers.ManageMessages())
.Do(async e => { .Do(async e =>
{
//var minutesStr = e.GetArg("minutes"); //var minutesStr = e.GetArg("minutes");
//if (string.IsNullOrWhiteSpace(minutesStr)) { //if (string.IsNullOrWhiteSpace(minutesStr)) {
// RatelimitingChannels.Remove(e.Channel.Id); // RatelimitingChannels.Remove(e.Channel.Id);
// return; // return;
//} //}
ConcurrentDictionary<ulong, DateTime> throwaway; ConcurrentDictionary<ulong, DateTime> throwaway;
if (RatelimitingChannels.TryRemove(e.Channel.Id, out throwaway)) { if (RatelimitingChannels.TryRemove(e.Channel.Id, out throwaway))
{
await e.Channel.SendMessage("Slow mode disabled."); await e.Channel.SendMessage("Slow mode disabled.");
return; return;
} }
if (RatelimitingChannels.TryAdd(e.Channel.Id, new ConcurrentDictionary<ulong, DateTime>())) { if (RatelimitingChannels.TryAdd(e.Channel.Id, new ConcurrentDictionary<ulong, DateTime>()))
{
await e.Channel.SendMessage("Slow mode initiated. " + await e.Channel.SendMessage("Slow mode initiated. " +
"Users can't send more than 1 message every 5 seconds."); "Users can't send more than 1 message every 5 seconds.");
} }

View File

@ -0,0 +1,166 @@
using Discord;
using Discord.Commands;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels;
using NadekoBot.Commands;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Timers;
namespace NadekoBot.Modules.Administration.Commands
{
class Remind : DiscordCommand
{
Regex regex = new Regex(@"^(?:(?<months>\d)mo)?(?:(?<weeks>\d)w)?(?:(?<days>\d{1,2})d)?(?:(?<hours>\d{1,2})h)?(?:(?<minutes>\d{1,2})m)?$",
RegexOptions.Compiled | RegexOptions.Multiline);
List<Timer> reminders = new List<Timer>();
public Remind(DiscordModule module) : base(module)
{
var remList = DbHandler.Instance.GetAllRows<Reminder>();
Console.WriteLine(string.Join("\n-", remList.Select(r => r.When.ToString())));
reminders = remList.Select(StartNewReminder).ToList();
}
private Timer StartNewReminder(Reminder r)
{
var now = DateTime.Now;
var twoMins = new TimeSpan(0, 2, 0);
TimeSpan time = (r.When - now) < twoMins
? twoMins //if the time is less than 2 minutes,
: r.When - now; //it will send the message 2 minutes after start
//To account for high bot startup times
var t = new Timer(time.TotalMilliseconds);
t.Elapsed += async (s, e) =>
{
try
{
Channel ch;
if (r.IsPrivate)
{
ch = NadekoBot.Client.PrivateChannels.FirstOrDefault(c => (long)c.Id == r.ChannelId);
if (ch == null)
ch = await NadekoBot.Client.CreatePrivateChannel((ulong)r.ChannelId);
}
else
ch = NadekoBot.Client.GetServer((ulong)r.ServerId)?.GetChannel((ulong)r.ChannelId);
if (ch == null)
return;
await ch.SendMessage($"❗⏰**I've been told to remind you to '{r.Message}' now by <@{r.UserId}>.**⏰❗");
}
catch (Exception ex)
{
Console.WriteLine($"Timer error! {ex}");
}
finally
{
DbHandler.Instance.Delete<Reminder>(r.Id);
t.Stop();
t.Dispose();
}
};
t.Start();
return t;
}
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "remind")
.Parameter("meorchannel", ParameterType.Required)
.Parameter("time", ParameterType.Required)
.Parameter("message", ParameterType.Unparsed)
.Do(async e =>
{
var meorchStr = e.GetArg("meorchannel").ToUpperInvariant();
Channel ch;
bool isPrivate = false;
if (meorchStr == "ME")
{
isPrivate = true;
ch = await e.User.CreatePMChannel();
}
else if (meorchStr == "HERE")
{
ch = e.Channel;
}
else {
ch = e.Server.FindChannels(meorchStr).FirstOrDefault();
}
if (ch == null)
{
await e.Channel.SendMessage($"{e.User.Mention} Something went wrong (channel cannot be found) ;(");
return;
}
var timeStr = e.GetArg("time");
var m = regex.Match(timeStr);
if (m.Length == 0)
{
await e.Channel.SendMessage("Not a valid time format blablabla");
return;
}
string output = "";
var namesAndValues = new Dictionary<string, int>();
foreach (var groupName in regex.GetGroupNames())
{
if (groupName == "0") continue;
int value = 0;
int.TryParse(m.Groups[groupName].Value, out value);
if (string.IsNullOrEmpty(m.Groups[groupName].Value))
{
namesAndValues[groupName] = 0;
continue;
}
else if (value < 1 ||
(groupName == "months" && value > 1) ||
(groupName == "weeks" && value > 4) ||
(groupName == "days" && value >= 7) ||
(groupName == "hours" && value > 23) ||
(groupName == "minutes" && value > 59))
{
await e.Channel.SendMessage($"Invalid {groupName} value.");
return;
}
else
namesAndValues[groupName] = value;
output += m.Groups[groupName].Value + " " + groupName + " ";
}
var time = DateTime.Now + new TimeSpan(30 * namesAndValues["months"] +
7 * namesAndValues["weeks"] +
namesAndValues["days"],
namesAndValues["hours"],
namesAndValues["minutes"],
0);
var rem = new Reminder
{
ChannelId = (long)ch.Id,
IsPrivate = isPrivate,
When = time,
Message = e.GetArg("message"),
UserId = (long)e.User.Id,
ServerId = (long)e.Server.Id
};
DbHandler.Instance.InsertData(rem);
reminders.Add(StartNewReminder(rem));
await e.Channel.SendMessage($"⏰ I will remind \"{ch.Name}\" to \"{e.GetArg("message").ToString()}\" in {output}. ({time:d.M.yyyy.} at {time:HH:m})");
});
}
}
}

View File

@ -1,29 +1,35 @@
using System.Collections.Generic; using Discord.Commands;
using System.Linq;
using System.Text;
using Discord.Commands;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Classes.Permissions; using NadekoBot.Classes.Permissions;
using NadekoBot.Modules; using NadekoBot.Commands;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
internal class SelfAssignedRolesCommand : DiscordCommand { {
internal class SelfAssignedRolesCommand : DiscordCommand
{
public SelfAssignedRolesCommand(DiscordModule module) : base(module) { } public SelfAssignedRolesCommand(DiscordModule module) : base(module) { }
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(".asar") cgb.CreateCommand(".asar")
.Description("Adds a role, or list of roles separated by whitespace" + .Description("Adds a role, or list of roles separated by whitespace" +
"(use quotations for multiword roles) to the list of self-assignable roles.\n**Usage**: .asar Gamer") "(use quotations for multiword roles) to the list of self-assignable roles.\n**Usage**: .asar Gamer")
.Parameter("roles", ParameterType.Multiple) .Parameter("roles", ParameterType.Multiple)
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => { .Do(async e =>
{
var config = SpecificConfigurations.Default.Of(e.Server.Id); var config = SpecificConfigurations.Default.Of(e.Server.Id);
var msg = new StringBuilder(); var msg = new StringBuilder();
foreach (var arg in e.Args) { foreach (var arg in e.Args)
{
var role = e.Server.FindRoles(arg.Trim()).FirstOrDefault(); var role = e.Server.FindRoles(arg.Trim()).FirstOrDefault();
if (role == null) if (role == null)
msg.AppendLine($":anger:Role **{arg}** not found."); msg.AppendLine($":anger:Role **{arg}** not found.");
else { else {
if (config.ListOfSelfAssignableRoles.Contains(role.Id)) { if (config.ListOfSelfAssignableRoles.Contains(role.Id))
{
msg.AppendLine($":anger:Role **{role.Name}** is already in the list."); msg.AppendLine($":anger:Role **{role.Name}** is already in the list.");
continue; continue;
} }
@ -38,17 +44,20 @@ namespace NadekoBot.Commands {
.Description("Removes a specified role from the list of self-assignable roles.") .Description("Removes a specified role from the list of self-assignable roles.")
.Parameter("role", ParameterType.Unparsed) .Parameter("role", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => { .Do(async e =>
{
var roleName = e.GetArg("role")?.Trim(); var roleName = e.GetArg("role")?.Trim();
if (string.IsNullOrWhiteSpace(roleName)) if (string.IsNullOrWhiteSpace(roleName))
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(":anger:That role does not exist."); await e.Channel.SendMessage(":anger:That role does not exist.");
return; return;
} }
var config = SpecificConfigurations.Default.Of(e.Server.Id); var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (!config.ListOfSelfAssignableRoles.Contains(role.Id)) { if (!config.ListOfSelfAssignableRoles.Contains(role.Id))
{
await e.Channel.SendMessage(":anger:That role is not self-assignable."); await e.Channel.SendMessage(":anger:That role is not self-assignable.");
return; return;
} }
@ -59,20 +68,25 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(".lsar") cgb.CreateCommand(".lsar")
.Description("Lits all self-assignable roles.") .Description("Lits all self-assignable roles.")
.Parameter("roles", ParameterType.Multiple) .Parameter("roles", ParameterType.Multiple)
.Do(async e => { .Do(async e =>
{
var config = SpecificConfigurations.Default.Of(e.Server.Id); var config = SpecificConfigurations.Default.Of(e.Server.Id);
var msg = new StringBuilder($"There are `{config.ListOfSelfAssignableRoles.Count}` self assignable roles:\n"); var msg = new StringBuilder($"There are `{config.ListOfSelfAssignableRoles.Count}` self assignable roles:\n");
var toRemove = new HashSet<ulong>(); var toRemove = new HashSet<ulong>();
foreach (var roleId in config.ListOfSelfAssignableRoles) { foreach (var roleId in config.ListOfSelfAssignableRoles)
{
var role = e.Server.GetRole(roleId); var role = e.Server.GetRole(roleId);
if (role == null) { if (role == null)
{
msg.Append($"`{roleId} not found. Cleaned up.`, "); msg.Append($"`{roleId} not found. Cleaned up.`, ");
toRemove.Add(roleId); toRemove.Add(roleId);
} else { }
else {
msg.Append($"**{role.Name}**, "); msg.Append($"**{role.Name}**, ");
} }
} }
foreach (var id in toRemove) { foreach (var id in toRemove)
{
config.ListOfSelfAssignableRoles.Remove(id); config.ListOfSelfAssignableRoles.Remove(id);
} }
await e.Channel.SendMessage(msg.ToString()); await e.Channel.SendMessage(msg.ToString());
@ -83,21 +97,25 @@ namespace NadekoBot.Commands {
"Role must be on a list of self-assignable roles." + "Role must be on a list of self-assignable roles." +
"\n**Usage**: .iam Gamer") "\n**Usage**: .iam Gamer")
.Parameter("role", ParameterType.Unparsed) .Parameter("role", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
var roleName = e.GetArg("role")?.Trim(); var roleName = e.GetArg("role")?.Trim();
if (string.IsNullOrWhiteSpace(roleName)) if (string.IsNullOrWhiteSpace(roleName))
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(":anger:That role does not exist."); await e.Channel.SendMessage(":anger:That role does not exist.");
return; return;
} }
var config = SpecificConfigurations.Default.Of(e.Server.Id); var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (!config.ListOfSelfAssignableRoles.Contains(role.Id)) { if (!config.ListOfSelfAssignableRoles.Contains(role.Id))
{
await e.Channel.SendMessage(":anger:That role is not self-assignable."); await e.Channel.SendMessage(":anger:That role is not self-assignable.");
return; return;
} }
if (e.User.HasRole(role)) { if (e.User.HasRole(role))
{
await e.Channel.SendMessage($":anger:You already have {role.Name} role."); await e.Channel.SendMessage($":anger:You already have {role.Name} role.");
return; return;
} }
@ -111,21 +129,25 @@ namespace NadekoBot.Commands {
"Role must be on a list of self-assignable roles." + "Role must be on a list of self-assignable roles." +
"\n**Usage**: .iamn Gamer") "\n**Usage**: .iamn Gamer")
.Parameter("role", ParameterType.Unparsed) .Parameter("role", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
var roleName = e.GetArg("role")?.Trim(); var roleName = e.GetArg("role")?.Trim();
if (string.IsNullOrWhiteSpace(roleName)) if (string.IsNullOrWhiteSpace(roleName))
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(":anger:That role does not exist."); await e.Channel.SendMessage(":anger:That role does not exist.");
return; return;
} }
var config = SpecificConfigurations.Default.Of(e.Server.Id); var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (!config.ListOfSelfAssignableRoles.Contains(role.Id)) { if (!config.ListOfSelfAssignableRoles.Contains(role.Id))
{
await e.Channel.SendMessage(":anger:That role is not self-assignable."); await e.Channel.SendMessage(":anger:That role is not self-assignable.");
return; return;
} }
if (!e.User.HasRole(role)) { if (!e.User.HasRole(role))
{
await e.Channel.SendMessage($":anger:You don't have {role.Name} role."); await e.Channel.SendMessage($":anger:You don't have {role.Name} role.");
return; return;
} }

View File

@ -1,12 +1,9 @@
using System; using Discord;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Discord.Commands; using Discord.Commands;
using System.Collections.Concurrent; using NadekoBot.Commands;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using Discord; using System.Collections.Concurrent;
using NadekoBot.Modules; using System.Linq;
/* Voltana's legacy /* Voltana's legacy
public class AsyncLazy<T> : Lazy<Task<T>> public class AsyncLazy<T> : Lazy<Task<T>>
@ -21,14 +18,17 @@ public class AsyncLazy<T> : Lazy<Task<T>>
} }
*/ */
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
internal class ServerGreetCommand : DiscordCommand { {
internal class ServerGreetCommand : DiscordCommand
{
public static ConcurrentDictionary<ulong, AnnounceControls> AnnouncementsDictionary; public static ConcurrentDictionary<ulong, AnnounceControls> AnnouncementsDictionary;
public static long Greeted = 0; public static long Greeted = 0;
public ServerGreetCommand(DiscordModule module) : base(module) { public ServerGreetCommand(DiscordModule module) : base(module)
{
AnnouncementsDictionary = new ConcurrentDictionary<ulong, AnnounceControls>(); AnnouncementsDictionary = new ConcurrentDictionary<ulong, AnnounceControls>();
NadekoBot.Client.UserJoined += UserJoined; NadekoBot.Client.UserJoined += UserJoined;
@ -41,8 +41,10 @@ namespace NadekoBot.Commands {
AnnouncementsDictionary.TryAdd((ulong)obj.ServerId, new AnnounceControls(obj)); AnnouncementsDictionary.TryAdd((ulong)obj.ServerId, new AnnounceControls(obj));
} }
private async void UserLeft(object sender, UserEventArgs e) { private async void UserLeft(object sender, UserEventArgs e)
try { {
try
{
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id) || if (!AnnouncementsDictionary.ContainsKey(e.Server.Id) ||
!AnnouncementsDictionary[e.Server.Id].Bye) return; !AnnouncementsDictionary[e.Server.Id].Bye) return;
@ -52,9 +54,11 @@ namespace NadekoBot.Commands {
if (string.IsNullOrEmpty(msg)) if (string.IsNullOrEmpty(msg))
return; return;
if (controls.ByePM) { if (controls.ByePM)
{
Greeted++; Greeted++;
try { try
{
await e.User.SendMessage($"`Farewell Message From {e.Server?.Name}`\n" + msg); await e.User.SendMessage($"`Farewell Message From {e.Server?.Name}`\n" + msg);
} }
catch { } catch { }
@ -68,8 +72,10 @@ namespace NadekoBot.Commands {
catch { } catch { }
} }
private async void UserJoined(object sender, Discord.UserEventArgs e) { private async void UserJoined(object sender, Discord.UserEventArgs e)
try { {
try
{
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id) || if (!AnnouncementsDictionary.ContainsKey(e.Server.Id) ||
!AnnouncementsDictionary[e.Server.Id].Greet) return; !AnnouncementsDictionary[e.Server.Id].Greet) return;
@ -79,7 +85,8 @@ namespace NadekoBot.Commands {
var msg = controls.GreetText.Replace("%user%", e.User.Mention).Trim(); var msg = controls.GreetText.Replace("%user%", e.User.Mention).Trim();
if (string.IsNullOrEmpty(msg)) if (string.IsNullOrEmpty(msg))
return; return;
if (controls.GreetPM) { if (controls.GreetPM)
{
Greeted++; Greeted++;
await e.User.SendMessage($"`Welcome Message From {e.Server.Name}`\n" + msg); await e.User.SendMessage($"`Welcome Message From {e.Server.Name}`\n" + msg);
} }
@ -92,7 +99,8 @@ namespace NadekoBot.Commands {
catch { } catch { }
} }
public class AnnounceControls { public class AnnounceControls
{
private Classes._DataModels.Announcement _model { get; } private Classes._DataModels.Announcement _model { get; }
public bool Greet { public bool Greet {
@ -139,28 +147,36 @@ namespace NadekoBot.Commands {
set { _model.ServerId = (long)value; } set { _model.ServerId = (long)value; }
} }
public AnnounceControls(Classes._DataModels.Announcement model) { public AnnounceControls(Classes._DataModels.Announcement model)
{
this._model = model; this._model = model;
} }
public AnnounceControls(ulong serverId) { public AnnounceControls(ulong serverId)
{
this._model = new Classes._DataModels.Announcement(); this._model = new Classes._DataModels.Announcement();
ServerId = serverId; ServerId = serverId;
} }
internal bool ToggleBye(ulong id) { internal bool ToggleBye(ulong id)
if (Bye) { {
if (Bye)
{
return Bye = false; return Bye = false;
} else { }
else {
ByeChannel = id; ByeChannel = id;
return Bye = true; return Bye = true;
} }
} }
internal bool ToggleGreet(ulong id) { internal bool ToggleGreet(ulong id)
if (Greet) { {
if (Greet)
{
return Greet = false; return Greet = false;
} else { }
else {
GreetChannel = id; GreetChannel = id;
return Greet = true; return Greet = true;
} }
@ -168,16 +184,19 @@ namespace NadekoBot.Commands {
internal bool ToggleGreetPM() => GreetPM = !GreetPM; internal bool ToggleGreetPM() => GreetPM = !GreetPM;
internal bool ToggleByePM() => ByePM = !ByePM; internal bool ToggleByePM() => ByePM = !ByePM;
private void Save() { private void Save()
{
Classes.DbHandler.Instance.Save(_model); Classes.DbHandler.Instance.Save(_model);
} }
} }
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "greet") cgb.CreateCommand(Module.Prefix + "greet")
.Description("Enables or Disables anouncements on the current channel when someone joins the server.") .Description("Enables or Disables anouncements on the current channel when someone joins the server.")
.Do(async e => { .Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return; if (!e.User.ServerPermissions.ManageServer) return;
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) if (!AnnouncementsDictionary.ContainsKey(e.Server.Id))
AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
@ -193,7 +212,8 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(Module.Prefix + "greetmsg") cgb.CreateCommand(Module.Prefix + "greetmsg")
.Description("Sets a new announce message. Type %user% if you want to mention the new member.\n**Usage**: .greetmsg Welcome to the server, %user%.") .Description("Sets a new announce message. Type %user% if you want to mention the new member.\n**Usage**: .greetmsg Welcome to the server, %user%.")
.Parameter("msg", ParameterType.Unparsed) .Parameter("msg", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return; if (!e.User.ServerPermissions.ManageServer) return;
if (e.GetArg("msg") == null) return; if (e.GetArg("msg") == null) return;
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) if (!AnnouncementsDictionary.ContainsKey(e.Server.Id))
@ -207,7 +227,8 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(Module.Prefix + "bye") cgb.CreateCommand(Module.Prefix + "bye")
.Description("Enables or Disables anouncements on the current channel when someone leaves the server.") .Description("Enables or Disables anouncements on the current channel when someone leaves the server.")
.Do(async e => { .Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return; if (!e.User.ServerPermissions.ManageServer) return;
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) if (!AnnouncementsDictionary.ContainsKey(e.Server.Id))
AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
@ -223,7 +244,8 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(Module.Prefix + "byemsg") cgb.CreateCommand(Module.Prefix + "byemsg")
.Description("Sets a new announce leave message. Type %user% if you want to mention the new member.\n**Usage**: .byemsg %user% has left the server.") .Description("Sets a new announce leave message. Type %user% if you want to mention the new member.\n**Usage**: .byemsg %user% has left the server.")
.Parameter("msg", ParameterType.Unparsed) .Parameter("msg", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return; if (!e.User.ServerPermissions.ManageServer) return;
if (e.GetArg("msg") == null) return; if (e.GetArg("msg") == null) return;
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) if (!AnnouncementsDictionary.ContainsKey(e.Server.Id))
@ -237,7 +259,8 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(Module.Prefix + "byepm") cgb.CreateCommand(Module.Prefix + "byepm")
.Description("Toggles whether the good bye messages will be sent in a PM or in the text channel.") .Description("Toggles whether the good bye messages will be sent in a PM or in the text channel.")
.Do(async e => { .Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return; if (!e.User.ServerPermissions.ManageServer) return;
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) if (!AnnouncementsDictionary.ContainsKey(e.Server.Id))
AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
@ -253,7 +276,8 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(Module.Prefix + "greetpm") cgb.CreateCommand(Module.Prefix + "greetpm")
.Description("Toggles whether the greet messages will be sent in a PM or in the text channel.") .Description("Toggles whether the greet messages will be sent in a PM or in the text channel.")
.Do(async e => { .Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return; if (!e.User.ServerPermissions.ManageServer) return;
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id)) if (!AnnouncementsDictionary.ContainsKey(e.Server.Id))
AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id)); AnnouncementsDictionary.TryAdd(e.Server.Id, new AnnounceControls(e.Server.Id));

View File

@ -1,34 +1,40 @@
using System; using Discord;
using Discord.Commands;
using NadekoBot.Commands;
using System;
using System.Collections.Concurrent;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord.Commands;
using System.Collections.Concurrent;
using Discord;
using NadekoBot.Modules;
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
internal class VoiceNotificationCommand : DiscordCommand { {
internal class VoiceNotificationCommand : DiscordCommand
{
//voicechannel/text channel //voicechannel/text channel
private readonly ConcurrentDictionary<Channel, Channel> subscribers = new ConcurrentDictionary<Channel, Channel>(); private readonly ConcurrentDictionary<Channel, Channel> subscribers = new ConcurrentDictionary<Channel, Channel>();
public Func<CommandEventArgs, Task> DoFunc() => async e => { public Func<CommandEventArgs, Task> DoFunc() => async e =>
{
var arg = e.GetArg("voice_name"); var arg = e.GetArg("voice_name");
if (string.IsNullOrWhiteSpace("voice_name")) if (string.IsNullOrWhiteSpace("voice_name"))
return; return;
var voiceChannel = e.Server.FindChannels(arg, ChannelType.Voice).FirstOrDefault(); var voiceChannel = e.Server.FindChannels(arg, ChannelType.Voice).FirstOrDefault();
if (voiceChannel == null) if (voiceChannel == null)
return; return;
if (subscribers.ContainsKey(voiceChannel)) { if (subscribers.ContainsKey(voiceChannel))
{
await e.Channel.SendMessage("`Voice channel notifications disabled.`"); await e.Channel.SendMessage("`Voice channel notifications disabled.`");
return; return;
} }
if (subscribers.TryAdd(voiceChannel, e.Channel)) { if (subscribers.TryAdd(voiceChannel, e.Channel))
{
await e.Channel.SendMessage("`Voice channel notifications enabled.`"); await e.Channel.SendMessage("`Voice channel notifications enabled.`");
} }
}; };
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "voicenotif") cgb.CreateCommand(Module.Prefix + "voicenotif")
.Description("Enables notifications on who joined/left the voice channel.\n**Usage**:.voicenotif Karaoke club") .Description("Enables notifications on who joined/left the voice channel.\n**Usage**:.voicenotif Karaoke club")
.Parameter("voice_name", ParameterType.Unparsed) .Parameter("voice_name", ParameterType.Unparsed)

View File

@ -1,20 +1,24 @@
using System; using Discord;
using System.Linq;
using System.Runtime.CompilerServices;
using Discord;
using Discord.Commands; using Discord.Commands;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Classes.Permissions; using NadekoBot.Classes.Permissions;
using NadekoBot.Modules; using NadekoBot.Commands;
using System;
using System.Linq;
using ChPermOverride = Discord.ChannelPermissionOverrides; using ChPermOverride = Discord.ChannelPermissionOverrides;
namespace NadekoBot.Commands { namespace NadekoBot.Modules.Administration.Commands
internal class VoicePlusTextCommand : DiscordCommand { {
internal class VoicePlusTextCommand : DiscordCommand
{
public VoicePlusTextCommand(DiscordModule module) : base(module) { public VoicePlusTextCommand(DiscordModule module) : base(module)
{
// changing servers may cause bugs // changing servers may cause bugs
NadekoBot.Client.UserUpdated += async (sender, e) => { NadekoBot.Client.UserUpdated += async (sender, e) =>
try { {
try
{
if (e.Server == null) if (e.Server == null)
return; return;
var config = SpecificConfigurations.Default.Of(e.Server.Id); var config = SpecificConfigurations.Default.Of(e.Server.Id);
@ -24,20 +28,24 @@ namespace NadekoBot.Commands {
var serverPerms = e.Server.GetUser(NadekoBot.Client.CurrentUser.Id)?.ServerPermissions; var serverPerms = e.Server.GetUser(NadekoBot.Client.CurrentUser.Id)?.ServerPermissions;
if (serverPerms == null) if (serverPerms == null)
return; return;
if (!serverPerms.Value.ManageChannels || !serverPerms.Value.ManageRoles) { if (!serverPerms.Value.ManageChannels || !serverPerms.Value.ManageRoles)
{
try { try
{
await e.Server.Owner.SendMessage( await e.Server.Owner.SendMessage(
"I don't have manage server and/or Manage Channels permission," + "I don't have manage server and/or Manage Channels permission," +
$" so I cannot run voice+text on **{e.Server.Name}** server."); $" so I cannot run voice+text on **{e.Server.Name}** server.");
} catch { } // meh }
catch { } // meh
config.VoicePlusTextEnabled = false; config.VoicePlusTextEnabled = false;
return; return;
} }
var beforeVch = e.Before.VoiceChannel; var beforeVch = e.Before.VoiceChannel;
if (beforeVch != null) { if (beforeVch != null)
{
var textChannel = var textChannel =
e.Server.FindChannels(GetChannelName(beforeVch.Name), ChannelType.Text).FirstOrDefault(); e.Server.FindChannels(GetChannelName(beforeVch.Name), ChannelType.Text).FirstOrDefault();
if (textChannel != null) if (textChannel != null)
@ -46,12 +54,14 @@ namespace NadekoBot.Commands {
sendMessages: PermValue.Deny)); sendMessages: PermValue.Deny));
} }
var afterVch = e.After.VoiceChannel; var afterVch = e.After.VoiceChannel;
if (afterVch != null) { if (afterVch != null)
{
var textChannel = e.Server.FindChannels( var textChannel = e.Server.FindChannels(
GetChannelName(afterVch.Name), GetChannelName(afterVch.Name),
ChannelType.Text) ChannelType.Text)
.FirstOrDefault(); .FirstOrDefault();
if (textChannel == null) { if (textChannel == null)
{
textChannel = (await e.Server.CreateChannel(GetChannelName(afterVch.Name), ChannelType.Text)); textChannel = (await e.Server.CreateChannel(GetChannelName(afterVch.Name), ChannelType.Text));
await textChannel.AddPermissionsRule(e.Server.EveryoneRole, await textChannel.AddPermissionsRule(e.Server.EveryoneRole,
new ChPermOverride(readMessages: PermValue.Deny, new ChPermOverride(readMessages: PermValue.Deny,
@ -61,7 +71,9 @@ namespace NadekoBot.Commands {
new ChPermOverride(readMessages: PermValue.Allow, new ChPermOverride(readMessages: PermValue.Allow,
sendMessages: PermValue.Allow)); sendMessages: PermValue.Allow));
} }
} catch (Exception ex) { }
catch (Exception ex)
{
Console.WriteLine(ex); Console.WriteLine(ex);
} }
}; };
@ -70,22 +82,30 @@ namespace NadekoBot.Commands {
private string GetChannelName(string voiceName) => private string GetChannelName(string voiceName) =>
voiceName.Replace(" ", "-").Trim() + "-voice"; voiceName.Replace(" ", "-").Trim() + "-voice";
internal override void Init(CommandGroupBuilder cgb) { internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "v+t") cgb.CreateCommand(Module.Prefix + "v+t")
.Alias(Module.Prefix + "voice+text") .Alias(Module.Prefix + "voice+text")
.Description("Creates a text channel for each voice channel only users in that voice channel can see." + .Description("Creates a text channel for each voice channel only users in that voice channel can see." +
"If you are server owner, keep in mind you will see them all the time regardless.") "If you are server owner, keep in mind you will see them all the time regardless.")
.AddCheck(SimpleCheckers.ManageChannels()) .AddCheck(SimpleCheckers.ManageChannels())
.AddCheck(SimpleCheckers.CanManageRoles) .AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => { .Do(async e =>
try { {
try
{
var config = SpecificConfigurations.Default.Of(e.Server.Id); var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (config.VoicePlusTextEnabled == true) { if (config.VoicePlusTextEnabled == true)
{
config.VoicePlusTextEnabled = false; config.VoicePlusTextEnabled = false;
foreach (var textChannel in e.Server.TextChannels.Where(c => c.Name.EndsWith("-voice"))) { foreach (var textChannel in e.Server.TextChannels.Where(c => c.Name.EndsWith("-voice")))
try { {
try
{
await textChannel.Delete(); await textChannel.Delete();
} catch { }
catch
{
await await
e.Channel.SendMessage( e.Channel.SendMessage(
":anger: Error: Most likely i don't have permissions to do this."); ":anger: Error: Most likely i don't have permissions to do this.");
@ -99,7 +119,9 @@ namespace NadekoBot.Commands {
await e.Channel.SendMessage("Successfuly enabled voice + text feature. " + await e.Channel.SendMessage("Successfuly enabled voice + text feature. " +
"**Make sure the bot has manage roles and manage channels permissions**"); "**Make sure the bot has manage roles and manage channels permissions**");
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage(ex.ToString()); await e.Channel.SendMessage(ex.ToString());
} }
}); });

View File

@ -1,16 +1,14 @@
using System; using Discord.Commands;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using Discord.Modules; using Discord.Modules;
using NadekoBot.Classes.ClashOfClans; using NadekoBot.Classes.ClashOfClans;
using NadekoBot.Modules; using NadekoBot.Modules;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;
namespace NadekoBot.Commands { namespace NadekoBot.Commands
{
internal class ClashOfClans : DiscordModule internal class ClashOfClans : DiscordModule
{ {
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.ClashOfClans; public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.ClashOfClans;
@ -19,8 +17,10 @@ namespace NadekoBot.Commands {
private readonly object writeLock = new object(); private readonly object writeLock = new object();
public override void Install(ModuleManager manager) { public override void Install(ModuleManager manager)
manager.CreateCommands("", cgb => { {
manager.CreateCommands("", cgb =>
{
cgb.CreateCommand(Prefix + "createwar") cgb.CreateCommand(Prefix + "createwar")
.Alias(Prefix + "cw") .Alias(Prefix + "cw")
@ -28,38 +28,48 @@ namespace NadekoBot.Commands {
$"Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name.\n**Usage**:{Prefix}cw 15 The Enemy Clan") $"Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name.\n**Usage**:{Prefix}cw 15 The Enemy Clan")
.Parameter("size") .Parameter("size")
.Parameter("enemy_clan", ParameterType.Unparsed) .Parameter("enemy_clan", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
if (!e.User.ServerPermissions.ManageChannels) if (!e.User.ServerPermissions.ManageChannels)
return; return;
List<ClashWar> wars; List<ClashWar> wars;
if (!ClashWars.TryGetValue(e.Server.Id, out wars)) { if (!ClashWars.TryGetValue(e.Server.Id, out wars))
{
wars = new List<ClashWar>(); wars = new List<ClashWar>();
if (!ClashWars.TryAdd(e.Server.Id, wars)) if (!ClashWars.TryAdd(e.Server.Id, wars))
return; return;
} }
var enemyClan = e.GetArg("enemy_clan"); var enemyClan = e.GetArg("enemy_clan");
if (string.IsNullOrWhiteSpace(enemyClan)) { if (string.IsNullOrWhiteSpace(enemyClan))
{
return; return;
} }
int size; int size;
if (!int.TryParse(e.GetArg("size"), out size) || size < 10 || size > 50 || size % 5 != 0) { if (!int.TryParse(e.GetArg("size"), out size) || size < 10 || size > 50 || size % 5 != 0)
{
await e.Channel.SendMessage("💢🔰 Not a Valid war size"); await e.Channel.SendMessage("💢🔰 Not a Valid war size");
return; return;
} }
var cw = new ClashWar(enemyClan, size, e); var cw = new ClashWar(enemyClan, size, e);
//cw.Start(); //cw.Start();
wars.Add(cw); wars.Add(cw);
cw.OnUserTimeExpired += async (u) => { cw.OnUserTimeExpired += async (u) =>
try { {
try
{
await await
e.Channel.SendMessage( e.Channel.SendMessage(
$"❗🔰**Claim from @{u} for a war against {cw.ShortPrint()} has expired.**"); $"❗🔰**Claim from @{u} for a war against {cw.ShortPrint()} has expired.**");
} catch { } }
catch { }
}; };
cw.OnWarEnded += async () => { cw.OnWarEnded += async () =>
try { {
try
{
await e.Channel.SendMessage($"❗🔰**War against {cw.ShortPrint()} ended.**"); await e.Channel.SendMessage($"❗🔰**War against {cw.ShortPrint()} ended.**");
} catch { } }
catch { }
}; };
await e.Channel.SendMessage($"❗🔰**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**"); await e.Channel.SendMessage($"❗🔰**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**");
//war with the index X started. //war with the index X started.
@ -69,18 +79,23 @@ namespace NadekoBot.Commands {
.Alias(Prefix + "startwar") .Alias(Prefix + "startwar")
.Description("Starts a war with a given number.") .Description("Starts a war with a given number.")
.Parameter("number", ParameterType.Required) .Parameter("number", ParameterType.Required)
.Do(async e => { .Do(async e =>
{
var warsInfo = GetInfo(e); var warsInfo = GetInfo(e);
if (warsInfo == null) { if (warsInfo == null)
{
await e.Channel.SendMessage("💢🔰 **That war does not exist.**"); await e.Channel.SendMessage("💢🔰 **That war does not exist.**");
return; return;
} }
var war = warsInfo.Item1[warsInfo.Item2]; var war = warsInfo.Item1[warsInfo.Item2];
try { try
{
var startTask = war.Start(); var startTask = war.Start();
await e.Channel.SendMessage($"🔰**STARTED WAR AGAINST {war.ShortPrint()}**"); await e.Channel.SendMessage($"🔰**STARTED WAR AGAINST {war.ShortPrint()}**");
await startTask; await startTask;
} catch { }
catch
{
await e.Channel.SendMessage($"🔰**WAR AGAINST {war.ShortPrint()} IS ALREADY STARTED**"); await e.Channel.SendMessage($"🔰**WAR AGAINST {war.ShortPrint()} IS ALREADY STARTED**");
} }
}); });
@ -89,13 +104,16 @@ namespace NadekoBot.Commands {
.Alias(Prefix + "lw") .Alias(Prefix + "lw")
.Description($"Shows the active war claims by a number. Shows all wars in a short way if no number is specified.\n**Usage**: {Prefix}lw [war_number] or {Prefix}lw") .Description($"Shows the active war claims by a number. Shows all wars in a short way if no number is specified.\n**Usage**: {Prefix}lw [war_number] or {Prefix}lw")
.Parameter("number", ParameterType.Optional) .Parameter("number", ParameterType.Optional)
.Do(async e => { .Do(async e =>
{
// if number is null, print all wars in a short way // if number is null, print all wars in a short way
if (string.IsNullOrWhiteSpace(e.GetArg("number"))) { if (string.IsNullOrWhiteSpace(e.GetArg("number")))
{
//check if there are any wars //check if there are any wars
List<ClashWar> wars = null; List<ClashWar> wars = null;
ClashWars.TryGetValue(e.Server.Id, out wars); ClashWars.TryGetValue(e.Server.Id, out wars);
if (wars == null || wars.Count == 0) { if (wars == null || wars.Count == 0)
{
await e.Channel.SendMessage("🔰 **No active wars.**"); await e.Channel.SendMessage("🔰 **No active wars.**");
return; return;
} }
@ -103,7 +121,8 @@ namespace NadekoBot.Commands {
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine("🔰 **LIST OF ACTIVE WARS**"); sb.AppendLine("🔰 **LIST OF ACTIVE WARS**");
sb.AppendLine("**-------------------------**"); sb.AppendLine("**-------------------------**");
for (var i = 0; i < wars.Count; i++) { for (var i = 0; i < wars.Count; i++)
{
sb.AppendLine($"**#{i + 1}.** `Enemy:` **{wars[i].EnemyClan}**"); sb.AppendLine($"**#{i + 1}.** `Enemy:` **{wars[i].EnemyClan}**");
sb.AppendLine($"\t\t`Size:` **{wars[i].Size} v {wars[i].Size}**"); sb.AppendLine($"\t\t`Size:` **{wars[i].Size} v {wars[i].Size}**");
sb.AppendLine("**-------------------------**"); sb.AppendLine("**-------------------------**");
@ -113,7 +132,8 @@ namespace NadekoBot.Commands {
} }
//if number is not null, print the war needed //if number is not null, print the war needed
var warsInfo = GetInfo(e); var warsInfo = GetInfo(e);
if (warsInfo == null) { if (warsInfo == null)
{
await e.Channel.SendMessage("💢🔰 **That war does not exist.**"); await e.Channel.SendMessage("💢🔰 **That war does not exist.**");
return; return;
} }
@ -127,14 +147,17 @@ namespace NadekoBot.Commands {
.Parameter("number") .Parameter("number")
.Parameter("baseNumber") .Parameter("baseNumber")
.Parameter("other_name", ParameterType.Unparsed) .Parameter("other_name", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
var warsInfo = GetInfo(e); var warsInfo = GetInfo(e);
if (warsInfo == null || warsInfo.Item1.Count == 0) { if (warsInfo == null || warsInfo.Item1.Count == 0)
{
await e.Channel.SendMessage("💢🔰 **That war does not exist.**"); await e.Channel.SendMessage("💢🔰 **That war does not exist.**");
return; return;
} }
int baseNum; int baseNum;
if (!int.TryParse(e.GetArg("baseNumber"), out baseNum)) { if (!int.TryParse(e.GetArg("baseNumber"), out baseNum))
{
await e.Channel.SendMessage("💢🔰 **Invalid base number.**"); await e.Channel.SendMessage("💢🔰 **Invalid base number.**");
return; return;
} }
@ -142,11 +165,14 @@ namespace NadekoBot.Commands {
string.IsNullOrWhiteSpace(e.GetArg("other_name")) ? string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
e.User.Name : e.User.Name :
e.GetArg("other_name"); e.GetArg("other_name");
try { try
{
var war = warsInfo.Item1[warsInfo.Item2]; var war = warsInfo.Item1[warsInfo.Item2];
war.Call(usr, baseNum - 1); war.Call(usr, baseNum - 1);
await e.Channel.SendMessage($"🔰**{usr}** claimed a base #{baseNum} for a war against {war.ShortPrint()}"); await e.Channel.SendMessage($"🔰**{usr}** claimed a base #{baseNum} for a war against {war.ShortPrint()}");
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage($"💢🔰 {ex.Message}"); await e.Channel.SendMessage($"💢🔰 {ex.Message}");
} }
}); });
@ -156,9 +182,11 @@ namespace NadekoBot.Commands {
.Description($"Finish your claim if you destroyed a base. Optional second argument finishes for someone else.\n**Usage**: {Prefix}cf [war_number] [optional_other_name]") .Description($"Finish your claim if you destroyed a base. Optional second argument finishes for someone else.\n**Usage**: {Prefix}cf [war_number] [optional_other_name]")
.Parameter("number", ParameterType.Required) .Parameter("number", ParameterType.Required)
.Parameter("other_name", ParameterType.Unparsed) .Parameter("other_name", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
var warInfo = GetInfo(e); var warInfo = GetInfo(e);
if (warInfo == null || warInfo.Item1.Count == 0) { if (warInfo == null || warInfo.Item1.Count == 0)
{
await e.Channel.SendMessage("💢🔰 **That war does not exist.**"); await e.Channel.SendMessage("💢🔰 **That war does not exist.**");
return; return;
} }
@ -168,10 +196,13 @@ namespace NadekoBot.Commands {
e.GetArg("other_name"); e.GetArg("other_name");
var war = warInfo.Item1[warInfo.Item2]; var war = warInfo.Item1[warInfo.Item2];
try { try
{
var baseNum = war.FinishClaim(usr); var baseNum = war.FinishClaim(usr);
await e.Channel.SendMessage($"❗🔰{e.User.Mention} **DESTROYED** a base #{baseNum + 1} in a war against {war.ShortPrint()}"); await e.Channel.SendMessage($"❗🔰{e.User.Mention} **DESTROYED** a base #{baseNum + 1} in a war against {war.ShortPrint()}");
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage($"💢🔰 {ex.Message}"); await e.Channel.SendMessage($"💢🔰 {ex.Message}");
} }
}); });
@ -182,9 +213,11 @@ namespace NadekoBot.Commands {
.Description($"Removes your claim from a certain war. Optional second argument denotes a person in whos place to unclaim\n**Usage**: {Prefix}uc [war_number] [optional_other_name]") .Description($"Removes your claim from a certain war. Optional second argument denotes a person in whos place to unclaim\n**Usage**: {Prefix}uc [war_number] [optional_other_name]")
.Parameter("number", ParameterType.Required) .Parameter("number", ParameterType.Required)
.Parameter("other_name", ParameterType.Unparsed) .Parameter("other_name", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
var warsInfo = GetInfo(e); var warsInfo = GetInfo(e);
if (warsInfo == null || warsInfo.Item1.Count == 0) { if (warsInfo == null || warsInfo.Item1.Count == 0)
{
await e.Channel.SendMessage("💢🔰 **That war does not exist.**"); await e.Channel.SendMessage("💢🔰 **That war does not exist.**");
return; return;
} }
@ -192,11 +225,14 @@ namespace NadekoBot.Commands {
string.IsNullOrWhiteSpace(e.GetArg("other_name")) ? string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
e.User.Name : e.User.Name :
e.GetArg("other_name"); e.GetArg("other_name");
try { try
{
var war = warsInfo.Item1[warsInfo.Item2]; var war = warsInfo.Item1[warsInfo.Item2];
var baseNumber = war.Uncall(usr); var baseNumber = war.Uncall(usr);
await e.Channel.SendMessage($"🔰 @{usr} has **UNCLAIMED** a base #{baseNumber + 1} from a war against {war.ShortPrint()}"); await e.Channel.SendMessage($"🔰 @{usr} has **UNCLAIMED** a base #{baseNumber + 1} from a war against {war.ShortPrint()}");
} catch (Exception ex) { }
catch (Exception ex)
{
await e.Channel.SendMessage($"💢🔰 {ex.Message}"); await e.Channel.SendMessage($"💢🔰 {ex.Message}");
} }
}); });
@ -205,9 +241,11 @@ namespace NadekoBot.Commands {
.Alias(Prefix + "ew") .Alias(Prefix + "ew")
.Description($"Ends the war with a given index.\n**Usage**:{Prefix}ew [war_number]") .Description($"Ends the war with a given index.\n**Usage**:{Prefix}ew [war_number]")
.Parameter("number") .Parameter("number")
.Do(async e => { .Do(async e =>
{
var warsInfo = GetInfo(e); var warsInfo = GetInfo(e);
if (warsInfo == null) { if (warsInfo == null)
{
await e.Channel.SendMessage("💢🔰 That war does not exist."); await e.Channel.SendMessage("💢🔰 That war does not exist.");
return; return;
} }
@ -219,18 +257,21 @@ namespace NadekoBot.Commands {
}); });
} }
private static Tuple<List<ClashWar>, int> GetInfo(CommandEventArgs e) { private static Tuple<List<ClashWar>, int> GetInfo(CommandEventArgs e)
{
//check if there are any wars //check if there are any wars
List<ClashWar> wars = null; List<ClashWar> wars = null;
ClashWars.TryGetValue(e.Server.Id, out wars); ClashWars.TryGetValue(e.Server.Id, out wars);
if (wars == null || wars.Count == 0) { if (wars == null || wars.Count == 0)
{
return null; return null;
} }
// get the number of the war // get the number of the war
int num; int num;
if (string.IsNullOrWhiteSpace(e.GetArg("number"))) if (string.IsNullOrWhiteSpace(e.GetArg("number")))
num = 0; num = 0;
else if (!int.TryParse(e.GetArg("number"), out num) || num > wars.Count) { else if (!int.TryParse(e.GetArg("number"), out num) || num > wars.Count)
{
return null; return null;
} }
num -= 1; num -= 1;

View File

@ -159,6 +159,7 @@ namespace NadekoBot.Modules
}); });
cgb.CreateCommand("how are you") cgb.CreateCommand("how are you")
.Alias("how are you?")
.Description("Replies positive only if bot owner is online.") .Description("Replies positive only if bot owner is online.")
.Do(async e => .Do(async e =>
{ {

View File

@ -19,7 +19,7 @@ namespace NadekoBot.Modules.Gambling
internal override void Init(CommandGroupBuilder cgb) internal override void Init(CommandGroupBuilder cgb)
{ {
cgb.CreateCommand(Module.Prefix + "roll") cgb.CreateCommand(Module.Prefix + "roll")
.Description("Rolls 2 dice from 0-10. If you supply a number [x] it rolls up to 30 normal dice.\n**Usage**: $roll [x]") .Description("Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice.\n**Usage**: $roll [x]")
.Parameter("num", ParameterType.Optional) .Parameter("num", ParameterType.Optional)
.Do(Roll0to10Func()); .Do(Roll0to10Func());
cgb.CreateCommand(Module.Prefix + "nroll") cgb.CreateCommand(Module.Prefix + "nroll")
@ -28,7 +28,13 @@ namespace NadekoBot.Modules.Gambling
.Do(Roll0to5Func()); .Do(Roll0to5Func());
} }
private Image GetDice(int num) => Properties.Resources.ResourceManager.GetObject("_" + num) as Image; private Image GetDice(int num) => num != 10
? Properties.Resources.ResourceManager.GetObject("_" + num) as Image
: new[]
{
(Properties.Resources.ResourceManager.GetObject("_" + 1) as Image),
(Properties.Resources.ResourceManager.GetObject("_" + 0) as Image),
}.Merge();
private Func<CommandEventArgs, Task> Roll0to10Func() private Func<CommandEventArgs, Task> Roll0to10Func()
{ {
@ -37,30 +43,24 @@ namespace NadekoBot.Modules.Gambling
{ {
if (e.Args[0] == "") if (e.Args[0] == "")
{ {
var num1 = r.Next(0, 10); var gen = r.Next(0, 101);
var num2 = r.Next(0, 10);
Image[] images; var num1 = gen / 10;
var num2 = gen % 10;
if (num1 == 0 && num2 == 0 && r.Next(0, 2) == 1) var imageStream = new Image[2] { GetDice(num1), GetDice(num2) }.Merge().ToStream(ImageFormat.Png);
await e.Channel.SendFile("dice.png", imageStream);
}
else
{ {
images = new Image[3] { GetDice(1), GetDice(0), GetDice(0) };
}
else {
images = new Image[2] { GetDice(num1), GetDice(num2) };
}
var bitmap = images.Merge();
await e.Channel.SendFile("dice.png", bitmap.ToStream(ImageFormat.Png));
}
else {
try try
{ {
var num = int.Parse(e.Args[0]); var num = int.Parse(e.Args[0]);
if (num < 1) num = 1; if (num < 1) num = 1;
if (num > 30) if (num > 30)
{ {
await e.Channel.SendMessage("You can roll up to 30 dies at a time."); await e.Channel.SendMessage("You can roll up to 30 dice at a time.");
num = 30; num = 30;
} }
var dices = new List<Image>(num); var dices = new List<Image>(num);
@ -113,7 +113,8 @@ namespace NadekoBot.Modules.Gambling
throw new ArgumentException("First argument should be bigger than the second one."); throw new ArgumentException("First argument should be bigger than the second one.");
rolled = new Random().Next(arr[0], arr[1] + 1); rolled = new Random().Next(arr[0], arr[1] + 1);
} }
else { else
{
rolled = new Random().Next(0, int.Parse(e.GetArg("range")) + 1); rolled = new Random().Next(0, int.Parse(e.GetArg("range")) + 1);
} }

View File

@ -33,9 +33,11 @@ namespace NadekoBot.Modules.Gambling
.Description("Prints a name and ID of a random user from the online list from the (optional) role.") .Description("Prints a name and ID of a random user from the online list from the (optional) role.")
.Parameter("role", ParameterType.Optional) .Parameter("role", ParameterType.Optional)
.Do(RaffleFunc()); .Do(RaffleFunc());
cgb.CreateCommand(Prefix + "$$") cgb.CreateCommand(Prefix + "$$")
.Description(string.Format("Check how much {0}s you have.", NadekoBot.Config.CurrencyName)) .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(string.Format("Give someone a certain amount of {0}s", NadekoBot.Config.CurrencyName)) .Description(string.Format("Give someone a certain amount of {0}s", NadekoBot.Config.CurrencyName))
.Parameter("amount", ParameterType.Required) .Parameter("amount", ParameterType.Required)
@ -61,12 +63,56 @@ namespace NadekoBot.Modules.Gambling
return; return;
} }
await FlowersHandler.RemoveFlowersAsync(e.User, "Gift", (int)amount); FlowersHandler.RemoveFlowers(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} {NadekoBot.Config.CurrencyName}s to {mentionedUser.Mention}!"); await e.Channel.SendMessage($"{e.User.Mention} successfully sent {amount} {NadekoBot.Config.CurrencyName}s to {mentionedUser.Mention}!");
}); });
cgb.CreateCommand(Prefix + "award")
.Description("Gives someone a certain amount of flowers. **Owner only!**")
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Parameter("amount", ParameterType.Required)
.Parameter("receiver", ParameterType.Unparsed)
.Do(async e =>
{
var amountStr = e.GetArg("amount")?.Trim();
long amount;
if (!long.TryParse(amountStr, out amount) || amount < 0)
return;
var mentionedUser = e.Message.MentionedUsers.FirstOrDefault(u =>
u.Id != NadekoBot.Client.CurrentUser.Id);
if (mentionedUser == null)
return;
await FlowersHandler.AddFlowersAsync(mentionedUser, $"Awarded by bot owner. ({e.User.Name}/{e.User.Id})", (int)amount);
await e.Channel.SendMessage($"{e.User.Mention} successfully awarded {amount} {NadekoBot.Config.CurrencyName}s to {mentionedUser.Mention}!");
});
cgb.CreateCommand(Prefix + "take")
.Description("Takes a certain amount of flowers from someone. **Owner only!**")
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Parameter("amount", ParameterType.Required)
.Parameter("rektperson", ParameterType.Unparsed)
.Do(async e =>
{
var amountStr = e.GetArg("amount")?.Trim();
long amount;
if (!long.TryParse(amountStr, out amount) || amount < 0)
return;
var mentionedUser = e.Message.MentionedUsers.FirstOrDefault(u =>
u.Id != NadekoBot.Client.CurrentUser.Id);
if (mentionedUser == null)
return;
FlowersHandler.RemoveFlowers(mentionedUser, $"Taken by bot owner.({e.User.Name}/{e.User.Id})", (int)amount);
await e.Channel.SendMessage($"{e.User.Mention} successfully took {amount} {NadekoBot.Config.CurrencyName}s from {mentionedUser.Mention}!");
});
}); });
} }

View File

@ -1,28 +1,32 @@
using System; using Discord.Commands;
using System.Linq;
using Discord.Modules; using Discord.Modules;
using NadekoBot.Commands; using NadekoBot.Commands;
using Newtonsoft.Json.Linq;
using System.IO;
using Discord.Commands;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using System;
using System.Linq;
namespace NadekoBot.Modules { namespace NadekoBot.Modules
internal class Games : DiscordModule { {
internal class Games : DiscordModule
{
private readonly Random rng = new Random(); private readonly Random rng = new Random();
public Games() { public Games()
{
commands.Add(new Trivia(this)); commands.Add(new Trivia(this));
commands.Add(new SpeedTyping(this)); commands.Add(new SpeedTyping(this));
commands.Add(new PollCommand(this)); commands.Add(new PollCommand(this));
commands.Add(new PlantPick(this));
//commands.Add(new BetrayGame(this)); //commands.Add(new BetrayGame(this));
} }
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Games; public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Games;
public override void Install(ModuleManager manager) { public override void Install(ModuleManager manager)
manager.CreateCommands("", cgb => { {
manager.CreateCommands("", cgb =>
{
cgb.AddCheck(Classes.Permissions.PermissionChecker.Instance); cgb.AddCheck(Classes.Permissions.PermissionChecker.Instance);
@ -30,8 +34,9 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "choose") cgb.CreateCommand(Prefix + "choose")
.Description("Chooses a thing from a list of things\n**Usage**: >choose Get up;Sleep;Sleep more") .Description("Chooses a thing from a list of things\n**Usage**: >choose Get up;Sleep;Sleep more")
.Parameter("list", Discord.Commands.ParameterType.Unparsed) .Parameter("list", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
var arg = e.GetArg("list"); var arg = e.GetArg("list");
if (string.IsNullOrWhiteSpace(arg)) if (string.IsNullOrWhiteSpace(arg))
return; return;
@ -43,24 +48,29 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "8ball") cgb.CreateCommand(Prefix + "8ball")
.Description("Ask the 8ball a yes/no question.") .Description("Ask the 8ball a yes/no question.")
.Parameter("question", Discord.Commands.ParameterType.Unparsed) .Parameter("question", ParameterType.Unparsed)
.Do(async e => { .Do(async e =>
{
var question = e.GetArg("question"); var question = e.GetArg("question");
if (string.IsNullOrWhiteSpace(question)) if (string.IsNullOrWhiteSpace(question))
return; return;
try { try
{
await e.Channel.SendMessage( await e.Channel.SendMessage(
$":question: **Question**: `{question}` \n🎱 **8Ball Answers**: `{NadekoBot.Config._8BallResponses[rng.Next(0, NadekoBot.Config._8BallResponses.Length)]}`"); $":question: **Question**: `{question}` \n🎱 **8Ball Answers**: `{NadekoBot.Config._8BallResponses[rng.Next(0, NadekoBot.Config._8BallResponses.Length)]}`");
} catch { } }
catch { }
}); });
cgb.CreateCommand(Prefix + "rps") cgb.CreateCommand(Prefix + "rps")
.Description("Play a game of rocket paperclip scissors with nadkeo.\n**Usage**: >rps scissors") .Description("Play a game of rocket paperclip scissors with Nadeko.\n**Usage**: >rps scissors")
.Parameter("input", ParameterType.Required) .Parameter("input", ParameterType.Required)
.Do(async e => { .Do(async e =>
{
var input = e.GetArg("input").Trim(); var input = e.GetArg("input").Trim();
int pick; int pick;
switch (input) { switch (input)
{
case "r": case "r":
case "rock": case "rock":
case "rocket": case "rocket":
@ -96,7 +106,8 @@ namespace NadekoBot.Modules {
.Description("Prints a customizable Linux interjection") .Description("Prints a customizable Linux interjection")
.Parameter("gnu", ParameterType.Required) .Parameter("gnu", ParameterType.Required)
.Parameter("linux", ParameterType.Required) .Parameter("linux", ParameterType.Required)
.Do(async e => { .Do(async e =>
{
var guhnoo = e.Args[0]; var guhnoo = e.Args[0];
var loonix = e.Args[1]; var loonix = e.Args[1];
@ -112,7 +123,8 @@ There really is a {loonix}, and these people are using it, but it is just a part
}); });
} }
private string GetRPSPick(int i) { private string GetRPSPick(int i)
{
if (i == 0) if (i == 0)
return "rocket"; return "rocket";
else if (i == 1) else if (i == 1)

View File

@ -70,6 +70,7 @@ namespace NadekoBot.Modules
cgb.CreateCommand("n") cgb.CreateCommand("n")
.Alias("next") .Alias("next")
.Alias("skip")
.Description("Goes to the next song in the queue.") .Description("Goes to the next song in the queue.")
.Do(e => .Do(e =>
{ {
@ -138,7 +139,15 @@ namespace NadekoBot.Modules
await e.Channel.SendMessage("🎵 No active music player."); await e.Channel.SendMessage("🎵 No active music player.");
return; return;
} }
var toSend = "🎵 **" + musicPlayer.Playlist.Count + "** `tracks currently queued.` "; var currentSong = musicPlayer.CurrentSong;
if (currentSong == null)
return;
var toSend = $"🎵`Now Playing` {currentSong.PrettyName} " + $"{currentSong.PrettyCurrentTime()}\n";
if (musicPlayer.RepeatSong)
toSend += "🔂";
else if (musicPlayer.RepeatPlaylist)
toSend += "🔁";
toSend += $" **{musicPlayer.Playlist.Count}** `tracks currently queued.` ";
if (musicPlayer.Playlist.Count >= MusicPlayer.MaximumPlaylistSize) if (musicPlayer.Playlist.Count >= MusicPlayer.MaximumPlaylistSize)
toSend += "**Song queue is full!**\n"; toSend += "**Song queue is full!**\n";
else else
@ -156,7 +165,8 @@ namespace NadekoBot.Modules
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
return; return;
var currentSong = musicPlayer.CurrentSong; var currentSong = musicPlayer.CurrentSong;
if (currentSong != null) if (currentSong == null)
return;
await e.Channel.SendMessage($"🎵`Now Playing` {currentSong.PrettyName} " + await e.Channel.SendMessage($"🎵`Now Playing` {currentSong.PrettyName} " +
$"{currentSong.PrettyCurrentTime()}"); $"{currentSong.PrettyCurrentTime()}");
}); });
@ -303,7 +313,7 @@ namespace NadekoBot.Modules
}); });
cgb.CreateCommand("radio").Alias("ra") cgb.CreateCommand("radio").Alias("ra")
.Description("Queues a direct radio stream from a link.") .Description("Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf")
.Parameter("radio_link", ParameterType.Required) .Parameter("radio_link", ParameterType.Required)
.Do(async e => .Do(async e =>
{ {
@ -385,6 +395,34 @@ namespace NadekoBot.Modules
} }
}); });
cgb.CreateCommand("rcs")
.Alias("repeatcurrentsong")
.Description("Toggles repeat of current song.")
.Do(async e =>
{
MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
return;
var currentSong = musicPlayer.CurrentSong;
if (currentSong == null)
return;
var currentValue = musicPlayer.ToggleRepeatSong();
await e.Channel.SendMessage(currentValue ?
$"🎵🔂`Repeating track:`{currentSong.PrettyName}" :
$"🎵🔂`Current track repeat stopped.`");
});
cgb.CreateCommand("rpl")
.Alias("repeatplaylist")
.Description("Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue).")
.Do(async e =>
{
MusicPlayer musicPlayer;
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
return;
var currentValue = musicPlayer.ToggleRepeatPlaylist();
await e.Channel.SendMessage($"🎵🔁`Repeat playlist {(currentValue ? "enabled" : "disabled")}`");
});
//cgb.CreateCommand("debug") //cgb.CreateCommand("debug")
// .Description("Does something magical. **BOT OWNER ONLY**") // .Description("Does something magical. **BOT OWNER ONLY**")
// .AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly()) // .AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())

View File

@ -79,7 +79,11 @@ namespace NadekoBot.Modules.Pokemon
{"bullet punch",16}, {"bullet punch",16},
{"metal burst",16}, {"metal burst",16},
{"gear grind",16}, {"gear grind",16},
{"magnet bomb",16} {"magnet bomb",16},
{"fairy wind",17},
{"draining kiss",17},
{"dazzling gleam",17},
{"play rough",17}
}; };

View File

@ -1,15 +1,12 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NadekoBot.Modules.Pokemon namespace NadekoBot.Modules.Pokemon
{ {
class PokeStats class PokeStats
{ {
//Health left //Health left
public int HP { get; set; } = 500; public int Hp { get; set; } = 500;
public int MaxHp { get; } = 500;
//Amount of moves made since last time attacked //Amount of moves made since last time attacked
public int MovesMade { get; set; } = 0; public int MovesMade { get; set; } = 0;
//Last people attacked //Last people attacked

View File

@ -1,40 +1,64 @@
using System; using Discord.Commands;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.Modules; using Discord.Modules;
using Discord.Commands;
using NadekoBot.Commands;
using NadekoBot.Classes; using NadekoBot.Classes;
using NadekoBot.Extensions;
using NadekoBot.Classes._DataModels; using NadekoBot.Classes._DataModels;
using NadekoBot.Classes.Permissions; using NadekoBot.Classes.Permissions;
using System.Collections.Concurrent; using NadekoBot.Extensions;
using NadekoBot.Modules.Pokemon.PokeTypes; using NadekoBot.Modules.Pokemon.PokeTypes;
using NadekoBot.Modules.Pokemon.PokeTypes.Extensions; using NadekoBot.Modules.Pokemon.PokeTypes.Extensions;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace NadekoBot.Modules.Pokemon namespace NadekoBot.Modules.Pokemon
{ {
class PokemonModule : DiscordModule
class PokemonGame : DiscordModule
{ {
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Pokemon; public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Pokemon;
public readonly int BaseHealth = 500;
//private Dictionary<ulong, Pokestats> stats = new Dictionary<ulong, Pokestats>();
private ConcurrentDictionary<ulong, PokeStats> Stats = new ConcurrentDictionary<ulong, PokeStats>(); private ConcurrentDictionary<ulong, PokeStats> Stats = new ConcurrentDictionary<ulong, PokeStats>();
public PokemonModule()
public PokemonGame()
{ {
//Something? DbHandler.Instance.DeleteAll<PokeMoves>();
DbHandler.Instance.InsertMany(
DefaultMoves.DefaultMovesList.Select(move => new PokeMoves
{
move = move.Key,
type = move.Value
}));
} }
private int GetDamage(PokeType usertype, PokeType targetType)
{
var rng = new Random();
int damage = rng.Next(40, 60);
var multiplier = usertype.Multiplier(targetType);
damage = (int)(damage * multiplier);
return damage;
}
private PokeType GetPokeType(ulong id)
{
var db = DbHandler.Instance.GetAllRows<UserPokeTypes>();
Dictionary<long, int> setTypes = db.ToDictionary(x => x.UserId, y => y.type);
if (setTypes.ContainsKey((long)id))
{
return PokemonTypesMain.IntToPokeType(setTypes[(long)id]);
}
int remainder = Math.Abs((int)(id % 18));
return PokemonTypesMain.IntToPokeType(remainder);
}
public override void Install(ModuleManager manager) public override void Install(ModuleManager manager)
{ {
manager.CreateCommands("", cgb => manager.CreateCommands("", cgb =>
{ {
cgb.AddCheck(Classes.Permissions.PermissionChecker.Instance); cgb.AddCheck(PermissionChecker.Instance);
commands.ForEach(cmd => cmd.Init(cgb)); commands.ForEach(cmd => cmd.Init(cgb));
@ -45,20 +69,28 @@ namespace NadekoBot.Modules.Pokemon
.Do(async e => .Do(async e =>
{ {
var move = e.GetArg("move"); var move = e.GetArg("move");
var target = e.Server.FindUsers(e.GetArg("target")).FirstOrDefault(); var targetStr = e.GetArg("target")?.Trim();
if (string.IsNullOrWhiteSpace(targetStr))
return;
var target = e.Server.FindUsers(targetStr).FirstOrDefault();
if (target == null) if (target == null)
{ {
await e.Channel.SendMessage("No such person."); await e.Channel.SendMessage("No such person.");
return; return;
} }
else if (target == e.User)
{
await e.Channel.SendMessage("You can't attack yourself.");
return;
}
// Checking stats first, then move // Checking stats first, then move
//Set up the userstats //Set up the userstats
PokeStats userStats; PokeStats userStats;
userStats = Stats.GetOrAdd(e.User.Id, defaultStats()); userStats = Stats.GetOrAdd(e.User.Id, new PokeStats());
//Check if able to move //Check if able to move
//User not able if HP < 0, has made more than 4 attacks //User not able if HP < 0, has made more than 4 attacks
if (userStats.HP < 0) if (userStats.Hp < 0)
{ {
await e.Channel.SendMessage($"{e.User.Mention} has fainted and was not able to move!"); await e.Channel.SendMessage($"{e.User.Mention} has fainted and was not able to move!");
return; return;
@ -75,17 +107,17 @@ namespace NadekoBot.Modules.Pokemon
} }
//get target stats //get target stats
PokeStats targetStats; PokeStats targetStats;
targetStats = Stats.GetOrAdd(target.Id, defaultStats()); targetStats = Stats.GetOrAdd(target.Id, new PokeStats());
//If target's HP is below 0, no use attacking //If target's HP is below 0, no use attacking
if (targetStats.HP <= 0) if (targetStats.Hp <= 0)
{ {
await e.Channel.SendMessage($"{target.Mention} has already fainted!"); await e.Channel.SendMessage($"{target.Mention} has already fainted!");
return; return;
} }
//Check whether move can be used //Check whether move can be used
IPokeType userType = getPokeType(e.User.Id); PokeType userType = GetPokeType(e.User.Id);
var enabledMoves = userType.GetMoves(); var enabledMoves = userType.GetMoves();
if (!enabledMoves.Contains(move.ToLowerInvariant())) if (!enabledMoves.Contains(move.ToLowerInvariant()))
@ -95,13 +127,13 @@ namespace NadekoBot.Modules.Pokemon
} }
//get target type //get target type
IPokeType targetType = getPokeType(target.Id); PokeType targetType = GetPokeType(target.Id);
//generate damage //generate damage
int damage = getDamage(userType, targetType); int damage = GetDamage(userType, targetType);
//apply damage to target //apply damage to target
targetStats.HP -= damage; targetStats.Hp -= damage;
var response = $"{e.User.Mention} used **{move}**{userType.GetImage()} on {target.Mention}{targetType.GetImage()} for **{damage}** damage"; var response = $"{e.User.Mention} used **{move}**{userType.Image} on {target.Mention}{targetType.Image} for **{damage}** damage";
//Damage type //Damage type
if (damage < 40) if (damage < 40)
@ -119,13 +151,13 @@ namespace NadekoBot.Modules.Pokemon
//check fainted //check fainted
if (targetStats.HP <= 0) if (targetStats.Hp <= 0)
{ {
response += $"\n**{target.Name}** has fainted!"; response += $"\n**{target.Name}** has fainted!";
} }
else else
{ {
response += $"\n**{target.Name}** has {targetStats.HP} HP remaining"; response += $"\n**{target.Name}** has {targetStats.Hp} HP remaining";
} }
//update other stats //update other stats
@ -145,53 +177,30 @@ namespace NadekoBot.Modules.Pokemon
await e.Channel.SendMessage(response); await e.Channel.SendMessage(response);
}); });
cgb.CreateCommand(Prefix + "listmoves") cgb.CreateCommand(Prefix + "ml")
.Alias("movelist")
.Description("Lists the moves you are able to use") .Description("Lists the moves you are able to use")
.Do(async e => .Do(async e =>
{ {
var userType = getPokeType(e.User.Id); var userType = GetPokeType(e.User.Id);
List<string> movesList = userType.GetMoves(); List<string> movesList = userType.GetMoves();
var str = "**Moves:**"; var str = $"**Moves for `{userType.Name}` type.**";
foreach (string m in movesList) foreach (string m in movesList)
{ {
str += $"\n{userType.GetImage()}{m}"; str += $"\n{userType.Image}{m}";
} }
await e.Channel.SendMessage(str); await e.Channel.SendMessage(str);
}); });
cgb.CreateCommand(Prefix + "addmove")
.Description($"Adds move given to database.\n**Usage**: {Prefix}addmove flame fire")
.Parameter("movename", ParameterType.Required)
.Parameter("movetype", ParameterType.Required)
.Do(async e =>
{
//Implement NadekoFlowers????
string newMove = e.GetArg("movename").ToLowerInvariant();
var newType = PokemonTypesMain.stringToPokeType(e.GetArg("movetype").ToUpperInvariant());
int typeNum = newType.GetNum();
var db = DbHandler.Instance.GetAllRows<PokeMoves>().Select(x => x.move);
if (db.Contains(newMove))
{
await e.Channel.SendMessage($"{newMove} already exists");
return;
}
await Task.Run(() =>
{
DbHandler.Instance.InsertData(new Classes._DataModels.PokeMoves
{
move = newMove,
type = typeNum
});
});
await e.Channel.SendMessage($"Added {newType.GetImage()}{newMove}");
});
cgb.CreateCommand(Prefix + "heal") cgb.CreateCommand(Prefix + "heal")
.Description($"Heals someone. Revives those that fainted. Costs a NadekoFlower \n**Usage**:{Prefix}revive @someone") .Description($"Heals someone. Revives those that fainted. Costs a NadekoFlower \n**Usage**:{Prefix}revive @someone")
.Parameter("target", ParameterType.Required) .Parameter("target", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
var usr = e.Server.FindUsers(e.GetArg("target")).FirstOrDefault(); var targetStr = e.GetArg("target")?.Trim();
if (string.IsNullOrWhiteSpace(targetStr))
return;
var usr = e.Server.FindUsers(targetStr).FirstOrDefault();
if (usr == null) if (usr == null)
{ {
await e.Channel.SendMessage("No such person."); await e.Channel.SendMessage("No such person.");
@ -201,8 +210,8 @@ namespace NadekoBot.Modules.Pokemon
{ {
var targetStats = Stats[usr.Id]; var targetStats = Stats[usr.Id];
int HP = targetStats.HP; int HP = targetStats.Hp;
if (targetStats.HP == BaseHealth) if (targetStats.Hp == targetStats.MaxHp)
{ {
await e.Channel.SendMessage($"{usr.Name} already has full HP!"); await e.Channel.SendMessage($"{usr.Name} already has full HP!");
return; return;
@ -212,21 +221,21 @@ namespace NadekoBot.Modules.Pokemon
var pts = Classes.DbHandler.Instance.GetStateByUserId((long)e.User.Id)?.Value ?? 0; var pts = Classes.DbHandler.Instance.GetStateByUserId((long)e.User.Id)?.Value ?? 0;
if (pts < amount) if (pts < amount)
{ {
await e.Channel.SendMessage($"{e.User.Mention} you don't have enough NadekoFlowers! \nYou still need {amount - pts} to be able to do this!"); await e.Channel.SendMessage($"{e.User.Mention} you don't have enough {NadekoBot.Config.CurrencyName}s! \nYou still need {amount - pts} to be able to do this!");
return; return;
} }
var up = (usr.Id == e.User.Id) ? "yourself" : usr.Name; var target = (usr.Id == e.User.Id) ? "yourself" : usr.Name;
await FlowersHandler.RemoveFlowersAsync(e.User, $"heal {up}", amount); FlowersHandler.RemoveFlowers(e.User, $"Poke-Heal {target}", amount);
//healing //healing
targetStats.HP = BaseHealth; targetStats.Hp = targetStats.MaxHp;
if (HP < 0) if (HP < 0)
{ {
//Could heal only for half HP? //Could heal only for half HP?
Stats[usr.Id].HP = (BaseHealth / 2); Stats[usr.Id].Hp = (targetStats.MaxHp / 2);
await e.Channel.SendMessage($"{e.User.Name} revived {usr.Name} for 🌸"); await e.Channel.SendMessage($"{e.User.Name} revived {usr.Name} with one {NadekoBot.Config.CurrencySign}");
return; return;
} }
await e.Channel.SendMessage($"{e.User.Name} healed {usr.Name} for {BaseHealth - HP} HP with a 🌸"); await e.Channel.SendMessage($"{e.User.Name} healed {usr.Name} for {targetStats.MaxHp - HP} HP with a 🌸");
return; return;
} }
else else
@ -237,142 +246,73 @@ namespace NadekoBot.Modules.Pokemon
cgb.CreateCommand(Prefix + "type") cgb.CreateCommand(Prefix + "type")
.Description($"Get the poketype of the target.\n**Usage**: {Prefix}type @someone") .Description($"Get the poketype of the target.\n**Usage**: {Prefix}type @someone")
.Parameter("target", ParameterType.Required) .Parameter("target", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
var usr = e.Server.FindUsers(e.GetArg("target")).FirstOrDefault(); var usrStr = e.GetArg("target")?.Trim();
if (string.IsNullOrWhiteSpace(usrStr))
return;
var usr = e.Server.FindUsers(usrStr).FirstOrDefault();
if (usr == null) if (usr == null)
{ {
await e.Channel.SendMessage("No such person."); await e.Channel.SendMessage("No such person.");
return; return;
} }
var pType = getPokeType(usr.Id); var pType = GetPokeType(usr.Id);
await e.Channel.SendMessage($"Type of {usr.Name} is **{pType.GetName().ToLowerInvariant()}**{pType.GetImage()}"); await e.Channel.SendMessage($"Type of {usr.Name} is **{pType.Name.ToLowerInvariant()}**{pType.Image}");
});
cgb.CreateCommand(Prefix + "setdefaultmoves")
.Description($"Sets the moves DB to the default state and returns them all **OWNER ONLY**")
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
{
//clear DB
var db = DbHandler.Instance.GetAllRows<PokeMoves>();
foreach (PokeMoves p in db)
{
DbHandler.Instance.Delete<PokeMoves>(p.Id);
}
foreach (var entry in DefaultMoves.DefaultMovesList)
{
DbHandler.Instance.InsertData(new Classes._DataModels.PokeMoves
{
move = entry.Key,
type = entry.Value
});
}
var str = "**Reset moves to default**.\n**Moves:**";
//could sort, but meh
var dbMoves = DbHandler.Instance.GetAllRows<PokeMoves>();
foreach (PokeMoves m in dbMoves)
{
var t = PokemonTypesMain.IntToPokeType(m.type);
str += $"\n{t.GetImage()}{m.move}";
}
await e.Channel.SendMessage(str);
}); });
cgb.CreateCommand(Prefix + "settype") cgb.CreateCommand(Prefix + "settype")
.Description($"Set your poketype. Costs a NadekoFlower.\n**Usage**: {Prefix}settype fire") .Description($"Set your poketype. Costs a {NadekoBot.Config.CurrencyName}.\n**Usage**: {Prefix}settype fire")
.Parameter("targetType", ParameterType.Required) .Parameter("targetType", ParameterType.Unparsed)
.Do(async e => .Do(async e =>
{ {
var targetTypeString = e.GetArg("targetType"); var targetTypeStr = e.GetArg("targetType")?.ToUpperInvariant();
var targetType = PokemonTypesMain.stringToPokeType(targetTypeString.ToUpperInvariant()); if (string.IsNullOrWhiteSpace(targetTypeStr))
return;
var targetType = PokemonTypesMain.stringToPokeType(targetTypeStr);
if (targetType == null) if (targetType == null)
{ {
await e.Channel.SendMessage("Invalid type specified. Type must be one of:\nNORMAL, FIRE, WATER, ELECTRIC, GRASS, ICE, FIGHTING, POISON, GROUND, FLYING, PSYCHIC, BUG, ROCK, GHOST, DRAGON, DARK, STEEL"); await e.Channel.SendMessage("Invalid type specified. Type must be one of:\nNORMAL, FIRE, WATER, ELECTRIC, GRASS, ICE, FIGHTING, POISON, GROUND, FLYING, PSYCHIC, BUG, ROCK, GHOST, DRAGON, DARK, STEEL");
return; return;
} }
if (targetType == getPokeType(e.User.Id)) if (targetType == GetPokeType(e.User.Id))
{ {
await e.Channel.SendMessage($"Your type is already {targetType.GetName().ToLowerInvariant()}{targetType.GetImage()}"); await e.Channel.SendMessage($"Your type is already {targetType.Name.ToLowerInvariant()}{targetType.Image}");
return; return;
} }
//Payment~ //Payment~
var amount = 1; var amount = 1;
var pts = Classes.DbHandler.Instance.GetStateByUserId((long)e.User.Id)?.Value ?? 0; var pts = DbHandler.Instance.GetStateByUserId((long)e.User.Id)?.Value ?? 0;
if (pts < amount) if (pts < amount)
{ {
await e.Channel.SendMessage($"{e.User.Mention} you don't have enough NadekoFlowers! \nYou still need {amount - pts} to be able to do this!"); await e.Channel.SendMessage($"{e.User.Mention} you don't have enough {NadekoBot.Config.CurrencyName}s! \nYou still need {amount - pts} to be able to do this!");
return; return;
} }
await FlowersHandler.RemoveFlowersAsync(e.User, $"set usertype to {targetTypeString}", amount); FlowersHandler.RemoveFlowers(e.User, $"set usertype to {targetTypeStr}", amount);
//Actually changing the type here //Actually changing the type here
var preTypes = DbHandler.Instance.GetAllRows<userPokeTypes>(); var preTypes = DbHandler.Instance.GetAllRows<UserPokeTypes>();
Dictionary<long, int> Dict = preTypes.ToDictionary(x => x.UserId, y => y.Id); Dictionary<long, int> Dict = preTypes.ToDictionary(x => x.UserId, y => y.Id);
if (Dict.ContainsKey((long)e.User.Id)) if (Dict.ContainsKey((long)e.User.Id))
{ {
//delete previous type //delete previous type
DbHandler.Instance.Delete<userPokeTypes>(Dict[(long)e.User.Id]); DbHandler.Instance.Delete<UserPokeTypes>(Dict[(long)e.User.Id]);
} }
DbHandler.Instance.InsertData(new Classes._DataModels.userPokeTypes DbHandler.Instance.InsertData(new UserPokeTypes
{ {
UserId = (long)e.User.Id, UserId = (long)e.User.Id,
type = targetType.GetNum() type = targetType.Num
}); });
//Now for the response //Now for the response
await e.Channel.SendMessage($"Set type of {e.User.Mention} to {targetTypeString}{targetType.GetImage()} for a 🌸"); await e.Channel.SendMessage($"Set type of {e.User.Mention} to {targetTypeStr}{targetType.Image} for a {NadekoBot.Config.CurrencySign}");
}); });
}); });
} }
private int getDamage(IPokeType usertype, IPokeType targetType)
{
Random rng = new Random();
int damage = rng.Next(40, 60);
double multiplier = 1;
multiplier = usertype.GetMagnifier(targetType);
damage = (int)(damage * multiplier);
return damage;
}
private IPokeType getPokeType(ulong id)
{
var db = DbHandler.Instance.GetAllRows<userPokeTypes>();
Dictionary<long, int> setTypes = db.ToDictionary(x => x.UserId, y => y.type);
if (setTypes.ContainsKey((long)id))
{
return PokemonTypesMain.IntToPokeType(setTypes[(long)id]);
}
int remainder = (int)id % 16;
return PokemonTypesMain.IntToPokeType(remainder);
}
private PokeStats defaultStats()
{
PokeStats s = new PokeStats();
s.HP = BaseHealth;
return s;
}
} }
} }

View File

@ -1,22 +1,16 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class BugType : IPokeType class BugType : PokeType
{ {
static readonly string name = "BUG"; static readonly string name = "BUG";
public static int numType = 11; public static int numType = 11;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "FIRE": return 0.5; case "FIRE": return 0.5;
@ -24,8 +18,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
case "FIGHTING": return 0.5; case "FIGHTING": return 0.5;
case "POISON": return 0.5; case "POISON": return 0.5;
case "FLYING": return 0.5; case "FLYING": return 0.5;
case "GHOST": return 0.5;
case "PSYCHIC": return 2; case "PSYCHIC": return 2;
case "ROCK": return 0.5; case "ROCK": return 0.5;
case "FAIRY": return 0.5;
case "DARK": return 2; case "DARK": return 2;
case "STEEL": return 0.5; case "STEEL": return 0.5;
default: return 1; default: return 1;
@ -33,24 +29,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
} }
List<string> moves = new List<string>(); List<string> moves = new List<string>();
public string Name => name;
public string Image => "🐛";
public int Num => numType;
public string GetName()
{
return name;
}
public string GetImage()
{
return "🐛";
}
public int GetNum()
{
return numType;
}
} }
} }

View File

@ -1,52 +1,32 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class DarkType : IPokeType class DarkType : PokeType
{ {
static readonly string name = "DARK"; static readonly string name = "DARK";
public static int numType = 15; public static int numType = 15;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "FIGHTING": return 0.5; case "FIGHTING": return 0.5;
case "PSYCHIC": return 2; case "PSYCHIC": return 2;
case "GHOST": return 2; case "GHOST": return 2;
case "DARK": return 0.5; case "DARK": return 0.5;
case "STEEL": return 0.5; case "FAIRY": return 0.5;
default: return 1; default: return 1;
} }
} }
List<string> moves = new List<string>(); List<string> moves = new List<string>();
public string Name => name;
public string Image => "🕶";
public int Num => numType;
public string GetName()
{
return name;
}
public string GetImage()
{
return "🕶";
}
public int GetNum()
{
return numType;
}
} }
} }

View File

@ -1,26 +1,21 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class DragonType : IPokeType class DragonType : PokeType
{ {
static readonly string name = "DRAGON"; static readonly string name = "DRAGON";
public static int numType = 14; public static int numType = 14;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "DRAGON": return 2; case "DRAGON": return 2;
case "STEEL": return 0.5; case "STEEL": return 0.5;
case "FAIRY": return 0;
default: return 1; default: return 1;
} }
} }
@ -29,21 +24,12 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
public string GetName() public string Name => name;
{
return name;
}
public string GetImage() public string Image => "🐉";
{
return "🐉";
}
public int GetNum() public int Num => numType;
{
return numType;
}
} }
} }

View File

@ -1,22 +1,16 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class ElectricType : IPokeType class ElectricType : PokeType
{ {
static readonly string name = "ELECTRIC"; static readonly string name = "ELECTRIC";
public static int numType = 3; public static int numType = 3;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "WATER": return 2; case "WATER": return 2;
@ -33,20 +27,11 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
public string GetName() public string Name => name;
{
return name;
}
public string GetImage() public string Image => "⚡️";
{
return "⚡️";
}
public int GetNum() public int Num => numType;
{
return numType;
}
} }
} }

View File

@ -0,0 +1,33 @@
using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic;
namespace NadekoBot.Modules.Pokemon.PokemonTypes
{
class FairyType : PokeType
{
static readonly string name = "FAIRY";
public static int numType = 17;
public double Multiplier(PokeType target)
{
switch (target.Name)
{
case "FIGHTING": return 2;
case "FIRE": return 0.5;
case "DARK": return 0.5;
case "POISON": return 0.5;
case "STEEL": return 2;
case "DRAGON": return 2;
default: return 1;
}
}
List<string> moves = new List<string>();
public string Name => name;
public string Image => "💫";
public int Num => numType;
}
}

View File

@ -1,22 +1,16 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class FightingType : IPokeType class FightingType : PokeType
{ {
static readonly string name = "FIGHTING"; static readonly string name = "FIGHTING";
public static int numType = 6; public static int numType = 6;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "NORMAL": return 2; case "NORMAL": return 2;
@ -29,6 +23,7 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
case "GHOST": return 0; case "GHOST": return 0;
case "DARK": return 2; case "DARK": return 2;
case "STEEL": return 2; case "STEEL": return 2;
case "FAIRY": return 0.5;
default: return 1; default: return 1;
} }
} }
@ -37,20 +32,11 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
public string GetName() public string Name => name;
{
return name;
}
public string GetImage() public string Image => "✊";
{
return "✊";
}
public int GetNum() public int Num => numType;
{
return numType;
}
} }
} }

View File

@ -1,24 +1,18 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class FireType : IPokeType class FireType : PokeType
{ {
static readonly string name = "FIRE"; static readonly string name = "FIRE";
public static int numType = 1; public static int numType = 1;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "FIRE": return 0.5; case "FIRE": return 0.5;
@ -33,25 +27,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
} }
} }
List<string> moves = new List<string>(); List<string> moves = new List<string>();
public string Name => name;
public string Image => "🔥";
public int Num => numType;
public string GetName()
{
return name;
}
public string GetImage()
{
return "🔥";
}
public int GetNum()
{
return numType;
}
} }
} }

View File

@ -1,22 +1,16 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class FlyingType : IPokeType class FlyingType : PokeType
{ {
static readonly string name = "FLYING"; static readonly string name = "FLYING";
public static int numType = 9; public static int numType = 9;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "ELECTRIC": return 0.5; case "ELECTRIC": return 0.5;
@ -33,21 +27,12 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
public string GetName() public string Name => name;
{
return name;
}
public string GetImage() public string Image => "☁";
{
return "☁";
}
public int GetNum() public int Num => numType;
{
return numType;
}
} }
} }

View File

@ -1,22 +1,16 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class GhostType : IPokeType class GhostType : PokeType
{ {
static readonly string name = "GHOST"; static readonly string name = "GHOST";
public static int numType = 13; public static int numType = 13;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "NORMAL": return 0; case "NORMAL": return 0;
@ -32,21 +26,12 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
public string GetName() public string Name => name;
{
return name;
}
public string GetImage() public string Image => "👻";
{
return "👻";
}
public int GetNum() public int Num => numType;
{
return numType;
}
} }
} }

View File

@ -1,22 +1,16 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class GrassType : IPokeType class GrassType : PokeType
{ {
static readonly string name = "GRASS"; static readonly string name = "GRASS";
public static int numType = 4; public static int numType = 4;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "FIRE": return 0.5; case "FIRE": return 0.5;
@ -35,20 +29,11 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
public string GetName() public string Name => name;
{
return name;
}
public string GetImage() public string Image => "🌿";
{
return "🌿";
}
public int GetNum() public int Num => numType;
{
return numType;
}
} }
} }

View File

@ -1,22 +1,16 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class GroundType : IPokeType class GroundType : PokeType
{ {
static readonly string name = "GROUND"; static readonly string name = "GROUND";
public static int numType = 8; public static int numType = 8;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "FIRE": return 2; case "FIRE": return 2;
@ -32,24 +26,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
} }
List<string> moves = new List<string>(); List<string> moves = new List<string>();
public string Name => name;
public string Image => "🗻";
public int Num => numType;
public string GetName()
{
return name;
}
public string GetImage()
{
return "🗻";
}
public int GetNum()
{
return numType;
}
} }
} }

View File

@ -6,13 +6,13 @@ namespace NadekoBot.Modules.Pokemon.PokeTypes.Extensions
{ {
public static class IPokeTypeExtensions public static class IPokeTypeExtensions
{ {
public static List<string> GetMoves(this IPokeType poketype) public static List<string> GetMoves(this PokeType poketype)
{ {
var db = DbHandler.Instance.GetAllRows<PokeMoves>(); var db = DbHandler.Instance.GetAllRows<PokeMoves>();
List<string> moves = new List<string>(); List<string> moves = new List<string>();
foreach (PokeMoves p in db) foreach (PokeMoves p in db)
{ {
if (p.type == poketype.GetNum()) if (p.type == poketype.Num)
{ {
if (!moves.Contains(p.move)) if (!moves.Contains(p.move))
{ {

View File

@ -1,22 +1,16 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class IceType : IPokeType class IceType : PokeType
{ {
static readonly string name = "ICE"; static readonly string name = "ICE";
public static int numType = 5; public static int numType = 5;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "FIRE": return 0.5; case "FIRE": return 0.5;
@ -32,23 +26,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
} }
List<string> moves = new List<string>(); List<string> moves = new List<string>();
public string Name => name;
public string Image => "❄";
public int Num => numType;
public string GetName()
{
return name;
}
public string GetImage()
{
return "❄";
}
public int GetNum()
{
return numType;
}
} }
} }

View File

@ -1,26 +1,18 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels;
using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class NormalType : IPokeType class NormalType : PokeType
{ {
static readonly string name = "NORMAL"; static readonly string name = "NORMAL";
public static int type_num = 0; public static int type_num = 0;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "ROCK": return 0.5; case "ROCK": return 0.5;
case "GHOST": return 0; case "GHOST": return 0;
case "STEEL": return 0.5; case "STEEL": return 0.5;
@ -29,24 +21,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
} }
List<string> moves = new List<string>(); List<string> moves = new List<string>();
public string Name => name;
public string Image => "⭕️";
public int Num => type_num;
public string GetName()
{
return name;
}
public string GetImage()
{
return "⭕️";
}
public int GetNum()
{
return type_num;
}
} }
} }

View File

@ -1,23 +1,16 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels;
using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class PoisonType : IPokeType class PoisonType : PokeType
{ {
static readonly string name = "POISON"; static readonly string name = "POISON";
public static int numType = 7; public static int numType = 7;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "GRASS": return 2; case "GRASS": return 2;
@ -26,28 +19,16 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
case "ROCK": return 0.5; case "ROCK": return 0.5;
case "GHOST": return 0.5; case "GHOST": return 0.5;
case "STEEL": return 0; case "STEEL": return 0;
case "FAIRY": return 2;
default: return 1; default: return 1;
} }
} }
List<string> moves = new List<string>(); List<string> moves = new List<string>();
public string Name => name;
public string Image => "☠";
public int Num => numType;
public string GetName()
{
return name;
}
public string GetImage()
{
return "☠";
}
public int GetNum()
{
return numType;
}
} }
} }

View File

@ -1,28 +1,24 @@
using System.Collections.Generic; using NadekoBot.Modules.Pokemon.PokemonTypes;
using NadekoBot.Classes; using System.Collections.Generic;
using NadekoBot.Classes._DataModels;
using NadekoBot.Modules.Pokemon.PokemonTypes;
namespace NadekoBot.Modules.Pokemon.PokeTypes namespace NadekoBot.Modules.Pokemon.PokeTypes
{ {
public interface PokeType
public interface IPokeType
{ {
string Image { get; }
string GetImage(); string Name { get; }
string GetName(); int Num { get; }
int GetNum(); double Multiplier(PokeType target);
double GetMagnifier(IPokeType target);
} }
public class PokemonTypesMain public class PokemonTypesMain
{ {
public static IPokeType stringToPokeType(string newType) public static PokeType stringToPokeType(string newType)
{ {
foreach (IPokeType t in TypeList) foreach (PokeType t in TypeList)
{ {
if (t.GetName() == newType) if (t.Name == newType)
{ {
return t; return t;
} }
@ -30,26 +26,8 @@ namespace NadekoBot.Modules.Pokemon.PokeTypes
return null; return null;
} }
//public static List<string> getMoves(int numType)
//{
// var db = DbHandler.Instance.GetAllRows<PokeMoves>();
// List<string> moves = new List<string>();
// foreach (PokeMoves p in db)
// {
// if (p.type == numType)
// {
// if (!moves.Contains(p.move))
// {
// moves.Add(p.move);
// }
// }
// }
// return moves;
//}
//These classes can use all methods (except getMoves) //These classes can use all methods (except getMoves)
public static List<IPokeType> TypeList = new List<IPokeType>() public static List<PokeType> TypeList = new List<PokeType>()
{ {
new NormalType(), new NormalType(),
new FireType(), new FireType(),
@ -67,14 +45,15 @@ namespace NadekoBot.Modules.Pokemon.PokeTypes
new GhostType(), new GhostType(),
new DragonType(), new DragonType(),
new DarkType(), new DarkType(),
new SteelType() new SteelType(),
new FairyType()
}; };
public static IPokeType IntToPokeType(int id) public static PokeType IntToPokeType(int id)
{ {
foreach (IPokeType t in TypeList) foreach (PokeType t in TypeList)
{ {
if (t.GetNum() == id) if (t.Num == id)
{ {
return t; return t;
} }

View File

@ -1,23 +1,16 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels;
using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class PsychicType : IPokeType class PsychicType : PokeType
{ {
static readonly string name = "PSYCHIC"; static readonly string name = "PSYCHIC";
public static int numType = 10; public static int numType = 10;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "FIGHTING": return 2; case "FIGHTING": return 2;
@ -33,21 +26,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
public string GetName() public string Name => name;
{
return name;
}
public string Image => "🔮";
public int Num => numType;
public string GetImage()
{
return "💫";
}
public int GetNum()
{
return numType;
}
} }
} }

View File

@ -1,22 +1,16 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class RockType : IPokeType class RockType : PokeType
{ {
static readonly string name = "ROCK"; static readonly string name = "ROCK";
public static int numType = 12; public static int numType = 12;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "FIRE": return 2; case "FIRE": return 2;
@ -31,24 +25,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
} }
List<string> moves = new List<string>(); List<string> moves = new List<string>();
public string Name => name;
public string Image => "💎";
public int Num => numType;
public string GetName()
{
return name;
}
public string GetImage()
{
return "💎";
}
public int GetNum()
{
return numType;
}
} }
} }

View File

@ -1,22 +1,16 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class SteelType : IPokeType class SteelType : PokeType
{ {
static readonly string name = "STEEL"; static readonly string name = "STEEL";
public static int numType = -1; public static int numType = 16;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "FIRE": return 0.5; case "FIRE": return 0.5;
@ -30,23 +24,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
} }
List<string> moves = new List<string>(); List<string> moves = new List<string>();
public string Name => name;
public string Image => "🔩";
public int Num => numType;
public string GetName()
{
return name;
}
public string GetImage()
{
return "🔩";
}
public int GetNum()
{
return numType;
}
} }
} }

View File

@ -1,22 +1,16 @@
using System; using NadekoBot.Modules.Pokemon.PokeTypes;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels; using NadekoBot.Modules.Pokemon.PokeTypes; using NadekoBot.Modules.Pokemon.PokeTypes;
namespace NadekoBot.Modules.Pokemon.PokemonTypes namespace NadekoBot.Modules.Pokemon.PokemonTypes
{ {
class WaterType : IPokeType class WaterType : PokeType
{ {
static readonly string name = "WATER"; static readonly string name = "WATER";
public static int numType = 2; public static int numType = 2;
public double GetMagnifier(IPokeType target) public double Multiplier(PokeType target)
{ {
switch (target.GetName()) switch (target.Name)
{ {
case "FIRE": return 2; case "FIRE": return 2;
@ -30,23 +24,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
} }
List<string> moves = new List<string>(); List<string> moves = new List<string>();
public string Name => name;
public string Image => "💦";
public int Num => numType;
public string GetName()
{
return name;
}
public string GetImage()
{
return "💦";
}
public int GetNum()
{
return numType;
}
} }
} }

View File

@ -317,9 +317,62 @@ $@"🌍 **Weather for** 【{obj["target"]}】
.Description("Shows a random quote.") .Description("Shows a random quote.")
.Do(async e => .Do(async e =>
{ {
await var quote = NadekoBot.Config.Quotes[rng.Next(0, NadekoBot.Config.Quotes.Count)].ToString();
e.Channel.SendMessage( await e.Channel.SendMessage(quote);
NadekoBot.Config.Quotes[new Random().Next(0, NadekoBot.Config.Quotes.Count)].ToString()); });
cgb.CreateCommand(Prefix + "catfact")
.Description("Shows a random catfact from <http://catfacts-api.appspot.com/api/facts>")
.Do(async e =>
{
var response = await SearchHelper.GetResponseStringAsync("http://catfacts-api.appspot.com/api/facts");
if (response == null)
return;
await e.Channel.SendMessage($"🐈 `{JObject.Parse(response)["facts"][0].ToString()}`");
});
cgb.CreateCommand(Prefix + "yomama")
.Alias(Prefix + "ym")
.Description("Shows a random joke from <http://api.yomomma.info/>")
.Do(async e =>
{
var response = await SearchHelper.GetResponseStringAsync("http://api.yomomma.info/");
await e.Channel.SendMessage("`" + JObject.Parse(response)["joke"].ToString() + "` 😆");
});
cgb.CreateCommand(Prefix + "randjoke")
.Alias(Prefix + "rj")
.Description("Shows a random joke from <http://tambal.azurewebsites.net/joke/random>")
.Do(async e =>
{
var response = await SearchHelper.GetResponseStringAsync("http://tambal.azurewebsites.net/joke/random");
await e.Channel.SendMessage("`" + JObject.Parse(response)["joke"].ToString() + "` 😆");
});
cgb.CreateCommand(Prefix + "chucknorris")
.Alias(Prefix + "cn")
.Description("Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random>")
.Do(async e =>
{
var response = await SearchHelper.GetResponseStringAsync("http://api.icndb.com/jokes/random/");
await e.Channel.SendMessage("`" + JObject.Parse(response)["value"]["joke"].ToString() + "` 😆");
});
cgb.CreateCommand(Prefix + "revav")
.Description("Returns a google reverse image search for someone's avatar.")
.Parameter("user", ParameterType.Unparsed)
.Do(async e =>
{
var usrStr = e.GetArg("user")?.Trim();
if (string.IsNullOrWhiteSpace(usrStr))
return;
var usr = e.Server.FindUsers(usrStr).FirstOrDefault();
if (usr == null || string.IsNullOrWhiteSpace(usr.AvatarUrl))
return;
await e.Channel.SendMessage($"https://images.google.com/searchbyimage?image_url={usr.AvatarUrl}");
}); });
}); });
} }

View File

@ -5,8 +5,10 @@ using Discord.Modules;
using NadekoBot.Classes.JSONModels; using NadekoBot.Classes.JSONModels;
using NadekoBot.Commands; using NadekoBot.Commands;
using NadekoBot.Modules; using NadekoBot.Modules;
using NadekoBot.Modules.Administration;
using NadekoBot.Modules.Gambling; using NadekoBot.Modules.Gambling;
using NadekoBot.Modules.Pokemon; using NadekoBot.Modules.Pokemon;
using NadekoBot.Modules.Translator;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -14,13 +16,12 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using NadekoBot.Modules.Translator;
namespace NadekoBot namespace NadekoBot
{ {
public class NadekoBot public class NadekoBot
{ {
public static DiscordClient Client; public static DiscordClient Client { get; private set; }
public static Credentials Creds { get; set; } public static Credentials Creds { get; set; }
public static Configuration Config { get; set; } public static Configuration Config { get; set; }
public static LocalizedStrings Locale { get; set; } = new LocalizedStrings(); public static LocalizedStrings Locale { get; set; } = new LocalizedStrings();
@ -110,7 +111,7 @@ namespace NadekoBot
Client = new DiscordClient(new DiscordConfigBuilder() Client = new DiscordClient(new DiscordConfigBuilder()
{ {
MessageCacheSize = 10, MessageCacheSize = 10,
ConnectionTimeout = 60000, ConnectionTimeout = 120000,
LogLevel = LogSeverity.Warning, LogLevel = LogSeverity.Warning,
LogHandler = (s, e) => LogHandler = (s, e) =>
Console.WriteLine($"Severity: {e.Severity}" + Console.WriteLine($"Severity: {e.Severity}" +
@ -157,7 +158,7 @@ namespace NadekoBot
})); }));
//install modules //install modules
modules.Add(new Administration(), "Administration", ModuleFilter.None); modules.Add(new AdministrationModule(), "Administration", ModuleFilter.None);
modules.Add(new Help(), "Help", ModuleFilter.None); modules.Add(new Help(), "Help", ModuleFilter.None);
modules.Add(new PermissionModule(), "Permissions", ModuleFilter.None); modules.Add(new PermissionModule(), "Permissions", ModuleFilter.None);
modules.Add(new Conversations(), "Conversations", ModuleFilter.None); modules.Add(new Conversations(), "Conversations", ModuleFilter.None);
@ -167,7 +168,7 @@ namespace NadekoBot
modules.Add(new Searches(), "Searches", ModuleFilter.None); modules.Add(new Searches(), "Searches", ModuleFilter.None);
modules.Add(new NSFW(), "NSFW", ModuleFilter.None); modules.Add(new NSFW(), "NSFW", ModuleFilter.None);
modules.Add(new ClashOfClans(), "ClashOfClans", ModuleFilter.None); modules.Add(new ClashOfClans(), "ClashOfClans", ModuleFilter.None);
modules.Add(new PokemonGame(), "Pokegame", ModuleFilter.None); modules.Add(new PokemonModule(), "Pokegame", ModuleFilter.None);
modules.Add(new TranslatorModule(), "Translator", ModuleFilter.None); modules.Add(new TranslatorModule(), "Translator", ModuleFilter.None);
if (!string.IsNullOrWhiteSpace(Creds.TrelloAppKey)) if (!string.IsNullOrWhiteSpace(Creds.TrelloAppKey))
modules.Add(new Trello(), "Trello", ModuleFilter.None); modules.Add(new Trello(), "Trello", ModuleFilter.None);

View File

@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>NadekoBot</RootNamespace> <RootNamespace>NadekoBot</RootNamespace>
<AssemblyName>NadekoBot</AssemblyName> <AssemblyName>NadekoBot</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion> <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<IsWebBootstrapper>false</IsWebBootstrapper> <IsWebBootstrapper>false</IsWebBootstrapper>
@ -32,6 +32,7 @@
<BootstrapperEnabled>true</BootstrapperEnabled> <BootstrapperEnabled>true</BootstrapperEnabled>
<NuGetPackageImportStamp> <NuGetPackageImportStamp>
</NuGetPackageImportStamp> </NuGetPackageImportStamp>
<TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
@ -145,27 +146,30 @@
<Compile Include="Classes\_DataModels\IDataModel.cs" /> <Compile Include="Classes\_DataModels\IDataModel.cs" />
<Compile Include="Classes\_DataModels\pokemoves.cs" /> <Compile Include="Classes\_DataModels\pokemoves.cs" />
<Compile Include="Classes\_DataModels\PokeTypes.cs" /> <Compile Include="Classes\_DataModels\PokeTypes.cs" />
<Compile Include="Classes\_DataModels\Reminder.cs" />
<Compile Include="Classes\_DataModels\RequestModel.cs" /> <Compile Include="Classes\_DataModels\RequestModel.cs" />
<Compile Include="Classes\_DataModels\StatsModel.cs" /> <Compile Include="Classes\_DataModels\StatsModel.cs" />
<Compile Include="Classes\_DataModels\TypingArticleModel.cs" /> <Compile Include="Classes\_DataModels\TypingArticleModel.cs" />
<Compile Include="Classes\_DataModels\UserQuoteModel.cs" /> <Compile Include="Classes\_DataModels\UserQuoteModel.cs" />
<Compile Include="Commands\BetrayGame.cs" /> <Compile Include="Commands\BetrayGame.cs" />
<Compile Include="Commands\CrossServerTextChannel.cs" /> <Compile Include="Commands\PlantPick.cs" />
<Compile Include="Commands\SelfAssignedRolesCommand.cs" /> <Compile Include="Modules\Administration\Commands\CrossServerTextChannel.cs" />
<Compile Include="Modules\Administration\Commands\Remind.cs" />
<Compile Include="Modules\Administration\Commands\SelfAssignedRolesCommand.cs" />
<Compile Include="Modules\ClashOfClans.cs" /> <Compile Include="Modules\ClashOfClans.cs" />
<Compile Include="Commands\FilterWordsCommand.cs" /> <Compile Include="Commands\FilterWordsCommand.cs" />
<Compile Include="Commands\FilterInvitesCommand.cs" /> <Compile Include="Commands\FilterInvitesCommand.cs" />
<Compile Include="Commands\LogCommand.cs" /> <Compile Include="Modules\Administration\Commands\LogCommand.cs" />
<Compile Include="Commands\LoLCommands.cs" /> <Compile Include="Commands\LoLCommands.cs" />
<Compile Include="Commands\MessageRepeater.cs" /> <Compile Include="Modules\Administration\Commands\MessageRepeater.cs" />
<Compile Include="Commands\PlayingRotate.cs" /> <Compile Include="Modules\Administration\Commands\PlayingRotate.cs" />
<Compile Include="Commands\StreamNotifications.cs" /> <Compile Include="Commands\StreamNotifications.cs" />
<Compile Include="Commands\TriviaCommand.cs" /> <Compile Include="Commands\TriviaCommand.cs" />
<Compile Include="Classes\Trivia\TriviaGame.cs" /> <Compile Include="Classes\Trivia\TriviaGame.cs" />
<Compile Include="Classes\Trivia\TriviaQuestion.cs" /> <Compile Include="Classes\Trivia\TriviaQuestion.cs" />
<Compile Include="Classes\Trivia\TriviaQuestionPool.cs" /> <Compile Include="Classes\Trivia\TriviaQuestionPool.cs" />
<Compile Include="Commands\RequestsCommand.cs" /> <Compile Include="Commands\RequestsCommand.cs" />
<Compile Include="Commands\ServerGreetCommand.cs" /> <Compile Include="Modules\Administration\Commands\ServerGreetCommand.cs" />
<Compile Include="Commands\SpeedTyping.cs" /> <Compile Include="Commands\SpeedTyping.cs" />
<Compile Include="Modules\Gambling\Helpers\Cards.cs" /> <Compile Include="Modules\Gambling\Helpers\Cards.cs" />
<Compile Include="Classes\Extensions.cs" /> <Compile Include="Classes\Extensions.cs" />
@ -175,9 +179,9 @@
<Compile Include="Modules\Gambling\DrawCommand.cs" /> <Compile Include="Modules\Gambling\DrawCommand.cs" />
<Compile Include="Modules\Gambling\FlipCoinCommand.cs" /> <Compile Include="Modules\Gambling\FlipCoinCommand.cs" />
<Compile Include="Commands\HelpCommand.cs" /> <Compile Include="Commands\HelpCommand.cs" />
<Compile Include="Commands\VoiceNotificationCommand.cs" /> <Compile Include="Modules\Administration\Commands\VoiceNotificationCommand.cs" />
<Compile Include="Commands\VoicePlusTextCommand.cs" /> <Compile Include="Modules\Administration\Commands\VoicePlusTextCommand.cs" />
<Compile Include="Modules\Administration.cs" /> <Compile Include="Modules\Administration\AdministrationModule.cs" />
<Compile Include="Modules\Conversations.cs" /> <Compile Include="Modules\Conversations.cs" />
<Compile Include="Modules\DiscordModule.cs" /> <Compile Include="Modules\DiscordModule.cs" />
<Compile Include="Modules\Gambling\GamblingModule.cs" /> <Compile Include="Modules\Gambling\GamblingModule.cs" />
@ -187,9 +191,10 @@
<Compile Include="Commands\PollCommand.cs" /> <Compile Include="Commands\PollCommand.cs" />
<Compile Include="Modules\NSFW.cs" /> <Compile Include="Modules\NSFW.cs" />
<Compile Include="Modules\Permissions.cs" /> <Compile Include="Modules\Permissions.cs" />
<Compile Include="Commands\RatelimitCommand.cs" /> <Compile Include="Modules\Administration\Commands\RatelimitCommand.cs" />
<Compile Include="Modules\Pokemon\DefaultMoves.cs" /> <Compile Include="Modules\Pokemon\DefaultMoves.cs" />
<Compile Include="Modules\Pokemon\PokemonModule.cs" /> <Compile Include="Modules\Pokemon\PokemonModule.cs" />
<Compile Include="Modules\Pokemon\PokemonTypes\FairyType.cs" />
<Compile Include="Modules\Pokemon\PokemonTypes\IPokeTypeExtensions.cs" /> <Compile Include="Modules\Pokemon\PokemonTypes\IPokeTypeExtensions.cs" />
<Compile Include="Modules\Pokemon\PokemonTypes\PokeType.cs" /> <Compile Include="Modules\Pokemon\PokemonTypes\PokeType.cs" />
<Compile Include="Modules\Pokemon\PokemonTypes\PsychicType.cs" /> <Compile Include="Modules\Pokemon\PokemonTypes\PsychicType.cs" />

View File

@ -16,7 +16,7 @@
"Gambling": "$", "Gambling": "$",
"Permissions": ";", "Permissions": ";",
"Programming": "%", "Programming": "%",
"Pokemon": "poke" "Pokemon": ">"
}, },
"ServerBlacklist": [], "ServerBlacklist": [],
"ChannelBlacklist": [], "ChannelBlacklist": [],

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -9,7 +9,7 @@
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net452" /> <package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net452" />
<package id="Newtonsoft.Json" version="8.0.2" targetFramework="net452" /> <package id="Newtonsoft.Json" version="8.0.2" targetFramework="net452" />
<package id="Parse" version="1.6.2" targetFramework="net452" /> <package id="Parse" version="1.6.2" targetFramework="net452" />
<package id="RestSharp" version="105.2.3" targetFramework="net452" /> <package id="RestSharp" version="105.2.3" targetFramework="net452" requireReinstallation="true" />
<package id="sqlite-net" version="1.0.8" targetFramework="net452" /> <package id="sqlite-net" version="1.0.8" targetFramework="net452" />
<package id="taglib" version="2.1.0.0" targetFramework="net452" /> <package id="taglib" version="2.1.0.0" targetFramework="net452" />
<package id="VideoLibrary" version="1.3.3" targetFramework="net452" /> <package id="VideoLibrary" version="1.3.3" targetFramework="net452" />

View File

@ -8,7 +8,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Tests</RootNamespace> <RootNamespace>Tests</RootNamespace>
<AssemblyName>Tests</AssemblyName> <AssemblyName>Tests</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion> <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion> <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>

View File

@ -2,7 +2,7 @@
######You can donate on paypal: `nadekodiscordbot@gmail.com` or Bitcoin `17MZz1JAqME39akMLrVT4XBPffQJ2n1EPa` ######You can donate on paypal: `nadekodiscordbot@gmail.com` or Bitcoin `17MZz1JAqME39akMLrVT4XBPffQJ2n1EPa`
#NadekoBot List Of Commands #NadekoBot List Of Commands
Version: `NadekoBot v0.9.5930.23184` Version: `NadekoBot v0.9.5933.23628`
### Administration ### Administration
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
@ -31,6 +31,7 @@ Command and aliases | Description | Usage
`.lsar` | Lits all self-assignable roles. `.lsar` | Lits all self-assignable roles.
`.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | .iam Gamer `.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | .iam Gamer
`.iamn`, `.iamnot` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | .iamn Gamer `.iamn`, `.iamnot` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | .iamn Gamer
`.remind` |
`.sr`, `.setrole` | Sets a role for a given user. | .sr @User Guest `.sr`, `.setrole` | Sets a role for a given user. | .sr @User Guest
`.rr`, `.removerole` | Removes a role from a given user. | .rr @User Admin `.rr`, `.removerole` | Removes a role from a given user. | .rr @User Admin
`.r`, `.role`, `.cr` | Creates a role with a given name. | .r Awesome Role `.r`, `.role`, `.cr` | Creates a role with a given name. | .r Awesome Role
@ -46,7 +47,7 @@ Command and aliases | Description | Usage
`.vch`, `.cvch` | Creates a new voice channel with a given name. `.vch`, `.cvch` | Creates a new voice channel with a given name.
`.rch`, `.rtch` | Removes a text channel with a given name. `.rch`, `.rtch` | Removes a text channel with a given name.
`.ch`, `.tch` | Creates a new text channel with a given name. `.ch`, `.tch` | Creates a new text channel with a given name.
`.st`, `.settopic` | Sets a topic on the current channel. `.st`, `.settopic`, `.topic` | Sets a topic on the current channel.
`.uid`, `.userid` | Shows user ID. `.uid`, `.userid` | Shows user ID.
`.cid`, `.channelid` | Shows current channel ID. `.cid`, `.channelid` | Shows current channel ID.
`.sid`, `.serverid` | Shows current server ID. `.sid`, `.serverid` | Shows current server ID.
@ -70,7 +71,6 @@ Command and aliases | Description | Usage
`.unstuck` | Clears the message queue. **Owner Only!** `.unstuck` | Clears the message queue. **Owner Only!**
`.donators` | List of lovely people who donated to keep this project alive. `.donators` | List of lovely people who donated to keep this project alive.
`.adddon`, `.donadd` | Add a donator to the database. `.adddon`, `.donadd` | Add a donator to the database.
`.topic` | Sets current channel's topic.
`.videocall` | 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. `.videocall` | 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.
### Help ### Help
@ -138,7 +138,7 @@ Command and aliases | Description | Usage
`@BotName uptime` | Shows how long Nadeko has been running for. `@BotName uptime` | Shows how long Nadeko has been running for.
`@BotName die` | Works only for the owner. Shuts the bot down. `@BotName die` | Works only for the owner. Shuts the bot down.
`@BotName do you love me` | Replies with positive answer only to the bot owner. `@BotName do you love me` | Replies with positive answer only to the bot owner.
`@BotName how are you` | Replies positive only if bot owner is online. `@BotName how are you`, `@BotName how are you?` | Replies positive only if bot owner is online.
`@BotName insult` | Insults @X person. | @NadekoBot insult @X. `@BotName insult` | Insults @X person. | @NadekoBot insult @X.
`@BotName praise` | Praises @X person. | @NadekoBot praise @X. `@BotName praise` | Praises @X person. | @NadekoBot praise @X.
`@BotName pat` | Pat someone ^_^ `@BotName pat` | Pat someone ^_^
@ -169,8 +169,10 @@ Command and aliases | Description | Usage
`$roll` | Rolls 2 dice from 0-10. If you supply a number [x] it rolls up to 30 normal dice. | $roll [x] `$roll` | Rolls 2 dice from 0-10. If you supply a number [x] it rolls up to 30 normal dice. | $roll [x]
`$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15` `$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15`
`$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. `$raffle` | Prints a name and ID of a random user from the online list from the (optional) role.
`$$$` | Check how many NadekoFlowers you have. `$$$` | Check how much NadekoFlowers you have.
`$give` | Give someone a certain amount of flowers `$give` | Give someone a certain amount of NadekoFlowers
`$award` | Gives someone a certain amount of flowers. **Owner only!**
`$take` | Takes a certain amount of flowers from someone. **Owner only!**
### Games ### Games
Command and aliases | Description | Usage Command and aliases | Description | Usage
@ -185,15 +187,13 @@ Command and aliases | Description | Usage
`>pollend` | Stops active poll on this server and prints the results in this channel. `>pollend` | Stops active poll on this server and prints the results in this channel.
`>choose` | Chooses a thing from a list of things | >choose Get up;Sleep;Sleep more `>choose` | Chooses a thing from a list of things | >choose Get up;Sleep;Sleep more
`>8ball` | Ask the 8ball a yes/no question. `>8ball` | Ask the 8ball a yes/no question.
`>attack` | Attack a person. Supported attacks: 'splash', 'strike', 'burn', 'surge'. | >attack strike @User `>rps` | Play a game of rocket paperclip scissors with Nadeko. | >rps scissors
`>poketype` | Gets the users element type. Use this to do more damage with strike!
`>rps` | Play a game of rocket paperclip scissors with nadkeo. | >rps scissors
`>linux` | Prints a customizable Linux interjection `>linux` | Prints a customizable Linux interjection
### Music ### Music
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------
`!m n`, `!m next` | Goes to the next song in the queue. `!m n`, `!m next`, `!m skip` | Goes to the next song in the queue.
`!m s`, `!m stop` | Stops the music and clears the playlist. Stays in the channel. `!m s`, `!m stop` | Stops the music and clears the playlist. Stays in the channel.
`!m d`, `!m destroy` | Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) `!m d`, `!m destroy` | Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour)
`!m p`, `!m pause` | Pauses or Unpauses the song. `!m p`, `!m pause` | Pauses or Unpauses the song.
@ -209,7 +209,7 @@ Command and aliases | Description | Usage
`!m setgame` | Sets the game of the bot to the number of songs playing. **Owner only** `!m setgame` | Sets the game of the bot to the number of songs playing. **Owner only**
`!m pl` | Queues up to 25 songs from a youtube playlist specified by a link, or keywords. `!m pl` | Queues up to 25 songs from a youtube playlist specified by a link, or keywords.
`!m lopl` | Queues up to 50 songs from a directory. **Owner Only!** `!m lopl` | Queues up to 50 songs from a directory. **Owner Only!**
`!m radio`, `!m ra` | Queues a direct radio stream from a link. `!m radio`, `!m ra` | Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf
`!m lo` | Queues a local file by specifying a full path. **Owner Only!** `!m lo` | Queues a local file by specifying a full path. **Owner Only!**
`!m mv` | Moves the bot to your voice channel. (works only if music is already playing) `!m mv` | Moves the bot to your voice channel. (works only if music is already playing)
`!m rm` | Remove a song by its # in the queue, or 'all' to remove whole queue. `!m rm` | Remove a song by its # in the queue, or 'all' to remove whole queue.
@ -222,6 +222,7 @@ Command and aliases | Description | Usage
`~lolban` | Shows top 6 banned champions ordered by ban rate. Ban these champions and you will be Plat 5 in no time. `~lolban` | Shows top 6 banned champions ordered by ban rate. Ban these champions and you will be Plat 5 in no time.
`~hitbox`, `~hb` | Notifies this channel when a certain user starts streaming. | ~hitbox SomeStreamer `~hitbox`, `~hb` | Notifies this channel when a certain user starts streaming. | ~hitbox SomeStreamer
`~twitch`, `~tw` | Notifies this channel when a certain user starts streaming. | ~twitch SomeStreamer `~twitch`, `~tw` | Notifies this channel when a certain user starts streaming. | ~twitch SomeStreamer
`~beam`, `~bm` | Notifies this channel when a certain user starts streaming. | ~beam SomeStreamer
`~removestream`, `~rms` | Removes notifications of a certain streamer on this channel. | ~rms SomeGuy `~removestream`, `~rms` | Removes notifications of a certain streamer on this channel. | ~rms SomeGuy
`~liststreams`, `~ls` | Lists all streams you are following on this server. | ~ls `~liststreams`, `~ls` | Lists all streams you are following on this server. | ~ls
`~we` | Shows weather data for a specified city and a country BOTH ARE REQUIRED. Weather api is very random if you make a mistake. `~we` | Shows weather data for a specified city and a country BOTH ARE REQUIRED. Weather api is very random if you make a mistake.
@ -238,12 +239,11 @@ Command and aliases | Description | Usage
`~ud` | Searches Urban Dictionary for a word. | ~ud Pineapple `~ud` | Searches Urban Dictionary for a word. | ~ud Pineapple
`~#` | Searches Tagdef.com for a hashtag. | ~# ff `~#` | Searches Tagdef.com for a hashtag. | ~# ff
`~quote` | Shows a random quote. `~quote` | Shows a random quote.
`~catfact` | Shows a random catfact from <http://catfacts-api.appspot.com/api/facts>
### Translator `~yomama`, `~ym` | Shows a random joke from <http://api.yomomma.info/>
Command and aliases | Description | Usage `~randjoke`, `~rj` | Shows a random joke from <http://tambal.azurewebsites.net/joke/random>
----------------|--------------|------- `~chucknorris`, `~cn` | Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random>
`~trans` | Translates from>to text. From the given language to the destiation language. `~revav` | Returns a google reverse image search for someone's avatar.
`~translangs` | List the valid languages for translation.
### NSFW ### NSFW
Command and aliases | Description | Usage Command and aliases | Description | Usage
@ -267,6 +267,21 @@ Command and aliases | Description | Usage
`,unclaim`, `,uncall`, `,uc` | Removes your claim from a certain war. Optional second argument denotes a person in whos place to unclaim | ,uc [war_number] [optional_other_name] `,unclaim`, `,uncall`, `,uc` | Removes your claim from a certain war. Optional second argument denotes a person in whos place to unclaim | ,uc [war_number] [optional_other_name]
`,endwar`, `,ew` | Ends the war with a given index. | ,ew [war_number] `,endwar`, `,ew` | Ends the war with a given index. | ,ew [war_number]
### Pokegame
Command and aliases | Description | Usage
----------------|--------------|-------
`>attack` | Attacks a target with the given move
`>ml`, `movelist` | Lists the moves you are able to use
`>heal` | Heals someone. Revives those that fainted. Costs a NadekoFlower | >revive @someone
`>type` | Get the poketype of the target. | >type @someone
`>settype` | Set your poketype. Costs a NadekoFlower. | >settype fire
### Translator
Command and aliases | Description | Usage
----------------|--------------|-------
`~trans` | Translates from>to text. From the given language to the destiation language.
`~translangs` | List the valid languages for translation.
### Trello ### Trello
Command and aliases | Description | Usage Command and aliases | Description | Usage
----------------|--------------|------- ----------------|--------------|-------