Make most commands deferred/follow up so they don't fail. bug fixes
This commit is contained in:
parent
12ba17de30
commit
cd15a08e37
@ -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)
|
||||||
|
20
Bot/Game.fs
20
Bot/Game.fs
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
27
Bot/Store.fs
27
Bot/Store.fs
@ -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
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -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 let’s **HACK!** 💻\n\n"
|
("Now let’s **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'
|
||||||
|
@ -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 =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user