namespace Degenz open System open DSharpPlus open DSharpPlus.Entities open Newtonsoft.Json module Armory = let weapons = let file = System.IO.File.ReadAllText("Items.json") // let file = System.IO.File.ReadAllText("Bot/Items.json") JsonConvert.DeserializeObject(file) |> Array.toList module Inventory = let itemToHack item power hackClass cooldown = { Id = item.Id Name = item.Name Price = item.Price Power = power Class = hackClass Cooldown = cooldown } 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 findItemById id inventory = inventory |> List.find (fun item -> item.Id = id) let tryFindItemById id inventory = inventory |> List.tryFind (fun item -> item.Id = 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 = let SameTargetAttackCooldown = System.TimeSpan.FromHours(1) let getClassButtonColor item = match item.Type with | Hack (_,0,_) | Shield (0,_) -> ButtonStyle.Danger | Hack (_,1,_) | Shield (1,_) -> ButtonStyle.Primary | Hack (_,2,_) | Shield (2,_) -> ButtonStyle.Success | _ -> ButtonStyle.Primary let getClassEmbedColor item = match item.Type with | Hack (_,0,_) | Shield (0,_) -> DiscordColor.Red | Hack (_,1,_) | Shield (1,_) -> DiscordColor.Blurple | Hack (_,2,_) | Shield (2,_) -> DiscordColor.Green | _ -> DiscordColor.Blurple let getGoodAgainst = function | 0 -> ( ItemId.Firewall , ItemId.Virus ) | 1 -> ( ItemId.Encryption , ItemId.RemoteAccess ) | _ -> ( ItemId.Cypher , ItemId.Worm ) module Player = let getHackEvents player = player.Events |> List.filter (fun act -> match act.Type with PlayerEventType.Hacking h -> h.IsInstigator | _ -> false) let getShieldEvents player = player.Events |> List.filter (fun act -> match act.Type with PlayerEventType.Shielding _ -> true | _ -> false) let removeExpiredActions player = let actions = player.Events |> List.filter (fun (act : PlayerEvent) -> let cooldown = System.TimeSpan.FromMinutes(int act.Cooldown) System.DateTime.UtcNow - act.Timestamp < cooldown) { player with Events = actions } let modifyBank (player : PlayerData) amount = { player with Bank = max (player.Bank + amount) 0 } module PlayerStats = // 4.17f would go from 100 to 0 in roughly 24 hours let Strength = { Id = StatId.Strength ; BaseDecayRate = 4.17 ; BaseRange = Range.normalized } let Focus = { Id = StatId.Focus ; BaseDecayRate = 4.17 ; BaseRange = Range.normalized } let Luck = { Id = StatId.Luck ; BaseDecayRate = 4.17 ; BaseRange = Range.normalized } let Charisma = { Id = StatId.Charisma ; BaseDecayRate = 4.17 ; BaseRange = Range.normalized } let stats = [ Strength ; Focus ; Luck ; Charisma ] let calculateActiveStat statId amount items = let statConfig = stats |> List.find (fun s -> s.Id = statId) // let hoursElapsed = (DateTime.UtcNow - lastRead).Hours // let totalDecay = float hoursElapsed * statConfig.BaseDecayRate let modMinMax = let min = items |> List.sumBy (fun item -> match item.Type with | Accessory(_,floorBoost,_) -> floorBoost | _ -> 0) let max = items |> List.sumBy (fun item -> match item.Type with | Accessory(_,_,ceilBoost) -> ceilBoost | _ -> 0) Range.create (statConfig.BaseRange.Min + min) (statConfig.BaseRange.Max + max) let amountAfterDecay = modMinMax |> Range.constrain amount { Id = statId ; Amount = amountAfterDecay ; ModRange = modMinMax ; LastRead = DateTime.UtcNow } module Arsenal = let battleItemFormat (items : Item list) = match items with | [] -> "None" | _ -> items |> List.map (fun item -> item.Name) |> String.concat ", " let actionFormat (actions : PlayerEvent List) = match actions with | [] -> "None" | acts -> acts |> List.map (fun act -> match act.Type with | Hacking h -> let item = Armory.weapons |> Inventory.findHackById h.HackId let cooldown = Messaging.getTimeText false WeaponClass.SameTargetAttackCooldown act.Timestamp $"Hacked {h.Adversary.Name} with {item.Name} {cooldown} ago" | Shielding id -> let item = Armory.weapons |> Inventory.findHackById id let cooldown = Messaging.getTimeText true (System.TimeSpan.FromMinutes(int act.Cooldown)) act.Timestamp $"{item.Name} Shield active for {cooldown}" | _ -> "") |> List.filter (System.String.IsNullOrWhiteSpace >> not) |> String.concat "\n" let statusFormat p = let hacks = Player.getHackEvents p $"**Hacks:** {Inventory.filterByHacks p.Inventory |> battleItemFormat}\n **Shields:** {Inventory.filterByShields p.Inventory |> battleItemFormat}\n **Hack Attacks:**\n{ hacks |> List.take (min hacks.Length 10) |> actionFormat}\n **Active Shields:**\n{Player.getShieldEvents p |> actionFormat}"