New item types
This commit is contained in:
		
							parent
							
								
									9659656e4a
								
							
						
					
					
						commit
						a0267b4cbb
					
				
							
								
								
									
										15
									
								
								Bot/Bot.fs
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								Bot/Bot.fs
									
									
									
									
									
								
							@ -19,6 +19,7 @@ let storeConfig = DiscordConfiguration()
 | 
				
			|||||||
let stealConfig = DiscordConfiguration()
 | 
					let stealConfig = DiscordConfiguration()
 | 
				
			||||||
//let slotMachineConfig = DiscordConfiguration()
 | 
					//let slotMachineConfig = DiscordConfiguration()
 | 
				
			||||||
//hackerBattleConfig.MinimumLogLevel <- Microsoft.Extensions.Logging.LogLevel.Trace
 | 
					//hackerBattleConfig.MinimumLogLevel <- Microsoft.Extensions.Logging.LogLevel.Trace
 | 
				
			||||||
 | 
					//storeConfig.MinimumLogLevel <- Microsoft.Extensions.Logging.LogLevel.Trace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//let configs = [| hackerBattleConfig ; storeConfig ; slotMachineConfig ; |]
 | 
					//let configs = [| hackerBattleConfig ; storeConfig ; slotMachineConfig ; |]
 | 
				
			||||||
let configs = [ hackerBattleConfig ; storeConfig ; stealConfig ]
 | 
					let configs = [ hackerBattleConfig ; storeConfig ; stealConfig ]
 | 
				
			||||||
@ -99,20 +100,6 @@ stealBot.ConnectAsync() |> Async.AwaitTask |> Async.RunSynchronously
 | 
				
			|||||||
//    return ()
 | 
					//    return ()
 | 
				
			||||||
//} |> Async.RunSynchronously
 | 
					//} |> Async.RunSynchronously
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if guild = 922419263275425832uL then
 | 
					 | 
				
			||||||
    let interactionsConfig = DiscordConfiguration()
 | 
					 | 
				
			||||||
    interactionsConfig.TokenType <- TokenType.Bot
 | 
					 | 
				
			||||||
    interactionsConfig.Intents <- DiscordIntents.All
 | 
					 | 
				
			||||||
    interactionsConfig.Token <- GuildEnvironment.tokenPlayerInteractions
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let interactionsBot = new DiscordClient(interactionsConfig)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let commands = interactionsBot.UseSlashCommands()
 | 
					 | 
				
			||||||
    commands.RegisterCommands<PlayerInteractions.PlayerInteractions>(guild)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    interactionsBot.ConnectAsync() |> Async.AwaitTask |> Async.RunSynchronously
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Task.Delay(-1)
 | 
					Task.Delay(-1)
 | 
				
			||||||
|> Async.AwaitTask
 | 
					|> Async.AwaitTask
 | 
				
			||||||
|> Async.RunSynchronously
 | 
					|> Async.RunSynchronously
 | 
				
			||||||
 | 
				
			|||||||
@ -1,23 +1,23 @@
 | 
				
			|||||||
module Degenz.DbService
 | 
					module Degenz.DbService
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open Degenz
 | 
					 | 
				
			||||||
open System
 | 
					open System
 | 
				
			||||||
open Npgsql.FSharp
 | 
					open Npgsql.FSharp
 | 
				
			||||||
 | 
					open Degenz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type User = {
 | 
					type User = {
 | 
				
			||||||
    Name : string
 | 
					    Name : string
 | 
				
			||||||
    DiscordId : uint64
 | 
					    DiscordId : uint64
 | 
				
			||||||
    Bank : int<GBT>
 | 
					    Bank : int<GBT>
 | 
				
			||||||
    Strength : int
 | 
					    Strength : int
 | 
				
			||||||
    Inventory : int array
 | 
					    Inventory : int list
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let mapBack user : PlayerData =
 | 
					let mapBack user : PlayerData =
 | 
				
			||||||
    { DiscordId = user.DiscordId
 | 
					    { DiscordId = user.DiscordId
 | 
				
			||||||
      Name = user.Name
 | 
					      Name = user.Name
 | 
				
			||||||
      Inventory = user.Inventory |> Array.choose (fun id -> Armory.battleItems |> Array.tryFind (fun i -> i.Id = id))
 | 
					      Inventory = user.Inventory |> List.choose (fun id -> Armory.battleItems |> List.tryFind (fun item -> item.Id = id))
 | 
				
			||||||
      Events = [||]
 | 
					      Events = [||]
 | 
				
			||||||
      Traits = { PlayerTraits.empty with Strength = user.Strength }
 | 
					      Stats = [ { Id = StatId.Strength ; Amount = user.Strength } ]
 | 
				
			||||||
      Bank = user.Bank
 | 
					      Bank = user.Bank
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -70,7 +70,7 @@ let tryFindPlayer connStr (discordId : uint64) =
 | 
				
			|||||||
                    Name = read.string "display_name"
 | 
					                    Name = read.string "display_name"
 | 
				
			||||||
                    Bank = read.int "gbt" * 1<GBT>
 | 
					                    Bank = read.int "gbt" * 1<GBT>
 | 
				
			||||||
                    Strength = read.int "strength"
 | 
					                    Strength = read.int "strength"
 | 
				
			||||||
                    Inventory = read.intArray "inventory"
 | 
					                    Inventory = read.intArray "inventory" |> Array.toList
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            |> Async.AwaitTask
 | 
					            |> Async.AwaitTask
 | 
				
			||||||
        match List.tryHead user with
 | 
					        match List.tryHead user with
 | 
				
			||||||
@ -90,8 +90,8 @@ let updatePlayer connStr (player : PlayerData) =
 | 
				
			|||||||
    |> Sql.parameters [
 | 
					    |> Sql.parameters [
 | 
				
			||||||
        "did", Sql.string (string player.DiscordId)
 | 
					        "did", Sql.string (string player.DiscordId)
 | 
				
			||||||
        "gbt", Sql.int (int player.Bank)
 | 
					        "gbt", Sql.int (int player.Bank)
 | 
				
			||||||
        "str", Sql.int (int player.Traits.Strength)
 | 
					        "str", Sql.int (player |> Player.getStat StatId.Strength |> int)
 | 
				
			||||||
        "inv", Sql.intArray (player.Inventory |> Array.map (fun i -> i.Id))
 | 
					        "inv", Sql.intArray (player.Inventory |> Array.ofList |> Array.map (fun item -> item.Id))
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
    |> Sql.query """
 | 
					    |> Sql.query """
 | 
				
			||||||
           UPDATE "user" SET gbt = @gbt, strength = @str, inventory = @inv
 | 
					           UPDATE "user" SET gbt = @gbt, strength = @str, inventory = @inv
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										134
									
								
								Bot/Embeds.fs
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								Bot/Embeds.fs
									
									
									
									
									
								
							@ -8,35 +8,29 @@ open DSharpPlus.Entities
 | 
				
			|||||||
let hackGif = "https://s10.gifyu.com/images/Hacker-Degenz-V20ce8eb832734aa62-min.gif"
 | 
					let hackGif = "https://s10.gifyu.com/images/Hacker-Degenz-V20ce8eb832734aa62-min.gif"
 | 
				
			||||||
let shieldGif = "https://s10.gifyu.com/images/Defense-Degenz-V2-min.gif"
 | 
					let shieldGif = "https://s10.gifyu.com/images/Defense-Degenz-V2-min.gif"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let getHackIcon = function
 | 
					let getItemIcon id =
 | 
				
			||||||
    | HackId.Virus -> "https://s10.gifyu.com/images/Virus-icon.jpg"
 | 
					    match enum<ItemId>(id) with
 | 
				
			||||||
    | HackId.RemoteAccess -> "https://s10.gifyu.com/images/Mind-Control-Degenz-V2-min.jpg"
 | 
					    | ItemId.Virus -> "https://s10.gifyu.com/images/Virus-icon.jpg"
 | 
				
			||||||
    | HackId.Worm -> "https://s10.gifyu.com/images/WormBugAttack_Degenz-min.jpg"
 | 
					    | ItemId.RemoteAccess -> "https://s10.gifyu.com/images/Mind-Control-Degenz-V2-min.jpg"
 | 
				
			||||||
 | 
					    | ItemId.Worm -> "https://s10.gifyu.com/images/WormBugAttack_Degenz-min.jpg"
 | 
				
			||||||
 | 
					    | ItemId.Firewall -> "https://s10.gifyu.com/images/Defense-GIF-1-Degenz-1.jpg"
 | 
				
			||||||
 | 
					    | ItemId.Encryption -> "https://s10.gifyu.com/images/Encryption-Degenz-V2-1-min.jpg"
 | 
				
			||||||
 | 
					    | ItemId.Cypher -> "https://s10.gifyu.com/images/Cypher-Smaller.jpg"
 | 
				
			||||||
    | _ -> hackGif
 | 
					    | _ -> hackGif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let getShieldIcon = function
 | 
					let getItemGif id =
 | 
				
			||||||
    | ShieldId.Firewall -> "https://s10.gifyu.com/images/Defense-GIF-1-Degenz-1.jpg"
 | 
					    match enum<ItemId>(id) with
 | 
				
			||||||
    | ShieldId.Encryption -> "https://s10.gifyu.com/images/Encryption-Degenz-V2-1-min.jpg"
 | 
					    | ItemId.Virus -> "https://s10.gifyu.com/images/Attack-DegenZ-1.gif"
 | 
				
			||||||
    | ShieldId.Cypher -> "https://s10.gifyu.com/images/Cypher-Smaller.jpg"
 | 
					    | ItemId.RemoteAccess -> "https://s10.gifyu.com/images/Mind-Control-Degenz-V2-min.gif"
 | 
				
			||||||
    | _ -> shieldGif
 | 
					    | ItemId.Worm -> "https://s10.gifyu.com/images/WormBugAttack_Degenz-min.gif"
 | 
				
			||||||
 | 
					    | ItemId.Firewall -> "https://s10.gifyu.com/images/Defense-GIF-1-Degenz-min.gif"
 | 
				
			||||||
let getHackGif = function
 | 
					    | ItemId.Encryption -> "https://s10.gifyu.com/images/Encryption-Degenz-V2-1-min.gif"
 | 
				
			||||||
    | HackId.Virus -> "https://s10.gifyu.com/images/Attack-DegenZ-1.gif"
 | 
					    | ItemId.Cypher -> "https://s10.gifyu.com/images/Cypher-Smaller.gif"
 | 
				
			||||||
    | HackId.RemoteAccess -> "https://s10.gifyu.com/images/Mind-Control-Degenz-V2-min.gif"
 | 
					 | 
				
			||||||
    | HackId.Worm -> "https://s10.gifyu.com/images/WormBugAttack_Degenz-min.gif"
 | 
					 | 
				
			||||||
    | _ -> hackGif
 | 
					    | _ -> hackGif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let getShieldGif = function
 | 
					let constructButtons (actionId: string) (buttonInfo : string) (player: PlayerData) items ignoreCooldown =
 | 
				
			||||||
    | ShieldId.Firewall -> "https://s10.gifyu.com/images/Defense-GIF-1-Degenz-min.gif"
 | 
					    items
 | 
				
			||||||
    | ShieldId.Encryption -> "https://s10.gifyu.com/images/Encryption-Degenz-V2-1-min.gif"
 | 
					    |> List.map (fun item ->
 | 
				
			||||||
    | ShieldId.Cypher -> "https://s10.gifyu.com/images/Cypher-Smaller.gif"
 | 
					 | 
				
			||||||
    | _ -> shieldGif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let constructButtons (actionId: string) (buttonInfo : string) (player: PlayerData) itemType ignoreCooldown =
 | 
					 | 
				
			||||||
    player
 | 
					 | 
				
			||||||
    |> Player.getItems itemType
 | 
					 | 
				
			||||||
    |> Array.sortBy (fun i -> i.Power)
 | 
					 | 
				
			||||||
    |> Array.map (fun item ->
 | 
					 | 
				
			||||||
        let action =
 | 
					        let action =
 | 
				
			||||||
            player.Events
 | 
					            player.Events
 | 
				
			||||||
            |> Array.tryFind (fun i ->
 | 
					            |> Array.tryFind (fun i ->
 | 
				
			||||||
@ -44,7 +38,7 @@ let constructButtons (actionId: string) (buttonInfo : string) (player: PlayerDat
 | 
				
			|||||||
                | Hacking h -> h.HackId = item.Id && h.IsInstigator
 | 
					                | Hacking h -> h.HackId = item.Id && h.IsInstigator
 | 
				
			||||||
                | Shielding id -> id = item.Id
 | 
					                | Shielding id -> id = item.Id
 | 
				
			||||||
                | _ -> false)
 | 
					                | _ -> false)
 | 
				
			||||||
        let btnColor = WeaponClass.getClassButtonColor item.Class
 | 
					        let btnColor = WeaponClass.getClassButtonColor item
 | 
				
			||||||
        match action , ignoreCooldown with
 | 
					        match action , ignoreCooldown with
 | 
				
			||||||
        | None , _ | Some _ , true ->
 | 
					        | None , _ | Some _ , true ->
 | 
				
			||||||
            DiscordButtonComponent(btnColor, $"{actionId}-{item.Id}-{buttonInfo}-{player.Name}", $"{item.Name}")
 | 
					            DiscordButtonComponent(btnColor, $"{actionId}-{item.Id}-{buttonInfo}-{player.Name}", $"{item.Name}")
 | 
				
			||||||
@ -54,17 +48,18 @@ let constructButtons (actionId: string) (buttonInfo : string) (player: PlayerDat
 | 
				
			|||||||
    |> Seq.cast<DiscordComponent>
 | 
					    |> Seq.cast<DiscordComponent>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let pickDefense actionId player isTrainer =
 | 
					let pickDefense actionId player isTrainer =
 | 
				
			||||||
    let buttons = constructButtons actionId (string player.DiscordId) player ItemType.Shield isTrainer
 | 
					    let shieldItems = player |> Player.getShieldItems
 | 
				
			||||||
 | 
					    let buttons = constructButtons actionId (string player.DiscordId) player shieldItems isTrainer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let embed =
 | 
					    let embed =
 | 
				
			||||||
        DiscordEmbedBuilder()
 | 
					        DiscordEmbedBuilder()
 | 
				
			||||||
            .WithTitle("Shield Defense")
 | 
					            .WithTitle("Shield Defense")
 | 
				
			||||||
            .WithDescription("Pick a shield to protect yourself from hacks")
 | 
					            .WithDescription("Pick a shield to protect yourself from hacks")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for s in Player.getShields player |> Array.sortBy (fun i -> i.Power) do
 | 
					    for (item,sClass,cooldown) in Player.getShields player do
 | 
				
			||||||
        let hours = TimeSpan.FromMinutes(int s.Cooldown).TotalHours
 | 
					        let hours = TimeSpan.FromMinutes(int cooldown).TotalHours
 | 
				
			||||||
        let against = WeaponClass.getGoodAgainst(s.Class) |> snd
 | 
					        let against = WeaponClass.getGoodAgainst(sClass) |> snd
 | 
				
			||||||
        embed.AddField(s.Name, $"Active {hours} hours\nDefeats {against}", true) |> ignore
 | 
					        embed.AddField(item.Name, $"Active {hours} hours\nDefeats {against}", true) |> ignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DiscordFollowupMessageBuilder()
 | 
					    DiscordFollowupMessageBuilder()
 | 
				
			||||||
        .AddComponents(buttons)
 | 
					        .AddComponents(buttons)
 | 
				
			||||||
@ -72,7 +67,8 @@ let pickDefense actionId player isTrainer =
 | 
				
			|||||||
        .AsEphemeral(true)
 | 
					        .AsEphemeral(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let pickHack actionId attacker defender isTrainer =
 | 
					let pickHack actionId attacker defender isTrainer =
 | 
				
			||||||
    let buttons = constructButtons actionId $"{defender.DiscordId}-{defender.Name}" attacker ItemType.Hack isTrainer
 | 
					    let hackItems = attacker |> Player.getHackItems
 | 
				
			||||||
 | 
					    let buttons = constructButtons actionId $"{defender.DiscordId}-{defender.Name}" attacker hackItems isTrainer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let stealMsg = if not isTrainer then $"{defender.Name} has **{defender.Bank} $GBT** we can take from them. " else ""
 | 
					    let stealMsg = if not isTrainer then $"{defender.Name} has **{defender.Bank} $GBT** we can take from them. " else ""
 | 
				
			||||||
    let embed =
 | 
					    let embed =
 | 
				
			||||||
@ -81,9 +77,9 @@ let pickHack actionId attacker defender isTrainer =
 | 
				
			|||||||
            .WithDescription($"{stealMsg}Pick the hack you want to use.")
 | 
					            .WithDescription($"{stealMsg}Pick the hack you want to use.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if not isTrainer then
 | 
					    if not isTrainer then
 | 
				
			||||||
        for h in Player.getHacks attacker |> Array.sortBy (fun i -> i.Power) do
 | 
					        for (item,power,hClass,cooldown) in Player.getHacks attacker do
 | 
				
			||||||
            let amount = if h.Power > int defender.Bank then int defender.Bank else h.Power
 | 
					            let amount = if power > int defender.Bank then int defender.Bank else power
 | 
				
			||||||
            embed.AddField(h.Name, $"Cooldown {h.Cooldown} mins\nExtract {amount} $GBT", true) |> ignore
 | 
					            embed.AddField(item.Name, $"Cooldown {cooldown} mins\nExtract {amount} $GBT", true) |> ignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DiscordFollowupMessageBuilder()
 | 
					    DiscordFollowupMessageBuilder()
 | 
				
			||||||
        .AddComponents(buttons)
 | 
					        .AddComponents(buttons)
 | 
				
			||||||
@ -93,7 +89,7 @@ let pickHack actionId attacker defender isTrainer =
 | 
				
			|||||||
let responseSuccessfulHack earnedMoney (targetId : uint64) amountTaken (hack : Item) =
 | 
					let responseSuccessfulHack earnedMoney (targetId : uint64) amountTaken (hack : Item) =
 | 
				
			||||||
    let embed =
 | 
					    let embed =
 | 
				
			||||||
        DiscordEmbedBuilder()
 | 
					        DiscordEmbedBuilder()
 | 
				
			||||||
          .WithImageUrl(getHackGif (enum<HackId>(hack.Id)))
 | 
					          .WithImageUrl(getItemGif hack.Id)
 | 
				
			||||||
          .WithTitle("Hack Attack")
 | 
					          .WithTitle("Hack Attack")
 | 
				
			||||||
          .WithDescription($"You successfully hacked <@{targetId}> using {hack.Name}"
 | 
					          .WithDescription($"You successfully hacked <@{targetId}> using {hack.Name}"
 | 
				
			||||||
                            + (if earnedMoney then $", and took {amountTaken} 💰$GBT from them!" else "!"))
 | 
					                            + (if earnedMoney then $", and took {amountTaken} 💰$GBT from them!" else "!"))
 | 
				
			||||||
@ -102,10 +98,10 @@ let responseSuccessfulHack earnedMoney (targetId : uint64) amountTaken (hack : I
 | 
				
			|||||||
        .AddEmbed(embed.Build())
 | 
					        .AddEmbed(embed.Build())
 | 
				
			||||||
        .AsEphemeral(true)
 | 
					        .AsEphemeral(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let responseCreatedShield (shield : Item) =
 | 
					let responseCreatedShield ((item,_,cooldown) : ShieldItem) =
 | 
				
			||||||
    let embed = DiscordEmbedBuilder().WithImageUrl(getShieldGif (enum<ShieldId>(shield.Id)))
 | 
					    let embed = DiscordEmbedBuilder().WithImageUrl(getItemGif item.Id)
 | 
				
			||||||
    embed.Title <- "Mounted Shield"
 | 
					    embed.Title <- "Mounted Shield"
 | 
				
			||||||
    embed.Description <- $"Mounted {shield.Name} shield for {TimeSpan.FromMinutes(int shield.Cooldown).Hours} hours"
 | 
					    embed.Description <- $"Mounted {item.Name} shield for {TimeSpan.FromMinutes(int cooldown).Hours} hours"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DiscordFollowupMessageBuilder()
 | 
					    DiscordFollowupMessageBuilder()
 | 
				
			||||||
        .AddEmbed(embed)
 | 
					        .AddEmbed(embed)
 | 
				
			||||||
@ -115,60 +111,52 @@ let eventSuccessfulHack (ctx : IDiscordContext) target prize =
 | 
				
			|||||||
    DiscordMessageBuilder()
 | 
					    DiscordMessageBuilder()
 | 
				
			||||||
        .WithContent($"{ctx.GetDiscordMember().Username} successfully hacked <@{target.DiscordId}> and took {prize} GoodBoyTokenz")
 | 
					        .WithContent($"{ctx.GetDiscordMember().Username} successfully hacked <@{target.DiscordId}> and took {prize} GoodBoyTokenz")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let getBuyItemsEmbed (player : PlayerData) (itemType : ItemType) (store : Item array) =
 | 
					let getBuyItemsEmbed (playerInventory : Inventory) (storeInventory : Inventory) =
 | 
				
			||||||
    let embeds , buttons =
 | 
					    let embeds , buttons =
 | 
				
			||||||
        store
 | 
					        storeInventory
 | 
				
			||||||
        |> Array.filter (fun i -> i.Type = itemType)
 | 
					        |> List.map (fun item ->
 | 
				
			||||||
        |> Array.map (fun item ->
 | 
					 | 
				
			||||||
            let embed = DiscordEmbedBuilder()
 | 
					            let embed = DiscordEmbedBuilder()
 | 
				
			||||||
            match item.Type with
 | 
					            match item.Type with
 | 
				
			||||||
            | ItemType.Hack ->
 | 
					            | Hack(power,_,cooldown) ->
 | 
				
			||||||
                embed
 | 
					                embed.AddField($"$GBT Reward  |", string power, true)
 | 
				
			||||||
                    .AddField($"$GBT Reward  |", string item.Power, true)
 | 
					                     .AddField("Cooldown  |", $"{TimeSpan.FromMinutes(int cooldown).Minutes} minutes", true)
 | 
				
			||||||
                    .AddField("Cooldown  |", $"{TimeSpan.FromMinutes(int item.Cooldown).Minutes} minutes", true)
 | 
					                     .WithThumbnail(getItemIcon item.Id)
 | 
				
			||||||
                    .WithThumbnail(getHackIcon (enum<HackId>(item.Id)))
 | 
					 | 
				
			||||||
                     |> ignore
 | 
					                     |> ignore
 | 
				
			||||||
            | _ ->
 | 
					            | Shield(shieldClass,cooldown) ->
 | 
				
			||||||
                embed
 | 
					                embed.AddField($"Strong against  |", WeaponClass.getGoodAgainst shieldClass |> snd |> string, true)
 | 
				
			||||||
//                    .AddField($"Defensive Strength  |", string item.Power, true)
 | 
					//                    .AddField($"Defensive Strength  |", string item.Power, true)
 | 
				
			||||||
                    .AddField($"Strong against  |", WeaponClass.getGoodAgainst item.Class |> snd |> string, true)
 | 
					                     .AddField("Active For  |", $"{TimeSpan.FromMinutes(int cooldown).Hours} hours", true)
 | 
				
			||||||
                    .AddField("Active For  |", $"{TimeSpan.FromMinutes(int item.Cooldown).Hours} hours", true)
 | 
					                     .WithThumbnail(getItemIcon item.Id)
 | 
				
			||||||
                    .WithThumbnail(getShieldIcon (enum<ShieldId>(item.Id)))
 | 
					 | 
				
			||||||
                     |> ignore
 | 
					                     |> ignore
 | 
				
			||||||
 | 
					            | _ -> ()
 | 
				
			||||||
            embed
 | 
					            embed
 | 
				
			||||||
              .AddField("Price 💰", (if item.Price = 0<GBT> then "Free" else $"{item.Price} $GBT"), true)
 | 
					              .AddField("Price 💰", (if item.Price = 0<GBT> then "Free" else $"{item.Price} $GBT"), true)
 | 
				
			||||||
              .WithColor(WeaponClass.getClassEmbedColor item.Class)
 | 
					              .WithColor(WeaponClass.getClassEmbedColor item)
 | 
				
			||||||
              .WithTitle($"{item.Name}")
 | 
					              .WithTitle($"{item.Name}")
 | 
				
			||||||
              |> ignore
 | 
					              |> ignore
 | 
				
			||||||
            let button =
 | 
					            let button =
 | 
				
			||||||
                if player.Inventory |> Array.exists (fun i -> i.Id = item.Id)
 | 
					                if playerInventory |> List.exists (fun i -> i.Id = item.Id)
 | 
				
			||||||
                    then DiscordButtonComponent(WeaponClass.getClassButtonColor item.Class, $"Buy-{item.Id}", $"Own {item.Name}", true)
 | 
					                    then DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Buy-{item.Id}", $"Own {item.Name}", true)
 | 
				
			||||||
                    else DiscordButtonComponent(WeaponClass.getClassButtonColor item.Class, $"Buy-{item.Id}", $"Buy {item.Name}")
 | 
					                    else DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Buy-{item.Id}", $"Buy {item.Name}")
 | 
				
			||||||
            embed.Build() , button :> DiscordComponent)
 | 
					            ( embed.Build() , button :> DiscordComponent ))
 | 
				
			||||||
        |> Array.unzip
 | 
					        |> List.unzip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DiscordFollowupMessageBuilder()
 | 
					    DiscordFollowupMessageBuilder()
 | 
				
			||||||
        .AddEmbeds(embeds)
 | 
					        .AddEmbeds(embeds)
 | 
				
			||||||
        .AddComponents(buttons)
 | 
					        .AddComponents(buttons)
 | 
				
			||||||
        .AsEphemeral(true)
 | 
					        .AsEphemeral(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let getSellEmbed (itemType : ItemType) (player : PlayerData) =
 | 
					let getSellEmbed (items : Item list) =
 | 
				
			||||||
    let embeds , buttons =
 | 
					    let embeds , buttons =
 | 
				
			||||||
        player.Inventory
 | 
					        items
 | 
				
			||||||
        |> Array.filter (fun i -> i.Type = itemType)
 | 
					        |> List.map (fun item ->
 | 
				
			||||||
        |> Array.map (fun item ->
 | 
					            DiscordEmbedBuilder()
 | 
				
			||||||
            let embed = DiscordEmbedBuilder()
 | 
					 | 
				
			||||||
            match item.Type with
 | 
					 | 
				
			||||||
            | ItemType.Hack -> embed.WithThumbnail(getHackIcon (enum<HackId>(item.Id))) |> ignore
 | 
					 | 
				
			||||||
            | _ -> embed.WithThumbnail(getShieldIcon (enum<ShieldId>(item.Id))) |> ignore
 | 
					 | 
				
			||||||
            embed
 | 
					 | 
				
			||||||
              .AddField("Sell For 💰", $"{item.Price} $GBT", true)
 | 
					              .AddField("Sell For 💰", $"{item.Price} $GBT", true)
 | 
				
			||||||
              .WithTitle($"{item.Name}")
 | 
					              .WithTitle($"{item.Name}")
 | 
				
			||||||
              .WithColor(WeaponClass.getClassEmbedColor item.Class)
 | 
					              .WithColor(WeaponClass.getClassEmbedColor item)
 | 
				
			||||||
              |> ignore
 | 
					              .Build()
 | 
				
			||||||
            let button = DiscordButtonComponent(WeaponClass.getClassButtonColor item.Class, $"Sell-{item.Id}", $"Sell {item.Name}")
 | 
					            , DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Sell-{id}", $"Sell {item.Name}") :> DiscordComponent)
 | 
				
			||||||
            embed.Build() , button :> DiscordComponent)
 | 
					        |> List.unzip
 | 
				
			||||||
        |> Array.unzip
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DiscordFollowupMessageBuilder()
 | 
					    DiscordFollowupMessageBuilder()
 | 
				
			||||||
        .AddEmbeds(embeds)
 | 
					        .AddEmbeds(embeds)
 | 
				
			||||||
 | 
				
			|||||||
@ -9,35 +9,80 @@ module Armory =
 | 
				
			|||||||
        let file = System.IO.File.ReadAllText("Items.json")
 | 
					        let file = System.IO.File.ReadAllText("Items.json")
 | 
				
			||||||
//        let file = System.IO.File.ReadAllText("Bot/Items.json")
 | 
					//        let file = System.IO.File.ReadAllText("Bot/Items.json")
 | 
				
			||||||
        JsonConvert.DeserializeObject<Item array>(file)
 | 
					        JsonConvert.DeserializeObject<Item array>(file)
 | 
				
			||||||
 | 
					        |> Array.toList
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let hacks = battleItems |> Array.filter (fun bi -> match bi.Type with ItemType.Hack -> true | _ -> false)
 | 
					    let hacks = battleItems |> List.filter (fun item -> match item.Type with Hack _ -> true | _ -> false)
 | 
				
			||||||
    let shields = battleItems |> Array.filter (fun bi -> match bi.Type with ItemType.Shield -> true | _ -> false)
 | 
					    let shields = battleItems |> List.filter (fun item -> match item.Type with Shield _ -> true | _ -> false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let getItem itemId = battleItems |> Array.find (fun w -> w.Id = itemId)
 | 
					    let getItem itemId = battleItems |> List.find (fun item -> item.Id = itemId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let getHackItems inventory =
 | 
				
			||||||
 | 
					        inventory
 | 
				
			||||||
 | 
					        |> List.filter (fun item -> match item.Type with Hack _ -> true | _ -> false)
 | 
				
			||||||
 | 
					        |> List.sortBy (fun item -> item.Id)
 | 
				
			||||||
 | 
					    let getShieldItems inventory =
 | 
				
			||||||
 | 
					        inventory
 | 
				
			||||||
 | 
					        |> List.filter (fun item -> match item.Type with Shield _ -> true | _ -> false)
 | 
				
			||||||
 | 
					        |> List.sortBy (fun item -> item.Id)
 | 
				
			||||||
 | 
					    let getHacks  : HackItem list =
 | 
				
			||||||
 | 
					        battleItems
 | 
				
			||||||
 | 
					        |> List.choose (fun item ->
 | 
				
			||||||
 | 
					            match item.Type with
 | 
				
			||||||
 | 
					            | Hack(power, hackClass, cooldown) -> Some (item , power, hackClass, cooldown) | _ -> None)
 | 
				
			||||||
 | 
					        |> List.sortBy (fun (item,_,_,_) -> item.Id)
 | 
				
			||||||
 | 
					    let getShields : ShieldItem list =
 | 
				
			||||||
 | 
					        battleItems
 | 
				
			||||||
 | 
					        |> List.choose (fun item ->
 | 
				
			||||||
 | 
					            match item.Type with
 | 
				
			||||||
 | 
					            | Shield(hackClass, cooldown) -> Some (item,hackClass,cooldown) | _ -> None)
 | 
				
			||||||
 | 
					        |> List.sortBy (fun (item,_,_) -> item.Id)
 | 
				
			||||||
 | 
					    let getHackById id = getHacks |> List.find (fun (item,_,_,_) -> item.Id = id)
 | 
				
			||||||
 | 
					    let getShieldById id = getShields |> List.find (fun (item,_,_) -> item.Id = id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module WeaponClass =
 | 
					module WeaponClass =
 | 
				
			||||||
    // TODO: Find a different place to put this
 | 
					    // TODO: Find a different place to put this
 | 
				
			||||||
    let SameTargetAttackCooldown = System.TimeSpan.FromHours(1)
 | 
					    let SameTargetAttackCooldown = System.TimeSpan.FromHours(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let getClassButtonColor = function
 | 
					    let getClassButtonColor item =
 | 
				
			||||||
        | 0 -> ButtonStyle.Danger
 | 
					        match item.Type with
 | 
				
			||||||
        | 1 -> ButtonStyle.Primary
 | 
					        | Hack (_,0,_) | Shield (0,_) -> ButtonStyle.Danger
 | 
				
			||||||
        | _ -> ButtonStyle.Success
 | 
					        | Hack (_,1,_) | Shield (1,_) -> ButtonStyle.Primary
 | 
				
			||||||
 | 
					        | Hack (_,2,_) | Shield (2,_) -> ButtonStyle.Success
 | 
				
			||||||
 | 
					        | _ -> ButtonStyle.Primary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let getClassEmbedColor = function
 | 
					    let getClassEmbedColor item =
 | 
				
			||||||
        | 0 -> DiscordColor.Red
 | 
					        match item.Type with
 | 
				
			||||||
        | 1 -> DiscordColor.Blurple
 | 
					        | Hack (_,0,_) | Shield (0,_) -> DiscordColor.Red
 | 
				
			||||||
        | _ -> DiscordColor.Green
 | 
					        | Hack (_,1,_) | Shield (1,_) -> DiscordColor.Blurple
 | 
				
			||||||
 | 
					        | Hack (_,2,_) | Shield (2,_) -> DiscordColor.Green
 | 
				
			||||||
 | 
					        | _ -> DiscordColor.Blurple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let getGoodAgainst = function
 | 
					    let getGoodAgainst = function
 | 
				
			||||||
        | 0     -> ( ShieldId.Firewall   , HackId.Virus        )
 | 
					        | 0     -> ( ItemId.Firewall   , ItemId.Virus        )
 | 
				
			||||||
        | 1     -> ( ShieldId.Encryption , HackId.RemoteAccess )
 | 
					        | 1     -> ( ItemId.Encryption , ItemId.RemoteAccess )
 | 
				
			||||||
        | _     -> ( ShieldId.Cypher     , HackId.Worm         )
 | 
					        | _     -> ( ItemId.Cypher     , ItemId.Worm         )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module Player =
 | 
					module Player =
 | 
				
			||||||
    let getItems itemType (player : PlayerData) = player.Inventory |> Array.filter (fun i -> i.Type = itemType)
 | 
					    let getHackItems player =
 | 
				
			||||||
    let getHacks (player : PlayerData) = getItems ItemType.Hack player
 | 
					        player.Inventory
 | 
				
			||||||
    let getShields (player : PlayerData) = getItems ItemType.Shield player
 | 
					        |> List.filter (fun item -> match item.Type with Hack _ -> true | _ -> false)
 | 
				
			||||||
 | 
					        |> List.sortBy (fun item -> item.Id)
 | 
				
			||||||
 | 
					    let getShieldItems player =
 | 
				
			||||||
 | 
					        player.Inventory
 | 
				
			||||||
 | 
					        |> List.filter (fun item -> match item.Type with Shield _ -> true | _ -> false)
 | 
				
			||||||
 | 
					        |> List.sortBy (fun item -> item.Id)
 | 
				
			||||||
 | 
					    let getHacks player : HackItem list =
 | 
				
			||||||
 | 
					        player.Inventory
 | 
				
			||||||
 | 
					        |> List.choose (fun item ->
 | 
				
			||||||
 | 
					            match item.Type with
 | 
				
			||||||
 | 
					            | Hack(power, hackClass, cooldown) -> Some (item , power, hackClass, cooldown) | _ -> None)
 | 
				
			||||||
 | 
					        |> List.sortBy (fun (item,_,_,_) -> item.Id)
 | 
				
			||||||
 | 
					    let getShields player : ShieldItem list =
 | 
				
			||||||
 | 
					        player.Inventory
 | 
				
			||||||
 | 
					        |> List.choose (fun item ->
 | 
				
			||||||
 | 
					            match item.Type with
 | 
				
			||||||
 | 
					            | Shield(hackClass, cooldown) -> Some (item , hackClass, cooldown) | _ -> None)
 | 
				
			||||||
 | 
					        |> List.sortBy (fun (item,_,_) -> item.Id)
 | 
				
			||||||
    let getHackEvents player =
 | 
					    let getHackEvents player =
 | 
				
			||||||
        player.Events
 | 
					        player.Events
 | 
				
			||||||
        |> Array.filter (fun act -> match act.Type with PlayerEventType.Hacking h -> h.IsInstigator | _ -> false)
 | 
					        |> Array.filter (fun act -> match act.Type with PlayerEventType.Hacking h -> h.IsInstigator | _ -> false)
 | 
				
			||||||
@ -55,11 +100,17 @@ module Player =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    let modifyBank (player : PlayerData) amount = { player with Bank = max (player.Bank + amount) 0<GBT> }
 | 
					    let modifyBank (player : PlayerData) amount = { player with Bank = max (player.Bank + amount) 0<GBT> }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let getStat statId player =
 | 
				
			||||||
 | 
					        player.Stats
 | 
				
			||||||
 | 
					        |> List.tryFind (fun stat -> statId = stat.Id)
 | 
				
			||||||
 | 
					        |> Option.map (fun stat -> stat.Amount)
 | 
				
			||||||
 | 
					        |> Option.defaultValue 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module Arsenal =
 | 
					module Arsenal =
 | 
				
			||||||
    let battleItemFormat (items : Item array) =
 | 
					    let battleItemFormat (items : Item list) =
 | 
				
			||||||
        match items with
 | 
					        match items with
 | 
				
			||||||
        | [||] -> "None"
 | 
					        | [] -> "None"
 | 
				
			||||||
        | _ -> items |> Array.toList |> List.map (fun i -> i.Name) |> String.concat ", "
 | 
					        | _ -> items |> List.map (fun item -> item.Name) |> String.concat ", "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let actionFormat (actions : PlayerEvent array) =
 | 
					    let actionFormat (actions : PlayerEvent array) =
 | 
				
			||||||
        match actions with
 | 
					        match actions with
 | 
				
			||||||
@ -82,8 +133,8 @@ module Arsenal =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    let statusFormat p =
 | 
					    let statusFormat p =
 | 
				
			||||||
        let hacks = Player.getHackEvents p
 | 
					        let hacks = Player.getHackEvents p
 | 
				
			||||||
        $"**Hacks:** {Player.getHacks p |> battleItemFormat}\n
 | 
					        $"**Hacks:** {Player.getHackItems p |> battleItemFormat}\n
 | 
				
			||||||
    **Shields:** {Player.getShields p |> battleItemFormat}\n
 | 
					    **Shields:** {Player.getShieldItems p |> battleItemFormat}\n
 | 
				
			||||||
    **Hack Attacks:**\n{ hacks |> Array.take (min hacks.Length 10) |> actionFormat}\n
 | 
					    **Hack Attacks:**\n{ hacks |> Array.take (min hacks.Length 10) |> actionFormat}\n
 | 
				
			||||||
    **Active Shields:**\n{Player.getShieldEvents p |> actionFormat}"
 | 
					    **Active Shields:**\n{Player.getShieldEvents p |> actionFormat}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										128
									
								
								Bot/GameTypes.fs
									
									
									
									
									
								
							
							
						
						
									
										128
									
								
								Bot/GameTypes.fs
									
									
									
									
									
								
							@ -1,111 +1,111 @@
 | 
				
			|||||||
namespace Degenz
 | 
					[<Microsoft.FSharp.Core.AutoOpen>]
 | 
				
			||||||
 | 
					module Degenz.Types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open System
 | 
					open System
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[<Microsoft.FSharp.Core.AutoOpen>]
 | 
					[<Measure>]
 | 
				
			||||||
module Types =
 | 
					type mins
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [<Measure>]
 | 
					[<Measure>]
 | 
				
			||||||
    type mins
 | 
					type GBT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [<Measure>]
 | 
					type ItemId =
 | 
				
			||||||
    type GBT
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    type HackId =
 | 
					 | 
				
			||||||
    | Virus = 0
 | 
					    | Virus = 0
 | 
				
			||||||
    | RemoteAccess = 1
 | 
					    | RemoteAccess = 1
 | 
				
			||||||
    | Worm = 2
 | 
					    | Worm = 2
 | 
				
			||||||
 | 
					 | 
				
			||||||
    type ShieldId =
 | 
					 | 
				
			||||||
    | Firewall = 6
 | 
					    | Firewall = 6
 | 
				
			||||||
    | Encryption = 7
 | 
					    | Encryption = 7
 | 
				
			||||||
    | Cypher = 8
 | 
					    | Cypher = 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    type ItemType =
 | 
					type StatId =
 | 
				
			||||||
        | Hack = 0
 | 
					    | Strength = 0
 | 
				
			||||||
        | Shield = 1
 | 
					    | Focus = 1
 | 
				
			||||||
        | Food = 1
 | 
					    | Luck = 2
 | 
				
			||||||
 | 
					    | Charisma = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    type ItemAttributes = {
 | 
					type Stat = {
 | 
				
			||||||
        Sell : bool
 | 
					    Id : StatId
 | 
				
			||||||
        Buy : bool
 | 
					    BaseDecayRate : single
 | 
				
			||||||
        Consume : bool
 | 
					    BaseMinMax : Range
 | 
				
			||||||
        Drop : bool
 | 
					}
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    with static member empty = { Sell = false ; Buy = false ; Consume = false ; Drop = false }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    type Item = {
 | 
					type ActiveStat = {
 | 
				
			||||||
        Id : int
 | 
					    Id : StatId
 | 
				
			||||||
        Name : string
 | 
					    Amount : int
 | 
				
			||||||
        Price : int<GBT>
 | 
					}
 | 
				
			||||||
        Type : ItemType
 | 
					 | 
				
			||||||
        Power : int
 | 
					 | 
				
			||||||
        Class : int
 | 
					 | 
				
			||||||
        Cooldown : int<mins>
 | 
					 | 
				
			||||||
        Attributes : ItemAttributes
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    with static member empty =
 | 
					 | 
				
			||||||
          { Id = -1
 | 
					 | 
				
			||||||
            Name = "None"
 | 
					 | 
				
			||||||
            Price = 0<GBT>
 | 
					 | 
				
			||||||
            Type = ItemType.Hack
 | 
					 | 
				
			||||||
            Power = 0
 | 
					 | 
				
			||||||
            Class = -1
 | 
					 | 
				
			||||||
            Cooldown = 0<mins>
 | 
					 | 
				
			||||||
            Attributes = ItemAttributes.empty }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    type HackResult =
 | 
					module PlayerStats =
 | 
				
			||||||
 | 
					    let Strength = { Id = StatId.Strength ; BaseDecayRate = 5.0f ; BaseMinMax = Range(0, 100) }
 | 
				
			||||||
 | 
					    let Focus    = { Id = StatId.Focus ; BaseDecayRate = 5.0f ; BaseMinMax = Range(0, 100) }
 | 
				
			||||||
 | 
					    let Luck     = { Id = StatId.Luck ; BaseDecayRate = 5.0f ; BaseMinMax = Range(0, 100) }
 | 
				
			||||||
 | 
					    let Charisma = { Id = StatId.Charisma ; BaseDecayRate = 5.0f ; BaseMinMax = Range(0, 100) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let stats = [| Strength ; Focus ; Luck ; Charisma |]
 | 
				
			||||||
 | 
					    let statConsumableMap =
 | 
				
			||||||
 | 
					        [ ( StatId.Strength , 12 )
 | 
				
			||||||
 | 
					          ( StatId.Focus , 13 )
 | 
				
			||||||
 | 
					          ( StatId.Luck , 14 )
 | 
				
			||||||
 | 
					          ( StatId.Charisma , 15 ) ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type HackResult =
 | 
				
			||||||
    | Strong
 | 
					    | Strong
 | 
				
			||||||
    | Weak
 | 
					    | Weak
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [<CLIMutable>]
 | 
					[<CLIMutable>]
 | 
				
			||||||
    type DiscordPlayer = { Id: uint64; Name: string }
 | 
					type DiscordPlayer = { Id: uint64; Name: string }
 | 
				
			||||||
    with static member empty = { Id = 0uL ; Name = "None" }
 | 
					    with static member empty = { Id = 0uL ; Name = "None" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    type HackEvent = {
 | 
					type HackEvent = {
 | 
				
			||||||
    IsInstigator : bool
 | 
					    IsInstigator : bool
 | 
				
			||||||
    Adversary : DiscordPlayer
 | 
					    Adversary : DiscordPlayer
 | 
				
			||||||
    Success : bool
 | 
					    Success : bool
 | 
				
			||||||
    HackId : int
 | 
					    HackId : int
 | 
				
			||||||
    }
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    type PlayerEventType =
 | 
					type PlayerEventType =
 | 
				
			||||||
    | Hacking of HackEvent
 | 
					    | Hacking of HackEvent
 | 
				
			||||||
    | Shielding of shieldId : int
 | 
					    | Shielding of shieldId : int
 | 
				
			||||||
    | Stealing of instigator : bool * adversary : DiscordPlayer
 | 
					    | Stealing of instigator : bool * adversary : DiscordPlayer
 | 
				
			||||||
    | Imprison
 | 
					    | Imprison
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    type PlayerEvent =
 | 
					type PlayerEvent =
 | 
				
			||||||
    { Type : PlayerEventType
 | 
					    { Type : PlayerEventType
 | 
				
			||||||
      Cooldown : int<mins>
 | 
					      Cooldown : int<mins>
 | 
				
			||||||
      Timestamp : DateTime }
 | 
					      Timestamp : DateTime }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    type PlayerTraits = {
 | 
					type HackItem = Item * int * int * int<mins>
 | 
				
			||||||
        Strength : int
 | 
					and  ShieldItem = Item * int * int<mins>
 | 
				
			||||||
        Focus : int
 | 
					and  FoodItem = Item * (Item -> PlayerData -> PlayerData)
 | 
				
			||||||
        Luck : int
 | 
					and  AccessoryItem = Item * (Item -> PlayerData -> PlayerData)
 | 
				
			||||||
        Charisma : int
 | 
					and  ItemType =
 | 
				
			||||||
    }
 | 
					    | Hack of power : int * hackClass : int * cooldown : int<mins>
 | 
				
			||||||
    with static member empty = { Strength = 0 ; Focus = 0 ; Luck = 0 ; Charisma = 0 }
 | 
					    | Shield of shieldClass : int * cooldown : int<mins>
 | 
				
			||||||
 | 
					    | Food of effect : (Item -> PlayerData -> PlayerData)
 | 
				
			||||||
    [<CLIMutable>]
 | 
					    | Accessory of effect : (Item -> PlayerData -> PlayerData)
 | 
				
			||||||
    type PlayerData = {
 | 
					and Item = {
 | 
				
			||||||
 | 
					    Id : int
 | 
				
			||||||
 | 
					    Name : string
 | 
				
			||||||
 | 
					    Price : int<GBT>
 | 
				
			||||||
 | 
					    Type : ItemType
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					and Inventory = Item list
 | 
				
			||||||
 | 
					and PlayerData = {
 | 
				
			||||||
    DiscordId : uint64
 | 
					    DiscordId : uint64
 | 
				
			||||||
    Name : string
 | 
					    Name : string
 | 
				
			||||||
        Inventory : Item array
 | 
					    Inventory : Inventory
 | 
				
			||||||
    Events : PlayerEvent array
 | 
					    Events : PlayerEvent array
 | 
				
			||||||
        Traits : PlayerTraits
 | 
					    Stats : ActiveStat list
 | 
				
			||||||
    Bank : int<GBT>
 | 
					    Bank : int<GBT>
 | 
				
			||||||
    }
 | 
					}
 | 
				
			||||||
//        Achievements : string array
 | 
					//        Achievements : string array
 | 
				
			||||||
//        XP : int
 | 
					//        XP : int
 | 
				
			||||||
    with member this.basicPlayer = { Id = this.DiscordId ; Name = this.Name }
 | 
					with member this.basicPlayer = { Id = this.DiscordId ; Name = this.Name }
 | 
				
			||||||
     static member empty =
 | 
					     static member empty =
 | 
				
			||||||
         { DiscordId = 0uL
 | 
					         { DiscordId = 0uL
 | 
				
			||||||
           Name = "None"
 | 
					           Name = "None"
 | 
				
			||||||
               Inventory = [||]
 | 
					           Inventory = []
 | 
				
			||||||
           Events = [||]
 | 
					           Events = [||]
 | 
				
			||||||
               Traits = PlayerTraits.empty
 | 
					           Stats = []
 | 
				
			||||||
//               Achievements = [||]
 | 
					//               Achievements = [||]
 | 
				
			||||||
//               XP = 0
 | 
					//               XP = 0
 | 
				
			||||||
           Bank = 0<GBT> }
 | 
					           Bank = 0<GBT> }
 | 
				
			||||||
 | 
				
			|||||||
@ -45,21 +45,21 @@ let checkWeaponHasCooldown (weapon : Item) attacker =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
let checkHasEmptyHacks attacker =
 | 
					let checkHasEmptyHacks attacker =
 | 
				
			||||||
    match Player.getHacks attacker with
 | 
					    match Player.getHacks attacker with
 | 
				
			||||||
    | [||] -> Error $"You currently do not have any Hacks to take 💰$GBT from others. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one."
 | 
					    | [] -> Error $"You currently do not have any Hacks to take 💰$GBT from others. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one."
 | 
				
			||||||
    | _ -> Ok attacker
 | 
					    | _ -> Ok attacker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let checkPlayerOwnsWeapon (item : Item) player =
 | 
					let checkPlayerOwnsWeapon (item : Item) player =
 | 
				
			||||||
    match player.Inventory |> Array.exists (fun i -> i.Id = item.Id) with
 | 
					    match player.Inventory |> List.exists (fun i -> i.Id = item.Id) with
 | 
				
			||||||
    | true -> Ok player
 | 
					    | true -> Ok player
 | 
				
			||||||
    | false -> Error $"You sold your weapon already, you cheeky bastard..."
 | 
					    | false -> Error $"You sold your weapon already, you cheeky bastard..."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let checkPlayerHasShieldSlotsAvailable (shield : Item) player =
 | 
					let checkPlayerHasShieldSlotsAvailable player =
 | 
				
			||||||
    let updatedPlayer = player |> Player.removeExpiredActions
 | 
					    let updatedPlayer = player |> Player.removeExpiredActions
 | 
				
			||||||
    let defenses = Player.getShieldEvents updatedPlayer
 | 
					    let defenses = Player.getShieldEvents updatedPlayer
 | 
				
			||||||
    match defenses |> Array.length >= 3 with
 | 
					    match defenses |> Array.length >= 3 with
 | 
				
			||||||
    | true ->
 | 
					    | true ->
 | 
				
			||||||
        let timestamp = defenses |> Array.rev |> Array.head |> fun a -> a.Timestamp // This should be the next expiring timestamp
 | 
					        let event = defenses |> Array.rev |> Array.head // This should be the next expiring timestamp
 | 
				
			||||||
        let cooldown = getTimeText true (TimeSpan.FromMinutes(int shield.Cooldown)) timestamp
 | 
					        let cooldown = getTimeText true (TimeSpan.FromMinutes(int event.Cooldown)) event.Timestamp
 | 
				
			||||||
        Error $"You are only allowed three shields at a time. Wait {cooldown} to add another shield"
 | 
					        Error $"You are only allowed three shields at a time. Wait {cooldown} to add another shield"
 | 
				
			||||||
    | false -> Ok updatedPlayer
 | 
					    | false -> Ok updatedPlayer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -68,35 +68,36 @@ let checkTargetHasFunds target player =
 | 
				
			|||||||
    | true -> Error $"Looks like the poor bastard has no $GBT... pick a different victim."
 | 
					    | true -> Error $"Looks like the poor bastard has no $GBT... pick a different victim."
 | 
				
			||||||
    | false -> Ok player
 | 
					    | false -> Ok player
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let calculateDamage (hack : Item) (shield : Item) =
 | 
					let calculateDamage ((_,_,hackClass,_) : HackItem) ((_,shieldClass,_) : ShieldItem) =
 | 
				
			||||||
    if hack.Class = shield.Class
 | 
					    if hackClass = shieldClass
 | 
				
			||||||
        then Weak
 | 
					        then Weak
 | 
				
			||||||
        else Strong
 | 
					        else Strong
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let runHackerBattle defender hack =
 | 
					let runHackerBattle defender (hack : HackItem) =
 | 
				
			||||||
    defender
 | 
					    defender
 | 
				
			||||||
    |> Player.removeExpiredActions
 | 
					    |> Player.removeExpiredActions
 | 
				
			||||||
    |> fun p -> p.Events
 | 
					    |> fun p -> p.Events
 | 
				
			||||||
    |> Array.choose (fun event ->
 | 
					    |> Array.choose (fun event ->
 | 
				
			||||||
        match event.Type with
 | 
					        match event.Type with
 | 
				
			||||||
        | Shielding id -> Armory.battleItems |> Array.find (fun w -> w.Id = id) |> Some
 | 
					        | Shielding id -> Armory.getShields |> List.find (fun (item,_,_) -> item.Id = id) |> Some
 | 
				
			||||||
        | _ -> None)
 | 
					        | _ -> None)
 | 
				
			||||||
    |> Array.map (calculateDamage hack)
 | 
					    |> Array.map (calculateDamage hack)
 | 
				
			||||||
    |> Array.contains Weak
 | 
					    |> Array.contains Weak
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let updateCombatants successfulHack (attacker : PlayerData) (defender : PlayerData) (hack : Item) prize =
 | 
					let updateCombatants successfulHack (attacker : PlayerData) (defender : PlayerData) (hack : HackItem) prize =
 | 
				
			||||||
 | 
					    let (item, power, hackClass, cooldown) = hack
 | 
				
			||||||
    let updatePlayer amount attack p =
 | 
					    let updatePlayer amount attack p =
 | 
				
			||||||
       { p with Events = Array.append [| attack |] p.Events ; Bank = max (p.Bank + amount) 0<GBT> }
 | 
					       { p with Events = Array.append [| attack |] p.Events ; Bank = max (p.Bank + amount) 0<GBT> }
 | 
				
			||||||
    let event isDefenderEvent =
 | 
					    let event isDefenderEvent =
 | 
				
			||||||
        let hackEvent = {
 | 
					        let hackEvent = {
 | 
				
			||||||
            HackId = hack.Id
 | 
					            HackId = item.Id
 | 
				
			||||||
            Adversary = if isDefenderEvent then attacker.basicPlayer else defender.basicPlayer
 | 
					            Adversary = if isDefenderEvent then attacker.basicPlayer else defender.basicPlayer
 | 
				
			||||||
            IsInstigator = not isDefenderEvent
 | 
					            IsInstigator = not isDefenderEvent
 | 
				
			||||||
            Success = successfulHack
 | 
					            Success = successfulHack
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        { Type = Hacking hackEvent
 | 
					        { Type = Hacking hackEvent
 | 
				
			||||||
          Timestamp = DateTime.UtcNow
 | 
					          Timestamp = DateTime.UtcNow
 | 
				
			||||||
          Cooldown = if isDefenderEvent then int WeaponClass.SameTargetAttackCooldown.TotalMinutes * 1<mins> else hack.Cooldown }
 | 
					          Cooldown = if isDefenderEvent then int WeaponClass.SameTargetAttackCooldown.TotalMinutes * 1<mins> else cooldown }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [ DbService.updatePlayer GuildEnvironment.pgDb <| updatePlayer  prize (event false) attacker
 | 
					    [ DbService.updatePlayer GuildEnvironment.pgDb <| updatePlayer  prize (event false) attacker
 | 
				
			||||||
      DbService.updatePlayer GuildEnvironment.pgDb <| updatePlayer -prize (event true)  defender
 | 
					      DbService.updatePlayer GuildEnvironment.pgDb <| updatePlayer -prize (event true)  defender
 | 
				
			||||||
@ -105,12 +106,13 @@ let updateCombatants successfulHack (attacker : PlayerData) (defender : PlayerDa
 | 
				
			|||||||
    |> Async.Parallel
 | 
					    |> Async.Parallel
 | 
				
			||||||
    |> Async.Ignore
 | 
					    |> Async.Ignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let successfulHack (ctx : IDiscordContext) attacker defender hack =
 | 
					let successfulHack (ctx : IDiscordContext) attacker defender (hack : HackItem) =
 | 
				
			||||||
    async {
 | 
					    async {
 | 
				
			||||||
        let prizeAmount = if hack.Power < int defender.Bank then hack.Power else int defender.Bank
 | 
					        let (item,power,hackClass,cooldown) = hack
 | 
				
			||||||
 | 
					        let prizeAmount = if power < int defender.Bank then power else int defender.Bank
 | 
				
			||||||
        do! updateCombatants true attacker defender hack (prizeAmount * 1<GBT>)
 | 
					        do! updateCombatants true attacker defender hack (prizeAmount * 1<GBT>)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let embed = Embeds.responseSuccessfulHack true defender.DiscordId prizeAmount hack
 | 
					        let embed = Embeds.responseSuccessfulHack true defender.DiscordId prizeAmount item
 | 
				
			||||||
        do! ctx.FollowUp embed |> Async.AwaitTask
 | 
					        do! ctx.FollowUp embed |> Async.AwaitTask
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let builder = Embeds.eventSuccessfulHack ctx defender prizeAmount
 | 
					        let builder = Embeds.eventSuccessfulHack ctx defender prizeAmount
 | 
				
			||||||
@ -120,9 +122,10 @@ let successfulHack (ctx : IDiscordContext) attacker defender hack =
 | 
				
			|||||||
            |> Async.Ignore
 | 
					            |> Async.Ignore
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let failedHack (ctx : IDiscordContext) attacker defender hack =
 | 
					let failedHack (ctx : IDiscordContext) attacker defender (hack : HackItem) =
 | 
				
			||||||
 | 
					    let (item, power, hackClass, cooldown) = hack
 | 
				
			||||||
    async {
 | 
					    async {
 | 
				
			||||||
        let lostAmount = if hack.Power < int attacker.Bank then hack.Power else int attacker.Bank
 | 
					        let lostAmount = if power < int attacker.Bank then power else int attacker.Bank
 | 
				
			||||||
        let msg = $"Hack failed! {defender.Name} was able to mount a successful defense! You lost {lostAmount} $GBT!"
 | 
					        let msg = $"Hack failed! {defender.Name} was able to mount a successful defense! You lost {lostAmount} $GBT!"
 | 
				
			||||||
        do! sendFollowUpMessage ctx msg
 | 
					        do! sendFollowUpMessage ctx msg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -155,7 +158,7 @@ let handleAttack (ctx : IDiscordContext) =
 | 
				
			|||||||
    executePlayerAction ctx (fun attacker -> async {
 | 
					    executePlayerAction ctx (fun attacker -> async {
 | 
				
			||||||
        let tokens = ctx.GetInteractionId().Split("-")
 | 
					        let tokens = ctx.GetInteractionId().Split("-")
 | 
				
			||||||
        let hackId = int tokens.[1]
 | 
					        let hackId = int tokens.[1]
 | 
				
			||||||
        let hack = Armory.getItem hackId
 | 
					        let item,_,_,_ as hackItem = Armory.getHackById hackId
 | 
				
			||||||
        let resultId , targetId = UInt64.TryParse tokens.[2]
 | 
					        let resultId , targetId = UInt64.TryParse tokens.[2]
 | 
				
			||||||
        let! resultTarget = DbService.tryFindPlayer GuildEnvironment.pgDb targetId
 | 
					        let! resultTarget = DbService.tryFindPlayer GuildEnvironment.pgDb targetId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -164,21 +167,21 @@ let handleAttack (ctx : IDiscordContext) =
 | 
				
			|||||||
            do! attacker
 | 
					            do! attacker
 | 
				
			||||||
                |> Player.removeExpiredActions
 | 
					                |> Player.removeExpiredActions
 | 
				
			||||||
                |> checkAlreadyHackedTarget defender
 | 
					                |> checkAlreadyHackedTarget defender
 | 
				
			||||||
                >>= checkPlayerOwnsWeapon hack
 | 
					                >>= checkPlayerOwnsWeapon item
 | 
				
			||||||
                >>= checkWeaponHasCooldown hack
 | 
					                >>= checkWeaponHasCooldown item
 | 
				
			||||||
                |> function
 | 
					                |> function
 | 
				
			||||||
                   | Ok atkr ->
 | 
					                   | Ok atkr ->
 | 
				
			||||||
                       runHackerBattle defender hack
 | 
					                       runHackerBattle defender hackItem
 | 
				
			||||||
                       |> function
 | 
					                       |> function
 | 
				
			||||||
                          | false -> successfulHack ctx atkr defender hack
 | 
					                          | false -> successfulHack ctx atkr defender hackItem
 | 
				
			||||||
                          | true -> failedHack ctx attacker defender hack
 | 
					                          | true -> failedHack ctx attacker defender hackItem
 | 
				
			||||||
                   | Error msg -> Messaging.sendFollowUpMessage ctx msg
 | 
					                   | Error msg -> Messaging.sendFollowUpMessage ctx msg
 | 
				
			||||||
        | _ -> do! Messaging.sendFollowUpMessage ctx "Error occurred processing attack"
 | 
					        | _ -> do! Messaging.sendFollowUpMessage ctx "Error occurred processing attack"
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let defend (ctx : IDiscordContext) =
 | 
					let defend (ctx : IDiscordContext) =
 | 
				
			||||||
    executePlayerAction ctx (fun player -> async {
 | 
					    executePlayerAction ctx (fun player -> async {
 | 
				
			||||||
        if Player.getShields player |> Array.length > 0 then
 | 
					        if Player.getShields player |> List.length > 0 then
 | 
				
			||||||
            let p = Player.removeExpiredActions player
 | 
					            let p = Player.removeExpiredActions player
 | 
				
			||||||
            let embed = Embeds.pickDefense "Defend" p false
 | 
					            let embed = Embeds.pickDefense "Defend" p false
 | 
				
			||||||
            do! ctx.FollowUp embed |> Async.AwaitTask
 | 
					            do! ctx.FollowUp embed |> Async.AwaitTask
 | 
				
			||||||
@ -191,18 +194,18 @@ let handleDefense (ctx : IDiscordContext) =
 | 
				
			|||||||
    executePlayerAction ctx (fun player -> async {
 | 
					    executePlayerAction ctx (fun player -> async {
 | 
				
			||||||
        let tokens = ctx.GetInteractionId().Split("-")
 | 
					        let tokens = ctx.GetInteractionId().Split("-")
 | 
				
			||||||
        let shieldId = int tokens.[1]
 | 
					        let shieldId = int tokens.[1]
 | 
				
			||||||
        let shield = Armory.getItem shieldId
 | 
					        let item, shieldClass, cooldown as shield = Armory.getShields |> List.find (fun (item,_,_) -> item.Id = shieldId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        do! player
 | 
					        do! player
 | 
				
			||||||
            |> checkPlayerOwnsWeapon shield
 | 
					            |> checkPlayerOwnsWeapon item
 | 
				
			||||||
            >>= checkPlayerHasShieldSlotsAvailable shield
 | 
					            >>= checkPlayerHasShieldSlotsAvailable
 | 
				
			||||||
            >>= checkWeaponHasCooldown shield
 | 
					            >>= checkWeaponHasCooldown item
 | 
				
			||||||
            |> handleResultWithResponse ctx (fun p -> async {
 | 
					            |> handleResultWithResponse ctx (fun p -> async {
 | 
				
			||||||
                let embed = Embeds.responseCreatedShield shield
 | 
					                let embed = Embeds.responseCreatedShield shield
 | 
				
			||||||
                do! ctx.FollowUp embed |> Async.AwaitTask
 | 
					                do! ctx.FollowUp embed |> Async.AwaitTask
 | 
				
			||||||
                let defense = {
 | 
					                let defense = {
 | 
				
			||||||
                    Type = Shielding shieldId
 | 
					                    Type = Shielding shieldId
 | 
				
			||||||
                    Cooldown = shield.Cooldown
 | 
					                    Cooldown = cooldown
 | 
				
			||||||
                    Timestamp = DateTime.UtcNow
 | 
					                    Timestamp = DateTime.UtcNow
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                do! DbService.updatePlayer GuildEnvironment.pgDb p
 | 
					                do! DbService.updatePlayer GuildEnvironment.pgDb p
 | 
				
			||||||
 | 
				
			|||||||
@ -15,30 +15,31 @@ let checkHasSufficientFunds (item : Item) player =
 | 
				
			|||||||
       else Error $"You do not have sufficient funds to buy this item! Current balance: {player.Bank} GBT"
 | 
					       else Error $"You do not have sufficient funds to buy this item! Current balance: {player.Bank} GBT"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let checkAlreadyOwnsItem (item : Item) player =
 | 
					let checkAlreadyOwnsItem (item : Item) player =
 | 
				
			||||||
    if player.Inventory |> Array.exists (fun w -> item.Id = w.Id)
 | 
					    if player.Inventory |> List.exists (fun w -> item.Id = w.Id)
 | 
				
			||||||
        then Error $"You already own {item.Name}!"
 | 
					        then Error $"You already own {item.Name}!"
 | 
				
			||||||
        else Ok player
 | 
					        else Ok player
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let checkSoldItemAlready (item : Item) player =
 | 
					let checkSoldItemAlready item player =
 | 
				
			||||||
    if player.Inventory |> Array.exists (fun w -> item.Id = w.Id)
 | 
					    if player.Inventory |> List.exists (fun i -> item.Id = i.Id)
 | 
				
			||||||
        then Ok player
 | 
					        then Ok player
 | 
				
			||||||
        else Error $"{item.Name} not found in your arsenal! Looks like you sold it already."
 | 
					        else Error $"{item.Name} not found in your inventory! Looks like you sold it already."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let checkHasItemsInArsenal itemType player =
 | 
					let checkHasItemsInArsenal itemType items player =
 | 
				
			||||||
    if player.Inventory |> Array.filter (fun i -> i.Type = itemType ) |> Array.length > 0
 | 
					    if List.isEmpty items |> not
 | 
				
			||||||
        then Ok player
 | 
					        then Ok player
 | 
				
			||||||
        else Error $"You currently have no {itemType}s in your arsenal to sell!"
 | 
					        else Error $"You currently have no {itemType} in your arsenal to sell!"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let buy itemType (ctx : IDiscordContext) =
 | 
					let buy getItems (ctx : IDiscordContext) =
 | 
				
			||||||
    executePlayerAction ctx (fun player -> async {
 | 
					    executePlayerAction ctx (fun player -> async {
 | 
				
			||||||
        let itemStore = Embeds.getBuyItemsEmbed player itemType Armory.battleItems
 | 
					        let itemStore = Embeds.getBuyItemsEmbed (getItems player.Inventory) (getItems Armory.battleItems)
 | 
				
			||||||
        do! ctx.FollowUp itemStore |> Async.AwaitTask
 | 
					        do! ctx.FollowUp itemStore |> Async.AwaitTask
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let sell itemType (ctx : IDiscordContext) =
 | 
					let sell itemType getItems (ctx : IDiscordContext) =
 | 
				
			||||||
    executePlayerAction ctx (fun player -> async {
 | 
					    executePlayerAction ctx (fun player -> async {
 | 
				
			||||||
        match checkHasItemsInArsenal itemType player with
 | 
					        let items = getItems player
 | 
				
			||||||
        | Ok _ -> let itemStore = Embeds.getSellEmbed itemType player
 | 
					        match checkHasItemsInArsenal itemType items player with
 | 
				
			||||||
 | 
					        | Ok _ -> let itemStore = Embeds.getSellEmbed items
 | 
				
			||||||
                  do! ctx.FollowUp(itemStore) |> Async.AwaitTask
 | 
					                  do! ctx.FollowUp(itemStore) |> Async.AwaitTask
 | 
				
			||||||
        | Error e -> do! sendFollowUpMessage ctx e
 | 
					        | Error e -> do! sendFollowUpMessage ctx e
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
@ -46,13 +47,13 @@ let sell itemType (ctx : IDiscordContext) =
 | 
				
			|||||||
// TODO: When you buy a shield, prompt the user to activate it
 | 
					// TODO: When you buy a shield, prompt the user to activate it
 | 
				
			||||||
let handleBuyItem (ctx : IDiscordContext) itemId =
 | 
					let handleBuyItem (ctx : IDiscordContext) itemId =
 | 
				
			||||||
    executePlayerAction ctx (fun player -> async {
 | 
					    executePlayerAction ctx (fun player -> async {
 | 
				
			||||||
        let item = Armory.battleItems |> Array.find (fun w -> w.Id = itemId)
 | 
					        let item = Armory.getItem itemId
 | 
				
			||||||
        do! player
 | 
					        do! player
 | 
				
			||||||
            |> checkHasSufficientFunds item
 | 
					            |> checkHasSufficientFunds item
 | 
				
			||||||
            >>= checkAlreadyOwnsItem item
 | 
					            >>= checkAlreadyOwnsItem item
 | 
				
			||||||
            |> handleResultWithResponse ctx (fun player -> async {
 | 
					            |> handleResultWithResponse ctx (fun player -> async {
 | 
				
			||||||
                let newBalance = player.Bank - item.Price
 | 
					                let newBalance = player.Bank - item.Price
 | 
				
			||||||
                let p = { player with Bank = newBalance ; Inventory = Array.append [| item |] player.Inventory }
 | 
					                let p = { player with Bank = newBalance ; Inventory = item::player.Inventory }
 | 
				
			||||||
                do! DbService.updatePlayer GuildEnvironment.pgDb p |> Async.Ignore
 | 
					                do! DbService.updatePlayer GuildEnvironment.pgDb p |> Async.Ignore
 | 
				
			||||||
                do! sendFollowUpMessage ctx $"Successfully purchased {item.Name}! You now have {newBalance} 💰$GBT remaining"
 | 
					                do! sendFollowUpMessage ctx $"Successfully purchased {item.Name}! You now have {newBalance} 💰$GBT remaining"
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
@ -68,7 +69,7 @@ let handleSell (ctx : IDiscordContext) itemId =
 | 
				
			|||||||
            let updatedPlayer = {
 | 
					            let updatedPlayer = {
 | 
				
			||||||
                player with
 | 
					                player with
 | 
				
			||||||
                    Bank = player.Bank + item.Price
 | 
					                    Bank = player.Bank + item.Price
 | 
				
			||||||
                    Inventory = player.Inventory |> Array.filter (fun i -> i.Id <> itemId)
 | 
					                    Inventory = player.Inventory |> List.filter (fun i -> i.Id <> itemId)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            do!
 | 
					            do!
 | 
				
			||||||
            [ DbService.updatePlayer GuildEnvironment.pgDb updatedPlayer |> Async.Ignore
 | 
					            [ DbService.updatePlayer GuildEnvironment.pgDb updatedPlayer |> Async.Ignore
 | 
				
			||||||
@ -76,7 +77,6 @@ let handleSell (ctx : IDiscordContext) itemId =
 | 
				
			|||||||
              sendFollowUpMessage ctx $"Sold {item.Type} {item.Name} for {item.Price}! Current Balance: {updatedPlayer.Bank}" ]
 | 
					              sendFollowUpMessage ctx $"Sold {item.Type} {item.Name} for {item.Price}! Current Balance: {updatedPlayer.Bank}" ]
 | 
				
			||||||
            |> Async.Parallel
 | 
					            |> Async.Parallel
 | 
				
			||||||
            |> Async.Ignore
 | 
					            |> Async.Ignore
 | 
				
			||||||
 | 
					 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -108,14 +108,14 @@ type Store() =
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [<SlashCommand("buy-hack", "Purchase a hack attack you can use to earn GoodBoyTokenz")>]
 | 
					    [<SlashCommand("buy-hack", "Purchase a hack attack you can use to earn GoodBoyTokenz")>]
 | 
				
			||||||
    member _.BuyHack (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (buy ItemType.Hack)
 | 
					    member _.BuyHack (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (buy Armory.getHackItems)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [<SlashCommand("buy-shield", "Purchase a hack shield so you can protect your GoodBoyTokenz")>]
 | 
					    [<SlashCommand("buy-shield", "Purchase a hack shield so you can protect your GoodBoyTokenz")>]
 | 
				
			||||||
    member this.BuyShield (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (buy ItemType.Shield)
 | 
					    member this.BuyShield (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (buy Armory.getShieldItems)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [<SlashCommand("sell-hack", "Sell a hack for GoodBoyTokenz")>]
 | 
					    [<SlashCommand("sell-hack", "Sell a hack for GoodBoyTokenz")>]
 | 
				
			||||||
    member this.SellHack (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (sell ItemType.Hack)
 | 
					    member this.SellHack (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (sell "Hacks" Player.getHackItems)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [<SlashCommand("sell-shield", "Sell a shield for GoodBoyTokenz")>]
 | 
					    [<SlashCommand("sell-shield", "Sell a shield for GoodBoyTokenz")>]
 | 
				
			||||||
    member this.SellShield (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (sell ItemType.Shield)
 | 
					    member this.SellShield (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (sell "Shields" Player.getShieldItems)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -128,7 +128,9 @@ let steal target amount (ctx : IDiscordContext) =
 | 
				
			|||||||
        >>= checkPrizeRequestZero amount
 | 
					        >>= checkPrizeRequestZero amount
 | 
				
			||||||
        |> handleResultWithResponse ctx (fun _ -> async {
 | 
					        |> handleResultWithResponse ctx (fun _ -> async {
 | 
				
			||||||
            let cappedPrize , winPercentage , wasCapped =
 | 
					            let cappedPrize , winPercentage , wasCapped =
 | 
				
			||||||
                calculateWinPercentage amount (int victim.Bank) thief.Traits.Strength victim.Traits.Strength
 | 
					//                calculateWinPercentage amount (int victim.Bank) thief.Stats.Strength victim.Stats.Strength
 | 
				
			||||||
 | 
					                // TODO: Readd stats
 | 
				
			||||||
 | 
					                calculateWinPercentage amount (int victim.Bank) 0 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let chance = int (winPercentage * 100.0)
 | 
					            let chance = int (winPercentage * 100.0)
 | 
				
			||||||
            let buttons =
 | 
					            let buttons =
 | 
				
			||||||
@ -138,7 +140,8 @@ let steal target amount (ctx : IDiscordContext) =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            let cappedMsg = if wasCapped then $"They only have {cappedPrize} $GBT though... " else ""
 | 
					            let cappedMsg = if wasCapped then $"They only have {cappedPrize} $GBT though... " else ""
 | 
				
			||||||
            let strengthMsg =
 | 
					            let strengthMsg =
 | 
				
			||||||
                match thief.Traits.Strength - victim.Traits.Strength with
 | 
					                // TODO: Readd stats
 | 
				
			||||||
 | 
					                match 0 - 0 with
 | 
				
			||||||
                | diff when diff < -50 -> "much stronger"
 | 
					                | diff when diff < -50 -> "much stronger"
 | 
				
			||||||
                | diff when diff < 0   -> "stronger"
 | 
					                | diff when diff < 0   -> "stronger"
 | 
				
			||||||
                | diff when diff < 50  -> "weaker"
 | 
					                | diff when diff < 50  -> "weaker"
 | 
				
			||||||
@ -161,7 +164,8 @@ let handleSteal (ctx : IDiscordContext) =
 | 
				
			|||||||
        let targetId = uint64 tokens.[2]
 | 
					        let targetId = uint64 tokens.[2]
 | 
				
			||||||
        let targetName = tokens.[3]
 | 
					        let targetName = tokens.[3]
 | 
				
			||||||
        let amount = int tokens.[4]
 | 
					        let amount = int tokens.[4]
 | 
				
			||||||
        let prize , winPercentage , _ = calculateWinPercentage amount (int victim.Bank) thief.Traits.Strength victim.Traits.Strength
 | 
					        // TODO: Readd stats
 | 
				
			||||||
 | 
					        let prize , winPercentage , _ = calculateWinPercentage amount (int victim.Bank) 0 0
 | 
				
			||||||
        let prize = int prize * 1<GBT>
 | 
					        let prize = int prize * 1<GBT>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let rand = Random(Guid.NewGuid().GetHashCode())
 | 
					        let rand = Random(Guid.NewGuid().GetHashCode())
 | 
				
			||||||
 | 
				
			|||||||
@ -9,8 +9,8 @@ open Degenz.Messaging
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
let trainerAchievement = "FINISHED_TRAINER"
 | 
					let trainerAchievement = "FINISHED_TRAINER"
 | 
				
			||||||
let Sensei = { Id = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" }
 | 
					let Sensei = { Id = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" }
 | 
				
			||||||
let defaultHack = Armory.battleItems |> Array.find (fun i -> i.Id = int HackId.Virus)
 | 
					let defaultHackItem, hackPower, hackClass, hackCooldown as defaultHack = Armory.getHackById (int ItemId.Virus)
 | 
				
			||||||
let defaultShield = Armory.battleItems |> Array.find (fun i -> i.Id = int ShieldId.Firewall)
 | 
					let defaultShieldItem, shieldClass, shieldCooldown as defaultShield = Armory.getShieldById (int ItemId.Firewall)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let TrainerEvents = [|
 | 
					let TrainerEvents = [|
 | 
				
			||||||
  { Timestamp = System.DateTime.UtcNow
 | 
					  { Timestamp = System.DateTime.UtcNow
 | 
				
			||||||
@ -19,10 +19,10 @@ let TrainerEvents = [|
 | 
				
			|||||||
        Adversary = Sensei
 | 
					        Adversary = Sensei
 | 
				
			||||||
        Success = true
 | 
					        Success = true
 | 
				
			||||||
        IsInstigator = true
 | 
					        IsInstigator = true
 | 
				
			||||||
        HackId = defaultHack.Id } }
 | 
					        HackId = defaultHackItem.Id } }
 | 
				
			||||||
  { Timestamp = System.DateTime.UtcNow
 | 
					  { Timestamp = System.DateTime.UtcNow
 | 
				
			||||||
    Cooldown = defaultShield.Cooldown
 | 
					    Cooldown =  shieldCooldown
 | 
				
			||||||
    Type = Shielding defaultShield.Id }
 | 
					    Type = Shielding defaultShieldItem.Id }
 | 
				
			||||||
|]
 | 
					|]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let sendInitialEmbed (client : DiscordClient)  =
 | 
					let sendInitialEmbed (client : DiscordClient)  =
 | 
				
			||||||
@ -52,7 +52,7 @@ let handleTrainerStep1 (ctx : IDiscordContext) =
 | 
				
			|||||||
            |> Async.AwaitTask
 | 
					            |> Async.AwaitTask
 | 
				
			||||||
        let msg = "Beautopia© is a dangerous place... quick, put up a SHIELD 🛡 before another Degen hacks you, and takes your 💰$GBT.\n\n"
 | 
					        let msg = "Beautopia© is a dangerous place... quick, put up a SHIELD 🛡 before another Degen hacks you, and takes your 💰$GBT.\n\n"
 | 
				
			||||||
                + "To enable it, you need to run the `/shield` slash command.\n\n"
 | 
					                + "To enable it, you need to run the `/shield` slash command.\n\n"
 | 
				
			||||||
                + $"Type the `/shield` command now, then select - `{defaultShield.Name}`\n"
 | 
					                + $"Type the `/shield` command now, then select - `{defaultShieldItem.Name}`\n"
 | 
				
			||||||
        let builder =
 | 
					        let builder =
 | 
				
			||||||
            DiscordInteractionResponseBuilder()
 | 
					            DiscordInteractionResponseBuilder()
 | 
				
			||||||
               .WithContent(msg)
 | 
					               .WithContent(msg)
 | 
				
			||||||
@ -66,7 +66,7 @@ let defend (ctx : IDiscordContext) =
 | 
				
			|||||||
        do! Messaging.defer ctx
 | 
					        do! Messaging.defer ctx
 | 
				
			||||||
        let m = ctx.GetDiscordMember()
 | 
					        let m = ctx.GetDiscordMember()
 | 
				
			||||||
        let name = if System.String.IsNullOrEmpty m.Nickname then m.DisplayName else m.Nickname
 | 
					        let name = if System.String.IsNullOrEmpty m.Nickname then m.DisplayName else m.Nickname
 | 
				
			||||||
        let embed = Embeds.pickDefense "Trainer-2" { PlayerData.empty with Inventory = [| defaultShield |] ; Name = name } true
 | 
					        let embed = Embeds.pickDefense "Trainer-2" { PlayerData.empty with Inventory = [ defaultShieldItem ] ; Name = name } true
 | 
				
			||||||
        do! ctx.FollowUp(embed) |> Async.AwaitTask
 | 
					        do! ctx.FollowUp(embed) |> Async.AwaitTask
 | 
				
			||||||
    } |> Async.StartAsTask :> Task
 | 
					    } |> Async.StartAsTask :> Task
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -83,17 +83,16 @@ let handleDefense (ctx : IDiscordContext) =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        let sendMessage' = sendFollowUpMessage ctx
 | 
					        let sendMessage' = sendFollowUpMessage ctx
 | 
				
			||||||
        let tokens = ctx.GetInteractionId().Split("-")
 | 
					        let tokens = ctx.GetInteractionId().Split("-")
 | 
				
			||||||
        let shieldId = enum<ShieldId>(int tokens.[2])
 | 
					        let shieldId = enum<ItemId>(int tokens.[2])
 | 
				
			||||||
        let shield = Armory.getItem (int shieldId)
 | 
					 | 
				
			||||||
        let playerName = tokens.[4]
 | 
					        let playerName = tokens.[4]
 | 
				
			||||||
        let embed = Embeds.responseCreatedShield shield
 | 
					        let embed = Embeds.responseCreatedShield defaultShield
 | 
				
			||||||
        do! ctx.FollowUp embed |> Async.AwaitTask
 | 
					        do! ctx.FollowUp embed |> Async.AwaitTask
 | 
				
			||||||
        do! Async.Sleep 4000
 | 
					        do! Async.Sleep 4000
 | 
				
			||||||
        do! sendMessage' $"Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now with **{defaultHack.Name}**"
 | 
					        do! sendMessage' $"Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now with **{defaultHackItem.Name}**"
 | 
				
			||||||
        do! Async.Sleep 5000
 | 
					        do! Async.Sleep 5000
 | 
				
			||||||
        do! sendMessage' $"❌ HACKING FAILED!\n\n{playerName} defended hack from <@{Sensei.Id}>!"
 | 
					        do! sendMessage' $"❌ HACKING FAILED!\n\n{playerName} defended hack from <@{Sensei.Id}>!"
 | 
				
			||||||
        do! Async.Sleep 4000
 | 
					        do! Async.Sleep 4000
 | 
				
			||||||
        do! sendFollowUpMessageWithButton ctx (handleDefenseMsg defaultHack.Name)
 | 
					        do! sendFollowUpMessageWithButton ctx (handleDefenseMsg defaultHackItem.Name)
 | 
				
			||||||
    } |> Async.StartAsTask :> Task
 | 
					    } |> Async.StartAsTask :> Task
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let handleTrainerStep3 (ctx : IDiscordContext) =
 | 
					let handleTrainerStep3 (ctx : IDiscordContext) =
 | 
				
			||||||
@ -104,7 +103,7 @@ let handleTrainerStep3 (ctx : IDiscordContext) =
 | 
				
			|||||||
             .WithContent
 | 
					             .WithContent
 | 
				
			||||||
                 ( "Now let’s **HACK** 💻... I want you to **HACK ME**!\n\n"
 | 
					                 ( "Now let’s **HACK** 💻... I want you to **HACK ME**!\n\n"
 | 
				
			||||||
                 + "To **hack**, you need to run the `/hack` slash command.\n"
 | 
					                 + "To **hack**, you need to run the `/hack` slash command.\n"
 | 
				
			||||||
                 + $"Type the `/hack` command now, then choose me - <@{Sensei.Id}> as your target, and select `{defaultHack.Name}`")
 | 
					                 + $"Type the `/hack` command now, then choose me - <@{Sensei.Id}> as your target, and select `{defaultHackItem.Name}`")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, builder) |> Async.AwaitTask
 | 
					        do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, builder) |> Async.AwaitTask
 | 
				
			||||||
    } |> Async.StartAsTask :> Task
 | 
					    } |> Async.StartAsTask :> Task
 | 
				
			||||||
@ -117,7 +116,7 @@ let hack (target : DiscordUser) (ctx : IDiscordContext) =
 | 
				
			|||||||
        match isRightTarget with
 | 
					        match isRightTarget with
 | 
				
			||||||
        | true ->
 | 
					        | true ->
 | 
				
			||||||
            let bot = { PlayerData.empty with DiscordId = Sensei.Id ; Name = Sensei.Name }
 | 
					            let bot = { PlayerData.empty with DiscordId = Sensei.Id ; Name = Sensei.Name }
 | 
				
			||||||
            let embed = Embeds.pickHack "Trainer-4" { PlayerData.empty with Inventory = [| defaultHack |] } bot true
 | 
					            let embed = Embeds.pickHack "Trainer-4" { PlayerData.empty with Inventory = [ defaultHackItem ] } bot true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            do! ctx.FollowUp(embed) |> Async.AwaitTask
 | 
					            do! ctx.FollowUp(embed) |> Async.AwaitTask
 | 
				
			||||||
        | false ->
 | 
					        | false ->
 | 
				
			||||||
@ -133,7 +132,7 @@ let handleHack (ctx : IDiscordContext) =
 | 
				
			|||||||
    PlayerInteractions.executePlayerAction ctx (fun player -> async {
 | 
					    PlayerInteractions.executePlayerAction ctx (fun player -> async {
 | 
				
			||||||
        let sendMessage' = sendFollowUpMessage ctx
 | 
					        let sendMessage' = sendFollowUpMessage ctx
 | 
				
			||||||
        do! Async.Sleep 1000
 | 
					        do! Async.Sleep 1000
 | 
				
			||||||
        let embed = Embeds.responseSuccessfulHack false Sensei.Id defaultHack.Power defaultHack
 | 
					        let embed = Embeds.responseSuccessfulHack false Sensei.Id hackPower defaultHackItem
 | 
				
			||||||
        do! ctx.FollowUp(embed) |> Async.AwaitTask
 | 
					        do! ctx.FollowUp(embed) |> Async.AwaitTask
 | 
				
			||||||
        do! Async.Sleep 4000
 | 
					        do! Async.Sleep 4000
 | 
				
			||||||
        do! sendMessage'
 | 
					        do! sendMessage'
 | 
				
			||||||
@ -151,7 +150,7 @@ let handleHack (ctx : IDiscordContext) =
 | 
				
			|||||||
            do! DbService.addAchievement GuildEnvironment.pgDb player.DiscordId trainerAchievement
 | 
					            do! DbService.addAchievement GuildEnvironment.pgDb player.DiscordId trainerAchievement
 | 
				
			||||||
                |> Async.Ignore
 | 
					                |> Async.Ignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            sb.Append($"I'm going to gift you a hack,`{defaultHack.Name}` and a shield, `{defaultShield.Name}`") |> ignore
 | 
					            sb.Append($"I'm going to gift you a hack,`{defaultHackItem.Name}` and a shield, `{defaultShieldItem.Name}`") |> ignore
 | 
				
			||||||
            sb.Append(", you'll need em to survive\n\n") |> ignore
 | 
					            sb.Append(", you'll need em to survive\n\n") |> ignore
 | 
				
			||||||
            sb.AppendLine("To finish your training and collect the loot, type the `/arsenal` command **NOW**") |> ignore
 | 
					            sb.AppendLine("To finish your training and collect the loot, type the `/arsenal` command **NOW**") |> ignore
 | 
				
			||||||
            do! Async.Sleep 1000
 | 
					            do! Async.Sleep 1000
 | 
				
			||||||
@ -166,12 +165,12 @@ let handleHack (ctx : IDiscordContext) =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
let handleArsenal (ctx : IDiscordContext) =
 | 
					let handleArsenal (ctx : IDiscordContext) =
 | 
				
			||||||
    PlayerInteractions.executePlayerAction ctx (fun player -> async {
 | 
					    PlayerInteractions.executePlayerAction ctx (fun player -> async {
 | 
				
			||||||
        let hasStockWeapons = Player.getHacks player |> Array.exists (fun item -> item.Id = defaultHack.Id)
 | 
					        let hasStockWeapons = Player.getHackItems player |> List.exists (fun item -> item.Id = defaultHackItem.Id)
 | 
				
			||||||
        let updatedPlayer =
 | 
					        let updatedPlayer =
 | 
				
			||||||
            if not hasStockWeapons then {
 | 
					            if not hasStockWeapons then {
 | 
				
			||||||
                Player.removeExpiredActions player with
 | 
					                Player.removeExpiredActions player with
 | 
				
			||||||
                    Events = TrainerEvents |> Array.append player.Events
 | 
					                    Events = TrainerEvents |> Array.append player.Events
 | 
				
			||||||
                    Inventory = [| defaultHack ; defaultShield |] |> Array.append player.Inventory
 | 
					                    Inventory = defaultHackItem::defaultShieldItem::player.Inventory
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
                Player.removeExpiredActions player
 | 
					                Player.removeExpiredActions player
 | 
				
			||||||
@ -188,7 +187,7 @@ let handleArsenal (ctx : IDiscordContext) =
 | 
				
			|||||||
        let! completed = DbService.checkHasAchievement GuildEnvironment.pgDb player.DiscordId trainerAchievement
 | 
					        let! completed = DbService.checkHasAchievement GuildEnvironment.pgDb player.DiscordId trainerAchievement
 | 
				
			||||||
        if not completed then
 | 
					        if not completed then
 | 
				
			||||||
            do! Async.Sleep 3000
 | 
					            do! Async.Sleep 3000
 | 
				
			||||||
            let rewards = [ $"{defaultHack.Name} Hack" ; $"{defaultShield.Name} Shield" ]
 | 
					            let rewards = [ $"{defaultHackItem.Name} Hack" ; $"{defaultShieldItem.Name} Shield" ]
 | 
				
			||||||
            let embed = Embeds.getAchievementEmbed rewards "You completed the Training Dojo and collected loot." trainerAchievement
 | 
					            let embed = Embeds.getAchievementEmbed rewards "You completed the Training Dojo and collected loot." trainerAchievement
 | 
				
			||||||
            do! ctx.FollowUp(embed) |> Async.AwaitTask
 | 
					            do! ctx.FollowUp(embed) |> Async.AwaitTask
 | 
				
			||||||
        do! Async.Sleep 2000
 | 
					        do! Async.Sleep 2000
 | 
				
			||||||
 | 
				
			|||||||
@ -2,91 +2,76 @@
 | 
				
			|||||||
  {
 | 
					  {
 | 
				
			||||||
    "Id": 0,
 | 
					    "Id": 0,
 | 
				
			||||||
    "Name": "Virus",
 | 
					    "Name": "Virus",
 | 
				
			||||||
    "Type": 0,
 | 
					 | 
				
			||||||
    "Price": 0,
 | 
					    "Price": 0,
 | 
				
			||||||
    "Power": 25,
 | 
					    "Type": {
 | 
				
			||||||
    "Cooldown": 1,
 | 
					      "Case": "Hack",
 | 
				
			||||||
    "Class": 0,
 | 
					      "Fields": [
 | 
				
			||||||
    "Attributes": {
 | 
					        25,
 | 
				
			||||||
      "Sell": false,
 | 
					        0,
 | 
				
			||||||
      "Buy": false,
 | 
					        1
 | 
				
			||||||
      "Consume": false,
 | 
					      ]
 | 
				
			||||||
      "Drop": false
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    "Id": 1,
 | 
					    "Id": 1,
 | 
				
			||||||
    "Name": "RemoteAccess",
 | 
					    "Name": "RemoteAccess",
 | 
				
			||||||
    "Type": 0,
 | 
					 | 
				
			||||||
    "Price": 500,
 | 
					    "Price": 500,
 | 
				
			||||||
    "Power": 75,
 | 
					    "Type": {
 | 
				
			||||||
    "Cooldown": 3,
 | 
					      "Case": "Hack",
 | 
				
			||||||
    "Class": 1,
 | 
					      "Fields": [
 | 
				
			||||||
    "Attributes": {
 | 
					        75,
 | 
				
			||||||
      "Sell": true,
 | 
					        1,
 | 
				
			||||||
      "Buy": true,
 | 
					        3
 | 
				
			||||||
      "Consume": false,
 | 
					      ]
 | 
				
			||||||
      "Drop": true
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    "Id": 2,
 | 
					    "Id": 2,
 | 
				
			||||||
    "Name": "Worm",
 | 
					    "Name": "Worm",
 | 
				
			||||||
    "Type": 0,
 | 
					 | 
				
			||||||
    "Price": 5000,
 | 
					    "Price": 5000,
 | 
				
			||||||
    "Power": 150,
 | 
					    "Type": {
 | 
				
			||||||
    "Cooldown": 5,
 | 
					      "Case": "Hack",
 | 
				
			||||||
    "Class": 2,
 | 
					      "Fields": [
 | 
				
			||||||
    "Attributes": {
 | 
					        150,
 | 
				
			||||||
      "Sell": true,
 | 
					        2,
 | 
				
			||||||
      "Buy": true,
 | 
					        5
 | 
				
			||||||
      "Consume": false,
 | 
					      ]
 | 
				
			||||||
      "Drop": true
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    "Id": 6,
 | 
					    "Id": 6,
 | 
				
			||||||
    "Name": "Firewall",
 | 
					    "Name": "Firewall",
 | 
				
			||||||
    "Type": 1,
 | 
					 | 
				
			||||||
    "Price": 0,
 | 
					    "Price": 0,
 | 
				
			||||||
    "Power": 10,
 | 
					    "Type": {
 | 
				
			||||||
    "Class": 0,
 | 
					      "Case": "Shield",
 | 
				
			||||||
    "Cooldown": 120,
 | 
					      "Fields": [
 | 
				
			||||||
    "Attributes": {
 | 
					        0,
 | 
				
			||||||
      "Sell": false,
 | 
					        120
 | 
				
			||||||
      "Buy": false,
 | 
					      ]
 | 
				
			||||||
      "Consume": false,
 | 
					 | 
				
			||||||
      "Drop": false
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    "Id": 7,
 | 
					    "Id": 7,
 | 
				
			||||||
    "Name": "Encryption",
 | 
					    "Name": "Encryption",
 | 
				
			||||||
    "Type": 1,
 | 
					 | 
				
			||||||
    "Price": 500,
 | 
					    "Price": 500,
 | 
				
			||||||
    "Power": 50,
 | 
					    "Type": {
 | 
				
			||||||
    "Class": 1,
 | 
					      "Case": "Shield",
 | 
				
			||||||
    "Cooldown": 240,
 | 
					      "Fields": [
 | 
				
			||||||
    "Attributes": {
 | 
					        1,
 | 
				
			||||||
      "Sell": true,
 | 
					        240
 | 
				
			||||||
      "Buy": true,
 | 
					      ]
 | 
				
			||||||
      "Consume": false,
 | 
					 | 
				
			||||||
      "Drop": true
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    "Id": 8,
 | 
					    "Id": 8,
 | 
				
			||||||
    "Name": "Cypher",
 | 
					    "Name": "Cypher",
 | 
				
			||||||
    "Type": 1,
 | 
					 | 
				
			||||||
    "Price": 5000,
 | 
					    "Price": 5000,
 | 
				
			||||||
    "Power": 80,
 | 
					    "Type": {
 | 
				
			||||||
    "Class": 2,
 | 
					      "Case": "Shield",
 | 
				
			||||||
    "Cooldown": 380,
 | 
					      "Fields": [
 | 
				
			||||||
    "Attributes": {
 | 
					        2,
 | 
				
			||||||
      "Sell": true,
 | 
					        380
 | 
				
			||||||
      "Buy": true,
 | 
					      ]
 | 
				
			||||||
      "Consume": false,
 | 
					 | 
				
			||||||
      "Drop": true
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,6 @@ module Degenz.PlayerInteractions
 | 
				
			|||||||
open System.Threading.Tasks
 | 
					open System.Threading.Tasks
 | 
				
			||||||
open DSharpPlus
 | 
					open DSharpPlus
 | 
				
			||||||
open DSharpPlus.Entities
 | 
					open DSharpPlus.Entities
 | 
				
			||||||
open DSharpPlus.SlashCommands
 | 
					 | 
				
			||||||
open Degenz.Messaging
 | 
					open Degenz.Messaging
 | 
				
			||||||
open Degenz.DbService
 | 
					open Degenz.DbService
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -57,52 +56,3 @@ let handleResultWithResponse ctx fn (player : Result<PlayerData, string>) =
 | 
				
			|||||||
   match player with
 | 
					   match player with
 | 
				
			||||||
   | Ok p -> fn p
 | 
					   | Ok p -> fn p
 | 
				
			||||||
   | Error e -> async { do! Messaging.sendFollowUpMessage ctx e }
 | 
					   | Error e -> async { do! Messaging.sendFollowUpMessage ctx e }
 | 
				
			||||||
 | 
					 | 
				
			||||||
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 = Armory.battleItems |> Array.find (fun i -> i.Id = randHack)
 | 
					 | 
				
			||||||
        let shield = Armory.battleItems |> Array.find (fun i -> i.Id = randShield)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        { DiscordId = membr
 | 
					 | 
				
			||||||
          Name = nickname
 | 
					 | 
				
			||||||
          Inventory = [| hack ; shield |]
 | 
					 | 
				
			||||||
          Events  = [||]
 | 
					 | 
				
			||||||
//          XP = 0
 | 
					 | 
				
			||||||
//          Achievements = [||]
 | 
					 | 
				
			||||||
          Traits = PlayerTraits.empty
 | 
					 | 
				
			||||||
          Bank = 100<GBT> }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let upsertPlayer discordId =
 | 
					 | 
				
			||||||
        async {
 | 
					 | 
				
			||||||
            let! player = DbService.tryFindPlayer GuildEnvironment.pgDb discordId
 | 
					 | 
				
			||||||
            let! newPlayer =
 | 
					 | 
				
			||||||
                match player with
 | 
					 | 
				
			||||||
                | Some _ -> async.Return false
 | 
					 | 
				
			||||||
                | None ->
 | 
					 | 
				
			||||||
                    async {
 | 
					 | 
				
			||||||
//                        do! newPlayer "" discordId |> DbService.insertNewPlayer
 | 
					 | 
				
			||||||
                        return true
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
            return newPlayer
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    [<CLIMutable>]
 | 
					 | 
				
			||||||
    type LeaderboardEntry = {
 | 
					 | 
				
			||||||
        Position : string
 | 
					 | 
				
			||||||
        Amount : string
 | 
					 | 
				
			||||||
        Name : string
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type PlayerInteractions() =
 | 
					 | 
				
			||||||
    inherit ApplicationCommandModule ()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    [<SlashCommand("redpill", "Take the redpill and become a hacker")>]
 | 
					 | 
				
			||||||
    member _.AddHackerRole (ctx : InteractionContext) = Commands.upsertPlayer ctx.Member.Id
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//    [<SlashCommand("leaderboard", "View the current list of players ranked by highest earnings")>]
 | 
					 | 
				
			||||||
//    member this.Leaderboard (ctx : InteractionContext) = Commands.leaderboard ctx
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@ open DSharpPlus.Entities
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type RewardType =
 | 
					type RewardType =
 | 
				
			||||||
    | Currency of int<GBT>
 | 
					    | Currency of int<GBT>
 | 
				
			||||||
    | RandomItem of itemType : ItemType * amount : int
 | 
					//    | RandomItem of itemType : ItemType * amount : int
 | 
				
			||||||
    | SpecialItem of id : int
 | 
					    | SpecialItem of id : int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[<Literal>]
 | 
					[<Literal>]
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +0,0 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="utf-8"?>
 | 
					 | 
				
			||||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
					 | 
				
			||||||
  <PropertyGroup>
 | 
					 | 
				
			||||||
    <TargetFramework>net6.0</TargetFramework>
 | 
					 | 
				
			||||||
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
 | 
					 | 
				
			||||||
  </PropertyGroup>
 | 
					 | 
				
			||||||
  <ItemGroup>
 | 
					 | 
				
			||||||
    <ProjectReference Include="..\Shared\Shared.fsproj" />
 | 
					 | 
				
			||||||
  </ItemGroup>
 | 
					 | 
				
			||||||
  <Import Project="..\.paket\Paket.Restore.targets" />
 | 
					 | 
				
			||||||
</Project>
 | 
					 | 
				
			||||||
@ -1,8 +0,0 @@
 | 
				
			|||||||
FSharp.Core
 | 
					 | 
				
			||||||
DSharpPlus
 | 
					 | 
				
			||||||
// DSharpPlus.CommandsNext
 | 
					 | 
				
			||||||
// DSharpPlus.Interactivity
 | 
					 | 
				
			||||||
DSharpPlus.SlashCommands
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
MongoDB.Driver
 | 
					 | 
				
			||||||
Npgsql.FSharp
 | 
					 | 
				
			||||||
@ -1,9 +0,0 @@
 | 
				
			|||||||
namespace Degenz
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
open System
 | 
					 | 
				
			||||||
open System.Threading.Tasks
 | 
					 | 
				
			||||||
open DSharpPlus
 | 
					 | 
				
			||||||
open DSharpPlus.Entities
 | 
					 | 
				
			||||||
open DSharpPlus.EventArgs
 | 
					 | 
				
			||||||
open DSharpPlus.SlashCommands
 | 
					 | 
				
			||||||
open Newtonsoft.Json
 | 
					 | 
				
			||||||
@ -1,12 +0,0 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="utf-8"?>
 | 
					 | 
				
			||||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
					 | 
				
			||||||
  <PropertyGroup>
 | 
					 | 
				
			||||||
    <TargetFramework>net6.0</TargetFramework>
 | 
					 | 
				
			||||||
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
 | 
					 | 
				
			||||||
  </PropertyGroup>
 | 
					 | 
				
			||||||
  <ItemGroup>
 | 
					 | 
				
			||||||
    <Content Include="paket.references" />
 | 
					 | 
				
			||||||
    <Compile Include="Shared.fs" />
 | 
					 | 
				
			||||||
  </ItemGroup>
 | 
					 | 
				
			||||||
  <Import Project="..\.paket\Paket.Restore.targets" />
 | 
					 | 
				
			||||||
</Project>
 | 
					 | 
				
			||||||
@ -1,3 +0,0 @@
 | 
				
			|||||||
FSharp.Core
 | 
					 | 
				
			||||||
DSharpPlus
 | 
					 | 
				
			||||||
DSharpPlus.SlashCommands
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user