213 lines
9.7 KiB
Forth
213 lines
9.7 KiB
Forth
module Degenz.Trainer
|
||
|
||
open System.Text
|
||
open System.Threading.Tasks
|
||
open DSharpPlus
|
||
open DSharpPlus.Entities
|
||
open DSharpPlus.EventArgs
|
||
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
|
||
Cooldown = 2<mins>
|
||
Type = Hacking {
|
||
Adversary = Sensei
|
||
Success = true
|
||
IsInstigator = true
|
||
HackId = defaultHack.Id } }
|
||
{ Timestamp = System.DateTime.UtcNow
|
||
Cooldown = defaultShield.Cooldown
|
||
Type = Shielding defaultShield.Id }
|
||
|]
|
||
|
||
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.Name}`\n"
|
||
let builder =
|
||
DiscordInteractionResponseBuilder()
|
||
.WithContent(msg)
|
||
.AsEphemeral(true)
|
||
|
||
do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, builder) |> Async.AwaitTask
|
||
} |> 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 = [| defaultShield |] ; Name = name } 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) =
|
||
async {
|
||
do! Messaging.defer ctx
|
||
|
||
let sendMessage' = sendFollowUpMessage ctx
|
||
let tokens = ctx.GetInteractionId().Split("-")
|
||
let shieldId = enum<ShieldId>(int tokens.[2])
|
||
let shield = Armory.getItem (int shieldId)
|
||
let playerName = tokens.[4]
|
||
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{playerName} defended hack from <@{Sensei.Id}>!"
|
||
do! Async.Sleep 4000
|
||
do! sendFollowUpMessageWithButton ctx (handleDefenseMsg defaultHack.Name)
|
||
} |> 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
|
||
} |> 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 bot = { PlayerData.empty with DiscordId = Sensei.Id ; Name = Sensei.Name }
|
||
let embed = Embeds.pickHack "Trainer-4" { PlayerData.empty with Inventory = [| defaultHack |] } 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
|
||
} |> Async.StartAsTask :> Task
|
||
|
||
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.Power defaultHack
|
||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||
do! Async.Sleep 4000
|
||
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! Async.Sleep 5000
|
||
|
||
let sb = StringBuilder("Here, ")
|
||
|
||
let! completed = DbService.checkHasAchievement GuildEnvironment.pgDb player.DiscordId trainerAchievement
|
||
if not completed then
|
||
do! DbService.addAchievement GuildEnvironment.pgDb player.DiscordId trainerAchievement
|
||
|> Async.Ignore
|
||
|
||
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.addPlayerEvent GuildEnvironment.pgDb player.DiscordId TrainerEvents.[0]
|
||
DbService.addPlayerEvent GuildEnvironment.pgDb player.DiscordId TrainerEvents.[1]
|
||
DbService.updatePlayer GuildEnvironment.pgDb updatedPlayer ]
|
||
|> Async.Parallel
|
||
|> Async.Ignore
|
||
let embed = Embeds.getArsenalEmbed updatedPlayer
|
||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||
|
||
let! completed = DbService.checkHasAchievement GuildEnvironment.pgDb player.DiscordId trainerAchievement
|
||
if not completed 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 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"
|
||
}
|
||
|