Move some stuff around

This commit is contained in:
Joseph Ferano 2022-02-01 19:54:52 +07:00
parent 69545bf3a6
commit ef3d5c58f5
12 changed files with 270 additions and 286 deletions

View File

@ -1,6 +1,5 @@
module Degenz.Bot module Degenz.Bot
open System
open System.Threading.Tasks open System.Threading.Tasks
open DSharpPlus open DSharpPlus
open DSharpPlus.SlashCommands open DSharpPlus.SlashCommands

View File

@ -11,8 +11,8 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<Content Include="paket.references" /> <Content Include="paket.references" />
<Compile Include="GameConfig.fs" />
<Compile Include="GuildEnvironment.fs" /> <Compile Include="GuildEnvironment.fs" />
<Compile Include="Game.fs" />
<Compile Include="Embeds.fs" /> <Compile Include="Embeds.fs" />
<Compile Include="Store.fs" /> <Compile Include="Store.fs" />
<Compile Include="Trainer.fs" /> <Compile Include="Trainer.fs" />

View File

@ -1,7 +1,7 @@
module Degenz.Embeds module Degenz.Embeds
open DSharpPlus.EventArgs open DSharpPlus.EventArgs
open Degenz.Shared open Degenz.Types
open DSharpPlus.Entities open DSharpPlus.Entities
open AsciiTableFormatter open AsciiTableFormatter
@ -34,7 +34,7 @@ let constructEmbed message =
let pickDefense actionId player = let pickDefense actionId player =
let buttons = let buttons =
constructButtons actionId (string player.DiscordId) (Player.shields player) Messaging.constructButtons actionId (string player.DiscordId) (Player.shields player)
|> Seq.cast<DiscordComponent> |> Seq.cast<DiscordComponent>
let embed = let embed =
@ -50,7 +50,7 @@ let pickDefense actionId player =
let pickHack actionId attacker defender = let pickHack actionId attacker defender =
let buttons = let buttons =
constructButtons actionId $"{defender.DiscordId}-{defender.Name}" (Player.hacks attacker) Messaging.constructButtons actionId $"{defender.DiscordId}-{defender.Name}" (Player.hacks attacker)
|> Seq.cast<DiscordComponent> |> Seq.cast<DiscordComponent>
let embed = let embed =

15
Bot/Game.fs Normal file
View File

@ -0,0 +1,15 @@
module Degenz.Game
open System.Threading.Tasks
open DSharpPlus.SlashCommands
open Degenz.DbService
let executePlayerAction (ctx : InteractionContext) (dispatch : PlayerData -> Async<unit>) =
async {
let! playerResult = tryFindPlayer ctx.Member.Id
match playerResult with
| Some player -> do! dispatch player
| None -> do! Messaging.sendSimpleResponse ctx "You are currently not a hacker, first use the /redpill command to become one"
} |> Async.StartAsTask
:> Task

View File

@ -1 +0,0 @@
module Degenz.GameConfig

View File

@ -7,8 +7,7 @@ open DSharpPlus.Entities
open DSharpPlus.EventArgs open DSharpPlus.EventArgs
open DSharpPlus.SlashCommands open DSharpPlus.SlashCommands
open Degenz open Degenz
open Degenz.Shared open Degenz.Messaging
open Degenz.Store
let getTimeTillCooldownFinishes (timespan : TimeSpan) timestamp = let getTimeTillCooldownFinishes (timespan : TimeSpan) timestamp =
let timeRemaining = timespan - (DateTime.UtcNow - timestamp) let timeRemaining = timespan - (DateTime.UtcNow - timestamp)
@ -26,8 +25,8 @@ let checkIfPlayerIsAttackingThemselves defender attacker =
let checkForExistingHack defenderId attacker = let checkForExistingHack defenderId attacker =
attacker.Actions attacker.Actions
|> removeExpiredActions |> Player.removeExpiredActions
|> getAttacksFlat |> Player.getAttacksFlat
|> Array.tryFind (fun (_,t,_) -> t.Id = defenderId) |> Array.tryFind (fun (_,t,_) -> t.Id = defenderId)
|> function |> function
| Some ( atk , target , _ ) -> | Some ( atk , target , _ ) ->
@ -47,7 +46,7 @@ let checkIfHackHasCooldown hackId attacker =
Ok attacker Ok attacker
else else
let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromMinutes(5)) mostRecentHackAttack let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromMinutes(5)) mostRecentHackAttack
let item = armoury |> Array.find (fun i -> i.Id = hackId) let item = Armoury.battleItems |> Array.find (fun i -> i.Id = hackId)
Error $"{item.Name} is currently on cooldown, wait {cooldown} to use it again." Error $"{item.Name} is currently on cooldown, wait {cooldown} to use it again."
let checkIfInventoryIsEmpty attacker = let checkIfInventoryIsEmpty attacker =
@ -62,8 +61,8 @@ let calculateDamage (hack : BattleItem) (shield : BattleItem) =
let runHackerBattle defender hack = let runHackerBattle defender hack =
Player.defenses defender Player.defenses defender
|> removeExpiredActions |> Player.removeExpiredActions
|> Array.map (fun dfn -> armoury |> Array.find (fun w -> w.Id = dfn.ActionId)) |> Array.map (fun dfn -> Armoury.battleItems |> Array.find (fun w -> w.Id = dfn.ActionId))
|> Array.map (calculateDamage (hack)) |> Array.map (calculateDamage (hack))
|> Array.contains Weak |> Array.contains Weak
@ -74,7 +73,7 @@ let updateCombatants attacker defender hack prize =
let attack = { ActionId = int hack ; Type = Attack { Target = target ; Result = prize > 0<GBT> } ; Timestamp = DateTime.UtcNow } let attack = { ActionId = int hack ; Type = Attack { Target = target ; Result = prize > 0<GBT> } ; Timestamp = DateTime.UtcNow }
[ DbService.updatePlayer <| updatePlayer prize attack attacker [ DbService.updatePlayer <| updatePlayer prize attack attacker
DbService.updatePlayer <| modifyPlayerBank defender -prize ] DbService.updatePlayer <| Player.modifyBank defender -prize ]
|> Async.Parallel |> Async.Parallel
|> Async.Ignore |> Async.Ignore
@ -115,11 +114,10 @@ let failedHack (event : ComponentInteractionCreateEventArgs) attacker defender h
} }
let attack (ctx : InteractionContext) (target : DiscordUser) = let attack (ctx : InteractionContext) (target : DiscordUser) =
async { Game.executePlayerAction ctx (fun attacker -> async {
let! attacker = DbService.tryFindPlayer ctx.Member.Id
let! defender = DbService.tryFindPlayer target.Id let! defender = DbService.tryFindPlayer target.Id
match attacker , defender with match defender with
| Some attacker , Some defender -> | Some defender ->
let hackAttempt = let hackAttempt =
checkForExistingHack defender.DiscordId attacker checkForExistingHack defender.DiscordId attacker
|> Result.bind checkIfInventoryIsEmpty |> Result.bind checkIfInventoryIsEmpty
@ -136,10 +134,8 @@ let attack (ctx : InteractionContext) (target : DiscordUser) =
.AsEphemeral(true) .AsEphemeral(true)
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask |> Async.AwaitTask
| None , _ -> do! notYetAHackerMsg ctx | None -> do! sendSimpleResponse ctx "Your target is not connected to the network, they must join first by using the /redpill command"
| _ , None -> do! createSimpleResponseAsync "Your target is not connected to the network, they must join first by using the /redpill command" ctx })
} |> Async.StartAsTask
:> Task
let handleAttack (event : ComponentInteractionCreateEventArgs) = let handleAttack (event : ComponentInteractionCreateEventArgs) =
async { async {
@ -155,7 +151,7 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
|> Result.bind (checkIfHackHasCooldown (int hack)) |> Result.bind (checkIfHackHasCooldown (int hack))
|> function |> function
| Ok _ -> | Ok _ ->
runHackerBattle defender (getItemFromArmoury <| int hack) runHackerBattle defender (Armoury.getItem (int hack))
|> 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
@ -175,10 +171,7 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
} }
let defend (ctx : InteractionContext) = let defend (ctx : InteractionContext) =
async { Game.executePlayerAction ctx (fun player -> async {
let! player = DbService.tryFindPlayer ctx.Member.Id
match player with
| Some player ->
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.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed)
@ -189,9 +182,7 @@ let defend (ctx : InteractionContext) =
builder.AsEphemeral true |> ignore builder.AsEphemeral true |> ignore
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask |> Async.AwaitTask
| None -> do! notYetAHackerMsg ctx })
} |> Async.StartAsTask
:> Task
let handleDefense (event : ComponentInteractionCreateEventArgs) = let handleDefense (event : ComponentInteractionCreateEventArgs) =
async { async {
@ -200,7 +191,7 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
let! playerResult = DbService.tryFindPlayer event.User.Id let! playerResult = DbService.tryFindPlayer event.User.Id
match playerResult with match playerResult with
| Some player -> | Some player ->
let updatedDefenses = Player.defenses player |> removeExpiredActions let updatedDefenses = Player.defenses player |> Player.removeExpiredActions
let alreadyUsedShield = updatedDefenses |> Array.exists (fun d -> d.ActionId = int shield) let alreadyUsedShield = updatedDefenses |> Array.exists (fun d -> d.ActionId = int shield)
match alreadyUsedShield , updatedDefenses.Length < 2 with match alreadyUsedShield , updatedDefenses.Length < 2 with

View File

@ -5,15 +5,15 @@ open DSharpPlus.Entities
open DSharpPlus open DSharpPlus
open DSharpPlus.SlashCommands open DSharpPlus.SlashCommands
open Degenz.Store open Degenz.Store
open Degenz.Shared open Degenz.Types
module Commands = module Commands =
let newPlayer nickname (membr : uint64) = let newPlayer nickname (membr : uint64) =
let rand = System.Random(System.Guid.NewGuid().GetHashCode()) let rand = System.Random(System.Guid.NewGuid().GetHashCode())
let randHack = rand.Next(0, 3) let randHack = rand.Next(0, 3)
let randShield = rand.Next(6, 9) let randShield = rand.Next(6, 9)
let hack = armoury |> Array.find (fun i -> i.Id = randHack) let hack = Armoury.battleItems |> Array.find (fun i -> i.Id = randHack)
let shield = armoury |> Array.find (fun i -> i.Id = randShield) let shield = Armoury.battleItems |> Array.find (fun i -> i.Id = randShield)
{ DiscordId = membr { DiscordId = membr
Name = nickname Name = nickname
@ -72,21 +72,16 @@ module Commands =
// :> Task // :> Task
let status (ctx : InteractionContext) = let status (ctx : InteractionContext) =
async { Game.executePlayerAction ctx (fun player -> async {
let! maybePlayer = DbService.tryFindPlayer ctx.Member.Id let updatedActions = Player.removeExpiredActions player.Actions
match maybePlayer with
| Some player ->
let updatedActions = removeExpiredActions player.Actions
let updatedPlayer = { player with Actions = updatedActions } let updatedPlayer = { player with Actions = updatedActions }
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
builder.IsEphemeral <- true builder.IsEphemeral <- true
builder.Content <- statusFormat updatedPlayer builder.Content <- Messaging.statusFormat updatedPlayer
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask |> Async.AwaitTask
do! DbService.updatePlayer updatedPlayer do! DbService.updatePlayer updatedPlayer
| None -> do! notYetAHackerMsg ctx })
} |> Async.StartAsTask
:> Task
type PlayerInteractions() = type PlayerInteractions() =
inherit ApplicationCommandModule () inherit ApplicationCommandModule ()

View File

@ -5,7 +5,7 @@ open System.Threading.Tasks
open DSharpPlus open DSharpPlus
open DSharpPlus.Entities open DSharpPlus.Entities
open DSharpPlus.SlashCommands open DSharpPlus.SlashCommands
open Degenz.Shared 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" |]
@ -13,11 +13,8 @@ type SlotMachine() =
inherit ApplicationCommandModule () inherit ApplicationCommandModule ()
[<SlashCommand("spin", "Want to try your luck?")>] [<SlashCommand("spin", "Want to try your luck?")>]
member this.AttackCommand (ctx : InteractionContext) = member this.Spin (ctx : InteractionContext) =
async { Game.executePlayerAction ctx (fun player -> async {
let! playerResult = DbService.tryFindPlayer ctx.Member.Id
match playerResult with
| Some player ->
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)]
@ -73,8 +70,5 @@ type SlotMachine() =
do! ctx.Interaction.CreateFollowupMessageAsync(builder) do! ctx.Interaction.CreateFollowupMessageAsync(builder)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore |> Async.Ignore
})
| None -> do! notYetAHackerMsg ctx
} |> Async.StartAsTask
:> Task

View File

@ -8,54 +8,27 @@ open DSharpPlus.EventArgs
open DSharpPlus.SlashCommands open DSharpPlus.SlashCommands
open Degenz open Degenz
open Degenz.Embeds open Degenz.Embeds
open Degenz.Shared open Degenz.Messaging
open Newtonsoft.Json
let getItemFromArmoury id = armoury |> Array.find (fun w -> w.Id = id)
let removeExpiredActions actions =
actions
|> Array.filter (fun (act : Action) ->
let item = armoury |> Array.find (fun w -> w.Id = act.ActionId)
DateTime.UtcNow - act.Timestamp < TimeSpan.FromMinutes(int item.Cooldown))
let viewStore (ctx : InteractionContext) = let viewStore (ctx : InteractionContext) =
async { async {
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, Embeds.storeListing armoury) do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, Embeds.storeListing Armoury.battleItems)
|> Async.AwaitTask |> Async.AwaitTask
} |> Async.StartAsTask } |> Async.StartAsTask
:> Task :> Task
let buyItem (ctx : InteractionContext) itemId = let buyItem (ctx : InteractionContext) itemType =
async { Game.executePlayerAction ctx (fun player -> async {
let! playerResult = DbService.tryFindPlayer ctx.Member.Id let embed = DiscordEmbedBuilder()
let item = armoury |> Array.find (fun w -> w.Id = itemId)
match playerResult with
| Some player ->
let newBalance = player.Bank - item.Cost
if newBalance >= 0<GBT> then
let playerHasItem = player.Arsenal |> Array.exists (fun w -> item.Id = w.Id)
if not playerHasItem then
let p = { player with Bank = newBalance ; Arsenal = Array.append [| item |] player.Arsenal }
do! DbService.updatePlayer p
do! createSimpleResponseAsync $"Successfully purchased {item.Name}! You now have {newBalance} remaining" ctx
else
do! createSimpleResponseAsync $"You already own this item!" ctx
else
do! createSimpleResponseAsync $"You do not have sufficient funds to buy this item! Current balance: {player.Bank} GBT" ctx
| None -> do! notYetAHackerMsg ctx
} |> Async.StartAsTask
:> Task
let constructItemButtons playerInfo itemType (items : 'a array) = // embed.Fields
items
|> Seq.map (fun item -> DiscordButtonComponent(ButtonStyle.Primary, $"{playerInfo}-{itemType}-{item}", $"{item}")) do! ctx.CreateResponseAsync(embed, true)
|> Async.AwaitTask
})
let sell (ctx : InteractionContext) = let sell (ctx : InteractionContext) =
async { Game.executePlayerAction ctx (fun player -> async {
let! playerResult = DbService.tryFindPlayer ctx.Member.Id
match playerResult with
| Some player ->
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 = DiscordInteractionResponseBuilder()
@ -74,17 +47,12 @@ let sell (ctx : InteractionContext) =
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask |> Async.AwaitTask
else else
do! createSimpleResponseAsync "You currently have no inventory to sell" ctx do! sendSimpleResponse ctx "You currently have no inventory to sell"
| None -> do! notYetAHackerMsg ctx })
return ()
} |> Async.StartAsTask
:> Task
let updateArsenal player salePrice updatedArsenal = { player with Bank = player.Bank + salePrice ; Arsenal = updatedArsenal }
let sellItem (event : ComponentInteractionCreateEventArgs) player itemId = let sellItem (event : ComponentInteractionCreateEventArgs) player itemId =
async { async {
let item = armoury |> Array.find (fun i -> i.Id = itemId) let item = Armoury.battleItems |> Array.find (fun i -> i.Id = 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 = DiscordInteractionResponseBuilder()
@ -94,6 +62,22 @@ let sellItem (event : ComponentInteractionCreateEventArgs) player itemId =
|> Async.AwaitTask |> Async.AwaitTask
} }
let handleBuyItem (ctx : InteractionContext) itemId =
Game.executePlayerAction ctx (fun player -> async {
let item = Armoury.battleItems |> Array.find (fun w -> w.Id = itemId)
let newBalance = player.Bank - item.Cost
if newBalance >= 0<GBT> then
let playerHasItem = player.Arsenal |> Array.exists (fun w -> item.Id = w.Id)
if not playerHasItem then
let p = { player with Bank = newBalance ; Arsenal = Array.append [| item |] player.Arsenal }
do! DbService.updatePlayer p
do! sendSimpleResponse ctx $"Successfully purchased {item.Name}! You now have {newBalance} remaining"
else
do! sendSimpleResponse ctx $"You already own this item!"
else
do! sendSimpleResponse 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) =
async { async {
let! playerResult = DbService.tryFindPlayer event.User.Id let! playerResult = DbService.tryFindPlayer event.User.Id
@ -112,17 +96,15 @@ let handleSellButtonEvents (_ : DiscordClient) (event : ComponentInteractionCrea
type Store() = type Store() =
inherit ApplicationCommandModule () inherit ApplicationCommandModule ()
// [<SlashCommand("view-store", "View items available for purchase")>]
[<SlashCommand("view-store", "View items available for purchase")>] // member _.ViewStore (ctx : InteractionContext) = viewStore ctx
member _.ViewStore (ctx : InteractionContext) = viewStore ctx
[<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, [<Option("hack-id", "The ID of the hack you wish to purchase")>] hackId : HackId) = member _.BuyHack (ctx : InteractionContext) = buyItem ctx Hack
buyItem ctx (int hackId)
[<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, [<Option("shield-id", "The ID of the shield you wish to purchase")>] shieldId : ShieldId) = member this.BuyShield (ctx : InteractionContext) = buyItem ctx Shield
buyItem ctx (int shieldId)
[<SlashCommand("sell", "Sell an item in your inventory for GoodBoyTokenz")>] [<SlashCommand("sell", "Sell an item in your inventory for GoodBoyTokenz")>]
member this.SellItem (ctx : InteractionContext) = sell ctx member this.SellItem (ctx : InteractionContext) = sell ctx

View File

@ -5,11 +5,11 @@ open DSharpPlus
open DSharpPlus.Entities open DSharpPlus.Entities
open DSharpPlus.EventArgs open DSharpPlus.EventArgs
open DSharpPlus.SlashCommands open DSharpPlus.SlashCommands
open Degenz.Shared open Degenz.Types
open Degenz.Store open Degenz.Messaging
let defaultHack = armoury |> Array.find (fun i -> i.Id = int HackId.Virus) let defaultHack = Armoury.battleItems |> Array.find (fun i -> i.Id = int HackId.Virus)
let defaultShield = armoury |> Array.find (fun i -> i.Id = int ShieldId.Firewall) let defaultShield = Armoury.battleItems |> Array.find (fun i -> i.Id = int ShieldId.Firewall)
let sendInitialEmbed (client : DiscordClient) = let sendInitialEmbed (client : DiscordClient) =
async { async {
@ -41,10 +41,10 @@ let handleTrainerStep1 (event : ComponentInteractionCreateEventArgs) =
|> Async.AwaitTask |> Async.AwaitTask
match maybePlayer with match maybePlayer with
| Some _ -> | Some _ ->
do! Message.sendFollowUpMessageWithButton event step1Msg do! sendFollowUpMessageWithButton event step1Msg
| None -> | None ->
let msg = "Looks like an error occurred, you're not a registered degenerate. Please contact a moderator." let msg = "Looks like an error occurred, you're not a registered degenerate. Please contact a moderator."
do! Message.sendFollowUpMessage event msg do! sendFollowUpMessage event msg
} }
let handleTrainerStep2 (event : ComponentInteractionCreateEventArgs) = let handleTrainerStep2 (event : ComponentInteractionCreateEventArgs) =
@ -53,19 +53,19 @@ let handleTrainerStep2 (event : ComponentInteractionCreateEventArgs) =
match result with match result with
| Some player -> | Some player ->
let weaponName = Player.shields player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name let weaponName = Player.shields player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name
do! Message.updateMessageWithGreyedOutButtons event step1Msg do! updateMessageWithGreyedOutButtons event step1Msg
let shieldMessage = let shieldMessage =
if Player.shields player |> Array.isEmpty if Player.shields player |> Array.isEmpty
then $"You do not have any Shields in your arsenal, here's a {defaultShield.Name} you can use for now" then $"You do not have any Shields in your arsenal, here's a {defaultShield.Name} you can use for now"
else $"You currently have {weaponName} in your arsenal" else $"You currently have {weaponName} in your arsenal"
do! Message.sendFollowUpMessage event do! sendFollowUpMessage event
($"First things first, let's get your system protected. Let's enable a shield to protect you from potential hackers. " ($"First things first, let's get your system protected. Let's enable a shield to protect you from potential hackers. "
+ $"{shieldMessage}. To enable it and protect your system, you can use the `/defend` slash command to choose a shield." + $"{shieldMessage}. To enable it and protect your system, you can use the `/defend` slash command to choose a shield."
+ $"\n\nRun the `/defend` command now and then select '{weaponName}'.") + $"\n\nRun the `/defend` command now and then select '{weaponName}'.")
| None -> | None ->
do! Message.sendFollowUpMessage event $"Something went wrong, please contact a moderator" do! sendFollowUpMessage event $"Something went wrong, please contact a moderator"
} }
let defend (ctx : InteractionContext) = let defend (ctx : InteractionContext) =
@ -100,7 +100,7 @@ let handleDefenseMsg = {
} }
let handleDefense (event : ComponentInteractionCreateEventArgs) = let handleDefense (event : ComponentInteractionCreateEventArgs) =
let sendMessage' = Message.sendFollowUpMessage event let sendMessage' = sendFollowUpMessage event
async { async {
do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate) do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate)
|> Async.AwaitTask |> Async.AwaitTask
@ -116,7 +116,7 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
do! Async.Sleep 4000 do! Async.Sleep 4000
do! sendMessage' $"Hacking attempt failed! {player.Name} defended hack from Degenz-Trainer and took {prize} from them! " do! sendMessage' $"Hacking attempt failed! {player.Name} defended hack from Degenz-Trainer and took {prize} from them! "
do! Async.Sleep 3000 do! Async.Sleep 3000
do! Message.sendFollowUpMessageWithButton event handleDefenseMsg do! sendFollowUpMessageWithButton event handleDefenseMsg
| None -> | None ->
do! sendMessage' $"Something went wrong, please contact a moderator" do! sendMessage' $"Something went wrong, please contact a moderator"
} }
@ -127,19 +127,19 @@ let handleTrainerStep4 (event : ComponentInteractionCreateEventArgs) =
match result with match result with
| Some player -> | Some player ->
let weaponName = Player.hacks player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name let weaponName = Player.hacks player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name
do! Message.updateMessageWithGreyedOutButtons event handleDefenseMsg do! updateMessageWithGreyedOutButtons event handleDefenseMsg
let hackMessage = let hackMessage =
if Player.shields player |> Array.isEmpty if Player.shields player |> Array.isEmpty
then $"You do not have any Hacks in your arsenal, here's a {defaultHack.Name} you can use for now" then $"You do not have any Hacks in your arsenal, here's a {defaultHack.Name} you can use for now"
else $"You currently have {weaponName} in your arsenal" else $"You currently have {weaponName} in your arsenal"
do! Message.sendFollowUpMessage event do! sendFollowUpMessage event
($"Next why don't you try hacking me. {hackMessage}. To hack me and get some money, " ($"Next why don't you try hacking me. {hackMessage}. To hack me and get some money, "
+ $" you can use the '/hack' slash command and select a user to hack, then choose the hack attack you wish to use." + $" you can use the '/hack' slash command and select a user to hack, then choose the hack attack you wish to use."
+ $"\n\nRun the `/hack` command now and pick me as your target, then click on the '{weaponName}' button.") + $"\n\nRun the `/hack` command now and pick me as your target, then click on the '{weaponName}' button.")
| None -> | None ->
do! Message.sendInteractionEvent event $"Something went wrong, please contact a moderator" do! sendInteractionEvent event $"Something went wrong, please contact a moderator"
} }
let attack (ctx : InteractionContext) (target : DiscordUser) = let attack (ctx : InteractionContext) (target : DiscordUser) =
@ -184,7 +184,7 @@ let handleAttackMsg = {
} }
let handleAttack (event : ComponentInteractionCreateEventArgs) = let handleAttack (event : ComponentInteractionCreateEventArgs) =
let sendMessage' = Message.sendFollowUpMessage event let sendMessage' = sendFollowUpMessage event
async { async {
do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate) do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate)
|> Async.AwaitTask |> Async.AwaitTask
@ -200,7 +200,7 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
do! sendMessage' ("Look at that, you are now officially an elite haxor! By successfully hacking other people you can earn GoodBoyTokenz. " do! sendMessage' ("Look at that, you are now officially an elite haxor! By successfully hacking other people you can earn GoodBoyTokenz. "
+ "Hacks take time to recover so check back in later once you've used all your hacks.") + "Hacks take time to recover so check back in later once you've used all your hacks.")
do! Async.Sleep 7000 do! Async.Sleep 7000
do! Message.sendFollowUpMessageWithButton event handleAttackMsg do! sendFollowUpMessageWithButton event handleAttackMsg
| None -> | None ->
do! sendMessage' $"Something went wrong, please contact a moderator" do! sendMessage' $"Something went wrong, please contact a moderator"
} }
@ -214,7 +214,7 @@ let handleTrainerStep6 (event : ComponentInteractionCreateEventArgs) =
let builder = DiscordFollowupMessageBuilder() let builder = DiscordFollowupMessageBuilder()
builder.IsEphemeral <- true builder.IsEphemeral <- true
builder.Content <- "Get out of here!" builder.Content <- "Get out of here!"
do! Message.updateMessageWithGreyedOutButtons event handleAttackMsg do! updateMessageWithGreyedOutButtons event handleAttackMsg
do! event.Interaction.CreateFollowupMessageAsync(builder) do! event.Interaction.CreateFollowupMessageAsync(builder)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore |> Async.Ignore
@ -230,6 +230,6 @@ let handleButtonEvent (event : ComponentInteractionCreateEventArgs) =
| 4 -> do! handleTrainerStep4 event | 4 -> do! handleTrainerStep4 event
| 5 -> do! handleAttack event | 5 -> do! handleAttack event
| 6 -> do! handleTrainerStep6 event | 6 -> do! handleTrainerStep6 event
| _ -> do! Message.sendFollowUpMessage event "No action found" | _ -> do! sendFollowUpMessage event "No action found"
} }

View File

@ -2,7 +2,8 @@
open System open System
open System.Collections.Generic open System.Collections.Generic
open Degenz.Shared open System.Threading.Tasks
open Degenz.Types
open MongoDB.Bson open MongoDB.Bson
open MongoDB.Bson.Serialization open MongoDB.Bson.Serialization
open MongoDB.Driver open MongoDB.Driver
@ -62,7 +63,7 @@ let private playerMap (player : PlayerData) = {
let private mapBack (player : PlayerEntry) : PlayerData = { let private mapBack (player : PlayerEntry) : PlayerData = {
DiscordId = player.DiscordId DiscordId = player.DiscordId
Name = player.Name Name = player.Name
Arsenal = player.Arsenal |> Array.map (fun w -> armoury |> Array.find (fun w' -> w = w'.Id)) Arsenal = player.Arsenal |> Array.map (fun w -> Armoury.battleItems |> Array.find (fun w' -> w = w'.Id))
Actions = Actions =
let atks = player.Attacks |> Array.map attackToAction let atks = player.Attacks |> Array.map attackToAction
let dfns = player.Defenses |> Array.map defenseToAction let dfns = player.Defenses |> Array.map defenseToAction
@ -113,6 +114,7 @@ let updatePlayer (player : PlayerData) =
return! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore return! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore
} }
//let getTopPlayers amount = //let getTopPlayers amount =
// async { // async {
// return! players.FindAsync() // return! players.FindAsync()

View File

@ -1,4 +1,4 @@
module Degenz.Shared namespace Degenz
open System open System
open DSharpPlus open DSharpPlus
@ -7,6 +7,9 @@ open DSharpPlus.EventArgs
open DSharpPlus.SlashCommands open DSharpPlus.SlashCommands
open Newtonsoft.Json open Newtonsoft.Json
[<Microsoft.FSharp.Core.AutoOpen>]
module Types =
[<Measure>] [<Measure>]
type mins type mins
@ -73,6 +76,14 @@ type PlayerData =
Actions : Action array Actions : Action array
Bank : int<GBT> } Bank : int<GBT> }
module Armoury =
let battleItems =
let file = System.IO.File.ReadAllText("Items.json")
JsonConvert.DeserializeObject<BattleItem array>(file)
let getItem itemId = battleItems |> Array.find (fun w -> w.Id = itemId)
module Player = module Player =
let hacks player = player.Arsenal |> Array.filter (fun bi -> bi.Type = Hack) let hacks player = player.Arsenal |> Array.filter (fun bi -> bi.Type = Hack)
let shields player = player.Arsenal |> Array.filter (fun bi -> bi.Type = Shield) let shields player = player.Arsenal |> Array.filter (fun bi -> bi.Type = Shield)
@ -81,24 +92,24 @@ module Player =
|> Array.choose (fun act -> match act.Type with Attack ar -> Some (act,ar.Target,ar.Result) | Defense -> None) |> Array.choose (fun act -> match act.Type with Attack ar -> Some (act,ar.Target,ar.Result) | Defense -> None)
let defenses player = player.Actions |> Array.filter (fun act -> match act.Type with Defense _ -> true | _ -> false) let defenses player = player.Actions |> Array.filter (fun act -> match act.Type with Defense _ -> true | _ -> false)
let removeExpiredActions actions =
actions
|> Array.filter (fun (act : Action) ->
let item = Armoury.battleItems |> Array.find (fun w -> w.Id = act.ActionId)
DateTime.UtcNow - act.Timestamp < TimeSpan.FromMinutes(int item.Cooldown))
let modifyBank player amount = { player with Bank = max (player.Bank + amount) 0<GBT> }
let getAttacksFlat actions = actions |> Array.choose (fun act -> match act.Type with Attack ar -> Some (act,ar.Target,ar.Result) | Defense -> None) let getAttacksFlat actions = actions |> Array.choose (fun act -> match act.Type with Attack ar -> Some (act,ar.Target,ar.Result) | Defense -> None)
let createSimpleResponseAsync msg (ctx: InteractionContext) =
async {
let builder = DiscordInteractionResponseBuilder()
builder.Content <- msg
builder.AsEphemeral true |> ignore
do! module Messaging =
ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) type InteractiveMessage = {
|> Async.AwaitTask ButtonId : string
ButtonText : string
Message : string
} }
let notYetAHackerMsg =
createSimpleResponseAsync "You are currently not a hacker, first use the /redpill command to become one"
let hackDescription = ""
let statusFormat p = let statusFormat p =
$"Hacks: {Player.hacks p |> Array.toList} $"Hacks: {Player.hacks p |> Array.toList}
Shields: {Player.shields p |> Array.toList} Shields: {Player.shields p |> Array.toList}
@ -110,19 +121,15 @@ let constructButtons (actionType: string) (playerInfo: string) (weapons: BattleI
weapons weapons
|> Array.map (fun w -> DiscordButtonComponent(ButtonStyle.Success, $"{actionType}-{w.Id}-{playerInfo}", $"{w.Name}")) |> Array.map (fun w -> DiscordButtonComponent(ButtonStyle.Success, $"{actionType}-{w.Id}-{playerInfo}", $"{w.Name}"))
let modifyPlayerBank player amount = { player with Bank = max (player.Bank + amount) 0<GBT> } let sendSimpleResponse (ctx: InteractionContext) msg =
async {
let armoury = let builder = DiscordInteractionResponseBuilder()
let file = System.IO.File.ReadAllText("Items.json") builder.Content <- msg
JsonConvert.DeserializeObject<BattleItem array>(file) builder.AsEphemeral true |> ignore
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
type InteractiveMessage = { |> Async.AwaitTask
ButtonId : string
ButtonText : string
Message : string
} }
module Message =
let sendFollowUpMessage (event : ComponentInteractionCreateEventArgs) msg = let sendFollowUpMessage (event : ComponentInteractionCreateEventArgs) msg =
async { async {
let builder = DiscordFollowupMessageBuilder() let builder = DiscordFollowupMessageBuilder()