discord-bot-game/Bot/Games/SlotMachine.fs

301 lines
13 KiB
Forth
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

module Degenz.SlotMachine
open System
open System.Threading.Tasks
open DSharpPlus
open DSharpPlus.Entities
open DSharpPlus.EventArgs
open Degenz.Messaging
open Degenz.Types
open Npgsql.FSharp
type SlotSymbol = {
index : int
emojiName : string
reel1Count : int
reel2Count : int
reel3Count : int
}
let BigBrother = { index = 0 ; reel1Count = 1 ; reel2Count = 1 ; reel3Count = 1 ; emojiName = "bigbrother" }
let Eye = { index = 1 ; reel1Count = 3 ; reel2Count = 2 ; reel3Count = 1 ; emojiName = "aneye" }
let Obey = { index = 2 ; reel1Count = 2 ; reel2Count = 2 ; reel3Count = 2 ; emojiName = "obey" }
let AnonMask = { index = 3 ; reel1Count = 1 ; reel2Count = 2 ; reel3Count = 4 ; emojiName = "anonmask" }
let Ramen = { index = 5 ; reel1Count = 3 ; reel2Count = 3 ; reel3Count = 1 ; emojiName = "ramen" }
let Sushi = { index = 4 ; reel1Count = 3 ; reel2Count = 2 ; reel3Count = 2 ; emojiName = "sushi" }
let Pizza = { index = 6 ; reel1Count = 2 ; reel2Count = 4 ; reel3Count = 0 ; emojiName = "pizza" }
let Alcohol = { index = 7 ; reel1Count = 1 ; reel2Count = 1 ; reel3Count = 1 ; emojiName = "alcohol" }
let Circuit = { index = 0 ; reel1Count = 0 ; reel2Count = 0 ; reel3Count = 2 ; emojiName = "circuitboard" }
let OldTv = { index = 9 ; reel1Count = 1 ; reel2Count = 2 ; reel3Count = 2 ; emojiName = "oldtv" }
let Pills = { index = 10 ; reel1Count = 2 ; reel2Count = 1 ; reel3Count = 2 ; emojiName = "pills" }
let Rat = { index = 11 ; reel1Count = 2 ; reel2Count = 1 ; reel3Count = 1 ; emojiName = "rat" }
let symbols = [ BigBrother ; Eye ; Obey ; AnonMask ; Sushi ; Ramen ; Pizza ; Alcohol ; Circuit ; OldTv ; Pills ; Rat ]
//let symbols = [ BigBrother ; Eye ; Obey ; AnonMask ; Sushi ; Ramen ; Pizza ; Alcohol ]
let getReel fn = List.fold (fun acc elem -> (List.replicate (fn elem) elem) @ acc) [] symbols |> List.toArray
type Prize =
| Money of int<GBT>
| Jackpot
type Slot =
| Symbol of SlotSymbol
| Any
let prizeTable =
[| Symbol BigBrother , Symbol BigBrother , Symbol BigBrother , Jackpot
Symbol Eye , Symbol Eye , Symbol Eye , Money 500<GBT>
Symbol Eye , Symbol Eye , Symbol Obey , Money 500<GBT>
Symbol AnonMask , Symbol AnonMask , Symbol AnonMask , Money 250<GBT>
Symbol AnonMask , Symbol AnonMask , Symbol Eye , Money 250<GBT>
Symbol Ramen , Symbol Ramen , Symbol Ramen , Money 100<GBT>
Symbol Ramen , Symbol Ramen , Symbol Eye , Money 100<GBT>
Symbol Sushi , Symbol Sushi , Any , Money 50<GBT>
Symbol Pizza , Any , Any , Money 20<GBT> |]
let totalPerReel (reel : SlotSymbol -> int) = List.sumBy reel symbols
let calculateOdds prizeIndex =
match prizeTable.[prizeIndex] with
| Symbol s1 , Symbol s2 , Symbol s3 , _ -> s1.reel1Count * s2.reel2Count * s3.reel3Count
| Symbol s1 , Symbol s2 , Any , _ -> s1.reel1Count * s2.reel2Count * totalPerReel (fun s -> s.reel3Count)
| Symbol s1 , Any , Any , _ -> s1.reel1Count * totalPerReel (fun s -> s.reel2Count) * totalPerReel (fun s -> s.reel3Count)
| _ -> 0
let getTotalCombinations () =
(List.sumBy (fun s -> s.reel1Count) symbols)
* (List.sumBy (fun s -> s.reel2Count) symbols)
* (List.sumBy (fun s -> s.reel3Count) symbols)
let getOddsForPrize prizeIndex =
let odds = calculateOdds prizeIndex
let total = getTotalCombinations ()
$"{odds} in {total }"
//getOddsForPrize 0
//getOddsForPrize 1
//getOddsForPrize 5
//getOddsForPrize 8
let getTotalWaysOfWinning () =
[0..prizeTable.Length - 1]
|> List.sumBy calculateOdds
//totalPerReel (fun s -> s.reel1Count)
//totalPerReel (fun s -> s.reel2Count)
//totalPerReel (fun s -> s.reel3Count)
let reel1 = getReel (fun s -> s.reel1Count)
let reel2 = getReel (fun s -> s.reel2Count)
let reel3 = getReel (fun s -> s.reel3Count)
let slots =
[| "https://s7.gifyu.com/images/aneye.png"
"https://s7.gifyu.com/images/anonmask.png"
"https://s7.gifyu.com/images/circuitboard.png"
"https://s7.gifyu.com/images/obey.png"
"https://s7.gifyu.com/images/oldtv.png"
"https://s7.gifyu.com/images/pills.png"
"https://s7.gifyu.com/images/pizza0d47578733961746.png"
"https://s7.gifyu.com/images/ramen0515f00869e1f4eb.png"
"https://s7.gifyu.com/images/rat69609f842a0eb9f5.png"
"https://s7.gifyu.com/images/alcohol.png"
"https://s7.gifyu.com/images/bigbrother.png"
"https://s7.gifyu.com/images/sushi.png" |]
// [| "https://s7.gifyu.com/images/A-bottle-of-pills0a3006d0170e08df.png"
// "https://s7.gifyu.com/images/an-eyec362d8152ae2382b.png"
// "https://s7.gifyu.com/images/anon-face-mask6c7624821c89fc08.png"
// "https://s7.gifyu.com/images/a-piece-of-sushi77071d30f60a89c6.png"
// "https://s7.gifyu.com/images/Circuit-board89056017b80f1d13.png"
// "https://s7.gifyu.com/images/OBEYf2a8234109836c03.png"
// "https://s7.gifyu.com/images/old-tv-screendc6bc9d4b6c1fd65.png"
// "https://s7.gifyu.com/images/pizza030ffc00ff50da0e.png"
// "https://s7.gifyu.com/images/ramen08336d448018c98f.png"
// "https://s7.gifyu.com/images/rat14f65f54f0d75036.png" |]
let slotEmojiNames =
[| "sushi"
"bigbrother"
"pizza"
"ramen"
"circuitboard"
"obey"
"pills"
"oldtv"
"rat"
"aneye"
"alcohol"
"anonmask" |]
let PlayPrice = 5<GBT>
let sleepTime = 1500
let mutable guildEmojis : Map<string, DiscordEmoji> option = None
let mutable anyEmoji : DiscordEmoji option = None
let getJackpotAmount () =
GuildEnvironment.connectionString
|> Sql.connect
|> Sql.query "SELECT stock FROM item WHERE symbol = 'JACKPOT'"
|> Sql.executeRowAsync (fun read -> (read.int "price") * 1<GBT>)
let incrementJackpot amount =
GuildEnvironment.connectionString
|> Sql.connect
|> Sql.parameters [ ( "amount" , Sql.int (int amount) ) ]
|> Sql.query "UPDATE item SET stock = stock + @amount WHERE symbol = 'JACKPOT'"
|> Sql.executeNonQueryAsync
let spinEmojis (results : SlotSymbol array) (ctx : IDiscordContext) =
async {
let itx = ctx.GetInteraction()
let builder = DiscordFollowupMessageBuilder()
builder.Content <- "Spinning!"
builder.IsEphemeral <- true
let! followUp = itx.CreateFollowupMessageAsync(builder) |> Async.AwaitTask
match guildEmojis with
| Some emojis ->
let e1 = Formatter.Emoji(emojis.[results.[0].emojiName])
let e2 = Formatter.Emoji(emojis.[results.[1].emojiName])
let e3 = Formatter.Emoji(emojis.[results.[2].emojiName])
do! Async.Sleep sleepTime
let content = $"{e1}"
let! _ = itx.EditFollowupMessageAsync(followUp.Id, DiscordWebhookBuilder().WithContent(content)) |> Async.AwaitTask
do! Async.Sleep sleepTime
let content = $"{e1}{e2}"
let! _ = itx.EditFollowupMessageAsync(followUp.Id, DiscordWebhookBuilder().WithContent(content)) |> Async.AwaitTask
do! Async.Sleep sleepTime
let content = $"{e1}{e2}{e3}"
let! _ = itx.EditFollowupMessageAsync(followUp.Id, DiscordWebhookBuilder().WithContent(content)) |> Async.AwaitTask
return ()
| None -> return ()
}
let spin spinType (ctx : IDiscordContext) =
PlayerInteractions.executePlayerAction ctx (fun player -> async {
let random = Random(Guid.NewGuid().GetHashCode())
let symbols = [| reel1.[random.Next(0, reel1.Length)] ; reel2.[random.Next(0, reel2.Length)] ; reel3.[random.Next(0, reel3.Length)] |]
let prize =
prizeTable
|> Array.tryPick (fun (s1,s2,s3,prize) ->
match s1 , s2 , s3 with
| Symbol s1' , Symbol s2' , Symbol s3' when s1'.index = symbols.[0].index && s2'.index = symbols.[1].index && s3'.index = symbols.[2].index -> Some prize
| Symbol s1' , Symbol s2' , Any when s1'.index = symbols.[0].index && s2'.index = symbols.[1].index -> Some prize
| Symbol s1' , Any , Any when s1'.index = symbols.[0].index -> Some prize
| _ -> None)
match spinType with
| "Emojis" -> do! spinEmojis symbols ctx
// | "Files" -> do! spinFiles symbols ctx
| _ -> ()
do! Async.Sleep 2000
let builder = DiscordFollowupMessageBuilder()
builder.IsEphemeral <- true
let embed4 = DiscordEmbedBuilder()
embed4.Title <- "Results"
match prize with
| Some (Money amount) ->
do! DbService.updatePlayerCurrency amount player |> Async.Ignore
embed4.ImageUrl <- "https://s7.gifyu.com/images/youwin.png"
embed4.Description <- $"You win **{amount}** GBT!"
| Some (Jackpot) ->
embed4.ImageUrl <- "https://s7.gifyu.com/images/jackpot2ac30c9823f6a91c.png"
embed4.Description <- $"YOU HIT THE JACKPOT!!!"
| None ->
do! DbService.updatePlayerCurrency -PlayPrice player |> Async.Ignore
do! incrementJackpot PlayPrice |> Async.AwaitTask |> Async.Ignore
embed4.Description <- $"Better luck next time! You paid {PlayPrice} $GBT"
let button1 = DiscordButtonComponent(ButtonStyle.Success, $"spin", $"Spin Again {PlayPrice} $GBT") :> DiscordComponent
let button2 = DiscordButtonComponent(ButtonStyle.Success, $"prizes", $"Show Prizes") :> DiscordComponent
builder.AddComponents [| button1 ; button2 |] |> ignore
builder.AddEmbed(embed4) |> ignore
do! ctx.FollowUp(builder) |> Async.AwaitTask |> Async.Ignore
return ()
})
let handlePrizeTable (ctx : IDiscordContext) =
task {
do! Messaging.defer ctx
let embed = DiscordEmbedBuilder()
match guildEmojis , anyEmoji with
| Some emojis , Some any ->
let folder acc elem =
let s1,s2,s3,prize = elem
let prizeTxt =
match prize with
| Money m -> $"**{m}** $GBT"
| Jackpot -> $"**🎉JACKPOT🎉**"
let line =
match s1 , s2 , s3 with
| Symbol s1' , Symbol s2' , Symbol s3' ->
$"{Formatter.Emoji(emojis.[s1'.emojiName])}{Formatter.Emoji(emojis.[s2'.emojiName])}{Formatter.Emoji(emojis.[s3'.emojiName])}"
| Symbol s1' , Symbol s2' , Any ->
$"{Formatter.Emoji(emojis.[s1'.emojiName])}{Formatter.Emoji(emojis.[s2'.emojiName])}{Formatter.Emoji(any)}"
| Symbol s1' , Any , Any ->
$"{Formatter.Emoji(emojis.[s1'.emojiName])}{Formatter.Emoji(any)}{Formatter.Emoji(any)}"
| _ -> ""
$"{acc}\n{line} {prizeTxt}"
let! jackpot = getJackpotAmount ()
let rows = Array.fold folder "" prizeTable
embed.Color <- DiscordColor.Green
embed.Title <- "Degenz Slots Prize Table"
embed.Description <- $"Current Jackpot At: **{jackpot}** $GBT\n\n**Combo** **Prize**\n{rows}"
let builder = DiscordFollowupMessageBuilder()
builder.IsEphemeral <- true
do! ctx.FollowUp(builder.AddEmbed(embed))
| _ , _ -> return ()
} :> Task
let handleButton (_ : DiscordClient) (event : ComponentInteractionCreateEventArgs) =
let ctx = DiscordEventContext event
task {
match event.Id with
| "spin" -> do! spin "Emojis" ctx
| "prizes" -> do! handlePrizeTable ctx
| _ ->
printfn "Wrong Spin ID"
return ()
} :> Task
let handleGuildDownloadCompleted (_ : DiscordClient) (event : GuildDownloadCompletedEventArgs) =
task {
let ( result , guild ) = event.Guilds.TryGetValue(GuildEnvironment.guildId)
guildEmojis <-
guild.Emojis
|> Seq.map (fun kvp -> kvp.Value) |> Seq.toArray
|> Seq.filter (fun de -> Array.contains de.Name slotEmojiNames)
|> Seq.distinctBy (fun de -> de.Name)
|> Seq.map (fun de -> ( de.Name , de ))
|> Map.ofSeq
|> Some
anyEmoji <- guild.Emojis |> Seq.tryPick (fun kvp -> if kvp.Value.Name = "any" then Some kvp.Value else None)
return ()
} :> Task
let sendInitialEmbed (ctx : IDiscordContext) =
async {
try
let channel = ctx.GetGuild().GetChannel(GuildEnvironment.channelSlots)
let builder = DiscordMessageBuilder()
let embed = DiscordEmbedBuilder()
embed.Title <- "Degenz Slot Machine"
embed.Description <- "Hello I am an embed"
embed.ImageUrl <- "https://i.kym-cdn.com/photos/images/original/001/169/608/a43.gif"
builder.AddEmbed(embed) |> ignore
let button1 = DiscordButtonComponent(ButtonStyle.Success, $"spin", $"Spin {PlayPrice} $GBT") :> DiscordComponent
let button2 = DiscordButtonComponent(ButtonStyle.Success, $"prizes", $"Show Prizes") :> DiscordComponent
builder.AddComponents [| button1 ; button2 |] |> ignore
do! GuildEnvironment.botClientSlots.Value.SendMessageAsync(channel, builder)
|> Async.AwaitTask
|> Async.Ignore
with e ->
printfn $"Error trying to get channel Training Dojo\n\n{e.Message}"
} |> Async.RunSynchronously