From 6d7ee2ed16716d1cb8b053f8c26510d760311e88 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Tue, 22 Feb 2022 22:53:49 +0700 Subject: [PATCH] New player events model --- Bot/Embeds.fs | 17 ++++++----- Bot/Game.fs | 23 ++++++++------- Bot/HackerBattle.fs | 67 +++++++++++++++++++++++------------------- Bot/Store.fs | 5 +--- Bot/Thief.fs | 39 ++++++++++-------------- Bot/Trainer.fs | 18 +++++------- DbService/DbService.fs | 8 ++--- Shared/Shared.fs | 25 +++++++++------- 8 files changed, 101 insertions(+), 101 deletions(-) diff --git a/Bot/Embeds.fs b/Bot/Embeds.fs index 527d245..b01ccfa 100644 --- a/Bot/Embeds.fs +++ b/Bot/Embeds.fs @@ -39,15 +39,18 @@ let constructButtons (actionId: string) (buttonInfo : string) (player: PlayerDat |> Array.map (fun item -> let action = player.Events - |> Array.tryFind (fun i -> i.ItemId = item.Id) - let btnColor = itemType + |> Array.tryFind (fun i -> + match i.Type with + | Hacking h -> h.HackId = item.Id + | Shielding id -> id = item.Id + | _ -> false) + let btnColor = Game.getClassButtonColor item.Class match action , ignoreCooldown with | None , _ | Some _ , true -> - DiscordButtonComponent(Game.getClassButtonColor item.Class, $"{actionId}-{item.Id}-{buttonInfo}-{player.Name}", $"{item.Name}") - | Some act , false -> - let c = ((Armory.getItem act.ItemId).Cooldown) - let time = Messaging.getShortTimeText (TimeSpan.FromMinutes(int c)) act.Timestamp - DiscordButtonComponent(Game.getClassButtonColor item.Class, $"{actionId}-{item.Id}", $"{item.Name} ({time} left)", true)) + DiscordButtonComponent(btnColor, $"{actionId}-{item.Id}-{buttonInfo}-{player.Name}", $"{item.Name}") + | Some event , false -> + let time = Messaging.getShortTimeText (TimeSpan.FromMinutes(int event.Cooldown)) event.Timestamp + DiscordButtonComponent(btnColor, $"{actionId}-{item.Id}", $"{item.Name} ({time} left)", true)) |> Seq.cast let pickDefense actionId player isTrainer = diff --git a/Bot/Game.fs b/Bot/Game.fs index 8ca530b..18ea069 100644 --- a/Bot/Game.fs +++ b/Bot/Game.fs @@ -76,10 +76,10 @@ module 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) + |> 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 && act.ItemId < 12) + |> Array.filter (fun act -> match act.Type with PlayerEventType.Shielding _ -> true | _ -> false) let removeExpiredActions player = let actions = @@ -102,14 +102,17 @@ module Arsenal = | [||] -> "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}") + 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 = diff --git a/Bot/HackerBattle.fs b/Bot/HackerBattle.fs index 7eb4ea0..effeb9c 100644 --- a/Bot/HackerBattle.fs +++ b/Bot/HackerBattle.fs @@ -16,7 +16,10 @@ let checkPlayerIsAttackingThemselves defender attacker = let checkAlreadyHackedTarget defender attacker = defender.Events - |> Array.tryFind (fun event -> event.Adversary.Id = attacker.DiscordId && event.IsInstigator = false) + |> Array.tryFind (fun event -> + match event.Type with + | Hacking h -> h.Adversary.Id = attacker.DiscordId && h.IsInstigator = false + | _ -> false) |> function | Some event -> let cooldown = getTimeText true Game.SameTargetAttackCooldown event.Timestamp @@ -24,12 +27,16 @@ let checkAlreadyHackedTarget defender attacker = | None -> Ok attacker let checkWeaponHasCooldown (weapon : Item) attacker = - let cooldown = attacker.Events |> Array.tryFind (fun a -> a.ItemId = weapon.Id) - match cooldown with - | Some event -> - let cooldown = getTimeText true (TimeSpan.FromMinutes(int event.Cooldown)) event.Timestamp - Error $"{weapon.Name} is still active, it will expire in {cooldown}." - | None -> Ok attacker + attacker.Events + |> Array.tryPick (fun a -> + match a.Type with + | Hacking h -> if h.HackId = weapon.Id then Some ( h , a ) else None + | _ -> None) + |> function + | Some ( _ , event ) -> + let cooldown = getTimeText true (TimeSpan.FromMinutes(int event.Cooldown)) event.Timestamp + Error $"{weapon.Name} is still active, it will expire in {cooldown}." + | None -> Ok attacker let checkHasEmptyHacks attacker = match Player.getHacks attacker with @@ -59,28 +66,32 @@ let calculateDamage (hack : Item) (shield : Item) = let runHackerBattle defender hack = defender |> Player.removeExpiredActions - |> Player.getShieldEvents - |> Array.map (fun dfn -> Armory.battleItems |> Array.find (fun w -> w.Id = dfn.ItemId)) - |> Array.map (calculateDamage (hack)) + |> fun p -> p.Events + |> Array.choose (fun event -> + match event.Type with + | Shielding id -> Armory.battleItems |> Array.find (fun w -> w.Id = id) |> Some + | _ -> None) + |> Array.map (calculateDamage hack) |> Array.contains Weak let updateCombatants successfulHack (attacker : PlayerData) (defender : PlayerData) (hack : Item) prize = let updatePlayer amount attack p = { p with Events = Array.append [| attack |] p.Events ; Bank = max (p.Bank + amount) 0 } - let event isDefenderEvent = { - ItemId = hack.Id - Type = PlayerEventType.Hacking - Adversary = if isDefenderEvent then attacker.basicPlayer else defender.basicPlayer - Cooldown = if isDefenderEvent then Game.SameTargetAttackCooldown.Minutes * 1 else hack.Cooldown - Timestamp = DateTime.UtcNow - IsInstigator = not isDefenderEvent - Result = - match successfulHack , isDefenderEvent with - | true , true -> PlayerEventResult.Negative - | false , true -> PlayerEventResult.Positive - | true , false -> PlayerEventResult.Positive - | false , false -> PlayerEventResult.Negative - } + let event isDefenderEvent = + let hackEvent = { + HackId = hack.Id + Adversary = if isDefenderEvent then attacker.basicPlayer else defender.basicPlayer + IsInstigator = not isDefenderEvent + Result = + match successfulHack , isDefenderEvent with + | true , true -> PlayerEventResult.Negative + | false , true -> PlayerEventResult.Positive + | true , false -> PlayerEventResult.Positive + | false , false -> PlayerEventResult.Negative + } + { Type = Hacking hackEvent + Timestamp = DateTime.UtcNow + Cooldown = if isDefenderEvent then Game.SameTargetAttackCooldown.Minutes * 1 else hack.Cooldown } [ DbService.updatePlayer GuildEnvironment.pgDb <| updatePlayer prize (event false) attacker DbService.updatePlayer GuildEnvironment.pgDb <| updatePlayer -prize (event true) defender ] @@ -182,13 +193,9 @@ let handleDefense (ctx : IDiscordContext) = let embed = Embeds.responseCreatedShield shield do! ctx.FollowUp embed |> Async.AwaitTask let defense = { - ItemId = shieldId - Type = PlayerEventType.Shielding - Result = PlayerEventResult.Positive - Timestamp = DateTime.UtcNow + Type = Shielding shieldId Cooldown = shield.Cooldown - IsInstigator = true - Adversary = DiscordPlayer.empty + Timestamp = DateTime.UtcNow } do! DbService.updatePlayer GuildEnvironment.pgDb <| { p with Events = Array.append [| defense |] p.Events } |> Async.Ignore diff --git a/Bot/Store.fs b/Bot/Store.fs index 6449de9..7b7010b 100644 --- a/Bot/Store.fs +++ b/Bot/Store.fs @@ -68,10 +68,7 @@ let handleSell (ctx : IDiscordContext) itemId = player with Bank = player.Bank + item.Price Inventory = player.Inventory |> Array.filter (fun i -> i.Id <> itemId) - Events = - if item.Type = ItemType.Shield - then player.Events |> Array.filter (fun a -> a.ItemId <> itemId) - else player.Events + Events = player.Events |> Array.filter (fun e -> match e.Type with Shielding _ -> true | _ -> false) } do! DbService.updatePlayer GuildEnvironment.pgDb updatedPlayer |> Async.Ignore diff --git a/Bot/Thief.fs b/Bot/Thief.fs index 87018b7..665b3a1 100644 --- a/Bot/Thief.fs +++ b/Bot/Thief.fs @@ -66,11 +66,13 @@ let getResultEmbed chance prize (bank : int) thief (victim : DiscordPlayer) .WithDescription(msg) .WithImageUrl(img) +// TODO: See if we are going to keep this let checkVictimStealingCooldown defender attacker = defender |> Player.removeExpiredActions |> fun p -> p.Events - |> Array.tryFind (fun pe -> pe.Type = PlayerEventType.Steal && pe.Result = PlayerEventResult.Negative) + |> Array.tryFind (fun e -> + match e.Type with Stealing _ -> true | _ -> false) |> function | Some act -> let cooldown = VictimRecovery - (DateTime.UtcNow - act.Timestamp) @@ -82,7 +84,7 @@ let checkThiefCooldown attacker = attacker |> Player.removeExpiredActions |> fun p -> p.Events - |> Array.tryFind (fun pe -> pe.Type = PlayerEventType.Steal) + |> Array.tryFind (fun pe -> match pe.Type with Stealing _ -> true | _ -> false) |> function | Some act -> let cooldown = ThiefCooldown - (DateTime.UtcNow - act.Timestamp) @@ -104,8 +106,9 @@ let calculateWinPercentage amountRequested bank attackerStrength defenderStrengt let steal target amount (ctx : IDiscordContext) = Game.executePlayerActionWithTarget target ctx (fun thief victim -> async { do! - thief - |> checkVictimStealingCooldown victim +// thief +// |> checkVictimStealingCooldown victim + Ok thief |> handleResultWithResponse ctx (fun _ -> async { let cappedPrize , winPercentage , wasCapped = calculateWinPercentage amount (int victim.Bank) thief.Traits.Strength victim.Traits.Strength @@ -149,14 +152,10 @@ let handleSteal (ctx : IDiscordContext) = let num = rand.NextDouble() let dp = { DiscordPlayer.Id = targetId ; DiscordPlayer.Name = targetName } let stealAction result = { - ItemId = -1 - Type = PlayerEventType.Steal - Result = result - Adversary = dp - IsInstigator = true + Type = Stealing ( true , dp ) Cooldown = ThiefCooldown.Minutes * 1 Timestamp = DateTime.UtcNow - } + } let getResultEmbed' = getResultEmbed winPercentage prize thief.Bank thief dp // TODO: Send event to the hall of privacy // TODO: We need to check if the player is on cooldown @@ -167,12 +166,8 @@ let handleSteal (ctx : IDiscordContext) = match! DbService.tryFindPlayer GuildEnvironment.pgDb targetId with | Some t -> let mugged = { - ItemId = -1 - Type = PlayerEventType.Steal - Result = PlayerEventResult.Negative - Adversary = thief.basicPlayer + Type = Stealing ( false , thief.basicPlayer ) Timestamp = DateTime.UtcNow - IsInstigator = false Cooldown = VictimRecovery.Minutes * 1 } let actions = t |> Player.removeExpiredActions |> fun p -> Array.append [| mugged |] p.Events @@ -181,13 +176,9 @@ let handleSteal (ctx : IDiscordContext) = | None -> () let stole = { - ItemId = -1 - Type = PlayerEventType.Steal - Result = PlayerEventResult.Positive - Adversary = dp - Timestamp = DateTime.UtcNow - IsInstigator = true - Cooldown = ThiefCooldown.Minutes * 1 + Type = Stealing ( true , dp ) + Cooldown = ThiefCooldown.Minutes * 1 + Timestamp = DateTime.UtcNow } let actions = thief |> Player.removeExpiredActions |> fun p -> Array.append [| stole |] p.Events do! DbService.updatePlayer GuildEnvironment.pgDb { thief with Bank = thief.Bank + prize ; Events = actions } @@ -206,8 +197,8 @@ let handleSteal (ctx : IDiscordContext) = Game.executePlayerActionWithTargetId true targetId ctx (fun attacker defender -> async { do! attacker |> Player.removeExpiredActions - |> checkVictimStealingCooldown defender - >>= checkThiefCooldown +// |> checkVictimStealingCooldown defender + |> checkThiefCooldown |> handleResultWithResponse ctx (handleYes defender ) }) else diff --git a/Bot/Trainer.fs b/Bot/Trainer.fs index b45693a..5881691 100644 --- a/Bot/Trainer.fs +++ b/Bot/Trainer.fs @@ -15,19 +15,15 @@ let defaultShield = Armory.battleItems |> Array.find (fun i -> i.Id = int Shield let TrainerEvents = [| { Timestamp = System.DateTime.UtcNow - Adversary = Sensei - Type = PlayerEventType.Hacking - Result = PlayerEventResult.Positive - Cooldown = 5 - IsInstigator = true - ItemId = defaultHack.Id } + Cooldown = 2 + Type = Hacking { + Adversary = Sensei + Result = PlayerEventResult.Positive + IsInstigator = true + HackId = defaultHack.Id } } { Timestamp = System.DateTime.UtcNow - Adversary = DiscordPlayer.empty - Type = PlayerEventType.Shielding - Result = PlayerEventResult.Positive Cooldown = defaultShield.Cooldown - IsInstigator = true - ItemId = defaultShield.Id } + Type = Shielding defaultShield.Id } |] let sendInitialEmbed (client : DiscordClient) = diff --git a/DbService/DbService.fs b/DbService/DbService.fs index efe1cb9..f28eb9f 100644 --- a/DbService/DbService.fs +++ b/DbService/DbService.fs @@ -73,10 +73,10 @@ let updatePlayer connStr (player : PlayerData) = let addAchievement connStr (did : uint64) (achievement : string) = connStr |> Sql.connect - |> Sql.query ( - "WITH ach AS (INSERT INTO achievement (symbol) VALUES (@symbol) RETURNING id), - usr AS (SELECT id FROM \"user\" WHERE discord_id = @did) - INSERT INTO user_achievements_achievement (user_id, achievement_id) SELECT usr.id, ach.id FROM usr, ach") + |> Sql.query + ("WITH ach AS (INSERT INTO achievement (symbol) VALUES (@symbol) RETURNING id), + usr AS (SELECT id FROM \"user\" WHERE discord_id = @did) + INSERT INTO user_achievements_achievement (user_id, achievement_id) SELECT usr.id, ach.id FROM usr, ach") |> Sql.parameters [ ( "did" , Sql.string (string did) ) ; ( "achievement", Sql.string achievement ) ] |> Sql.executeNonQueryAsync diff --git a/Shared/Shared.fs b/Shared/Shared.fs index 99b004d..28fb11e 100644 --- a/Shared/Shared.fs +++ b/Shared/Shared.fs @@ -88,23 +88,26 @@ module Types = with static member empty = { Id = 0uL ; Name = "None" } type PlayerEventResult = - | Positive = 0 - | Neutral = 1 - | Negative = 2 + | Positive + | Neutral + | Negative + + type HackEvent = { + IsInstigator : bool + Adversary : DiscordPlayer + Result : PlayerEventResult + HackId : int + } type PlayerEventType = - | Hacking = 0 - | Shielding = 1 - | Steal = 2 - | Imprison = 3 + | Hacking of HackEvent + | Shielding of shieldId : int + | Stealing of instigator : bool * adversary : DiscordPlayer + | Imprison [] type PlayerEvent = { Type : PlayerEventType - Result : PlayerEventResult - IsInstigator : bool - Adversary : DiscordPlayer - ItemId : int Cooldown : int Timestamp : DateTime }