namespace Degenz open System.Threading.Tasks open DSharpPlus open DSharpPlus.Entities open DSharpPlus.EventArgs open DSharpPlus.SlashCommands open Degenz.DbService open Degenz.Messaging module Game = let HackPrize = 10 let ShieldPrize = 5 let SameTargetAttackCooldown = System.TimeSpan.FromHours(6) let executePlayerAction (ctx : IDiscordContext) (dispatch : PlayerData -> Async) = async { let builder = DiscordInteractionResponseBuilder() builder.IsEphemeral <- true builder.Content <- "Content" do! ctx.Respond InteractionResponseType.DeferredChannelMessageWithSource builder |> Async.AwaitTask let! playerResult = tryFindPlayer (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) = async { let builder = DiscordInteractionResponseBuilder() builder.IsEphemeral <- true builder.Content <- "Content" do! ctx.Respond InteractionResponseType.DeferredChannelMessageWithSource builder |> Async.AwaitTask let! players = [ tryFindPlayer (ctx.GetDiscordMember().Id) tryFindPlayer 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) = async { let builder = DiscordInteractionResponseBuilder() builder.IsEphemeral <- true builder.Content <- "Content" if defer then do! ctx.Respond InteractionResponseType.DeferredChannelMessageWithSource builder |> Async.AwaitTask let! players = [ tryFindPlayer (ctx.GetDiscordMember().Id) tryFindPlayer 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 && act.ItemId < 12) let getShieldEvents player = player.Events |> Array.filter (fun act -> match act.Type with PlayerEventType.Shielding -> true | _ -> false && act.ItemId < 12) 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 } 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 -> let item = Armory.getItem act.ItemId match act.Type with | PlayerEventType.Hacking -> let cooldown = Messaging.getTimeText false Game.SameTargetAttackCooldown act.Timestamp $"Hacked {act.Adversary.Name} with {item.Name} {cooldown} ago" | _ -> let cooldown = Messaging.getTimeText true (System.TimeSpan.FromMinutes(int item.Cooldown)) act.Timestamp $"{item.Name} Shield active for {cooldown}") |> 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}"