[Raid] Add start command
This commit is contained in:
@@ -11,4 +11,8 @@
|
||||
<PackageReference Include="Discord.Net" Version="3.8.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Modules" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -8,12 +8,13 @@ using Discord;
|
||||
using Discord.Interactions;
|
||||
using Discord.WebSocket;
|
||||
|
||||
namespace Cocotte.Modules;
|
||||
namespace Cocotte.Modules.Ping;
|
||||
|
||||
/// <summary>
|
||||
/// Module containing different test and debug commands
|
||||
/// </summary>
|
||||
[RequireOwner]
|
||||
[Group("ping", "Debug related commands")]
|
||||
public class PingModule : InteractionModuleBase<SocketInteractionContext>
|
||||
{
|
||||
private readonly ILogger<PingModule> _logger;
|
||||
@@ -291,7 +292,7 @@ public class FoodModal : IModal
|
||||
[ModalTextInput("food_name", placeholder: "Pizza", maxLength: 20)]
|
||||
public string? Food { get; set; }
|
||||
|
||||
// Additional paremeters can be specified to further customize the input.
|
||||
// Additional paremeters can be specified to further customize the input.
|
||||
// Parameters can be optional
|
||||
[RequiredInput(false)]
|
||||
[InputLabel("Why??")]
|
||||
8
Cocotte/Modules/Raids/IRaidsRepository.cs
Normal file
8
Cocotte/Modules/Raids/IRaidsRepository.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Cocotte.Modules.Raids;
|
||||
|
||||
public interface IRaidsRepository
|
||||
{
|
||||
Raid this[ulong raidId] { get; }
|
||||
|
||||
bool AddNewRaid(ulong raidId, DateTime dateTime);
|
||||
}
|
||||
18
Cocotte/Modules/Raids/MemoryRaidRepository.cs
Normal file
18
Cocotte/Modules/Raids/MemoryRaidRepository.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace Cocotte.Modules.Raids;
|
||||
|
||||
public class MemoryRaidRepository : IRaidsRepository
|
||||
{
|
||||
private readonly Dictionary<ulong, Raid> _raids;
|
||||
|
||||
public Raid this[ulong raidId] => _raids[raidId];
|
||||
|
||||
public MemoryRaidRepository()
|
||||
{
|
||||
_raids = new Dictionary<ulong, Raid>();
|
||||
}
|
||||
|
||||
public bool AddNewRaid(ulong raidId, DateTime dateTime)
|
||||
{
|
||||
return _raids.TryAdd(raidId, new Raid(raidId, dateTime));
|
||||
}
|
||||
}
|
||||
38
Cocotte/Modules/Raids/Raid.cs
Normal file
38
Cocotte/Modules/Raids/Raid.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using Cocotte.Utils;
|
||||
|
||||
namespace Cocotte.Modules.Raids;
|
||||
|
||||
public class Raid
|
||||
{
|
||||
public ulong Id { get; }
|
||||
public DateTime DateTime { get; }
|
||||
|
||||
private readonly RosterManager _rosterManager = new();
|
||||
|
||||
public IEnumerable<IGrouping<int, RosterPlayer>> Rosters => _rosterManager.Rosters;
|
||||
|
||||
public Raid(ulong id, DateTime dateTime)
|
||||
{
|
||||
Id = id;
|
||||
DateTime = dateTime;
|
||||
|
||||
#if DEBUG
|
||||
this.AddTestPlayers();
|
||||
#endif
|
||||
}
|
||||
|
||||
public bool AddPlayer(string name, PlayerRole role, int fc, bool substitute = false)
|
||||
{
|
||||
return _rosterManager.AddPlayer(new RosterPlayer(name, role, fc, substitute));
|
||||
}
|
||||
|
||||
public override bool Equals(object? other)
|
||||
{
|
||||
return other is Raid roster && roster.Id == Id;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (int) (Id % int.MaxValue);
|
||||
}
|
||||
}
|
||||
79
Cocotte/Modules/Raids/RaidModule.cs
Normal file
79
Cocotte/Modules/Raids/RaidModule.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Cocotte.Utils;
|
||||
using Discord;
|
||||
using Discord.Interactions;
|
||||
|
||||
namespace Cocotte.Modules.Raids;
|
||||
|
||||
[Group("raid", "Raid related commands")]
|
||||
public class RaidModule : InteractionModuleBase<SocketInteractionContext>
|
||||
{
|
||||
private readonly ILogger<RaidModule> _logger;
|
||||
private readonly IRaidsRepository _raidsRepository;
|
||||
|
||||
public RaidModule(ILogger<RaidModule> logger, IRaidsRepository raidsRepository)
|
||||
{
|
||||
_logger = logger;
|
||||
_raidsRepository = raidsRepository;
|
||||
}
|
||||
|
||||
[SlashCommand("start", "Start a raid formation")]
|
||||
public async Task Ping()
|
||||
{
|
||||
// Raids are identified using their original message id
|
||||
await RespondAsync("`Creating a new raid...`");
|
||||
|
||||
var response = await GetOriginalResponseAsync();
|
||||
var raidId = response.Id;
|
||||
|
||||
_logger.LogInformation("Created new raid with id {RaidId}", raidId);
|
||||
|
||||
// New raid instance
|
||||
// TODO: Ask for date
|
||||
if (!_raidsRepository.AddNewRaid(raidId, DateTime.Now))
|
||||
{
|
||||
// A raid with this message id already exists, how??
|
||||
_logger.LogWarning("Tried to create a new raid with already existing id: {RaidId}", raidId);
|
||||
|
||||
await FollowupAsync(ephemeral: true, embed: EmbedUtils.ErrorEmbed("Can't create a new raid with same raid id").Build());
|
||||
await DeleteOriginalResponseAsync();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Build the raid message
|
||||
var embed = RaidEmbed(raidId);
|
||||
|
||||
await ModifyOriginalResponseAsync(m =>
|
||||
{
|
||||
m.Content = "";
|
||||
m.Embed = embed.Build();
|
||||
});
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
|
||||
private EmbedBuilder RaidEmbed(ulong raidId)
|
||||
{
|
||||
EmbedFieldBuilder RosterEmbed(int rosterNumber, IEnumerable<RosterPlayer> players)
|
||||
{
|
||||
var nonSubstitute = players.Where(p => !p.Substitue);
|
||||
var substitute = players.Where(p => p.Substitue);
|
||||
|
||||
var separatorLength = Math.Max(nonSubstitute.Select(p => p.Name.Length).Max(), substitute.Select(p => p.Name.Length).Max());
|
||||
separatorLength = (int) ((separatorLength + 13) * 0.49); // Don't ask why, it just works
|
||||
|
||||
return new EmbedFieldBuilder()
|
||||
.WithName($"Roster {rosterNumber}")
|
||||
.WithValue($"{string.Join("\n", nonSubstitute)}\n{new string('━', separatorLength)}\n{string.Join("\n", substitute)}")
|
||||
.WithIsInline(true);
|
||||
}
|
||||
|
||||
var raid = _raidsRepository[raidId];
|
||||
|
||||
return new EmbedBuilder()
|
||||
.WithColor(Colors.CocotteBlue)
|
||||
.WithTitle(":crossed_swords: Raid")
|
||||
.WithDescription($"**Date:** {TimestampTag.FromDateTime(raid.DateTime, TimestampTagStyles.LongDateTime)}")
|
||||
.WithFields(raid.Rosters.Select(r => RosterEmbed(r.Key, r)));
|
||||
}
|
||||
}
|
||||
16
Cocotte/Modules/Raids/RosterManager.cs
Normal file
16
Cocotte/Modules/Raids/RosterManager.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace Cocotte.Modules.Raids;
|
||||
|
||||
public class RosterManager
|
||||
{
|
||||
private readonly ISet<RosterPlayer> _rosters = new HashSet<RosterPlayer>();
|
||||
|
||||
public IEnumerable<IGrouping<int, RosterPlayer>> Rosters => _rosters.GroupBy(p => p.RosterNumber);
|
||||
|
||||
public bool AddPlayer(RosterPlayer rosterPlayer)
|
||||
{
|
||||
// TODO add logic to split player in multiple rosters
|
||||
rosterPlayer.RosterNumber = 1;
|
||||
|
||||
return _rosters.Add(rosterPlayer);
|
||||
}
|
||||
}
|
||||
33
Cocotte/Modules/Raids/RosterPlayer.cs
Normal file
33
Cocotte/Modules/Raids/RosterPlayer.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
namespace Cocotte.Modules.Raids;
|
||||
|
||||
public record RosterPlayer(string Name, PlayerRole Role, int Fc, bool Substitue = false)
|
||||
{
|
||||
public int RosterNumber { get; set; }
|
||||
|
||||
private static string RoleToEmote(PlayerRole role) => role switch
|
||||
{
|
||||
PlayerRole.Dps => ":red_circle:",
|
||||
PlayerRole.Tank => ":yellow_circle:",
|
||||
PlayerRole.Healer => ":green_circle:",
|
||||
_ => ":question:"
|
||||
};
|
||||
|
||||
public static string FcFormat(int fc) => fc switch
|
||||
{
|
||||
< 1_000 => $"{fc}",
|
||||
_ => $"{fc/1000}k"
|
||||
};
|
||||
|
||||
public override string ToString() => Substitue switch
|
||||
{
|
||||
false => $"{RoleToEmote(Role)} {Name} ({FcFormat(Fc)} FC)",
|
||||
true => $"*{RoleToEmote(Role)} {Name} ({FcFormat(Fc)} FC)*"
|
||||
};
|
||||
}
|
||||
|
||||
public enum PlayerRole
|
||||
{
|
||||
Dps,
|
||||
Healer,
|
||||
Tank
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using Cocotte.Modules.Raids;
|
||||
using Cocotte.Options;
|
||||
using Cocotte.Services;
|
||||
using Discord;
|
||||
@@ -31,6 +32,9 @@ IHost host = Host.CreateDefaultBuilder(args)
|
||||
|
||||
services.AddHostedService<CocotteService>();
|
||||
|
||||
// Data
|
||||
services.AddSingleton<IRaidsRepository, MemoryRaidRepository>();
|
||||
|
||||
// Custom
|
||||
services.AddSingleton<SharedCounter>();
|
||||
services.AddTransient<TransientCounter>();
|
||||
|
||||
13
Cocotte/Utils/Colors.cs
Normal file
13
Cocotte/Utils/Colors.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Discord;
|
||||
|
||||
namespace Cocotte.Utils;
|
||||
|
||||
public static class Colors
|
||||
{
|
||||
// Main Cocotte colors
|
||||
public static Color CocotteBlue => new(0x3196c8);
|
||||
|
||||
// Colors used in embeds
|
||||
public static Color ErrorColor => new(0xFB6060);
|
||||
public static Color InfoColor => new(0x66D9EF);
|
||||
}
|
||||
28
Cocotte/Utils/EmbedUtils.cs
Normal file
28
Cocotte/Utils/EmbedUtils.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Discord;
|
||||
|
||||
namespace Cocotte.Utils;
|
||||
|
||||
public static class EmbedUtils
|
||||
{
|
||||
public static EmbedBuilder ErrorEmbed(string message)
|
||||
{
|
||||
return new EmbedBuilder()
|
||||
.WithColor(Colors.ErrorColor)
|
||||
.WithAuthor(a => a
|
||||
.WithName("Error")
|
||||
.WithIconUrl("https://sage.cdn.ilysix.fr/assets/Cocotte/icons/error.webp")
|
||||
)
|
||||
.WithDescription(message);
|
||||
}
|
||||
|
||||
public static EmbedBuilder InfoEmbed(string message)
|
||||
{
|
||||
return new EmbedBuilder()
|
||||
.WithColor(Colors.InfoColor)
|
||||
.WithAuthor(a => a
|
||||
.WithName("Info")
|
||||
.WithIconUrl("https://sage.cdn.ilysix.fr/assets/Cocotte/icons/info.webp")
|
||||
)
|
||||
.WithDescription(message);
|
||||
}
|
||||
}
|
||||
14
Cocotte/Utils/RaidExtensions.cs
Normal file
14
Cocotte/Utils/RaidExtensions.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Cocotte.Modules.Raids;
|
||||
|
||||
namespace Cocotte.Utils;
|
||||
|
||||
public static class RaidExtensions
|
||||
{
|
||||
public static void AddTestPlayers(this Raid raid)
|
||||
{
|
||||
raid.AddPlayer("YamaRaja", PlayerRole.Healer, 30000, false);
|
||||
raid.AddPlayer("Zaku", PlayerRole.Dps, 40000, false);
|
||||
raid.AddPlayer("Juchi", PlayerRole.Tank, 40000, false);
|
||||
raid.AddPlayer("Akeno", PlayerRole.Dps, 40000, true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user