Store: Buy Weapons and Shields, and selling
This commit is contained in:
parent
5ef3243c41
commit
07246dcdb2
@ -10,8 +10,11 @@ type PlayerEntry = {
|
||||
Player : Player
|
||||
}
|
||||
|
||||
let mongo = MongoClient("mongodb://localhost:27017")
|
||||
let db = mongo.GetDatabase("degenz-game")
|
||||
//let connString = "mongodb://localhost:27017"
|
||||
let connString = "mongodb+srv://joe:mtmu3XXe3crUfXdO@stage.2hyxh.mongodb.net/degenz?retryWrites=true&w=majority"
|
||||
|
||||
let mongo = MongoClient(connString)
|
||||
let db = mongo.GetDatabase("degenz")
|
||||
let players = db.GetCollection<PlayerEntry>("players")
|
||||
|
||||
let tryFindPlayer (id : uint64) : Async<Player option> =
|
||||
@ -38,13 +41,6 @@ let removePlayer (memberId : uint64) =
|
||||
|> Async.Ignore
|
||||
}
|
||||
|
||||
let updateAttacks (playerId : uint64) (attacks : Attack array) =
|
||||
async {
|
||||
let filter = Builders<PlayerEntry>.Filter.Eq((fun e -> e.Player.DiscordId), playerId)
|
||||
let update = Builders<PlayerEntry>.Update.Set((fun e -> e.Player.Attacks), attacks)
|
||||
return! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore
|
||||
}
|
||||
|
||||
let updatePlayer player =
|
||||
async {
|
||||
let filter = Builders<PlayerEntry>.Filter.Eq((fun e -> e.Player.DiscordId), player.DiscordId)
|
||||
|
@ -24,7 +24,7 @@ let attack (ctx : InteractionContext) (target : DiscordUser) =
|
||||
let updatedAttacks =
|
||||
attacker.Attacks
|
||||
|> removeExpiredActions (TimeSpan.FromMinutes(15)) (fun (atk : Attack) -> atk.Timestamp)
|
||||
do! DbService.updateAttacks attacker.DiscordId updatedAttacks
|
||||
do! DbService.updatePlayer <| { attacker with Attacks = updatedAttacks }
|
||||
if updatedAttacks.Length < 2 then
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.AddEmbed (constructEmbed "Pick the hack you wish to use.") |> ignore
|
||||
|
@ -15,7 +15,7 @@ type HackerGame() =
|
||||
member this.AttackCommand (ctx : InteractionContext, [<Option("target", "The player you want to hack")>] target : DiscordUser) =
|
||||
Commands.attack ctx target
|
||||
|
||||
[<SlashCommand("defend", "Create a passive defense that will last a certain amount of time")>]
|
||||
[<SlashCommand("defend", "Create a passive defense that will last 24 hours")>]
|
||||
member this.DefendCommand (ctx : InteractionContext) = Commands.defend ctx
|
||||
|
||||
let config = DiscordConfiguration()
|
@ -15,7 +15,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Commands.fs" />
|
||||
<Compile Include="Program.fs" />
|
||||
<Compile Include="HackerBattle.fs" />
|
||||
<Content Include="paket.references" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<RootNamespace>PlayerRegistration</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.fs" />
|
||||
<Compile Include="PlayerInteractions.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include=".dockerignore" />
|
||||
|
@ -6,8 +6,8 @@ open DSharpPlus.Entities
|
||||
open DSharpPlus.SlashCommands
|
||||
|
||||
type ItemType =
|
||||
| Weapon = 0
|
||||
| Shield = 1
|
||||
| Weapon
|
||||
| Shield
|
||||
|
||||
type ActionClass =
|
||||
| Network
|
||||
@ -40,7 +40,6 @@ type Item = {
|
||||
let weaponInventory = [| Weapon.Virus ; Weapon.Ransom ; Weapon.DDos ; Weapon.Worm ; Weapon.Crack ; Weapon.Injection |]
|
||||
let shieldInventory = [| Shield.Firewall ; Shield.PortScan ; Shield.Encryption ; Shield.Cypher ; Shield.Hardening ; Shield.Sanitation |]
|
||||
|
||||
|
||||
let getClass =
|
||||
function
|
||||
| 0
|
||||
@ -91,7 +90,7 @@ let createSimpleResponseAsync msg (ctx: InteractionContext) =
|
||||
}
|
||||
|
||||
let notYetAHackerMsg =
|
||||
createSimpleResponseAsync "You are not currently a hacker, first use the /redpill command to become one"
|
||||
createSimpleResponseAsync "You are currently not a hacker, first use the /redpill command to become one"
|
||||
|
||||
let hackDescription = ""
|
||||
|
||||
|
112
Store/Program.fs
112
Store/Program.fs
@ -1,112 +0,0 @@
|
||||
open System
|
||||
open System.Threading.Tasks
|
||||
open DSharpPlus.Entities
|
||||
open DSharpPlus
|
||||
open DSharpPlus.EventArgs
|
||||
open DSharpPlus.SlashCommands
|
||||
open DegenzGame.Shared
|
||||
open Emzi0767.Utilities
|
||||
open Newtonsoft.Json
|
||||
|
||||
module Commands =
|
||||
let constructItemButtons playerInfo (items : 'a array) =
|
||||
items
|
||||
|> Seq.map (fun item -> DiscordButtonComponent(ButtonStyle.Primary, $"{playerInfo}-{item}", $"{item}"))
|
||||
|
||||
let viewStore (ctx : InteractionContext) =
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
|
||||
try
|
||||
let file = System.IO.File.ReadAllText("Items.json")
|
||||
JsonConvert.DeserializeObject<Item array>(file)
|
||||
|> Array.groupBy (fun (i : Item) -> i.ItemType)
|
||||
|> Array.iter (fun ( itemType , items ) ->
|
||||
let itemList = items |> Array.map (fun i -> $"{i.Name} - {i.Cost} GBT") |> String.concat "\n"
|
||||
builder.AddEmbed (constructEmbed $"{itemType}:\n{itemList}") |> ignore)
|
||||
with _ -> builder.Content <- "System error preparing inventory for viewing"
|
||||
|
||||
builder.AsEphemeral true |> ignore
|
||||
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let buyHack (ctx : InteractionContext) hackId =
|
||||
async {
|
||||
return ()
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let buyShield (ctx : InteractionContext) shieldId =
|
||||
async {
|
||||
return ()
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let sellItem (ctx : InteractionContext) =
|
||||
async {
|
||||
return ()
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
type EmptyGlobalCommandToAvoidFamousDuplicateSlashCommandsBug() = inherit ApplicationCommandModule ()
|
||||
|
||||
type Store() =
|
||||
inherit ApplicationCommandModule ()
|
||||
|
||||
[<SlashCommand("store", "View items available for purchase")>]
|
||||
member _.ViewStore (ctx : InteractionContext) = Commands.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
|
||||
|
||||
[<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
|
||||
|
||||
[<SlashCommand("sell", "Sell an item in your inventory for GoodBoyTokenz")>]
|
||||
member this.SellItem (ctx : InteractionContext) =
|
||||
Commands.sellItem ctx
|
||||
|
||||
let handleButtonEvent (_ : DiscordClient) (event : ComponentInteractionCreateEventArgs) =
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- $""
|
||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let config = DiscordConfiguration()
|
||||
config.Token <- "OTIyNDIyMDIyMTI1MDEwOTU1.YcBOcw.JxfW1CSIwEO7j6RbRFCnPZ-HoTk"
|
||||
config.TokenType <- TokenType.Bot
|
||||
config.Intents <- DiscordIntents.All
|
||||
//config.MinimumLogLevel <- Microsoft.Extensions.Logging.LogLevel.Trace
|
||||
|
||||
let client = new DiscordClient(config)
|
||||
|
||||
client.add_ComponentInteractionCreated(AsyncEventHandler(handleButtonEvent))
|
||||
|
||||
let slash = client.UseSlashCommands()
|
||||
|
||||
// My server
|
||||
slash.RegisterCommands<Store>(922419263275425832uL);
|
||||
// Degenz
|
||||
//slash.RegisterCommands<HackerGame>(922414052708327494uL);
|
||||
|
||||
client.ConnectAsync ()
|
||||
|> Async.AwaitTask
|
||||
|> Async.RunSynchronously
|
||||
|
||||
Task.Delay(-1)
|
||||
|> Async.AwaitTask
|
||||
|> Async.RunSynchronously
|
||||
|
||||
client.DisconnectAsync ()
|
||||
|> Async.AwaitTask
|
||||
|> Async.RunSynchronously
|
||||
|
198
Store/Store.fs
Normal file
198
Store/Store.fs
Normal file
@ -0,0 +1,198 @@
|
||||
open System
|
||||
open System.Threading.Tasks
|
||||
open DSharpPlus.Entities
|
||||
open DSharpPlus
|
||||
open DSharpPlus.EventArgs
|
||||
open DSharpPlus.SlashCommands
|
||||
open DegenzGame
|
||||
open DegenzGame.Shared
|
||||
open Emzi0767.Utilities
|
||||
open Newtonsoft.Json
|
||||
|
||||
let store =
|
||||
try
|
||||
let file = System.IO.File.ReadAllText("Items.json")
|
||||
JsonConvert.DeserializeObject<Item array>(file)
|
||||
|> Array.groupBy (fun (i : Item) -> i.ItemType)
|
||||
with _ -> [||]
|
||||
|
||||
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}"))
|
||||
|
||||
module Commands =
|
||||
let viewStore (ctx : InteractionContext) =
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
|
||||
builder.AddEmbeds(storeListing)
|
||||
.AsEphemeral(true)
|
||||
|> ignore
|
||||
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let getItems itemType = store |> Array.find (fun ( t , _ ) -> t = itemType) |> snd
|
||||
|
||||
let buyHack (ctx : InteractionContext) hackId =
|
||||
async {
|
||||
let! playerResult = DbService.tryFindPlayer ctx.Member.Id
|
||||
let weapons = getItems ItemType.Weapon
|
||||
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
|
||||
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)
|
||||
let p = { player with Bank = newBalance ; Weapons = Array.append [| weapon |] player.Weapons }
|
||||
do! DbService.updatePlayer p
|
||||
do! createSimpleResponseAsync $"Successfully purchased {item.Name}! You now have {newBalance} remaining" ctx
|
||||
else
|
||||
do! createSimpleResponseAsync $"You already own this item!" ctx
|
||||
else
|
||||
do! createSimpleResponseAsync $"You do not have sufficient funds to buy this item! Current balance: {player.Bank} GBT" ctx
|
||||
}
|
||||
| None , _ -> notYetAHackerMsg ctx
|
||||
| _ -> createSimpleResponseAsync "Something is wrong" ctx
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let buyShield (ctx : InteractionContext) shieldId =
|
||||
async {
|
||||
let! playerResult = DbService.tryFindPlayer ctx.Member.Id
|
||||
let shieldResult =
|
||||
getItems ItemType.Shield
|
||||
|> Array.tryFind (fun w -> w.Name = string shieldId)
|
||||
return!
|
||||
match playerResult , shieldResult with
|
||||
| Some player , Some item ->
|
||||
async {
|
||||
let newBalance = player.Bank - item.Cost
|
||||
if newBalance >= 0.0f 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)
|
||||
let p = { player with Bank = newBalance ; Shields = Array.append [| shield |] player.Shields }
|
||||
do! DbService.updatePlayer p
|
||||
do! createSimpleResponseAsync $"Successfully purchased {item.Name}! You now have {newBalance} remaining" ctx
|
||||
else
|
||||
do! createSimpleResponseAsync $"You already own this item!" ctx
|
||||
else
|
||||
do! createSimpleResponseAsync $"You do not have sufficient funds to buy this item! Current balance: {player.Bank} GBT" ctx
|
||||
}
|
||||
| None , _ -> notYetAHackerMsg ctx
|
||||
| _ -> createSimpleResponseAsync "Something is wrong" ctx
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let constructItemButtons playerInfo itemType (items : 'a array) =
|
||||
items
|
||||
|> Seq.map (fun item -> DiscordButtonComponent(ButtonStyle.Primary, $"{playerInfo}-{itemType}-{item}", $"{item}"))
|
||||
|
||||
let sellItem (ctx : InteractionContext) =
|
||||
async {
|
||||
let! playerResult = DbService.tryFindPlayer ctx.Member.Id
|
||||
match playerResult with
|
||||
| Some player ->
|
||||
let hasInventoryToSell = Array.length player.Weapons + Array.length player.Shields > 0
|
||||
if hasInventoryToSell then
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.AddEmbed (constructEmbed "Pick the item you wish to sell.") |> ignore
|
||||
|
||||
Array.chunkBySize 3 player.Weapons
|
||||
|> Array.iter
|
||||
(fun wps ->
|
||||
wps
|
||||
|> Array.map (fun w ->
|
||||
DiscordButtonComponent(ButtonStyle.Primary, $"{player.DiscordId}-Weapon-{w}", $"{w}"))
|
||||
|> Seq.cast<DiscordComponent>
|
||||
|> builder.AddComponents
|
||||
|> ignore)
|
||||
Array.chunkBySize 3 player.Shields
|
||||
|> Array.iter
|
||||
(fun shs ->
|
||||
shs
|
||||
|> Array.map (fun s ->
|
||||
DiscordButtonComponent(ButtonStyle.Primary, $"{player.DiscordId}-Shield-{s}", $"{s}"))
|
||||
|> Seq.cast<DiscordComponent>
|
||||
|> builder.AddComponents
|
||||
|> ignore)
|
||||
|
||||
builder.AsEphemeral true |> ignore
|
||||
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
else
|
||||
do! createSimpleResponseAsync "You currently have no inventory to sell" ctx
|
||||
| None -> do! notYetAHackerMsg ctx
|
||||
return ()
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let handleSellButtonEvents (_ : DiscordClient) (event : ComponentInteractionCreateEventArgs) =
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- $"{event.Id}"
|
||||
do! event.Interaction.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
type EmptyGlobalCommandToAvoidFamousDuplicateSlashCommandsBug() = inherit ApplicationCommandModule ()
|
||||
|
||||
type Store() =
|
||||
inherit ApplicationCommandModule ()
|
||||
|
||||
[<SlashCommand("store", "View items available for purchase")>]
|
||||
member _.ViewStore (ctx : InteractionContext) = Commands.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
|
||||
|
||||
[<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
|
||||
|
||||
[<SlashCommand("sell", "Sell an item in your inventory for GoodBoyTokenz")>]
|
||||
member this.SellItem (ctx : InteractionContext) =
|
||||
Commands.sellItem ctx
|
||||
|
||||
let config = DiscordConfiguration()
|
||||
config.Token <- "OTIyNDIyMDIyMTI1MDEwOTU1.YcBOcw.JxfW1CSIwEO7j6RbRFCnPZ-HoTk"
|
||||
config.TokenType <- TokenType.Bot
|
||||
config.Intents <- DiscordIntents.All
|
||||
//config.MinimumLogLevel <- Microsoft.Extensions.Logging.LogLevel.Trace
|
||||
|
||||
let client = new DiscordClient(config)
|
||||
|
||||
client.add_ComponentInteractionCreated(AsyncEventHandler(handleSellButtonEvents))
|
||||
|
||||
let slash = client.UseSlashCommands()
|
||||
|
||||
// My server
|
||||
slash.RegisterCommands<Store>(922419263275425832uL);
|
||||
// Degenz
|
||||
//slash.RegisterCommands<HackerGame>(922414052708327494uL);
|
||||
|
||||
client.ConnectAsync ()
|
||||
|> Async.AwaitTask
|
||||
|> Async.RunSynchronously
|
||||
|
||||
Task.Delay(-1)
|
||||
|> Async.AwaitTask
|
||||
|> Async.RunSynchronously
|
||||
|
||||
client.DisconnectAsync ()
|
||||
|> Async.AwaitTask
|
||||
|> Async.RunSynchronously
|
||||
|
@ -6,7 +6,7 @@
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.fs" />
|
||||
<Compile Include="Store.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include=".dockerignore" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user