Fixes to Trainer copy, Check if defender has money, bring back status (arsenal)
This commit is contained in:
parent
e772a6d6f3
commit
ad613064a8
@ -9,14 +9,7 @@ open DSharpPlus.SlashCommands
|
|||||||
open Degenz
|
open Degenz
|
||||||
open Degenz.Messaging
|
open Degenz.Messaging
|
||||||
|
|
||||||
let getTimeTillCooldownFinishes (timespan : TimeSpan) timestamp =
|
let (>>=) x f = Result.bind f x
|
||||||
let timeRemaining = timespan - (DateTime.UtcNow - timestamp)
|
|
||||||
if timeRemaining.Hours > 0 then
|
|
||||||
$"{timeRemaining.Hours} hours"
|
|
||||||
elif timeRemaining.Minutes > 0 then
|
|
||||||
$"{timeRemaining.Minutes} minutes"
|
|
||||||
else
|
|
||||||
$"{timeRemaining.Seconds} seconds"
|
|
||||||
|
|
||||||
let checkIfPlayerIsAttackingThemselves defender attacker =
|
let checkIfPlayerIsAttackingThemselves defender attacker =
|
||||||
match attacker.DiscordId = defender.DiscordId with
|
match attacker.DiscordId = defender.DiscordId with
|
||||||
@ -30,10 +23,9 @@ let checkForExistingHack defenderId attacker =
|
|||||||
|> Array.tryFind (fun (_,t,_) -> t.Id = defenderId)
|
|> Array.tryFind (fun (_,t,_) -> t.Id = defenderId)
|
||||||
|> function
|
|> function
|
||||||
| Some ( atk , target , _ ) ->
|
| Some ( atk , target , _ ) ->
|
||||||
let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromHours(24)) atk.Timestamp
|
let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromHours(2)) atk.Timestamp
|
||||||
Error $"You can only hack the same target once every 24 hours, wait {cooldown} to attempt another hack on {target.Name}."
|
Error $"You can only hack the same target once every 2 hours, wait {cooldown} to attempt another hack on {target.Name}."
|
||||||
| None ->
|
| None -> Ok attacker
|
||||||
Ok attacker
|
|
||||||
|
|
||||||
let checkIfHackHasCooldown hackId attacker =
|
let checkIfHackHasCooldown hackId attacker =
|
||||||
let mostRecentHackAttack =
|
let mostRecentHackAttack =
|
||||||
@ -54,6 +46,11 @@ let checkIfInventoryIsEmpty attacker =
|
|||||||
| [||] -> 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 checkIfTargetHasMoney (target : PlayerData) attacker =
|
||||||
|
if target.Bank < Game.HackPrize
|
||||||
|
then Error $"{target.Name} does not have enough 💰$GBT to steal from, the broke loser. Pick a different target."
|
||||||
|
else Ok attacker
|
||||||
|
|
||||||
let calculateDamage (hack : BattleItem) (shield : BattleItem) =
|
let calculateDamage (hack : BattleItem) (shield : BattleItem) =
|
||||||
if hack.Class = shield.Class
|
if hack.Class = shield.Class
|
||||||
then Strong
|
then Strong
|
||||||
@ -115,21 +112,21 @@ let attack (ctx : InteractionContext) (target : DiscordUser) =
|
|||||||
let! defender = DbService.tryFindPlayer target.Id
|
let! defender = DbService.tryFindPlayer target.Id
|
||||||
match defender with
|
match defender with
|
||||||
| Some defender ->
|
| Some defender ->
|
||||||
let hackAttempt =
|
do! checkForExistingHack defender.DiscordId attacker
|
||||||
checkForExistingHack defender.DiscordId attacker
|
>>= checkIfInventoryIsEmpty
|
||||||
|> Result.bind checkIfInventoryIsEmpty
|
>>= (checkIfTargetHasMoney defender)
|
||||||
|> Result.bind (checkIfPlayerIsAttackingThemselves defender)
|
>>= (checkIfPlayerIsAttackingThemselves defender)
|
||||||
match hackAttempt with
|
|> function
|
||||||
| Ok _ ->
|
| Ok _ ->
|
||||||
let embed = Embeds.pickHack "Attack" attacker defender
|
let embed = Embeds.pickHack "Attack" attacker defender
|
||||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed)
|
ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed)
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
| Error msg ->
|
| Error msg ->
|
||||||
let builder =
|
let builder =
|
||||||
DiscordInteractionResponseBuilder()
|
DiscordInteractionResponseBuilder()
|
||||||
.WithContent(msg)
|
.WithContent(msg)
|
||||||
.AsEphemeral(true)
|
.AsEphemeral(true)
|
||||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
| None -> do! sendSimpleResponse ctx "Your target is not connected to the network, they must join first by using the /redpill command"
|
| None -> do! sendSimpleResponse ctx "Your target is not connected to the network, they must join first by using the /redpill command"
|
||||||
})
|
})
|
||||||
@ -260,7 +257,7 @@ type HackerGame() =
|
|||||||
else
|
else
|
||||||
attack ctx target
|
attack ctx target
|
||||||
|
|
||||||
[<SlashCommand("shield", "Create a passive defense that will last 24 hours")>]
|
[<SlashCommand("shield", "Create a passive shield that will protect you for a certain time")>]
|
||||||
member this.ShieldCommand (ctx : InteractionContext) =
|
member this.ShieldCommand (ctx : InteractionContext) =
|
||||||
if ctx.Channel.Id = GuildEnvironment.channelTraining then
|
if ctx.Channel.Id = GuildEnvironment.channelTraining then
|
||||||
Trainer.defend ctx
|
Trainer.defend ctx
|
||||||
|
@ -71,27 +71,12 @@ module Commands =
|
|||||||
// } |> Async.StartAsTask
|
// } |> Async.StartAsTask
|
||||||
// :> Task
|
// :> Task
|
||||||
|
|
||||||
let status (ctx : InteractionContext) =
|
|
||||||
Game.executePlayerInteraction ctx (fun player -> async {
|
|
||||||
let updatedActions = Player.removeExpiredActions player.Actions
|
|
||||||
let updatedPlayer = { player with Actions = updatedActions }
|
|
||||||
let builder = DiscordInteractionResponseBuilder()
|
|
||||||
builder.IsEphemeral <- true
|
|
||||||
builder.Content <- Messaging.statusFormat updatedPlayer
|
|
||||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
|
||||||
|> Async.AwaitTask
|
|
||||||
do! DbService.updatePlayer updatedPlayer
|
|
||||||
})
|
|
||||||
|
|
||||||
type PlayerInteractions() =
|
type PlayerInteractions() =
|
||||||
inherit ApplicationCommandModule ()
|
inherit ApplicationCommandModule ()
|
||||||
|
|
||||||
[<SlashCommand("redpill", "Take the redpill and become a hacker")>]
|
[<SlashCommand("redpill", "Take the redpill and become a hacker")>]
|
||||||
member _.AddHackerRole (ctx : InteractionContext) = Commands.addHackerRole ctx
|
member _.AddHackerRole (ctx : InteractionContext) = Commands.addHackerRole ctx
|
||||||
|
|
||||||
[<SlashCommand("status", "Get your current status like bank account, and active hacks and defenses")>]
|
|
||||||
member this.Status (ctx : InteractionContext) = Commands.status ctx
|
|
||||||
|
|
||||||
// [<SlashCommand("leaderboard", "View the current list of players ranked by highest earnings")>]
|
// [<SlashCommand("leaderboard", "View the current list of players ranked by highest earnings")>]
|
||||||
// member this.Leaderboard (ctx : InteractionContext) = Commands.leaderboard ctx
|
// member this.Leaderboard (ctx : InteractionContext) = Commands.leaderboard ctx
|
||||||
|
|
||||||
|
17
Bot/Store.fs
17
Bot/Store.fs
@ -94,12 +94,29 @@ let handleSellButtonEvents (_ : DiscordClient) (event : ComponentInteractionCrea
|
|||||||
} |> Async.StartAsTask
|
} |> Async.StartAsTask
|
||||||
:> Task
|
:> Task
|
||||||
|
|
||||||
|
let status (ctx : InteractionContext) =
|
||||||
|
Game.executePlayerInteraction ctx (fun player -> async {
|
||||||
|
let updatedActions = Player.removeExpiredActions player.Actions
|
||||||
|
let updatedPlayer = { player with Actions = updatedActions }
|
||||||
|
let builder = DiscordInteractionResponseBuilder()
|
||||||
|
let embed = DiscordEmbedBuilder()
|
||||||
|
embed.AddField("Arsenal", Messaging.statusFormat updatedPlayer) |> ignore
|
||||||
|
builder.AddEmbed(embed) |> ignore
|
||||||
|
builder.IsEphemeral <- true
|
||||||
|
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||||
|
|> Async.AwaitTask
|
||||||
|
do! DbService.updatePlayer updatedPlayer
|
||||||
|
})
|
||||||
|
|
||||||
type Store() =
|
type Store() =
|
||||||
inherit ApplicationCommandModule ()
|
inherit ApplicationCommandModule ()
|
||||||
// [<SlashCommand("view-store", "View items available for purchase")>]
|
// [<SlashCommand("view-store", "View items available for purchase")>]
|
||||||
|
|
||||||
// member _.ViewStore (ctx : InteractionContext) = viewStore ctx
|
// member _.ViewStore (ctx : InteractionContext) = viewStore ctx
|
||||||
|
|
||||||
|
[<SlashCommand("arsenal", "Get the Hacks and Shields you own, and which ones are active")>]
|
||||||
|
member this.Arsenal (ctx : InteractionContext) = status ctx
|
||||||
|
|
||||||
[<SlashCommand("buy-hack", "Purchase a hack attack you can use to earn GoodBoyTokenz")>]
|
[<SlashCommand("buy-hack", "Purchase a hack attack you can use to earn GoodBoyTokenz")>]
|
||||||
member _.BuyHack (ctx : InteractionContext) = buyItem ctx Hack
|
member _.BuyHack (ctx : InteractionContext) = buyItem ctx Hack
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
module Degenz.Trainer
|
module Degenz.Trainer
|
||||||
|
|
||||||
open System.Threading.Tasks
|
|
||||||
open DSharpPlus
|
open DSharpPlus
|
||||||
|
open System.Threading.Tasks
|
||||||
open DSharpPlus.Entities
|
open DSharpPlus.Entities
|
||||||
open DSharpPlus.EventArgs
|
open DSharpPlus.EventArgs
|
||||||
open DSharpPlus.SlashCommands
|
open DSharpPlus.SlashCommands
|
||||||
@ -39,7 +39,7 @@ let handleTrainerStep1 (event : ComponentInteractionCreateEventArgs) =
|
|||||||
|
|
||||||
do! sendInteractionEvent event
|
do! sendInteractionEvent event
|
||||||
("Beautopia© is a dangerous place...\n"
|
("Beautopia© is a dangerous place...\n"
|
||||||
+ "Quick, put up a DEFENSE 🛡 before another Degen hacks you, and steals your 💰$GBT.\n"
|
+ "Quick, put up a SHIELD 🛡 before another Degen hacks you, and steals your 💰$GBT.\n"
|
||||||
+ shieldMessage
|
+ shieldMessage
|
||||||
+ "To enable it, you need to run the `/shield` slash command.\n\n"
|
+ "To enable it, you need to run the `/shield` slash command.\n\n"
|
||||||
+ $"Type the `/shield` command now, then select - `{weaponName}`\n")
|
+ $"Type the `/shield` command now, then select - `{weaponName}`\n")
|
||||||
@ -60,7 +60,7 @@ let defend (ctx : InteractionContext) =
|
|||||||
let handleDefenseMsg = {
|
let handleDefenseMsg = {
|
||||||
ButtonId = "Trainer-3"
|
ButtonId = "Trainer-3"
|
||||||
ButtonText = "Got it"
|
ButtonText = "Got it"
|
||||||
Message = "🎉 Congratulations 🎉\n\n"
|
Message = "🎉 Congratulations\n\n"
|
||||||
+ "You successfully defended my hack!\n\n"
|
+ "You successfully defended my hack!\n\n"
|
||||||
+ "Because I tried hacking you when you had your defense up, you stole money from me...\n"
|
+ "Because I tried hacking you when you had your defense up, you stole money from me...\n"
|
||||||
+ "Defenses only protect you for a LIMITED TIME, so remember to keep at least 1 defense up at all times, or risk getting hacked!"
|
+ "Defenses only protect you for a LIMITED TIME, so remember to keep at least 1 defense up at all times, or risk getting hacked!"
|
||||||
@ -77,7 +77,7 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
|
|||||||
do! Async.Sleep 2000
|
do! Async.Sleep 2000
|
||||||
do! sendMessage' "Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now"
|
do! sendMessage' "Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now"
|
||||||
do! Async.Sleep 4000
|
do! Async.Sleep 4000
|
||||||
do! sendMessage' $"❌ HACKING FAILED! ❌\n\n{player.Name} defended the hack from <@{GuildEnvironment.botHackerBattle}>, and stole 💰$GBT {Game.ShieldPrize} from them!"
|
do! sendMessage' $"❌ HACKING FAILED!\n\n{player.Name} defended the hack from <@{GuildEnvironment.botHackerBattle}>, and stole 💰$GBT {Game.ShieldPrize} from them!"
|
||||||
do! Async.Sleep 3000
|
do! Async.Sleep 3000
|
||||||
do! sendFollowUpMessageWithButton event handleDefenseMsg
|
do! sendFollowUpMessageWithButton event handleDefenseMsg
|
||||||
})
|
})
|
||||||
@ -133,15 +133,17 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
|
|||||||
let embed = Embeds.responseSuccessfulHackTrainer hack
|
let embed = Embeds.responseSuccessfulHackTrainer hack
|
||||||
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
|
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
|
||||||
do! Async.Sleep 3000
|
do! Async.Sleep 3000
|
||||||
do! sendMessage' ("🎉 **Congratulations** 🎉\n\n"
|
do! sendMessage'
|
||||||
|
("🎉 **Congratulations**\n\n"
|
||||||
+ "You successfully **HACKED** me, and are now an **Elite Haxor!**\n\n"
|
+ "You successfully **HACKED** me, and are now an **Elite Haxor!**\n\n"
|
||||||
+ "When you **HACK** other Degenz, you **STEAL** their 💰**$GBT.**\n"
|
+ "When you **HACK** other Degenz, you **STEAL** their 💰$GBT.\n"
|
||||||
+ "But remember, hacks take time to recover, so use them wisely.")
|
+ "But remember, hacks take time to recover, so use them wisely.")
|
||||||
do! Async.Sleep 7000
|
do! Async.Sleep 7000
|
||||||
do! sendFollowUpMessage event ("Your training is **complete!**\n\n"
|
do! sendFollowUpMessage event
|
||||||
+ "But, you’re going to need more **HACKS & DEFENSES** 🛡 to survive in **Beautopia©...**\n"
|
("Your training is **complete!**\n\n"
|
||||||
+ $"You can purchase them from <@{GuildEnvironment.botArmory}>, at <#{GuildEnvironment.channelArmory}> anytime you want...\n\n"
|
+ "But, you’re going to need more **HACKS & SHIELDS** 🛡 to survive in **Beautopia©...**\n"
|
||||||
+ "Go there **NOW** to buy **HACKS** & **SHIELDS** before you get hacked! 😱")
|
+ $"You can purchase them from <@{GuildEnvironment.botArmory}> anytime you want...\n\n"
|
||||||
|
+ $"Go to the <#{GuildEnvironment.channelArmory}> **NOW** and type the `/buy-shield` slash command! 😱")
|
||||||
})
|
})
|
||||||
|
|
||||||
let handleButtonEvent (event : ComponentInteractionCreateEventArgs) =
|
let handleButtonEvent (event : ComponentInteractionCreateEventArgs) =
|
||||||
|
@ -76,7 +76,6 @@ module Types =
|
|||||||
Actions : Action array
|
Actions : Action array
|
||||||
Bank : int<GBT> }
|
Bank : int<GBT> }
|
||||||
|
|
||||||
|
|
||||||
module Armory =
|
module Armory =
|
||||||
let battleItems =
|
let battleItems =
|
||||||
let file = System.IO.File.ReadAllText("Items.json")
|
let file = System.IO.File.ReadAllText("Items.json")
|
||||||
@ -89,9 +88,10 @@ module Player =
|
|||||||
let shields player = player.Arsenal |> Array.filter (fun bi -> bi.Type = Shield)
|
let shields player = player.Arsenal |> Array.filter (fun bi -> bi.Type = Shield)
|
||||||
let attacks player =
|
let attacks player =
|
||||||
player.Actions
|
player.Actions
|
||||||
|> Array.choose (fun act -> match act.Type with Attack ar -> Some (act,ar.Target,ar.Result) | Defense -> None)
|
|> Array.filter (fun act -> match act.Type with Attack _ -> true | _ -> false)
|
||||||
let defenses player = player.Actions |> Array.filter (fun act -> match act.Type with Defense _ -> true | _ -> false)
|
let defenses player = player.Actions |> Array.filter (fun act -> match act.Type with Defense -> true | _ -> false)
|
||||||
|
|
||||||
|
// TODO: I have to fix this, this will remove hacks before the single target cooldown expires
|
||||||
let removeExpiredActions actions =
|
let removeExpiredActions actions =
|
||||||
actions
|
actions
|
||||||
|> Array.filter (fun (act : Action) ->
|
|> Array.filter (fun (act : Action) ->
|
||||||
@ -110,12 +110,39 @@ module Messaging =
|
|||||||
Message : string
|
Message : string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let getTimeTillCooldownFinishes (timespan : TimeSpan) timestamp =
|
||||||
|
let timeRemaining = timespan - (DateTime.UtcNow - timestamp)
|
||||||
|
if timeRemaining.Hours > 0 then
|
||||||
|
$"{timeRemaining.Hours} hours"
|
||||||
|
elif timeRemaining.Minutes > 0 then
|
||||||
|
$"{timeRemaining.Minutes} minutes"
|
||||||
|
else
|
||||||
|
$"{timeRemaining.Seconds} seconds"
|
||||||
|
|
||||||
|
let battleItemFormat (items : BattleItem array) =
|
||||||
|
match items with
|
||||||
|
| [||] -> "None"
|
||||||
|
| _ -> items |> Array.toList |> List.map (fun i -> i.Name) |> String.concat ", "
|
||||||
|
|
||||||
|
let actionFormat (actions : Action array) =
|
||||||
|
match actions with
|
||||||
|
| [||] -> "None"
|
||||||
|
| _ ->
|
||||||
|
actions
|
||||||
|
|> Array.map (fun act ->
|
||||||
|
match act.Type with
|
||||||
|
| Attack atk -> $"Hacked {atk.Target} at {act.Timestamp.ToLongDateString()}"
|
||||||
|
| Defense ->
|
||||||
|
let item = Armory.getItem act.ActionId
|
||||||
|
let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromMinutes(int item.Cooldown))
|
||||||
|
$"{item.Name} active for {cooldown}")
|
||||||
|
|> String.concat "\n"
|
||||||
|
|
||||||
let statusFormat p =
|
let statusFormat p =
|
||||||
$"Hacks: {Player.hacks p |> Array.toList}
|
$"**Hacks:** {Player.hacks p |> battleItemFormat}\n
|
||||||
Shields: {Player.shields p |> Array.toList}
|
**Shields:** {Player.shields p |> battleItemFormat}\n
|
||||||
Hack Attacks: {Player.attacks p |> Array.toList}
|
**Hack Attacks:** {Player.attacks p |> actionFormat}\n
|
||||||
Active Defenses: {Player.defenses p |> Array.toList}
|
**Active Shields:** {Player.defenses p |> actionFormat}"
|
||||||
Bank: {p.Bank}"
|
|
||||||
|
|
||||||
let constructButtons (actionType: string) (playerInfo: string) (weapons: BattleItem array) =
|
let constructButtons (actionType: string) (playerInfo: string) (weapons: BattleItem array) =
|
||||||
weapons
|
weapons
|
||||||
|
Loading…
x
Reference in New Issue
Block a user