only actual externalization left. Trivia is now >t

This commit is contained in:
Master Kwoth 2016-03-11 20:13:48 +01:00
parent d9a8a6d4fa
commit c8c930e52b
24 changed files with 445 additions and 441 deletions

View File

@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Discord.Commands;
namespace NadekoBot.Classes.ClashOfClans {
internal class Caller {
public string CallUser { get; }
public DateTime TimeAdded { get; private set; }
public bool BaseDestroyed { get; internal set; }
public Caller(string callUser, DateTime timeAdded, bool baseDestroyed) {
CallUser = callUser;
TimeAdded = timeAdded;
BaseDestroyed = baseDestroyed;
}
public void ResetTime() {
TimeAdded = DateTime.Now;
}
public void Destroy() {
BaseDestroyed = true;
}
}
internal class ClashWar {
private static TimeSpan callExpire => new TimeSpan(2, 0, 0);
private CommandEventArgs e;
public string EnemyClan { get; }
public int Size { get; }
private Caller[] bases { get; }
private CancellationTokenSource[] baseCancelTokens;
private CancellationTokenSource endTokenSource { get; } = new CancellationTokenSource();
public event Action<string> OnUserTimeExpired = delegate { };
public event Action OnWarEnded = delegate { };
public bool Started { get; set; } = false;
public ClashWar(string enemyClan, int size, CommandEventArgs e) {
this.EnemyClan = enemyClan;
this.Size = size;
this.bases = new Caller[size];
this.baseCancelTokens = new CancellationTokenSource[size];
}
internal void End() {
if (endTokenSource.Token.IsCancellationRequested) return;
endTokenSource.Cancel();
OnWarEnded();
}
internal void Call(string u, int baseNumber) {
if (baseNumber < 0 || baseNumber >= bases.Length)
throw new ArgumentException("Invalid base number");
if (bases[baseNumber] != null)
throw new ArgumentException("That base is already claimed.");
for (var i = 0; i < bases.Length; i++) {
if (bases[i]?.BaseDestroyed == false && bases[i]?.CallUser == u)
throw new ArgumentException($"@{u} You already claimed a base #{i + 1}. You can't claim a new one.");
}
bases[baseNumber] = new Caller(u.Trim(), DateTime.Now, false);
}
internal async Task Start() {
if (Started)
throw new InvalidOperationException();
try {
Started = true;
foreach (var b in bases.Where(b => b != null)) {
b.ResetTime();
}
Task.Run(async () => await ClearArray()).ConfigureAwait(false);
await Task.Delay(new TimeSpan(24, 0, 0), endTokenSource.Token);
} catch { } finally {
End();
}
}
internal int Uncall(string user) {
user = user.Trim();
for (var i = 0; i < bases.Length; i++) {
if (bases[i]?.CallUser != user) continue;
bases[i] = null;
return i;
}
throw new InvalidOperationException("You are not participating in that war.");
}
private async Task ClearArray() {
while (!endTokenSource.IsCancellationRequested) {
await Task.Delay(5000);
for (var i = 0; i < bases.Length; i++) {
if (bases[i] == null) continue;
if (!bases[i].BaseDestroyed && DateTime.Now - bases[i].TimeAdded >= callExpire) {
Console.WriteLine($"Removing user {bases[i].CallUser}");
OnUserTimeExpired(bases[i].CallUser);
bases[i] = null;
}
}
}
Console.WriteLine("Out of clear array");
}
public string ShortPrint() =>
$"`{EnemyClan}` ({Size} v {Size})";
public override string ToString() {
var sb = new StringBuilder();
sb.AppendLine($"🔰**WAR AGAINST `{EnemyClan}` ({Size} v {Size}) INFO:**");
if (!Started)
sb.AppendLine("`not started`");
for (var i = 0; i < bases.Length; i++) {
if (bases[i] == null) {
sb.AppendLine($"`{i + 1}.` ❌*unclaimed*");
} else {
if (bases[i].BaseDestroyed) {
sb.AppendLine($"`{i + 1}.` ✅ `{bases[i].CallUser}` ⭐ ⭐ ⭐");
} else {
var left = Started ? callExpire - (DateTime.Now - bases[i].TimeAdded) : callExpire;
sb.AppendLine($"`{i + 1}.` ✅ `{bases[i].CallUser}` {left.Hours}h {left.Minutes}m {left.Seconds}s left");
}
}
}
return sb.ToString();
}
internal int FinishClaim(string user) {
user = user.Trim();
for (var i = 0; i < bases.Length; i++) {
if (bases[i]?.BaseDestroyed != false || bases[i]?.CallUser != user) continue;
bases[i].BaseDestroyed = true;
return i;
}
throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base.");
}
}
}

View File

@ -1,374 +0,0 @@
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 NadekoBot.Modules;
namespace NadekoBot.Commands {
internal class ClashOfClans : DiscordCommand {
private const string prefix = ",";
public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; } = new ConcurrentDictionary<ulong, List<ClashWar>>();
private readonly object writeLock = new object();
public ClashOfClans(DiscordModule module) : base(module) { }
public Func<CommandEventArgs, Task> DoFunc() => async e => {
if (!e.User.ServerPermissions.ManageChannels)
return;
List<ClashWar> 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)) {
return;
}
int size;
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 {
await
e.Channel.SendMessage($"❗🔰**Claim from @{u} for a war against {cw.ShortPrint()} has expired.**");
} catch { }
};
cw.OnWarEnded += async () => {
try {
await e.Channel.SendMessage($"❗🔰**War against {cw.ShortPrint()} ended.**");
} catch { }
};
await e.Channel.SendMessage($"❗🔰**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**");
//war with the index X started.
};
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand(prefix + "createwar")
.Alias(prefix + "cw")
.Description($"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(DoFunc());
cgb.CreateCommand(prefix + "sw")
.Alias(prefix + "startwar")
.Description("Starts a war with a given number.")
.Parameter("number", ParameterType.Required)
.Do(async e => {
var warsInfo = GetInfo(e);
if (warsInfo == null) {
await e.Channel.SendMessage("💢🔰 **That war does not exist.**");
return;
}
var war = warsInfo.Item1[warsInfo.Item2];
try {
var startTask = war.Start();
await e.Channel.SendMessage($"🔰**STARTED WAR AGAINST {war.ShortPrint()}**");
await startTask;
} catch {
await e.Channel.SendMessage($"🔰**WAR AGAINST {war.ShortPrint()} IS ALREADY STARTED**");
}
});
cgb.CreateCommand(prefix + "listwar")
.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 => {
// if number is null, print all wars in a short way
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) {
await e.Channel.SendMessage("🔰 **No active wars.**");
return;
}
var sb = new StringBuilder();
sb.AppendLine("🔰 **LIST OF ACTIVE WARS**");
sb.AppendLine("**-------------------------**");
for (var i = 0; i < wars.Count; i++) {
sb.AppendLine($"**#{i + 1}.** `Enemy:` **{wars[i].EnemyClan}**");
sb.AppendLine($"\t\t`Size:` **{wars[i].Size} v {wars[i].Size}**");
sb.AppendLine("**-------------------------**");
}
await e.Channel.SendMessage(sb.ToString());
return;
}
//if number is not null, print the war needed
var warsInfo = GetInfo(e);
if (warsInfo == null) {
await e.Channel.SendMessage("💢🔰 **That war does not exist.**");
return;
}
await e.Channel.SendMessage(warsInfo.Item1[warsInfo.Item2].ToString());
});
cgb.CreateCommand(prefix + "claim")
.Alias(prefix + "call")
.Alias(prefix + "c")
.Description($"Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. \n**Usage**: {prefix}call [war_number] [base_number] (optional_otheruser)")
.Parameter("number")
.Parameter("baseNumber")
.Parameter("other_name", ParameterType.Unparsed)
.Do(async e => {
var warsInfo = GetInfo(e);
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)) {
await e.Channel.SendMessage("💢🔰 **Invalid base number.**");
return;
}
var usr =
string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
e.User.Name :
e.GetArg("other_name");
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) {
await e.Channel.SendMessage($"💢🔰 {ex.Message}");
}
});
cgb.CreateCommand(prefix + "cf")
.Alias(prefix + "claimfinish")
.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 => {
var warInfo = GetInfo(e);
if (warInfo == null || warInfo.Item1.Count == 0) {
await e.Channel.SendMessage("💢🔰 **That war does not exist.**");
return;
}
var usr =
string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
e.User.Name :
e.GetArg("other_name");
var war = warInfo.Item1[warInfo.Item2];
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) {
await e.Channel.SendMessage($"💢🔰 {ex.Message}");
}
});
cgb.CreateCommand(prefix + "unclaim")
.Alias(prefix + "uncall")
.Alias(prefix + "uc")
.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 => {
var warsInfo = GetInfo(e);
if (warsInfo == null || warsInfo.Item1.Count == 0) {
await e.Channel.SendMessage("💢🔰 **That war does not exist.**");
return;
}
var usr =
string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
e.User.Name :
e.GetArg("other_name");
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) {
await e.Channel.SendMessage($"💢🔰 {ex.Message}");
}
});
cgb.CreateCommand(prefix + "endwar")
.Alias(prefix + "ew")
.Description($"Ends the war with a given index.\n**Usage**:{prefix}ew [war_number]")
.Parameter("number")
.Do(async e => {
var warsInfo = GetInfo(e);
if (warsInfo == null) {
await e.Channel.SendMessage("💢🔰 That war does not exist.");
return;
}
warsInfo.Item1[warsInfo.Item2].End();
var size = warsInfo.Item1[warsInfo.Item2].Size;
warsInfo.Item1.RemoveAt(warsInfo.Item2);
});
}
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) {
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) {
return null;
}
num -= 1;
//get the actual war
return new Tuple<List<ClashWar>, int>(wars, num);
}
}
internal class Caller {
public string CallUser { get; }
public DateTime TimeAdded { get; private set; }
public bool BaseDestroyed { get; internal set; }
public Caller(string callUser, DateTime timeAdded, bool baseDestroyed) {
CallUser = callUser;
TimeAdded = timeAdded;
BaseDestroyed = baseDestroyed;
}
public void ResetTime() {
TimeAdded = DateTime.Now;
}
public void Destroy() {
BaseDestroyed = true;
}
}
internal class ClashWar {
private static TimeSpan callExpire => new TimeSpan(2, 0, 0);
private CommandEventArgs e;
public string EnemyClan { get; }
public int Size { get; }
private Caller[] bases { get; }
private CancellationTokenSource[] baseCancelTokens;
private CancellationTokenSource endTokenSource { get; } = new CancellationTokenSource();
public event Action<string> OnUserTimeExpired = delegate { };
public event Action OnWarEnded = delegate { };
public bool Started { get; set; } = false;
public ClashWar(string enemyClan, int size, CommandEventArgs e) {
this.EnemyClan = enemyClan;
this.Size = size;
this.bases = new Caller[size];
this.baseCancelTokens = new CancellationTokenSource[size];
}
internal void End() {
if (endTokenSource.Token.IsCancellationRequested) return;
endTokenSource.Cancel();
OnWarEnded();
}
internal void Call(string u, int baseNumber) {
if (baseNumber < 0 || baseNumber >= bases.Length)
throw new ArgumentException("Invalid base number");
if (bases[baseNumber] != null)
throw new ArgumentException("That base is already claimed.");
for (var i = 0; i < bases.Length; i++) {
if (bases[i]?.BaseDestroyed == false && bases[i]?.CallUser == u)
throw new ArgumentException($"@{u} You already claimed a base #{i + 1}. You can't claim a new one.");
}
bases[baseNumber] = new Caller(u.Trim(), DateTime.Now, false);
}
internal async Task Start() {
if (Started)
throw new InvalidOperationException();
try {
Started = true;
foreach (var b in bases.Where(b => b != null)) {
b.ResetTime();
}
Task.Run(async () => await ClearArray()).ConfigureAwait(false);
await Task.Delay(new TimeSpan(24, 0, 0), endTokenSource.Token);
} catch { } finally {
End();
}
}
internal int Uncall(string user) {
user = user.Trim();
for (var i = 0; i < bases.Length; i++) {
if (bases[i]?.CallUser != user) continue;
bases[i] = null;
return i;
}
throw new InvalidOperationException("You are not participating in that war.");
}
private async Task ClearArray() {
while (!endTokenSource.IsCancellationRequested) {
await Task.Delay(5000);
for (var i = 0; i < bases.Length; i++) {
if (bases[i] == null) continue;
if (!bases[i].BaseDestroyed && DateTime.Now - bases[i].TimeAdded >= callExpire) {
Console.WriteLine($"Removing user {bases[i].CallUser}");
OnUserTimeExpired(bases[i].CallUser);
bases[i] = null;
}
}
}
Console.WriteLine("Out of clear array");
}
public string ShortPrint() =>
$"`{EnemyClan}` ({Size} v {Size})";
public override string ToString() {
var sb = new StringBuilder();
sb.AppendLine($"🔰**WAR AGAINST `{EnemyClan}` ({Size} v {Size}) INFO:**");
if (!Started)
sb.AppendLine("`not started`");
for (var i = 0; i < bases.Length; i++) {
if (bases[i] == null) {
sb.AppendLine($"`{i + 1}.` ❌*unclaimed*");
} else {
if (bases[i].BaseDestroyed) {
sb.AppendLine($"`{i + 1}.` ✅ `{bases[i].CallUser}` ⭐ ⭐ ⭐");
} else {
var left = Started ? callExpire - (DateTime.Now - bases[i].TimeAdded) : callExpire;
sb.AppendLine($"`{i + 1}.` ✅ `{bases[i].CallUser}` {left.Hours}h {left.Minutes}m {left.Seconds}s left");
}
}
}
return sb.ToString();
}
internal int FinishClaim(string user) {
user = user.Trim();
for (var i = 0; i < bases.Length; i++) {
if (bases[i]?.BaseDestroyed != false || bases[i]?.CallUser != user) continue;
bases[i].BaseDestroyed = true;
return i;
}
throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base.");
}
}
}

View File

@ -69,11 +69,11 @@ namespace NadekoBot.Commands {
private Image GetDice(int num) => Properties.Resources.ResourceManager.GetObject("_" + num) as Image;
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand("$roll")
cgb.CreateCommand(Module.Prefix + "roll")
.Description("Rolls 2 dice from 0-10. If you supply a number [x] it rolls up to 30 normal dice.\n**Usage**: $roll [x]")
.Parameter("num", ParameterType.Optional)
.Do(DoFunc());
cgb.CreateCommand("$nroll")
cgb.CreateCommand(Module.Prefix + "nroll")
.Description("Rolls in a given range.\n**Usage**: `$nroll 5` (rolls 0-5) or `$nroll 5-15`")
.Parameter("range", ParameterType.Required)
.Do(NDoFunc());

View File

@ -47,13 +47,13 @@ namespace NadekoBot.Commands {
};
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand("$draw")
cgb.CreateCommand(Module.Prefix + "draw")
.Description("Draws a card from the deck.If you supply number [x], she draws up to 5 cards from the deck.\n**Usage**: $draw [x]")
.Parameter("count", ParameterType.Optional)
.Do(DoFunc());
cgb.CreateCommand("$shuffle")
.Alias("$reshuffle")
cgb.CreateCommand(Module.Prefix + "shuffle")
.Alias(Module.Prefix + "sh")
.Description("Reshuffles all cards back into the deck.")
.Do(async e => {
AllDecks.AddOrUpdate(e.Server,

View File

@ -41,8 +41,8 @@ namespace NadekoBot.Commands {
}
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand(";cfi")
.Alias(";channelfilterinvites")
cgb.CreateCommand(Module.Prefix + "cfi")
.Alias(Module.Prefix + "channelfilterinvites")
.Description("Enables or disables automatic deleting of invites on the channel." +
"If no channel supplied, it will default to current one. Use ALL to apply to all existing channels at once." +
"\n**Usage**: ;cfi enable #general-chat")
@ -74,8 +74,8 @@ namespace NadekoBot.Commands {
}
});
cgb.CreateCommand(";sfi")
.Alias(";serverfilterinvites")
cgb.CreateCommand(Module.Prefix + "sfi")
.Alias(Module.Prefix + "serverfilterinvites")
.Description("Enables or disables automatic deleting of invites on the server.\n**Usage**: ;sfi disable")
.Parameter("bool")
.Do(async e => {

View File

@ -36,7 +36,7 @@ namespace NadekoBot.Commands {
};
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand("$flip")
cgb.CreateCommand(Module.Prefix + "flip")
.Description("Flips coin(s) - heads or tails, and shows an image.\n**Usage**: `$flip` or `$flip 3`")
.Parameter("count", ParameterType.Optional)
.Do(DoFunc());

View File

@ -80,17 +80,17 @@ Version: `{NadekoStats.Instance.BotVersion}`";
};
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand("-h")
.Alias(new string[] { "-help", NadekoBot.BotMention + " help", NadekoBot.BotMention + " h", "~h" })
cgb.CreateCommand(Module.Prefix + "h")
.Alias(Module.Prefix + "help", NadekoBot.BotMention + " help", NadekoBot.BotMention + " h", "~h")
.Description("Either shows a help for a single command, or PMs you help link if no arguments are specified.\n**Usage**: '-h !m q' or just '-h' ")
.Parameter("command", ParameterType.Unparsed)
.Do(DoFunc());
cgb.CreateCommand("-hgit")
cgb.CreateCommand(Module.Prefix + "hgit")
.Description("OWNER ONLY commandlist.md file generation.")
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Do(DoGitFunc());
cgb.CreateCommand("-readme")
.Alias("-guide")
cgb.CreateCommand(Module.Prefix + "readme")
.Alias(Module.Prefix + "guide")
.Description("Sends a readme and a guide links to the channel.")
.Do(async e =>
await e.Channel.SendMessage(
@ -100,7 +100,7 @@ Version: `{NadekoStats.Instance.BotVersion}`";
**LIST OF COMMANDS**: <https://github.com/Kwoth/NadekoBot/blob/master/commandlist.md>"));
cgb.CreateCommand("-donate")
cgb.CreateCommand(Module.Prefix + "donate")
.Alias("~donate")
.Description("Instructions for helping the project!")
.Do(async e => {

View File

@ -57,7 +57,7 @@ namespace NadekoBot.Commands {
}
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand("~lolchamp")
cgb.CreateCommand(Module.Prefix + "lolchamp")
.Description("Shows League Of Legends champion statistics. If there are spaces/apostrophes or in the name - omit them. Optional second parameter is a role.\n**Usage**:~lolchamp Riven or ~lolchamp Annie sup")
.Parameter("champ", ParameterType.Required)
.Parameter("position", ParameterType.Unparsed)
@ -244,7 +244,7 @@ Assists: {general["assists"]} Ban: {general["banRate"]}%
}
});
cgb.CreateCommand("~lolban")
cgb.CreateCommand(Module.Prefix + "lolban")
.Description("Shows top 6 banned champions ordered by ban rate. Ban these champions and you will be Plat 5 in no time.")
.Do(async e => {

View File

@ -122,11 +122,11 @@ namespace NadekoBot.Commands {
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand(".logserver")
cgb.CreateCommand(Module.Prefix + "logserver")
.Description("Toggles logging in this channel. Logs every message sent/deleted/edited on the server. BOT OWNER ONLY. SERVER OWNER ONLY.")
.Do(DoFunc());
cgb.CreateCommand(".userpresence")
cgb.CreateCommand(Module.Prefix + "userpresence")
.Description("Starts logging to this channel when someone from the server goes online/offline/idle. BOT OWNER ONLY. SERVER OWNER ONLY.")
.Do(async e => {
if (!NadekoBot.IsOwner(e.User.Id) ||
@ -142,7 +142,7 @@ namespace NadekoBot.Commands {
await e.Channel.SendMessage($"**User presence notifications disabled.**");
});
cgb.CreateCommand(".voicepresence")
cgb.CreateCommand(Module.Prefix + "voicepresence")
.Description("Toggles logging to this channel whenever someone joins or leaves a voice channel you are in right now. BOT OWNER ONLY. SERVER OWNER ONLY.")
.Parameter("all", ParameterType.Optional)
.Do(async e => {

View File

@ -36,7 +36,7 @@ namespace NadekoBot.Commands {
}
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand(".repeat")
cgb.CreateCommand(Module.Prefix + "repeat")
.Description("Repeat a message every X minutes. If no parameters are specified, " +
"repeat is disabled. Requires manage messages.")
.Parameter("minutes", ParameterType.Optional)

View File

@ -73,14 +73,14 @@ namespace NadekoBot.Commands {
};
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand(".rotateplaying")
.Alias(".ropl")
cgb.CreateCommand(Module.Prefix + "rotateplaying")
.Alias(Module.Prefix + "ropl")
.Description("Toggles rotation of playing status of the dynamic strings you specified earlier.")
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Do(DoFunc());
cgb.CreateCommand(".addplaying")
.Alias(".adpl")
cgb.CreateCommand(Module.Prefix + "addplaying")
.Alias(Module.Prefix + "adpl")
.Description("Adds a specified string to the list of playing strings to rotate. " +
"Supported placeholders: " + string.Join(", ", PlayingPlaceholders.Keys))
.Parameter("text", ParameterType.Unparsed)
@ -96,8 +96,8 @@ namespace NadekoBot.Commands {
await e.Channel.SendMessage("🆗 `Added a new playing string.`");
});
cgb.CreateCommand(".listplaying")
.Alias(".lipl")
cgb.CreateCommand(Module.Prefix + "listplaying")
.Alias(Module.Prefix + "lipl")
.Description("Lists all playing statuses with their corresponding number.")
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())
.Do(async e => {
@ -111,8 +111,8 @@ namespace NadekoBot.Commands {
await e.Channel.SendMessage(sb.ToString());
});
cgb.CreateCommand(".removeplaying")
.Alias(".repl", ".rmpl")
cgb.CreateCommand(Module.Prefix + "removeplaying")
.Alias(Module.Prefix + "repl", Module.Prefix + "rmpl")
.Description("Removes a playing string on a given number.")
.Parameter("number", ParameterType.Required)
.AddCheck(Classes.Permissions.SimpleCheckers.OwnerOnly())

View File

@ -18,7 +18,7 @@ namespace NadekoBot.Commands {
}
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand(">poll")
cgb.CreateCommand(Module.Prefix + "poll")
.Description("Creates a poll, only person who has manage server permission can do it.\n**Usage**: >poll Question?;Answer1;Answ 2;A_3")
.Parameter("allargs", ParameterType.Unparsed)
.Do(async e => {
@ -40,7 +40,7 @@ namespace NadekoBot.Commands {
}
});
});
cgb.CreateCommand(">pollend")
cgb.CreateCommand(Module.Prefix + "pollend")
.Description("Stops active poll on this server and prints the results in this channel.")
.Do(async e => {
if (!e.User.ServerPermissions.ManageChannels)

View File

@ -30,7 +30,7 @@ namespace NadekoBot.Commands {
}
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand(".slowmode")
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)
.Do(async e => {

View File

@ -175,7 +175,7 @@ namespace NadekoBot.Commands {
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand(".greet")
cgb.CreateCommand(Module.Prefix + "greet")
.Description("Enables or Disables anouncements on the current channel when someone joins the server.")
.Do(async e => {
if (!e.User.ServerPermissions.ManageServer) return;
@ -190,7 +190,7 @@ namespace NadekoBot.Commands {
await e.Channel.SendMessage("Greet announcements disabled.");
});
cgb.CreateCommand(".greetmsg")
cgb.CreateCommand(Module.Prefix + "greetmsg")
.Description("Sets a new announce message. Type %user% if you want to mention the new member.\n**Usage**: .greetmsg Welcome to the server, %user%.")
.Parameter("msg", ParameterType.Unparsed)
.Do(async e => {
@ -205,7 +205,7 @@ namespace NadekoBot.Commands {
await e.Channel.SendMessage("Enable greet messsages by typing `.greet`");
});
cgb.CreateCommand(".bye")
cgb.CreateCommand(Module.Prefix + "bye")
.Description("Enables or Disables anouncements on the current channel when someone leaves the server.")
.Do(async e => {
if (!e.User.ServerPermissions.ManageServer) return;
@ -220,7 +220,7 @@ namespace NadekoBot.Commands {
await e.Channel.SendMessage("Bye announcements disabled.");
});
cgb.CreateCommand(".byemsg")
cgb.CreateCommand(Module.Prefix + "byemsg")
.Description("Sets a new announce leave message. Type %user% if you want to mention the new member.\n**Usage**: .byemsg %user% has left the server.")
.Parameter("msg", ParameterType.Unparsed)
.Do(async e => {
@ -235,7 +235,7 @@ namespace NadekoBot.Commands {
await e.Channel.SendMessage("Enable bye messsages by typing `.bye`.");
});
cgb.CreateCommand(".byepm")
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 => {
if (!e.User.ServerPermissions.ManageServer) return;
@ -251,7 +251,7 @@ namespace NadekoBot.Commands {
await e.Channel.SendMessage("Enable bye messsages by typing `.bye`, and set the bye message using `.byemsg`");
});
cgb.CreateCommand(".greetpm")
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 => {
if (!e.User.ServerPermissions.ManageServer) return;

View File

@ -140,15 +140,15 @@ namespace NadekoBot.Commands {
};
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand("typestart")
cgb.CreateCommand(Module.Prefix + "typestart")
.Description("Starts a typing contest.")
.Do(DoFunc());
cgb.CreateCommand("typestop")
cgb.CreateCommand(Module.Prefix + "typestop")
.Description("Stops a typing contest on the current channel.")
.Do(QuitFunc());
cgb.CreateCommand("typeadd")
cgb.CreateCommand(Module.Prefix + "typeadd")
.Description("Adds a new article to the typing contest. Owner only.")
.Parameter("text", ParameterType.Unparsed)
.Do(async e => {

View File

@ -23,16 +23,12 @@ namespace NadekoBot.Commands {
};
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand("t")
cgb.CreateCommand(Module.Prefix + "t")
.Description("Starts a game of trivia.")
.Alias("-t")
.Do(DoFunc());
cgb.CreateCommand("tl")
cgb.CreateCommand(Module.Prefix + "tl")
.Description("Shows a current trivia leaderboard.")
.Alias("-tl")
.Alias("tlb")
.Alias("-tlb")
.Do(async e=> {
TriviaGame trivia;
if (RunningTrivias.TryGetValue(e.Server.Id, out trivia))
@ -41,9 +37,8 @@ namespace NadekoBot.Commands {
await e.Channel.SendMessage("No trivia is running on this server.");
});
cgb.CreateCommand("tq")
cgb.CreateCommand(Module.Prefix + "tq")
.Description("Quits current trivia after current question.")
.Alias("-tq")
.Do(async e=> {
TriviaGame trivia;
if (RunningTrivias.TryGetValue(e.Server.Id, out trivia)) {

View File

@ -29,14 +29,12 @@ namespace NadekoBot.Commands {
};
internal override void Init(CommandGroupBuilder cgb) {
/*
cgb.CreateCommand(".voicenotif")
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)
.Do(DoFunc());
*/
}
public VoiceNotificationCommand(DiscordModule module) : base(module) {}
public VoiceNotificationCommand(DiscordModule module) : base(module) { }
}
}

View File

@ -59,8 +59,8 @@ namespace NadekoBot.Commands {
}
internal override void Init(CommandGroupBuilder cgb) {
cgb.CreateCommand(".v+t")
.Alias(".voice+text")
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())

View File

@ -0,0 +1,241 @@
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.Modules;
using NadekoBot.Classes.ClashOfClans;
using NadekoBot.Modules;
namespace NadekoBot.Commands {
internal class ClashOfClans : DiscordModule
{
public override string Prefix { get; } = ",";
public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; } = new ConcurrentDictionary<ulong, List<ClashWar>>();
private readonly object writeLock = new object();
public override void Install(ModuleManager manager) {
manager.CreateCommands("", cgb => {
cgb.CreateCommand(Prefix + "createwar")
.Alias(Prefix + "cw")
.Description(
$"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 => {
if (!e.User.ServerPermissions.ManageChannels)
return;
List<ClashWar> 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)) {
return;
}
int size;
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 {
await
e.Channel.SendMessage(
$"❗🔰**Claim from @{u} for a war against {cw.ShortPrint()} has expired.**");
} catch { }
};
cw.OnWarEnded += async () => {
try {
await e.Channel.SendMessage($"❗🔰**War against {cw.ShortPrint()} ended.**");
} catch { }
};
await e.Channel.SendMessage($"❗🔰**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**");
//war with the index X started.
});
cgb.CreateCommand(Prefix + "sw")
.Alias(Prefix + "startwar")
.Description("Starts a war with a given number.")
.Parameter("number", ParameterType.Required)
.Do(async e => {
var warsInfo = GetInfo(e);
if (warsInfo == null) {
await e.Channel.SendMessage("💢🔰 **That war does not exist.**");
return;
}
var war = warsInfo.Item1[warsInfo.Item2];
try {
var startTask = war.Start();
await e.Channel.SendMessage($"🔰**STARTED WAR AGAINST {war.ShortPrint()}**");
await startTask;
} catch {
await e.Channel.SendMessage($"🔰**WAR AGAINST {war.ShortPrint()} IS ALREADY STARTED**");
}
});
cgb.CreateCommand(Prefix + "listwar")
.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 => {
// if number is null, print all wars in a short way
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) {
await e.Channel.SendMessage("🔰 **No active wars.**");
return;
}
var sb = new StringBuilder();
sb.AppendLine("🔰 **LIST OF ACTIVE WARS**");
sb.AppendLine("**-------------------------**");
for (var i = 0; i < wars.Count; i++) {
sb.AppendLine($"**#{i + 1}.** `Enemy:` **{wars[i].EnemyClan}**");
sb.AppendLine($"\t\t`Size:` **{wars[i].Size} v {wars[i].Size}**");
sb.AppendLine("**-------------------------**");
}
await e.Channel.SendMessage(sb.ToString());
return;
}
//if number is not null, print the war needed
var warsInfo = GetInfo(e);
if (warsInfo == null) {
await e.Channel.SendMessage("💢🔰 **That war does not exist.**");
return;
}
await e.Channel.SendMessage(warsInfo.Item1[warsInfo.Item2].ToString());
});
cgb.CreateCommand(Prefix + "claim")
.Alias(Prefix + "call")
.Alias(Prefix + "c")
.Description($"Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. \n**Usage**: {Prefix}call [war_number] [base_number] (optional_otheruser)")
.Parameter("number")
.Parameter("baseNumber")
.Parameter("other_name", ParameterType.Unparsed)
.Do(async e => {
var warsInfo = GetInfo(e);
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)) {
await e.Channel.SendMessage("💢🔰 **Invalid base number.**");
return;
}
var usr =
string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
e.User.Name :
e.GetArg("other_name");
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) {
await e.Channel.SendMessage($"💢🔰 {ex.Message}");
}
});
cgb.CreateCommand(Prefix + "cf")
.Alias(Prefix + "claimfinish")
.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 => {
var warInfo = GetInfo(e);
if (warInfo == null || warInfo.Item1.Count == 0) {
await e.Channel.SendMessage("💢🔰 **That war does not exist.**");
return;
}
var usr =
string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
e.User.Name :
e.GetArg("other_name");
var war = warInfo.Item1[warInfo.Item2];
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) {
await e.Channel.SendMessage($"💢🔰 {ex.Message}");
}
});
cgb.CreateCommand(Prefix + "unclaim")
.Alias(Prefix + "uncall")
.Alias(Prefix + "uc")
.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 => {
var warsInfo = GetInfo(e);
if (warsInfo == null || warsInfo.Item1.Count == 0) {
await e.Channel.SendMessage("💢🔰 **That war does not exist.**");
return;
}
var usr =
string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
e.User.Name :
e.GetArg("other_name");
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) {
await e.Channel.SendMessage($"💢🔰 {ex.Message}");
}
});
cgb.CreateCommand(Prefix + "endwar")
.Alias(Prefix + "ew")
.Description($"Ends the war with a given index.\n**Usage**:{Prefix}ew [war_number]")
.Parameter("number")
.Do(async e => {
var warsInfo = GetInfo(e);
if (warsInfo == null) {
await e.Channel.SendMessage("💢🔰 That war does not exist.");
return;
}
warsInfo.Item1[warsInfo.Item2].End();
var size = warsInfo.Item1[warsInfo.Item2].Size;
warsInfo.Item1.RemoveAt(warsInfo.Item2);
});
});
}
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) {
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) {
return null;
}
num -= 1;
//get the actual war
return new Tuple<List<ClashWar>, int>(wars, num);
}
}
}

View File

@ -26,7 +26,7 @@ namespace NadekoBot.Modules
commands.ForEach(com => com.Init(cgb));
cgb.CreateCommand("$raffle")
cgb.CreateCommand(Prefix +"raffle")
.Description("Prints a name and ID of a random user from the online list from the (optional) role.")
.Parameter("role", ParameterType.Optional)
.Do(async e => {
@ -41,7 +41,7 @@ namespace NadekoBot.Modules
var usr = membersArray[new System.Random().Next(0, membersArray.Length)];
await e.Channel.SendMessage($"**Raffled user:** {usr.Name} (id: {usr.Id})");
});
cgb.CreateCommand("$$$")
cgb.CreateCommand(Prefix + "$$")
.Description("Check how many NadekoFlowers you have.")
.Do(async e => {
var pts = Classes.DbHandler.Instance.GetStateByUserId((long)e.User.Id)?.Value ?? 0;

View File

@ -7,8 +7,6 @@ using System.IO;
using Discord.Commands;
using NadekoBot.Extensions;
//🃏
//🏁
namespace NadekoBot.Modules {
internal class Games : DiscordModule {
private readonly string[] _8BallAnswers;
@ -18,7 +16,6 @@ namespace NadekoBot.Modules {
commands.Add(new Trivia(this));
commands.Add(new SpeedTyping(this));
commands.Add(new PollCommand(this));
commands.Add(new ClashOfClans(this));
_8BallAnswers = JArray.Parse(File.ReadAllText("data/8ball.json")).Select(t => t.ToString()).ToArray();
}

View File

@ -18,15 +18,15 @@ namespace NadekoBot.Modules {
cgb.AddCheck(Classes.Permissions.PermissionChecker.Instance);
commands.ForEach(com => com.Init(cgb));
cgb.CreateCommand(".modules")
.Alias("-modules")
cgb.CreateCommand(Prefix + "modules")
.Alias(".modules")
.Description("List all bot modules.")
.Do(async e => {
await e.Channel.SendMessage("`List of modules:` \n• " + string.Join("\n• ", NadekoBot.Client.GetService<ModuleService>().Modules.Select(m => m.Name)));
});
cgb.CreateCommand(".commands")
.Alias("-commands")
cgb.CreateCommand(Prefix + "commands")
.Alias(".commands")
.Description("List all of the bot's commands from a certain module.")
.Parameter("module", ParameterType.Unparsed)
.Do(async e => {

View File

@ -33,12 +33,12 @@ namespace NadekoBot.Modules {
}
public override string Prefix { get; } = "!m ";
public override string Prefix { get; } = "!m";
public override void Install(ModuleManager manager) {
var client = NadekoBot.Client;
manager.CreateCommands("!m", cgb => {
manager.CreateCommands(Prefix, cgb => {
cgb.AddCheck(Classes.Permissions.PermissionChecker.Instance);

View File

@ -121,6 +121,7 @@ namespace NadekoBot {
modules.Add(new Music(), "Music", ModuleFilter.None);
modules.Add(new Searches(), "Searches", ModuleFilter.None);
modules.Add(new NSFW(), "NSFW", ModuleFilter.None);
modules.Add(new ClashOfClans(), "ClashOfClans", ModuleFilter.None);
if (!string.IsNullOrWhiteSpace(Creds.TrelloAppKey))
modules.Add(new Trello(), "Trello", ModuleFilter.None);