Introduce denormalized records + mapping functions
This commit is contained in:
		
							parent
							
								
									a0267b4cbb
								
							
						
					
					
						commit
						9867d06512
					
				@ -48,7 +48,7 @@ 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 shieldItems = player |> Player.getShieldItems
 | 
					    let shieldItems = player.Inventory |> Inventory.filterByShields
 | 
				
			||||||
    let buttons = constructButtons actionId (string player.DiscordId) player shieldItems isTrainer
 | 
					    let buttons = constructButtons actionId (string player.DiscordId) player shieldItems isTrainer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let embed =
 | 
					    let embed =
 | 
				
			||||||
@ -56,10 +56,10 @@ let pickDefense actionId player isTrainer =
 | 
				
			|||||||
            .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 (item,sClass,cooldown) in Player.getShields player do
 | 
					    for shield in Inventory.getShieldItems player.Inventory do
 | 
				
			||||||
        let hours = TimeSpan.FromMinutes(int cooldown).TotalHours
 | 
					        let hours = TimeSpan.FromMinutes(int shield.Cooldown).TotalHours
 | 
				
			||||||
        let against = WeaponClass.getGoodAgainst(sClass) |> snd
 | 
					        let against = WeaponClass.getGoodAgainst(shield.Class) |> snd
 | 
				
			||||||
        embed.AddField(item.Name, $"Active {hours} hours\nDefeats {against}", true) |> ignore
 | 
					        embed.AddField(shield.Name, $"Active {hours} hours\nDefeats {against}", true) |> ignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DiscordFollowupMessageBuilder()
 | 
					    DiscordFollowupMessageBuilder()
 | 
				
			||||||
        .AddComponents(buttons)
 | 
					        .AddComponents(buttons)
 | 
				
			||||||
@ -67,7 +67,7 @@ let pickDefense actionId player isTrainer =
 | 
				
			|||||||
        .AsEphemeral(true)
 | 
					        .AsEphemeral(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let pickHack actionId attacker defender isTrainer =
 | 
					let pickHack actionId attacker defender isTrainer =
 | 
				
			||||||
    let hackItems = attacker |> Player.getHackItems
 | 
					    let hackItems = attacker.Inventory |> Inventory.filterByHacks
 | 
				
			||||||
    let buttons = constructButtons actionId $"{defender.DiscordId}-{defender.Name}" attacker hackItems isTrainer
 | 
					    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 ""
 | 
				
			||||||
@ -77,16 +77,16 @@ 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 (item,power,hClass,cooldown) in Player.getHacks attacker do
 | 
					        for hack in Inventory.getHackItems attacker.Inventory do
 | 
				
			||||||
            let amount = if power > int defender.Bank then int defender.Bank else power
 | 
					            let amount = if hack.Power > int defender.Bank then int defender.Bank else hack.Power
 | 
				
			||||||
            embed.AddField(item.Name, $"Cooldown {cooldown} mins\nExtract {amount} $GBT", true) |> ignore
 | 
					            embed.AddField(hack.Name, $"Cooldown {hack.Cooldown} mins\nExtract {amount} $GBT", true) |> ignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DiscordFollowupMessageBuilder()
 | 
					    DiscordFollowupMessageBuilder()
 | 
				
			||||||
        .AddComponents(buttons)
 | 
					        .AddComponents(buttons)
 | 
				
			||||||
        .AddEmbeds([ DiscordEmbedBuilder().WithImageUrl(hackGif).Build() ; embed.Build() ])
 | 
					        .AddEmbeds([ DiscordEmbedBuilder().WithImageUrl(hackGif).Build() ; embed.Build() ])
 | 
				
			||||||
        .AsEphemeral true
 | 
					        .AsEphemeral true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let responseSuccessfulHack earnedMoney (targetId : uint64) amountTaken (hack : Item) =
 | 
					let responseSuccessfulHack earnedMoney (targetId : uint64) amountTaken (hack : HackItem) =
 | 
				
			||||||
    let embed =
 | 
					    let embed =
 | 
				
			||||||
        DiscordEmbedBuilder()
 | 
					        DiscordEmbedBuilder()
 | 
				
			||||||
          .WithImageUrl(getItemGif hack.Id)
 | 
					          .WithImageUrl(getItemGif hack.Id)
 | 
				
			||||||
@ -98,10 +98,10 @@ let responseSuccessfulHack earnedMoney (targetId : uint64) amountTaken (hack : I
 | 
				
			|||||||
        .AddEmbed(embed.Build())
 | 
					        .AddEmbed(embed.Build())
 | 
				
			||||||
        .AsEphemeral(true)
 | 
					        .AsEphemeral(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let responseCreatedShield ((item,_,cooldown) : ShieldItem) =
 | 
					let responseCreatedShield (shield : ShieldItem) =
 | 
				
			||||||
    let embed = DiscordEmbedBuilder().WithImageUrl(getItemGif item.Id)
 | 
					    let embed = DiscordEmbedBuilder().WithImageUrl(getItemGif shield.Id)
 | 
				
			||||||
    embed.Title <- "Mounted Shield"
 | 
					    embed.Title <- "Mounted Shield"
 | 
				
			||||||
    embed.Description <- $"Mounted {item.Name} shield for {TimeSpan.FromMinutes(int cooldown).Hours} hours"
 | 
					    embed.Description <- $"Mounted {shield.Name} shield for {TimeSpan.FromMinutes(int shield.Cooldown).Hours} hours"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DiscordFollowupMessageBuilder()
 | 
					    DiscordFollowupMessageBuilder()
 | 
				
			||||||
        .AddEmbed(embed)
 | 
					        .AddEmbed(embed)
 | 
				
			||||||
@ -111,58 +111,6 @@ 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 (playerInventory : Inventory) (storeInventory : Inventory) =
 | 
					 | 
				
			||||||
    let embeds , buttons =
 | 
					 | 
				
			||||||
        storeInventory
 | 
					 | 
				
			||||||
        |> List.map (fun item ->
 | 
					 | 
				
			||||||
            let embed = DiscordEmbedBuilder()
 | 
					 | 
				
			||||||
            match item.Type with
 | 
					 | 
				
			||||||
            | Hack(power,_,cooldown) ->
 | 
					 | 
				
			||||||
                embed.AddField($"$GBT Reward  |", string power, true)
 | 
					 | 
				
			||||||
                     .AddField("Cooldown  |", $"{TimeSpan.FromMinutes(int cooldown).Minutes} minutes", true)
 | 
					 | 
				
			||||||
                     .WithThumbnail(getItemIcon item.Id)
 | 
					 | 
				
			||||||
                     |> ignore
 | 
					 | 
				
			||||||
            | Shield(shieldClass,cooldown) ->
 | 
					 | 
				
			||||||
                embed.AddField($"Strong against  |", WeaponClass.getGoodAgainst shieldClass |> snd |> string, true)
 | 
					 | 
				
			||||||
//                    .AddField($"Defensive Strength  |", string item.Power, true)
 | 
					 | 
				
			||||||
                     .AddField("Active For  |", $"{TimeSpan.FromMinutes(int cooldown).Hours} hours", true)
 | 
					 | 
				
			||||||
                     .WithThumbnail(getItemIcon item.Id)
 | 
					 | 
				
			||||||
                     |> ignore
 | 
					 | 
				
			||||||
            | _ -> ()
 | 
					 | 
				
			||||||
            embed
 | 
					 | 
				
			||||||
              .AddField("Price 💰", (if item.Price = 0<GBT> then "Free" else $"{item.Price} $GBT"), true)
 | 
					 | 
				
			||||||
              .WithColor(WeaponClass.getClassEmbedColor item)
 | 
					 | 
				
			||||||
              .WithTitle($"{item.Name}")
 | 
					 | 
				
			||||||
              |> ignore
 | 
					 | 
				
			||||||
            let button =
 | 
					 | 
				
			||||||
                if playerInventory |> List.exists (fun i -> i.Id = item.Id)
 | 
					 | 
				
			||||||
                    then DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Buy-{item.Id}", $"Own {item.Name}", true)
 | 
					 | 
				
			||||||
                    else DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Buy-{item.Id}", $"Buy {item.Name}")
 | 
					 | 
				
			||||||
            ( embed.Build() , button :> DiscordComponent ))
 | 
					 | 
				
			||||||
        |> List.unzip
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    DiscordFollowupMessageBuilder()
 | 
					 | 
				
			||||||
        .AddEmbeds(embeds)
 | 
					 | 
				
			||||||
        .AddComponents(buttons)
 | 
					 | 
				
			||||||
        .AsEphemeral(true)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let getSellEmbed (items : Item list) =
 | 
					 | 
				
			||||||
    let embeds , buttons =
 | 
					 | 
				
			||||||
        items
 | 
					 | 
				
			||||||
        |> List.map (fun item ->
 | 
					 | 
				
			||||||
            DiscordEmbedBuilder()
 | 
					 | 
				
			||||||
              .AddField("Sell For 💰", $"{item.Price} $GBT", true)
 | 
					 | 
				
			||||||
              .WithTitle($"{item.Name}")
 | 
					 | 
				
			||||||
              .WithColor(WeaponClass.getClassEmbedColor item)
 | 
					 | 
				
			||||||
              .Build()
 | 
					 | 
				
			||||||
            , DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Sell-{id}", $"Sell {item.Name}") :> DiscordComponent)
 | 
					 | 
				
			||||||
        |> List.unzip
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    DiscordFollowupMessageBuilder()
 | 
					 | 
				
			||||||
        .AddEmbeds(embeds)
 | 
					 | 
				
			||||||
        .AddComponents(buttons)
 | 
					 | 
				
			||||||
        .AsEphemeral(true)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let getArsenalEmbed (player : PlayerData) =
 | 
					let getArsenalEmbed (player : PlayerData) =
 | 
				
			||||||
    DiscordFollowupMessageBuilder()
 | 
					    DiscordFollowupMessageBuilder()
 | 
				
			||||||
        .AsEphemeral(true)
 | 
					        .AsEphemeral(true)
 | 
				
			||||||
 | 
				
			|||||||
@ -24,20 +24,60 @@ module Armory =
 | 
				
			|||||||
        inventory
 | 
					        inventory
 | 
				
			||||||
        |> List.filter (fun item -> match item.Type with Shield _ -> true | _ -> false)
 | 
					        |> List.filter (fun item -> match item.Type with Shield _ -> true | _ -> false)
 | 
				
			||||||
        |> List.sortBy (fun item -> item.Id)
 | 
					        |> List.sortBy (fun item -> item.Id)
 | 
				
			||||||
    let getHacks  : HackItem list =
 | 
					    let getHackById id inventory = inventory |> getHackItems |> List.find (fun item -> item.Id = id)
 | 
				
			||||||
        battleItems
 | 
					    let getShieldById id inventory = inventory |> getShieldItems |> List.find (fun item -> item.Id = id)
 | 
				
			||||||
        |> List.choose (fun item ->
 | 
					
 | 
				
			||||||
            match item.Type with
 | 
					module Inventory =
 | 
				
			||||||
            | Hack(power, hackClass, cooldown) -> Some (item , power, hackClass, cooldown) | _ -> None)
 | 
					    let itemToHack item power hackClass cooldown = {
 | 
				
			||||||
        |> List.sortBy (fun (item,_,_,_) -> item.Id)
 | 
					        Id = item.Id
 | 
				
			||||||
    let getShields : ShieldItem list =
 | 
					        Name = item.Name
 | 
				
			||||||
        battleItems
 | 
					        Price = item.Price
 | 
				
			||||||
        |> List.choose (fun item ->
 | 
					        Power = power
 | 
				
			||||||
            match item.Type with
 | 
					        Class = hackClass
 | 
				
			||||||
            | Shield(hackClass, cooldown) -> Some (item,hackClass,cooldown) | _ -> None)
 | 
					        Cooldown = cooldown
 | 
				
			||||||
        |> 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)
 | 
					    let itemToShield item hackClass cooldown = {
 | 
				
			||||||
 | 
					        Id = item.Id
 | 
				
			||||||
 | 
					        Name = item.Name
 | 
				
			||||||
 | 
					        Price = item.Price
 | 
				
			||||||
 | 
					        Class = hackClass
 | 
				
			||||||
 | 
					        Cooldown = cooldown
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let hackToItem (hack : HackItem) = {
 | 
				
			||||||
 | 
					        Id = hack.Id
 | 
				
			||||||
 | 
					        Name = hack.Name
 | 
				
			||||||
 | 
					        Price = hack.Price
 | 
				
			||||||
 | 
					        Type = Hack (hack.Power, hack.Class, hack.Cooldown)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let shieldToItem (shield : ShieldItem) = {
 | 
				
			||||||
 | 
					        Id = shield.Id
 | 
				
			||||||
 | 
					        Name = shield.Name
 | 
				
			||||||
 | 
					        Price = shield.Price
 | 
				
			||||||
 | 
					        Type = Shield (shield.Class, shield.Cooldown)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let filterByHacks inventory =
 | 
				
			||||||
 | 
					        inventory |> List.filter (fun item -> match item.Type with Hack _   -> true | _ -> false)
 | 
				
			||||||
 | 
					    let filterByShields inventory =
 | 
				
			||||||
 | 
					        inventory |> List.filter (fun item -> match item.Type with Shield _ -> true | _ -> false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let getHackItems inventory =
 | 
				
			||||||
 | 
					        inventory
 | 
				
			||||||
 | 
					        |> List.choose (fun item -> match item.Type with Hack (p,cl,co) -> Some (itemToHack item p cl co) | _ -> None)
 | 
				
			||||||
 | 
					        |> List.sortBy (fun item -> item.Id)
 | 
				
			||||||
 | 
					    let getShieldItems inventory =
 | 
				
			||||||
 | 
					        inventory
 | 
				
			||||||
 | 
					        |> List.choose (fun item -> match item.Type with Shield (cl,co) -> Some (itemToShield item cl co) | _ -> None)
 | 
				
			||||||
 | 
					        |> List.sortBy (fun item -> item.Id)
 | 
				
			||||||
 | 
					    let findHackById id inventory =
 | 
				
			||||||
 | 
					        inventory |> getHackItems |> List.pick (fun item -> if item.Id = id then Some item else None)
 | 
				
			||||||
 | 
					    let findShieldById id inventory =
 | 
				
			||||||
 | 
					        inventory |> getShieldItems |> List.pick (fun item -> if item.Id = id then Some item else None)
 | 
				
			||||||
 | 
					    let tryFindHackById id inventory =
 | 
				
			||||||
 | 
					        inventory |> getHackItems |> List.tryFind (fun item -> item.Id = id)
 | 
				
			||||||
 | 
					    let tryFindShieldById id inventory =
 | 
				
			||||||
 | 
					        inventory |> getShieldItems |> List.tryFind (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
 | 
				
			||||||
@ -63,26 +103,6 @@ module WeaponClass =
 | 
				
			|||||||
        | _     -> ( ItemId.Cypher     , ItemId.Worm         )
 | 
					        | _     -> ( ItemId.Cypher     , ItemId.Worm         )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module Player =
 | 
					module Player =
 | 
				
			||||||
    let getHackItems player =
 | 
					 | 
				
			||||||
        player.Inventory
 | 
					 | 
				
			||||||
        |> 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)
 | 
				
			||||||
@ -133,8 +153,27 @@ module Arsenal =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    let statusFormat p =
 | 
					    let statusFormat p =
 | 
				
			||||||
        let hacks = Player.getHackEvents p
 | 
					        let hacks = Player.getHackEvents p
 | 
				
			||||||
        $"**Hacks:** {Player.getHackItems p |> battleItemFormat}\n
 | 
					        $"**Hacks:** {Inventory.filterByHacks p.Inventory |> battleItemFormat}\n
 | 
				
			||||||
    **Shields:** {Player.getShieldItems p |> battleItemFormat}\n
 | 
					    **Shields:** {Inventory.filterByShields p.Inventory |> 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}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module Items =
 | 
				
			||||||
 | 
					    let mapHack fn inventory =
 | 
				
			||||||
 | 
					        inventory
 | 
				
			||||||
 | 
					        |> List.choose (fun item ->
 | 
				
			||||||
 | 
					            match item.Type with
 | 
				
			||||||
 | 
					            | Hack(power, hackClass, cooldown) -> Some <| fn item power hackClass cooldown
 | 
				
			||||||
 | 
					            | _ -> None)
 | 
				
			||||||
 | 
					    let mapShield fn inventory =
 | 
				
			||||||
 | 
					        inventory
 | 
				
			||||||
 | 
					        |> List.choose (fun item ->
 | 
				
			||||||
 | 
					            match item.Type with
 | 
				
			||||||
 | 
					            | Shield(hackClass, cooldown) -> Some <| fn item hackClass cooldown
 | 
				
			||||||
 | 
					            | _ -> None)
 | 
				
			||||||
 | 
					    let doShields fn inventory =
 | 
				
			||||||
 | 
					        inventory
 | 
				
			||||||
 | 
					        |> List.iter (fun item ->
 | 
				
			||||||
 | 
					            match item.Type with
 | 
				
			||||||
 | 
					            | Shield(hackClass, cooldown) -> fn item hackClass cooldown
 | 
				
			||||||
 | 
					            | _ -> ())
 | 
				
			||||||
 | 
				
			|||||||
@ -73,11 +73,24 @@ type PlayerEvent =
 | 
				
			|||||||
      Cooldown : int<mins>
 | 
					      Cooldown : int<mins>
 | 
				
			||||||
      Timestamp : DateTime }
 | 
					      Timestamp : DateTime }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type HackItem = Item * int * int * int<mins>
 | 
					type HackItem = {
 | 
				
			||||||
and  ShieldItem = Item * int * int<mins>
 | 
					    Id : int
 | 
				
			||||||
and  FoodItem = Item * (Item -> PlayerData -> PlayerData)
 | 
					    Name : string
 | 
				
			||||||
and  AccessoryItem = Item * (Item -> PlayerData -> PlayerData)
 | 
					    Price : int<GBT>
 | 
				
			||||||
and  ItemType =
 | 
					    Power : int
 | 
				
			||||||
 | 
					    Class : int
 | 
				
			||||||
 | 
					    Cooldown : int<mins>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ShieldItem = {
 | 
				
			||||||
 | 
					    Id : int
 | 
				
			||||||
 | 
					    Name : string
 | 
				
			||||||
 | 
					    Price : int<GBT>
 | 
				
			||||||
 | 
					    Class : int
 | 
				
			||||||
 | 
					    Cooldown : int<mins>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ItemType =
 | 
				
			||||||
    | Hack of power : int * hackClass : int * cooldown : int<mins>
 | 
					    | Hack of power : int * hackClass : int * cooldown : int<mins>
 | 
				
			||||||
    | Shield of shieldClass : int * cooldown : int<mins>
 | 
					    | Shield of shieldClass : int * cooldown : int<mins>
 | 
				
			||||||
    | Food of effect : (Item -> PlayerData -> PlayerData)
 | 
					    | Food of effect : (Item -> PlayerData -> PlayerData)
 | 
				
			||||||
 | 
				
			|||||||
@ -44,7 +44,7 @@ let checkWeaponHasCooldown (weapon : Item) attacker =
 | 
				
			|||||||
       | None -> Ok attacker
 | 
					       | None -> Ok attacker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let checkHasEmptyHacks attacker =
 | 
					let checkHasEmptyHacks attacker =
 | 
				
			||||||
    match Player.getHacks attacker with
 | 
					    match Inventory.getHackItems attacker.Inventory 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -68,36 +68,30 @@ 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 ((_,_,hackClass,_) : HackItem) ((_,shieldClass,_) : ShieldItem) =
 | 
					 | 
				
			||||||
    if hackClass = shieldClass
 | 
					 | 
				
			||||||
        then Weak
 | 
					 | 
				
			||||||
        else Strong
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let runHackerBattle defender (hack : HackItem) =
 | 
					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.getShields |> List.find (fun (item,_,_) -> item.Id = id) |> Some
 | 
					        | Shielding id -> defender.Inventory |> Inventory.getShieldItems |> List.find (fun item -> item.Id = id) |> Some
 | 
				
			||||||
        | _ -> None)
 | 
					        | _ -> None)
 | 
				
			||||||
    |> Array.map (calculateDamage hack)
 | 
					    |> Array.map (fun shield -> if hack.Class = shield.Class then Weak else Strong)
 | 
				
			||||||
    |> Array.contains Weak
 | 
					    |> Array.contains Weak
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let updateCombatants successfulHack (attacker : PlayerData) (defender : PlayerData) (hack : HackItem) 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 = item.Id
 | 
					            HackId = hack.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 cooldown }
 | 
					          Cooldown = if isDefenderEvent then int WeaponClass.SameTargetAttackCooldown.TotalMinutes * 1<mins> else hack.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
 | 
				
			||||||
@ -108,11 +102,10 @@ let updateCombatants successfulHack (attacker : PlayerData) (defender : PlayerDa
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
let successfulHack (ctx : IDiscordContext) attacker defender (hack : HackItem) =
 | 
					let successfulHack (ctx : IDiscordContext) attacker defender (hack : HackItem) =
 | 
				
			||||||
    async {
 | 
					    async {
 | 
				
			||||||
        let (item,power,hackClass,cooldown) = hack
 | 
					        let prizeAmount = if hack.Power < int defender.Bank then hack.Power else int defender.Bank
 | 
				
			||||||
        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 item
 | 
					        let embed = Embeds.responseSuccessfulHack true defender.DiscordId prizeAmount hack
 | 
				
			||||||
        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
 | 
				
			||||||
@ -123,9 +116,8 @@ let successfulHack (ctx : IDiscordContext) attacker defender (hack : HackItem) =
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let failedHack (ctx : IDiscordContext) attacker defender (hack : HackItem) =
 | 
					let failedHack (ctx : IDiscordContext) attacker defender (hack : HackItem) =
 | 
				
			||||||
    let (item, power, hackClass, cooldown) = hack
 | 
					 | 
				
			||||||
    async {
 | 
					    async {
 | 
				
			||||||
        let lostAmount = if power < int attacker.Bank then power else int attacker.Bank
 | 
					        let lostAmount = if hack.Power < int attacker.Bank then hack.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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -158,7 +150,8 @@ 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 item,_,_,_ as hackItem = Armory.getHackById hackId
 | 
					        let hack = Armory.battleItems |> Inventory.findHackById hackId
 | 
				
			||||||
 | 
					        let hackAsItem = Inventory.hackToItem hack
 | 
				
			||||||
        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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -167,21 +160,21 @@ let handleAttack (ctx : IDiscordContext) =
 | 
				
			|||||||
            do! attacker
 | 
					            do! attacker
 | 
				
			||||||
                |> Player.removeExpiredActions
 | 
					                |> Player.removeExpiredActions
 | 
				
			||||||
                |> checkAlreadyHackedTarget defender
 | 
					                |> checkAlreadyHackedTarget defender
 | 
				
			||||||
                >>= checkPlayerOwnsWeapon item
 | 
					                >>= checkPlayerOwnsWeapon hackAsItem
 | 
				
			||||||
                >>= checkWeaponHasCooldown item
 | 
					                >>= checkWeaponHasCooldown hackAsItem
 | 
				
			||||||
                |> function
 | 
					                |> function
 | 
				
			||||||
                   | Ok atkr ->
 | 
					                   | Ok atkr ->
 | 
				
			||||||
                       runHackerBattle defender hackItem
 | 
					                       runHackerBattle defender hack
 | 
				
			||||||
                       |> function
 | 
					                       |> function
 | 
				
			||||||
                          | false -> successfulHack ctx atkr defender hackItem
 | 
					                          | false -> successfulHack ctx atkr defender hack
 | 
				
			||||||
                          | true -> failedHack ctx attacker defender hackItem
 | 
					                          | true -> failedHack ctx attacker defender hack
 | 
				
			||||||
                   | 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 |> List.length > 0 then
 | 
					        if player.Inventory |> Inventory.filterByShields |> 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
 | 
				
			||||||
@ -194,18 +187,19 @@ 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 item, shieldClass, cooldown as shield = Armory.getShields |> List.find (fun (item,_,_) -> item.Id = shieldId)
 | 
					        let shield = Armory.battleItems |> Inventory.findShieldById shieldId
 | 
				
			||||||
 | 
					        let shieldAsItem = Inventory.shieldToItem shield
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        do! player
 | 
					        do! player
 | 
				
			||||||
            |> checkPlayerOwnsWeapon item
 | 
					            |> checkPlayerOwnsWeapon shieldAsItem
 | 
				
			||||||
            >>= checkPlayerHasShieldSlotsAvailable
 | 
					            >>= checkPlayerHasShieldSlotsAvailable
 | 
				
			||||||
            >>= checkWeaponHasCooldown item
 | 
					            >>= checkWeaponHasCooldown shieldAsItem
 | 
				
			||||||
            |> 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 = cooldown
 | 
					                    Cooldown = shield.Cooldown
 | 
				
			||||||
                    Timestamp = DateTime.UtcNow
 | 
					                    Timestamp = DateTime.UtcNow
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                do! DbService.updatePlayer GuildEnvironment.pgDb p
 | 
					                do! DbService.updatePlayer GuildEnvironment.pgDb p
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
module Degenz.Store
 | 
					module Degenz.Store
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					open System
 | 
				
			||||||
open System.Threading.Tasks
 | 
					open System.Threading.Tasks
 | 
				
			||||||
open DSharpPlus.Entities
 | 
					open DSharpPlus.Entities
 | 
				
			||||||
open DSharpPlus
 | 
					open DSharpPlus
 | 
				
			||||||
@ -9,6 +10,58 @@ open Degenz
 | 
				
			|||||||
open Degenz.Messaging
 | 
					open Degenz.Messaging
 | 
				
			||||||
open Degenz.PlayerInteractions
 | 
					open Degenz.PlayerInteractions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let getBuyItemsEmbed (playerInventory : Inventory) (storeInventory : Inventory) =
 | 
				
			||||||
 | 
					    let embeds , buttons =
 | 
				
			||||||
 | 
					        storeInventory
 | 
				
			||||||
 | 
					        |> List.map (fun item ->
 | 
				
			||||||
 | 
					            let embed = DiscordEmbedBuilder()
 | 
				
			||||||
 | 
					            match item.Type with
 | 
				
			||||||
 | 
					            | Hack(power,_,cooldown) ->
 | 
				
			||||||
 | 
					                embed.AddField($"$GBT Reward  |", string power, true)
 | 
				
			||||||
 | 
					                     .AddField("Cooldown  |", $"{TimeSpan.FromMinutes(int cooldown).Minutes} minutes", true)
 | 
				
			||||||
 | 
					                     .WithThumbnail(Embeds.getItemIcon item.Id)
 | 
				
			||||||
 | 
					                     |> ignore
 | 
				
			||||||
 | 
					            | Shield(shieldClass,cooldown) ->
 | 
				
			||||||
 | 
					                embed.AddField($"Strong against  |", WeaponClass.getGoodAgainst shieldClass |> snd |> string, true)
 | 
				
			||||||
 | 
					//                    .AddField($"Defensive Strength  |", string item.Power, true)
 | 
				
			||||||
 | 
					                     .AddField("Active For  |", $"{TimeSpan.FromMinutes(int cooldown).Hours} hours", true)
 | 
				
			||||||
 | 
					                     .WithThumbnail(Embeds.getItemIcon item.Id)
 | 
				
			||||||
 | 
					                     |> ignore
 | 
				
			||||||
 | 
					            | _ -> ()
 | 
				
			||||||
 | 
					            embed
 | 
				
			||||||
 | 
					              .AddField("Price 💰", (if item.Price = 0<GBT> then "Free" else $"{item.Price} $GBT"), true)
 | 
				
			||||||
 | 
					              .WithColor(WeaponClass.getClassEmbedColor item)
 | 
				
			||||||
 | 
					              .WithTitle($"{item.Name}")
 | 
				
			||||||
 | 
					              |> ignore
 | 
				
			||||||
 | 
					            let button =
 | 
				
			||||||
 | 
					                if playerInventory |> List.exists (fun i -> i.Id = item.Id)
 | 
				
			||||||
 | 
					                    then DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Buy-{item.Id}", $"Own {item.Name}", true)
 | 
				
			||||||
 | 
					                    else DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Buy-{item.Id}", $"Buy {item.Name}")
 | 
				
			||||||
 | 
					            ( embed.Build() , button :> DiscordComponent ))
 | 
				
			||||||
 | 
					        |> List.unzip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DiscordFollowupMessageBuilder()
 | 
				
			||||||
 | 
					        .AddEmbeds(embeds)
 | 
				
			||||||
 | 
					        .AddComponents(buttons)
 | 
				
			||||||
 | 
					        .AsEphemeral(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let getSellEmbed (items : Item list) =
 | 
				
			||||||
 | 
					    let embeds , buttons =
 | 
				
			||||||
 | 
					        items
 | 
				
			||||||
 | 
					        |> List.map (fun item ->
 | 
				
			||||||
 | 
					            DiscordEmbedBuilder()
 | 
				
			||||||
 | 
					              .AddField("Sell For 💰", $"{item.Price} $GBT", true)
 | 
				
			||||||
 | 
					              .WithTitle($"{item.Name}")
 | 
				
			||||||
 | 
					              .WithColor(WeaponClass.getClassEmbedColor item)
 | 
				
			||||||
 | 
					              .Build()
 | 
				
			||||||
 | 
					            , DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Sell-{id}", $"Sell {item.Name}") :> DiscordComponent)
 | 
				
			||||||
 | 
					        |> List.unzip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DiscordFollowupMessageBuilder()
 | 
				
			||||||
 | 
					        .AddEmbeds(embeds)
 | 
				
			||||||
 | 
					        .AddComponents(buttons)
 | 
				
			||||||
 | 
					        .AsEphemeral(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let checkHasSufficientFunds (item : Item) player =
 | 
					let checkHasSufficientFunds (item : Item) player =
 | 
				
			||||||
    if player.Bank - item.Price >= 0<GBT>
 | 
					    if player.Bank - item.Price >= 0<GBT>
 | 
				
			||||||
       then Ok player
 | 
					       then Ok player
 | 
				
			||||||
@ -31,15 +84,15 @@ let checkHasItemsInArsenal itemType items player =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
let buy getItems (ctx : IDiscordContext) =
 | 
					let buy getItems (ctx : IDiscordContext) =
 | 
				
			||||||
    executePlayerAction ctx (fun player -> async {
 | 
					    executePlayerAction ctx (fun player -> async {
 | 
				
			||||||
        let itemStore = Embeds.getBuyItemsEmbed (getItems player.Inventory) (getItems Armory.battleItems)
 | 
					        let itemStore = getBuyItemsEmbed (getItems player.Inventory) (getItems Armory.battleItems)
 | 
				
			||||||
        do! ctx.FollowUp itemStore |> Async.AwaitTask
 | 
					        do! ctx.FollowUp itemStore |> Async.AwaitTask
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let sell itemType getItems (ctx : IDiscordContext) =
 | 
					let sell itemType getItems (ctx : IDiscordContext) =
 | 
				
			||||||
    executePlayerAction ctx (fun player -> async {
 | 
					    executePlayerAction ctx (fun player -> async {
 | 
				
			||||||
        let items = getItems player
 | 
					        let items = getItems player.Inventory
 | 
				
			||||||
        match checkHasItemsInArsenal itemType items player with
 | 
					        match checkHasItemsInArsenal itemType items player with
 | 
				
			||||||
        | Ok _ -> let itemStore = Embeds.getSellEmbed items
 | 
					        | Ok _ -> let itemStore = 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
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
@ -114,8 +167,8 @@ type Store() =
 | 
				
			|||||||
    member this.BuyShield (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (buy Armory.getShieldItems)
 | 
					    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 "Hacks" Player.getHackItems)
 | 
					    member this.SellHack (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (sell "Hacks" Inventory.filterByHacks)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [<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 "Shields" Player.getShieldItems)
 | 
					    member this.SellShield (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (sell "Shields" Inventory.filterByShields)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -9,20 +9,20 @@ 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 defaultHackItem, hackPower, hackClass, hackCooldown as defaultHack = Armory.getHackById (int ItemId.Virus)
 | 
					let defaultHack = Armory.battleItems |> Inventory.findHackById (int ItemId.Virus)
 | 
				
			||||||
let defaultShieldItem, shieldClass, shieldCooldown as defaultShield = Armory.getShieldById (int ItemId.Firewall)
 | 
					let defaultShield = Armory.battleItems |> Inventory.findShieldById (int ItemId.Firewall)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let TrainerEvents = [|
 | 
					let TrainerEvents = [|
 | 
				
			||||||
  { Timestamp = System.DateTime.UtcNow
 | 
					  { Timestamp = System.DateTime.UtcNow
 | 
				
			||||||
    Cooldown = 2<mins>
 | 
					    Cooldown = defaultHack.Cooldown
 | 
				
			||||||
    Type = Hacking {
 | 
					    Type = Hacking {
 | 
				
			||||||
        Adversary = Sensei
 | 
					        Adversary = Sensei
 | 
				
			||||||
        Success = true
 | 
					        Success = true
 | 
				
			||||||
        IsInstigator = true
 | 
					        IsInstigator = true
 | 
				
			||||||
        HackId = defaultHackItem.Id } }
 | 
					        HackId = defaultHack.Id } }
 | 
				
			||||||
  { Timestamp = System.DateTime.UtcNow
 | 
					  { Timestamp = System.DateTime.UtcNow
 | 
				
			||||||
    Cooldown =  shieldCooldown
 | 
					    Cooldown =  defaultShield.Cooldown
 | 
				
			||||||
    Type = Shielding defaultShieldItem.Id }
 | 
					    Type = Shielding defaultShield.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 - `{defaultShieldItem.Name}`\n"
 | 
					                + $"Type the `/shield` command now, then select - `{defaultShield.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 = [ defaultShieldItem ] ; Name = name } true
 | 
					        let embed = Embeds.pickDefense "Trainer-2" { PlayerData.empty with Inventory = [ Inventory.shieldToItem defaultShield ] ; Name = name } true
 | 
				
			||||||
        do! ctx.FollowUp(embed) |> Async.AwaitTask
 | 
					        do! ctx.FollowUp(embed) |> Async.AwaitTask
 | 
				
			||||||
    } |> Async.StartAsTask :> Task
 | 
					    } |> Async.StartAsTask :> Task
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -88,11 +88,11 @@ let handleDefense (ctx : IDiscordContext) =
 | 
				
			|||||||
        let embed = Embeds.responseCreatedShield defaultShield
 | 
					        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 **{defaultHackItem.Name}**"
 | 
					        do! sendMessage' $"Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now with **{defaultHack.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 defaultHackItem.Name)
 | 
					        do! sendFollowUpMessageWithButton ctx (handleDefenseMsg defaultHack.Name)
 | 
				
			||||||
    } |> Async.StartAsTask :> Task
 | 
					    } |> Async.StartAsTask :> Task
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let handleTrainerStep3 (ctx : IDiscordContext) =
 | 
					let handleTrainerStep3 (ctx : IDiscordContext) =
 | 
				
			||||||
@ -103,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 `{defaultHackItem.Name}`")
 | 
					                 + $"Type the `/hack` command now, then choose me - <@{Sensei.Id}> as your target, and select `{defaultHack.Name}`")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, builder) |> Async.AwaitTask
 | 
					        do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, builder) |> Async.AwaitTask
 | 
				
			||||||
    } |> Async.StartAsTask :> Task
 | 
					    } |> Async.StartAsTask :> Task
 | 
				
			||||||
@ -115,8 +115,9 @@ let hack (target : DiscordUser) (ctx : IDiscordContext) =
 | 
				
			|||||||
        let isRightTarget = target.Id = Sensei.Id
 | 
					        let isRightTarget = target.Id = Sensei.Id
 | 
				
			||||||
        match isRightTarget with
 | 
					        match isRightTarget with
 | 
				
			||||||
        | true ->
 | 
					        | true ->
 | 
				
			||||||
 | 
					            let player = { PlayerData.empty with Inventory = [ Inventory.hackToItem defaultHack ] }
 | 
				
			||||||
            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 = [ defaultHackItem ] } bot true
 | 
					            let embed = Embeds.pickHack "Trainer-4" player bot true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            do! ctx.FollowUp(embed) |> Async.AwaitTask
 | 
					            do! ctx.FollowUp(embed) |> Async.AwaitTask
 | 
				
			||||||
        | false ->
 | 
					        | false ->
 | 
				
			||||||
@ -132,7 +133,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 hackPower defaultHackItem
 | 
					        let embed = Embeds.responseSuccessfulHack false Sensei.Id defaultHack.Power defaultHack
 | 
				
			||||||
        do! ctx.FollowUp(embed) |> Async.AwaitTask
 | 
					        do! ctx.FollowUp(embed) |> Async.AwaitTask
 | 
				
			||||||
        do! Async.Sleep 4000
 | 
					        do! Async.Sleep 4000
 | 
				
			||||||
        do! sendMessage'
 | 
					        do! sendMessage'
 | 
				
			||||||
@ -150,7 +151,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,`{defaultHackItem.Name}` and a shield, `{defaultShieldItem.Name}`") |> ignore
 | 
					            sb.Append($"I'm going to gift you a hack,`{defaultHack.Name}` and a shield, `{defaultShield.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
 | 
				
			||||||
@ -165,12 +166,15 @@ 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.getHackItems player |> List.exists (fun item -> item.Id = defaultHackItem.Id)
 | 
					        let hasStockWeapons =
 | 
				
			||||||
 | 
					            player.Inventory
 | 
				
			||||||
 | 
					            |> List.choose (fun item -> if item.Id = defaultHack.Id || item.Id = defaultShield.Id then Some item else None)
 | 
				
			||||||
 | 
					            |> List.length > 0
 | 
				
			||||||
        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 = defaultHackItem::defaultShieldItem::player.Inventory
 | 
					                    Inventory = Inventory.hackToItem defaultHack::Inventory.shieldToItem defaultShield::player.Inventory
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
                Player.removeExpiredActions player
 | 
					                Player.removeExpiredActions player
 | 
				
			||||||
@ -187,7 +191,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 = [ $"{defaultHackItem.Name} Hack" ; $"{defaultShieldItem.Name} Shield" ]
 | 
					            let rewards = [ $"{defaultHack.Name} Hack" ; $"{defaultShield.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
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user