diff options
Diffstat (limited to 'src/LivingVillage.Desktop/Game.fs')
| -rw-r--r-- | src/LivingVillage.Desktop/Game.fs | 77 |
1 files changed, 64 insertions, 13 deletions
diff --git a/src/LivingVillage.Desktop/Game.fs b/src/LivingVillage.Desktop/Game.fs index 6252117..3d04ca7 100644 --- a/src/LivingVillage.Desktop/Game.fs +++ b/src/LivingVillage.Desktop/Game.fs @@ -388,6 +388,10 @@ type LivingVillageGame() as this = let mutable p47Step = 0 let mutable p47PendingName = "" let mutable p47Pending = false + // P73 证据钩子:LV_P73_SHOT=1 时在同一生成器世界的桥头光源处,按 + // 6/12/18/22 时各拍一帧(同机位),四张真实帧用于四时段光照档差异核验。 + let p73ShotMode = Environment.GetEnvironmentVariable("LV_P73_SHOT") = "1" + let mutable p73Step = 0 // P52 证据钩子:LV_P52_SHOT=1 时选职业开局 → 走到 NPC 旁用真实 Interact 开对话 → // 真实 BuyFromTarget / SellToTarget 各一次,拍「对话入口 / 买入后 / 卖出后」三帧; // 每笔交易打印钱与背包数量前后值,供 analyze 脚本算 delta。 @@ -1474,7 +1478,39 @@ type LivingVillageGame() as this = let placeCameraOn (tileX: int) (tileY: int) = world <- { world with Avatar = { world.Avatar with Pos = { X = float32 (tileX * Sim.tilePixels); Y = float32 (tileY * Sim.tilePixels) } } } this.CenterCamera() - if not p47Pending then + if p73ShotMode then + // 同一桥头光源机位的四时段巡拍;tick 只经 setHour 改变,保证画面差异只来自光照档。 + let hours = [ ("p73-morning", 6.0); ("p73-noon", 12.0); ("p73-dusk", 18.0); ("p73-night", 22.0) ] + if p73Step < hours.Length then + match riverscapeMap with + | Some map -> + let pick = + SceneDetail.lightSources map + |> List.sortByDescending (fun (x, y, _) -> SceneDetail.reflectionLength map x y) + |> List.tryHead + let spot = match pick with Some (x, y, _) -> x, y | None -> map.Core.MinX, map.Core.MinY + let name, hour = hours.[p73Step] + setHour hour + placeCameraOn (fst spot) (snd spot) + p47PendingName <- name + let tint = (M6Presentation.profileAtTick world.Tick).WorldTint + printfn + "p73-shot=%s hour=%.1f tick=%d period=%s blend=%.3f lantern=%.2f tint=%d,%d,%d veil=%d" + name hour world.Tick + (M6Presentation.lightingPeriodName (M6Presentation.periodAtTick world.Tick)) + (M6Presentation.lightingBlend world.Tick) + (M6Presentation.effectiveLanternGlow world.Tick) + (int tint.R) (int tint.G) (int tint.B) + (M6Presentation.periodLightingAtTick world.Tick).VeilAlpha + p47Pending <- true + | None -> + printfn "p73-shot=error no-riverscape-map" + this.Exit() + else + printfn "p73-shot=done" + this.Exit() + () + elif not p47Pending then match riverscapeMap with | None -> this.Exit() | Some map -> @@ -1582,9 +1618,14 @@ type LivingVillageGame() as this = p47Pending <- false System.IO.Directory.CreateDirectory recordDirectory |> ignore this.SaveBackBuffer(sprintf "%s/%s.png" recordDirectory p47PendingName) - printfn "p47-shot=%s tick=%d pos=(%.0f,%.0f) camera=(%.0f,%.0f)" - p47PendingName world.Tick world.Avatar.Pos.X world.Avatar.Pos.Y camera.X camera.Y - p47Step <- p47Step + 1 + if p73ShotMode then + printfn "p73-frame=%s tick=%d pos=(%.0f,%.0f) camera=(%.0f,%.0f)" + p47PendingName world.Tick world.Avatar.Pos.X world.Avatar.Pos.Y camera.X camera.Y + p73Step <- p73Step + 1 + else + printfn "p47-shot=%s tick=%d pos=(%.0f,%.0f) camera=(%.0f,%.0f)" + p47PendingName world.Tick world.Avatar.Pos.X world.Avatar.Pos.Y camera.X camera.Y + p47Step <- p47Step + 1 /// P52 证据:选职业开局 → 真实 Interact 开对话 → 真实 BuyFromTarget / SellToTarget 各一次。 member private this.PrepareP52Shot () = @@ -2386,7 +2427,7 @@ type LivingVillageGame() as this = elif p57ShotMode then if menu.Page = MainMenu then this.PrepareP57Shot() - elif p47ShotMode then + elif p47ShotMode || p73ShotMode then if menu.Page = MainMenu then this.DispatchMenuInput Confirm elif menu.Page = OccupationSelect then @@ -2864,7 +2905,7 @@ type LivingVillageGame() as this = this.CaptureP46Shot() if p57ShotMode then this.CaptureP57Shot() - if p47ShotMode && menu.Page = Playing then + if (p47ShotMode || p73ShotMode) && menu.Page = Playing then this.CaptureP47Shot() if p52ShotMode && menu.Page = Playing then this.CaptureP52Shot() @@ -3126,6 +3167,10 @@ type LivingVillageGame() as this = member private this.DrawWorldView() = let profile = M6Presentation.profileAtTick world.Tick + // P73:时段档并入世界色调与灯光强度;正午档为恒等,不影响既有正午观感。 + let period = M6Presentation.periodLightingAtTick world.Tick + let worldTint = M6Presentation.multiplyTint profile.WorldTint period.AmbientTint + let lanternGlow = M6Presentation.effectiveLanternGlow world.Tick let viewport = this.GraphicsDevice.Viewport this.GraphicsDevice.Clear(profile.Background) spriteBatch.Begin() @@ -3145,14 +3190,14 @@ type LivingVillageGame() as this = renderPlan riverscapeMap world.Tick - profile.WorldTint + worldTint // Warm lantern / window glows strengthen as night falls (pure function of tick phase). // Concentric premultiplied circles follow a quadratic radial falloff (radius 3-4 tiles), // so the core stays a soft warm disc instead of saturating to a white block and no glow // is painted where there is no light entity. 生成器世界用桥头灯笼 + 民居门窗。 - if profile.LanternGlow > 0.3f then - let glow = profile.LanternGlow + if lanternGlow > 0.3f then + let glow = lanternGlow let peakAlpha = int (140.0f * glow) let tileX x = x * Sim.tilePixels - int camera.X let tileY y = y * Sim.tilePixels - int camera.Y @@ -3180,9 +3225,9 @@ type LivingVillageGame() as this = spriteBatch.Draw(pixel, rect, color) | _ -> () - match riverscapeMap, profile.LanternGlow > 0.3f with + match riverscapeMap, lanternGlow > 0.3f with | Some map, true -> - VillageArt.drawCc0BoatOverlay spriteBatch artTextures camera map profile.WorldTint + VillageArt.drawCc0BoatOverlay spriteBatch artTextures camera map worldTint | _ -> () // P47 场景细节:河道倒影 + 岸边芦苇加密度 + 漂浮元素 + 近景楼层层错落。 @@ -3202,12 +3247,12 @@ type LivingVillageGame() as this = VillageArt.drawGroundShadow spriteBatch pixel camera world.Avatar.Pos let avatarSpec = VillageArt.avatarSpriteSpec avatarFacing avatarMoving world.Tick - VillageArt.drawCharacter spriteBatch artTextures camera world.Avatar.Pos avatarSpec profile.WorldTint + VillageArt.drawCharacter spriteBatch artTextures camera world.Avatar.Pos avatarSpec worldTint for npc in world.Npcs do 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 + VillageArt.drawCharacter spriteBatch artTextures camera npc.Pos spec 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 @@ -3224,6 +3269,12 @@ type LivingVillageGame() as this = if moonAlpha > 0 then let mr, mg, mb = M6Presentation.moonlightRgb spriteBatch.Draw(pixel, Rectangle(0, 0, viewport.Width, viewport.Height), VillageArt.premultiply mr mg mb moonAlpha) + + // P73:时段档加性覆盖色,最后叠上,保证 6/12/18/22 四时段色调肉眼可辨; + // 正午 alpha=0 故为恒等,清晨偏冷、黄昏暖橙、夜晚冷蓝。 + if period.VeilAlpha > 0 then + let v = period.Veil + spriteBatch.Draw(pixel, Rectangle(0, 0, viewport.Width, viewport.Height), VillageArt.premultiply (int v.R) (int v.G) (int v.B) period.VeilAlpha) spriteBatch.End() // Contextual floating prompt over the unique target; same CJK atlas font path as the HUD. |
