discord-bot-game/Bot/GameHelpers.fs
2022-02-27 23:13:23 +07:00

167 lines
6.8 KiB
Forth

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<Item array>(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 =
// TODO: Find a different place to put this
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
|> Array.filter (fun act -> match act.Type with PlayerEventType.Hacking h -> h.IsInstigator | _ -> false)
let getShieldEvents player =
player.Events
|> Array.filter (fun act -> match act.Type with PlayerEventType.Shielding _ -> true | _ -> false)
let removeExpiredActions player =
let actions =
player.Events
|> Array.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<GBT> }
let getStat statId player =
player.Stats
|> List.tryFind (fun stat -> statId = stat.Id)
|> Option.map (fun stat -> stat.Amount)
|> Option.defaultValue 0
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 calculateStatDecay (stat : PlayerStat) =
let statConfig = stats |> List.find (fun s -> s.Id = stat.Id)
let hoursElapsed = (DateTime.UtcNow - stat.LastRead).Hours
let totalDecay = hoursElapsed * int statConfig.BaseDecayRate
{ stat with Amount = max stat.ModMinMax.Start.Value (stat.Amount - totalDecay) ; LastRead = DateTime.UtcNow }
let statConsumableMap =
[ ( StatId.Strength , 12 )
( StatId.Focus , 13 )
( StatId.Luck , 14 )
( StatId.Charisma , 15 ) ]
module Arsenal =
let battleItemFormat (items : Item list) =
match items with
| [] -> "None"
| _ -> items |> List.map (fun item -> item.Name) |> String.concat ", "
let actionFormat (actions : PlayerEvent array) =
match actions with
| [||] -> "None"
| acts ->
acts
|> Array.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}"
| _ -> "")
|> Array.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 |> Array.take (min hacks.Length 10) |> actionFormat}\n
**Active Shields:**\n{Player.getShieldEvents p |> actionFormat}"