267 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 = "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 CurrencyGift = 250<GBT>
let BeginnerProtectionHours = 24
let HackEvent () = {
Timestamp = System.DateTime.UtcNow
Cooldown = 1<mins>
Type = Hacking {
Adversary = Sensei
Success = true
IsInstigator = true
HackId = defaultHack.Item.Id
}
}
let ShieldEvents () = [
{ Timestamp = System.DateTime.UtcNow
Cooldown = BeginnerProtectionHours * 60<mins>
Type = Shielding (int ItemId.Firewall) }
{ Timestamp = System.DateTime.UtcNow
Cooldown = BeginnerProtectionHours * 60<mins>
Type = Shielding (int ItemId.Encryption) }
{ Timestamp = System.DateTime.UtcNow
Cooldown = BeginnerProtectionHours * 60<mins>
Type = Shielding (int ItemId.Cypher) }
]
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.Item.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 = [ Shield defaultShield ] ; 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 shieldId = enum<ItemId>(int tokens.[2])
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.Item.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.Item.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.Item.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 = [ 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
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.Item.Name}`,
2. A shield - `{defaultShield.Item.Name}`,
3. `{CurrencyGift} 💰 $GBT`,
I'm also going to give you some **TEMPORARY SHIELDS** until you buy your own.
They will **ONLY** protect you from hacks for **{BeginnerProtectionHours} hrs**...
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 : ItemDetails) (inventory : Inventory) =
if inventory |> List.exists (fun i -> i.Id = weapon.Id)
then inventory
else weapon::inventory
let updatedPlayer = {
player with
Events =
player
|> Player.removeExpiredActions
|> fun p -> p.Events
|> List.filter (fun e -> match e.Type with Shielding _ -> false | _ -> true)
|> List.append (ShieldEvents())
|> List.consTo (HackEvent())
Inventory =
player.Inventory
|> addIfDoesntExist (Hack defaultHack)
|> addIfDoesntExist (Shield defaultShield)
Bank = player.Bank + CurrencyGift
}
do! DbService.updatePlayer updatedPlayer |> Async.Ignore
try
do! ShieldEvents ()
|> List.map (DbService.addPlayerEvent player.DiscordId)
|> Async.Parallel
|> Async.Ignore
with ex ->
printfn "%s" ex.Message
()
let embed = Embeds.getArsenalEmbed updatedPlayer
do! ctx.FollowUp(embed) |> Async.AwaitTask
do! Async.Sleep 2000
let rewards = [ $"{defaultHack.Item.Name} Hack" ; $"{defaultShield.Item.Name} Shield" ; $"{CurrencyGift} 💰$GBT"]
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! InviteTracker.acceptInvite ctx player |> 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"
}