Finish adding back the class system, fix messaging

This commit is contained in:
Joseph Ferano 2022-02-22 10:47:49 +07:00
parent 34b24c29aa
commit 5df4ed9399
6 changed files with 68 additions and 55 deletions

View File

@ -40,13 +40,14 @@ let constructButtons (actionId: string) (buttonInfo : string) (player: PlayerDat
let action =
player.Events
|> Array.tryFind (fun i -> i.ItemId = item.Id)
let btnColor = itemType
match action , ignoreCooldown with
| None , _ | Some _ , true ->
DiscordButtonComponent(ButtonStyle.Primary, $"{actionId}-{item.Id}-{buttonInfo}-{player.Name}", $"{item.Name}")
DiscordButtonComponent(Game.getClassButtonColor item.Class, $"{actionId}-{item.Id}-{buttonInfo}-{player.Name}", $"{item.Name}")
| Some act , false ->
let c = ((Armory.getItem act.ItemId).Cooldown)
let time = Messaging.getShortTimeText (TimeSpan.FromMinutes(int c)) act.Timestamp
DiscordButtonComponent(ButtonStyle.Primary, $"{actionId}-{item.Id}", $"{item.Name} ({time} left)", true))
DiscordButtonComponent(Game.getClassButtonColor item.Class, $"{actionId}-{item.Id}", $"{item.Name} ({time} left)", true))
|> Seq.cast<DiscordComponent>
let pickDefense actionId player isTrainer =
@ -77,12 +78,13 @@ let pickHack actionId attacker defender isTrainer =
.AddEmbed(embed.Build())
.AsEphemeral true
let responseSuccessfulHack earnedMoney (targetId : uint64) (hack : Item) =
let embed = DiscordEmbedBuilder()
embed.ImageUrl <- getHackGif (enum<HackId>(hack.Id))
embed.Title <- "Hack Attack"
embed.Description <- $"You successfully hacked <@{targetId}> using {hack.Name}"
+ (if earnedMoney then $", and stole {Game.HackPrize} 💰$GBT from them!" else "!")
let responseSuccessfulHack earnedMoney (targetId : uint64) amountTaken (hack : Item) =
let embed =
DiscordEmbedBuilder()
.WithImageUrl(getHackGif (enum<HackId>(hack.Id)))
.WithTitle("Hack Attack")
.WithDescription($"You successfully hacked <@{targetId}> using {hack.Name}"
+ (if earnedMoney then $", and took {amountTaken} 💰$GBT from them!" else "!"))
DiscordFollowupMessageBuilder()
.AddEmbed(embed.Build())
@ -99,7 +101,7 @@ let responseCreatedShield (shield : Item) =
let eventSuccessfulHack (ctx : IDiscordContext) target prize =
DiscordMessageBuilder()
.WithContent($"{ctx.GetDiscordMember().Username} successfully hacked <@{target.DiscordId}> for a total of {prize} GoodBoyTokenz")
.WithContent($"{ctx.GetDiscordMember().Username} successfully hacked <@{target.DiscordId}> and took {prize} GoodBoyTokenz")
let getBuyItemsEmbed (player : PlayerData) (itemType : ItemType) (store : Item array) =
let embeds , buttons =
@ -110,24 +112,26 @@ let getBuyItemsEmbed (player : PlayerData) (itemType : ItemType) (store : Item a
match item.Type with
| ItemType.Hack ->
embed
.AddField($"Hacking Power |", string item.Power, true)
.AddField($"$GBT Reward |", string item.Power, true)
.AddField("Cooldown |", $"{TimeSpan.FromMinutes(int item.Cooldown).Minutes} minutes", true)
.WithThumbnail(getHackIcon (enum<HackId>(item.Id)))
|> ignore
| _ ->
embed
.AddField($"Defensive Strength |", string item.Power, true)
// .AddField($"Defensive Strength |", string item.Power, true)
.AddField($"Strong against |", Game.getGoodAgainst item.Class |> snd |> string, true)
.AddField("Active For |", $"{TimeSpan.FromMinutes(int item.Cooldown).Hours} hours", true)
.WithThumbnail(getShieldIcon (enum<ShieldId>(item.Id)))
|> ignore
embed
.AddField("Price 💰", $"{item.Price} $GBT", true)
.AddField("Price 💰", (if item.Price = 0<GBT> then "Free" else $"{item.Price} $GBT"), true)
.WithColor(Game.getClassEmbedColor item.Class)
.WithTitle($"{item.Name}")
|> ignore
let button =
if player.Inventory |> Array.exists (fun i -> i.Id = item.Id)
then DiscordButtonComponent(ButtonStyle.Primary, $"Buy-{item.Id}", $"Own {item.Name}", true)
else DiscordButtonComponent(ButtonStyle.Primary, $"Buy-{item.Id}", $"Buy {item.Name}")
then DiscordButtonComponent(Game.getClassButtonColor item.Class, $"Buy-{item.Id}", $"Own {item.Name}", true)
else DiscordButtonComponent(Game.getClassButtonColor item.Class, $"Buy-{item.Id}", $"Buy {item.Name}")
embed.Build() , button :> DiscordComponent)
|> Array.unzip
@ -136,7 +140,7 @@ let getBuyItemsEmbed (player : PlayerData) (itemType : ItemType) (store : Item a
.AddComponents(buttons)
.AsEphemeral(true)
let getSellItemsEmbed (itemType : ItemType) (player : PlayerData) =
let getSellEmbed (itemType : ItemType) (player : PlayerData) =
let embeds , buttons =
player.Inventory
|> Array.filter (fun i -> i.Type = itemType)
@ -148,8 +152,9 @@ let getSellItemsEmbed (itemType : ItemType) (player : PlayerData) =
embed
.AddField("Sell For 💰", $"{item.Price} $GBT", true)
.WithTitle($"{item.Name}")
.WithColor(Game.getClassEmbedColor item.Class)
|> ignore
let button = DiscordButtonComponent(ButtonStyle.Primary, $"Sell-{item.Id}", $"Sell {item.Name}")
let button = DiscordButtonComponent(Game.getClassButtonColor item.Class, $"Sell-{item.Id}", $"Sell {item.Name}")
embed.Build() , button :> DiscordComponent)
|> Array.unzip

View File

@ -9,10 +9,22 @@ open Degenz.DbService
open Degenz.Messaging
module Game =
let HackPrize = 10<GBT>
let ShieldPrize = 5<GBT>
let SameTargetAttackCooldown = System.TimeSpan.FromHours(2)
let SameTargetAttackCooldown = System.TimeSpan.FromHours(6)
let getClassButtonColor = function
| 0 -> ButtonStyle.Danger
| 1 -> ButtonStyle.Success
| _ -> ButtonStyle.Primary
let getClassEmbedColor = function
| 0 -> DiscordColor.Red
| 1 -> DiscordColor.Blurple
| _ -> DiscordColor.Green
let getGoodAgainst = function
| 0 -> ( ShieldId.Firewall , HackId.Virus )
| 1 -> ( ShieldId.Cypher , HackId.RemoteAccess )
| _ -> ( ShieldId.Encryption , HackId.Worm )
let executePlayerAction (ctx : IDiscordContext) (dispatch : PlayerData -> Async<unit>) =
async {

View File

@ -33,7 +33,7 @@ let checkWeaponHasCooldown (weapon : Item) attacker =
let checkHasEmptyHacks attacker =
match Player.getHacks attacker with
| [||] -> Error $"You currently do not have any Hacks to steal 💰$GBT from others. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one."
| [||] -> Error $"You currently do not have any Hacks to take 💰$GBT from others. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one."
| _ -> Ok attacker
let checkPlayerOwnsWeapon (item : Item) player =
@ -41,19 +41,14 @@ let checkPlayerOwnsWeapon (item : Item) player =
| true -> Ok player
| false -> Error $"You sold your weapon already, you cheeky bastard..."
let checkTargetHasMoney (target : PlayerData) attacker =
if target.Bank < Game.HackPrize
then Error $"{target.Name} does not have enough 💰$GBT to steal from, the broke loser. Pick a different target."
else Ok attacker
let checkPlayerHasShieldSlotsAvailable (shield : Item) player =
let updatedPlayer = player |> Player.removeExpiredActions
let defenses = Player.getShieldEvents updatedPlayer
match defenses |> Array.length >= 2 with
match defenses |> Array.length >= 3 with
| true ->
let timestamp = defenses |> Array.rev |> Array.head |> fun a -> a.Timestamp // This should be the next expiring timestamp
let cooldown = getTimeText true (TimeSpan.FromMinutes(int shield.Cooldown)) timestamp
Error $"You are only allowed two 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
let calculateDamage (hack : Item) (shield : Item) =
@ -94,12 +89,13 @@ let updateCombatants successfulHack (attacker : PlayerData) (defender : PlayerDa
let successfulHack (ctx : IDiscordContext) attacker defender hack =
async {
do! updateCombatants true attacker defender hack Game.HackPrize
let finalAmount = max 0 (int defender.Bank - hack.Power) * 1<GBT>
do! updateCombatants true attacker defender hack finalAmount
let embed = Embeds.responseSuccessfulHack true defender.DiscordId hack
let embed = Embeds.responseSuccessfulHack true defender.DiscordId finalAmount hack
do! ctx.FollowUp embed |> Async.AwaitTask
let builder = Embeds.eventSuccessfulHack ctx defender Game.HackPrize
let builder = Embeds.eventSuccessfulHack ctx defender finalAmount
let channel = ctx.GetGuild().GetChannel(GuildEnvironment.channelEventsHackerBattle)
do! channel.SendMessageAsync(builder)
|> Async.AwaitTask
@ -108,26 +104,26 @@ let successfulHack (ctx : IDiscordContext) attacker defender hack =
let failedHack (ctx : IDiscordContext) attacker defender hack =
async {
let msg = $"Hack failed! {defender.Name} was able to mount a successful defense! You lost {Game.ShieldPrize} $GBT!"
let finalAmount = max 0 (int defender.Bank - hack.Power) * 1<GBT>
let msg = $"Hack failed! {defender.Name} was able to mount a successful defense! You lost {finalAmount} $GBT!"
do! sendFollowUpMessage ctx msg
do! updateCombatants false attacker defender hack -Game.ShieldPrize
do! updateCombatants false attacker defender hack -finalAmount
let builder = DiscordMessageBuilder()
builder.WithContent($"Hacking attempt failed! <@{defender.DiscordId}> defended hack from {ctx.GetDiscordMember().Username} and stole {Game.ShieldPrize} $GBT from them! ") |> ignore
builder.WithContent($"Hacking attempt failed! <@{defender.DiscordId}> defended hack from {ctx.GetDiscordMember().Username} and took {finalAmount} $GBT from them! ") |> ignore
let channel = (ctx.GetGuild().GetChannel(GuildEnvironment.channelEventsHackerBattle))
do! channel.SendMessageAsync(builder)
|> Async.AwaitTask
|> Async.Ignore
}
let attack (target : DiscordUser) (ctx : IDiscordContext) =
let hack (target : DiscordUser) (ctx : IDiscordContext) =
Game.executePlayerActionWithTarget target ctx (fun attacker defender -> async {
do! attacker
|> Player.removeExpiredActions
|> checkAlreadyHackedTarget defender
<!> Player.removeExpiredActions
>>= checkHasEmptyHacks
>>= checkTargetHasMoney defender
>>= checkPlayerIsAttackingThemselves defender
|> function
| Ok atkr ->
@ -261,7 +257,7 @@ type HackerGame() =
[<SlashCommand("hack", "Send a hack attack to another player")>]
member this.AttackCommand (ctx : InteractionContext, [<Option("target", "The player you want to hack")>] target : DiscordUser) =
enforceChannels (DiscordInteractionContext ctx) (Trainer.hack target) (attack target)
enforceChannels (DiscordInteractionContext ctx) (Trainer.hack target) (hack target)
[<SlashCommand("shield", "Create a passive shield that will protect you for a certain time")>]
member this.ShieldCommand (ctx : InteractionContext) =

View File

@ -4,8 +4,8 @@
"Name": "Virus",
"Type": 0,
"Price": 0,
"Power": 10,
"Cooldown": 2,
"Power": 25,
"Cooldown": 1,
"Class": 0,
"Attributes": {
"Sell": false,
@ -19,8 +19,8 @@
"Name": "RemoteAccess",
"Type": 0,
"Price": 500,
"Power": 50,
"Cooldown": 2,
"Power": 75,
"Cooldown": 3,
"Class": 1,
"Attributes": {
"Sell": true,
@ -34,8 +34,8 @@
"Name": "Worm",
"Type": 0,
"Price": 5000,
"Power": 80,
"Cooldown": 2,
"Power": 150,
"Cooldown": 5,
"Class": 2,
"Attributes": {
"Sell": true,
@ -51,7 +51,7 @@
"Price": 0,
"Power": 10,
"Class": 0,
"Cooldown": 600,
"Cooldown": 120,
"Attributes": {
"Sell": false,
"Buy": false,
@ -63,10 +63,10 @@
"Id": 7,
"Name": "Encryption",
"Type": 1,
"Price": 5000,
"Power": 80,
"Price": 500,
"Power": 50,
"Class": 1,
"Cooldown": 600,
"Cooldown": 240,
"Attributes": {
"Sell": true,
"Buy": true,
@ -78,10 +78,10 @@
"Id": 8,
"Name": "Cypher",
"Type": 1,
"Price": 500,
"Power": 50,
"Price": 5000,
"Power": 80,
"Class": 2,
"Cooldown": 600,
"Cooldown": 380,
"Attributes": {
"Sell": true,
"Buy": true,

View File

@ -37,7 +37,7 @@ let buy itemType (ctx : IDiscordContext) =
let sell itemType (ctx : IDiscordContext) =
Game.executePlayerAction ctx (fun player -> async {
match checkHasItemsInArsenal itemType player with
| Ok _ -> let itemStore = Embeds.getSellItemsEmbed itemType player
| Ok _ -> let itemStore = Embeds.getSellEmbed itemType player
do! ctx.FollowUp(itemStore) |> Async.AwaitTask
| Error e -> do! sendFollowUpMessage ctx e
})

View File

@ -38,7 +38,7 @@ let sendInitialEmbed (client : DiscordClient) =
embed.ImageUrl <- "https://s10.gifyu.com/images/MasterTraining_Degenz.gif"
builder.AddEmbed embed |> ignore
builder.Content <- "Welcome Degen… To the Hacker Training Program.\n"
+ "Here you will learn how to defend yourself, and hack other Degenz to steal their 💰$GBT.\n"
+ "Here you will learn how to defend yourself, and hack other Degenz to take their 💰$GBT.\n"
+ "Are you ready?"
let button = DiscordButtonComponent(ButtonStyle.Success, $"Trainer-1", $"LFG") :> DiscordComponent
builder.AddComponents [| button |] |> ignore
@ -52,7 +52,7 @@ let handleTrainerStep1 (ctx : IDiscordContext) =
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleTrainee)
do! ctx.GetDiscordMember().GrantRoleAsync(role)
|> Async.AwaitTask
let msg = "Beautopia© is a dangerous place... quick, put up a SHIELD 🛡 before another Degen hacks you, and steals 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"
+ $"Type the `/shield` command now, then select - `{defaultShield.Name}`\n"
let builder =
@ -135,13 +135,13 @@ let handleHack (ctx : IDiscordContext) =
Game.executePlayerAction ctx (fun player -> async {
let sendMessage' = sendFollowUpMessage ctx
do! Async.Sleep 1000
let embed = Embeds.responseSuccessfulHack false Sensei.Id defaultHack
let embed = Embeds.responseSuccessfulHack false Sensei.Id defaultHack.Power defaultHack
do! ctx.FollowUp(embed) |> Async.AwaitTask
do! Async.Sleep 5000
do! sendMessage'
("🎉 **Congratulations**\n\n"
+ "You successfully **HACKED** me, and are now an **Elite Haxor!**\n\n"
+ "When you **HACK** other Degenz, you **STEAL** their 💰$GBT.\n"
+ "When you **HACK** other Degenz, you **TAKE** their 💰$GBT.\n"
+ "But remember, hacks take time to recover, so use them wisely.")
do! Async.Sleep 6000