.rafflecur added

This commit is contained in:
Master Kwoth
2017-10-20 17:20:26 +02:00
parent cfee252ce3
commit 204cdbfb2b
9 changed files with 129 additions and 57 deletions

View File

@ -1,34 +1,85 @@
using Discord;
using NadekoBot.Common;
using NadekoBot.Core.Services;
using System;
using NLog;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace NadekoBot.Core.Modules.Gambling.Common
{
public class CurrencyRaffleGame
{
private readonly HashSet<IUser> _users = new HashSet<IUser>();
public IEnumerable<IUser> Users => _users;
private readonly int _amount;
public CurrencyRaffleGame(int amount)
{
if (amount < 1)
throw new ArgumentOutOfRangeException();
_amount = amount;
public enum Type {
Mixed,
Normal
}
public bool AddUser(IUser usr)
public class User
{
if (!_users.Add(usr))
public IUser DiscordUser { get; set; }
public int Amount { get; set; }
public override int GetHashCode()
{
return DiscordUser.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is User u
? u.DiscordUser == DiscordUser
: false;
}
}
private readonly HashSet<User> _users = new HashSet<User>();
public IEnumerable<User> Users => _users;
public Type GameType { get; }
private readonly Logger _log;
public CurrencyRaffleGame(Type type)
{
GameType = type;
_log = LogManager.GetCurrentClassLogger();
}
public bool AddUser(IUser usr, int amount)
{
// if game type is normal, and someone already joined the game
// (that's the user who created it)
if (GameType == Type.Normal && _users.Count > 0 &&
_users.First().Amount != amount)
return false;
if (!_users.Add(new User
{
DiscordUser = usr,
Amount = amount,
}))
{
return false;
}
return true;
}
public User GetWinner()
{
var rng = new NadekoRandom();
if (GameType == Type.Mixed)
{
var num = rng.Next(0, Users.Sum(x => x.Amount));
var sum = 0;
foreach (var u in Users)
{
sum += u.Amount;
if (sum > num)
return u;
}
_log.Error("Woah. Report this.\nRoll: {0}\nAmounts: {1}", num, string.Join(",", Users.Select(x => x.Amount)));
}
var usrs = _users.ToArray();
return usrs[rng.Next(0, usrs.Length)];
}
}
}

View File

@ -2,9 +2,10 @@
using NadekoBot.Core.Modules.Gambling.Services;
using System.Threading.Tasks;
using Discord;
using System;
using NadekoBot.Core.Services;
using NadekoBot.Extensions;
using System.Linq;
using Discord.Commands;
namespace NadekoBot.Modules.Gambling
{
@ -18,28 +19,42 @@ namespace NadekoBot.Modules.Gambling
{
_bc = bc;
}
public enum Mixed { Mixed }
[NadekoCommand, Usage, Description, Aliases]
public async Task RaffleCur(int amount)
[RequireContext(ContextType.Guild)]
[Priority(0)]
public Task RaffleCur(Mixed _, int amount) =>
RaffleCur(amount, true);
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[Priority(1)]
public async Task RaffleCur(int amount, bool mixed = false)
{
if (amount < 1)
return;
async Task OnEnded(IUser arg, int won)
{
await ReplyConfirmLocalized("rafflecur_ended", _bc.BotConfig.CurrencyName, Format.Bold(arg.ToString()), won + _bc.BotConfig.CurrencySign);
await Context.Channel.SendConfirmAsync(GetText("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)
Context.User, amount, mixed, 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);
await Context.Channel.SendConfirmAsync(GetText("rafflecur", res.Item1.GameType.ToString()),
string.Join("\n", res.Item1.Users.Select(x => $"{x.DiscordUser} ({x.Amount})")),
footer: GetText("rafflecur_joined", Context.User.ToString())).ConfigureAwait(false);
}
else
{
if (res.Item2 == CurrencyRaffleService.JoinErrorType.AlreadyJoined)
if (res.Item2 == CurrencyRaffleService.JoinErrorType.AlreadyJoinedOrInvalidAmount)
await ReplyErrorLocalized("rafflecur_already_joined").ConfigureAwait(false);
else if (res.Item2 == CurrencyRaffleService.JoinErrorType.NotEnoughCurrency)
await ReplyErrorLocalized("not_enough").ConfigureAwait(false);
await ReplyErrorLocalized("not_enough", _bc.BotConfig.CurrencySign).ConfigureAwait(false);
}
}
}

View File

@ -3,7 +3,6 @@ using NadekoBot.Core.Services;
using NadekoBot.Core.Modules.Gambling.Common;
using System.Threading;
using System.Linq;
using NadekoBot.Common;
using System.Collections.Generic;
using Discord;
using System;
@ -12,9 +11,10 @@ namespace NadekoBot.Core.Modules.Gambling.Services
{
public class CurrencyRaffleService : INService
{
public enum JoinErrorType {
public enum JoinErrorType
{
NotEnoughCurrency,
AlreadyJoined
AlreadyJoinedOrInvalidAmount
}
private readonly SemaphoreSlim _locker = new SemaphoreSlim(1, 1);
private readonly DbService _db;
@ -28,7 +28,7 @@ namespace NadekoBot.Core.Modules.Gambling.Services
_cs = cs;
}
public async Task<(CurrencyRaffleGame, JoinErrorType?)> JoinOrCreateGame(ulong channelId, IUser user, int amount, Func<IUser, int, Task> onEnded)
public async Task<(CurrencyRaffleGame, JoinErrorType?)> JoinOrCreateGame(ulong channelId, IUser user, int amount, bool mixed, Func<IUser, int, Task> onEnded)
{
await _locker.WaitAsync().ConfigureAwait(false);
try
@ -37,7 +37,10 @@ namespace NadekoBot.Core.Modules.Gambling.Services
if (!Games.TryGetValue(channelId, out var crg))
{
newGame = true;
crg = new CurrencyRaffleGame(amount);
crg = new CurrencyRaffleGame(mixed
? CurrencyRaffleGame.Type.Mixed
: CurrencyRaffleGame.Type.Normal);
Games.Add(channelId, crg);
}
using (var uow = _db.UnitOfWork)
{
@ -45,40 +48,43 @@ namespace NadekoBot.Core.Modules.Gambling.Services
// user created it and doesn't have the money
if (!await _cs.RemoveAsync(user.Id, "Currency Raffle Join", amount, uow).ConfigureAwait(false))
{
if(newGame)
if (newGame)
Games.Remove(channelId);
return (null, JoinErrorType.NotEnoughCurrency);
}
if (!crg.AddUser(user))
if (!crg.AddUser(user, amount))
{
await _cs.AddAsync(user.Id, "Curency Raffle Refund", amount, uow).ConfigureAwait(false);
return (null, JoinErrorType.AlreadyJoined);
return (null, JoinErrorType.AlreadyJoinedOrInvalidAmount);
}
uow.Complete();
}
if (newGame)
{
var _t = new Timer(async state =>
var _t = Task.Run(async () =>
{
await Task.Delay(30000).ConfigureAwait(false);
await _locker.WaitAsync().ConfigureAwait(false);
try
{
var users = crg.Users.ToArray();
var rng = new NadekoRandom();
var usr = users[rng.Next(0, users.Length)];
var winner = crg.GetWinner();
var won = crg.Users.Sum(x => x.Amount);
using (var uow = _db.UnitOfWork)
{
await _cs.AddAsync(usr.Id, "Currency Raffle Win",
amount * users.Length, uow);
await _cs.AddAsync(winner.DiscordUser.Id, "Currency Raffle Win",
won, uow);
uow.Complete();
}
Games.Remove(channelId, out _);
var oe = onEnded(usr, users.Length * amount);
var oe = onEnded(winner.DiscordUser, won);
}
catch { }
finally { _locker.Release(); }
}, null, 30000, Timeout.Infinite);
});
}
return (crg, null);
}
@ -88,4 +94,4 @@ namespace NadekoBot.Core.Modules.Gambling.Services
}
}
}
}
}

View File

@ -39,7 +39,7 @@ namespace NadekoBot.Modules.Games
private async Task InternalStartPoll(string arg)
{
if(await _service.StartPoll((ITextChannel)Context.Channel, Context.Message, arg) == false)
if(await _service.StartPoll(Context.Channel.Id, Context.Message, arg) == false)
await ReplyErrorLocalized("poll_already_running").ConfigureAwait(false);
}
@ -53,8 +53,6 @@ namespace NadekoBot.Modules.Games
_service.ActivePolls.TryRemove(channel.Guild.Id, out var poll);
await poll.StopPoll().ConfigureAwait(false);
}
}
}
}
}

View File

@ -26,7 +26,7 @@ namespace NadekoBot.Modules.Games.Services
_strings = strings;
}
public async Task<bool?> StartPoll(ITextChannel channel, IUserMessage msg, string arg)
public async Task<bool?> StartPoll(ulong guildId, IUserMessage msg, string arg)
{
if (string.IsNullOrWhiteSpace(arg) || !arg.Contains(";"))
return null;
@ -35,7 +35,7 @@ namespace NadekoBot.Modules.Games.Services
return null;
var poll = new Poll(_client, _strings, msg, data[0], data.Skip(1));
if (ActivePolls.TryAdd(channel.Guild.Id, poll))
if (ActivePolls.TryAdd(guildId, poll))
{
poll.OnEnded += (gid) =>
{

View File

@ -24,13 +24,17 @@ namespace NadekoBot.Modules.Utility
private readonly IStatsService _stats;
private readonly IBotCredentials _creds;
private readonly NadekoBot _bot;
private readonly DbService _db;
public Utility(NadekoBot nadeko, DiscordSocketClient client, IStatsService stats, IBotCredentials creds)
public Utility(NadekoBot nadeko, DiscordSocketClient client,
IStatsService stats, IBotCredentials creds,
DbService db)
{
_client = client;
_stats = stats;
_creds = creds;
_bot = nadeko;
_db = db;
}
[NadekoCommand, Usage, Description, Aliases]