231 lines
10 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 = "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 HackEvent = {
Timestamp = System.DateTime.UtcNow
Cooldown = 1<mins>
Type = Hacking {
Adversary = Sensei
Success = true
IsInstigator = true
HackId = defaultHack.Item.Id
}
}
let ShieldEvent = {
Timestamp = System.DateTime.UtcNow
Cooldown = defaultShield.Cooldown
Type = Shielding defaultShield.Item.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.Item.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 = [ Shield 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<ItemId>(int tokens.[2])
let playerName = tokens.[4]
let embed = Embeds.responseCreatedShield defaultShield
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.Item.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.Item.Name)
} |> 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.Item.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 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
} |> 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 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 player.DiscordId trainerAchievement
if not completed then
do! DbService.addAchievement player.DiscordId trainerAchievement
|> Async.Ignore
sb.Append($"I'm going to gift you a hack,`{defaultHack.Item.Name}` and a shield, `{defaultShield.Item.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) =
PlayerInteractions.executePlayerAction ctx (fun player -> async {
let hack =
if player.Inventory |> List.exists (fun i -> i.Id = defaultHack.Item.Id)
then []
else [ Hack defaultHack ]
let shield =
if player.Inventory |> List.exists (fun i -> i.Id = defaultShield.Item.Id)
then []
else [ Shield defaultShield ]
let shieldEvent =
let hasShield =
player
|> Player.removeExpiredActions
|> fun p -> p.Events
|> List.exists (fun e -> match e.Type with Shielding shieldId -> shieldId = defaultShield.Item.Id | _ -> false)
if hasShield
then []
else [ ShieldEvent ]
let updatedPlayer = {
Player.removeExpiredActions player with
Events = shieldEvent @ player.Events
Inventory = hack @ shield @ player.Inventory
}
if not (List.isEmpty hack) || not (List.isEmpty shield) then
do! DbService.updatePlayer updatedPlayer |> Async.Ignore
if not (List.isEmpty shieldEvent) then
do! DbService.addPlayerEvent player.DiscordId (List.head shieldEvent) |> Async.Ignore
let playerForEmbed = {
player with
Events = [ HackEvent ; ShieldEvent ]
Inventory = hack @ shield @ player.Inventory
}
let embed = Embeds.getArsenalEmbed playerForEmbed
do! ctx.FollowUp(embed) |> Async.AwaitTask
let! completed = DbService.checkHasAchievement player.DiscordId trainerAchievement
if not completed then
do! Async.Sleep 3000
let rewards = [ $"{defaultHack.Item.Name} Hack" ; $"{defaultShield.Item.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"
}