diff options
Diffstat (limited to 'src/LivingVillage.Desktop')
| -rw-r--r-- | src/LivingVillage.Desktop/Game.fs | 8 | ||||
| -rw-r--r-- | src/LivingVillage.Desktop/M6Presentation.fs | 44 |
2 files changed, 38 insertions, 14 deletions
diff --git a/src/LivingVillage.Desktop/Game.fs b/src/LivingVillage.Desktop/Game.fs index 765cea8..e48888e 100644 --- a/src/LivingVillage.Desktop/Game.fs +++ b/src/LivingVillage.Desktop/Game.fs @@ -893,6 +893,14 @@ type LivingVillageGame() as this = VillageArt.drawGroundShadow spriteBatch pixel camera npc.Pos let spec = VillageArt.npcSpriteSpecAtTarget npc.Id npc.Pos npc.Mind.Target world.Tick VillageArt.drawCharacter spriteBatch artTextures camera npc.Pos spec profile.WorldTint + + // Golden-hour wash: the multiplicative WorldTint can only darken, so a warm + // premultiplied veil is layered over the whole scene. Because rgb is premultiplied + // by its own low alpha it adds warm light without ever saturating to white; alpha + // is a pure tick function, so noon/midnight get none and dawn/dusk peak warm. + let veilAlpha = M6Presentation.goldenVeilAlpha world.Tick + if veilAlpha > 0 then + spriteBatch.Draw(pixel, Rectangle(0, 0, viewport.Width, viewport.Height), VillageArt.premultiply 255 150 70 veilAlpha) spriteBatch.End() // Contextual floating prompt over the unique target; same CJK atlas font path as the HUD. diff --git a/src/LivingVillage.Desktop/M6Presentation.fs b/src/LivingVillage.Desktop/M6Presentation.fs index 752034a..25737d7 100644 --- a/src/LivingVillage.Desktop/M6Presentation.fs +++ b/src/LivingVillage.Desktop/M6Presentation.fs @@ -23,13 +23,17 @@ module M6Presentation = | Day -> "白天" | Night -> "夜晚" - // Transition windows in float hours. Dawn lingers past 6:00 and dusk begins before - // 20:00 so the blue hour is longer and the sky warms before it darkens; the anchors - // still agree with Sim.isNightTick (night >= 22:00 or < 6:00) once fully dark. + // Transition windows in float hours. Dawn lingers past 6:00 so the blue hour is long. + // Dusk keeps two independent ramps: the darkening ramp 20:00 -> 22:00 (still agrees with + // Sim.isNightTick at 22:00), and a wider golden-hour warmth bump peaking at 20:30. Keeping + // them separate is what makes the orange dusk visible: at 20:45 the scene is still only + // ~0.37 dark (Day mode) while warmth is high. let dawnStartHour = 4.0f let dawnEndHour = 6.5f - let duskStartHour = 19.5f + let duskStartHour = 20.0f let duskEndHour = 22.0f + let duskWarmthStartHour = 19.25f + let duskWarmthEndHour = 21.75f /// Continuous light blend: 0 = full day, 1 = full night. Deterministic pure function /// of the simulation tick, parameterised by the dawn/dusk windows above. @@ -53,23 +57,32 @@ module M6Presentation = let mid = (startHour + endHour) * 0.5f let half = (endHour - startHour) * 0.5f 1.0f - abs (hour - mid) / half - max (bump dawnStartHour dawnEndHour) (bump duskStartHour duskEndHour) + max (bump dawnStartHour dawnEndHour) (bump duskWarmthStartHour duskWarmthEndHour) + + /// Additive golden-hour veil alpha (0 at noon/midnight, peaks ~150 at dawn/dusk mid). + /// Multiplicative WorldTint alone cannot warm green foliage, so the renderer layers this + /// premultiplied orange wash over the finished world scene. + let goldenVeilAlpha (tick: int64) : int = + int (150.0f * transitionWarmth tick) let private lerp (a: int) (b: int) (blend: float32) : int = a + int (float32 (b - a) * blend) - /// Blended sky/world colour plus the golden-hour warmth shift (warm channels up, blue down). + /// Blended sky colour plus a strong golden-hour shift: at dusk this reads as a warm orange + /// horizon (red up hard, blue down hard) rather than the old muted blue-grey twilight. let backgroundAtWarmth (blend: float32) (warmth: float32) : Color = Color( - lerp 100 18 blend + int (52.0f * warmth), - lerp 160 25 blend + int (14.0f * warmth), - lerp 210 55 blend - int (34.0f * warmth)) + lerp 100 18 blend + int (120.0f * warmth), + lerp 160 25 blend + int (20.0f * warmth), + lerp 210 55 blend - int (90.0f * warmth)) + /// World tint also warms (red up, green slightly down, blue down) so tiles, props and + /// characters all lean golden before the additive veil is layered on top. let worldTintAtWarmth (blend: float32) (warmth: float32) : Color = Color( - lerp 255 118 blend + int (10.0f * warmth), - lerp 248 136 blend - int (6.0f * warmth), - lerp 224 184 blend - int (26.0f * warmth)) + lerp 255 118 blend + int (70.0f * warmth), + lerp 248 136 blend - int (10.0f * warmth), + lerp 224 184 blend - int (75.0f * warmth)) /// Warmth-free base colours (kept for callers that only have a blend value). let backgroundAtBlend (blend: float32) : Color = backgroundAtWarmth blend 0.0f @@ -83,7 +96,9 @@ module M6Presentation = Background = backgroundAtWarmth blend warmth Blend = blend WorldTint = worldTintAtWarmth blend warmth - LanternGlow = blend + // Lanterns glow through the golden hour too, so dusk reads as warm lanterns at a + // warm sunset rather than only a local night point-light. + LanternGlow = max blend (warmth * 0.8f) SkyWarmth = warmth } let profileAtTick (tick: int64) : M6RenderProfile = lightingAtTick tick @@ -122,10 +137,11 @@ module M6Presentation = sprintf "%02d:%02d" hour minute /// 时段标签:清晨/白天/黄昏/夜晚,与实际 tick 一致(纯函数)。 + /// 黄昏覆盖到 21:00,与 dusk 暖色窗口(峰值 20:30)对齐;22:00 起才是夜晚。 let timePeriodLabel (tick: int64) : string = let hour = hourOf tick if hour < 5 then "夜晚" elif hour < 8 then "清晨" elif hour < 17 then "白天" - elif hour < 20 then "黄昏" + elif hour < 21 then "黄昏" else "夜晚" |
