Refactor for new Item design
This commit is contained in:
parent
7881acab4f
commit
bf68d0ae4a
@ -108,19 +108,19 @@ let sellWeaponCommand (discordMember : DiscordMember) weaponType =
|
||||
]
|
||||
track "Sell Weapon Command Invoked" discordMember.Id data
|
||||
|
||||
let buyWeaponButton (discordMember : DiscordMember) (weapon : ItemDetails) =
|
||||
let buyWeaponButton (discordMember : DiscordMember) itemName itemPrice =
|
||||
let data = [
|
||||
"user_display_name" , discordMember.Username
|
||||
"weapon_name" , weapon.Name
|
||||
"weapon_price" , string weapon.Price
|
||||
"weapon_name" , itemName
|
||||
"weapon_price" , string itemPrice
|
||||
]
|
||||
track "Buy Weapon Button Clicked" discordMember.Id data
|
||||
|
||||
let sellWeaponButton (discordMember : DiscordMember) (weapon : ItemDetails) =
|
||||
let sellWeaponButton (discordMember : DiscordMember) (weapon : Item) price =
|
||||
let data = [
|
||||
"user_display_name" , discordMember.Username
|
||||
"weapon_name" , weapon.Name
|
||||
"weapon_price" , string weapon.Price
|
||||
"weapon_price" , string price
|
||||
]
|
||||
track "Sell Weapon Button Clicked" discordMember.Id data
|
||||
|
||||
|
@ -7,39 +7,38 @@ open Degenz
|
||||
open Newtonsoft.Json
|
||||
|
||||
module Armory =
|
||||
let weapons : ItemDetails list =
|
||||
let weapons : Inventory =
|
||||
let file = System.IO.File.ReadAllText("Items.json")
|
||||
// let file = System.IO.File.ReadAllText("Bot/Items.json")
|
||||
JsonConvert.DeserializeObject<ItemDetails array>(file)
|
||||
|> Array.toList
|
||||
JsonConvert.DeserializeObject<Inventory>(file)
|
||||
|
||||
module Inventory =
|
||||
let getItemsByType itemType inventory =
|
||||
match itemType with
|
||||
| ItemType.Hack -> inventory |> List.filter (fun item -> match item with Hack _ -> true | _ -> false)
|
||||
| ItemType.Shield -> inventory |> List.filter (fun item -> match item with Shield _ -> true | _ -> false)
|
||||
| ItemType.Food -> inventory |> List.filter (fun item -> match item with Food _ -> true | _ -> false)
|
||||
| ItemType.Accessory -> inventory |> List.filter (fun item -> match item with Accessory _ -> true | _ -> false)
|
||||
// let getItemsByType itemType inventory =
|
||||
// match itemType with
|
||||
// | ItemType.Hack -> inventory |> List.filter (fun item -> match item with Hack _ -> true | _ -> false)
|
||||
// | ItemType.Shield -> inventory |> List.filter (fun item -> match item with Shield _ -> true | _ -> false)
|
||||
// | ItemType.Food -> inventory |> List.filter (fun item -> match item with Food _ -> true | _ -> false)
|
||||
// | ItemType.Accessory -> inventory |> List.filter (fun item -> match item with Accessory _ -> true | _ -> false)
|
||||
|
||||
let findItemById id (inventory : Inventory) = inventory |> List.find (fun item -> item.Id = id)
|
||||
|
||||
let findHackById id inventory =
|
||||
inventory |> List.pick (fun item -> match item with | Hack h -> (if h.Item.Id = id then Some h else None) | _ -> None)
|
||||
let findShieldById id inventory =
|
||||
inventory |> List.pick (fun item -> match item with | Shield s -> (if s.Item.Id = id then Some s else None) | _ -> None)
|
||||
let findFoodById id inventory =
|
||||
inventory |> List.pick (fun item -> match item with | Food f -> (if f.Item.Id = id then Some f else None) | _ -> None)
|
||||
let findAccessoryById id inventory =
|
||||
inventory |> List.pick (fun item -> match item with | Accessory a -> (if a.Item.Id = id then Some a else None) | _ -> None)
|
||||
|
||||
let getHacks inventory =
|
||||
inventory |> List.choose (fun item -> match item with | Hack h -> Some h | _ -> None)
|
||||
let getShields inventory =
|
||||
inventory |> List.choose (fun item -> match item with | Shield s -> Some s | _ -> None)
|
||||
let getFoods inventory =
|
||||
inventory |> List.choose (fun item -> match item with | Food f -> Some f | _ -> None)
|
||||
let getAccessories inventory =
|
||||
inventory |> List.choose (fun item -> match item with | Accessory a -> Some a | _ -> None)
|
||||
// let findHackById id inventory =
|
||||
// inventory |> List.pick (fun item -> match item with | Hack h -> (if h.Item.Id = id then Some h else None) | _ -> None)
|
||||
// let findShieldById id inventory =
|
||||
// inventory |> List.pick (fun item -> match item with | Shield s -> (if s.Item.Id = id then Some s else None) | _ -> None)
|
||||
// let findFoodById id inventory =
|
||||
// inventory |> List.pick (fun item -> match item with | Food f -> (if f.Item.Id = id then Some f else None) | _ -> None)
|
||||
// let findAccessoryById id inventory =
|
||||
// inventory |> List.pick (fun item -> match item with | Accessory a -> (if a.Item.Id = id then Some a else None) | _ -> None)
|
||||
//
|
||||
// let getHacks inventory =
|
||||
// inventory |> List.choose (fun item -> match item with | Hack h -> Some h | _ -> None)
|
||||
// let getShields inventory =
|
||||
// inventory |> List.choose (fun item -> match item with | Shield s -> Some s | _ -> None)
|
||||
// let getFoods inventory =
|
||||
// inventory |> List.choose (fun item -> match item with | Food f -> Some f | _ -> None)
|
||||
// let getAccessories inventory =
|
||||
// inventory |> List.choose (fun item -> match item with | Accessory a -> Some a | _ -> None)
|
||||
|
||||
module WeaponClass =
|
||||
let SameTargetAttackCooldown = TimeSpan.FromHours(4)
|
||||
|
115
Bot/GameTypes.fs
115
Bot/GameTypes.fs
@ -89,89 +89,51 @@ type ItemType =
|
||||
| Food
|
||||
| Accessory
|
||||
|
||||
type ItemAttributes = {
|
||||
CanBuy : bool
|
||||
CanSell : bool
|
||||
CanConsume : bool
|
||||
CanTrade : bool
|
||||
CanDrop : bool
|
||||
type Effect =
|
||||
| Min of int
|
||||
| Max of int
|
||||
| Booster of int
|
||||
| RateMultiplier of float
|
||||
|
||||
type StatEffect = {
|
||||
TargetStat : StatId
|
||||
Effect : Effect
|
||||
}
|
||||
|
||||
type ItemAttribute =
|
||||
| Buyable of price : int<GBT>
|
||||
| Sellable of price : int<GBT>
|
||||
| Expireable of lifetime : int<mins>
|
||||
| Consumable of effects : StatEffect list
|
||||
| Passive of effects : StatEffect list
|
||||
| Droppable of chance : float
|
||||
| Tradeable of yes : unit
|
||||
| Attackable of power : int
|
||||
| Defendable of resistance : int
|
||||
| Classable of className : string
|
||||
| Stackable of max : int
|
||||
|
||||
let (|CanBuy|_|) itemAttrs = itemAttrs |> List.tryPick (function Buyable p -> Some p | _ -> None)
|
||||
let (|CanSell|_|) itemAttrs = itemAttrs |> List.tryPick (function Sellable p -> Some p | _ -> None)
|
||||
let (|CanExpire|_|) itemAttrs = itemAttrs |> List.tryPick (function Expireable l -> Some l | _ -> None)
|
||||
let (|CanConsume|_|) itemAttrs = itemAttrs |> List.tryPick (function Consumable es -> Some es | _ -> None)
|
||||
let (|CanPassive|_|) itemAttrs = itemAttrs |> List.tryPick (function Passive es -> Some es | _ -> None)
|
||||
let (|CanDrop|_|) itemAttrs = itemAttrs |> List.tryPick (function Droppable c -> Some c | _ -> None)
|
||||
let (|CanTrade|_|) itemAttrs = itemAttrs |> List.tryPick (function Tradeable () -> Some () | _ -> None)
|
||||
let (|CanAttack|_|) itemAttrs = itemAttrs |> List.tryPick (function Attackable p -> Some p | _ -> None)
|
||||
let (|CanDefend|_|) itemAttrs = itemAttrs |> List.tryPick (function Defendable r -> Some r | _ -> None)
|
||||
let (|CanClass|_|) itemAttrs = itemAttrs |> List.tryPick (function Classable c -> Some c | _ -> None)
|
||||
let (|CanStack|_|) itemAttrs = itemAttrs |> List.tryPick (function Stackable m -> Some m | _ -> None)
|
||||
|
||||
|
||||
type Item = {
|
||||
Id : int
|
||||
Name : string
|
||||
Price : int<GBT>
|
||||
MaxAllowed : int
|
||||
Attributes : ItemAttributes
|
||||
Type : ItemType
|
||||
Attributes : ItemAttribute list
|
||||
}
|
||||
|
||||
type HackItem = {
|
||||
Power : int
|
||||
Class : int
|
||||
Cooldown : int<mins>
|
||||
Item : Item
|
||||
}
|
||||
|
||||
type ShieldItem = {
|
||||
Class : int
|
||||
Cooldown : int<mins>
|
||||
Item : Item
|
||||
}
|
||||
|
||||
type FoodItem = {
|
||||
TargetStat : StatId
|
||||
BoostAmount : int
|
||||
Item : Item
|
||||
}
|
||||
|
||||
type AccessoryItem = {
|
||||
TargetStat : StatId
|
||||
FloorBoost : int
|
||||
CeilBoost : int
|
||||
Item : Item
|
||||
}
|
||||
|
||||
type MeleeWeapon = {
|
||||
BreakChance : float
|
||||
Item : Item
|
||||
}
|
||||
|
||||
type ItemDetails =
|
||||
| Hack of HackItem
|
||||
| Shield of ShieldItem
|
||||
| Food of FoodItem
|
||||
| Accessory of AccessoryItem
|
||||
member this.Id =
|
||||
match this with
|
||||
| Hack i -> i.Item.Id
|
||||
| Shield i -> i.Item.Id
|
||||
| Food i -> i.Item.Id
|
||||
| Accessory i -> i.Item.Id
|
||||
member this.Name =
|
||||
match this with
|
||||
| Hack i -> i.Item.Name
|
||||
| Shield i -> i.Item.Name
|
||||
| Food i -> i.Item.Name
|
||||
| Accessory i -> i.Item.Name
|
||||
member this.Price =
|
||||
match this with
|
||||
| Hack i -> i.Item.Price
|
||||
| Shield i -> i.Item.Price
|
||||
| Food i -> i.Item.Price
|
||||
| Accessory i -> i.Item.Price
|
||||
member this.getItem =
|
||||
match this with
|
||||
| Hack i -> i.Item
|
||||
| Shield i -> i.Item
|
||||
| Food i -> i.Item
|
||||
| Accessory i -> i.Item
|
||||
static member getClass = function
|
||||
| Hack i -> i.Class
|
||||
| Shield i -> i.Class
|
||||
| Food _ -> -1
|
||||
| Accessory _ -> -1
|
||||
|
||||
type Inventory = ItemDetails list
|
||||
type Inventory = Item list
|
||||
|
||||
type PlayerData = {
|
||||
DiscordId : uint64
|
||||
@ -195,3 +157,4 @@ with member this.toDiscordPlayer = { Id = this.DiscordId ; Name = this.Name }
|
||||
// XP = 0
|
||||
Bank = 0<GBT>
|
||||
Active = false }
|
||||
|
||||
|
@ -15,30 +15,33 @@ let getBuyItemsEmbed (playerInventory : Inventory) (storeInventory : Inventory)
|
||||
storeInventory
|
||||
|> List.map (fun item ->
|
||||
let embed = DiscordEmbedBuilder()
|
||||
match item with
|
||||
| Hack hack ->
|
||||
embed.AddField($"$GBT Reward |", string hack.Power, true)
|
||||
.AddField("Cooldown |", $"{TimeSpan.FromMinutes(int hack.Cooldown).Minutes} minutes", true)
|
||||
.WithThumbnail(Embeds.getItemIcon item.Id)
|
||||
|> ignore
|
||||
| Shield shield ->
|
||||
embed.AddField($"Strong against |", WeaponClass.getGoodAgainst shield.Class |> snd |> string, true)
|
||||
// .AddField($"Defensive Strength |", string item.Power, true)
|
||||
.AddField("Active For |", $"{TimeSpan.FromMinutes(int shield.Cooldown).Hours} hours", true)
|
||||
.WithThumbnail(Embeds.getItemIcon item.Id)
|
||||
|> ignore
|
||||
| Food food ->
|
||||
embed.AddField($"Stat |", $"{food.TargetStat}", true)
|
||||
.AddField($"Amount |", $"+{food.BoostAmount}", true) |> ignore
|
||||
| Accessory accessory ->
|
||||
embed.AddField($"Stat |", $"{accessory.TargetStat}", true) |> ignore
|
||||
if accessory.FloorBoost > 0 then
|
||||
embed.AddField($"Min Boost |", $"+{accessory.FloorBoost}", true) |> ignore
|
||||
if accessory.CeilBoost > 0 then
|
||||
embed.AddField($"Max Boost |", $"+{accessory.CeilBoost}", true) |> ignore
|
||||
match item.Attributes with
|
||||
| CanBuy price -> embed.AddField("Price 💰", (if price = 0<GBT> then "Free" else $"{price} $GBT"), true) |> ignore
|
||||
| CanAttack power ->
|
||||
let title = match item.Type with ItemType.Hack -> "$GBT Reward" | _ -> "Power"
|
||||
embed.AddField($"{title} |", string power, true) |> ignore
|
||||
| CanExpire time ->
|
||||
let title = match item.Type with ItemType.Hack -> "Cooldown" | ItemType.Shield -> "Active For" | _ -> "Expires"
|
||||
let ts = TimeSpan.FromMinutes(int time)
|
||||
let timeStr = if ts.Hours = 0 then $"{ts.Minutes} mins" else $"{ts.Hours} hours"
|
||||
embed.AddField($"{title} |", timeStr, true) |> ignore
|
||||
| CanConsume effects | CanPassive effects ->
|
||||
let fx =
|
||||
effects
|
||||
|> List.map (fun f ->
|
||||
match f.Effect with
|
||||
| Min i -> $"Min - {f.TargetStat}"
|
||||
| Max i -> $"Max - {f.TargetStat}"
|
||||
| Booster i ->
|
||||
let str = if i > 0 then "Boost" else "Penalty"
|
||||
$"{str} - {f.TargetStat}"
|
||||
| RateMultiplier i -> $"Multiplier - {f.TargetStat}")
|
||||
|> String.concat "\n"
|
||||
embed.AddField($"Effect - Amount |", $"{fx}", true) |> ignore
|
||||
| _ -> ()
|
||||
embed
|
||||
.AddField("Price 💰", (if item.Price = 0<GBT> then "Free" else $"{item.Price} $GBT"), true)
|
||||
.WithColor(WeaponClass.getClassEmbedColor item)
|
||||
.WithThumbnail(Embeds.getItemIcon item.Id)
|
||||
.WithTitle($"{item.Name}")
|
||||
|> ignore
|
||||
let button =
|
||||
@ -53,47 +56,36 @@ let getBuyItemsEmbed (playerInventory : Inventory) (storeInventory : Inventory)
|
||||
.AddComponents(buttons)
|
||||
.AsEphemeral(true)
|
||||
|
||||
let getSellEmbed (items : ItemDetails list) =
|
||||
let getSellEmbed (items : Inventory) =
|
||||
let embeds , buttons =
|
||||
items
|
||||
|> List.map (fun item ->
|
||||
|> List.choose (fun item ->
|
||||
match item.Attributes with
|
||||
| CanSell price ->
|
||||
let builder =
|
||||
DiscordEmbedBuilder()
|
||||
.AddField("Sell For 💰", $"{item.Price} $GBT", true)
|
||||
.AddField("Sell For 💰", $"{price} $GBT", true)
|
||||
.WithTitle($"{item.Name}")
|
||||
.WithColor(WeaponClass.getClassEmbedColor item)
|
||||
.Build()
|
||||
, DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Sell-{item.Id}", $"Sell {item.Name}") :> DiscordComponent)
|
||||
|> List.unzip
|
||||
|
||||
DiscordFollowupMessageBuilder()
|
||||
.AddEmbeds(embeds)
|
||||
.AddComponents(buttons)
|
||||
.AsEphemeral(true)
|
||||
|
||||
let getConsumeEmbed (items : ItemDetails list) =
|
||||
let embeds , buttons =
|
||||
items
|
||||
|> List.groupBy (fun item -> item.Id)
|
||||
|> List.map (fun (itemId , items ) ->
|
||||
let item = List.head items
|
||||
let foodItem = Inventory.findFoodById itemId items
|
||||
DiscordEmbedBuilder()
|
||||
.AddField($"{foodItem.Item.Name}", $"Total {items.Length}\nBoosts {foodItem.TargetStat} +{foodItem.BoostAmount}", true)
|
||||
.WithTitle($"Food Items")
|
||||
.WithColor(WeaponClass.getClassEmbedColor item)
|
||||
.Build()
|
||||
, DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Sell-{id}", $"Sell {item.Name}") :> DiscordComponent)
|
||||
let button = DiscordButtonComponent(WeaponClass.getClassButtonColor item, $"Sell-{item.Id}", $"Sell {item.Name}") :> DiscordComponent
|
||||
Some ( builder , button )
|
||||
| _ -> None)
|
||||
|> List.unzip
|
||||
|
||||
// TODO: We should alert the user that they have no sellable items
|
||||
DiscordFollowupMessageBuilder()
|
||||
.AddEmbeds(embeds)
|
||||
.AddComponents(buttons)
|
||||
.AsEphemeral(true)
|
||||
|
||||
let checkHasSufficientFunds (item : Item) player =
|
||||
if player.Bank - item.Price >= 0<GBT>
|
||||
match item.Attributes with
|
||||
| CanBuy price ->
|
||||
if player.Bank - price >= 0<GBT>
|
||||
then Ok player
|
||||
else Error $"You do not have sufficient funds to buy this item! Current balance: {player.Bank} GBT"
|
||||
| _ -> Error $"{item.Name} item cannot be bought"
|
||||
|
||||
let checkAlreadyOwnsItem (item : Item) player =
|
||||
if player.Inventory |> List.exists (fun w -> item.Id = w.Id)
|
||||
@ -134,14 +126,15 @@ let handleBuyItem (ctx : IDiscordContext) itemId =
|
||||
executePlayerAction ctx (fun player -> async {
|
||||
let item = Armory.weapons |> Inventory.findItemById itemId
|
||||
do! player
|
||||
|> checkHasSufficientFunds item.getItem
|
||||
>>= checkAlreadyOwnsItem item.getItem
|
||||
|> checkHasSufficientFunds item
|
||||
>>= checkAlreadyOwnsItem item
|
||||
|> handleResultWithResponse ctx (fun player -> async {
|
||||
let newBalance = player.Bank - item.Price
|
||||
let price = match item.Attributes with CanBuy price -> price | _ -> 0<GBT>
|
||||
let newBalance = player.Bank - price
|
||||
let p = { player with Bank = newBalance ; Inventory = item::player.Inventory }
|
||||
do! DbService.updatePlayer p |> Async.Ignore
|
||||
do! sendFollowUpMessage ctx $"Successfully purchased {item.Name}! You now have {newBalance} 💰$GBT remaining"
|
||||
do! Analytics.buyWeaponButton (ctx.GetDiscordMember()) item
|
||||
do! Analytics.buyWeaponButton (ctx.GetDiscordMember()) item.Name price
|
||||
})
|
||||
})
|
||||
|
||||
@ -150,20 +143,23 @@ let handleSell (ctx : IDiscordContext) itemId =
|
||||
let item = Armory.weapons |> Inventory.findItemById itemId
|
||||
do!
|
||||
player
|
||||
|> checkSoldItemAlready item.getItem
|
||||
|> checkSoldItemAlready item
|
||||
|> handleResultWithResponse ctx (fun player -> async {
|
||||
match item.Attributes with
|
||||
| CanSell price ->
|
||||
let updatedPlayer = {
|
||||
player with
|
||||
Bank = player.Bank + item.Price
|
||||
Bank = player.Bank + price
|
||||
Inventory = player.Inventory |> List.filter (fun i -> i.Id <> itemId)
|
||||
}
|
||||
do!
|
||||
[ DbService.updatePlayer updatedPlayer |> Async.Ignore
|
||||
DbService.removeShieldEvent updatedPlayer.DiscordId itemId |> Async.Ignore
|
||||
sendFollowUpMessage ctx $"Sold {item.Name} for {item.Price}! Current Balance: {updatedPlayer.Bank}"
|
||||
Analytics.sellWeaponButton (ctx.GetDiscordMember()) item ]
|
||||
sendFollowUpMessage ctx $"Sold {item.Name} for {price}! Current Balance: {updatedPlayer.Bank}"
|
||||
Analytics.sellWeaponButton (ctx.GetDiscordMember()) item price ]
|
||||
|> Async.Parallel
|
||||
|> Async.Ignore
|
||||
| _ -> ()
|
||||
})
|
||||
})
|
||||
|
||||
@ -187,33 +183,33 @@ let showInventoryEmbed (ctx : IDiscordContext) = PlayerInteractions.executePlaye
|
||||
player.Inventory
|
||||
|> List.map (fun item ->
|
||||
let embed = DiscordEmbedBuilder()
|
||||
match item with
|
||||
| Hack hack ->
|
||||
embed.AddField($"$GBT Reward |", string hack.Power, true)
|
||||
.AddField("Cooldown |", $"{TimeSpan.FromMinutes(int hack.Cooldown).Minutes} minutes", true)
|
||||
.WithColor(DiscordColor.Red)
|
||||
.WithThumbnail(Embeds.getItemIcon item.Id)
|
||||
|> ignore
|
||||
| Shield shield ->
|
||||
embed.AddField($"Strong against |", WeaponClass.getGoodAgainst shield.Class |> snd |> string, true)
|
||||
// .AddField($"Defensive Strength |", string item.Power, true)
|
||||
.AddField("Active For |", $"{TimeSpan.FromMinutes(int shield.Cooldown).Hours} hours", true)
|
||||
.WithColor(DiscordColor.SapGreen)
|
||||
.WithThumbnail(Embeds.getItemIcon item.Id)
|
||||
|> ignore
|
||||
| Food food ->
|
||||
embed.AddField($"Stat |", $"{food.TargetStat}", true)
|
||||
.WithColor(DiscordColor.Azure)
|
||||
.AddField($"Amount |", $"+{food.BoostAmount}", true) |> ignore
|
||||
| Accessory accessory ->
|
||||
embed.AddField($"Stat |", $"{accessory.TargetStat}", true)
|
||||
.WithColor(DiscordColor.Goldenrod) |> ignore
|
||||
if accessory.FloorBoost > 0 then
|
||||
embed.AddField($"Min Boost |", $"+{accessory.FloorBoost}", true) |> ignore
|
||||
if accessory.CeilBoost > 0 then
|
||||
embed.AddField($"Max Boost |", $"+{accessory.CeilBoost}", true) |> ignore
|
||||
match item.Attributes with
|
||||
| CanBuy price -> embed.AddField("Price 💰", (if price = 0<GBT> then "Free" else $"{price} $GBT"), true) |> ignore
|
||||
| CanAttack power ->
|
||||
let title = match item.Type with ItemType.Hack -> "$GBT Reward" | _ -> "Power"
|
||||
embed.AddField($"{title} |", string power, true) |> ignore
|
||||
| CanExpire time ->
|
||||
let title = match item.Type with ItemType.Hack -> "Cooldown" | ItemType.Shield -> "Active For" | _ -> "Expires"
|
||||
let ts = TimeSpan.FromMinutes(int time)
|
||||
let timeStr = if ts.Hours = 0 then $"{ts.Minutes} mins" else $"{ts.Hours} hours"
|
||||
embed.AddField($"{title} |", timeStr, true) |> ignore
|
||||
| CanConsume effects | CanPassive effects ->
|
||||
let fx =
|
||||
effects
|
||||
|> List.map (fun f ->
|
||||
match f.Effect with
|
||||
| Min i -> $"Min - {f.TargetStat}"
|
||||
| Max i -> $"Max - {f.TargetStat}"
|
||||
| Booster i ->
|
||||
let str = if i > 0 then "Boost" else "Penalty"
|
||||
$"{str} - {f.TargetStat}"
|
||||
| RateMultiplier i -> $"Multiplier - {f.TargetStat}")
|
||||
|> String.concat "\n"
|
||||
embed.AddField($"Effect - Amount |", $"{fx}", true) |> ignore
|
||||
| _ -> ()
|
||||
embed
|
||||
.AddField("Price 💰", (if item.Price = 0<GBT> then "Free" else $"{item.Price} $GBT"), true)
|
||||
.WithColor(WeaponClass.getClassEmbedColor item)
|
||||
.WithThumbnail(Embeds.getItemIcon item.Id)
|
||||
.WithTitle($"{item.Name}")
|
||||
|> ignore
|
||||
let button =
|
||||
|
Loading…
x
Reference in New Issue
Block a user