diff --git a/Program.fs b/Program.fs index ff7158b..333192a 100644 --- a/Program.fs +++ b/Program.fs @@ -1,11 +1,11 @@ -open System.IO +open System +open System.IO open System.Threading.Tasks open DSharpPlus open DSharpPlus.Entities +open DSharpPlus.EventArgs open DSharpPlus.SlashCommands open Emzi0767.Utilities -open LiteDB -open LiteDB.FSharp type HackType = | Virus = 0 @@ -13,37 +13,41 @@ type HackType = | DDos = 2 | Worm = 3 | Crack = 4 - | SomeOtherThing = 4 + | Injection = 5 type DefenseType = - | Firewall - | PortScan - | Encryption - | Cypher - | Hardening - -[] -type Weapon = { - Id : int - Name : string - Damage : single -} + | Firewall = 0 + | PortScan = 1 + | Encryption = 2 + | Cypher = 3 + | Hardening = 4 + | Sanitation = 5 type Player = { - Id : int - Name : string - Nickname : string - DiscordId : uint16 - Weapons : int array + DiscordId : uint64 + Hacks : HackType list + Defenses : DefenseType list + Bank : int64 } -type Match = - { scorePlayer1 : int - round : int - scorePlayer2 : int } - +let mutable players : Player list = [] + type EmptyGlobalCommandToAvoidFamousDuplicateSlashCommandsBug() = inherit ApplicationCommandModule () +let newPlayer (membr : uint64) = +// let rand = System.Random(System.Guid.NewGuid().GetHashCode()) +// let hacks = +// [0..2] +// |> Set.map (fun _ -> enum(rand.Next(0, 6))) +// let defns = +// [0..2] +// |> Set.map (fun _ -> enum(rand.Next(0, 6))) + + { DiscordId = membr + Hacks = [ HackType.Virus ; HackType.Worm ; HackType.Injection ] + Defenses = [ DefenseType.Cypher ; DefenseType.Sanitation ; DefenseType.Firewall ] + Bank = 0L } + type JoeBot() = inherit ApplicationCommandModule () @@ -54,8 +58,21 @@ type JoeBot() = if role.Value.Name = "Hacker" then do! ctx.Member.GrantRoleAsync(role.Value) |> Async.AwaitTask - do! ctx.CreateResponseAsync("You are now an elite haxxor", true) - |> Async.AwaitTask + + let player = players |> List.tryFind (fun p -> int64 p.DiscordId = int64 ctx.Member.Id) + players <- + match player with + | Some _ -> players + | None -> (newPlayer ctx.Member.Id)::players + + if Option.isSome player then + do! ctx.CreateResponseAsync("Already registered as an elite haxxor", true) + |> Async.AwaitTask + else + do! ctx.CreateResponseAsync("You are now an elite haxxor", true) + |> Async.AwaitTask + + } |> Async.StartAsTask :> Task @@ -71,6 +88,51 @@ type JoeBot() = } |> Async.StartAsTask :> Task + [] + member this.Hack (ctx : InteractionContext, [] player : DiscordUser) = + let constructButtons (playerId : uint64) (weapons : 'a list) = + weapons + |> Seq.map (fun hack -> + // TODO:L Button ID should be a GUID and we should keep an in-memory store of the buttons we're waiting for + DiscordButtonComponent( + ButtonStyle.Primary, + $"Hack-{hack}-{player.Id}", + $"{hack}")) + + players + |> List.tryFind (fun p -> p.DiscordId = ctx.Member.Id) + |> function + | Some player -> + async { + let builder = DiscordInteractionResponseBuilder() + builder.AddEmbed (this.Embed()) |> ignore + + constructButtons player.DiscordId player.Hacks + |> Seq.cast + |> builder.AddComponents + |> ignore + + builder.AsEphemeral true |> ignore + + do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) + |> Async.AwaitTask + + } |> Async.StartAsTask + :> Task + | None -> + async { + let builder = DiscordInteractionResponseBuilder() + builder.Content <- $"You are not currently a hacker, first use the /redpill command to become one" + + builder.AsEphemeral true |> ignore + + do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) + |> Async.AwaitTask + + } |> Async.StartAsTask + :> Task + + [] member _.StartMatch (ctx : InteractionContext, [] player : DiscordUser) = async { @@ -86,6 +148,15 @@ type JoeBot() = ButtonStyle.Danger, "second_button", "No thank you") +// let yes = DiscordButtonComponent( +// ButtonStyle.Primary, +// $"yes_for_{ctx.Member.Id}", +// "I do") +// let no = DiscordButtonComponent( +// ButtonStyle.Danger, +// $"no_for_{ctx.Member.Id}", +// "No thank you") +// builder.AddComponents(yes, no) |> ignore let builder = DiscordMessageBuilder() let builder = builder.AddComponents(yes, no) use img = new FileStream("challenge.jpg", FileMode.Open) @@ -116,53 +187,15 @@ type JoeBot() = member _.Embed () = let builder = DiscordEmbedBuilder() - builder.Color <- Optional(DiscordColor.Blurple) - builder.Description <- "This is a test embed" + builder.Color <- Optional(DiscordColor.PhthaloGreen) + builder.Description <- "Pick the hack you wish to use. " let author = DiscordEmbedBuilder.EmbedAuthor() author.Name <- "Joebot Pro" author.Url <- "https://ferano.io" author.IconUrl <- "https://i.kym-cdn.com/entries/icons/original/000/028/861/cover3.jpg" builder.Author <- author - let footer = DiscordEmbedBuilder.EmbedFooter() - footer.Text <- "This is a footer" - footer.IconUrl <- "https://dg8krxphbh767.cloudfront.net/exercises/bird-watcher.svg" - builder.Footer <- footer - builder.Title <- "THIS IS A TITLE" - builder.ImageUrl <- "https://avatars3.githubusercontent.com/u/2642263" builder.Build() - [] - member this.Hack (ctx : InteractionContext, [] player : DiscordUser) = - let constructButtons (weapons : HackType list) = - weapons - |> Seq.map (fun hack -> - // TODO:L Button ID should be a GUID and we should keep an in-memory store of the buttons we're waiting for - DiscordButtonComponent( - ButtonStyle.Primary, - $"{hack}{System.Guid.NewGuid()}", - $"{hack}")) - async { - let builder = DiscordInteractionResponseBuilder() - builder.AddEmbed (this.Embed()) |> ignore - - constructButtons [ HackType.Virus ; HackType.Crack ; HackType.Ransom ; HackType.Worm ; HackType.DDos ] - |> Seq.cast - |> builder.AddComponents - |> ignore - - constructButtons [ HackType.Virus ; HackType.Crack ; HackType.Ransom ; HackType.Worm ; HackType.DDos ] - |> Seq.cast - |> builder.AddComponents - |> ignore - - builder.AsEphemeral true |> ignore - - do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) - |> Async.AwaitTask - - } |> Async.StartAsTask - :> Task - [] member this.TestEmbed (ctx : InteractionContext) = async { @@ -172,9 +205,38 @@ type JoeBot() = } |> Async.StartAsTask :> Task -let mapper = FSharpBsonMapper() - -let db = new LiteDatabase("hacker-game.db", mapper) +let handleButtonEvent (client : DiscordClient) (event : ComponentInteractionCreateEventArgs) = + async { + match event.Id with + | id when id.StartsWith("Hack") -> + let split = event.Id.Split("-") + let ( resultHack , hackType ) = Enum.TryParse(typedefof, split.[1]) + let ( resultId , target ) = UInt64.TryParse split.[2] + match resultHack , resultId with + | true , true -> + let builder = DiscordInteractionResponseBuilder() + builder.IsEphemeral <- true + builder.Content <- $"Hack has been sent to {target}!" + do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder) + |> Async.AwaitTask + + let builder = DiscordMessageBuilder() +// builder..Add(UserMention(target)) + builder.WithContent($"{event.User.Username} has sent a hack to ") |> ignore + let battleChannel = (event.Guild.GetChannel(927444uL)) + do! battleChannel.SendMessageAsync(builder) + |> Async.AwaitTask + |> Async.Ignore + | _ -> + let builder = DiscordInteractionResponseBuilder() + builder.IsEphemeral <- true + builder.Content <- "Error parsing Button Id" + do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) + |> Async.AwaitTask + + | _ -> () + } |> Async.StartAsTask + :> Task let config = DiscordConfiguration() config.Token <- "OTIyNDIyMDIyMTI1MDEwOTU1.YcBOcw.JxfW1CSIwEO7j6RbRFCnPZ-HoTk" @@ -184,12 +246,7 @@ config.Intents <- DiscordIntents.All let client = new DiscordClient(config) -client.add_ComponentInteractionCreated(AsyncEventHandler( - fun client event -> - async { - return () - } |> Async.StartAsTask - :> Task)) +client.add_ComponentInteractionCreated(AsyncEventHandler(handleButtonEvent)) let slash = client.UseSlashCommands() diff --git a/paket.dependencies b/paket.dependencies index c8ca7fc..a935bee 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -11,4 +11,3 @@ nuget DSharpPlus >= 4.2.0-nightly-01054 nuget DSharpPlus.SlashCommands >= 4.2.0-nightly-01054 nuget LiteDB.FSharp 2.16.0 -nuget LiteDB 4.1.4 diff --git a/paket.references b/paket.references index 1f488ff..9c14efd 100644 --- a/paket.references +++ b/paket.references @@ -3,5 +3,4 @@ DSharpPlus // DSharpPlus.CommandsNext // DSharpPlus.Interactivity DSharpPlus.SlashCommands -LiteDB LiteDB.FSharp