Add hacker gif when issuing a hack command. Disable slot machine

This commit is contained in:
Joseph Ferano 2022-01-21 14:50:57 +07:00
parent a007f55c55
commit 9af3f7ef9d
9 changed files with 234 additions and 188 deletions

View File

@ -19,9 +19,10 @@ let playerInteractionsConfig = DiscordConfiguration()
let trainerConfig = DiscordConfiguration()
let hackerBattleConfig = DiscordConfiguration()
let storeConfig = DiscordConfiguration()
let slotMachineConfig = DiscordConfiguration()
//let slotMachineConfig = DiscordConfiguration()
let configs = [| playerInteractionsConfig ; trainerConfig ; hackerBattleConfig ; storeConfig ; slotMachineConfig ; |]
//let configs = [| playerInteractionsConfig ; trainerConfig ; hackerBattleConfig ; storeConfig ; slotMachineConfig ; |]
let configs = [| playerInteractionsConfig ; trainerConfig ; hackerBattleConfig ; storeConfig |]
for conf in configs do
conf.TokenType <- TokenType.Bot
@ -36,7 +37,7 @@ playerInteractionsConfig.Token <- Environment.GetEnvironmentVariable("BOT_PLAYER
trainerConfig.Token <- Environment.GetEnvironmentVariable("BOT_TRAINER")
hackerBattleConfig.Token <- Environment.GetEnvironmentVariable("BOT_HACKER_BATTLE")
storeConfig.Token <- Environment.GetEnvironmentVariable("BOT_STORE")
slotMachineConfig.Token <- Environment.GetEnvironmentVariable("BOT_SLOT_MACHINE")
//slotMachineConfig.Token <- Environment.GetEnvironmentVariable("BOT_SLOT_MACHINE")
//config.MinimumLogLevel <- Microsoft.Extensions.Logging.LogLevel.Trace
@ -44,24 +45,26 @@ let playerInteractionsBot = new DiscordClient(playerInteractionsConfig)
let trainerBot = new DiscordClient(trainerConfig)
let hackerBattleBot = new DiscordClient(hackerBattleConfig)
let storeBot = new DiscordClient(storeConfig)
let slotMachineBot = new DiscordClient(slotMachineConfig)
//let slotMachineBot = new DiscordClient(slotMachineConfig)
hackerBattleBot.add_ComponentInteractionCreated(AsyncEventHandler(HackerBattle.handleButtonEvent))
trainerBot.add_ComponentInteractionCreated(AsyncEventHandler(Trainer.handleButtonEvent))
storeBot.add_ComponentInteractionCreated(AsyncEventHandler(Store.handleSellButtonEvents))
let clients = [| playerInteractionsBot ; trainerBot ; hackerBattleBot ; storeBot ; slotMachineBot |]
//let clients = [| storeBot ; trainerBot ; hackerBattleBot ; playerInteractionsBot ; slotMachineBot |]
let clients = [| storeBot ; trainerBot ; hackerBattleBot ; playerInteractionsBot |]
let sc1 = playerInteractionsBot.UseSlashCommands()
let sc2 = trainerBot.UseSlashCommands()
let sc3 = hackerBattleBot.UseSlashCommands()
let sc4 = storeBot.UseSlashCommands()
let sc5 = slotMachineBot.UseSlashCommands()
//let sc5 = slotMachineBot.UseSlashCommands()
sc1.RegisterCommands<PlayerInteractions>(guild);
sc2.RegisterCommands<Trainer>(guild);
sc3.RegisterCommands<HackerGame>(guild);
sc4.RegisterCommands<Store>(guild);
sc5.RegisterCommands<SlotMachine>(guild);
//sc5.RegisterCommands<SlotMachine>(guild);
let run (client : DiscordClient) =
async {

View File

@ -27,8 +27,13 @@ let attack (ctx : InteractionContext) (target : DiscordUser) =
|> removeExpiredActions (TimeSpan.FromMinutes(15)) (fun (atk : Attack) -> atk.Timestamp)
do! DbService.updatePlayer <| { attacker with Attacks = updatedAttacks }
if updatedAttacks.Length < 2 then
let embed = DiscordEmbedBuilder()
embed.Color <- Optional(DiscordColor.PhthaloGreen)
embed.Description <- "Pick the hack that you want to use"
embed.ImageUrl <- "https://s10.gifyu.com/images/Hacker-Degenz-V2.gif"
let builder = DiscordInteractionResponseBuilder()
builder.AddEmbed (constructEmbed "Pick the hack you wish to use.") |> ignore
builder.AddEmbed (embed.Build()) |> ignore
let defenderInfo = $"{defender.DiscordId}-{target.Username}"
constructButtons "Attack" defenderInfo attacker.Weapons
@ -94,10 +99,10 @@ let defend (ctx : InteractionContext) =
let handleAttack (event : ComponentInteractionCreateEventArgs) =
let updatePlayer amount attack p =
{ p with Attacks = Array.append [| attack |] p.Attacks ; Bank = MathF.Max(p.Bank + amount, 0f) }
{ p with Attacks = Array.append [| attack |] p.Attacks ; Bank = Math.Max(p.Bank + amount, 0) }
async {
let split = event.Id.Split("-")
let weapon = Enum.Parse(typedefof<Weapon>, split.[1]) :?> Weapon
let weapon = Enum.Parse(typedefof<Hack>, split.[1]) :?> Hack
let ( resultId , targetId ) = UInt64.TryParse split.[2]
let! resultPlayer = DbService.tryFindPlayer event.User.Id
let! resultTarget = DbService.tryFindPlayer targetId
@ -114,7 +119,7 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
match wasSuccessfulHack with
| false ->
let prize = 1.337f // LEET
let attack = { HackType = enum<Weapon>(int weapon) ; Timestamp = DateTime.UtcNow ; Target = { Id = targetId ; Name = split.[3] } }
let attack = { HackType = enum<Hack>(int weapon) ; Timestamp = DateTime.UtcNow ; Target = { Id = targetId ; Name = split.[3] } }
// TODO: Make a single update instead of two
do! DbService.updatePlayer <| updatePlayer prize attack player
do! DbService.updatePlayer { target with Bank = MathF.Max(target.Bank - prize, 0f)}
@ -139,7 +144,7 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
|> Async.AwaitTask
let attack = { HackType = enum<Weapon>(int weapon) ; Timestamp = DateTime.UtcNow ; Target = { Id = targetId ; Name = split.[3] } }
let attack = { HackType = enum<Hack>(int weapon) ; Timestamp = DateTime.UtcNow ; Target = { Id = targetId ; Name = split.[3] } }
do! DbService.updatePlayer <| updatePlayer -prize attack player
do! DbService.updatePlayer { target with Bank = target.Bank + prize }

View File

@ -1,32 +1,32 @@
[
{
"Name" : "Virus",
"ItemType" : { "Case" : "Weapon" },
"ItemType" : { "Case" : "Hack" },
"Cost" : 5.0
},
{
"Name" : "Ransom",
"ItemType" : { "Case" : "Weapon" },
"ItemType" : { "Case" : "Hack" },
"Cost" : 10.0
},
{
"Name" : "Worm",
"ItemType" : { "Case" : "Weapon" },
"ItemType" : { "Case" : "Hack" },
"Cost" : 5.0
},
{
"Name" : "DDos",
"ItemType" : { "Case" : "Weapon" },
"ItemType" : { "Case" : "Hack" },
"Cost" : 10.0
},
{
"Name" : "Crack",
"ItemType" : { "Case" : "Weapon" },
"ItemType" : { "Case" : "Hack" },
"Cost" : 5.0
},
{
"Name" : "Injection",
"ItemType" : { "Case" : "Weapon" },
"ItemType" : { "Case" : "Hack" },
"Cost" : 10.0
},
{
@ -39,24 +39,24 @@
"ItemType" : { "Case" : "Shield" },
"Cost" : 10.0
},
{
"Name" : "Cypher",
"ItemType" : { "Case" : "Shield" },
"Cost" : 5.0
},
{
"Name" : "Encryption",
"ItemType" : { "Case" : "Shield" },
"Cost" : 10.0
},
{
"Name" : "Sanitation",
"ItemType" : { "Case" : "Shield" },
"Cost" : 5.0
},
{
"Name" : "Hardening",
"ItemType" : { "Case" : "Shield" },
"Cost" : 10.0
},
{
"Name" : "Cypher",
"ItemType" : { "Case" : "Shield" },
"Cost" : 5.0
},
{
"Name" : "Sanitation",
"ItemType" : { "Case" : "Shield" },
"Cost" : 10.0
}
]

View File

@ -75,6 +75,13 @@ module Commands =
} |> Async.StartAsTask
:> Task
[<CLIMutable>]
type LeaderboardEntry = {
Position : string
Amount : string
Name : string
}
let leaderboard (ctx : InteractionContext) =
async {
let builder = DiscordInteractionResponseBuilder()
@ -82,12 +89,12 @@ module Commands =
let! leaders = DbService.getTopPlayers 10
let content =
// TODO: There's a bug, it's not in the right order
leaders
|> Seq.toArray
|> Array.mapi (fun i p -> $"{i + 1}. {p.Bank} {p.Name}")
|> String.concat "\n"
builder.Content <- if not <| String.IsNullOrEmpty content then content else "There are no active hackers"
|> Array.sortByDescending (fun p -> p.Bank)
|> Array.mapi (fun i p -> { Position = string (i + 1) ; Amount = string p.Bank ; Name = p.Name })
|> Formatter.Format
builder.Content <- if not <| String.IsNullOrEmpty content then $"```{content}```" else "There are no active hackers"
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|> Async.AwaitTask
} |> Async.StartAsTask

View File

@ -8,6 +8,7 @@ open DSharpPlus.SlashCommands
open Degenz
open Degenz.Shared
open Newtonsoft.Json
open AsciiTableFormatter
let store =
try
@ -16,13 +17,43 @@ let store =
|> Array.groupBy (fun (i : Item) -> i.ItemType)
with _ -> [||]
//[<Sealed>]
//type Table() =
// member val Name = "" with get , set
// member val Cost = "" with get , set
// member val Class = "" with get , set
//
[<CLIMutable>]
type Table = {
Name : string
Cost : string
Class : string
}
let storeListing =
store
|> Array.map (fun ( itemType , items ) ->
let itemList = items |> Array.map (fun i -> $"{i.Name} - {i.Cost} GBT") |> String.concat "\n"
(constructEmbed $"{itemType}:\n{itemList}"))
let itemsData =
items
|> Array.map (fun (item : Item) ->
let itemClass =
if itemType = ItemType.Hack
then weaponInventory
|> Array.find (fun w -> item.Name = string w)
|> int
|> getClass
else shieldInventory
|> Array.find (fun w -> item.Name = string w)
|> int
|> getClass
{ Name = item.Name ; Cost = string item.Cost ; Class = string itemClass })
let table = Formatter.Format(ResizeArray(itemsData))
(constructEmbed $"**{itemType}s**\n```{table}```"))
module Commands =
let viewStore (ctx : InteractionContext) =
async {
let builder = DiscordInteractionResponseBuilder()
@ -41,14 +72,14 @@ module Commands =
let buyHack (ctx : InteractionContext) hackId =
async {
let! playerResult = DbService.tryFindPlayer ctx.Member.Id
let weapons = getItems ItemType.Weapon
let weapons = getItems ItemType.Hack
let weaponResult = weapons |> Array.tryFind (fun w -> w.Name = string hackId)
return!
match playerResult , weaponResult with
| Some player , Some item ->
async {
let newBalance = player.Bank - item.Cost
if newBalance >= 0.0f then
if newBalance >= 0 then
let playerHasItem = player.Weapons |> Array.exists (fun w -> item.Name = string w)
if not playerHasItem then
let weapon = weaponInventory |> Array.find (fun w -> item.Name = string w)
@ -76,7 +107,7 @@ module Commands =
| Some player , Some item ->
async {
let newBalance = player.Bank - item.Cost
if newBalance >= 0.0f then
if newBalance >= 0 then
let playerHasItem = player.Shields |> Array.exists (fun w -> item.Name = string w)
if not playerHasItem then
let shield = shieldInventory |> Array.find (fun w -> item.Name = string w)
@ -111,7 +142,7 @@ module Commands =
|> Array.iter
(fun wps ->
wps
|> Array.map (fun w -> DiscordButtonComponent(ButtonStyle.Primary, $"Weapon-{w}", $"{w}"))
|> Array.map (fun w -> DiscordButtonComponent(ButtonStyle.Primary, $"Hack-{w}", $"{w}"))
|> Seq.cast<DiscordComponent>
|> builder.AddComponents
|> ignore)
@ -141,23 +172,23 @@ module Commands =
match playerResult with
| Some player ->
let split = event.Id.Split("-")
let itemType = match split.[0] with "Weapon" -> ItemType.Weapon | _ -> ItemType.Shield
let itemType = match split.[0] with "Hack" -> ItemType.Hack | _ -> ItemType.Shield
let itemName = split.[1]
match itemType with
| ItemType.Weapon ->
let item = getItems ItemType.Weapon |> Array.find (fun w -> w.Name = itemName)
let salePrice = item.Cost / 2.f
let updatedWeapons = player.Weapons |> Array.filter (fun (w : Weapon) -> string w <> itemName)
| ItemType.Hack ->
let item = getItems ItemType.Hack |> Array.find (fun w -> w.Name = itemName)
let salePrice = item.Cost / 2
let updatedWeapons = player.Weapons |> Array.filter (fun (w : Hack) -> string w <> itemName)
let updatedPlayer = { player with Bank = player.Bank + salePrice ; Weapons = updatedWeapons }
do! DbService.updatePlayer updatedPlayer
let builder = DiscordInteractionResponseBuilder()
builder.IsEphemeral <- true
builder.Content <- $"Sold weapon {itemName} for {salePrice}! Current Balance: {updatedPlayer.Bank}"
builder.Content <- $"Sold hack {itemName} for {salePrice}! Current Balance: {updatedPlayer.Bank}"
do! event.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder)
|> Async.AwaitTask
| ItemType.Shield ->
let item = getItems ItemType.Shield |> Array.find (fun s -> s.Name = itemName)
let salePrice = item.Cost / 2.f
let salePrice = item.Cost / 2
let updatedShields = player.Shields |> Array.filter (fun (s : Shield) -> string s <> itemName)
let updatedPlayer = { player with Bank = player.Bank + salePrice ; Shields = updatedShields }
do! DbService.updatePlayer updatedPlayer
@ -179,17 +210,16 @@ type Store() =
inherit ApplicationCommandModule ()
[<SlashCommand("store", "View items available for purchase")>]
member _.ViewStore (ctx : InteractionContext) = Commands.viewStore ctx
member _.ViewStore (ctx : InteractionContext) = viewStore ctx
[<SlashCommand("buy-hack", "Purchase a hack attack you can use to earn GoodBoyTokenz")>]
member _.BuyHack (ctx : InteractionContext, [<Option("hack-id", "The ID of the hack you wish to purchase")>] hackId : Weapon) =
Commands.buyHack ctx hackId
member _.BuyHack (ctx : InteractionContext, [<Option("hack-id", "The ID of the hack you wish to purchase")>] hackId : Hack) =
buyHack ctx hackId
[<SlashCommand("buy-shield", "Purchase a hack shield so you can protect your GoodBoyTokenz")>]
member this.BuyShield (ctx : InteractionContext, [<Option("shield-id", "The ID of the shield you wish to purchase")>] shieldId : Shield) =
Commands.buyShield ctx shieldId
buyShield ctx shieldId
[<SlashCommand("sell", "Sell an item in your inventory for GoodBoyTokenz")>]
member this.SellItem (ctx : InteractionContext) =
Commands.sellItem ctx
member this.SellItem (ctx : InteractionContext) = sellItem ctx

View File

@ -2,3 +2,4 @@ FSharp.Core
DSharpPlus
DSharpPlus.SlashCommands
dotenv.net
DanielStout.AsciiTableFormatter

View File

@ -6,7 +6,7 @@ open DSharpPlus.Entities
open DSharpPlus.SlashCommands
type ItemType =
| Weapon
| Hack
| Shield
type ActionClass =
@ -14,7 +14,7 @@ type ActionClass =
| Exploit
| Penetration
type Weapon =
type Hack =
| Virus = 0
| Ransom = 1
| Worm = 2
@ -34,20 +34,17 @@ type Shield =
type Item = {
Name : string
ItemType : ItemType
Cost : single
Cost : int
}
let weaponInventory = [| Weapon.Virus ; Weapon.Ransom ; Weapon.DDos ; Weapon.Worm ; Weapon.Crack ; Weapon.Injection |]
let weaponInventory = [| Hack.Virus ; Hack.Ransom ; Hack.DDos ; Hack.Worm ; Hack.Crack ; Hack.Injection |]
let shieldInventory = [| Shield.Firewall ; Shield.PortScan ; Shield.Encryption ; Shield.Cypher ; Shield.Hardening ; Shield.Sanitation |]
let getClass =
function
| 0
| 1 -> Network
| 2
| 3 -> Exploit
| 4
| _ -> Penetration
| 0 | 1 -> Network
| 2 | 3 -> Exploit
| 4 | _ -> Penetration
type HackResult =
| Strong
@ -58,7 +55,7 @@ type DiscordPlayer = { Id: uint64; Name: string }
[<CLIMutable>]
type Attack =
{ HackType: Weapon
{ HackType: Hack
Target: DiscordPlayer
Timestamp: DateTime }
@ -71,11 +68,11 @@ type Defense =
type Player =
{ DiscordId: uint64
Name: string
Weapons: Weapon array
Weapons: Hack array
Shields: Shield array
Attacks: Attack array
Defenses: Defense array
Bank: single }
Bank: int }
let createSimpleResponseAsync msg (ctx: InteractionContext) =

View File

@ -13,3 +13,5 @@ nuget DSharpPlus.SlashCommands >= 4.2.0-nightly-01061
nuget MongoDB.Driver
nuget dotenv.net 3.1.1
nuget DanielStout.AsciiTableFormatter

View File

@ -2,6 +2,7 @@ STORAGE: NONE
RESTRICTION: || (== net6.0) (== netstandard2.0) (== netstandard2.1)
NUGET
remote: https://api.nuget.org/v3/index.json
DanielStout.AsciiTableFormatter (1.1)
DnsClient (1.5)
Microsoft.Win32.Registry (>= 5.0)
System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= net471)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net471)) (&& (== netstandard2.1) (< netstandard2.0))