Move some stuff around
This commit is contained in:
		
							parent
							
								
									69545bf3a6
								
							
						
					
					
						commit
						ef3d5c58f5
					
				@ -1,6 +1,5 @@
 | 
			
		||||
module Degenz.Bot
 | 
			
		||||
 | 
			
		||||
open System
 | 
			
		||||
open System.Threading.Tasks
 | 
			
		||||
open DSharpPlus
 | 
			
		||||
open DSharpPlus.SlashCommands
 | 
			
		||||
 | 
			
		||||
@ -11,8 +11,8 @@
 | 
			
		||||
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
			
		||||
    </Content>
 | 
			
		||||
    <Content Include="paket.references" />
 | 
			
		||||
    <Compile Include="GameConfig.fs" />
 | 
			
		||||
    <Compile Include="GuildEnvironment.fs" />
 | 
			
		||||
    <Compile Include="Game.fs" />
 | 
			
		||||
    <Compile Include="Embeds.fs" />
 | 
			
		||||
    <Compile Include="Store.fs" />
 | 
			
		||||
    <Compile Include="Trainer.fs" />
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
module Degenz.Embeds
 | 
			
		||||
 | 
			
		||||
open DSharpPlus.EventArgs
 | 
			
		||||
open Degenz.Shared
 | 
			
		||||
open Degenz.Types
 | 
			
		||||
open DSharpPlus.Entities
 | 
			
		||||
open AsciiTableFormatter
 | 
			
		||||
 | 
			
		||||
@ -34,7 +34,7 @@ let constructEmbed message =
 | 
			
		||||
 | 
			
		||||
let pickDefense actionId player =
 | 
			
		||||
    let buttons =
 | 
			
		||||
        constructButtons actionId (string player.DiscordId) (Player.shields player)
 | 
			
		||||
        Messaging.constructButtons actionId (string player.DiscordId) (Player.shields player)
 | 
			
		||||
        |> Seq.cast<DiscordComponent>
 | 
			
		||||
 | 
			
		||||
    let embed =
 | 
			
		||||
@ -50,7 +50,7 @@ let pickDefense actionId player =
 | 
			
		||||
 | 
			
		||||
let pickHack actionId attacker defender =
 | 
			
		||||
    let buttons =
 | 
			
		||||
        constructButtons actionId $"{defender.DiscordId}-{defender.Name}" (Player.hacks attacker)
 | 
			
		||||
        Messaging.constructButtons actionId $"{defender.DiscordId}-{defender.Name}" (Player.hacks attacker)
 | 
			
		||||
        |> Seq.cast<DiscordComponent>
 | 
			
		||||
 | 
			
		||||
    let embed =
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								Bot/Game.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								Bot/Game.fs
									
									
									
									
									
										Normal 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
 | 
			
		||||
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
module Degenz.GameConfig
 | 
			
		||||
@ -7,8 +7,7 @@ open DSharpPlus.Entities
 | 
			
		||||
open DSharpPlus.EventArgs
 | 
			
		||||
open DSharpPlus.SlashCommands
 | 
			
		||||
open Degenz
 | 
			
		||||
open Degenz.Shared
 | 
			
		||||
open Degenz.Store
 | 
			
		||||
open Degenz.Messaging
 | 
			
		||||
 | 
			
		||||
let getTimeTillCooldownFinishes (timespan : TimeSpan) timestamp =
 | 
			
		||||
    let timeRemaining = timespan - (DateTime.UtcNow - timestamp)
 | 
			
		||||
@ -26,8 +25,8 @@ let checkIfPlayerIsAttackingThemselves defender attacker  =
 | 
			
		||||
 | 
			
		||||
let checkForExistingHack defenderId attacker =
 | 
			
		||||
    attacker.Actions
 | 
			
		||||
    |> removeExpiredActions
 | 
			
		||||
    |> getAttacksFlat
 | 
			
		||||
    |> Player.removeExpiredActions
 | 
			
		||||
    |> Player.getAttacksFlat
 | 
			
		||||
    |> Array.tryFind (fun (_,t,_) -> t.Id = defenderId)
 | 
			
		||||
    |> function
 | 
			
		||||
       | Some ( atk , target , _ ) ->
 | 
			
		||||
@ -47,7 +46,7 @@ let checkIfHackHasCooldown hackId attacker =
 | 
			
		||||
        Ok attacker
 | 
			
		||||
    else
 | 
			
		||||
       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."
 | 
			
		||||
 | 
			
		||||
let checkIfInventoryIsEmpty attacker =
 | 
			
		||||
@ -62,8 +61,8 @@ let calculateDamage (hack : BattleItem) (shield : BattleItem) =
 | 
			
		||||
 | 
			
		||||
let runHackerBattle defender hack =
 | 
			
		||||
    Player.defenses defender
 | 
			
		||||
    |> removeExpiredActions
 | 
			
		||||
    |> Array.map (fun dfn -> armoury |> Array.find (fun w -> w.Id = dfn.ActionId))
 | 
			
		||||
    |> Player.removeExpiredActions
 | 
			
		||||
    |> Array.map (fun dfn -> Armoury.battleItems |> Array.find (fun w -> w.Id = dfn.ActionId))
 | 
			
		||||
    |> Array.map (calculateDamage (hack))
 | 
			
		||||
    |> 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 }
 | 
			
		||||
 | 
			
		||||
    [ DbService.updatePlayer <| updatePlayer prize attack attacker
 | 
			
		||||
      DbService.updatePlayer <| modifyPlayerBank defender -prize ]
 | 
			
		||||
      DbService.updatePlayer <| Player.modifyBank defender -prize ]
 | 
			
		||||
    |> Async.Parallel
 | 
			
		||||
    |> Async.Ignore
 | 
			
		||||
 | 
			
		||||
@ -115,11 +114,10 @@ let failedHack (event : ComponentInteractionCreateEventArgs) attacker defender h
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
let attack (ctx : InteractionContext) (target : DiscordUser) =
 | 
			
		||||
    async {
 | 
			
		||||
        let! attacker = DbService.tryFindPlayer ctx.Member.Id
 | 
			
		||||
    Game.executePlayerAction ctx (fun attacker -> async {
 | 
			
		||||
        let! defender = DbService.tryFindPlayer target.Id
 | 
			
		||||
        match attacker , defender with
 | 
			
		||||
        | Some attacker , Some defender ->
 | 
			
		||||
        match defender with
 | 
			
		||||
        | Some defender ->
 | 
			
		||||
            let hackAttempt =
 | 
			
		||||
                checkForExistingHack defender.DiscordId attacker
 | 
			
		||||
                |> Result.bind checkIfInventoryIsEmpty
 | 
			
		||||
@ -136,10 +134,8 @@ let attack (ctx : InteractionContext) (target : DiscordUser) =
 | 
			
		||||
                        .AsEphemeral(true)
 | 
			
		||||
                do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
			
		||||
                    |> Async.AwaitTask
 | 
			
		||||
        | None , _ -> do! notYetAHackerMsg ctx
 | 
			
		||||
        | _ , None -> do! createSimpleResponseAsync "Your target is not connected to the network, they must join first by using the /redpill command" ctx
 | 
			
		||||
    } |> Async.StartAsTask
 | 
			
		||||
    :> Task
 | 
			
		||||
        | 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) =
 | 
			
		||||
    async {
 | 
			
		||||
@ -155,7 +151,7 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
 | 
			
		||||
                |> Result.bind (checkIfHackHasCooldown (int hack))
 | 
			
		||||
                |> function
 | 
			
		||||
                   | Ok _ ->
 | 
			
		||||
                       runHackerBattle defender (getItemFromArmoury <| int hack)
 | 
			
		||||
                       runHackerBattle defender (Armoury.getItem (int hack))
 | 
			
		||||
                       |> function
 | 
			
		||||
                          | false -> successfulHack event attacker defender hack
 | 
			
		||||
                          | true -> failedHack event attacker defender hack
 | 
			
		||||
@ -175,10 +171,7 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
let defend (ctx : InteractionContext) =
 | 
			
		||||
    async {
 | 
			
		||||
        let! player = DbService.tryFindPlayer ctx.Member.Id
 | 
			
		||||
        match player with
 | 
			
		||||
        | Some player ->
 | 
			
		||||
    Game.executePlayerAction ctx (fun player -> async {
 | 
			
		||||
        if Player.shields player |> Array.length > 0 then
 | 
			
		||||
            let embed = Embeds.pickDefense "Defend" player
 | 
			
		||||
            do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed)
 | 
			
		||||
@ -189,9 +182,7 @@ let defend (ctx : InteractionContext) =
 | 
			
		||||
            builder.AsEphemeral true |> ignore
 | 
			
		||||
            do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
			
		||||
                |> Async.AwaitTask
 | 
			
		||||
        | None -> do! notYetAHackerMsg ctx
 | 
			
		||||
    } |> Async.StartAsTask
 | 
			
		||||
    :> Task
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
let handleDefense (event : ComponentInteractionCreateEventArgs) =
 | 
			
		||||
    async {
 | 
			
		||||
@ -200,7 +191,7 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
 | 
			
		||||
        let! playerResult = DbService.tryFindPlayer event.User.Id
 | 
			
		||||
        match playerResult with
 | 
			
		||||
        | 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)
 | 
			
		||||
 | 
			
		||||
            match alreadyUsedShield , updatedDefenses.Length < 2 with
 | 
			
		||||
 | 
			
		||||
@ -5,15 +5,15 @@ open DSharpPlus.Entities
 | 
			
		||||
open DSharpPlus
 | 
			
		||||
open DSharpPlus.SlashCommands
 | 
			
		||||
open Degenz.Store
 | 
			
		||||
open Degenz.Shared
 | 
			
		||||
open Degenz.Types
 | 
			
		||||
 | 
			
		||||
module Commands =
 | 
			
		||||
    let newPlayer nickname (membr : uint64) =
 | 
			
		||||
        let rand = System.Random(System.Guid.NewGuid().GetHashCode())
 | 
			
		||||
        let randHack = rand.Next(0, 3)
 | 
			
		||||
        let randShield = rand.Next(6, 9)
 | 
			
		||||
        let hack = armoury |> Array.find (fun i -> i.Id = randHack)
 | 
			
		||||
        let shield = armoury |> Array.find (fun i -> i.Id = randShield)
 | 
			
		||||
        let hack = Armoury.battleItems |> Array.find (fun i -> i.Id = randHack)
 | 
			
		||||
        let shield = Armoury.battleItems |> Array.find (fun i -> i.Id = randShield)
 | 
			
		||||
 | 
			
		||||
        { DiscordId = membr
 | 
			
		||||
          Name = nickname
 | 
			
		||||
@ -72,21 +72,16 @@ module Commands =
 | 
			
		||||
//        :> Task
 | 
			
		||||
 | 
			
		||||
    let status (ctx : InteractionContext) =
 | 
			
		||||
        async {
 | 
			
		||||
            let! maybePlayer = DbService.tryFindPlayer ctx.Member.Id
 | 
			
		||||
            match maybePlayer with
 | 
			
		||||
            | Some player ->
 | 
			
		||||
                let updatedActions = removeExpiredActions player.Actions
 | 
			
		||||
        Game.executePlayerAction ctx (fun player -> async {
 | 
			
		||||
            let updatedActions = Player.removeExpiredActions player.Actions
 | 
			
		||||
            let updatedPlayer = { player with Actions = updatedActions }
 | 
			
		||||
            let builder = DiscordInteractionResponseBuilder()
 | 
			
		||||
            builder.IsEphemeral <- true
 | 
			
		||||
                builder.Content <- statusFormat updatedPlayer
 | 
			
		||||
            builder.Content <- Messaging.statusFormat updatedPlayer
 | 
			
		||||
            do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
			
		||||
                |> Async.AwaitTask
 | 
			
		||||
            do! DbService.updatePlayer updatedPlayer
 | 
			
		||||
            | None -> do! notYetAHackerMsg ctx
 | 
			
		||||
        } |> Async.StartAsTask
 | 
			
		||||
        :> Task
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
type PlayerInteractions() =
 | 
			
		||||
    inherit ApplicationCommandModule ()
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ open System.Threading.Tasks
 | 
			
		||||
open DSharpPlus
 | 
			
		||||
open DSharpPlus.Entities
 | 
			
		||||
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" |]
 | 
			
		||||
 | 
			
		||||
@ -13,11 +13,8 @@ type SlotMachine() =
 | 
			
		||||
    inherit ApplicationCommandModule ()
 | 
			
		||||
 | 
			
		||||
    [<SlashCommand("spin", "Want to try your luck?")>]
 | 
			
		||||
    member this.AttackCommand (ctx : InteractionContext) =
 | 
			
		||||
        async {
 | 
			
		||||
            let! playerResult = DbService.tryFindPlayer ctx.Member.Id
 | 
			
		||||
            match playerResult with
 | 
			
		||||
            | Some player ->
 | 
			
		||||
    member this.Spin (ctx : InteractionContext) =
 | 
			
		||||
        Game.executePlayerAction ctx (fun player -> async {
 | 
			
		||||
            let sleepTime = 1000
 | 
			
		||||
            let random = Random(System.Guid.NewGuid().GetHashCode())
 | 
			
		||||
            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)
 | 
			
		||||
                    |> Async.AwaitTask
 | 
			
		||||
                    |> Async.Ignore
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
            | None -> do! notYetAHackerMsg ctx
 | 
			
		||||
 | 
			
		||||
        } |> Async.StartAsTask
 | 
			
		||||
        :> Task
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										86
									
								
								Bot/Store.fs
									
									
									
									
									
								
							
							
						
						
									
										86
									
								
								Bot/Store.fs
									
									
									
									
									
								
							@ -8,54 +8,27 @@ open DSharpPlus.EventArgs
 | 
			
		||||
open DSharpPlus.SlashCommands
 | 
			
		||||
open Degenz
 | 
			
		||||
open Degenz.Embeds
 | 
			
		||||
open Degenz.Shared
 | 
			
		||||
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))
 | 
			
		||||
open Degenz.Messaging
 | 
			
		||||
 | 
			
		||||
let viewStore (ctx : InteractionContext) =
 | 
			
		||||
    async {
 | 
			
		||||
        do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, Embeds.storeListing armoury)
 | 
			
		||||
        do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, Embeds.storeListing Armoury.battleItems)
 | 
			
		||||
            |> Async.AwaitTask
 | 
			
		||||
    } |> Async.StartAsTask
 | 
			
		||||
      :> Task
 | 
			
		||||
 | 
			
		||||
let buyItem (ctx : InteractionContext) itemId =
 | 
			
		||||
    async {
 | 
			
		||||
        let! playerResult = DbService.tryFindPlayer ctx.Member.Id
 | 
			
		||||
        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 buyItem (ctx : InteractionContext) itemType =
 | 
			
		||||
    Game.executePlayerAction ctx (fun player -> async {
 | 
			
		||||
        let embed = DiscordEmbedBuilder()
 | 
			
		||||
 | 
			
		||||
let constructItemButtons playerInfo itemType (items : 'a array) =
 | 
			
		||||
    items
 | 
			
		||||
    |> Seq.map (fun item -> DiscordButtonComponent(ButtonStyle.Primary, $"{playerInfo}-{itemType}-{item}", $"{item}"))
 | 
			
		||||
//        embed.Fields
 | 
			
		||||
 | 
			
		||||
        do! ctx.CreateResponseAsync(embed, true)
 | 
			
		||||
            |> Async.AwaitTask
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
let sell (ctx : InteractionContext) =
 | 
			
		||||
    async {
 | 
			
		||||
        let! playerResult = DbService.tryFindPlayer ctx.Member.Id
 | 
			
		||||
        match playerResult with
 | 
			
		||||
        | Some player ->
 | 
			
		||||
    Game.executePlayerAction ctx (fun player -> async {
 | 
			
		||||
        let hasInventoryToSell = Array.length player.Arsenal > 0
 | 
			
		||||
        if hasInventoryToSell then
 | 
			
		||||
            let builder = DiscordInteractionResponseBuilder()
 | 
			
		||||
@ -74,17 +47,12 @@ let sell (ctx : InteractionContext) =
 | 
			
		||||
            do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
			
		||||
                |> Async.AwaitTask
 | 
			
		||||
        else
 | 
			
		||||
                do! createSimpleResponseAsync "You currently have no inventory to sell" ctx
 | 
			
		||||
        | None -> do! notYetAHackerMsg ctx
 | 
			
		||||
        return ()
 | 
			
		||||
    } |> Async.StartAsTask
 | 
			
		||||
      :> Task
 | 
			
		||||
 | 
			
		||||
let updateArsenal player salePrice updatedArsenal = { player with Bank = player.Bank + salePrice ; Arsenal = updatedArsenal }
 | 
			
		||||
            do! sendSimpleResponse ctx "You currently have no inventory to sell"
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
let sellItem (event : ComponentInteractionCreateEventArgs) player itemId =
 | 
			
		||||
    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)}
 | 
			
		||||
        do! DbService.updatePlayer updatedPlayer
 | 
			
		||||
        let builder = DiscordInteractionResponseBuilder()
 | 
			
		||||
@ -94,6 +62,22 @@ let sellItem (event : ComponentInteractionCreateEventArgs) player itemId =
 | 
			
		||||
            |> 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) =
 | 
			
		||||
    async {
 | 
			
		||||
        let! playerResult = DbService.tryFindPlayer event.User.Id
 | 
			
		||||
@ -112,17 +96,15 @@ let handleSellButtonEvents (_ : DiscordClient) (event : ComponentInteractionCrea
 | 
			
		||||
 | 
			
		||||
type Store() =
 | 
			
		||||
    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")>]
 | 
			
		||||
    member _.BuyHack (ctx : InteractionContext, [<Option("hack-id", "The ID of the hack you wish to purchase")>] hackId : HackId) =
 | 
			
		||||
        buyItem ctx (int hackId)
 | 
			
		||||
    member _.BuyHack (ctx : InteractionContext) = buyItem ctx Hack
 | 
			
		||||
 | 
			
		||||
    [<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) =
 | 
			
		||||
        buyItem ctx (int shieldId)
 | 
			
		||||
    member this.BuyShield (ctx : InteractionContext) = buyItem ctx Shield
 | 
			
		||||
 | 
			
		||||
    [<SlashCommand("sell", "Sell an item in your inventory for GoodBoyTokenz")>]
 | 
			
		||||
    member this.SellItem (ctx : InteractionContext) = sell ctx
 | 
			
		||||
 | 
			
		||||
@ -5,11 +5,11 @@ open DSharpPlus
 | 
			
		||||
open DSharpPlus.Entities
 | 
			
		||||
open DSharpPlus.EventArgs
 | 
			
		||||
open DSharpPlus.SlashCommands
 | 
			
		||||
open Degenz.Shared
 | 
			
		||||
open Degenz.Store
 | 
			
		||||
open Degenz.Types
 | 
			
		||||
open Degenz.Messaging
 | 
			
		||||
 | 
			
		||||
let defaultHack = armoury |> Array.find (fun i -> i.Id = int HackId.Virus)
 | 
			
		||||
let defaultShield = armoury |> Array.find (fun i -> i.Id = int ShieldId.Firewall)
 | 
			
		||||
let defaultHack = Armoury.battleItems |> Array.find (fun i -> i.Id = int HackId.Virus)
 | 
			
		||||
let defaultShield = Armoury.battleItems |> Array.find (fun i -> i.Id = int ShieldId.Firewall)
 | 
			
		||||
 | 
			
		||||
let sendInitialEmbed (client : DiscordClient)  =
 | 
			
		||||
    async {
 | 
			
		||||
@ -41,10 +41,10 @@ let handleTrainerStep1 (event : ComponentInteractionCreateEventArgs) =
 | 
			
		||||
            |> Async.AwaitTask
 | 
			
		||||
        match maybePlayer with
 | 
			
		||||
        | Some _ ->
 | 
			
		||||
            do! Message.sendFollowUpMessageWithButton event step1Msg
 | 
			
		||||
            do! sendFollowUpMessageWithButton event step1Msg
 | 
			
		||||
        | None ->
 | 
			
		||||
            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) =
 | 
			
		||||
@ -53,19 +53,19 @@ let handleTrainerStep2 (event : ComponentInteractionCreateEventArgs) =
 | 
			
		||||
        match result with
 | 
			
		||||
        | Some player ->
 | 
			
		||||
            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 =
 | 
			
		||||
                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"
 | 
			
		||||
                    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. "
 | 
			
		||||
                     + $"{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}'.")
 | 
			
		||||
        | 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) =
 | 
			
		||||
@ -100,7 +100,7 @@ let handleDefenseMsg = {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let handleDefense (event : ComponentInteractionCreateEventArgs) =
 | 
			
		||||
    let sendMessage' = Message.sendFollowUpMessage event
 | 
			
		||||
    let sendMessage' = sendFollowUpMessage event
 | 
			
		||||
    async {
 | 
			
		||||
        do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate)
 | 
			
		||||
            |> Async.AwaitTask
 | 
			
		||||
@ -116,7 +116,7 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
 | 
			
		||||
            do! Async.Sleep 4000
 | 
			
		||||
            do! sendMessage' $"Hacking attempt failed! {player.Name} defended hack from Degenz-Trainer and took {prize} from them! "
 | 
			
		||||
            do! Async.Sleep 3000
 | 
			
		||||
            do! Message.sendFollowUpMessageWithButton event handleDefenseMsg
 | 
			
		||||
            do! sendFollowUpMessageWithButton event handleDefenseMsg
 | 
			
		||||
        | None ->
 | 
			
		||||
            do! sendMessage' $"Something went wrong, please contact a moderator"
 | 
			
		||||
    }
 | 
			
		||||
@ -127,19 +127,19 @@ let handleTrainerStep4 (event : ComponentInteractionCreateEventArgs) =
 | 
			
		||||
        match result with
 | 
			
		||||
        | Some player ->
 | 
			
		||||
            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 =
 | 
			
		||||
                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"
 | 
			
		||||
                    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, "
 | 
			
		||||
                  + $" 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.")
 | 
			
		||||
        | 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) =
 | 
			
		||||
@ -184,7 +184,7 @@ let handleAttackMsg = {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let handleAttack (event : ComponentInteractionCreateEventArgs) =
 | 
			
		||||
    let sendMessage' = Message.sendFollowUpMessage event
 | 
			
		||||
    let sendMessage' = sendFollowUpMessage event
 | 
			
		||||
    async {
 | 
			
		||||
        do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate)
 | 
			
		||||
            |> 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. "
 | 
			
		||||
                              + "Hacks take time to recover so check back in later once you've used all your hacks.")
 | 
			
		||||
            do! Async.Sleep 7000
 | 
			
		||||
            do! Message.sendFollowUpMessageWithButton event handleAttackMsg
 | 
			
		||||
            do! sendFollowUpMessageWithButton event handleAttackMsg
 | 
			
		||||
        | None ->
 | 
			
		||||
            do! sendMessage' $"Something went wrong, please contact a moderator"
 | 
			
		||||
    }
 | 
			
		||||
@ -214,7 +214,7 @@ let handleTrainerStep6 (event : ComponentInteractionCreateEventArgs) =
 | 
			
		||||
        let builder = DiscordFollowupMessageBuilder()
 | 
			
		||||
        builder.IsEphemeral <- true
 | 
			
		||||
        builder.Content <- "Get out of here!"
 | 
			
		||||
        do! Message.updateMessageWithGreyedOutButtons event handleAttackMsg
 | 
			
		||||
        do! updateMessageWithGreyedOutButtons event handleAttackMsg
 | 
			
		||||
        do! event.Interaction.CreateFollowupMessageAsync(builder)
 | 
			
		||||
            |> Async.AwaitTask
 | 
			
		||||
            |> Async.Ignore
 | 
			
		||||
@ -230,6 +230,6 @@ let handleButtonEvent (event : ComponentInteractionCreateEventArgs) =
 | 
			
		||||
        | 4 -> do! handleTrainerStep4 event
 | 
			
		||||
        | 5 -> do! handleAttack event
 | 
			
		||||
        | 6 -> do! handleTrainerStep6 event
 | 
			
		||||
        | _ -> do! Message.sendFollowUpMessage event "No action found"
 | 
			
		||||
        | _ -> do! sendFollowUpMessage event "No action found"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,8 @@
 | 
			
		||||
 | 
			
		||||
open System
 | 
			
		||||
open System.Collections.Generic
 | 
			
		||||
open Degenz.Shared
 | 
			
		||||
open System.Threading.Tasks
 | 
			
		||||
open Degenz.Types
 | 
			
		||||
open MongoDB.Bson
 | 
			
		||||
open MongoDB.Bson.Serialization
 | 
			
		||||
open MongoDB.Driver
 | 
			
		||||
@ -62,7 +63,7 @@ let private playerMap (player : PlayerData) = {
 | 
			
		||||
let private mapBack (player : PlayerEntry) : PlayerData = {
 | 
			
		||||
    DiscordId = player.DiscordId
 | 
			
		||||
    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 =
 | 
			
		||||
        let atks = player.Attacks |> Array.map attackToAction
 | 
			
		||||
        let dfns = player.Defenses |> Array.map defenseToAction
 | 
			
		||||
@ -113,6 +114,7 @@ let updatePlayer (player : PlayerData) =
 | 
			
		||||
        return! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//let getTopPlayers amount =
 | 
			
		||||
//    async {
 | 
			
		||||
//        return! players.FindAsync()
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
module Degenz.Shared
 | 
			
		||||
namespace Degenz
 | 
			
		||||
 | 
			
		||||
open System
 | 
			
		||||
open DSharpPlus
 | 
			
		||||
@ -7,6 +7,9 @@ open DSharpPlus.EventArgs
 | 
			
		||||
open DSharpPlus.SlashCommands
 | 
			
		||||
open Newtonsoft.Json
 | 
			
		||||
 | 
			
		||||
[<Microsoft.FSharp.Core.AutoOpen>]
 | 
			
		||||
module Types =
 | 
			
		||||
 | 
			
		||||
    [<Measure>]
 | 
			
		||||
    type mins
 | 
			
		||||
 | 
			
		||||
@ -73,6 +76,14 @@ type PlayerData =
 | 
			
		||||
          Actions : Action array
 | 
			
		||||
          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 =
 | 
			
		||||
    let hacks player = player.Arsenal |> Array.filter (fun bi -> bi.Type = Hack)
 | 
			
		||||
    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)
 | 
			
		||||
    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 createSimpleResponseAsync msg (ctx: InteractionContext) =
 | 
			
		||||
    async {
 | 
			
		||||
        let builder = DiscordInteractionResponseBuilder()
 | 
			
		||||
        builder.Content <- msg
 | 
			
		||||
        builder.AsEphemeral true |> ignore
 | 
			
		||||
 | 
			
		||||
        do!
 | 
			
		||||
            ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
			
		||||
            |> Async.AwaitTask
 | 
			
		||||
module Messaging =
 | 
			
		||||
    type InteractiveMessage = {
 | 
			
		||||
        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 =
 | 
			
		||||
        $"Hacks: {Player.hacks p |> Array.toList}
 | 
			
		||||
    Shields: {Player.shields p |> Array.toList}
 | 
			
		||||
@ -110,19 +121,15 @@ let constructButtons (actionType: string) (playerInfo: string) (weapons: BattleI
 | 
			
		||||
        weapons
 | 
			
		||||
        |> 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 armoury =
 | 
			
		||||
    let file = System.IO.File.ReadAllText("Items.json")
 | 
			
		||||
    JsonConvert.DeserializeObject<BattleItem array>(file)
 | 
			
		||||
 | 
			
		||||
type InteractiveMessage = {
 | 
			
		||||
    ButtonId : string
 | 
			
		||||
    ButtonText : string
 | 
			
		||||
    Message : string
 | 
			
		||||
    let sendSimpleResponse (ctx: InteractionContext) msg =
 | 
			
		||||
        async {
 | 
			
		||||
            let builder = DiscordInteractionResponseBuilder()
 | 
			
		||||
            builder.Content <- msg
 | 
			
		||||
            builder.AsEphemeral true |> ignore
 | 
			
		||||
            do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
			
		||||
                |> Async.AwaitTask
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
module Message =
 | 
			
		||||
    let sendFollowUpMessage (event : ComponentInteractionCreateEventArgs) msg =
 | 
			
		||||
        async {
 | 
			
		||||
            let builder = DiscordFollowupMessageBuilder()
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user