Skip to content

Commit

Permalink
✨ Timed turns (#30)
Browse files Browse the repository at this point in the history
* TPT implementation, career + songwriting migrated

* Drink interaction to timed-turn

* Eat interaction to timed-turns

* Exercise interaction to turn-timed

* Playing game interaction to timed-turns

* Reading book interaction to timed-turns

* Watch Tv interaction to timed-turns

* Flight interaction to timed-turns

* Concert preparation interactions to timed-turns

* Concert finish interaction to timed-turns

* Wait interaction to timed-turns

* Minigame interactions to timed-turns

* Practice interaction and others, 90 minutes per turn

* Recording interactions to timed-turns

* Social interactions timed-turns, cleanup

* Show time left on clock

* Adjust times

* Working tests

* Fix double wait time
  • Loading branch information
sleepyfran authored Oct 15, 2024
1 parent 90d91e8 commit 8d7685f
Show file tree
Hide file tree
Showing 50 changed files with 587 additions and 454 deletions.
13 changes: 13 additions & 0 deletions src/Duets.Cli/Components/Commands/Clock.Command.fs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
namespace Duets.Cli.Components.Commands

open Duets.Agents
open Duets.Cli.Components
open Duets.Cli.SceneIndex
open Duets.Cli.Text
open Duets.Common
open Duets.Entities
open Duets.Simulation

[<RequireQualifiedAccess>]
module ClockCommand =
Expand All @@ -19,6 +22,9 @@ module ClockCommand =
"Shows the current day moment and the number of day moments until the end of the day"
Handler =
(fun _ ->
let turnInfo =
Queries.Calendar.currentTurnInformation (State.get ())

dayMomentsWithEvents
|> List.indexed
|> List.fold
Expand Down Expand Up @@ -58,4 +64,11 @@ module ClockCommand =
|> Styles.highlight
|> showMessage

let formatDayMoment =
Generic.dayMomentName >> String.lowercase >> Styles.time

$"Spent {turnInfo.TimeSpent} minutes on {turnInfo.CurrentDayMoment |> formatDayMoment}. {turnInfo.TimeLeft} minutes until {turnInfo.NextDayMoment |> formatDayMoment}"
|> Styles.faded
|> showMessage

Scene.World) }
13 changes: 4 additions & 9 deletions src/Duets.Cli/Components/Commands/Help.Command.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,20 @@ open Duets.Entities
module HelpCommand =
/// Creates a command that shows the name and description of all given
/// commands as a list.
let create (commands: (int<dayMoments> * Command) list) =
let create (commands: Command list) =
{ Name = "help"
Description = Command.helpDescription
Handler =
fun _ ->
showMessage Command.helpDescription

let columns =
[ Styles.header "Command"
Styles.header "Description"
Styles.header Emoji.clock ]
[ Styles.header "Command"; Styles.header "Description" ]

let rows =
commands
|> List.map (fun (timeConsumption, command) ->
[ Styles.highlight command.Name
command.Description
if timeConsumption > 0<dayMoments> then
$"{timeConsumption}" ])
|> List.map (fun command ->
[ Styles.highlight command.Name; command.Description ])

showTable columns rows

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module LeaveCommand =
$"Allows you to leave the {Generic.miniGameName miniGameId} game"
Handler =
(fun _ ->
let result = Blackjack.leave (State.get ()) miniGameState
let result = Blackjack.leave miniGameState

match result with
| Ok effect -> effect |> Effect.applyMultiple
Expand Down
4 changes: 2 additions & 2 deletions src/Duets.Cli/Components/Effect.fs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ let private displayEffect effect =
let place = job.Location ||> Queries.World.placeInCityById

Career.careerPromoted job place.Name salary |> showMessage
| CareerShiftPerformed(_, payment) ->
| CareerShiftPerformed(_, _, payment) ->
Career.workShiftFinished payment |> showMessage
| CharacterAttributeChanged(_, attr, Diff(previous, current)) ->
match attr with
Expand Down Expand Up @@ -199,7 +199,7 @@ let private displayEffect effect =
"Choose where you want to go next" |> showMessage

showMapUntilChoice () |> applyMultiple
| PlayResult result ->
| GamePlayed result ->
lineBreak ()

let gameResultMessage simpleResult =
Expand Down
12 changes: 5 additions & 7 deletions src/Duets.Cli/Scenes/World.fs
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,7 @@ let private commandsFromInteractions interactions =
match interactionWithMetadata.State with
| InteractionState.Enabled -> command
| InteractionState.Disabled disabledReason ->
Command.disable disabledReason command
|> Tuple.two interactionWithMetadata.TimeAdvance)
Command.disable disabledReason command)

let private filterAttributesForInfoBar =
List.choose (fun (attr, amount) ->
Expand Down Expand Up @@ -275,11 +274,10 @@ let worldScene mode =
relationshipLevel
| _ -> Command.commonPrompt today currentDayMoment characterAttributes

let commandsWithMetadata =
let commands =
commandsFromInteractions interactionsWithState
@ [ (0<dayMoments>, ExitCommand.get); (0<dayMoments>, MeCommand.get) ]
@ [ ExitCommand.get; MeCommand.get ]

commandsWithMetadata
|> List.map snd
|> (@) [ HelpCommand.create commandsWithMetadata ]
commands
|> (@) [ HelpCommand.create commands ]
|> showCommandPrompt promptText
3 changes: 3 additions & 0 deletions src/Duets.Common/Func.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ module Duets.Common.Func

/// Transforms an F# function into a System.Func.
let toFunc<'a, 'b> f = System.Func<'a, 'b>(f)

/// Wraps a value in a function that ignores its input and returns the value.
let toConst<'a> (value: 'a) _ = value
14 changes: 13 additions & 1 deletion src/Duets.Entities/Calendar.fs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
module rec Duets.Entities.Calendar

open Duets.Common
open FSharp.Data.UnitSystems.SI.UnitNames
open Fugit.Shorthand
open Duets.Common
open System
open System.Globalization

Expand All @@ -27,8 +28,13 @@ let everyDay =
DayOfWeek.Sunday ]

module DayMoments =
/// Contains all the possible day moments in a week.
let oneWeek = Calendar.allDayMoments |> List.length |> (*) 7<dayMoments>

/// Transforms the given number of day moments into minutes.
let toMinutes dayMoments =
dayMoments / 1<dayMoments> * 180<minute>

[<RequireQualifiedAccess>]
module Ops =
/// Adds the given number of days to the date.
Expand Down Expand Up @@ -214,5 +220,11 @@ module Parse =
| "Midnight" -> Midnight
| _ -> EarlyMorning


[<RequireQualifiedAccess>]
module Seconds =
/// Transforms the given number of seconds into minutes.
let toMinutes seconds = (seconds / 60<second>) * 1<minute>

/// Returns the date in which the game starts.
let gameBeginning = Date.Now |> Transform.changeDayMoment EarlyMorning
4 changes: 4 additions & 0 deletions src/Duets.Entities/Lenses.fs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ module State =
let today_ =
(fun (s: State) -> s.Today), (fun v (s: State) -> { s with Today = v })

let turnMinutes_ =
(fun (s: State) -> s.TurnMinutes),
(fun v (s: State) -> { s with TurnMinutes = v })

let worldItems_ =
(fun (s: State) -> s.WorldItems),
(fun v (s: State) -> { s with WorldItems = v })
Expand Down
1 change: 1 addition & 0 deletions src/Duets.Entities/State.fs
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ let empty =
SocialNetworkCurrentAccountStatus.NoAccountCreated
Accounts = Map.empty } }
Today = Calendar.gameBeginning
TurnMinutes = 0<minute>
WorldItems = Map.empty }
19 changes: 17 additions & 2 deletions src/Duets.Entities/Types/Effect.Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,20 @@ module EffectTypes =
| AlbumReleased of Band * ReleasedAlbum
| AlbumReleasedUpdate of Band * ReleasedAlbum
| AlbumReviewsReceived of Band * ReleasedAlbum
| AlbumSongAdded of Band * UnreleasedAlbum * Recorded<Song>
| AlbumUpdated of Band * UnreleasedAlbum
| Ate of item: Item * food: EdibleItem
| BalanceUpdated of BankAccountHolder * Diff<Amount>
| BandFansChanged of Band * Diff<Fans>
| BandSwitchedGenre of Band * Diff<Genre>
| BookRead of Item * Book
| CareerAccept of CharacterId * Job
| CareerLeave of CharacterId * Job
| CareerPromoted of Job * salary: Amount
| CareerShiftPerformed of Job * payment: Amount
| CareerShiftPerformed of
Job *
shiftDuration: int<dayMoments> *
payment: Amount
| CharacterAttributeChanged of
character: CharacterId *
attribute: CharacterAttribute *
Expand All @@ -32,9 +38,14 @@ module EffectTypes =
| ConcertFinished of band: Band * concert: PastConcert * income: Amount
| ConcertUpdated of Band * ScheduledConcert
| ConcertCancelled of Band * PastConcert
| ConcertSoundcheckPerformed
| Drank of item: Item * drink: DrinkableItem
| Exercised of Item
| FlightBooked of Flight
| FlightUpdated of Flight
| FlightLanded of Flight
| GameCreated of State
| GamePlayed of PlayResult
| GenreMarketsUpdated of GenreMarketByGenre
| ItemAddedToCharacterInventory of Item
| ItemChangedInCharacterInventory of Diff<Item>
Expand All @@ -45,8 +56,10 @@ module EffectTypes =
| ItemRemovedFromWorld of RoomCoordinates * Item
| MerchPriceSet of band: Band * merchItem: Item * price: Amount
| MerchSold of band: Band * (Item * int<quantity>) list * income: Amount
| MerchStandSetup
| MemberHired of Band * Character * CurrentMember * SkillWithLevel list
| MemberFired of Band * CurrentMember * PastMember
| MiniGamePlayed of MiniGameId
| MoneyEarned of BankAccountHolder * BankTransaction
| MoneyTransferred of BankAccountHolder * BankTransaction
| NotificationScheduled of Date * DayMoment * Notification
Expand All @@ -61,6 +74,7 @@ module EffectTypes =
| RentalUpdated of Rental
| SituationChanged of Situation
| SkillImproved of Character * Diff<SkillWithLevel>
| SocialActionPerformed of SocializingState * SocialActionKind
| SocialNetworkAccountCreated of SocialNetworkKey * SocialNetworkAccount
| SocialNetworkAccountFollowersChanged of
SocialNetworkKey *
Expand All @@ -80,8 +94,9 @@ module EffectTypes =
| SongDiscarded of Band * Unfinished<Song>
| SongPracticed of Band * Finished<Song>
| PlaceClosed of Place
| PlayResult of PlayResult
| TimeAdvanced of Date
| TurnTimeUpdated of int<minute>
| WatchedTv of Item
/// Moves the player to a new room inside the current place.
| WorldEnterRoom of Diff<RoomCoordinates>
/// Moves the player to a different place in the current city or a
Expand Down
3 changes: 1 addition & 2 deletions src/Duets.Entities/Types/Interaction.Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,7 @@ module InteractionTypes =
/// of time that it'll take to perform it.
type InteractionWithMetadata =
{ Interaction: Interaction
State: InteractionState
TimeAdvance: int<dayMoments> }
State: InteractionState }

/// Defines a simple win/lose result for a non-interactive game.
[<RequireQualifiedAccess>]
Expand Down
2 changes: 2 additions & 0 deletions src/Duets.Entities/Types/State.Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@ module StateTypes =
Rentals: CharacterRentals
Situation: Situation
SocialNetworks: SocialNetworks
// TODO: Merge today and turn minutes into one property.
Today: Date
TurnMinutes: int<minute>
WorldItems: WorldItems }
5 changes: 1 addition & 4 deletions src/Duets.Simulation/Careers/Work.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ open Duets.Entities
open Duets.Simulation
open Duets.Simulation.Bank.Operations
open Duets.Simulation.Character
open Duets.Simulation.Time

let private workAttributeChange state (job: Job) =
let character = Queries.Characters.playableCharacter state
Expand Down Expand Up @@ -44,7 +43,6 @@ let workShift state job =
let characterAccount = Queries.Bank.playableCharacterAccount state

let shiftDayMoments = timeAdvancement state job
let timeEffects = AdvanceTime.advanceDayMoment' state shiftDayMoments

let shiftSalary =
job.CurrentStage.BaseSalaryPerDayMoment * decimal shiftDayMoments
Expand All @@ -53,7 +51,6 @@ let workShift state job =

let attributeEffects = workAttributeChange state job

[ yield CareerShiftPerformed(job, shiftSalary)
yield! timeEffects
[ yield CareerShiftPerformed(job, shiftDayMoments, shiftSalary)
yield shiftPay
yield! attributeEffects ]
8 changes: 6 additions & 2 deletions src/Duets.Simulation/Concerts/Live/Live.Actions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ let soundcheck state checklist =
Config.MusicSimulation.Merch.soundcheckTime
|> advanceDayMoment' state

[ Situations.preparingConcert' updatedChecklist; yield! timeEffects ]
[ ConcertSoundcheckPerformed
Situations.preparingConcert' updatedChecklist
yield! timeEffects ]


/// Sets up the merch stand, which improves the ticket sales of the concert.
Expand All @@ -35,7 +37,9 @@ let setupMerchStand state checklist =
Config.MusicSimulation.Merch.standSetupTime
|> advanceDayMoment' state

[ Situations.preparingConcert' updatedChecklist; yield! timeEffects ]
[ MerchStandSetup
Situations.preparingConcert' updatedChecklist
yield! timeEffects ]

/// Starts the given concert if the band is ready to play.
let startConcert state concert =
Expand Down
5 changes: 5 additions & 0 deletions src/Duets.Simulation/Config.fs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ module Revenue =
/// Indicates how many dd a band makes per stream.
let revenuePerStream = 0.0055

module Time =
/// Number of minutes that a day moment has, which is effectively the
/// number of minutes we allow the player to perform per turn.
let minutesPerDayMoment = 180<minute>

module Travel =
/// Price per kilometers for buying plane tickets.
let pricePerKm = 0.067m
Loading

0 comments on commit 8d7685f

Please sign in to comment.