Anti spam cooldown for player and a 12 hour global cooldown for victim
This commit is contained in:
parent
7e2b46a96b
commit
04add71c6e
26
Bot/Game.fs
26
Bot/Game.fs
@ -41,15 +41,17 @@ module Game =
|
||||
| None -> do! Messaging.sendFollowUpMessage ctx "You are currently not a hacker, first use the /redpill command to become one"
|
||||
} |> Async.StartAsTask :> Task
|
||||
|
||||
let executePlayerWithTargetAction (targetPlayer : DiscordUser) (ctx : IDiscordContext) (dispatch : PlayerData -> PlayerData -> Async<unit>) =
|
||||
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! playerResult = tryFindPlayer (ctx.GetDiscordMember().Id)
|
||||
let! targetResult = tryFindPlayer targetPlayer.Id
|
||||
match playerResult , targetResult with
|
||||
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 ->
|
||||
@ -58,6 +60,22 @@ module Game =
|
||||
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 (targetId : uint64) (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 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.Arsenal |> Array.filter (fun i -> i.Type = itemType)
|
||||
let getHacks (player : PlayerData) = getItems ItemType.Hack player
|
||||
|
@ -9,8 +9,6 @@ open DSharpPlus.SlashCommands
|
||||
open Degenz
|
||||
open Degenz.Messaging
|
||||
|
||||
// TODO: Do not allow any attacks until the user has completed training
|
||||
// TODO: Introduce second round of weapons, more expensive and with better stats
|
||||
let checkPlayerIsAttackingThemselves defender attacker =
|
||||
match attacker.DiscordId = defender.DiscordId with
|
||||
| true -> Error "You think you're clever? You can't hack yourself, pal."
|
||||
@ -120,7 +118,7 @@ let failedHack (ctx : IDiscordContext) attacker defender hack =
|
||||
}
|
||||
|
||||
let attack (target : DiscordUser) (ctx : IDiscordContext) =
|
||||
Game.executePlayerWithTargetAction target ctx (fun attacker defender -> async {
|
||||
Game.executePlayerActionWithTarget target ctx (fun attacker defender -> async {
|
||||
do! attacker
|
||||
|> checkAlreadyHackedTarget defender.DiscordId
|
||||
<!> (Player.removeExpiredActions true)
|
||||
@ -180,7 +178,7 @@ let handleDefense (ctx : IDiscordContext) =
|
||||
|> checkPlayerOwnsWeapon shieldId
|
||||
>>= checkPlayerHasShieldSlotsAvailable shield
|
||||
>>= checkItemHasCooldown shieldId
|
||||
|> handleResultWithResponseFromEvent ctx (fun p -> async {
|
||||
|> handleResultWithResponse ctx (fun p -> async {
|
||||
let embed = Embeds.responseCreatedShield (Armory.getItem shieldId)
|
||||
do! ctx.FollowUp embed |> Async.AwaitTask
|
||||
let defense = { ActionId = shieldId ; Type = Defense ; Timestamp = DateTime.UtcNow }
|
||||
|
@ -28,7 +28,7 @@ let player1Won p1m p2m =
|
||||
| _ , _ -> Draw
|
||||
|
||||
let playRPS target ctx =
|
||||
Game.executePlayerWithTargetAction target ctx (fun attacker defender -> async {
|
||||
Game.executePlayerActionWithTarget target ctx (fun attacker defender -> async {
|
||||
|
||||
return ()
|
||||
})
|
||||
|
@ -49,7 +49,7 @@ let handleBuyItem (ctx : IDiscordContext) itemId =
|
||||
do! player
|
||||
|> checkHasSufficientFunds item
|
||||
>>= checkAlreadyOwnsItem item
|
||||
|> handleResultWithResponseFromEvent ctx (fun player -> async {
|
||||
|> handleResultWithResponse ctx (fun player -> async {
|
||||
let newBalance = player.Bank - item.Cost
|
||||
let p = { player with Bank = newBalance ; Arsenal = Array.append [| item |] player.Arsenal }
|
||||
do! DbService.updatePlayer p
|
||||
@ -62,7 +62,7 @@ let handleSell (ctx : IDiscordContext) itemId =
|
||||
let item = Armory.getItem itemId
|
||||
do! player
|
||||
|> checkSoldItemAlready item
|
||||
|> handleResultWithResponseFromEvent ctx (fun player -> async {
|
||||
|> handleResultWithResponse ctx (fun player -> async {
|
||||
let updatedPlayer = {
|
||||
player with
|
||||
Bank = player.Bank + item.Cost
|
||||
|
61
Bot/Thief.fs
61
Bot/Thief.fs
@ -7,6 +7,14 @@ open DSharpPlus.Entities
|
||||
open DSharpPlus.SlashCommands
|
||||
open Degenz.Messaging
|
||||
|
||||
[<Literal>]
|
||||
let StealActionId = 12
|
||||
[<Literal>]
|
||||
let VictimDefenseActionId = 12
|
||||
|
||||
let ThiefCooldown = TimeSpan.FromMinutes(1)
|
||||
let VictimRecovery = TimeSpan.FromHours(12)
|
||||
|
||||
type StealResult =
|
||||
| Success
|
||||
| WentToPrison
|
||||
@ -78,8 +86,38 @@ let getResultEmbed targetName result =
|
||||
.WithImageUrl(img)
|
||||
.WithTitle($"Robbery Results")
|
||||
|
||||
let checkVictimStealingCooldown defender attacker =
|
||||
defender
|
||||
|> Player.getDefenses
|
||||
|> Array.tryFind (fun act -> act.ActionId = VictimDefenseActionId)
|
||||
|> function
|
||||
| Some act ->
|
||||
let cooldown = VictimRecovery - (DateTime.UtcNow - act.Timestamp)
|
||||
let hours = if cooldown.Hours = 0 then "hour" else $"{cooldown.Hours} hours"
|
||||
Error $"{defender.Name} was robbed recently so they won't be going out for at least another {hours}."
|
||||
| None -> Ok attacker
|
||||
|
||||
// TODO: Look for ways to generalize checking for action cooldowns
|
||||
let checkThiefCooldown attacker =
|
||||
attacker
|
||||
|> Player.getAttacks
|
||||
|> Array.tryFind (fun act -> act.ActionId = StealActionId)
|
||||
|> function
|
||||
| Some act ->
|
||||
if ThiefCooldown > (DateTime.UtcNow - act.Timestamp) then
|
||||
let cooldown = ThiefCooldown - (DateTime.UtcNow - act.Timestamp)
|
||||
let minutes = if cooldown.Minutes = 0 then "minute" else $"{cooldown.Minutes} minutes"
|
||||
Error $"Whoa there you clepto, wait at least another {minutes} before you try stealing again."
|
||||
else
|
||||
Ok attacker
|
||||
| None -> Ok attacker
|
||||
|
||||
let steal target (ctx : IDiscordContext) =
|
||||
Game.executePlayerWithTargetAction target ctx (fun attacker defender -> async {
|
||||
Game.executePlayerActionWithTarget target ctx (fun attacker defender -> async {
|
||||
do! attacker
|
||||
|> checkVictimStealingCooldown defender
|
||||
>>= checkThiefCooldown
|
||||
|> handleResultWithResponse ctx (fun player -> async {
|
||||
let ``base`` = 0.5
|
||||
let winPercentage = double (attacker.Stats.Strength - defender.Stats.Strength) * 0.45 + ``base``
|
||||
let prize = payout (float defender.Bank) winPercentage
|
||||
@ -87,12 +125,13 @@ let steal target (ctx : IDiscordContext) =
|
||||
|
||||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||||
})
|
||||
})
|
||||
|
||||
let handleSteal (ctx : IDiscordContext) =
|
||||
let split = ctx.GetInteractionId().Split("-")
|
||||
let answer = split.[1]
|
||||
if answer = "yes" then
|
||||
Game.executePlayerAction ctx (fun player -> async {
|
||||
|
||||
let handleYes player = async {
|
||||
let targetId = uint64 split.[2]
|
||||
let targetName = split.[3]
|
||||
let chance = double split.[4]
|
||||
@ -109,9 +148,13 @@ let handleSteal (ctx : IDiscordContext) =
|
||||
embed.AddField("XP Gained", $"{xp}+") |> ignore
|
||||
do! Messaging.sendFollowUpEmbed ctx (embed.Build())
|
||||
match! DbService.tryFindPlayer targetId with
|
||||
| Some t -> do! DbService.updatePlayer { t with Bank = max (t.Bank - prize) 0<GBT> }
|
||||
| Some t ->
|
||||
let action = { ActionId = VictimDefenseActionId ; Type = Defense ; Timestamp = DateTime.UtcNow }
|
||||
do! DbService.updatePlayer { t with Bank = max (t.Bank - prize) 0<GBT> ; Actions = Array.append [| action |] t.Actions }
|
||||
| None -> ()
|
||||
do! DbService.updatePlayer { player with Bank = player.Bank + prize ; XP = player.XP + xp }
|
||||
let dp = { DiscordPlayer.Id = targetId ; DiscordPlayer.Name = targetName }
|
||||
let action = { ActionId = StealActionId ; Type = Attack { AttackResult.Result = true ; AttackResult.Target = dp } ; Timestamp = DateTime.UtcNow }
|
||||
do! DbService.updatePlayer { player with Bank = player.Bank + prize ; XP = player.XP + xp ; Actions = Array.append [| action |] player.Actions }
|
||||
| false , false ->
|
||||
let embed = getResultEmbed targetName TargetRanAway
|
||||
do! Messaging.sendFollowUpEmbed ctx (embed.Build())
|
||||
@ -121,6 +164,14 @@ let handleSteal (ctx : IDiscordContext) =
|
||||
do! Async.Sleep 5000
|
||||
let role = ctx.GetGuild().GetRole(GuildEnvironment.rolePrisoner)
|
||||
do! ctx.GetDiscordMember().GrantRoleAsync(role) |> Async.AwaitTask
|
||||
}
|
||||
if answer = "yes" then
|
||||
let targetId = uint64 split.[2]
|
||||
Game.executePlayerActionWithTargetId targetId ctx (fun attacker defender -> async {
|
||||
do! attacker
|
||||
|> checkVictimStealingCooldown defender
|
||||
>>= checkThiefCooldown
|
||||
|> handleResultWithResponse ctx handleYes
|
||||
})
|
||||
else
|
||||
async {
|
||||
|
@ -169,7 +169,8 @@ let handleAttack (ctx : IDiscordContext) =
|
||||
sb.AppendLine("To finish your training and collect the loot, type the `/arsenal` command **NOW**") |> ignore
|
||||
do! Async.Sleep 1000
|
||||
let updatedPlayer = {
|
||||
player with Bank = player.Bank + hackMoney + shieldMoney
|
||||
player with
|
||||
Bank = player.Bank + hackMoney + shieldMoney
|
||||
Actions = [
|
||||
{ Action.Timestamp = System.DateTime.UtcNow
|
||||
Action.Type =
|
||||
|
@ -228,8 +228,3 @@ module Messaging =
|
||||
| Ok p -> fn p
|
||||
| Error e -> async { do! sendFollowUpMessage ctx e }
|
||||
|
||||
let handleResultWithResponseFromEvent event fn (player : Result<PlayerData, string>) =
|
||||
match player with
|
||||
| Ok p -> fn p
|
||||
| Error e -> async { do! sendFollowUpMessage event e }
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user