230 lines
12 KiB
Forth
230 lines
12 KiB
Forth
module Degenz.Trainer
|
||
|
||
open System.Text
|
||
open DSharpPlus
|
||
open DSharpPlus.Entities
|
||
open DSharpPlus.EventArgs
|
||
open Degenz.Types
|
||
open Degenz.Messaging
|
||
|
||
let trainerAchievement = "FINISHED_TRAINER"
|
||
|
||
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.Encryption)
|
||
|
||
let sendInitialEmbed (client : DiscordClient) =
|
||
async {
|
||
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 steal 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
|
||
} |> Async.RunSynchronously
|
||
|
||
let handleTrainerStep1 (ctx : IDiscordContext) =
|
||
Game.executePlayerAction ctx (fun player -> async {
|
||
let shieldMessage , weaponName =
|
||
if Player.getShields player |> Array.isEmpty
|
||
then $"You do not have any Shields in your arsenal, take the `{defaultShield.Name}` shield, you can use it for now.\n\n" , defaultShield.Name
|
||
else
|
||
let name = Player.getShields player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name
|
||
$"Looks like you have `{name}` in your arsenal… 👀\n\n" , name
|
||
|
||
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee)
|
||
do! ctx.GetDiscordMember().GrantRoleAsync(role)
|
||
|> Async.AwaitTask
|
||
|
||
do! sendFollowUpMessage ctx
|
||
("Beautopia© is a dangerous place... quick, put up a SHIELD 🛡 before another Degen hacks you, and steals your 💰$GBT.\n\n"
|
||
+ shieldMessage
|
||
+ "To enable it, you need to run the `/shield` slash command.\n\n"
|
||
+ $"Type the `/shield` command now, then select - `{weaponName}`\n")
|
||
})
|
||
|
||
let defend (ctx : IDiscordContext) =
|
||
Game.executePlayerAction ctx (fun player -> async {
|
||
let playerWithShields =
|
||
match Player.getShields player with
|
||
| [||] -> { player with Arsenal = [| defaultShield |] }
|
||
| _ -> player
|
||
|
||
let embed = Embeds.pickDefense "Trainer-2" playerWithShields true
|
||
|
||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||
})
|
||
|
||
let handleDefenseMsg shieldId hackId = {
|
||
ButtonId = "Trainer-3"
|
||
ButtonText = "Got it"
|
||
Message = "🎉 Congratulations you successfully defended my hack!\n\n"
|
||
+ $"The `{shieldId}` shield is strong against the `{hackId}` hack, so make sure to have multiple shields up to protect from multiple attacks..."
|
||
+ "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) =
|
||
Game.executePlayerAction ctx (fun player -> async {
|
||
let sendMessage' = sendFollowUpMessage ctx
|
||
let split = ctx.GetInteractionId().Split("-")
|
||
let shieldId = enum<ShieldId>(int split.[2])
|
||
let shield = Armory.getItem (int shieldId)
|
||
let embed = Embeds.responseCreatedShield shield
|
||
do! ctx.FollowUp embed |> Async.AwaitTask
|
||
do! Async.Sleep 4000
|
||
let weakHack = Game.getGoodAgainst shield.Class
|
||
do! sendMessage' $"Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now with **{snd weakHack}**"
|
||
do! Async.Sleep 5000
|
||
do! sendMessage' $"❌ HACKING FAILED!\n\n{player.Name} defended hack from <@{GuildEnvironment.botIdHackerBattle}>!"
|
||
do! Async.Sleep 4000
|
||
do! sendFollowUpMessageWithButton ctx (handleDefenseMsg shieldId (snd weakHack))
|
||
|
||
})
|
||
let handleTrainerStep3 (ctx : IDiscordContext) =
|
||
Game.executePlayerAction ctx (fun player -> async {
|
||
let hackMessage , weaponName =
|
||
if Player.getHacks player |> Array.isEmpty
|
||
then $"You do not have any Hacks in your arsenal, take this `{defaultHack.Name}`, you can use it for now.\n\n" , defaultHack.Name
|
||
else
|
||
let name = Player.getHacks player |> Array.tryHead |> Option.defaultValue defaultHack |> fun w -> w.Name
|
||
$"Looks like you have `{name}` in your arsenal...\n\n" , name
|
||
|
||
do! sendFollowUpMessage ctx
|
||
("Now let’s **HACK!** 💻\n\n"
|
||
+ "I want you to **HACK ME**...\n\n"
|
||
+ hackMessage
|
||
+ "To deploy it, you need to run the `/hack` slash command.\n"
|
||
+ $"Type the `/hack` command now, then choose me - <@{GuildEnvironment.botIdHackerBattle}> as your target, and select `{weaponName}`")
|
||
})
|
||
|
||
let attack (target : DiscordUser) (ctx : IDiscordContext) =
|
||
Game.executePlayerAction ctx (fun player -> async {
|
||
let isRightTarget = target.Id = GuildEnvironment.botIdHackerBattle
|
||
match isRightTarget with
|
||
| true ->
|
||
let playerWithAttacks =
|
||
match Player.getHacks player with
|
||
| [||] -> { player with Arsenal = [| defaultHack |] }
|
||
| _ -> player
|
||
let bot = { player with DiscordId = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" }
|
||
let embed = Embeds.pickHack "Trainer-4" playerWithAttacks bot true
|
||
|
||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||
| false ->
|
||
let builder = DiscordFollowupMessageBuilder()
|
||
builder.Content <- "You picked the wrong target, you dufus. Try again, this time pick me!"
|
||
|
||
builder.IsEphemeral <- true
|
||
|
||
do! ctx.FollowUp(builder) |> Async.AwaitTask
|
||
})
|
||
|
||
let handleAttack (ctx : IDiscordContext) =
|
||
Game.executePlayerAction ctx (fun player -> async {
|
||
let sendMessage' = sendFollowUpMessage ctx
|
||
do! Async.Sleep 1000
|
||
let hack = Player.getHacks player |> Array.tryHead |> Option.defaultValue defaultHack
|
||
let embed = Embeds.responseSuccessfulHack false GuildEnvironment.botIdHackerBattle hack
|
||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||
do! Async.Sleep 5000
|
||
do! sendMessage'
|
||
("🎉 **Congratulations**\n\n"
|
||
+ "You successfully **HACKED** me, and are now an **Elite Haxor!**\n\n"
|
||
+ "When you **HACK** other Degenz, you **STEAL** their 💰$GBT.\n"
|
||
+ "But remember, hacks take time to recover, so use them wisely.")
|
||
|
||
do! Async.Sleep 6000
|
||
|
||
let sb = StringBuilder("Here, ")
|
||
|
||
let! achievements = DbService.getAchievements player.DiscordId
|
||
let isFirstTrainer = achievements |> Option.map (Seq.contains trainerAchievement >> not) |> Option.defaultValue true
|
||
if isFirstTrainer then
|
||
do! DbService.addAchievement player.DiscordId trainerAchievement
|
||
|
||
let hasHacks = Player.getHacks player |> Array.isEmpty |> not
|
||
let hasShields = Player.getShields player |> Array.isEmpty |> not
|
||
|
||
let rand = System.Random(System.Guid.NewGuid().GetHashCode())
|
||
let freeHack = Armory.hacks.[rand.Next(0, 3)]
|
||
let freeShield = Armory.shields.[rand.Next(0, 3)]
|
||
let hackMoney = if hasHacks then defaultHack.Cost else 0<GBT>
|
||
let shieldMoney = if hasShields then defaultShield.Cost else 0<GBT>
|
||
|
||
let giftMsg =
|
||
match hasHacks , hasShields with
|
||
| true , true -> $"I'm going to give you these {hackMoney + shieldMoney} 💰$GBT"
|
||
| false , true -> $"I'm going to gift you a hack, `{freeHack.Name}` and {defaultHack.Cost} 💰$GBT"
|
||
| true , false -> $"I'm going to gift you a shield, `{freeShield.Name}` and {defaultHack.Cost} 💰$GBT"
|
||
| false , false -> $"I'm going to gift you a hack,`{freeHack.Name}` and a shield, `{freeShield.Name}`"
|
||
|
||
sb.Append(giftMsg) |> 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
|
||
let updatedPlayer = {
|
||
player with Bank = player.Bank + hackMoney + shieldMoney
|
||
Actions = [
|
||
{ Action.Timestamp = System.DateTime.UtcNow
|
||
Action.Type =
|
||
Attack {
|
||
Result = true
|
||
Target = { Id = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" }
|
||
}
|
||
ActionId = defaultHack.Id
|
||
}
|
||
if not hasShields && Array.exists (fun act -> act.ActionId = freeShield.Id) player.Actions |> not then {
|
||
Action.Timestamp = System.DateTime.UtcNow
|
||
Action.Type = Defense
|
||
Action.ActionId = freeShield.Id
|
||
}
|
||
] |> Seq.toArray
|
||
|> Array.append player.Actions
|
||
Arsenal = [
|
||
if not hasHacks then freeHack
|
||
if not hasShields then freeShield
|
||
] |> Seq.toArray
|
||
|> Array.append player.Arsenal
|
||
}
|
||
do! DbService.updatePlayer updatedPlayer
|
||
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}> **NOW** 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 updatedPlayer = Player.removeExpiredActions false player
|
||
let embed = Embeds.getArsenalEmbed updatedPlayer
|
||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||
do! Async.Sleep 3000
|
||
let embed = Embeds.getAchievementEmbed "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 split = ctx.GetInteractionId().Split("-")
|
||
match int split.[1] with
|
||
| 1 -> do! handleTrainerStep1 ctx |> Async.AwaitTask
|
||
| 2 -> do! handleDefense ctx |> Async.AwaitTask
|
||
| 3 -> do! handleTrainerStep3 ctx |> Async.AwaitTask
|
||
| 4 -> do! handleAttack ctx |> Async.AwaitTask
|
||
| _ -> do! sendFollowUpMessage ctx "No action found"
|
||
}
|
||
|