196 lines
9.0 KiB
Forth
196 lines
9.0 KiB
Forth
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.battleItems |> Array.find (fun i -> i.Id = int HackId.Virus)
|
||
let defaultShield = Armory.battleItems |> Array.find (fun i -> i.Id = int ShieldId.Firewall)
|
||
|
||
let TrainerEvents = [|
|
||
{ Timestamp = System.DateTime.UtcNow
|
||
Adversary = Sensei
|
||
Type = PlayerEventType.Hacking
|
||
Result = PlayerEventResult.Positive
|
||
Cooldown = 5<mins>
|
||
IsInstigator = true
|
||
ItemId = defaultHack.Id }
|
||
{ Timestamp = System.DateTime.UtcNow
|
||
Adversary = DiscordPlayer.empty
|
||
Type = PlayerEventType.Shielding
|
||
Result = PlayerEventResult.Positive
|
||
Cooldown = defaultShield.Cooldown
|
||
IsInstigator = true
|
||
ItemId = defaultShield.Id }
|
||
|]
|
||
|
||
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 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"
|
||
+ "To enable it, you need to run the `/shield` slash command.\n\n"
|
||
+ $"Type the `/shield` command now, then select - `{defaultShield.Name}`\n")
|
||
})
|
||
|
||
let defend (ctx : IDiscordContext) =
|
||
async {
|
||
let builder = DiscordInteractionResponseBuilder()
|
||
builder.IsEphemeral <- true
|
||
builder.Content <- "Content"
|
||
do! ctx.Respond InteractionResponseType.DeferredChannelMessageWithSource builder |> Async.AwaitTask
|
||
let embed = Embeds.pickDefense "Trainer-2" { PlayerData.empty with Inventory = [| defaultShield |] } true
|
||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||
} |> Async.StartAsTask :> Task
|
||
|
||
let handleDefenseMsg hackId = {
|
||
ButtonId = "Trainer-3"
|
||
ButtonText = "Got it"
|
||
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) =
|
||
Game.executePlayerAction ctx (fun player -> async {
|
||
let sendMessage' = sendFollowUpMessage ctx
|
||
let split = ctx.GetInteractionId().Split("-")
|
||
let shieldId = enum<ShieldId>(int split.[2])
|
||
let shield = Armory.getItem (int shieldId)
|
||
let embed = Embeds.responseCreatedShield shield
|
||
do! ctx.FollowUp embed |> Async.AwaitTask
|
||
do! Async.Sleep 4000
|
||
do! sendMessage' $"Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now with **{defaultHack.Name}**"
|
||
do! Async.Sleep 5000
|
||
do! sendMessage' $"❌ HACKING FAILED!\n\n{player.Name} defended hack from <@{Sensei.Id}>!"
|
||
do! Async.Sleep 4000
|
||
do! sendFollowUpMessageWithButton ctx (handleDefenseMsg defaultHack.Name)
|
||
})
|
||
|
||
let handleTrainerStep3 (ctx : IDiscordContext) =
|
||
async {
|
||
let builder = DiscordInteractionResponseBuilder()
|
||
builder.IsEphemeral <- true
|
||
builder.Content <- "Content"
|
||
do! ctx.Respond InteractionResponseType.DeferredChannelMessageWithSource builder |> Async.AwaitTask
|
||
do! sendFollowUpMessage ctx
|
||
( "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.Name}`")
|
||
} |> Async.StartAsTask :> Task
|
||
|
||
let hack (target : DiscordUser) (ctx : IDiscordContext) =
|
||
Game.executePlayerAction ctx (fun player -> async {
|
||
let isRightTarget = target.Id = Sensei.Id
|
||
match isRightTarget with
|
||
| true ->
|
||
let bot = { PlayerData.empty with DiscordId = Sensei.Id ; Name = Sensei.Name }
|
||
let embed = Embeds.pickHack "Trainer-4" { player with Inventory = [| defaultHack |] } 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 handleHack (ctx : IDiscordContext) =
|
||
Game.executePlayerAction ctx (fun player -> async {
|
||
let sendMessage' = sendFollowUpMessage ctx
|
||
do! Async.Sleep 1000
|
||
let embed = Embeds.responseSuccessfulHack false Sensei.Id defaultHack
|
||
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 isFirstTrainer = player.Achievements |> Seq.contains trainerAchievement |> not
|
||
if isFirstTrainer then
|
||
do! DbService.addAchievement player.DiscordId trainerAchievement
|
||
|
||
sb.Append($"I'm going to gift you a hack,`{defaultHack.Name}` and a shield, `{defaultShield.Name}`") |> 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
|
||
|
||
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}> 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 hasStockWeapons = Player.getHacks player |> Array.exists (fun item -> item.Id = defaultHack.Id)
|
||
let updatedPlayer =
|
||
if not hasStockWeapons then {
|
||
Player.removeExpiredActions player with
|
||
Events = TrainerEvents |> Array.append player.Events
|
||
Inventory = [| defaultHack ; defaultShield |] |> Array.append player.Inventory
|
||
}
|
||
else
|
||
Player.removeExpiredActions player
|
||
if not hasStockWeapons then
|
||
do! DbService.updatePlayer updatedPlayer
|
||
let embed = Embeds.getArsenalEmbed updatedPlayer
|
||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||
if not (player.Achievements |> Array.contains trainerAchievement) then
|
||
do! Async.Sleep 3000
|
||
let rewards = [ $"{defaultHack.Name} Hack" ; $"{defaultShield.Name} Shield" ]
|
||
let embed = Embeds.getAchievementEmbed rewards "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! handleHack ctx |> Async.AwaitTask
|
||
| _ -> do! sendFollowUpMessage ctx "No action found"
|
||
}
|
||
|