125 lines
6.1 KiB
Forth

namespace Degenz
open System.Threading.Tasks
open DSharpPlus
open DSharpPlus.Entities
open Degenz.DbService
open Degenz.Messaging
module Game =
let SameTargetAttackCooldown = System.TimeSpan.FromHours(2)
let getClassButtonColor = function
| 0 -> ButtonStyle.Danger
| 1 -> ButtonStyle.Success
| _ -> ButtonStyle.Primary
let getClassEmbedColor = function
| 0 -> DiscordColor.Red
| 1 -> DiscordColor.Blurple
| _ -> DiscordColor.Green
let getGoodAgainst = function
| 0 -> ( ShieldId.Firewall , HackId.Virus )
| 1 -> ( ShieldId.Cypher , HackId.RemoteAccess )
| _ -> ( ShieldId.Encryption , HackId.Worm )
let executePlayerAction (ctx : IDiscordContext) (dispatch : PlayerData -> Async<unit>) =
async {
let builder = DiscordInteractionResponseBuilder().AsEphemeral(true)
do! ctx.Respond(InteractionResponseType.DeferredChannelMessageWithSource, builder) |> Async.AwaitTask
let! playerResult = tryFindPlayer GuildEnvironment.pgDb (ctx.GetDiscordMember().Id)
match playerResult with
| Some player -> do! dispatch player
| None -> do! Messaging.sendFollowUpMessage ctx "You are currently not a hacker, first use the /redpill command to become one"
} |> Async.StartAsTask :> Task
let executePlayerActionWithTarget (targetPlayer : DiscordUser) (ctx : IDiscordContext) (dispatch : PlayerData -> PlayerData -> Async<unit>) =
async {
let builder = DiscordInteractionResponseBuilder()
builder.IsEphemeral <- true
builder.Content <- "Content"
do! ctx.Respond(InteractionResponseType.DeferredChannelMessageWithSource, builder) |> Async.AwaitTask
let! players =
[ tryFindPlayer GuildEnvironment.pgDb (ctx.GetDiscordMember().Id)
tryFindPlayer GuildEnvironment.pgDb targetPlayer.Id ]
|> Async.Parallel
match players.[0] , players.[1] with
| Some player , Some target -> do! dispatch player target
| None , _ -> do! Messaging.sendFollowUpMessage ctx "You are currently not a hacker, first use the /redpill command to become one"
| _ , None ->
if targetPlayer.IsBot
then do! Messaging.sendFollowUpMessage ctx $"{targetPlayer.Username} is a bot, pick a real human to hack"
else do! Messaging.sendFollowUpMessage ctx "Your target is not connected to the network, they must join first by using the /redpill command"
} |> Async.StartAsTask :> Task
let executePlayerActionWithTargetId defer (targetId : uint64) (ctx : IDiscordContext) (dispatch : PlayerData -> PlayerData -> Async<unit>) =
async {
let builder = DiscordInteractionResponseBuilder()
builder.IsEphemeral <- true
builder.Content <- "Content"
if defer then
do! ctx.Respond(InteractionResponseType.DeferredChannelMessageWithSource, builder) |> Async.AwaitTask
let! players =
[ tryFindPlayer GuildEnvironment.pgDb (ctx.GetDiscordMember().Id)
tryFindPlayer GuildEnvironment.pgDb targetId ]
|> Async.Parallel
match players.[0] , players.[1] with
| Some player , Some target -> do! dispatch player target
| None , _ -> do! Messaging.sendFollowUpMessage ctx "You are currently not a hacker, first use the /redpill command to become one"
| _ , None -> do! Messaging.sendFollowUpMessage ctx "Your target is not connected to the network, they must join first by using the /redpill command"
} |> Async.StartAsTask :> Task
module Player =
let getItems itemType (player : PlayerData) = player.Inventory |> Array.filter (fun i -> i.Type = itemType)
let getHacks (player : PlayerData) = getItems ItemType.Hack player
let getShields (player : PlayerData) = getItems ItemType.Shield player
let getHackEvents player =
player.Events
|> Array.filter (fun act -> match act.Type with PlayerEventType.Hacking _ -> true | _ -> 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> }
module Arsenal =
let battleItemFormat (items : Item array) =
match items with
| [||] -> "None"
| _ -> items |> Array.toList |> List.map (fun i -> i.Name) |> String.concat ", "
let actionFormat (actions : PlayerEvent array) =
match actions with
| [||] -> "None"
| _ -> actions
|> Array.map (fun act ->
match act.Type with
| Hacking h ->
let item = Armory.getItem h.HackId
let cooldown = Messaging.getTimeText false Game.SameTargetAttackCooldown act.Timestamp
$"Hacked {h.Adversary.Name} with {item.Name} {cooldown} ago"
| Shielding id ->
let item = Armory.getItem 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)
|> String.concat "\n"
let statusFormat p =
let hacks = Player.getHackEvents p
$"**Hacks:** {Player.getHacks p |> battleItemFormat}\n
**Shields:** {Player.getShields p |> battleItemFormat}\n
**Hack Attacks:**\n{ hacks |> Array.take (min hacks.Length 10) |> actionFormat}\n
**Active Shields:**\n{Player.getShieldEvents p |> actionFormat}"