summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop
diff options
context:
space:
mode:
Diffstat (limited to 'src/LivingVillage.Desktop')
-rw-r--r--src/LivingVillage.Desktop/Game.fs15
-rw-r--r--src/LivingVillage.Desktop/M6Presentation.fs45
2 files changed, 50 insertions, 10 deletions
diff --git a/src/LivingVillage.Desktop/Game.fs b/src/LivingVillage.Desktop/Game.fs
index 1d50f3d..9464c8b 100644
--- a/src/LivingVillage.Desktop/Game.fs
+++ b/src/LivingVillage.Desktop/Game.fs
@@ -676,6 +676,21 @@ type LivingVillageGame() as this =
world.Tick
profile.WorldTint
+ // Warm lantern glows strengthen as night falls (pure function of tick phase).
+ if profile.LanternGlow > 0.3f then
+ let glow = profile.LanternGlow
+ let haloAlpha = int (90.0f * glow)
+ for prop in renderPlan.Props do
+ match prop.Kind with
+ | RiverLantern ->
+ let position = VillageArt.worldTile renderPlan prop.Position
+ let screenX = position.X * Sim.tilePixels - int camera.X + Sim.tilePixels / 2
+ let screenY = position.Y * Sim.tilePixels - int camera.Y - Sim.tilePixels / 2
+ spriteBatch.Draw(pixel, Rectangle(screenX - 22, screenY - 22, 60, 60), Color(252, 216, 148, int (float32 haloAlpha * 0.35f)))
+ spriteBatch.Draw(pixel, Rectangle(screenX - 14, screenY - 14, 44, 44), Color(252, 216, 148, haloAlpha))
+ spriteBatch.Draw(pixel, Rectangle(screenX - 8, screenY - 8, 32, 32), Color(255, 236, 180, haloAlpha))
+ | _ -> ()
+
let avatarSpec = VillageArt.avatarSpriteSpec avatarFacing world.Tick
VillageArt.drawCharacter spriteBatch artTextures camera world.Avatar.Pos avatarSpec profile.WorldTint
diff --git a/src/LivingVillage.Desktop/M6Presentation.fs b/src/LivingVillage.Desktop/M6Presentation.fs
index 8e13183..ea8fd2f 100644
--- a/src/LivingVillage.Desktop/M6Presentation.fs
+++ b/src/LivingVillage.Desktop/M6Presentation.fs
@@ -11,7 +11,9 @@ type M6DayNight =
type M6RenderProfile =
{ Mode: M6DayNight
Background: Color
- WorldTint: Color }
+ WorldTint: Color
+ Blend: float32
+ LanternGlow: float32 }
module M6Presentation =
@@ -20,15 +22,38 @@ module M6Presentation =
| Day -> "白天"
| Night -> "夜晚"
- let profileAtTick (tick: int64) : M6RenderProfile =
- if Sim.isNightTick tick then
- { Mode = Night
- Background = Color(18, 25, 55)
- WorldTint = Color(118, 136, 184) }
- else
- { Mode = Day
- Background = Color(100, 160, 210)
- WorldTint = Color(255, 248, 224) }
+ /// Continuous light blend: 0 = full day, 1 = full night. Ramps are deterministic
+ /// pure functions of the simulation tick (dawn 4:00-6:00, dusk 20:00-22:00), so the
+ /// boundaries agree with Sim.isNightTick (night >= 22:00 or < 6:00).
+ let lightingBlend (tick: int64) : float32 =
+ let hourTicks = Sim.ticksPerDay / 24L
+ let hour = float32 (tick / hourTicks)
+ let clamp01 v = if v < 0.0f then 0.0f elif v > 1.0f then 1.0f else v
+ if hour >= 6.0f && hour < 20.0f then 0.0f
+ elif hour >= 22.0f then 1.0f
+ elif hour < 4.0f then 1.0f
+ elif hour < 6.0f then clamp01 (1.0f - (hour - 4.0f) / 2.0f)
+ else clamp01 ((hour - 20.0f) / 2.0f)
+
+ let private lerp (a: int) (b: int) (blend: float32) : int =
+ a + int (float32 (b - a) * blend)
+
+ let backgroundAtBlend (blend: float32) : Color =
+ Color(lerp 100 18 blend, lerp 160 25 blend, lerp 210 55 blend)
+
+ let worldTintAtBlend (blend: float32) : Color =
+ Color(lerp 255 118 blend, lerp 248 136 blend, lerp 224 184 blend)
+
+ /// Pure day-phase lighting: deterministic tint/background plus lantern warm-glow boost.
+ let lightingAtTick (tick: int64) : M6RenderProfile =
+ let blend = lightingBlend tick
+ { Mode = if blend < 0.5f then Day else Night
+ Background = backgroundAtBlend blend
+ Blend = blend
+ WorldTint = worldTintAtBlend blend
+ LanternGlow = blend }
+
+ let profileAtTick (tick: int64) : M6RenderProfile = lightingAtTick tick
let clockLabel (control: SimulationControl) : string =
if control.Paused then