diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-22 16:33:03 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-22 16:33:03 +0800 |
| commit | 9821b54ff2a77539898b62471d79dc4685b59cad (patch) | |
| tree | ffd5fb63883dd05b80fca5729af74be41df3a04d /src/LivingVillage.Desktop/Interaction.fs | |
| parent | 0539bba17c260f6a4b51d3cefddac0ff448c19bc (diff) | |
| download | living-village-9821b54ff2a77539898b62471d79dc4685b59cad.tar.gz | |
feat(kernel,desktop): P31 step3 story annals + identity entry + glyph atlas
- Sim.AnnalKind gains StoryAnnal (summary lives in the existing Summary
field); WorldSave v3 serializes it with the new 'story' token. v1/v2
saves never contain the token and stay byte-identical; v3 save -> load
-> save roundtrips byte-for-byte (tested).
- Occupation.Story.identitySummaryOf: plain chronicle-style identity line
written to the yearbook at game start (design section 3), e.g. yi-da-yu-wei-sheng.
- Desktop: story summaries render in the chronicle panel; StartNewGame
appends the identity annal; chooseIntent now routes responses through
Occupation.biasResponse and advances the storyline (one stage per
player dialogue) with the summary appended as a StoryAnnal.
- M5View gains Seed (world seed source for the story start-day hash).
- Chinese copy synced into requiredUiLabels; cjk-glyphs.txt +
CjkGlyphAtlas.characterTable extended 238 -> 307 glyphs (384x480),
atlas regenerated with the deterministic script.
- 4 new kernel tests (115 -> 119); performance digest unchanged.
Diffstat (limited to 'src/LivingVillage.Desktop/Interaction.fs')
| -rw-r--r-- | src/LivingVillage.Desktop/Interaction.fs | 36 |
1 files changed, 30 insertions, 6 deletions
diff --git a/src/LivingVillage.Desktop/Interaction.fs b/src/LivingVillage.Desktop/Interaction.fs index dd372ef..bfe26c8 100644 --- a/src/LivingVillage.Desktop/Interaction.fs +++ b/src/LivingVillage.Desktop/Interaction.fs @@ -49,7 +49,9 @@ type M5View = HomeMode: HomeMode Prompt: string option PromptTargetPos: Vec2 option - Task: Occupation.State option } + Task: Occupation.State option + /// 世界种子(与 Game.fs 的开局种子同源),供剧情线开线日哈希使用。 + Seed: uint64 } module InteractionResolver = @@ -211,7 +213,8 @@ module M5Interaction = HomeMode = Outside Prompt = None PromptTargetPos = None - Task = None } + Task = None + Seed = 42UL } let worldInputAllowed (view: M5View) : bool = view.Panel = WorldPanel @@ -299,17 +302,37 @@ module M5Interaction = match List.tryItem index menu.Options with | None -> world, { view with Status = "invalid dialogue option" } | Some intent -> - match Sim.chooseDialogue menu.Target intent world with + // P-d:回应经职业偏差纯函数;无职业走既有 identity 路径(逐字节不变)。 + let respond = + match view.Task with + | Some task -> Occupation.biasResponse (Some task.Profile.Kind) + | None -> Sim.responseFor + match Sim.chooseDialogueWith respond menu.Target intent world with | DialogueSucceeded(outcome, next) -> - next, + // P-d 剧情线:每次玩家对话至多推进一段,摘要写年鉴(StoryAnnal)。 + let storyWorld, storyTask = + match view.Task with + | Some task -> + let nextState, summary = Occupation.Story.onDialogue view.Seed task next + let withAnnal = + match summary with + | Some text -> + Sim.appendAnnal + { Tick = next.Tick; Kind = StoryAnnal; Summary = text } + next + | None -> next + withAnnal, Some nextState + | None -> next, None + storyWorld, { view with Panel = WorldPanel Menu = None - Chronicle = Sim.annalText next + Chronicle = Sim.annalText storyWorld Prompt = None PromptTargetPos = None + Task = storyTask Status = sprintf "dialogue intent=%A response=%A" outcome.Intent outcome.Response - StatusTick = Some next.Tick } + StatusTick = Some storyWorld.Tick } | DialogueRejected(failure, next) -> next, { view with @@ -536,6 +559,7 @@ module M5Interaction = quantity unitPrice | _ -> "交易记录" + | StoryAnnal -> entry.Summary let private chronicleLines (world: World) : string list = world.Annals |
