First pass on thief game
This commit is contained in:
parent
dd33492418
commit
bb9c04fe6e
10
Bot/Bot.fs
10
Bot/Bot.fs
@ -6,6 +6,7 @@ open DSharpPlus.SlashCommands
|
||||
open Degenz
|
||||
open Degenz.HackerBattle
|
||||
open Degenz.Store
|
||||
open Degenz.Thief
|
||||
open Emzi0767.Utilities
|
||||
//open Degenz.SlotMachine
|
||||
|
||||
@ -36,12 +37,13 @@ let storeBot = new DiscordClient(storeConfig)
|
||||
//let slotMachineBot = new DiscordClient(slotMachineConfig)
|
||||
|
||||
//let clients = [| hackerBattleBot ; storeBot ; slotMachineBot |]
|
||||
let sc1 = hackerBattleBot.UseSlashCommands()
|
||||
let sc2 = storeBot.UseSlashCommands()
|
||||
let hackerCommands = hackerBattleBot.UseSlashCommands()
|
||||
let storeCommands = storeBot.UseSlashCommands()
|
||||
//let sc3 = slotMachineBot.UseSlashCommands()
|
||||
|
||||
sc1.RegisterCommands<HackerGame>(guild);
|
||||
sc2.RegisterCommands<Store>(guild);
|
||||
hackerCommands.RegisterCommands<HackerGame>(guild);
|
||||
hackerCommands.RegisterCommands<StealGame>(guild);
|
||||
storeCommands.RegisterCommands<Store>(guild);
|
||||
//sc3.RegisterCommands<SlotMachine>(guild);
|
||||
|
||||
hackerBattleBot.add_ComponentInteractionCreated(AsyncEventHandler(HackerBattle.handleButtonEvent))
|
||||
|
@ -16,9 +16,10 @@
|
||||
<Compile Include="PlayerInteractions.fs" />
|
||||
<Compile Include="Embeds.fs" />
|
||||
<Compile Include="Store.fs" />
|
||||
<Compile Include="Thief.fs" />
|
||||
<Compile Include="SlotMachine.fs" />
|
||||
<Compile Include="Trainer.fs" />
|
||||
<Compile Include="HackerBattle.fs" />
|
||||
<Compile Include="SlotMachine.fs" />
|
||||
<Compile Include="Bot.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
19
Bot/Game.fs
19
Bot/Game.fs
@ -38,7 +38,24 @@ module Game =
|
||||
let! playerResult = tryFindPlayer (ctx.GetDiscordMember().Id)
|
||||
match playerResult with
|
||||
| Some player -> do! dispatch player
|
||||
| None -> do! Messaging.sendSimpleResponse ctx "You are currently not a hacker, first use the /redpill command to become one"
|
||||
| None -> do! Messaging.sendFollowUpMessage ctx "You are currently not a hacker, first use the /redpill command to become one"
|
||||
} |> Async.StartAsTask :> Task
|
||||
|
||||
let executePlayerWithTargetAction (targetPlayer : DiscordUser) (ctx : IDiscordContext) (dispatch : PlayerData -> PlayerData -> Async<unit>) =
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.IsEphemeral <- true
|
||||
builder.Content <- "Content"
|
||||
do! ctx.Respond InteractionResponseType.DeferredChannelMessageWithSource builder |> Async.AwaitTask
|
||||
let! playerResult = tryFindPlayer (ctx.GetDiscordMember().Id)
|
||||
let! targetResult = tryFindPlayer targetPlayer.Id
|
||||
match playerResult , targetResult with
|
||||
| Some player , Some target -> do! dispatch player target
|
||||
| None , _ -> do! Messaging.sendFollowUpMessage ctx "You are currently not a hacker, first use the /redpill command to become one"
|
||||
| _ , None ->
|
||||
if targetPlayer.IsBot
|
||||
then do! Messaging.sendFollowUpMessage ctx $"{targetPlayer.Username} is a bot, pick a real human to hack"
|
||||
else do! Messaging.sendFollowUpMessage ctx "Your target is not connected to the network, they must join first by using the /redpill command"
|
||||
} |> Async.StartAsTask :> Task
|
||||
|
||||
module Player =
|
||||
|
@ -120,26 +120,18 @@ let failedHack (ctx : IDiscordContext) attacker defender hack =
|
||||
}
|
||||
|
||||
let attack (target : DiscordUser) (ctx : IDiscordContext) =
|
||||
Game.executePlayerAction ctx (fun attacker -> async {
|
||||
let! defender = DbService.tryFindPlayer target.Id
|
||||
match defender with
|
||||
| Some defender ->
|
||||
do! attacker
|
||||
|> checkAlreadyHackedTarget defender.DiscordId
|
||||
<!> (Player.removeExpiredActions true)
|
||||
>>= checkHasEmptyHacks
|
||||
>>= checkTargetHasMoney defender
|
||||
>>= checkPlayerIsAttackingThemselves defender
|
||||
|> function
|
||||
| Ok atkr ->
|
||||
let embed = Embeds.pickHack "Attack" atkr defender false
|
||||
ctx.FollowUp(embed) |> Async.AwaitTask
|
||||
| Error msg -> sendFollowUpMessage ctx msg
|
||||
| None ->
|
||||
if target.IsBot
|
||||
then do! sendFollowUpMessage ctx $"{target.Username} is a bot, pick a real human to hack"
|
||||
else do! sendFollowUpMessage ctx "Your target is not connected to the network, they must join first by using the /redpill command"
|
||||
|
||||
Game.executePlayerWithTargetAction target ctx (fun attacker defender -> async {
|
||||
do! attacker
|
||||
|> checkAlreadyHackedTarget defender.DiscordId
|
||||
<!> (Player.removeExpiredActions true)
|
||||
>>= checkHasEmptyHacks
|
||||
>>= checkTargetHasMoney defender
|
||||
>>= checkPlayerIsAttackingThemselves defender
|
||||
|> function
|
||||
| Ok atkr ->
|
||||
let embed = Embeds.pickHack "Attack" atkr defender false
|
||||
ctx.FollowUp(embed) |> Async.AwaitTask
|
||||
| Error msg -> sendFollowUpMessage ctx msg
|
||||
})
|
||||
|
||||
let handleAttack (ctx : IDiscordContext) =
|
||||
@ -208,6 +200,7 @@ let handleButtonEvent (_ : DiscordClient) (event : ComponentInteractionCreateEve
|
||||
| id when id.StartsWith("Attack") -> handleAttack eventCtx
|
||||
| id when id.StartsWith("Defend") -> handleDefense eventCtx
|
||||
| id when id.StartsWith("Trainer") -> Trainer.handleButtonEvent eventCtx |> Async.StartAsTask :> Task
|
||||
| id when id.StartsWith("Steal") -> Thief.handleSteal eventCtx
|
||||
| _ ->
|
||||
task {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
|
@ -16,6 +16,8 @@ module Commands =
|
||||
Name = nickname
|
||||
Arsenal = [| hack ; shield |]
|
||||
Actions = [||]
|
||||
XP = 0
|
||||
Stats = PlayerStats.empty
|
||||
Bank = 100<GBT> }
|
||||
|
||||
let addHackerRole (ctx : InteractionContext) =
|
||||
|
102
Bot/Thief.fs
Normal file
102
Bot/Thief.fs
Normal file
@ -0,0 +1,102 @@
|
||||
module Degenz.Thief
|
||||
|
||||
open System
|
||||
open System.Threading.Tasks
|
||||
open DSharpPlus
|
||||
open DSharpPlus.Entities
|
||||
open DSharpPlus.SlashCommands
|
||||
open Degenz.Messaging
|
||||
|
||||
let getRandomStealBtnLabels () =
|
||||
let rand = Random(Guid.NewGuid().GetHashCode())
|
||||
let affirmative = [| "LFG" ; "YOLO" ; "IDGAF" |]
|
||||
let negative = [| "NOPE" ; "IM OUT" ; "BAIL" |]
|
||||
( affirmative.[rand.Next(0, 3)] , negative.[rand.Next(0, 3)] )
|
||||
|
||||
let chanceOfSuccessMsg = function
|
||||
| amt when amt < 0.20 -> "Looking pretty bad"
|
||||
| amt when amt < 0.50 -> "I mean, maybe"
|
||||
| amt when amt < 0.80 -> "I think you got this"
|
||||
| _ -> "Totally worth it"
|
||||
|
||||
let targetEvaluationMsg = function
|
||||
| amt when amt < 0.20 -> "but man, they look swole."
|
||||
| amt when amt < 0.50 -> "but they look a little confident"
|
||||
| amt when amt < 0.80 -> "and they're looking a little nervous"
|
||||
| _ -> "and they look weak af man"
|
||||
|
||||
let payoutChance targetBank chance = targetBank * 0.1 * (1.0 - chance)
|
||||
|
||||
let getStealEmbed chance (target : PlayerData) (player : PlayerData) =
|
||||
let buttons =
|
||||
let yes , no = getRandomStealBtnLabels ()
|
||||
[ DiscordButtonComponent(ButtonStyle.Success, $"Steal-yes-{target.DiscordId}-{target.Name}-{chance}", yes)
|
||||
DiscordButtonComponent(ButtonStyle.Danger, $"Steal-no", no) ]
|
||||
|> Seq.cast<DiscordComponent>
|
||||
let embed =
|
||||
DiscordEmbedBuilder()
|
||||
.AddField("Chance of Success", $"{chanceOfSuccessMsg chance}", true)
|
||||
.WithDescription($"{target.Name} is coming towards you in a dark alley, {targetEvaluationMsg chance}")
|
||||
.WithImageUrl("https://cdnb.artstation.com/p/assets/images/images/017/553/457/large/maarten-hof-backalley-mainshot.jpg")
|
||||
.WithTitle($"Steal Money")
|
||||
|
||||
DiscordFollowupMessageBuilder()
|
||||
.AddEmbed(embed)
|
||||
.AddComponents(buttons)
|
||||
.AsEphemeral(true)
|
||||
|
||||
|
||||
let steal target (ctx : IDiscordContext) =
|
||||
Game.executePlayerWithTargetAction target ctx (fun attacker defender -> async {
|
||||
let winPercentage = if attacker.Stats.Strength > defender.Stats.Strength then 1.0 else 0.0
|
||||
let embed = getStealEmbed winPercentage defender attacker
|
||||
|
||||
do! ctx.FollowUp(embed) |> Async.AwaitTask
|
||||
})
|
||||
|
||||
let handleSteal (ctx : IDiscordContext) =
|
||||
let split = ctx.GetInteractionId().Split("-")
|
||||
let answer = split.[1]
|
||||
if answer = "yes" then
|
||||
Game.executePlayerAction ctx (fun player -> async {
|
||||
let targetId = uint64 split.[2]
|
||||
let targetName = split.[3]
|
||||
let chance = double split.[4]
|
||||
|
||||
let rand = Random(Guid.NewGuid().GetHashCode())
|
||||
let result = rand.NextDouble()
|
||||
|
||||
if chance >= result then
|
||||
let! target = DbService.tryFindPlayer targetId
|
||||
do! Messaging.sendFollowUpMessage ctx $"You stole {targetName} money"
|
||||
else
|
||||
do! Messaging.sendFollowUpMessage ctx "You failed miserably"
|
||||
|
||||
return ()
|
||||
})
|
||||
else
|
||||
async {
|
||||
let builder = DiscordInteractionResponseBuilder()
|
||||
builder.Content <- "I thought better of it"
|
||||
do! ctx.Respond InteractionResponseType.UpdateMessage builder |> Async.AwaitTask
|
||||
} |> Async.StartAsTask :> Task
|
||||
|
||||
|
||||
type StealGame() =
|
||||
inherit ApplicationCommandModule ()
|
||||
|
||||
let enforceChannel (ctx : IDiscordContext) (storeFn : IDiscordContext -> Task) =
|
||||
match ctx.GetChannel().Id with
|
||||
| id when id = GuildEnvironment.channelArmory -> storeFn ctx
|
||||
| _ ->
|
||||
task {
|
||||
let msg = $"You must go to <#{GuildEnvironment.channelArmory}> channel to buy or sell weapons"
|
||||
do! Messaging.sendSimpleResponse ctx msg
|
||||
}
|
||||
|
||||
[<SlashCommand("steal", "Steal some money from another player, but you might go to prison if caught")>]
|
||||
member this.Steal (ctx : InteractionContext, [<Option("target", "Who do you want to steal from?")>] target : DiscordUser) =
|
||||
// enforceChannel (DiscordInteractionContext ctx) (steal target)
|
||||
steal target (DiscordInteractionContext ctx)
|
||||
|
||||
|
@ -67,6 +67,8 @@ let private mapBack (player : PlayerEntry) : PlayerData = {
|
||||
let atks = player.Attacks |> Array.map attackToAction
|
||||
let dfns = player.Defenses |> Array.map defenseToAction
|
||||
Array.append atks dfns
|
||||
Stats = PlayerStats.empty
|
||||
XP = 0
|
||||
Bank = player.Bank * 1<GBT>
|
||||
}
|
||||
|
||||
|
@ -74,12 +74,31 @@ module Types =
|
||||
Type : ActionType
|
||||
Timestamp : DateTime }
|
||||
|
||||
type StatAmount = int
|
||||
type XPAmount = int
|
||||
|
||||
type AttributeId =
|
||||
| Strength = 0
|
||||
| Cunning = 1
|
||||
|
||||
type PlayerStats = {
|
||||
Strength : int
|
||||
Focus : int
|
||||
}
|
||||
with static member empty = { Strength = 0 ; Focus = 0 }
|
||||
|
||||
type PlayerXP = {
|
||||
Amount : XPAmount
|
||||
}
|
||||
|
||||
[<CLIMutable>]
|
||||
type PlayerData =
|
||||
{ DiscordId : uint64
|
||||
Name : string
|
||||
Arsenal : BattleItem array
|
||||
Actions : Action array
|
||||
Stats : PlayerStats
|
||||
XP : int
|
||||
Bank : int<GBT> }
|
||||
|
||||
module Armory =
|
||||
@ -175,6 +194,15 @@ module Messaging =
|
||||
do! ctx.FollowUp(builder) |> Async.AwaitTask
|
||||
}
|
||||
|
||||
let sendFollowUpEmbed (ctx : IDiscordContext) embed =
|
||||
async {
|
||||
let builder =
|
||||
DiscordFollowupMessageBuilder()
|
||||
.AsEphemeral(true)
|
||||
.AddEmbed(embed)
|
||||
do! ctx.FollowUp(builder) |> Async.AwaitTask
|
||||
}
|
||||
|
||||
let sendFollowUpMessageWithButton (ctx : IDiscordContext) interactiveMessage =
|
||||
async {
|
||||
let builder = DiscordFollowupMessageBuilder()
|
||||
|
Loading…
x
Reference in New Issue
Block a user