248 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 System.Threading.Tasks
open DSharpPlus
open DSharpPlus.Entities
open Degenz.Types
open Degenz.Messaging
let TrainerAchievement = "LEARN_TO_HACKER_BATTLE_QUEST_COMPLETED"
let Sensei = { Id = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" }
let hackItem = Arsenal.weapons |> Inventory.findItemById (string ItemId.REMOTE)
let shieldItem = Arsenal.weapons |> Inventory.findItemById (string ItemId.FIREWALL)
let defaultHack = (Inventory.getHackItem hackItem).Value
let defaultShield = (Inventory.getShieldItem shieldItem ).Value
let HackEvent () = {
Timestamp = System.DateTime.UtcNow
Cooldown = 1<mins>
Type = Hacking {
Adversary = Sensei
Success = true
IsInstigator = true
HackId = defaultHack.Id
}
}
let ShieldEvent () = {
Timestamp = System.DateTime.UtcNow
Cooldown = defaultShield.Cooldown
Type = Shielding defaultShield.Id
}
let sendInitialEmbed (ctx : IDiscordContext) =
async {
try
let channel = ctx.GetGuild().GetChannel(GuildEnvironment.channelTraining)
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! GuildEnvironment.botClientHacker.Value.SendMessageAsync(channel, 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.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 = [ shieldItem ] ; 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 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.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.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 lets **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}`")
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 = [ hackItem ] }
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.Name}`,
2. A shield - `{defaultShield.Name}`,
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 : Item) (inventory : Inventory) =
if inventory |> List.exists (fun i -> i.Id = weapon.Id)
then inventory
else weapon::inventory
if player.Inventory |> List.exists (fun i -> i.Id = hackItem.Id) |> not then
do! DbService.addToPlayerInventory player.DiscordId hackItem |> Async.Ignore
if player.Inventory |> List.exists (fun i -> i.Id = shieldItem.Id) |> not then
do! DbService.addToPlayerInventory player.DiscordId shieldItem |> Async.Ignore
let updatedPlayer = {
player with
Events =
player
|> Player.removeExpiredActions
|> fun p -> p.Events
|> List.filter (fun e -> match e.Type with Shielding shieldId -> shieldId <> defaultShield.Id | _ -> true)
|> (@) [ HackEvent() ; ShieldEvent() ]
Inventory =
player.Inventory
|> addIfDoesntExist hackItem
|> addIfDoesntExist shieldItem
}
let embed = Embeds.getArsenalEmbed updatedPlayer
do! ctx.FollowUp(embed) |> Async.AwaitTask
do! Async.Sleep 2000
let rewards = [ $"{defaultHack.Name} Hack" ; $"{defaultShield.Name} Shield" ]
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! 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"
}