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,10 +120,7 @@ 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 ->
 | 
			
		||||
    Game.executePlayerWithTargetAction target ctx (fun attacker defender -> async {
 | 
			
		||||
      do! attacker
 | 
			
		||||
          |> checkAlreadyHackedTarget defender.DiscordId
 | 
			
		||||
          <!> (Player.removeExpiredActions true)
 | 
			
		||||
@ -135,11 +132,6 @@ let attack (target : DiscordUser) (ctx : IDiscordContext) =
 | 
			
		||||
                 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"
 | 
			
		||||
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
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