summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop/Game.fs
diff options
context:
space:
mode:
Diffstat (limited to 'src/LivingVillage.Desktop/Game.fs')
-rw-r--r--src/LivingVillage.Desktop/Game.fs94
1 files changed, 94 insertions, 0 deletions
diff --git a/src/LivingVillage.Desktop/Game.fs b/src/LivingVillage.Desktop/Game.fs
index a0e6fc0..ba925f3 100644
--- a/src/LivingVillage.Desktop/Game.fs
+++ b/src/LivingVillage.Desktop/Game.fs
@@ -343,6 +343,12 @@ type LivingVillageGame() as this =
let mutable p65Step = 0
let mutable p65PendingName = ""
let mutable p65Pending = false
+ // P67 证据钩子(职业每日任务 UI 目标展示):农夫真实开局 → 找到当日「帮工」任务 →
+ // 拍带目标帧(帮工:… → 村民 N)与同模板无目标帧(帮工:…,文案与旧版逐字节一致)各一帧。
+ let p67ShotMode = Environment.GetEnvironmentVariable("LV_P67_SHOT") = "1"
+ let mutable p67Step = 0
+ let mutable p67PendingName = ""
+ let mutable p67Pending = false
// P45 证据钩子:LV_P45_SHOT=1 时拍角色 idle / 行走朝下 / 行走朝右 三帧(真实游戏截图)。
let p45ShotMode = Environment.GetEnvironmentVariable("LV_P45_SHOT") = "1"
let mutable p45Step = 0
@@ -1238,6 +1244,84 @@ type LivingVillageGame() as this =
m5View.Status
p65Step <- p65Step + 1
+ /// P67 证据:任务面板的目标展示(带目标 / 无目标各一帧),走真实每日任务纯函数生成的 DailyTask。
+ member private this.PrepareP67Shot () =
+ let noonOfDay (day: int64) : int64 =
+ day * Sim.ticksPerDay + M6Presentation.resolveStartTick (Some 12.0) false
+ let targets = WorldBootstrap.reachableTargets world
+ let dayTask (day: int64) (targeted: bool) =
+ if targeted then
+ Occupation.dailyTaskOfWith targets 42UL (Occupation.occupationSeedOf Occupation.Farmer) day Occupation.Farmer
+ else
+ Occupation.dailyTaskOf 42UL (Occupation.occupationSeedOf Occupation.Farmer) day Occupation.Farmer
+ // 找一天当日任务为「帮工」(有目标语义),使两帧同模板可直接对照。
+ let mutable helpDay = 0L
+ let mutable found = false
+ for day in 0L .. 120L do
+ if not found then
+ match dayTask day true with
+ | Some task when task.TemplateId = Occupation.HelpWork -> helpDay <- day; found <- true
+ | _ -> ()
+ let setToday (task: Occupation.DailyTask) =
+ match m5View.Task with
+ | Some state -> m5View <- { m5View with Task = Some { state with Today = Some task } }
+ | None -> ()
+ let ask (command: M5Command) =
+ let nextWorld, nextView = M5Interaction.apply command world m5View
+ world <- nextWorld
+ m5View <- nextView
+ if not p67Pending then
+ match p67Step with
+ | 0 ->
+ let tick = noonOfDay helpDay
+ world <- { world with Tick = tick; Time = float tick * Sim.dtSeconds }
+ match dayTask helpDay true with
+ | Some task -> setToday task
+ | None -> ()
+ ask M5Command.ShowTaskPanel
+ this.CenterCamera()
+ p67PendingName <- "p67-target"
+ p67Pending <- true
+ | 1 ->
+ match dayTask helpDay false with
+ | Some task -> setToday task
+ | None -> ()
+ p67PendingName <- "p67-wildcard"
+ p67Pending <- true
+ | _ ->
+ printfn "p67-shot=done"
+ this.Exit()
+
+ /// P67 证据:落盘并打印帧名/面板/模板/目标/整行文案/缺字槽位,供 analyze 核验。
+ member private this.CaptureP67Shot () =
+ if p67Pending then
+ p67Pending <- false
+ System.IO.Directory.CreateDirectory recordDirectory |> ignore
+ this.SaveBackBuffer(sprintf "%s/%s.png" recordDirectory p67PendingName)
+ let lines = M5Interaction.panelLines world m5View
+ let missingSlots =
+ lines
+ |> List.sumBy (fun line ->
+ line
+ |> Seq.filter (fun c -> c <> ' ' && not (PixelText.isRenderable (string c)))
+ |> Seq.length)
+ let templateText, targetText, lineText =
+ match m5View.Task |> Option.bind (fun state -> state.Today) with
+ | None -> "none", "<none>", "<none>"
+ | Some task ->
+ Occupation.taskNameOf task.TemplateId,
+ (TaskRuntime.targetText task |> Option.defaultValue "<none>"),
+ (TaskRuntime.taskLine task "进行中")
+ printfn
+ "p67-shot=%s panel=%s template=%s target=%s line=%s missing_glyph_slots=%d"
+ p67PendingName
+ (M5Interaction.panelName m5View)
+ templateText
+ targetText
+ lineText
+ missingSlots
+ p67Step <- p67Step + 1
+
member private this.PrepareP45Shot () =
let baseTick = M6Presentation.resolveStartTick (Some 12.0) false
let setTick (tick: int64) =
@@ -2255,6 +2339,14 @@ type LivingVillageGame() as this =
else this.DispatchMenuInput Confirm
elif menu.Page = Playing then
this.PrepareP65Shot()
+ elif p67ShotMode then
+ if menu.Page = MainMenu then
+ this.DispatchMenuInput Confirm
+ elif menu.Page = OccupationSelect then
+ if menu.Selected <> 0 then this.DispatchMenuInput Down
+ else this.DispatchMenuInput Confirm
+ elif menu.Page = Playing then
+ this.PrepareP67Shot()
elif p45ShotMode then
if menu.Page = MainMenu then
this.DispatchMenuInput Confirm
@@ -2733,6 +2825,8 @@ type LivingVillageGame() as this =
this.CaptureP64Shot()
if p65ShotMode && menu.Page = Playing then
this.CaptureP65Shot()
+ if p67ShotMode && menu.Page = Playing then
+ this.CaptureP67Shot()
if p45ShotMode && menu.Page = Playing then
this.CaptureP45Shot()
if p46ShotMode then