diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-21 19:34:32 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-21 19:34:32 +0800 |
| commit | 98b6b21c56c7b061578e7d4b56d52450dc7bd575 (patch) | |
| tree | 8c3ce5912294207d37863c37b15f2bce89c0787f /src/LivingVillage.Desktop | |
| parent | c348da258f072bc88ea422cbc534c0831817b3c8 (diff) | |
| download | living-village-98b6b21c56c7b061578e7d4b56d52450dc7bd575.tar.gz | |
feat(desktop): P12 中文每日任务面板——T 键任务页、Offered/Active/Done 三态+职业名,存读档字段级携带职业
Diffstat (limited to 'src/LivingVillage.Desktop')
| -rw-r--r-- | src/LivingVillage.Desktop/Game.fs | 8 | ||||
| -rw-r--r-- | src/LivingVillage.Desktop/Interaction.fs | 37 |
2 files changed, 39 insertions, 6 deletions
diff --git a/src/LivingVillage.Desktop/Game.fs b/src/LivingVillage.Desktop/Game.fs index 9fab5f7..cbe2b9d 100644 --- a/src/LivingVillage.Desktop/Game.fs +++ b/src/LivingVillage.Desktop/Game.fs @@ -202,7 +202,7 @@ type LivingVillageGame() as this = member private this.SaveWorld (prefix: string) : bool = try - WorldSave.saveToFile savePath world + WorldSave.saveToFileWith m5View.Task savePath world m5View <- { m5View with Status = "save succeeded"; StatusTick = Some world.Tick } printfn $"{prefix}=ok path={savePath} tick={world.Tick}" true @@ -213,10 +213,11 @@ type LivingVillageGame() as this = false member private this.LoadWorld (prefix: string) : Result<int64, string> = - match WorldSave.loadFromFile savePath with - | Ok nextWorld -> + match WorldSave.loadFromFileWith savePath with + | Ok (nextWorld, occupation) -> world <- nextWorld this.ResetWorldView() + m5View <- { m5View with Task = occupation } printfn $"{prefix}=ok path={savePath} tick={world.Tick}" Ok world.Tick | Error failure -> @@ -384,6 +385,7 @@ type LivingVillageGame() as this = elif pressed Keys.Q then Some Observe elif pressed Keys.Tab then Some ToggleNeeds elif pressed Keys.C then Some ShowChronicle + elif pressed Keys.T then Some ShowTaskPanel else None match m5Command with | Some command -> diff --git a/src/LivingVillage.Desktop/Interaction.fs b/src/LivingVillage.Desktop/Interaction.fs index 3f04da8..95aa84c 100644 --- a/src/LivingVillage.Desktop/Interaction.fs +++ b/src/LivingVillage.Desktop/Interaction.fs @@ -22,6 +22,7 @@ type M5Panel = | ObservationPanel | DialoguePanel | ChroniclePanel + | TaskPanel type M5Command = | Interact @@ -34,6 +35,7 @@ type M5Command = | Observe | ToggleNeeds | ShowChronicle + | ShowTaskPanel | ClosePanel type M5View = @@ -46,7 +48,8 @@ type M5View = StatusTick: int64 option HomeMode: HomeMode Prompt: string option - PromptTargetPos: Vec2 option } + PromptTargetPos: Vec2 option + Task: Occupation.State option } module InteractionResolver = @@ -208,7 +211,8 @@ module M5Interaction = StatusTick = None HomeMode = Outside Prompt = None - PromptTargetPos = None } + PromptTargetPos = None + Task = None } let worldInputAllowed (view: M5View) : bool = view.Panel = WorldPanel @@ -326,7 +330,8 @@ module M5Interaction = | Intent6 -> view.Panel = DialoguePanel | Observe | ToggleNeeds - | ShowChronicle -> view.Panel <> DialoguePanel + | ShowChronicle + | ShowTaskPanel -> view.Panel <> DialoguePanel let private applyAllowed (command: M5Command) (world: World) (view: M5View) : World * M5View = match command with @@ -404,6 +409,13 @@ module M5Interaction = Prompt = None PromptTargetPos = None Status = sprintf "chronicle entries=%d" world.Annals.Length } + | ShowTaskPanel -> + world, + { view with + Panel = TaskPanel + Prompt = None + PromptTargetPos = None + Status = "task panel open" } | ClosePanel -> world, refreshPrompt world { view with Panel = WorldPanel; Menu = None; Status = "panel closed" } let apply (command: M5Command) (world: World) (view: M5View) : World * M5View = @@ -440,6 +452,7 @@ module M5Interaction = | ObservationPanel -> "observation" | DialoguePanel -> "dialogue" | ChroniclePanel -> "chronicle" + | TaskPanel -> "task" let titleText (view: M5View) : string = match view.Panel with @@ -456,6 +469,7 @@ module M5Interaction = sprintf "互动:村民 %d | %s | ESC 关闭" (npcNumber menu.Target) options | None -> "互动已记录 | E 互动 | ESC 关闭" | ChroniclePanel -> "年鉴 | TAB 需求 | Q 观察 | ESC 关闭" + | TaskPanel -> "任务 | TAB 需求 | Q 观察 | ESC 关闭" let private statusLabel (status: string) : string = match status with @@ -474,6 +488,7 @@ module M5Interaction = if String.IsNullOrWhiteSpace reason then "对话失败" else sprintf "对话失败:%s" reason | value when value.StartsWith("observation") -> "观察完成" | value when value.StartsWith("chronicle") -> "年鉴已打开" + | "task panel open" -> "任务面板已打开" | value when value.StartsWith("no dialogue") -> "当前没有可用对话" | value when value.StartsWith("invalid dialogue") -> "对话选项无效" | value when value.StartsWith("no nearby") -> "附近没有可互动目标" @@ -576,3 +591,19 @@ module M5Interaction = | ChroniclePanel -> let entries = chronicleLines world "年鉴" :: (if entries.IsEmpty then [ "暂无记录" ] else entries) @ [ status ] + | TaskPanel -> + let taskStateText (state: Occupation.TaskState) : string = + match state with + | Occupation.Offered -> "待接受" + | Occupation.Active -> "进行中" + | Occupation.Done -> "已完成" + | Occupation.Failed -> "已失败" + match view.Task with + | None -> [ "任务"; "无职业"; status ] + | Some occupationState -> + let taskLines = + match occupationState.Today with + | None -> [ "今日暂无任务" ] + | Some task -> + [ sprintf "%s:%s" (Occupation.taskNameOf task.TemplateId) (taskStateText task.State) ] + Occupation.nameOf occupationState.Profile.Kind :: taskLines @ [ status ] |
