.rafflecur added
This commit is contained in:
parent
cfee252ce3
commit
204cdbfb2b
@ -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)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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) =>
|
||||
{
|
||||
|
@ -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]
|
||||
|
@ -1,8 +1,4 @@
|
||||
using StackExchange.Redis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Core.Services
|
||||
|
@ -885,7 +885,8 @@
|
||||
"customreactions_edit_fail": "Custom reaction with that ID does not exist.",
|
||||
"searches_streaming": "Streaming",
|
||||
"searches_followers": "Followers",
|
||||
"gambling_rafflecur_joined": "User {0} joined the raffle!",
|
||||
"gambling_rafflecur_already_joined": "You have already joined this raffle.",
|
||||
"gambling_rafflecur": "{0} Currency Raffle",
|
||||
"gambling_rafflecur_joined": "User {0} joined the raffle",
|
||||
"gambling_rafflecur_already_joined": "You have already joined this raffle or the value you used is not valid.",
|
||||
"gambling_rafflecur_ended": "{0} raffle ended. {1} won {2}!"
|
||||
}
|
@ -3040,9 +3040,10 @@
|
||||
},
|
||||
"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.",
|
||||
"desc": "Starts or joins 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. There is also a `mixed` mode in which the users will be able to join the game with any amount of currency, and have their chances be proportional to the amount they've bet.",
|
||||
"usage": [
|
||||
"{0}rafflecur 20"
|
||||
"{0}rafflecur 20",
|
||||
"{0}rafflecur mixed 15"
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user