diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/LivingVillage.Desktop.Tests/PrototypeTests.fs | 14 | ||||
| -rw-r--r-- | src/LivingVillage.Desktop/Game.fs | 26 | ||||
| -rw-r--r-- | src/LivingVillage.Desktop/M6Presentation.fs | 7 |
3 files changed, 36 insertions, 11 deletions
diff --git a/src/LivingVillage.Desktop.Tests/PrototypeTests.fs b/src/LivingVillage.Desktop.Tests/PrototypeTests.fs index 4d2c895..b250824 100644 --- a/src/LivingVillage.Desktop.Tests/PrototypeTests.fs +++ b/src/LivingVillage.Desktop.Tests/PrototypeTests.fs @@ -902,6 +902,20 @@ type PrototypeTests () = Assert.AreEqual<int64>(6L * ticksPerHour, M6Presentation.startTickForHour 6.0) [<TestMethod>] + member _.StartTickResolutionHonoursEvidenceHourThenDaylightThenMidnight () = + let ticksPerHour = Sim.ticksPerDay / 24L + + // P17-FIX: the evidence hour must win on the sample/autoplay path too, otherwise + // StartNewGame re-created the world at 00:00 and dusk/day shots were actually night. + Assert.AreEqual<int64>(M6Presentation.startTickForHour 20.75, M6Presentation.resolveStartTick (Some 20.75) false) + Assert.AreEqual<int64>(int64 20 * ticksPerHour + ticksPerHour * 3L / 4L, M6Presentation.resolveStartTick (Some 20.75) false) + // Explicit hour overrides the daylight bootstrap. + Assert.AreEqual<int64>(12L * ticksPerHour, M6Presentation.resolveStartTick (Some 12.0) true) + // No override: daylight -> 6:00, otherwise midnight. + Assert.AreEqual<int64>(6L * ticksPerHour, M6Presentation.resolveStartTick None true) + Assert.AreEqual<int64>(0L, M6Presentation.resolveStartTick None false) + + [<TestMethod>] member _.TitleEntranceProgressIsDeterministicAndCompleteAfterTwoSeconds () = // 120 frames at the fixed 60Hz step = 2s entrance, pure function of frame count. Assert.AreEqual<float32>(1.0f, TitleScreen.entranceProgress 0L) diff --git a/src/LivingVillage.Desktop/Game.fs b/src/LivingVillage.Desktop/Game.fs index 4760d4e..765cea8 100644 --- a/src/LivingVillage.Desktop/Game.fs +++ b/src/LivingVillage.Desktop/Game.fs @@ -134,13 +134,16 @@ type LivingVillageGame() as this = match Double.TryParse(value, Globalization.NumberStyles.Float, Globalization.CultureInfo.InvariantCulture) with | true, hour -> Some hour | _ -> None + // Single source of truth for the starting tick so the sample/autoplay path (which + // re-creates the world via StartNewGame) honours the evidence hour too. + let evidenceStartTick () = + M6Presentation.resolveStartTick startHourOverride daylightAutoplay + let withStartTick (world: World) : World = + let tick = evidenceStartTick () + { world with Tick = tick; Time = float tick * Sim.dtSeconds } let createInitialWorld () = - let baseWorld = WorldBootstrap.initialWorldForDaylight daylightAutoplay 42UL Sim.npcCount - match startHourOverride with - | Some hour -> - let tick = M6Presentation.startTickForHour hour - { baseWorld with Tick = tick; Time = float tick * Sim.dtSeconds } - | None -> baseWorld + WorldBootstrap.initialWorldForDaylight daylightAutoplay 42UL Sim.npcCount + |> withStartTick let mutable world = createInitialWorld () let mutable camera = Vector2.Zero let mutable avatarFacing = VillageArt.SouthFacing @@ -223,17 +226,18 @@ type LivingVillageGame() as this = this.CenterCamera() member private this.StartNewGame (occupation: Occupation.Kind option) = + let startTick = evidenceStartTick () let state = occupation - |> Option.map (fun kind -> - let startTick = if daylightAutoplay then 6L * Sim.ticksPerDay / 24L else 0L - WorldBootstrap.occupationStateFor 42UL kind startTick) - world <- WorldBootstrap.initialWorldWithOccupation daylightAutoplay 42UL Sim.npcCount state + |> Option.map (fun kind -> WorldBootstrap.occupationStateFor 42UL kind startTick) + world <- + WorldBootstrap.initialWorldWithOccupation daylightAutoplay 42UL Sim.npcCount state + |> withStartTick this.ResetWorldView() m5View <- { m5View with Task = state } menu <- menu |> MenuState.setCurrentWorld true |> MenuState.enterGame let occupationName = occupation |> Option.map Occupation.nameOf |> Option.defaultValue "none" - printfn $"new-game=ok seed=42 npcs={Sim.npcCount} occupation={occupationName}" + printfn $"new-game=ok seed=42 npcs={Sim.npcCount} occupation={occupationName} tick={world.Tick}" member private this.SaveWorld (prefix: string) : bool = try diff --git a/src/LivingVillage.Desktop/M6Presentation.fs b/src/LivingVillage.Desktop/M6Presentation.fs index a64d494..752034a 100644 --- a/src/LivingVillage.Desktop/M6Presentation.fs +++ b/src/LivingVillage.Desktop/M6Presentation.fs @@ -104,6 +104,13 @@ module M6Presentation = let startTickForHour (hour: float) : int64 = int64 (hour * float (Sim.ticksPerDay / 24L)) + /// Start-tick decision shared by bootstrap and new-game: an explicit evidence hour wins, + /// else daylight starts at 6:00, else midnight. Pure function, no side effects. + let resolveStartTick (startHour: float option) (startAtDaylight: bool) : int64 = + match startHour with + | Some hour -> startTickForHour hour + | None -> if startAtDaylight then 6L * Sim.ticksPerDay / 24L else 0L + let private hourOf (tick: int64) : int = int ((tick / (Sim.ticksPerDay / 24L)) % 24L) |
