Fixed bug with defending and small changes to gameplay

This commit is contained in:
Joseph Ferano 2022-01-16 02:46:42 +07:00
parent 162f6af03f
commit 5ab49e674e
3 changed files with 58 additions and 58 deletions

View File

@ -23,7 +23,7 @@ let attack (ctx : InteractionContext) (target : DiscordUser) =
| Some attacker , Some defender -> | Some attacker , Some defender ->
let updatedAttacks = let updatedAttacks =
attacker.Attacks attacker.Attacks
|> removeExpiredActions (TimeSpan.FromMinutes(5)) (fun (atk : Attack) -> atk.Timestamp) |> removeExpiredActions (TimeSpan.FromMinutes(15)) (fun (atk : Attack) -> atk.Timestamp)
do! DbService.updateAttacks attacker.DiscordId updatedAttacks do! DbService.updateAttacks attacker.DiscordId updatedAttacks
if updatedAttacks.Length < 2 then if updatedAttacks.Length < 2 then
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
@ -61,11 +61,11 @@ let defend (ctx : InteractionContext) =
let! player = DbService.tryFindPlayer ctx.Member.Id let! player = DbService.tryFindPlayer ctx.Member.Id
match player with match player with
| Some player -> | Some player ->
let updatedDefenses = removeExpiredActions (TimeSpan.FromMinutes(60)) (fun (pro : Defense) -> pro.Timestamp) player.Defenses let updatedDefenses = removeExpiredActions (TimeSpan.FromHours(24)) (fun (pro : Defense) -> pro.Timestamp) player.Defenses
do! DbService.updatePlayer <| { player with Defenses = updatedDefenses } do! DbService.updatePlayer <| { player with Defenses = updatedDefenses }
if updatedDefenses.Length < 2 then if updatedDefenses.Length < 3 then
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
builder.AddEmbed (constructEmbed "Pick a defense to mount for a duration of time") |> ignore builder.AddEmbed (constructEmbed "Pick a defense to mount for 24 hours") |> ignore
constructButtons "Defend" (string player.DiscordId) player.Shields constructButtons "Defend" (string player.DiscordId) player.Shields
|> Seq.cast<DiscordComponent> |> Seq.cast<DiscordComponent>
@ -80,7 +80,8 @@ let defend (ctx : InteractionContext) =
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
let timestamp = updatedDefenses |> Array.rev |> Array.head |> fun a -> a.Timestamp // This should be the next expiring timestamp let timestamp = updatedDefenses |> Array.rev |> Array.head |> fun a -> a.Timestamp // This should be the next expiring timestamp
let timeRemaining = TimeSpan.FromMinutes(15) - (DateTime.UtcNow - timestamp) let timeRemaining = TimeSpan.FromMinutes(15) - (DateTime.UtcNow - timestamp)
builder.Content <- $"Cannot add new defense, please wait {timeRemaining.Minutes} minutes and {timeRemaining.Seconds} seconds to add another defense" // TODO: Make this handle hours and minutes
builder.Content <- $"Cannot add new defense, please wait {timeRemaining.Hours} hours and {timeRemaining.Minutes} minutes to add another defense"
builder.AsEphemeral true |> ignore builder.AsEphemeral true |> ignore
@ -101,43 +102,46 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
let! resultTarget = DbService.tryFindPlayer targetId let! resultTarget = DbService.tryFindPlayer targetId
match resultPlayer , resultTarget , resultHack , resultId with match resultPlayer , resultTarget , resultHack , resultId with
| Some player , Some target , true , true -> | Some player , Some target , true , true ->
let updatedDefenses = removeExpiredActions (TimeSpan.FromHours(24)) (fun (p : Defense) -> p.Timestamp) target.Defenses
do! DbService.updatePlayer <| { player with Defenses = updatedDefenses }
let wasSuccessfulHack = let wasSuccessfulHack =
target.Defenses updatedDefenses
|> Seq.toArray |> Seq.toArray
|> Array.map (fun dfn -> int dfn.DefenseType) |> Array.map (fun dfn -> int dfn.DefenseType)
|> Array.map (calculateDamage weapon) |> Array.map (calculateDamage weapon)
|> Array.contains Weak |> Array.contains Weak
match wasSuccessfulHack with match wasSuccessfulHack with
| false -> | false ->
let prize = 0.1726f let prize = 1.337f // LEET
let attack = { HackType = enum<Weapon>(weapon) ; Timestamp = DateTime.UtcNow ; Target = { Id = targetId ; Name = split.[3] } } let attack = { HackType = enum<Weapon>(weapon) ; Timestamp = DateTime.UtcNow ; Target = { Id = targetId ; Name = split.[3] } }
do! DbService.updatePlayer <| updatePlayer prize attack player do! DbService.updatePlayer <| updatePlayer prize attack player
do! DbService.updatePlayer { target with Bank = MathF.Max(target.Bank - prize, 0f)}
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
builder.IsEphemeral <- true builder.IsEphemeral <- true
builder.Content <- $"Successfully hacked {split.[3]} using {weapon}! You just won {prize} genz!" builder.Content <- $"Successfully hacked {split.[3]} using {weapon}! You just won {prize} GoodBoyTokenz!"
do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder) do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
|> Async.AwaitTask |> Async.AwaitTask
let builder = DiscordMessageBuilder() let builder = DiscordMessageBuilder()
builder.WithContent($"{event.User.Username} successfully hacked <@{targetId}>!") |> ignore builder.WithContent($"{event.User.Username} successfully hacked <@{targetId}> for a total of {prize} GoodBoyTokenz") |> ignore
let channel = (event.Guild.GetChannel(battleChannel)) let channel = (event.Guild.GetChannel(battleChannel))
do! channel.SendMessageAsync(builder) do! channel.SendMessageAsync(builder)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore |> Async.Ignore
| true -> | true ->
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
let loss = -0.0623f let prize = 0.0623f
builder.IsEphemeral <- true builder.IsEphemeral <- true
builder.Content <- $"Hack failed! {split.[3]} was able to mount a successful defense! You lost {loss} genz!" builder.Content <- $"Hack failed! {split.[3]} was able to mount a successful defense! You lost {prize} GoodBoyTokenz!"
do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder) do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
|> Async.AwaitTask |> Async.AwaitTask
let attack = { HackType = enum<Weapon>(weapon) ; Timestamp = DateTime.UtcNow ; Target = { Id = targetId ; Name = split.[3] } } let attack = { HackType = enum<Weapon>(weapon) ; Timestamp = DateTime.UtcNow ; Target = { Id = targetId ; Name = split.[3] } }
do! DbService.updatePlayer <| updatePlayer loss attack player do! DbService.updatePlayer <| updatePlayer -prize attack player
let builder = DiscordMessageBuilder() let builder = DiscordMessageBuilder()
builder.WithContent($"{event.User.Username} failed to hack <@{targetId}>!") |> ignore builder.WithContent($"Hacking attempt failed! <@{targetId}> defended hack from {event.User} and took {prize} from them! ") |> ignore
let channel = (event.Guild.GetChannel(battleChannel)) let channel = (event.Guild.GetChannel(battleChannel))
do! channel.SendMessageAsync(builder) do! channel.SendMessageAsync(builder)
|> Async.AwaitTask |> Async.AwaitTask

View File

@ -94,6 +94,9 @@ module Commands =
let! player = DbService.tryFindPlayer ctx.Member.Id let! player = DbService.tryFindPlayer ctx.Member.Id
match player with match player with
| Some p -> | Some p ->
let updatedAttacks = p.Attacks |> removeExpiredActions (TimeSpan.FromMinutes(15)) (fun (atk : Attack) -> atk.Timestamp)
let updatedDefenses = p.Defenses |> removeExpiredActions (TimeSpan.FromHours(24)) (fun (p : Defense) -> p.Timestamp)
do! DbService.updatePlayer <| { p with Attacks = updatedAttacks ; Defenses = updatedDefenses }
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
builder.IsEphemeral <- true builder.IsEphemeral <- true
builder.Content <- statusFormat p builder.Content <- statusFormat p

View File

@ -26,55 +26,56 @@ type Shield =
| Sanitation = 5 | Sanitation = 5
| Cypher = 3 | Cypher = 3
let getClass = function let getClass =
| 0 | 1 -> Network function
| 2 | 3 -> Exploit | 0
| 4 | _ -> Penetration | 1 -> Network
| 2
| 3 -> Exploit
| 4
| _ -> Penetration
type HackResult = type HackResult =
| Strong | Strong
| Weak | Weak
[<CLIMutable>] [<CLIMutable>]
type DiscordPlayer = { type DiscordPlayer = { Id: uint64; Name: string }
Id : uint64
Name : string
}
[<CLIMutable>] [<CLIMutable>]
type Attack = { type Attack =
HackType : Weapon { HackType: Weapon
Target : DiscordPlayer Target: DiscordPlayer
Timestamp : DateTime Timestamp: DateTime }
}
[<CLIMutable>] [<CLIMutable>]
type Defense = { type Defense =
DefenseType : Shield { DefenseType: Shield
Timestamp : DateTime Timestamp: DateTime }
}
[<CLIMutable>] [<CLIMutable>]
type Player = { type Player =
DiscordId : uint64 { DiscordId: uint64
Name : string Name: string
Weapons : Weapon array Weapons: Weapon array
Shields : Shield array Shields: Shield array
Attacks : Attack array Attacks: Attack array
Defenses : Defense array Defenses: Defense array
Bank : single Bank: single }
}
let createSimpleResponseAsync msg (ctx : InteractionContext) = let createSimpleResponseAsync msg (ctx: InteractionContext) =
async { async {
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
builder.Content <- msg builder.Content <- msg
builder.AsEphemeral true |> ignore builder.AsEphemeral true |> ignore
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
do!
ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask |> Async.AwaitTask
} }
let notYetAHackerMsg = createSimpleResponseAsync "You are not currently a hacker, first use the /redpill command to become one" let notYetAHackerMsg =
createSimpleResponseAsync "You are not currently a hacker, first use the /redpill command to become one"
let hackDescription = "" let hackDescription = ""
@ -85,20 +86,12 @@ Active Hacks: {player.Attacks |> Array.toList}
Active Defenses: {player.Defenses |> Array.toList} Active Defenses: {player.Defenses |> Array.toList}
Bank: {player.Bank}" Bank: {player.Bank}"
let constructButtons (actionType : string) (playerInfo : string) (weapons : 'a array) = let constructButtons (actionType: string) (playerInfo: string) (weapons: 'a array) =
weapons weapons
|> Seq.map (fun hack -> |> Seq.map (fun hack -> DiscordButtonComponent(ButtonStyle.Primary, $"{actionType}-{hack}-{playerInfo}", $"{hack}"))
DiscordButtonComponent(
ButtonStyle.Primary,
$"{actionType}-{hack}-{playerInfo}",
$"{hack}"))
let removeExpiredActions timespan (timestamp : 'a -> DateTime) actions = let removeExpiredActions timespan (timestamp: 'a -> DateTime) actions =
actions actions |> Array.filter (fun act -> DateTime.UtcNow - (timestamp act) < timespan)
|> Array.filter (fun act ->
if DateTime.UtcNow - (timestamp act) < timespan
then true
else false)
let constructEmbed message = let constructEmbed message =
let builder = DiscordEmbedBuilder() let builder = DiscordEmbedBuilder()
@ -111,10 +104,10 @@ let constructEmbed message =
builder.Author <- author builder.Author <- author
builder.Build() builder.Build()
let calculateDamage (hack : int) (shield : int) = let calculateDamage (hack: int) (shield: int) =
let hackClass = getClass hack let hackClass = getClass hack
let protectionClass = getClass shield let protectionClass = getClass shield
match hackClass , protectionClass with
| h , p when h = p -> Weak
| _ -> Strong
match hackClass, protectionClass with
| h, p when h = p -> Weak
| _ -> Strong