Make most commands deferred/follow up so they don't fail. bug fixes

This commit is contained in:
Joseph Ferano 2022-02-03 02:59:11 +07:00
parent 12ba17de30
commit cd15a08e37
7 changed files with 162 additions and 165 deletions

View File

@ -1,23 +1,24 @@
module Degenz.Embeds module Degenz.Embeds
open System
open DSharpPlus.EventArgs open DSharpPlus.EventArgs
open Degenz.Types open Degenz.Types
open DSharpPlus.Entities open DSharpPlus.Entities
open AsciiTableFormatter open AsciiTableFormatter
let hackGif = "https://s10.gifyu.com/images/Hacker-Degenz-V2.gif" let hackGif = "https://s10.gifyu.com/images/Hacker-Degenz-V20ce8eb832734aa62-min.gif"
let shieldGif = "https://s10.gifyu.com/images/Defense-Degenz-V2.gif" let shieldGif = "https://s10.gifyu.com/images/Defense-Degenz-V2-min.gif"
let getHackGif = function let getHackGif = function
| HackId.Virus -> "https://s10.gifyu.com/images/Attack-DegenZ.gif" | HackId.Virus -> "https://s10.gifyu.com/images/Attack-DegenZ-1.gif"
| HackId.RemoteAccess -> "https://s10.gifyu.com/images/Mind-Control-Degenz-V2.gif" | HackId.RemoteAccess -> "https://s10.gifyu.com/images/Mind-Control-Degenz-V2-min.gif"
| HackId.Worm -> "https://s10.gifyu.com/images/WormBugAttack_Degenz.gif" | HackId.Worm -> "https://s10.gifyu.com/images/WormBugAttack_Degenz-min.gif"
| _ -> hackGif | _ -> hackGif
let getShieldGif = function let getShieldGif = function
| ShieldId.Firewall -> "https://s10.gifyu.com/images/Defense-GIF-1-Degenz.gif" | ShieldId.Firewall -> "https://s10.gifyu.com/images/Defense-GIF-1-Degenz-min.gif"
| ShieldId.Encryption -> "https://s10.gifyu.com/images/Encryption-Degenz-V2.gif" | ShieldId.Encryption -> "https://s10.gifyu.com/images/Encryption-Degenz-V2-1-min.gif"
| ShieldId.Cypher -> "https://s10.gifyu.com/images/Matrix_Degenz.gif" | ShieldId.Cypher -> "https://s10.gifyu.com/images/Cypher-Smaller.gif"
| _ -> shieldGif | _ -> shieldGif
@ -40,10 +41,10 @@ let pickDefense actionId player =
let embed = let embed =
DiscordEmbedBuilder() DiscordEmbedBuilder()
.WithColor(DiscordColor.Blurple) .WithColor(DiscordColor.Blurple)
.WithDescription("Pick a defense to mount for 10 hours") .WithDescription("Pick a shield to protect yourself from hacks")
.WithImageUrl(shieldGif) .WithImageUrl(shieldGif)
DiscordInteractionResponseBuilder() DiscordFollowupMessageBuilder()
.AddComponents(buttons) .AddComponents(buttons)
.AddEmbed(embed) .AddEmbed(embed)
.AsEphemeral true .AsEphemeral true
@ -59,21 +60,12 @@ let pickHack actionId attacker defender =
.WithDescription("Pick the hack that you want to use") .WithDescription("Pick the hack that you want to use")
.WithImageUrl(hackGif) .WithImageUrl(hackGif)
DiscordInteractionResponseBuilder() DiscordFollowupMessageBuilder()
.AddComponents(buttons) .AddComponents(buttons)
.AddEmbed(embed.Build()) .AddEmbed(embed.Build())
.AsEphemeral true .AsEphemeral true
let responseSuccessfulHack defenderName hack prize = let responseSuccessfulHack (hack : BattleItem) =
let embed = DiscordEmbedBuilder()
embed.ImageUrl <- getHackGif hack
DiscordInteractionResponseBuilder()
.WithContent($"Successfully hacked {defenderName} using {hack}! You just won {prize} GoodBoyTokenz!")
.AddEmbed(embed.Build())
.AsEphemeral(true)
let responseSuccessfulHackTrainer (hack : BattleItem) =
let embed = DiscordEmbedBuilder() let embed = DiscordEmbedBuilder()
embed.ImageUrl <- getHackGif (enum<HackId>(hack.Id)) embed.ImageUrl <- getHackGif (enum<HackId>(hack.Id))
@ -82,11 +74,11 @@ let responseSuccessfulHackTrainer (hack : BattleItem) =
.AddEmbed(embed.Build()) .AddEmbed(embed.Build())
.AsEphemeral(true) .AsEphemeral(true)
let responseCreatedShield shield = let responseCreatedShield (shield : BattleItem) =
DiscordInteractionResponseBuilder() DiscordFollowupMessageBuilder()
.AddEmbed(DiscordEmbedBuilder().WithImageUrl(getShieldGif shield)) .AddEmbed(DiscordEmbedBuilder().WithImageUrl(getShieldGif (enum<ShieldId>(shield.Id))))
.AsEphemeral(true) .AsEphemeral(true)
.WithContent($"Mounted a {shield} defense for 6 hours") .WithContent($"Mounted {shield.Name} shield for {TimeSpan.FromMinutes(int shield.Cooldown).Hours} hours")
let responseCreatedShieldTrainer (shield : BattleItem) = let responseCreatedShieldTrainer (shield : BattleItem) =
DiscordFollowupMessageBuilder() DiscordFollowupMessageBuilder()
@ -120,11 +112,14 @@ let storeListing store =
store store
|> Array.groupBy (fun (bi : BattleItem) -> bi.Type) |> Array.groupBy (fun (bi : BattleItem) -> bi.Type)
|> Array.map (fun ( itemType , items ) -> |> Array.map (fun ( itemType , items ) ->
items let msg =
|> Array.map (fun item -> { Name = item.Name ; Cost = string item.Cost ; Class = string item.Class }) items
|> Formatter.Format |> Array.map (fun item -> { Name = item.Name ; Cost = string item.Cost ; Class = string item.Class })
|> sprintf "**%As**\n``` %s ```" itemType |> Formatter.Format
|> constructEmbed) |> sprintf "**%As**\n``` %s ```" itemType
DiscordEmbedBuilder()
.WithDescription(msg)
.Build())
DiscordInteractionResponseBuilder() DiscordInteractionResponseBuilder()
.AddEmbeds(embeds) .AddEmbeds(embeds)

View File

@ -1,15 +1,24 @@
module Degenz.Game module Degenz.Game
open System
open System.Threading.Tasks open System.Threading.Tasks
open DSharpPlus
open DSharpPlus.Entities
open DSharpPlus.EventArgs open DSharpPlus.EventArgs
open DSharpPlus.SlashCommands open DSharpPlus.SlashCommands
open Degenz.DbService open Degenz.DbService
open Microsoft.VisualBasic
let HackPrize = 10<GBT> let HackPrize = 10<GBT>
let ShieldPrize = 5<GBT> let ShieldPrize = 5<GBT>
let executePlayerInteraction (ctx : InteractionContext) (dispatch : PlayerData -> Async<unit>) = let executePlayerInteraction (ctx : InteractionContext) (dispatch : PlayerData -> Async<unit>) =
async { async {
let builder = DiscordInteractionResponseBuilder()
builder.IsEphemeral <- true
builder.Content <- "Content"
do! ctx.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource, builder)
|> Async.AwaitTask
let! playerResult = tryFindPlayer ctx.Member.Id let! playerResult = tryFindPlayer ctx.Member.Id
match playerResult with match playerResult with
| Some player -> do! dispatch player | Some player -> do! dispatch player
@ -18,12 +27,17 @@ let executePlayerInteraction (ctx : InteractionContext) (dispatch : PlayerData -
:> Task :> Task
// TODO: Create an abstraction for these two helper functions // TODO: Create an abstraction for these two helper functions
let executePlayerEvent (ctx : ComponentInteractionCreateEventArgs) (dispatch : PlayerData -> Async<unit>) = let executePlayerEvent (event : ComponentInteractionCreateEventArgs) (dispatch : PlayerData -> Async<unit>) =
async { async {
let! playerResult = tryFindPlayer ctx.User.Id let builder = DiscordInteractionResponseBuilder()
builder.IsEphemeral <- true
builder.Content <- "Content"
do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource, builder)
|> Async.AwaitTask
let! playerResult = tryFindPlayer event.User.Id
match playerResult with match playerResult with
| Some player -> do! dispatch player | Some player -> do! dispatch player
| None -> do! Messaging.sendInteractionEvent ctx "You are currently not a hacker, first use the /redpill command to become one" | None -> do! Messaging.sendInteractionEvent event "You are currently not a hacker, first use the /redpill command to become one"
} |> Async.StartAsTask } |> Async.StartAsTask
:> Task :> Task

View File

@ -79,9 +79,10 @@ let successfulHack (event : ComponentInteractionCreateEventArgs) attacker defend
async { async {
do! updateCombatants attacker defender hack Game.HackPrize do! updateCombatants attacker defender hack Game.HackPrize
let embed = Embeds.responseSuccessfulHack defender.Name hack Game.HackPrize let embed = Embeds.responseSuccessfulHack (Armory.getItem (int hack))
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed) do! event.Interaction.CreateFollowupMessageAsync(embed)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore
let builder = Embeds.eventSuccessfulHack event defender.DiscordId Game.HackPrize let builder = Embeds.eventSuccessfulHack event defender.DiscordId Game.HackPrize
let channel = event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle) let channel = event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle)
@ -122,28 +123,29 @@ let attack (ctx : InteractionContext) (target : DiscordUser) =
|> function |> function
| Ok _ -> | Ok _ ->
let embed = Embeds.pickHack "Attack" attacker defender let embed = Embeds.pickHack "Attack" attacker defender
ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed) ctx.FollowUpAsync(embed)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore
| Error msg -> | Error msg ->
let builder = let builder =
DiscordInteractionResponseBuilder() DiscordFollowupMessageBuilder()
.WithContent(msg) .WithContent(msg)
.AsEphemeral(true) .AsEphemeral(true)
ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) ctx.FollowUpAsync(builder)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore
| None -> do! sendSimpleResponse ctx "Your target is not connected to the network, they must join first by using the /redpill command" | None -> do! sendSimpleResponse ctx "Your target is not connected to the network, they must join first by using the /redpill command"
}) })
let handleAttack (event : ComponentInteractionCreateEventArgs) = let handleAttack (event : ComponentInteractionCreateEventArgs) =
async { Game.executePlayerEvent event (fun attacker -> async {
let split = event.Id.Split("-") let split = event.Id.Split("-")
let hack = enum<HackId>(int split.[1]) let hack = enum<HackId>(int split.[1])
let ( resultId , targetId ) = UInt64.TryParse split.[2] let ( resultId , targetId ) = UInt64.TryParse split.[2]
let! resultPlayer = DbService.tryFindPlayer event.User.Id
let! resultTarget = DbService.tryFindPlayer targetId let! resultTarget = DbService.tryFindPlayer targetId
match resultPlayer , resultTarget , true , resultId with match resultTarget , true , resultId with
| Some attacker , Some defender , true , true -> | Some defender , true , true ->
do! attacker do! attacker
|> Player.removeExpiredActions |> Player.removeExpiredActions
|> checkForExistingTarget defender.DiscordId |> checkForExistingTarget defender.DiscordId
@ -154,103 +156,78 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
|> function |> function
| false -> successfulHack event attacker defender hack | false -> successfulHack event attacker defender hack
| true -> failedHack event attacker defender hack | true -> failedHack event attacker defender hack
| Error msg -> | Error msg -> Messaging.sendFollowUpMessage event msg
let builder = | _ -> do! Messaging.sendFollowUpMessage event "Error occurred processing attack"
DiscordInteractionResponseBuilder() })
.WithContent(msg)
.AsEphemeral(true)
event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask
| _ ->
let builder = DiscordInteractionResponseBuilder()
builder.IsEphemeral <- true
builder.Content <- "Error occurred processing attack"
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask
}
let defend (ctx : InteractionContext) = let defend (ctx : InteractionContext) =
Game.executePlayerInteraction ctx (fun player -> async { Game.executePlayerInteraction ctx (fun player -> async {
if Player.shields player |> Array.length > 0 then if Player.shields player |> Array.length > 0 then
let embed = Embeds.pickDefense "Defend" player let embed = Embeds.pickDefense "Defend" player
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed) do! ctx.FollowUpAsync(embed)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore
else else
let builder = DiscordInteractionResponseBuilder() let msg = $"You currently do not have any Shields to protect you. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one."
builder.Content <- $"You currently do not have any Shields to protect you. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one." do! Messaging.sendFollowUpMessageFromCtx ctx msg
builder.AsEphemeral true |> ignore
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask
}) })
let handleDefense (event : ComponentInteractionCreateEventArgs) = let handleDefense (event : ComponentInteractionCreateEventArgs) =
async { Game.executePlayerEvent event (fun player -> async {
let split = event.Id.Split("-") let split = event.Id.Split("-")
let shield = enum<ShieldId>(int split.[1]) let shieldId = enum<ShieldId>(int split.[1])
let! playerResult = DbService.tryFindPlayer event.User.Id let updatedDefenses = player |> Player.removeExpiredActions |> Player.defenses
match playerResult with let alreadyUsedShield = updatedDefenses |> Array.exists (fun d -> d.ActionId = int shieldId)
| Some player ->
let updatedDefenses = player |> Player.removeExpiredActions |> Player.defenses
let alreadyUsedShield = updatedDefenses |> Array.exists (fun d -> d.ActionId = int shield)
match alreadyUsedShield , updatedDefenses.Length < 2 with match alreadyUsedShield , updatedDefenses.Length < 2 with
| false , true -> | false , true ->
let embed = Embeds.responseCreatedShield shield let embed = Embeds.responseCreatedShield (Armory.getItem (int shieldId))
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed) do! event.Interaction.CreateFollowupMessageAsync(embed)
|> Async.AwaitTask |> Async.AwaitTask
let defense = { ActionId = int shield ; Type = Defense ; Timestamp = DateTime.UtcNow } |> Async.Ignore
do! DbService.updatePlayer <| { player with Actions = Array.append [| defense |] player.Actions } let defense = { ActionId = int shieldId ; Type = Defense ; Timestamp = DateTime.UtcNow }
let builder = DiscordMessageBuilder() do! DbService.updatePlayer <| { player with Actions = Array.append [| defense |] player.Actions }
builder.WithContent($"{event.User.Username} has protected their system!") |> ignore let builder = DiscordMessageBuilder()
let channel = event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle) builder.WithContent($"{event.User.Username} has protected their system!") |> ignore
do! channel.SendMessageAsync(builder) let channel = event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle)
|> Async.AwaitTask do! channel.SendMessageAsync(builder)
|> Async.Ignore |> Async.AwaitTask
| _ , false -> |> Async.Ignore
let builder = DiscordInteractionResponseBuilder() | _ , false ->
builder.IsEphemeral <- true let builder = DiscordFollowupMessageBuilder()
let timestamp = updatedDefenses |> Array.rev |> Array.head |> fun a -> a.Timestamp // This should be the next expiring timestamp
let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromHours(6)) timestamp
builder.Content <- $"You are only allowed two shields at a time. Wait {cooldown} minutes to add another shield"
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask
do! DbService.updatePlayer <| { player with Actions = updatedDefenses }
| true , _ ->
let builder = DiscordInteractionResponseBuilder()
builder.IsEphemeral <- true
let timestamp = updatedDefenses |> Array.find (fun d -> d.ActionId = int shield) |> fun a -> a.Timestamp
let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromHours(6)) timestamp
builder.Content <- $"{shield} shield is already in use. Wait {cooldown} minutes to use this shield again"
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask
do! DbService.updatePlayer <| { player with Actions = updatedDefenses }
| _ ->
let builder = DiscordInteractionResponseBuilder()
builder.IsEphemeral <- true builder.IsEphemeral <- true
builder.Content <- "Error parsing Button Id" let timestamp = updatedDefenses |> Array.rev |> Array.head |> fun a -> a.Timestamp // This should be the next expiring timestamp
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromHours(6)) timestamp
|> Async.AwaitTask builder.Content <- $"You are only allowed two shields at a time. Wait {cooldown} minutes to add another shield"
} do! event.Interaction.CreateFollowupMessageAsync(builder)
|> Async.AwaitTask
|> Async.Ignore
do! DbService.updatePlayer <| { player with Actions = updatedDefenses }
| true , _ ->
let builder = DiscordFollowupMessageBuilder()
builder.IsEphemeral <- true
let timestamp = updatedDefenses |> Array.find (fun d -> d.ActionId = int shieldId) |> fun a -> a.Timestamp
let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromHours(6)) timestamp
builder.Content <- $"{shieldId} shield is already in use. Wait {cooldown} minutes to use this shield again"
do! event.Interaction.CreateFollowupMessageAsync(builder)
|> Async.AwaitTask
|> Async.Ignore
do! DbService.updatePlayer <| { player with Actions = updatedDefenses }
})
let handleButtonEvent (_ : DiscordClient) (event : ComponentInteractionCreateEventArgs) = let handleButtonEvent (_ : DiscordClient) (event : ComponentInteractionCreateEventArgs) =
let task = match event.Id with
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 | id when id.StartsWith("Trainer") -> Trainer.handleButtonEvent event |> Async.StartAsTask :> Task
| id when id.StartsWith("Trainer") -> Trainer.handleButtonEvent event | _ ->
| _ -> task {
async { let builder = DiscordInteractionResponseBuilder()
let builder = DiscordInteractionResponseBuilder() builder.IsEphemeral <- true
builder.IsEphemeral <- true builder.Content <- $"Incorrect Action identifier {event.Id}"
builder.Content <- $"Incorrect Action identifier {event.Id}" do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) |> Async.AwaitTask
|> Async.AwaitTask }
}
async {
return! task
} |> Async.StartAsTask
:> Task
type HackerGame() = type HackerGame() =
inherit ApplicationCommandModule () inherit ApplicationCommandModule ()
@ -273,7 +250,6 @@ type HackerGame() =
member this.TestAutoComplete (ctx : InteractionContext) = member this.TestAutoComplete (ctx : InteractionContext) =
async { async {
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
// builder.WithContent("Not working")
builder.IsEphemeral <- true builder.IsEphemeral <- true
do! ctx.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) do! ctx.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask |> Async.AwaitTask

View File

@ -49,7 +49,7 @@
}, },
"Cost": 100, "Cost": 100,
"Power": 50, "Power": 50,
"Cooldown": 240 "Cooldown": 600
}, },
{ {
"Id": 7, "Id": 7,
@ -62,7 +62,7 @@
}, },
"Cost": 100, "Cost": 100,
"Power": 50, "Power": 50,
"Cooldown": 240 "Cooldown": 600
}, },
{ {
"Id": 8, "Id": 8,
@ -75,6 +75,6 @@
}, },
"Cost": 100, "Cost": 100,
"Power": 50, "Power": 50,
"Cooldown": 240 "Cooldown": 600
} }
] ]

View File

@ -25,11 +25,11 @@ let buyItem (ctx : InteractionContext) itemId =
if not playerHasItem then if not playerHasItem then
let p = { player with Bank = newBalance ; Arsenal = Array.append [| item |] player.Arsenal } let p = { player with Bank = newBalance ; Arsenal = Array.append [| item |] player.Arsenal }
do! DbService.updatePlayer p do! DbService.updatePlayer p
do! sendSimpleResponse ctx $"Successfully purchased {item.Name}! You now have {newBalance} remaining" do! sendFollowUpMessageFromCtx ctx $"Successfully purchased {item.Name}! You now have {newBalance} 💰$GBT remaining"
else else
do! sendSimpleResponse ctx $"You already own this item!" do! sendFollowUpMessageFromCtx ctx $"You already own this item!"
else else
do! sendSimpleResponse ctx $"You do not have sufficient funds to buy this item! Current balance: {player.Bank} GBT" do! sendFollowUpMessageFromCtx ctx $"You do not have sufficient funds to buy this item! Current balance: {player.Bank} GBT"
}) })
@ -37,7 +37,7 @@ let sell (ctx : InteractionContext) =
Game.executePlayerInteraction ctx (fun player -> async { Game.executePlayerInteraction ctx (fun player -> async {
let hasInventoryToSell = Array.length player.Arsenal > 0 let hasInventoryToSell = Array.length player.Arsenal > 0
if hasInventoryToSell then if hasInventoryToSell then
let builder = DiscordInteractionResponseBuilder() let builder = DiscordFollowupMessageBuilder()
builder.AddEmbed (constructEmbed "Pick the item you wish to sell.") |> ignore builder.AddEmbed (constructEmbed "Pick the item you wish to sell.") |> ignore
Array.chunkBySize 5 player.Arsenal Array.chunkBySize 5 player.Arsenal
@ -50,8 +50,9 @@ let sell (ctx : InteractionContext) =
|> ignore) |> ignore)
builder.AsEphemeral true |> ignore builder.AsEphemeral true |> ignore
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) do! ctx.FollowUpAsync(builder)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore
else else
do! sendSimpleResponse ctx "You currently have no inventory to sell" do! sendSimpleResponse ctx "You currently have no inventory to sell"
}) })
@ -65,11 +66,11 @@ let handleBuyItem (ctx : InteractionContext) itemId =
if not playerHasItem then if not playerHasItem then
let p = { player with Bank = newBalance ; Arsenal = Array.append [| item |] player.Arsenal } let p = { player with Bank = newBalance ; Arsenal = Array.append [| item |] player.Arsenal }
do! DbService.updatePlayer p do! DbService.updatePlayer p
do! sendSimpleResponse ctx $"Successfully purchased {item.Name}! You now have {newBalance} remaining" do! sendFollowUpMessageFromCtx ctx $"Successfully purchased {item.Name}! You now have {newBalance} 💰$GBT remaining"
else else
do! sendSimpleResponse ctx $"You already own this item!" do! sendFollowUpMessageFromCtx ctx $"You already own this item!"
else else
do! sendSimpleResponse ctx $"You do not have sufficient funds to buy this item! Current balance: {player.Bank} GBT" do! sendFollowUpMessageFromCtx ctx $"You do not have sufficient funds to buy this item! Current balance: {player.Bank} GBT"
}) })
let handleSellButtonEvents (_ : DiscordClient) (event : ComponentInteractionCreateEventArgs) = let handleSellButtonEvents (_ : DiscordClient) (event : ComponentInteractionCreateEventArgs) =
@ -78,23 +79,25 @@ let handleSellButtonEvents (_ : DiscordClient) (event : ComponentInteractionCrea
let item = Armory.getItem itemId let item = Armory.getItem itemId
let updatedPlayer = { player with Bank = player.Bank + item.Cost ; Arsenal = player.Arsenal |> Array.filter (fun w -> w.Id <> itemId)} let updatedPlayer = { player with Bank = player.Bank + item.Cost ; Arsenal = player.Arsenal |> Array.filter (fun w -> w.Id <> itemId)}
do! DbService.updatePlayer updatedPlayer do! DbService.updatePlayer updatedPlayer
let builder = DiscordInteractionResponseBuilder() let builder = DiscordFollowupMessageBuilder()
builder.IsEphemeral <- true builder.IsEphemeral <- true
builder.Content <- $"Sold {item.Type} {item.Name} for {item.Cost}! Current Balance: {updatedPlayer.Bank}" builder.Content <- $"Sold {item.Type} {item.Name} for {item.Cost}! Current Balance: {updatedPlayer.Bank}"
do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder) do! event.Interaction.CreateFollowupMessageAsync(builder)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore
}) })
let status (ctx : InteractionContext) = let status (ctx : InteractionContext) =
Game.executePlayerInteraction ctx (fun player -> async { Game.executePlayerInteraction ctx (fun player -> async {
let updatedPlayer = Player.removeExpiredActions player let updatedPlayer = Player.removeExpiredActions player
let builder = DiscordInteractionResponseBuilder() let builder = DiscordFollowupMessageBuilder()
let embed = DiscordEmbedBuilder() let embed = DiscordEmbedBuilder()
embed.AddField("Arsenal", Messaging.statusFormat updatedPlayer) |> ignore embed.AddField("Arsenal", Messaging.statusFormat updatedPlayer) |> ignore
builder.AddEmbed(embed) |> ignore builder.AddEmbed(embed) |> ignore
builder.IsEphemeral <- true builder.IsEphemeral <- true
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) do! ctx.FollowUpAsync(builder)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore
do! DbService.updatePlayer updatedPlayer do! DbService.updatePlayer updatedPlayer
}) })

View File

@ -30,14 +30,15 @@ let sendInitialEmbed (client : DiscordClient) =
let handleTrainerStep1 (event : ComponentInteractionCreateEventArgs) = let handleTrainerStep1 (event : ComponentInteractionCreateEventArgs) =
Game.executePlayerEvent event (fun player -> async { Game.executePlayerEvent event (fun player -> async {
let weaponName = Player.shields player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name
let shieldMessage = let shieldMessage , weaponName =
if Player.shields player |> Array.isEmpty if Player.shields player |> Array.isEmpty
then $"You do not have any Shields in your arsenal, take this {defaultShield.Name}, you can use it for now.\n\n" then $"You do not have any Shields in your arsenal, take this {defaultShield.Name}, you can use it for now.\n\n" , defaultShield.Name
else $"Looks like you have `{weaponName}` in your arsenal… 👀\n\n" else
let name = Player.shields player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name
$"Looks like you have `{name}` in your arsenal… 👀\n\n" , name
do! sendInteractionEvent event do! sendFollowUpMessage event
("Beautopia© is a dangerous place...\n" ("Beautopia© is a dangerous place...\n"
+ "Quick, put up a SHIELD 🛡 before another Degen hacks you, and steals your 💰$GBT.\n" + "Quick, put up a SHIELD 🛡 before another Degen hacks you, and steals your 💰$GBT.\n"
+ shieldMessage + shieldMessage
@ -51,10 +52,12 @@ let defend (ctx : InteractionContext) =
match player.Arsenal with match player.Arsenal with
| [||] -> { player with Arsenal = [| defaultShield |] } | [||] -> { player with Arsenal = [| defaultShield |] }
| _ -> player | _ -> player
let embed = Embeds.pickDefense "Trainer-2" playerWithShields let embed = Embeds.pickDefense "Trainer-2" playerWithShields
do! ctx.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed) do! ctx.FollowUpAsync(embed)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore
}) })
let handleDefenseMsg = { let handleDefenseMsg = {
@ -69,8 +72,6 @@ let handleDefenseMsg = {
let handleDefense (event : ComponentInteractionCreateEventArgs) = let handleDefense (event : ComponentInteractionCreateEventArgs) =
Game.executePlayerEvent event (fun player -> async { Game.executePlayerEvent event (fun player -> async {
let sendMessage' = sendFollowUpMessage event let sendMessage' = sendFollowUpMessage event
do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate)
|> Async.AwaitTask
let shield = Player.shields player |> Array.tryHead |> Option.defaultValue defaultShield let shield = Player.shields player |> Array.tryHead |> Option.defaultValue defaultShield
let embed = Embeds.responseCreatedShieldTrainer shield let embed = Embeds.responseCreatedShieldTrainer shield
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
@ -84,20 +85,19 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
let handleTrainerStep3 (event : ComponentInteractionCreateEventArgs) = let handleTrainerStep3 (event : ComponentInteractionCreateEventArgs) =
Game.executePlayerEvent event (fun player -> async { Game.executePlayerEvent event (fun player -> async {
let weaponName = Player.hacks player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name let hackMessage , weaponName =
do! updateMessageWithGreyedOutButtons event handleDefenseMsg
let hackMessage =
if Player.shields player |> Array.isEmpty if Player.shields player |> Array.isEmpty
then $"You do not have any Hacks in your arsenal, take this {defaultHack.Name}, you can use it for now.\n\n" then $"You do not have any Hacks in your arsenal, take this `{defaultHack.Name}`, you can use it for now.\n\n" , defaultHack.Name
else $"Looks like you have `{weaponName}` in your arsenal...\n\n" else
let name = Player.hacks player |> Array.tryHead |> Option.defaultValue defaultHack |> fun w -> w.Name
$"Looks like you have `{name}` in your arsenal...\n\n" , name
do! sendFollowUpMessage event do! sendFollowUpMessage event
("Now lets **HACK!** 💻\n\n" ("Now lets **HACK!** 💻\n\n"
+ "I want you to **HACK ME**, and try to steal my 💰$GBT...\n\n" + "I want you to **HACK ME**, and try to steal my 💰$GBT...\n\n"
+ hackMessage + hackMessage
+ "To deploy it, you need to run the `/hack` slash command.\n" + "To deploy it, you need to run the `/hack` slash command.\n"
+ $"Type the `/hack` command now, then choose me - <@{GuildEnvironment.botHackerBattle}> as your target, and select - `{weaponName}`") + $"Type the `/hack` command now, then choose me - <@{GuildEnvironment.botHackerBattle}> as your target, and select `{weaponName}`")
}) })
let attack (ctx : InteractionContext) (target : DiscordUser) = let attack (ctx : InteractionContext) (target : DiscordUser) =
@ -111,26 +111,26 @@ let attack (ctx : InteractionContext) (target : DiscordUser) =
| _ -> player | _ -> player
let embed = Embeds.pickHack "Trainer-4" playerWithAttacks player let embed = Embeds.pickHack "Trainer-4" playerWithAttacks player
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed) do! ctx.FollowUpAsync(embed)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore
| false -> | false ->
let builder = DiscordInteractionResponseBuilder() let builder = DiscordFollowupMessageBuilder()
builder.Content <- "You picked the wrong target, you dufus. Try again, this time pick me!" builder.Content <- "You picked the wrong target, you dufus. Try again, this time pick me!"
builder.IsEphemeral <- true builder.IsEphemeral <- true
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) do! ctx.FollowUpAsync(builder)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore
}) })
let handleAttack (event : ComponentInteractionCreateEventArgs) = let handleAttack (event : ComponentInteractionCreateEventArgs) =
Game.executePlayerEvent event (fun player -> async { Game.executePlayerEvent event (fun player -> async {
let sendMessage' = sendFollowUpMessage event let sendMessage' = sendFollowUpMessage event
do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate)
|> Async.AwaitTask
do! Async.Sleep 1000 do! Async.Sleep 1000
let hack = Player.hacks player |> Array.tryHead |> Option.defaultValue defaultHack let hack = Player.hacks player |> Array.tryHead |> Option.defaultValue defaultHack
let embed = Embeds.responseSuccessfulHackTrainer hack let embed = Embeds.responseSuccessfulHack hack
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
do! Async.Sleep 3000 do! Async.Sleep 3000
do! sendMessage' do! sendMessage'

View File

@ -137,17 +137,17 @@ module Messaging =
actions actions
|> Array.map (fun act -> |> Array.map (fun act ->
match act.Type with match act.Type with
| Attack atk -> $"Hacked {atk.Target} at {act.Timestamp.ToLongDateString()}" | Attack atk -> $"Hacked {atk.Target.Name} at {act.Timestamp.ToShortTimeString()}"
| Defense -> | Defense ->
let item = Armory.getItem act.ActionId let item = Armory.getItem act.ActionId
let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromMinutes(int item.Cooldown)) let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromMinutes(int item.Cooldown)) act.Timestamp
$"{item.Name} active for {cooldown}") $"{item.Name} active for {cooldown}")
|> String.concat "\n" |> String.concat "\n"
let statusFormat p = let statusFormat p =
$"**Hacks:** {Player.hacks p |> battleItemFormat}\n $"**Hacks:** {Player.hacks p |> battleItemFormat}\n
**Shields:** {Player.shields p |> battleItemFormat}\n **Shields:** {Player.shields p |> battleItemFormat}\n
**Hack Attacks:** {Player.attacks p |> actionFormat}\n **Hack Attacks:**\n{Player.attacks p |> actionFormat}\n
**Active Shields:** {Player.defenses p |> actionFormat}" **Active Shields:** {Player.defenses p |> actionFormat}"
let constructButtons (actionType: string) (playerInfo: string) (weapons: BattleItem array) = let constructButtons (actionType: string) (playerInfo: string) (weapons: BattleItem array) =
@ -173,6 +173,16 @@ module Messaging =
|> Async.Ignore |> Async.Ignore
} }
let sendFollowUpMessageFromCtx (ctx : InteractionContext) msg =
async {
let builder = DiscordFollowupMessageBuilder()
builder.IsEphemeral <- true
builder.Content <- msg
do! ctx.FollowUpAsync(builder)
|> Async.AwaitTask
|> Async.Ignore
}
let sendFollowUpMessageWithEmbed (event : ComponentInteractionCreateEventArgs) (embed : DiscordEmbed) msg = let sendFollowUpMessageWithEmbed (event : ComponentInteractionCreateEventArgs) (embed : DiscordEmbed) msg =
async { async {
let builder = let builder =
@ -206,7 +216,6 @@ module Messaging =
builder.Content <- interactiveMessage.Message builder.Content <- interactiveMessage.Message
do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder) do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore
} }
let sendInteractionEvent (event : ComponentInteractionCreateEventArgs) msg = let sendInteractionEvent (event : ComponentInteractionCreateEventArgs) msg =