Major refactor for new BattleItem/Action data models
This commit is contained in:
		
							parent
							
								
									d1cf329521
								
							
						
					
					
						commit
						7c8a460d5b
					
				
							
								
								
									
										102
									
								
								Bot/Embeds.fs
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								Bot/Embeds.fs
									
									
									
									
									
								
							@ -5,23 +5,27 @@ open Degenz.Shared
 | 
				
			|||||||
open DSharpPlus.Entities
 | 
					open DSharpPlus.Entities
 | 
				
			||||||
open AsciiTableFormatter
 | 
					open AsciiTableFormatter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let hackGif = "https://s10.gifyu.com/images/Hacker-Degenz-V2.gif"
 | 
				
			||||||
 | 
					let shieldGif = "https://s10.gifyu.com/images/Defense-Degenz-V2.gif"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let getHackGif = function
 | 
					let getHackGif = function
 | 
				
			||||||
    | Hack.Virus -> "https://s10.gifyu.com/images/Attack-DegenZ.gif"
 | 
					    | HackId.Virus -> "https://s10.gifyu.com/images/Attack-DegenZ.gif"
 | 
				
			||||||
    | Hack.Ransom -> "https://s10.gifyu.com/images/Mind-Control-Degenz-V2.gif"
 | 
					    | HackId.Ransom -> "https://s10.gifyu.com/images/Mind-Control-Degenz-V2.gif"
 | 
				
			||||||
    | Hack.Worm -> "https://s10.gifyu.com/images/WormBugAttack_Degenz.gif"
 | 
					    | HackId.Worm -> "https://s10.gifyu.com/images/WormBugAttack_Degenz.gif"
 | 
				
			||||||
    | Hack.DDos -> "https://s10.gifyu.com/images/Attack-DegenZ.gif"
 | 
					    | HackId.DDos -> "https://s10.gifyu.com/images/Attack-DegenZ.gif"
 | 
				
			||||||
    | Hack.Crack -> "https://s10.gifyu.com/images/Attack-DegenZ.gif"
 | 
					    | HackId.Crack -> "https://s10.gifyu.com/images/Attack-DegenZ.gif"
 | 
				
			||||||
    | Hack.Injection -> "https://s10.gifyu.com/images/Attack-DegenZ.gif"
 | 
					    | HackId.Injection -> "https://s10.gifyu.com/images/Attack-DegenZ.gif"
 | 
				
			||||||
    | _ -> "https://s10.gifyu.com/images/Hacker-Degenz-V2.gif"
 | 
					    | _ -> hackGif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let getShieldGif = function
 | 
					let getShieldGif = function
 | 
				
			||||||
    | Shield.Firewall -> "https://s10.gifyu.com/images/Defense-GIF-1-Degenz.gif"
 | 
					    | ShieldId.Firewall -> "https://s10.gifyu.com/images/Defense-GIF-1-Degenz.gif"
 | 
				
			||||||
    | Shield.PortScan -> "https://s10.gifyu.com/images/PortScanDefense_Degenz.gif"
 | 
					    | ShieldId.PortScan -> "https://s10.gifyu.com/images/PortScanDefense_Degenz.gif"
 | 
				
			||||||
    | Shield.Encryption -> "https://s10.gifyu.com/images/Anonymous-Degenz-V2.gif"
 | 
					    | ShieldId.Encryption -> "https://s10.gifyu.com/images/Anonymous-Degenz-V2.gif"
 | 
				
			||||||
    | Shield.Hardening -> "https://s10.gifyu.com/images/Encryption-Degenz-V2.gif"
 | 
					    | ShieldId.Hardening -> "https://s10.gifyu.com/images/Encryption-Degenz-V2.gif"
 | 
				
			||||||
    | Shield.Sanitation -> "https://s10.gifyu.com/images/VPN-Degenz.gif"
 | 
					    | ShieldId.Sanitation -> "https://s10.gifyu.com/images/VPN-Degenz.gif"
 | 
				
			||||||
    | Shield.Cypher -> "https://s10.gifyu.com/images/Matrix_Degenz.gif"
 | 
					    | ShieldId.Cypher -> "https://s10.gifyu.com/images/Matrix_Degenz.gif"
 | 
				
			||||||
    | _ -> "https://s10.gifyu.com/images/Hacker-Degenz-V2.gif"
 | 
					    | _ -> shieldGif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let constructEmbed message =
 | 
					let constructEmbed message =
 | 
				
			||||||
    let builder = DiscordEmbedBuilder()
 | 
					    let builder = DiscordEmbedBuilder()
 | 
				
			||||||
@ -36,14 +40,14 @@ let constructEmbed message =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
let pickDefense actionId player =
 | 
					let pickDefense actionId player =
 | 
				
			||||||
    let buttons =
 | 
					    let buttons =
 | 
				
			||||||
        constructButtons actionId (string player.DiscordId) player.Shields
 | 
					        constructButtons actionId (string player.DiscordId) (Player.shields player)
 | 
				
			||||||
        |> Seq.cast<DiscordComponent>
 | 
					        |> Seq.cast<DiscordComponent>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let embed =
 | 
					    let embed =
 | 
				
			||||||
        DiscordEmbedBuilder()
 | 
					        DiscordEmbedBuilder()
 | 
				
			||||||
            .WithColor(DiscordColor.Blurple)
 | 
					            .WithColor(DiscordColor.Blurple)
 | 
				
			||||||
            .WithDescription("Pick a defense to mount for 10 hours")
 | 
					            .WithDescription("Pick a defense to mount for 10 hours")
 | 
				
			||||||
            .WithImageUrl("https://s10.gifyu.com/images/Defense-Degenz-V2.gif")
 | 
					            .WithImageUrl(shieldGif)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DiscordInteractionResponseBuilder()
 | 
					    DiscordInteractionResponseBuilder()
 | 
				
			||||||
        .AddComponents(buttons)
 | 
					        .AddComponents(buttons)
 | 
				
			||||||
@ -52,37 +56,61 @@ let pickDefense actionId player =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
let pickHack actionId attacker defender =
 | 
					let pickHack actionId attacker defender =
 | 
				
			||||||
    let buttons =
 | 
					    let buttons =
 | 
				
			||||||
        constructButtons actionId $"{defender.DiscordId}-{defender.Name}" attacker.Weapons
 | 
					        constructButtons actionId $"{defender.DiscordId}-{defender.Name}" (Player.hacks attacker)
 | 
				
			||||||
        |> Seq.cast<DiscordComponent>
 | 
					        |> Seq.cast<DiscordComponent>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let embed =
 | 
					    let embed =
 | 
				
			||||||
        DiscordEmbedBuilder()
 | 
					        DiscordEmbedBuilder()
 | 
				
			||||||
            .WithColor(DiscordColor.Blurple)
 | 
					            .WithColor(DiscordColor.Blurple)
 | 
				
			||||||
            .WithDescription("Pick the hack that you want to use")
 | 
					            .WithDescription("Pick the hack that you want to use")
 | 
				
			||||||
            .WithImageUrl("https://s10.gifyu.com/images/Hacker-Degenz-V2.gif")
 | 
					            .WithImageUrl(hackGif)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DiscordInteractionResponseBuilder()
 | 
					    DiscordInteractionResponseBuilder()
 | 
				
			||||||
        .AddComponents(buttons)
 | 
					        .AddComponents(buttons)
 | 
				
			||||||
        .AddEmbed(embed.Build())
 | 
					        .AddEmbed(embed.Build())
 | 
				
			||||||
        .AsEphemeral true
 | 
					        .AsEphemeral true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let eventSuccessfulHack (event : ComponentInteractionCreateEventArgs) targetId prize =
 | 
					let responseSuccessfulHack defenderName hack prize =
 | 
				
			||||||
    let embed =
 | 
					    let embed = DiscordEmbedBuilder()
 | 
				
			||||||
        DiscordEmbedBuilder()
 | 
					    embed.ImageUrl <- getHackGif hack
 | 
				
			||||||
            .WithColor(DiscordColor.Blurple)
 | 
					 | 
				
			||||||
            .WithDescription("Pick the hack that you want to use")
 | 
					 | 
				
			||||||
            .WithImageUrl("https://s10.gifyu.com/images/Hacker-Degenz-V2.gif")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DiscordInteractionResponseBuilder()
 | 
				
			||||||
 | 
					        .WithContent($"Successfully hacked {defenderName} using {hack}! You just won {prize} GoodBoyTokenz!")
 | 
				
			||||||
 | 
					        .AddEmbed(embed.Build())
 | 
				
			||||||
 | 
					        .AsEphemeral(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let responseSuccessfulHackTrainer defenderName (hack : BattleItem) prize =
 | 
				
			||||||
 | 
					    let embed = DiscordEmbedBuilder()
 | 
				
			||||||
 | 
					    embed.ImageUrl <- getHackGif (enum<HackId>(hack.Id))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DiscordFollowupMessageBuilder()
 | 
				
			||||||
 | 
					        .WithContent($"Successfully hacked {defenderName} using {hack}! You just won {prize} GoodBoyTokenz!")
 | 
				
			||||||
 | 
					        .AddEmbed(embed.Build())
 | 
				
			||||||
 | 
					        .AsEphemeral(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let responseCreatedShield shield =
 | 
				
			||||||
 | 
					    DiscordInteractionResponseBuilder()
 | 
				
			||||||
 | 
					        .AddEmbed(DiscordEmbedBuilder().WithImageUrl(getShieldGif shield))
 | 
				
			||||||
 | 
					        .AsEphemeral(true)
 | 
				
			||||||
 | 
					        .WithContent($"Mounted a {shield} defense for 6 hours")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let responseCreatedShieldTrainer (shield : BattleItem) =
 | 
				
			||||||
 | 
					    DiscordFollowupMessageBuilder()
 | 
				
			||||||
 | 
					        .AddEmbed(DiscordEmbedBuilder().WithImageUrl(getShieldGif (enum<ShieldId>(shield.Id))))
 | 
				
			||||||
 | 
					        .AsEphemeral(true)
 | 
				
			||||||
 | 
					        .WithContent($"Mounted a {shield.Name} defense for 6 hours")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let eventSuccessfulHack (event : ComponentInteractionCreateEventArgs) targetId prize =
 | 
				
			||||||
    DiscordMessageBuilder()
 | 
					    DiscordMessageBuilder()
 | 
				
			||||||
        .WithContent($"{event.User.Username} successfully hacked <@{targetId}> for a total of {prize} GoodBoyTokenz")
 | 
					        .WithContent($"{event.User.Username} successfully hacked <@{targetId}> for a total of {prize} GoodBoyTokenz")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let eventFailedHack (event : ComponentInteractionCreateEventArgs) targetId prize =
 | 
					let eventFailedHack (event : ComponentInteractionCreateEventArgs) targetId prize =
 | 
				
			||||||
    let embed =
 | 
					//    let embed =
 | 
				
			||||||
        DiscordEmbedBuilder()
 | 
					//        DiscordEmbedBuilder()
 | 
				
			||||||
            .WithColor(DiscordColor.Blurple)
 | 
					//            .WithColor(DiscordColor.Blurple)
 | 
				
			||||||
            .WithDescription("Pick the hack that you want to use")
 | 
					//            .WithDescription("Pick the hack that you want to use")
 | 
				
			||||||
            .WithImageUrl("https://s10.gifyu.com/images/Hacker-Degenz-V2.gif")
 | 
					//            .WithImageUrl(hackGif)
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
    DiscordMessageBuilder()
 | 
					    DiscordMessageBuilder()
 | 
				
			||||||
        .WithContent($"{event.User.Username} successfully hacked <@{targetId}> for a total of {prize} GoodBoyTokenz")
 | 
					        .WithContent($"{event.User.Username} successfully hacked <@{targetId}> for a total of {prize} GoodBoyTokenz")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -96,20 +124,10 @@ type Table = {
 | 
				
			|||||||
let storeListing store =
 | 
					let storeListing store =
 | 
				
			||||||
    let embeds =
 | 
					    let embeds =
 | 
				
			||||||
        store
 | 
					        store
 | 
				
			||||||
 | 
					        |> Array.groupBy (fun (bi : BattleItem) -> bi.Type)
 | 
				
			||||||
        |> Array.map (fun ( itemType , items ) ->
 | 
					        |> Array.map (fun ( itemType , items ) ->
 | 
				
			||||||
            items
 | 
					            items
 | 
				
			||||||
            |> Array.map (fun (item : Item) ->
 | 
					            |> Array.map (fun item -> { Name = item.Name ; Cost = string item.Cost ; Class = string item.Class })
 | 
				
			||||||
                let itemClass =
 | 
					 | 
				
			||||||
                    if itemType = ItemType.Hack
 | 
					 | 
				
			||||||
                        then hackInventory
 | 
					 | 
				
			||||||
                             |> Array.find (fun w -> item.Name = string w)
 | 
					 | 
				
			||||||
                             |> int
 | 
					 | 
				
			||||||
                             |> getClass
 | 
					 | 
				
			||||||
                        else shieldInventory
 | 
					 | 
				
			||||||
                             |> Array.find (fun w -> item.Name = string w)
 | 
					 | 
				
			||||||
                             |> int
 | 
					 | 
				
			||||||
                             |> getClass
 | 
					 | 
				
			||||||
                { Name = item.Name ; Cost = string item.Cost ; Class = string itemClass })
 | 
					 | 
				
			||||||
            |> Formatter.Format
 | 
					            |> Formatter.Format
 | 
				
			||||||
            |> sprintf "**%As**\n``` %s ```" itemType
 | 
					            |> sprintf "**%As**\n``` %s ```" itemType
 | 
				
			||||||
            |> constructEmbed)
 | 
					            |> constructEmbed)
 | 
				
			||||||
 | 
				
			|||||||
@ -25,22 +25,21 @@ let checkIfPlayerIsAttackingThemselves defender attacker  =
 | 
				
			|||||||
    | false -> Ok attacker
 | 
					    | false -> Ok attacker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let checkForExistingHack defenderId attacker =
 | 
					let checkForExistingHack defenderId attacker =
 | 
				
			||||||
    let updatedAttacks =
 | 
					    attacker.Actions
 | 
				
			||||||
        attacker.Attacks
 | 
					    |> removeExpiredActions
 | 
				
			||||||
        |> removeExpiredActions (TimeSpan.FromHours(24)) (fun atk -> atk.Timestamp)
 | 
					    |> getAttacksFlat
 | 
				
			||||||
    updatedAttacks
 | 
					    |> Array.tryFind (fun (_,t,_) -> t.Id = defenderId)
 | 
				
			||||||
    |> Array.tryFind (fun a -> a.Target.Id = defenderId)
 | 
					 | 
				
			||||||
    |> function
 | 
					    |> function
 | 
				
			||||||
       | Some attack ->
 | 
					       | Some ( atk , target , _ ) ->
 | 
				
			||||||
           let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromHours(24)) attack.Timestamp
 | 
					           let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromHours(24)) atk.Timestamp
 | 
				
			||||||
           Error $"You can only hack the same target once every 24 hours, wait {cooldown} to attempt another hack on {attack.Target.Name}."
 | 
					           Error $"You can only hack the same target once every 24 hours, wait {cooldown} to attempt another hack on {target.Name}."
 | 
				
			||||||
       | None ->
 | 
					       | None ->
 | 
				
			||||||
           Ok attacker
 | 
					           Ok attacker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let checkIfHackHasCooldown hack attacker =
 | 
					let checkIfHackHasCooldown hackId attacker =
 | 
				
			||||||
    let mostRecentHackAttack =
 | 
					    let mostRecentHackAttack =
 | 
				
			||||||
        attacker.Attacks
 | 
					        attacker.Actions
 | 
				
			||||||
        |> Array.tryFind (fun a -> a.HackType = hack)
 | 
					        |> Array.tryFind (fun a -> a.ActionId = hackId)
 | 
				
			||||||
        |> function
 | 
					        |> function
 | 
				
			||||||
           | Some a -> a.Timestamp
 | 
					           | Some a -> a.Timestamp
 | 
				
			||||||
           | None -> DateTime.MinValue
 | 
					           | None -> DateTime.MinValue
 | 
				
			||||||
@ -48,33 +47,31 @@ let checkIfHackHasCooldown hack attacker =
 | 
				
			|||||||
        Ok attacker
 | 
					        Ok attacker
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
       let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromMinutes(5)) mostRecentHackAttack
 | 
					       let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromMinutes(5)) mostRecentHackAttack
 | 
				
			||||||
       Error $"{hack} is currently on cooldown, wait {cooldown} to use it again."
 | 
					       let item = armoury |> Array.find (fun i -> i.Id = hackId)
 | 
				
			||||||
 | 
					       Error $"{item.Name} is currently on cooldown, wait {cooldown} to use it again."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let checkIfInventoryIsEmpty attacker =
 | 
					let checkIfInventoryIsEmpty attacker =
 | 
				
			||||||
    match attacker.Weapons with
 | 
					    match attacker.Arsenal with
 | 
				
			||||||
    | [||] -> Error $"You currently do not have any Hacks to use against others. Please go to the store and purchase one."
 | 
					    | [||] -> Error $"You currently do not have any Hacks to use against others. Please go to the store and purchase one."
 | 
				
			||||||
    | _ -> Ok attacker
 | 
					    | _ -> Ok attacker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let calculateDamage (hack: int) (shield: int) =
 | 
					let calculateDamage (hack : BattleItem) (shield : BattleItem) =
 | 
				
			||||||
    let hackClass = getClass hack
 | 
					    if hack.Power > shield.Power
 | 
				
			||||||
    let protectionClass = getClass shield
 | 
					        then Strong
 | 
				
			||||||
 | 
					        else Weak
 | 
				
			||||||
    match hackClass, protectionClass with
 | 
					 | 
				
			||||||
    | h, p when h = p -> Weak
 | 
					 | 
				
			||||||
    | _ -> Strong
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
let runHackerBattle defender hack =
 | 
					let runHackerBattle defender hack =
 | 
				
			||||||
    defender.Defenses
 | 
					    Player.defenses defender
 | 
				
			||||||
    |> removeExpiredActions (TimeSpan.FromHours(6)) (fun (pro : Defense) -> pro.Timestamp)
 | 
					    |> removeExpiredActions
 | 
				
			||||||
    |> Seq.toArray
 | 
					    |> Array.map (fun dfn -> armoury |> Array.find (fun w -> w.Id = dfn.ActionId))
 | 
				
			||||||
    |> Array.map (fun dfn -> int dfn.DefenseType)
 | 
					    |> Array.map (calculateDamage (hack))
 | 
				
			||||||
    |> Array.map (calculateDamage (int hack))
 | 
					 | 
				
			||||||
    |> Array.contains Weak
 | 
					    |> Array.contains Weak
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let updateCombatants attacker defender hack prize =
 | 
					let updateCombatants attacker defender hack prize =
 | 
				
			||||||
    let updatePlayer amount attack p =
 | 
					    let updatePlayer amount attack p =
 | 
				
			||||||
       { p with Attacks = Array.append [| attack |] p.Attacks ; Bank = Math.Max(p.Bank + amount, 0) }
 | 
					       { p with Actions = Array.append [| attack |] p.Actions ; Bank = max (p.Bank + amount) 0<GBT> }
 | 
				
			||||||
   let attack = { HackType = enum<Hack>(int hack) ; Timestamp = DateTime.UtcNow ; Target = { Id = defender.DiscordId ; Name = defender.Name } }
 | 
					    let target = { Id = defender.DiscordId ; Name = defender.Name }
 | 
				
			||||||
 | 
					    let attack = { ActionId = int hack ; Type = Attack ( target , 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 <| modifyPlayerBank defender -prize ]
 | 
				
			||||||
@ -83,7 +80,7 @@ let updateCombatants attacker defender hack prize =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
let successfulHack (event : ComponentInteractionCreateEventArgs) attacker defender hack =
 | 
					let successfulHack (event : ComponentInteractionCreateEventArgs) attacker defender hack =
 | 
				
			||||||
    async {
 | 
					    async {
 | 
				
			||||||
        let prize = 3
 | 
					        let prize = 3<GBT>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        do! updateCombatants attacker defender hack prize
 | 
					        do! updateCombatants attacker defender hack prize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -101,7 +98,7 @@ let successfulHack (event : ComponentInteractionCreateEventArgs) attacker defend
 | 
				
			|||||||
let failedHack (event : ComponentInteractionCreateEventArgs) attacker defender hack =
 | 
					let failedHack (event : ComponentInteractionCreateEventArgs) attacker defender hack =
 | 
				
			||||||
    async {
 | 
					    async {
 | 
				
			||||||
        let builder = DiscordInteractionResponseBuilder()
 | 
					        let builder = DiscordInteractionResponseBuilder()
 | 
				
			||||||
        let prize = 2
 | 
					        let prize = 2<GBT>
 | 
				
			||||||
        builder.IsEphemeral <- true
 | 
					        builder.IsEphemeral <- true
 | 
				
			||||||
        builder.Content <- $"Hack failed! {defender.Name} was able to mount a successful defense! You lost {prize} GoodBoyTokenz!"
 | 
					        builder.Content <- $"Hack failed! {defender.Name} was able to mount a successful defense! You lost {prize} GoodBoyTokenz!"
 | 
				
			||||||
        do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
					        do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
				
			||||||
@ -147,7 +144,7 @@ let attack (ctx : InteractionContext) (target : DiscordUser) =
 | 
				
			|||||||
let handleAttack (event : ComponentInteractionCreateEventArgs) =
 | 
					let handleAttack (event : ComponentInteractionCreateEventArgs) =
 | 
				
			||||||
    async {
 | 
					    async {
 | 
				
			||||||
        let split = event.Id.Split("-")
 | 
					        let split = event.Id.Split("-")
 | 
				
			||||||
        let hack = Enum.Parse(typedefof<Hack>, split.[1]) :?> Hack
 | 
					        let hack = enum<HackId>(int split.[1])
 | 
				
			||||||
        let ( resultId , targetId ) = UInt64.TryParse split.[2]
 | 
					        let ( resultId , targetId ) = UInt64.TryParse split.[2]
 | 
				
			||||||
        let! resultPlayer = DbService.tryFindPlayer event.User.Id
 | 
					        let! resultPlayer = DbService.tryFindPlayer event.User.Id
 | 
				
			||||||
        let! resultTarget = DbService.tryFindPlayer targetId
 | 
					        let! resultTarget = DbService.tryFindPlayer targetId
 | 
				
			||||||
@ -155,10 +152,10 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
 | 
				
			|||||||
        match resultPlayer , resultTarget , true , resultId with
 | 
					        match resultPlayer , resultTarget , true , resultId with
 | 
				
			||||||
        | Some attacker , Some defender , true , true ->
 | 
					        | Some attacker , Some defender , true , true ->
 | 
				
			||||||
            do! checkForExistingHack defender.DiscordId attacker
 | 
					            do! checkForExistingHack defender.DiscordId attacker
 | 
				
			||||||
                |> Result.bind (checkIfHackHasCooldown hack)
 | 
					                |> Result.bind (checkIfHackHasCooldown (int hack))
 | 
				
			||||||
                |> function
 | 
					                |> function
 | 
				
			||||||
                   | Ok _ ->
 | 
					                   | Ok _ ->
 | 
				
			||||||
                       runHackerBattle defender hack
 | 
					                       runHackerBattle defender (getItemFromArmoury <| 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
 | 
				
			||||||
@ -182,13 +179,13 @@ let defend (ctx : InteractionContext) =
 | 
				
			|||||||
        let! player = DbService.tryFindPlayer ctx.Member.Id
 | 
					        let! player = DbService.tryFindPlayer ctx.Member.Id
 | 
				
			||||||
        match player with
 | 
					        match player with
 | 
				
			||||||
        | Some player ->
 | 
					        | Some player ->
 | 
				
			||||||
            if player.Shields.Length > 0 then
 | 
					            if Player.defenses 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)
 | 
				
			||||||
                    |> Async.AwaitTask
 | 
					                    |> Async.AwaitTask
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
                let builder = DiscordInteractionResponseBuilder()
 | 
					                let builder = DiscordInteractionResponseBuilder()
 | 
				
			||||||
                builder.Content <- $"You currently do not have any Shields to protect your system. Please go to the store and purchase one."
 | 
					                builder.Content <- $"You currently do not have any Shields to protect your system. Please go to the armoury and purchase one."
 | 
				
			||||||
                builder.AsEphemeral true |> ignore
 | 
					                builder.AsEphemeral true |> ignore
 | 
				
			||||||
                do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
					                do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
				
			||||||
                    |> Async.AwaitTask
 | 
					                    |> Async.AwaitTask
 | 
				
			||||||
@ -199,20 +196,20 @@ let defend (ctx : InteractionContext) =
 | 
				
			|||||||
let handleDefense (event : ComponentInteractionCreateEventArgs) =
 | 
					let handleDefense (event : ComponentInteractionCreateEventArgs) =
 | 
				
			||||||
    async {
 | 
					    async {
 | 
				
			||||||
        let split = event.Id.Split("-")
 | 
					        let split = event.Id.Split("-")
 | 
				
			||||||
        let ( shieldResult , shield ) = Shield.TryParse(split.[1])
 | 
					        let shield = enum<ShieldId>(int split.[1])
 | 
				
			||||||
        let! playerResult = DbService.tryFindPlayer event.User.Id
 | 
					        let! playerResult = DbService.tryFindPlayer event.User.Id
 | 
				
			||||||
        match playerResult , shieldResult with
 | 
					        match playerResult with
 | 
				
			||||||
        | Some player , true ->
 | 
					        | Some player ->
 | 
				
			||||||
            let updatedDefenses = removeExpiredActions (TimeSpan.FromHours(6)) (fun (pro : Defense) -> pro.Timestamp) player.Defenses
 | 
					            let updatedDefenses = Player.defenses player |> removeExpiredActions
 | 
				
			||||||
            let alreadyUsedShield = updatedDefenses |> Array.exists (fun d -> d.DefenseType = shield)
 | 
					            let alreadyUsedShield = updatedDefenses |> Array.exists (fun d -> d.ActionId = int shield)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            match alreadyUsedShield , updatedDefenses.Length < 2 with
 | 
					            match alreadyUsedShield , updatedDefenses.Length < 2 with
 | 
				
			||||||
            | false , true ->
 | 
					            | false , true ->
 | 
				
			||||||
                let embed = Embeds.responseCreatedShield shield
 | 
					                let embed = Embeds.responseCreatedShield shield
 | 
				
			||||||
                do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed)
 | 
					                do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed)
 | 
				
			||||||
                    |> Async.AwaitTask
 | 
					                    |> Async.AwaitTask
 | 
				
			||||||
                let defense = { DefenseType = shield ; Timestamp = DateTime.UtcNow }
 | 
					                let defense = { ActionId = int shield ; Type = Defense ; Timestamp = DateTime.UtcNow }
 | 
				
			||||||
                do! DbService.updatePlayer <| { player with Defenses = Array.append [| defense |] player.Defenses  }
 | 
					                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($"{event.User.Username} has protected their system!") |> ignore
 | 
				
			||||||
                let channel = event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle)
 | 
					                let channel = event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle)
 | 
				
			||||||
@ -227,16 +224,16 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
 | 
				
			|||||||
                builder.Content <- $"You are only allowed two shields at a time. Wait {cooldown} minutes to add another shield"
 | 
					                builder.Content <- $"You are only allowed two shields at a time. Wait {cooldown} minutes to add another shield"
 | 
				
			||||||
                do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
					                do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
				
			||||||
                    |> Async.AwaitTask
 | 
					                    |> Async.AwaitTask
 | 
				
			||||||
                do! DbService.updatePlayer <| { player with Defenses = updatedDefenses }
 | 
					                do! DbService.updatePlayer <| { player with Actions = updatedDefenses }
 | 
				
			||||||
            | true , _ ->
 | 
					            | true , _ ->
 | 
				
			||||||
                let builder = DiscordInteractionResponseBuilder()
 | 
					                let builder = DiscordInteractionResponseBuilder()
 | 
				
			||||||
                builder.IsEphemeral <- true
 | 
					                builder.IsEphemeral <- true
 | 
				
			||||||
                let timestamp = updatedDefenses |> Array.find (fun d -> d.DefenseType = shield) |> fun a -> a.Timestamp
 | 
					                let timestamp = updatedDefenses |> Array.find (fun d -> d.ActionId = int shield) |> fun a -> a.Timestamp
 | 
				
			||||||
                let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromHours(6)) timestamp
 | 
					                let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromHours(6)) timestamp
 | 
				
			||||||
                builder.Content <- $"{shield} shield is already in use. Wait {cooldown} minutes to use this shield again"
 | 
					                builder.Content <- $"{shield} shield is already in use. Wait {cooldown} minutes to use this shield again"
 | 
				
			||||||
                do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
					                do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
				
			||||||
                    |> Async.AwaitTask
 | 
					                    |> Async.AwaitTask
 | 
				
			||||||
                do! DbService.updatePlayer <| { player with Defenses = updatedDefenses }
 | 
					                do! DbService.updatePlayer <| { player with Actions = updatedDefenses }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        | _ ->
 | 
					        | _ ->
 | 
				
			||||||
            let builder = DiscordInteractionResponseBuilder()
 | 
					            let builder = DiscordInteractionResponseBuilder()
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										156
									
								
								Bot/Items.json
									
									
									
									
									
								
							
							
						
						
									
										156
									
								
								Bot/Items.json
									
									
									
									
									
								
							@ -1,62 +1,158 @@
 | 
				
			|||||||
[
 | 
					[
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
 | 
					    "Id": 0,
 | 
				
			||||||
    "Name": "Virus",
 | 
					    "Name": "Virus",
 | 
				
			||||||
    "ItemType" : { "Case" : "Hack" },
 | 
					    "Type": {
 | 
				
			||||||
    "Cost" : 5
 | 
					      "Case": "Hack"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Class": {
 | 
				
			||||||
 | 
					      "Case": "Network"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Cost": 100,
 | 
				
			||||||
 | 
					    "Power": 50,
 | 
				
			||||||
 | 
					    "Cooldown": 260
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
 | 
					    "Id": 1,
 | 
				
			||||||
    "Name": "Ransom",
 | 
					    "Name": "Ransom",
 | 
				
			||||||
    "ItemType" : { "Case" : "Hack" },
 | 
					    "Type": {
 | 
				
			||||||
    "Cost" : 10
 | 
					      "Case": "Hack"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Class": {
 | 
				
			||||||
 | 
					      "Case": "Network"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Cost": 100,
 | 
				
			||||||
 | 
					    "Power": 50,
 | 
				
			||||||
 | 
					    "Cooldown": 260
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
 | 
					    "Id": 2,
 | 
				
			||||||
    "Name": "Worm",
 | 
					    "Name": "Worm",
 | 
				
			||||||
    "ItemType" : { "Case" : "Hack" },
 | 
					    "Type": {
 | 
				
			||||||
    "Cost" : 5
 | 
					      "Case": "Hack"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Class": {
 | 
				
			||||||
 | 
					      "Case": "Network"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Cost": 100,
 | 
				
			||||||
 | 
					    "Power": 50,
 | 
				
			||||||
 | 
					    "Cooldown": 260
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
 | 
					    "Id": 3,
 | 
				
			||||||
    "Name": "DDos",
 | 
					    "Name": "DDos",
 | 
				
			||||||
    "ItemType" : { "Case" : "Hack" },
 | 
					    "Type": {
 | 
				
			||||||
    "Cost" : 10
 | 
					      "Case": "Hack"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Class": {
 | 
				
			||||||
 | 
					      "Case": "Network"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Cost": 100,
 | 
				
			||||||
 | 
					    "Power": 50,
 | 
				
			||||||
 | 
					    "Cooldown": 260
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
 | 
					    "Id": 4,
 | 
				
			||||||
    "Name": "Crack",
 | 
					    "Name": "Crack",
 | 
				
			||||||
    "ItemType" : { "Case" : "Hack" },
 | 
					    "Type": {
 | 
				
			||||||
    "Cost" : 5
 | 
					      "Case": "Hack"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Class": {
 | 
				
			||||||
 | 
					      "Case": "Network"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Cost": 100,
 | 
				
			||||||
 | 
					    "Power": 50,
 | 
				
			||||||
 | 
					    "Cooldown": 260
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
 | 
					    "Id": 5,
 | 
				
			||||||
    "Name": "Injection",
 | 
					    "Name": "Injection",
 | 
				
			||||||
    "ItemType" : { "Case" : "Hack" },
 | 
					    "Type": {
 | 
				
			||||||
    "Cost" : 10
 | 
					      "Case": "Hack"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Class": {
 | 
				
			||||||
 | 
					      "Case": "Network"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Cost": 100,
 | 
				
			||||||
 | 
					    "Power": 50,
 | 
				
			||||||
 | 
					    "Cooldown": 260
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
 | 
					    "Id": 6,
 | 
				
			||||||
    "Name": "Firewall",
 | 
					    "Name": "Firewall",
 | 
				
			||||||
    "ItemType" : { "Case" : "Shield" },
 | 
					    "Type": {
 | 
				
			||||||
    "Cost" : 5
 | 
					      "Case": "Shield"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Class": {
 | 
				
			||||||
 | 
					      "Case": "Network"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Cost": 100,
 | 
				
			||||||
 | 
					    "Power": 50,
 | 
				
			||||||
 | 
					    "Cooldown": 260
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
 | 
					    "Id": 7,
 | 
				
			||||||
    "Name": "PortScan",
 | 
					    "Name": "PortScan",
 | 
				
			||||||
    "ItemType" : { "Case" : "Shield" },
 | 
					    "Type": {
 | 
				
			||||||
    "Cost" : 10
 | 
					      "Case": "Shield"
 | 
				
			||||||
  },
 | 
					    },
 | 
				
			||||||
  {
 | 
					    "Class": {
 | 
				
			||||||
    "Name" : "Cypher",
 | 
					      "Case": "Network"
 | 
				
			||||||
    "ItemType" : { "Case" : "Shield" },
 | 
					    },
 | 
				
			||||||
    "Cost" : 5
 | 
					    "Cost": 100,
 | 
				
			||||||
 | 
					    "Power": 50,
 | 
				
			||||||
 | 
					    "Cooldown": 260
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
 | 
					    "Id": 8,
 | 
				
			||||||
    "Name": "Encryption",
 | 
					    "Name": "Encryption",
 | 
				
			||||||
    "ItemType" : { "Case" : "Shield" },
 | 
					    "Type": {
 | 
				
			||||||
    "Cost" : 10
 | 
					      "Case": "Shield"
 | 
				
			||||||
  },
 | 
					    },
 | 
				
			||||||
  {
 | 
					    "Class": {
 | 
				
			||||||
    "Name" : "Sanitation",
 | 
					      "Case": "Network"
 | 
				
			||||||
    "ItemType" : { "Case" : "Shield" },
 | 
					    },
 | 
				
			||||||
    "Cost" : 5
 | 
					    "Cost": 100,
 | 
				
			||||||
 | 
					    "Power": 50,
 | 
				
			||||||
 | 
					    "Cooldown": 260
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
 | 
					    "Id": 9,
 | 
				
			||||||
    "Name": "Hardening",
 | 
					    "Name": "Hardening",
 | 
				
			||||||
    "ItemType" : { "Case" : "Shield" },
 | 
					    "Type": {
 | 
				
			||||||
    "Cost" : 10
 | 
					      "Case": "Shield"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Class": {
 | 
				
			||||||
 | 
					      "Case": "Network"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Cost": 100,
 | 
				
			||||||
 | 
					    "Power": 50,
 | 
				
			||||||
 | 
					    "Cooldown": 260
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "Id": 10,
 | 
				
			||||||
 | 
					    "Name": "Sanitation",
 | 
				
			||||||
 | 
					    "Type": {
 | 
				
			||||||
 | 
					      "Case": "Shield"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Class": {
 | 
				
			||||||
 | 
					      "Case": "Network"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Cost": 100,
 | 
				
			||||||
 | 
					    "Power": 50,
 | 
				
			||||||
 | 
					    "Cooldown": 260
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "Id": 11,
 | 
				
			||||||
 | 
					    "Name": "Cypher",
 | 
				
			||||||
 | 
					    "Type": {
 | 
				
			||||||
 | 
					      "Case": "Shield"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Class": {
 | 
				
			||||||
 | 
					      "Case": "Network"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "Cost": 100,
 | 
				
			||||||
 | 
					    "Power": 50,
 | 
				
			||||||
 | 
					    "Cooldown": 260
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@ open Degenz
 | 
				
			|||||||
open Degenz.Shared
 | 
					open Degenz.Shared
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module Commands =
 | 
					module Commands =
 | 
				
			||||||
    let newPlayer nickname (membr : uint64) =
 | 
					//    let newPlayer nickname (membr : uint64) =
 | 
				
			||||||
//        let h1 = [| Weapon.Virus ; Weapon.Ransom |]
 | 
					//        let h1 = [| Weapon.Virus ; Weapon.Ransom |]
 | 
				
			||||||
//        let h2 = [| Weapon.DDos  ; Weapon.Worm |]
 | 
					//        let h2 = [| Weapon.DDos  ; Weapon.Worm |]
 | 
				
			||||||
//        let h3 = [| Weapon.Crack ; Weapon.Injection |]
 | 
					//        let h3 = [| Weapon.Crack ; Weapon.Injection |]
 | 
				
			||||||
@ -18,51 +18,49 @@ module Commands =
 | 
				
			|||||||
//        let d2 = [| Shield.Encryption ; Shield.Cypher |]
 | 
					//        let d2 = [| Shield.Encryption ; Shield.Cypher |]
 | 
				
			||||||
//        let d3 = [| Shield.Hardening  ; Shield.Sanitation |]
 | 
					//        let d3 = [| Shield.Hardening  ; Shield.Sanitation |]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let rand = System.Random(System.Guid.NewGuid().GetHashCode())
 | 
					//        let rand = System.Random(System.Guid.NewGuid().GetHashCode())
 | 
				
			||||||
        let getRandom (actions : 'a array) = actions.[rand.Next(0, Math.Max(0, actions.Length - 1))]
 | 
					//        let getRandom (actions : 'a array) = actions.[rand.Next(0, max 0 (actions.Length - 1))]
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
        let weapons = [| getRandom hackInventory |]
 | 
					//        let weapons = [| getRandom hackInventory |]
 | 
				
			||||||
        let shields = [| getRandom shieldInventory |]
 | 
					//        let shields = [| getRandom shieldInventory |]
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
        { DiscordId = membr
 | 
					//        { DiscordId = membr
 | 
				
			||||||
          Name = nickname
 | 
					//          Name = nickname
 | 
				
			||||||
          Weapons = weapons
 | 
					//          Weapons = weapons
 | 
				
			||||||
          Shields  = shields
 | 
					//          Shields  = shields
 | 
				
			||||||
          Attacks = [||]
 | 
					//          Attacks = [||]
 | 
				
			||||||
          Defenses = [||]
 | 
					//          Defenses = [||]
 | 
				
			||||||
          Bank = 15 }
 | 
					//          Bank = 15 }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    let addHackerRole (ctx : InteractionContext) =
 | 
					 | 
				
			||||||
        async {
 | 
					 | 
				
			||||||
            let! player = DbService.tryFindPlayer ctx.Member.Id
 | 
					 | 
				
			||||||
            let! newPlayer =
 | 
					 | 
				
			||||||
                match player with
 | 
					 | 
				
			||||||
                | Some _ -> async.Return false
 | 
					 | 
				
			||||||
                | None ->
 | 
					 | 
				
			||||||
                    async {
 | 
					 | 
				
			||||||
                        do! newPlayer ctx.Member.DisplayName ctx.Member.Id
 | 
					 | 
				
			||||||
                            |> DbService.insertNewPlayer
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//    let addHackerRole (ctx : InteractionContext) =
 | 
				
			||||||
 | 
					//        async {
 | 
				
			||||||
 | 
					//            let! player = DbService.tryFindPlayer ctx.Member.Id
 | 
				
			||||||
 | 
					//            let! newPlayer =
 | 
				
			||||||
 | 
					//                match player with
 | 
				
			||||||
 | 
					//                | Some _ -> async.Return false
 | 
				
			||||||
 | 
					//                | None ->
 | 
				
			||||||
 | 
					//                    async {
 | 
				
			||||||
 | 
					//                        do! newPlayer ctx.Member.DisplayName ctx.Member.Id
 | 
				
			||||||
 | 
					//                            |> DbService.insertNewPlayer
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
//                        for role in ctx.Guild.Roles do
 | 
					//                        for role in ctx.Guild.Roles do
 | 
				
			||||||
//                            if role.Value.Name = "Hacker" then
 | 
					//                            if role.Value.Name = "Hacker" then
 | 
				
			||||||
//                                do! ctx.Member.GrantRoleAsync(role.Value)
 | 
					//                                do! ctx.Member.GrantRoleAsync(role.Value)
 | 
				
			||||||
//                                    |> Async.AwaitTask
 | 
					//                                    |> Async.AwaitTask
 | 
				
			||||||
 | 
					//                        return true
 | 
				
			||||||
 | 
					//                    }
 | 
				
			||||||
 | 
					//            if newPlayer then
 | 
				
			||||||
 | 
					//                do! ctx.CreateResponseAsync("You are now an elite haxxor", true)
 | 
				
			||||||
 | 
					//                    |> Async.AwaitTask
 | 
				
			||||||
 | 
					//            else
 | 
				
			||||||
 | 
					//                do! ctx.CreateResponseAsync("Already registered as an elite haxxor", true)
 | 
				
			||||||
 | 
					//                    |> Async.AwaitTask
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//        } |> Async.StartAsTask
 | 
				
			||||||
 | 
					//        :> Task
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        return true
 | 
					//    let removeHackerRole (ctx : InteractionContext) =
 | 
				
			||||||
                    }
 | 
					//        async {
 | 
				
			||||||
 | 
					 | 
				
			||||||
            if newPlayer then
 | 
					 | 
				
			||||||
                do! ctx.CreateResponseAsync("You are now an elite haxxor", true)
 | 
					 | 
				
			||||||
                    |> Async.AwaitTask
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                do! ctx.CreateResponseAsync("Already registered as an elite haxxor", true)
 | 
					 | 
				
			||||||
                    |> Async.AwaitTask
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        } |> Async.StartAsTask
 | 
					 | 
				
			||||||
        :> Task
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let removeHackerRole (ctx : InteractionContext) =
 | 
					 | 
				
			||||||
        async {
 | 
					 | 
				
			||||||
//            for role in ctx.Member.Roles do
 | 
					//            for role in ctx.Member.Roles do
 | 
				
			||||||
//                if role.Name = "Hacker" then
 | 
					//                if role.Name = "Hacker" then
 | 
				
			||||||
//                    do! ctx.Member.RevokeRoleAsync(role)
 | 
					//                    do! ctx.Member.RevokeRoleAsync(role)
 | 
				
			||||||
@ -70,10 +68,10 @@ module Commands =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
//            do! DbService.removePlayer ctx.Member.Id
 | 
					//            do! DbService.removePlayer ctx.Member.Id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            do! ctx.CreateResponseAsync("You are now lame", true)
 | 
					//            do! ctx.CreateResponseAsync("You are now lame", true)
 | 
				
			||||||
                |> Async.AwaitTask
 | 
					//                |> Async.AwaitTask
 | 
				
			||||||
        } |> Async.StartAsTask
 | 
					//        } |> Async.StartAsTask
 | 
				
			||||||
        :> Task
 | 
					//        :> Task
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [<CLIMutable>]
 | 
					    [<CLIMutable>]
 | 
				
			||||||
    type LeaderboardEntry = {
 | 
					    type LeaderboardEntry = {
 | 
				
			||||||
@ -108,13 +106,13 @@ module Commands =
 | 
				
			|||||||
            let! player = DbService.tryFindPlayer ctx.Member.Id
 | 
					            let! player = DbService.tryFindPlayer ctx.Member.Id
 | 
				
			||||||
            match player with
 | 
					            match player with
 | 
				
			||||||
            | Some p ->
 | 
					            | Some p ->
 | 
				
			||||||
                let updatedAttacks = p.Attacks |> removeExpiredActions (TimeSpan.FromHours(24)) (fun (atk : Attack) -> atk.Timestamp)
 | 
					//                let updatedAttacks = p.Attacks |> removeExpiredActions (TimeSpan.FromHours(24)) (fun (atk : Attack) -> atk.Timestamp)
 | 
				
			||||||
                let updatedDefenses = p.Defenses |> removeExpiredActions (TimeSpan.FromHours(6)) (fun (p : Defense) -> p.Timestamp)
 | 
					//                let updatedDefenses = p.Defenses |> removeExpiredActions (TimeSpan.FromHours(6)) (fun (p : Defense) -> p.Timestamp)
 | 
				
			||||||
                let updatedPlayer = { p with Attacks = updatedAttacks ; Defenses = updatedDefenses }
 | 
					//                let updatedPlayer = { p with Attacks = updatedAttacks ; Defenses = updatedDefenses }
 | 
				
			||||||
                do! DbService.updatePlayer updatedPlayer
 | 
					//                do! DbService.updatePlayer updatedPlayer
 | 
				
			||||||
                let builder = DiscordInteractionResponseBuilder()
 | 
					                let builder = DiscordInteractionResponseBuilder()
 | 
				
			||||||
                builder.IsEphemeral <- true
 | 
					                builder.IsEphemeral <- true
 | 
				
			||||||
                builder.Content <- statusFormat updatedPlayer
 | 
					//                builder.Content <- statusFormat updatedPlayer
 | 
				
			||||||
                do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
					                do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
				
			||||||
                    |> Async.AwaitTask
 | 
					                    |> Async.AwaitTask
 | 
				
			||||||
            | None -> do! notYetAHackerMsg ctx
 | 
					            | None -> do! notYetAHackerMsg ctx
 | 
				
			||||||
@ -124,11 +122,11 @@ module Commands =
 | 
				
			|||||||
type PlayerInteractions() =
 | 
					type PlayerInteractions() =
 | 
				
			||||||
    inherit ApplicationCommandModule ()
 | 
					    inherit ApplicationCommandModule ()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [<SlashCommand("redpill", "Take the redpill and become a hacker")>]
 | 
					//    [<SlashCommand("redpill", "Take the redpill and become a hacker")>]
 | 
				
			||||||
    member _.AddHackerRole (ctx : InteractionContext) = Commands.addHackerRole ctx
 | 
					//    member _.AddHackerRole (ctx : InteractionContext) = Commands.addHackerRole ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [<SlashCommand("bluepill", "Take the bluepill and become lame")>]
 | 
					//    [<SlashCommand("bluepill", "Take the bluepill and become lame")>]
 | 
				
			||||||
    member _.RemoveHackerRole (ctx : InteractionContext) = Commands.removeHackerRole ctx
 | 
					//    member _.RemoveHackerRole (ctx : InteractionContext) = Commands.removeHackerRole ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [<SlashCommand("status", "Get your current status like bank account, and active hacks and defenses")>]
 | 
					    [<SlashCommand("status", "Get your current status like bank account, and active hacks and defenses")>]
 | 
				
			||||||
    member this.Status (ctx : InteractionContext) = Commands.status ctx
 | 
					    member this.Status (ctx : InteractionContext) = Commands.status ctx
 | 
				
			||||||
 | 
				
			|||||||
@ -26,9 +26,9 @@ type SlotMachine() =
 | 
				
			|||||||
                                    || (results.[0] <> results.[1] && results.[1] <> results.[2] && results.[0] <> results.[2])
 | 
					                                    || (results.[0] <> results.[1] && results.[1] <> results.[2] && results.[0] <> results.[2])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if winConditions then
 | 
					                if winConditions then
 | 
				
			||||||
                    do! DbService.updatePlayer { player with Bank = player.Bank + 10 }
 | 
					                    do! DbService.updatePlayer { player with Bank = player.Bank + 10<GBT> }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                    do! DbService.updatePlayer { player with Bank = Math.Max(player.Bank - 1, 0) }
 | 
					                    do! DbService.updatePlayer { player with Bank = max (player.Bank - 1<GBT>) 0<GBT> }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                do! ctx.Interaction.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource)
 | 
					                do! ctx.Interaction.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										104
									
								
								Bot/Store.fs
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								Bot/Store.fs
									
									
									
									
									
								
							@ -8,74 +8,32 @@ open DSharpPlus.SlashCommands
 | 
				
			|||||||
open Degenz
 | 
					open Degenz
 | 
				
			||||||
open Degenz.Embeds
 | 
					open Degenz.Embeds
 | 
				
			||||||
open Degenz.Shared
 | 
					open Degenz.Shared
 | 
				
			||||||
open Newtonsoft.Json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let store =
 | 
					 | 
				
			||||||
        let file = System.IO.File.ReadAllText("Items.json")
 | 
					 | 
				
			||||||
        JsonConvert.DeserializeObject<Item array>(file)
 | 
					 | 
				
			||||||
        |> Array.groupBy (fun (i : Item) -> i.ItemType)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
let viewStore (ctx : InteractionContext) =
 | 
					let viewStore (ctx : InteractionContext) =
 | 
				
			||||||
    async {
 | 
					    async {
 | 
				
			||||||
        do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, Embeds.storeListing store)
 | 
					        do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, Embeds.storeListing armoury)
 | 
				
			||||||
            |> Async.AwaitTask
 | 
					            |> Async.AwaitTask
 | 
				
			||||||
    } |> Async.StartAsTask
 | 
					    } |> Async.StartAsTask
 | 
				
			||||||
      :> Task
 | 
					      :> Task
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let getItems itemType = store |> Array.find (fun ( t , _ ) -> t = itemType) |> snd
 | 
					let buyItem (ctx : InteractionContext) itemId =
 | 
				
			||||||
 | 
					 | 
				
			||||||
let buyHack (ctx : InteractionContext) hackId =
 | 
					 | 
				
			||||||
    async {
 | 
					    async {
 | 
				
			||||||
        let! playerResult = DbService.tryFindPlayer ctx.Member.Id
 | 
					        let! playerResult = DbService.tryFindPlayer ctx.Member.Id
 | 
				
			||||||
        let weapons = getItems ItemType.Hack
 | 
					        let item = armoury |> Array.find (fun w -> w.Id = itemId)
 | 
				
			||||||
        let weaponResult = weapons |> Array.tryFind (fun w -> w.Name = string hackId)
 | 
					        match playerResult with
 | 
				
			||||||
        return!
 | 
					        | Some player ->
 | 
				
			||||||
            match playerResult , weaponResult with
 | 
					 | 
				
			||||||
            | Some player , Some item ->
 | 
					 | 
				
			||||||
                async {
 | 
					 | 
				
			||||||
            let newBalance = player.Bank - item.Cost
 | 
					            let newBalance = player.Bank - item.Cost
 | 
				
			||||||
                    if newBalance >= 0 then
 | 
					            if newBalance >= 0<GBT> then
 | 
				
			||||||
                        let playerHasItem = player.Weapons |> Array.exists (fun w -> item.Name = string w)
 | 
					                let playerHasItem = player.Arsenal |> Array.exists (fun w -> item.Id = w.Id)
 | 
				
			||||||
                if not playerHasItem then
 | 
					                if not playerHasItem then
 | 
				
			||||||
                            let weapon = hackInventory |> Array.find (fun w -> item.Name = string w)
 | 
					                    let p = { player with Bank = newBalance ; Arsenal = Array.append [| item |] player.Arsenal }
 | 
				
			||||||
                            let p = { player with Bank = newBalance ; Weapons = Array.append [| weapon |] player.Weapons }
 | 
					 | 
				
			||||||
                    do! DbService.updatePlayer p
 | 
					                    do! DbService.updatePlayer p
 | 
				
			||||||
                    do! createSimpleResponseAsync $"Successfully purchased {item.Name}! You now have {newBalance} remaining" ctx
 | 
					                    do! createSimpleResponseAsync $"Successfully purchased {item.Name}! You now have {newBalance} remaining" ctx
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                    do! createSimpleResponseAsync $"You already own this item!" ctx
 | 
					                    do! createSimpleResponseAsync $"You already own this item!" ctx
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
                do! createSimpleResponseAsync $"You do not have sufficient funds to buy this item! Current balance: {player.Bank} GBT" ctx
 | 
					                do! createSimpleResponseAsync $"You do not have sufficient funds to buy this item! Current balance: {player.Bank} GBT" ctx
 | 
				
			||||||
                }
 | 
					        | None -> do! notYetAHackerMsg ctx
 | 
				
			||||||
            | None , _ -> notYetAHackerMsg ctx
 | 
					 | 
				
			||||||
            | _ -> createSimpleResponseAsync "Something is wrong" ctx
 | 
					 | 
				
			||||||
    } |> Async.StartAsTask
 | 
					 | 
				
			||||||
      :> Task
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let buyShield (ctx : InteractionContext) shieldId =
 | 
					 | 
				
			||||||
    async {
 | 
					 | 
				
			||||||
        let! playerResult = DbService.tryFindPlayer ctx.Member.Id
 | 
					 | 
				
			||||||
        let shieldResult =
 | 
					 | 
				
			||||||
            getItems ItemType.Shield
 | 
					 | 
				
			||||||
            |> Array.tryFind (fun w -> w.Name = string shieldId)
 | 
					 | 
				
			||||||
        return!
 | 
					 | 
				
			||||||
            match playerResult , shieldResult with
 | 
					 | 
				
			||||||
            | Some player , Some item ->
 | 
					 | 
				
			||||||
                async {
 | 
					 | 
				
			||||||
                    let newBalance = player.Bank - item.Cost
 | 
					 | 
				
			||||||
                    if newBalance >= 0 then
 | 
					 | 
				
			||||||
                        let playerHasItem = player.Shields |> Array.exists (fun w -> item.Name = string w)
 | 
					 | 
				
			||||||
                        if not playerHasItem then
 | 
					 | 
				
			||||||
                            let shield = shieldInventory |> Array.find (fun w -> item.Name = string w)
 | 
					 | 
				
			||||||
                            let p = { player with Bank = newBalance ; Shields = Array.append [| shield |] player.Shields }
 | 
					 | 
				
			||||||
                            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 , _ -> notYetAHackerMsg ctx
 | 
					 | 
				
			||||||
            | _ -> createSimpleResponseAsync "Something is wrong" ctx
 | 
					 | 
				
			||||||
    } |> Async.StartAsTask
 | 
					    } |> Async.StartAsTask
 | 
				
			||||||
      :> Task
 | 
					      :> Task
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -88,28 +46,19 @@ let sell (ctx : InteractionContext) =
 | 
				
			|||||||
        let! playerResult = DbService.tryFindPlayer ctx.Member.Id
 | 
					        let! playerResult = DbService.tryFindPlayer ctx.Member.Id
 | 
				
			||||||
        match playerResult with
 | 
					        match playerResult with
 | 
				
			||||||
        | Some player ->
 | 
					        | Some player ->
 | 
				
			||||||
            let hasInventoryToSell = Array.length player.Weapons + Array.length player.Shields > 0
 | 
					            let hasInventoryToSell = Array.length player.Arsenal > 0
 | 
				
			||||||
            if hasInventoryToSell then
 | 
					            if hasInventoryToSell then
 | 
				
			||||||
                let builder = DiscordInteractionResponseBuilder()
 | 
					                let builder = DiscordInteractionResponseBuilder()
 | 
				
			||||||
                builder.AddEmbed (constructEmbed "Pick the item you wish to sell.") |> ignore
 | 
					                builder.AddEmbed (constructEmbed "Pick the item you wish to sell.") |> ignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Array.chunkBySize 3 player.Weapons
 | 
					                Array.chunkBySize 5 player.Arsenal
 | 
				
			||||||
                |> Array.iter
 | 
					                |> Array.iter
 | 
				
			||||||
                    (fun wps ->
 | 
					                    (fun wps ->
 | 
				
			||||||
                        wps
 | 
					                        wps
 | 
				
			||||||
                        |> Array.map (fun w -> DiscordButtonComponent(ButtonStyle.Primary, $"Hack-{w}", $"{w}"))
 | 
					                        |> Array.map (fun w -> DiscordButtonComponent(ButtonStyle.Primary, $"{w.Type}-{w.Id}", $"{w.Name}"))
 | 
				
			||||||
                        |> Seq.cast<DiscordComponent>
 | 
					                        |> Seq.cast<DiscordComponent>
 | 
				
			||||||
                        |> builder.AddComponents
 | 
					                        |> builder.AddComponents
 | 
				
			||||||
                        |> ignore)
 | 
					                        |> ignore)
 | 
				
			||||||
                Array.chunkBySize 3 player.Shields
 | 
					 | 
				
			||||||
                |> Array.iter
 | 
					 | 
				
			||||||
                    (fun shs ->
 | 
					 | 
				
			||||||
                        shs
 | 
					 | 
				
			||||||
                        |> Array.map (fun s -> DiscordButtonComponent(ButtonStyle.Primary, $"Shield-{s}", $"{s}"))
 | 
					 | 
				
			||||||
                        |> Seq.cast<DiscordComponent>
 | 
					 | 
				
			||||||
                        |> builder.AddComponents
 | 
					 | 
				
			||||||
                        |> ignore)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                builder.AsEphemeral true |> ignore
 | 
					                builder.AsEphemeral true |> ignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
					                do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
 | 
				
			||||||
@ -121,19 +70,16 @@ let sell (ctx : InteractionContext) =
 | 
				
			|||||||
    } |> Async.StartAsTask
 | 
					    } |> Async.StartAsTask
 | 
				
			||||||
      :> Task
 | 
					      :> Task
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let updateShields player salePrice updatedShields = { player with Bank = player.Bank + salePrice ; Shields = updatedShields }
 | 
					let updateArsenal player salePrice updatedArsenal = { player with Bank = player.Bank + salePrice ; Arsenal = updatedArsenal }
 | 
				
			||||||
let updateHacks player salePrice updatedHacks = { player with Bank = player.Bank + salePrice ; Weapons = updatedHacks }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
let sellItem (event : ComponentInteractionCreateEventArgs) updateFn player inventory itemType itemName =
 | 
					let sellItem (event : ComponentInteractionCreateEventArgs) player itemId =
 | 
				
			||||||
    async {
 | 
					    async {
 | 
				
			||||||
        let item = getItems itemType |> Array.find (fun i -> i.Name = itemName)
 | 
					        let item = armoury |> Array.find (fun i -> i.Id = itemId)
 | 
				
			||||||
        let salePrice = item.Cost
 | 
					        let updatedPlayer = { player with Bank = player.Bank + item.Cost ; Arsenal = player.Arsenal |> Array.filter (fun w -> w.Id = itemId)}
 | 
				
			||||||
        let updatedItems = inventory |> Array.filter (fun i -> string i <> itemName)
 | 
					 | 
				
			||||||
        let updatedPlayer = updateFn player salePrice updatedItems
 | 
					 | 
				
			||||||
        do! DbService.updatePlayer updatedPlayer
 | 
					        do! DbService.updatePlayer updatedPlayer
 | 
				
			||||||
        let builder = DiscordInteractionResponseBuilder()
 | 
					        let builder = DiscordInteractionResponseBuilder()
 | 
				
			||||||
        builder.IsEphemeral <- true
 | 
					        builder.IsEphemeral <- true
 | 
				
			||||||
        builder.Content <- $"Sold {itemType.ToString().ToLower()} {itemName} for {salePrice}! Current Balance: {updatedPlayer.Bank}"
 | 
					        builder.Content <- $"Sold {item.Type} {item.Name} for {item.Cost}! Current Balance: {updatedPlayer.Bank}"
 | 
				
			||||||
        do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
 | 
					        do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
 | 
				
			||||||
            |> Async.AwaitTask
 | 
					            |> Async.AwaitTask
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -143,12 +89,8 @@ let handleSellButtonEvents (_ : DiscordClient) (event : ComponentInteractionCrea
 | 
				
			|||||||
        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 split = event.Id.Split("-")
 | 
					            let itemId = int <| event.Id.Split("-").[1]
 | 
				
			||||||
            let itemType = match split.[0] with "Hack" -> ItemType.Hack | _ -> ItemType.Shield
 | 
					            do! sellItem event player itemId
 | 
				
			||||||
            let itemName = split.[1]
 | 
					 | 
				
			||||||
            match itemType with
 | 
					 | 
				
			||||||
            | ItemType.Hack -> do! sellItem event updateHacks player player.Weapons ItemType.Hack itemName
 | 
					 | 
				
			||||||
            | ItemType.Shield -> do! sellItem event updateShields player player.Shields ItemType.Shield itemName
 | 
					 | 
				
			||||||
        | None ->
 | 
					        | None ->
 | 
				
			||||||
            let builder = DiscordInteractionResponseBuilder()
 | 
					            let builder = DiscordInteractionResponseBuilder()
 | 
				
			||||||
            builder.IsEphemeral <- true
 | 
					            builder.IsEphemeral <- true
 | 
				
			||||||
@ -165,12 +107,12 @@ type Store() =
 | 
				
			|||||||
    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 : Hack) =
 | 
					    member _.BuyHack (ctx : InteractionContext, [<Option("hack-id", "The ID of the hack you wish to purchase")>] hackId : HackId) =
 | 
				
			||||||
        buyHack ctx hackId
 | 
					        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 : Shield) =
 | 
					    member this.BuyShield (ctx : InteractionContext, [<Option("shield-id", "The ID of the shield you wish to purchase")>] shieldId : ShieldId) =
 | 
				
			||||||
        buyShield ctx shieldId
 | 
					        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
 | 
				
			||||||
 | 
				
			|||||||
@ -7,8 +7,8 @@ open DSharpPlus.EventArgs
 | 
				
			|||||||
open DSharpPlus.SlashCommands
 | 
					open DSharpPlus.SlashCommands
 | 
				
			||||||
open Degenz.Shared
 | 
					open Degenz.Shared
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let defaultHack = Hack.Virus
 | 
					let defaultHack = armoury |> Array.find (fun i -> i.Id = int HackId.Virus)
 | 
				
			||||||
let defaultShield = Shield.Firewall
 | 
					let defaultShield = armoury |> Array.find (fun i -> i.Id = int ShieldId.Firewall)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let sendInitialEmbed (client : DiscordClient)  =
 | 
					let sendInitialEmbed (client : DiscordClient)  =
 | 
				
			||||||
    async {
 | 
					    async {
 | 
				
			||||||
@ -32,13 +32,17 @@ let handleTrainerStep1 (event : ComponentInteractionCreateEventArgs) =
 | 
				
			|||||||
        do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate)
 | 
					        do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate)
 | 
				
			||||||
            |> Async.AwaitTask
 | 
					            |> Async.AwaitTask
 | 
				
			||||||
        match maybePlayer with
 | 
					        match maybePlayer with
 | 
				
			||||||
        | Some player when not <| Array.isEmpty player.Weapons && not <| Array.isEmpty player.Shields ->
 | 
					        | Some player when player.Arsenal |> Array.exists (fun w -> w.Type = Hack)
 | 
				
			||||||
 | 
					                           && player.Arsenal |> Array.exists (fun w -> w.Type = Shield) ->
 | 
				
			||||||
            let msg = "First time, eh? Beautopia is a dangerous place. I'm going to teach you how to protect yourself from other degenerates. "
 | 
					            let msg = "First time, eh? Beautopia is a dangerous place. I'm going to teach you how to protect yourself from other degenerates. "
 | 
				
			||||||
                       + "And in the process, I'll also show you how to hack some sheeple, so you can earn some cash."
 | 
					                       + "And in the process, I'll also show you how to hack some sheeple, so you can earn some cash."
 | 
				
			||||||
            do! Message.sendFollowUpMessageWithButton event "Trainer-2" msg
 | 
					            do! Message.sendFollowUpMessageWithButton event "Trainer-2" msg
 | 
				
			||||||
        | Some player ->
 | 
					        | Some player ->
 | 
				
			||||||
            let missingItem = match player.Weapons with [||] -> "Hacks" | _ -> "Shields"
 | 
					            let missingItem =
 | 
				
			||||||
            let msg = $"Looks like you don't own any {missingItem}. Go to the store and purchase some before proceeding."
 | 
					                if player.Arsenal |> Array.exists (fun w -> w.Type = Hack)
 | 
				
			||||||
 | 
					                    then "Shields"
 | 
				
			||||||
 | 
					                    else "Hacks"
 | 
				
			||||||
 | 
					            let msg = $"Looks like you're missing  {missingItem}. Go to the store and purchase some before proceeding."
 | 
				
			||||||
            do! Message.sendFollowUpMessage event msg
 | 
					            do! Message.sendFollowUpMessage event msg
 | 
				
			||||||
        | None ->
 | 
					        | None ->
 | 
				
			||||||
            let msg = "An error occurred, please contact a moderator"
 | 
					            let msg = "An error occurred, please contact a moderator"
 | 
				
			||||||
@ -50,7 +54,7 @@ let handleTrainerStep2 (event : ComponentInteractionCreateEventArgs) =
 | 
				
			|||||||
        let! result = DbService.tryFindPlayer event.User.Id
 | 
					        let! result = DbService.tryFindPlayer event.User.Id
 | 
				
			||||||
        match result with
 | 
					        match result with
 | 
				
			||||||
        | Some player ->
 | 
					        | Some player ->
 | 
				
			||||||
            let weaponName = player.Shields |> Array.tryHead |> Option.defaultValue defaultShield
 | 
					            let weaponName = Player.shields player |> Array.tryHead |> Option.defaultValue defaultShield
 | 
				
			||||||
            do! Message.sendInteractionEvent event
 | 
					            do! Message.sendInteractionEvent 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. "
 | 
				
			||||||
                     + $"You currently have {weaponName} in your arsenal. To enable it and protect your system, you can use the `/defend` slash command to choose a shield."
 | 
					                     + $"You currently have {weaponName} in your arsenal. To enable it and protect your system, you can use the `/defend` slash command to choose a shield."
 | 
				
			||||||
@ -65,8 +69,8 @@ let defend (ctx : InteractionContext) =
 | 
				
			|||||||
        match playerResult with
 | 
					        match playerResult with
 | 
				
			||||||
        | Some player ->
 | 
					        | Some player ->
 | 
				
			||||||
            let playerWithShields =
 | 
					            let playerWithShields =
 | 
				
			||||||
                match player.Shields with
 | 
					                match player.Arsenal with
 | 
				
			||||||
                | [||] -> { player with Shields = [| defaultShield |] }
 | 
					                | [||] -> { player with Arsenal = [| defaultShield |] }
 | 
				
			||||||
                | _ -> player
 | 
					                | _ -> player
 | 
				
			||||||
            let embed = Embeds.pickDefense "Trainer-3" playerWithShields
 | 
					            let embed = Embeds.pickDefense "Trainer-3" playerWithShields
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -92,7 +96,7 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
 | 
				
			|||||||
        match result with
 | 
					        match result with
 | 
				
			||||||
        | Some player ->
 | 
					        | Some player ->
 | 
				
			||||||
            let prize = 0.223f
 | 
					            let prize = 0.223f
 | 
				
			||||||
            let shield = player.Shields |> Array.tryHead |> Option.defaultValue defaultShield
 | 
					            let shield = player.Arsenal |> Array.tryHead |> Option.defaultValue defaultShield
 | 
				
			||||||
            let embed = Embeds.responseCreatedShieldTrainer shield
 | 
					            let embed = Embeds.responseCreatedShieldTrainer shield
 | 
				
			||||||
            do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
 | 
					            do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
 | 
				
			||||||
            do! Async.Sleep 2000
 | 
					            do! Async.Sleep 2000
 | 
				
			||||||
@ -112,7 +116,7 @@ let handleTrainerStep4 (event : ComponentInteractionCreateEventArgs) =
 | 
				
			|||||||
        let! result = DbService.tryFindPlayer event.User.Id
 | 
					        let! result = DbService.tryFindPlayer event.User.Id
 | 
				
			||||||
        match result with
 | 
					        match result with
 | 
				
			||||||
        | Some player ->
 | 
					        | Some player ->
 | 
				
			||||||
            let weaponName = player.Weapons |> Array.tryHead |> Option.defaultValue defaultHack
 | 
					            let weaponName = player.Arsenal |> Array.tryHead |> Option.defaultValue defaultHack
 | 
				
			||||||
            do! Message.sendInteractionEvent event
 | 
					            do! Message.sendInteractionEvent event
 | 
				
			||||||
                  ($"Next why don't you try hacking me. You currently have {weaponName} equipped. To hack me and get some money, "
 | 
					                  ($"Next why don't you try hacking me. You currently have {weaponName} equipped. 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."
 | 
				
			||||||
@ -160,7 +164,7 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
 | 
				
			|||||||
        | Some player ->
 | 
					        | Some player ->
 | 
				
			||||||
            let prize = 2
 | 
					            let prize = 2
 | 
				
			||||||
            do! Async.Sleep 1000
 | 
					            do! Async.Sleep 1000
 | 
				
			||||||
            let hack = player.Weapons |> Array.tryHead |> Option.defaultValue defaultHack
 | 
					            let hack = player.Arsenal |> Array.tryHead |> Option.defaultValue defaultHack
 | 
				
			||||||
            let embed = Embeds.responseSuccessfulHackTrainer $"<@{GuildEnvironment.botHackerBattle}>" hack prize
 | 
					            let embed = Embeds.responseSuccessfulHackTrainer $"<@{GuildEnvironment.botHackerBattle}>" hack prize
 | 
				
			||||||
            do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
 | 
					            do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
 | 
				
			||||||
            do! Async.Sleep 3000
 | 
					            do! Async.Sleep 3000
 | 
				
			||||||
 | 
				
			|||||||
@ -20,11 +20,11 @@ let tryFindPlayer (id : uint64) =
 | 
				
			|||||||
        | p -> return p
 | 
					        | p -> return p
 | 
				
			||||||
                .GetValue("Player")
 | 
					                .GetValue("Player")
 | 
				
			||||||
                .ToBsonDocument()
 | 
					                .ToBsonDocument()
 | 
				
			||||||
                |> BsonSerializer.Deserialize<Player>
 | 
					                |> BsonSerializer.Deserialize<PlayerData>
 | 
				
			||||||
                |> Some
 | 
					                |> Some
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let insertNewPlayer (player : Player) =
 | 
					let insertNewPlayer (player : PlayerData) =
 | 
				
			||||||
    async {
 | 
					    async {
 | 
				
			||||||
        let dict = [ KeyValuePair("Player" , player.ToBsonDocument() :> Object) ]
 | 
					        let dict = [ KeyValuePair("Player" , player.ToBsonDocument() :> Object) ]
 | 
				
			||||||
        do! BsonDocument(dict)
 | 
					        do! BsonDocument(dict)
 | 
				
			||||||
@ -32,7 +32,7 @@ let insertNewPlayer (player : Player) =
 | 
				
			|||||||
            |> Async.AwaitTask
 | 
					            |> Async.AwaitTask
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let deletePlayer (player : Player) =
 | 
					let deletePlayer (player : PlayerData) =
 | 
				
			||||||
    async {
 | 
					    async {
 | 
				
			||||||
        let dict = [ KeyValuePair("Player" , player.ToBsonDocument() :> Object) ]
 | 
					        let dict = [ KeyValuePair("Player" , player.ToBsonDocument() :> Object) ]
 | 
				
			||||||
        do! BsonDocument(dict)
 | 
					        do! BsonDocument(dict)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										129
									
								
								Shared/Shared.fs
									
									
									
									
									
								
							
							
						
						
									
										129
									
								
								Shared/Shared.fs
									
									
									
									
									
								
							@ -5,17 +5,20 @@ open DSharpPlus
 | 
				
			|||||||
open DSharpPlus.Entities
 | 
					open DSharpPlus.Entities
 | 
				
			||||||
open DSharpPlus.EventArgs
 | 
					open DSharpPlus.EventArgs
 | 
				
			||||||
open DSharpPlus.SlashCommands
 | 
					open DSharpPlus.SlashCommands
 | 
				
			||||||
 | 
					open Newtonsoft.Json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ItemType =
 | 
					[<Measure>]
 | 
				
			||||||
    | Hack
 | 
					type mins
 | 
				
			||||||
    | Shield
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ActionClass =
 | 
					[<Measure>]
 | 
				
			||||||
 | 
					type GBT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type BattleClass =
 | 
				
			||||||
    | Network
 | 
					    | Network
 | 
				
			||||||
    | Exploit
 | 
					    | Exploit
 | 
				
			||||||
    | Penetration
 | 
					    | Penetration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Hack =
 | 
					type HackId =
 | 
				
			||||||
    | Virus = 0
 | 
					    | Virus = 0
 | 
				
			||||||
    | Ransom = 1
 | 
					    | Ransom = 1
 | 
				
			||||||
    | Worm = 2
 | 
					    | Worm = 2
 | 
				
			||||||
@ -23,30 +26,28 @@ type Hack =
 | 
				
			|||||||
    | Crack = 4
 | 
					    | Crack = 4
 | 
				
			||||||
    | Injection = 5
 | 
					    | Injection = 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Shield =
 | 
					type ShieldId =
 | 
				
			||||||
    | Firewall = 0
 | 
					    | Firewall = 6
 | 
				
			||||||
    | PortScan = 1
 | 
					    | PortScan = 7
 | 
				
			||||||
    | Encryption = 2
 | 
					    | Encryption = 8
 | 
				
			||||||
    | Hardening = 4
 | 
					    | Hardening = 9
 | 
				
			||||||
    | Sanitation = 5
 | 
					    | Sanitation = 10
 | 
				
			||||||
    | Cypher = 3
 | 
					    | Cypher = 11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[<CLIMutable>]
 | 
					type ItemType =
 | 
				
			||||||
type Item = {
 | 
					    | Hack
 | 
				
			||||||
 | 
					    | Shield
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type BattleItem = {
 | 
				
			||||||
 | 
					    Id : int
 | 
				
			||||||
    Name : string
 | 
					    Name : string
 | 
				
			||||||
    ItemType : ItemType
 | 
					    Cost : int<GBT>
 | 
				
			||||||
    Cost : int
 | 
					    Type : ItemType
 | 
				
			||||||
 | 
					    Class : BattleClass
 | 
				
			||||||
 | 
					    Power : int
 | 
				
			||||||
 | 
					    Cooldown : int<mins>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let hackInventory = [| Hack.Virus ; Hack.Ransom ; Hack.DDos ; Hack.Worm ; Hack.Crack ; Hack.Injection |]
 | 
					 | 
				
			||||||
let shieldInventory = [| Shield.Firewall  ; Shield.PortScan ; Shield.Encryption ; Shield.Cypher ; Shield.Hardening ; Shield.Sanitation |]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let getClass =
 | 
					 | 
				
			||||||
    function
 | 
					 | 
				
			||||||
    | 0 | 1 -> Network
 | 
					 | 
				
			||||||
    | 2 | 3 -> Exploit
 | 
					 | 
				
			||||||
    | 4 | _ -> Penetration
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type HackResult =
 | 
					type HackResult =
 | 
				
			||||||
    | Strong
 | 
					    | Strong
 | 
				
			||||||
    | Weak
 | 
					    | Weak
 | 
				
			||||||
@ -54,26 +55,37 @@ type HackResult =
 | 
				
			|||||||
[<CLIMutable>]
 | 
					[<CLIMutable>]
 | 
				
			||||||
type DiscordPlayer = { Id: uint64; Name: string }
 | 
					type DiscordPlayer = { Id: uint64; Name: string }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[<CLIMutable>]
 | 
					type Attack = {
 | 
				
			||||||
type Attack =
 | 
					    Result : bool
 | 
				
			||||||
    { HackType: Hack
 | 
					 | 
				
			||||||
    Target : DiscordPlayer
 | 
					    Target : DiscordPlayer
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ActionType =
 | 
				
			||||||
 | 
					    | Attack of target : DiscordPlayer * result : bool
 | 
				
			||||||
 | 
					    | Defense
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Action =
 | 
				
			||||||
 | 
					    { ActionId : int
 | 
				
			||||||
 | 
					      Type : ActionType
 | 
				
			||||||
      Timestamp : DateTime }
 | 
					      Timestamp : DateTime }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[<CLIMutable>]
 | 
					[<CLIMutable>]
 | 
				
			||||||
type Defense =
 | 
					type PlayerData =
 | 
				
			||||||
    { DefenseType: Shield
 | 
					 | 
				
			||||||
      Timestamp: DateTime }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[<CLIMutable>]
 | 
					 | 
				
			||||||
type Player =
 | 
					 | 
				
			||||||
    { DiscordId : uint64
 | 
					    { DiscordId : uint64
 | 
				
			||||||
      Name : string
 | 
					      Name : string
 | 
				
			||||||
      Weapons: Hack array
 | 
					      Arsenal : BattleItem array
 | 
				
			||||||
      Shields: Shield array
 | 
					      Actions : Action array
 | 
				
			||||||
      Attacks: Attack array
 | 
					      Bank : int<GBT> }
 | 
				
			||||||
      Defenses: Defense array
 | 
					
 | 
				
			||||||
      Bank: int }
 | 
					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 = Hack)
 | 
				
			||||||
 | 
					    let attacks player =
 | 
				
			||||||
 | 
					        player.Actions
 | 
				
			||||||
 | 
					        |> Array.choose (fun act -> match act.Type with Attack (t,r) -> Some (act,t,r) | Defense -> None)
 | 
				
			||||||
 | 
					    let defenses player = player.Actions |> Array.filter (fun act -> match act.Type with Defense _ -> true | _ -> false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let getAttacksFlat actions = actions |> Array.choose (fun act -> match act.Type with Attack (t,r) -> Some (act,t,r) | Defense -> None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let createSimpleResponseAsync msg (ctx: InteractionContext) =
 | 
					let createSimpleResponseAsync msg (ctx: InteractionContext) =
 | 
				
			||||||
    async {
 | 
					    async {
 | 
				
			||||||
@ -91,21 +103,30 @@ let notYetAHackerMsg =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
let hackDescription = ""
 | 
					let hackDescription = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let statusFormat player =
 | 
					let statusFormat p =
 | 
				
			||||||
    $"Hack Inventory: {player.Weapons |> Array.toList}
 | 
					    $"Hacks: {Player.hacks p |> Array.toList}
 | 
				
			||||||
Shield Inventory: {player.Shields |> Array.toList}
 | 
					Shields: {Player.defenses p |> Array.toList}
 | 
				
			||||||
Active Hacks: {player.Attacks |> Array.toList}
 | 
					Hack Attacks: {Player.attacks p |> Array.toList}
 | 
				
			||||||
Active Defenses: {player.Defenses |> Array.toList}
 | 
					Active Defenses: {Player.defenses p |> Array.toList}
 | 
				
			||||||
Bank: {player.Bank}"
 | 
					Bank: {p.Bank}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let armoury =
 | 
				
			||||||
 | 
					    let file = System.IO.File.ReadAllText("Items.json")
 | 
				
			||||||
 | 
					    JsonConvert.DeserializeObject<BattleItem array>(file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let getItemFromArmoury id = armoury |> Array.find (fun w -> w.Id = id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let constructButtons (actionType: string) (playerInfo: string) (weapons: 'a array) =
 | 
					let constructButtons (actionType: string) (playerInfo: string) (weapons: 'a array) =
 | 
				
			||||||
    weapons
 | 
					    weapons
 | 
				
			||||||
    |> Seq.map (fun hack -> DiscordButtonComponent(ButtonStyle.Primary, $"{actionType}-{hack}-{playerInfo}", $"{hack}"))
 | 
					    |> Seq.map (fun hack -> DiscordButtonComponent(ButtonStyle.Primary, $"{actionType}-{hack}-{playerInfo}", $"{hack}"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let removeExpiredActions timespan (timestamp: 'a -> DateTime) actions =
 | 
					let removeExpiredActions actions =
 | 
				
			||||||
    actions |> Array.filter (fun act -> DateTime.UtcNow - (timestamp act) < timespan)
 | 
					    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 modifyPlayerBank player amount = { player with Bank = Math.Max(player.Bank + amount, 0) }
 | 
					let modifyPlayerBank player amount = { player with Bank = max (player.Bank + amount) 0<GBT> }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module Message =
 | 
					module Message =
 | 
				
			||||||
    let sendFollowUpMessage (event : ComponentInteractionCreateEventArgs) msg =
 | 
					    let sendFollowUpMessage (event : ComponentInteractionCreateEventArgs) msg =
 | 
				
			||||||
@ -118,6 +139,18 @@ module Message =
 | 
				
			|||||||
                |> Async.Ignore
 | 
					                |> 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) buttonId msg =
 | 
					    let sendFollowUpMessageWithButton (event : ComponentInteractionCreateEventArgs) buttonId msg =
 | 
				
			||||||
        async {
 | 
					        async {
 | 
				
			||||||
            let builder = DiscordFollowupMessageBuilder()
 | 
					            let builder = DiscordFollowupMessageBuilder()
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user