New player events model

This commit is contained in:
Joseph Ferano 2022-02-22 22:53:49 +07:00
parent 014862d642
commit 6d7ee2ed16
8 changed files with 101 additions and 101 deletions

View File

@ -39,15 +39,18 @@ let constructButtons (actionId: string) (buttonInfo : string) (player: PlayerDat
|> Array.map (fun item -> |> Array.map (fun item ->
let action = let action =
player.Events player.Events
|> Array.tryFind (fun i -> i.ItemId = item.Id) |> Array.tryFind (fun i ->
let btnColor = itemType 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 match action , ignoreCooldown with
| None , _ | Some _ , true -> | None , _ | Some _ , true ->
DiscordButtonComponent(Game.getClassButtonColor item.Class, $"{actionId}-{item.Id}-{buttonInfo}-{player.Name}", $"{item.Name}") DiscordButtonComponent(btnColor, $"{actionId}-{item.Id}-{buttonInfo}-{player.Name}", $"{item.Name}")
| Some act , false -> | Some event , false ->
let c = ((Armory.getItem act.ItemId).Cooldown) let time = Messaging.getShortTimeText (TimeSpan.FromMinutes(int event.Cooldown)) event.Timestamp
let time = Messaging.getShortTimeText (TimeSpan.FromMinutes(int c)) act.Timestamp DiscordButtonComponent(btnColor, $"{actionId}-{item.Id}", $"{item.Name} ({time} left)", true))
DiscordButtonComponent(Game.getClassButtonColor item.Class, $"{actionId}-{item.Id}", $"{item.Name} ({time} left)", true))
|> Seq.cast<DiscordComponent> |> Seq.cast<DiscordComponent>
let pickDefense actionId player isTrainer = let pickDefense actionId player isTrainer =

View File

@ -76,10 +76,10 @@ module Player =
let getShields (player : PlayerData) = getItems ItemType.Shield player let getShields (player : PlayerData) = getItems ItemType.Shield player
let getHackEvents player = let getHackEvents player =
player.Events 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 = let getShieldEvents player =
player.Events 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 removeExpiredActions player =
let actions = let actions =
@ -102,14 +102,17 @@ module Arsenal =
| [||] -> "None" | [||] -> "None"
| _ -> actions | _ -> actions
|> Array.map (fun act -> |> Array.map (fun act ->
let item = Armory.getItem act.ItemId
match act.Type with match act.Type with
| PlayerEventType.Hacking -> | Hacking h ->
let item = Armory.getItem h.HackId
let cooldown = Messaging.getTimeText false Game.SameTargetAttackCooldown act.Timestamp let cooldown = Messaging.getTimeText false Game.SameTargetAttackCooldown act.Timestamp
$"Hacked {act.Adversary.Name} with {item.Name} {cooldown} ago" $"Hacked {h.Adversary.Name} with {item.Name} {cooldown} ago"
| _ -> | Shielding id ->
let cooldown = Messaging.getTimeText true (System.TimeSpan.FromMinutes(int item.Cooldown)) act.Timestamp let item = Armory.getItem id
$"{item.Name} Shield active for {cooldown}") 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" |> String.concat "\n"
let statusFormat p = let statusFormat p =

View File

@ -16,7 +16,10 @@ let checkPlayerIsAttackingThemselves defender attacker =
let checkAlreadyHackedTarget defender attacker = let checkAlreadyHackedTarget defender attacker =
defender.Events 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 |> function
| Some event -> | Some event ->
let cooldown = getTimeText true Game.SameTargetAttackCooldown event.Timestamp let cooldown = getTimeText true Game.SameTargetAttackCooldown event.Timestamp
@ -24,9 +27,13 @@ let checkAlreadyHackedTarget defender attacker =
| None -> Ok attacker | None -> Ok attacker
let checkWeaponHasCooldown (weapon : Item) attacker = let checkWeaponHasCooldown (weapon : Item) attacker =
let cooldown = attacker.Events |> Array.tryFind (fun a -> a.ItemId = weapon.Id) attacker.Events
match cooldown with |> Array.tryPick (fun a ->
| Some event -> 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 let cooldown = getTimeText true (TimeSpan.FromMinutes(int event.Cooldown)) event.Timestamp
Error $"{weapon.Name} is still active, it will expire in {cooldown}." Error $"{weapon.Name} is still active, it will expire in {cooldown}."
| None -> Ok attacker | None -> Ok attacker
@ -59,20 +66,21 @@ let calculateDamage (hack : Item) (shield : Item) =
let runHackerBattle defender hack = let runHackerBattle defender hack =
defender defender
|> Player.removeExpiredActions |> Player.removeExpiredActions
|> Player.getShieldEvents |> fun p -> p.Events
|> Array.map (fun dfn -> Armory.battleItems |> Array.find (fun w -> w.Id = dfn.ItemId)) |> Array.choose (fun event ->
|> Array.map (calculateDamage (hack)) match event.Type with
| Shielding id -> Armory.battleItems |> Array.find (fun w -> w.Id = id) |> Some
| _ -> None)
|> Array.map (calculateDamage hack)
|> Array.contains Weak |> Array.contains Weak
let updateCombatants successfulHack (attacker : PlayerData) (defender : PlayerData) (hack : Item) prize = let updateCombatants successfulHack (attacker : PlayerData) (defender : PlayerData) (hack : Item) prize =
let updatePlayer amount attack p = let updatePlayer amount attack p =
{ p with Events = Array.append [| attack |] p.Events ; Bank = max (p.Bank + amount) 0<GBT> } { p with Events = Array.append [| attack |] p.Events ; Bank = max (p.Bank + amount) 0<GBT> }
let event isDefenderEvent = { let event isDefenderEvent =
ItemId = hack.Id let hackEvent = {
Type = PlayerEventType.Hacking HackId = hack.Id
Adversary = if isDefenderEvent then attacker.basicPlayer else defender.basicPlayer Adversary = if isDefenderEvent then attacker.basicPlayer else defender.basicPlayer
Cooldown = if isDefenderEvent then Game.SameTargetAttackCooldown.Minutes * 1<mins> else hack.Cooldown
Timestamp = DateTime.UtcNow
IsInstigator = not isDefenderEvent IsInstigator = not isDefenderEvent
Result = Result =
match successfulHack , isDefenderEvent with match successfulHack , isDefenderEvent with
@ -81,6 +89,9 @@ let updateCombatants successfulHack (attacker : PlayerData) (defender : PlayerDa
| true , false -> PlayerEventResult.Positive | true , false -> PlayerEventResult.Positive
| false , false -> PlayerEventResult.Negative | false , false -> PlayerEventResult.Negative
} }
{ Type = Hacking hackEvent
Timestamp = DateTime.UtcNow
Cooldown = if isDefenderEvent then Game.SameTargetAttackCooldown.Minutes * 1<mins> else hack.Cooldown }
[ DbService.updatePlayer GuildEnvironment.pgDb <| updatePlayer prize (event false) attacker [ DbService.updatePlayer GuildEnvironment.pgDb <| updatePlayer prize (event false) attacker
DbService.updatePlayer GuildEnvironment.pgDb <| updatePlayer -prize (event true) defender ] DbService.updatePlayer GuildEnvironment.pgDb <| updatePlayer -prize (event true) defender ]
@ -182,13 +193,9 @@ let handleDefense (ctx : IDiscordContext) =
let embed = Embeds.responseCreatedShield shield let embed = Embeds.responseCreatedShield shield
do! ctx.FollowUp embed |> Async.AwaitTask do! ctx.FollowUp embed |> Async.AwaitTask
let defense = { let defense = {
ItemId = shieldId Type = Shielding shieldId
Type = PlayerEventType.Shielding
Result = PlayerEventResult.Positive
Timestamp = DateTime.UtcNow
Cooldown = shield.Cooldown Cooldown = shield.Cooldown
IsInstigator = true Timestamp = DateTime.UtcNow
Adversary = DiscordPlayer.empty
} }
do! DbService.updatePlayer GuildEnvironment.pgDb <| { p with Events = Array.append [| defense |] p.Events } do! DbService.updatePlayer GuildEnvironment.pgDb <| { p with Events = Array.append [| defense |] p.Events }
|> Async.Ignore |> Async.Ignore

View File

@ -68,10 +68,7 @@ let handleSell (ctx : IDiscordContext) itemId =
player with player with
Bank = player.Bank + item.Price Bank = player.Bank + item.Price
Inventory = player.Inventory |> Array.filter (fun i -> i.Id <> itemId) Inventory = player.Inventory |> Array.filter (fun i -> i.Id <> itemId)
Events = Events = player.Events |> Array.filter (fun e -> match e.Type with Shielding _ -> true | _ -> false)
if item.Type = ItemType.Shield
then player.Events |> Array.filter (fun a -> a.ItemId <> itemId)
else player.Events
} }
do! DbService.updatePlayer GuildEnvironment.pgDb updatedPlayer do! DbService.updatePlayer GuildEnvironment.pgDb updatedPlayer
|> Async.Ignore |> Async.Ignore

View File

@ -66,11 +66,13 @@ let getResultEmbed chance prize (bank : int<GBT>) thief (victim : DiscordPlayer)
.WithDescription(msg) .WithDescription(msg)
.WithImageUrl(img) .WithImageUrl(img)
// TODO: See if we are going to keep this
let checkVictimStealingCooldown defender attacker = let checkVictimStealingCooldown defender attacker =
defender defender
|> Player.removeExpiredActions |> Player.removeExpiredActions
|> fun p -> p.Events |> 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 |> function
| Some act -> | Some act ->
let cooldown = VictimRecovery - (DateTime.UtcNow - act.Timestamp) let cooldown = VictimRecovery - (DateTime.UtcNow - act.Timestamp)
@ -82,7 +84,7 @@ let checkThiefCooldown attacker =
attacker attacker
|> Player.removeExpiredActions |> Player.removeExpiredActions
|> fun p -> p.Events |> fun p -> p.Events
|> Array.tryFind (fun pe -> pe.Type = PlayerEventType.Steal) |> Array.tryFind (fun pe -> match pe.Type with Stealing _ -> true | _ -> false)
|> function |> function
| Some act -> | Some act ->
let cooldown = ThiefCooldown - (DateTime.UtcNow - act.Timestamp) let cooldown = ThiefCooldown - (DateTime.UtcNow - act.Timestamp)
@ -104,8 +106,9 @@ let calculateWinPercentage amountRequested bank attackerStrength defenderStrengt
let steal target amount (ctx : IDiscordContext) = let steal target amount (ctx : IDiscordContext) =
Game.executePlayerActionWithTarget target ctx (fun thief victim -> async { do! Game.executePlayerActionWithTarget target ctx (fun thief victim -> async { do!
thief // thief
|> checkVictimStealingCooldown victim // |> checkVictimStealingCooldown victim
Ok thief
|> handleResultWithResponse ctx (fun _ -> async { |> handleResultWithResponse ctx (fun _ -> async {
let cappedPrize , winPercentage , wasCapped = let cappedPrize , winPercentage , wasCapped =
calculateWinPercentage amount (int victim.Bank) thief.Traits.Strength victim.Traits.Strength calculateWinPercentage amount (int victim.Bank) thief.Traits.Strength victim.Traits.Strength
@ -149,11 +152,7 @@ let handleSteal (ctx : IDiscordContext) =
let num = rand.NextDouble() let num = rand.NextDouble()
let dp = { DiscordPlayer.Id = targetId ; DiscordPlayer.Name = targetName } let dp = { DiscordPlayer.Id = targetId ; DiscordPlayer.Name = targetName }
let stealAction result = { let stealAction result = {
ItemId = -1 Type = Stealing ( true , dp )
Type = PlayerEventType.Steal
Result = result
Adversary = dp
IsInstigator = true
Cooldown = ThiefCooldown.Minutes * 1<mins> Cooldown = ThiefCooldown.Minutes * 1<mins>
Timestamp = DateTime.UtcNow Timestamp = DateTime.UtcNow
} }
@ -167,12 +166,8 @@ let handleSteal (ctx : IDiscordContext) =
match! DbService.tryFindPlayer GuildEnvironment.pgDb targetId with match! DbService.tryFindPlayer GuildEnvironment.pgDb targetId with
| Some t -> | Some t ->
let mugged = { let mugged = {
ItemId = -1 Type = Stealing ( false , thief.basicPlayer )
Type = PlayerEventType.Steal
Result = PlayerEventResult.Negative
Adversary = thief.basicPlayer
Timestamp = DateTime.UtcNow Timestamp = DateTime.UtcNow
IsInstigator = false
Cooldown = VictimRecovery.Minutes * 1<mins> Cooldown = VictimRecovery.Minutes * 1<mins>
} }
let actions = t |> Player.removeExpiredActions |> fun p -> Array.append [| mugged |] p.Events let actions = t |> Player.removeExpiredActions |> fun p -> Array.append [| mugged |] p.Events
@ -181,13 +176,9 @@ let handleSteal (ctx : IDiscordContext) =
| None -> () | None -> ()
let stole = { let stole = {
ItemId = -1 Type = Stealing ( true , dp )
Type = PlayerEventType.Steal
Result = PlayerEventResult.Positive
Adversary = dp
Timestamp = DateTime.UtcNow
IsInstigator = true
Cooldown = ThiefCooldown.Minutes * 1<mins> Cooldown = ThiefCooldown.Minutes * 1<mins>
Timestamp = DateTime.UtcNow
} }
let actions = thief |> Player.removeExpiredActions |> fun p -> Array.append [| stole |] p.Events 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 } 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 { Game.executePlayerActionWithTargetId true targetId ctx (fun attacker defender -> async {
do! attacker do! attacker
|> Player.removeExpiredActions |> Player.removeExpiredActions
|> checkVictimStealingCooldown defender // |> checkVictimStealingCooldown defender
>>= checkThiefCooldown |> checkThiefCooldown
|> handleResultWithResponse ctx (handleYes defender ) |> handleResultWithResponse ctx (handleYes defender )
}) })
else else

View File

@ -15,19 +15,15 @@ let defaultShield = Armory.battleItems |> Array.find (fun i -> i.Id = int Shield
let TrainerEvents = [| let TrainerEvents = [|
{ Timestamp = System.DateTime.UtcNow { Timestamp = System.DateTime.UtcNow
Cooldown = 2<mins>
Type = Hacking {
Adversary = Sensei Adversary = Sensei
Type = PlayerEventType.Hacking
Result = PlayerEventResult.Positive Result = PlayerEventResult.Positive
Cooldown = 5<mins>
IsInstigator = true IsInstigator = true
ItemId = defaultHack.Id } HackId = defaultHack.Id } }
{ Timestamp = System.DateTime.UtcNow { Timestamp = System.DateTime.UtcNow
Adversary = DiscordPlayer.empty
Type = PlayerEventType.Shielding
Result = PlayerEventResult.Positive
Cooldown = defaultShield.Cooldown Cooldown = defaultShield.Cooldown
IsInstigator = true Type = Shielding defaultShield.Id }
ItemId = defaultShield.Id }
|] |]
let sendInitialEmbed (client : DiscordClient) = let sendInitialEmbed (client : DiscordClient) =

View File

@ -73,8 +73,8 @@ let updatePlayer connStr (player : PlayerData) =
let addAchievement connStr (did : uint64) (achievement : string) = let addAchievement connStr (did : uint64) (achievement : string) =
connStr connStr
|> Sql.connect |> Sql.connect
|> Sql.query ( |> Sql.query
"WITH ach AS (INSERT INTO achievement (symbol) VALUES (@symbol) RETURNING id), ("WITH ach AS (INSERT INTO achievement (symbol) VALUES (@symbol) RETURNING id),
usr AS (SELECT id FROM \"user\" WHERE discord_id = @did) 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") INSERT INTO user_achievements_achievement (user_id, achievement_id) SELECT usr.id, ach.id FROM usr, ach")

View File

@ -88,23 +88,26 @@ module Types =
with static member empty = { Id = 0uL ; Name = "None" } with static member empty = { Id = 0uL ; Name = "None" }
type PlayerEventResult = type PlayerEventResult =
| Positive = 0 | Positive
| Neutral = 1 | Neutral
| Negative = 2 | Negative
type HackEvent = {
IsInstigator : bool
Adversary : DiscordPlayer
Result : PlayerEventResult
HackId : int
}
type PlayerEventType = type PlayerEventType =
| Hacking = 0 | Hacking of HackEvent
| Shielding = 1 | Shielding of shieldId : int
| Steal = 2 | Stealing of instigator : bool * adversary : DiscordPlayer
| Imprison = 3 | Imprison
[<CLIMutable>] [<CLIMutable>]
type PlayerEvent = type PlayerEvent =
{ Type : PlayerEventType { Type : PlayerEventType
Result : PlayerEventResult
IsInstigator : bool
Adversary : DiscordPlayer
ItemId : int
Cooldown : int<mins> Cooldown : int<mins>
Timestamp : DateTime } Timestamp : DateTime }