diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs
index f7dcd48a..fec1a2d0 100644
--- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs
+++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs
@@ -1,167 +1,219 @@
-//using Discord;
-//using Discord.Commands;
-//using NadekoBot.Classes;
-//using NadekoBot.Extensions;
-//using NadekoBot.Modules.Permissions.Classes;
-//using System;
-//using System.Collections.Concurrent;
-//using System.Collections.Generic;
-//using System.IO;
-//using System.Linq;
-//using System.Security.Cryptography;
-//using System.Threading;
-//using System.Threading.Tasks;
+using Discord;
+using Discord.Commands;
+using Discord.WebSocket;
+using NadekoBot.Attributes;
+using NadekoBot.Extensions;
+using NadekoBot.Services;
+using NadekoBot.Services.Database;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Threading;
+using System.Threading.Tasks;
-////todo rewrite
-//namespace NadekoBot.Modules.Games
-//{
-// ///
-// /// 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
-// {
+//todo rewrite
+namespace NadekoBot.Modules.Games
+{
+ public partial class Games
+ {
+ ///
+ /// 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
+ ///
+ public class PlantPick
+ {
-// private Random rng;
-// public PlantPick(DiscordModule module) : base(module)
-// {
-// NadekoBot.Client.MessageReceived += PotentialFlowerGeneration;
-// rng = new Random();
-// }
+ private Random rng;
-// private static readonly ConcurrentDictionary plantpickCooldowns = new ConcurrentDictionary();
+ private ConcurrentDictionary generationChannels = new ConcurrentDictionary();
+ //channelid/message
+ private ConcurrentDictionary> plantedFlowers = new ConcurrentDictionary>();
+ //channelId/last generation
+ private ConcurrentDictionary lastGenerations = new ConcurrentDictionary();
-// private async void PotentialFlowerGeneration(object sender, Discord.MessageEventArgs e)
-// {
-// try
-// {
-// if (e.Server == null || e.Channel.IsPrivate || e.Message.IsAuthor)
-// return;
-// var config = Classes.SpecificConfigurations.Default.Of(e.Server.Id);
-// var now = DateTime.Now;
-// int cd;
-// DateTime lastSpawned;
-// if (config.GenerateCurrencyChannels.TryGetValue(e.Channel.Id, out cd))
-// if (!plantpickCooldowns.TryGetValue(e.Channel.Id, out lastSpawned) || (lastSpawned + new TimeSpan(0, cd, 0)) < now)
-// {
-// var rnd = Math.Abs(rng.Next(0,101));
-// if (rnd == 0)
-// {
-// var msgs = new[] { await e.Channel.SendFile(GetRandomCurrencyImagePath()), await channel.SendMessageAsync($"❗ A random {Gambling.CurrencyName} appeared! Pick it up by typing `>pick`") };
-// plantedFlowerChannels.AddOrUpdate(e.Channel.Id, msgs, (u, m) => { m.ForEach(async msgToDelete => { try { await msgToDelete.Delete(); } catch { } }); return msgs; });
-// plantpickCooldowns.AddOrUpdate(e.Channel.Id, now, (i, d) => now);
-// }
-// }
-// }
-// catch { }
-// }
-// //channelid/messageid pair
-// ConcurrentDictionary> plantedFlowerChannels = new ConcurrentDictionary>();
+ private float chance;
+ private int cooldown;
-// private SemaphoreSlim locker = new SemaphoreSlim(1,1);
+ public PlantPick(DiscordModule module)
+ {
+ NadekoBot.Client.MessageReceived += PotentialFlowerGeneration;
+ rng = new Random();
-// public override void Init(CommandGroupBuilder cgb)
-// {
-// cgb.CreateCommand(Module.Prefix + "pick")
-// .Description($"Picks a flower planted in this channel. | `{Prefix}pick`")
-// .Do(async e =>
-// {
-// IEnumerable msgs;
+ using (var uow = DbHandler.UnitOfWork())
+ {
+ var conf = uow.BotConfig.GetOrCreate();
+ var x =
+ generationChannels = new ConcurrentDictionary(uow.GuildConfigs.GetAll()
+ .Where(c => c.GenerateCurrencyChannelId != null)
+ .ToDictionary(c => c.GenerateCurrencyChannelId.Value, c => true));
+ chance = conf.CurrencyGenerationChance;
+ cooldown = conf.CurrencyGenerationCooldown;
+ }
+ }
-// await e.Message.Delete().ConfigureAwait(false);
-// if (!plantedFlowerChannels.TryRemove(e.Channel.Id, out msgs))
-// return;
+ private Task PotentialFlowerGeneration(IMessage imsg)
+ {
+ var msg = imsg as IUserMessage;
+ if (msg == null)
+ return Task.CompletedTask;
-// foreach(var msgToDelete in msgs)
-// await msgToDelete.Delete().ConfigureAwait(false);
+ var channel = imsg.Channel as ITextChannel;
+ if (channel == null)
+ return Task.CompletedTask;
-// await CurrencyHandler.AddFlowersAsync(umsg.Author, "Picked a flower.", 1, true).ConfigureAwait(false);
-// var msg = await channel.SendMessageAsync($"**{umsg.Author.Username}** picked a {Gambling.CurrencyName}!").ConfigureAwait(false);
-// ThreadPool.QueueUserWorkItem(async (state) =>
-// {
-// try
-// {
-// await Task.Delay(10000).ConfigureAwait(false);
-// await msg.Delete().ConfigureAwait(false);
-// }
-// catch { }
-// });
-// });
+ bool shouldGenerate;
+ if (!generationChannels.TryGetValue(channel.Id, out shouldGenerate) || !shouldGenerate)
+ return Task.CompletedTask;
-// 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) | `{Prefix}plant`")
-// .Do(async e =>
-// {
-// await locker.WaitAsync().ConfigureAwait(false);
-// try
-// {
-// if (plantedFlowerChannels.ContainsKey(e.Channel.Id))
-// {
-// await channel.SendMessageAsync($"There is already a {Gambling.CurrencyName} in this channel.").ConfigureAwait(false);
-// return;
-// }
-// var removed = await CurrencyHandler.RemoveFlowers(umsg.Author, "Planted a flower.", 1, true).ConfigureAwait(false);
-// if (!removed)
-// {
-// await channel.SendMessageAsync($"You don't have any {Gambling.CurrencyName}s.").ConfigureAwait(false);
-// return;
-// }
+ var t = Task.Run(async () =>
+ {
+ var lastGeneration = lastGenerations.GetOrAdd(channel.Id, DateTime.MinValue);
-// var file = GetRandomCurrencyImagePath();
-// Message msg;
-// if (file == null)
-// msg = await channel.SendMessageAsync(Gambling.CurrencySign).ConfigureAwait(false);
-// else
-// msg = await e.Channel.SendFile(file).ConfigureAwait(false);
-// var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(Gambling.CurrencyName[0]);
-// var msg2 = await channel.SendMessageAsync($"Oh how Nice! **{umsg.Author.Username}** planted {(vowelFirst ? "an" : "a")} {Gambling.CurrencyName}. Pick it using {Module.Prefix}pick").ConfigureAwait(false);
-// plantedFlowerChannels.TryAdd(e.Channel.Id, new[] { msg, msg2 });
-// }
-// finally { locker.Release(); }
-// });
+ if (DateTime.Now - TimeSpan.FromSeconds(cooldown) < lastGeneration) //recently generated in this channel, don't generate again
+ return;
-// cgb.CreateCommand(Prefix + "gencurrency")
-// .Alias(Prefix + "gc")
-// .Description($"Toggles currency generation on this channel. Every posted message will have 2% chance to spawn a {Gambling.CurrencyName}. Optional parameter cooldown time in minutes, 5 minutes by default. Requires Manage Messages permission. | `{Prefix}gc` or `{Prefix}gc 60`")
-// .AddCheck(SimpleCheckers.ManageMessages())
-// .Parameter("cd", ParameterType.Unparsed)
-// .Do(async e =>
-// {
-// var cdStr = cd;
-// int cd = 2;
-// if (!int.TryParse(cdStr, out cd) || cd < 0)
-// {
-// cd = 2;
-// }
-// var config = SpecificConfigurations.Default.Of(e.Server.Id);
-// int throwaway;
-// if (config.GenerateCurrencyChannels.TryRemove(e.Channel.Id, out throwaway))
-// {
-// await channel.SendMessageAsync("`Currency generation disabled on this channel.`").ConfigureAwait(false);
-// }
-// else
-// {
-// if (config.GenerateCurrencyChannels.TryAdd(e.Channel.Id, cd))
-// await channel.SendMessageAsync($"`Currency generation enabled on this channel. Cooldown is {cd} minutes.`").ConfigureAwait(false);
-// }
-// });
-// }
+ var num = rng.Next(1, 101) + chance * 100;
-// private string GetRandomCurrencyImagePath() =>
-// Directory.GetFiles("data/currency_images").OrderBy(s => rng.Next()).FirstOrDefault();
+ if (num > 100)
+ {
+ lastGenerations.AddOrUpdate(channel.Id, DateTime.Now, (id, old) => DateTime.Now);
+ //todo get prefix
+ try
+ {
+ var sent = await channel.SendFileAsync(
+ GetRandomCurrencyImagePath(),
+ $"❗ A random { Gambling.Gambling.CurrencyName } appeared! Pick it up by typing `>pick`")
+ .ConfigureAwait(false);
+ plantedFlowers.AddOrUpdate(channel.Id, new List() { sent }, (id, old) => { old.Add(sent); return old; });
+ }
+ catch { }
+
+ }
+ });
+ return Task.CompletedTask;
+ }
+ [LocalizedCommand, LocalizedDescription, LocalizedSummary, LocalizedAlias]
+ [RequireContext(ContextType.Guild)]
+ public async Task Pick(IUserMessage imsg)
+ {
+ var channel = (ITextChannel)imsg.Channel;
-// int GetRandomNumber()
-// {
-// using (var rg = RandomNumberGenerator.Create())
-// {
-// byte[] rno = new byte[4];
-// rg.GetBytes(rno);
-// int randomvalue = BitConverter.ToInt32(rno, 0);
-// return randomvalue;
-// }
-// }
-// }
-//}
+ if (!channel.Guild.GetCurrentUser().GetPermissions(channel).ManageMessages)
+ {
+ await channel.SendMessageAsync("`I need manage channel permissions in order to process this command.`").ConfigureAwait(false);
+ return;
+ }
+
+ List msgs;
+
+ await imsg.DeleteAsync().ConfigureAwait(false);
+ if (!plantedFlowers.TryRemove(channel.Id, out msgs))
+ return;
+
+ await Task.WhenAll(msgs.Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false);
+
+ await CurrencyHandler.AddCurrencyAsync((IGuildUser)imsg.Author, "Picked a flower.", 1, false).ConfigureAwait(false);
+ var msg = await channel.SendMessageAsync($"**{imsg.Author.Username}** picked a {Gambling.Gambling.CurrencyName}!").ConfigureAwait(false);
+ var t = Task.Run(async () =>
+ {
+ try
+ {
+ await Task.Delay(10000).ConfigureAwait(false);
+ await msg.DeleteAsync().ConfigureAwait(false);
+ }
+ catch { }
+ });
+ }
+
+ [LocalizedCommand, LocalizedDescription, LocalizedSummary, LocalizedAlias]
+ [RequireContext(ContextType.Guild)]
+ public async Task Plant(IUserMessage imsg)
+ {
+ var channel = (ITextChannel)imsg.Channel;
+ if (channel == null)
+ return;
+
+ var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)imsg.Author, "Planted a flower.", 1, true).ConfigureAwait(false);
+ if (!removed)
+ {
+ await channel.SendMessageAsync($"You don't have any {Gambling.Gambling.CurrencyName}s.").ConfigureAwait(false);
+ return;
+ }
+
+ var file = GetRandomCurrencyImagePath();
+ IUserMessage msg;
+ var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(Gambling.Gambling.CurrencyName[0]);
+ var msgToSend = $"Oh how Nice! **{imsg.Author.Username}** planted {(vowelFirst ? "an" : "a")} {Gambling.Gambling.CurrencyName}. Pick it using >pick";
+ if (file == null)
+ {
+ msg = await channel.SendMessageAsync(Gambling.Gambling.CurrencySign).ConfigureAwait(false);
+ }
+ else
+ {
+ //todo add prefix
+ msg = await channel.SendFileAsync(file, msgToSend).ConfigureAwait(false);
+ }
+ plantedFlowers.AddOrUpdate(channel.Id, new List() { msg }, (id, old) => { old.Add(msg); return old; });
+ }
+
+ [LocalizedCommand, LocalizedDescription, LocalizedSummary, LocalizedAlias]
+ [RequireContext(ContextType.Guild)]
+ [RequirePermission(GuildPermission.ManageMessages)]
+ public async Task Gencurrency(IUserMessage imsg)
+ {
+ var channel = imsg.Channel as ITextChannel;
+ if (channel == null)
+ return;
+
+ bool enabled;
+ using (var uow = DbHandler.UnitOfWork())
+ {
+ var guildConfig = uow.GuildConfigs.For(channel.Id);
+
+ if (guildConfig.GenerateCurrencyChannelId == null)
+ {
+ guildConfig.GenerateCurrencyChannelId = channel.Id;
+ generationChannels.TryAdd(channel.Id, true);
+ enabled = true;
+ }
+ else
+ {
+ guildConfig.GenerateCurrencyChannelId = null;
+ bool throwaway;
+ generationChannels.TryRemove(channel.Id, out throwaway);
+ enabled = false;
+ }
+
+ }
+ if (enabled)
+ {
+ await channel.SendMessageAsync("`Currency generation disabled on this channel.`").ConfigureAwait(false);
+ }
+ else
+ {
+ await channel.SendMessageAsync($"`Currency generation enabled on this channel.`").ConfigureAwait(false);
+ }
+ }
+
+ private string GetRandomCurrencyImagePath() =>
+ Directory.GetFiles("data/currency_images").OrderBy(s => rng.Next()).FirstOrDefault();
+
+ int GetRandomNumber()
+ {
+ using (var rg = RandomNumberGenerator.Create())
+ {
+ byte[] rno = new byte[4];
+ rg.GetBytes(rno);
+ int randomvalue = BitConverter.ToInt32(rno, 0);
+ return randomvalue;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NadekoBot/Services/Database/Models/BotConfig.cs b/src/NadekoBot/Services/Database/Models/BotConfig.cs
index 6bb02fb3..25beddb7 100644
--- a/src/NadekoBot/Services/Database/Models/BotConfig.cs
+++ b/src/NadekoBot/Services/Database/Models/BotConfig.cs
@@ -15,6 +15,9 @@ namespace NadekoBot.Services.Database.Models
public bool ForwardMessages { get; set; } = true;
public bool ForwardToAllOwners { get; set; } = true;
+ public float CurrencyGenerationChance { get; set; } = 0.1f;
+ public int CurrencyGenerationCooldown { get; set; } = 10;
+
public List ModulePrefixes { get; set; } = new List()
{
new ModulePrefix() { ModuleName="Administration", Prefix="." },
diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs
index c07652e4..ada21e94 100644
--- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs
+++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs
@@ -38,5 +38,8 @@ namespace NadekoBot.Services.Database.Models
//stream notifications
public List FollowedStreams { get; set; } = new List();
+
+ //currencyGeneration
+ public ulong? GenerateCurrencyChannelId { get; set; }
}
}