249 lines
12 KiB
Forth
249 lines
12 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 = "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 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}`")
|
||
|
||
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 0 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 bot = { PlayerData.empty with DiscordId = Sensei.Id ; Name = Sensei.Name }
|
||
let embed = Embeds.responseSuccessfulHack player bot (defaultHack.Power * 1<GBT>) 0<GBT> 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"
|
||
}
|
||
|