forked from EllieBotDevs/elliebot
224 lines
8.1 KiB
C#
224 lines
8.1 KiB
C#
|
#nullable disable
|
||
|
using SixLabors.ImageSharp;
|
||
|
using SixLabors.ImageSharp.PixelFormats;
|
||
|
using System.Text.RegularExpressions;
|
||
|
using Image = SixLabors.ImageSharp.Image;
|
||
|
|
||
|
namespace EllieBot.Modules.Gambling;
|
||
|
|
||
|
public partial class Gambling
|
||
|
{
|
||
|
[Group]
|
||
|
public partial class DiceRollCommands : EllieModule
|
||
|
{
|
||
|
private static readonly Regex _dndRegex = new(@"^(?<n1>\d+)d(?<n2>\d+)(?:\+(?<add>\d+))?(?:\-(?<sub>\d+))?$",
|
||
|
RegexOptions.Compiled);
|
||
|
|
||
|
private static readonly Regex _fudgeRegex = new(@"^(?<n1>\d+)d(?:F|f)$", RegexOptions.Compiled);
|
||
|
|
||
|
private static readonly char[] _fateRolls = ['-', ' ', '+'];
|
||
|
private readonly IImageCache _images;
|
||
|
|
||
|
public DiceRollCommands(IImageCache images)
|
||
|
=> _images = images;
|
||
|
|
||
|
[Cmd]
|
||
|
public async Task Roll()
|
||
|
{
|
||
|
var rng = new EllieRandom();
|
||
|
var gen = rng.Next(1, 101);
|
||
|
|
||
|
var num1 = gen / 10;
|
||
|
var num2 = gen % 10;
|
||
|
|
||
|
using var img1 = await GetDiceAsync(num1);
|
||
|
using var img2 = await GetDiceAsync(num2);
|
||
|
using var img = new[] { img1, img2 }.Merge(out var format);
|
||
|
await using var ms = await img.ToStreamAsync(format);
|
||
|
|
||
|
var fileName = $"dice.{format.FileExtensions.First()}";
|
||
|
|
||
|
var eb = _sender.CreateEmbed()
|
||
|
.WithOkColor()
|
||
|
.WithAuthor(ctx.User)
|
||
|
.AddField(GetText(strs.roll2), gen)
|
||
|
.WithImageUrl($"attachment://{fileName}");
|
||
|
|
||
|
await ctx.Channel.SendFileAsync(ms,
|
||
|
fileName,
|
||
|
embed: eb.Build());
|
||
|
}
|
||
|
|
||
|
[Cmd]
|
||
|
[Priority(1)]
|
||
|
public async Task Roll(int num)
|
||
|
=> await InternalRoll(num, true);
|
||
|
|
||
|
|
||
|
[Cmd]
|
||
|
[Priority(1)]
|
||
|
public async Task Rolluo(int num = 1)
|
||
|
=> await InternalRoll(num, false);
|
||
|
|
||
|
[Cmd]
|
||
|
[Priority(0)]
|
||
|
public async Task Roll(string arg)
|
||
|
=> await InternallDndRoll(arg, true);
|
||
|
|
||
|
[Cmd]
|
||
|
[Priority(0)]
|
||
|
public async Task Rolluo(string arg)
|
||
|
=> await InternallDndRoll(arg, false);
|
||
|
|
||
|
private async Task InternalRoll(int num, bool ordered)
|
||
|
{
|
||
|
if (num is < 1 or > 30)
|
||
|
{
|
||
|
await Response().Error(strs.dice_invalid_number(1, 30)).SendAsync();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var rng = new EllieRandom();
|
||
|
|
||
|
var dice = new List<Image<Rgba32>>(num);
|
||
|
var values = new List<int>(num);
|
||
|
for (var i = 0; i < num; i++)
|
||
|
{
|
||
|
var randomNumber = rng.Next(1, 7);
|
||
|
var toInsert = dice.Count;
|
||
|
if (ordered)
|
||
|
{
|
||
|
if (randomNumber == 6 || dice.Count == 0)
|
||
|
toInsert = 0;
|
||
|
else if (randomNumber != 1)
|
||
|
{
|
||
|
for (var j = 0; j < dice.Count; j++)
|
||
|
{
|
||
|
if (values[j] < randomNumber)
|
||
|
{
|
||
|
toInsert = j;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
toInsert = dice.Count;
|
||
|
|
||
|
dice.Insert(toInsert, await GetDiceAsync(randomNumber));
|
||
|
values.Insert(toInsert, randomNumber);
|
||
|
}
|
||
|
|
||
|
using var bitmap = dice.Merge(out var format);
|
||
|
await using var ms = bitmap.ToStream(format);
|
||
|
foreach (var d in dice)
|
||
|
d.Dispose();
|
||
|
|
||
|
var imageName = $"dice.{format.FileExtensions.First()}";
|
||
|
var eb = _sender.CreateEmbed()
|
||
|
.WithOkColor()
|
||
|
.WithAuthor(ctx.User)
|
||
|
.AddField(GetText(strs.rolls), values.Select(x => Format.Code(x.ToString())).Join(' '), true)
|
||
|
.AddField(GetText(strs.total), values.Sum(), true)
|
||
|
.WithDescription(GetText(strs.dice_rolled_num(Format.Bold(values.Count.ToString()))))
|
||
|
.WithImageUrl($"attachment://{imageName}");
|
||
|
|
||
|
await ctx.Channel.SendFileAsync(ms,
|
||
|
imageName,
|
||
|
embed: eb.Build());
|
||
|
}
|
||
|
|
||
|
private async Task InternallDndRoll(string arg, bool ordered)
|
||
|
{
|
||
|
Match match;
|
||
|
if ((match = _fudgeRegex.Match(arg)).Length != 0
|
||
|
&& int.TryParse(match.Groups["n1"].ToString(), out var n1)
|
||
|
&& n1 is > 0 and < 500)
|
||
|
{
|
||
|
var rng = new EllieRandom();
|
||
|
|
||
|
var rolls = new List<char>();
|
||
|
|
||
|
for (var i = 0; i < n1; i++)
|
||
|
rolls.Add(_fateRolls[rng.Next(0, _fateRolls.Length)]);
|
||
|
var embed = _sender.CreateEmbed()
|
||
|
.WithOkColor()
|
||
|
.WithAuthor(ctx.User)
|
||
|
.WithDescription(GetText(strs.dice_rolled_num(Format.Bold(n1.ToString()))))
|
||
|
.AddField(Format.Bold("Result"),
|
||
|
string.Join(" ", rolls.Select(c => Format.Code($"[{c}]"))));
|
||
|
|
||
|
await Response().Embed(embed).SendAsync();
|
||
|
}
|
||
|
else if ((match = _dndRegex.Match(arg)).Length != 0)
|
||
|
{
|
||
|
var rng = new EllieRandom();
|
||
|
if (int.TryParse(match.Groups["n1"].ToString(), out n1)
|
||
|
&& int.TryParse(match.Groups["n2"].ToString(), out var n2)
|
||
|
&& n1 <= 50
|
||
|
&& n2 <= 100000
|
||
|
&& n1 > 0
|
||
|
&& n2 > 0)
|
||
|
{
|
||
|
if (!int.TryParse(match.Groups["add"].Value, out var add))
|
||
|
add = 0;
|
||
|
if (!int.TryParse(match.Groups["sub"].Value, out var sub))
|
||
|
sub = 0;
|
||
|
|
||
|
var arr = new int[n1];
|
||
|
for (var i = 0; i < n1; i++)
|
||
|
arr[i] = rng.Next(1, n2 + 1);
|
||
|
|
||
|
var sum = arr.Sum();
|
||
|
var embed = _sender.CreateEmbed()
|
||
|
.WithOkColor()
|
||
|
.WithAuthor(ctx.User)
|
||
|
.WithDescription(GetText(strs.dice_rolled_num(n1 + $"`1 - {n2}`")))
|
||
|
.AddField(Format.Bold(GetText(strs.rolls)),
|
||
|
string.Join(" ",
|
||
|
(ordered ? arr.OrderBy(x => x).AsEnumerable() : arr).Select(x
|
||
|
=> Format.Code(x.ToString()))))
|
||
|
.AddField(Format.Bold("Sum"),
|
||
|
sum + " + " + add + " - " + sub + " = " + (sum + add - sub));
|
||
|
await Response().Embed(embed).SendAsync();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[Cmd]
|
||
|
public async Task NRoll([Leftover] string range)
|
||
|
{
|
||
|
int rolled;
|
||
|
if (range.Contains("-"))
|
||
|
{
|
||
|
var arr = range.Split('-').Take(2).Select(int.Parse).ToArray();
|
||
|
if (arr[0] > arr[1])
|
||
|
{
|
||
|
await Response().Error(strs.second_larger_than_first).SendAsync();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
rolled = new EllieRandom().Next(arr[0], arr[1] + 1);
|
||
|
}
|
||
|
else
|
||
|
rolled = new EllieRandom().Next(0, int.Parse(range) + 1);
|
||
|
|
||
|
await Response().Confirm(strs.dice_rolled(Format.Bold(rolled.ToString()))).SendAsync();
|
||
|
}
|
||
|
|
||
|
private async Task<Image<Rgba32>> GetDiceAsync(int num)
|
||
|
{
|
||
|
if (num is < 0 or > 10)
|
||
|
throw new ArgumentOutOfRangeException(nameof(num));
|
||
|
|
||
|
if (num == 10)
|
||
|
{
|
||
|
using var imgOne = Image.Load<Rgba32>(await _images.GetDiceAsync(1));
|
||
|
using var imgZero = Image.Load<Rgba32>(await _images.GetDiceAsync(0));
|
||
|
return new[] { imgOne, imgZero }.Merge();
|
||
|
}
|
||
|
|
||
|
return Image.Load<Rgba32>(await _images.GetDiceAsync(num));
|
||
|
}
|
||
|
}
|
||
|
}
|