Create IDiscordContext abstraction to simplify code
This commit is contained in:
parent
d563303f90
commit
dd33492418
@ -1,7 +1,7 @@
|
|||||||
module Degenz.Embeds
|
module Degenz.Embeds
|
||||||
|
|
||||||
open System
|
open System
|
||||||
open DSharpPlus.EventArgs
|
open Degenz.Messaging
|
||||||
open Degenz.Types
|
open Degenz.Types
|
||||||
open DSharpPlus.Entities
|
open DSharpPlus.Entities
|
||||||
|
|
||||||
@ -96,9 +96,9 @@ let responseCreatedShield (shield : BattleItem) =
|
|||||||
.AddEmbed(embed)
|
.AddEmbed(embed)
|
||||||
.AsEphemeral(true)
|
.AsEphemeral(true)
|
||||||
|
|
||||||
let eventSuccessfulHack (event : ComponentInteractionCreateEventArgs) target prize =
|
let eventSuccessfulHack (ctx : IDiscordContext) target prize =
|
||||||
DiscordMessageBuilder()
|
DiscordMessageBuilder()
|
||||||
.WithContent($"{event.User.Username} successfully hacked <@{target.DiscordId}> for a total of {prize} GoodBoyTokenz")
|
.WithContent($"{ctx.GetDiscordMember().Username} successfully hacked <@{target.DiscordId}> for a total of {prize} GoodBoyTokenz")
|
||||||
|
|
||||||
let getBuyItemsEmbed (player : PlayerData) (itemType : ItemType) (store : BattleItem array) =
|
let getBuyItemsEmbed (player : PlayerData) (itemType : ItemType) (store : BattleItem array) =
|
||||||
let embeds , buttons =
|
let embeds , buttons =
|
||||||
@ -166,7 +166,7 @@ let getArsenalEmbed (player : PlayerData) =
|
|||||||
DiscordEmbedBuilder()
|
DiscordEmbedBuilder()
|
||||||
.AddField( "Arsenal", Arsenal.statusFormat player ))
|
.AddField( "Arsenal", Arsenal.statusFormat player ))
|
||||||
|
|
||||||
let getAchievementEmbed (player : PlayerData) description achievement =
|
let getAchievementEmbed description achievement =
|
||||||
let embed = DiscordEmbedBuilder()
|
let embed = DiscordEmbedBuilder()
|
||||||
|
|
||||||
GuildEnvironment.botUserHackerBattle
|
GuildEnvironment.botUserHackerBattle
|
||||||
|
28
Bot/Game.fs
28
Bot/Game.fs
@ -6,6 +6,7 @@ open DSharpPlus.Entities
|
|||||||
open DSharpPlus.EventArgs
|
open DSharpPlus.EventArgs
|
||||||
open DSharpPlus.SlashCommands
|
open DSharpPlus.SlashCommands
|
||||||
open Degenz.DbService
|
open Degenz.DbService
|
||||||
|
open Degenz.Messaging
|
||||||
|
|
||||||
module Game =
|
module Game =
|
||||||
let HackPrize = 10<GBT>
|
let HackPrize = 10<GBT>
|
||||||
@ -28,34 +29,17 @@ module Game =
|
|||||||
| BattleClass.Penetration -> ( ShieldId.Cypher , HackId.RemoteAccess )
|
| BattleClass.Penetration -> ( ShieldId.Cypher , HackId.RemoteAccess )
|
||||||
| BattleClass.Exploit -> ( ShieldId.Encryption , HackId.Worm )
|
| BattleClass.Exploit -> ( ShieldId.Encryption , HackId.Worm )
|
||||||
|
|
||||||
let executePlayerInteraction (ctx : InteractionContext) (dispatch : PlayerData -> Async<unit>) =
|
let executePlayerAction (ctx : IDiscordContext) (dispatch : PlayerData -> Async<unit>) =
|
||||||
async {
|
async {
|
||||||
let builder = DiscordInteractionResponseBuilder()
|
let builder = DiscordInteractionResponseBuilder()
|
||||||
builder.IsEphemeral <- true
|
builder.IsEphemeral <- true
|
||||||
builder.Content <- "Content"
|
builder.Content <- "Content"
|
||||||
do! ctx.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource, builder)
|
do! ctx.Respond InteractionResponseType.DeferredChannelMessageWithSource builder |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
let! playerResult = tryFindPlayer (ctx.GetDiscordMember().Id)
|
||||||
let! playerResult = tryFindPlayer ctx.Member.Id
|
|
||||||
match playerResult with
|
match playerResult with
|
||||||
| Some player -> do! dispatch player
|
| Some player -> do! dispatch player
|
||||||
| None -> do! Messaging.sendFollowUpMessageFromCtx ctx "You are currently not a hacker, first use the /redpill command to become one"
|
| None -> do! Messaging.sendSimpleResponse ctx "You are currently not a hacker, first use the /redpill command to become one"
|
||||||
} |> Async.StartAsTask
|
} |> Async.StartAsTask :> Task
|
||||||
:> Task
|
|
||||||
|
|
||||||
// TODO J: Create an abstraction for these two helper functions
|
|
||||||
let executePlayerEvent (event : ComponentInteractionCreateEventArgs) (dispatch : PlayerData -> Async<unit>) =
|
|
||||||
async {
|
|
||||||
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
|
|
||||||
| Some player -> do! dispatch player
|
|
||||||
| None -> do! Messaging.sendInteractionEvent event "You are currently not a hacker, first use the /redpill command to become one"
|
|
||||||
} |> Async.StartAsTask
|
|
||||||
:> Task
|
|
||||||
|
|
||||||
module Player =
|
module Player =
|
||||||
let getItems itemType (player : PlayerData) = player.Arsenal |> Array.filter (fun i -> i.Type = itemType)
|
let getItems itemType (player : PlayerData) = player.Arsenal |> Array.filter (fun i -> i.Type = itemType)
|
||||||
|
@ -90,39 +90,37 @@ let updateCombatants attacker defender hack prize =
|
|||||||
|> Async.Parallel
|
|> Async.Parallel
|
||||||
|> Async.Ignore
|
|> Async.Ignore
|
||||||
|
|
||||||
let successfulHack (event : ComponentInteractionCreateEventArgs) attacker defender hack =
|
let successfulHack (ctx : IDiscordContext) attacker defender hack =
|
||||||
async {
|
async {
|
||||||
do! updateCombatants attacker defender hack Game.HackPrize
|
do! updateCombatants attacker defender hack Game.HackPrize
|
||||||
|
|
||||||
let embed = Embeds.responseSuccessfulHack true defender.DiscordId (Armory.getItem hack)
|
let embed = Embeds.responseSuccessfulHack true defender.DiscordId (Armory.getItem hack)
|
||||||
do! event.Interaction.CreateFollowupMessageAsync(embed)
|
do! ctx.FollowUp embed |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
|> Async.Ignore
|
|
||||||
|
|
||||||
let builder = Embeds.eventSuccessfulHack event defender Game.HackPrize
|
let builder = Embeds.eventSuccessfulHack ctx defender Game.HackPrize
|
||||||
let channel = event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle)
|
let channel = ctx.GetGuild().GetChannel(GuildEnvironment.channelEventsHackerBattle)
|
||||||
do! channel.SendMessageAsync(builder)
|
do! channel.SendMessageAsync(builder)
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
|> Async.Ignore
|
|> Async.Ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
let failedHack (event : ComponentInteractionCreateEventArgs) attacker defender hack =
|
let failedHack (ctx : IDiscordContext) attacker defender hack =
|
||||||
async {
|
async {
|
||||||
let msg = $"Hack failed! {defender.Name} was able to mount a successful defense! You lost {Game.ShieldPrize} $GBT!"
|
let msg = $"Hack failed! {defender.Name} was able to mount a successful defense! You lost {Game.ShieldPrize} $GBT!"
|
||||||
do! sendFollowUpMessage event msg
|
do! sendFollowUpMessage ctx msg
|
||||||
|
|
||||||
do! updateCombatants attacker defender hack -Game.ShieldPrize
|
do! updateCombatants attacker defender hack -Game.ShieldPrize
|
||||||
|
|
||||||
let builder = DiscordMessageBuilder()
|
let builder = DiscordMessageBuilder()
|
||||||
builder.WithContent($"Hacking attempt failed! <@{defender.DiscordId}> defended hack from {event.User.Username} and stole {Game.ShieldPrize} $GBT from them! ") |> ignore
|
builder.WithContent($"Hacking attempt failed! <@{defender.DiscordId}> defended hack from {ctx.GetDiscordMember().Username} and stole {Game.ShieldPrize} $GBT from them! ") |> ignore
|
||||||
let channel = (event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle))
|
let channel = (ctx.GetGuild().GetChannel(GuildEnvironment.channelEventsHackerBattle))
|
||||||
do! channel.SendMessageAsync(builder)
|
do! channel.SendMessageAsync(builder)
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
|> Async.Ignore
|
|> Async.Ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
let attack (target : DiscordUser) (ctx : InteractionContext) =
|
let attack (target : DiscordUser) (ctx : IDiscordContext) =
|
||||||
Game.executePlayerInteraction ctx (fun attacker -> async {
|
Game.executePlayerAction ctx (fun attacker -> async {
|
||||||
let! defender = DbService.tryFindPlayer target.Id
|
let! defender = DbService.tryFindPlayer target.Id
|
||||||
match defender with
|
match defender with
|
||||||
| Some defender ->
|
| Some defender ->
|
||||||
@ -135,20 +133,18 @@ let attack (target : DiscordUser) (ctx : InteractionContext) =
|
|||||||
|> function
|
|> function
|
||||||
| Ok atkr ->
|
| Ok atkr ->
|
||||||
let embed = Embeds.pickHack "Attack" atkr defender false
|
let embed = Embeds.pickHack "Attack" atkr defender false
|
||||||
ctx.FollowUpAsync(embed)
|
ctx.FollowUp(embed) |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
| Error msg -> sendFollowUpMessage ctx msg
|
||||||
|> Async.Ignore
|
|
||||||
| Error msg -> sendFollowUpMessageFromCtx ctx msg
|
|
||||||
| None ->
|
| None ->
|
||||||
if target.IsBot
|
if target.IsBot
|
||||||
then do! sendFollowUpMessageFromCtx ctx $"{target.Username} is a bot, pick a real human to hack"
|
then do! sendFollowUpMessage ctx $"{target.Username} is a bot, pick a real human to hack"
|
||||||
else do! sendFollowUpMessageFromCtx ctx "Your target is not connected to the network, they must join first by using the /redpill command"
|
else do! sendFollowUpMessage ctx "Your target is not connected to the network, they must join first by using the /redpill command"
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
let handleAttack (event : ComponentInteractionCreateEventArgs) =
|
let handleAttack (ctx : IDiscordContext) =
|
||||||
Game.executePlayerEvent event (fun attacker -> async {
|
Game.executePlayerAction ctx (fun attacker -> async {
|
||||||
let split = event.Id.Split("-")
|
let split = ctx.GetInteractionId().Split("-")
|
||||||
let hackId = int split.[1]
|
let hackId = int split.[1]
|
||||||
let hack = enum<HackId>(hackId)
|
let hack = enum<HackId>(hackId)
|
||||||
let ( resultId , targetId ) = UInt64.TryParse split.[2]
|
let ( resultId , targetId ) = UInt64.TryParse split.[2]
|
||||||
@ -165,28 +161,26 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
|
|||||||
| Ok atkr ->
|
| Ok atkr ->
|
||||||
runHackerBattle defender (Armory.getItem (int hackId))
|
runHackerBattle defender (Armory.getItem (int hackId))
|
||||||
|> function
|
|> function
|
||||||
| false -> successfulHack event atkr defender hackId
|
| false -> successfulHack ctx atkr defender hackId
|
||||||
| true -> failedHack event attacker defender hackId
|
| true -> failedHack ctx attacker defender hackId
|
||||||
| Error msg -> Messaging.sendFollowUpMessage event msg
|
| Error msg -> Messaging.sendFollowUpMessage ctx msg
|
||||||
| _ -> do! Messaging.sendFollowUpMessage event "Error occurred processing attack"
|
| _ -> do! Messaging.sendFollowUpMessage ctx "Error occurred processing attack"
|
||||||
})
|
})
|
||||||
|
|
||||||
let defend (ctx : InteractionContext) =
|
let defend (ctx : IDiscordContext) =
|
||||||
Game.executePlayerInteraction ctx (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
if Player.getShields player |> Array.length > 0 then
|
if Player.getShields player |> Array.length > 0 then
|
||||||
let p = Player.removeExpiredActions false player
|
let p = Player.removeExpiredActions false player
|
||||||
let embed = Embeds.pickDefense "Defend" p false
|
let embed = Embeds.pickDefense "Defend" p false
|
||||||
do! ctx.FollowUpAsync(embed)
|
do! ctx.FollowUp embed |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
|> Async.Ignore
|
|
||||||
else
|
else
|
||||||
let msg = $"You currently do not have any Shields to protect yourself from hacks. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one."
|
let msg = $"You currently do not have any Shields to protect yourself from hacks. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one."
|
||||||
do! Messaging.sendFollowUpMessageFromCtx ctx msg
|
do! Messaging.sendFollowUpMessage ctx msg
|
||||||
})
|
})
|
||||||
|
|
||||||
let handleDefense (event : ComponentInteractionCreateEventArgs) =
|
let handleDefense (ctx : IDiscordContext) =
|
||||||
Game.executePlayerEvent event (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
let split = event.Id.Split("-")
|
let split = ctx.GetInteractionId().Split("-")
|
||||||
let shieldId = int split.[1]
|
let shieldId = int split.[1]
|
||||||
let shield = Armory.getItem shieldId
|
let shield = Armory.getItem shieldId
|
||||||
|
|
||||||
@ -194,16 +188,14 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
|
|||||||
|> checkPlayerOwnsWeapon shieldId
|
|> checkPlayerOwnsWeapon shieldId
|
||||||
>>= checkPlayerHasShieldSlotsAvailable shield
|
>>= checkPlayerHasShieldSlotsAvailable shield
|
||||||
>>= checkItemHasCooldown shieldId
|
>>= checkItemHasCooldown shieldId
|
||||||
|> handleResultWithResponseFromEvent event (fun p -> async {
|
|> handleResultWithResponseFromEvent ctx (fun p -> async {
|
||||||
let embed = Embeds.responseCreatedShield (Armory.getItem shieldId)
|
let embed = Embeds.responseCreatedShield (Armory.getItem shieldId)
|
||||||
do! event.Interaction.CreateFollowupMessageAsync(embed)
|
do! ctx.FollowUp embed |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
|> Async.Ignore
|
|
||||||
let defense = { ActionId = shieldId ; Type = Defense ; Timestamp = DateTime.UtcNow }
|
let defense = { ActionId = shieldId ; Type = Defense ; Timestamp = DateTime.UtcNow }
|
||||||
do! DbService.updatePlayer <| { player with Actions = Array.append [| defense |] player.Actions }
|
do! DbService.updatePlayer <| { player with Actions = Array.append [| defense |] player.Actions }
|
||||||
let builder = DiscordMessageBuilder()
|
let builder = DiscordMessageBuilder()
|
||||||
builder.WithContent($"{event.User.Username} has protected their system!") |> ignore
|
builder.WithContent($"{ctx.GetDiscordMember().Username} has protected their system!") |> ignore
|
||||||
let channel = event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle)
|
let channel = ctx.GetGuild().GetChannel(GuildEnvironment.channelEventsHackerBattle)
|
||||||
do! channel.SendMessageAsync(builder)
|
do! channel.SendMessageAsync(builder)
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
|> Async.Ignore
|
|> Async.Ignore
|
||||||
@ -211,40 +203,38 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
|
|||||||
})
|
})
|
||||||
|
|
||||||
let handleButtonEvent (_ : DiscordClient) (event : ComponentInteractionCreateEventArgs) =
|
let handleButtonEvent (_ : DiscordClient) (event : ComponentInteractionCreateEventArgs) =
|
||||||
|
let eventCtx = DiscordEventContext event :> IDiscordContext
|
||||||
match event.Id with
|
match event.Id with
|
||||||
| id when id.StartsWith("Attack") -> handleAttack event
|
| id when id.StartsWith("Attack") -> handleAttack eventCtx
|
||||||
| id when id.StartsWith("Defend") -> handleDefense event
|
| id when id.StartsWith("Defend") -> handleDefense eventCtx
|
||||||
| id when id.StartsWith("Trainer") -> Trainer.handleButtonEvent event |> Async.StartAsTask :> Task
|
| id when id.StartsWith("Trainer") -> Trainer.handleButtonEvent eventCtx |> Async.StartAsTask :> Task
|
||||||
| _ ->
|
| _ ->
|
||||||
task {
|
task {
|
||||||
let builder = DiscordInteractionResponseBuilder()
|
let builder = DiscordInteractionResponseBuilder()
|
||||||
builder.IsEphemeral <- true
|
builder.IsEphemeral <- true
|
||||||
builder.Content <- $"Incorrect Action identifier {event.Id}"
|
builder.Content <- $"Incorrect Action identifier {eventCtx.GetInteractionId()}"
|
||||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
do! eventCtx.Respond InteractionResponseType.ChannelMessageWithSource builder |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let arsenal (ctx : InteractionContext) =
|
let arsenal (ctx : IDiscordContext) =
|
||||||
Game.executePlayerInteraction ctx (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
let updatedPlayer = Player.removeExpiredActions false player
|
let updatedPlayer = Player.removeExpiredActions false player
|
||||||
let builder = DiscordFollowupMessageBuilder()
|
let builder = DiscordFollowupMessageBuilder()
|
||||||
let embed = DiscordEmbedBuilder()
|
let embed = DiscordEmbedBuilder()
|
||||||
embed.AddField("Arsenal", Arsenal.statusFormat updatedPlayer) |> ignore
|
embed.AddField("Arsenal", Arsenal.statusFormat updatedPlayer) |> ignore
|
||||||
builder.AddEmbed(embed) |> ignore
|
builder.AddEmbed(embed) |> ignore
|
||||||
builder.IsEphemeral <- true
|
builder.IsEphemeral <- true
|
||||||
do! ctx.FollowUpAsync(builder)
|
do! ctx.FollowUp(builder) |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
|> Async.Ignore
|
|
||||||
do! DbService.updatePlayer updatedPlayer
|
do! DbService.updatePlayer updatedPlayer
|
||||||
})
|
})
|
||||||
|
|
||||||
type HackerGame() =
|
type HackerGame() =
|
||||||
inherit ApplicationCommandModule ()
|
inherit ApplicationCommandModule ()
|
||||||
|
|
||||||
let enforceChannels (ctx : InteractionContext) (trainerFn : InteractionContext -> Task) (battleFn : InteractionContext -> Task) =
|
let enforceChannels (ctx : IDiscordContext) (trainerFn : IDiscordContext -> Task) (battleFn : IDiscordContext -> Task) =
|
||||||
match ctx.Channel.Id with
|
match ctx.GetChannel().Id with
|
||||||
| id when id = GuildEnvironment.channelTraining ->
|
| id when id = GuildEnvironment.channelTraining ->
|
||||||
let hasTraineeRole = Seq.exists (fun (r : DiscordRole) -> r.Id = GuildEnvironment.roleTrainee) ctx.Member.Roles
|
let hasTraineeRole = Seq.exists (fun (r : DiscordRole) -> r.Id = GuildEnvironment.roleTrainee) (ctx.GetDiscordMember().Roles)
|
||||||
if hasTraineeRole then
|
if hasTraineeRole then
|
||||||
trainerFn ctx
|
trainerFn ctx
|
||||||
else
|
else
|
||||||
@ -263,15 +253,15 @@ type HackerGame() =
|
|||||||
|
|
||||||
[<SlashCommand("arsenal", "Get the Hacks and Shields you own, and which ones are active")>]
|
[<SlashCommand("arsenal", "Get the Hacks and Shields you own, and which ones are active")>]
|
||||||
member this.Arsenal (ctx : InteractionContext) =
|
member this.Arsenal (ctx : InteractionContext) =
|
||||||
enforceChannels ctx (Trainer.handleArsenal) arsenal
|
enforceChannels (DiscordInteractionContext ctx) (Trainer.handleArsenal) arsenal
|
||||||
|
|
||||||
[<SlashCommand("hack", "Send a hack attack to another player")>]
|
[<SlashCommand("hack", "Send a hack attack to another player")>]
|
||||||
member this.AttackCommand (ctx : InteractionContext, [<Option("target", "The player you want to hack")>] target : DiscordUser) =
|
member this.AttackCommand (ctx : InteractionContext, [<Option("target", "The player you want to hack")>] target : DiscordUser) =
|
||||||
enforceChannels ctx (Trainer.attack target) (attack target)
|
enforceChannels (DiscordInteractionContext ctx) (Trainer.attack target) (attack target)
|
||||||
|
|
||||||
[<SlashCommand("shield", "Create a passive shield that will protect you for a certain time")>]
|
[<SlashCommand("shield", "Create a passive shield that will protect you for a certain time")>]
|
||||||
member this.ShieldCommand (ctx : InteractionContext) =
|
member this.ShieldCommand (ctx : InteractionContext) =
|
||||||
enforceChannels ctx Trainer.defend defend
|
enforceChannels (DiscordInteractionContext ctx) Trainer.defend defend
|
||||||
|
|
||||||
// [<SlashCommand("test-autocomplete", "Create a passive defense that will last 24 hours")>]
|
// [<SlashCommand("test-autocomplete", "Create a passive defense that will last 24 hours")>]
|
||||||
member this.TestAutoComplete (ctx : InteractionContext) =
|
member this.TestAutoComplete (ctx : InteractionContext) =
|
||||||
|
@ -5,6 +5,7 @@ open System.Threading.Tasks
|
|||||||
open DSharpPlus
|
open DSharpPlus
|
||||||
open DSharpPlus.Entities
|
open DSharpPlus.Entities
|
||||||
open DSharpPlus.SlashCommands
|
open DSharpPlus.SlashCommands
|
||||||
|
open Degenz.Messaging
|
||||||
open Degenz.Types
|
open Degenz.Types
|
||||||
|
|
||||||
let slots = [| "https://i.ibb.co/pKqZdr7/cherry.png" ; "https://i.ibb.co/JnghQsL/lemon.jpg" ; "https://i.ibb.co/1JTFPSs/seven.png" |]
|
let slots = [| "https://i.ibb.co/pKqZdr7/cherry.png" ; "https://i.ibb.co/JnghQsL/lemon.jpg" ; "https://i.ibb.co/1JTFPSs/seven.png" |]
|
||||||
@ -14,7 +15,7 @@ type SlotMachine() =
|
|||||||
|
|
||||||
[<SlashCommand("spin", "Want to try your luck?")>]
|
[<SlashCommand("spin", "Want to try your luck?")>]
|
||||||
member this.Spin (ctx : InteractionContext) =
|
member this.Spin (ctx : InteractionContext) =
|
||||||
Game.executePlayerInteraction ctx (fun player -> async {
|
Game.executePlayerAction (DiscordInteractionContext ctx) (fun player -> async {
|
||||||
let sleepTime = 1000
|
let sleepTime = 1000
|
||||||
let random = Random(System.Guid.NewGuid().GetHashCode())
|
let random = Random(System.Guid.NewGuid().GetHashCode())
|
||||||
let results = [ random.Next(0, 3) ; random.Next(0, 3) ; random.Next(0, 3)]
|
let results = [ random.Next(0, 3) ; random.Next(0, 3) ; random.Next(0, 3)]
|
||||||
|
66
Bot/Store.fs
66
Bot/Store.fs
@ -6,7 +6,6 @@ open DSharpPlus
|
|||||||
open DSharpPlus.EventArgs
|
open DSharpPlus.EventArgs
|
||||||
open DSharpPlus.SlashCommands
|
open DSharpPlus.SlashCommands
|
||||||
open Degenz
|
open Degenz
|
||||||
open Degenz.Embeds
|
|
||||||
open Degenz.Messaging
|
open Degenz.Messaging
|
||||||
|
|
||||||
let checkHasSufficientFunds (item : BattleItem) player =
|
let checkHasSufficientFunds (item : BattleItem) player =
|
||||||
@ -29,47 +28,41 @@ let checkHasItemsInArsenal itemType player =
|
|||||||
then Ok player
|
then Ok player
|
||||||
else Error $"You currently have no {itemType}s in your arsenal to sell!"
|
else Error $"You currently have no {itemType}s in your arsenal to sell!"
|
||||||
|
|
||||||
let buy itemType (ctx : InteractionContext) =
|
let buy itemType (ctx : IDiscordContext) =
|
||||||
Game.executePlayerInteraction ctx (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
let itemStore = Embeds.getBuyItemsEmbed player itemType Armory.battleItems
|
let itemStore = Embeds.getBuyItemsEmbed player itemType Armory.battleItems
|
||||||
do! ctx.Interaction.CreateFollowupMessageAsync(itemStore)
|
do! ctx.FollowUp itemStore |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
|> Async.Ignore
|
|
||||||
})
|
})
|
||||||
|
|
||||||
let sell itemType (ctx : InteractionContext) =
|
let sell itemType (ctx : IDiscordContext) =
|
||||||
Game.executePlayerInteraction ctx (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
match checkHasItemsInArsenal itemType player with
|
match checkHasItemsInArsenal itemType player with
|
||||||
| Ok _ ->
|
| Ok _ -> let itemStore = Embeds.getSellItemsEmbed itemType player
|
||||||
let itemStore = Embeds.getSellItemsEmbed itemType player
|
do! ctx.FollowUp(itemStore) |> Async.AwaitTask
|
||||||
|
| Error e -> do! sendFollowUpMessage ctx e
|
||||||
do! ctx.FollowUpAsync(itemStore)
|
|
||||||
|> Async.AwaitTask
|
|
||||||
|> Async.Ignore
|
|
||||||
| Error e -> do! sendFollowUpMessageFromCtx ctx e
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: When you buy a shield, prompt the user to activate it
|
// TODO: When you buy a shield, prompt the user to activate it
|
||||||
let handleBuyItem (event : ComponentInteractionCreateEventArgs) itemId =
|
let handleBuyItem (ctx : IDiscordContext) itemId =
|
||||||
Game.executePlayerEvent event (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
let item = Armory.battleItems |> Array.find (fun w -> w.Id = itemId)
|
let item = Armory.battleItems |> Array.find (fun w -> w.Id = itemId)
|
||||||
do! player
|
do! player
|
||||||
|> checkHasSufficientFunds item
|
|> checkHasSufficientFunds item
|
||||||
>>= checkAlreadyOwnsItem item
|
>>= checkAlreadyOwnsItem item
|
||||||
|> handleResultWithResponseFromEvent event (fun player -> async {
|
|> handleResultWithResponseFromEvent ctx (fun player -> async {
|
||||||
let newBalance = player.Bank - item.Cost
|
let newBalance = player.Bank - item.Cost
|
||||||
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! sendFollowUpMessage event $"Successfully purchased {item.Name}! You now have {newBalance} 💰$GBT remaining"
|
do! sendFollowUpMessage ctx $"Successfully purchased {item.Name}! You now have {newBalance} 💰$GBT remaining"
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
let handleSell (event : ComponentInteractionCreateEventArgs) itemId =
|
let handleSell (ctx : IDiscordContext) itemId =
|
||||||
Game.executePlayerEvent event (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
let item = Armory.getItem itemId
|
let item = Armory.getItem itemId
|
||||||
do! player
|
do! player
|
||||||
|> checkSoldItemAlready item
|
|> checkSoldItemAlready item
|
||||||
|> handleResultWithResponseFromEvent event (fun player -> async {
|
|> handleResultWithResponseFromEvent ctx (fun player -> async {
|
||||||
let updatedPlayer = {
|
let updatedPlayer = {
|
||||||
player with
|
player with
|
||||||
Bank = player.Bank + item.Cost
|
Bank = player.Bank + item.Cost
|
||||||
@ -80,29 +73,30 @@ let handleSell (event : ComponentInteractionCreateEventArgs) itemId =
|
|||||||
else player.Actions
|
else player.Actions
|
||||||
}
|
}
|
||||||
do! DbService.updatePlayer updatedPlayer
|
do! DbService.updatePlayer updatedPlayer
|
||||||
do! sendFollowUpMessage event $"Sold {item.Type} {item.Name} for {item.Cost}! Current Balance: {updatedPlayer.Bank}"
|
do! sendFollowUpMessage ctx $"Sold {item.Type} {item.Name} for {item.Cost}! Current Balance: {updatedPlayer.Bank}"
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
let handleStoreEvents (_ : DiscordClient) (event : ComponentInteractionCreateEventArgs) =
|
let handleStoreEvents (_ : DiscordClient) (event : ComponentInteractionCreateEventArgs) =
|
||||||
let itemId = int <| event.Id.Split("-").[1]
|
let ctx = DiscordEventContext event :> IDiscordContext
|
||||||
match event.Id with
|
let id = ctx.GetInteractionId()
|
||||||
| id when id.StartsWith("Buy") -> handleBuyItem event itemId
|
let itemId = int <| id.Split("-").[1]
|
||||||
| id when id.StartsWith("Sell") -> handleSell event itemId
|
match id with
|
||||||
|
| id when id.StartsWith("Buy") -> handleBuyItem ctx itemId
|
||||||
|
| id when id.StartsWith("Sell") -> handleSell ctx itemId
|
||||||
| _ ->
|
| _ ->
|
||||||
task {
|
task {
|
||||||
let builder = DiscordInteractionResponseBuilder()
|
let builder = DiscordInteractionResponseBuilder()
|
||||||
builder.IsEphemeral <- true
|
builder.IsEphemeral <- true
|
||||||
builder.Content <- $"Incorrect Action identifier {event.Id}"
|
builder.Content <- $"Incorrect Action identifier {id}"
|
||||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
do! ctx.Respond InteractionResponseType.ChannelMessageWithSource builder |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Store() =
|
type Store() =
|
||||||
inherit ApplicationCommandModule ()
|
inherit ApplicationCommandModule ()
|
||||||
|
|
||||||
let enforceChannel (ctx : InteractionContext) (storeFn : InteractionContext -> Task) =
|
let enforceChannel (ctx : IDiscordContext) (storeFn : IDiscordContext -> Task) =
|
||||||
match ctx.Channel.Id with
|
match ctx.GetChannel().Id with
|
||||||
| id when id = GuildEnvironment.channelArmory -> storeFn ctx
|
| id when id = GuildEnvironment.channelArmory -> storeFn ctx
|
||||||
| _ ->
|
| _ ->
|
||||||
task {
|
task {
|
||||||
@ -111,14 +105,14 @@ type Store() =
|
|||||||
}
|
}
|
||||||
|
|
||||||
[<SlashCommand("buy-hack", "Purchase a hack attack you can use to earn GoodBoyTokenz")>]
|
[<SlashCommand("buy-hack", "Purchase a hack attack you can use to earn GoodBoyTokenz")>]
|
||||||
member _.BuyHack (ctx : InteractionContext) = enforceChannel ctx (buy ItemType.Hack)
|
member _.BuyHack (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (buy ItemType.Hack)
|
||||||
|
|
||||||
[<SlashCommand("buy-shield", "Purchase a hack shield so you can protect your GoodBoyTokenz")>]
|
[<SlashCommand("buy-shield", "Purchase a hack shield so you can protect your GoodBoyTokenz")>]
|
||||||
member this.BuyShield (ctx : InteractionContext) = enforceChannel ctx (buy ItemType.Shield)
|
member this.BuyShield (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (buy ItemType.Shield)
|
||||||
|
|
||||||
[<SlashCommand("sell-hack", "Sell a hack for GoodBoyTokenz")>]
|
[<SlashCommand("sell-hack", "Sell a hack for GoodBoyTokenz")>]
|
||||||
member this.SellHack (ctx : InteractionContext) = enforceChannel ctx (sell ItemType.Hack)
|
member this.SellHack (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (sell ItemType.Hack)
|
||||||
|
|
||||||
[<SlashCommand("sell-shield", "Sell a shield for GoodBoyTokenz")>]
|
[<SlashCommand("sell-shield", "Sell a shield for GoodBoyTokenz")>]
|
||||||
member this.SellShield (ctx : InteractionContext) = enforceChannel ctx (sell ItemType.Shield)
|
member this.SellShield (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (sell ItemType.Shield)
|
||||||
|
|
||||||
|
104
Bot/Trainer.fs
104
Bot/Trainer.fs
@ -4,7 +4,6 @@ open System.Text
|
|||||||
open DSharpPlus
|
open DSharpPlus
|
||||||
open DSharpPlus.Entities
|
open DSharpPlus.Entities
|
||||||
open DSharpPlus.EventArgs
|
open DSharpPlus.EventArgs
|
||||||
open DSharpPlus.SlashCommands
|
|
||||||
open Degenz.Types
|
open Degenz.Types
|
||||||
open Degenz.Messaging
|
open Degenz.Messaging
|
||||||
|
|
||||||
@ -30,8 +29,8 @@ let sendInitialEmbed (client : DiscordClient) =
|
|||||||
|> Async.Ignore
|
|> Async.Ignore
|
||||||
} |> Async.RunSynchronously
|
} |> Async.RunSynchronously
|
||||||
|
|
||||||
let handleTrainerStep1 (event : ComponentInteractionCreateEventArgs) =
|
let handleTrainerStep1 (ctx : IDiscordContext) =
|
||||||
Game.executePlayerEvent event (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
let shieldMessage , weaponName =
|
let shieldMessage , weaponName =
|
||||||
if Player.getShields player |> Array.isEmpty
|
if Player.getShields player |> Array.isEmpty
|
||||||
then $"You do not have any Shields in your arsenal, take the `{defaultShield.Name}` shield, you can use it for now.\n\n" , defaultShield.Name
|
then $"You do not have any Shields in your arsenal, take the `{defaultShield.Name}` shield, you can use it for now.\n\n" , defaultShield.Name
|
||||||
@ -39,20 +38,19 @@ let handleTrainerStep1 (event : ComponentInteractionCreateEventArgs) =
|
|||||||
let name = Player.getShields player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name
|
let name = Player.getShields player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name
|
||||||
$"Looks like you have `{name}` in your arsenal… 👀\n\n" , name
|
$"Looks like you have `{name}` in your arsenal… 👀\n\n" , name
|
||||||
|
|
||||||
let membr = event.User :?> DiscordMember
|
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee)
|
||||||
let role = event.Guild.GetRole(GuildEnvironment.roleTrainee)
|
do! ctx.GetDiscordMember().GrantRoleAsync(role)
|
||||||
do! membr.GrantRoleAsync(role)
|
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
|
|
||||||
do! sendFollowUpMessage event
|
do! sendFollowUpMessage ctx
|
||||||
("Beautopia© is a dangerous place... quick, put up a SHIELD 🛡 before another Degen hacks you, and steals your 💰$GBT.\n\n"
|
("Beautopia© is a dangerous place... quick, put up a SHIELD 🛡 before another Degen hacks you, and steals your 💰$GBT.\n\n"
|
||||||
+ shieldMessage
|
+ shieldMessage
|
||||||
+ "To enable it, you need to run the `/shield` slash command.\n\n"
|
+ "To enable it, you need to run the `/shield` slash command.\n\n"
|
||||||
+ $"Type the `/shield` command now, then select - `{weaponName}`\n")
|
+ $"Type the `/shield` command now, then select - `{weaponName}`\n")
|
||||||
})
|
})
|
||||||
|
|
||||||
let defend (ctx : InteractionContext) =
|
let defend (ctx : IDiscordContext) =
|
||||||
Game.executePlayerInteraction ctx (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
let playerWithShields =
|
let playerWithShields =
|
||||||
match Player.getShields player with
|
match Player.getShields player with
|
||||||
| [||] -> { player with Arsenal = [| defaultShield |] }
|
| [||] -> { player with Arsenal = [| defaultShield |] }
|
||||||
@ -60,9 +58,7 @@ let defend (ctx : InteractionContext) =
|
|||||||
|
|
||||||
let embed = Embeds.pickDefense "Trainer-2" playerWithShields true
|
let embed = Embeds.pickDefense "Trainer-2" playerWithShields true
|
||||||
|
|
||||||
do! ctx.FollowUpAsync(embed)
|
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
|> Async.Ignore
|
|
||||||
})
|
})
|
||||||
|
|
||||||
let handleDefenseMsg shieldId hackId = {
|
let handleDefenseMsg shieldId hackId = {
|
||||||
@ -73,25 +69,25 @@ let handleDefenseMsg shieldId hackId = {
|
|||||||
+ "Shields only protect you for a LIMITED TIME, so remember to keep them mounted at all times, or risk getting hacked!"
|
+ "Shields only protect you for a LIMITED TIME, so remember to keep them mounted at all times, or risk getting hacked!"
|
||||||
}
|
}
|
||||||
|
|
||||||
let handleDefense (event : ComponentInteractionCreateEventArgs) =
|
let handleDefense (ctx : IDiscordContext) =
|
||||||
Game.executePlayerEvent event (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
let sendMessage' = sendFollowUpMessage event
|
let sendMessage' = sendFollowUpMessage ctx
|
||||||
let split = event.Id.Split("-")
|
let split = ctx.GetInteractionId().Split("-")
|
||||||
let shieldId = enum<ShieldId>(int split.[2])
|
let shieldId = enum<ShieldId>(int split.[2])
|
||||||
let shield = Armory.getItem (int shieldId)
|
let shield = Armory.getItem (int shieldId)
|
||||||
let embed = Embeds.responseCreatedShield (shield)
|
let embed = Embeds.responseCreatedShield shield
|
||||||
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
|
do! ctx.FollowUp embed |> Async.AwaitTask
|
||||||
do! Async.Sleep 4000
|
do! Async.Sleep 4000
|
||||||
let weakHack = Game.getGoodAgainst shield.Class
|
let weakHack = Game.getGoodAgainst shield.Class
|
||||||
do! sendMessage' $"Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now with **{snd weakHack}**"
|
do! sendMessage' $"Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now with **{snd weakHack}**"
|
||||||
do! Async.Sleep 5000
|
do! Async.Sleep 5000
|
||||||
do! sendMessage' $"❌ HACKING FAILED!\n\n{player.Name} defended hack from <@{GuildEnvironment.botIdHackerBattle}>!"
|
do! sendMessage' $"❌ HACKING FAILED!\n\n{player.Name} defended hack from <@{GuildEnvironment.botIdHackerBattle}>!"
|
||||||
do! Async.Sleep 4000
|
do! Async.Sleep 4000
|
||||||
do! sendFollowUpMessageWithButton event (handleDefenseMsg shieldId (snd weakHack))
|
do! sendFollowUpMessageWithButton ctx (handleDefenseMsg shieldId (snd weakHack))
|
||||||
|
|
||||||
})
|
})
|
||||||
let handleTrainerStep3 (event : ComponentInteractionCreateEventArgs) =
|
let handleTrainerStep3 (ctx : IDiscordContext) =
|
||||||
Game.executePlayerEvent event (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
let hackMessage , weaponName =
|
let hackMessage , weaponName =
|
||||||
if Player.getHacks player |> Array.isEmpty
|
if Player.getHacks 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" , defaultHack.Name
|
then $"You do not have any Hacks in your arsenal, take this `{defaultHack.Name}`, you can use it for now.\n\n" , defaultHack.Name
|
||||||
@ -99,7 +95,7 @@ let handleTrainerStep3 (event : ComponentInteractionCreateEventArgs) =
|
|||||||
let name = Player.getHacks player |> Array.tryHead |> Option.defaultValue defaultHack |> fun w -> w.Name
|
let name = Player.getHacks player |> Array.tryHead |> Option.defaultValue defaultHack |> fun w -> w.Name
|
||||||
$"Looks like you have `{name}` in your arsenal...\n\n" , name
|
$"Looks like you have `{name}` in your arsenal...\n\n" , name
|
||||||
|
|
||||||
do! sendFollowUpMessage event
|
do! sendFollowUpMessage ctx
|
||||||
("Now let’s **HACK!** 💻\n\n"
|
("Now let’s **HACK!** 💻\n\n"
|
||||||
+ "I want you to **HACK ME**...\n\n"
|
+ "I want you to **HACK ME**...\n\n"
|
||||||
+ hackMessage
|
+ hackMessage
|
||||||
@ -107,8 +103,8 @@ let handleTrainerStep3 (event : ComponentInteractionCreateEventArgs) =
|
|||||||
+ $"Type the `/hack` command now, then choose me - <@{GuildEnvironment.botIdHackerBattle}> as your target, and select `{weaponName}`")
|
+ $"Type the `/hack` command now, then choose me - <@{GuildEnvironment.botIdHackerBattle}> as your target, and select `{weaponName}`")
|
||||||
})
|
})
|
||||||
|
|
||||||
let attack (target : DiscordUser) (ctx : InteractionContext) =
|
let attack (target : DiscordUser) (ctx : IDiscordContext) =
|
||||||
Game.executePlayerInteraction ctx (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
let isRightTarget = target.Id = GuildEnvironment.botIdHackerBattle
|
let isRightTarget = target.Id = GuildEnvironment.botIdHackerBattle
|
||||||
match isRightTarget with
|
match isRightTarget with
|
||||||
| true ->
|
| true ->
|
||||||
@ -119,27 +115,23 @@ let attack (target : DiscordUser) (ctx : InteractionContext) =
|
|||||||
let bot = { player with DiscordId = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" }
|
let bot = { player with DiscordId = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" }
|
||||||
let embed = Embeds.pickHack "Trainer-4" playerWithAttacks bot true
|
let embed = Embeds.pickHack "Trainer-4" playerWithAttacks bot true
|
||||||
|
|
||||||
do! ctx.FollowUpAsync(embed)
|
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
|> Async.Ignore
|
|
||||||
| false ->
|
| false ->
|
||||||
let builder = DiscordFollowupMessageBuilder()
|
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.FollowUpAsync(builder)
|
do! ctx.FollowUp(builder) |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
|> Async.Ignore
|
|
||||||
})
|
})
|
||||||
|
|
||||||
let handleAttack (event : ComponentInteractionCreateEventArgs) =
|
let handleAttack (ctx : IDiscordContext) =
|
||||||
Game.executePlayerEvent event (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
let sendMessage' = sendFollowUpMessage event
|
let sendMessage' = sendFollowUpMessage ctx
|
||||||
do! Async.Sleep 1000
|
do! Async.Sleep 1000
|
||||||
let hack = Player.getHacks player |> Array.tryHead |> Option.defaultValue defaultHack
|
let hack = Player.getHacks player |> Array.tryHead |> Option.defaultValue defaultHack
|
||||||
let embed = Embeds.responseSuccessfulHack false GuildEnvironment.botIdHackerBattle hack
|
let embed = Embeds.responseSuccessfulHack false GuildEnvironment.botIdHackerBattle hack
|
||||||
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
|
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||||||
do! Async.Sleep 5000
|
do! Async.Sleep 5000
|
||||||
do! sendMessage'
|
do! sendMessage'
|
||||||
("🎉 **Congratulations**\n\n"
|
("🎉 **Congratulations**\n\n"
|
||||||
@ -201,43 +193,37 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
|
|||||||
|> Array.append player.Arsenal
|
|> Array.append player.Arsenal
|
||||||
}
|
}
|
||||||
do! DbService.updatePlayer updatedPlayer
|
do! DbService.updatePlayer updatedPlayer
|
||||||
do! sendFollowUpMessage event (sb.ToString())
|
do! sendFollowUpMessage ctx (sb.ToString())
|
||||||
else
|
else
|
||||||
do! sendFollowUpMessage event ($"Your training is now complete. If you want to buy more **HACKS & SHIELDS**, go to the <#{GuildEnvironment.channelArmory}> **NOW** and type the `/buy-hack` and `/buy-shield` commands! 😱")
|
do! sendFollowUpMessage ctx ($"Your training is now complete. If you want to buy more **HACKS & SHIELDS**, go to the <#{GuildEnvironment.channelArmory}> **NOW** and type the `/buy-hack` and `/buy-shield` commands! 😱")
|
||||||
let role = event.Guild.GetRole(GuildEnvironment.roleTrainee)
|
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee)
|
||||||
let ``member`` = event.User :?> DiscordMember
|
do! ctx.GetDiscordMember().RevokeRoleAsync(role)
|
||||||
do! ``member``.RevokeRoleAsync(role)
|
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
})
|
})
|
||||||
|
|
||||||
let handleArsenal (ctx : InteractionContext) =
|
let handleArsenal (ctx : IDiscordContext) =
|
||||||
Game.executePlayerInteraction ctx (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
let updatedPlayer = Player.removeExpiredActions false player
|
let updatedPlayer = Player.removeExpiredActions false player
|
||||||
let embed = Embeds.getArsenalEmbed updatedPlayer
|
let embed = Embeds.getArsenalEmbed updatedPlayer
|
||||||
do! ctx.FollowUpAsync(embed)
|
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
|> Async.Ignore
|
|
||||||
do! Async.Sleep 3000
|
do! Async.Sleep 3000
|
||||||
let embed = Embeds.getAchievementEmbed player "You completed the Training Dojo and collected loot." trainerAchievement
|
let embed = Embeds.getAchievementEmbed "You completed the Training Dojo and collected loot." trainerAchievement
|
||||||
do! ctx.FollowUpAsync(embed)
|
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
|> Async.Ignore
|
|
||||||
do! Async.Sleep 2000
|
do! Async.Sleep 2000
|
||||||
let role = ctx.Guild.GetRole(GuildEnvironment.roleTrainee)
|
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee)
|
||||||
do! ctx.Member.RevokeRoleAsync(role)
|
do! ctx.GetDiscordMember().RevokeRoleAsync(role) |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
|
|
||||||
do! sendFollowUpMessageFromCtx ctx $"Now get out of there and go hack other Degenz in the <#{GuildEnvironment.channelBattle}> channel!"
|
do! sendFollowUpMessage ctx $"Now get out of there and go hack other Degenz in the <#{GuildEnvironment.channelBattle}> channel!"
|
||||||
})
|
})
|
||||||
|
|
||||||
let handleButtonEvent (event : ComponentInteractionCreateEventArgs) =
|
let handleButtonEvent (ctx : IDiscordContext) =
|
||||||
async {
|
async {
|
||||||
let split = event.Id.Split("-")
|
let split = ctx.GetInteractionId().Split("-")
|
||||||
match int split.[1] with
|
match int split.[1] with
|
||||||
| 1 -> do! handleTrainerStep1 event |> Async.AwaitTask
|
| 1 -> do! handleTrainerStep1 ctx |> Async.AwaitTask
|
||||||
| 2 -> do! handleDefense event |> Async.AwaitTask
|
| 2 -> do! handleDefense ctx |> Async.AwaitTask
|
||||||
| 3 -> do! handleTrainerStep3 event |> Async.AwaitTask
|
| 3 -> do! handleTrainerStep3 ctx |> Async.AwaitTask
|
||||||
| 4 -> do! handleAttack event |> Async.AwaitTask
|
| 4 -> do! handleAttack ctx |> Async.AwaitTask
|
||||||
| _ -> do! sendFollowUpMessage event "No action found"
|
| _ -> do! sendFollowUpMessage ctx "No action found"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
namespace Degenz
|
namespace Degenz
|
||||||
|
|
||||||
open System
|
open System
|
||||||
|
open System.Threading.Tasks
|
||||||
open DSharpPlus
|
open DSharpPlus
|
||||||
open DSharpPlus.Entities
|
open DSharpPlus.Entities
|
||||||
open DSharpPlus.EventArgs
|
open DSharpPlus.EventArgs
|
||||||
@ -71,7 +72,7 @@ module Types =
|
|||||||
type Action =
|
type Action =
|
||||||
{ ActionId : int
|
{ ActionId : int
|
||||||
Type : ActionType
|
Type : ActionType
|
||||||
Timestamp : System.DateTime }
|
Timestamp : DateTime }
|
||||||
|
|
||||||
[<CLIMutable>]
|
[<CLIMutable>]
|
||||||
type PlayerData =
|
type PlayerData =
|
||||||
@ -98,6 +99,48 @@ module Messaging =
|
|||||||
Message : string
|
Message : string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DiscordContext =
|
||||||
|
| Interaction of InteractionContext
|
||||||
|
| Event of ComponentInteractionCreateEventArgs
|
||||||
|
|
||||||
|
type IDiscordContext =
|
||||||
|
abstract member Respond : InteractionResponseType -> DiscordInteractionResponseBuilder -> Task
|
||||||
|
abstract member FollowUp : DiscordFollowupMessageBuilder -> Task
|
||||||
|
abstract member GetDiscordMember : unit -> DiscordMember
|
||||||
|
abstract member GetGuild : unit -> DiscordGuild
|
||||||
|
abstract member GetInteractionId : unit -> string
|
||||||
|
abstract member GetChannel : unit -> DiscordChannel
|
||||||
|
|
||||||
|
type DiscordInteractionContext(ctx : InteractionContext) =
|
||||||
|
interface IDiscordContext with
|
||||||
|
member this.Respond responseType builder =
|
||||||
|
async {
|
||||||
|
do! ctx.Interaction.CreateResponseAsync(responseType, builder) |> Async.AwaitTask
|
||||||
|
} |> Async.StartAsTask :> Task
|
||||||
|
member this.FollowUp(builder) =
|
||||||
|
async {
|
||||||
|
do! ctx.Interaction.CreateFollowupMessageAsync(builder) |> Async.AwaitTask |> Async.Ignore
|
||||||
|
} |> Async.StartAsTask :> Task
|
||||||
|
member this.GetDiscordMember() = ctx.Member
|
||||||
|
member this.GetGuild() = ctx.Guild
|
||||||
|
member this.GetInteractionId() = string ctx.InteractionId
|
||||||
|
member this.GetChannel() = ctx.Channel
|
||||||
|
|
||||||
|
type DiscordEventContext(ctx : ComponentInteractionCreateEventArgs) =
|
||||||
|
interface IDiscordContext with
|
||||||
|
member this.Respond responseType builder =
|
||||||
|
async {
|
||||||
|
do! ctx.Interaction.CreateResponseAsync(responseType, builder) |> Async.AwaitTask
|
||||||
|
} |> Async.StartAsTask :> Task
|
||||||
|
member this.FollowUp(builder) =
|
||||||
|
async {
|
||||||
|
do! ctx.Interaction.CreateFollowupMessageAsync(builder) |> Async.AwaitTask |> Async.Ignore
|
||||||
|
} |> Async.StartAsTask :> Task
|
||||||
|
member this.GetDiscordMember() = ctx.User :?> DiscordMember
|
||||||
|
member this.GetGuild() = ctx.Guild
|
||||||
|
member this.GetInteractionId() = ctx.Id
|
||||||
|
member this.GetChannel() = ctx.Channel
|
||||||
|
|
||||||
let getTimeText isCooldown (timespan : TimeSpan) timestamp =
|
let getTimeText isCooldown (timespan : TimeSpan) timestamp =
|
||||||
let span =
|
let span =
|
||||||
if isCooldown
|
if isCooldown
|
||||||
@ -116,82 +159,46 @@ module Messaging =
|
|||||||
let minutesRemaining = if remaining.Hours = 0 then remaining.Minutes + 1 else remaining.Minutes
|
let minutesRemaining = if remaining.Hours = 0 then remaining.Minutes + 1 else remaining.Minutes
|
||||||
$"{hours}{minutesRemaining}min"
|
$"{hours}{minutesRemaining}min"
|
||||||
|
|
||||||
let sendSimpleResponse (ctx: InteractionContext) msg =
|
let sendSimpleResponse (ctx: IDiscordContext) msg =
|
||||||
async {
|
async {
|
||||||
let builder = DiscordInteractionResponseBuilder()
|
let builder = DiscordInteractionResponseBuilder()
|
||||||
builder.Content <- msg
|
builder.Content <- msg
|
||||||
builder.AsEphemeral true |> ignore
|
builder.AsEphemeral true |> ignore
|
||||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
do! ctx.Respond InteractionResponseType.ChannelMessageWithSource builder |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let sendFollowUpMessage (event : ComponentInteractionCreateEventArgs) msg =
|
let sendFollowUpMessage (ctx : IDiscordContext) msg =
|
||||||
async {
|
async {
|
||||||
let builder = DiscordFollowupMessageBuilder()
|
let builder = DiscordFollowupMessageBuilder()
|
||||||
builder.IsEphemeral <- true
|
builder.IsEphemeral <- true
|
||||||
builder.Content <- msg
|
builder.Content <- msg
|
||||||
do! event.Interaction.CreateFollowupMessageAsync(builder)
|
do! ctx.FollowUp(builder) |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
|> Async.Ignore
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let sendFollowUpMessageFromCtx (ctx : InteractionContext) msg =
|
let sendFollowUpMessageWithButton (ctx : IDiscordContext) interactiveMessage =
|
||||||
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 =
|
|
||||||
async {
|
|
||||||
let builder =
|
|
||||||
DiscordFollowupMessageBuilder()
|
|
||||||
.AsEphemeral(true)
|
|
||||||
.WithContent(msg)
|
|
||||||
.AddEmbed(embed)
|
|
||||||
do! event.Interaction.CreateFollowupMessageAsync(builder)
|
|
||||||
|> Async.AwaitTask
|
|
||||||
|> Async.Ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
let sendFollowUpMessageWithButton (event : ComponentInteractionCreateEventArgs) interactiveMessage =
|
|
||||||
async {
|
async {
|
||||||
let builder = DiscordFollowupMessageBuilder()
|
let builder = DiscordFollowupMessageBuilder()
|
||||||
let button = DiscordButtonComponent(ButtonStyle.Success, interactiveMessage.ButtonId, interactiveMessage.ButtonText) :> DiscordComponent
|
let button = DiscordButtonComponent(ButtonStyle.Success, interactiveMessage.ButtonId, interactiveMessage.ButtonText) :> DiscordComponent
|
||||||
builder.AddComponents [| button |] |> ignore
|
builder.AddComponents [| button |] |> ignore
|
||||||
builder.IsEphemeral <- true
|
builder.IsEphemeral <- true
|
||||||
builder.Content <- interactiveMessage.Message
|
builder.Content <- interactiveMessage.Message
|
||||||
do! event.Interaction.CreateFollowupMessageAsync(builder)
|
do! ctx.FollowUp(builder) |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
|> Async.Ignore
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let updateMessageWithGreyedOutButtons (event : ComponentInteractionCreateEventArgs) interactiveMessage =
|
let updateMessageWithGreyedOutButtons (ctx : IDiscordContext) interactiveMessage =
|
||||||
async {
|
async {
|
||||||
let builder = DiscordInteractionResponseBuilder()
|
let builder = DiscordInteractionResponseBuilder()
|
||||||
let button = DiscordButtonComponent(ButtonStyle.Success, interactiveMessage.ButtonId, interactiveMessage.ButtonText, true) :> DiscordComponent
|
let button = DiscordButtonComponent(ButtonStyle.Success, interactiveMessage.ButtonId, interactiveMessage.ButtonText, true) :> DiscordComponent
|
||||||
builder.AddComponents [| button |] |> ignore
|
builder.AddComponents [| button |] |> ignore
|
||||||
builder.IsEphemeral <- true
|
builder.IsEphemeral <- true
|
||||||
builder.Content <- interactiveMessage.Message
|
builder.Content <- interactiveMessage.Message
|
||||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
|
do! ctx.Respond InteractionResponseType.UpdateMessage builder |> Async.AwaitTask
|
||||||
|> Async.AwaitTask
|
|
||||||
}
|
|
||||||
|
|
||||||
let sendInteractionEvent (event : ComponentInteractionCreateEventArgs) msg =
|
|
||||||
async {
|
|
||||||
let builder = DiscordInteractionResponseBuilder()
|
|
||||||
builder.IsEphemeral <- true
|
|
||||||
builder.Content <- msg
|
|
||||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) |> Async.AwaitTask
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let handleResultWithResponse ctx fn (player : Result<PlayerData, string>) =
|
let handleResultWithResponse ctx fn (player : Result<PlayerData, string>) =
|
||||||
match player with
|
match player with
|
||||||
| Ok p -> fn p
|
| Ok p -> fn p
|
||||||
| Error e -> async { do! sendFollowUpMessageFromCtx ctx e }
|
| Error e -> async { do! sendFollowUpMessage ctx e }
|
||||||
|
|
||||||
let handleResultWithResponseFromEvent event fn (player : Result<PlayerData, string>) =
|
let handleResultWithResponseFromEvent event fn (player : Result<PlayerData, string>) =
|
||||||
match player with
|
match player with
|
||||||
|
Loading…
x
Reference in New Issue
Block a user