Implement new Trainer improvements and clean up a few more things

This commit is contained in:
Joseph Ferano 2022-02-01 22:45:27 +07:00
parent ef3d5c58f5
commit e772a6d6f3
11 changed files with 135 additions and 200 deletions

View File

@ -74,7 +74,7 @@ let run (client : DiscordClient) =
do! client.ConnectAsync () |> Async.AwaitTask do! client.ConnectAsync () |> Async.AwaitTask
} }
//Trainer.sendInitialEmbed hackerBattleBot Trainer.sendInitialEmbed hackerBattleBot
clients clients
|> Array.map run |> Array.map run

View File

@ -73,12 +73,12 @@ let responseSuccessfulHack defenderName hack prize =
.AddEmbed(embed.Build()) .AddEmbed(embed.Build())
.AsEphemeral(true) .AsEphemeral(true)
let responseSuccessfulHackTrainer defenderName (hack : BattleItem) prize = let responseSuccessfulHackTrainer (hack : BattleItem) =
let embed = DiscordEmbedBuilder() let embed = DiscordEmbedBuilder()
embed.ImageUrl <- getHackGif (enum<HackId>(hack.Id)) embed.ImageUrl <- getHackGif (enum<HackId>(hack.Id))
DiscordFollowupMessageBuilder() DiscordFollowupMessageBuilder()
.WithContent($"Successfully hacked {defenderName} using {hack.Name}! You just won {prize} GoodBoyTokenz!") .WithContent($"You successfully hacked <@{GuildEnvironment.botHackerBattle}> using {hack.Name}, and stole 💰$GBT {Game.HackPrize} from them!")
.AddEmbed(embed.Build()) .AddEmbed(embed.Build())
.AsEphemeral(true) .AsEphemeral(true)

View File

@ -1,10 +1,14 @@
module Degenz.Game module Degenz.Game
open System.Threading.Tasks open System.Threading.Tasks
open DSharpPlus.EventArgs
open DSharpPlus.SlashCommands open DSharpPlus.SlashCommands
open Degenz.DbService open Degenz.DbService
let executePlayerAction (ctx : InteractionContext) (dispatch : PlayerData -> Async<unit>) = let HackPrize = 10<GBT>
let ShieldPrize = 5<GBT>
let executePlayerInteraction (ctx : InteractionContext) (dispatch : PlayerData -> Async<unit>) =
async { async {
let! playerResult = tryFindPlayer ctx.Member.Id let! playerResult = tryFindPlayer ctx.Member.Id
match playerResult with match playerResult with
@ -13,3 +17,13 @@ let executePlayerAction (ctx : InteractionContext) (dispatch : PlayerData -> Asy
} |> Async.StartAsTask } |> Async.StartAsTask
:> Task :> Task
// TODO: Create an abstraction for these two helper functions
let executePlayerEvent (ctx : ComponentInteractionCreateEventArgs) (dispatch : PlayerData -> Async<unit>) =
async {
let! playerResult = tryFindPlayer ctx.User.Id
match playerResult with
| Some player -> do! dispatch player
| None -> do! Messaging.sendInteractionEvent ctx "You are currently not a hacker, first use the /redpill command to become one"
} |> Async.StartAsTask
:> Task

View File

@ -16,5 +16,7 @@ let tokenHackerBattle = getVar "TOKEN_HACKER_BATTLE"
let tokenStore = getVar "TOKEN_STORE" let tokenStore = getVar "TOKEN_STORE"
let channelEventsHackerBattle = getId "CHANNEL_EVENTS_HACKER_BATTLE" let channelEventsHackerBattle = getId "CHANNEL_EVENTS_HACKER_BATTLE"
let channelTraining = getId "CHANNEL_TRAINING" let channelTraining = getId "CHANNEL_TRAINING"
let channelArmory = getId "CHANNEL_ARMORY"
let botHackerBattle = getId "BOT_HACKER_BATTLE" let botHackerBattle = getId "BOT_HACKER_BATTLE"
let botArmory = getId "BOT_ARMORY"
let roleTrainee = getId "ROLE_TRAINEE" let roleTrainee = getId "ROLE_TRAINEE"

View File

@ -46,12 +46,12 @@ let checkIfHackHasCooldown hackId attacker =
Ok attacker Ok attacker
else else
let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromMinutes(5)) mostRecentHackAttack let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromMinutes(5)) mostRecentHackAttack
let item = Armoury.battleItems |> Array.find (fun i -> i.Id = hackId) let item = Armory.battleItems |> Array.find (fun i -> i.Id = hackId)
Error $"{item.Name} is currently on cooldown, wait {cooldown} to use it again." Error $"{item.Name} is currently on cooldown, wait {cooldown} to use it again."
let checkIfInventoryIsEmpty attacker = let checkIfInventoryIsEmpty attacker =
match attacker.Arsenal with match attacker.Arsenal with
| [||] -> Error $"You currently do not have any Hacks to use against others. Please go to the store 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 calculateDamage (hack : BattleItem) (shield : BattleItem) = let calculateDamage (hack : BattleItem) (shield : BattleItem) =
@ -62,7 +62,7 @@ let calculateDamage (hack : BattleItem) (shield : BattleItem) =
let runHackerBattle defender hack = let runHackerBattle defender hack =
Player.defenses defender Player.defenses defender
|> Player.removeExpiredActions |> Player.removeExpiredActions
|> Array.map (fun dfn -> Armoury.battleItems |> Array.find (fun w -> w.Id = dfn.ActionId)) |> Array.map (fun dfn -> Armory.battleItems |> Array.find (fun w -> w.Id = dfn.ActionId))
|> Array.map (calculateDamage (hack)) |> Array.map (calculateDamage (hack))
|> Array.contains Weak |> Array.contains Weak
@ -79,15 +79,13 @@ let updateCombatants attacker defender hack prize =
let successfulHack (event : ComponentInteractionCreateEventArgs) attacker defender hack = let successfulHack (event : ComponentInteractionCreateEventArgs) attacker defender hack =
async { async {
let prize = 3<GBT> do! updateCombatants attacker defender hack Game.HackPrize
do! updateCombatants attacker defender hack prize let embed = Embeds.responseSuccessfulHack defender.Name hack Game.HackPrize
let embed = Embeds.responseSuccessfulHack defender.Name hack prize
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed) do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed)
|> Async.AwaitTask |> Async.AwaitTask
let builder = Embeds.eventSuccessfulHack event defender.DiscordId prize let builder = Embeds.eventSuccessfulHack event defender.DiscordId Game.HackPrize
let channel = event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle) let channel = event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle)
do! channel.SendMessageAsync(builder) do! channel.SendMessageAsync(builder)
|> Async.AwaitTask |> Async.AwaitTask
@ -97,16 +95,15 @@ let successfulHack (event : ComponentInteractionCreateEventArgs) attacker defend
let failedHack (event : ComponentInteractionCreateEventArgs) attacker defender hack = let failedHack (event : ComponentInteractionCreateEventArgs) attacker defender hack =
async { async {
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
let prize = 2<GBT>
builder.IsEphemeral <- true builder.IsEphemeral <- true
builder.Content <- $"Hack failed! {defender.Name} was able to mount a successful defense! You lost {prize} GoodBoyTokenz!" builder.Content <- $"Hack failed! {defender.Name} was able to mount a successful defense! You lost {Game.ShieldPrize} GoodBoyTokenz!"
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask |> Async.AwaitTask
do! updateCombatants attacker defender hack -prize do! updateCombatants attacker defender hack -Game.ShieldPrize
let builder = DiscordMessageBuilder() let builder = DiscordMessageBuilder()
builder.WithContent($"Hacking attempt failed! <@{defender.DiscordId}> defended hack from {event.User.Username} and took {prize} from them! ") |> ignore builder.WithContent($"Hacking attempt failed! <@{defender.DiscordId}> defended hack from {event.User.Username} and took {Game.ShieldPrize} from them! ") |> ignore
let channel = (event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle)) let channel = (event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle))
do! channel.SendMessageAsync(builder) do! channel.SendMessageAsync(builder)
|> Async.AwaitTask |> Async.AwaitTask
@ -114,7 +111,7 @@ let failedHack (event : ComponentInteractionCreateEventArgs) attacker defender h
} }
let attack (ctx : InteractionContext) (target : DiscordUser) = let attack (ctx : InteractionContext) (target : DiscordUser) =
Game.executePlayerAction ctx (fun attacker -> async { Game.executePlayerInteraction ctx (fun attacker -> async {
let! defender = DbService.tryFindPlayer target.Id let! defender = DbService.tryFindPlayer target.Id
match defender with match defender with
| Some defender -> | Some defender ->
@ -151,7 +148,7 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
|> Result.bind (checkIfHackHasCooldown (int hack)) |> Result.bind (checkIfHackHasCooldown (int hack))
|> function |> function
| Ok _ -> | Ok _ ->
runHackerBattle defender (Armoury.getItem (int hack)) runHackerBattle defender (Armory.getItem (int hack))
|> function |> function
| false -> successfulHack event attacker defender hack | false -> successfulHack event attacker defender hack
| true -> failedHack event attacker defender hack | true -> failedHack event attacker defender hack
@ -171,14 +168,14 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
} }
let defend (ctx : InteractionContext) = let defend (ctx : InteractionContext) =
Game.executePlayerAction ctx (fun player -> async { Game.executePlayerInteraction ctx (fun player -> async {
if Player.shields player |> Array.length > 0 then if Player.shields player |> Array.length > 0 then
let embed = Embeds.pickDefense "Defend" player let embed = Embeds.pickDefense "Defend" player
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed) do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed)
|> Async.AwaitTask |> Async.AwaitTask
else else
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
builder.Content <- $"You currently do not have any Shields to protect your system. Please go to the armoury and purchase one." builder.Content <- $"You currently do not have any Shields to protect you. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one."
builder.AsEphemeral true |> ignore builder.AsEphemeral true |> ignore
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask |> Async.AwaitTask
@ -263,8 +260,8 @@ type HackerGame() =
else else
attack ctx target attack ctx target
[<SlashCommand("defend", "Create a passive defense that will last 24 hours")>] [<SlashCommand("shield", "Create a passive defense that will last 24 hours")>]
member this.DefendCommand (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
else else

View File

@ -12,8 +12,8 @@ module Commands =
let rand = System.Random(System.Guid.NewGuid().GetHashCode()) let rand = System.Random(System.Guid.NewGuid().GetHashCode())
let randHack = rand.Next(0, 3) let randHack = rand.Next(0, 3)
let randShield = rand.Next(6, 9) let randShield = rand.Next(6, 9)
let hack = Armoury.battleItems |> Array.find (fun i -> i.Id = randHack) let hack = Armory.battleItems |> Array.find (fun i -> i.Id = randHack)
let shield = Armoury.battleItems |> Array.find (fun i -> i.Id = randShield) let shield = Armory.battleItems |> Array.find (fun i -> i.Id = randShield)
{ DiscordId = membr { DiscordId = membr
Name = nickname Name = nickname
@ -72,7 +72,7 @@ module Commands =
// :> Task // :> Task
let status (ctx : InteractionContext) = let status (ctx : InteractionContext) =
Game.executePlayerAction ctx (fun player -> async { Game.executePlayerInteraction ctx (fun player -> async {
let updatedActions = Player.removeExpiredActions player.Actions let updatedActions = Player.removeExpiredActions player.Actions
let updatedPlayer = { player with Actions = updatedActions } let updatedPlayer = { player with Actions = updatedActions }
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()

View File

@ -14,7 +14,7 @@ type SlotMachine() =
[<SlashCommand("spin", "Want to try your luck?")>] [<SlashCommand("spin", "Want to try your luck?")>]
member this.Spin (ctx : InteractionContext) = member this.Spin (ctx : InteractionContext) =
Game.executePlayerAction ctx (fun player -> async { Game.executePlayerInteraction ctx (fun player -> async {
let sleepTime = 1000 let sleepTime = 1000
let random = Random(System.Guid.NewGuid().GetHashCode()) let random = Random(System.Guid.NewGuid().GetHashCode())
let results = [ random.Next(0, 3) ; random.Next(0, 3) ; random.Next(0, 3)] let results = [ random.Next(0, 3) ; random.Next(0, 3) ; random.Next(0, 3)]

View File

@ -12,13 +12,13 @@ open Degenz.Messaging
let viewStore (ctx : InteractionContext) = let viewStore (ctx : InteractionContext) =
async { async {
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, Embeds.storeListing Armoury.battleItems) do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, Embeds.storeListing Armory.battleItems)
|> Async.AwaitTask |> Async.AwaitTask
} |> Async.StartAsTask } |> Async.StartAsTask
:> Task :> Task
let buyItem (ctx : InteractionContext) itemType = let buyItem (ctx : InteractionContext) itemType =
Game.executePlayerAction ctx (fun player -> async { Game.executePlayerInteraction ctx (fun player -> async {
let embed = DiscordEmbedBuilder() let embed = DiscordEmbedBuilder()
// embed.Fields // embed.Fields
@ -28,7 +28,7 @@ let buyItem (ctx : InteractionContext) itemType =
}) })
let sell (ctx : InteractionContext) = let sell (ctx : InteractionContext) =
Game.executePlayerAction ctx (fun player -> async { Game.executePlayerInteraction ctx (fun player -> async {
let hasInventoryToSell = Array.length player.Arsenal > 0 let hasInventoryToSell = Array.length player.Arsenal > 0
if hasInventoryToSell then if hasInventoryToSell then
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
@ -52,7 +52,7 @@ let sell (ctx : InteractionContext) =
let sellItem (event : ComponentInteractionCreateEventArgs) player itemId = let sellItem (event : ComponentInteractionCreateEventArgs) player itemId =
async { async {
let item = Armoury.battleItems |> Array.find (fun i -> i.Id = itemId) let item = Armory.battleItems |> Array.find (fun i -> i.Id = itemId)
let updatedPlayer = { player with Bank = player.Bank + item.Cost ; Arsenal = player.Arsenal |> Array.filter (fun w -> w.Id <> itemId)} let updatedPlayer = { player with Bank = player.Bank + item.Cost ; Arsenal = player.Arsenal |> Array.filter (fun w -> w.Id <> itemId)}
do! DbService.updatePlayer updatedPlayer do! DbService.updatePlayer updatedPlayer
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
@ -63,8 +63,8 @@ let sellItem (event : ComponentInteractionCreateEventArgs) player itemId =
} }
let handleBuyItem (ctx : InteractionContext) itemId = let handleBuyItem (ctx : InteractionContext) itemId =
Game.executePlayerAction ctx (fun player -> async { Game.executePlayerInteraction ctx (fun player -> async {
let item = Armoury.battleItems |> Array.find (fun w -> w.Id = itemId) let item = Armory.battleItems |> Array.find (fun w -> w.Id = itemId)
let newBalance = player.Bank - item.Cost let newBalance = player.Bank - item.Cost
if newBalance >= 0<GBT> then if newBalance >= 0<GBT> then
let playerHasItem = player.Arsenal |> Array.exists (fun w -> item.Id = w.Id) let playerHasItem = player.Arsenal |> Array.exists (fun w -> item.Id = w.Id)

View File

@ -8,8 +8,8 @@ open DSharpPlus.SlashCommands
open Degenz.Types open Degenz.Types
open Degenz.Messaging open Degenz.Messaging
let defaultHack = Armoury.battleItems |> Array.find (fun i -> i.Id = int HackId.Virus) let defaultHack = Armory.battleItems |> Array.find (fun i -> i.Id = int HackId.Virus)
let defaultShield = Armoury.battleItems |> Array.find (fun i -> i.Id = int ShieldId.Firewall) let defaultShield = Armory.battleItems |> Array.find (fun i -> i.Id = int ShieldId.Encryption)
let sendInitialEmbed (client : DiscordClient) = let sendInitialEmbed (client : DiscordClient) =
async { async {
@ -18,145 +18,102 @@ let sendInitialEmbed (client : DiscordClient) =
let embed = DiscordEmbedBuilder() let embed = DiscordEmbedBuilder()
embed.ImageUrl <- "https://s10.gifyu.com/images/MasterTraining_Degenz.gif" embed.ImageUrl <- "https://s10.gifyu.com/images/MasterTraining_Degenz.gif"
builder.AddEmbed embed |> ignore builder.AddEmbed embed |> ignore
builder.Content <- "Welcome to the hacker dojo you degenerate, are you ready to get started?" builder.Content <- "Welcome Degen… To the Hacker Training Program.\n"
let button = DiscordButtonComponent(ButtonStyle.Success, $"Trainer-1", $"Get started") :> DiscordComponent + "Here you will learn how to defend yourself, and hack other Degenz to steal their 💰$GBT.\n"
+ "Are you ready?"
let button = DiscordButtonComponent(ButtonStyle.Success, $"Trainer-1", $"LFG") :> DiscordComponent
builder.AddComponents [| button |] |> ignore builder.AddComponents [| button |] |> ignore
do! channel.SendMessageAsync(builder) do! channel.SendMessageAsync(builder)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore |> Async.Ignore
} |> Async.RunSynchronously } |> Async.RunSynchronously
let step1Msg = {
ButtonId = "Trainer-2"
ButtonText = "Show me"
Message = "First time, eh? Beautopia is a dangerous place. I'm going to teach you how to protect yourself from other degenerates. "
+ "And in the process, I'll also show you how to hack some sheeple, so you can earn some cash."
}
let handleTrainerStep1 (event : ComponentInteractionCreateEventArgs) = let handleTrainerStep1 (event : ComponentInteractionCreateEventArgs) =
async { Game.executePlayerEvent event (fun player -> async {
let! maybePlayer = DbService.tryFindPlayer event.User.Id let weaponName = Player.shields player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name
do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate) let shieldMessage =
|> Async.AwaitTask if Player.shields player |> Array.isEmpty
match maybePlayer with then $"You do not have any Shields in your arsenal, take this {defaultShield.Name}, you can use it for now"
| Some _ -> else $"Looks like you have `{weaponName}` in your arsenal… 👀\n"
do! sendFollowUpMessageWithButton event step1Msg
| None ->
let msg = "Looks like an error occurred, you're not a registered degenerate. Please contact a moderator."
do! sendFollowUpMessage event msg
}
let handleTrainerStep2 (event : ComponentInteractionCreateEventArgs) = do! sendInteractionEvent event
async { ("Beautopia© is a dangerous place...\n"
let! result = DbService.tryFindPlayer event.User.Id + "Quick, put up a DEFENSE 🛡 before another Degen hacks you, and steals your 💰$GBT.\n"
match result with + shieldMessage
| Some player -> + "To enable it, you need to run the `/shield` slash command.\n\n"
let weaponName = Player.shields player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name + $"Type the `/shield` command now, then select - `{weaponName}`\n")
do! updateMessageWithGreyedOutButtons event step1Msg })
let shieldMessage =
if Player.shields player |> Array.isEmpty
then $"You do not have any Shields in your arsenal, here's a {defaultShield.Name} you can use for now"
else $"You currently have {weaponName} in your arsenal"
do! sendFollowUpMessage event
($"First things first, let's get your system protected. Let's enable a shield to protect you from potential hackers. "
+ $"{shieldMessage}. To enable it and protect your system, you can use the `/defend` slash command to choose a shield."
+ $"\n\nRun the `/defend` command now and then select '{weaponName}'.")
| None ->
do! sendFollowUpMessage event $"Something went wrong, please contact a moderator"
}
let defend (ctx : InteractionContext) = let defend (ctx : InteractionContext) =
async { Game.executePlayerInteraction ctx (fun player -> async {
let! playerResult = DbService.tryFindPlayer ctx.Member.Id let playerWithShields =
match playerResult with match player.Arsenal with
| Some player -> | [||] -> { player with Arsenal = [| defaultShield |] }
let playerWithShields = | _ -> player
match player.Arsenal with let embed = Embeds.pickDefense "Trainer-2" playerWithShields
| [||] -> { player with Arsenal = [| defaultShield |] }
| _ -> player
let embed = Embeds.pickDefense "Trainer-3" playerWithShields
do! ctx.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed) do! ctx.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed)
|> Async.AwaitTask |> Async.AwaitTask
| None -> })
let builder = DiscordInteractionResponseBuilder()
builder.Content <- "Error, please contact a moderator"
builder.AsEphemeral true |> ignore
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask
} |> Async.StartAsTask
:> Task
let handleDefenseMsg = { let handleDefenseMsg = {
ButtonId = "Trainer-4" ButtonId = "Trainer-3"
ButtonText = "Got it" ButtonText = "Got it"
Message = "I wasn't able to hack you. Great job! Because you had your system protected when I tried to hack you, you took some money from me. " Message = "🎉 Congratulations 🎉\n\n"
+ "Shields only protect you for a certain amount of time, so remember to keep your system protected at all times." + "You successfully defended my hack!\n\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!"
} }
let handleDefense (event : ComponentInteractionCreateEventArgs) = let handleDefense (event : ComponentInteractionCreateEventArgs) =
let sendMessage' = sendFollowUpMessage event Game.executePlayerEvent event (fun player -> async {
async { let sendMessage' = sendFollowUpMessage event
do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate) do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate)
|> Async.AwaitTask |> Async.AwaitTask
let! maybePlayer = DbService.tryFindPlayer event.User.Id let shield = Player.shields player |> Array.tryHead |> Option.defaultValue defaultShield
match maybePlayer with let embed = Embeds.responseCreatedShieldTrainer shield
| Some player -> do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
let prize = 0.223f do! Async.Sleep 2000
let shield = Player.shields player |> Array.tryHead |> Option.defaultValue defaultShield do! sendMessage' "Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now"
let embed = Embeds.responseCreatedShieldTrainer shield do! Async.Sleep 4000
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore do! sendMessage' $"❌ HACKING FAILED! ❌\n\n{player.Name} defended the hack from <@{GuildEnvironment.botHackerBattle}>, and stole 💰$GBT {Game.ShieldPrize} from them!"
do! Async.Sleep 2000 do! Async.Sleep 3000
do! sendMessage' "Ok, good, let me make sure that worked. I'll try to hack you now" do! sendFollowUpMessageWithButton event handleDefenseMsg
do! Async.Sleep 4000 })
do! sendMessage' $"Hacking attempt failed! {player.Name} defended hack from Degenz-Trainer and took {prize} from them! "
do! Async.Sleep 3000
do! sendFollowUpMessageWithButton event handleDefenseMsg
| None ->
do! sendMessage' $"Something went wrong, please contact a moderator"
}
let handleTrainerStep4 (event : ComponentInteractionCreateEventArgs) = let handleTrainerStep3 (event : ComponentInteractionCreateEventArgs) =
async { Game.executePlayerEvent event (fun player -> async {
let! result = DbService.tryFindPlayer event.User.Id let weaponName = Player.hacks player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name
match result with do! updateMessageWithGreyedOutButtons event handleDefenseMsg
| Some player ->
let weaponName = Player.hacks player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name
do! updateMessageWithGreyedOutButtons event handleDefenseMsg
let hackMessage = let hackMessage =
if Player.shields player |> Array.isEmpty if Player.shields player |> Array.isEmpty
then $"You do not have any Hacks in your arsenal, here's a {defaultHack.Name} you can use for now" then $"You do not have any Hacks in your arsenal, take this {defaultHack.Name}, you can use it for now"
else $"You currently have {weaponName} in your arsenal" else $"Looks like you have `{weaponName}` in your arsenal..."
do! sendFollowUpMessage event do! sendFollowUpMessage event
($"Next why don't you try hacking me. {hackMessage}. To hack me and get some money, " ("Now lets **HACK!** 💻\n\n"
+ $" you can use the '/hack' slash command and select a user to hack, then choose the hack attack you wish to use." + "I want you to **HACK ME**, and try to steal my 💰$GBT...\n\n"
+ $"\n\nRun the `/hack` command now and pick me as your target, then click on the '{weaponName}' button.") + hackMessage
| None -> + "To deploy it, you need to run the `/hack` slash command.\n"
do! sendInteractionEvent event $"Something went wrong, please contact a moderator" + $"Type the `/hack` command now, then choose me - <@{GuildEnvironment.botHackerBattle}> as your target, and select - `{weaponName}`")
} })
let attack (ctx : InteractionContext) (target : DiscordUser) = let attack (ctx : InteractionContext) (target : DiscordUser) =
async { Game.executePlayerInteraction ctx (fun player -> async {
let isRightTarget = target.Id = GuildEnvironment.botHackerBattle let isRightTarget = target.Id = GuildEnvironment.botHackerBattle
let! playerResult = DbService.tryFindPlayer ctx.Member.Id match isRightTarget with
match isRightTarget , playerResult with | true ->
| true , Some player ->
let playerWithAttacks = let playerWithAttacks =
match player.Arsenal with match player.Arsenal with
| [||] -> { player with Arsenal = [| defaultHack |] } | [||] -> { player with Arsenal = [| defaultHack |] }
| _ -> player | _ -> player
let embed = Embeds.pickHack "Trainer-5" playerWithAttacks player let embed = Embeds.pickHack "Trainer-4" playerWithAttacks player
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed) do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed)
|> Async.AwaitTask |> Async.AwaitTask
| false , _ -> | false ->
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()
builder.Content <- "You picked the wrong target, you dufus. Try again, this time pick me!" builder.Content <- "You picked the wrong target, you dufus. Try again, this time pick me!"
@ -164,72 +121,37 @@ let attack (ctx : InteractionContext) (target : DiscordUser) =
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder) do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask |> Async.AwaitTask
| _ -> })
let builder = DiscordInteractionResponseBuilder()
builder.Content <- "Error, please contact a moderator"
builder.AsEphemeral true |> ignore
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask
} |> Async.StartAsTask
:> Task
let handleAttackMsg = {
ButtonId = "Trainer-6"
ButtonText = "Hell yeah"
Message = "I think we're done. You are going to need more hacks and shields if you want to survive in this crazy world. "
+ "Remember to go check out the store and purchase whatever you need to add to your arsenal."
+ "\n\nAlright you degenerate, off you go!"
}
let handleAttack (event : ComponentInteractionCreateEventArgs) = let handleAttack (event : ComponentInteractionCreateEventArgs) =
let sendMessage' = sendFollowUpMessage event Game.executePlayerEvent event (fun player -> async {
async { let sendMessage' = sendFollowUpMessage event
do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate) do! event.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate)
|> Async.AwaitTask |> Async.AwaitTask
let! result = DbService.tryFindPlayer event.User.Id do! Async.Sleep 1000
match result with let hack = Player.hacks player |> Array.tryHead |> Option.defaultValue defaultHack
| Some player -> let embed = Embeds.responseSuccessfulHackTrainer hack
let prize = 2 do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
do! Async.Sleep 1000 do! Async.Sleep 3000
let hack = player.Arsenal |> Array.tryHead |> Option.defaultValue defaultHack do! sendMessage' ("🎉 **Congratulations** 🎉\n\n"
let embed = Embeds.responseSuccessfulHackTrainer $"<@{GuildEnvironment.botHackerBattle}>" hack prize + "You successfully **HACKED** me, and are now an **Elite Haxor!**\n\n"
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore + "When you **HACK** other Degenz, you **STEAL** their 💰**$GBT.**\n"
do! Async.Sleep 3000 + "But remember, hacks take time to recover, so use them wisely.")
do! sendMessage' ("Look at that, you are now officially an elite haxor! By successfully hacking other people you can earn GoodBoyTokenz. " do! Async.Sleep 7000
+ "Hacks take time to recover so check back in later once you've used all your hacks.") do! sendFollowUpMessage event ("Your training is **complete!**\n\n"
do! Async.Sleep 7000 + "But, youre going to need more **HACKS & DEFENSES** 🛡 to survive in **Beautopia©...**\n"
do! sendFollowUpMessageWithButton event handleAttackMsg + $"You can purchase them from <@{GuildEnvironment.botArmory}>, at <#{GuildEnvironment.channelArmory}> anytime you want...\n\n"
| None -> + "Go there **NOW** to buy **HACKS** & **SHIELDS** before you get hacked! 😱")
do! sendMessage' $"Something went wrong, please contact a moderator" })
}
let handleTrainerStep6 (event : ComponentInteractionCreateEventArgs) =
async {
// let! membr = event.Guild.GetMemberAsync(event.User.Id) |> Async.AwaitTask
// let role = event.Guild.GetRole(GuildEnvironment.roleTrainee)
// do! membr.RevokeRoleAsync(role) |> Async.AwaitTask
let builder = DiscordFollowupMessageBuilder()
builder.IsEphemeral <- true
builder.Content <- "Get out of here!"
do! updateMessageWithGreyedOutButtons event handleAttackMsg
do! event.Interaction.CreateFollowupMessageAsync(builder)
|> Async.AwaitTask
|> Async.Ignore
}
let handleButtonEvent (event : ComponentInteractionCreateEventArgs) = let handleButtonEvent (event : ComponentInteractionCreateEventArgs) =
async { async {
let split = event.Id.Split("-") let split = event.Id.Split("-")
match int split.[1] with match int split.[1] with
| 1 -> do! handleTrainerStep1 event | 1 -> do! handleTrainerStep1 event |> Async.AwaitTask
| 2 -> do! handleTrainerStep2 event | 2 -> do! handleDefense event |> Async.AwaitTask
| 3 -> do! handleDefense event | 3 -> do! handleTrainerStep3 event |> Async.AwaitTask
| 4 -> do! handleTrainerStep4 event | 4 -> do! handleAttack event |> Async.AwaitTask
| 5 -> do! handleAttack event
| 6 -> do! handleTrainerStep6 event
| _ -> do! sendFollowUpMessage event "No action found" | _ -> do! sendFollowUpMessage event "No action found"
} }

View File

@ -63,7 +63,7 @@ let private playerMap (player : PlayerData) = {
let private mapBack (player : PlayerEntry) : PlayerData = { let private mapBack (player : PlayerEntry) : PlayerData = {
DiscordId = player.DiscordId DiscordId = player.DiscordId
Name = player.Name Name = player.Name
Arsenal = player.Arsenal |> Array.map (fun w -> Armoury.battleItems |> Array.find (fun w' -> w = w'.Id)) Arsenal = player.Arsenal |> Array.map (fun w -> Armory.battleItems |> Array.find (fun w' -> w = w'.Id))
Actions = Actions =
let atks = player.Attacks |> Array.map attackToAction let atks = player.Attacks |> Array.map attackToAction
let dfns = player.Defenses |> Array.map defenseToAction let dfns = player.Defenses |> Array.map defenseToAction

View File

@ -77,7 +77,7 @@ module Types =
Bank : int<GBT> } Bank : int<GBT> }
module Armoury = module Armory =
let battleItems = let battleItems =
let file = System.IO.File.ReadAllText("Items.json") let file = System.IO.File.ReadAllText("Items.json")
JsonConvert.DeserializeObject<BattleItem array>(file) JsonConvert.DeserializeObject<BattleItem array>(file)
@ -95,7 +95,7 @@ module Player =
let removeExpiredActions actions = let removeExpiredActions actions =
actions actions
|> Array.filter (fun (act : Action) -> |> Array.filter (fun (act : Action) ->
let item = Armoury.battleItems |> Array.find (fun w -> w.Id = act.ActionId) let item = Armory.battleItems |> Array.find (fun w -> w.Id = act.ActionId)
DateTime.UtcNow - act.Timestamp < TimeSpan.FromMinutes(int item.Cooldown)) DateTime.UtcNow - act.Timestamp < TimeSpan.FromMinutes(int item.Cooldown))
let modifyBank player amount = { player with Bank = max (player.Bank + amount) 0<GBT> } let modifyBank player amount = { player with Bank = max (player.Bank + amount) 0<GBT> }