From 5df4ed9399d4b85228bf2b69928c1ee55aa37a0a Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Tue, 22 Feb 2022 10:47:49 +0700 Subject: [PATCH] Finish adding back the class system, fix messaging --- Bot/Embeds.fs | 37 +++++++++++++++++++++---------------- Bot/Game.fs | 18 +++++++++++++++--- Bot/HackerBattle.fs | 32 ++++++++++++++------------------ Bot/Items.json | 26 +++++++++++++------------- Bot/Store.fs | 2 +- Bot/Trainer.fs | 8 ++++---- 6 files changed, 68 insertions(+), 55 deletions(-) diff --git a/Bot/Embeds.fs b/Bot/Embeds.fs index 5f415dd..527d245 100644 --- a/Bot/Embeds.fs +++ b/Bot/Embeds.fs @@ -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 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(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(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(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(item.Id))) |> ignore embed - .AddField("Price 💰", $"{item.Price} $GBT", true) + .AddField("Price 💰", (if item.Price = 0 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 diff --git a/Bot/Game.fs b/Bot/Game.fs index af6ff61..c852d02 100644 --- a/Bot/Game.fs +++ b/Bot/Game.fs @@ -9,10 +9,22 @@ open Degenz.DbService open Degenz.Messaging module Game = - let HackPrize = 10 - let ShieldPrize = 5 + 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) = async { diff --git a/Bot/HackerBattle.fs b/Bot/HackerBattle.fs index f60c793..bbb600b 100644 --- a/Bot/HackerBattle.fs +++ b/Bot/HackerBattle.fs @@ -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 + 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 + 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() = [] member this.AttackCommand (ctx : InteractionContext, [] target : DiscordUser) = - enforceChannels (DiscordInteractionContext ctx) (Trainer.hack target) (attack target) + enforceChannels (DiscordInteractionContext ctx) (Trainer.hack target) (hack target) [] member this.ShieldCommand (ctx : InteractionContext) = diff --git a/Bot/Items.json b/Bot/Items.json index b9d48df..238bb0b 100644 --- a/Bot/Items.json +++ b/Bot/Items.json @@ -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, diff --git a/Bot/Store.fs b/Bot/Store.fs index b1c009d..aa2e731 100644 --- a/Bot/Store.fs +++ b/Bot/Store.fs @@ -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 }) diff --git a/Bot/Trainer.fs b/Bot/Trainer.fs index 18c8305..7661870 100644 --- a/Bot/Trainer.fs +++ b/Bot/Trainer.fs @@ -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