WIP: Check if player has role or recruits
This commit is contained in:
parent
929195393a
commit
c4f542d885
@ -28,7 +28,7 @@
|
||||
<Compile Include="Whitelist.fs" />
|
||||
<Compile Include="Admin.fs" />
|
||||
<Compile Include="Bot.fs" />
|
||||
<None Include="Scripts\Whitelist.fsx" />
|
||||
<None Include="Scripts\GetWhitelisted.fsx" />
|
||||
<None Include="Scripts\Airdrop.fsx" />
|
||||
</ItemGroup>
|
||||
<Import Project="..\.paket\Paket.Restore.targets" />
|
||||
|
@ -116,6 +116,8 @@ let getStoreItems (storeId : string) =
|
||||
Stock = reader.int "stock"
|
||||
LimitStock = reader.bool "limit_stock"
|
||||
Available = reader.bool "available"
|
||||
RequiresInvites = None
|
||||
RequiresRole = None
|
||||
StoreItem.Item = readItem reader
|
||||
})
|
||||
|> Async.AwaitTask
|
||||
@ -136,6 +138,8 @@ let getStoreItemBySymbol (itemSymbol : string) =
|
||||
Stock = reader.int "stock"
|
||||
LimitStock = reader.bool "limit_stock"
|
||||
Available = reader.bool "available"
|
||||
RequiresInvites = None
|
||||
RequiresRole = None
|
||||
StoreItem.Item = readItem reader
|
||||
})
|
||||
|> Async.AwaitTask
|
||||
|
@ -141,6 +141,8 @@ type StoreItem = {
|
||||
Stock : int
|
||||
LimitStock : bool
|
||||
Available : bool
|
||||
RequiresRole : uint64 option
|
||||
RequiresInvites : int option
|
||||
Item : Item
|
||||
}
|
||||
|
||||
|
@ -9,22 +9,32 @@ open DSharpPlus.SlashCommands
|
||||
open Degenz
|
||||
open Degenz.Messaging
|
||||
open Degenz.PlayerInteractions
|
||||
open FsToolkit.ErrorHandling
|
||||
|
||||
let checkHasStock (item : StoreItem) player =
|
||||
let embedWithError error =
|
||||
DiscordFollowupMessageBuilder()
|
||||
.AsEphemeral()
|
||||
.WithContent(error)
|
||||
|> Error
|
||||
|
||||
let checkHasStock (item : StoreItem) =
|
||||
if item.Stock > 0 || item.LimitStock = false
|
||||
then Ok player
|
||||
else Error $"{item.Item.Name} is out of stock! Check back later to purchase"
|
||||
then Ok ()
|
||||
else $"{item.Item.Name} is out of stock! Check back later to purchase"
|
||||
|> embedWithError
|
||||
|
||||
let checkHasSufficientFunds (item : Item) player =
|
||||
match item.Attributes with
|
||||
| CanBuy price ->
|
||||
if player.Bank - price >= 0<GBT>
|
||||
then Ok player
|
||||
else Error $"""
|
||||
then Ok ()
|
||||
else $"""
|
||||
**__Current Balance:__** {player.Bank} 💰 $GBT
|
||||
Hold up Degen! You don't have enough $GBT!
|
||||
Go to <#{GuildEnvironment.channelQuests}> to start earning some now..."""
|
||||
| _ -> Error $"{item.Name} item cannot be bought"
|
||||
|> embedWithError
|
||||
| _ -> $"{item.Name} item cannot be bought"
|
||||
|> embedWithError
|
||||
|
||||
let getTotalOwnedOfItem (item : Item) (inventory : Item list) =
|
||||
inventory
|
||||
@ -37,20 +47,23 @@ let checkDoesntExceedStackCap (item : Item) player =
|
||||
match item.Attributes , itemCount with
|
||||
| CanStack max , Some count ->
|
||||
if count >= max
|
||||
then Error $"You own the maximum allowed amount {item.Name}!"
|
||||
else Ok player
|
||||
| _ , Some _ -> Error $"You already own this item"
|
||||
| _ -> Ok player
|
||||
then $"You own the maximum allowed amount {item.Name}!"
|
||||
|> embedWithError
|
||||
else Ok ()
|
||||
| _ , Some _ -> "You already own this item" |> embedWithError
|
||||
| _ -> Ok ()
|
||||
|
||||
let checkSoldItemAlready (item : Item) player =
|
||||
if player.Inventory |> List.exists (fun i -> item.Id = i.Id)
|
||||
then Ok player
|
||||
else Error $"{item.Name} not found in your inventory! Looks like you sold it already."
|
||||
then Ok ()
|
||||
else $"{item.Name} not found in your inventory! Looks like you sold it already."
|
||||
|> embedWithError
|
||||
|
||||
let checkHasItemsInArsenal itemType items player =
|
||||
if List.isEmpty items |> not
|
||||
then Ok player
|
||||
else Error $"You currently have no {itemType} in your arsenal to sell!"
|
||||
then Ok ()
|
||||
else $"You currently have no {itemType} in your arsenal to sell!"
|
||||
|> embedWithError
|
||||
|
||||
let getItemEmbeds owned (items : StoreItem list) =
|
||||
items
|
||||
@ -198,7 +211,7 @@ let showJpegsEmbed (ctx : IDiscordContext) = PlayerInteractions.executePlayerAct
|
||||
let jpegs =
|
||||
player.Inventory
|
||||
|> Inventory.getItemsByType ItemType.Jpeg
|
||||
|> List.map (fun i -> { StoreId = "BACKALLEY" ; Item = i ; Stock = 1 ; LimitStock = false ; Available = true })
|
||||
|> List.map (fun i -> { StoreId = "" ; Item = i ; Stock = 1 ; LimitStock = false ; Available = true ; RequiresInvites = None ; RequiresRole = None })
|
||||
match jpegs with
|
||||
| [] -> do! Messaging.sendFollowUpMessage ctx $"You currently do not own any jpegs or raffle tickets. Go to <#{GuildEnvironment.channelBackAlley}> to buy some"
|
||||
| jpegs ->
|
||||
@ -224,56 +237,104 @@ let buy storeId (filterBy : ItemType option) (ctx : IDiscordContext) =
|
||||
with ex -> printfn $"{ex.Message}"
|
||||
})
|
||||
|
||||
let buyForPlayer storeId player (filterBy : ItemType option) (ctx : IDiscordContext) = async {
|
||||
try
|
||||
let! items = DbService.getStoreItems storeId
|
||||
if items.Length > 0 then
|
||||
let items' =
|
||||
match filterBy with
|
||||
| Some itemType -> items |> List.filter (fun item -> item.Item.Type = itemType)
|
||||
| None -> items
|
||||
let itemStore = getBuyItemsEmbed storeId player items'
|
||||
do! ctx.FollowUp itemStore |> Async.AwaitTask
|
||||
do! Analytics.buyItemCommand (ctx.GetDiscordMember()) storeId
|
||||
else
|
||||
do! Messaging.sendFollowUpMessage ctx "There are currently no items available, check back later"
|
||||
with ex -> printfn $"{ex.Message}"
|
||||
}
|
||||
|
||||
let sell itemType getItems (ctx : IDiscordContext) =
|
||||
executePlayerAction ctx (fun player -> async {
|
||||
let items = getItems player.Inventory
|
||||
match checkHasItemsInArsenal itemType items player with
|
||||
| Ok _ -> let itemStore = getSellEmbed items
|
||||
do! ctx.FollowUp(itemStore) |> Async.AwaitTask
|
||||
| Error e -> do! sendFollowUpMessage ctx e
|
||||
| Error e -> do! ctx.FollowUp e |> Async.AwaitTask
|
||||
do! Analytics.buyItemCommand (ctx.GetDiscordMember()) itemType
|
||||
})
|
||||
|
||||
let checkHasRequiredInvites storeItem player =
|
||||
async {
|
||||
match storeItem.RequiresInvites with
|
||||
| Some amount ->
|
||||
let! totalInvites = InviteTracker.getInvitedUserCount player.DiscordId
|
||||
if amount <= totalInvites then
|
||||
return Ok ()
|
||||
else
|
||||
return "" |> embedWithError
|
||||
| None -> return Ok ()
|
||||
}
|
||||
|
||||
let checkHasRequiredRole storeItem (user : DiscordMember) =
|
||||
match storeItem.RequiresRole with
|
||||
| Some roleId ->
|
||||
if user.Roles |> Seq.exists (fun r -> r.Id = roleId) then
|
||||
Ok ()
|
||||
else
|
||||
let builder = DiscordFollowupMessageBuilder().AsEphemeral()
|
||||
let embed = DiscordEmbedBuilder()
|
||||
embed.Description <- $"""
|
||||
|
||||
"""
|
||||
builder.AddEmbed(embed)
|
||||
"" |> embedWithError
|
||||
| None -> Ok ()
|
||||
|
||||
// TODO: When you buy a shield, prompt the user to activate it
|
||||
let handleBuyItem (dispatch : IDiscordContext -> Task) (ctx : IDiscordContext) itemId =
|
||||
executePlayerAction ctx (fun player -> async {
|
||||
let storeId = ctx.GetInteractionId().Split("-").[2]
|
||||
let! storeInventory = DbService.getStoreItems storeId
|
||||
let storeItem = storeInventory |> List.find (fun si -> si.Item.Id = itemId)
|
||||
let item = storeInventory |> List.map (fun i -> i.Item) |> Inventory.findItemById itemId
|
||||
do! player
|
||||
|> checkHasSufficientFunds item
|
||||
>>= checkHasStock storeItem
|
||||
>>= checkDoesntExceedStackCap item
|
||||
|> handleResultWithResponse ctx (fun player -> async {
|
||||
let price = match item.Attributes with CanBuy price -> price | _ -> 0<GBT>
|
||||
let! result = asyncResult {
|
||||
let! storeInventory = DbService.getStoreItems storeId
|
||||
let storeItem = storeInventory |> List.find (fun si -> si.Item.Id = itemId)
|
||||
do! checkHasSufficientFunds storeItem.Item player
|
||||
do! checkHasStock storeItem
|
||||
do! checkDoesntExceedStackCap storeItem.Item player
|
||||
do! checkHasRequiredRole storeItem (ctx.GetDiscordMember())
|
||||
do! checkHasRequiredInvites storeItem player
|
||||
return storeItem
|
||||
}
|
||||
return!
|
||||
result
|
||||
|> handleResultWithEmbed ctx (fun storeItem -> async {
|
||||
let price = match storeItem.Item.Attributes with CanBuy price -> price | _ -> 0<GBT>
|
||||
try
|
||||
do! dispatch ctx |> Async.AwaitTask
|
||||
do! DbService.updatePlayerCurrency -price player.DiscordId |> Async.Ignore
|
||||
do! DbService.addToPlayerInventory player.DiscordId item |> Async.Ignore
|
||||
do! DbService.addToPlayerInventory player.DiscordId storeItem.Item |> Async.Ignore
|
||||
if storeItem.LimitStock = true && storeItem.Stock > 0 then
|
||||
do! DbService.decrementItemStock item |> Async.Ignore
|
||||
do! DbService.decrementItemStock storeItem.Item |> Async.Ignore
|
||||
let builder = DiscordFollowupMessageBuilder().AsEphemeral(true)
|
||||
let embed = purchaseItemEmbed 1 item
|
||||
match item.Attributes , getTotalOwnedOfItem item player.Inventory |> Option.defaultValue 0 with
|
||||
let embed = purchaseItemEmbed 1 storeItem.Item
|
||||
match storeItem.Item.Attributes , getTotalOwnedOfItem storeItem.Item player.Inventory |> Option.defaultValue 0 with
|
||||
| CanStack max , amount ->
|
||||
embed.AddField("Owned", $"{amount + 1}", true) |> ignore
|
||||
embed.AddField("New $GBT Balance", $"`💰` {player.Bank - price} `(-{price} $GBT)`", true) |> ignore
|
||||
if amount + 1 < max then
|
||||
let btn = DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Buy-{item.Id}-{storeId}", $"Buy Another")
|
||||
let btn = DiscordButtonComponent(WeaponClass.getClassButtonColor storeItem.Item, $"Buy-{storeItem.Item.Id}-{storeId}", $"Buy Another")
|
||||
builder.AddComponents(btn) |> ignore
|
||||
| _ -> ()
|
||||
builder.AddEmbed(embed) |> ignore
|
||||
do! ctx.FollowUp builder |> Async.AwaitTask
|
||||
|
||||
let builder = DiscordMessageBuilder()
|
||||
builder.WithContent($"{player.Name} just purchased {item.Name}!") |> ignore
|
||||
builder.WithContent($"{player.Name} just purchased {storeItem.Item.Name}!") |> ignore
|
||||
let channel = ctx.GetGuild().GetChannel(GuildEnvironment.channelEventsHackerBattle)
|
||||
do! channel.SendMessageAsync(builder)
|
||||
|> Async.AwaitTask
|
||||
|> Async.Ignore
|
||||
|
||||
do! Analytics.buyItemButton (ctx.GetDiscordMember()) item.Id price
|
||||
do! Analytics.buyItemButton (ctx.GetDiscordMember()) storeItem.Item.Id price
|
||||
with ex ->
|
||||
printfn $"STORE ERROR: {ex.Message}"
|
||||
})
|
||||
@ -285,7 +346,7 @@ let handleSell (ctx : IDiscordContext) itemId =
|
||||
do!
|
||||
player
|
||||
|> checkSoldItemAlready item
|
||||
|> handleResultWithResponse ctx (fun player -> async {
|
||||
|> handleResultWithEmbed ctx (fun () -> async {
|
||||
match item.Attributes with
|
||||
| CanSell price ->
|
||||
do!
|
||||
@ -300,28 +361,6 @@ let handleSell (ctx : IDiscordContext) itemId =
|
||||
})
|
||||
})
|
||||
|
||||
let showStats (ctx : IDiscordContext) = PlayerInteractions.executePlayerAction ctx (fun player -> async {
|
||||
let embed = DiscordEmbedBuilder()
|
||||
PlayerStats.stats
|
||||
|> List.iter (fun statConfig ->
|
||||
let playerStat = PlayerStats.getPlayerStat statConfig player
|
||||
let min =
|
||||
match statConfig.BaseRange.Min = playerStat.ModRange.Min with
|
||||
| true -> $"{statConfig.BaseRange.Min}"
|
||||
| false -> $"{statConfig.BaseRange.Min} (+{playerStat.ModRange.Min}) "
|
||||
let max =
|
||||
match statConfig.BaseRange.Max = playerStat.ModRange.Max with
|
||||
| true -> $"{statConfig.BaseRange.Max}"
|
||||
| false -> $"{statConfig.BaseRange.Max} (+{playerStat.ModRange.Max}) "
|
||||
let field = $"{min} |---------------| {max}"
|
||||
embed.AddField(string statConfig.Id , field) |> ignore)
|
||||
let builder =
|
||||
DiscordFollowupMessageBuilder()
|
||||
.AddEmbed(embed)
|
||||
.AsEphemeral(true)
|
||||
do! ctx.FollowUp builder |> Async.AwaitTask
|
||||
})
|
||||
|
||||
let handleJpegEvents _ (event : ComponentInteractionCreateEventArgs) =
|
||||
let ctx = DiscordEventContext event :> IDiscordContext
|
||||
let id = ctx.GetInteractionId()
|
||||
@ -364,15 +403,15 @@ let sendBackalleyEmbed (ctx : IDiscordContext) =
|
||||
let builder = DiscordMessageBuilder()
|
||||
let embed = DiscordEmbedBuilder()
|
||||
embed.ImageUrl <- "https://s7.gifyu.com/images/ezgif.com-gif-maker-23203b9dca779ba7cf.gif"
|
||||
embed.Title <- "Jpeg Store"
|
||||
embed.Title <- "🎟️ Raffle Store"
|
||||
embed.Color <- DiscordColor.Black
|
||||
embed.Description <- "Hey, what do you want kid?"
|
||||
embed.Description <- $"Hey, what do you want, kid?\nI ain’t got all day… {Formatter.Emoji}"
|
||||
builder.AddEmbed embed |> ignore
|
||||
let button1 = DiscordButtonComponent(ButtonStyle.Success, $"ShowStore-0-BACKALLEY1", $"NFT Raffles") :> DiscordComponent
|
||||
let button1 = DiscordButtonComponent(ButtonStyle.Danger, $"ShowStore-0-BACKALLEY1", $"NFT Raffles") :> DiscordComponent
|
||||
let button2 = DiscordButtonComponent(ButtonStyle.Success, $"ShowStore-0-BACKALLEY2", $"Whitelist Raffles") :> DiscordComponent
|
||||
let button3 = DiscordButtonComponent(ButtonStyle.Success, $"ShowStore-0-BACKALLEY3", $"USDT Raffles") :> DiscordComponent
|
||||
// let button3 = DiscordButtonComponent(ButtonStyle.Success, $"ShowStore-0-BACKALLEY3", $"USDT Raffles") :> DiscordComponent
|
||||
let button4 = DiscordButtonComponent(ButtonStyle.Primary, $"ShowJpegInventory-0-0", $"View My Stash") :> DiscordComponent
|
||||
builder.AddComponents [| button1 ; button2 ; button3 ; button4 |] |> ignore
|
||||
builder.AddComponents [| button1 ; button2 ; button4 |] |> ignore
|
||||
|
||||
do! GuildEnvironment.botClientJpeg.Value.SendMessageAsync(channel, builder)
|
||||
|> Async.AwaitTask
|
||||
|
@ -11,7 +11,7 @@ open Npgsql.FSharp
|
||||
open Solnet.Wallet
|
||||
|
||||
let connStr = GuildEnvironment.connectionString
|
||||
let InviteRewardAmount = 100<GBT>
|
||||
let InviteRewardAmount = 300<GBT>
|
||||
let InviteLinkButtonText = "Get My Invite Link"
|
||||
|
||||
type Invite = {
|
||||
@ -318,16 +318,16 @@ let sendInitialEmbed (ctx : IDiscordContext) =
|
||||
try
|
||||
let channel = ctx.GetGuild().GetChannel(GuildEnvironment.channelRecruitment)
|
||||
let rewardMsg = $"""
|
||||
**__Win $2,000:__**
|
||||
**__Win $3,000:__**
|
||||
🙋 1 invite = 1 entry everyday*
|
||||
🎟 $100 daily raffles till mint
|
||||
|
||||
**__How To Invite:__**
|
||||
1️⃣ Click the green button below
|
||||
2️⃣ Share your unique link with Degenz
|
||||
2️⃣ Share your unique link with Friends
|
||||
|
||||
**__Bonus__**
|
||||
💰 Earn an extra 100 $GBT for every invite!
|
||||
💰 Earn an extra 300 $GBT for every invite!
|
||||
|
||||
**Every invite increases your chances of winning*
|
||||
"""
|
||||
@ -335,7 +335,7 @@ let sendInitialEmbed (ctx : IDiscordContext) =
|
||||
DiscordEmbedBuilder()
|
||||
.WithColor(DiscordColor.CornflowerBlue)
|
||||
.WithDescription(rewardMsg)
|
||||
.WithImageUrl("https://s8.gifyu.com/images/invite-banner-usdc.png")
|
||||
.WithImageUrl("https://s8.gifyu.com/images/invite-banner-usdcb670496dc3653cb3.png")
|
||||
.WithTitle("Invite Degenz")
|
||||
|
||||
let builder = DiscordMessageBuilder().AddEmbed(embed)
|
||||
|
@ -56,3 +56,8 @@ let handleResultWithResponse ctx fn (player : Result<PlayerData, string>) =
|
||||
match player with
|
||||
| Ok p -> fn p
|
||||
| Error e -> async { do! Messaging.sendFollowUpMessage ctx e }
|
||||
|
||||
let handleResultWithEmbed<'a> (ctx : IDiscordContext) fn (player : Result<'a, DiscordFollowupMessageBuilder>) =
|
||||
match player with
|
||||
| Ok a -> fn a
|
||||
| Error e -> async { do! ctx.FollowUp e |> Async.AwaitTask}
|
||||
|
@ -24,10 +24,12 @@ let sendInitialEmbed (ctx : IDiscordContext) =
|
||||
embed.Title <- "Degenz Game Whitelist"
|
||||
embed.Color <- DiscordColor.White
|
||||
embed.Description <- $"""
|
||||
You need to **BUY** Whitelist with 💰 $GBT...
|
||||
**__Requirements:__**
|
||||
You need to BUY Whitelist with 💰 $GBT
|
||||
You must have INVITED at least 1 Degen…
|
||||
|
||||
**__To Earn $GBT:__**
|
||||
1️⃣ Recruit Degenz in <#{GuildEnvironment.channelRecruitment}>
|
||||
1️⃣ Invite Degenz in <#{GuildEnvironment.channelRecruitment}>
|
||||
2️⃣ Chat to level up in the <#{GuildEnvironment.channelGeneral}>
|
||||
3️⃣ Complete fun quests inside <#{GuildEnvironment.channelQuests}>
|
||||
"""
|
||||
@ -59,7 +61,28 @@ let grantWhitelistRole isOg (ctx : IDiscordContext) =
|
||||
let handleButtonEvent _ (event : ComponentInteractionCreateEventArgs) =
|
||||
let ctx = DiscordEventContext event :> IDiscordContext
|
||||
match event.Id with
|
||||
| id when id.StartsWith("GimmeWhitelist") -> Store.buy "WHITELIST" None ctx
|
||||
| id when id.StartsWith("GimmeWhitelist") ->
|
||||
task {
|
||||
let builder = DiscordInteractionResponseBuilder().AsEphemeral(true).WithContent("Content")
|
||||
do! ctx.Respond(InteractionResponseType.DeferredChannelMessageWithSource, builder) |> Async.AwaitTask
|
||||
let! invites = InviteTracker.getInvitedUserCount (ctx.GetDiscordMember().Id)
|
||||
if invites > 0 then
|
||||
let! playerResult = DbService.tryFindPlayer (ctx.GetDiscordMember().Id)
|
||||
match playerResult with
|
||||
| Some player -> do! Store.buyForPlayer "WHITELIST" player None ctx |> Async.StartAsTask
|
||||
| None -> do! Messaging.sendFollowUpMessage ctx "You are currently not a hacker, first use the /redpill command to become one"
|
||||
else
|
||||
let builder = DiscordFollowupMessageBuilder().AsEphemeral(true)
|
||||
builder.Content <- $"""
|
||||
❌ **Degen**, can’t you **READ**?!
|
||||
⚠️ **__Requirements:__** 1x Invited User
|
||||
|
||||
To BUY Whitelist you must have **__INVITED__** 1 Degen.
|
||||
☑️ Go to <#{GuildEnvironment.channelRecruitment}>
|
||||
☑️ Invite just 1 Degen!
|
||||
"""
|
||||
do! ctx.FollowUp(builder)
|
||||
} :> Task
|
||||
| id when id.StartsWith("Buy") ->
|
||||
task {
|
||||
let id = ctx.GetInteractionId()
|
||||
|
@ -6,3 +6,4 @@ dotenv.net
|
||||
Npgsql.FSharp
|
||||
mixpanel-csharp
|
||||
Solnet.Rpc
|
||||
FsToolkit.ErrorHandling
|
@ -8,6 +8,7 @@ nuget FSharp.Core >= 6.0.0
|
||||
nuget DSharpPlus >= 4.3.0-nightly-01135
|
||||
nuget DSharpPlus.Interactivity >= 4.3.0-nightly-01135
|
||||
nuget DSharpPlus.SlashCommands >= 4.3.0-nightly-01135
|
||||
nuget FsToolkit.ErrorHandling
|
||||
|
||||
nuget MongoDB.Driver
|
||||
nuget dotenv.net 3.1.1
|
||||
|
@ -31,6 +31,8 @@ NUGET
|
||||
System.Runtime.CompilerServices.Unsafe (>= 5.0)
|
||||
System.ValueTuple (>= 4.5)
|
||||
FSharp.Core (6.0.3)
|
||||
FsToolkit.ErrorHandling (2.13)
|
||||
FSharp.Core (>= 4.7.2)
|
||||
Microsoft.Bcl.AsyncInterfaces (6.0) - restriction: || (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0)
|
||||
System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461))
|
||||
Microsoft.Bcl.HashCode (1.1.1) - restriction: || (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user