New Whitelist flow and accept invite when completing training

This commit is contained in:
Joseph Ferano 2022-03-24 23:21:08 +07:00
parent 7b26bd05cd
commit a8ab4a6abd
6 changed files with 216 additions and 77 deletions

View File

@ -81,10 +81,10 @@ let asdf (_ : DiscordClient) (event : DSharpPlus.EventArgs.InteractionCreateEven
:> Task
//hackerBattleBot.add_InteractionCreated(AsyncEventHandler(asdf))
//if guild <> 922419263275425832uL then
if guild <> 922419263275425832uL then
// Trainer.sendInitialEmbed hackerBattleBot
InviteTracker.sendInitialEmbed inviterBot
InviteTracker.sendInitialEmbed inviterBot
hackerBattleBot.ConnectAsync() |> Async.AwaitTask |> Async.RunSynchronously
GuildEnvironment.botUserHackerBattle <- Some hackerBattleBot.CurrentUser
@ -92,9 +92,9 @@ GuildEnvironment.botUserHackerBattle <- Some hackerBattleBot.CurrentUser
storeBot.ConnectAsync() |> Async.AwaitTask |> Async.RunSynchronously
GuildEnvironment.botUserArmory <- Some storeBot.CurrentUser
inviterBot.ConnectAsync() |> Async.AwaitTask |> Async.RunSynchronously
//stealBot.ConnectAsync() |> Async.AwaitTask |> Async.RunSynchronously
inviterBot.ConnectAsync() |> Async.AwaitTask |> Async.RunSynchronously
let rec loop areBotsRunning =

View File

@ -15,6 +15,7 @@ type User = {
Focus : int
Charisma : int
Luck : int
Active : bool
}
let getPlayerEvents (did : uint64) =
@ -75,7 +76,7 @@ let tryFindPlayer (discordId : uint64) = async {
|> Sql.connect
|> Sql.parameters [ "did", Sql.string (string discordId) ]
|> Sql.query """
SELECT discord_id, display_name, gbt, inventory, strength, focus, charisma, luck FROM "user"
SELECT discord_id, display_name, gbt, in_game, inventory, strength, focus, charisma, luck FROM "user"
WHERE discord_id = @did
"""
|> Sql.executeAsync (fun read ->
@ -89,6 +90,7 @@ let tryFindPlayer (discordId : uint64) = async {
Focus = read.intOrNone "focus" |> Option.defaultValue 0
Charisma = read.intOrNone "charisma" |> Option.defaultValue 0
Luck = read.intOrNone "luck" |> Option.defaultValue 0
Active = read.bool "in_game"
})
|> Async.AwaitTask
match List.tryHead user with
@ -106,7 +108,8 @@ let tryFindPlayer (discordId : uint64) = async {
Inventory = inventory
Events = events
Stats = { Strength = strength ; Focus = focus ; Charisma = charisma ; Luck = luck }
Bank = u.Bank }
Bank = u.Bank
Active = u.Active }
with e ->
printfn $"Got an error{e.Message}"
return None

View File

@ -174,6 +174,7 @@ type PlayerData = {
Events : PlayerEvent list
Stats : Stats
Bank : int<GBT>
Active : bool
}
// Achievements : string array
// XP : int
@ -186,4 +187,5 @@ with member this.toDiscordPlayer = { Id = this.DiscordId ; Name = this.Name }
Stats = Stats.empty
// Achievements = [||]
// XP = 0
Bank = 0<GBT> }
Bank = 0<GBT>
Active = false }

View File

@ -174,6 +174,9 @@ type the `/arsenal` command NOW"""
if not completed then
do! sendFollowUpMessage ctx message
else
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee)
do! ctx.GetDiscordMember().RevokeRoleAsync(role) |> Async.AwaitTask
do! sendFollowUpMessage ctx ($"Your training is now complete. If you want to buy more **HACKS & SHIELDS**, go to the <#{GuildEnvironment.channelArmory}> and type the `/buy-hack` and `/buy-shield` commands!")
})
@ -219,13 +222,20 @@ let handleArsenal (ctx : IDiscordContext) = PlayerInteractions.executePlayerActi
do! ctx.FollowUp(embed) |> Async.AwaitTask
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee)
do! ctx.GetDiscordMember().RevokeRoleAsync(role)
|> Async.AwaitTask
do! ctx.GetDiscordMember().RevokeRoleAsync(role) |> Async.AwaitTask
do! Async.Sleep 2000
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleHacker)
do! ctx.GetDiscordMember().GrantRoleAsync(role) |> Async.AwaitTask
do! InviteTracker.acceptInvite ctx player |> Async.AwaitTask
do! Async.Sleep 1000
do! sendFollowUpMessage ctx $"Now get out of there and go hack other Degenz in the <#{GuildEnvironment.channelBattle}> channel!"
else
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee)
do! ctx.GetDiscordMember().RevokeRoleAsync(role) |> Async.AwaitTask
do! sendFollowUpMessage ctx ($"Your training is now complete. If you want to buy more **HACKS & SHIELDS**, go to the <#{GuildEnvironment.channelArmory}> and type the `/buy-hack` and `/buy-shield` commands!")
})

View File

@ -26,6 +26,9 @@ let channelArmory = getId "CHANNEL_ARMORY"
let channelBattle = getId "CHANNEL_BATTLE"
let channelWelcome = getId "CHANNEL_WELCOME"
let channelWhitelist = getId "CHANNEL_WHITELIST"
let channelElite = getId "CHANNEL_ELITE"
let channelTosserTed = getId "CHANNEL_TOSSERTED"
let channelShelters = getId "CHANNEL_SHELTERS"
//let channelBackAlley = getId "CHANNEL_BACKALLEY"
//let channelMarket = getId "CHANNEL_MARKET"
//let channelAccessoryShop = getId "CHANNEL_ACCESSORIES"
@ -33,8 +36,10 @@ let channelWhitelist = getId "CHANNEL_WHITELIST"
//let channelThievery = getId "CHANNEL_THIEVERY"
let botIdHackerBattle = getId "BOT_HACKER_BATTLE"
let botIdArmory = getId "BOT_ARMORY"
let botIdTosserTed = getId "BOT_TOSSERTED"
//let botInviter = getId "BOT_INVITER"
let roleTrainee = getId "ROLE_TRAINEE"
let roleHacker = getId "ROLE_HACKER"
let rolePrisoner = getId "ROLE_PRISONER"
let roleWhitelist = getId "ROLE_WHITELIST"

View File

@ -11,7 +11,7 @@ open Npgsql.FSharp
let connStr = GuildEnvironment.connectionString
let InviteRewardAmount = 100<GBT>
let WhitelistInviteRequirement = 5
let WhitelistPrice = 1000
type Invite = {
Code : string
@ -19,20 +19,18 @@ type Invite = {
Count : int
}
let getInvites () = async {
let private mapInvite (reader : RowReader) = {
Code = reader.string "code"
Inviter = reader.string "inviter" |> uint64
Count = reader.int "count"
}
let private getInvites () = async {
let! invites =
connStr
|> Sql.connect
// TODO: Invites shouldn't expire anymore
|> Sql.query """
SELECT code, inviter, count FROM invite
WHERE created_at > (current_timestamp at time zone 'utc') - interval '1 day'
"""
|> Sql.executeAsync (fun read -> {
Code = read.string "code"
Inviter = read.string "inviter" |> uint64
Count = read.int "count"
})
|> Sql.query "SELECT code, inviter, count FROM invite"
|> Sql.executeAsync mapInvite
|> Async.AwaitTask
return
invites
@ -40,7 +38,7 @@ let getInvites () = async {
|> Map.ofList
}
let getInvitesFromUser discordId = async {
let private getInvitesFromUser discordId = async {
let! invites =
connStr
|> Sql.connect
@ -61,7 +59,7 @@ let getInvitesFromUser discordId = async {
|> Map.ofList
}
let createInvite inviter code =
let private createInvite inviter code =
connStr
|> Sql.connect
|> Sql.parameters [ "code" , Sql.string code ; "inviter" , Sql.string (string inviter) ]
@ -69,7 +67,7 @@ let createInvite inviter code =
|> Sql.executeNonQueryAsync
|> Async.AwaitTask
let addInvitedUser did code count =
let private addInvitedUser did code count =
try
connStr
|> Sql.connect
@ -84,7 +82,7 @@ let addInvitedUser did code count =
|> Async.Ignore
with _ -> async.Zero ()
let acceptInvite did =
let private markInvitedAccepted did =
connStr
|> Sql.connect
|> Sql.parameters [ "did" , Sql.string (string did) ]
@ -92,7 +90,19 @@ let acceptInvite did =
|> Sql.executeNonQueryAsync
|> Async.AwaitTask
let removeInvitedUser did =
let private getInviteFromInvitedUser invitedUser =
connStr
|> Sql.connect
|> Sql.parameters [ "did" , Sql.string (string invitedUser) ]
|> Sql.query """
SELECT code, inviter, count FROM invite
JOIN invited_user iu ON invite.id = iu.invite_id
WHERE iu.discord_id = @did
"""
|> Sql.executeRowAsync mapInvite
|> Async.AwaitTask
let private removeInvitedUser did =
try
connStr
|> Sql.connect
@ -103,7 +113,7 @@ let removeInvitedUser did =
|> Async.Ignore
with _ -> async.Zero ()
let checkUserInvited userId = async {
let private checkUserAlreadyInvited userId = async {
let! result =
connStr
|> Sql.connect
@ -117,7 +127,22 @@ let checkUserInvited userId = async {
return List.isEmpty result |> not
}
let getInviteAttributions userId =
let checkInviteAccepted (userId : uint64) = async {
try
let! result =
connStr
|> Sql.connect
|> Sql.parameters [ "did" , Sql.string (string userId) ]
|> Sql.query "SELECT accepted FROM invited_user WHERE discord_id = @did"
|> Sql.executeRowAsync (fun read -> read.bool "accepted")
|> Async.AwaitTask
return result
with ex ->
printfn "%s %u" ex.Message userId
return false
}
let private getInviteAttributions userId =
connStr
|> Sql.connect
|> Sql.parameters [ "did" , Sql.string (string userId) ]
@ -129,7 +154,7 @@ let getInviteAttributions userId =
|> Sql.executeRowAsync (fun read -> read.int "count")
|> Async.AwaitTask
let getInvitedUsers userId =
let private getInvitedUsers userId =
connStr
|> Sql.connect
|> Sql.parameters [ "did" , Sql.string (string userId) ]
@ -141,7 +166,7 @@ let getInvitedUsers userId =
|> Sql.executeAsync (fun read -> read.string "discord_id" |> uint64)
|> Async.AwaitTask
let createGuildInvite (ctx : IDiscordContext) showWhitelistReward =
let private createGuildInvite (ctx : IDiscordContext) showWhitelistReward =
task {
let invitesRequired = 5
let rewardMsg =
@ -168,7 +193,7 @@ let createGuildInvite (ctx : IDiscordContext) showWhitelistReward =
} :> Task
let listServerInvites (ctx : IDiscordContext) = task {
let private listServerInvites (ctx : IDiscordContext) = task {
let! invites = ctx.GetGuild().GetInvitesAsync()
let sb = StringBuilder()
for invite in invites do
@ -180,7 +205,7 @@ let listServerInvites (ctx : IDiscordContext) = task {
do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, msg)
}
let getAttributions (ctx : IDiscordContext) userId = task {
let private getAttributions (ctx : IDiscordContext) userId = task {
let! total = getInviteAttributions(userId)
let msg =
DiscordInteractionResponseBuilder()
@ -189,7 +214,7 @@ let getAttributions (ctx : IDiscordContext) userId = task {
do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, msg)
}
let getInvitedUsersForId (ctx : IDiscordContext) = task {
let private getInvitedUsersForId (ctx : IDiscordContext) = task {
let! users = getInvitedUsers(ctx.GetDiscordMember().Id)
let sb = StringBuilder()
let mutable count = 0
@ -213,35 +238,47 @@ let clearInvites (ctx : IDiscordContext) = task {
do!
invites
|> Seq.map (fun invite -> invite.DeleteAsync() |> Async.AwaitTask)
|> Async.Parallel
|> Async.Sequential
|> Async.Ignore
}
let processNewUser (eventArgs : GuildMemberAddEventArgs) =
// Discord doesn't have any way to tell you if the user came via an invite, the only way to tell is to compare the
// cached invites in the DB to the ones in the guild and see if any has been incremented
let private processNewUser (eventArgs : GuildMemberAddEventArgs) =
task {
let! guildInvites = eventArgs.Guild.GetInvitesAsync()
let! cachedInvites = getInvites()
let! cachedInvites = getInvites ()
for invite in guildInvites do
let result = cachedInvites.TryFind(invite.Code)
match result with
| Some (inviter,count) ->
| Some (_,count) ->
if invite.Uses > count then
do! addInvitedUser eventArgs.Member.Id invite.Code invite.Uses |> Async.Ignore
let! _ = acceptInvite eventArgs.Member.Id
let! player = DbService.tryFindPlayer inviter
match player with
| Some player ->
do! DbService.updatePlayerCurrency (int InviteRewardAmount) player |> Async.Ignore
let builder = DiscordMessageBuilder()
builder.WithContent($"{eventArgs.Member.DisplayName} was recruited to the server. <@{player.DiscordId}> just earned {InviteRewardAmount} 💰$GBT for their efforts!") |> ignore
let channel = eventArgs.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle)
do! channel.SendMessageAsync(builder)
|> Async.AwaitTask
|> Async.Ignore
| None -> return ()
| None -> ()
} :> Task
let acceptInvite (ctx : IDiscordContext) (invitedPlayer : PlayerData) =
task {
match! checkInviteAccepted invitedPlayer.DiscordId with
| false ->
let! _ = markInvitedAccepted invitedPlayer.DiscordId |> Async.Ignore
try
let! inviter = getInviteFromInvitedUser invitedPlayer.DiscordId
let! player = DbService.tryFindPlayer inviter.Inviter
match player with
| Some player ->
do! DbService.updatePlayerCurrency (int InviteRewardAmount) player |> Async.Ignore
let builder = DiscordMessageBuilder()
builder.WithContent($"{invitedPlayer.Name} was recruited to the server. <@{player.DiscordId}> just earned {InviteRewardAmount} 💰$GBT for their efforts!") |> ignore
let channel = ctx.GetGuild().GetChannel(GuildEnvironment.channelEventsHackerBattle)
do! channel.SendMessageAsync(builder)
|> Async.AwaitTask
|> Async.Ignore
| None -> return ()
with _ -> ()
| true -> return ()
} :> Task
// If we do it like this then there's an obvious exploit where the user can come and go as many times and it will keep
// rewarding GBT.
//let handleGuildMemberRemoved _ (eventArgs : GuildMemberRemoveEventArgs) =
@ -249,16 +286,30 @@ let processNewUser (eventArgs : GuildMemberAddEventArgs) =
// do! removeInvitedUser eventArgs.Member.Id
// } :> Task
//Degenz Game
//Mint Date: April 2022
//Supply: 3,333
//Price: 1.984 $SOL
//Your NFT will be your In-Game Character that provides you with unique traits, and abilities in game.
let sendInitialEmbed (client : DiscordClient) =
async {
try
let! channel = client.GetChannelAsync(GuildEnvironment.channelWhitelist) |> Async.AwaitTask
let builder = DiscordMessageBuilder()
let embed = DiscordEmbedBuilder()
embed.ImageUrl <- "https://securitygladiators.com/wp-content/uploads/2020/09/Whitelist-Website-Featured-Image.jpg"
embed.ImageUrl <- "https://s1.gifyu.com/images/whitelist-image-2.gif"
embed.Title <- "Degenz Game"
embed.Description <- """
Mint Date: **April 2022**
Supply: **3,333**
Price: **1.984 $SOL**
Your NFT will be your In-Game Character that provides you with unique traits, and abilities in game.
"""
builder.AddEmbed embed |> ignore
builder.Content <- "Click on the button to get whitelist!"
let button = DiscordButtonComponent(ButtonStyle.Success, $"GimmeWhitelist", $"Gimme") :> DiscordComponent
let button = DiscordButtonComponent(ButtonStyle.Success, $"GimmeWhitelist", $"Give Me Whitelist") :> DiscordComponent
builder.AddComponents [| button |] |> ignore
do! channel.SendMessageAsync(builder)
|> Async.AwaitTask
@ -268,40 +319,107 @@ let sendInitialEmbed (client : DiscordClient) =
} |> Async.RunSynchronously
type WhitelistResult =
| NotEnoughInvites of currentAmount : int
| Granted of DiscordRole
| NotInGame
| NotEnoughGBT of currentAmount : int
| Granted of PlayerData
| AlreadyWhitelisted
let tryGrantWhitelist (ctx : IDiscordContext) =
async {
task {
let user = ctx.GetDiscordMember()
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleWhitelist)
if Seq.contains role user.Roles
then return AlreadyWhitelisted
else
let! total = getInviteAttributions user.Id
if total >= WhitelistInviteRequirement then
return Granted role
match! DbService.tryFindPlayer user.Id with
| Some player ->
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleWhitelist)
if player.Active then
if Seq.contains role user.Roles then
return AlreadyWhitelisted
else
return NotEnoughInvites total
if int player.Bank >= WhitelistPrice then
return Granted player
else
return NotEnoughGBT (int player.Bank)
else
return NotInGame
| None -> return NotInGame
}
let handleWhitelist (ctx : IDiscordContext) =
let handleGimmeWhitelist (ctx : IDiscordContext) =
task {
let builder = DiscordInteractionResponseBuilder().AsEphemeral(true)
do! ctx.Respond(InteractionResponseType.DeferredChannelMessageWithSource, builder)
let builder = DiscordFollowupMessageBuilder().AsEphemeral(true)
match! tryGrantWhitelist ctx with
| NotInGame ->
builder.Content <- $"""
Woah slow down buddy… Youre not even in the game yet!
To get Whitelisted you need to buy it with **$GBT** by playing the game.
Go to <#{GuildEnvironment.channelShelters}> NOW to get assigned a private bunk, and **JOIN THE GAME!**
"""
| AlreadyWhitelisted ->
builder.Content <- "You are already whitelisted"
do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, builder)
| NotEnoughInvites total ->
do! createGuildInvite ctx true
// builder.Content <- "Testing"
// do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, builder)
// do! async.Zero()
| Granted role ->
builder.Content <- $"""
🎉 You're already WHITELISTED!
Come hang with all the other VIP Degenz in the <#{GuildEnvironment.channelElite}>
"""
| NotEnoughGBT total ->
builder.Content <- $"""
You don't have enough **$GBT** to buy a WHITELIST spot!
WHITELIST aint cheap, and looks like you're `{WhitelistPrice - total} $GBT` short.
Go earn more $GBT, and come back when you have `{WhitelistPrice} $GBT`!
`/recruit` other Degenz and get `{InviteRewardAmount} 💰 $GBT` for every Degen you recruit!
`/hack` other Degenz in <#{GuildEnvironment.channelBattle}> to steal their **$GBT**
`/toss` against <@{GuildEnvironment.botIdTosserTed}> in <#{GuildEnvironment.channelTosserTed}> to try double up!
Good luck Degen
"""
| Granted _ ->
let button = DiscordButtonComponent(ButtonStyle.Success, $"BuyWhitelist", $"Buy Now") :> DiscordComponent
builder.AddComponents([ button ]) |> ignore
builder.Content <- """
Look at you Degen, you played Big Brothers games and made it out alive!
Now you can use your $GBT to pay for one of our coveted Whitelist spots.
Click buy now below and the role will be auto assigned to you.
"""
do! ctx.FollowUp(builder)
} :> Task
let handleBuyWhitelist (ctx : IDiscordContext) =
task {
let builder = DiscordInteractionResponseBuilder().AsEphemeral(true)
do! ctx.Respond(InteractionResponseType.DeferredChannelMessageWithSource, builder)
let builder = DiscordFollowupMessageBuilder().AsEphemeral(true)
match! tryGrantWhitelist ctx with
| NotInGame -> builder.Content <- $"You somehow have left the game, what exactly are you doing?"
| AlreadyWhitelisted ->
builder.Content <- $"""
🎉 You're already WHITELISTED!
Come hang with all the other VIP Degenz in the <#{GuildEnvironment.channelElite}>
"""
| NotEnoughGBT _ -> builder.Content <- $"You somehow do not have enough $GBT, what exactly are you doing?"
| Granted player ->
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleWhitelist)
do! ctx.GetDiscordMember().GrantRoleAsync(role)
builder.Content <- "You have been granted whitelist"
do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, builder)
let! _ = DbService.updatePlayerCurrency -WhitelistPrice player
builder.Content <- $"""
🎉 Congratulations youve been WHITELISTED!
Come hang with all the other VIP Degenz in the <#{GuildEnvironment.channelElite}>
`/recruit` other Degenz and get 💰 $GBT {InviteRewardAmount} for every Degen you recruit!
"""
do! ctx.FollowUp(builder)
} :> Task
let handleCreateInvite (ctx : IDiscordContext) =
@ -333,12 +451,13 @@ let handleCreateInvite (ctx : IDiscordContext) =
.AsEphemeral(true)
do! ctx.FollowUp(msg)
}
} :> Task
let handleButtonEvent (_ : DiscordClient) (event : ComponentInteractionCreateEventArgs) =
let eventCtx = DiscordEventContext event :> IDiscordContext
match event.Id with
| id when id.StartsWith("GimmeWhitelist") -> handleWhitelist eventCtx
| id when id.StartsWith("GimmeWhitelist") -> handleGimmeWhitelist eventCtx
| id when id.StartsWith("BuyWhitelist") -> handleBuyWhitelist eventCtx
| id when id.StartsWith("CreateGuildInvite") -> handleCreateInvite eventCtx
| _ ->
task {
@ -350,7 +469,7 @@ let handleButtonEvent (_ : DiscordClient) (event : ComponentInteractionCreateEv
let handleGuildMemberAdded _ (eventArgs : GuildMemberAddEventArgs) =
task {
let! exists = checkUserInvited eventArgs.Member.Id
let! exists = checkUserAlreadyInvited eventArgs.Member.Id
if not exists then
do! processNewUser eventArgs
} :> Task