Getting defense command to work. Fixes and improvements

This commit is contained in:
Joseph Ferano 2022-01-10 12:33:14 +07:00
parent 97bf07e7ec
commit 2f3a9fd1f9

View File

@ -1,5 +1,4 @@
open System open System
open System.IO
open System.Threading.Tasks open System.Threading.Tasks
open DSharpPlus open DSharpPlus
open DSharpPlus.Entities open DSharpPlus.Entities
@ -23,13 +22,19 @@ type Protection =
| Hardening = 4 | Hardening = 4
| Sanitation = 5 | Sanitation = 5
type DiscordPlayer = {
Id : uint64
Name : string
}
type Attack = { type Attack = {
HackType : Hack HackType : Hack
Target : DiscordPlayer
Timestamp : DateTime Timestamp : DateTime
} }
type Defense = { type Defense = {
DefenseType : Hack DefenseType : Protection
Timestamp : DateTime Timestamp : DateTime
} }
@ -62,13 +67,12 @@ let newPlayer (membr : uint64) =
Bank = 0L Bank = 0L
Defenses = [] } Defenses = [] }
let constructButtons (actionType : string) (playerId : uint64) (weapons : 'a list) = let constructButtons (actionType : string) (playerInfo : string) (weapons : 'a list) =
weapons weapons
|> Seq.map (fun hack -> |> 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( DiscordButtonComponent(
ButtonStyle.Primary, ButtonStyle.Primary,
$"{actionType}-{hack}-{playerId}", $"{actionType}-{hack}-{playerInfo}",
$"{hack}")) $"{hack}"))
let notRegisteredYetMessage (ctx : InteractionContext) = let notRegisteredYetMessage (ctx : InteractionContext) =
@ -91,6 +95,17 @@ let removeExpiredActions timespan (timestamp : 'a -> DateTime) actions =
then true then true
else false) else false)
let constructEmbed message =
let builder = DiscordEmbedBuilder()
builder.Color <- Optional(DiscordColor.PhthaloGreen)
builder.Description <- message
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
builder.Build()
type JoeBot() = type JoeBot() =
inherit ApplicationCommandModule () inherit ApplicationCommandModule ()
@ -132,18 +147,23 @@ type JoeBot() =
:> Task :> Task
[<SlashCommand("hack", "Send a hack attack to another player")>] [<SlashCommand("hack", "Send a hack attack to another player")>]
member this.Attack (ctx : InteractionContext, [<Option("player", "The player you want to hack")>] player : DiscordUser) = member this.AttackCommand (ctx : InteractionContext, [<Option("target", "The player you want to hack")>] target : DiscordUser) =
// TODO: We need to check if the player has any active hacks going, if not they can cheat
players players
|> List.tryFind (fun p -> p.DiscordId = ctx.Member.Id) |> List.tryFind (fun p -> p.DiscordId = ctx.Member.Id)
|> function |> function
| Some player -> | Some player ->
let updatedAttacks = removeExpiredActions (TimeSpan.FromMinutes(5)) (fun (atk : Attack) -> atk.Timestamp) player.Attacks let updatedAttacks = removeExpiredActions (TimeSpan.FromMinutes(15)) (fun (atk : Attack) -> atk.Timestamp) player.Attacks
if updatedAttacks.Length <= 3 then players <-
players
|> List.map (fun p -> if p.DiscordId = player.DiscordId then { p with Attacks = updatedAttacks } else p)
if updatedAttacks.Length < 1 then
async { async {
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
builder.AddEmbed (this.Embed("Pick the hack you wish to use. ")) |> ignore builder.AddEmbed (constructEmbed "Pick the hack you wish to use.") |> ignore
constructButtons "Attack" player.DiscordId player.Hacks let targetInfo = $"{target.Id}-{target.Username}"
constructButtons "Attack" targetInfo player.Hacks
|> Seq.cast<DiscordComponent> |> Seq.cast<DiscordComponent>
|> builder.AddComponents |> builder.AddComponents
|> ignore |> ignore
@ -158,7 +178,8 @@ type JoeBot() =
else else
async { async {
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
builder.Content <- "You have no more hacks available, please wait for another hack to cooldown" let timeRemaining = TimeSpan.FromMinutes(15) - (DateTime.UtcNow - updatedAttacks.Head.Timestamp)
builder.Content <- $"You already hacked, please wait {timeRemaining.Minutes} minutes and {timeRemaining.Seconds} seconds to attempt another hack"
builder.AsEphemeral true |> ignore builder.AsEphemeral true |> ignore
@ -171,16 +192,20 @@ type JoeBot() =
[<SlashCommand("defend", "Create a passive defense that will last a certain amount of time")>] [<SlashCommand("defend", "Create a passive defense that will last a certain amount of time")>]
member this.Defend (ctx : InteractionContext) = member this.DefendCommand (ctx : InteractionContext) =
players players
|> List.tryFind (fun p -> p.DiscordId = ctx.Member.Id) |> List.tryFind (fun p -> p.DiscordId = ctx.Member.Id)
|> function |> function
| Some player -> | Some player ->
async { async {
let updatedDefenses = removeExpiredActions (TimeSpan.FromMinutes(60)) (fun (pro : Defense) -> pro.Timestamp) player.Defenses
players <-
players
|> List.map (fun p -> if p.DiscordId = player.DiscordId then { p with Defenses = updatedDefenses } else p)
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
builder.AddEmbed (this.Embed("Pick a defense to mount for a duration of time")) |> ignore builder.AddEmbed (constructEmbed "Pick a defense to mount for a duration of time") |> ignore
constructButtons "Defense" player.DiscordId player.Protections constructButtons "Defense" (string player.DiscordId) player.Protections
|> Seq.cast<DiscordComponent> |> Seq.cast<DiscordComponent>
|> builder.AddComponents |> builder.AddComponents
|> ignore |> ignore
@ -194,36 +219,27 @@ type JoeBot() =
:> Task :> Task
| None -> notRegisteredYetMessage ctx | None -> notRegisteredYetMessage ctx
member _.Embed message =
let builder = DiscordEmbedBuilder()
builder.Color <- Optional(DiscordColor.PhthaloGreen)
builder.Description <- message
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
builder.Build()
let handleAttack (event : ComponentInteractionCreateEventArgs) = let handleAttack (event : ComponentInteractionCreateEventArgs) =
async { async {
let split = event.Id.Split("-") let split = event.Id.Split("-")
let ( resultHack , hackType ) = Enum.TryParse(typedefof<Hack>, split.[1]) let ( resultHack , hackType ) = Enum.TryParse(typedefof<Hack>, split.[1])
let ( resultId , target ) = UInt64.TryParse split.[2] let ( resultId , targetId ) = UInt64.TryParse split.[2]
match resultHack , resultId with match resultHack , resultId with
| true , true -> | true , true ->
let hackType = hackType :?> Hack
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
builder.IsEphemeral <- true builder.IsEphemeral <- true
builder.Content <- $"Hack has been sent to {target}!" builder.Content <- $"Sent {hackType} to {split.[3]}!"
do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder) do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
|> Async.AwaitTask |> Async.AwaitTask
let attack = { HackType = hackType ; Timestamp = DateTime.UtcNow ; Target = { Id = targetId ; Name = split.[3] } }
players <- players <-
players players
|> List.map (fun p -> { p with Attacks = { HackType = hackType :?> Hack ; Timestamp = DateTime.UtcNow }::p.Attacks }) |> List.map (fun p -> if p.DiscordId = event.User.Id then { p with Attacks = attack::p.Attacks } else p)
let builder = DiscordMessageBuilder() let builder = DiscordMessageBuilder()
builder.WithContent($"{event.User.Username} has sent a hack to <@{target}>") |> ignore builder.WithContent($"{event.User.Username} has sent a hack to <@{targetId}>") |> ignore
let battleChannel = (event.Guild.GetChannel(927449884204867664uL)) let battleChannel = (event.Guild.GetChannel(927449884204867664uL))
do! battleChannel.SendMessageAsync(builder) do! battleChannel.SendMessageAsync(builder)
|> Async.AwaitTask |> Async.AwaitTask
@ -239,16 +255,21 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
let handleDefense (event : ComponentInteractionCreateEventArgs) = let handleDefense (event : ComponentInteractionCreateEventArgs) =
async { async {
let split = event.Id.Split("-") let split = event.Id.Split("-")
let ( resultHack , hackType ) = Enum.TryParse(typedefof<Hack>, split.[1]) let ( resultHack , protectionType ) = Enum.TryParse(typedefof<Protection>, split.[1])
let ( resultId , target ) = UInt64.TryParse split.[2] match resultHack with
match resultHack , resultId with | true ->
| true , true -> let protectionType = protectionType :?> Protection
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
builder.IsEphemeral <- true builder.IsEphemeral <- true
builder.Content <- $"Hack has been sent to your target!" builder.Content <- $"Mounted a {protectionType} defense for 1 hour"
do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder) do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
|> Async.AwaitTask |> Async.AwaitTask
let defense = { DefenseType = protectionType ; Timestamp = DateTime.UtcNow }
players <-
players
|> List.map (fun p -> { p with Defenses = defense::p.Defenses })
let builder = DiscordMessageBuilder() let builder = DiscordMessageBuilder()
builder.WithContent($"{event.User.Username} has protected their system!") |> ignore builder.WithContent($"{event.User.Username} has protected their system!") |> ignore
let battleChannel = (event.Guild.GetChannel(927449884204867664uL)) let battleChannel = (event.Guild.GetChannel(927449884204867664uL))
@ -265,10 +286,10 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
let handleButtonEvent (client : DiscordClient) (event : ComponentInteractionCreateEventArgs) = let handleButtonEvent (client : DiscordClient) (event : ComponentInteractionCreateEventArgs) =
async { async {
return match event.Id with return! match event.Id with
| id when id.StartsWith("Attack") -> handleAttack event | id when id.StartsWith("Attack") -> handleAttack event
| id when id.StartsWith("Defend") -> handleDefense event | id when id.StartsWith("Defend") -> handleDefense event
| _ -> async { return () } | _ -> async { return () }
} |> Async.StartAsTask } |> Async.StartAsTask
:> Task :> Task