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"
 | 
					                    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
 | 
					        } |> 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 {
 | 
					        async {
 | 
				
			||||||
            let builder = DiscordInteractionResponseBuilder()
 | 
					            let builder = DiscordInteractionResponseBuilder()
 | 
				
			||||||
            builder.IsEphemeral <- true
 | 
					            builder.IsEphemeral <- true
 | 
				
			||||||
            builder.Content <- "Content"
 | 
					            builder.Content <- "Content"
 | 
				
			||||||
            do! ctx.Respond InteractionResponseType.DeferredChannelMessageWithSource builder |> Async.AwaitTask
 | 
					            if defer then
 | 
				
			||||||
 | 
					                do! ctx.Respond InteractionResponseType.DeferredChannelMessageWithSource builder |> Async.AwaitTask
 | 
				
			||||||
            let! players =
 | 
					            let! players =
 | 
				
			||||||
                [ tryFindPlayer (ctx.GetDiscordMember().Id)
 | 
					                [ tryFindPlayer (ctx.GetDiscordMember().Id)
 | 
				
			||||||
                  tryFindPlayer targetId ]
 | 
					                  tryFindPlayer targetId ]
 | 
				
			||||||
 | 
				
			|||||||
@ -211,7 +211,7 @@ let handleButtonEvent (_ : DiscordClient) (event : ComponentInteractionCreateEve
 | 
				
			|||||||
    | id when id.StartsWith("Defend")  -> handleDefense eventCtx
 | 
					    | id when id.StartsWith("Defend")  -> handleDefense eventCtx
 | 
				
			||||||
    | id when id.StartsWith("Trainer") -> Trainer.handleButtonEvent eventCtx |> Async.StartAsTask :> Task
 | 
					    | id when id.StartsWith("Trainer") -> Trainer.handleButtonEvent eventCtx |> Async.StartAsTask :> Task
 | 
				
			||||||
    | id when id.StartsWith("Steal")   -> Thief.handleSteal eventCtx
 | 
					    | 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 {
 | 
					        task {
 | 
				
			||||||
            let builder = DiscordInteractionResponseBuilder()
 | 
					            let builder = DiscordInteractionResponseBuilder()
 | 
				
			||||||
 | 
				
			|||||||
@ -4,45 +4,137 @@ open System
 | 
				
			|||||||
open System.Threading.Tasks
 | 
					open System.Threading.Tasks
 | 
				
			||||||
open DSharpPlus
 | 
					open DSharpPlus
 | 
				
			||||||
open DSharpPlus.Entities
 | 
					open DSharpPlus.Entities
 | 
				
			||||||
 | 
					open DSharpPlus.EventArgs
 | 
				
			||||||
open DSharpPlus.SlashCommands
 | 
					open DSharpPlus.SlashCommands
 | 
				
			||||||
open Degenz.Messaging
 | 
					open Degenz.Messaging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Move =
 | 
					type Move =
 | 
				
			||||||
    | Rock
 | 
					    | Rock
 | 
				
			||||||
    | Paper
 | 
					    | Paper
 | 
				
			||||||
    | Scissor
 | 
					    | Scissors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RoundResult =
 | 
					type RoundResult =
 | 
				
			||||||
    | P1Win
 | 
					    | P1Win
 | 
				
			||||||
    | P2Win
 | 
					    | P2Win
 | 
				
			||||||
    | Draw
 | 
					    | 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
 | 
					    match p1m , p2m with
 | 
				
			||||||
    | Rock    , Paper    -> P2Win
 | 
					    | Rock    , Paper    -> P2Win
 | 
				
			||||||
    | Rock    , Scissor  -> P1Win
 | 
					    | Rock    , Scissors  -> P1Win
 | 
				
			||||||
    | Paper   , Rock     -> P1Win
 | 
					    | Paper   , Rock     -> P1Win
 | 
				
			||||||
    | Paper   , Scissor  -> P2Win
 | 
					    | Paper   , Scissors  -> P2Win
 | 
				
			||||||
    | Scissor , Rock     -> P2Win
 | 
					    | Scissors , Rock     -> P2Win
 | 
				
			||||||
    | Scissor , Paper    -> P1Win
 | 
					    | Scissors , Paper    -> P1Win
 | 
				
			||||||
    | _       , _        -> Draw
 | 
					    | _       , _        -> 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 =
 | 
					let playRPS target ctx =
 | 
				
			||||||
    Game.executePlayerActionWithTarget target ctx (fun attacker defender -> async {
 | 
					    Game.executePlayerActionWithTarget target ctx (fun _ defender -> async {
 | 
				
			||||||
        let buttons =
 | 
					        let buttons , embed = rpsEmbed false None defender
 | 
				
			||||||
            [ DiscordButtonComponent(ButtonStyle.Primary, $"RPS-rock-{defender.DiscordId}-{defender.Name}", "🪨 Rock")
 | 
					        let builder =
 | 
				
			||||||
              DiscordButtonComponent(ButtonStyle.Primary, $"RPS-paper", "📜 Paper")
 | 
					           DiscordFollowupMessageBuilder()
 | 
				
			||||||
              DiscordButtonComponent(ButtonStyle.Primary, $"RPS-scissors", "✂  Scissors") ]
 | 
					             .AddComponents(buttons)
 | 
				
			||||||
            |> Seq.cast<DiscordComponent>
 | 
					             .AddEmbed(embed)
 | 
				
			||||||
 | 
					             .AsEphemeral(true)
 | 
				
			||||||
        let builder = DiscordFollowupMessageBuilder()
 | 
					        do! ctx.FollowUp (builder) |> Async.AwaitTask
 | 
				
			||||||
        builder.AddComponents(buttons) |> ignore
 | 
					 | 
				
			||||||
        builder.IsEphemeral <- 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() =
 | 
					type RPSGame() =
 | 
				
			||||||
    inherit ApplicationCommandModule ()
 | 
					    inherit ApplicationCommandModule ()
 | 
				
			||||||
 | 
				
			|||||||
@ -171,7 +171,7 @@ let handleSteal (ctx : IDiscordContext) =
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    if answer = "yes" then
 | 
					    if answer = "yes" then
 | 
				
			||||||
        let targetId = uint64 split.[2]
 | 
					        let targetId = uint64 split.[2]
 | 
				
			||||||
        Game.executePlayerActionWithTargetId targetId ctx (fun attacker defender -> async {
 | 
					        Game.executePlayerActionWithTargetId true targetId ctx (fun attacker defender -> async {
 | 
				
			||||||
            do! attacker
 | 
					            do! attacker
 | 
				
			||||||
                |> Player.removeExpiredActions false
 | 
					                |> Player.removeExpiredActions false
 | 
				
			||||||
                |> checkVictimStealingCooldown defender
 | 
					                |> checkVictimStealingCooldown defender
 | 
				
			||||||
 | 
				
			|||||||
@ -129,6 +129,7 @@ module Messaging =
 | 
				
			|||||||
        abstract member GetGuild : unit -> DiscordGuild
 | 
					        abstract member GetGuild : unit -> DiscordGuild
 | 
				
			||||||
        abstract member GetInteractionId : unit -> string
 | 
					        abstract member GetInteractionId : unit -> string
 | 
				
			||||||
        abstract member GetChannel : unit -> DiscordChannel
 | 
					        abstract member GetChannel : unit -> DiscordChannel
 | 
				
			||||||
 | 
					        abstract member GetContext : unit -> obj
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    type DiscordInteractionContext(ctx : InteractionContext) =
 | 
					    type DiscordInteractionContext(ctx : InteractionContext) =
 | 
				
			||||||
        interface IDiscordContext with
 | 
					        interface IDiscordContext with
 | 
				
			||||||
@ -144,6 +145,7 @@ module Messaging =
 | 
				
			|||||||
            member this.GetGuild() = ctx.Guild
 | 
					            member this.GetGuild() = ctx.Guild
 | 
				
			||||||
            member this.GetInteractionId() = string ctx.InteractionId
 | 
					            member this.GetInteractionId() = string ctx.InteractionId
 | 
				
			||||||
            member this.GetChannel() = ctx.Channel
 | 
					            member this.GetChannel() = ctx.Channel
 | 
				
			||||||
 | 
					            member this.GetContext() = ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    type DiscordEventContext(ctx : ComponentInteractionCreateEventArgs) =
 | 
					    type DiscordEventContext(ctx : ComponentInteractionCreateEventArgs) =
 | 
				
			||||||
        interface IDiscordContext with
 | 
					        interface IDiscordContext with
 | 
				
			||||||
@ -159,6 +161,7 @@ module Messaging =
 | 
				
			|||||||
            member this.GetGuild() = ctx.Guild
 | 
					            member this.GetGuild() = ctx.Guild
 | 
				
			||||||
            member this.GetInteractionId() = ctx.Id
 | 
					            member this.GetInteractionId() = ctx.Id
 | 
				
			||||||
            member this.GetChannel() = ctx.Channel
 | 
					            member this.GetChannel() = ctx.Channel
 | 
				
			||||||
 | 
					            member this.GetContext() = ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let getTimeText isCooldown (timespan : TimeSpan) timestamp =
 | 
					    let getTimeText isCooldown (timespan : TimeSpan) timestamp =
 | 
				
			||||||
        let span =
 | 
					        let span =
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user