discord-bot-game/Program.fs
2021-12-29 03:33:40 +07:00

214 lines
8.2 KiB
Forth

open System.Threading.Tasks
open DSharpPlus
open DSharpPlus.Entities
open DSharpPlus.SlashCommands
open DSharpPlus.CommandsNext
open DSharpPlus.CommandsNext.Attributes
open Emzi0767.Utilities
type Move =
| Rock
| Paper
| Scissor
type RoundResult =
| P1Win
| P2Win
| Draw
type Player =
{ name : string
health : string }
type Turn =
| WaitingForBoth
| WaitingForOne of Move
| WaitingForTwo of Move
| BothCompleted of Move * Move
type Match =
{ player1 : DiscordMember
player2 : DiscordMember
round : int
scorePlayer1 : int
scorePlayer2 : int
turn : Turn }
type JoeBot() =
inherit BaseCommandModule ()
let mutable currentMatch : Match option = None
[<Command "start-match">]
[<Description "Start a match between two players">]
member this.StartMatch (ctx : CommandContext, [<Description "Player 1">] player1 : DiscordMember, [<Description "Player 2">] player2 : DiscordMember) =
async {
do! ctx.TriggerTypingAsync() |> Async.AwaitTask
currentMatch <- Some {
player1 = player1
player2 = player2
round = 0
scorePlayer1 = 0
scorePlayer2 = 0
turn = WaitingForBoth
}
do! ctx.RespondAsync (sprintf "Match started between %s and %s. May the best hacker win!" player1.DisplayName player2.DisplayName)
|> Async.AwaitTask
|> Async.Ignore
} |> Async.StartAsTask
:> Task
[<Command "send-move">]
[<Description "Challenge another member to combat">]
member this.SendMove (ctx : CommandContext, [<Description "The name of the move: rock, paper, or scissor">] moveString : string) =
async {
do! ctx.TriggerTypingAsync() |> Async.AwaitTask
let move =
match moveString.ToLower() with
| "rock" -> Some Rock
| "paper" -> Some Paper
| "scissor" -> Some Scissor
| _ -> None
match currentMatch , move with
| Some mtc , Some move ->
let updatedTurn =
match mtc.turn with
| WaitingForBoth ->
match ctx.Member with
| mem when mem = mtc.player1 -> WaitingForTwo move
| mem when mem = mtc.player2 -> WaitingForOne move
| _ -> mtc.turn
| WaitingForOne p1m ->
match ctx.Member with
| mem when mem = mtc.player1 -> BothCompleted ( p1m , move )
| mem when mem = mtc.player2 -> mtc.turn
| _ -> mtc.turn
| WaitingForTwo p2m ->
match ctx.Member with
| mem when mem = mtc.player1 -> mtc.turn
| mem when mem = mtc.player2 -> BothCompleted ( p2m , move )
| _ -> mtc.turn
| _ -> mtc.turn
match updatedTurn with
| BothCompleted ( p1m , p2m ) ->
let result =
match p1m , p2m with
| Rock , Paper -> P2Win
| Rock , Scissor -> P1Win
| Paper , Rock -> P1Win
| Paper , Scissor -> P2Win
| Scissor , Rock -> P2Win
| Scissor , Paper -> P1Win
| _ -> Draw
match result with
| P1Win | P2Win ->
let winner = match result with P1Win -> mtc.player1 | P2Win -> mtc.player2 | Draw -> mtc.player1
let message = $"{p1m} beats {p2m}! {winner} takes the round!"
do! ctx.RespondAsync message
|> Async.AwaitTask
|> Async.Ignore
if mtc.round >= 5 then
let winnerScore = match result with P1Win -> mtc.scorePlayer1 | P2Win -> mtc.scorePlayer2 | Draw -> 0
let loserScore = match result with P1Win -> mtc.scorePlayer2 | P2Win -> mtc.scorePlayer1 | Draw -> 0
currentMatch <- None
do! ctx.RespondAsync $"{winner} wins the match {winnerScore} to {loserScore}! Awarding a 100 genz!"
|> Async.AwaitTask
|> Async.Ignore
else
currentMatch <- Some
{ mtc with
round = mtc.round + 1
scorePlayer1 = mtc.scorePlayer1 + (match result with P1Win -> 1 | _ -> 0)
scorePlayer2 = mtc.scorePlayer2 + (match result with P2Win -> 1 | _ -> 0)
turn = updatedTurn
}
| Draw ->
do! ctx.RespondAsync $"{mtc.player1.DisplayName} and {mtc.player2.DisplayName} both did {p1m}. Round was a draw! Go again!"
|> Async.AwaitTask
|> Async.Ignore
| _ ->
if updatedTurn <> mtc.turn then
do! ctx.RespondAsync ($"Move received by {ctx.Member.DisplayName}!")
|> Async.AwaitTask
|> Async.Ignore
else
do! async{ return () }
| None , _ ->
do! ctx.RespondAsync ("No match has been found, please use the '/start-match' command and mention the two players")
|> Async.AwaitTask
|> Async.Ignore
| _ , None ->
do! ctx.RespondAsync $"Could not recognize move '{moveString}', please try again. Valid moves are 'rock', 'paper', or 'scissor'"
|> Async.AwaitTask
|> Async.Ignore
} |> Async.StartAsTask
:> Task
[<Command "get-status">]
[<Description "Challenge another member to combat">]
member this.Status (ctx : CommandContext) =
async {
do! ctx.TriggerTypingAsync() |> Async.AwaitTask
do! ctx.RespondAsync ("Status")
|> Async.AwaitTask
|> Async.Ignore
} |> Async.StartAsTask
:> Task
[<Command "challenge">]
[<Description "Challenge another member to combat">]
member this.Challenge (ctx : CommandContext, [<Description "Who do you want to challenge?">] user : DiscordMember) =
async {
do! ctx.TriggerTypingAsync() |> Async.AwaitTask
do! ctx.RespondAsync (sprintf "Targeting %u" user.Id)
|> Async.AwaitTask
|> Async.Ignore
} |> Async.StartAsTask
:> Task
let config = DiscordConfiguration()
config.Token <- "OTIyNDIyMDIyMTI1MDEwOTU1.YcBOcw.JxfW1CSIwEO7j6RbRFCnPZ-HoTk"
config.TokenType <- TokenType.Bot
let commandsConfig = CommandsNextConfiguration()
commandsConfig.StringPrefixes <- [ "/" ]
let client = new DiscordClient(config)
let slash = client.UseSlashCommands()
slash.add_SlashCommandExecuted(AsyncEventHandler<_,_>(
fun client e ->
async {
let builder = DiscordInteractionResponseBuilder()
builder.IsEphemeral <- true
builder.Content <- "Does this need to be filled out?"
return e.Context.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource, builder)
} |> Async.StartAsTask :> Task))
//let commands = client.UseCommandsNext(commandsConfig)
//commands.RegisterCommands<JoeBot>()
client.ConnectAsync ()
|> Async.AwaitTask
|> Async.RunSynchronously
Task.Delay(-1)
|> Async.AwaitTask
|> Async.RunSynchronously