module Degenz.Trainer open System.Text open System.Threading.Tasks open DSharpPlus open DSharpPlus.Entities open Degenz.Types open Degenz.Messaging let TrainerAchievement = "FINISHED_TRAINER" let Sensei = { Id = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" } let defaultHack = Armory.weapons |> Inventory.findHackById (int ItemId.Virus) let defaultShield = Armory.weapons |> Inventory.findShieldById (int ItemId.Firewall) let CurrencyGift = 250 let BeginnerProtectionHours = 24 let HackEvent () = { Timestamp = System.DateTime.UtcNow Cooldown = 1 Type = Hacking { Adversary = Sensei Success = true IsInstigator = true HackId = defaultHack.Item.Id } } let ShieldEvents () = [ { Timestamp = System.DateTime.UtcNow Cooldown = BeginnerProtectionHours * 60 Type = Shielding (int ItemId.Firewall) } { Timestamp = System.DateTime.UtcNow Cooldown = BeginnerProtectionHours * 60 Type = Shielding (int ItemId.Encryption) } { Timestamp = System.DateTime.UtcNow Cooldown = BeginnerProtectionHours * 60 Type = Shielding (int ItemId.Cypher) } ] let sendInitialEmbed (client : DiscordClient) = async { try 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 take 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 with e -> printfn $"Error trying to get channel {GuildEnvironment.channelTraining}\n\n{e.Message}" } |> Async.RunSynchronously let handleTrainerStep1 (ctx : IDiscordContext) = async { let role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee) do! ctx.GetDiscordMember().GrantRoleAsync(role) |> Async.AwaitTask let msg = "Beautopia© is a dangerous place... quick, put up a SHIELD 🛡 before another Degen hacks you, and takes your 💰$GBT.\n\n" + "To enable it, you need to run the `/shield` slash command.\n\n" + $"Type the `/shield` command now, then select - `{defaultShield.Item.Name}`\n" let builder = DiscordInteractionResponseBuilder() .WithContent(msg) .AsEphemeral(true) do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, builder) |> Async.AwaitTask do! Analytics.trainingDojoStep "LFG" (ctx.GetDiscordMember().Id) (ctx.GetDiscordMember().Username) } |> Async.StartAsTask :> Task let defend (ctx : IDiscordContext) = async { do! Messaging.defer ctx let m = ctx.GetDiscordMember() let name = if System.String.IsNullOrEmpty m.Nickname then m.DisplayName else m.Nickname let embed = Embeds.pickDefense "Trainer-2" { PlayerData.empty with Inventory = [ Shield defaultShield ] ; Name = name } true do! ctx.FollowUp(embed) |> Async.AwaitTask do! Analytics.trainingDojoStep "DefendCommand" (ctx.GetDiscordMember().Id) (ctx.GetDiscordMember().Username) } |> Async.StartAsTask :> Task let handleDefenseMsg hackId = { ButtonId = "Trainer-3" ButtonText = "Next" Message = $"🎉 Congratulations you successfully defended my {hackId} hack!\n\n" + "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) = async { do! Messaging.defer ctx let sendMessage' = sendFollowUpMessage ctx let tokens = ctx.GetInteractionId().Split("-") let shieldId = enum(int tokens.[2]) let playerName = tokens.[4] let embed = Embeds.responseCreatedShield defaultShield do! ctx.FollowUp embed |> Async.AwaitTask do! Async.Sleep 1000 do! sendMessage' $"Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now with **{defaultHack.Item.Name}**" do! Async.Sleep 3000 do! sendMessage' $"❌ HACKING FAILED!\n\n{playerName} defended hack from <@{Sensei.Id}>!" do! Async.Sleep 1500 do! sendFollowUpMessageWithButton ctx (handleDefenseMsg defaultHack.Item.Name) do! Analytics.trainingDojoStep "ShieldActivated" (ctx.GetDiscordMember().Id) (ctx.GetDiscordMember().Username) } |> Async.StartAsTask :> Task let handleTrainerStep3 (ctx : IDiscordContext) = async { let builder = DiscordInteractionResponseBuilder() .AsEphemeral(true) .WithContent ( "Now let’s **HACK** 💻... I want you to **HACK ME**!\n\n" + "To **hack**, you need to run the `/hack` slash command.\n" + $"Type the `/hack` command now, then choose me - <@{Sensei.Id}> as your target, and select `{defaultHack.Item.Name}`") do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, builder) |> Async.AwaitTask do! Analytics.trainingDojoStep "LetsHack" (ctx.GetDiscordMember().Id) (ctx.GetDiscordMember().Username) } |> Async.StartAsTask :> Task let hack (target : DiscordUser) (ctx : IDiscordContext) = async { do! Messaging.defer ctx let isRightTarget = target.Id = Sensei.Id match isRightTarget with | true -> let player = { PlayerData.empty with Inventory = [ Hack defaultHack ] } let bot = { PlayerData.empty with DiscordId = Sensei.Id ; Name = Sensei.Name } let embed = Embeds.pickHack "Trainer-4" player bot true do! ctx.FollowUp(embed) |> Async.AwaitTask | false -> let builder = DiscordFollowupMessageBuilder() .WithContent("You picked the wrong target, you dufus. Try again, this time pick me!") .AsEphemeral(true) do! ctx.FollowUp(builder) |> Async.AwaitTask do! Analytics.trainingDojoStep "HackCommand" (ctx.GetDiscordMember().Id) (ctx.GetDiscordMember().Username) } |> Async.StartAsTask :> Task let handleHack (ctx : IDiscordContext) = PlayerInteractions.executePlayerAction ctx (fun player -> async { let sendMessage' = sendFollowUpMessage ctx do! Async.Sleep 1000 let embed = Embeds.responseSuccessfulHack false Sensei.Id defaultHack.Power defaultHack do! ctx.FollowUp(embed) |> Async.AwaitTask do! Async.Sleep 1000 do! sendMessage' ("🎉 **Congratulations**\n\n" + "You successfully **HACKED** me, and are now an **Elite Haxor!**\n\n" + "When you **HACK** other Degenz, you **TAKE** their 💰$GBT.\n" + "But remember, hacks take time to recover, so use them wisely.") do! Analytics.trainingDojoStep "HackActivated" (ctx.GetDiscordMember().Id) (ctx.GetDiscordMember().Username) do! Async.Sleep 1000 let message = $""" **🎁 FREE GIFTS:** Here, I'm going to gift you: 1. A hack - `{defaultHack.Item.Name}`, 2. A shield - `{defaultShield.Item.Name}`, 3. `{CurrencyGift} 💰 $GBT`, I'm also going to give you some **TEMPORARY SHIELDS** until you buy your own. They will **ONLY** protect you from hacks for **{BeginnerProtectionHours} hrs**... To finish your training and collect all your **GIFTS**, type the `/arsenal` command NOW""" let! completed = DbService.checkHasAchievement player.DiscordId TrainerAchievement if not completed then do! sendFollowUpMessage ctx message else let role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee) do! ctx.GetDiscordMember().RevokeRoleAsync(role) |> Async.AwaitTask let role = ctx.GetGuild().GetRole(GuildEnvironment.roleHacker) do! ctx.GetDiscordMember().GrantRoleAsync(role) |> Async.AwaitTask do! sendFollowUpMessage ctx ($"Your training is now complete. If you want to buy more **HACKS & SHIELDS**, go to the <#{GuildEnvironment.channelArmory}> and type the `/buy-hack` and `/buy-shield` commands!") do! Analytics.trainingDojoStep "Completed" (ctx.GetDiscordMember().Id) (ctx.GetDiscordMember().Username) }) let handleArsenal (ctx : IDiscordContext) = PlayerInteractions.executePlayerAction ctx (fun player -> async { let! completed = DbService.checkHasAchievement player.DiscordId TrainerAchievement if not completed then do! DbService.addAchievement player.DiscordId TrainerAchievement |> Async.Ignore let addIfDoesntExist (weapon : ItemDetails) (inventory : Inventory) = if inventory |> List.exists (fun i -> i.Id = weapon.Id) then inventory else weapon::inventory let updatedPlayer = { player with Events = player |> Player.removeExpiredActions |> fun p -> p.Events |> List.filter (fun e -> match e.Type with Shielding _ -> false | _ -> true) |> List.append (ShieldEvents()) |> List.consTo (HackEvent()) Inventory = player.Inventory |> addIfDoesntExist (Hack defaultHack) |> addIfDoesntExist (Shield defaultShield) Bank = player.Bank + CurrencyGift } do! DbService.updatePlayer updatedPlayer |> Async.Ignore try do! ShieldEvents () |> List.map (DbService.addPlayerEvent player.DiscordId) |> Async.Parallel |> Async.Ignore with ex -> printfn "%s" ex.Message () let embed = Embeds.getArsenalEmbed updatedPlayer do! ctx.FollowUp(embed) |> Async.AwaitTask do! Async.Sleep 2000 let rewards = [ $"{defaultHack.Item.Name} Hack" ; $"{defaultShield.Item.Name} Shield" ; $"{CurrencyGift} 💰$GBT"] let embed = Embeds.getAchievementEmbed rewards "You completed the Training Dojo and collected some gifts." TrainerAchievement do! ctx.FollowUp(embed) |> Async.AwaitTask let role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee) do! ctx.GetDiscordMember().RevokeRoleAsync(role) |> Async.AwaitTask let role = ctx.GetGuild().GetRole(GuildEnvironment.roleHacker) do! ctx.GetDiscordMember().GrantRoleAsync(role) |> Async.AwaitTask do! InviteTracker.acceptInvite ctx player |> Async.AwaitTask do! Async.Sleep 1000 do! sendFollowUpMessage ctx $"Now get out of there and go hack other Degenz in the <#{GuildEnvironment.channelBattle}> channel!" do! Analytics.trainingDojoCompleted false (ctx.GetDiscordMember().Id) (ctx.GetDiscordMember().Username) else let role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee) do! ctx.GetDiscordMember().RevokeRoleAsync(role) |> Async.AwaitTask let role = ctx.GetGuild().GetRole(GuildEnvironment.roleHacker) do! ctx.GetDiscordMember().GrantRoleAsync(role) |> Async.AwaitTask do! sendFollowUpMessage ctx ($"Your training is now complete. If you want to buy more **HACKS & SHIELDS**, go to the <#{GuildEnvironment.channelArmory}> and type the `/buy-hack` and `/buy-shield` commands!") }) let handleButtonEvent (ctx : IDiscordContext) = async { let tokens = ctx.GetInteractionId().Split("-") match int tokens.[1] with | 1 -> do! handleTrainerStep1 ctx |> Async.AwaitTask | 2 -> do! handleDefense ctx |> Async.AwaitTask | 3 -> do! handleTrainerStep3 ctx |> Async.AwaitTask | 4 -> do! handleHack ctx |> Async.AwaitTask | _ -> do! sendFollowUpMessage ctx "No action found" }