summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop/Game.fs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-21 22:57:50 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-21 22:57:50 +0800
commit60bbc83d9a1d047933e4128e7b48e1c61c925a14 (patch)
treec41b351535add285f8644d8703fa6c4f1799eeb3 /src/LivingVillage.Desktop/Game.fs
parente1d8d45cf08b4f30e33299eb40e865729e7adfd2 (diff)
downloadliving-village-60bbc83d9a1d047933e4128e7b48e1c61c925a14.tar.gz
feat(desktop): P15 开局职业选择页——新档四选一+暂不选择,接入 v3 存档与当日任务
- MenuState:新增 OccupationSelect 页与 StartNewGameWith 命令;occupationOptions=农夫/渔夫/货郎/书生/暂不选择, 默认高亮「暂不选择」= 不写职业的旧行为;四选一确认后发 StartNewGameWith,ESC 返回主菜单(既有 MainMenu 行为与测试不变)。 - WorldBootstrap.occupationStateFor/refreshOccupationToday:按 seed+职业种子生成/跨日刷新当日 Offered 任务。 - Game:主菜单「开始新游戏」→ 职业选择页;选定后 initialWorldWithOccupation 注入 Money/Energy 与 Today, m5View.Task 随之写入 v3 存档;游玩中按日刷新;autoplay/flow 默认走「暂不选择」保持旧演示行为;DrawMenu 渲染职业页。 - 测试 Desktop 93(新增 6):职业页选项顺序/默认 None/标签、确认命令与返回、bootstrap 四职业 Money/Energy+当日池内 Offered 任务、四职业 v3 round-trip(职业+任务逐字段)、T 面板显示所选职业的模板名与「待接受」、跨日刷新保持同日。
Diffstat (limited to 'src/LivingVillage.Desktop/Game.fs')
-rw-r--r--src/LivingVillage.Desktop/Game.fs38
1 files changed, 33 insertions, 5 deletions
diff --git a/src/LivingVillage.Desktop/Game.fs b/src/LivingVillage.Desktop/Game.fs
index 6918e00..1b9508b 100644
--- a/src/LivingVillage.Desktop/Game.fs
+++ b/src/LivingVillage.Desktop/Game.fs
@@ -204,11 +204,18 @@ type LivingVillageGame() as this =
m5View <- M5Interaction.refreshPrompt world M5Interaction.initial
this.CenterCamera()
- member private this.StartNewGame() =
- world <- createInitialWorld ()
+ member private this.StartNewGame (occupation: Occupation.Kind option) =
+ let state =
+ occupation
+ |> Option.map (fun kind ->
+ let startTick = if daylightAutoplay then 6L * Sim.ticksPerDay / 24L else 0L
+ WorldBootstrap.occupationStateFor 42UL kind startTick)
+ world <- WorldBootstrap.initialWorldWithOccupation daylightAutoplay 42UL Sim.npcCount state
this.ResetWorldView()
+ m5View <- { m5View with Task = state }
menu <- menu |> MenuState.setCurrentWorld true |> MenuState.enterGame
- printfn $"new-game=ok seed=42 npcs={Sim.npcCount}"
+ let occupationName = occupation |> Option.map Occupation.nameOf |> Option.defaultValue "none"
+ printfn $"new-game=ok seed=42 npcs={Sim.npcCount} occupation={occupationName}"
member private this.SaveWorld (prefix: string) : bool =
try
@@ -247,7 +254,10 @@ type LivingVillageGame() as this =
| ContinueGame ->
menu <- menu |> MenuState.setCurrentWorld true |> MenuState.enterGame
printfn $"continue=ok tick={world.Tick}"
- | StartNewGame -> this.StartNewGame()
+ | StartNewGame ->
+ menu <- MenuState.openOccupationSelect menu
+ printfn "menu=occupation-select"
+ | StartNewGameWith occupation -> this.StartNewGame occupation
| LoadGame ->
match this.LoadWorld "load" with
| Ok _ ->
@@ -278,7 +288,9 @@ type LivingVillageGame() as this =
else None
match input with
| Some nextInput -> this.DispatchMenuInput nextInput
- | None when (autoplay || sampleMode) && not autoplayFlow && menu.Page = MainMenu && not menu.HasCurrentWorld ->
+ | None when (autoplay || sampleMode) && not autoplayFlow
+ && (menu.Page = MainMenu || menu.Page = OccupationSelect)
+ && not menu.HasCurrentWorld ->
autoplayFrames <- autoplayFrames + 1
if autoplayFrames >= 15 then
this.DispatchMenuInput Confirm
@@ -435,6 +447,12 @@ type LivingVillageGame() as this =
else
avatarMoving <- false
this.CenterCamera()
+ match m5View.Task with
+ | Some state ->
+ let refreshed = WorldBootstrap.refreshOccupationToday 42UL state world.Tick
+ if refreshed <> state then
+ m5View <- { m5View with Task = Some refreshed }
+ | None -> ()
m5View <- M5Interaction.refreshPrompt world m5View
member private this.RunAutoplayFlow() =
@@ -455,6 +473,9 @@ type LivingVillageGame() as this =
| 50 ->
printfn "flow=new-game"
flowStep <- 1
+ | 1 when menu.Page = OccupationSelect ->
+ this.DispatchMenuInput Confirm
+ printfn "flow=occupation=none"
| 1 when menu.Page = Playing ->
this.OpenMainMenu()
printfn "flow=return-menu"
@@ -619,6 +640,7 @@ type LivingVillageGame() as this =
let contentRows =
match menu.Page with
| MainMenu -> MenuState.items menu |> List.length
+ | OccupationSelect -> MenuState.occupationOptions.Length
| Settings -> MenuState.settings.Length
| Controls -> MenuState.controlRows.Length
| LoadError -> 4
@@ -696,6 +718,12 @@ type LivingVillageGame() as this =
MenuState.items menu
|> List.iteri (fun index item -> drawSelection index (MenuState.itemLabel item) (contentY + index * lineHeight))
drawText innerX (panelY + panelHeight - 40) mutedColor "UP DOWN 选择 ENTER 确认"
+ | OccupationSelect ->
+ drawText innerX headingY mutedColor "选择职业"
+ MenuState.occupationOptions
+ |> List.iteri (fun index occupation ->
+ drawSelection index (MenuState.occupationLabel occupation) (contentY + index * lineHeight))
+ drawText innerX (panelY + panelHeight - 40) mutedColor "UP DOWN 选择 ENTER 确认 ESC 返回"
| Settings ->
drawText innerX headingY mutedColor (ChineseText.menuHeading SettingsHeading)
MenuState.settings