module Degenz.RockPaperScissors open System open System.Threading.Tasks open DSharpPlus open DSharpPlus.Entities open DSharpPlus.EventArgs open DSharpPlus.SlashCommands open Degenz.Messaging type Move = | Rock | Paper | Scissors type RoundResult = | P1Win | P2Win | Draw 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 , Scissors -> P1Win | Paper , Rock -> 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 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 _ 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 : 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 () let enforceChannel (ctx : IDiscordContext) (storeFn : IDiscordContext -> Task) = match ctx.GetChannel().Id with | id when id = GuildEnvironment.channelArmory -> storeFn ctx | _ -> task { let msg = $"You must go to <#{GuildEnvironment.channelArmory}> channel to buy or sell weapons" do! Messaging.sendSimpleResponse ctx msg } [] member this.RPS (ctx : InteractionContext, [] target : DiscordUser) = // enforceChannel (DiscordInteractionContext ctx) (steal target) playRPS target (DiscordInteractionContext ctx)