module Degenz.Trainer open System.Text open DSharpPlus open DSharpPlus.Entities open DSharpPlus.EventArgs open Degenz.Types open Degenz.Messaging let trainerAchievement = "FINISHED_TRAINER" 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 (ctx : IDiscordContext) = Game.executePlayerAction ctx (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 role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee) do! ctx.GetDiscordMember().GrantRoleAsync(role) |> Async.AwaitTask do! sendFollowUpMessage ctx ("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 : IDiscordContext) = Game.executePlayerAction 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.FollowUp(embed) |> Async.AwaitTask }) 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 (ctx : IDiscordContext) = Game.executePlayerAction ctx (fun player -> async { let sendMessage' = sendFollowUpMessage ctx let split = ctx.GetInteractionId().Split("-") let shieldId = enum(int split.[2]) let shield = Armory.getItem (int shieldId) let embed = Embeds.responseCreatedShield shield do! ctx.FollowUp embed |> Async.AwaitTask 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 ctx (handleDefenseMsg shieldId (snd weakHack)) }) let handleTrainerStep3 (ctx : IDiscordContext) = Game.executePlayerAction ctx (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 ctx ("Now let’s **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 : IDiscordContext) = Game.executePlayerAction 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.FollowUp(embed) |> Async.AwaitTask | false -> let builder = DiscordFollowupMessageBuilder() builder.Content <- "You picked the wrong target, you dufus. Try again, this time pick me!" builder.IsEphemeral <- true do! ctx.FollowUp(builder) |> Async.AwaitTask }) let handleAttack (ctx : IDiscordContext) = Game.executePlayerAction ctx (fun player -> async { let sendMessage' = sendFollowUpMessage ctx do! Async.Sleep 1000 let hack = Player.getHacks player |> Array.tryHead |> Option.defaultValue defaultHack let embed = Embeds.responseSuccessfulHack false GuildEnvironment.botIdHackerBattle hack do! ctx.FollowUp(embed) |> Async.AwaitTask 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 let shieldMoney = if hasShields then defaultShield.Cost else 0 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 ctx (sb.ToString()) else do! sendFollowUpMessage ctx ($"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 = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee) do! ctx.GetDiscordMember().RevokeRoleAsync(role) |> Async.AwaitTask }) let handleArsenal (ctx : IDiscordContext) = Game.executePlayerAction ctx (fun player -> async { let updatedPlayer = Player.removeExpiredActions false player let embed = Embeds.getArsenalEmbed updatedPlayer do! ctx.FollowUp(embed) |> Async.AwaitTask do! Async.Sleep 3000 let embed = Embeds.getAchievementEmbed "You completed the Training Dojo and collected loot." trainerAchievement do! ctx.FollowUp(embed) |> Async.AwaitTask do! Async.Sleep 2000 let role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee) do! ctx.GetDiscordMember().RevokeRoleAsync(role) |> Async.AwaitTask do! sendFollowUpMessage ctx $"Now get out of there and go hack other Degenz in the <#{GuildEnvironment.channelBattle}> channel!" }) let handleButtonEvent (ctx : IDiscordContext) = async { let split = ctx.GetInteractionId().Split("-") match int split.[1] with | 1 -> do! handleTrainerStep1 ctx |> Async.AwaitTask | 2 -> do! handleDefense ctx |> Async.AwaitTask | 3 -> do! handleTrainerStep3 ctx |> Async.AwaitTask | 4 -> do! handleAttack ctx |> Async.AwaitTask | _ -> do! sendFollowUpMessage ctx "No action found" }