Fixes to Trainer copy, Check if defender has money, bring back status (arsenal)
This commit is contained in:
parent
e772a6d6f3
commit
ad613064a8
@ -9,14 +9,7 @@ open DSharpPlus.SlashCommands
|
||||
open Degenz
|
||||
open Degenz.Messaging
|
||||
|
||||
let getTimeTillCooldownFinishes (timespan : TimeSpan) timestamp =
|
||||
let timeRemaining = timespan - (DateTime.UtcNow - timestamp)
|
||||
if timeRemaining.Hours > 0 then
|
||||
$"{timeRemaining.Hours} hours"
|
||||
elif timeRemaining.Minutes > 0 then
|
||||
$"{timeRemaining.Minutes} minutes"
|
||||
else
|
||||
$"{timeRemaining.Seconds} seconds"
|
||||
let (>>=) x f = Result.bind f x
|
||||
|
||||
let checkIfPlayerIsAttackingThemselves defender attacker =
|
||||
match attacker.DiscordId = defender.DiscordId with
|
||||
@ -30,10 +23,9 @@ let checkForExistingHack defenderId attacker =
|
||||
|> Array.tryFind (fun (_,t,_) -> t.Id = defenderId)
|
||||
|> function
|
||||
| Some ( atk , target , _ ) ->
|
||||
let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromHours(24)) atk.Timestamp
|
||||
Error $"You can only hack the same target once every 24 hours, wait {cooldown} to attempt another hack on {target.Name}."
|
||||
| None ->
|
||||
Ok attacker
|
||||
let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromHours(2)) atk.Timestamp
|
||||
Error $"You can only hack the same target once every 2 hours, wait {cooldown} to attempt another hack on {target.Name}."
|
||||
| None -> Ok attacker
|
||||
|
||||
let checkIfHackHasCooldown hackId attacker =
|
||||
let mostRecentHackAttack =
|
||||
@ -54,6 +46,11 @@ let checkIfInventoryIsEmpty attacker =
|
||||
| [||] -> Error $"You currently do not have any Hacks to steal 💰$GBT from others. Please go to the <#{GuildEnvironment.channelArmory}> and purchase one."
|
||||
| _ -> Ok attacker
|
||||
|
||||
let checkIfTargetHasMoney (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 calculateDamage (hack : BattleItem) (shield : BattleItem) =
|
||||
if hack.Class = shield.Class
|
||||
then Strong
|
||||
@ -115,22 +112,22 @@ let attack (ctx : InteractionContext) (target : DiscordUser) =
|
||||
let! defender = DbService.tryFindPlayer target.Id
|
||||
match defender with
|
||||
| Some defender ->
|
||||
let hackAttempt =
|
||||
checkForExistingHack defender.DiscordId attacker
|
||||
|> Result.bind checkIfInventoryIsEmpty
|
||||
|> Result.bind (checkIfPlayerIsAttackingThemselves defender)
|
||||
match hackAttempt with
|
||||
| Ok _ ->
|
||||
let embed = Embeds.pickHack "Attack" attacker defender
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed)
|
||||
|> Async.AwaitTask
|
||||
| Error msg ->
|
||||
let builder =
|
||||
DiscordInteractionResponseBuilder()
|
||||
.WithContent(msg)
|
||||
.AsEphemeral(true)
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
do! checkForExistingHack defender.DiscordId attacker
|
||||
>>= checkIfInventoryIsEmpty
|
||||
>>= (checkIfTargetHasMoney defender)
|
||||
>>= (checkIfPlayerIsAttackingThemselves defender)
|
||||
|> function
|
||||
| Ok _ ->
|
||||
let embed = Embeds.pickHack "Attack" attacker defender
|
||||
ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, embed)
|
||||
|> Async.AwaitTask
|
||||
| Error msg ->
|
||||
let builder =
|
||||
DiscordInteractionResponseBuilder()
|
||||
.WithContent(msg)
|
||||
.AsEphemeral(true)
|
||||
ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
| None -> do! sendSimpleResponse ctx "Your target is not connected to the network, they must join first by using the /redpill command"
|
||||
})
|
||||
|
||||
@ -260,7 +257,7 @@ type HackerGame() =
|
||||
else
|
||||
attack ctx target
|
||||
|
||||
[<SlashCommand("shield", "Create a passive defense that will last 24 hours")>]
|
||||
[<SlashCommand("shield", "Create a passive shield that will protect you for a certain time")>]
|
||||
member this.ShieldCommand (ctx : InteractionContext) =
|
||||
if ctx.Channel.Id = GuildEnvironment.channelTraining then
|
||||
Trainer.defend ctx
|
||||
|
@ -71,27 +71,12 @@ module Commands =
|
||||
// } |> Async.StartAsTask
|
||||
// :> Task
|
||||
|
||||
let status (ctx : InteractionContext) =
|
||||
Game.executePlayerInteraction ctx (fun player -> async {
|
||||
let updatedActions = Player.removeExpiredActions player.Actions
|
||||
let updatedPlayer = { player with Actions = updatedActions }
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- Messaging.statusFormat updatedPlayer
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
do! DbService.updatePlayer updatedPlayer
|
||||
})
|
||||
|
||||
type PlayerInteractions() =
|
||||
inherit ApplicationCommandModule ()
|
||||
|
||||
[<SlashCommand("redpill", "Take the redpill and become a hacker")>]
|
||||
member _.AddHackerRole (ctx : InteractionContext) = Commands.addHackerRole ctx
|
||||
|
||||
[<SlashCommand("status", "Get your current status like bank account, and active hacks and defenses")>]
|
||||
member this.Status (ctx : InteractionContext) = Commands.status ctx
|
||||
|
||||
// [<SlashCommand("leaderboard", "View the current list of players ranked by highest earnings")>]
|
||||
// member this.Leaderboard (ctx : InteractionContext) = Commands.leaderboard ctx
|
||||
|
||||
|
17
Bot/Store.fs
17
Bot/Store.fs
@ -94,12 +94,29 @@ let handleSellButtonEvents (_ : DiscordClient) (event : ComponentInteractionCrea
|
||||
} |> Async.StartAsTask
|
||||
:> Task
|
||||
|
||||
let status (ctx : InteractionContext) =
|
||||
Game.executePlayerInteraction ctx (fun player -> async {
|
||||
let updatedActions = Player.removeExpiredActions player.Actions
|
||||
let updatedPlayer = { player with Actions = updatedActions }
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
let embed = DiscordEmbedBuilder()
|
||||
embed.AddField("Arsenal", Messaging.statusFormat updatedPlayer) |> ignore
|
||||
builder.AddEmbed(embed) |> ignore
|
||||
builder.IsEphemeral <- true
|
||||
do! ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, builder)
|
||||
|> Async.AwaitTask
|
||||
do! DbService.updatePlayer updatedPlayer
|
||||
})
|
||||
|
||||
type Store() =
|
||||
inherit ApplicationCommandModule ()
|
||||
// [<SlashCommand("view-store", "View items available for purchase")>]
|
||||
|
||||
// member _.ViewStore (ctx : InteractionContext) = viewStore ctx
|
||||
|
||||
[<SlashCommand("arsenal", "Get the Hacks and Shields you own, and which ones are active")>]
|
||||
member this.Arsenal (ctx : InteractionContext) = status ctx
|
||||
|
||||
[<SlashCommand("buy-hack", "Purchase a hack attack you can use to earn GoodBoyTokenz")>]
|
||||
member _.BuyHack (ctx : InteractionContext) = buyItem ctx Hack
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
module Degenz.Trainer
|
||||
|
||||
open System.Threading.Tasks
|
||||
open DSharpPlus
|
||||
open System.Threading.Tasks
|
||||
open DSharpPlus.Entities
|
||||
open DSharpPlus.EventArgs
|
||||
open DSharpPlus.SlashCommands
|
||||
@ -39,7 +39,7 @@ let handleTrainerStep1 (event : ComponentInteractionCreateEventArgs) =
|
||||
|
||||
do! sendInteractionEvent event
|
||||
("Beautopia© is a dangerous place...\n"
|
||||
+ "Quick, put up a DEFENSE 🛡 before another Degen hacks you, and steals your 💰$GBT.\n"
|
||||
+ "Quick, put up a SHIELD 🛡 before another Degen hacks you, and steals your 💰$GBT.\n"
|
||||
+ shieldMessage
|
||||
+ "To enable it, you need to run the `/shield` slash command.\n\n"
|
||||
+ $"Type the `/shield` command now, then select - `{weaponName}`\n")
|
||||
@ -60,7 +60,7 @@ let defend (ctx : InteractionContext) =
|
||||
let handleDefenseMsg = {
|
||||
ButtonId = "Trainer-3"
|
||||
ButtonText = "Got it"
|
||||
Message = "🎉 Congratulations 🎉\n\n"
|
||||
Message = "🎉 Congratulations\n\n"
|
||||
+ "You successfully defended my hack!\n\n"
|
||||
+ "Because I tried hacking you when you had your defense up, you stole money from me...\n"
|
||||
+ "Defenses only protect you for a LIMITED TIME, so remember to keep at least 1 defense up at all times, or risk getting hacked!"
|
||||
@ -77,7 +77,7 @@ let handleDefense (event : ComponentInteractionCreateEventArgs) =
|
||||
do! Async.Sleep 2000
|
||||
do! sendMessage' "Ok, good, let me make sure that worked.\n\nI'll try to **hack** you now"
|
||||
do! Async.Sleep 4000
|
||||
do! sendMessage' $"❌ HACKING FAILED! ❌\n\n{player.Name} defended the hack from <@{GuildEnvironment.botHackerBattle}>, and stole 💰$GBT {Game.ShieldPrize} from them!"
|
||||
do! sendMessage' $"❌ HACKING FAILED!\n\n{player.Name} defended the hack from <@{GuildEnvironment.botHackerBattle}>, and stole 💰$GBT {Game.ShieldPrize} from them!"
|
||||
do! Async.Sleep 3000
|
||||
do! sendFollowUpMessageWithButton event handleDefenseMsg
|
||||
})
|
||||
@ -133,15 +133,17 @@ let handleAttack (event : ComponentInteractionCreateEventArgs) =
|
||||
let embed = Embeds.responseSuccessfulHackTrainer hack
|
||||
do! event.Interaction.CreateFollowupMessageAsync(embed) |> Async.AwaitTask |> Async.Ignore
|
||||
do! Async.Sleep 3000
|
||||
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"
|
||||
+ "But remember, hacks take time to recover, so use them wisely.")
|
||||
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"
|
||||
+ "But remember, hacks take time to recover, so use them wisely.")
|
||||
do! Async.Sleep 7000
|
||||
do! sendFollowUpMessage event ("Your training is **complete!**\n\n"
|
||||
+ "But, you’re going to need more **HACKS & DEFENSES** 🛡 to survive in **Beautopia©...**\n"
|
||||
+ $"You can purchase them from <@{GuildEnvironment.botArmory}>, at <#{GuildEnvironment.channelArmory}> anytime you want...\n\n"
|
||||
+ "Go there **NOW** to buy **HACKS** & **SHIELDS** before you get hacked! 😱")
|
||||
do! sendFollowUpMessage event
|
||||
("Your training is **complete!**\n\n"
|
||||
+ "But, you’re going to need more **HACKS & SHIELDS** 🛡 to survive in **Beautopia©...**\n"
|
||||
+ $"You can purchase them from <@{GuildEnvironment.botArmory}> anytime you want...\n\n"
|
||||
+ $"Go to the <#{GuildEnvironment.channelArmory}> **NOW** and type the `/buy-shield` slash command! 😱")
|
||||
})
|
||||
|
||||
let handleButtonEvent (event : ComponentInteractionCreateEventArgs) =
|
||||
|
@ -76,7 +76,6 @@ module Types =
|
||||
Actions : Action array
|
||||
Bank : int<GBT> }
|
||||
|
||||
|
||||
module Armory =
|
||||
let battleItems =
|
||||
let file = System.IO.File.ReadAllText("Items.json")
|
||||
@ -89,9 +88,10 @@ module Player =
|
||||
let shields player = player.Arsenal |> Array.filter (fun bi -> bi.Type = Shield)
|
||||
let attacks player =
|
||||
player.Actions
|
||||
|> Array.choose (fun act -> match act.Type with Attack ar -> Some (act,ar.Target,ar.Result) | Defense -> None)
|
||||
let defenses player = player.Actions |> Array.filter (fun act -> match act.Type with Defense _ -> true | _ -> false)
|
||||
|> Array.filter (fun act -> match act.Type with Attack _ -> true | _ -> false)
|
||||
let defenses player = player.Actions |> Array.filter (fun act -> match act.Type with Defense -> true | _ -> false)
|
||||
|
||||
// TODO: I have to fix this, this will remove hacks before the single target cooldown expires
|
||||
let removeExpiredActions actions =
|
||||
actions
|
||||
|> Array.filter (fun (act : Action) ->
|
||||
@ -110,12 +110,39 @@ module Messaging =
|
||||
Message : string
|
||||
}
|
||||
|
||||
let getTimeTillCooldownFinishes (timespan : TimeSpan) timestamp =
|
||||
let timeRemaining = timespan - (DateTime.UtcNow - timestamp)
|
||||
if timeRemaining.Hours > 0 then
|
||||
$"{timeRemaining.Hours} hours"
|
||||
elif timeRemaining.Minutes > 0 then
|
||||
$"{timeRemaining.Minutes} minutes"
|
||||
else
|
||||
$"{timeRemaining.Seconds} seconds"
|
||||
|
||||
let battleItemFormat (items : BattleItem array) =
|
||||
match items with
|
||||
| [||] -> "None"
|
||||
| _ -> items |> Array.toList |> List.map (fun i -> i.Name) |> String.concat ", "
|
||||
|
||||
let actionFormat (actions : Action array) =
|
||||
match actions with
|
||||
| [||] -> "None"
|
||||
| _ ->
|
||||
actions
|
||||
|> Array.map (fun act ->
|
||||
match act.Type with
|
||||
| Attack atk -> $"Hacked {atk.Target} at {act.Timestamp.ToLongDateString()}"
|
||||
| Defense ->
|
||||
let item = Armory.getItem act.ActionId
|
||||
let cooldown = getTimeTillCooldownFinishes (TimeSpan.FromMinutes(int item.Cooldown))
|
||||
$"{item.Name} active for {cooldown}")
|
||||
|> String.concat "\n"
|
||||
|
||||
let statusFormat p =
|
||||
$"Hacks: {Player.hacks p |> Array.toList}
|
||||
Shields: {Player.shields p |> Array.toList}
|
||||
Hack Attacks: {Player.attacks p |> Array.toList}
|
||||
Active Defenses: {Player.defenses p |> Array.toList}
|
||||
Bank: {p.Bank}"
|
||||
$"**Hacks:** {Player.hacks p |> battleItemFormat}\n
|
||||
**Shields:** {Player.shields p |> battleItemFormat}\n
|
||||
**Hack Attacks:** {Player.attacks p |> actionFormat}\n
|
||||
**Active Shields:** {Player.defenses p |> actionFormat}"
|
||||
|
||||
let constructButtons (actionType: string) (playerInfo: string) (weapons: BattleItem array) =
|
||||
weapons
|
||||
|
Loading…
x
Reference in New Issue
Block a user