134 lines
6.8 KiB
Forth
134 lines
6.8 KiB
Forth
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<GBT>
|
|
let ShieldPrize = 5<GBT>
|
|
|
|
let SameTargetAttackCooldown = System.TimeSpan.FromHours(6)
|
|
|
|
let executePlayerAction (ctx : IDiscordContext) (dispatch : PlayerData -> Async<unit>) =
|
|
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<unit>) =
|
|
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<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 (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)
|
|
|
|
// TODO: This parameter is a result of putting the cooldown on the attack side. Put the cooldown on the defender
|
|
// side and only check if it's the same target, we need to refactor Actions
|
|
let removeExpiredActions filterByAttackCooldown player =
|
|
let actions =
|
|
player.Events
|
|
|> Array.filter (fun (act : PlayerEvent) ->
|
|
let itemCooldown =
|
|
if act.ItemId < 12 then
|
|
(Armory.getItem act.ItemId).Cooldown
|
|
else
|
|
match act.Type with
|
|
| PlayerEventType.Steal -> 1<mins>
|
|
| _ -> 720<mins>
|
|
|> int
|
|
|
|
match act.Type , filterByAttackCooldown with
|
|
| PlayerEventType.Hacking , true -> System.DateTime.UtcNow - act.Timestamp < System.TimeSpan.FromMinutes(itemCooldown)
|
|
| PlayerEventType.Hacking , false -> System.DateTime.UtcNow - act.Timestamp < Game.SameTargetAttackCooldown
|
|
| PlayerEventType.Shielding , _ -> System.DateTime.UtcNow - act.Timestamp < System.TimeSpan.FromMinutes(itemCooldown)
|
|
| _ -> System.DateTime.UtcNow - act.Timestamp < System.TimeSpan.FromMinutes(itemCooldown))
|
|
{ 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"
|
|
| _ ->
|
|
let hacks , defenses =
|
|
actions
|
|
|> Array.filter (fun act -> act.ItemId < 12)
|
|
|> Array.partition (fun act -> match act.Type with PlayerEventType.Hacking -> true | _ -> false)
|
|
let hacks = hacks |> Array.take (min hacks.Length 10)
|
|
hacks
|
|
|> Array.append defenses
|
|
|> 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} {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 =
|
|
$"**Hacks:** {Player.getHacks p |> battleItemFormat}\n
|
|
**Shields:** {Player.getShields p |> battleItemFormat}\n
|
|
**Hack Attacks:**\n{Player.getHackEvents p |> actionFormat}\n
|
|
**Active Shields:**\n{Player.getShieldEvents p |> actionFormat}"
|
|
|