Steal embed improvements, bug fixes, more fields for Events
This commit is contained in:
parent
63e3853788
commit
f7391682fd
@ -44,7 +44,7 @@ let storeCommands = storeBot.UseSlashCommands()
|
|||||||
|
|
||||||
hackerCommands.RegisterCommands<HackerGame>(guild);
|
hackerCommands.RegisterCommands<HackerGame>(guild);
|
||||||
hackerCommands.RegisterCommands<StealGame>(guild);
|
hackerCommands.RegisterCommands<StealGame>(guild);
|
||||||
hackerCommands.RegisterCommands<RPSGame>(guild);
|
//hackerCommands.RegisterCommands<RPSGame>(guild);
|
||||||
storeCommands.RegisterCommands<Store>(guild);
|
storeCommands.RegisterCommands<Store>(guild);
|
||||||
//sc3.RegisterCommands<SlotMachine>(guild);
|
//sc3.RegisterCommands<SlotMachine>(guild);
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ let getArsenalEmbed (player : PlayerData) =
|
|||||||
DiscordEmbedBuilder()
|
DiscordEmbedBuilder()
|
||||||
.AddField( "Arsenal", Arsenal.statusFormat player ))
|
.AddField( "Arsenal", Arsenal.statusFormat player ))
|
||||||
|
|
||||||
let getAchievementEmbed description achievement =
|
let getAchievementEmbed rewards description achievement =
|
||||||
let embed = DiscordEmbedBuilder()
|
let embed = DiscordEmbedBuilder()
|
||||||
|
|
||||||
GuildEnvironment.botUserHackerBattle
|
GuildEnvironment.botUserHackerBattle
|
||||||
@ -176,12 +176,12 @@ let getAchievementEmbed description achievement =
|
|||||||
|
|
||||||
DiscordFollowupMessageBuilder()
|
DiscordFollowupMessageBuilder()
|
||||||
.AddEmbed(
|
.AddEmbed(
|
||||||
// TODO: We can add a Reward field but we'd need to keep track of what the player was awarded
|
|
||||||
embed.WithTitle("Achievement Unlocked!")
|
embed.WithTitle("Achievement Unlocked!")
|
||||||
.WithDescription(description)
|
.WithDescription(description)
|
||||||
.WithColor(DiscordColor.Gold)
|
.WithColor(DiscordColor.Gold)
|
||||||
// .AddField("Achievement", $"🏆 {achievement}")
|
// .AddField("Achievement", $"🏆 {achievement}")
|
||||||
.AddField("Achievement", $"{achievement}")
|
.AddField("Achievement", $"{achievement}", true)
|
||||||
|
.AddField("Rewards", rewards |> String.concat "\n", true)
|
||||||
// TODO: Once we add another achievement, fix this
|
// TODO: Once we add another achievement, fix this
|
||||||
.WithImageUrl("https://s10.gifyu.com/images/MasterTraining_Degenz.gif"))
|
.WithImageUrl("https://s10.gifyu.com/images/MasterTraining_Degenz.gif"))
|
||||||
.AsEphemeral(true)
|
.AsEphemeral(true)
|
20
Bot/Game.fs
20
Bot/Game.fs
@ -73,26 +73,12 @@ module 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 && act.ItemId < 12)
|
||||||
|
|
||||||
// TODO: This parameter is a result of putting the cooldown on the attack side. Put the cooldown on the defender
|
let removeExpiredActions player =
|
||||||
// side and only check if it's the same target, we need to refactor Actions
|
|
||||||
let removeExpiredActions filterByAttackCooldown player =
|
|
||||||
let actions =
|
let actions =
|
||||||
player.Events
|
player.Events
|
||||||
|> Array.filter (fun (act : PlayerEvent) ->
|
|> Array.filter (fun (act : PlayerEvent) ->
|
||||||
let itemCooldown =
|
let cooldown = System.TimeSpan.FromMinutes(int act.Cooldown)
|
||||||
if act.ItemId > 0 && act.ItemId < 12 then
|
System.DateTime.UtcNow - act.Timestamp < cooldown)
|
||||||
(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 }
|
{ player with Events = actions }
|
||||||
|
|
||||||
let modifyBank (player : PlayerData) amount = { player with Bank = max (player.Bank + amount) 0<GBT> }
|
let modifyBank (player : PlayerData) amount = { player with Bank = max (player.Bank + amount) 0<GBT> }
|
||||||
|
@ -14,37 +14,30 @@ let checkPlayerIsAttackingThemselves defender attacker =
|
|||||||
| true -> Error "You think you're clever? You can't hack yourself, pal."
|
| true -> Error "You think you're clever? You can't hack yourself, pal."
|
||||||
| false -> Ok attacker
|
| false -> Ok attacker
|
||||||
|
|
||||||
let checkAlreadyHackedTarget defenderId attacker =
|
let checkAlreadyHackedTarget defender attacker =
|
||||||
attacker.Events
|
defender.Events
|
||||||
|> Array.tryFind (fun pe -> pe.Adversary.Id = defenderId)
|
|> Array.tryFind (fun event -> event.Adversary.Id = attacker.DiscordId && event.IsInstigator = false)
|
||||||
|> function
|
|> function
|
||||||
| Some event ->
|
| Some event ->
|
||||||
let cooldown = getTimeText true Game.SameTargetAttackCooldown event.Timestamp
|
let cooldown = getTimeText true Game.SameTargetAttackCooldown event.Timestamp
|
||||||
Error $"You can only hack the same target once every {Game.SameTargetAttackCooldown.Hours} hours, wait {cooldown} to attempt another hack on {event.Adversary.Name}."
|
Error $"You can only hack the same target once every {Game.SameTargetAttackCooldown.Hours} hours, wait {cooldown} to attempt another hack on <@{defender.DiscordId}>."
|
||||||
| None -> Ok attacker
|
| None -> Ok attacker
|
||||||
|
|
||||||
let checkItemHasCooldown itemId attacker =
|
let checkWeaponHasCooldown (weapon : Item) attacker =
|
||||||
let cooldown =
|
let cooldown = attacker.Events |> Array.tryFind (fun a -> a.ItemId = weapon.Id)
|
||||||
attacker.Events
|
match cooldown with
|
||||||
|> Array.tryFind (fun a -> a.ItemId = itemId)
|
| Some event ->
|
||||||
|> function
|
let cooldown = getTimeText true (TimeSpan.FromMinutes(int event.Cooldown)) event.Timestamp
|
||||||
| Some a -> a.Timestamp
|
Error $"{weapon.Name} is still active, it will expire in {cooldown}."
|
||||||
| None -> DateTime.MinValue
|
| None -> Ok attacker
|
||||||
let item = Armory.getItem itemId
|
|
||||||
if DateTime.UtcNow - cooldown > TimeSpan.FromMinutes(int item.Cooldown) then
|
|
||||||
Ok attacker
|
|
||||||
else
|
|
||||||
let cooldown = getTimeText true (TimeSpan.FromMinutes(int item.Cooldown)) cooldown
|
|
||||||
let item = Armory.battleItems |> Array.find (fun i -> i.Id = itemId)
|
|
||||||
Error $"{item.Name} is currently on cooldown, wait {cooldown} to use it again."
|
|
||||||
|
|
||||||
let checkHasEmptyHacks attacker =
|
let checkHasEmptyHacks attacker =
|
||||||
match Player.getHacks attacker with
|
match Player.getHacks attacker with
|
||||||
| [||] -> Error $"You currently do not have any Hacks to steal 💰$GBT from others. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one."
|
| [||] -> Error $"You currently do not have any Hacks to steal 💰$GBT from others. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one."
|
||||||
| _ -> Ok attacker
|
| _ -> Ok attacker
|
||||||
|
|
||||||
let checkPlayerOwnsWeapon itemId player =
|
let checkPlayerOwnsWeapon (item : Item) player =
|
||||||
match player.Inventory |> Array.exists (fun i -> i.Id = itemId) with
|
match player.Inventory |> Array.exists (fun i -> i.Id = item.Id) with
|
||||||
| true -> Ok player
|
| true -> Ok player
|
||||||
| false -> Error $"You sold your weapon already, you cheeky bastard..."
|
| false -> Error $"You sold your weapon already, you cheeky bastard..."
|
||||||
|
|
||||||
@ -53,8 +46,8 @@ let checkTargetHasMoney (target : PlayerData) attacker =
|
|||||||
then Error $"{target.Name} does not have enough 💰$GBT to steal from, the broke loser. Pick a different target."
|
then Error $"{target.Name} does not have enough 💰$GBT to steal from, the broke loser. Pick a different target."
|
||||||
else Ok attacker
|
else Ok attacker
|
||||||
|
|
||||||
let checkPlayerHasShieldSlotsAvailable shield player =
|
let checkPlayerHasShieldSlotsAvailable (shield : Item) player =
|
||||||
let updatedPlayer = player |> Player.removeExpiredActions false
|
let updatedPlayer = player |> Player.removeExpiredActions
|
||||||
let defenses = Player.getShieldEvents updatedPlayer
|
let defenses = Player.getShieldEvents updatedPlayer
|
||||||
match defenses |> Array.length >= 2 with
|
match defenses |> Array.length >= 2 with
|
||||||
| true ->
|
| true ->
|
||||||
@ -71,37 +64,40 @@ let calculateDamage (hack : Item) (shield : Item) =
|
|||||||
|
|
||||||
let runHackerBattle defender hack =
|
let runHackerBattle defender hack =
|
||||||
defender
|
defender
|
||||||
|> Player.removeExpiredActions false
|
|> Player.removeExpiredActions
|
||||||
|> Player.getShieldEvents
|
|> Player.getShieldEvents
|
||||||
|> Array.map (fun dfn -> Armory.battleItems |> Array.find (fun w -> w.Id = dfn.ItemId))
|
|> Array.map (fun dfn -> Armory.battleItems |> Array.find (fun w -> w.Id = dfn.ItemId))
|
||||||
|> Array.map (calculateDamage (hack))
|
|> Array.map (calculateDamage (hack))
|
||||||
|> Array.contains Weak
|
|> Array.contains Weak
|
||||||
|
|
||||||
let updateCombatants attacker defender hack 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 target = { Id = defender.DiscordId ; Name = defender.Name }
|
let event isDefenderEvent = {
|
||||||
let attack = {
|
ItemId = hack.Id
|
||||||
ItemId = int hack
|
|
||||||
Type = PlayerEventType.Hacking
|
Type = PlayerEventType.Hacking
|
||||||
Adversary = target
|
Adversary = if isDefenderEvent then attacker.basicPlayer else defender.basicPlayer
|
||||||
Result = if prize > 0<GBT> then PlayerEventResult.Positive else PlayerEventResult.Negative
|
Cooldown = if isDefenderEvent then Game.SameTargetAttackCooldown.Minutes * 1<mins> else hack.Cooldown
|
||||||
Timestamp = DateTime.UtcNow
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This is what I was talking about, this isn't a "Shield" event, this is a hack event but there's an adversary
|
[ DbService.updatePlayer <| updatePlayer prize (event false) attacker
|
||||||
// who loses, so the event itself is to just "hack", so there's no "mugged" event, there's just a failed steal defense
|
DbService.updatePlayer <| updatePlayer -prize (event true) defender ]
|
||||||
// or something like that.
|
|
||||||
[ DbService.updatePlayer <| updatePlayer prize attack attacker
|
|
||||||
DbService.updatePlayer <| Player.modifyBank defender -prize ]
|
|
||||||
|> Async.Parallel
|
|> Async.Parallel
|
||||||
|> Async.Ignore
|
|> Async.Ignore
|
||||||
|
|
||||||
let successfulHack (ctx : IDiscordContext) attacker defender hack =
|
let successfulHack (ctx : IDiscordContext) attacker defender hack =
|
||||||
async {
|
async {
|
||||||
do! updateCombatants attacker defender hack Game.HackPrize
|
do! updateCombatants true attacker defender hack Game.HackPrize
|
||||||
|
|
||||||
let embed = Embeds.responseSuccessfulHack true defender.DiscordId (Armory.getItem hack)
|
let embed = Embeds.responseSuccessfulHack true defender.DiscordId hack
|
||||||
do! ctx.FollowUp embed |> Async.AwaitTask
|
do! ctx.FollowUp embed |> Async.AwaitTask
|
||||||
|
|
||||||
let builder = Embeds.eventSuccessfulHack ctx defender Game.HackPrize
|
let builder = Embeds.eventSuccessfulHack ctx defender Game.HackPrize
|
||||||
@ -116,7 +112,7 @@ let failedHack (ctx : IDiscordContext) attacker defender hack =
|
|||||||
let msg = $"Hack failed! {defender.Name} was able to mount a successful defense! You lost {Game.ShieldPrize} $GBT!"
|
let msg = $"Hack failed! {defender.Name} was able to mount a successful defense! You lost {Game.ShieldPrize} $GBT!"
|
||||||
do! sendFollowUpMessage ctx msg
|
do! sendFollowUpMessage ctx msg
|
||||||
|
|
||||||
do! updateCombatants attacker defender hack -Game.ShieldPrize
|
do! updateCombatants false attacker defender hack -Game.ShieldPrize
|
||||||
|
|
||||||
let builder = DiscordMessageBuilder()
|
let builder = DiscordMessageBuilder()
|
||||||
builder.WithContent($"Hacking attempt failed! <@{defender.DiscordId}> defended hack from {ctx.GetDiscordMember().Username} and stole {Game.ShieldPrize} $GBT from them! ") |> ignore
|
builder.WithContent($"Hacking attempt failed! <@{defender.DiscordId}> defended hack from {ctx.GetDiscordMember().Username} and stole {Game.ShieldPrize} $GBT from them! ") |> ignore
|
||||||
@ -129,8 +125,8 @@ let failedHack (ctx : IDiscordContext) attacker defender hack =
|
|||||||
let attack (target : DiscordUser) (ctx : IDiscordContext) =
|
let attack (target : DiscordUser) (ctx : IDiscordContext) =
|
||||||
Game.executePlayerActionWithTarget target ctx (fun attacker defender -> async {
|
Game.executePlayerActionWithTarget target ctx (fun attacker defender -> async {
|
||||||
do! attacker
|
do! attacker
|
||||||
|> checkAlreadyHackedTarget defender.DiscordId
|
|> checkAlreadyHackedTarget defender
|
||||||
<!> (Player.removeExpiredActions true)
|
<!> Player.removeExpiredActions
|
||||||
>>= checkHasEmptyHacks
|
>>= checkHasEmptyHacks
|
||||||
>>= checkTargetHasMoney defender
|
>>= checkTargetHasMoney defender
|
||||||
>>= checkPlayerIsAttackingThemselves defender
|
>>= checkPlayerIsAttackingThemselves defender
|
||||||
@ -145,23 +141,23 @@ let handleAttack (ctx : IDiscordContext) =
|
|||||||
Game.executePlayerAction ctx (fun attacker -> async {
|
Game.executePlayerAction ctx (fun attacker -> async {
|
||||||
let split = ctx.GetInteractionId().Split("-")
|
let split = ctx.GetInteractionId().Split("-")
|
||||||
let hackId = int split.[1]
|
let hackId = int split.[1]
|
||||||
let hack = enum<HackId>(hackId)
|
let hack = Armory.getItem hackId
|
||||||
let ( resultId , targetId ) = UInt64.TryParse split.[2]
|
let resultId , targetId = UInt64.TryParse split.[2]
|
||||||
let! resultTarget = DbService.tryFindPlayer targetId
|
let! resultTarget = DbService.tryFindPlayer targetId
|
||||||
|
|
||||||
match resultTarget , true , resultId with
|
match resultTarget , true , resultId with
|
||||||
| Some defender , true , true ->
|
| Some defender , true , true ->
|
||||||
do! attacker
|
do! attacker
|
||||||
|> Player.removeExpiredActions false
|
|> Player.removeExpiredActions
|
||||||
|> checkAlreadyHackedTarget defender.DiscordId
|
|> checkAlreadyHackedTarget defender
|
||||||
>>= checkPlayerOwnsWeapon hackId
|
>>= checkPlayerOwnsWeapon hack
|
||||||
>>= checkItemHasCooldown hackId
|
>>= checkWeaponHasCooldown hack
|
||||||
|> function
|
|> function
|
||||||
| Ok atkr ->
|
| Ok atkr ->
|
||||||
runHackerBattle defender (Armory.getItem (int hackId))
|
runHackerBattle defender hack
|
||||||
|> function
|
|> function
|
||||||
| false -> successfulHack ctx atkr defender hackId
|
| false -> successfulHack ctx atkr defender hack
|
||||||
| true -> failedHack ctx attacker defender hackId
|
| true -> failedHack ctx attacker defender hack
|
||||||
| Error msg -> Messaging.sendFollowUpMessage ctx msg
|
| Error msg -> Messaging.sendFollowUpMessage ctx msg
|
||||||
| _ -> do! Messaging.sendFollowUpMessage ctx "Error occurred processing attack"
|
| _ -> do! Messaging.sendFollowUpMessage ctx "Error occurred processing attack"
|
||||||
})
|
})
|
||||||
@ -169,7 +165,7 @@ let handleAttack (ctx : IDiscordContext) =
|
|||||||
let defend (ctx : IDiscordContext) =
|
let defend (ctx : IDiscordContext) =
|
||||||
Game.executePlayerAction ctx (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
if Player.getShields player |> Array.length > 0 then
|
if Player.getShields player |> Array.length > 0 then
|
||||||
let p = Player.removeExpiredActions false player
|
let p = Player.removeExpiredActions player
|
||||||
let embed = Embeds.pickDefense "Defend" p false
|
let embed = Embeds.pickDefense "Defend" p false
|
||||||
do! ctx.FollowUp embed |> Async.AwaitTask
|
do! ctx.FollowUp embed |> Async.AwaitTask
|
||||||
else
|
else
|
||||||
@ -184,20 +180,22 @@ let handleDefense (ctx : IDiscordContext) =
|
|||||||
let shield = Armory.getItem shieldId
|
let shield = Armory.getItem shieldId
|
||||||
|
|
||||||
do! player
|
do! player
|
||||||
|> checkPlayerOwnsWeapon shieldId
|
|> checkPlayerOwnsWeapon shield
|
||||||
>>= checkPlayerHasShieldSlotsAvailable shield
|
>>= checkPlayerHasShieldSlotsAvailable shield
|
||||||
>>= checkItemHasCooldown shieldId
|
>>= checkWeaponHasCooldown shield
|
||||||
|> handleResultWithResponse ctx (fun _ -> async { // Don't use this player, it removes player cooldowns
|
|> handleResultWithResponse ctx (fun p -> async {
|
||||||
let embed = Embeds.responseCreatedShield (Armory.getItem shieldId)
|
let embed = Embeds.responseCreatedShield shield
|
||||||
do! ctx.FollowUp embed |> Async.AwaitTask
|
do! ctx.FollowUp embed |> Async.AwaitTask
|
||||||
let defense = {
|
let defense = {
|
||||||
ItemId = shieldId
|
ItemId = shieldId
|
||||||
Type = PlayerEventType.Shielding
|
Type = PlayerEventType.Shielding
|
||||||
Result = PlayerEventResult.Positive
|
Result = PlayerEventResult.Positive
|
||||||
Timestamp = DateTime.UtcNow
|
Timestamp = DateTime.UtcNow
|
||||||
|
Cooldown = shield.Cooldown
|
||||||
|
IsInstigator = true
|
||||||
Adversary = DiscordPlayer.empty
|
Adversary = DiscordPlayer.empty
|
||||||
}
|
}
|
||||||
do! DbService.updatePlayer <| { player with Events = Array.append [| defense |] player.Events }
|
do! DbService.updatePlayer <| { p with Events = Array.append [| defense |] p.Events }
|
||||||
let builder = DiscordMessageBuilder()
|
let builder = DiscordMessageBuilder()
|
||||||
builder.WithContent($"{ctx.GetDiscordMember().Username} has protected their system!") |> ignore
|
builder.WithContent($"{ctx.GetDiscordMember().Username} has protected their system!") |> ignore
|
||||||
let channel = ctx.GetGuild().GetChannel(GuildEnvironment.channelEventsHackerBattle)
|
let channel = ctx.GetGuild().GetChannel(GuildEnvironment.channelEventsHackerBattle)
|
||||||
@ -209,7 +207,7 @@ let handleDefense (ctx : IDiscordContext) =
|
|||||||
|
|
||||||
let arsenal (ctx : IDiscordContext) =
|
let arsenal (ctx : IDiscordContext) =
|
||||||
Game.executePlayerAction ctx (fun player -> async {
|
Game.executePlayerAction ctx (fun player -> async {
|
||||||
let updatedPlayer = Player.removeExpiredActions false player
|
let updatedPlayer = Player.removeExpiredActions player
|
||||||
let builder = DiscordFollowupMessageBuilder()
|
let builder = DiscordFollowupMessageBuilder()
|
||||||
let embed = DiscordEmbedBuilder()
|
let embed = DiscordEmbedBuilder()
|
||||||
embed.AddField("Arsenal", Arsenal.statusFormat updatedPlayer) |> ignore
|
embed.AddField("Arsenal", Arsenal.statusFormat updatedPlayer) |> ignore
|
||||||
|
54
Bot/Thief.fs
54
Bot/Thief.fs
@ -92,8 +92,8 @@ let getResultEmbed chance prize (bank : int<GBT>) thief (victim : DiscordPlayer)
|
|||||||
|
|
||||||
let checkVictimStealingCooldown defender attacker =
|
let checkVictimStealingCooldown defender attacker =
|
||||||
defender
|
defender
|
||||||
|> Player.removeExpiredActions false
|
|> Player.removeExpiredActions
|
||||||
|> Player.getShieldEvents
|
|> fun p -> p.Events
|
||||||
|> Array.tryFind (fun pe -> pe.Type = PlayerEventType.Steal && pe.Result = PlayerEventResult.Negative)
|
|> Array.tryFind (fun pe -> pe.Type = PlayerEventType.Steal && pe.Result = PlayerEventResult.Negative)
|
||||||
|> function
|
|> function
|
||||||
| Some act ->
|
| Some act ->
|
||||||
@ -102,19 +102,16 @@ let checkVictimStealingCooldown defender attacker =
|
|||||||
Error $"{defender.Name} was robbed recently so they won't be going out for at least another {hours}."
|
Error $"{defender.Name} was robbed recently so they won't be going out for at least another {hours}."
|
||||||
| None -> Ok attacker
|
| None -> Ok attacker
|
||||||
|
|
||||||
// TODO: Look for ways to generalize checking for action cooldowns
|
|
||||||
let checkThiefCooldown attacker =
|
let checkThiefCooldown attacker =
|
||||||
attacker
|
attacker
|
||||||
|> Player.getHackEvents
|
|> Player.removeExpiredActions
|
||||||
|
|> fun p -> p.Events
|
||||||
|> Array.tryFind (fun pe -> pe.Type = PlayerEventType.Steal)
|
|> Array.tryFind (fun pe -> pe.Type = PlayerEventType.Steal)
|
||||||
|> function
|
|> function
|
||||||
| Some act ->
|
| Some act ->
|
||||||
if ThiefCooldown > (DateTime.UtcNow - act.Timestamp) then
|
let cooldown = ThiefCooldown - (DateTime.UtcNow - act.Timestamp)
|
||||||
let cooldown = ThiefCooldown - (DateTime.UtcNow - act.Timestamp)
|
let minutes = if cooldown.Minutes = 0 then "minute" else $"{cooldown.Minutes} minutes"
|
||||||
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."
|
||||||
Error $"Whoa there you clepto, wait at least another {minutes} before you try stealing again."
|
|
||||||
else
|
|
||||||
Ok attacker
|
|
||||||
| None -> Ok attacker
|
| None -> Ok attacker
|
||||||
|
|
||||||
|
|
||||||
@ -157,7 +154,15 @@ let handleSteal (ctx : IDiscordContext) =
|
|||||||
let num = rand.NextDouble()
|
let num = rand.NextDouble()
|
||||||
let result = winPercentage >= num , rand.Next(0,3) = 0
|
let result = winPercentage >= num , rand.Next(0,3) = 0
|
||||||
let dp = { DiscordPlayer.Id = targetId ; DiscordPlayer.Name = targetName }
|
let dp = { DiscordPlayer.Id = targetId ; DiscordPlayer.Name = targetName }
|
||||||
let stealAction result = { ItemId = -1 ; Type = PlayerEventType.Steal ; Result = result ; Adversary = dp ; Timestamp = DateTime.UtcNow }
|
let stealAction result = {
|
||||||
|
ItemId = -1
|
||||||
|
Type = PlayerEventType.Steal
|
||||||
|
Result = result
|
||||||
|
Adversary = dp
|
||||||
|
IsInstigator = true
|
||||||
|
Cooldown = ThiefCooldown.Minutes * 1<mins>
|
||||||
|
Timestamp = DateTime.UtcNow
|
||||||
|
}
|
||||||
let getResultEmbed' = getResultEmbed winPercentage prize thief.Bank thief dp
|
let getResultEmbed' = getResultEmbed winPercentage prize thief.Bank thief dp
|
||||||
// TODO: Send event to the hall of privacy
|
// TODO: Send event to the hall of privacy
|
||||||
// TODO: We need to check if the player is on cooldown
|
// TODO: We need to check if the player is on cooldown
|
||||||
@ -169,12 +174,29 @@ let handleSteal (ctx : IDiscordContext) =
|
|||||||
do! Messaging.sendFollowUpEmbed ctx (embed.Build())
|
do! Messaging.sendFollowUpEmbed ctx (embed.Build())
|
||||||
match! DbService.tryFindPlayer targetId with
|
match! DbService.tryFindPlayer targetId with
|
||||||
| Some t ->
|
| Some t ->
|
||||||
let mugged = { ItemId = -1 ; Type = PlayerEventType.Steal ; Result = PlayerEventResult.Negative ; Adversary = thief.basicPlayer ; Timestamp = DateTime.UtcNow }
|
let mugged = {
|
||||||
let actions = t |> Player.removeExpiredActions false |> fun p -> Array.append [| mugged |] p.Events
|
ItemId = -1
|
||||||
|
Type = PlayerEventType.Steal
|
||||||
|
Result = PlayerEventResult.Negative
|
||||||
|
Adversary = thief.basicPlayer
|
||||||
|
Timestamp = DateTime.UtcNow
|
||||||
|
IsInstigator = false
|
||||||
|
Cooldown = VictimRecovery.Minutes * 1<mins>
|
||||||
|
}
|
||||||
|
let actions = t |> Player.removeExpiredActions |> fun p -> Array.append [| mugged |] p.Events
|
||||||
do! DbService.updatePlayer { t with Bank = max (t.Bank - prize) 0<GBT> ; Events = actions }
|
do! DbService.updatePlayer { t with Bank = max (t.Bank - prize) 0<GBT> ; Events = actions }
|
||||||
| None -> ()
|
| None -> ()
|
||||||
let stole = { ItemId = -1 ; Type = PlayerEventType.Steal ; Result = PlayerEventResult.Positive ; Adversary = dp ; Timestamp = DateTime.UtcNow }
|
|
||||||
let actions = thief |> Player.removeExpiredActions false |> fun p -> Array.append [| stole |] p.Events
|
let stole = {
|
||||||
|
ItemId = -1
|
||||||
|
Type = PlayerEventType.Steal
|
||||||
|
Result = PlayerEventResult.Positive
|
||||||
|
Adversary = dp
|
||||||
|
Timestamp = DateTime.UtcNow
|
||||||
|
IsInstigator = true
|
||||||
|
Cooldown = ThiefCooldown.Minutes * 1<mins>
|
||||||
|
}
|
||||||
|
let actions = thief |> Player.removeExpiredActions |> fun p -> Array.append [| stole |] p.Events
|
||||||
do! DbService.updatePlayer { thief with Bank = thief.Bank + prize ; XP = thief.XP + 0 ; Events = actions }
|
do! DbService.updatePlayer { thief with Bank = thief.Bank + prize ; XP = thief.XP + 0 ; Events = actions }
|
||||||
// do! Async.Sleep 2000
|
// do! Async.Sleep 2000
|
||||||
// do! ctx.FollowUp (XP.getRewardsEmbed 1 player) |> Async.AwaitTask
|
// do! ctx.FollowUp (XP.getRewardsEmbed 1 player) |> Async.AwaitTask
|
||||||
@ -194,7 +216,7 @@ let handleSteal (ctx : IDiscordContext) =
|
|||||||
let targetId = uint64 split.[2]
|
let targetId = uint64 split.[2]
|
||||||
Game.executePlayerActionWithTargetId true targetId ctx (fun attacker defender -> async {
|
Game.executePlayerActionWithTargetId true targetId ctx (fun attacker defender -> async {
|
||||||
do! attacker
|
do! attacker
|
||||||
|> Player.removeExpiredActions false
|
|> Player.removeExpiredActions
|
||||||
|> checkVictimStealingCooldown defender
|
|> checkVictimStealingCooldown defender
|
||||||
>>= checkThiefCooldown
|
>>= checkThiefCooldown
|
||||||
|> handleResultWithResponse ctx (handleYes defender )
|
|> handleResultWithResponse ctx (handleYes defender )
|
||||||
|
@ -13,16 +13,20 @@ let defaultHack = Armory.battleItems |> Array.find (fun i -> i.Id = int HackId.V
|
|||||||
let defaultShield = Armory.battleItems |> Array.find (fun i -> i.Id = int ShieldId.Firewall)
|
let defaultShield = Armory.battleItems |> Array.find (fun i -> i.Id = int ShieldId.Firewall)
|
||||||
|
|
||||||
let TrainerEvents = [|
|
let TrainerEvents = [|
|
||||||
{ PlayerEvent.Timestamp = System.DateTime.UtcNow
|
{ Timestamp = System.DateTime.UtcNow
|
||||||
PlayerEvent.Adversary = Sensei
|
Adversary = Sensei
|
||||||
PlayerEvent.Type = PlayerEventType.Hacking
|
Type = PlayerEventType.Hacking
|
||||||
PlayerEvent.Result = PlayerEventResult.Positive
|
Result = PlayerEventResult.Positive
|
||||||
PlayerEvent.ItemId = defaultHack.Id }
|
Cooldown = 5<mins>
|
||||||
{ PlayerEvent.Timestamp = System.DateTime.UtcNow
|
IsInstigator = true
|
||||||
PlayerEvent.Adversary = DiscordPlayer.empty
|
ItemId = defaultHack.Id }
|
||||||
PlayerEvent.Type = PlayerEventType.Shielding
|
{ Timestamp = System.DateTime.UtcNow
|
||||||
PlayerEvent.Result = PlayerEventResult.Positive
|
Adversary = DiscordPlayer.empty
|
||||||
PlayerEvent.ItemId = defaultShield.Id }
|
Type = PlayerEventType.Shielding
|
||||||
|
Result = PlayerEventResult.Positive
|
||||||
|
Cooldown = defaultShield.Cooldown
|
||||||
|
IsInstigator = true
|
||||||
|
ItemId = defaultShield.Id }
|
||||||
|]
|
|]
|
||||||
|
|
||||||
let sendInitialEmbed (client : DiscordClient) =
|
let sendInitialEmbed (client : DiscordClient) =
|
||||||
@ -156,19 +160,20 @@ let handleArsenal (ctx : IDiscordContext) =
|
|||||||
let hasStockWeapons = Player.getHacks player |> Array.exists (fun item -> item.Id = defaultHack.Id)
|
let hasStockWeapons = Player.getHacks player |> Array.exists (fun item -> item.Id = defaultHack.Id)
|
||||||
let updatedPlayer =
|
let updatedPlayer =
|
||||||
if not hasStockWeapons then {
|
if not hasStockWeapons then {
|
||||||
Player.removeExpiredActions false player with
|
Player.removeExpiredActions player with
|
||||||
Events = TrainerEvents |> Array.append player.Events
|
Events = TrainerEvents |> Array.append player.Events
|
||||||
Inventory = [| defaultHack ; defaultShield |] |> Array.append player.Inventory
|
Inventory = [| defaultHack ; defaultShield |] |> Array.append player.Inventory
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Player.removeExpiredActions false player
|
Player.removeExpiredActions player
|
||||||
if not hasStockWeapons then
|
if not hasStockWeapons then
|
||||||
do! DbService.updatePlayer updatedPlayer
|
do! DbService.updatePlayer updatedPlayer
|
||||||
let embed = Embeds.getArsenalEmbed updatedPlayer
|
let embed = Embeds.getArsenalEmbed updatedPlayer
|
||||||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||||||
if not (player.Achievements |> Array.contains trainerAchievement) then
|
if not (player.Achievements |> Array.contains trainerAchievement) then
|
||||||
do! Async.Sleep 3000
|
do! Async.Sleep 3000
|
||||||
let embed = Embeds.getAchievementEmbed "You completed the Training Dojo and collected loot." trainerAchievement
|
let rewards = [ $"{defaultHack.Name} Hack" ; $"{defaultShield.Name} Shield" ]
|
||||||
|
let embed = Embeds.getAchievementEmbed rewards "You completed the Training Dojo and collected loot." trainerAchievement
|
||||||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||||||
do! Async.Sleep 2000
|
do! Async.Sleep 2000
|
||||||
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee)
|
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee)
|
||||||
|
@ -59,7 +59,6 @@ module Types =
|
|||||||
}
|
}
|
||||||
with static member empty = { Sell = false ; Buy = false ; Consume = false ; Drop = false }
|
with static member empty = { Sell = false ; Buy = false ; Consume = false ; Drop = false }
|
||||||
|
|
||||||
|
|
||||||
type Item = {
|
type Item = {
|
||||||
Id : int
|
Id : int
|
||||||
Name : string
|
Name : string
|
||||||
@ -101,8 +100,10 @@ module Types =
|
|||||||
type PlayerEvent =
|
type PlayerEvent =
|
||||||
{ Type : PlayerEventType
|
{ Type : PlayerEventType
|
||||||
Result : PlayerEventResult
|
Result : PlayerEventResult
|
||||||
|
IsInstigator : bool
|
||||||
Adversary : DiscordPlayer
|
Adversary : DiscordPlayer
|
||||||
ItemId : int
|
ItemId : int
|
||||||
|
Cooldown : int<mins>
|
||||||
Timestamp : DateTime }
|
Timestamp : DateTime }
|
||||||
|
|
||||||
[<CLIMutable>]
|
[<CLIMutable>]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user