discord-bot-game/Bot/Trainer.fs

247 lines
12 KiB
Forth
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

module Degenz.Trainer
open System.Text
open DSharpPlus
open DSharpPlus.Entities
open DSharpPlus.EventArgs
open DSharpPlus.SlashCommands
open Degenz.Types
open Degenz.Messaging
let trainerAchievement = "FINISHED_TRAINER"
// TODO: We should either gift the weapons to the player during training, or have them buy it
// TODO: We should tell the user to type out /arsenal during the training
// TODO: How do we handle the money being generated here? It's fake but fake is confusing
let defaultHack = Armory.battleItems |> Array.find (fun i -> i.Id = int HackId.Virus)
let defaultShield = Armory.battleItems |> Array.find (fun i -> i.Id = int ShieldId.Encryption)
let sendInitialEmbed (client : DiscordClient) =
async {
let! channel = client.GetChannelAsync(GuildEnvironment.channelTraining) |> Async.AwaitTask
let builder = DiscordMessageBuilder()
let embed = DiscordEmbedBuilder()
embed.ImageUrl <- "https://s10.gifyu.com/images/MasterTraining_Degenz.gif"
builder.AddEmbed embed |> ignore
builder.Content <- "Welcome Degen… To the Hacker Training Program.\n"
+ "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
do! channel.SendMessageAsync(builder)
|> Async.AwaitTask
|> Async.Ignore
} |> Async.RunSynchronously
let handleTrainerStep1 (event : ComponentInteractionCreateEventArgs) =
Game.executePlayerEvent event (fun player -> async {
let shieldMessage , weaponName =
if Player.getShields player |> Array.isEmpty
then $"You do not have any Shields in your arsenal, take the `{defaultShield.Name}` shield, you can use it for now.\n\n" , defaultShield.Name
else
let name = Player.getShields player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name
$"Looks like you have `{name}` in your arsenal… 👀\n\n" , name
let membr = event.User :?> DiscordMember
let role = event.Guild.GetRole(GuildEnvironment.roleTrainee)
do! membr.GrantRoleAsync(role)
|> Async.AwaitTask
do! sendFollowUpMessage event
("Beautopia© is a dangerous place... quick, put up a SHIELD 🛡 before another Degen hacks you, and steals your 💰$GBT.\n\n"
+ shieldMessage
+ "To enable it, you need to run the `/shield` slash command.\n\n"
+ $"Type the `/shield` command now, then select - `{weaponName}`\n")
})
let defend (ctx : InteractionContext) =
Game.executePlayerInteraction ctx (fun player -> async {
let playerWithShields =
match Player.getShields player with
| [||] -> { player with Arsenal = [| defaultShield |] }
| _ -> player
let embed = Embeds.pickDefense "Trainer-2" playerWithShields true
do! ctx.FollowUpAsync(embed)
|> Async.AwaitTask
|> Async.Ignore
})
let handleDefenseMsg shieldId hackId = {
ButtonId = "Trainer-3"
ButtonText = "Got it"
Message = "🎉 Congratulations you successfully defended my hack!\n\n"
+ $"The `{shieldId}` shield is strong against the `{hackId}` hack, so make sure to have multiple shields up to protect from multiple attacks..."
+ "Shields only protect you for a LIMITED TIME, so remember to keep them mounted at all times, or risk getting hacked!"
}
let handleDefense (event : ComponentInteractionCreateEventArgs) =
Game.executePlayerEvent event (fun player -> async {
let sendMessage' = sendFollowUpMessage event
let split = event.Id.Split("-")
let shieldId = enum<ShieldId>(int split.[2])
let shield = Armory.getItem (int shieldId)
let embed = Embeds.responseCreatedShield (shield)
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
do! Async.Sleep 4000
let weakHack = Game.getGoodAgainst shield.Class
do! sendMessage' $"Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now with **{snd weakHack}**"
do! Async.Sleep 5000
do! sendMessage' $"❌ HACKING FAILED!\n\n{player.Name} defended hack from <@{GuildEnvironment.botIdHackerBattle}>!"
do! Async.Sleep 4000
do! sendFollowUpMessageWithButton event (handleDefenseMsg shieldId (snd weakHack))
})
let handleTrainerStep3 (event : ComponentInteractionCreateEventArgs) =
Game.executePlayerEvent event (fun player -> async {
let hackMessage , weaponName =
if Player.getHacks player |> Array.isEmpty
then $"You do not have any Hacks in your arsenal, take this `{defaultHack.Name}`, you can use it for now.\n\n" , defaultHack.Name
else
let name = Player.getHacks player |> Array.tryHead |> Option.defaultValue defaultHack |> fun w -> w.Name
$"Looks like you have `{name}` in your arsenal...\n\n" , name
do! sendFollowUpMessage event
("Now lets **HACK!** 💻\n\n"
+ "I want you to **HACK ME**...\n\n"
+ hackMessage
+ "To deploy it, you need to run the `/hack` slash command.\n"
+ $"Type the `/hack` command now, then choose me - <@{GuildEnvironment.botIdHackerBattle}> as your target, and select `{weaponName}`")
})
let attack (target : DiscordUser) (ctx : InteractionContext) =
Game.executePlayerInteraction ctx (fun player -> async {
let isRightTarget = target.Id = GuildEnvironment.botIdHackerBattle
match isRightTarget with
| true ->
let playerWithAttacks =
match Player.getHacks player with
| [||] -> { player with Arsenal = [| defaultHack |] }
| _ -> player
let bot = { player with DiscordId = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" }
let embed = Embeds.pickHack "Trainer-4" playerWithAttacks bot true
do! ctx.FollowUpAsync(embed)
|> Async.AwaitTask
|> Async.Ignore
| false ->
let builder = DiscordFollowupMessageBuilder()
builder.Content <- "You picked the wrong target, you dufus. Try again, this time pick me!"
builder.IsEphemeral <- true
do! ctx.FollowUpAsync(builder)
|> Async.AwaitTask
|> Async.Ignore
})
let handleAttack (event : ComponentInteractionCreateEventArgs) =
Game.executePlayerEvent event (fun player -> async {
let sendMessage' = sendFollowUpMessage event
do! Async.Sleep 1000
let hack = Player.getHacks player |> Array.tryHead |> Option.defaultValue defaultHack
let embed = Embeds.responseSuccessfulHack false GuildEnvironment.botIdHackerBattle hack
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
do! Async.Sleep 5000
do! sendMessage'
("🎉 **Congratulations**\n\n"
+ "You successfully **HACKED** me, and are now an **Elite Haxor!**\n\n"
+ "When you **HACK** other Degenz, you **STEAL** their 💰$GBT.\n"
+ "But remember, hacks take time to recover, so use them wisely.")
do! Async.Sleep 6000
let sb = StringBuilder("Here, ")
let! achievements = DbService.getAchievements player.DiscordId
let isFirstTrainer = achievements |> Option.map (Seq.contains trainerAchievement >> not) |> Option.defaultValue true
if isFirstTrainer then
do! DbService.addAchievement player.DiscordId trainerAchievement
let hasHacks = Player.getHacks player |> Array.isEmpty |> not
let hasShields = Player.getShields player |> Array.isEmpty |> not
let rand = System.Random(System.Guid.NewGuid().GetHashCode())
let freeHack = Armory.hacks.[rand.Next(0, 3)]
let freeShield = Armory.shields.[rand.Next(0, 3)]
let hackMoney = if hasHacks then defaultHack.Cost else 0<GBT>
let shieldMoney = if hasShields then defaultShield.Cost else 0<GBT>
let giftMsg =
match hasHacks , hasShields with
| true , true -> $"I'm going to give you these {hackMoney + shieldMoney} 💰$GBT"
| false , true -> $"I'm going to gift you a hack, `{freeHack.Name}` and {defaultHack.Cost} 💰$GBT"
| true , false -> $"I'm going to gift you a shield, `{freeShield.Name}` and {defaultHack.Cost} 💰$GBT"
| false , false -> $"I'm going to gift you a hack,`{freeHack.Name}` and a shield, `{freeShield.Name}`"
sb.Append(giftMsg) |> ignore
sb.Append(", you'll need em to survive\n\n") |> ignore
sb.AppendLine("To finish your training and collect the loot, type the `/arsenal` command **NOW**") |> ignore
do! Async.Sleep 1000
let updatedPlayer = {
player with Bank = player.Bank + hackMoney + shieldMoney
Actions = [
{ Action.Timestamp = System.DateTime.UtcNow
Action.Type =
Attack {
Result = true
Target = { Id = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" }
}
ActionId = defaultHack.Id
}
if not hasShields && Array.exists (fun act -> act.ActionId = freeShield.Id) player.Actions |> not then {
Action.Timestamp = System.DateTime.UtcNow
Action.Type = Defense
Action.ActionId = freeShield.Id
}
] |> Seq.toArray
|> Array.append player.Actions
Arsenal = [
if not hasHacks then freeHack
if not hasShields then freeShield
] |> Seq.toArray
|> Array.append player.Arsenal
}
do! DbService.updatePlayer updatedPlayer
do! sendFollowUpMessage event (sb.ToString())
else
do! sendFollowUpMessage event ($"Your training is now complete. If you want to buy more **HACKS & SHIELDS**, go to the <#{GuildEnvironment.channelArmory}> **NOW** and type the `/buy-hack` and `/buy-shield` commands! 😱")
let role = event.Guild.GetRole(GuildEnvironment.roleTrainee)
let ``member`` = event.User :?> DiscordMember
do! ``member``.RevokeRoleAsync(role)
|> Async.AwaitTask
})
let handleArsenal (ctx : InteractionContext) =
Game.executePlayerInteraction ctx (fun player -> async {
let updatedPlayer = Player.removeExpiredActions false player
let embed = Embeds.getArsenalEmbed updatedPlayer
do! ctx.FollowUpAsync(embed)
|> Async.AwaitTask
|> Async.Ignore
do! Async.Sleep 3000
let embed = Embeds.getAchievementEmbed player "You completed the Training Dojo and collected loot." trainerAchievement
do! ctx.FollowUpAsync(embed)
|> Async.AwaitTask
|> Async.Ignore
do! Async.Sleep 2000
let role = ctx.Guild.GetRole(GuildEnvironment.roleTrainee)
do! ctx.Member.RevokeRoleAsync(role)
|> Async.AwaitTask
do! sendFollowUpMessageFromCtx ctx "Now get out of there and go hack other Degenz!"
})
let handleButtonEvent (event : ComponentInteractionCreateEventArgs) =
async {
let split = event.Id.Split("-")
match int split.[1] with
| 1 -> do! handleTrainerStep1 event |> Async.AwaitTask
| 2 -> do! handleDefense event |> Async.AwaitTask
| 3 -> do! handleTrainerStep3 event |> Async.AwaitTask
| 4 -> do! handleAttack event |> Async.AwaitTask
| _ -> do! sendFollowUpMessage event "No action found"
}