discord-bot-game/Bot/GameHelpers.fs

170 lines
7.9 KiB
Forth

namespace Degenz
open System
open DSharpPlus
open DSharpPlus.Entities
open Degenz
open Newtonsoft.Json
module Armory =
let weapons : Inventory =
let file = System.IO.File.ReadAllText("Items.json")
// let file = System.IO.File.ReadAllText("Bot/Items.json")
JsonConvert.DeserializeObject<Inventory>(file)
module Inventory =
let getItemsByType itemType inventory =
match itemType with
| ItemType.Hack -> inventory |> List.filter (fun item -> match item.Type with ItemType.Hack _ -> true | _ -> false)
| ItemType.Shield -> inventory |> List.filter (fun item -> match item.Type with ItemType.Shield _ -> true | _ -> false)
| ItemType.Food -> inventory |> List.filter (fun item -> match item.Type with ItemType.Food _ -> true | _ -> false)
| ItemType.Accessory -> inventory |> List.filter (fun item -> match item.Type with ItemType.Accessory _ -> true | _ -> false)
let findItemById id (inventory : Inventory) = inventory |> List.find (fun item -> item.Id = id)
let getHackItem item =
match item.Type , item.Attributes with
| ItemType.Hack , CanBuy buyPrice & CanSell _ & CanAttack power & CanExpire cooldown & CanClass ``class``->
Some { Id = item.Id
Name = item.Name
Price = buyPrice
Cooldown = cooldown
Power = power
Class = ``class`` }
| _ -> None
let getShieldItem item =
match item.Type , item.Attributes with
| ItemType.Shield , CanBuy buyPrice & CanSell _ & CanDefend resistance & CanExpire cooldown & CanClass ``class`` ->
Some { Id = item.Id
Name = item.Name
Price = buyPrice
Cooldown = cooldown
Resistance = resistance
Class = ``class`` }
| _ -> None
// let findHackById id inventory =
// inventory |> List.pick (fun item -> match item with | Hack h -> (if h.Item.Id = id then Some h else None) | _ -> None)
// let findShieldById id inventory =
// inventory |> List.pick (fun item -> match item with | Shield s -> (if s.Item.Id = id then Some s else None) | _ -> None)
// let findFoodById id inventory =
// inventory |> List.pick (fun item -> match item with | Food f -> (if f.Item.Id = id then Some f else None) | _ -> None)
// let findAccessoryById id inventory =
// inventory |> List.pick (fun item -> match item with | Accessory a -> (if a.Item.Id = id then Some a else None) | _ -> None)
//
let getHacks inventory = inventory |> List.choose getHackItem
let getShields inventory = inventory |> List.choose getShieldItem
let getFoods inventory =
inventory |> List.choose (fun item -> match item.Type with | ItemType.Food -> Some item | _ -> None)
let getAccessories inventory =
inventory |> List.choose (fun item -> match item.Type with | ItemType.Accessory -> Some item | _ -> None)
module WeaponClass =
let SameTargetAttackCooldown = TimeSpan.FromHours(4)
let getClassButtonColor item =
match item.Attributes with
| CanClass "0" -> ButtonStyle.Danger
| CanClass "1" -> ButtonStyle.Primary
| CanClass "2" -> ButtonStyle.Success
| _ -> ButtonStyle.Primary
let getClassEmbedColor item =
match item.Attributes with
| CanClass "0" -> DiscordColor.Red
| CanClass "1" -> DiscordColor.Blurple
| CanClass "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 = TimeSpan.FromMinutes(int act.Cooldown)
DateTime.UtcNow - act.Timestamp < cooldown)
{ player with Events = actions }
let modifyBank (player : PlayerData) amount = { player with Bank = max (player.Bank + amount) 0<GBT> }
module PlayerStats =
// 2.09f would go from 100 to 0 in roughly 48 hours
let Strength = { Id = StatId.Strength ; BaseDecayRate = 2.09 ; BaseRange = Range.normalized }
let Focus = { Id = StatId.Focus ; BaseDecayRate = 2.09 ; BaseRange = Range.normalized }
let Luck = { Id = StatId.Luck ; BaseDecayRate = 2.09 ; BaseRange = Range.normalized }
let Charisma = { Id = StatId.Charisma ; BaseDecayRate = 2.09 ; BaseRange = Range.normalized }
let stats = [ Strength ; Focus ; Charisma ; Luck ]
let getPlayerStat (statConfig : StatConfig) player =
match statConfig.Id with
| StatId.Strength -> player.Stats.Strength
| StatId.Focus -> player.Stats.Focus
| StatId.Charisma -> player.Stats.Charisma
| StatId.Luck -> player.Stats.Luck
| _ -> player.Stats.Luck
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.choose (fun i -> match i.Attributes with CanModify fx -> Some fx | _ -> None)
|> List.concat
|> List.sumBy (fun fx -> match fx.Effect with | Min x -> x | _ -> 0)
let max =
items
|> List.choose (fun i -> match i.Attributes with CanModify fx -> Some fx | _ -> None)
|> List.concat
|> List.sumBy (fun fx -> match fx.Effect with | Max x -> x | _ -> 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 : Inventory) =
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 event ->
match event.Type with
| Hacking h ->
let item = Armory.weapons |> Inventory.findItemById h.HackId
let cooldown = Messaging.getTimeText false WeaponClass.SameTargetAttackCooldown event.Timestamp
$"Hacked {h.Adversary.Name} with {item.Name} {cooldown} ago"
| Shielding id ->
let item = Armory.weapons |> Inventory.findItemById id
let cooldown = Messaging.getTimeText true (TimeSpan.FromMinutes(int event.Cooldown)) event.Timestamp
$"{item.Name} Shield active for {cooldown}"
| _ -> "")
|> List.filter (String.IsNullOrWhiteSpace >> not)
|> String.concat "\n"
let statusFormat p =
let hacks = Player.getHackEvents p
$"**Hacks:** {Inventory.getItemsByType ItemType.Hack p.Inventory |> battleItemFormat}\n
**Shields:** {Inventory.getItemsByType ItemType.Shield p.Inventory |> battleItemFormat}\n
**Hack Attacks:**\n{hacks |> List.take (min hacks.Length 10) |> actionFormat}\n
**Active Shields:**\n{Player.getShieldEvents p |> actionFormat}"