blob: 75675aabe1a3a50cc14e706c53a9f2c7b6dfab64 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
namespace LivingVillage.Desktop
open LivingVillage.Kernel
/// P54 职业切片三:把 Kernel 的当日任务状态机接到 Desktop 运行时(玩家可见 / 可完成)。
///
/// 全部为纯函数:接受任务、按**真实世界事件/信号**推进、给出短中文反馈。
/// 完成判定只复用 Kernel 既有 `Occupation.advanceTask` / `applySignal`
/// (其内部是 `satisfiesCompletion`),绝不按日历索引硬编码计数。
module TaskRuntime =
let private completionMessage (before: Occupation.DailyTask option) (after: Occupation.DailyTask option) : string option =
match before, after with
| Some previous, Some current when previous.State = Occupation.Active && current.State = Occupation.Done ->
Some(sprintf "任务完成:%s" (Occupation.taskNameOf current.TemplateId))
| _ -> None
/// 接受当日任务(Offered → Active);无任务 / 已在进行 / 终态时无变化、无反馈。
let accept (state: Occupation.State) : Occupation.State * string option =
match state.Today with
| Some task when task.State = Occupation.Offered ->
{ state with Today = Some { task with State = Occupation.Active } },
Some(sprintf "已接受任务:%s" (Occupation.taskNameOf task.TemplateId))
| _ -> state, None
/// 用一条既有世界事件推进当日任务;Active → Done 时返回短中文反馈。
let advanceWithEvent (event: Sim.InteractionEvent) (state: Occupation.State) : Occupation.State * string option =
let before = state.Today
let next = Occupation.advanceTask event state
next, completionMessage before next.Today
/// 用一条已折叠的任务信号(到达瓦片 / 观察 / 夜在水边)推进当日任务。
let advanceWithSignal (signal: Occupation.TaskSignal) (state: Occupation.State) : Occupation.State * string option =
match state.Today with
| Some task ->
let after = Occupation.applySignal signal task
{ state with Today = Some after }, completionMessage (Some task) (Some after)
| None -> state, None
/// 折叠多条信号(后面的不覆盖已得到的完成反馈)。
let foldSignals (signals: Occupation.TaskSignal list) (state: Occupation.State) : Occupation.State * string option =
signals
|> List.fold
(fun (current, found) signal ->
let next, message = advanceWithSignal signal current
next, (match found with Some _ -> found | None -> message))
(state, None)
/// 由真实世界环境折叠出的任务信号:跨瓦片 → 到达;夜 + 水边 → 夜在水边。
/// `previousTile = None`(尚未建立基线)时不产生到达信号,避免开局即误判完成。
let environmentSignals
(isNight: bool)
(nearWater: bool)
(previousTile: (int * int) option)
(tile: int * int)
: Occupation.TaskSignal list =
[ if previousTile.IsSome && previousTile.Value <> tile then yield Occupation.ArrivedAt tile
if isNight && nearWater then yield Occupation.NightAtWater ]
/// 比较两份职业状态,返回本次推进是否让当日任务完成(供交易等路径复用)。
let completedMessage (before: Occupation.State option) (after: Occupation.State option) : string option =
completionMessage
(before |> Option.bind (fun state -> state.Today))
(after |> Option.bind (fun state -> state.Today))
|