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/
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
**/Bin/Debug/**
**/Bin/Release/
**/Bin/PRIVATE/
!**/Bin/Debug/opus.dll
@ -19,9 +18,11 @@ obj/
!**/Bin/Debug/Nito.AsyncEx.dll
!**/Bin/Debug/WebSocket4Net.dll
!**/Bin/Debug/sqlite3.dll
!**/Bin/Debug/data/*
!**/Bin/Debug/data/
!**/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
# 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 System.Linq;
using NadekoBot.Classes._DataModels;
using SQLite;
using NadekoBot.Classes._DataModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace NadekoBot.Classes {
internal class DbHandler {
namespace NadekoBot.Classes
{
internal class DbHandler
{
public static DbHandler Instance { get; } = new DbHandler();
private string FilePath { get; } = "data/nadekobot.sqlite";
static DbHandler() { }
public DbHandler() {
using (var conn = new SQLiteConnection(FilePath)) {
public DbHandler()
{
using (var conn = new SQLiteConnection(FilePath))
{
conn.CreateTable<Stats>();
conn.CreateTable<Command>();
conn.CreateTable<Announcement>();
@ -23,44 +27,83 @@ namespace NadekoBot.Classes {
conn.CreateTable<CurrencyTransaction>();
conn.CreateTable<Donator>();
conn.CreateTable<PokeMoves>();
conn.CreateTable<userPokeTypes>();
conn.CreateTable<UserPokeTypes>();
conn.CreateTable<UserQuote>();
conn.CreateTable<Reminder>();
conn.Execute(Queries.TransactionTriggerQuery);
}
}
internal void InsertData<T>(T o) where T : IDataModel {
using (var conn = new SQLiteConnection(FilePath)) {
internal T FindOne<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
{
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));
}
}
internal void InsertMany<T>(T objects) where T : IEnumerable<IDataModel> {
using (var conn = new SQLiteConnection(FilePath)) {
internal void InsertMany<T>(T objects) where T : IEnumerable<IDataModel>
{
using (var conn = new SQLiteConnection(FilePath))
{
conn.InsertAll(objects);
}
}
internal void UpdateData<T>(T o) where T : IDataModel {
using (var conn = new SQLiteConnection(FilePath)) {
internal void UpdateData<T>(T o) where T : IDataModel
{
using (var conn = new SQLiteConnection(FilePath))
{
conn.Update(o, typeof(T));
}
}
internal HashSet<T> GetAllRows<T>() where T : IDataModel, new() {
using (var conn = new SQLiteConnection(FilePath)) {
internal HashSet<T> GetAllRows<T>() where T : IDataModel, new()
{
using (var conn = new SQLiteConnection(FilePath))
{
return new HashSet<T>(conn.Table<T>());
}
}
internal CurrencyState GetStateByUserId(long id) {
using (var conn = new SQLiteConnection(FilePath)) {
internal CurrencyState GetStateByUserId(long id)
{
using (var conn = new SQLiteConnection(FilePath))
{
return conn.Table<CurrencyState>().Where(x => x.UserId == id).FirstOrDefault();
}
}
internal T Delete<T>(int id) where T : IDataModel, new() {
using (var conn = new SQLiteConnection(FilePath)) {
internal T Delete<T>(int id) where T : IDataModel, new()
{
using (var conn = new SQLiteConnection(FilePath))
{
var found = conn.Find<T>(id);
if (found != null)
conn.Delete<T>(found.Id);
@ -71,8 +114,10 @@ namespace NadekoBot.Classes {
/// <summary>
/// Updates an existing object or creates a new one
/// </summary>
internal void Save<T>(T o) where T : IDataModel, new() {
using (var conn = new SQLiteConnection(FilePath)) {
internal void Save<T>(T o) where T : IDataModel, new()
{
using (var conn = new SQLiteConnection(FilePath))
{
var found = conn.Find<T>(o.Id);
if (found == null)
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() {
using (var conn = new SQLiteConnection(FilePath)) {
internal T GetRandom<T>(Expression<Func<T, bool>> p) where T : IDataModel, new()
{
using (var conn = new SQLiteConnection(FilePath))
{
var r = new Random();
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 = @"
CREATE TRIGGER IF NOT EXISTS OnTransactionAdded
AFTER INSERT ON CurrencyTransaction

View File

@ -4,7 +4,7 @@ namespace NadekoBot.Classes
{
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)
return;
@ -17,6 +17,10 @@ namespace NadekoBot.Classes
Value = amount,
});
});
if (silent)
return;
var flows = "";
for (var i = 0; i < amount; i++)
{
@ -25,19 +29,23 @@ namespace NadekoBot.Classes
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)
return;
await Task.Run(() =>
{
return false;
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
{
Reason = reason,
UserId = (long)u.Id,
Value = -amount,
});
});
return true;
}
}
}

View File

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

View File

@ -5,15 +5,18 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace NadekoBot.Classes.Music {
namespace NadekoBot.Classes.Music
{
public enum MusicType {
public enum MusicType
{
Radio,
Normal,
Local
}
public enum StreamState {
public enum StreamState
{
Resolving,
Queued,
Buffering, //not using it atm
@ -21,7 +24,8 @@ namespace NadekoBot.Classes.Music {
Completed
}
public class MusicPlayer {
public class MusicPlayer
{
public static int MaximumPlaylistSize => 50;
private IAudioClient audioClient { get; set; }
@ -44,8 +48,11 @@ namespace NadekoBot.Classes.Music {
public Channel PlaybackVoiceChannel { get; private set; }
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)
throw new ArgumentNullException(nameof(startingVoiceChannel));
if (startingVoiceChannel.Type != ChannelType.Voice)
@ -56,27 +63,42 @@ namespace NadekoBot.Classes.Music {
SongCancelSource = new CancellationTokenSource();
cancelToken = SongCancelSource.Token;
Task.Run(async () => {
while (!Destroyed) {
try {
Task.Run(async () =>
{
while (!Destroyed)
{
try
{
if (audioClient?.State != ConnectionState.Connected)
audioClient = await PlaybackVoiceChannel.JoinAudio();
} catch {
}
catch
{
await Task.Delay(1000);
continue;
}
CurrentSong = GetNextSong();
var curSong = CurrentSong;
if (curSong != null) {
try {
if (curSong != null)
{
try
{
OnStarted(this, curSong);
await curSong.Play(audioClient, cancelToken);
} catch (OperationCanceledException) {
}
catch (OperationCanceledException)
{
Console.WriteLine("Song canceled");
} catch (Exception ex) {
}
catch (Exception ex)
{
Console.WriteLine($"Exception in PlaySong: {ex}");
}
OnCompleted(this, curSong);
if (RepeatSong)
playlist.Insert(0, curSong);
else if (RepeatPlaylist)
playlist.Insert(playlist.Count, curSong);
SongCancelSource = new CancellationTokenSource();
cancelToken = SongCancelSource.Token;
}
@ -85,17 +107,22 @@ namespace NadekoBot.Classes.Music {
});
}
public void Next() {
lock (playlistLock) {
if (!SongCancelSource.IsCancellationRequested) {
public void Next()
{
lock (playlistLock)
{
if (!SongCancelSource.IsCancellationRequested)
{
Paused = false;
SongCancelSource.Cancel();
}
}
}
public void Stop() {
lock (playlistLock) {
public void Stop()
{
lock (playlistLock)
{
playlist.Clear();
CurrentSong = null;
if (!SongCancelSource.IsCancellationRequested)
@ -105,13 +132,16 @@ namespace NadekoBot.Classes.Music {
public void TogglePause() => Paused = !Paused;
public void Shuffle() {
lock (playlistLock) {
public void Shuffle()
{
lock (playlistLock)
{
playlist.Shuffle();
}
}
public int SetVolume(int volume) {
public int SetVolume(int volume)
{
if (volume < 0)
volume = 0;
if (volume > 150)
@ -121,8 +151,10 @@ namespace NadekoBot.Classes.Music {
return volume;
}
private Song GetNextSong() {
lock (playlistLock) {
private Song GetNextSong()
{
lock (playlistLock)
{
if (playlist.Count == 0)
return null;
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)
throw new ArgumentNullException(nameof(s));
lock (playlistLock) {
lock (playlistLock)
{
playlist.Add(s);
}
}
public void RemoveSong(Song s) {
public void RemoveSong(Song s)
{
if (s == null)
throw new ArgumentNullException(nameof(s));
lock (playlistLock) {
lock (playlistLock)
{
playlist.Remove(s);
}
}
public void RemoveSongAt(int index) {
lock (playlistLock) {
public void RemoveSongAt(int index)
{
lock (playlistLock)
{
if (index < 0 || index >= playlist.Count)
throw new ArgumentException("Invalid index");
playlist.RemoveAt(index);
}
}
internal Task MoveToVoiceChannel(Channel voiceChannel) {
internal Task MoveToVoiceChannel(Channel voiceChannel)
{
if (audioClient?.State != ConnectionState.Connected)
throw new InvalidOperationException("Can't move while bot is not connected to voice channel.");
PlaybackVoiceChannel = voiceChannel;
return PlaybackVoiceChannel.JoinAudio();
}
internal void ClearQueue() {
lock (playlistLock) {
internal void ClearQueue()
{
lock (playlistLock)
{
playlist.Clear();
}
}
public void Destroy() {
lock (playlistLock) {
public void Destroy()
{
lock (playlistLock)
{
playlist.Clear();
Destroyed = true;
CurrentSong = null;
@ -178,5 +221,9 @@ namespace NadekoBot.Classes.Music {
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.Commands;
using NadekoBot.Extensions;
using NadekoBot.Modules;
using NadekoBot.Modules.Administration.Commands;
using System;
using System.Diagnostics;
using System.Linq;
using NadekoBot.Extensions;
using System.Threading.Tasks;
using System.Reflection;
using System.Threading.Tasks;
using System.Timers;
using NadekoBot.Modules;
namespace NadekoBot {
public class NadekoStats {
namespace NadekoBot
{
public class NadekoStats
{
public static NadekoStats Instance { get; } = new NadekoStats();
public string BotVersion => $"{Assembly.GetExecutingAssembly().GetName().Name} v{Assembly.GetExecutingAssembly().GetName().Version}";
@ -27,7 +30,8 @@ namespace NadekoBot {
static NadekoStats() { }
private NadekoStats() {
private NadekoStats()
{
var commandService = NadekoBot.Client.GetService<CommandService>();
statsStopwatch.Start();
@ -43,52 +47,66 @@ namespace NadekoBot {
TextChannelsCount = channelsArray.Count(c => c.Type == ChannelType.Text);
VoiceChannelsCount = channelsArray.Count() - TextChannelsCount;
NadekoBot.Client.JoinedServer += (s, e) => {
try {
NadekoBot.Client.JoinedServer += (s, e) =>
{
try
{
ServerCount++;
TextChannelsCount += e.Server.TextChannels.Count();
VoiceChannelsCount += e.Server.VoiceChannels.Count();
} catch { }
}
catch { }
};
NadekoBot.Client.LeftServer += (s, e) => {
try {
NadekoBot.Client.LeftServer += (s, e) =>
{
try
{
ServerCount--;
TextChannelsCount -= e.Server.TextChannels.Count();
VoiceChannelsCount -= e.Server.VoiceChannels.Count();
} catch { }
}
catch { }
};
NadekoBot.Client.ChannelCreated += (s, e) => {
try {
NadekoBot.Client.ChannelCreated += (s, e) =>
{
try
{
if (e.Channel.IsPrivate)
return;
if (e.Channel.Type == ChannelType.Text)
TextChannelsCount++;
else if (e.Channel.Type == ChannelType.Voice)
VoiceChannelsCount++;
} catch { }
}
catch { }
};
NadekoBot.Client.ChannelDestroyed += (s, e) => {
try {
NadekoBot.Client.ChannelDestroyed += (s, e) =>
{
try
{
if (e.Channel.IsPrivate)
return;
if (e.Channel.Type == ChannelType.Text)
VoiceChannelsCount++;
else if (e.Channel.Type == ChannelType.Voice)
VoiceChannelsCount--;
} catch { }
}
catch { }
};
}
public TimeSpan GetUptime() =>
DateTime.Now - Process.GetCurrentProcess().StartTime;
public string GetUptimeString() {
public string GetUptimeString()
{
var time = (DateTime.Now - Process.GetCurrentProcess().StartTime);
return time.Days + " days, " + time.Hours + " hours, and " + time.Minutes + " minutes.";
}
public Task LoadStats() =>
Task.Run(() => {
Task.Run(() =>
{
var songs = Music.MusicPlayers.Count(mp => mp.Value.CurrentSong != null);
var sb = new System.Text.StringBuilder();
sb.AppendLine("`Author: Kwoth` `Library: Discord.Net`");
@ -102,7 +120,7 @@ namespace NadekoBot {
sb.AppendLine($" | VoiceChannels: {VoiceChannelsCount}`");
sb.AppendLine($"`Commands Ran this session: {commandsRan}`");
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) +
$"{Music.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count)} queued.`");
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 async Task<string> GetStats() {
public async Task<string> GetStats()
{
if (statsStopwatch.Elapsed.Seconds < 4 &&
!string.IsNullOrWhiteSpace(statsCache)) return statsCache;
await LoadStats();
@ -119,35 +138,45 @@ namespace NadekoBot {
return statsCache;
}
private async Task StartCollecting() {
while (true) {
private async Task StartCollecting()
{
while (true)
{
await Task.Delay(new TimeSpan(0, 30, 0));
try {
try
{
var onlineUsers = await Task.Run(() => NadekoBot.Client.Servers.Sum(x => x.Users.Count()));
var realOnlineUsers = await Task.Run(() => NadekoBot.Client.Servers
.Sum(x => x.Users.Count(u => u.Status == UserStatus.Online)));
var connectedServers = NadekoBot.Client.Servers.Count();
Classes.DbHandler.Instance.InsertData(new Classes._DataModels.Stats {
Classes.DbHandler.Instance.InsertData(new Classes._DataModels.Stats
{
OnlineUsers = onlineUsers,
RealOnlineUsers = realOnlineUsers,
Uptime = GetUptime(),
ConnectedServers = connectedServers,
DateAdded = DateTime.Now
});
} catch {
}
catch
{
Console.WriteLine("DB Exception in stats collecting.");
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}");
await Task.Run(() => {
try {
await Task.Run(() =>
{
try
{
commandsRan++;
Classes.DbHandler.Instance.InsertData(new Classes._DataModels.Command {
Classes.DbHandler.Instance.InsertData(new Classes._DataModels.Command
{
ServerId = (long)e.Server.Id,
ServerName = e.Server.Name,
ChannelId = (long)e.Channel.Id,
@ -157,7 +186,9 @@ namespace NadekoBot {
CommandName = e.Command.Text,
DateAdded = DateTime.Now
});
} catch {
}
catch
{
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.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using NadekoBot.Classes.JSONModels;
using Newtonsoft.Json;
namespace NadekoBot.Classes {
internal class SpecificConfigurations {
namespace NadekoBot.Classes
{
internal class SpecificConfigurations
{
public static SpecificConfigurations Default { get; } = new SpecificConfigurations();
public static bool Instantiated { get; private set; }
@ -17,14 +18,19 @@ namespace NadekoBot.Classes {
static SpecificConfigurations() { }
private SpecificConfigurations() {
private SpecificConfigurations()
{
if (File.Exists(filePath)) {
try {
if (File.Exists(filePath))
{
try
{
configs = JsonConvert
.DeserializeObject<ConcurrentDictionary<ulong, ServerSpecificConfig>>(
File.ReadAllText(filePath));
} catch (Exception ex) {
}
catch (Exception ex)
{
Console.WriteLine($"Deserialization failing: {ex}");
}
}
@ -42,14 +48,17 @@ namespace NadekoBot.Classes {
private readonly object saveLock = new object();
public void Save() {
lock (saveLock) {
public void Save()
{
lock (saveLock)
{
File.WriteAllText(filePath, JsonConvert.SerializeObject(configs, Formatting.Indented));
}
}
}
internal class ServerSpecificConfig : INotifyPropertyChanged {
internal class ServerSpecificConfig : INotifyPropertyChanged
{
[JsonProperty("VoicePlusTextEnabled")]
private bool voicePlusTextEnabled;
[JsonIgnore]
@ -78,7 +87,8 @@ namespace NadekoBot.Classes {
set {
listOfSelfAssignableRoles = value;
if (value != null)
listOfSelfAssignableRoles.CollectionChanged += (s, e) => {
listOfSelfAssignableRoles.CollectionChanged += (s, e) =>
{
if (!SpecificConfigurations.Instantiated) return;
OnPropertyChanged();
};
@ -92,34 +102,39 @@ namespace NadekoBot.Classes {
set {
observingStreams = value;
if (value != null)
observingStreams.CollectionChanged += (s, e) => {
observingStreams.CollectionChanged += (s, e) =>
{
if (!SpecificConfigurations.Instantiated) return;
OnPropertyChanged();
};
}
}
public ServerSpecificConfig() {
public ServerSpecificConfig()
{
ListOfSelfAssignableRoles = new ObservableCollection<ulong>();
ObservingStreams = new ObservableCollection<StreamNotificationConfig>();
}
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");
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class StreamNotificationConfig : IEquatable<StreamNotificationConfig> {
public class StreamNotificationConfig : IEquatable<StreamNotificationConfig>
{
public string Username { get; set; }
public StreamType Type { get; set; }
public ulong ServerId { get; set; }
public ulong ChannelId { get; set; }
public bool LastStatus { get; set; }
public enum StreamType {
public enum StreamType
{
Twitch,
Beam,
Hitbox,
@ -131,7 +146,8 @@ namespace NadekoBot.Classes {
this.Type == other.Type &&
this.ServerId == other.ServerId;
public override int GetHashCode() {
public override int GetHashCode()
{
return (int)((int)ServerId + Username.Length + (int)Type);
}
}

View File

@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace NadekoBot.Classes._DataModels
{
class userPokeTypes : IDataModel
class UserPokeTypes : IDataModel
{
public long UserId { 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 System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Discord;
using Discord;
using Discord.Commands;
using NadekoBot.Classes;
using NadekoBot.Classes.Permissions;
using NadekoBot.Modules;
using System;
using System.Linq;
using ServerPermissions = NadekoBot.Classes.Permissions.ServerPermissions;
namespace NadekoBot.Commands {
internal class FilterWords : DiscordCommand {
public FilterWords(DiscordModule module) : base(module) {
NadekoBot.Client.MessageReceived += async (sender, args) => {
namespace NadekoBot.Commands
{
internal class FilterWords : DiscordCommand
{
public FilterWords(DiscordModule module) : base(module)
{
NadekoBot.Client.MessageReceived += async (sender, args) =>
{
if (args.Channel.IsPrivate || args.User.Id == NadekoBot.Client.CurrentUser.Id) return;
try {
try
{
ServerPermissions serverPerms;
if (!IsChannelOrServerFiltering(args.Channel, out serverPerms)) return;
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();
IncidentsHandler.Add(args.Server.Id, $"User [{args.User.Name}/{args.User.Id}] posted " +
$"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 " +
$"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 (serverPerms.Permissions.FilterWords)
@ -44,7 +48,8 @@ namespace NadekoBot.Commands {
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")
.Alias(Module.Prefix + "channelfilterwords")
.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")
.Parameter("bool")
.Parameter("channel", ParameterType.Optional)
.Do(async e => {
try {
.Do(async e =>
{
try
{
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
var chanStr = e.GetArg("channel")?.ToLowerInvariant().Trim();
if (chanStr != "all") {
if (chanStr != "all")
{
var chan = string.IsNullOrWhiteSpace(chanStr)
? e.Channel
: PermissionHelper.ValidateChannel(e.Server, chanStr);
@ -67,11 +75,14 @@ namespace NadekoBot.Commands {
}
//all channels
foreach (var curChannel in e.Server.TextChannels) {
foreach (var curChannel in e.Server.TextChannels)
{
PermissionsHandler.SetChannelWordPermission(curChannel, state);
}
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}");
}
});
@ -81,15 +92,19 @@ namespace NadekoBot.Commands {
.Description("Adds a new word to the list of filtered words" +
"\n**Usage**: ;aw poop")
.Parameter("word", ParameterType.Unparsed)
.Do(async e => {
try {
.Do(async e =>
{
try
{
var word = e.GetArg("word");
if (string.IsNullOrWhiteSpace(word))
return;
PermissionsHandler.AddFilteredWord(e.Server, word.ToLowerInvariant().Trim());
await e.Channel.SendMessage($"Successfully added new filtered word.");
} catch (Exception ex) {
}
catch (Exception ex)
{
await e.Channel.SendMessage($"💢 Error: {ex.Message}");
}
});
@ -99,15 +114,19 @@ namespace NadekoBot.Commands {
.Description("Removes the word from the list of filtered words" +
"\n**Usage**: ;rw poop")
.Parameter("word", ParameterType.Unparsed)
.Do(async e => {
try {
.Do(async e =>
{
try
{
var word = e.GetArg("word");
if (string.IsNullOrWhiteSpace(word))
return;
PermissionsHandler.RemoveFilteredWord(e.Server, word.ToLowerInvariant().Trim());
await e.Channel.SendMessage($"Successfully removed filtered word.");
} catch (Exception ex) {
}
catch (Exception ex)
{
await e.Channel.SendMessage($"💢 Error: {ex.Message}");
}
});
@ -116,14 +135,18 @@ namespace NadekoBot.Commands {
.Alias(Module.Prefix + "listfilteredwords")
.Description("Shows a list of filtered words" +
"\n**Usage**: ;lfw")
.Do(async e => {
try {
.Do(async e =>
{
try
{
ServerPermissions serverPerms;
if (!PermissionsHandler.PermissionsDict.TryGetValue(e.Server.Id, out serverPerms))
return;
await e.Channel.SendMessage($"There are `{serverPerms.Words.Count}` filtered words.\n" +
string.Join("\n", serverPerms.Words));
} catch (Exception ex) {
}
catch (Exception ex)
{
await e.Channel.SendMessage($"💢 Error: {ex.Message}");
}
});
@ -132,13 +155,17 @@ namespace NadekoBot.Commands {
.Alias(Module.Prefix + "serverfilterwords")
.Description("Enables or disables automatic deleting of messages containing forbidden words on the server.\n**Usage**: ;sfi disable")
.Parameter("bool")
.Do(async e => {
try {
.Do(async e =>
{
try
{
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
PermissionsHandler.SetServerWordPermission(e.Server, state);
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}");
}
});

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 Newtonsoft.Json.Linq;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;
using System.Timers;
@ -18,11 +19,15 @@ namespace NadekoBot.Commands
{
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)
{
checkTimer.Elapsed += async (s, e) =>
{
cachedStatuses.Clear();
try
{
var streams = SpecificConfigurations.Default.AllConfigs.SelectMany(c => c.ObservingStreams);
@ -74,23 +79,39 @@ namespace NadekoBot.Commands
bool isLive;
string response;
JObject data;
Tuple<bool, string> result;
switch (stream.Type)
{
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);
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:
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);
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:
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);
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:
break;
}

View File

@ -4,19 +4,19 @@ using Discord.Modules;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels;
using NadekoBot.Classes.Permissions;
using NadekoBot.Commands;
using NadekoBot.Extensions;
using NadekoBot.Modules.Administration.Commands;
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Linq;
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 LogCommand(this));
@ -26,6 +26,7 @@ namespace NadekoBot.Modules
commands.Add(new VoicePlusTextCommand(this));
commands.Add(new CrossServerTextChannel(this));
commands.Add(new SelfAssignedRolesCommand(this));
commands.Add(new Remind(this));
}
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Administration;
@ -227,6 +228,7 @@ namespace NadekoBot.Modules
try
{
await e.Server.Ban(usr);
await e.Channel.SendMessage("Banned user " + usr.Name + " Id: " + usr.Id);
}
catch
@ -456,6 +458,7 @@ namespace NadekoBot.Modules
cgb.CreateCommand(Prefix + "st").Alias(Prefix + "settopic")
.Alias(Prefix + "topic")
.Description("Sets a topic on the current channel.")
.AddCheck(SimpleCheckers.ManageChannels())
.Parameter("topic", ParameterType.Unparsed)
.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.Generic;
using System.Linq;
using Discord;
using Discord.Commands;
using NadekoBot.Classes.Permissions;
using NadekoBot.Modules;
namespace NadekoBot.Commands {
class CrossServerTextChannel : DiscordCommand {
public CrossServerTextChannel(DiscordModule module) : base(module) {
NadekoBot.Client.MessageReceived += async (s, e) => {
try {
namespace NadekoBot.Modules.Administration.Commands
{
class CrossServerTextChannel : DiscordCommand
{
public CrossServerTextChannel(DiscordModule module) : base(module)
{
NadekoBot.Client.MessageReceived += async (s, e) =>
{
try
{
if (e.User.Id == NadekoBot.Client.CurrentUser.Id) return;
foreach (var subscriber in Subscribers) {
foreach (var subscriber in Subscribers)
{
var set = subscriber.Value;
if (!set.Contains(e.Channel))
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));
}
}
} catch { }
}
catch { }
};
NadekoBot.Client.MessageUpdated += async (s, e) => {
try {
NadekoBot.Client.MessageUpdated += async (s, e) =>
{
try
{
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;
if (!set.Contains(e.Channel))
continue;
foreach (var chan in set.Except(new[] { e.Channel })) {
foreach (var chan in set.Except(new[] { e.Channel }))
{
var msg = chan.Messages
.FirstOrDefault(m =>
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>>();
internal override void Init(CommandGroupBuilder cgb) {
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "scsc")
.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")
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e => {
.Do(async e =>
{
var token = new Random().Next();
var set = new HashSet<Channel>();
if (Subscribers.TryAdd(token, set)) {
if (Subscribers.TryAdd(token, set))
{
set.Add(e.Channel);
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.")
.Parameter("token")
.AddCheck(SimpleCheckers.ManageServer())
.Do(async e => {
.Do(async e =>
{
int token;
if (!int.TryParse(e.GetArg("token"), out token))
return;
@ -80,8 +97,10 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(Module.Prefix + "lcsc")
.Description("Leaves Cross server channel instance from this channel")
.AddCheck(SimpleCheckers.ManageServer())
.Do(async e => {
foreach (var subscriber in Subscribers) {
.Do(async e =>
{
foreach (var subscriber in Subscribers)
{
subscriber.Value.Remove(e.Channel);
}
await e.Channel.SendMessage(":ok:");

View File

@ -2,13 +2,13 @@
using Discord.Commands;
using NadekoBot.Classes;
using NadekoBot.Classes.Permissions;
using NadekoBot.Modules;
using NadekoBot.Commands;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;
namespace NadekoBot.Commands
namespace NadekoBot.Modules.Administration.Commands
{
internal class LogCommand : DiscordCommand
{

View File

@ -1,15 +1,18 @@
using System;
using System.Timers;
using System.Collections.Concurrent;
using Discord;
using NadekoBot.Classes.Permissions;
using Discord;
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 {
class MessageRepeater : DiscordCommand {
namespace NadekoBot.Modules.Administration.Commands
{
class MessageRepeater : DiscordCommand
{
private readonly ConcurrentDictionary<Server, Repeater> repeaters = new ConcurrentDictionary<Server, Repeater>();
private class Repeater {
private class Repeater
{
[Newtonsoft.Json.JsonIgnore]
public Timer MessageTimer { get; set; }
[Newtonsoft.Json.JsonIgnore]
@ -20,21 +23,27 @@ namespace NadekoBot.Commands {
public string RepeatingMessage { get; set; }
public int Interval { get; set; }
public Repeater Start() {
public Repeater Start()
{
MessageTimer = new Timer { Interval = Interval };
MessageTimer.Elapsed += async (s, e) => {
MessageTimer.Elapsed += async (s, e) =>
{
var ch = RepeatingChannel;
var msg = RepeatingMessage;
if (ch != null && !string.IsNullOrWhiteSpace(msg)) {
try {
if (ch != null && !string.IsNullOrWhiteSpace(msg))
{
try
{
await ch.SendMessage(msg);
} catch { }
}
catch { }
}
};
return this;
}
}
internal override void Init(CommandGroupBuilder cgb) {
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "repeat")
.Description("Repeat a message every X minutes. If no parameters are specified, " +
@ -42,12 +51,14 @@ namespace NadekoBot.Commands {
.Parameter("minutes", ParameterType.Optional)
.Parameter("msg", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.ManageMessages())
.Do(async e => {
.Do(async e =>
{
var minutesStr = e.GetArg("minutes");
var msg = e.GetArg("msg");
// if both null, disable
if (string.IsNullOrWhiteSpace(msg) && string.IsNullOrWhiteSpace(minutesStr)) {
if (string.IsNullOrWhiteSpace(msg) && string.IsNullOrWhiteSpace(minutesStr))
{
await e.Channel.SendMessage("Repeating disabled");
Repeater rep;
if (repeaters.TryGetValue(e.Server, out rep))
@ -55,14 +66,16 @@ namespace NadekoBot.Commands {
return;
}
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");
return;
}
var repeater = repeaters.GetOrAdd(
e.Server,
s => new Repeater {
s => new Repeater
{
Interval = minutes * 60 * 1000,
RepeatingChannel = e.Channel,
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.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
using System.Timers;
using NadekoBot.Classes.JSONModels;
using NadekoBot.Modules;
namespace NadekoBot.Commands {
internal class PlayingRotate : DiscordCommand {
namespace NadekoBot.Modules.Administration.Commands
{
internal class PlayingRotate : DiscordCommand
{
private static readonly Timer timer = new Timer(12000);
public static Dictionary<string, Func<string>> PlayingPlaceholders { get; } =
@ -34,16 +36,21 @@ namespace NadekoBot.Commands {
private readonly object playingPlaceholderLock = new object();
public PlayingRotate(DiscordModule module) : base(module) {
public PlayingRotate(DiscordModule module) : base(module)
{
var i = -1;
timer.Elapsed += (s, e) => {
try {
timer.Elapsed += (s, e) =>
{
try
{
i++;
var status = "";
lock (playingPlaceholderLock) {
lock (playingPlaceholderLock)
{
if (PlayingPlaceholders.Count == 0)
return;
if (i >= PlayingPlaceholders.Count) {
if (i >= PlayingPlaceholders.Count)
{
i = -1;
return;
}
@ -54,14 +61,17 @@ namespace NadekoBot.Commands {
if (string.IsNullOrWhiteSpace(status))
return;
Task.Run(() => { NadekoBot.Client.SetGame(status); });
} catch { }
}
catch { }
};
timer.Enabled = NadekoBot.Config.IsRotatingStatus;
}
public Func<CommandEventArgs, Task> DoFunc() => async e => {
lock (playingPlaceholderLock) {
public Func<CommandEventArgs, Task> DoFunc() => async e =>
{
lock (playingPlaceholderLock)
{
if (timer.Enabled)
timer.Stop();
else
@ -72,7 +82,8 @@ namespace NadekoBot.Commands {
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")
.Alias(Module.Prefix + "ropl")
.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))
.Parameter("text", ParameterType.Unparsed)
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Do(async e => {
.Do(async e =>
{
var arg = e.GetArg("text");
if (string.IsNullOrWhiteSpace(arg))
return;
lock (playingPlaceholderLock) {
lock (playingPlaceholderLock)
{
NadekoBot.Config.RotatingStatuses.Add(arg);
ConfigHandler.SaveConfig();
}
@ -100,12 +113,14 @@ namespace NadekoBot.Commands {
.Alias(Module.Prefix + "lipl")
.Description("Lists all playing statuses with their corresponding number.")
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Do(async e => {
.Do(async e =>
{
if (NadekoBot.Config.RotatingStatuses.Count == 0)
await e.Channel.SendMessage("`There are no playing strings. " +
"Add some with .addplaying [text] command.`");
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]}");
}
await e.Channel.SendMessage(sb.ToString());
@ -116,11 +131,13 @@ namespace NadekoBot.Commands {
.Description("Removes a playing string on a given number.")
.Parameter("number", ParameterType.Required)
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Do(async e => {
.Do(async e =>
{
var arg = e.GetArg("number");
int num;
string str;
lock (playingPlaceholderLock) {
lock (playingPlaceholderLock)
{
if (!int.TryParse(arg.Trim(), out num) || num <= 0 || num > NadekoBot.Config.RotatingStatuses.Count)
return;
str = NadekoBot.Config.RotatingStatuses[num - 1];

View File

@ -1,28 +1,36 @@
using System;
using System.Collections.Concurrent;
using Discord.Commands;
using NadekoBot.Classes.Permissions;
using NadekoBot.Modules;
using NadekoBot.Commands;
using System;
using System.Collections.Concurrent;
namespace NadekoBot.Commands {
internal class RatelimitCommand : DiscordCommand {
namespace NadekoBot.Modules.Administration.Commands
{
internal class RatelimitCommand : DiscordCommand
{
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);
public RatelimitCommand(DiscordModule module) : base(module) {
NadekoBot.Client.MessageReceived += async (s, e) => {
public RatelimitCommand(DiscordModule module) : base(module)
{
NadekoBot.Client.MessageReceived += async (s, e) =>
{
if (e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id)
return;
ConcurrentDictionary<ulong, DateTime> userTimePair;
if (!RatelimitingChannels.TryGetValue(e.Channel.Id, out userTimePair)) return;
DateTime lastMessageTime;
if (userTimePair.TryGetValue(e.User.Id, out lastMessageTime)) {
if (DateTime.Now - lastMessageTime < ratelimitTime) {
try {
if (userTimePair.TryGetValue(e.User.Id, out lastMessageTime))
{
if (DateTime.Now - lastMessageTime < ratelimitTime)
{
try
{
await e.Message.Delete();
} catch { }
}
catch { }
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")
.Description("Toggles slow mode. When ON, users will be able to send only 1 message every 5 seconds.")
.Parameter("minutes", ParameterType.Optional)
.AddCheck(SimpleCheckers.ManageMessages())
.Do(async e => {
.Do(async e =>
{
//var minutesStr = e.GetArg("minutes");
//if (string.IsNullOrWhiteSpace(minutesStr)) {
// RatelimitingChannels.Remove(e.Channel.Id);
// return;
//}
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.");
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. " +
"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 System.Linq;
using System.Text;
using Discord.Commands;
using Discord.Commands;
using NadekoBot.Classes;
using NadekoBot.Classes.Permissions;
using NadekoBot.Modules;
using NadekoBot.Commands;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NadekoBot.Commands {
internal class SelfAssignedRolesCommand : DiscordCommand {
namespace NadekoBot.Modules.Administration.Commands
{
internal class SelfAssignedRolesCommand : DiscordCommand
{
public SelfAssignedRolesCommand(DiscordModule module) : base(module) { }
internal override void Init(CommandGroupBuilder cgb) {
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(".asar")
.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")
.Parameter("roles", ParameterType.Multiple)
.AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => {
.Do(async e =>
{
var config = SpecificConfigurations.Default.Of(e.Server.Id);
var msg = new StringBuilder();
foreach (var arg in e.Args) {
foreach (var arg in e.Args)
{
var role = e.Server.FindRoles(arg.Trim()).FirstOrDefault();
if (role == null)
msg.AppendLine($":anger:Role **{arg}** not found.");
else {
if (config.ListOfSelfAssignableRoles.Contains(role.Id)) {
if (config.ListOfSelfAssignableRoles.Contains(role.Id))
{
msg.AppendLine($":anger:Role **{role.Name}** is already in the list.");
continue;
}
@ -38,17 +44,20 @@ namespace NadekoBot.Commands {
.Description("Removes a specified role from the list of self-assignable roles.")
.Parameter("role", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => {
.Do(async e =>
{
var roleName = e.GetArg("role")?.Trim();
if (string.IsNullOrWhiteSpace(roleName))
return;
var role = e.Server.FindRoles(roleName).FirstOrDefault();
if (role == null) {
if (role == null)
{
await e.Channel.SendMessage(":anger:That role does not exist.");
return;
}
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.");
return;
}
@ -59,20 +68,25 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(".lsar")
.Description("Lits all self-assignable roles.")
.Parameter("roles", ParameterType.Multiple)
.Do(async e => {
.Do(async e =>
{
var config = SpecificConfigurations.Default.Of(e.Server.Id);
var msg = new StringBuilder($"There are `{config.ListOfSelfAssignableRoles.Count}` self assignable roles:\n");
var toRemove = new HashSet<ulong>();
foreach (var roleId in config.ListOfSelfAssignableRoles) {
foreach (var roleId in config.ListOfSelfAssignableRoles)
{
var role = e.Server.GetRole(roleId);
if (role == null) {
if (role == null)
{
msg.Append($"`{roleId} not found. Cleaned up.`, ");
toRemove.Add(roleId);
} else {
}
else {
msg.Append($"**{role.Name}**, ");
}
}
foreach (var id in toRemove) {
foreach (var id in toRemove)
{
config.ListOfSelfAssignableRoles.Remove(id);
}
await e.Channel.SendMessage(msg.ToString());
@ -83,21 +97,25 @@ namespace NadekoBot.Commands {
"Role must be on a list of self-assignable roles." +
"\n**Usage**: .iam Gamer")
.Parameter("role", ParameterType.Unparsed)
.Do(async e => {
.Do(async e =>
{
var roleName = e.GetArg("role")?.Trim();
if (string.IsNullOrWhiteSpace(roleName))
return;
var role = e.Server.FindRoles(roleName).FirstOrDefault();
if (role == null) {
if (role == null)
{
await e.Channel.SendMessage(":anger:That role does not exist.");
return;
}
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.");
return;
}
if (e.User.HasRole(role)) {
if (e.User.HasRole(role))
{
await e.Channel.SendMessage($":anger:You already have {role.Name} role.");
return;
}
@ -111,21 +129,25 @@ namespace NadekoBot.Commands {
"Role must be on a list of self-assignable roles." +
"\n**Usage**: .iamn Gamer")
.Parameter("role", ParameterType.Unparsed)
.Do(async e => {
.Do(async e =>
{
var roleName = e.GetArg("role")?.Trim();
if (string.IsNullOrWhiteSpace(roleName))
return;
var role = e.Server.FindRoles(roleName).FirstOrDefault();
if (role == null) {
if (role == null)
{
await e.Channel.SendMessage(":anger:That role does not exist.");
return;
}
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.");
return;
}
if (!e.User.HasRole(role)) {
if (!e.User.HasRole(role))
{
await e.Channel.SendMessage($":anger:You don't have {role.Name} role.");
return;
}

View File

@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using System.Collections.Concurrent;
using NadekoBot.Commands;
using NadekoBot.Extensions;
using Discord;
using NadekoBot.Modules;
using System.Collections.Concurrent;
using System.Linq;
/* Voltana's legacy
public class AsyncLazy<T> : Lazy<Task<T>>
@ -21,14 +18,17 @@ public class AsyncLazy<T> : Lazy<Task<T>>
}
*/
namespace NadekoBot.Commands {
internal class ServerGreetCommand : DiscordCommand {
namespace NadekoBot.Modules.Administration.Commands
{
internal class ServerGreetCommand : DiscordCommand
{
public static ConcurrentDictionary<ulong, AnnounceControls> AnnouncementsDictionary;
public static long Greeted = 0;
public ServerGreetCommand(DiscordModule module) : base(module) {
public ServerGreetCommand(DiscordModule module) : base(module)
{
AnnouncementsDictionary = new ConcurrentDictionary<ulong, AnnounceControls>();
NadekoBot.Client.UserJoined += UserJoined;
@ -41,8 +41,10 @@ namespace NadekoBot.Commands {
AnnouncementsDictionary.TryAdd((ulong)obj.ServerId, new AnnounceControls(obj));
}
private async void UserLeft(object sender, UserEventArgs e) {
try {
private async void UserLeft(object sender, UserEventArgs e)
{
try
{
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id) ||
!AnnouncementsDictionary[e.Server.Id].Bye) return;
@ -52,9 +54,11 @@ namespace NadekoBot.Commands {
if (string.IsNullOrEmpty(msg))
return;
if (controls.ByePM) {
if (controls.ByePM)
{
Greeted++;
try {
try
{
await e.User.SendMessage($"`Farewell Message From {e.Server?.Name}`\n" + msg);
}
catch { }
@ -68,8 +72,10 @@ namespace NadekoBot.Commands {
catch { }
}
private async void UserJoined(object sender, Discord.UserEventArgs e) {
try {
private async void UserJoined(object sender, Discord.UserEventArgs e)
{
try
{
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id) ||
!AnnouncementsDictionary[e.Server.Id].Greet) return;
@ -79,7 +85,8 @@ namespace NadekoBot.Commands {
var msg = controls.GreetText.Replace("%user%", e.User.Mention).Trim();
if (string.IsNullOrEmpty(msg))
return;
if (controls.GreetPM) {
if (controls.GreetPM)
{
Greeted++;
await e.User.SendMessage($"`Welcome Message From {e.Server.Name}`\n" + msg);
}
@ -92,7 +99,8 @@ namespace NadekoBot.Commands {
catch { }
}
public class AnnounceControls {
public class AnnounceControls
{
private Classes._DataModels.Announcement _model { get; }
public bool Greet {
@ -139,28 +147,36 @@ namespace NadekoBot.Commands {
set { _model.ServerId = (long)value; }
}
public AnnounceControls(Classes._DataModels.Announcement model) {
public AnnounceControls(Classes._DataModels.Announcement model)
{
this._model = model;
}
public AnnounceControls(ulong serverId) {
public AnnounceControls(ulong serverId)
{
this._model = new Classes._DataModels.Announcement();
ServerId = serverId;
}
internal bool ToggleBye(ulong id) {
if (Bye) {
internal bool ToggleBye(ulong id)
{
if (Bye)
{
return Bye = false;
} else {
}
else {
ByeChannel = id;
return Bye = true;
}
}
internal bool ToggleGreet(ulong id) {
if (Greet) {
internal bool ToggleGreet(ulong id)
{
if (Greet)
{
return Greet = false;
} else {
}
else {
GreetChannel = id;
return Greet = true;
}
@ -168,16 +184,19 @@ namespace NadekoBot.Commands {
internal bool ToggleGreetPM() => GreetPM = !GreetPM;
internal bool ToggleByePM() => ByePM = !ByePM;
private void Save() {
private void Save()
{
Classes.DbHandler.Instance.Save(_model);
}
}
internal override void Init(CommandGroupBuilder cgb) {
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "greet")
.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 (!AnnouncementsDictionary.ContainsKey(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")
.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)
.Do(async e => {
.Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return;
if (e.GetArg("msg") == null) return;
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id))
@ -207,7 +227,8 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(Module.Prefix + "bye")
.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 (!AnnouncementsDictionary.ContainsKey(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")
.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)
.Do(async e => {
.Do(async e =>
{
if (!e.User.ServerPermissions.ManageServer) return;
if (e.GetArg("msg") == null) return;
if (!AnnouncementsDictionary.ContainsKey(e.Server.Id))
@ -237,7 +259,8 @@ namespace NadekoBot.Commands {
cgb.CreateCommand(Module.Prefix + "byepm")
.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 (!AnnouncementsDictionary.ContainsKey(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")
.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 (!AnnouncementsDictionary.ContainsKey(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.Threading.Tasks;
using Discord.Commands;
using System.Collections.Concurrent;
using Discord;
using NadekoBot.Modules;
namespace NadekoBot.Commands {
internal class VoiceNotificationCommand : DiscordCommand {
namespace NadekoBot.Modules.Administration.Commands
{
internal class VoiceNotificationCommand : DiscordCommand
{
//voicechannel/text 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");
if (string.IsNullOrWhiteSpace("voice_name"))
return;
var voiceChannel = e.Server.FindChannels(arg, ChannelType.Voice).FirstOrDefault();
if (voiceChannel == null)
return;
if (subscribers.ContainsKey(voiceChannel)) {
if (subscribers.ContainsKey(voiceChannel))
{
await e.Channel.SendMessage("`Voice channel notifications disabled.`");
return;
}
if (subscribers.TryAdd(voiceChannel, e.Channel)) {
if (subscribers.TryAdd(voiceChannel, e.Channel))
{
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")
.Description("Enables notifications on who joined/left the voice channel.\n**Usage**:.voicenotif Karaoke club")
.Parameter("voice_name", ParameterType.Unparsed)

View File

@ -1,20 +1,24 @@
using System;
using System.Linq;
using System.Runtime.CompilerServices;
using Discord;
using Discord;
using Discord.Commands;
using NadekoBot.Classes;
using NadekoBot.Classes.Permissions;
using NadekoBot.Modules;
using NadekoBot.Commands;
using System;
using System.Linq;
using ChPermOverride = Discord.ChannelPermissionOverrides;
namespace NadekoBot.Commands {
internal class VoicePlusTextCommand : DiscordCommand {
namespace NadekoBot.Modules.Administration.Commands
{
internal class VoicePlusTextCommand : DiscordCommand
{
public VoicePlusTextCommand(DiscordModule module) : base(module) {
public VoicePlusTextCommand(DiscordModule module) : base(module)
{
// changing servers may cause bugs
NadekoBot.Client.UserUpdated += async (sender, e) => {
try {
NadekoBot.Client.UserUpdated += async (sender, e) =>
{
try
{
if (e.Server == null)
return;
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;
if (serverPerms == null)
return;
if (!serverPerms.Value.ManageChannels || !serverPerms.Value.ManageRoles) {
if (!serverPerms.Value.ManageChannels || !serverPerms.Value.ManageRoles)
{
try {
try
{
await e.Server.Owner.SendMessage(
"I don't have manage server and/or Manage Channels permission," +
$" so I cannot run voice+text on **{e.Server.Name}** server.");
} catch { } // meh
}
catch { } // meh
config.VoicePlusTextEnabled = false;
return;
}
var beforeVch = e.Before.VoiceChannel;
if (beforeVch != null) {
if (beforeVch != null)
{
var textChannel =
e.Server.FindChannels(GetChannelName(beforeVch.Name), ChannelType.Text).FirstOrDefault();
if (textChannel != null)
@ -46,12 +54,14 @@ namespace NadekoBot.Commands {
sendMessages: PermValue.Deny));
}
var afterVch = e.After.VoiceChannel;
if (afterVch != null) {
if (afterVch != null)
{
var textChannel = e.Server.FindChannels(
GetChannelName(afterVch.Name),
ChannelType.Text)
.FirstOrDefault();
if (textChannel == null) {
if (textChannel == null)
{
textChannel = (await e.Server.CreateChannel(GetChannelName(afterVch.Name), ChannelType.Text));
await textChannel.AddPermissionsRule(e.Server.EveryoneRole,
new ChPermOverride(readMessages: PermValue.Deny,
@ -61,7 +71,9 @@ namespace NadekoBot.Commands {
new ChPermOverride(readMessages: PermValue.Allow,
sendMessages: PermValue.Allow));
}
} catch (Exception ex) {
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
};
@ -70,22 +82,30 @@ namespace NadekoBot.Commands {
private string GetChannelName(string voiceName) =>
voiceName.Replace(" ", "-").Trim() + "-voice";
internal override void Init(CommandGroupBuilder cgb) {
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "v+t")
.Alias(Module.Prefix + "voice+text")
.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.")
.AddCheck(SimpleCheckers.ManageChannels())
.AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e => {
try {
.Do(async e =>
{
try
{
var config = SpecificConfigurations.Default.Of(e.Server.Id);
if (config.VoicePlusTextEnabled == true) {
if (config.VoicePlusTextEnabled == true)
{
config.VoicePlusTextEnabled = false;
foreach (var textChannel in e.Server.TextChannels.Where(c => c.Name.EndsWith("-voice"))) {
try {
foreach (var textChannel in e.Server.TextChannels.Where(c => c.Name.EndsWith("-voice")))
{
try
{
await textChannel.Delete();
} catch {
}
catch
{
await
e.Channel.SendMessage(
":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. " +
"**Make sure the bot has manage roles and manage channels permissions**");
} catch (Exception ex) {
}
catch (Exception ex)
{
await e.Channel.SendMessage(ex.ToString());
}
});

View File

@ -1,16 +1,14 @@
using System;
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.Commands;
using Discord.Modules;
using NadekoBot.Classes.ClashOfClans;
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
{
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.ClashOfClans;
@ -19,8 +17,10 @@ namespace NadekoBot.Commands {
private readonly object writeLock = new object();
public override void Install(ModuleManager manager) {
manager.CreateCommands("", cgb => {
public override void Install(ModuleManager manager)
{
manager.CreateCommands("", cgb =>
{
cgb.CreateCommand(Prefix + "createwar")
.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")
.Parameter("size")
.Parameter("enemy_clan", ParameterType.Unparsed)
.Do(async e => {
.Do(async e =>
{
if (!e.User.ServerPermissions.ManageChannels)
return;
List<ClashWar> wars;
if (!ClashWars.TryGetValue(e.Server.Id, out wars)) {
if (!ClashWars.TryGetValue(e.Server.Id, out wars))
{
wars = new List<ClashWar>();
if (!ClashWars.TryAdd(e.Server.Id, wars))
return;
}
var enemyClan = e.GetArg("enemy_clan");
if (string.IsNullOrWhiteSpace(enemyClan)) {
if (string.IsNullOrWhiteSpace(enemyClan))
{
return;
}
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");
return;
}
var cw = new ClashWar(enemyClan, size, e);
//cw.Start();
wars.Add(cw);
cw.OnUserTimeExpired += async (u) => {
try {
cw.OnUserTimeExpired += async (u) =>
{
try
{
await
e.Channel.SendMessage(
$"❗🔰**Claim from @{u} for a war against {cw.ShortPrint()} has expired.**");
} catch { }
}
catch { }
};
cw.OnWarEnded += async () => {
try {
cw.OnWarEnded += async () =>
{
try
{
await e.Channel.SendMessage($"❗🔰**War against {cw.ShortPrint()} ended.**");
} catch { }
}
catch { }
};
await e.Channel.SendMessage($"❗🔰**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**");
//war with the index X started.
@ -69,18 +79,23 @@ namespace NadekoBot.Commands {
.Alias(Prefix + "startwar")
.Description("Starts a war with a given number.")
.Parameter("number", ParameterType.Required)
.Do(async e => {
.Do(async e =>
{
var warsInfo = GetInfo(e);
if (warsInfo == null) {
if (warsInfo == null)
{
await e.Channel.SendMessage("💢🔰 **That war does not exist.**");
return;
}
var war = warsInfo.Item1[warsInfo.Item2];
try {
try
{
var startTask = war.Start();
await e.Channel.SendMessage($"🔰**STARTED WAR AGAINST {war.ShortPrint()}**");
await startTask;
} catch {
}
catch
{
await e.Channel.SendMessage($"🔰**WAR AGAINST {war.ShortPrint()} IS ALREADY STARTED**");
}
});
@ -89,13 +104,16 @@ namespace NadekoBot.Commands {
.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")
.Parameter("number", ParameterType.Optional)
.Do(async e => {
.Do(async e =>
{
// 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
List<ClashWar> wars = null;
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.**");
return;
}
@ -103,7 +121,8 @@ namespace NadekoBot.Commands {
var sb = new StringBuilder();
sb.AppendLine("🔰 **LIST OF ACTIVE WARS**");
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($"\t\t`Size:` **{wars[i].Size} v {wars[i].Size}**");
sb.AppendLine("**-------------------------**");
@ -113,7 +132,8 @@ namespace NadekoBot.Commands {
}
//if number is not null, print the war needed
var warsInfo = GetInfo(e);
if (warsInfo == null) {
if (warsInfo == null)
{
await e.Channel.SendMessage("💢🔰 **That war does not exist.**");
return;
}
@ -127,14 +147,17 @@ namespace NadekoBot.Commands {
.Parameter("number")
.Parameter("baseNumber")
.Parameter("other_name", ParameterType.Unparsed)
.Do(async e => {
.Do(async 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.**");
return;
}
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.**");
return;
}
@ -142,11 +165,14 @@ namespace NadekoBot.Commands {
string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
e.User.Name :
e.GetArg("other_name");
try {
try
{
var war = warsInfo.Item1[warsInfo.Item2];
war.Call(usr, baseNum - 1);
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}");
}
});
@ -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]")
.Parameter("number", ParameterType.Required)
.Parameter("other_name", ParameterType.Unparsed)
.Do(async e => {
.Do(async 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.**");
return;
}
@ -168,10 +196,13 @@ namespace NadekoBot.Commands {
e.GetArg("other_name");
var war = warInfo.Item1[warInfo.Item2];
try {
try
{
var baseNum = war.FinishClaim(usr);
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}");
}
});
@ -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]")
.Parameter("number", ParameterType.Required)
.Parameter("other_name", ParameterType.Unparsed)
.Do(async e => {
.Do(async 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.**");
return;
}
@ -192,11 +225,14 @@ namespace NadekoBot.Commands {
string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
e.User.Name :
e.GetArg("other_name");
try {
try
{
var war = warsInfo.Item1[warsInfo.Item2];
var baseNumber = war.Uncall(usr);
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}");
}
});
@ -205,9 +241,11 @@ namespace NadekoBot.Commands {
.Alias(Prefix + "ew")
.Description($"Ends the war with a given index.\n**Usage**:{Prefix}ew [war_number]")
.Parameter("number")
.Do(async e => {
.Do(async e =>
{
var warsInfo = GetInfo(e);
if (warsInfo == null) {
if (warsInfo == null)
{
await e.Channel.SendMessage("💢🔰 That war does not exist.");
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
List<ClashWar> wars = null;
ClashWars.TryGetValue(e.Server.Id, out wars);
if (wars == null || wars.Count == 0) {
if (wars == null || wars.Count == 0)
{
return null;
}
// get the number of the war
int num;
if (string.IsNullOrWhiteSpace(e.GetArg("number")))
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;
}
num -= 1;

View File

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

View File

@ -19,7 +19,7 @@ namespace NadekoBot.Modules.Gambling
internal override void Init(CommandGroupBuilder cgb)
{
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)
.Do(Roll0to10Func());
cgb.CreateCommand(Module.Prefix + "nroll")
@ -28,7 +28,13 @@ namespace NadekoBot.Modules.Gambling
.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()
{
@ -37,30 +43,24 @@ namespace NadekoBot.Modules.Gambling
{
if (e.Args[0] == "")
{
var num1 = r.Next(0, 10);
var num2 = r.Next(0, 10);
var gen = r.Next(0, 101);
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
{
var num = int.Parse(e.Args[0]);
if (num < 1) num = 1;
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;
}
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.");
rolled = new Random().Next(arr[0], arr[1] + 1);
}
else {
else
{
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.")
.Parameter("role", ParameterType.Optional)
.Do(RaffleFunc());
cgb.CreateCommand(Prefix + "$$")
.Description(string.Format("Check how much {0}s you have.", NadekoBot.Config.CurrencyName))
.Do(NadekoFlowerCheckFunc());
cgb.CreateCommand(Prefix + "give")
.Description(string.Format("Give someone a certain amount of {0}s", NadekoBot.Config.CurrencyName))
.Parameter("amount", ParameterType.Required)
@ -61,12 +63,56 @@ namespace NadekoBot.Modules.Gambling
return;
}
await FlowersHandler.RemoveFlowersAsync(e.User, "Gift", (int)amount);
FlowersHandler.RemoveFlowers(e.User, "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}!");
});
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 System.Linq;
using Discord.Commands;
using Discord.Modules;
using NadekoBot.Commands;
using Newtonsoft.Json.Linq;
using System.IO;
using Discord.Commands;
using NadekoBot.Extensions;
using System;
using System.Linq;
namespace NadekoBot.Modules {
internal class Games : DiscordModule {
namespace NadekoBot.Modules
{
internal class Games : DiscordModule
{
private readonly Random rng = new Random();
public Games() {
public Games()
{
commands.Add(new Trivia(this));
commands.Add(new SpeedTyping(this));
commands.Add(new PollCommand(this));
commands.Add(new PlantPick(this));
//commands.Add(new BetrayGame(this));
}
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Games;
public override void Install(ModuleManager manager) {
manager.CreateCommands("", cgb => {
public override void Install(ModuleManager manager)
{
manager.CreateCommands("", cgb =>
{
cgb.AddCheck(Classes.Permissions.PermissionChecker.Instance);
@ -30,8 +34,9 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "choose")
.Description("Chooses a thing from a list of things\n**Usage**: >choose Get up;Sleep;Sleep more")
.Parameter("list", Discord.Commands.ParameterType.Unparsed)
.Do(async e => {
.Parameter("list", ParameterType.Unparsed)
.Do(async e =>
{
var arg = e.GetArg("list");
if (string.IsNullOrWhiteSpace(arg))
return;
@ -43,24 +48,29 @@ namespace NadekoBot.Modules {
cgb.CreateCommand(Prefix + "8ball")
.Description("Ask the 8ball a yes/no question.")
.Parameter("question", Discord.Commands.ParameterType.Unparsed)
.Do(async e => {
.Parameter("question", ParameterType.Unparsed)
.Do(async e =>
{
var question = e.GetArg("question");
if (string.IsNullOrWhiteSpace(question))
return;
try {
try
{
await e.Channel.SendMessage(
$":question: **Question**: `{question}` \n🎱 **8Ball Answers**: `{NadekoBot.Config._8BallResponses[rng.Next(0, NadekoBot.Config._8BallResponses.Length)]}`");
} catch { }
}
catch { }
});
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)
.Do(async e => {
.Do(async e =>
{
var input = e.GetArg("input").Trim();
int pick;
switch (input) {
switch (input)
{
case "r":
case "rock":
case "rocket":
@ -96,7 +106,8 @@ namespace NadekoBot.Modules {
.Description("Prints a customizable Linux interjection")
.Parameter("gnu", ParameterType.Required)
.Parameter("linux", ParameterType.Required)
.Do(async e => {
.Do(async e =>
{
var guhnoo = e.Args[0];
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)
return "rocket";
else if (i == 1)

View File

@ -70,6 +70,7 @@ namespace NadekoBot.Modules
cgb.CreateCommand("n")
.Alias("next")
.Alias("skip")
.Description("Goes to the next song in the queue.")
.Do(e =>
{
@ -138,7 +139,15 @@ namespace NadekoBot.Modules
await e.Channel.SendMessage("🎵 No active music player.");
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)
toSend += "**Song queue is full!**\n";
else
@ -156,7 +165,8 @@ namespace NadekoBot.Modules
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
return;
var currentSong = musicPlayer.CurrentSong;
if (currentSong != null)
if (currentSong == null)
return;
await e.Channel.SendMessage($"🎵`Now Playing` {currentSong.PrettyName} " +
$"{currentSong.PrettyCurrentTime()}");
});
@ -303,7 +313,7 @@ namespace NadekoBot.Modules
});
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)
.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")
// .Description("Does something magical. **BOT OWNER ONLY**")
// .AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())

View File

@ -79,7 +79,11 @@ namespace NadekoBot.Modules.Pokemon
{"bullet punch",16},
{"metal burst",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.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace NadekoBot.Modules.Pokemon
{
class PokeStats
{
//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
public int MovesMade { get; set; } = 0;
//Last people attacked

View File

@ -1,40 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
using Discord.Modules;
using Discord.Commands;
using NadekoBot.Commands;
using NadekoBot.Classes;
using NadekoBot.Extensions;
using NadekoBot.Classes._DataModels;
using NadekoBot.Classes.Permissions;
using System.Collections.Concurrent;
using NadekoBot.Extensions;
using NadekoBot.Modules.Pokemon.PokeTypes;
using NadekoBot.Modules.Pokemon.PokeTypes.Extensions;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace NadekoBot.Modules.Pokemon
{
class PokemonGame : DiscordModule
class PokemonModule : DiscordModule
{
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>();
public PokemonGame()
public PokemonModule()
{
//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)
{
manager.CreateCommands("", cgb =>
{
cgb.AddCheck(Classes.Permissions.PermissionChecker.Instance);
cgb.AddCheck(PermissionChecker.Instance);
commands.ForEach(cmd => cmd.Init(cgb));
@ -45,20 +69,28 @@ namespace NadekoBot.Modules.Pokemon
.Do(async e =>
{
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)
{
await e.Channel.SendMessage("No such person.");
return;
}
else if (target == e.User)
{
await e.Channel.SendMessage("You can't attack yourself.");
return;
}
// Checking stats first, then move
//Set up the userstats
PokeStats userStats;
userStats = Stats.GetOrAdd(e.User.Id, defaultStats());
userStats = Stats.GetOrAdd(e.User.Id, new PokeStats());
//Check if able to move
//User not able if HP < 0, has made more than 4 attacks
if (userStats.HP < 0)
if (userStats.Hp < 0)
{
await e.Channel.SendMessage($"{e.User.Mention} has fainted and was not able to move!");
return;
@ -75,17 +107,17 @@ namespace NadekoBot.Modules.Pokemon
}
//get target stats
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 (targetStats.HP <= 0)
if (targetStats.Hp <= 0)
{
await e.Channel.SendMessage($"{target.Mention} has already fainted!");
return;
}
//Check whether move can be used
IPokeType userType = getPokeType(e.User.Id);
PokeType userType = GetPokeType(e.User.Id);
var enabledMoves = userType.GetMoves();
if (!enabledMoves.Contains(move.ToLowerInvariant()))
@ -95,13 +127,13 @@ namespace NadekoBot.Modules.Pokemon
}
//get target type
IPokeType targetType = getPokeType(target.Id);
PokeType targetType = GetPokeType(target.Id);
//generate damage
int damage = getDamage(userType, targetType);
int damage = GetDamage(userType, targetType);
//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
if (damage < 40)
@ -119,13 +151,13 @@ namespace NadekoBot.Modules.Pokemon
//check fainted
if (targetStats.HP <= 0)
if (targetStats.Hp <= 0)
{
response += $"\n**{target.Name}** has fainted!";
}
else
{
response += $"\n**{target.Name}** has {targetStats.HP} HP remaining";
response += $"\n**{target.Name}** has {targetStats.Hp} HP remaining";
}
//update other stats
@ -145,53 +177,30 @@ namespace NadekoBot.Modules.Pokemon
await e.Channel.SendMessage(response);
});
cgb.CreateCommand(Prefix + "listmoves")
cgb.CreateCommand(Prefix + "ml")
.Alias("movelist")
.Description("Lists the moves you are able to use")
.Do(async e =>
{
var userType = getPokeType(e.User.Id);
var userType = GetPokeType(e.User.Id);
List<string> movesList = userType.GetMoves();
var str = "**Moves:**";
var str = $"**Moves for `{userType.Name}` type.**";
foreach (string m in movesList)
{
str += $"\n{userType.GetImage()}{m}";
str += $"\n{userType.Image}{m}";
}
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")
.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 =>
{
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)
{
await e.Channel.SendMessage("No such person.");
@ -201,8 +210,8 @@ namespace NadekoBot.Modules.Pokemon
{
var targetStats = Stats[usr.Id];
int HP = targetStats.HP;
if (targetStats.HP == BaseHealth)
int HP = targetStats.Hp;
if (targetStats.Hp == targetStats.MaxHp)
{
await e.Channel.SendMessage($"{usr.Name} already has full HP!");
return;
@ -212,21 +221,21 @@ namespace NadekoBot.Modules.Pokemon
var pts = Classes.DbHandler.Instance.GetStateByUserId((long)e.User.Id)?.Value ?? 0;
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;
}
var up = (usr.Id == e.User.Id) ? "yourself" : usr.Name;
await FlowersHandler.RemoveFlowersAsync(e.User, $"heal {up}", amount);
var target = (usr.Id == e.User.Id) ? "yourself" : usr.Name;
FlowersHandler.RemoveFlowers(e.User, $"Poke-Heal {target}", amount);
//healing
targetStats.HP = BaseHealth;
targetStats.Hp = targetStats.MaxHp;
if (HP < 0)
{
//Could heal only for half HP?
Stats[usr.Id].HP = (BaseHealth / 2);
await e.Channel.SendMessage($"{e.User.Name} revived {usr.Name} for 🌸");
Stats[usr.Id].Hp = (targetStats.MaxHp / 2);
await e.Channel.SendMessage($"{e.User.Name} revived {usr.Name} with one {NadekoBot.Config.CurrencySign}");
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;
}
else
@ -237,142 +246,73 @@ namespace NadekoBot.Modules.Pokemon
cgb.CreateCommand(Prefix + "type")
.Description($"Get the poketype of the target.\n**Usage**: {Prefix}type @someone")
.Parameter("target", ParameterType.Required)
.Parameter("target", ParameterType.Unparsed)
.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)
{
await e.Channel.SendMessage("No such person.");
return;
}
var pType = getPokeType(usr.Id);
await e.Channel.SendMessage($"Type of {usr.Name} is **{pType.GetName().ToLowerInvariant()}**{pType.GetImage()}");
});
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);
var pType = GetPokeType(usr.Id);
await e.Channel.SendMessage($"Type of {usr.Name} is **{pType.Name.ToLowerInvariant()}**{pType.Image}");
});
cgb.CreateCommand(Prefix + "settype")
.Description($"Set your poketype. Costs a NadekoFlower.\n**Usage**: {Prefix}settype fire")
.Parameter("targetType", ParameterType.Required)
.Description($"Set your poketype. Costs a {NadekoBot.Config.CurrencyName}.\n**Usage**: {Prefix}settype fire")
.Parameter("targetType", ParameterType.Unparsed)
.Do(async e =>
{
var targetTypeString = e.GetArg("targetType");
var targetType = PokemonTypesMain.stringToPokeType(targetTypeString.ToUpperInvariant());
var targetTypeStr = e.GetArg("targetType")?.ToUpperInvariant();
if (string.IsNullOrWhiteSpace(targetTypeStr))
return;
var targetType = PokemonTypesMain.stringToPokeType(targetTypeStr);
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");
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;
}
//Payment~
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)
{
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;
}
await FlowersHandler.RemoveFlowersAsync(e.User, $"set usertype to {targetTypeString}", amount);
FlowersHandler.RemoveFlowers(e.User, $"set usertype to {targetTypeStr}", amount);
//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);
if (Dict.ContainsKey((long)e.User.Id))
{
//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,
type = targetType.GetNum()
type = targetType.Num
});
//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.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
{
class BugType : IPokeType
class BugType : PokeType
{
static readonly string name = "BUG";
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;
@ -24,8 +18,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
case "FIGHTING": return 0.5;
case "POISON": return 0.5;
case "FLYING": return 0.5;
case "GHOST": return 0.5;
case "PSYCHIC": return 2;
case "ROCK": return 0.5;
case "FAIRY": return 0.5;
case "DARK": return 2;
case "STEEL": return 0.5;
default: return 1;
@ -33,24 +29,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
}
List<string> moves = new List<string>();
public string Name => name;
public string Image => "🐛";
public string GetName()
{
return name;
}
public string GetImage()
{
return "🐛";
}
public int GetNum()
{
return numType;
}
public int Num => numType;
}
}

View File

@ -1,52 +1,32 @@
using System;
using NadekoBot.Modules.Pokemon.PokeTypes;
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
{
class DarkType : IPokeType
class DarkType : PokeType
{
static readonly string name = "DARK";
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 "PSYCHIC": return 2;
case "GHOST": return 2;
case "DARK": return 0.5;
case "STEEL": return 0.5;
case "FAIRY": return 0.5;
default: return 1;
}
}
List<string> moves = new List<string>();
public string Name => name;
public string Image => "🕶";
public string GetName()
{
return name;
}
public string GetImage()
{
return "🕶";
}
public int GetNum()
{
return numType;
}
public int Num => numType;
}
}

View File

@ -1,26 +1,21 @@
using System;
using NadekoBot.Modules.Pokemon.PokeTypes;
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
{
class DragonType : IPokeType
class DragonType : PokeType
{
static readonly string name = "DRAGON";
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 "STEEL": return 0.5;
case "FAIRY": return 0;
default: return 1;
}
}
@ -29,21 +24,12 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
public string GetName()
{
return name;
}
public string Name => name;
public string GetImage()
{
return "🐉";
}
public string Image => "🐉";
public int GetNum()
{
return numType;
}
public int Num => numType;
}
}

View File

@ -1,22 +1,16 @@
using System;
using NadekoBot.Modules.Pokemon.PokeTypes;
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
{
class ElectricType : IPokeType
class ElectricType : PokeType
{
static readonly string name = "ELECTRIC";
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;
@ -33,20 +27,11 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
public string GetName()
{
return name;
}
public string Name => name;
public string GetImage()
{
return "⚡️";
}
public string Image => "⚡️";
public int GetNum()
{
return numType;
}
public int Num => 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.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
{
class FightingType : IPokeType
class FightingType : PokeType
{
static readonly string name = "FIGHTING";
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;
@ -29,6 +23,7 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
case "GHOST": return 0;
case "DARK": return 2;
case "STEEL": return 2;
case "FAIRY": return 0.5;
default: return 1;
}
}
@ -37,20 +32,11 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
public string GetName()
{
return name;
}
public string Name => name;
public string GetImage()
{
return "✊";
}
public string Image => "✊";
public int GetNum()
{
return numType;
}
public int Num => numType;
}
}

View File

@ -1,24 +1,18 @@
using System;
using NadekoBot.Modules.Pokemon.PokeTypes;
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
{
class FireType : IPokeType
class FireType : PokeType
{
static readonly string name = "FIRE";
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;
@ -33,25 +27,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
}
}
List<string> moves = new List<string>();
public string Name => name;
public string Image => "🔥";
public string GetName()
{
return name;
}
public string GetImage()
{
return "🔥";
}
public int GetNum()
{
return numType;
}
public int Num => numType;
}
}

View File

@ -1,22 +1,16 @@
using System;
using NadekoBot.Modules.Pokemon.PokeTypes;
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
{
class FlyingType : IPokeType
class FlyingType : PokeType
{
static readonly string name = "FLYING";
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;
@ -33,21 +27,12 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
public string GetName()
{
return name;
}
public string Name => name;
public string GetImage()
{
return "☁";
}
public string Image => "☁";
public int GetNum()
{
return numType;
}
public int Num => numType;
}
}

View File

@ -1,22 +1,16 @@
using System;
using NadekoBot.Modules.Pokemon.PokeTypes;
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
{
class GhostType : IPokeType
class GhostType : PokeType
{
static readonly string name = "GHOST";
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;
@ -32,21 +26,12 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
public string GetName()
{
return name;
}
public string Name => name;
public string GetImage()
{
return "👻";
}
public string Image => "👻";
public int GetNum()
{
return numType;
}
public int Num => numType;
}
}

View File

@ -1,22 +1,16 @@
using System;
using NadekoBot.Modules.Pokemon.PokeTypes;
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
{
class GrassType : IPokeType
class GrassType : PokeType
{
static readonly string name = "GRASS";
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;
@ -35,20 +29,11 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
public string GetName()
{
return name;
}
public string Name => name;
public string GetImage()
{
return "🌿";
}
public string Image => "🌿";
public int GetNum()
{
return numType;
}
public int Num => numType;
}
}

View File

@ -1,22 +1,16 @@
using System;
using NadekoBot.Modules.Pokemon.PokeTypes;
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
{
class GroundType : IPokeType
class GroundType : PokeType
{
static readonly string name = "GROUND";
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;
@ -32,24 +26,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
}
List<string> moves = new List<string>();
public string Name => name;
public string Image => "🗻";
public string GetName()
{
return name;
}
public string GetImage()
{
return "🗻";
}
public int GetNum()
{
return numType;
}
public int Num => numType;
}
}

View File

@ -6,13 +6,13 @@ namespace NadekoBot.Modules.Pokemon.PokeTypes.Extensions
{
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>();
List<string> moves = new List<string>();
foreach (PokeMoves p in db)
{
if (p.type == poketype.GetNum())
if (p.type == poketype.Num)
{
if (!moves.Contains(p.move))
{

View File

@ -1,22 +1,16 @@
using System;
using NadekoBot.Modules.Pokemon.PokeTypes;
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
{
class IceType : IPokeType
class IceType : PokeType
{
static readonly string name = "ICE";
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;
@ -32,23 +26,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
}
List<string> moves = new List<string>();
public string Name => name;
public string Image => "❄";
public string GetName()
{
return name;
}
public string GetImage()
{
return "❄";
}
public int GetNum()
{
return numType;
}
public int Num => numType;
}
}

View File

@ -1,26 +1,18 @@
using System;
using NadekoBot.Modules.Pokemon.PokeTypes;
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
{
class NormalType : IPokeType
class NormalType : PokeType
{
static readonly string name = "NORMAL";
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 "GHOST": return 0;
case "STEEL": return 0.5;
@ -29,24 +21,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
}
List<string> moves = new List<string>();
public string Name => name;
public string Image => "⭕️";
public string GetName()
{
return name;
}
public string GetImage()
{
return "⭕️";
}
public int GetNum()
{
return type_num;
}
public int Num => type_num;
}
}

View File

@ -1,23 +1,16 @@
using System;
using NadekoBot.Modules.Pokemon.PokeTypes;
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
{
class PoisonType : IPokeType
class PoisonType : PokeType
{
static readonly string name = "POISON";
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;
@ -26,28 +19,16 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
case "ROCK": return 0.5;
case "GHOST": return 0.5;
case "STEEL": return 0;
case "FAIRY": return 2;
default: return 1;
}
}
List<string> moves = new List<string>();
public string Name => name;
public string Image => "☠";
public string GetName()
{
return name;
}
public string GetImage()
{
return "☠";
}
public int GetNum()
{
return numType;
}
public int Num => numType;
}
}

View File

@ -1,28 +1,24 @@
using System.Collections.Generic;
using NadekoBot.Classes;
using NadekoBot.Classes._DataModels;
using NadekoBot.Modules.Pokemon.PokemonTypes;
using NadekoBot.Modules.Pokemon.PokemonTypes;
using System.Collections.Generic;
namespace NadekoBot.Modules.Pokemon.PokeTypes
{
public interface IPokeType
public interface PokeType
{
string GetImage();
string GetName();
int GetNum();
double GetMagnifier(IPokeType target);
string Image { get; }
string Name { get; }
int Num { get; }
double Multiplier(PokeType target);
}
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;
}
@ -30,26 +26,8 @@ namespace NadekoBot.Modules.Pokemon.PokeTypes
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)
public static List<IPokeType> TypeList = new List<IPokeType>()
public static List<PokeType> TypeList = new List<PokeType>()
{
new NormalType(),
new FireType(),
@ -67,14 +45,15 @@ namespace NadekoBot.Modules.Pokemon.PokeTypes
new GhostType(),
new DragonType(),
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;
}

View File

@ -1,23 +1,16 @@
using System;
using NadekoBot.Modules.Pokemon.PokeTypes;
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
{
class PsychicType : IPokeType
class PsychicType : PokeType
{
static readonly string name = "PSYCHIC";
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;
@ -33,21 +26,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
public string GetName()
{
return name;
}
public string Name => name;
public string Image => "🔮";
public string GetImage()
{
return "💫";
}
public int GetNum()
{
return numType;
}
public int Num => numType;
}
}

View File

@ -1,22 +1,16 @@
using System;
using NadekoBot.Modules.Pokemon.PokeTypes;
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
{
class RockType : IPokeType
class RockType : PokeType
{
static readonly string name = "ROCK";
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;
@ -31,24 +25,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
}
List<string> moves = new List<string>();
public string Name => name;
public string Image => "💎";
public string GetName()
{
return name;
}
public string GetImage()
{
return "💎";
}
public int GetNum()
{
return numType;
}
public int Num => numType;
}
}

View File

@ -1,22 +1,16 @@
using System;
using NadekoBot.Modules.Pokemon.PokeTypes;
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
{
class SteelType : IPokeType
class SteelType : PokeType
{
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;
@ -30,23 +24,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
}
List<string> moves = new List<string>();
public string Name => name;
public string Image => "🔩";
public string GetName()
{
return name;
}
public string GetImage()
{
return "🔩";
}
public int GetNum()
{
return numType;
}
public int Num => numType;
}
}

View File

@ -1,22 +1,16 @@
using System;
using NadekoBot.Modules.Pokemon.PokeTypes;
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
{
class WaterType : IPokeType
class WaterType : PokeType
{
static readonly string name = "WATER";
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;
@ -30,23 +24,10 @@ namespace NadekoBot.Modules.Pokemon.PokemonTypes
}
List<string> moves = new List<string>();
public string Name => name;
public string Image => "💦";
public string GetName()
{
return name;
}
public string GetImage()
{
return "💦";
}
public int GetNum()
{
return numType;
}
public int Num => numType;
}
}

View File

@ -317,9 +317,62 @@ $@"🌍 **Weather for** 【{obj["target"]}】
.Description("Shows a random quote.")
.Do(async e =>
{
await
e.Channel.SendMessage(
NadekoBot.Config.Quotes[new Random().Next(0, NadekoBot.Config.Quotes.Count)].ToString());
var quote = NadekoBot.Config.Quotes[rng.Next(0, NadekoBot.Config.Quotes.Count)].ToString();
await e.Channel.SendMessage(quote);
});
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.Commands;
using NadekoBot.Modules;
using NadekoBot.Modules.Administration;
using NadekoBot.Modules.Gambling;
using NadekoBot.Modules.Pokemon;
using NadekoBot.Modules.Translator;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
@ -14,13 +16,12 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Translator;
namespace NadekoBot
{
public class NadekoBot
{
public static DiscordClient Client;
public static DiscordClient Client { get; private set; }
public static Credentials Creds { get; set; }
public static Configuration Config { get; set; }
public static LocalizedStrings Locale { get; set; } = new LocalizedStrings();
@ -110,7 +111,7 @@ namespace NadekoBot
Client = new DiscordClient(new DiscordConfigBuilder()
{
MessageCacheSize = 10,
ConnectionTimeout = 60000,
ConnectionTimeout = 120000,
LogLevel = LogSeverity.Warning,
LogHandler = (s, e) =>
Console.WriteLine($"Severity: {e.Severity}" +
@ -157,7 +158,7 @@ namespace NadekoBot
}));
//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 PermissionModule(), "Permissions", 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 NSFW(), "NSFW", 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);
if (!string.IsNullOrWhiteSpace(Creds.TrelloAppKey))
modules.Add(new Trello(), "Trello", ModuleFilter.None);

View File

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

View File

@ -16,7 +16,7 @@
"Gambling": "$",
"Permissions": ";",
"Programming": "%",
"Pokemon": "poke"
"Pokemon": ">"
},
"ServerBlacklist": [],
"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="Newtonsoft.Json" version="8.0.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="taglib" version="2.1.0.0" targetFramework="net452" />
<package id="VideoLibrary" version="1.3.3" targetFramework="net452" />

View File

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

View File

@ -2,7 +2,7 @@
######You can donate on paypal: `nadekodiscordbot@gmail.com` or Bitcoin `17MZz1JAqME39akMLrVT4XBPffQJ2n1EPa`
#NadekoBot List Of Commands
Version: `NadekoBot v0.9.5930.23184`
Version: `NadekoBot v0.9.5933.23628`
### Administration
Command and aliases | Description | Usage
----------------|--------------|-------
@ -31,6 +31,7 @@ Command and aliases | Description | Usage
`.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
`.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
`.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
@ -46,7 +47,7 @@ Command and aliases | Description | Usage
`.vch`, `.cvch` | Creates a new voice 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.
`.st`, `.settopic` | Sets a topic on the current channel.
`.st`, `.settopic`, `.topic` | Sets a topic on the current channel.
`.uid`, `.userid` | Shows user ID.
`.cid`, `.channelid` | Shows current channel ID.
`.sid`, `.serverid` | Shows current server ID.
@ -70,7 +71,6 @@ Command and aliases | Description | Usage
`.unstuck` | Clears the message queue. **Owner Only!**
`.donators` | List of lovely people who donated to keep this project alive.
`.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.
### Help
@ -138,7 +138,7 @@ Command and aliases | Description | Usage
`@BotName uptime` | Shows how long Nadeko has been running for.
`@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 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 praise` | Praises @X person. | @NadekoBot praise @X.
`@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]
`$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.
`$$$` | Check how many NadekoFlowers you have.
`$give` | Give someone a certain amount of flowers
`$$$` | Check how much NadekoFlowers you have.
`$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
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.
`>choose` | Chooses a thing from a list of things | >choose Get up;Sleep;Sleep more
`>8ball` | Ask the 8ball a yes/no question.
`>attack` | Attack a person. Supported attacks: 'splash', 'strike', 'burn', 'surge'. | >attack strike @User
`>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
`>rps` | Play a game of rocket paperclip scissors with Nadeko. | >rps scissors
`>linux` | Prints a customizable Linux interjection
### Music
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 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.
@ -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 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 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 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.
@ -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.
`~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
`~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
`~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.
@ -238,12 +239,11 @@ Command and aliases | Description | Usage
`~ud` | Searches Urban Dictionary for a word. | ~ud Pineapple
`~#` | Searches Tagdef.com for a hashtag. | ~# ff
`~quote` | Shows a random quote.
### 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.
`~catfact` | Shows a random catfact from <http://catfacts-api.appspot.com/api/facts>
`~yomama`, `~ym` | Shows a random joke from <http://api.yomomma.info/>
`~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>
`~revav` | Returns a google reverse image search for someone's avatar.
### NSFW
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]
`,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
Command and aliases | Description | Usage
----------------|--------------|-------