diff --git a/src/Duets.Cli/Components/Commands/Computer/OpenApp.Command.fs b/src/Duets.Cli/Components/Commands/Computer/OpenApp.Command.fs new file mode 100644 index 00000000..b8912f5f --- /dev/null +++ b/src/Duets.Cli/Components/Commands/Computer/OpenApp.Command.fs @@ -0,0 +1,38 @@ +namespace Duets.Cli.Components.Commands + +open Duets.Cli +open Duets.Cli.Components +open Duets.Cli.SceneIndex +open Duets.Cli.Text +open Duets.Entities +open Duets.Simulation + +[<RequireQualifiedAccess>] +module OpenAppCommand = + let private appName = + function + | WordProcessor -> "Word" + + /// Command to open an app on the currently used computer. + let create item computer apps = + { Name = "open app" + Description = "Shows a picker to open an app on the computer" + Handler = + fun _ -> + let selectedApp = + showOptionalChoicePrompt + "Select an app" + Generic.cancel + appName + apps + + match selectedApp with + | Some app -> + $"Opening {app |> appName}..." |> showMessage + + wait 500<millisecond> + + Computer.openApp item computer app |> Effect.applyMultiple + | None -> () + + Scene.World } diff --git a/src/Duets.Cli/Components/Commands/Items/Interactive.Command.fs b/src/Duets.Cli/Components/Commands/Items/Interactive.Command.fs index 5cd6dd84..fdce8746 100644 --- a/src/Duets.Cli/Components/Commands/Items/Interactive.Command.fs +++ b/src/Duets.Cli/Components/Commands/Items/Interactive.Command.fs @@ -54,6 +54,19 @@ module InteractiveCommand = Items.itemNotReadable |> showMessage Scene.World) + let ``use`` = + Command.itemInteraction + (Command.VerbOnly "use") + Command.useDescription + ItemInteraction.Use + (function + | Ok effects -> + effects |> Duets.Cli.Effect.applyMultiple + Scene.World + | Error _ -> + Items.itemNotUsable |> showMessage + Scene.World) + let watch = Command.itemInteraction (Command.VerbOnly "watch") diff --git a/src/Duets.Cli/Components/Effect.fs b/src/Duets.Cli/Components/Effect.fs index d65d5de7..bf74f839 100644 --- a/src/Duets.Cli/Components/Effect.fs +++ b/src/Duets.Cli/Components/Effect.fs @@ -255,6 +255,27 @@ let private displayEffect effect = $"""It's time to prepare for the concert! If you have any merchandise, you can set up a stand to sell it by the {"bar" |> Styles.place}. Otherwise, head to the {"stage" |> Styles.place} to do a soundcheck""" |> Styles.information |> showMessage + | SituationChanged(Focused(UsingComputer(_, computer))) when + computer.ComputerState = Booting + -> + clearScreen () + + "DuOS" |> showFiglet + "Booting up version 1.21..." |> Styles.faded |> showMessage + wait 1000<millisecond> + + let createBootMessage message = + $"""[[ {"OK" |> Styles.success} ]] {message}""" + + [ createBootMessage "Started network manager" + createBootMessage "Started display manager" + createBootMessage "Started system services" + createBootMessage "Started shell" ] + |> List.iter (fun message -> + message |> showMessage + wait 550<millisecond>) + + "Finished booting, took 4.2 seconds" |> Styles.success |> showMessage | SongImproved(_, Diff(before, after)) -> let (Unfinished(_, _, previousQuality)) = before let (Unfinished(_, _, currentQuality)) = after diff --git a/src/Duets.Cli/Duets.Cli.fsproj b/src/Duets.Cli/Duets.Cli.fsproj index 35425195..97bb33a8 100644 --- a/src/Duets.Cli/Duets.Cli.fsproj +++ b/src/Duets.Cli/Duets.Cli.fsproj @@ -45,6 +45,7 @@ <Compile Include="Text\World\RehearsalSpace.fs"/> <Compile Include="Text\World\Studio.fs"/> <Compile Include="Text\World\World.fs"/> + <Compile Include="Text\Focused.fs" /> <Compile Include="Components\VisualEffects.fs"/> <Compile Include="Components\Separator.fs"/> <Compile Include="Components\Layout.fs"/> @@ -96,6 +97,7 @@ <Compile Include="Components\Commands\RehearsalRoom\ListSongs.Command.fs"/> <Compile Include="Components\Commands\RehearsalRoom\SwitchGenre.Command.fs"/> <Compile Include="Components\Commands\Career\Work.Command.fs"/> + <Compile Include="Components\Commands\Computer\OpenApp.Command.fs" /> <Compile Include="Components\Commands\Concert\ConcertCommon.fs"/> <Compile Include="Components\Commands\Concert\StartConcert.Command.fs"/> <Compile Include="Components\Commands\Concert\DoEncore.Command.fs"/> diff --git a/src/Duets.Cli/Scenes/World.fs b/src/Duets.Cli/Scenes/World.fs index c80e00ea..d6b5cf78 100644 --- a/src/Duets.Cli/Scenes/World.fs +++ b/src/Duets.Cli/Scenes/World.fs @@ -98,6 +98,7 @@ let private commandsFromInteractions interactions = | ItemInteraction.Play -> [ InteractiveCommand.play ] | ItemInteraction.Read -> [ InteractiveCommand.read ] | ItemInteraction.Sleep -> [ SleepCommand.get ] + | ItemInteraction.Use -> [ InteractiveCommand.``use`` ] | ItemInteraction.Watch -> [ InteractiveCommand.watch ] | Interaction.FreeRoam freeRoamInteraction -> match freeRoamInteraction with @@ -164,6 +165,10 @@ let private commandsFromInteractions interactions = | ShopInteraction.Buy shop -> [ BuyCommand.create shop ] | ShopInteraction.Order shop -> [ OrderCommand.create shop ] | ShopInteraction.SeeMenu shop -> [ SeeMenuCommand.create shop ] + | Interaction.Situational computerInteraction -> + match computerInteraction with + | ComputerInteraction.OpenApp(item, computer, apps) -> + [ OpenAppCommand.create item computer apps ] | Interaction.Social socialInteraction -> match socialInteraction with | SocialInteraction.StartConversation(knownNpcs, unknownNpcs) -> @@ -259,6 +264,12 @@ let worldScene mode = currentDayMoment characterAttributes ongoingConcert.Points + | Focused focus -> + Focused.actionPrompt + today + currentDayMoment + characterAttributes + focus | PlayingMiniGame miniGameState -> MiniGame.actionPrompt today currentDayMoment miniGameState | Socializing socializingState -> diff --git a/src/Duets.Cli/Text/Command.fs b/src/Duets.Cli/Text/Command.fs index e1846010..31562cb2 100644 --- a/src/Duets.Cli/Text/Command.fs +++ b/src/Duets.Cli/Text/Command.fs @@ -161,6 +161,9 @@ let eatDescription = let readDescription = $"""Allows you to read a book. Use as {Styles.information "read {book name}"}""" +let useDescription = + $"""Allows you to use an item. Use as {Styles.information "use {item name}"}""" + let putUsage = $"""{Styles.information "put {item name} in {storage name}"}""" let putDescription = diff --git a/src/Duets.Cli/Text/Emoji.fs b/src/Duets.Cli/Text/Emoji.fs index 2e74f58c..a14c812b 100644 --- a/src/Duets.Cli/Text/Emoji.fs +++ b/src/Duets.Cli/Text/Emoji.fs @@ -11,6 +11,12 @@ let flying = ":airplane_departure:" /// the space in the end since the emoji does not seem to render well without it. let concert = ":admission_tickets: " +/// Emoji for representing actions related to computers. +let computer = ":desktop_computer:" + +/// Emoji for representing actions related to writing. +let writing = ":pencil:" + /// Emoji for representing actions related to socializing. let socializing = ":mouth:" diff --git a/src/Duets.Cli/Text/Focused.fs b/src/Duets.Cli/Text/Focused.fs new file mode 100644 index 00000000..b8c7122c --- /dev/null +++ b/src/Duets.Cli/Text/Focused.fs @@ -0,0 +1,26 @@ +module rec Duets.Cli.Text.Focused + +open Duets.Entities +open Duets.Entities.SituationTypes + +let actionPrompt date dayMoment attributes activity = + $"""{Generic.infoBar date dayMoment attributes} +{activityEmoji activity} {activityName activity}""" + |> Styles.prompt + +let activityName activity = + match activity with + | FocusSituation.UsingComputer(item, computer) -> + match computer.ComputerState with + | Booting -> "" (* Won't be shown, it'll be switched right after. *) + | AppSwitcher -> $"Using {item.Name}" + | AppRunning(WordProcessor) -> "Using Word" + |> Styles.faded + +let activityEmoji activity = + match activity with + | FocusSituation.UsingComputer(_, computer) -> + match computer.ComputerState with + | Booting -> "" + | AppSwitcher -> $"{Emoji.computer} " + | AppRunning(WordProcessor) -> Emoji.writing diff --git a/src/Duets.Cli/Text/Generic.fs b/src/Duets.Cli/Text/Generic.fs index e01b1566..ac10c3d8 100644 --- a/src/Duets.Cli/Text/Generic.fs +++ b/src/Duets.Cli/Text/Generic.fs @@ -258,6 +258,7 @@ let itemDetailedName (item: Item) = | Key(Chip(cityId, placeId)) -> let place = Queries.World.placeInCityById cityId placeId $"Chip for {place.Name} in {cityName cityId}" + | Usable(Computer _) -> $"{item.Brand} {item.Name}" |> Styles.item | _ -> itemName item let moreDates = Styles.faded "More dates" diff --git a/src/Duets.Cli/Text/Items.fs b/src/Duets.Cli/Text/Items.fs index 0ffc8a39..005b8f5a 100644 --- a/src/Duets.Cli/Text/Items.fs +++ b/src/Duets.Cli/Text/Items.fs @@ -37,6 +37,8 @@ let itemNotEdible = Styles.error "You can't eat that!" let itemNotReadable = Styles.error "How are you planning to read that?" +let itemNotUsable = Styles.error "You can't use that!" + let itemCannotBeExercisedWith = Styles.error "You can't exercise with that! Try a treadmill" diff --git a/src/Duets.Data/Items/Book.Items.fs b/src/Duets.Data/Items/Book.Items.fs index b7d1929c..d55ac5ba 100644 --- a/src/Duets.Data/Items/Book.Items.fs +++ b/src/Duets.Data/Items/Book.Items.fs @@ -11,12 +11,14 @@ let private specialBooks = (* Music Theory volumes. *) { Title = "Music Theory Vol. I" Author = "Duets Academy" + Genre = Technical BookEffects = [ SkillGain(SkillId.Composition, 5) ] ReadProgress = 0<percent> }, 30m<dd> { Title = "Music Theory Vol. II" Author = "Duets Academy" + Genre = Technical BookEffects = [ SkillGain(SkillId.Composition, 10) ] ReadProgress = 0<percent> }, 60m<dd> @@ -24,12 +26,14 @@ let private specialBooks = (* Music production volumes. *) { Title = "Music Production Vol. I" Author = "Duets Academy" + Genre = Technical BookEffects = [ SkillGain(SkillId.MusicProduction, 3) ] ReadProgress = 0<percent> }, 30m<dd> { Title = "Music Production Vol. II" Author = "Duets Academy" + Genre = Technical BookEffects = [ SkillGain(SkillId.MusicProduction, 8) ] ReadProgress = 0<percent> }, 30m<dd> ] @@ -42,6 +46,7 @@ let all: PurchasableItem list = |> List.map (fun dataBook -> { Title = dataBook.Title Author = dataBook.Author + Genre = Fiction (* TODO: Extract from the data-set. *) BookEffects = [] ReadProgress = 0<percent> }, 15m<dd>) diff --git a/src/Duets.Data/Items/Electronics.Items.fs b/src/Duets.Data/Items/Electronics.Items.fs index 77e28160..3556c683 100644 --- a/src/Duets.Data/Items/Electronics.Items.fs +++ b/src/Duets.Data/Items/Electronics.Items.fs @@ -2,6 +2,14 @@ module Duets.Data.Items.Electronics open Duets.Entities +module Computer = + let surface: PurchasableItem = + { Brand = "Microsoft" + Name = "Surface Pro" + Properties = + [ Computer.forPerformance 100m<percent> |> Computer |> Usable ] }, + 1100m<dd> + module Dartboard = let dartboard: PurchasableItem = { Brand = "Bull's" diff --git a/src/Duets.Entities/Computer.fs b/src/Duets.Entities/Computer.fs new file mode 100644 index 00000000..2ba4fded --- /dev/null +++ b/src/Duets.Entities/Computer.fs @@ -0,0 +1,10 @@ +module Duets.Entities.Computer + +/// Default state of a computer's storage. +let defaultStorage = { WordProcessor = { BookProjects = [] } } + +/// Creates a computer with the default state and storage and the given performance. +let forPerformance perf = + { Performance = perf + ComputerState = Booting + Storage = defaultStorage } diff --git a/src/Duets.Entities/Duets.Entities.fsproj b/src/Duets.Entities/Duets.Entities.fsproj index 023980f0..7336011c 100644 --- a/src/Duets.Entities/Duets.Entities.fsproj +++ b/src/Duets.Entities/Duets.Entities.fsproj @@ -25,6 +25,7 @@ <Compile Include="Types\Places\Studio.Types.fs"/> <Compile Include="Types\Places\Shop.Types.fs"/> <Compile Include="Types\World.Coordinates.Types.fs"/> + <Compile Include="Types\Computer.Types.fs" /> <Compile Include="Types\Item.Types.fs"/> <Compile Include="Types\Merch.Types.fs"/> <Compile Include="Types\World.Types.fs"/> @@ -58,6 +59,7 @@ <Compile Include="Song.fs"/> <Compile Include="Flight.fs"/> <Compile Include="Instrument.fs"/> + <Compile Include="Computer.fs" /> <Compile Include="Item.fs"/> <Compile Include="Skill.fs"/> <Compile Include="Relationships.fs"/> diff --git a/src/Duets.Entities/Types/Book.Types.fs b/src/Duets.Entities/Types/Book.Types.fs index f3e02956..252f6f44 100644 --- a/src/Duets.Entities/Types/Book.Types.fs +++ b/src/Duets.Entities/Types/Book.Types.fs @@ -2,6 +2,28 @@ namespace Duets.Entities [<AutoOpen>] module BookTypes = + /// Defines all genres a book can belong to. + type BookGenre = + | Fiction + | NonFiction + | ScienceFiction + | Fantasy + | Mystery + | Romance + | Horror + | Thriller + | Biography + | Autobiography + | SelfHelp + | History + | Poetry + | Drama + | Comedy + | Satire + | Tragedy + | Epic + | Technical + /// Defines the effect that reading a specific book has on a character. type BookEffect = | SkillGain of skill: SkillId * amount: int @@ -13,5 +35,6 @@ module BookTypes = type Book = { Title: string Author: string + Genre: BookGenre BookEffects: BookEffect list ReadProgress: int<percent> } diff --git a/src/Duets.Entities/Types/Computer.Types.fs b/src/Duets.Entities/Types/Computer.Types.fs new file mode 100644 index 00000000..265d2edd --- /dev/null +++ b/src/Duets.Entities/Types/Computer.Types.fs @@ -0,0 +1,43 @@ +namespace Duets.Entities + +[<AutoOpen>] +module ComputerTypes = + /// Represents the kind of applications that can be used in the computer. + type App = | WordProcessor + + /// Represents the different states that the computer can be in. + type ComputerState = + | Booting + | AppSwitcher + | AppRunning of App + + /// Types related to the word processor application. + module WordProcessor = + /// Represents a book that the character is currently working on. + type BookProject = + { Title: string + Genre: BookGenre + Progress: int<percent> } + + /// Represents a collection of books that the character is currently + /// working on. + type WordProcessorStorage = { BookProjects: BookProject list } + + /// Represents what's stored in a computer. + type ComputerStorage = + { WordProcessor: WordProcessor.WordProcessorStorage } + + /// Resembles a computer that the character can use. + type Computer = + { + /// Represents the kind of performance that can be extracted from the + /// computer. The performance depends on the computer's hardware + /// and depletes over time. + Performance: decimal<percent> + + /// Represents the current state of the computer. + ComputerState: ComputerState + + /// Represents the storage available in the computer. + Storage: ComputerStorage + } diff --git a/src/Duets.Entities/Types/Interaction.Types.fs b/src/Duets.Entities/Types/Interaction.Types.fs index 453be482..25c59160 100644 --- a/src/Duets.Entities/Types/Interaction.Types.fs +++ b/src/Duets.Entities/Types/Interaction.Types.fs @@ -18,6 +18,11 @@ module InteractionTypes = /// Starts a work shift in the given job. | Work of job: Job + [<RequireQualifiedAccess>] + type ComputerInteraction = + /// Allows the character to open an application on the computer. + | OpenApp of Item * Computer * App list + /// Interactions that can be done while on a concert. [<RequireQualifiedAccess>] type ConcertInteraction = @@ -90,6 +95,7 @@ module InteractionTypes = | Play | Read | Sleep + | Use | Watch /// Interactions related to moving around the world. @@ -231,6 +237,7 @@ module InteractionTypes = | MiniGame of MiniGameInteraction | MerchandiseWorkshop of MerchandiseWorkshopInteraction | Rehearsal of RehearsalInteraction + | Situational of ComputerInteraction | Shop of ShopInteraction | Social of SocialInteraction | Studio of StudioInteraction diff --git a/src/Duets.Entities/Types/Item.Types.fs b/src/Duets.Entities/Types/Item.Types.fs index 982e1f9f..2a438a16 100644 --- a/src/Duets.Entities/Types/Item.Types.fs +++ b/src/Duets.Entities/Types/Item.Types.fs @@ -65,6 +65,9 @@ module rec ItemTypes = /// Defines all the items placed inside a storage. type StoredItems = Item list + /// Defines all items that can be used via custom commands. + type UsableItem = Computer of Computer + /// Defines all types of wearable items available in the game. type WearableItem = | Hoodie @@ -75,8 +78,7 @@ module rec ItemTypes = | TShirt /// Defines all types of properties that an item can have. These properties - /// define how an item can be used by the character and can be combined - /// together. + /// define how an item can be used by the character and can be combined. type ItemProperty = /// Example: a stove. | Cookware @@ -102,6 +104,8 @@ module rec ItemTypes = | Storage of StorageType * items: StoredItems /// Example: a bed. | Sleepable + /// Example: a computer. + | Usable of UsableItem /// Example: a TV. | Watchable /// Example: a t-shirt. diff --git a/src/Duets.Entities/Types/Situations.Types.fs b/src/Duets.Entities/Types/Situations.Types.fs index 3f9c9765..f08bb8b8 100644 --- a/src/Duets.Entities/Types/Situations.Types.fs +++ b/src/Duets.Entities/Types/Situations.Types.fs @@ -9,6 +9,11 @@ module SituationTypes = | Preparing of ConcertPreparationChecklist | InConcert of OngoingConcert + /// Situations in which the character is focused on something and cannot + /// interact with anything else. + /// TODO: Merge this and socializing? + type FocusSituation = UsingComputer of Item * Computer + /// Defines all situations in which the character can be in. type Situation = /// Player is exploring the world in no specific situation. @@ -17,6 +22,8 @@ module SituationTypes = | Airport of AirportSituation /// Player is performing a concert. | Concert of ConcertSituation + /// Player is focused on something. + | Focused of FocusSituation /// Playing a mini-game. | PlayingMiniGame of MiniGameState /// Player is in a conversation with an NPC. diff --git a/src/Duets.Simulation/Computer/Computer.fs b/src/Duets.Simulation/Computer/Computer.fs new file mode 100644 index 00000000..38afc801 --- /dev/null +++ b/src/Duets.Simulation/Computer/Computer.fs @@ -0,0 +1,17 @@ +module Duets.Simulation.Computer + +open Duets.Entities +open Duets.Entities.SituationTypes +open Duets.Simulation + +/// Opens an app on the given computer. +let openApp item computer app = + let updatedComputer = + { computer with + ComputerState = AppRunning app } + + let updatedItem = + Item.updateProperty (Usable(Computer updatedComputer)) item + + [ Diff(item, updatedItem) |> ItemChangedInCharacterInventory + Situations.focused (UsingComputer(updatedItem, updatedComputer)) ] diff --git a/src/Duets.Simulation/Duets.Simulation.fsproj b/src/Duets.Simulation/Duets.Simulation.fsproj index d64747dc..80afdd26 100644 --- a/src/Duets.Simulation/Duets.Simulation.fsproj +++ b/src/Duets.Simulation/Duets.Simulation.fsproj @@ -38,6 +38,8 @@ <Compile Include="Queries\Interactions\Interactions.Items.fs"/> <Compile Include="Queries\Interactions\Interactions.Casino.fs"/> <Compile Include="Queries\Interactions\Interactions.Career.fs"/> + <Compile Include="Queries\Interactions\Interactions.Computer.fs" /> + <Compile Include="Queries\Interactions\Interactions.Situational.fs" /> <Compile Include="Queries\Interactions\Interactions.Shop.fs"/> <Compile Include="Queries\Interactions\Interactions.Gym.fs"/> <Compile Include="Queries\Interactions\Interactions.MerchandiseWorkshop.fs"/> @@ -101,6 +103,7 @@ <Compile Include="Interactions\Items\Food.Interactions.fs"/> <Compile Include="Interactions\Items\Item.Interactions.fs"/> <Compile Include="Interactions\Sleep.fs"/> + <Compile Include="Computer\Computer.fs" /> <Compile Include="Concerts\DailyUpdate.fs"/> <Compile Include="Concerts\Scheduler.fs"/> <Compile Include="Concerts\OpeningActOpportunities.fs"/> diff --git a/src/Duets.Simulation/Interactions/Items/Item.Interactions.fs b/src/Duets.Simulation/Interactions/Items/Item.Interactions.fs index 2716ffe4..cd8e6201 100644 --- a/src/Duets.Simulation/Interactions/Items/Item.Interactions.fs +++ b/src/Duets.Simulation/Interactions/Items/Item.Interactions.fs @@ -70,6 +70,15 @@ let private (|ReadingBooks|_|) (action, item) = | _ -> None) | _ -> None +let private (|UsingComputer|_|) (action, item) = + match action with + | ItemInteraction.Use -> + item + |> Item.Property.tryPick (function + | Usable(Computer computer) -> Some computer + | _ -> None) + | _ -> None + let private (|WatchingTV|_|) (action, item) = match action with | ItemInteraction.Watch -> @@ -140,6 +149,19 @@ let perform state (item: Item) action = CharacterAttribute.Mood Config.LifeSimulation.Mood.readingBookIncrease ] |> Ok + | UsingComputer computer -> + [ + (* Set an initial booting to show the booting sequence first. *) + SituationTypes.UsingComputer(item, computer) |> Situations.focused + + (* Then switch to the app switcher. *) + SituationTypes.UsingComputer( + item, + { computer with + ComputerState = AppSwitcher } + ) + |> Situations.focused ] + |> Ok | WatchingTV -> Character.Attribute.add character diff --git a/src/Duets.Simulation/Queries/Interactions/InteractionCommon.fs b/src/Duets.Simulation/Queries/Interactions/InteractionCommon.fs index 80a3b4e3..6e59992e 100644 --- a/src/Duets.Simulation/Queries/Interactions/InteractionCommon.fs +++ b/src/Duets.Simulation/Queries/Interactions/InteractionCommon.fs @@ -36,6 +36,10 @@ module InteractionCommon = | Interaction.Concert _ -> true | Interaction.Item _ -> true | _ -> false + | Focused _ -> + match interaction with + | Interaction.Situational _ -> true + | _ -> false | PlayingMiniGame _ -> match interaction with | Interaction.MiniGame _ -> true diff --git a/src/Duets.Simulation/Queries/Interactions/InteractionTime.fs b/src/Duets.Simulation/Queries/Interactions/InteractionTime.fs index 7d521cf4..bd4cde3e 100644 --- a/src/Duets.Simulation/Queries/Interactions/InteractionTime.fs +++ b/src/Duets.Simulation/Queries/Interactions/InteractionTime.fs @@ -25,6 +25,7 @@ module InteractionTime = | ItemInteraction.Eat | ItemInteraction.Open | ItemInteraction.Put + | ItemInteraction.Use | ItemInteraction.Sleep (* Sleeping asks how long to sleep. *) -> 0<dayMoments> | Interaction.FreeRoam FreeRoamInteraction.Wait -> 1<dayMoments> diff --git a/src/Duets.Simulation/Queries/Interactions/Interactions.Computer.fs b/src/Duets.Simulation/Queries/Interactions/Interactions.Computer.fs new file mode 100644 index 00000000..330ffc97 --- /dev/null +++ b/src/Duets.Simulation/Queries/Interactions/Interactions.Computer.fs @@ -0,0 +1,11 @@ +namespace Duets.Simulation.Queries.Internal.Interactions + +open Duets.Common +open Duets.Entities + +module Computer = + let internal interaction item computer = + let apps = Union.allCasesOf<App> () + + [ ComputerInteraction.OpenApp(item, computer, apps) + |> Interaction.Situational ] diff --git a/src/Duets.Simulation/Queries/Interactions/Interactions.Items.fs b/src/Duets.Simulation/Queries/Interactions/Interactions.Items.fs index db2b1568..22543501 100644 --- a/src/Duets.Simulation/Queries/Interactions/Interactions.Items.fs +++ b/src/Duets.Simulation/Queries/Interactions/Interactions.Items.fs @@ -31,6 +31,7 @@ module rec Items = | Storage _ -> ItemInteraction.Open |> Interaction.Item |> Some | Sleepable -> ItemInteraction.Sleep |> Interaction.Item |> Some + | Usable _ -> ItemInteraction.Use |> Interaction.Item |> Some | Watchable -> ItemInteraction.Watch |> Interaction.Item |> Some | Wearable _ -> None (* TODO: Add "wear" interactions once we support buying clothes *) )) diff --git a/src/Duets.Simulation/Queries/Interactions/Interactions.Situational.fs b/src/Duets.Simulation/Queries/Interactions/Interactions.Situational.fs new file mode 100644 index 00000000..0ce06241 --- /dev/null +++ b/src/Duets.Simulation/Queries/Interactions/Interactions.Situational.fs @@ -0,0 +1,13 @@ +namespace Duets.Simulation.Queries.Internal.Interactions + +open Duets.Entities.SituationTypes +open Duets.Simulation + +module Situational = + let internal interaction state = + let currentSituation = Queries.Situations.current state + + match currentSituation with + | Focused(UsingComputer(item, computer)) -> + Computer.interaction item computer + | _ -> [] diff --git a/src/Duets.Simulation/Queries/Interactions/Interactions.Social.fs b/src/Duets.Simulation/Queries/Interactions/Interactions.Social.fs index 8628e7c0..7e89f813 100644 --- a/src/Duets.Simulation/Queries/Interactions/Interactions.Social.fs +++ b/src/Duets.Simulation/Queries/Interactions/Interactions.Social.fs @@ -39,4 +39,5 @@ module Social = | FreeRoam -> startConversationInteractions state (* Not available. *) | Concert _ + | Focused _ | PlayingMiniGame _ -> [] diff --git a/src/Duets.Simulation/Queries/Interactions/Interactions.fs b/src/Duets.Simulation/Queries/Interactions/Interactions.fs index e7abd8d2..c1b841e7 100644 --- a/src/Duets.Simulation/Queries/Interactions/Interactions.fs +++ b/src/Duets.Simulation/Queries/Interactions/Interactions.fs @@ -59,11 +59,14 @@ module Interactions = let clockInteraction = getClockInteraction state + let situationInteraction = Situational.interaction state + let defaultInteractions = clockInteraction :: itemInteractions @ freeRoamInteractions @ careerInteractions @ socialInteractions + @ situationInteraction let placeSpecificInteractions = match currentPlace.PlaceType with diff --git a/src/Duets.Simulation/Situations/Situations.fs b/src/Duets.Simulation/Situations/Situations.fs index d6ed1ed6..318b3add 100644 --- a/src/Duets.Simulation/Situations/Situations.fs +++ b/src/Duets.Simulation/Situations/Situations.fs @@ -24,6 +24,11 @@ let preparingConcert' checklist = /// concert situation. let inConcert ongoingConcert = InConcert ongoingConcert |> Concert |> SituationChanged + +/// Sets the current situation to focused, which makes the character focus +/// on a specific task and prevents them from doing other things. +let focused focusedState = + focusedState |> Focused |> SituationChanged /// Sets the current situation to inside of the plane, flying somewhere. let onboardedInPlane flight = diff --git a/src/Duets.Simulation/Skills/ImproveSkills.Composition.fs b/src/Duets.Simulation/Skills/ImproveSkills.Composition.fs index 9d390d80..f14d5918 100644 --- a/src/Duets.Simulation/Skills/ImproveSkills.Composition.fs +++ b/src/Duets.Simulation/Skills/ImproveSkills.Composition.fs @@ -5,7 +5,7 @@ open Duets.Simulation /// Grants a 50% chance of improving the composition, genre and instrument of /// all members of the band between 0 and 5, generated random for each member. -let improveBandSkillsChance band state = +let improveBandSkillsChance (band: Band) state = Queries.Bands.currentBandMembers state |> List.collect (fun currentMember -> Common.applySkillModificationChance diff --git a/tests/Simulation.Tests/Interactions/Read.Test.fs b/tests/Simulation.Tests/Interactions/Read.Test.fs index 144f6c1f..e4353c06 100644 --- a/tests/Simulation.Tests/Interactions/Read.Test.fs +++ b/tests/Simulation.Tests/Interactions/Read.Test.fs @@ -18,6 +18,7 @@ let private createBookItem readProgress = Properties = { Title = "Random Book" Author = "Random Author" + Genre = Drama BookEffects = [ SkillGain(SkillId.Barista, 10) MoodletGain(MoodletType.JetLagged, MoodletExpirationTime.Never) ]