Rock Paper Scissors
This commit is contained in:
parent
537145dae6
commit
9f756540f1
@ -60,12 +60,13 @@ module Game =
|
||||
else do! Messaging.sendFollowUpMessage ctx "Your target is not connected to the network, they must join first by using the /redpill command"
|
||||
} |> Async.StartAsTask :> Task
|
||||
|
||||
let executePlayerActionWithTargetId (targetId : uint64) (ctx : IDiscordContext) (dispatch : PlayerData -> PlayerData -> Async<unit>) =
|
||||
let executePlayerActionWithTargetId defer (targetId : uint64) (ctx : IDiscordContext) (dispatch : PlayerData -> PlayerData -> Async<unit>) =
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- "Content"
|
||||
do! ctx.Respond InteractionResponseType.DeferredChannelMessageWithSource builder |> Async.AwaitTask
|
||||
if defer then
|
||||
do! ctx.Respond InteractionResponseType.DeferredChannelMessageWithSource builder |> Async.AwaitTask
|
||||
let! players =
|
||||
[ tryFindPlayer (ctx.GetDiscordMember().Id)
|
||||
tryFindPlayer targetId ]
|
||||
|
@ -211,7 +211,7 @@ let handleButtonEvent (_ : DiscordClient) (event : ComponentInteractionCreateEve
|
||||
| id when id.StartsWith("Defend") -> handleDefense eventCtx
|
||||
| id when id.StartsWith("Trainer") -> Trainer.handleButtonEvent eventCtx |> Async.StartAsTask :> Task
|
||||
| id when id.StartsWith("Steal") -> Thief.handleSteal eventCtx
|
||||
| id when id.StartsWith("Steal") -> RockPaperScissors.handleRPS eventCtx
|
||||
| id when id.StartsWith("RPS") -> RockPaperScissors.handleRPS eventCtx
|
||||
| _ ->
|
||||
task {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
|
@ -4,45 +4,137 @@ open System
|
||||
open System.Threading.Tasks
|
||||
open DSharpPlus
|
||||
open DSharpPlus.Entities
|
||||
open DSharpPlus.EventArgs
|
||||
open DSharpPlus.SlashCommands
|
||||
open Degenz.Messaging
|
||||
|
||||
type Move =
|
||||
| Rock
|
||||
| Paper
|
||||
| Scissor
|
||||
| Scissors
|
||||
|
||||
type RoundResult =
|
||||
| P1Win
|
||||
| P2Win
|
||||
| Draw
|
||||
|
||||
let player1Won p1m p2m =
|
||||
let moveFromString = function
|
||||
| "rock" -> Rock
|
||||
| "paper" -> Paper
|
||||
| "scissors" -> Scissors
|
||||
| _ -> failwith "Unknown RPS move"
|
||||
|
||||
let getWinner p1m p2m =
|
||||
match p1m , p2m with
|
||||
| Rock , Paper -> P2Win
|
||||
| Rock , Scissor -> P1Win
|
||||
| Rock , Scissors -> P1Win
|
||||
| Paper , Rock -> P1Win
|
||||
| Paper , Scissor -> P2Win
|
||||
| Scissor , Rock -> P2Win
|
||||
| Scissor , Paper -> P1Win
|
||||
| Paper , Scissors -> P2Win
|
||||
| Scissors , Rock -> P2Win
|
||||
| Scissors , Paper -> P1Win
|
||||
| _ , _ -> Draw
|
||||
|
||||
let leftGif = function
|
||||
| Rock -> "https://s10.gifyu.com/images/Sprite-0001614d8697f32165af.gif"
|
||||
| Paper -> "https://s10.gifyu.com/images/Sprite-0001e7e8ac379d1c5112.gif"
|
||||
| Scissors -> "https://s10.gifyu.com/images/Sprite-00012c83b50d768a2ed1.gif"
|
||||
|
||||
let rightGif = function
|
||||
| Rock -> "https://s10.gifyu.com/images/Sprite-0001b4002047d9699732.gif"
|
||||
| Paper -> "https://s10.gifyu.com/images/Sprite-00014072202347b8271e.gif"
|
||||
| Scissors -> "https://s10.gifyu.com/images/Sprite-0001c8532b0538ed8706.gif"
|
||||
|
||||
let rpsEmbed disabled opponentMove opponent =
|
||||
let buttonId move =
|
||||
match opponentMove with
|
||||
| Some m -> $"RPS-{move}-{opponent.DiscordId}-{opponent.Name}-True-{m}"
|
||||
| None -> $"RPS-{move}-{opponent.DiscordId}-{opponent.Name}-False"
|
||||
let buttons =
|
||||
[ DiscordButtonComponent(ButtonStyle.Primary, buttonId "rock", "🪨 Rock", disabled)
|
||||
DiscordButtonComponent(ButtonStyle.Primary, buttonId "paper", "📜 Paper", disabled)
|
||||
DiscordButtonComponent(ButtonStyle.Primary, buttonId "scissors", "✂ Scissors", disabled) ]
|
||||
|> Seq.cast<DiscordComponent>
|
||||
|
||||
let embed =
|
||||
DiscordEmbedBuilder()
|
||||
.WithTitle("Rock Paper Scissors")
|
||||
.AddField("Opponent", opponent.Name)
|
||||
.WithImageUrl("https://s10.gifyu.com/images/222e9b8f5459e5d3a7d.png")
|
||||
( buttons , embed )
|
||||
|
||||
let matchResultsEmbed winner move1 move2 player1 player2 =
|
||||
let firstEmbed =
|
||||
DiscordEmbedBuilder()
|
||||
.WithTitle($"{player1.Name}'s Move")
|
||||
.WithImageUrl(leftGif move1)
|
||||
let secondEmbed =
|
||||
DiscordEmbedBuilder()
|
||||
.WithTitle($"{player2.Name}'s Move")
|
||||
.WithImageUrl(rightGif move2)
|
||||
|
||||
let description =
|
||||
match winner with
|
||||
| P1Win -> $"{player1.Name} wins with {move1}"
|
||||
| P2Win -> $"{player2.Name} wins with {move2}"
|
||||
| Draw -> $"Draw! Both players played {move1}"
|
||||
let thirdEmbed =
|
||||
DiscordEmbedBuilder()
|
||||
.WithTitle($"Results")
|
||||
.WithDescription(description)
|
||||
|
||||
[ firstEmbed ; secondEmbed ; thirdEmbed ]
|
||||
|
||||
let playRPS target ctx =
|
||||
Game.executePlayerActionWithTarget target ctx (fun attacker defender -> async {
|
||||
let buttons =
|
||||
[ DiscordButtonComponent(ButtonStyle.Primary, $"RPS-rock-{defender.DiscordId}-{defender.Name}", "🪨 Rock")
|
||||
DiscordButtonComponent(ButtonStyle.Primary, $"RPS-paper", "📜 Paper")
|
||||
DiscordButtonComponent(ButtonStyle.Primary, $"RPS-scissors", "✂ Scissors") ]
|
||||
|> Seq.cast<DiscordComponent>
|
||||
|
||||
let builder = DiscordFollowupMessageBuilder()
|
||||
builder.AddComponents(buttons) |> ignore
|
||||
builder.IsEphemeral <- true
|
||||
|
||||
do! ctx.FollowUp builder |> Async.AwaitTask
|
||||
Game.executePlayerActionWithTarget target ctx (fun _ defender -> async {
|
||||
let buttons , embed = rpsEmbed false None defender
|
||||
let builder =
|
||||
DiscordFollowupMessageBuilder()
|
||||
.AddComponents(buttons)
|
||||
.AddEmbed(embed)
|
||||
.AsEphemeral(true)
|
||||
do! ctx.FollowUp (builder) |> Async.AwaitTask
|
||||
})
|
||||
|
||||
let handleRPS ctx = async.Zero() |> Async.StartAsTask
|
||||
let handleRPS (ctx : IDiscordContext) =
|
||||
let split = ctx.GetInteractionId().Split("-")
|
||||
let move = split.[1]
|
||||
let targetId = uint64 split.[2]
|
||||
let isResponse = split.[4] = "True"
|
||||
Game.executePlayerActionWithTargetId false targetId ctx (fun attacker defender -> async {
|
||||
if isResponse then
|
||||
let eventCtx = ctx.GetContext() :?> ComponentInteractionCreateEventArgs
|
||||
let buttons , embed = rpsEmbed true None attacker
|
||||
let builder =
|
||||
DiscordInteractionResponseBuilder()
|
||||
.AddComponents(buttons)
|
||||
.AddEmbed(embed)
|
||||
.AsEphemeral(true)
|
||||
do! eventCtx.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder) |> Async.AwaitTask
|
||||
let move1 = moveFromString move
|
||||
let move2 = moveFromString split.[5]
|
||||
let winner = getWinner move1 move2
|
||||
let embeds = matchResultsEmbed winner move1 move2 attacker defender |> Seq.map (fun e -> e.Build())
|
||||
let builder = DiscordMessageBuilder().AddEmbeds(embeds)
|
||||
do! ctx.GetChannel().SendMessageAsync(builder) |> Async.AwaitTask |> Async.Ignore
|
||||
else
|
||||
let eventCtx = ctx.GetContext() :?> ComponentInteractionCreateEventArgs
|
||||
let buttons , embed = rpsEmbed true None attacker
|
||||
let builder =
|
||||
DiscordInteractionResponseBuilder()
|
||||
.AddComponents(buttons)
|
||||
.AddEmbed(embed)
|
||||
.AsEphemeral(true)
|
||||
do! eventCtx.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, builder) |> Async.AwaitTask
|
||||
// do! sendFollowUpMessage ctx $"Sent challenge to {defender.Name}, wait till they respond"
|
||||
let buttons , embed = rpsEmbed false (Some move) attacker
|
||||
let builder =
|
||||
DiscordMessageBuilder()
|
||||
.WithContent($"<@{defender.DiscordId}>, you have been challenged to a match of Rock, Paper, Scissors. Pick your move!")
|
||||
.AddComponents(buttons)
|
||||
.AddEmbed(embed)
|
||||
|
||||
do! ctx.GetChannel().SendMessageAsync(builder) |> Async.AwaitTask |> Async.Ignore
|
||||
})
|
||||
|
||||
type RPSGame() =
|
||||
inherit ApplicationCommandModule ()
|
||||
|
@ -171,7 +171,7 @@ let handleSteal (ctx : IDiscordContext) =
|
||||
}
|
||||
if answer = "yes" then
|
||||
let targetId = uint64 split.[2]
|
||||
Game.executePlayerActionWithTargetId targetId ctx (fun attacker defender -> async {
|
||||
Game.executePlayerActionWithTargetId true targetId ctx (fun attacker defender -> async {
|
||||
do! attacker
|
||||
|> Player.removeExpiredActions false
|
||||
|> checkVictimStealingCooldown defender
|
||||
|
@ -129,6 +129,7 @@ module Messaging =
|
||||
abstract member GetGuild : unit -> DiscordGuild
|
||||
abstract member GetInteractionId : unit -> string
|
||||
abstract member GetChannel : unit -> DiscordChannel
|
||||
abstract member GetContext : unit -> obj
|
||||
|
||||
type DiscordInteractionContext(ctx : InteractionContext) =
|
||||
interface IDiscordContext with
|
||||
@ -144,6 +145,7 @@ module Messaging =
|
||||
member this.GetGuild() = ctx.Guild
|
||||
member this.GetInteractionId() = string ctx.InteractionId
|
||||
member this.GetChannel() = ctx.Channel
|
||||
member this.GetContext() = ctx
|
||||
|
||||
type DiscordEventContext(ctx : ComponentInteractionCreateEventArgs) =
|
||||
interface IDiscordContext with
|
||||
@ -159,6 +161,7 @@ module Messaging =
|
||||
member this.GetGuild() = ctx.Guild
|
||||
member this.GetInteractionId() = ctx.Id
|
||||
member this.GetChannel() = ctx.Channel
|
||||
member this.GetContext() = ctx
|
||||
|
||||
let getTimeText isCooldown (timespan : TimeSpan) timestamp =
|
||||
let span =
|
||||
|
Loading…
x
Reference in New Issue
Block a user