Model for the new RPG mechanics
This commit is contained in:
parent
c7ee6bfa6a
commit
881fd12aa9
@ -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<HackId>(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<ShieldId>(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<HackId>(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<HackId>(item.Id))) |> ignore
|
||||
| Shield -> embed.WithThumbnail(getShieldIcon (enum<ShieldId>(item.Id))) |> ignore
|
||||
| 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)
|
||||
.WithTitle($"{item.Name}")
|
||||
|
@ -98,7 +98,7 @@ module Player =
|
||||
let modifyBank (player : PlayerData) amount = { player with Bank = max (player.Bank + amount) 0<GBT> }
|
||||
|
||||
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 ", "
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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<GBT>
|
||||
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."
|
||||
|
@ -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<GBT>
|
||||
Events = [
|
||||
{ PlayerEvent.Timestamp = System.DateTime.UtcNow
|
||||
PlayerEvent.Adversary = { Id = GuildEnvironment.botIdHackerBattle ; Name = "Sensei" }
|
||||
|
@ -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
|
||||
|
||||
[<CLIMutable>]
|
||||
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<BsonDocument>("players")
|
||||
|
||||
let tryWithDefault (bson : BsonDocument) field (defaultValue : 'a) (map : BsonValue -> 'a) =
|
||||
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<GBT> (fun v -> v.AsInt32 * 1<GBT>)
|
||||
Events = tryWithDefault bson "Events" [||] (fun v ->
|
||||
v.AsBsonArray
|
||||
|> Seq.map (fun (bv : BsonValue) ->
|
||||
BsonSerializer.Deserialize<PlayerEvent>(bv.ToBsonDocument()))
|
||||
|> Seq.toArray)
|
||||
Traits =
|
||||
tryWithDefault bson "Traits" PlayerTraits.empty (fun v ->
|
||||
BsonSerializer.Deserialize<PlayerTraits>(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<GBT> (fun v -> v.AsInt32 * 1<GBT>)
|
||||
}
|
||||
|
||||
let mongo = MongoClient(Environment.GetEnvironmentVariable("CONN_STRING"))
|
||||
let db = mongo.GetDatabase("degenz")
|
||||
let players = db.GetCollection<BsonDocument>("players")
|
||||
|
||||
let tryFindPlayer (id : uint64) =
|
||||
async {
|
||||
let filter = Builders<BsonDocument>.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<BsonDocument>.Filter.Eq("Player.DiscordId", player.DiscordId)
|
||||
let update = Builders<BsonDocument>.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<BsonDocument>.Filter.Eq("Player.DiscordId", id)
|
||||
try
|
||||
let! player = players.FindAsync<BsonDocument>(filter) |> Async.AwaitTask
|
||||
match player.FirstOrDefault() with
|
||||
| null -> return None
|
||||
| p -> return p
|
||||
.GetValue("achievements")
|
||||
.AsBsonArray
|
||||
|> Seq.map (fun (bv : BsonValue) -> bv.AsString)
|
||||
|> Some
|
||||
with ex -> return None
|
||||
let update = Builders<BsonDocument>.Update.Set("Player", player.ToBsonDocument())
|
||||
do! players.UpdateOneAsync(filter, update) |> Async.AwaitTask |> Async.Ignore
|
||||
}
|
||||
|
||||
let addAchievement (id : uint64) (achievement : string) =
|
||||
@ -91,30 +72,3 @@ let addAchievement (id : uint64) (achievement : string) =
|
||||
let update = Builders<BsonDocument>.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()
|
||||
// }
|
@ -47,10 +47,12 @@ module Types =
|
||||
| Cypher = 8
|
||||
|
||||
type ItemType =
|
||||
| Hack
|
||||
| Shield
|
||||
| Hack = 0
|
||||
| Shield = 1
|
||||
| Consumable = 1
|
||||
|
||||
type BattleItem = {
|
||||
[<CLIMutable>]
|
||||
type Item = {
|
||||
Id : int
|
||||
Name : string
|
||||
Price : int<GBT>
|
||||
@ -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<BattleItem array>(file)
|
||||
// let file = System.IO.File.ReadAllText("Bot/Items.json")
|
||||
JsonConvert.DeserializeObject<Item array>(file)
|
||||
|
||||
let hacks = battleItems |> Array.filter (fun bi -> match bi.Type with Hack -> true | Shield -> false)
|
||||
let shields = battleItems |> Array.filter (fun bi -> match bi.Type with Shield -> true | Hack -> false)
|
||||
let 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)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user