diff --git a/Bot/Embeds.fs b/Bot/Embeds.fs index 15cc99e..4fc6fdb 100644 --- a/Bot/Embeds.fs +++ b/Bot/Embeds.fs @@ -77,7 +77,7 @@ let pickHack actionId attacker defender isTrainer = .AddEmbed(embed.Build()) .AsEphemeral true -let responseSuccessfulHack earnedMoney (targetId : uint64) (hack : BattleItem) = +let responseSuccessfulHack earnedMoney (targetId : uint64) (hack : Item) = let embed = DiscordEmbedBuilder() embed.ImageUrl <- getHackGif (enum(hack.Id)) embed.Title <- "Hack Attack" @@ -88,7 +88,7 @@ let responseSuccessfulHack earnedMoney (targetId : uint64) (hack : BattleItem) = .AddEmbed(embed.Build()) .AsEphemeral(true) -let responseCreatedShield (shield : BattleItem) = +let responseCreatedShield (shield : Item) = let embed = DiscordEmbedBuilder().WithImageUrl(getShieldGif (enum(shield.Id))) embed.Title <- "Mounted Shield" embed.Description <- $"Mounted {shield.Name} shield for {TimeSpan.FromMinutes(int shield.Cooldown).Hours} hours" @@ -101,20 +101,20 @@ let eventSuccessfulHack (ctx : IDiscordContext) target prize = DiscordMessageBuilder() .WithContent($"{ctx.GetDiscordMember().Username} successfully hacked <@{target.DiscordId}> for a total of {prize} GoodBoyTokenz") -let getBuyItemsEmbed (player : PlayerData) (itemType : ItemType) (store : BattleItem array) = +let getBuyItemsEmbed (player : PlayerData) (itemType : ItemType) (store : Item array) = let embeds , buttons = store |> Array.filter (fun i -> i.Type = itemType) |> Array.map (fun item -> let embed = DiscordEmbedBuilder() match item.Type with - | Hack -> + | ItemType.Hack -> embed .AddField($"Hacking Power |", string item.Power, true) .AddField("Cooldown |", $"{TimeSpan.FromMinutes(int item.Cooldown).Minutes} minutes", true) .WithThumbnail(getHackIcon (enum(item.Id))) |> ignore - | Shield -> + | _ -> embed .AddField($"Defensive Strength |", string item.Power, true) .AddField("Active For |", $"{TimeSpan.FromMinutes(int item.Cooldown).Hours} hours", true) @@ -143,8 +143,8 @@ let getSellItemsEmbed (itemType : ItemType) (player : PlayerData) = |> Array.map (fun item -> let embed = DiscordEmbedBuilder() match item.Type with - | Hack -> embed.WithThumbnail(getHackIcon (enum(item.Id))) |> ignore - | Shield -> embed.WithThumbnail(getShieldIcon (enum(item.Id))) |> ignore + | ItemType.Hack -> embed.WithThumbnail(getHackIcon (enum(item.Id))) |> ignore + | _ -> embed.WithThumbnail(getShieldIcon (enum(item.Id))) |> ignore embed .AddField("Sell For 💰", $"{item.Price} $GBT", true) .WithTitle($"{item.Name}") diff --git a/Bot/Game.fs b/Bot/Game.fs index e73777a..bfaf375 100644 --- a/Bot/Game.fs +++ b/Bot/Game.fs @@ -98,7 +98,7 @@ module Player = let modifyBank (player : PlayerData) amount = { player with Bank = max (player.Bank + amount) 0 } module Arsenal = - let battleItemFormat (items : BattleItem array) = + let battleItemFormat (items : Item array) = match items with | [||] -> "None" | _ -> items |> Array.toList |> List.map (fun i -> i.Name) |> String.concat ", " diff --git a/Bot/HackerBattle.fs b/Bot/HackerBattle.fs index 8fd6c8e..90200b3 100644 --- a/Bot/HackerBattle.fs +++ b/Bot/HackerBattle.fs @@ -63,7 +63,8 @@ let checkPlayerHasShieldSlotsAvailable shield player = Error $"You are only allowed two shields at a time. Wait {cooldown} to add another shield" | false -> Ok updatedPlayer -let calculateDamage (hack : BattleItem) (shield : BattleItem) = +// TODO H: Need to update the new hacker game mechanics +let calculateDamage (hack : Item) (shield : Item) = if hack.Power < shield.Power then Weak else Strong diff --git a/Bot/Items.json b/Bot/Items.json index bb67ab4..e9c7bbc 100644 --- a/Bot/Items.json +++ b/Bot/Items.json @@ -2,12 +2,7 @@ { "Id": 0, "Name": "Virus", - "Type": { - "Case": "Hack" - }, - "Class": { - "Case": "Network" - }, + "Type": 0, "Cost": 50, "Power": 50, "Cooldown": 2 @@ -15,12 +10,7 @@ { "Id": 1, "Name": "RemoteAccess", - "Type": { - "Case": "Hack" - }, - "Class": { - "Case": "Penetration" - }, + "Type": 0, "Cost": 50, "Power": 50, "Cooldown": 2 @@ -28,12 +18,7 @@ { "Id": 2, "Name": "Worm", - "Type": { - "Case": "Hack" - }, - "Class": { - "Case": "Exploit" - }, + "Type": 0, "Cost": 50, "Power": 50, "Cooldown": 2 @@ -41,12 +26,7 @@ { "Id": 6, "Name": "Firewall", - "Type": { - "Case": "Shield" - }, - "Class": { - "Case": "Network" - }, + "Type": 1, "Cost": 50, "Power": 50, "Cooldown": 600 @@ -54,12 +34,7 @@ { "Id": 8, "Name": "Cypher", - "Type": { - "Case": "Shield" - }, - "Class": { - "Case": "Penetration" - }, + "Type": 1, "Cost": 50, "Power": 50, "Cooldown": 600 @@ -67,12 +42,7 @@ { "Id": 7, "Name": "Encryption", - "Type": { - "Case": "Shield" - }, - "Class": { - "Case": "Exploit" - }, + "Type": 1, "Cost": 50, "Power": 50, "Cooldown": 600 diff --git a/Bot/Store.fs b/Bot/Store.fs index 6e0a30c..b5a7610 100644 --- a/Bot/Store.fs +++ b/Bot/Store.fs @@ -8,17 +8,17 @@ open DSharpPlus.SlashCommands open Degenz open Degenz.Messaging -let checkHasSufficientFunds (item : BattleItem) player = +let checkHasSufficientFunds (item : Item) player = if player.Bank - item.Price >= 0 then Ok player else Error $"You do not have sufficient funds to buy this item! Current balance: {player.Bank} GBT" -let checkAlreadyOwnsItem (item : BattleItem) player = +let checkAlreadyOwnsItem (item : Item) player = if player.Inventory |> Array.exists (fun w -> item.Id = w.Id) then Error $"You already own {item.Name}!" else Ok player -let checkSoldItemAlready (item : BattleItem) player = +let checkSoldItemAlready (item : Item) player = if player.Inventory |> Array.exists (fun w -> item.Id = w.Id) then Ok player else Error $"{item.Name} not found in your arsenal! Looks like you sold it already." diff --git a/Bot/Trainer.fs b/Bot/Trainer.fs index d161485..18be935 100644 --- a/Bot/Trainer.fs +++ b/Bot/Trainer.fs @@ -168,7 +168,7 @@ let handleAttack (ctx : IDiscordContext) = do! Async.Sleep 1000 let updatedPlayer = { player with - Bank = player.Bank + hackMoney + shieldMoney + Bank = player.Bank + 100 Events = [ { PlayerEvent.Timestamp = System.DateTime.UtcNow PlayerEvent.Adversary = { Id = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" } diff --git a/DbService/DbService.fs b/DbService/DbService.fs index 930f6a3..6cf7fa4 100644 --- a/DbService/DbService.fs +++ b/DbService/DbService.fs @@ -1,50 +1,46 @@ module Degenz.DbService +open Degenz.Types + open System -open System.Collections.Generic open MongoDB.Bson open MongoDB.Bson.Serialization open MongoDB.Driver -open Degenz.Types -[] -type PlayerEntry = - { DiscordId : uint64 - Name : string - XP : int - Bank : int } - -let private playerMap (player : PlayerData) = { - DiscordId = player.DiscordId - Name = player.Name - XP = player.XP - Bank = int player.Bank -} +let mongo = MongoClient(Environment.GetEnvironmentVariable("CONN_STRING")) +let db = mongo.GetDatabase("degenz") +let players = db.GetCollection("players") let tryWithDefault (bson : BsonDocument) field (defaultValue : 'a) (map : BsonValue -> 'a) = - let result , bval = bson.TryGetValue(field) - if result then map bval else defaultValue + try + let result , bval = bson.TryGetValue(field) + if result then map bval else defaultValue + with _ -> defaultValue -let private mapBack (bson : BsonDocument) : PlayerData = - { DiscordId = tryWithDefault bson "Player.DiscordId" 0uL (fun v -> v.AsInt64 |> uint64) - Name = tryWithDefault bson "Player.Name" "Empty" (fun v -> v.AsString) +let mapBack (bson : BsonDocument) : PlayerData = + { DiscordId = tryWithDefault bson "DiscordId" 0uL (fun v -> v.AsInt64 |> uint64) + Name = tryWithDefault bson "Name" "Empty" (fun v -> v.AsString) Inventory = tryWithDefault bson "Inventory" [||] (fun v -> v.AsBsonArray |> Seq.map (fun (bv : BsonValue) -> bv.AsInt32) |> Seq.map (fun w -> Armory.battleItems |> Array.find (fun w' -> w = w'.Id)) |> Seq.toArray) - Events = tryWithDefault bson "Events" [||] (fun _ -> [||]) - Traits = tryWithDefault bson "Traits" PlayerTraits.empty (fun _ -> PlayerTraits.empty) - Achievements = tryWithDefault bson "Achievements" [||] (fun _ -> [||]) - XP = tryWithDefault bson "XP" 0 (fun _ -> 0) - Bank = tryWithDefault bson "Player.Bank" 0 (fun v -> v.AsInt32 * 1) + Events = tryWithDefault bson "Events" [||] (fun v -> + v.AsBsonArray + |> Seq.map (fun (bv : BsonValue) -> + BsonSerializer.Deserialize(bv.ToBsonDocument())) + |> Seq.toArray) + Traits = + tryWithDefault bson "Traits" PlayerTraits.empty (fun v -> + BsonSerializer.Deserialize(v.ToBsonDocument())) + Achievements = + tryWithDefault bson "Achievements" [||] (fun v -> + v.AsBsonArray |> Seq.map (fun (bv : BsonValue) -> bv.AsString) |> Seq.toArray) + XP = tryWithDefault bson "XP" 0 (fun v -> v.AsInt32) + Bank = tryWithDefault bson "Bank" 0 (fun v -> v.AsInt32 * 1) } -let mongo = MongoClient(Environment.GetEnvironmentVariable("CONN_STRING")) -let db = mongo.GetDatabase("degenz") -let players = db.GetCollection("players") - let tryFindPlayer (id : uint64) = async { let filter = Builders.Filter.Eq("Player.DiscordId", id) @@ -58,31 +54,16 @@ let tryFindPlayer (id : uint64) = |> Some } +let insertNewPlayer (player : PlayerData) = + async { + do! BsonDocument("Player", player.ToBsonDocument()) |> players.InsertOneAsync |> Async.AwaitTask + } + let updatePlayer (player : PlayerData) = async { let filter = Builders.Filter.Eq("Player.DiscordId", player.DiscordId) - let update = Builders.Update - .Set("Player", playerMap player) - .AddToSet("Traits", player.Traits) - .AddToSet("Events", player.Events) - .AddToSet("Achievements", player.Achievements) - .AddToSet("Inventory", player.Inventory) - return! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore - } - -let getAchievements (id : uint64) = - async { - let filter = Builders.Filter.Eq("Player.DiscordId", id) - try - let! player = players.FindAsync(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 update = Builders.Update.Set("Player", player.ToBsonDocument()) + do! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore } let addAchievement (id : uint64) (achievement : string) = @@ -90,31 +71,4 @@ let addAchievement (id : uint64) (achievement : string) = let filter = Builders.Filter.Eq("Player.DiscordId", id) let update = Builders.Update.Push("Achievements", achievement) return! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore - } - -let insertNewPlayer (player : PlayerData) = - async { - let dict = [ - KeyValuePair("Player" , (playerMap player).ToBsonDocument() :> Object) - KeyValuePair("Events" , [||] :> Object) - KeyValuePair("Inventory" , [||] :> Object) - KeyValuePair("Traits" , PlayerTraits.empty.ToBsonDocument() :> Object) - KeyValuePair("XP" , 0 :> Object) - ] - do! BsonDocument(dict) - |> players.InsertOneAsync - |> Async.AwaitTask - } - -//let deletePlayer (player : PlayerData) = -// async { -// let dict = [ KeyValuePair("Player" , player.ToBsonDocument() :> Object) ] -// do! BsonDocument(dict) -// |> players.InsertOneAsync -// |> Async.AwaitTask -// } -// -//let getTopPlayers amount = -// async { -// return! players.FindAsync() -// } \ No newline at end of file + } \ No newline at end of file diff --git a/Shared/Shared.fs b/Shared/Shared.fs index b9c9ddf..2d9f4fa 100644 --- a/Shared/Shared.fs +++ b/Shared/Shared.fs @@ -47,10 +47,12 @@ module Types = | Cypher = 8 type ItemType = - | Hack - | Shield + | Hack = 0 + | Shield = 1 + | Consumable = 1 - type BattleItem = { + [] + type Item = { Id : int Name : string Price : int @@ -99,7 +101,7 @@ module Types = type PlayerData = { DiscordId : uint64 Name : string - Inventory : BattleItem array + Inventory : Item array Events : PlayerEvent array Traits : PlayerTraits Achievements : string array @@ -111,10 +113,11 @@ module Types = module Armory = let battleItems = let file = System.IO.File.ReadAllText("Items.json") - JsonConvert.DeserializeObject(file) +// let file = System.IO.File.ReadAllText("Bot/Items.json") + JsonConvert.DeserializeObject(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 hacks = battleItems |> Array.filter (fun bi -> match bi.Type with ItemType.Hack -> true | _ -> false) + let shields = battleItems |> Array.filter (fun bi -> match bi.Type with ItemType.Shield -> true | _ -> false) let getItem itemId = battleItems |> Array.find (fun w -> w.Id = itemId)