Files
nadekobot/src/NadekoBot/Modules/Gambling/Connect4Commands.cs
Kwoth d5fd6aae8e - More code cleanup and codestyle updates
- Fixed some possible nullref exceptions
- Methods signatures now have up to 3 parameters before breakaing down each parameter in a separate line
- Method invocations have the same rule, except the first parameter will be in the same line as the invocation to prevent some ugliness when passing lambas as arguments
- Applied many more codestyles
- Extensions folder fully reformatted
2021-12-26 17:28:39 +01:00

197 lines
7.4 KiB
C#

using NadekoBot.Modules.Gambling.Common;
using NadekoBot.Modules.Gambling.Common.Connect4;
using NadekoBot.Modules.Gambling.Services;
using System.Text;
namespace NadekoBot.Modules.Gambling;
public partial class Gambling
{
[Group]
public class Connect4Commands : GamblingSubmodule<GamblingService>
{
private readonly DiscordSocketClient _client;
private readonly ICurrencyService _cs;
private static readonly string[] numbers = new string[] { ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:" };
public Connect4Commands(DiscordSocketClient client, ICurrencyService cs, GamblingConfigService gamb)
: base(gamb)
{
_client = client;
_cs = cs;
}
[NadekoCommand, Aliases]
[RequireContext(ContextType.Guild)]
[NadekoOptionsAttribute(typeof(Connect4Game.Options))]
public async Task Connect4(params string[] args)
{
var (options, _) = OptionsParser.ParseFrom(new Connect4Game.Options(), args);
if (!await CheckBetOptional(options.Bet).ConfigureAwait(false))
return;
var newGame = new Connect4Game(ctx.User.Id, ctx.User.ToString(), options, _cs);
Connect4Game game;
if ((game = _service.Connect4Games.GetOrAdd(ctx.Channel.Id, newGame)) != newGame)
{
if (game.CurrentPhase != Connect4Game.Phase.Joining)
return;
newGame.Dispose();
//means game already exists, try to join
var joined = await game.Join(ctx.User.Id, ctx.User.ToString(), options.Bet).ConfigureAwait(false);
return;
}
if (options.Bet > 0)
{
if (!await _cs.RemoveAsync(ctx.User.Id, "Connect4-bet", options.Bet, true).ConfigureAwait(false))
{
await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
_service.Connect4Games.TryRemove(ctx.Channel.Id, out _);
game.Dispose();
return;
}
}
game.OnGameStateUpdated += Game_OnGameStateUpdated;
game.OnGameFailedToStart += Game_OnGameFailedToStart;
game.OnGameEnded += Game_OnGameEnded;
_client.MessageReceived += _client_MessageReceived;
game.Initialize();
if (options.Bet == 0)
{
await ReplyConfirmLocalizedAsync(strs.connect4_created).ConfigureAwait(false);
}
else
{
await ReplyErrorLocalizedAsync(strs.connect4_created_bet(options.Bet + CurrencySign));
}
Task _client_MessageReceived(SocketMessage arg)
{
if (ctx.Channel.Id != arg.Channel.Id)
return Task.CompletedTask;
var _ = Task.Run(async () =>
{
var success = false;
if (int.TryParse(arg.Content, out var col))
{
success = await game.Input(arg.Author.Id, col).ConfigureAwait(false);
}
if (success)
try { await arg.DeleteAsync().ConfigureAwait(false); } catch { }
else
{
if (game.CurrentPhase is Connect4Game.Phase.Joining or Connect4Game.Phase.Ended)
{
return;
}
RepostCounter++;
if (RepostCounter == 0)
try { msg = await ctx.Channel.SendMessageAsync("", embed: (Embed)msg.Embeds.First()).ConfigureAwait(false); } catch { }
}
});
return Task.CompletedTask;
}
Task Game_OnGameFailedToStart(Connect4Game arg)
{
if (_service.Connect4Games.TryRemove(ctx.Channel.Id, out var toDispose))
{
_client.MessageReceived -= _client_MessageReceived;
toDispose.Dispose();
}
return ErrorLocalizedAsync(strs.connect4_failed_to_start);
}
Task Game_OnGameEnded(Connect4Game arg, Connect4Game.Result result)
{
if (_service.Connect4Games.TryRemove(ctx.Channel.Id, out var toDispose))
{
_client.MessageReceived -= _client_MessageReceived;
toDispose.Dispose();
}
string title;
if (result == Connect4Game.Result.CurrentPlayerWon)
{
title = GetText(strs.connect4_won(Format.Bold(arg.CurrentPlayer.Username), Format.Bold(arg.OtherPlayer.Username)));
}
else if (result == Connect4Game.Result.OtherPlayerWon)
{
title = GetText(strs.connect4_won(Format.Bold(arg.OtherPlayer.Username), Format.Bold(arg.CurrentPlayer.Username)));
}
else
title = GetText(strs.connect4_draw);
return msg.ModifyAsync(x => x.Embed = _eb.Create()
.WithTitle(title)
.WithDescription(GetGameStateText(game))
.WithOkColor()
.Build());
}
}
private IUserMessage msg;
private int _repostCounter = 0;
private int RepostCounter
{
get => _repostCounter;
set
{
if (value is < 0 or > 7)
_repostCounter = 0;
else _repostCounter = value;
}
}
private async Task Game_OnGameStateUpdated(Connect4Game game)
{
var embed = _eb.Create()
.WithTitle($"{game.CurrentPlayer.Username} vs {game.OtherPlayer.Username}")
.WithDescription(GetGameStateText(game))
.WithOkColor();
if (msg is null)
msg = await ctx.Channel.EmbedAsync(embed).ConfigureAwait(false);
else
await msg.ModifyAsync(x => x.Embed = embed.Build()).ConfigureAwait(false);
}
private string GetGameStateText(Connect4Game game)
{
var sb = new StringBuilder();
if (game.CurrentPhase is Connect4Game.Phase.P1Move or Connect4Game.Phase.P2Move)
sb.AppendLine(GetText(strs.connect4_player_to_move(Format.Bold(game.CurrentPlayer.Username))));
for (var i = Connect4Game.NumberOfRows; i > 0; i--)
{
for (var j = 0; j < Connect4Game.NumberOfColumns; j++)
{
var cur = game.GameState[i + (j * Connect4Game.NumberOfRows) - 1];
if (cur == Connect4Game.Field.Empty)
sb.Append("⚫"); //black circle
else if (cur == Connect4Game.Field.P1)
sb.Append("🔴"); //red circle
else
sb.Append("🔵"); //blue circle
}
sb.AppendLine();
}
for (var i = 0; i < Connect4Game.NumberOfColumns; i++)
{
sb.Append(numbers[i]);
}
return sb.ToString();
}
}
}