Removed module projects because it can't work like that atm. Commented out package commands.
This commit is contained in:
@ -0,0 +1,161 @@
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Gambling.Common.AnimalRacing.Exceptions;
|
||||
using NadekoBot.Core.Services;
|
||||
using NadekoBot.Core.Services.Database.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common.AnimalRacing
|
||||
{
|
||||
public class AnimalRace : IDisposable
|
||||
{
|
||||
public enum Phase
|
||||
{
|
||||
WaitingForPlayers,
|
||||
Running,
|
||||
Ended,
|
||||
}
|
||||
|
||||
private const int _startingDelayMiliseconds = 20_000;
|
||||
|
||||
public Phase CurrentPhase = Phase.WaitingForPlayers;
|
||||
|
||||
public event Func<AnimalRace, Task> OnStarted = delegate { return Task.CompletedTask; };
|
||||
public event Func<AnimalRace, Task> OnStartingFailed = delegate { return Task.CompletedTask; };
|
||||
public event Func<AnimalRace, Task> OnStateUpdate = delegate { return Task.CompletedTask; };
|
||||
public event Func<AnimalRace, Task> OnEnded = delegate { return Task.CompletedTask; };
|
||||
|
||||
public ImmutableArray<AnimalRacingUser> Users => _users.ToImmutableArray();
|
||||
public List<AnimalRacingUser> FinishedUsers { get; } = new List<AnimalRacingUser>();
|
||||
|
||||
private readonly SemaphoreSlim _locker = new SemaphoreSlim(1, 1);
|
||||
private readonly HashSet<AnimalRacingUser> _users = new HashSet<AnimalRacingUser>();
|
||||
private readonly CurrencyService _currency;
|
||||
private readonly Queue<RaceAnimal> _animalsQueue;
|
||||
public int MaxUsers { get; }
|
||||
|
||||
public AnimalRace(CurrencyService currency, RaceAnimal[] availableAnimals)
|
||||
{
|
||||
this._currency = currency;
|
||||
this._animalsQueue = new Queue<RaceAnimal>(availableAnimals);
|
||||
this.MaxUsers = availableAnimals.Length;
|
||||
|
||||
if (this._animalsQueue.Count == 0)
|
||||
CurrentPhase = Phase.Ended;
|
||||
}
|
||||
|
||||
public void Initialize() //lame name
|
||||
{
|
||||
var _t = Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(_startingDelayMiliseconds).ConfigureAwait(false);
|
||||
|
||||
await _locker.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
if (CurrentPhase != Phase.WaitingForPlayers)
|
||||
return;
|
||||
|
||||
await Start().ConfigureAwait(false);
|
||||
}
|
||||
finally { _locker.Release(); }
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<AnimalRacingUser> JoinRace(ulong userId, string userName, int bet = 0)
|
||||
{
|
||||
if (bet < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(bet));
|
||||
|
||||
var user = new AnimalRacingUser(userName, userId, bet);
|
||||
|
||||
await _locker.WaitAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
if (_users.Count == MaxUsers)
|
||||
throw new AnimalRaceFullException();
|
||||
|
||||
if (CurrentPhase != Phase.WaitingForPlayers)
|
||||
throw new AlreadyStartedException();
|
||||
|
||||
if (!await _currency.RemoveAsync(userId, "BetRace", bet).ConfigureAwait(false))
|
||||
throw new NotEnoughFundsException();
|
||||
|
||||
if (_users.Contains(user))
|
||||
throw new AlreadyJoinedException();
|
||||
|
||||
var animal = _animalsQueue.Dequeue();
|
||||
user.Animal = animal;
|
||||
_users.Add(user);
|
||||
|
||||
if (_animalsQueue.Count == 0) //start if no more spots left
|
||||
await Start().ConfigureAwait(false);
|
||||
|
||||
return user;
|
||||
}
|
||||
finally { _locker.Release(); }
|
||||
}
|
||||
|
||||
private async Task Start()
|
||||
{
|
||||
CurrentPhase = Phase.Running;
|
||||
if (_users.Count <= 1)
|
||||
{
|
||||
foreach (var user in _users)
|
||||
{
|
||||
if(user.Bet > 0)
|
||||
await _currency.AddAsync(user.UserId, "Race refund", user.Bet).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var _sf = OnStartingFailed?.Invoke(this);
|
||||
CurrentPhase = Phase.Ended;
|
||||
return;
|
||||
}
|
||||
|
||||
var _ = OnStarted?.Invoke(this);
|
||||
var _t = Task.Run(async () =>
|
||||
{
|
||||
var rng = new NadekoRandom();
|
||||
while (!_users.All(x => x.Progress >= 60))
|
||||
{
|
||||
foreach (var user in _users)
|
||||
{
|
||||
user.Progress += rng.Next(1, 11);
|
||||
if (user.Progress >= 60)
|
||||
user.Progress = 60;
|
||||
}
|
||||
|
||||
var finished = _users.Where(x => x.Progress >= 60 && !FinishedUsers.Contains(x))
|
||||
.Shuffle();
|
||||
|
||||
FinishedUsers.AddRange(finished);
|
||||
|
||||
var _ignore = OnStateUpdate?.Invoke(this);
|
||||
await Task.Delay(2500).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (FinishedUsers[0].Bet > 0)
|
||||
await _currency.AddAsync(FinishedUsers[0].UserId, "Won a Race", FinishedUsers[0].Bet * (_users.Count - 1))
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var _ended = OnEnded?.Invoke(this);
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CurrentPhase = Phase.Ended;
|
||||
OnStarted = null;
|
||||
OnEnded = null;
|
||||
OnStartingFailed = null;
|
||||
OnStateUpdate = null;
|
||||
_locker.Dispose();
|
||||
_users.Clear();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
using NadekoBot.Core.Services.Database.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common.AnimalRacing
|
||||
{
|
||||
public class AnimalRacingUser
|
||||
{
|
||||
public int Bet { get; }
|
||||
public string Username { get; }
|
||||
public ulong UserId { get; }
|
||||
public RaceAnimal Animal { get; set; }
|
||||
public int Progress { get; set; }
|
||||
|
||||
public AnimalRacingUser(string username, ulong userId, int bet)
|
||||
{
|
||||
this.Bet = bet;
|
||||
this.Username = username;
|
||||
this.UserId = userId;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is AnimalRacingUser x
|
||||
? x.UserId == this.UserId
|
||||
: false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.UserId.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common.AnimalRacing.Exceptions
|
||||
{
|
||||
public class AlreadyJoinedException : Exception
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common.AnimalRacing.Exceptions
|
||||
{
|
||||
public class AlreadyStartedException : Exception
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common.AnimalRacing.Exceptions
|
||||
{
|
||||
public class AnimalRaceFullException : Exception
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common.AnimalRacing.Exceptions
|
||||
{
|
||||
public class NotEnoughFundsException : Exception
|
||||
{
|
||||
|
||||
}
|
||||
}
|
234
NadekoBot.Core/Modules/Gambling/Common/Cards.cs
Normal file
234
NadekoBot.Core/Modules/Gambling/Common/Cards.cs
Normal file
@ -0,0 +1,234 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Extensions;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common
|
||||
{
|
||||
public class Cards
|
||||
{
|
||||
private static readonly Dictionary<int, string> cardNames = new Dictionary<int, string>() {
|
||||
{ 1, "Ace" },
|
||||
{ 2, "Two" },
|
||||
{ 3, "Three" },
|
||||
{ 4, "Four" },
|
||||
{ 5, "Five" },
|
||||
{ 6, "Six" },
|
||||
{ 7, "Seven" },
|
||||
{ 8, "Eight" },
|
||||
{ 9, "Nine" },
|
||||
{ 10, "Ten" },
|
||||
{ 11, "Jack" },
|
||||
{ 12, "Queen" },
|
||||
{ 13, "King" }
|
||||
};
|
||||
private static Dictionary<string, Func<List<Card>, bool>> handValues;
|
||||
|
||||
|
||||
public enum CardSuit
|
||||
{
|
||||
Spades = 1,
|
||||
Hearts = 2,
|
||||
Diamonds = 3,
|
||||
Clubs = 4
|
||||
}
|
||||
|
||||
public class Card : IComparable
|
||||
{
|
||||
public CardSuit Suit { get; }
|
||||
public int Number { get; }
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
var str = "";
|
||||
|
||||
if (Number <= 10 && Number > 1)
|
||||
{
|
||||
str += "_" + Number;
|
||||
}
|
||||
else {
|
||||
str += GetName().ToLower();
|
||||
}
|
||||
return str + "_of_" + Suit.ToString().ToLower();
|
||||
}
|
||||
}
|
||||
|
||||
public Card(CardSuit s, int cardNum)
|
||||
{
|
||||
this.Suit = s;
|
||||
this.Number = cardNum;
|
||||
}
|
||||
|
||||
public string GetName() => cardNames[Number];
|
||||
|
||||
public override string ToString() => cardNames[Number] + " Of " + Suit;
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (!(obj is Card)) return 0;
|
||||
var c = (Card)obj;
|
||||
return this.Number - c.Number;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Card> cardPool;
|
||||
public List<Card> CardPool
|
||||
{
|
||||
get { return cardPool; }
|
||||
set { cardPool = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the BlackJackGame, this allows you to create multiple games running at one time.
|
||||
/// </summary>
|
||||
public Cards()
|
||||
{
|
||||
cardPool = new List<Card>(52);
|
||||
RefillPool();
|
||||
InitHandValues();
|
||||
}
|
||||
/// <summary>
|
||||
/// Restart the game of blackjack. It will only refill the pool for now. Probably wont be used, unless you want to have only 1 bjg running at one time,
|
||||
/// then you will restart the same game every time.
|
||||
/// </summary>
|
||||
public void Restart() => RefillPool();
|
||||
|
||||
/// <summary>
|
||||
/// Removes all cards from the pool and refills the pool with all of the possible cards. NOTE: I think this is too expensive.
|
||||
/// We should probably make it so it copies another premade list with all the cards, or something.
|
||||
/// </summary>
|
||||
private void RefillPool()
|
||||
{
|
||||
cardPool.Clear();
|
||||
//foreach suit
|
||||
for (var j = 1; j < 14; j++)
|
||||
{
|
||||
// and number
|
||||
for (var i = 1; i < 5; i++)
|
||||
{
|
||||
//generate a card of that suit and number and add it to the pool
|
||||
|
||||
// the pool will go from ace of spades,hears,diamonds,clubs all the way to the king of spades. hearts, ...
|
||||
cardPool.Add(new Card((CardSuit)i, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
private Random r = new NadekoRandom();
|
||||
/// <summary>
|
||||
/// Take a card from the pool, you either take it from the top if the deck is shuffled, or from a random place if the deck is in the default order.
|
||||
/// </summary>
|
||||
/// <returns>A card from the pool</returns>
|
||||
public Card DrawACard()
|
||||
{
|
||||
if (CardPool.Count == 0)
|
||||
Restart();
|
||||
//you can either do this if your deck is not shuffled
|
||||
|
||||
var num = r.Next(0, cardPool.Count);
|
||||
var c = cardPool[num];
|
||||
cardPool.RemoveAt(num);
|
||||
return c;
|
||||
|
||||
// if you want to shuffle when you fill, then take the first one
|
||||
/*
|
||||
Card c = cardPool[0];
|
||||
cardPool.RemoveAt(0);
|
||||
return c;
|
||||
*/
|
||||
}
|
||||
/// <summary>
|
||||
/// Shuffles the deck. Use this if you want to take cards from the top of the deck, instead of randomly. See DrawACard method.
|
||||
/// </summary>
|
||||
private void Shuffle()
|
||||
{
|
||||
if (cardPool.Count <= 1) return;
|
||||
var orderedPool = cardPool.Shuffle();
|
||||
cardPool = cardPool as List<Card> ?? orderedPool.ToList();
|
||||
}
|
||||
public override string ToString() => string.Concat(cardPool.Select(c => c.ToString())) + Environment.NewLine;
|
||||
|
||||
private static void InitHandValues()
|
||||
{
|
||||
Func<List<Card>, bool> hasPair =
|
||||
cards => cards.GroupBy(card => card.Number)
|
||||
.Count(group => group.Count() == 2) == 1;
|
||||
Func<List<Card>, bool> isPair =
|
||||
cards => cards.GroupBy(card => card.Number)
|
||||
.Count(group => group.Count() == 3) == 0
|
||||
&& hasPair(cards);
|
||||
|
||||
Func<List<Card>, bool> isTwoPair =
|
||||
cards => cards.GroupBy(card => card.Number)
|
||||
.Count(group => group.Count() == 2) == 2;
|
||||
|
||||
Func<List<Card>, bool> isStraight =
|
||||
cards =>
|
||||
{
|
||||
if (cards.GroupBy(card => card.Number).Count() != cards.Count())
|
||||
return false;
|
||||
var toReturn = (cards.Max(card => (int)card.Number)
|
||||
- cards.Min(card => (int)card.Number) == 4);
|
||||
if (toReturn || cards.All(c => c.Number != 1)) return toReturn;
|
||||
|
||||
var newCards = cards.Select(c => c.Number == 1 ? new Card(c.Suit, 14) : c);
|
||||
return (newCards.Max(card => (int)card.Number)
|
||||
- newCards.Min(card => (int)card.Number) == 4);
|
||||
};
|
||||
|
||||
Func<List<Card>, bool> hasThreeOfKind =
|
||||
cards => cards.GroupBy(card => card.Number)
|
||||
.Any(group => group.Count() == 3);
|
||||
|
||||
Func<List<Card>, bool> isThreeOfKind =
|
||||
cards => hasThreeOfKind(cards) && !hasPair(cards);
|
||||
|
||||
Func<List<Card>, bool> isFlush =
|
||||
cards => cards.GroupBy(card => card.Suit).Count() == 1;
|
||||
|
||||
Func<List<Card>, bool> isFourOfKind =
|
||||
cards => cards.GroupBy(card => card.Number)
|
||||
.Any(group => group.Count() == 4);
|
||||
|
||||
Func<List<Card>, bool> isFullHouse =
|
||||
cards => hasPair(cards) && hasThreeOfKind(cards);
|
||||
|
||||
Func<List<Card>, bool> hasStraightFlush =
|
||||
cards => isFlush(cards) && isStraight(cards);
|
||||
|
||||
Func<List<Card>, bool> isRoyalFlush =
|
||||
cards => cards.Min(card => card.Number) == 1 &&
|
||||
cards.Max(card => card.Number) == 13
|
||||
&& hasStraightFlush(cards);
|
||||
|
||||
Func<List<Card>, bool> isStraightFlush =
|
||||
cards => hasStraightFlush(cards) && !isRoyalFlush(cards);
|
||||
|
||||
handValues = new Dictionary<string, Func<List<Card>, bool>>
|
||||
{
|
||||
{ "Royal Flush", isRoyalFlush },
|
||||
{ "Straight Flush", isStraightFlush },
|
||||
{ "Four Of A Kind", isFourOfKind },
|
||||
{ "Full House", isFullHouse },
|
||||
{ "Flush", isFlush },
|
||||
{ "Straight", isStraight },
|
||||
{ "Three Of A Kind", isThreeOfKind },
|
||||
{ "Two Pairs", isTwoPair },
|
||||
{ "A Pair", isPair }
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetHandValue(List<Card> cards)
|
||||
{
|
||||
if (handValues == null)
|
||||
InitHandValues();
|
||||
foreach (var kvp in handValues.Where(x => x.Value(cards)))
|
||||
{
|
||||
return kvp.Key;
|
||||
}
|
||||
return "High card " + (cards.FirstOrDefault(c => c.Number == 1)?.GetName() ?? cards.Max().GetName());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common
|
||||
{
|
||||
public abstract class CurrencyEvent
|
||||
{
|
||||
public abstract Task Stop();
|
||||
public abstract Task Start(IUserMessage msg, ICommandContext channel);
|
||||
}
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Core.Services;
|
||||
using NadekoBot.Core.Services.Database.Models;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common
|
||||
{
|
||||
public class ReactionEvent : CurrencyEvent
|
||||
{
|
||||
private readonly ConcurrentHashSet<ulong> _reactionAwardedUsers = new ConcurrentHashSet<ulong>();
|
||||
private readonly BotConfig _bc;
|
||||
private readonly Logger _log;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly CurrencyService _cs;
|
||||
private readonly SocketSelfUser _botUser;
|
||||
|
||||
private IUserMessage StartingMessage { get; set; }
|
||||
|
||||
private CancellationTokenSource Source { get; }
|
||||
private CancellationToken CancelToken { get; }
|
||||
|
||||
private readonly ConcurrentQueue<ulong> _toGiveTo = new ConcurrentQueue<ulong>();
|
||||
private readonly int _amount;
|
||||
|
||||
public ReactionEvent(BotConfig bc, DiscordSocketClient client, CurrencyService cs, int amount)
|
||||
{
|
||||
_bc = bc;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_client = client;
|
||||
_cs = cs;
|
||||
_botUser = client.CurrentUser;
|
||||
_amount = amount;
|
||||
Source = new CancellationTokenSource();
|
||||
CancelToken = Source.Token;
|
||||
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
var users = new List<ulong>();
|
||||
while (!CancelToken.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
while (_toGiveTo.TryDequeue(out var usrId))
|
||||
{
|
||||
users.Add(usrId);
|
||||
}
|
||||
|
||||
if (users.Count > 0)
|
||||
{
|
||||
await _cs.AddToManyAsync("Reaction Event", _amount, users.ToArray()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
users.Clear();
|
||||
}
|
||||
}, CancelToken);
|
||||
}
|
||||
|
||||
public override async Task Stop()
|
||||
{
|
||||
if (StartingMessage != null)
|
||||
await StartingMessage.DeleteAsync().ConfigureAwait(false);
|
||||
|
||||
if (!Source.IsCancellationRequested)
|
||||
Source.Cancel();
|
||||
|
||||
_client.MessageDeleted -= MessageDeletedEventHandler;
|
||||
}
|
||||
|
||||
private Task MessageDeletedEventHandler(Cacheable<IMessage, ulong> msg, ISocketMessageChannel channel)
|
||||
{
|
||||
if (StartingMessage?.Id == msg.Id)
|
||||
{
|
||||
_log.Warn("Stopping flower reaction event because message is deleted.");
|
||||
var __ = Task.Run(Stop);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task Start(IUserMessage umsg, ICommandContext context)
|
||||
{
|
||||
StartingMessage = umsg;
|
||||
_client.MessageDeleted += MessageDeletedEventHandler;
|
||||
|
||||
IEmote iemote;
|
||||
if (Emote.TryParse(_bc.CurrencySign, out var emote))
|
||||
{
|
||||
iemote = emote;
|
||||
}
|
||||
else
|
||||
iemote = new Emoji(_bc.CurrencySign);
|
||||
try { await StartingMessage.AddReactionAsync(iemote).ConfigureAwait(false); }
|
||||
catch
|
||||
{
|
||||
try { await StartingMessage.AddReactionAsync(iemote).ConfigureAwait(false); }
|
||||
catch
|
||||
{
|
||||
try { await StartingMessage.DeleteAsync().ConfigureAwait(false); }
|
||||
catch { return; }
|
||||
}
|
||||
}
|
||||
using (StartingMessage.OnReaction(_client, (r) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (r.UserId == _botUser.Id)
|
||||
return;
|
||||
|
||||
if (r.Emote.Name == iemote.Name && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _reactionAwardedUsers.Add(r.User.Value.Id))
|
||||
{
|
||||
_toGiveTo.Enqueue(r.UserId);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}))
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromHours(24), CancelToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
}
|
||||
if (CancelToken.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
_log.Warn("Stopping flower reaction event because it expired.");
|
||||
await Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Common.Collections;
|
||||
using NadekoBot.Core.Services;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common.CurrencyEvents
|
||||
{
|
||||
public class SneakyEvent : CurrencyEvent
|
||||
{
|
||||
public event Action OnEnded;
|
||||
public string Code { get; private set; } = string.Empty;
|
||||
private readonly ConcurrentHashSet<ulong> _sneakyGameAwardedUsers = new ConcurrentHashSet<ulong>();
|
||||
|
||||
private readonly char[] _sneakyGameStatusChars = Enumerable.Range(48, 10)
|
||||
.Concat(Enumerable.Range(65, 26))
|
||||
.Concat(Enumerable.Range(97, 26))
|
||||
.Select(x => (char)x)
|
||||
.ToArray();
|
||||
|
||||
private readonly CurrencyService _cs;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IBotConfigProvider _bc;
|
||||
private readonly int _length;
|
||||
|
||||
public SneakyEvent(CurrencyService cs, DiscordSocketClient client,
|
||||
IBotConfigProvider bc, int len)
|
||||
{
|
||||
_cs = cs;
|
||||
_client = client;
|
||||
_bc = bc;
|
||||
_length = len;
|
||||
}
|
||||
|
||||
public override async Task Start(IUserMessage msg, ICommandContext channel)
|
||||
{
|
||||
GenerateCode();
|
||||
|
||||
//start the event
|
||||
_client.MessageReceived += SneakyGameMessageReceivedEventHandler;
|
||||
await _client.SetGameAsync($"type {Code} for " + _bc.BotConfig.CurrencyPluralName)
|
||||
.ConfigureAwait(false);
|
||||
await Task.Delay(_length * 1000).ConfigureAwait(false);
|
||||
await Stop().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private void GenerateCode()
|
||||
{
|
||||
var rng = new NadekoRandom();
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
Code += _sneakyGameStatusChars[rng.Next(0, _sneakyGameStatusChars.Length)];
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
_client.MessageReceived -= SneakyGameMessageReceivedEventHandler;
|
||||
Code = string.Empty;
|
||||
_sneakyGameAwardedUsers.Clear();
|
||||
await _client.SetGameAsync(null).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
|
||||
OnEnded?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private Task SneakyGameMessageReceivedEventHandler(SocketMessage arg)
|
||||
{
|
||||
if (arg.Content == Code &&
|
||||
_sneakyGameAwardedUsers.Add(arg.Author.Id))
|
||||
{
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
await _cs.AddAsync(arg.Author, "Sneaky Game Event", 100, false)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
try { await arg.DeleteAsync(new RequestOptions() { RetryMode = RetryMode.AlwaysFail }).ConfigureAwait(false); }
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
using NadekoBot.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common.WheelOfFortune
|
||||
{
|
||||
public class WheelOfFortune
|
||||
{
|
||||
private static readonly NadekoRandom _rng = new NadekoRandom();
|
||||
|
||||
private static readonly ImmutableArray<string> _emojis = new string[] {
|
||||
"⬆",
|
||||
"↖",
|
||||
"⬅",
|
||||
"↙",
|
||||
"⬇",
|
||||
"↘",
|
||||
"➡",
|
||||
"↗" }.ToImmutableArray();
|
||||
|
||||
public static readonly ImmutableArray<float> Multipliers = new float[] {
|
||||
1.7f,
|
||||
1.5f,
|
||||
0.2f,
|
||||
0.1f,
|
||||
0.3f,
|
||||
0.5f,
|
||||
1.2f,
|
||||
2.4f,
|
||||
}.ToImmutableArray();
|
||||
|
||||
public int Result { get; }
|
||||
public string Emoji => _emojis[Result];
|
||||
public float Multiplier => Multipliers[Result];
|
||||
|
||||
public WheelOfFortune()
|
||||
{
|
||||
this.Result = _rng.Next(0, 8);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user