diff --git a/NadekoBot/App.config b/NadekoBot/App.config index 151cc154..be94d15f 100644 --- a/NadekoBot/App.config +++ b/NadekoBot/App.config @@ -1,14 +1,14 @@ -ο»Ώ + - + - - + + - \ No newline at end of file + diff --git a/NadekoBot/Classes/DBHandler.cs b/NadekoBot/Classes/DBHandler.cs index ba99b635..c6488a27 100644 --- a/NadekoBot/Classes/DBHandler.cs +++ b/NadekoBot/Classes/DBHandler.cs @@ -34,6 +34,14 @@ namespace NadekoBot.Classes } } + internal T FindOne(Expression> p) where T : IDataModel, new() + { + using (var conn = new SQLiteConnection(FilePath)) + { + return conn.Table().Where(p).FirstOrDefault(); + } + } + internal void DeleteAll() where T : IDataModel { using (var conn = new SQLiteConnection(FilePath)) diff --git a/NadekoBot/Classes/FlowersHandler.cs b/NadekoBot/Classes/FlowersHandler.cs index c40dd83e..d696c0b1 100644 --- a/NadekoBot/Classes/FlowersHandler.cs +++ b/NadekoBot/Classes/FlowersHandler.cs @@ -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 { - DbHandler.Instance.InsertData(new _DataModels.CurrencyTransaction - { - Reason = reason, - UserId = (long)u.Id, - Value = -amount, - }); + Reason = reason, + UserId = (long)u.Id, + Value = -amount, }); + return true; } } } diff --git a/NadekoBot/Commands/PlantPick.cs b/NadekoBot/Commands/PlantPick.cs new file mode 100644 index 00000000..8d688911 --- /dev/null +++ b/NadekoBot/Commands/PlantPick.cs @@ -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 +{ + /// + /// 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 + /// + class PlantPick : DiscordCommand + { + public PlantPick(DiscordModule module) : base(module) + { + + } + + //channelid/messageid pair + ConcurrentDictionary plantedFlowerChannels = new ConcurrentDictionary(); + + 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(); + }); + } + } +} diff --git a/NadekoBot/Modules/Administration/AdministrationModule.cs b/NadekoBot/Modules/Administration/AdministrationModule.cs index cc07e6a1..1a0cbb29 100644 --- a/NadekoBot/Modules/Administration/AdministrationModule.cs +++ b/NadekoBot/Modules/Administration/AdministrationModule.cs @@ -228,6 +228,7 @@ namespace NadekoBot.Modules.Administration try { await e.Server.Ban(usr); + await e.Channel.SendMessage("Banned user " + usr.Name + " Id: " + usr.Id); } catch diff --git a/NadekoBot/Modules/ClashOfClans.cs b/NadekoBot/Modules/ClashOfClans.cs index 17264553..2bc9ab42 100644 --- a/NadekoBot/Modules/ClashOfClans.cs +++ b/NadekoBot/Modules/ClashOfClans.cs @@ -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 wars; - if (!ClashWars.TryGetValue(e.Server.Id, out wars)) { + if (!ClashWars.TryGetValue(e.Server.Id, out wars)) + { wars = new List(); 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 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, int> GetInfo(CommandEventArgs e) { + private static Tuple, int> GetInfo(CommandEventArgs e) + { //check if there are any wars List 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; diff --git a/NadekoBot/Modules/Gambling/GamblingModule.cs b/NadekoBot/Modules/Gambling/GamblingModule.cs index 911fd367..8fe25f16 100644 --- a/NadekoBot/Modules/Gambling/GamblingModule.cs +++ b/NadekoBot/Modules/Gambling/GamblingModule.cs @@ -63,7 +63,7 @@ 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}!"); @@ -109,7 +109,7 @@ namespace NadekoBot.Modules.Gambling if (mentionedUser == null) return; - await FlowersHandler.RemoveFlowersAsync(mentionedUser, $"Taken by bot owner.({e.User.Name}/{e.User.Id})", (int)amount); + 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}!"); }); diff --git a/NadekoBot/Modules/Games.cs b/NadekoBot/Modules/Games.cs index 508a0603..6d2e39c7 100644 --- a/NadekoBot/Modules/Games.cs +++ b/NadekoBot/Modules/Games.cs @@ -16,6 +16,7 @@ namespace NadekoBot.Modules 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)); } diff --git a/NadekoBot/Modules/Pokemon/PokemonModule.cs b/NadekoBot/Modules/Pokemon/PokemonModule.cs index 11db1f23..285fceb5 100644 --- a/NadekoBot/Modules/Pokemon/PokemonModule.cs +++ b/NadekoBot/Modules/Pokemon/PokemonModule.cs @@ -225,7 +225,7 @@ namespace NadekoBot.Modules.Pokemon return; } var target = (usr.Id == e.User.Id) ? "yourself" : usr.Name; - await FlowersHandler.RemoveFlowersAsync(e.User, $"Poke-Heal {target}", amount); + FlowersHandler.RemoveFlowers(e.User, $"Poke-Heal {target}", amount); //healing targetStats.Hp = targetStats.MaxHp; if (HP < 0) @@ -285,13 +285,13 @@ namespace NadekoBot.Modules.Pokemon //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!"); return; } - await FlowersHandler.RemoveFlowersAsync(e.User, $"set usertype to {targetTypeStr}", amount); + FlowersHandler.RemoveFlowers(e.User, $"set usertype to {targetTypeStr}", amount); //Actually changing the type here var preTypes = DbHandler.Instance.GetAllRows(); Dictionary Dict = preTypes.ToDictionary(x => x.UserId, y => y.Id); diff --git a/NadekoBot/NadekoBot.csproj b/NadekoBot/NadekoBot.csproj index dcd4fa07..f5960d68 100644 --- a/NadekoBot/NadekoBot.csproj +++ b/NadekoBot/NadekoBot.csproj @@ -9,7 +9,7 @@ Properties NadekoBot NadekoBot - v4.5.2 + v4.6 512 true false @@ -32,6 +32,7 @@ true + AnyCPU @@ -151,6 +152,7 @@ + diff --git a/NadekoBot/packages.config b/NadekoBot/packages.config index ec861bf0..19d0d51d 100644 --- a/NadekoBot/packages.config +++ b/NadekoBot/packages.config @@ -9,7 +9,7 @@ - + diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index d83b8b1a..0ddc6cc5 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -8,7 +8,7 @@ Properties Tests Tests - v4.5.2 + v4.6 512 {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10.0