diff --git a/NadekoBot.Core/Modules/Gambling/Common/CurrencyRaffleGame.cs b/NadekoBot.Core/Modules/Gambling/Common/CurrencyRaffleGame.cs index 20869bdd..6da88d7c 100644 --- a/NadekoBot.Core/Modules/Gambling/Common/CurrencyRaffleGame.cs +++ b/NadekoBot.Core/Modules/Gambling/Common/CurrencyRaffleGame.cs @@ -1,6 +1,9 @@ -using NadekoBot.Core.Services; +using Discord; +using NadekoBot.Common; +using NadekoBot.Core.Services; using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -8,33 +11,24 @@ namespace NadekoBot.Core.Modules.Gambling.Common { public class CurrencyRaffleGame { - private readonly HashSet<(string, ulong)> _users = new HashSet<(string, ulong)>(); + private readonly HashSet _users = new HashSet(); + public IEnumerable Users => _users; private readonly int _amount; - private readonly CurrencyService _cs; - private readonly DbService _db; - private bool running; - public CurrencyRaffleGame(int amount, CurrencyService cs, DbService db) + public CurrencyRaffleGame(int amount) { if (amount < 1) throw new ArgumentOutOfRangeException(); _amount = amount; - _cs = cs; - _db = db; } - public async Task AddUser(string username, ulong userId) + public bool AddUser(IUser usr) { + if (!_users.Add(usr)) + return false; - } - - public void ForceStop() - { - lock (_locker) - { - running = false; - } + return true; } } } diff --git a/NadekoBot.Core/Modules/Gambling/CurrencyRaffleCommands.cs b/NadekoBot.Core/Modules/Gambling/CurrencyRaffleCommands.cs index 05a286f7..48b97e08 100644 --- a/NadekoBot.Core/Modules/Gambling/CurrencyRaffleCommands.cs +++ b/NadekoBot.Core/Modules/Gambling/CurrencyRaffleCommands.cs @@ -1,6 +1,10 @@ using NadekoBot.Common.Attributes; using NadekoBot.Core.Modules.Gambling.Services; using System.Threading.Tasks; +using Discord; +using System; +using NadekoBot.Core.Services; +using NadekoBot.Extensions; namespace NadekoBot.Modules.Gambling { @@ -8,13 +12,34 @@ namespace NadekoBot.Modules.Gambling { public class CurrencyRaffleCommands : NadekoSubmodule { + private readonly IBotConfigProvider _bc; + + public CurrencyRaffleCommands(IBotConfigProvider bc) + { + _bc = bc; + } [NadekoCommand, Usage, Description, Aliases] public async Task RaffleCur(int amount) { - if (_service.Games.TryAdd(Context.Channel.Id, - )) + async Task OnEnded(IUser arg, int won) { + await ReplyConfirmLocalized("rafflecur_ended", _bc.BotConfig.CurrencyName, Format.Bold(arg.ToString()), won + _bc.BotConfig.CurrencySign); + } + var res = await _service.JoinOrCreateGame(Context.Channel.Id, + Context.User, amount, OnEnded) + .ConfigureAwait(false); + if (res.Item1 != null) + { + await Context.Channel.SendConfirmAsync(GetText("rafflecur_joined", Context.User.ToString()), + string.Join("\n", res.Item1.Users)).ConfigureAwait(false); + } + else + { + if (res.Item2 == CurrencyRaffleService.JoinErrorType.AlreadyJoined) + await ReplyErrorLocalized("rafflecur_already_joined").ConfigureAwait(false); + else if (res.Item2 == CurrencyRaffleService.JoinErrorType.NotEnoughCurrency) + await ReplyErrorLocalized("not_enough").ConfigureAwait(false); } } } diff --git a/NadekoBot.Core/Modules/Gambling/Services/CurrencyRaffleService.cs b/NadekoBot.Core/Modules/Gambling/Services/CurrencyRaffleService.cs index 5a917905..08865881 100644 --- a/NadekoBot.Core/Modules/Gambling/Services/CurrencyRaffleService.cs +++ b/NadekoBot.Core/Modules/Gambling/Services/CurrencyRaffleService.cs @@ -1,40 +1,86 @@ using System.Threading.Tasks; using NadekoBot.Core.Services; -using System.Collections.Concurrent; using NadekoBot.Core.Modules.Gambling.Common; using System.Threading; +using System.Linq; +using NadekoBot.Common; +using System.Collections.Generic; +using Discord; +using System; namespace NadekoBot.Core.Modules.Gambling.Services { public class CurrencyRaffleService : INService { + public enum JoinErrorType { + NotEnoughCurrency, + AlreadyJoined + } private readonly SemaphoreSlim _locker = new SemaphoreSlim(1, 1); private readonly DbService _db; + private readonly CurrencyService _cs; - public ConcurrentDictionary Games { get; } + public Dictionary Games { get; } = new Dictionary(); - public CurrencyRaffleService(DbService db) + public CurrencyRaffleService(DbService db, CurrencyService cs) { _db = db; + _cs = cs; } - public async Task JoinOrCreateGame(ulong channelId, string username, - ulong userId) + public async Task<(CurrencyRaffleGame, JoinErrorType?)> JoinOrCreateGame(ulong channelId, IUser user, int amount, Func onEnded) { await _locker.WaitAsync().ConfigureAwait(false); try { + var newGame = false; + if (!Games.TryGetValue(channelId, out var crg)) + { + newGame = true; + crg = new CurrencyRaffleGame(amount); + } using (var uow = _db.UnitOfWork) { - //remove money - if (!await _cs.RemoveAsync(userId, "Currency Raffle Join", _amount).ConfigureAwait(false)) - return false; - } + //remove money, and stop the game if this + // user created it and doesn't have the money + if (!await _cs.RemoveAsync(user.Id, "Currency Raffle Join", amount, uow).ConfigureAwait(false)) + { + if(newGame) + Games.Remove(channelId); + return (null, JoinErrorType.NotEnoughCurrency); + } - //add to to list - if (_users.Add((username, userId))) - return false; - return true; + if (!crg.AddUser(user)) + { + await _cs.AddAsync(user.Id, "Curency Raffle Refund", amount, uow).ConfigureAwait(false); + return (null, JoinErrorType.AlreadyJoined); + } + } + if (newGame) + { + var _t = new Timer(async state => + { + await _locker.WaitAsync().ConfigureAwait(false); + try + { + var users = crg.Users.ToArray(); + var rng = new NadekoRandom(); + var usr = users[rng.Next(0, users.Length)]; + + using (var uow = _db.UnitOfWork) + { + await _cs.AddAsync(usr.Id, "Currency Raffle Win", + amount * users.Length, uow); + } + Games.Remove(channelId, out _); + var oe = onEnded(usr, users.Length * amount); + } + catch { } + finally { _locker.Release(); } + + }, null, 30000, Timeout.Infinite); + } + return (crg, null); } finally { diff --git a/src/NadekoBot/_strings/ResponseStrings.en-US.json b/src/NadekoBot/_strings/ResponseStrings.en-US.json index 0215b21f..3ac614ab 100644 --- a/src/NadekoBot/_strings/ResponseStrings.en-US.json +++ b/src/NadekoBot/_strings/ResponseStrings.en-US.json @@ -884,5 +884,8 @@ "administration_restarting": "Restarting.", "customreactions_edit_fail": "Custom reaction with that ID does not exist.", "searches_streaming": "Streaming", - "searches_followers": "Followers" + "searches_followers": "Followers", + "gambling_rafflecur_joined": "User {0} joined the raffle!", + "gambling_rafflecur_already_joined": "You have already joined this raffle.", + "gambling_rafflecur_ended": "{0} raffle ended. {1} won {2}!" } \ No newline at end of file diff --git a/src/NadekoBot/data/command_strings.json b/src/NadekoBot/data/command_strings.json index f5d09a01..87783cc6 100644 --- a/src/NadekoBot/data/command_strings.json +++ b/src/NadekoBot/data/command_strings.json @@ -3037,5 +3037,12 @@ "usage": [ "{0}execsql UPDATE Currency SET Amount=Amount+1234" ] + }, + "rafflecur": { + "cmd": "rafflecur", + "desc": "Starts a currency raffle with a specified amount. Users who join the raffle will lose the amount of currency specified and add it to the pot. After 30 seconds, random winner will be selected who will receive the whole pot.", + "usage": [ + "{0}rafflecur 20" + ] } } \ No newline at end of file