New trainer bot flow that gifts weapons or money, plus achievement
This commit is contained in:
parent
213f9be2ee
commit
785660558d
36
Bot/Bot.fs
36
Bot/Bot.fs
@ -66,30 +66,38 @@ let asdf (_ : DiscordClient) (event : DSharpPlus.EventArgs.InteractionCreateEven
|
|||||||
if guild <> 922419263275425832uL then
|
if guild <> 922419263275425832uL then
|
||||||
Trainer.sendInitialEmbed hackerBattleBot
|
Trainer.sendInitialEmbed hackerBattleBot
|
||||||
|
|
||||||
let run (client : DiscordClient) =
|
hackerBattleBot.ConnectAsync() |> Async.AwaitTask |> Async.RunSynchronously
|
||||||
async {
|
GuildEnvironment.botUserHackerBattle <- Some hackerBattleBot.CurrentUser
|
||||||
do! client.ConnectAsync () |> Async.AwaitTask
|
storeBot.ConnectAsync() |> Async.AwaitTask |> Async.RunSynchronously
|
||||||
}
|
GuildEnvironment.botUserArmory <- Some storeBot.CurrentUser
|
||||||
|
|
||||||
let clients =
|
//async {
|
||||||
if guild = 922419263275425832uL then
|
// let! user = hackerBattleBot.GetUserAsync(GuildEnvironment.botIdHackerBattle) |> Async.AwaitTask
|
||||||
|
// if user <> null then
|
||||||
|
// GuildEnvironment.botUserHackerBattle <- Some user
|
||||||
|
// return ()
|
||||||
|
//} |> Async.RunSynchronously
|
||||||
|
|
||||||
|
//async {
|
||||||
|
// let! user = storeBot.GetUserAsync(GuildEnvironment.botIdHackerBattle) |> Async.AwaitTask
|
||||||
|
// if user <> null then
|
||||||
|
// GuildEnvironment.botUserHackerBattle <- Some user
|
||||||
|
// return ()
|
||||||
|
//} |> Async.RunSynchronously
|
||||||
|
|
||||||
|
if guild = 922419263275425832uL then
|
||||||
let interactionsConfig = DiscordConfiguration()
|
let interactionsConfig = DiscordConfiguration()
|
||||||
interactionsConfig.TokenType <- TokenType.Bot
|
interactionsConfig.TokenType <- TokenType.Bot
|
||||||
interactionsConfig.Intents <- DiscordIntents.All
|
interactionsConfig.Intents <- DiscordIntents.All
|
||||||
interactionsConfig.Token <- GuildEnvironment.tokenPlayerInteractions
|
interactionsConfig.Token <- GuildEnvironment.tokenPlayerInteractions
|
||||||
|
|
||||||
let interactionsBot = new DiscordClient(interactionsConfig)
|
let interactionsBot = new DiscordClient(interactionsConfig)
|
||||||
|
|
||||||
let commands = interactionsBot.UseSlashCommands()
|
let commands = interactionsBot.UseSlashCommands()
|
||||||
commands.RegisterCommands<PlayerInteractions.PlayerInteractions>(guild)
|
commands.RegisterCommands<PlayerInteractions.PlayerInteractions>(guild)
|
||||||
|
|
||||||
[ hackerBattleBot ; storeBot ; interactionsBot ]
|
interactionsBot.ConnectAsync() |> Async.AwaitTask |> Async.RunSynchronously
|
||||||
else
|
|
||||||
[ hackerBattleBot ; storeBot ]
|
|
||||||
|
|
||||||
clients
|
|
||||||
|> List.map run
|
|
||||||
|> Async.Sequential
|
|
||||||
|> Async.RunSynchronously
|
|
||||||
|> ignore
|
|
||||||
|
|
||||||
Task.Delay(-1)
|
Task.Delay(-1)
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
|
@ -10,19 +10,19 @@
|
|||||||
<Content Include="Items.json">
|
<Content Include="Items.json">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Include="paket.references"/>
|
<Content Include="paket.references" />
|
||||||
<Compile Include="GuildEnvironment.fs"/>
|
<Compile Include="GuildEnvironment.fs" />
|
||||||
<Compile Include="Game.fs"/>
|
<Compile Include="Game.fs" />
|
||||||
<Compile Include="PlayerInteractions.fs"/>
|
<Compile Include="PlayerInteractions.fs" />
|
||||||
<Compile Include="Embeds.fs"/>
|
<Compile Include="Embeds.fs" />
|
||||||
<Compile Include="Store.fs"/>
|
<Compile Include="Store.fs" />
|
||||||
<Compile Include="Trainer.fs"/>
|
<Compile Include="Trainer.fs" />
|
||||||
<Compile Include="HackerBattle.fs"/>
|
<Compile Include="HackerBattle.fs" />
|
||||||
<Compile Include="SlotMachine.fs"/>
|
<Compile Include="SlotMachine.fs" />
|
||||||
<Compile Include="Bot.fs"/>
|
<Compile Include="Bot.fs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\DbService\DbService.fsproj"/>
|
<ProjectReference Include="..\DbService\DbService.fsproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="..\.paket\Paket.Restore.targets"/>
|
<Import Project="..\.paket\Paket.Restore.targets" />
|
||||||
</Project>
|
</Project>
|
@ -76,36 +76,30 @@ let pickHack actionId attacker defender isTrainer =
|
|||||||
.AddEmbed(embed.Build())
|
.AddEmbed(embed.Build())
|
||||||
.AsEphemeral true
|
.AsEphemeral true
|
||||||
|
|
||||||
let responseSuccessfulHack (targetName : string) (hack : BattleItem) =
|
let responseSuccessfulHack earnedMoney (targetId : uint64) (hack : BattleItem) =
|
||||||
let embed = DiscordEmbedBuilder()
|
let embed = DiscordEmbedBuilder()
|
||||||
embed.ImageUrl <- getHackGif (enum<HackId>(hack.Id))
|
embed.ImageUrl <- getHackGif (enum<HackId>(hack.Id))
|
||||||
|
embed.Title <- "Hack Attack"
|
||||||
|
embed.Description <- $"You successfully hacked <@{targetId}> using {hack.Name}"
|
||||||
|
+ (if earnedMoney then ", and stole 💰$GBT {Game.HackPrize} from them!" else "!")
|
||||||
|
|
||||||
DiscordFollowupMessageBuilder()
|
DiscordFollowupMessageBuilder()
|
||||||
.WithContent($"You successfully hacked {targetName} using {hack.Name}, and stole 💰$GBT {Game.HackPrize} from them!")
|
|
||||||
.AddEmbed(embed.Build())
|
.AddEmbed(embed.Build())
|
||||||
.AsEphemeral(true)
|
.AsEphemeral(true)
|
||||||
|
|
||||||
let responseCreatedShield (shield : BattleItem) =
|
let responseCreatedShield (shield : BattleItem) =
|
||||||
DiscordFollowupMessageBuilder()
|
let embed = DiscordEmbedBuilder().WithImageUrl(getShieldGif (enum<ShieldId>(shield.Id)))
|
||||||
.AddEmbed(DiscordEmbedBuilder().WithImageUrl(getShieldGif (enum<ShieldId>(shield.Id))))
|
embed.Title <- "Mounted Shield"
|
||||||
.AsEphemeral(true)
|
embed.Description <- $"Mounted {shield.Name} shield for {TimeSpan.FromMinutes(int shield.Cooldown).Hours} hours"
|
||||||
.WithContent($"Mounted {shield.Name} shield for {TimeSpan.FromMinutes(int shield.Cooldown).Hours} hours")
|
|
||||||
|
|
||||||
let responseCreatedShieldTrainer (shield : BattleItem) =
|
|
||||||
DiscordFollowupMessageBuilder()
|
DiscordFollowupMessageBuilder()
|
||||||
.AddEmbed(DiscordEmbedBuilder().WithImageUrl(getShieldGif (enum<ShieldId>(shield.Id))))
|
.AddEmbed(embed)
|
||||||
.AsEphemeral(true)
|
.AsEphemeral(true)
|
||||||
.WithContent($"Mounted a {shield.Name} defense for {TimeSpan.FromMinutes(int shield.Cooldown).Hours} hours")
|
|
||||||
|
|
||||||
let eventSuccessfulHack (event : ComponentInteractionCreateEventArgs) target prize =
|
let eventSuccessfulHack (event : ComponentInteractionCreateEventArgs) target prize =
|
||||||
DiscordMessageBuilder()
|
DiscordMessageBuilder()
|
||||||
.WithContent($"{event.User.Username} successfully hacked <@{target.DiscordId}> for a total of {prize} GoodBoyTokenz")
|
.WithContent($"{event.User.Username} successfully hacked <@{target.DiscordId}> for a total of {prize} GoodBoyTokenz")
|
||||||
|
|
||||||
let getGoodAgainst = function
|
|
||||||
| BattleClass.Network -> ( ShieldId.Firewall , HackId.Virus )
|
|
||||||
| BattleClass.Penetration -> ( ShieldId.Cypher , HackId.RemoteAccess )
|
|
||||||
| BattleClass.Exploit -> ( ShieldId.Encryption , HackId.Worm )
|
|
||||||
|
|
||||||
let getBuyItemsEmbed (player : PlayerData) (itemType : ItemType) (store : BattleItem array) =
|
let getBuyItemsEmbed (player : PlayerData) (itemType : ItemType) (store : BattleItem array) =
|
||||||
let embeds , buttons =
|
let embeds , buttons =
|
||||||
store
|
store
|
||||||
@ -115,13 +109,13 @@ let getBuyItemsEmbed (player : PlayerData) (itemType : ItemType) (store : Battle
|
|||||||
match item.Type with
|
match item.Type with
|
||||||
| Hack ->
|
| Hack ->
|
||||||
embed
|
embed
|
||||||
.AddField($"Weak Against |", getGoodAgainst item.Class |> fst |> string , true)
|
.AddField($"Weak Against |", Game.getGoodAgainst item.Class |> fst |> string , true)
|
||||||
.AddField("Cooldown |", $"{TimeSpan.FromMinutes(int item.Cooldown).Minutes} minutes", true)
|
.AddField("Cooldown |", $"{TimeSpan.FromMinutes(int item.Cooldown).Minutes} minutes", true)
|
||||||
.WithThumbnail(getHackIcon (enum<HackId>(item.Id)))
|
.WithThumbnail(getHackIcon (enum<HackId>(item.Id)))
|
||||||
|> ignore
|
|> ignore
|
||||||
| Shield ->
|
| Shield ->
|
||||||
embed
|
embed
|
||||||
.AddField($"Strong Against |", getGoodAgainst item.Class |> snd |> string , true)
|
.AddField($"Strong Against |", Game.getGoodAgainst item.Class |> snd |> string , true)
|
||||||
.AddField("Active For |", $"{TimeSpan.FromMinutes(int item.Cooldown).Hours} hours", true)
|
.AddField("Active For |", $"{TimeSpan.FromMinutes(int item.Cooldown).Hours} hours", true)
|
||||||
.WithThumbnail(getShieldIcon (enum<ShieldId>(item.Id)))
|
.WithThumbnail(getShieldIcon (enum<ShieldId>(item.Id)))
|
||||||
|> ignore
|
|> ignore
|
||||||
@ -164,3 +158,30 @@ let getSellItemsEmbed (itemType : ItemType) (player : PlayerData) =
|
|||||||
.AddEmbeds(embeds)
|
.AddEmbeds(embeds)
|
||||||
.AddComponents(buttons)
|
.AddComponents(buttons)
|
||||||
.AsEphemeral(true)
|
.AsEphemeral(true)
|
||||||
|
|
||||||
|
let getArsenalEmbed (player : PlayerData) =
|
||||||
|
DiscordFollowupMessageBuilder()
|
||||||
|
.AsEphemeral(true)
|
||||||
|
.AddEmbed(
|
||||||
|
DiscordEmbedBuilder()
|
||||||
|
.AddField( "Arsenal", Arsenal.statusFormat player ))
|
||||||
|
|
||||||
|
let getAchievementEmbed (player : PlayerData) description achievement =
|
||||||
|
let embed = DiscordEmbedBuilder()
|
||||||
|
|
||||||
|
GuildEnvironment.botUserHackerBattle
|
||||||
|
|> Option.iter (fun bot ->
|
||||||
|
embed.Author <- DiscordEmbedBuilder.EmbedAuthor()
|
||||||
|
embed.Author.Name <- bot.Username
|
||||||
|
embed.Author.IconUrl <- bot.AvatarUrl)
|
||||||
|
|
||||||
|
DiscordFollowupMessageBuilder()
|
||||||
|
.AddEmbed(
|
||||||
|
// TODO: We can add a Reward field but we'd need to keep track of what the player was awarded
|
||||||
|
embed.WithTitle("Achievement Unlocked!")
|
||||||
|
.WithDescription(description)
|
||||||
|
.WithColor(DiscordColor.Gold)
|
||||||
|
.AddField("Achievement", achievement)
|
||||||
|
// TODO: Once we add another achievement, fix this
|
||||||
|
.WithImageUrl("https://s10.gifyu.com/images/MasterTraining_Degenz.gif"))
|
||||||
|
.AsEphemeral(true)
|
40
Bot/Game.fs
40
Bot/Game.fs
@ -23,6 +23,11 @@ module Game =
|
|||||||
| Penetration -> DiscordColor.Blurple
|
| Penetration -> DiscordColor.Blurple
|
||||||
| Exploit -> DiscordColor.Green
|
| Exploit -> DiscordColor.Green
|
||||||
|
|
||||||
|
let getGoodAgainst = function
|
||||||
|
| BattleClass.Network -> ( ShieldId.Firewall , HackId.Virus )
|
||||||
|
| BattleClass.Penetration -> ( ShieldId.Cypher , HackId.RemoteAccess )
|
||||||
|
| BattleClass.Exploit -> ( ShieldId.Encryption , HackId.Worm )
|
||||||
|
|
||||||
let executePlayerInteraction (ctx : InteractionContext) (dispatch : PlayerData -> Async<unit>) =
|
let executePlayerInteraction (ctx : InteractionContext) (dispatch : PlayerData -> Async<unit>) =
|
||||||
async {
|
async {
|
||||||
let builder = DiscordInteractionResponseBuilder()
|
let builder = DiscordInteractionResponseBuilder()
|
||||||
@ -54,9 +59,9 @@ module Game =
|
|||||||
|
|
||||||
module Player =
|
module Player =
|
||||||
let getItems itemType (player : PlayerData) = player.Arsenal |> Array.filter (fun i -> i.Type = itemType)
|
let getItems itemType (player : PlayerData) = player.Arsenal |> Array.filter (fun i -> i.Type = itemType)
|
||||||
let hacks (player : PlayerData) = getItems ItemType.Hack player
|
let getHacks (player : PlayerData) = getItems ItemType.Hack player
|
||||||
let getShields (player : PlayerData) = getItems ItemType.Shield player
|
let getShields (player : PlayerData) = getItems ItemType.Shield player
|
||||||
let attacks player =
|
let getAttacks player =
|
||||||
player.Actions
|
player.Actions
|
||||||
|> Array.filter (fun act -> match act.Type with Attack _ -> true | _ -> false)
|
|> Array.filter (fun act -> match act.Type with Attack _ -> true | _ -> false)
|
||||||
let getDefenses player = player.Actions |> Array.filter (fun act -> match act.Type with Defense -> true | _ -> false)
|
let getDefenses player = player.Actions |> Array.filter (fun act -> match act.Type with Defense -> true | _ -> false)
|
||||||
@ -76,3 +81,34 @@ module Player =
|
|||||||
|
|
||||||
let getAttacksFlat actions = actions |> Array.choose (fun act -> match act.Type with Attack ar -> Some (act,ar.Target,ar.Result) | Defense -> None)
|
let getAttacksFlat actions = actions |> Array.choose (fun act -> match act.Type with Attack ar -> Some (act,ar.Target,ar.Result) | Defense -> None)
|
||||||
|
|
||||||
|
module Arsenal =
|
||||||
|
let battleItemFormat (items : BattleItem array) =
|
||||||
|
match items with
|
||||||
|
| [||] -> "None"
|
||||||
|
| _ -> items |> Array.toList |> List.map (fun i -> i.Name) |> String.concat ", "
|
||||||
|
|
||||||
|
let actionFormat (actions : Action array) =
|
||||||
|
match actions with
|
||||||
|
| [||] -> "None"
|
||||||
|
| _ ->
|
||||||
|
let hacks , defenses = actions |> Array.partition (fun act -> match act.Type with Attack _ -> true | Defense -> false)
|
||||||
|
let hacks = hacks |> Array.take (min hacks.Length 10)
|
||||||
|
hacks
|
||||||
|
|> Array.append defenses
|
||||||
|
|> Array.map (fun act ->
|
||||||
|
let item = Armory.getItem act.ActionId
|
||||||
|
match act.Type with
|
||||||
|
| Attack atk ->
|
||||||
|
let cooldown = Messaging.getTimeText false Game.SameTargetAttackCooldown act.Timestamp
|
||||||
|
$"Hacked {atk.Target.Name} {cooldown} ago"
|
||||||
|
| Defense ->
|
||||||
|
let cooldown = Messaging.getTimeText true (System.TimeSpan.FromMinutes(int item.Cooldown)) act.Timestamp
|
||||||
|
$"{item.Name} Shield active for {cooldown}")
|
||||||
|
|> String.concat "\n"
|
||||||
|
|
||||||
|
let statusFormat p =
|
||||||
|
$"**Hacks:** {Player.getHacks p |> battleItemFormat}\n
|
||||||
|
**Shields:** {Player.getShields p |> battleItemFormat}\n
|
||||||
|
**Hack Attacks:**\n{Player.getAttacks p |> actionFormat}\n
|
||||||
|
**Active Shields:**\n{Player.getDefenses p |> actionFormat}"
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
module Degenz.GuildEnvironment
|
module Degenz.GuildEnvironment
|
||||||
|
|
||||||
open System
|
open System
|
||||||
|
open DSharpPlus.Entities
|
||||||
open dotenv.net
|
open dotenv.net
|
||||||
|
|
||||||
DotEnv.Load(DotEnvOptions(envFilePaths = [ "../../../../stag.env" ], overwriteExistingVars = false))
|
DotEnv.Load(DotEnvOptions(envFilePaths = [ "../../../../stag.env" ], overwriteExistingVars = false))
|
||||||
@ -18,6 +19,9 @@ let channelEventsHackerBattle = getId "CHANNEL_EVENTS_HACKER_BATTLE"
|
|||||||
let channelTraining = getId "CHANNEL_TRAINING"
|
let channelTraining = getId "CHANNEL_TRAINING"
|
||||||
let channelArmory = getId "CHANNEL_ARMORY"
|
let channelArmory = getId "CHANNEL_ARMORY"
|
||||||
let channelBattle = getId "CHANNEL_BATTLE"
|
let channelBattle = getId "CHANNEL_BATTLE"
|
||||||
let botHackerBattle = getId "BOT_HACKER_BATTLE"
|
let botIdHackerBattle = getId "BOT_HACKER_BATTLE"
|
||||||
let botArmory = getId "BOT_ARMORY"
|
let botIdArmory = getId "BOT_ARMORY"
|
||||||
let roleTrainee = getId "ROLE_TRAINEE"
|
let roleTrainee = getId "ROLE_TRAINEE"
|
||||||
|
|
||||||
|
let mutable botUserHackerBattle : DiscordUser option = None
|
||||||
|
let mutable botUserArmory : DiscordUser option = None
|
||||||
|
@ -42,7 +42,7 @@ let checkItemHasCooldown itemId attacker =
|
|||||||
Error $"{item.Name} is currently on cooldown, wait {cooldown} to use it again."
|
Error $"{item.Name} is currently on cooldown, wait {cooldown} to use it again."
|
||||||
|
|
||||||
let checkHasEmptyHacks attacker =
|
let checkHasEmptyHacks attacker =
|
||||||
match Player.hacks attacker with
|
match Player.getHacks attacker with
|
||||||
| [||] -> Error $"You currently do not have any Hacks to steal 💰$GBT from others. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one."
|
| [||] -> Error $"You currently do not have any Hacks to steal 💰$GBT from others. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one."
|
||||||
| _ -> Ok attacker
|
| _ -> Ok attacker
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ let successfulHack (event : ComponentInteractionCreateEventArgs) attacker defend
|
|||||||
async {
|
async {
|
||||||
do! updateCombatants attacker defender hack Game.HackPrize
|
do! updateCombatants attacker defender hack Game.HackPrize
|
||||||
|
|
||||||
let embed = Embeds.responseSuccessfulHack (defender.Name) (Armory.getItem hack)
|
let embed = Embeds.responseSuccessfulHack true defender.DiscordId (Armory.getItem hack)
|
||||||
do! event.Interaction.CreateFollowupMessageAsync(embed)
|
do! event.Interaction.CreateFollowupMessageAsync(embed)
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
|> Async.Ignore
|
|> Async.Ignore
|
||||||
@ -114,7 +114,7 @@ let failedHack (event : ComponentInteractionCreateEventArgs) attacker defender h
|
|||||||
do! updateCombatants attacker defender hack -Game.ShieldPrize
|
do! updateCombatants attacker defender hack -Game.ShieldPrize
|
||||||
|
|
||||||
let builder = DiscordMessageBuilder()
|
let builder = DiscordMessageBuilder()
|
||||||
builder.WithContent($"Hacking attempt failed! {defender.Name} defended hack from {event.User.Username} and stole {Game.ShieldPrize} $GBT from them! ") |> ignore
|
builder.WithContent($"Hacking attempt failed! <@{defender.DiscordId}> defended hack from {event.User.Username} and stole {Game.ShieldPrize} $GBT from them! ") |> ignore
|
||||||
let channel = (event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle))
|
let channel = (event.Guild.GetChannel(GuildEnvironment.channelEventsHackerBattle))
|
||||||
do! channel.SendMessageAsync(builder)
|
do! channel.SendMessageAsync(builder)
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
@ -224,6 +224,20 @@ let handleButtonEvent (_ : DiscordClient) (event : ComponentInteractionCreateEve
|
|||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let arsenal (ctx : InteractionContext) =
|
||||||
|
Game.executePlayerInteraction ctx (fun player -> async {
|
||||||
|
let updatedPlayer = Player.removeExpiredActions false player
|
||||||
|
let builder = DiscordFollowupMessageBuilder()
|
||||||
|
let embed = DiscordEmbedBuilder()
|
||||||
|
embed.AddField("Arsenal", Arsenal.statusFormat updatedPlayer) |> ignore
|
||||||
|
builder.AddEmbed(embed) |> ignore
|
||||||
|
builder.IsEphemeral <- true
|
||||||
|
do! ctx.FollowUpAsync(builder)
|
||||||
|
|> Async.AwaitTask
|
||||||
|
|> Async.Ignore
|
||||||
|
do! DbService.updatePlayer updatedPlayer
|
||||||
|
})
|
||||||
|
|
||||||
type HackerGame() =
|
type HackerGame() =
|
||||||
inherit ApplicationCommandModule ()
|
inherit ApplicationCommandModule ()
|
||||||
|
|
||||||
@ -247,6 +261,10 @@ type HackerGame() =
|
|||||||
do! Messaging.sendSimpleResponse ctx msg
|
do! Messaging.sendSimpleResponse ctx msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[<SlashCommand("arsenal", "Get the Hacks and Shields you own, and which ones are active")>]
|
||||||
|
member this.Arsenal (ctx : InteractionContext) =
|
||||||
|
enforceChannels ctx (Trainer.handleArsenal) arsenal
|
||||||
|
|
||||||
[<SlashCommand("hack", "Send a hack attack to another player")>]
|
[<SlashCommand("hack", "Send a hack attack to another player")>]
|
||||||
member this.AttackCommand (ctx : InteractionContext, [<Option("target", "The player you want to hack")>] target : DiscordUser) =
|
member this.AttackCommand (ctx : InteractionContext, [<Option("target", "The player you want to hack")>] target : DiscordUser) =
|
||||||
enforceChannels ctx (Trainer.attack target) (attack target)
|
enforceChannels ctx (Trainer.attack target) (attack target)
|
||||||
|
48
Bot/Store.fs
48
Bot/Store.fs
@ -29,51 +29,6 @@ let checkHasItemsInArsenal itemType player =
|
|||||||
then Ok player
|
then Ok player
|
||||||
else Error $"You currently have no {itemType}s in your arsenal to sell!"
|
else Error $"You currently have no {itemType}s in your arsenal to sell!"
|
||||||
|
|
||||||
let battleItemFormat (items : BattleItem array) =
|
|
||||||
match items with
|
|
||||||
| [||] -> "None"
|
|
||||||
| _ -> items |> Array.toList |> List.map (fun i -> i.Name) |> String.concat ", "
|
|
||||||
|
|
||||||
let actionFormat (actions : Action array) =
|
|
||||||
match actions with
|
|
||||||
| [||] -> "None"
|
|
||||||
| _ ->
|
|
||||||
let hacks , defenses = actions |> Array.partition (fun act -> match act.Type with Attack _ -> true | Defense -> false)
|
|
||||||
let hacks = hacks |> Array.take (min hacks.Length 10)
|
|
||||||
hacks
|
|
||||||
|> Array.append defenses
|
|
||||||
|> Array.map (fun act ->
|
|
||||||
let item = Armory.getItem act.ActionId
|
|
||||||
match act.Type with
|
|
||||||
| Attack atk ->
|
|
||||||
let cooldown = getTimeText false Game.SameTargetAttackCooldown act.Timestamp
|
|
||||||
$"Hacked {atk.Target.Name} {cooldown} ago"
|
|
||||||
| Defense ->
|
|
||||||
let cooldown = getTimeText true (System.TimeSpan.FromMinutes(int item.Cooldown)) act.Timestamp
|
|
||||||
$"{item.Name} Shield active for {cooldown}")
|
|
||||||
|> String.concat "\n"
|
|
||||||
|
|
||||||
let statusFormat p =
|
|
||||||
$"**Hacks:** {Player.hacks p |> battleItemFormat}\n
|
|
||||||
**Shields:** {Player.getShields p |> battleItemFormat}\n
|
|
||||||
**Hack Attacks:**\n{Player.attacks p |> actionFormat}\n
|
|
||||||
**Active Shields:**\n{Player.getDefenses p |> actionFormat}"
|
|
||||||
|
|
||||||
// TODO: There's a 1000 character limit for embeds, so you need to filter by N last actions
|
|
||||||
let arsenal (ctx : InteractionContext) =
|
|
||||||
Game.executePlayerInteraction ctx (fun player -> async {
|
|
||||||
let updatedPlayer = Player.removeExpiredActions false player
|
|
||||||
let builder = DiscordFollowupMessageBuilder()
|
|
||||||
let embed = DiscordEmbedBuilder()
|
|
||||||
embed.AddField("Arsenal", statusFormat updatedPlayer) |> ignore
|
|
||||||
builder.AddEmbed(embed) |> ignore
|
|
||||||
builder.IsEphemeral <- true
|
|
||||||
do! ctx.FollowUpAsync(builder)
|
|
||||||
|> Async.AwaitTask
|
|
||||||
|> Async.Ignore
|
|
||||||
do! DbService.updatePlayer updatedPlayer
|
|
||||||
})
|
|
||||||
|
|
||||||
let buy itemType (ctx : InteractionContext) =
|
let buy itemType (ctx : InteractionContext) =
|
||||||
Game.executePlayerInteraction ctx (fun player -> async {
|
Game.executePlayerInteraction ctx (fun player -> async {
|
||||||
let itemStore = Embeds.getBuyItemsEmbed player itemType Armory.battleItems
|
let itemStore = Embeds.getBuyItemsEmbed player itemType Armory.battleItems
|
||||||
@ -155,9 +110,6 @@ type Store() =
|
|||||||
do! Messaging.sendSimpleResponse ctx msg
|
do! Messaging.sendSimpleResponse ctx msg
|
||||||
}
|
}
|
||||||
|
|
||||||
[<SlashCommand("arsenal", "Get the Hacks and Shields you own, and which ones are active")>]
|
|
||||||
member this.Arsenal (ctx : InteractionContext) = arsenal ctx
|
|
||||||
|
|
||||||
[<SlashCommand("buy-hack", "Purchase a hack attack you can use to earn GoodBoyTokenz")>]
|
[<SlashCommand("buy-hack", "Purchase a hack attack you can use to earn GoodBoyTokenz")>]
|
||||||
member _.BuyHack (ctx : InteractionContext) = enforceChannel ctx (buy ItemType.Hack)
|
member _.BuyHack (ctx : InteractionContext) = enforceChannel ctx (buy ItemType.Hack)
|
||||||
|
|
||||||
|
130
Bot/Trainer.fs
130
Bot/Trainer.fs
@ -1,5 +1,6 @@
|
|||||||
module Degenz.Trainer
|
module Degenz.Trainer
|
||||||
|
|
||||||
|
open System.Text
|
||||||
open DSharpPlus
|
open DSharpPlus
|
||||||
open DSharpPlus.Entities
|
open DSharpPlus.Entities
|
||||||
open DSharpPlus.EventArgs
|
open DSharpPlus.EventArgs
|
||||||
@ -7,6 +8,8 @@ open DSharpPlus.SlashCommands
|
|||||||
open Degenz.Types
|
open Degenz.Types
|
||||||
open Degenz.Messaging
|
open Degenz.Messaging
|
||||||
|
|
||||||
|
let trainerAchievement = "FINISHED_TRAINER"
|
||||||
|
|
||||||
// TODO: We should either gift the weapons to the player during training, or have them buy it
|
// TODO: We should either gift the weapons to the player during training, or have them buy it
|
||||||
// TODO: We should tell the user to type out /arsenal during the training
|
// TODO: We should tell the user to type out /arsenal during the training
|
||||||
// TODO: How do we handle the money being generated here? It's fake but fake is confusing
|
// TODO: How do we handle the money being generated here? It's fake but fake is confusing
|
||||||
@ -34,7 +37,7 @@ let handleTrainerStep1 (event : ComponentInteractionCreateEventArgs) =
|
|||||||
Game.executePlayerEvent event (fun player -> async {
|
Game.executePlayerEvent event (fun player -> async {
|
||||||
let shieldMessage , weaponName =
|
let shieldMessage , weaponName =
|
||||||
if Player.getShields player |> Array.isEmpty
|
if Player.getShields player |> Array.isEmpty
|
||||||
then $"You do not have any Shields in your arsenal, take this {defaultShield.Name}, you can use it for now.\n\n" , defaultShield.Name
|
then $"You do not have any Shields in your arsenal, take the `{defaultShield.Name}` shield, you can use it for now.\n\n" , defaultShield.Name
|
||||||
else
|
else
|
||||||
let name = Player.getShields player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name
|
let name = Player.getShields player |> Array.tryHead |> Option.defaultValue defaultShield |> fun w -> w.Name
|
||||||
$"Looks like you have `{name}` in your arsenal… 👀\n\n" , name
|
$"Looks like you have `{name}` in your arsenal… 👀\n\n" , name
|
||||||
@ -45,8 +48,7 @@ let handleTrainerStep1 (event : ComponentInteractionCreateEventArgs) =
|
|||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
|
|
||||||
do! sendFollowUpMessage event
|
do! sendFollowUpMessage event
|
||||||
("Beautopia© is a dangerous place...\n"
|
("Beautopia© is a dangerous place... quick, put up a SHIELD 🛡 before another Degen hacks you, and steals your 💰$GBT.\n\n"
|
||||||
+ "Quick, put up a SHIELD 🛡 before another Degen hacks you, and steals your 💰$GBT.\n\n"
|
|
||||||
+ shieldMessage
|
+ shieldMessage
|
||||||
+ "To enable it, you need to run the `/shield` slash command.\n\n"
|
+ "To enable it, you need to run the `/shield` slash command.\n\n"
|
||||||
+ $"Type the `/shield` command now, then select - `{weaponName}`\n")
|
+ $"Type the `/shield` command now, then select - `{weaponName}`\n")
|
||||||
@ -66,13 +68,12 @@ let defend (ctx : InteractionContext) =
|
|||||||
|> Async.Ignore
|
|> Async.Ignore
|
||||||
})
|
})
|
||||||
|
|
||||||
let handleDefenseMsg = {
|
let handleDefenseMsg shieldId hackId = {
|
||||||
ButtonId = "Trainer-3"
|
ButtonId = "Trainer-3"
|
||||||
ButtonText = "Got it"
|
ButtonText = "Got it"
|
||||||
Message = "🎉 Congratulations\n\n"
|
Message = "🎉 Congratulations you successfully defended my hack!\n\n"
|
||||||
+ "You successfully defended my hack!\n\n"
|
+ $"The `{shieldId}` shield is strong against the `{hackId}` hack, so make sure to have multiple shields up to protect from multiple attacks..."
|
||||||
+ "Because I tried hacking you when you had your defense up, you stole money from me...\n"
|
+ "Shields only protect you for a LIMITED TIME, so remember to keep them mounted at all times, or risk getting hacked!"
|
||||||
+ "Defenses only protect you for a LIMITED TIME, so remember to keep at least 1 defense up at all times, or risk getting hacked!"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let handleDefense (event : ComponentInteractionCreateEventArgs) =
|
let handleDefense (event : ComponentInteractionCreateEventArgs) =
|
||||||
@ -81,43 +82,45 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
|
|||||||
let split = event.Id.Split("-")
|
let split = event.Id.Split("-")
|
||||||
let shieldId = enum<ShieldId>(int split.[2])
|
let shieldId = enum<ShieldId>(int split.[2])
|
||||||
let shield = Armory.getItem (int shieldId)
|
let shield = Armory.getItem (int shieldId)
|
||||||
let embed = Embeds.responseCreatedShieldTrainer shield
|
let embed = Embeds.responseCreatedShield (shield)
|
||||||
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
|
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
|
||||||
do! Async.Sleep 4000
|
do! Async.Sleep 4000
|
||||||
do! sendMessage' "Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now"
|
let weakHack = Game.getGoodAgainst shield.Class
|
||||||
|
do! sendMessage' $"Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now with **{snd weakHack}**"
|
||||||
do! Async.Sleep 5000
|
do! Async.Sleep 5000
|
||||||
do! sendMessage' $"❌ HACKING FAILED!\n\n{player.Name} defended the hack from <@{GuildEnvironment.botHackerBattle}>, and stole 💰$GBT {Game.ShieldPrize} from them!"
|
do! sendMessage' $"❌ HACKING FAILED!\n\n{player.Name} defended hack from <@{GuildEnvironment.botIdHackerBattle}>!"
|
||||||
do! Async.Sleep 4000
|
do! Async.Sleep 4000
|
||||||
do! sendFollowUpMessageWithButton event handleDefenseMsg
|
do! sendFollowUpMessageWithButton event (handleDefenseMsg shieldId (snd weakHack))
|
||||||
})
|
|
||||||
|
|
||||||
|
})
|
||||||
let handleTrainerStep3 (event : ComponentInteractionCreateEventArgs) =
|
let handleTrainerStep3 (event : ComponentInteractionCreateEventArgs) =
|
||||||
Game.executePlayerEvent event (fun player -> async {
|
Game.executePlayerEvent event (fun player -> async {
|
||||||
let hackMessage , weaponName =
|
let hackMessage , weaponName =
|
||||||
if Player.hacks player |> Array.isEmpty
|
if Player.getHacks player |> Array.isEmpty
|
||||||
then $"You do not have any Hacks in your arsenal, take this `{defaultHack.Name}`, you can use it for now.\n\n" , defaultHack.Name
|
then $"You do not have any Hacks in your arsenal, take this `{defaultHack.Name}`, you can use it for now.\n\n" , defaultHack.Name
|
||||||
else
|
else
|
||||||
let name = Player.hacks player |> Array.tryHead |> Option.defaultValue defaultHack |> fun w -> w.Name
|
let name = Player.getHacks player |> Array.tryHead |> Option.defaultValue defaultHack |> fun w -> w.Name
|
||||||
$"Looks like you have `{name}` in your arsenal...\n\n" , name
|
$"Looks like you have `{name}` in your arsenal...\n\n" , name
|
||||||
|
|
||||||
do! sendFollowUpMessage event
|
do! sendFollowUpMessage event
|
||||||
("Now let’s **HACK!** 💻\n\n"
|
("Now let’s **HACK!** 💻\n\n"
|
||||||
+ "I want you to **HACK ME**, and try to steal my 💰$GBT...\n\n"
|
+ "I want you to **HACK ME**...\n\n"
|
||||||
+ hackMessage
|
+ hackMessage
|
||||||
+ "To deploy it, you need to run the `/hack` slash command.\n"
|
+ "To deploy it, you need to run the `/hack` slash command.\n"
|
||||||
+ $"Type the `/hack` command now, then choose me - <@{GuildEnvironment.botHackerBattle}> as your target, and select `{weaponName}`")
|
+ $"Type the `/hack` command now, then choose me - <@{GuildEnvironment.botIdHackerBattle}> as your target, and select `{weaponName}`")
|
||||||
})
|
})
|
||||||
|
|
||||||
let attack (target : DiscordUser) (ctx : InteractionContext) =
|
let attack (target : DiscordUser) (ctx : InteractionContext) =
|
||||||
Game.executePlayerInteraction ctx (fun player -> async {
|
Game.executePlayerInteraction ctx (fun player -> async {
|
||||||
let isRightTarget = target.Id = GuildEnvironment.botHackerBattle
|
let isRightTarget = target.Id = GuildEnvironment.botIdHackerBattle
|
||||||
match isRightTarget with
|
match isRightTarget with
|
||||||
| true ->
|
| true ->
|
||||||
let playerWithAttacks =
|
let playerWithAttacks =
|
||||||
match Player.hacks player with
|
match Player.getHacks player with
|
||||||
| [||] -> { player with Arsenal = [| defaultHack |] }
|
| [||] -> { player with Arsenal = [| defaultHack |] }
|
||||||
| _ -> player
|
| _ -> player
|
||||||
let embed = Embeds.pickHack "Trainer-4" playerWithAttacks player true
|
let bot = { player with DiscordId = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" }
|
||||||
|
let embed = Embeds.pickHack "Trainer-4" playerWithAttacks bot true
|
||||||
|
|
||||||
do! ctx.FollowUpAsync(embed)
|
do! ctx.FollowUpAsync(embed)
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
@ -137,8 +140,8 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
|
|||||||
Game.executePlayerEvent event (fun player -> async {
|
Game.executePlayerEvent event (fun player -> async {
|
||||||
let sendMessage' = sendFollowUpMessage event
|
let sendMessage' = sendFollowUpMessage event
|
||||||
do! Async.Sleep 1000
|
do! Async.Sleep 1000
|
||||||
let hack = Player.hacks player |> Array.tryHead |> Option.defaultValue defaultHack
|
let hack = Player.getHacks player |> Array.tryHead |> Option.defaultValue defaultHack
|
||||||
let embed = Embeds.responseSuccessfulHack "Sensei" hack
|
let embed = Embeds.responseSuccessfulHack false GuildEnvironment.botIdHackerBattle hack
|
||||||
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
|
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
|
||||||
do! Async.Sleep 5000
|
do! Async.Sleep 5000
|
||||||
do! sendMessage'
|
do! sendMessage'
|
||||||
@ -149,16 +152,85 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
|
|||||||
|
|
||||||
do! Async.Sleep 6000
|
do! Async.Sleep 6000
|
||||||
|
|
||||||
let membr = event.User :?> DiscordMember
|
let sb = StringBuilder("Here, ")
|
||||||
|
|
||||||
|
let! achievements = DbService.getAchievements player.DiscordId
|
||||||
|
let isFirstTrainer = achievements |> Option.map (Seq.contains trainerAchievement >> not) |> Option.defaultValue true
|
||||||
|
if isFirstTrainer then
|
||||||
|
do! DbService.addAchievement player.DiscordId trainerAchievement
|
||||||
|
|
||||||
|
let hasHacks = Player.getHacks player |> Array.isEmpty |> not
|
||||||
|
let hasShields = Player.getShields player |> Array.isEmpty |> not
|
||||||
|
|
||||||
|
let rand = System.Random(System.Guid.NewGuid().GetHashCode())
|
||||||
|
let freeHack = Armory.hacks.[rand.Next(0, 3)]
|
||||||
|
let freeShield = Armory.shields.[rand.Next(0, 3)]
|
||||||
|
let hackMoney = if hasHacks then defaultHack.Cost else 0<GBT>
|
||||||
|
let shieldMoney = if hasShields then defaultShield.Cost else 0<GBT>
|
||||||
|
|
||||||
|
let giftMsg =
|
||||||
|
match hasHacks , hasShields with
|
||||||
|
| true , true -> $"I'm going to give you these {hackMoney + shieldMoney} 💰$GBT"
|
||||||
|
| false , true -> $"I'm going to gift you a hack, `{freeHack.Name}` and {defaultHack.Cost} 💰$GBT"
|
||||||
|
| true , false -> $"I'm going to gift you a shield, `{freeShield.Name}` and {defaultHack.Cost} 💰$GBT"
|
||||||
|
| false , false -> $"I'm going to gift you a hack,`{freeHack.Name}` and a shield, `{freeShield.Name}`"
|
||||||
|
|
||||||
|
sb.Append(giftMsg) |> ignore
|
||||||
|
sb.Append(", you'll need em to survive\n\n") |> ignore
|
||||||
|
sb.AppendLine("To finish your training and collect the loot, type the `/arsenal` command **NOW**") |> ignore
|
||||||
|
do! Async.Sleep 1000
|
||||||
|
let updatedPlayer = {
|
||||||
|
player with Bank = player.Bank + hackMoney + shieldMoney
|
||||||
|
Actions = [
|
||||||
|
{ Action.Timestamp = System.DateTime.UtcNow
|
||||||
|
Action.Type =
|
||||||
|
Attack {
|
||||||
|
Result = true
|
||||||
|
Target = { Id = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" }
|
||||||
|
}
|
||||||
|
ActionId = defaultHack.Id
|
||||||
|
}
|
||||||
|
if not hasShields then {
|
||||||
|
Action.Timestamp = System.DateTime.UtcNow
|
||||||
|
Action.Type = Defense
|
||||||
|
Action.ActionId = freeShield.Id
|
||||||
|
}
|
||||||
|
] |> Seq.toArray
|
||||||
|
|> Array.append player.Actions
|
||||||
|
Arsenal = [
|
||||||
|
if not hasHacks then freeHack
|
||||||
|
if not hasShields then freeShield
|
||||||
|
] |> Seq.toArray
|
||||||
|
|> Array.append player.Arsenal
|
||||||
|
}
|
||||||
|
do! DbService.updatePlayer updatedPlayer
|
||||||
|
do! sendFollowUpMessage event (sb.ToString())
|
||||||
|
else
|
||||||
|
do! sendFollowUpMessage event ($"Your training is now complete. If you want to buy more **HACKS & SHIELDS**, go to the <#{GuildEnvironment.channelArmory}> **NOW** and type the `/buy-hack` and `/buy-shield` commands! 😱")
|
||||||
let role = event.Guild.GetRole(GuildEnvironment.roleTrainee)
|
let role = event.Guild.GetRole(GuildEnvironment.roleTrainee)
|
||||||
do! membr.RevokeRoleAsync(role)
|
let ``member`` = event.User :?> DiscordMember
|
||||||
|
do! ``member``.RevokeRoleAsync(role)
|
||||||
|
|> Async.AwaitTask
|
||||||
|
})
|
||||||
|
|
||||||
|
let handleArsenal (ctx : InteractionContext) =
|
||||||
|
Game.executePlayerInteraction ctx (fun player -> async {
|
||||||
|
let updatedPlayer = Player.removeExpiredActions false player
|
||||||
|
let embed = Embeds.getArsenalEmbed updatedPlayer
|
||||||
|
do! ctx.FollowUpAsync(embed)
|
||||||
|
|> Async.AwaitTask
|
||||||
|
|> Async.Ignore
|
||||||
|
do! Async.Sleep 3000
|
||||||
|
let embed = Embeds.getAchievementEmbed player "You completed the Training Dojo and collected loot." trainerAchievement
|
||||||
|
do! ctx.FollowUpAsync(embed)
|
||||||
|
|> Async.AwaitTask
|
||||||
|
|> Async.Ignore
|
||||||
|
do! Async.Sleep 2000
|
||||||
|
let role = ctx.Guild.GetRole(GuildEnvironment.roleTrainee)
|
||||||
|
do! ctx.Member.RevokeRoleAsync(role)
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
|
|
||||||
do! sendFollowUpMessage event
|
do! sendFollowUpMessageFromCtx ctx "Now get out of there and go hack other Degenz!"
|
||||||
("Your training is **complete!**\n\n"
|
|
||||||
+ "But, you’re going to need more **HACKS & SHIELDS** 🛡 to survive in **Beautopia©...**\n"
|
|
||||||
+ $"You can purchase them from <@{GuildEnvironment.botArmory}> anytime you want...\n\n"
|
|
||||||
+ $"Go to the <#{GuildEnvironment.channelArmory}> **NOW** and type the `/buy-hack` slash command! 😱")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
let handleButtonEvent (event : ComponentInteractionCreateEventArgs) =
|
let handleButtonEvent (event : ComponentInteractionCreateEventArgs) =
|
||||||
|
@ -2,11 +2,10 @@
|
|||||||
|
|
||||||
open System
|
open System
|
||||||
open System.Collections.Generic
|
open System.Collections.Generic
|
||||||
open System.Threading.Tasks
|
|
||||||
open Degenz.Types
|
|
||||||
open MongoDB.Bson
|
open MongoDB.Bson
|
||||||
open MongoDB.Bson.Serialization
|
open MongoDB.Bson.Serialization
|
||||||
open MongoDB.Driver
|
open MongoDB.Driver
|
||||||
|
open Degenz.Types
|
||||||
|
|
||||||
[<CLIMutable>]
|
[<CLIMutable>]
|
||||||
type AttackAction =
|
type AttackAction =
|
||||||
@ -90,6 +89,28 @@ let tryFindPlayer (id : uint64) =
|
|||||||
|> Some
|
|> Some
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let getAchievements (id : uint64) =
|
||||||
|
async {
|
||||||
|
let filter = Builders<BsonDocument>.Filter.Eq("Player.DiscordId", id)
|
||||||
|
try
|
||||||
|
let! player = players.FindAsync<BsonDocument>(filter) |> Async.AwaitTask
|
||||||
|
match player.FirstOrDefault() with
|
||||||
|
| null -> return None
|
||||||
|
| p -> return p
|
||||||
|
.GetValue("achievements")
|
||||||
|
.AsBsonArray
|
||||||
|
|> Seq.map (fun (bv : BsonValue) -> bv.AsString)
|
||||||
|
|> Some
|
||||||
|
with ex -> return None
|
||||||
|
}
|
||||||
|
|
||||||
|
let addAchievement (id : uint64) (achievement : string) =
|
||||||
|
async {
|
||||||
|
let filter = Builders<BsonDocument>.Filter.Eq("Player.DiscordId", id)
|
||||||
|
let update = Builders<BsonDocument>.Update.Push("achievements", achievement)
|
||||||
|
return! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore
|
||||||
|
}
|
||||||
|
|
||||||
let insertNewPlayer (player : PlayerData) =
|
let insertNewPlayer (player : PlayerData) =
|
||||||
async {
|
async {
|
||||||
let p = playerMap player
|
let p = playerMap player
|
||||||
@ -114,7 +135,6 @@ let updatePlayer (player : PlayerData) =
|
|||||||
return! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore
|
return! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//let getTopPlayers amount =
|
//let getTopPlayers amount =
|
||||||
// async {
|
// async {
|
||||||
// return! players.FindAsync()
|
// return! players.FindAsync()
|
||||||
|
@ -71,7 +71,7 @@ module Types =
|
|||||||
type Action =
|
type Action =
|
||||||
{ ActionId : int
|
{ ActionId : int
|
||||||
Type : ActionType
|
Type : ActionType
|
||||||
Timestamp : DateTime }
|
Timestamp : System.DateTime }
|
||||||
|
|
||||||
[<CLIMutable>]
|
[<CLIMutable>]
|
||||||
type PlayerData =
|
type PlayerData =
|
||||||
@ -86,6 +86,9 @@ module Armory =
|
|||||||
let file = System.IO.File.ReadAllText("Items.json")
|
let file = System.IO.File.ReadAllText("Items.json")
|
||||||
JsonConvert.DeserializeObject<BattleItem array>(file)
|
JsonConvert.DeserializeObject<BattleItem array>(file)
|
||||||
|
|
||||||
|
let hacks = battleItems |> Array.filter (fun bi -> match bi.Type with Hack -> true | Shield -> false)
|
||||||
|
let shields = battleItems |> Array.filter (fun bi -> match bi.Type with Shield -> true | Hack -> false)
|
||||||
|
|
||||||
let getItem itemId = battleItems |> Array.find (fun w -> w.Id = itemId)
|
let getItem itemId = battleItems |> Array.find (fun w -> w.Id = itemId)
|
||||||
|
|
||||||
module Messaging =
|
module Messaging =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user