Several improvements and enhacements

This commit is contained in:
Joseph Ferano 2022-02-08 23:33:30 +07:00
parent b12dfe6788
commit 8f8aebd6ac
7 changed files with 63 additions and 34 deletions

View File

@ -21,9 +21,11 @@ let storeConfig = DiscordConfiguration()
//let configs = [| hackerBattleConfig ; storeConfig ; slotMachineConfig ; |] //let configs = [| hackerBattleConfig ; storeConfig ; slotMachineConfig ; |]
let configs = [ hackerBattleConfig ; storeConfig ] let configs = [ hackerBattleConfig ; storeConfig ]
for conf in configs do hackerBattleConfig.TokenType <- TokenType.Bot
conf.TokenType <- TokenType.Bot hackerBattleConfig.Intents <- DiscordIntents.All
conf.Intents <- DiscordIntents.All
storeConfig.TokenType <- TokenType.Bot
storeConfig.Intents <- DiscordIntents.All
hackerBattleConfig.Token <- GuildEnvironment.tokenHackerBattle hackerBattleConfig.Token <- GuildEnvironment.tokenHackerBattle
storeConfig.Token <- GuildEnvironment.tokenStore storeConfig.Token <- GuildEnvironment.tokenStore
@ -34,8 +36,6 @@ let storeBot = new DiscordClient(storeConfig)
//let slotMachineBot = new DiscordClient(slotMachineConfig) //let slotMachineBot = new DiscordClient(slotMachineConfig)
//let clients = [| hackerBattleBot ; storeBot ; slotMachineBot |] //let clients = [| hackerBattleBot ; storeBot ; slotMachineBot |]
let clients = [ hackerBattleBot ; storeBot ]
let sc1 = hackerBattleBot.UseSlashCommands() let sc1 = hackerBattleBot.UseSlashCommands()
let sc2 = storeBot.UseSlashCommands() let sc2 = storeBot.UseSlashCommands()
//let sc3 = slotMachineBot.UseSlashCommands() //let sc3 = slotMachineBot.UseSlashCommands()
@ -63,12 +63,27 @@ let asdf (_ : DiscordClient) (event : DSharpPlus.EventArgs.InteractionCreateEven
:> Task :> Task
//hackerBattleBot.add_InteractionCreated(AsyncEventHandler(asdf)) //hackerBattleBot.add_InteractionCreated(AsyncEventHandler(asdf))
if guild <> 922419263275425832uL then
Trainer.sendInitialEmbed hackerBattleBot
let run (client : DiscordClient) = let run (client : DiscordClient) =
async { async {
do! client.ConnectAsync () |> Async.AwaitTask do! client.ConnectAsync () |> Async.AwaitTask
} }
Trainer.sendInitialEmbed hackerBattleBot let clients =
if guild = 922419263275425832uL then
let interactionsConfig = DiscordConfiguration()
interactionsConfig.TokenType <- TokenType.Bot
interactionsConfig.Intents <- DiscordIntents.All
interactionsConfig.Token <- GuildEnvironment.tokenPlayerInteractions
let interactionsBot = new DiscordClient(interactionsConfig)
let commands = interactionsBot.UseSlashCommands()
commands.RegisterCommands<PlayerInteractions.PlayerInteractions>(guild)
[ hackerBattleBot ; storeBot ; interactionsBot ]
else
[ hackerBattleBot ; storeBot ]
clients clients
|> List.map run |> List.map run

View File

@ -1,6 +1,7 @@
module Degenz.Embeds module Degenz.Embeds
open System open System
open DSharpPlus
open DSharpPlus.EventArgs open DSharpPlus.EventArgs
open Degenz.Types open Degenz.Types
open DSharpPlus.Entities open DSharpPlus.Entities
@ -32,13 +33,16 @@ let getShieldGif = function
| ShieldId.Cypher -> "https://s10.gifyu.com/images/Cypher-Smaller.gif" | ShieldId.Cypher -> "https://s10.gifyu.com/images/Cypher-Smaller.gif"
| _ -> shieldGif | _ -> shieldGif
let constructButtons (actionType: string) (playerInfo: string) (items: BattleItem array) = let constructButtons (actionType: string) (player: PlayerData) (buttonId : string) (items: BattleItem array) =
items items
|> Array.map (fun item -> DiscordButtonComponent(Game.getClassButtonColor item.Class, $"{actionType}-{item.Id}-{playerInfo}", $"{item.Name}")) |> Array.map (fun item ->
match player.Actions |> Array.exists (fun i -> i.ActionId = item.Id) with
| true -> DiscordButtonComponent(Game.getClassButtonColor item.Class, $"{actionType}-{item.Id}", $"{item.Name} (on cooldown)", true)
| false -> DiscordButtonComponent(Game.getClassButtonColor item.Class, $"{actionType}-{item.Id}-{buttonId}", $"{item.Name}"))
let pickDefense actionId player = let pickDefense actionId player =
let buttons = let buttons =
constructButtons actionId (string player.DiscordId) (Player.shields player) constructButtons actionId player (string player.DiscordId) (Player.shields player)
|> Seq.cast<DiscordComponent> |> Seq.cast<DiscordComponent>
let embed = let embed =
@ -55,7 +59,7 @@ let pickDefense actionId player =
let pickHack actionId attacker defender = let pickHack actionId attacker defender =
let buttons = let buttons =
let hacks = Player.hacks attacker let hacks = Player.hacks attacker
constructButtons actionId $"{defender.DiscordId}-{defender.Name}" hacks constructButtons actionId attacker $"{defender.DiscordId}-{defender.Name}" hacks
|> Seq.cast<DiscordComponent> |> Seq.cast<DiscordComponent>
let embed = let embed =
@ -69,12 +73,12 @@ let pickHack actionId attacker defender =
.AddEmbed(embed.Build()) .AddEmbed(embed.Build())
.AsEphemeral true .AsEphemeral true
let responseSuccessfulHack (targetId : uint64) (hack : BattleItem) = let responseSuccessfulHack (targetName : string) (hack : BattleItem) =
let embed = DiscordEmbedBuilder() let embed = DiscordEmbedBuilder()
embed.ImageUrl <- getHackGif (enum<HackId>(hack.Id)) embed.ImageUrl <- getHackGif (enum<HackId>(hack.Id))
DiscordFollowupMessageBuilder() DiscordFollowupMessageBuilder()
.WithContent($"You successfully hacked <@{targetId}> using {hack.Name}, and stole 💰$GBT {Game.HackPrize} from them!") .WithContent($"You successfully hacked {targetName} using {hack.Name}, and stole 💰$GBT {Game.HackPrize} from them!")
.AddEmbed(embed.Build()) .AddEmbed(embed.Build())
.AsEphemeral(true) .AsEphemeral(true)
@ -90,20 +94,20 @@ let responseCreatedShieldTrainer (shield : BattleItem) =
.AsEphemeral(true) .AsEphemeral(true)
.WithContent($"Mounted a {shield.Name} defense for {TimeSpan.FromMinutes(int shield.Cooldown).Hours} hours") .WithContent($"Mounted a {shield.Name} defense for {TimeSpan.FromMinutes(int shield.Cooldown).Hours} hours")
let eventSuccessfulHack (event : ComponentInteractionCreateEventArgs) targetId prize = let eventSuccessfulHack (event : ComponentInteractionCreateEventArgs) target prize =
DiscordMessageBuilder() DiscordMessageBuilder()
.WithContent($"{event.User.Username} successfully hacked <@{targetId}> for a total of {prize} GoodBoyTokenz") .WithContent($"{event.User.Username} successfully hacked {target.Name} for a total of {prize} GoodBoyTokenz")
let eventFailedHack (event : ComponentInteractionCreateEventArgs) targetId prize = let eventFailedHack (event : ComponentInteractionCreateEventArgs) target prize =
DiscordMessageBuilder() DiscordMessageBuilder()
.WithContent($"{event.User.Username} successfully hacked <@{targetId}> for a total of {prize} GoodBoyTokenz") .WithContent($"{event.User.Username} successfully hacked {target.Name} for a total of {prize} GoodBoyTokenz")
let getGoodAgainst = function let getGoodAgainst = function
| BattleClass.Network -> ( ShieldId.Firewall , HackId.Virus ) | BattleClass.Network -> ( ShieldId.Firewall , HackId.Virus )
| BattleClass.Penetration -> ( ShieldId.Cypher , HackId.RemoteAccess ) | BattleClass.Penetration -> ( ShieldId.Cypher , HackId.RemoteAccess )
| BattleClass.Exploit -> ( ShieldId.Encryption , HackId.Worm ) | BattleClass.Exploit -> ( ShieldId.Encryption , HackId.Worm )
let getBuyItemsEmbed (itemType : ItemType) (store : BattleItem array) = let getBuyItemsEmbed (player : PlayerData) (itemType : ItemType) (store : BattleItem array) =
let embeds , buttons = let embeds , buttons =
store store
|> Array.filter (fun i -> i.Type = itemType) |> Array.filter (fun i -> i.Type = itemType)
@ -127,7 +131,10 @@ let getBuyItemsEmbed (itemType : ItemType) (store : BattleItem array) =
.WithColor(Game.getClassEmbedColor item.Class) .WithColor(Game.getClassEmbedColor item.Class)
.WithTitle($"{item.Name}") .WithTitle($"{item.Name}")
|> ignore |> ignore
let button = DiscordButtonComponent(Game.getClassButtonColor item.Class, $"Buy-{item.Id}", $"Buy {item.Name}") let button =
if player.Arsenal |> Array.exists (fun i -> i.Id = item.Id)
then DiscordButtonComponent(Game.getClassButtonColor item.Class, $"Buy-{item.Id}", $"Own {item.Name}", true)
else DiscordButtonComponent(Game.getClassButtonColor item.Class, $"Buy-{item.Id}", $"Buy {item.Name}")
embed.Build() , button :> DiscordComponent) embed.Build() , button :> DiscordComponent)
|> Array.unzip |> Array.unzip

View File

@ -33,11 +33,11 @@ module Game =
let! playerResult = tryFindPlayer ctx.Member.Id let! playerResult = tryFindPlayer ctx.Member.Id
match playerResult with match playerResult with
| Some player -> do! dispatch player | Some player -> do! dispatch player
| None -> do! Messaging.sendSimpleResponse ctx "You are currently not a hacker, first use the /redpill command to become one" | None -> do! Messaging.sendFollowUpMessageFromCtx ctx "You are currently not a hacker, first use the /redpill command to become one"
} |> Async.StartAsTask } |> Async.StartAsTask
:> Task :> Task
// TODO: Create an abstraction for these two helper functions // TODO J: Create an abstraction for these two helper functions
let executePlayerEvent (event : ComponentInteractionCreateEventArgs) (dispatch : PlayerData -> Async<unit>) = let executePlayerEvent (event : ComponentInteractionCreateEventArgs) (dispatch : PlayerData -> Async<unit>) =
async { async {
let builder = DiscordInteractionResponseBuilder() let builder = DiscordInteractionResponseBuilder()

View File

@ -9,6 +9,8 @@ open DSharpPlus.SlashCommands
open Degenz open Degenz
open Degenz.Messaging open Degenz.Messaging
// TODO: Do not allow any attacks until the user has completed training
// TODO: Introduce second round of weapons, more expensive and with better stats
let checkPlayerIsAttackingThemselves defender attacker = let checkPlayerIsAttackingThemselves defender attacker =
match attacker.DiscordId = defender.DiscordId with match attacker.DiscordId = defender.DiscordId with
| true -> Error "You think you're clever? You can't hack yourself, pal." | true -> Error "You think you're clever? You can't hack yourself, pal."
@ -77,12 +79,12 @@ let successfulHack (event : ComponentInteractionCreateEventArgs) attacker defend
async { async {
do! updateCombatants attacker defender hack Game.HackPrize do! updateCombatants attacker defender hack Game.HackPrize
let embed = Embeds.responseSuccessfulHack (defender.DiscordId) (Armory.getItem (int hack)) let embed = Embeds.responseSuccessfulHack (defender.Name) (Armory.getItem (int hack))
do! event.Interaction.CreateFollowupMessageAsync(embed) do! event.Interaction.CreateFollowupMessageAsync(embed)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore |> Async.Ignore
let builder = Embeds.eventSuccessfulHack event defender.DiscordId Game.HackPrize let builder = Embeds.eventSuccessfulHack event defender Game.HackPrize
let channel = event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle) let channel = event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle)
do! channel.SendMessageAsync(builder) do! channel.SendMessageAsync(builder)
|> Async.AwaitTask |> Async.AwaitTask
@ -97,7 +99,7 @@ let failedHack (event : ComponentInteractionCreateEventArgs) attacker defender h
do! updateCombatants attacker defender hack -Game.ShieldPrize do! updateCombatants attacker defender hack -Game.ShieldPrize
let builder = DiscordMessageBuilder() let builder = DiscordMessageBuilder()
builder.WithContent($"Hacking attempt failed! <@{defender.DiscordId}> defended hack from {event.User.Username} and stole {Game.ShieldPrize} $GBT from them! ") |> ignore builder.WithContent($"Hacking attempt failed! {defender.Name} defended hack from {event.User.Username} and stole {Game.ShieldPrize} $GBT from them! ") |> ignore
let channel = (event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle)) let channel = (event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle))
do! channel.SendMessageAsync(builder) do! channel.SendMessageAsync(builder)
|> Async.AwaitTask |> Async.AwaitTask
@ -122,7 +124,11 @@ let attack (target : DiscordUser) (ctx : InteractionContext) =
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore |> Async.Ignore
| Error msg -> sendFollowUpMessageFromCtx ctx msg | Error msg -> sendFollowUpMessageFromCtx ctx msg
| None -> do! sendFollowUpMessageFromCtx ctx "Your target is not connected to the network, they must join first by using the /redpill command" | None ->
if target.IsBot
then do! sendFollowUpMessageFromCtx ctx $"{target.Username} is a bot, pick a real human to hack"
else do! sendFollowUpMessageFromCtx ctx "Your target is not connected to the network, they must join first by using the /redpill command"
}) })
let handleAttack (event : ComponentInteractionCreateEventArgs) = let handleAttack (event : ComponentInteractionCreateEventArgs) =

View File

@ -61,7 +61,7 @@ let arsenal (ctx : InteractionContext) =
let buy itemType (ctx : InteractionContext) = let buy itemType (ctx : InteractionContext) =
Game.executePlayerInteraction ctx (fun player -> async { Game.executePlayerInteraction ctx (fun player -> async {
let itemStore = Embeds.getBuyItemsEmbed itemType Armory.battleItems let itemStore = Embeds.getBuyItemsEmbed player itemType Armory.battleItems
do! ctx.Interaction.CreateFollowupMessageAsync(itemStore) do! ctx.Interaction.CreateFollowupMessageAsync(itemStore)
|> Async.AwaitTask |> Async.AwaitTask
|> Async.Ignore |> Async.Ignore
@ -133,8 +133,7 @@ type Store() =
let enforceChannel (ctx : InteractionContext) (storeFn : InteractionContext -> Task) = let enforceChannel (ctx : InteractionContext) (storeFn : InteractionContext -> Task) =
match ctx.Channel.Id with match ctx.Channel.Id with
| id when id = GuildEnvironment.channelArmory -> | id when id = GuildEnvironment.channelArmory -> storeFn ctx
storeFn ctx
| _ -> | _ ->
task { task {
let msg = $"You must go to <#{GuildEnvironment.channelArmory}> channel to buy/sell or check your arsenal" let msg = $"You must go to <#{GuildEnvironment.channelArmory}> channel to buy/sell or check your arsenal"

View File

@ -8,6 +8,9 @@ open DSharpPlus.SlashCommands
open Degenz.Types open Degenz.Types
open Degenz.Messaging open Degenz.Messaging
// TODO: We should either gift the weapons to the player during training, or have them buy it
// TODO: We should tell the user to type out /arsenal during the training
// TODO: How do we handle the money being generated here? It's fake but fake is confusing
let defaultHack = Armory.battleItems |> Array.find (fun i -> i.Id = int HackId.Virus) 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 defaultShield = Armory.battleItems |> Array.find (fun i -> i.Id = int ShieldId.Encryption)
@ -136,7 +139,7 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
let sendMessage' = sendFollowUpMessage event let sendMessage' = sendFollowUpMessage event
do! Async.Sleep 1000 do! Async.Sleep 1000
let hack = Player.hacks player |> Array.tryHead |> Option.defaultValue defaultHack let hack = Player.hacks player |> Array.tryHead |> Option.defaultValue defaultHack
let embed = Embeds.responseSuccessfulHack GuildEnvironment.botHackerBattle hack let embed = Embeds.responseSuccessfulHack "Sensei" hack
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
do! Async.Sleep 5000 do! Async.Sleep 5000
do! sendMessage' do! sendMessage'

View File

@ -99,7 +99,7 @@ module Messaging =
let plural amount = if amount = 1 then "" else "s" let plural amount = if amount = 1 then "" else "s"
let ``and`` = if remaining.Hours > 0 then "and " else "" let ``and`` = if remaining.Hours > 0 then "and " else ""
let hours = if remaining.Hours > 0 then $"{remaining.Hours} hour{plural remaining.Hours} {``and``}" else String.Empty let hours = if remaining.Hours > 0 then $"{remaining.Hours} hour{plural remaining.Hours} {``and``}" else String.Empty
let totalMins = remaining.Minutes + 1 let totalMins = remaining.Minutes
let minutes = if totalMins > 0 then $"{totalMins} minute{plural totalMins}" else "1 minute" let minutes = if totalMins > 0 then $"{totalMins} minute{plural totalMins}" else "1 minute"
$"{hours}{minutes}" $"{hours}{minutes}"
@ -114,12 +114,11 @@ module Messaging =
| _ -> | _ ->
actions actions
|> Array.map (fun act -> |> Array.map (fun act ->
match act.Type with
| Attack atk -> $"Hacked {atk.Target.Name} at {act.Timestamp.ToShortTimeString()}"
| Defense ->
let item = Armory.getItem act.ActionId let item = Armory.getItem act.ActionId
let cooldown = getTimeTillCooldownFinishes (System.TimeSpan.FromMinutes(int item.Cooldown)) act.Timestamp let cooldown = getTimeTillCooldownFinishes (System.TimeSpan.FromMinutes(int item.Cooldown)) act.Timestamp
$"{item.Name} active for {cooldown}") match act.Type with
| Attack atk -> $"Hacked {atk.Target.Name} {cooldown} ago"
| Defense -> $"{item.Name} Shield active for {cooldown}")
|> String.concat "\n" |> String.concat "\n"
let sendSimpleResponse (ctx: InteractionContext) msg = let sendSimpleResponse (ctx: InteractionContext) msg =