Skip to content

Commit

Permalink
✨ Do not kick out characters from certain places
Browse files Browse the repository at this point in the history
- If a character has a concert in the place (or has had one recently)
- If a character works in the place
  • Loading branch information
sleepyfran committed Nov 13, 2023
1 parent a5e971c commit c912722
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 18 deletions.
7 changes: 7 additions & 0 deletions src/Duets.Entities/World.fs
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,10 @@ module Room =
let removeRequiredItemForEntrance room =
{ room with
RequiredItemsForEntrance = None }

[<RequireQualifiedAccess>]
module Coordinates =
/// Returns the PlaceCoordinates of the given room coordinates.
let toPlaceCoordinates (coords: RoomCoordinates) : PlaceCoordinates =
let cityId, placeId, _ = coords
cityId, placeId
27 changes: 25 additions & 2 deletions src/Duets.Simulation/Events/Place/ClosingTime.fs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module Duets.Simulation.Events.Place.ClosingTime (* Open all the doors and let you out into the wooooorld... *)
module rec Duets.Simulation.Events.Place.ClosingTime (* Open all the doors and let you out into the wooooorld... *)

open Duets.Entities
open Duets.Simulation
Expand All @@ -12,7 +12,30 @@ let checkCurrentPlace state =
let currentlyClosed =
Queries.World.placeCurrentlyOpen currentPlace currentTime |> not

if currentlyClosed then
let skipKickingOut = shouldPreserveCharacterInPlace state

if currentlyClosed && not skipKickingOut then
[ Effect.PlaceClosed currentPlace ]
else
[]

// Returns true if the character should not be kicked out of the place.
let private shouldPreserveCharacterInPlace state =
let currentCoordinates =
Queries.World.currentCoordinates state
|> World.Coordinates.toPlaceCoordinates

let isWorkplace () =
match Queries.Career.current state with
| Some job -> job.Location = currentCoordinates
| None -> false

let hasConcertInPlace () =
let bandId = Queries.Bands.currentBandId state
let cityId, placeId = currentCoordinates

Queries.Concerts.scheduledAroundDate state bandId
|> List.exists (fun concert ->
concert.CityId = cityId && concert.VenueId = placeId)

[ isWorkplace; hasConcertInPlace ] |> List.exists (fun fn -> fn ())
1 change: 1 addition & 0 deletions src/Duets.Simulation/Queries/Career.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ open Duets.Entities

/// Returns the current career in which the character works, if any.
let current = Optic.get Lenses.State.career_

2 changes: 1 addition & 1 deletion src/Duets.Simulation/Queries/Concerts.fs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ let scheduledAroundDate state bandId =

let aroundCurrentDate concert =
let spanBetween = concert.Date - today
if spanBetween.Days <= 1 then Some concert else None
if abs(spanBetween.Days) <= 1 then Some concert else None

let concertsScheduledAroundCurrentDate =
timeline.ScheduledEvents
Expand Down
202 changes: 202 additions & 0 deletions tests/Simulation.Tests/Events/ClosingTime.Events.Tests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
module Duets.Simulation.Tests.Events.ClosingTime

open FsCheck
open FsUnit
open NUnit.Framework
open Test.Common
open Test.Common.Generators

open Duets.Common
open Duets.Data
open Duets.Entities
open Duets.Simulation

let private cafe =
Queries.World.placesByTypeInCity Prague PlaceTypeIndex.Cafe |> List.head

let private concertSpace =
Queries.World.placesByTypeInCity Prague PlaceTypeIndex.ConcertSpace
|> List.head

let private cafeCareer =
{ Id = Barista
CurrentStage = (Careers.BaristaCareer.stages |> List.head)
Location = Prague, cafe.Id }

let nearClosingTime = dummyToday |> Calendar.Transform.changeDayMoment Evening
let closingTime = nearClosingTime |> Calendar.Query.next
let timeAdvancedEffect = TimeAdvanced(closingTime)

let private initialState =
dummyState
|> State.World.move Prague cafe.Id 0
|> State.Calendar.setTime nearClosingTime

[<Test>]
let ``tick of advance day moment kicks the character out of the place if it has closed``
()
=
Simulation.tickOne initialState timeAdvancedEffect
|> fst
|> List.filter (function
| PlaceClosed _ -> true
| _ -> false)
|> should haveLength 1

[<Test>]
let ``tick of advance day moment does not kick the character if they work there``
()
=
let state = initialState |> State.Career.set (Some cafeCareer)

Simulation.tickOne state timeAdvancedEffect
|> fst
|> List.filter (function
| PlaceClosed _ -> true
| _ -> false)
|> should haveLength 0

[<Test>]
let ``tick of advance day moment does not kick the character if they had a concert there``
()
=
let concert =
Concert.generator
{ From = dummyToday
To = dummyToday
City = Prague
Venue = cafe.Id
DayMoment = Evening }
|> Gen.sample 1 1
|> List.head

let band = Queries.Bands.currentBand initialState

let state =
initialState
|> State.Concerts.addPastConcert
band
(PerformedConcert(concert, 100<quality>))

Simulation.tickOne state timeAdvancedEffect
|> fst
|> List.filter (function
| PlaceClosed _ -> true
| _ -> false)
|> should haveLength 0

[<Test>]
let ``tick of advance day moment kicks out the character if they had a concert there but it was more than a day ago``
()
=
let concert =
Concert.generator
{ From = dummyToday |> Calendar.Ops.addDays -5
To = dummyToday |> Calendar.Ops.addDays -3
City = Prague
Venue = cafe.Id
DayMoment = Evening }
|> Gen.sample 1 1
|> List.head

let band = Queries.Bands.currentBand initialState

let state =
initialState
|> State.Concerts.addPastConcert
band
(PerformedConcert(concert, 100<quality>))

Simulation.tickOne state timeAdvancedEffect
|> fst
|> List.filter (function
| PlaceClosed _ -> true
| _ -> false)
|> should haveLength 1

[<Test>]
let ``tick of advance day moment kicks out the character if they have a concert scheduled there but it is in more than a day``
()
=
let concert =
Concert.generator
{ From = dummyToday |> Calendar.Ops.addDays 2
To = dummyToday |> Calendar.Ops.addDays 5
City = Prague
Venue = cafe.Id
DayMoment = Evening }
|> Gen.sample 1 1
|> List.head

let band = Queries.Bands.currentBand initialState

let state =
initialState
|> State.Concerts.addScheduledConcert
band
(ScheduledConcert(concert, dummyToday))

Simulation.tickOne state timeAdvancedEffect
|> fst
|> List.filter (function
| PlaceClosed _ -> true
| _ -> false)
|> should haveLength 1

[<Test>]
let ``tick of advance day moment kicks out the character if they had a concert but was in a different place``
()
=
let concert =
Concert.generator
{ From = dummyToday
To = dummyToday
City = Sydney
Venue = cafe.Id
DayMoment = Evening }
|> Gen.sample 1 1
|> List.head

let band = Queries.Bands.currentBand initialState

let state =
initialState
|> State.Concerts.addPastConcert
band
(PerformedConcert(concert, 100<quality>))

Simulation.tickOne state timeAdvancedEffect
|> fst
|> List.filter (function
| PlaceClosed _ -> true
| _ -> false)
|> should haveLength 1

[<Test>]
let ``tick of advance day moment kicks out the character if they have a concert scheduled but is in a different place``
()
=
let concert =
Concert.generator
{ From = dummyToday
To = dummyToday
City = Sydney
Venue = cafe.Id
DayMoment = Evening }
|> Gen.sample 1 1
|> List.head

let band = Queries.Bands.currentBand initialState

let state =
initialState
|> State.Concerts.addScheduledConcert
band
(ScheduledConcert(concert, dummyToday))

Simulation.tickOne state timeAdvancedEffect
|> fst
|> List.filter (function
| PlaceClosed _ -> true
| _ -> false)
|> should haveLength 1
31 changes: 16 additions & 15 deletions tests/Simulation.Tests/Simulation.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@
<Compile Include="Albums\ReviewGeneration.Tests.fs" />
<Compile Include="Bands\HireMember.Tests.fs" />
<Compile Include="Bands\FireMember.Tests.fs" />
<Compile Include="Bands\BandGeneration.Tests.fs"/>
<Compile Include="Bands\DistributeFunds.Tests.fs"/>
<Compile Include="Bands\BandGeneration.Tests.fs" />
<Compile Include="Bands\DistributeFunds.Tests.fs" />
<Compile Include="Bank\Transfer.Tests.fs" />
<Compile Include="Bank\Queries.Tests.fs" />
<Compile Include="Careers\JobBoard.Test.fs"/>
<Compile Include="Careers\Work.Test.fs"/>
<Compile Include="Careers\JobBoard.Test.fs" />
<Compile Include="Careers\Work.Test.fs" />
<Compile Include="Concerts\DailyUpdate.Tests.fs" />
<Compile Include="Concerts\Live.PlaySong.Tests.fs" />
<Compile Include="Concerts\Live.GreetAudience.Tests.fs" />
<Compile Include="Concerts\Live.DedicateSong.Tests.fs" />
<Compile Include="Concerts\Live.Finish.Tests.fs" />
<Compile Include="Concerts\OpeningActOpportunities.Tests.fs"/>
<Compile Include="Concerts\Live.Encore.Tests.fs"/>
<Compile Include="Concerts\OpeningActOpportunities.Tests.fs" />
<Compile Include="Concerts\Live.Encore.Tests.fs" />
<Compile Include="Market\GenreMarket.Tests.fs" />
<Compile Include="MiniGames\Blackjack.Tests.fs"/>
<Compile Include="MiniGames\Blackjack.Tests.fs" />
<Compile Include="Notifications\Notification.Tests.fs" />
<Compile Include="Time\AdvanceTime.Tests.fs" />
<Compile Include="SocialNetworks\DailyUpdate.Tests.fs" />
Expand All @@ -60,17 +60,18 @@
<Compile Include="Studio\RenameAlbum.Tests.fs" />
<Compile Include="Interactions\Drink.Interactions.Test.fs" />
<Compile Include="Interactions\Food.Interactions.Test.fs" />
<Compile Include="Interactions\Exercise.Interactions.Test.fs"/>
<Compile Include="Interactions\Sleep.Test.fs"/>
<Compile Include="Interactions\Play.Interactions.Test.fs"/>
<Compile Include="Interactions\Exercise.Interactions.Test.fs" />
<Compile Include="Interactions\Sleep.Test.fs" />
<Compile Include="Interactions\Play.Interactions.Test.fs" />
<Compile Include="Events\Character.Events.Tests.fs" />
<Compile Include="Events\Band.Events.Tests.fs"/>
<Compile Include="Events\Rental.Events.Tests.fs"/>
<Compile Include="Events\Career.Events.Tests.fs"/>
<Compile Include="Events\World.Events.Tests.fs"/>
<Compile Include="Events\ClosingTime.Events.Tests.fs" />
<Compile Include="Events\Band.Events.Tests.fs" />
<Compile Include="Events\Rental.Events.Tests.fs" />
<Compile Include="Events\Career.Events.Tests.fs" />
<Compile Include="Events\World.Events.Tests.fs" />
<Compile Include="Events\Moodlets\JetLagged.Moodlet.Events.Tests.fs" />
<Compile Include="Events\Moodlets\NotInspired.Moodlet.Events.Tests.fs" />
<Compile Include="EffectModifiers\Moodlet.EffectModifiers.Tests.fs"/>
<Compile Include="EffectModifiers\Moodlet.EffectModifiers.Tests.fs" />
<Compile Include="Simulation.Tests.fs" />
<Compile Include="Program.fs" />
</ItemGroup>
Expand Down

0 comments on commit c912722

Please sign in to comment.