New item types
This commit is contained in:
parent
9659656e4a
commit
a0267b4cbb
15
Bot/Bot.fs
15
Bot/Bot.fs
@ -19,6 +19,7 @@ let storeConfig = DiscordConfiguration()
|
|||||||
let stealConfig = DiscordConfiguration()
|
let stealConfig = DiscordConfiguration()
|
||||||
//let slotMachineConfig = DiscordConfiguration()
|
//let slotMachineConfig = DiscordConfiguration()
|
||||||
//hackerBattleConfig.MinimumLogLevel <- Microsoft.Extensions.Logging.LogLevel.Trace
|
//hackerBattleConfig.MinimumLogLevel <- Microsoft.Extensions.Logging.LogLevel.Trace
|
||||||
|
//storeConfig.MinimumLogLevel <- Microsoft.Extensions.Logging.LogLevel.Trace
|
||||||
|
|
||||||
//let configs = [| hackerBattleConfig ; storeConfig ; slotMachineConfig ; |]
|
//let configs = [| hackerBattleConfig ; storeConfig ; slotMachineConfig ; |]
|
||||||
let configs = [ hackerBattleConfig ; storeConfig ; stealConfig ]
|
let configs = [ hackerBattleConfig ; storeConfig ; stealConfig ]
|
||||||
@ -99,20 +100,6 @@ stealBot.ConnectAsync() |> Async.AwaitTask |> Async.RunSynchronously
|
|||||||
// return ()
|
// return ()
|
||||||
//} |> Async.RunSynchronously
|
//} |> Async.RunSynchronously
|
||||||
|
|
||||||
if guild = 922419263275425832uL then
|
|
||||||
let interactionsConfig = DiscordConfiguration()
|
|
||||||
interactionsConfig.TokenType <- TokenType.Bot
|
|
||||||
interactionsConfig.Intents <- DiscordIntents.All
|
|
||||||
interactionsConfig.Token <- GuildEnvironment.tokenPlayerInteractions
|
|
||||||
|
|
||||||
let interactionsBot = new DiscordClient(interactionsConfig)
|
|
||||||
|
|
||||||
let commands = interactionsBot.UseSlashCommands()
|
|
||||||
commands.RegisterCommands<PlayerInteractions.PlayerInteractions>(guild)
|
|
||||||
|
|
||||||
interactionsBot.ConnectAsync() |> Async.AwaitTask |> Async.RunSynchronously
|
|
||||||
|
|
||||||
|
|
||||||
Task.Delay(-1)
|
Task.Delay(-1)
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
|> Async.RunSynchronously
|
|> Async.RunSynchronously
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
module Degenz.DbService
|
module Degenz.DbService
|
||||||
|
|
||||||
open Degenz
|
|
||||||
open System
|
open System
|
||||||
open Npgsql.FSharp
|
open Npgsql.FSharp
|
||||||
|
open Degenz
|
||||||
|
|
||||||
type User = {
|
type User = {
|
||||||
Name : string
|
Name : string
|
||||||
DiscordId : uint64
|
DiscordId : uint64
|
||||||
Bank : int<GBT>
|
Bank : int<GBT>
|
||||||
Strength : int
|
Strength : int
|
||||||
Inventory : int array
|
Inventory : int list
|
||||||
}
|
}
|
||||||
|
|
||||||
let mapBack user : PlayerData =
|
let mapBack user : PlayerData =
|
||||||
{ DiscordId = user.DiscordId
|
{ DiscordId = user.DiscordId
|
||||||
Name = user.Name
|
Name = user.Name
|
||||||
Inventory = user.Inventory |> Array.choose (fun id -> Armory.battleItems |> Array.tryFind (fun i -> i.Id = id))
|
Inventory = user.Inventory |> List.choose (fun id -> Armory.battleItems |> List.tryFind (fun item -> item.Id = id))
|
||||||
Events = [||]
|
Events = [||]
|
||||||
Traits = { PlayerTraits.empty with Strength = user.Strength }
|
Stats = [ { Id = StatId.Strength ; Amount = user.Strength } ]
|
||||||
Bank = user.Bank
|
Bank = user.Bank
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ let tryFindPlayer connStr (discordId : uint64) =
|
|||||||
Name = read.string "display_name"
|
Name = read.string "display_name"
|
||||||
Bank = read.int "gbt" * 1<GBT>
|
Bank = read.int "gbt" * 1<GBT>
|
||||||
Strength = read.int "strength"
|
Strength = read.int "strength"
|
||||||
Inventory = read.intArray "inventory"
|
Inventory = read.intArray "inventory" |> Array.toList
|
||||||
})
|
})
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
match List.tryHead user with
|
match List.tryHead user with
|
||||||
@ -90,8 +90,8 @@ let updatePlayer connStr (player : PlayerData) =
|
|||||||
|> Sql.parameters [
|
|> Sql.parameters [
|
||||||
"did", Sql.string (string player.DiscordId)
|
"did", Sql.string (string player.DiscordId)
|
||||||
"gbt", Sql.int (int player.Bank)
|
"gbt", Sql.int (int player.Bank)
|
||||||
"str", Sql.int (int player.Traits.Strength)
|
"str", Sql.int (player |> Player.getStat StatId.Strength |> int)
|
||||||
"inv", Sql.intArray (player.Inventory |> Array.map (fun i -> i.Id))
|
"inv", Sql.intArray (player.Inventory |> Array.ofList |> Array.map (fun item -> item.Id))
|
||||||
]
|
]
|
||||||
|> Sql.query """
|
|> Sql.query """
|
||||||
UPDATE "user" SET gbt = @gbt, strength = @str, inventory = @inv
|
UPDATE "user" SET gbt = @gbt, strength = @str, inventory = @inv
|
||||||
|
134
Bot/Embeds.fs
134
Bot/Embeds.fs
@ -8,35 +8,29 @@ open DSharpPlus.Entities
|
|||||||
let hackGif = "https://s10.gifyu.com/images/Hacker-Degenz-V20ce8eb832734aa62-min.gif"
|
let hackGif = "https://s10.gifyu.com/images/Hacker-Degenz-V20ce8eb832734aa62-min.gif"
|
||||||
let shieldGif = "https://s10.gifyu.com/images/Defense-Degenz-V2-min.gif"
|
let shieldGif = "https://s10.gifyu.com/images/Defense-Degenz-V2-min.gif"
|
||||||
|
|
||||||
let getHackIcon = function
|
let getItemIcon id =
|
||||||
| HackId.Virus -> "https://s10.gifyu.com/images/Virus-icon.jpg"
|
match enum<ItemId>(id) with
|
||||||
| HackId.RemoteAccess -> "https://s10.gifyu.com/images/Mind-Control-Degenz-V2-min.jpg"
|
| ItemId.Virus -> "https://s10.gifyu.com/images/Virus-icon.jpg"
|
||||||
| HackId.Worm -> "https://s10.gifyu.com/images/WormBugAttack_Degenz-min.jpg"
|
| ItemId.RemoteAccess -> "https://s10.gifyu.com/images/Mind-Control-Degenz-V2-min.jpg"
|
||||||
|
| ItemId.Worm -> "https://s10.gifyu.com/images/WormBugAttack_Degenz-min.jpg"
|
||||||
|
| ItemId.Firewall -> "https://s10.gifyu.com/images/Defense-GIF-1-Degenz-1.jpg"
|
||||||
|
| ItemId.Encryption -> "https://s10.gifyu.com/images/Encryption-Degenz-V2-1-min.jpg"
|
||||||
|
| ItemId.Cypher -> "https://s10.gifyu.com/images/Cypher-Smaller.jpg"
|
||||||
| _ -> hackGif
|
| _ -> hackGif
|
||||||
|
|
||||||
let getShieldIcon = function
|
let getItemGif id =
|
||||||
| ShieldId.Firewall -> "https://s10.gifyu.com/images/Defense-GIF-1-Degenz-1.jpg"
|
match enum<ItemId>(id) with
|
||||||
| ShieldId.Encryption -> "https://s10.gifyu.com/images/Encryption-Degenz-V2-1-min.jpg"
|
| ItemId.Virus -> "https://s10.gifyu.com/images/Attack-DegenZ-1.gif"
|
||||||
| ShieldId.Cypher -> "https://s10.gifyu.com/images/Cypher-Smaller.jpg"
|
| ItemId.RemoteAccess -> "https://s10.gifyu.com/images/Mind-Control-Degenz-V2-min.gif"
|
||||||
| _ -> shieldGif
|
| ItemId.Worm -> "https://s10.gifyu.com/images/WormBugAttack_Degenz-min.gif"
|
||||||
|
| ItemId.Firewall -> "https://s10.gifyu.com/images/Defense-GIF-1-Degenz-min.gif"
|
||||||
let getHackGif = function
|
| ItemId.Encryption -> "https://s10.gifyu.com/images/Encryption-Degenz-V2-1-min.gif"
|
||||||
| HackId.Virus -> "https://s10.gifyu.com/images/Attack-DegenZ-1.gif"
|
| ItemId.Cypher -> "https://s10.gifyu.com/images/Cypher-Smaller.gif"
|
||||||
| HackId.RemoteAccess -> "https://s10.gifyu.com/images/Mind-Control-Degenz-V2-min.gif"
|
|
||||||
| HackId.Worm -> "https://s10.gifyu.com/images/WormBugAttack_Degenz-min.gif"
|
|
||||||
| _ -> hackGif
|
| _ -> hackGif
|
||||||
|
|
||||||
let getShieldGif = function
|
let constructButtons (actionId: string) (buttonInfo : string) (player: PlayerData) items ignoreCooldown =
|
||||||
| ShieldId.Firewall -> "https://s10.gifyu.com/images/Defense-GIF-1-Degenz-min.gif"
|
items
|
||||||
| ShieldId.Encryption -> "https://s10.gifyu.com/images/Encryption-Degenz-V2-1-min.gif"
|
|> List.map (fun item ->
|
||||||
| ShieldId.Cypher -> "https://s10.gifyu.com/images/Cypher-Smaller.gif"
|
|
||||||
| _ -> shieldGif
|
|
||||||
|
|
||||||
let constructButtons (actionId: string) (buttonInfo : string) (player: PlayerData) itemType ignoreCooldown =
|
|
||||||
player
|
|
||||||
|> Player.getItems itemType
|
|
||||||
|> Array.sortBy (fun i -> i.Power)
|
|
||||||
|> Array.map (fun item ->
|
|
||||||
let action =
|
let action =
|
||||||
player.Events
|
player.Events
|
||||||
|> Array.tryFind (fun i ->
|
|> Array.tryFind (fun i ->
|
||||||
@ -44,7 +38,7 @@ let constructButtons (actionId: string) (buttonInfo : string) (player: PlayerDat
|
|||||||
| Hacking h -> h.HackId = item.Id && h.IsInstigator
|
| Hacking h -> h.HackId = item.Id && h.IsInstigator
|
||||||
| Shielding id -> id = item.Id
|
| Shielding id -> id = item.Id
|
||||||
| _ -> false)
|
| _ -> false)
|
||||||
let btnColor = WeaponClass.getClassButtonColor item.Class
|
let btnColor = WeaponClass.getClassButtonColor item
|
||||||
match action , ignoreCooldown with
|
match action , ignoreCooldown with
|
||||||
| None , _ | Some _ , true ->
|
| None , _ | Some _ , true ->
|
||||||
DiscordButtonComponent(btnColor, $"{actionId}-{item.Id}-{buttonInfo}-{player.Name}", $"{item.Name}")
|
DiscordButtonComponent(btnColor, $"{actionId}-{item.Id}-{buttonInfo}-{player.Name}", $"{item.Name}")
|
||||||
@ -54,17 +48,18 @@ let constructButtons (actionId: string) (buttonInfo : string) (player: PlayerDat
|
|||||||
|> Seq.cast<DiscordComponent>
|
|> Seq.cast<DiscordComponent>
|
||||||
|
|
||||||
let pickDefense actionId player isTrainer =
|
let pickDefense actionId player isTrainer =
|
||||||
let buttons = constructButtons actionId (string player.DiscordId) player ItemType.Shield isTrainer
|
let shieldItems = player |> Player.getShieldItems
|
||||||
|
let buttons = constructButtons actionId (string player.DiscordId) player shieldItems isTrainer
|
||||||
|
|
||||||
let embed =
|
let embed =
|
||||||
DiscordEmbedBuilder()
|
DiscordEmbedBuilder()
|
||||||
.WithTitle("Shield Defense")
|
.WithTitle("Shield Defense")
|
||||||
.WithDescription("Pick a shield to protect yourself from hacks")
|
.WithDescription("Pick a shield to protect yourself from hacks")
|
||||||
|
|
||||||
for s in Player.getShields player |> Array.sortBy (fun i -> i.Power) do
|
for (item,sClass,cooldown) in Player.getShields player do
|
||||||
let hours = TimeSpan.FromMinutes(int s.Cooldown).TotalHours
|
let hours = TimeSpan.FromMinutes(int cooldown).TotalHours
|
||||||
let against = WeaponClass.getGoodAgainst(s.Class) |> snd
|
let against = WeaponClass.getGoodAgainst(sClass) |> snd
|
||||||
embed.AddField(s.Name, $"Active {hours} hours\nDefeats {against}", true) |> ignore
|
embed.AddField(item.Name, $"Active {hours} hours\nDefeats {against}", true) |> ignore
|
||||||
|
|
||||||
DiscordFollowupMessageBuilder()
|
DiscordFollowupMessageBuilder()
|
||||||
.AddComponents(buttons)
|
.AddComponents(buttons)
|
||||||
@ -72,7 +67,8 @@ let pickDefense actionId player isTrainer =
|
|||||||
.AsEphemeral(true)
|
.AsEphemeral(true)
|
||||||
|
|
||||||
let pickHack actionId attacker defender isTrainer =
|
let pickHack actionId attacker defender isTrainer =
|
||||||
let buttons = constructButtons actionId $"{defender.DiscordId}-{defender.Name}" attacker ItemType.Hack isTrainer
|
let hackItems = attacker |> Player.getHackItems
|
||||||
|
let buttons = constructButtons actionId $"{defender.DiscordId}-{defender.Name}" attacker hackItems isTrainer
|
||||||
|
|
||||||
let stealMsg = if not isTrainer then $"{defender.Name} has **{defender.Bank} $GBT** we can take from them. " else ""
|
let stealMsg = if not isTrainer then $"{defender.Name} has **{defender.Bank} $GBT** we can take from them. " else ""
|
||||||
let embed =
|
let embed =
|
||||||
@ -81,9 +77,9 @@ let pickHack actionId attacker defender isTrainer =
|
|||||||
.WithDescription($"{stealMsg}Pick the hack you want to use.")
|
.WithDescription($"{stealMsg}Pick the hack you want to use.")
|
||||||
|
|
||||||
if not isTrainer then
|
if not isTrainer then
|
||||||
for h in Player.getHacks attacker |> Array.sortBy (fun i -> i.Power) do
|
for (item,power,hClass,cooldown) in Player.getHacks attacker do
|
||||||
let amount = if h.Power > int defender.Bank then int defender.Bank else h.Power
|
let amount = if power > int defender.Bank then int defender.Bank else power
|
||||||
embed.AddField(h.Name, $"Cooldown {h.Cooldown} mins\nExtract {amount} $GBT", true) |> ignore
|
embed.AddField(item.Name, $"Cooldown {cooldown} mins\nExtract {amount} $GBT", true) |> ignore
|
||||||
|
|
||||||
DiscordFollowupMessageBuilder()
|
DiscordFollowupMessageBuilder()
|
||||||
.AddComponents(buttons)
|
.AddComponents(buttons)
|
||||||
@ -93,7 +89,7 @@ let pickHack actionId attacker defender isTrainer =
|
|||||||
let responseSuccessfulHack earnedMoney (targetId : uint64) amountTaken (hack : Item) =
|
let responseSuccessfulHack earnedMoney (targetId : uint64) amountTaken (hack : Item) =
|
||||||
let embed =
|
let embed =
|
||||||
DiscordEmbedBuilder()
|
DiscordEmbedBuilder()
|
||||||
.WithImageUrl(getHackGif (enum<HackId>(hack.Id)))
|
.WithImageUrl(getItemGif hack.Id)
|
||||||
.WithTitle("Hack Attack")
|
.WithTitle("Hack Attack")
|
||||||
.WithDescription($"You successfully hacked <@{targetId}> using {hack.Name}"
|
.WithDescription($"You successfully hacked <@{targetId}> using {hack.Name}"
|
||||||
+ (if earnedMoney then $", and took {amountTaken} 💰$GBT from them!" else "!"))
|
+ (if earnedMoney then $", and took {amountTaken} 💰$GBT from them!" else "!"))
|
||||||
@ -102,10 +98,10 @@ let responseSuccessfulHack earnedMoney (targetId : uint64) amountTaken (hack : I
|
|||||||
.AddEmbed(embed.Build())
|
.AddEmbed(embed.Build())
|
||||||
.AsEphemeral(true)
|
.AsEphemeral(true)
|
||||||
|
|
||||||
let responseCreatedShield (shield : Item) =
|
let responseCreatedShield ((item,_,cooldown) : ShieldItem) =
|
||||||
let embed = DiscordEmbedBuilder().WithImageUrl(getShieldGif (enum<ShieldId>(shield.Id)))
|
let embed = DiscordEmbedBuilder().WithImageUrl(getItemGif item.Id)
|
||||||
embed.Title <- "Mounted Shield"
|
embed.Title <- "Mounted Shield"
|
||||||
embed.Description <- $"Mounted {shield.Name} shield for {TimeSpan.FromMinutes(int shield.Cooldown).Hours} hours"
|
embed.Description <- $"Mounted {item.Name} shield for {TimeSpan.FromMinutes(int cooldown).Hours} hours"
|
||||||
|
|
||||||
DiscordFollowupMessageBuilder()
|
DiscordFollowupMessageBuilder()
|
||||||
.AddEmbed(embed)
|
.AddEmbed(embed)
|
||||||
@ -115,60 +111,52 @@ let eventSuccessfulHack (ctx : IDiscordContext) target prize =
|
|||||||
DiscordMessageBuilder()
|
DiscordMessageBuilder()
|
||||||
.WithContent($"{ctx.GetDiscordMember().Username} successfully hacked <@{target.DiscordId}> and took {prize} GoodBoyTokenz")
|
.WithContent($"{ctx.GetDiscordMember().Username} successfully hacked <@{target.DiscordId}> and took {prize} GoodBoyTokenz")
|
||||||
|
|
||||||
let getBuyItemsEmbed (player : PlayerData) (itemType : ItemType) (store : Item array) =
|
let getBuyItemsEmbed (playerInventory : Inventory) (storeInventory : Inventory) =
|
||||||
let embeds , buttons =
|
let embeds , buttons =
|
||||||
store
|
storeInventory
|
||||||
|> Array.filter (fun i -> i.Type = itemType)
|
|> List.map (fun item ->
|
||||||
|> Array.map (fun item ->
|
|
||||||
let embed = DiscordEmbedBuilder()
|
let embed = DiscordEmbedBuilder()
|
||||||
match item.Type with
|
match item.Type with
|
||||||
| ItemType.Hack ->
|
| Hack(power,_,cooldown) ->
|
||||||
embed
|
embed.AddField($"$GBT Reward |", string power, true)
|
||||||
.AddField($"$GBT Reward |", string item.Power, true)
|
.AddField("Cooldown |", $"{TimeSpan.FromMinutes(int cooldown).Minutes} minutes", true)
|
||||||
.AddField("Cooldown |", $"{TimeSpan.FromMinutes(int item.Cooldown).Minutes} minutes", true)
|
.WithThumbnail(getItemIcon item.Id)
|
||||||
.WithThumbnail(getHackIcon (enum<HackId>(item.Id)))
|
|
||||||
|> ignore
|
|> ignore
|
||||||
| _ ->
|
| Shield(shieldClass,cooldown) ->
|
||||||
embed
|
embed.AddField($"Strong against |", WeaponClass.getGoodAgainst shieldClass |> snd |> string, true)
|
||||||
// .AddField($"Defensive Strength |", string item.Power, true)
|
// .AddField($"Defensive Strength |", string item.Power, true)
|
||||||
.AddField($"Strong against |", WeaponClass.getGoodAgainst item.Class |> snd |> string, true)
|
.AddField("Active For |", $"{TimeSpan.FromMinutes(int cooldown).Hours} hours", true)
|
||||||
.AddField("Active For |", $"{TimeSpan.FromMinutes(int item.Cooldown).Hours} hours", true)
|
.WithThumbnail(getItemIcon item.Id)
|
||||||
.WithThumbnail(getShieldIcon (enum<ShieldId>(item.Id)))
|
|
||||||
|> ignore
|
|> ignore
|
||||||
|
| _ -> ()
|
||||||
embed
|
embed
|
||||||
.AddField("Price 💰", (if item.Price = 0<GBT> then "Free" else $"{item.Price} $GBT"), true)
|
.AddField("Price 💰", (if item.Price = 0<GBT> then "Free" else $"{item.Price} $GBT"), true)
|
||||||
.WithColor(WeaponClass.getClassEmbedColor item.Class)
|
.WithColor(WeaponClass.getClassEmbedColor item)
|
||||||
.WithTitle($"{item.Name}")
|
.WithTitle($"{item.Name}")
|
||||||
|> ignore
|
|> ignore
|
||||||
let button =
|
let button =
|
||||||
if player.Inventory |> Array.exists (fun i -> i.Id = item.Id)
|
if playerInventory |> List.exists (fun i -> i.Id = item.Id)
|
||||||
then DiscordButtonComponent(WeaponClass.getClassButtonColor item.Class, $"Buy-{item.Id}", $"Own {item.Name}", true)
|
then DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Buy-{item.Id}", $"Own {item.Name}", true)
|
||||||
else DiscordButtonComponent(WeaponClass.getClassButtonColor item.Class, $"Buy-{item.Id}", $"Buy {item.Name}")
|
else DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Buy-{item.Id}", $"Buy {item.Name}")
|
||||||
embed.Build() , button :> DiscordComponent)
|
( embed.Build() , button :> DiscordComponent ))
|
||||||
|> Array.unzip
|
|> List.unzip
|
||||||
|
|
||||||
DiscordFollowupMessageBuilder()
|
DiscordFollowupMessageBuilder()
|
||||||
.AddEmbeds(embeds)
|
.AddEmbeds(embeds)
|
||||||
.AddComponents(buttons)
|
.AddComponents(buttons)
|
||||||
.AsEphemeral(true)
|
.AsEphemeral(true)
|
||||||
|
|
||||||
let getSellEmbed (itemType : ItemType) (player : PlayerData) =
|
let getSellEmbed (items : Item list) =
|
||||||
let embeds , buttons =
|
let embeds , buttons =
|
||||||
player.Inventory
|
items
|
||||||
|> Array.filter (fun i -> i.Type = itemType)
|
|> List.map (fun item ->
|
||||||
|> Array.map (fun item ->
|
DiscordEmbedBuilder()
|
||||||
let embed = DiscordEmbedBuilder()
|
|
||||||
match item.Type with
|
|
||||||
| ItemType.Hack -> embed.WithThumbnail(getHackIcon (enum<HackId>(item.Id))) |> ignore
|
|
||||||
| _ -> embed.WithThumbnail(getShieldIcon (enum<ShieldId>(item.Id))) |> ignore
|
|
||||||
embed
|
|
||||||
.AddField("Sell For 💰", $"{item.Price} $GBT", true)
|
.AddField("Sell For 💰", $"{item.Price} $GBT", true)
|
||||||
.WithTitle($"{item.Name}")
|
.WithTitle($"{item.Name}")
|
||||||
.WithColor(WeaponClass.getClassEmbedColor item.Class)
|
.WithColor(WeaponClass.getClassEmbedColor item)
|
||||||
|> ignore
|
.Build()
|
||||||
let button = DiscordButtonComponent(WeaponClass.getClassButtonColor item.Class, $"Sell-{item.Id}", $"Sell {item.Name}")
|
, DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Sell-{id}", $"Sell {item.Name}") :> DiscordComponent)
|
||||||
embed.Build() , button :> DiscordComponent)
|
|> List.unzip
|
||||||
|> Array.unzip
|
|
||||||
|
|
||||||
DiscordFollowupMessageBuilder()
|
DiscordFollowupMessageBuilder()
|
||||||
.AddEmbeds(embeds)
|
.AddEmbeds(embeds)
|
||||||
|
@ -9,35 +9,80 @@ module Armory =
|
|||||||
let file = System.IO.File.ReadAllText("Items.json")
|
let file = System.IO.File.ReadAllText("Items.json")
|
||||||
// let file = System.IO.File.ReadAllText("Bot/Items.json")
|
// let file = System.IO.File.ReadAllText("Bot/Items.json")
|
||||||
JsonConvert.DeserializeObject<Item array>(file)
|
JsonConvert.DeserializeObject<Item array>(file)
|
||||||
|
|> Array.toList
|
||||||
|
|
||||||
let hacks = battleItems |> Array.filter (fun bi -> match bi.Type with ItemType.Hack -> true | _ -> false)
|
let hacks = battleItems |> List.filter (fun item -> match item.Type with Hack _ -> true | _ -> false)
|
||||||
let shields = battleItems |> Array.filter (fun bi -> match bi.Type with ItemType.Shield -> true | _ -> false)
|
let shields = battleItems |> List.filter (fun item -> match item.Type with Shield _ -> true | _ -> false)
|
||||||
|
|
||||||
let getItem itemId = battleItems |> Array.find (fun w -> w.Id = itemId)
|
let getItem itemId = battleItems |> List.find (fun item -> item.Id = itemId)
|
||||||
|
|
||||||
|
let getHackItems inventory =
|
||||||
|
inventory
|
||||||
|
|> List.filter (fun item -> match item.Type with Hack _ -> true | _ -> false)
|
||||||
|
|> List.sortBy (fun item -> item.Id)
|
||||||
|
let getShieldItems inventory =
|
||||||
|
inventory
|
||||||
|
|> List.filter (fun item -> match item.Type with Shield _ -> true | _ -> false)
|
||||||
|
|> List.sortBy (fun item -> item.Id)
|
||||||
|
let getHacks : HackItem list =
|
||||||
|
battleItems
|
||||||
|
|> List.choose (fun item ->
|
||||||
|
match item.Type with
|
||||||
|
| Hack(power, hackClass, cooldown) -> Some (item , power, hackClass, cooldown) | _ -> None)
|
||||||
|
|> List.sortBy (fun (item,_,_,_) -> item.Id)
|
||||||
|
let getShields : ShieldItem list =
|
||||||
|
battleItems
|
||||||
|
|> List.choose (fun item ->
|
||||||
|
match item.Type with
|
||||||
|
| Shield(hackClass, cooldown) -> Some (item,hackClass,cooldown) | _ -> None)
|
||||||
|
|> List.sortBy (fun (item,_,_) -> item.Id)
|
||||||
|
let getHackById id = getHacks |> List.find (fun (item,_,_,_) -> item.Id = id)
|
||||||
|
let getShieldById id = getShields |> List.find (fun (item,_,_) -> item.Id = id)
|
||||||
|
|
||||||
module WeaponClass =
|
module WeaponClass =
|
||||||
// TODO: Find a different place to put this
|
// TODO: Find a different place to put this
|
||||||
let SameTargetAttackCooldown = System.TimeSpan.FromHours(1)
|
let SameTargetAttackCooldown = System.TimeSpan.FromHours(1)
|
||||||
|
|
||||||
let getClassButtonColor = function
|
let getClassButtonColor item =
|
||||||
| 0 -> ButtonStyle.Danger
|
match item.Type with
|
||||||
| 1 -> ButtonStyle.Primary
|
| Hack (_,0,_) | Shield (0,_) -> ButtonStyle.Danger
|
||||||
| _ -> ButtonStyle.Success
|
| Hack (_,1,_) | Shield (1,_) -> ButtonStyle.Primary
|
||||||
|
| Hack (_,2,_) | Shield (2,_) -> ButtonStyle.Success
|
||||||
|
| _ -> ButtonStyle.Primary
|
||||||
|
|
||||||
let getClassEmbedColor = function
|
let getClassEmbedColor item =
|
||||||
| 0 -> DiscordColor.Red
|
match item.Type with
|
||||||
| 1 -> DiscordColor.Blurple
|
| Hack (_,0,_) | Shield (0,_) -> DiscordColor.Red
|
||||||
| _ -> DiscordColor.Green
|
| Hack (_,1,_) | Shield (1,_) -> DiscordColor.Blurple
|
||||||
|
| Hack (_,2,_) | Shield (2,_) -> DiscordColor.Green
|
||||||
|
| _ -> DiscordColor.Blurple
|
||||||
|
|
||||||
let getGoodAgainst = function
|
let getGoodAgainst = function
|
||||||
| 0 -> ( ShieldId.Firewall , HackId.Virus )
|
| 0 -> ( ItemId.Firewall , ItemId.Virus )
|
||||||
| 1 -> ( ShieldId.Encryption , HackId.RemoteAccess )
|
| 1 -> ( ItemId.Encryption , ItemId.RemoteAccess )
|
||||||
| _ -> ( ShieldId.Cypher , HackId.Worm )
|
| _ -> ( ItemId.Cypher , ItemId.Worm )
|
||||||
|
|
||||||
module Player =
|
module Player =
|
||||||
let getItems itemType (player : PlayerData) = player.Inventory |> Array.filter (fun i -> i.Type = itemType)
|
let getHackItems player =
|
||||||
let getHacks (player : PlayerData) = getItems ItemType.Hack player
|
player.Inventory
|
||||||
let getShields (player : PlayerData) = getItems ItemType.Shield player
|
|> List.filter (fun item -> match item.Type with Hack _ -> true | _ -> false)
|
||||||
|
|> List.sortBy (fun item -> item.Id)
|
||||||
|
let getShieldItems player =
|
||||||
|
player.Inventory
|
||||||
|
|> List.filter (fun item -> match item.Type with Shield _ -> true | _ -> false)
|
||||||
|
|> List.sortBy (fun item -> item.Id)
|
||||||
|
let getHacks player : HackItem list =
|
||||||
|
player.Inventory
|
||||||
|
|> List.choose (fun item ->
|
||||||
|
match item.Type with
|
||||||
|
| Hack(power, hackClass, cooldown) -> Some (item , power, hackClass, cooldown) | _ -> None)
|
||||||
|
|> List.sortBy (fun (item,_,_,_) -> item.Id)
|
||||||
|
let getShields player : ShieldItem list =
|
||||||
|
player.Inventory
|
||||||
|
|> List.choose (fun item ->
|
||||||
|
match item.Type with
|
||||||
|
| Shield(hackClass, cooldown) -> Some (item , hackClass, cooldown) | _ -> None)
|
||||||
|
|> List.sortBy (fun (item,_,_) -> item.Id)
|
||||||
let getHackEvents player =
|
let getHackEvents player =
|
||||||
player.Events
|
player.Events
|
||||||
|> Array.filter (fun act -> match act.Type with PlayerEventType.Hacking h -> h.IsInstigator | _ -> false)
|
|> Array.filter (fun act -> match act.Type with PlayerEventType.Hacking h -> h.IsInstigator | _ -> false)
|
||||||
@ -55,11 +100,17 @@ module Player =
|
|||||||
|
|
||||||
let modifyBank (player : PlayerData) amount = { player with Bank = max (player.Bank + amount) 0<GBT> }
|
let modifyBank (player : PlayerData) amount = { player with Bank = max (player.Bank + amount) 0<GBT> }
|
||||||
|
|
||||||
|
let getStat statId player =
|
||||||
|
player.Stats
|
||||||
|
|> List.tryFind (fun stat -> statId = stat.Id)
|
||||||
|
|> Option.map (fun stat -> stat.Amount)
|
||||||
|
|> Option.defaultValue 0
|
||||||
|
|
||||||
module Arsenal =
|
module Arsenal =
|
||||||
let battleItemFormat (items : Item array) =
|
let battleItemFormat (items : Item list) =
|
||||||
match items with
|
match items with
|
||||||
| [||] -> "None"
|
| [] -> "None"
|
||||||
| _ -> items |> Array.toList |> List.map (fun i -> i.Name) |> String.concat ", "
|
| _ -> items |> List.map (fun item -> item.Name) |> String.concat ", "
|
||||||
|
|
||||||
let actionFormat (actions : PlayerEvent array) =
|
let actionFormat (actions : PlayerEvent array) =
|
||||||
match actions with
|
match actions with
|
||||||
@ -82,8 +133,8 @@ module Arsenal =
|
|||||||
|
|
||||||
let statusFormat p =
|
let statusFormat p =
|
||||||
let hacks = Player.getHackEvents p
|
let hacks = Player.getHackEvents p
|
||||||
$"**Hacks:** {Player.getHacks p |> battleItemFormat}\n
|
$"**Hacks:** {Player.getHackItems p |> battleItemFormat}\n
|
||||||
**Shields:** {Player.getShields p |> battleItemFormat}\n
|
**Shields:** {Player.getShieldItems p |> battleItemFormat}\n
|
||||||
**Hack Attacks:**\n{ hacks |> Array.take (min hacks.Length 10) |> actionFormat}\n
|
**Hack Attacks:**\n{ hacks |> Array.take (min hacks.Length 10) |> actionFormat}\n
|
||||||
**Active Shields:**\n{Player.getShieldEvents p |> actionFormat}"
|
**Active Shields:**\n{Player.getShieldEvents p |> actionFormat}"
|
||||||
|
|
||||||
|
128
Bot/GameTypes.fs
128
Bot/GameTypes.fs
@ -1,111 +1,111 @@
|
|||||||
namespace Degenz
|
[<Microsoft.FSharp.Core.AutoOpen>]
|
||||||
|
module Degenz.Types
|
||||||
|
|
||||||
open System
|
open System
|
||||||
|
|
||||||
[<Microsoft.FSharp.Core.AutoOpen>]
|
[<Measure>]
|
||||||
module Types =
|
type mins
|
||||||
|
|
||||||
[<Measure>]
|
[<Measure>]
|
||||||
type mins
|
type GBT
|
||||||
|
|
||||||
[<Measure>]
|
type ItemId =
|
||||||
type GBT
|
|
||||||
|
|
||||||
type HackId =
|
|
||||||
| Virus = 0
|
| Virus = 0
|
||||||
| RemoteAccess = 1
|
| RemoteAccess = 1
|
||||||
| Worm = 2
|
| Worm = 2
|
||||||
|
|
||||||
type ShieldId =
|
|
||||||
| Firewall = 6
|
| Firewall = 6
|
||||||
| Encryption = 7
|
| Encryption = 7
|
||||||
| Cypher = 8
|
| Cypher = 8
|
||||||
|
|
||||||
type ItemType =
|
type StatId =
|
||||||
| Hack = 0
|
| Strength = 0
|
||||||
| Shield = 1
|
| Focus = 1
|
||||||
| Food = 1
|
| Luck = 2
|
||||||
|
| Charisma = 3
|
||||||
|
|
||||||
type ItemAttributes = {
|
type Stat = {
|
||||||
Sell : bool
|
Id : StatId
|
||||||
Buy : bool
|
BaseDecayRate : single
|
||||||
Consume : bool
|
BaseMinMax : Range
|
||||||
Drop : bool
|
}
|
||||||
}
|
|
||||||
with static member empty = { Sell = false ; Buy = false ; Consume = false ; Drop = false }
|
|
||||||
|
|
||||||
type Item = {
|
type ActiveStat = {
|
||||||
Id : int
|
Id : StatId
|
||||||
Name : string
|
Amount : int
|
||||||
Price : int<GBT>
|
}
|
||||||
Type : ItemType
|
|
||||||
Power : int
|
|
||||||
Class : int
|
|
||||||
Cooldown : int<mins>
|
|
||||||
Attributes : ItemAttributes
|
|
||||||
}
|
|
||||||
with static member empty =
|
|
||||||
{ Id = -1
|
|
||||||
Name = "None"
|
|
||||||
Price = 0<GBT>
|
|
||||||
Type = ItemType.Hack
|
|
||||||
Power = 0
|
|
||||||
Class = -1
|
|
||||||
Cooldown = 0<mins>
|
|
||||||
Attributes = ItemAttributes.empty }
|
|
||||||
|
|
||||||
type HackResult =
|
module PlayerStats =
|
||||||
|
let Strength = { Id = StatId.Strength ; BaseDecayRate = 5.0f ; BaseMinMax = Range(0, 100) }
|
||||||
|
let Focus = { Id = StatId.Focus ; BaseDecayRate = 5.0f ; BaseMinMax = Range(0, 100) }
|
||||||
|
let Luck = { Id = StatId.Luck ; BaseDecayRate = 5.0f ; BaseMinMax = Range(0, 100) }
|
||||||
|
let Charisma = { Id = StatId.Charisma ; BaseDecayRate = 5.0f ; BaseMinMax = Range(0, 100) }
|
||||||
|
|
||||||
|
let stats = [| Strength ; Focus ; Luck ; Charisma |]
|
||||||
|
let statConsumableMap =
|
||||||
|
[ ( StatId.Strength , 12 )
|
||||||
|
( StatId.Focus , 13 )
|
||||||
|
( StatId.Luck , 14 )
|
||||||
|
( StatId.Charisma , 15 ) ]
|
||||||
|
|
||||||
|
type HackResult =
|
||||||
| Strong
|
| Strong
|
||||||
| Weak
|
| Weak
|
||||||
|
|
||||||
[<CLIMutable>]
|
[<CLIMutable>]
|
||||||
type DiscordPlayer = { Id: uint64; Name: string }
|
type DiscordPlayer = { Id: uint64; Name: string }
|
||||||
with static member empty = { Id = 0uL ; Name = "None" }
|
with static member empty = { Id = 0uL ; Name = "None" }
|
||||||
|
|
||||||
type HackEvent = {
|
type HackEvent = {
|
||||||
IsInstigator : bool
|
IsInstigator : bool
|
||||||
Adversary : DiscordPlayer
|
Adversary : DiscordPlayer
|
||||||
Success : bool
|
Success : bool
|
||||||
HackId : int
|
HackId : int
|
||||||
}
|
}
|
||||||
|
|
||||||
type PlayerEventType =
|
type PlayerEventType =
|
||||||
| Hacking of HackEvent
|
| Hacking of HackEvent
|
||||||
| Shielding of shieldId : int
|
| Shielding of shieldId : int
|
||||||
| Stealing of instigator : bool * adversary : DiscordPlayer
|
| Stealing of instigator : bool * adversary : DiscordPlayer
|
||||||
| Imprison
|
| Imprison
|
||||||
|
|
||||||
type PlayerEvent =
|
type PlayerEvent =
|
||||||
{ Type : PlayerEventType
|
{ Type : PlayerEventType
|
||||||
Cooldown : int<mins>
|
Cooldown : int<mins>
|
||||||
Timestamp : DateTime }
|
Timestamp : DateTime }
|
||||||
|
|
||||||
type PlayerTraits = {
|
type HackItem = Item * int * int * int<mins>
|
||||||
Strength : int
|
and ShieldItem = Item * int * int<mins>
|
||||||
Focus : int
|
and FoodItem = Item * (Item -> PlayerData -> PlayerData)
|
||||||
Luck : int
|
and AccessoryItem = Item * (Item -> PlayerData -> PlayerData)
|
||||||
Charisma : int
|
and ItemType =
|
||||||
}
|
| Hack of power : int * hackClass : int * cooldown : int<mins>
|
||||||
with static member empty = { Strength = 0 ; Focus = 0 ; Luck = 0 ; Charisma = 0 }
|
| Shield of shieldClass : int * cooldown : int<mins>
|
||||||
|
| Food of effect : (Item -> PlayerData -> PlayerData)
|
||||||
[<CLIMutable>]
|
| Accessory of effect : (Item -> PlayerData -> PlayerData)
|
||||||
type PlayerData = {
|
and Item = {
|
||||||
|
Id : int
|
||||||
|
Name : string
|
||||||
|
Price : int<GBT>
|
||||||
|
Type : ItemType
|
||||||
|
}
|
||||||
|
and Inventory = Item list
|
||||||
|
and PlayerData = {
|
||||||
DiscordId : uint64
|
DiscordId : uint64
|
||||||
Name : string
|
Name : string
|
||||||
Inventory : Item array
|
Inventory : Inventory
|
||||||
Events : PlayerEvent array
|
Events : PlayerEvent array
|
||||||
Traits : PlayerTraits
|
Stats : ActiveStat list
|
||||||
Bank : int<GBT>
|
Bank : int<GBT>
|
||||||
}
|
}
|
||||||
// Achievements : string array
|
// Achievements : string array
|
||||||
// XP : int
|
// XP : int
|
||||||
with member this.basicPlayer = { Id = this.DiscordId ; Name = this.Name }
|
with member this.basicPlayer = { Id = this.DiscordId ; Name = this.Name }
|
||||||
static member empty =
|
static member empty =
|
||||||
{ DiscordId = 0uL
|
{ DiscordId = 0uL
|
||||||
Name = "None"
|
Name = "None"
|
||||||
Inventory = [||]
|
Inventory = []
|
||||||
Events = [||]
|
Events = [||]
|
||||||
Traits = PlayerTraits.empty
|
Stats = []
|
||||||
// Achievements = [||]
|
// Achievements = [||]
|
||||||
// XP = 0
|
// XP = 0
|
||||||
Bank = 0<GBT> }
|
Bank = 0<GBT> }
|
||||||
|
@ -45,21 +45,21 @@ let checkWeaponHasCooldown (weapon : Item) attacker =
|
|||||||
|
|
||||||
let checkHasEmptyHacks attacker =
|
let checkHasEmptyHacks attacker =
|
||||||
match Player.getHacks attacker with
|
match Player.getHacks attacker with
|
||||||
| [||] -> Error $"You currently do not have any Hacks to take 💰$GBT from others. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one."
|
| [] -> Error $"You currently do not have any Hacks to take 💰$GBT from others. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one."
|
||||||
| _ -> Ok attacker
|
| _ -> Ok attacker
|
||||||
|
|
||||||
let checkPlayerOwnsWeapon (item : Item) player =
|
let checkPlayerOwnsWeapon (item : Item) player =
|
||||||
match player.Inventory |> Array.exists (fun i -> i.Id = item.Id) with
|
match player.Inventory |> List.exists (fun i -> i.Id = item.Id) with
|
||||||
| true -> Ok player
|
| true -> Ok player
|
||||||
| false -> Error $"You sold your weapon already, you cheeky bastard..."
|
| false -> Error $"You sold your weapon already, you cheeky bastard..."
|
||||||
|
|
||||||
let checkPlayerHasShieldSlotsAvailable (shield : Item) player =
|
let checkPlayerHasShieldSlotsAvailable player =
|
||||||
let updatedPlayer = player |> Player.removeExpiredActions
|
let updatedPlayer = player |> Player.removeExpiredActions
|
||||||
let defenses = Player.getShieldEvents updatedPlayer
|
let defenses = Player.getShieldEvents updatedPlayer
|
||||||
match defenses |> Array.length >= 3 with
|
match defenses |> Array.length >= 3 with
|
||||||
| true ->
|
| true ->
|
||||||
let timestamp = defenses |> Array.rev |> Array.head |> fun a -> a.Timestamp // This should be the next expiring timestamp
|
let event = defenses |> Array.rev |> Array.head // This should be the next expiring timestamp
|
||||||
let cooldown = getTimeText true (TimeSpan.FromMinutes(int shield.Cooldown)) timestamp
|
let cooldown = getTimeText true (TimeSpan.FromMinutes(int event.Cooldown)) event.Timestamp
|
||||||
Error $"You are only allowed three shields at a time. Wait {cooldown} to add another shield"
|
Error $"You are only allowed three shields at a time. Wait {cooldown} to add another shield"
|
||||||
| false -> Ok updatedPlayer
|
| false -> Ok updatedPlayer
|
||||||
|
|
||||||
@ -68,35 +68,36 @@ let checkTargetHasFunds target player =
|
|||||||
| true -> Error $"Looks like the poor bastard has no $GBT... pick a different victim."
|
| true -> Error $"Looks like the poor bastard has no $GBT... pick a different victim."
|
||||||
| false -> Ok player
|
| false -> Ok player
|
||||||
|
|
||||||
let calculateDamage (hack : Item) (shield : Item) =
|
let calculateDamage ((_,_,hackClass,_) : HackItem) ((_,shieldClass,_) : ShieldItem) =
|
||||||
if hack.Class = shield.Class
|
if hackClass = shieldClass
|
||||||
then Weak
|
then Weak
|
||||||
else Strong
|
else Strong
|
||||||
|
|
||||||
let runHackerBattle defender hack =
|
let runHackerBattle defender (hack : HackItem) =
|
||||||
defender
|
defender
|
||||||
|> Player.removeExpiredActions
|
|> Player.removeExpiredActions
|
||||||
|> fun p -> p.Events
|
|> fun p -> p.Events
|
||||||
|> Array.choose (fun event ->
|
|> Array.choose (fun event ->
|
||||||
match event.Type with
|
match event.Type with
|
||||||
| Shielding id -> Armory.battleItems |> Array.find (fun w -> w.Id = id) |> Some
|
| Shielding id -> Armory.getShields |> List.find (fun (item,_,_) -> item.Id = id) |> Some
|
||||||
| _ -> None)
|
| _ -> None)
|
||||||
|> Array.map (calculateDamage hack)
|
|> Array.map (calculateDamage hack)
|
||||||
|> Array.contains Weak
|
|> Array.contains Weak
|
||||||
|
|
||||||
let updateCombatants successfulHack (attacker : PlayerData) (defender : PlayerData) (hack : Item) prize =
|
let updateCombatants successfulHack (attacker : PlayerData) (defender : PlayerData) (hack : HackItem) prize =
|
||||||
|
let (item, power, hackClass, cooldown) = hack
|
||||||
let updatePlayer amount attack p =
|
let updatePlayer amount attack p =
|
||||||
{ p with Events = Array.append [| attack |] p.Events ; Bank = max (p.Bank + amount) 0<GBT> }
|
{ p with Events = Array.append [| attack |] p.Events ; Bank = max (p.Bank + amount) 0<GBT> }
|
||||||
let event isDefenderEvent =
|
let event isDefenderEvent =
|
||||||
let hackEvent = {
|
let hackEvent = {
|
||||||
HackId = hack.Id
|
HackId = item.Id
|
||||||
Adversary = if isDefenderEvent then attacker.basicPlayer else defender.basicPlayer
|
Adversary = if isDefenderEvent then attacker.basicPlayer else defender.basicPlayer
|
||||||
IsInstigator = not isDefenderEvent
|
IsInstigator = not isDefenderEvent
|
||||||
Success = successfulHack
|
Success = successfulHack
|
||||||
}
|
}
|
||||||
{ Type = Hacking hackEvent
|
{ Type = Hacking hackEvent
|
||||||
Timestamp = DateTime.UtcNow
|
Timestamp = DateTime.UtcNow
|
||||||
Cooldown = if isDefenderEvent then int WeaponClass.SameTargetAttackCooldown.TotalMinutes * 1<mins> else hack.Cooldown }
|
Cooldown = if isDefenderEvent then int WeaponClass.SameTargetAttackCooldown.TotalMinutes * 1<mins> else cooldown }
|
||||||
|
|
||||||
[ DbService.updatePlayer GuildEnvironment.pgDb <| updatePlayer prize (event false) attacker
|
[ DbService.updatePlayer GuildEnvironment.pgDb <| updatePlayer prize (event false) attacker
|
||||||
DbService.updatePlayer GuildEnvironment.pgDb <| updatePlayer -prize (event true) defender
|
DbService.updatePlayer GuildEnvironment.pgDb <| updatePlayer -prize (event true) defender
|
||||||
@ -105,12 +106,13 @@ let updateCombatants successfulHack (attacker : PlayerData) (defender : PlayerDa
|
|||||||
|> Async.Parallel
|
|> Async.Parallel
|
||||||
|> Async.Ignore
|
|> Async.Ignore
|
||||||
|
|
||||||
let successfulHack (ctx : IDiscordContext) attacker defender hack =
|
let successfulHack (ctx : IDiscordContext) attacker defender (hack : HackItem) =
|
||||||
async {
|
async {
|
||||||
let prizeAmount = if hack.Power < int defender.Bank then hack.Power else int defender.Bank
|
let (item,power,hackClass,cooldown) = hack
|
||||||
|
let prizeAmount = if power < int defender.Bank then power else int defender.Bank
|
||||||
do! updateCombatants true attacker defender hack (prizeAmount * 1<GBT>)
|
do! updateCombatants true attacker defender hack (prizeAmount * 1<GBT>)
|
||||||
|
|
||||||
let embed = Embeds.responseSuccessfulHack true defender.DiscordId prizeAmount hack
|
let embed = Embeds.responseSuccessfulHack true defender.DiscordId prizeAmount item
|
||||||
do! ctx.FollowUp embed |> Async.AwaitTask
|
do! ctx.FollowUp embed |> Async.AwaitTask
|
||||||
|
|
||||||
let builder = Embeds.eventSuccessfulHack ctx defender prizeAmount
|
let builder = Embeds.eventSuccessfulHack ctx defender prizeAmount
|
||||||
@ -120,9 +122,10 @@ let successfulHack (ctx : IDiscordContext) attacker defender hack =
|
|||||||
|> Async.Ignore
|
|> Async.Ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
let failedHack (ctx : IDiscordContext) attacker defender hack =
|
let failedHack (ctx : IDiscordContext) attacker defender (hack : HackItem) =
|
||||||
|
let (item, power, hackClass, cooldown) = hack
|
||||||
async {
|
async {
|
||||||
let lostAmount = if hack.Power < int attacker.Bank then hack.Power else int attacker.Bank
|
let lostAmount = if power < int attacker.Bank then power else int attacker.Bank
|
||||||
let msg = $"Hack failed! {defender.Name} was able to mount a successful defense! You lost {lostAmount} $GBT!"
|
let msg = $"Hack failed! {defender.Name} was able to mount a successful defense! You lost {lostAmount} $GBT!"
|
||||||
do! sendFollowUpMessage ctx msg
|
do! sendFollowUpMessage ctx msg
|
||||||
|
|
||||||
@ -155,7 +158,7 @@ let handleAttack (ctx : IDiscordContext) =
|
|||||||
executePlayerAction ctx (fun attacker -> async {
|
executePlayerAction ctx (fun attacker -> async {
|
||||||
let tokens = ctx.GetInteractionId().Split("-")
|
let tokens = ctx.GetInteractionId().Split("-")
|
||||||
let hackId = int tokens.[1]
|
let hackId = int tokens.[1]
|
||||||
let hack = Armory.getItem hackId
|
let item,_,_,_ as hackItem = Armory.getHackById hackId
|
||||||
let resultId , targetId = UInt64.TryParse tokens.[2]
|
let resultId , targetId = UInt64.TryParse tokens.[2]
|
||||||
let! resultTarget = DbService.tryFindPlayer GuildEnvironment.pgDb targetId
|
let! resultTarget = DbService.tryFindPlayer GuildEnvironment.pgDb targetId
|
||||||
|
|
||||||
@ -164,21 +167,21 @@ let handleAttack (ctx : IDiscordContext) =
|
|||||||
do! attacker
|
do! attacker
|
||||||
|> Player.removeExpiredActions
|
|> Player.removeExpiredActions
|
||||||
|> checkAlreadyHackedTarget defender
|
|> checkAlreadyHackedTarget defender
|
||||||
>>= checkPlayerOwnsWeapon hack
|
>>= checkPlayerOwnsWeapon item
|
||||||
>>= checkWeaponHasCooldown hack
|
>>= checkWeaponHasCooldown item
|
||||||
|> function
|
|> function
|
||||||
| Ok atkr ->
|
| Ok atkr ->
|
||||||
runHackerBattle defender hack
|
runHackerBattle defender hackItem
|
||||||
|> function
|
|> function
|
||||||
| false -> successfulHack ctx atkr defender hack
|
| false -> successfulHack ctx atkr defender hackItem
|
||||||
| true -> failedHack ctx attacker defender hack
|
| true -> failedHack ctx attacker defender hackItem
|
||||||
| Error msg -> Messaging.sendFollowUpMessage ctx msg
|
| Error msg -> Messaging.sendFollowUpMessage ctx msg
|
||||||
| _ -> do! Messaging.sendFollowUpMessage ctx "Error occurred processing attack"
|
| _ -> do! Messaging.sendFollowUpMessage ctx "Error occurred processing attack"
|
||||||
})
|
})
|
||||||
|
|
||||||
let defend (ctx : IDiscordContext) =
|
let defend (ctx : IDiscordContext) =
|
||||||
executePlayerAction ctx (fun player -> async {
|
executePlayerAction ctx (fun player -> async {
|
||||||
if Player.getShields player |> Array.length > 0 then
|
if Player.getShields player |> List.length > 0 then
|
||||||
let p = Player.removeExpiredActions player
|
let p = Player.removeExpiredActions player
|
||||||
let embed = Embeds.pickDefense "Defend" p false
|
let embed = Embeds.pickDefense "Defend" p false
|
||||||
do! ctx.FollowUp embed |> Async.AwaitTask
|
do! ctx.FollowUp embed |> Async.AwaitTask
|
||||||
@ -191,18 +194,18 @@ let handleDefense (ctx : IDiscordContext) =
|
|||||||
executePlayerAction ctx (fun player -> async {
|
executePlayerAction ctx (fun player -> async {
|
||||||
let tokens = ctx.GetInteractionId().Split("-")
|
let tokens = ctx.GetInteractionId().Split("-")
|
||||||
let shieldId = int tokens.[1]
|
let shieldId = int tokens.[1]
|
||||||
let shield = Armory.getItem shieldId
|
let item, shieldClass, cooldown as shield = Armory.getShields |> List.find (fun (item,_,_) -> item.Id = shieldId)
|
||||||
|
|
||||||
do! player
|
do! player
|
||||||
|> checkPlayerOwnsWeapon shield
|
|> checkPlayerOwnsWeapon item
|
||||||
>>= checkPlayerHasShieldSlotsAvailable shield
|
>>= checkPlayerHasShieldSlotsAvailable
|
||||||
>>= checkWeaponHasCooldown shield
|
>>= checkWeaponHasCooldown item
|
||||||
|> handleResultWithResponse ctx (fun p -> async {
|
|> handleResultWithResponse ctx (fun p -> async {
|
||||||
let embed = Embeds.responseCreatedShield shield
|
let embed = Embeds.responseCreatedShield shield
|
||||||
do! ctx.FollowUp embed |> Async.AwaitTask
|
do! ctx.FollowUp embed |> Async.AwaitTask
|
||||||
let defense = {
|
let defense = {
|
||||||
Type = Shielding shieldId
|
Type = Shielding shieldId
|
||||||
Cooldown = shield.Cooldown
|
Cooldown = cooldown
|
||||||
Timestamp = DateTime.UtcNow
|
Timestamp = DateTime.UtcNow
|
||||||
}
|
}
|
||||||
do! DbService.updatePlayer GuildEnvironment.pgDb p
|
do! DbService.updatePlayer GuildEnvironment.pgDb p
|
||||||
|
@ -15,30 +15,31 @@ let checkHasSufficientFunds (item : Item) player =
|
|||||||
else Error $"You do not have sufficient funds to buy this item! Current balance: {player.Bank} GBT"
|
else Error $"You do not have sufficient funds to buy this item! Current balance: {player.Bank} GBT"
|
||||||
|
|
||||||
let checkAlreadyOwnsItem (item : Item) player =
|
let checkAlreadyOwnsItem (item : Item) player =
|
||||||
if player.Inventory |> Array.exists (fun w -> item.Id = w.Id)
|
if player.Inventory |> List.exists (fun w -> item.Id = w.Id)
|
||||||
then Error $"You already own {item.Name}!"
|
then Error $"You already own {item.Name}!"
|
||||||
else Ok player
|
else Ok player
|
||||||
|
|
||||||
let checkSoldItemAlready (item : Item) player =
|
let checkSoldItemAlready item player =
|
||||||
if player.Inventory |> Array.exists (fun w -> item.Id = w.Id)
|
if player.Inventory |> List.exists (fun i -> item.Id = i.Id)
|
||||||
then Ok player
|
then Ok player
|
||||||
else Error $"{item.Name} not found in your arsenal! Looks like you sold it already."
|
else Error $"{item.Name} not found in your inventory! Looks like you sold it already."
|
||||||
|
|
||||||
let checkHasItemsInArsenal itemType player =
|
let checkHasItemsInArsenal itemType items player =
|
||||||
if player.Inventory |> Array.filter (fun i -> i.Type = itemType ) |> Array.length > 0
|
if List.isEmpty items |> not
|
||||||
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} in your arsenal to sell!"
|
||||||
|
|
||||||
let buy itemType (ctx : IDiscordContext) =
|
let buy getItems (ctx : IDiscordContext) =
|
||||||
executePlayerAction ctx (fun player -> async {
|
executePlayerAction ctx (fun player -> async {
|
||||||
let itemStore = Embeds.getBuyItemsEmbed player itemType Armory.battleItems
|
let itemStore = Embeds.getBuyItemsEmbed (getItems player.Inventory) (getItems Armory.battleItems)
|
||||||
do! ctx.FollowUp itemStore |> Async.AwaitTask
|
do! ctx.FollowUp itemStore |> Async.AwaitTask
|
||||||
})
|
})
|
||||||
|
|
||||||
let sell itemType (ctx : IDiscordContext) =
|
let sell itemType getItems (ctx : IDiscordContext) =
|
||||||
executePlayerAction ctx (fun player -> async {
|
executePlayerAction ctx (fun player -> async {
|
||||||
match checkHasItemsInArsenal itemType player with
|
let items = getItems player
|
||||||
| Ok _ -> let itemStore = Embeds.getSellEmbed itemType player
|
match checkHasItemsInArsenal itemType items player with
|
||||||
|
| Ok _ -> let itemStore = Embeds.getSellEmbed items
|
||||||
do! ctx.FollowUp(itemStore) |> Async.AwaitTask
|
do! ctx.FollowUp(itemStore) |> Async.AwaitTask
|
||||||
| Error e -> do! sendFollowUpMessage ctx e
|
| Error e -> do! sendFollowUpMessage ctx e
|
||||||
})
|
})
|
||||||
@ -46,13 +47,13 @@ let sell itemType (ctx : IDiscordContext) =
|
|||||||
// TODO: When you buy a shield, prompt the user to activate it
|
// TODO: When you buy a shield, prompt the user to activate it
|
||||||
let handleBuyItem (ctx : IDiscordContext) itemId =
|
let handleBuyItem (ctx : IDiscordContext) itemId =
|
||||||
executePlayerAction ctx (fun player -> async {
|
executePlayerAction ctx (fun player -> async {
|
||||||
let item = Armory.battleItems |> Array.find (fun w -> w.Id = itemId)
|
let item = Armory.getItem itemId
|
||||||
do! player
|
do! player
|
||||||
|> checkHasSufficientFunds item
|
|> checkHasSufficientFunds item
|
||||||
>>= checkAlreadyOwnsItem item
|
>>= checkAlreadyOwnsItem item
|
||||||
|> handleResultWithResponse ctx (fun player -> async {
|
|> handleResultWithResponse ctx (fun player -> async {
|
||||||
let newBalance = player.Bank - item.Price
|
let newBalance = player.Bank - item.Price
|
||||||
let p = { player with Bank = newBalance ; Inventory = Array.append [| item |] player.Inventory }
|
let p = { player with Bank = newBalance ; Inventory = item::player.Inventory }
|
||||||
do! DbService.updatePlayer GuildEnvironment.pgDb p |> Async.Ignore
|
do! DbService.updatePlayer GuildEnvironment.pgDb p |> Async.Ignore
|
||||||
do! sendFollowUpMessage ctx $"Successfully purchased {item.Name}! You now have {newBalance} 💰$GBT remaining"
|
do! sendFollowUpMessage ctx $"Successfully purchased {item.Name}! You now have {newBalance} 💰$GBT remaining"
|
||||||
})
|
})
|
||||||
@ -68,7 +69,7 @@ let handleSell (ctx : IDiscordContext) itemId =
|
|||||||
let updatedPlayer = {
|
let updatedPlayer = {
|
||||||
player with
|
player with
|
||||||
Bank = player.Bank + item.Price
|
Bank = player.Bank + item.Price
|
||||||
Inventory = player.Inventory |> Array.filter (fun i -> i.Id <> itemId)
|
Inventory = player.Inventory |> List.filter (fun i -> i.Id <> itemId)
|
||||||
}
|
}
|
||||||
do!
|
do!
|
||||||
[ DbService.updatePlayer GuildEnvironment.pgDb updatedPlayer |> Async.Ignore
|
[ DbService.updatePlayer GuildEnvironment.pgDb updatedPlayer |> Async.Ignore
|
||||||
@ -76,7 +77,6 @@ let handleSell (ctx : IDiscordContext) itemId =
|
|||||||
sendFollowUpMessage ctx $"Sold {item.Type} {item.Name} for {item.Price}! Current Balance: {updatedPlayer.Bank}" ]
|
sendFollowUpMessage ctx $"Sold {item.Type} {item.Name} for {item.Price}! Current Balance: {updatedPlayer.Bank}" ]
|
||||||
|> Async.Parallel
|
|> Async.Parallel
|
||||||
|> Async.Ignore
|
|> Async.Ignore
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -108,14 +108,14 @@ type Store() =
|
|||||||
}
|
}
|
||||||
|
|
||||||
[<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 (DiscordInteractionContext(ctx)) (buy ItemType.Hack)
|
member _.BuyHack (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (buy Armory.getHackItems)
|
||||||
|
|
||||||
[<SlashCommand("buy-shield", "Purchase a hack shield so you can protect your GoodBoyTokenz")>]
|
[<SlashCommand("buy-shield", "Purchase a hack shield so you can protect your GoodBoyTokenz")>]
|
||||||
member this.BuyShield (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (buy ItemType.Shield)
|
member this.BuyShield (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (buy Armory.getShieldItems)
|
||||||
|
|
||||||
[<SlashCommand("sell-hack", "Sell a hack for GoodBoyTokenz")>]
|
[<SlashCommand("sell-hack", "Sell a hack for GoodBoyTokenz")>]
|
||||||
member this.SellHack (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (sell ItemType.Hack)
|
member this.SellHack (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (sell "Hacks" Player.getHackItems)
|
||||||
|
|
||||||
[<SlashCommand("sell-shield", "Sell a shield for GoodBoyTokenz")>]
|
[<SlashCommand("sell-shield", "Sell a shield for GoodBoyTokenz")>]
|
||||||
member this.SellShield (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (sell ItemType.Shield)
|
member this.SellShield (ctx : InteractionContext) = enforceChannel (DiscordInteractionContext(ctx)) (sell "Shields" Player.getShieldItems)
|
||||||
|
|
||||||
|
@ -128,7 +128,9 @@ let steal target amount (ctx : IDiscordContext) =
|
|||||||
>>= checkPrizeRequestZero amount
|
>>= checkPrizeRequestZero amount
|
||||||
|> handleResultWithResponse ctx (fun _ -> async {
|
|> handleResultWithResponse ctx (fun _ -> async {
|
||||||
let cappedPrize , winPercentage , wasCapped =
|
let cappedPrize , winPercentage , wasCapped =
|
||||||
calculateWinPercentage amount (int victim.Bank) thief.Traits.Strength victim.Traits.Strength
|
// calculateWinPercentage amount (int victim.Bank) thief.Stats.Strength victim.Stats.Strength
|
||||||
|
// TODO: Readd stats
|
||||||
|
calculateWinPercentage amount (int victim.Bank) 0 0
|
||||||
|
|
||||||
let chance = int (winPercentage * 100.0)
|
let chance = int (winPercentage * 100.0)
|
||||||
let buttons =
|
let buttons =
|
||||||
@ -138,7 +140,8 @@ let steal target amount (ctx : IDiscordContext) =
|
|||||||
|
|
||||||
let cappedMsg = if wasCapped then $"They only have {cappedPrize} $GBT though... " else ""
|
let cappedMsg = if wasCapped then $"They only have {cappedPrize} $GBT though... " else ""
|
||||||
let strengthMsg =
|
let strengthMsg =
|
||||||
match thief.Traits.Strength - victim.Traits.Strength with
|
// TODO: Readd stats
|
||||||
|
match 0 - 0 with
|
||||||
| diff when diff < -50 -> "much stronger"
|
| diff when diff < -50 -> "much stronger"
|
||||||
| diff when diff < 0 -> "stronger"
|
| diff when diff < 0 -> "stronger"
|
||||||
| diff when diff < 50 -> "weaker"
|
| diff when diff < 50 -> "weaker"
|
||||||
@ -161,7 +164,8 @@ let handleSteal (ctx : IDiscordContext) =
|
|||||||
let targetId = uint64 tokens.[2]
|
let targetId = uint64 tokens.[2]
|
||||||
let targetName = tokens.[3]
|
let targetName = tokens.[3]
|
||||||
let amount = int tokens.[4]
|
let amount = int tokens.[4]
|
||||||
let prize , winPercentage , _ = calculateWinPercentage amount (int victim.Bank) thief.Traits.Strength victim.Traits.Strength
|
// TODO: Readd stats
|
||||||
|
let prize , winPercentage , _ = calculateWinPercentage amount (int victim.Bank) 0 0
|
||||||
let prize = int prize * 1<GBT>
|
let prize = int prize * 1<GBT>
|
||||||
|
|
||||||
let rand = Random(Guid.NewGuid().GetHashCode())
|
let rand = Random(Guid.NewGuid().GetHashCode())
|
||||||
|
@ -9,8 +9,8 @@ open Degenz.Messaging
|
|||||||
|
|
||||||
let trainerAchievement = "FINISHED_TRAINER"
|
let trainerAchievement = "FINISHED_TRAINER"
|
||||||
let Sensei = { Id = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" }
|
let Sensei = { Id = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" }
|
||||||
let defaultHack = Armory.battleItems |> Array.find (fun i -> i.Id = int HackId.Virus)
|
let defaultHackItem, hackPower, hackClass, hackCooldown as defaultHack = Armory.getHackById (int ItemId.Virus)
|
||||||
let defaultShield = Armory.battleItems |> Array.find (fun i -> i.Id = int ShieldId.Firewall)
|
let defaultShieldItem, shieldClass, shieldCooldown as defaultShield = Armory.getShieldById (int ItemId.Firewall)
|
||||||
|
|
||||||
let TrainerEvents = [|
|
let TrainerEvents = [|
|
||||||
{ Timestamp = System.DateTime.UtcNow
|
{ Timestamp = System.DateTime.UtcNow
|
||||||
@ -19,10 +19,10 @@ let TrainerEvents = [|
|
|||||||
Adversary = Sensei
|
Adversary = Sensei
|
||||||
Success = true
|
Success = true
|
||||||
IsInstigator = true
|
IsInstigator = true
|
||||||
HackId = defaultHack.Id } }
|
HackId = defaultHackItem.Id } }
|
||||||
{ Timestamp = System.DateTime.UtcNow
|
{ Timestamp = System.DateTime.UtcNow
|
||||||
Cooldown = defaultShield.Cooldown
|
Cooldown = shieldCooldown
|
||||||
Type = Shielding defaultShield.Id }
|
Type = Shielding defaultShieldItem.Id }
|
||||||
|]
|
|]
|
||||||
|
|
||||||
let sendInitialEmbed (client : DiscordClient) =
|
let sendInitialEmbed (client : DiscordClient) =
|
||||||
@ -52,7 +52,7 @@ let handleTrainerStep1 (ctx : IDiscordContext) =
|
|||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
let msg = "Beautopia© is a dangerous place... quick, put up a SHIELD 🛡 before another Degen hacks you, and takes your 💰$GBT.\n\n"
|
let msg = "Beautopia© is a dangerous place... quick, put up a SHIELD 🛡 before another Degen hacks you, and takes your 💰$GBT.\n\n"
|
||||||
+ "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 - `{defaultShield.Name}`\n"
|
+ $"Type the `/shield` command now, then select - `{defaultShieldItem.Name}`\n"
|
||||||
let builder =
|
let builder =
|
||||||
DiscordInteractionResponseBuilder()
|
DiscordInteractionResponseBuilder()
|
||||||
.WithContent(msg)
|
.WithContent(msg)
|
||||||
@ -66,7 +66,7 @@ let defend (ctx : IDiscordContext) =
|
|||||||
do! Messaging.defer ctx
|
do! Messaging.defer ctx
|
||||||
let m = ctx.GetDiscordMember()
|
let m = ctx.GetDiscordMember()
|
||||||
let name = if System.String.IsNullOrEmpty m.Nickname then m.DisplayName else m.Nickname
|
let name = if System.String.IsNullOrEmpty m.Nickname then m.DisplayName else m.Nickname
|
||||||
let embed = Embeds.pickDefense "Trainer-2" { PlayerData.empty with Inventory = [| defaultShield |] ; Name = name } true
|
let embed = Embeds.pickDefense "Trainer-2" { PlayerData.empty with Inventory = [ defaultShieldItem ] ; Name = name } true
|
||||||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||||||
} |> Async.StartAsTask :> Task
|
} |> Async.StartAsTask :> Task
|
||||||
|
|
||||||
@ -83,17 +83,16 @@ let handleDefense (ctx : IDiscordContext) =
|
|||||||
|
|
||||||
let sendMessage' = sendFollowUpMessage ctx
|
let sendMessage' = sendFollowUpMessage ctx
|
||||||
let tokens = ctx.GetInteractionId().Split("-")
|
let tokens = ctx.GetInteractionId().Split("-")
|
||||||
let shieldId = enum<ShieldId>(int tokens.[2])
|
let shieldId = enum<ItemId>(int tokens.[2])
|
||||||
let shield = Armory.getItem (int shieldId)
|
|
||||||
let playerName = tokens.[4]
|
let playerName = tokens.[4]
|
||||||
let embed = Embeds.responseCreatedShield shield
|
let embed = Embeds.responseCreatedShield defaultShield
|
||||||
do! ctx.FollowUp embed |> Async.AwaitTask
|
do! ctx.FollowUp embed |> Async.AwaitTask
|
||||||
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 with **{defaultHack.Name}**"
|
do! sendMessage' $"Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now with **{defaultHackItem.Name}**"
|
||||||
do! Async.Sleep 5000
|
do! Async.Sleep 5000
|
||||||
do! sendMessage' $"❌ HACKING FAILED!\n\n{playerName} defended hack from <@{Sensei.Id}>!"
|
do! sendMessage' $"❌ HACKING FAILED!\n\n{playerName} defended hack from <@{Sensei.Id}>!"
|
||||||
do! Async.Sleep 4000
|
do! Async.Sleep 4000
|
||||||
do! sendFollowUpMessageWithButton ctx (handleDefenseMsg defaultHack.Name)
|
do! sendFollowUpMessageWithButton ctx (handleDefenseMsg defaultHackItem.Name)
|
||||||
} |> Async.StartAsTask :> Task
|
} |> Async.StartAsTask :> Task
|
||||||
|
|
||||||
let handleTrainerStep3 (ctx : IDiscordContext) =
|
let handleTrainerStep3 (ctx : IDiscordContext) =
|
||||||
@ -104,7 +103,7 @@ let handleTrainerStep3 (ctx : IDiscordContext) =
|
|||||||
.WithContent
|
.WithContent
|
||||||
( "Now let’s **HACK** 💻... I want you to **HACK ME**!\n\n"
|
( "Now let’s **HACK** 💻... I want you to **HACK ME**!\n\n"
|
||||||
+ "To **hack**, you need to run the `/hack` slash command.\n"
|
+ "To **hack**, you need to run the `/hack` slash command.\n"
|
||||||
+ $"Type the `/hack` command now, then choose me - <@{Sensei.Id}> as your target, and select `{defaultHack.Name}`")
|
+ $"Type the `/hack` command now, then choose me - <@{Sensei.Id}> as your target, and select `{defaultHackItem.Name}`")
|
||||||
|
|
||||||
do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, builder) |> Async.AwaitTask
|
do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, builder) |> Async.AwaitTask
|
||||||
} |> Async.StartAsTask :> Task
|
} |> Async.StartAsTask :> Task
|
||||||
@ -117,7 +116,7 @@ let hack (target : DiscordUser) (ctx : IDiscordContext) =
|
|||||||
match isRightTarget with
|
match isRightTarget with
|
||||||
| true ->
|
| true ->
|
||||||
let bot = { PlayerData.empty with DiscordId = Sensei.Id ; Name = Sensei.Name }
|
let bot = { PlayerData.empty with DiscordId = Sensei.Id ; Name = Sensei.Name }
|
||||||
let embed = Embeds.pickHack "Trainer-4" { PlayerData.empty with Inventory = [| defaultHack |] } bot true
|
let embed = Embeds.pickHack "Trainer-4" { PlayerData.empty with Inventory = [ defaultHackItem ] } bot true
|
||||||
|
|
||||||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||||||
| false ->
|
| false ->
|
||||||
@ -133,7 +132,7 @@ let handleHack (ctx : IDiscordContext) =
|
|||||||
PlayerInteractions.executePlayerAction ctx (fun player -> async {
|
PlayerInteractions.executePlayerAction ctx (fun player -> async {
|
||||||
let sendMessage' = sendFollowUpMessage ctx
|
let sendMessage' = sendFollowUpMessage ctx
|
||||||
do! Async.Sleep 1000
|
do! Async.Sleep 1000
|
||||||
let embed = Embeds.responseSuccessfulHack false Sensei.Id defaultHack.Power defaultHack
|
let embed = Embeds.responseSuccessfulHack false Sensei.Id hackPower defaultHackItem
|
||||||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||||||
do! Async.Sleep 4000
|
do! Async.Sleep 4000
|
||||||
do! sendMessage'
|
do! sendMessage'
|
||||||
@ -151,7 +150,7 @@ let handleHack (ctx : IDiscordContext) =
|
|||||||
do! DbService.addAchievement GuildEnvironment.pgDb player.DiscordId trainerAchievement
|
do! DbService.addAchievement GuildEnvironment.pgDb player.DiscordId trainerAchievement
|
||||||
|> Async.Ignore
|
|> Async.Ignore
|
||||||
|
|
||||||
sb.Append($"I'm going to gift you a hack,`{defaultHack.Name}` and a shield, `{defaultShield.Name}`") |> ignore
|
sb.Append($"I'm going to gift you a hack,`{defaultHackItem.Name}` and a shield, `{defaultShieldItem.Name}`") |> ignore
|
||||||
sb.Append(", you'll need em to survive\n\n") |> 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
|
sb.AppendLine("To finish your training and collect the loot, type the `/arsenal` command **NOW**") |> ignore
|
||||||
do! Async.Sleep 1000
|
do! Async.Sleep 1000
|
||||||
@ -166,12 +165,12 @@ let handleHack (ctx : IDiscordContext) =
|
|||||||
|
|
||||||
let handleArsenal (ctx : IDiscordContext) =
|
let handleArsenal (ctx : IDiscordContext) =
|
||||||
PlayerInteractions.executePlayerAction ctx (fun player -> async {
|
PlayerInteractions.executePlayerAction ctx (fun player -> async {
|
||||||
let hasStockWeapons = Player.getHacks player |> Array.exists (fun item -> item.Id = defaultHack.Id)
|
let hasStockWeapons = Player.getHackItems player |> List.exists (fun item -> item.Id = defaultHackItem.Id)
|
||||||
let updatedPlayer =
|
let updatedPlayer =
|
||||||
if not hasStockWeapons then {
|
if not hasStockWeapons then {
|
||||||
Player.removeExpiredActions player with
|
Player.removeExpiredActions player with
|
||||||
Events = TrainerEvents |> Array.append player.Events
|
Events = TrainerEvents |> Array.append player.Events
|
||||||
Inventory = [| defaultHack ; defaultShield |] |> Array.append player.Inventory
|
Inventory = defaultHackItem::defaultShieldItem::player.Inventory
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Player.removeExpiredActions player
|
Player.removeExpiredActions player
|
||||||
@ -188,7 +187,7 @@ let handleArsenal (ctx : IDiscordContext) =
|
|||||||
let! completed = DbService.checkHasAchievement GuildEnvironment.pgDb player.DiscordId trainerAchievement
|
let! completed = DbService.checkHasAchievement GuildEnvironment.pgDb player.DiscordId trainerAchievement
|
||||||
if not completed then
|
if not completed then
|
||||||
do! Async.Sleep 3000
|
do! Async.Sleep 3000
|
||||||
let rewards = [ $"{defaultHack.Name} Hack" ; $"{defaultShield.Name} Shield" ]
|
let rewards = [ $"{defaultHackItem.Name} Hack" ; $"{defaultShieldItem.Name} Shield" ]
|
||||||
let embed = Embeds.getAchievementEmbed rewards "You completed the Training Dojo and collected loot." trainerAchievement
|
let embed = Embeds.getAchievementEmbed rewards "You completed the Training Dojo and collected loot." trainerAchievement
|
||||||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||||||
do! Async.Sleep 2000
|
do! Async.Sleep 2000
|
||||||
|
@ -2,91 +2,76 @@
|
|||||||
{
|
{
|
||||||
"Id": 0,
|
"Id": 0,
|
||||||
"Name": "Virus",
|
"Name": "Virus",
|
||||||
"Type": 0,
|
|
||||||
"Price": 0,
|
"Price": 0,
|
||||||
"Power": 25,
|
"Type": {
|
||||||
"Cooldown": 1,
|
"Case": "Hack",
|
||||||
"Class": 0,
|
"Fields": [
|
||||||
"Attributes": {
|
25,
|
||||||
"Sell": false,
|
0,
|
||||||
"Buy": false,
|
1
|
||||||
"Consume": false,
|
]
|
||||||
"Drop": false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 1,
|
"Id": 1,
|
||||||
"Name": "RemoteAccess",
|
"Name": "RemoteAccess",
|
||||||
"Type": 0,
|
|
||||||
"Price": 500,
|
"Price": 500,
|
||||||
"Power": 75,
|
"Type": {
|
||||||
"Cooldown": 3,
|
"Case": "Hack",
|
||||||
"Class": 1,
|
"Fields": [
|
||||||
"Attributes": {
|
75,
|
||||||
"Sell": true,
|
1,
|
||||||
"Buy": true,
|
3
|
||||||
"Consume": false,
|
]
|
||||||
"Drop": true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 2,
|
"Id": 2,
|
||||||
"Name": "Worm",
|
"Name": "Worm",
|
||||||
"Type": 0,
|
|
||||||
"Price": 5000,
|
"Price": 5000,
|
||||||
"Power": 150,
|
"Type": {
|
||||||
"Cooldown": 5,
|
"Case": "Hack",
|
||||||
"Class": 2,
|
"Fields": [
|
||||||
"Attributes": {
|
150,
|
||||||
"Sell": true,
|
2,
|
||||||
"Buy": true,
|
5
|
||||||
"Consume": false,
|
]
|
||||||
"Drop": true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 6,
|
"Id": 6,
|
||||||
"Name": "Firewall",
|
"Name": "Firewall",
|
||||||
"Type": 1,
|
|
||||||
"Price": 0,
|
"Price": 0,
|
||||||
"Power": 10,
|
"Type": {
|
||||||
"Class": 0,
|
"Case": "Shield",
|
||||||
"Cooldown": 120,
|
"Fields": [
|
||||||
"Attributes": {
|
0,
|
||||||
"Sell": false,
|
120
|
||||||
"Buy": false,
|
]
|
||||||
"Consume": false,
|
|
||||||
"Drop": false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 7,
|
"Id": 7,
|
||||||
"Name": "Encryption",
|
"Name": "Encryption",
|
||||||
"Type": 1,
|
|
||||||
"Price": 500,
|
"Price": 500,
|
||||||
"Power": 50,
|
"Type": {
|
||||||
"Class": 1,
|
"Case": "Shield",
|
||||||
"Cooldown": 240,
|
"Fields": [
|
||||||
"Attributes": {
|
1,
|
||||||
"Sell": true,
|
240
|
||||||
"Buy": true,
|
]
|
||||||
"Consume": false,
|
|
||||||
"Drop": true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Id": 8,
|
"Id": 8,
|
||||||
"Name": "Cypher",
|
"Name": "Cypher",
|
||||||
"Type": 1,
|
|
||||||
"Price": 5000,
|
"Price": 5000,
|
||||||
"Power": 80,
|
"Type": {
|
||||||
"Class": 2,
|
"Case": "Shield",
|
||||||
"Cooldown": 380,
|
"Fields": [
|
||||||
"Attributes": {
|
2,
|
||||||
"Sell": true,
|
380
|
||||||
"Buy": true,
|
]
|
||||||
"Consume": false,
|
|
||||||
"Drop": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -3,7 +3,6 @@ module Degenz.PlayerInteractions
|
|||||||
open System.Threading.Tasks
|
open System.Threading.Tasks
|
||||||
open DSharpPlus
|
open DSharpPlus
|
||||||
open DSharpPlus.Entities
|
open DSharpPlus.Entities
|
||||||
open DSharpPlus.SlashCommands
|
|
||||||
open Degenz.Messaging
|
open Degenz.Messaging
|
||||||
open Degenz.DbService
|
open Degenz.DbService
|
||||||
|
|
||||||
@ -57,52 +56,3 @@ let handleResultWithResponse ctx fn (player : Result<PlayerData, string>) =
|
|||||||
match player with
|
match player with
|
||||||
| Ok p -> fn p
|
| Ok p -> fn p
|
||||||
| Error e -> async { do! Messaging.sendFollowUpMessage ctx e }
|
| Error e -> async { do! Messaging.sendFollowUpMessage ctx e }
|
||||||
|
|
||||||
module Commands =
|
|
||||||
let newPlayer nickname (membr : uint64) =
|
|
||||||
let rand = System.Random(System.Guid.NewGuid().GetHashCode())
|
|
||||||
let randHack = rand.Next(0, 3)
|
|
||||||
let randShield = rand.Next(6, 9)
|
|
||||||
let hack = Armory.battleItems |> Array.find (fun i -> i.Id = randHack)
|
|
||||||
let shield = Armory.battleItems |> Array.find (fun i -> i.Id = randShield)
|
|
||||||
|
|
||||||
{ DiscordId = membr
|
|
||||||
Name = nickname
|
|
||||||
Inventory = [| hack ; shield |]
|
|
||||||
Events = [||]
|
|
||||||
// XP = 0
|
|
||||||
// Achievements = [||]
|
|
||||||
Traits = PlayerTraits.empty
|
|
||||||
Bank = 100<GBT> }
|
|
||||||
|
|
||||||
let upsertPlayer discordId =
|
|
||||||
async {
|
|
||||||
let! player = DbService.tryFindPlayer GuildEnvironment.pgDb discordId
|
|
||||||
let! newPlayer =
|
|
||||||
match player with
|
|
||||||
| Some _ -> async.Return false
|
|
||||||
| None ->
|
|
||||||
async {
|
|
||||||
// do! newPlayer "" discordId |> DbService.insertNewPlayer
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return newPlayer
|
|
||||||
}
|
|
||||||
|
|
||||||
[<CLIMutable>]
|
|
||||||
type LeaderboardEntry = {
|
|
||||||
Position : string
|
|
||||||
Amount : string
|
|
||||||
Name : string
|
|
||||||
}
|
|
||||||
|
|
||||||
type PlayerInteractions() =
|
|
||||||
inherit ApplicationCommandModule ()
|
|
||||||
|
|
||||||
[<SlashCommand("redpill", "Take the redpill and become a hacker")>]
|
|
||||||
member _.AddHackerRole (ctx : InteractionContext) = Commands.upsertPlayer ctx.Member.Id
|
|
||||||
|
|
||||||
// [<SlashCommand("leaderboard", "View the current list of players ranked by highest earnings")>]
|
|
||||||
// member this.Leaderboard (ctx : InteractionContext) = Commands.leaderboard ctx
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ open DSharpPlus.Entities
|
|||||||
|
|
||||||
type RewardType =
|
type RewardType =
|
||||||
| Currency of int<GBT>
|
| Currency of int<GBT>
|
||||||
| RandomItem of itemType : ItemType * amount : int
|
// | RandomItem of itemType : ItemType * amount : int
|
||||||
| SpecialItem of id : int
|
| SpecialItem of id : int
|
||||||
|
|
||||||
[<Literal>]
|
[<Literal>]
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Shared\Shared.fsproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="..\.paket\Paket.Restore.targets" />
|
|
||||||
</Project>
|
|
@ -1,8 +0,0 @@
|
|||||||
FSharp.Core
|
|
||||||
DSharpPlus
|
|
||||||
// DSharpPlus.CommandsNext
|
|
||||||
// DSharpPlus.Interactivity
|
|
||||||
DSharpPlus.SlashCommands
|
|
||||||
|
|
||||||
MongoDB.Driver
|
|
||||||
Npgsql.FSharp
|
|
@ -1,9 +0,0 @@
|
|||||||
namespace Degenz
|
|
||||||
|
|
||||||
open System
|
|
||||||
open System.Threading.Tasks
|
|
||||||
open DSharpPlus
|
|
||||||
open DSharpPlus.Entities
|
|
||||||
open DSharpPlus.EventArgs
|
|
||||||
open DSharpPlus.SlashCommands
|
|
||||||
open Newtonsoft.Json
|
|
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="paket.references" />
|
|
||||||
<Compile Include="Shared.fs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="..\.paket\Paket.Restore.targets" />
|
|
||||||
</Project>
|
|
@ -1,3 +0,0 @@
|
|||||||
FSharp.Core
|
|
||||||
DSharpPlus
|
|
||||||
DSharpPlus.SlashCommands
|
|
Loading…
x
Reference in New Issue
Block a user