diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-28 22:38:52 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-28 22:38:52 +0800 |
| commit | aa3baa953ea5c4f99f5f23cb3eef9400338b61ec (patch) | |
| tree | 641759916bcf736ea91af48f798a0f7a3a406c99 /src/LivingVillage.Kernel | |
| parent | 3aa7221453afec24757b0c7e4d352f69af8b395b (diff) | |
| download | living-village-aa3baa953ea5c4f99f5f23cb3eef9400338b61ec.tar.gz | |
p51: 职业系统实现首切片——开局钱/体力/背包侧车 + 当日任务/跨日刷新 + StartNewGameWith 读回(design §2.4-1)
Diffstat (limited to 'src/LivingVillage.Kernel')
| -rw-r--r-- | src/LivingVillage.Kernel/Occupation.fs | 15 | ||||
| -rw-r--r-- | src/LivingVillage.Kernel/WorldSave.fs | 46 |
2 files changed, 52 insertions, 9 deletions
diff --git a/src/LivingVillage.Kernel/Occupation.fs b/src/LivingVillage.Kernel/Occupation.fs index c207395..45ef428 100644 --- a/src/LivingVillage.Kernel/Occupation.fs +++ b/src/LivingVillage.Kernel/Occupation.fs @@ -194,14 +194,25 @@ module Occupation = /// 挂在玩家侧的职业状态,随存档 v3 保存(design §2)。 /// Today = 当日任务(§3);TaskToken 保留为 v3 前缀占位扩展位(恒 0,暂未启用)。 + /// Backpack = 玩家背包侧车(design §2.4-1):开局 = profile.InitialInventory 的纯数据副本, + /// 不进 `Sim.World`、不动 `Sim.step` 数值路径;键值对保持声明顺序以稳定序列化。 type State = { Profile: Profile TaskToken: int Today: DailyTask option - StoryStage: int } + StoryStage: int + Backpack: (Sim.ItemKind * int) list } let stateOf (kind: Kind) : State = - { Profile = profileOf kind; TaskToken = 0; Today = None; StoryStage = 0 } + { Profile = profileOf kind + TaskToken = 0 + Today = None + StoryStage = 0 + Backpack = (profileOf kind).InitialInventory } + + /// 背包内某物品数量(纯函数;无则 0)。 + let backpackQuantity (item: Sim.ItemKind) (state: State) : int = + state.Backpack |> List.sumBy (fun (kind, quantity) -> if kind = item then quantity else 0) // ---- 既有事件通道 → 任务信号桥(design §3:完成判定统一走 InteractionEvent)---- diff --git a/src/LivingVillage.Kernel/WorldSave.fs b/src/LivingVillage.Kernel/WorldSave.fs index 7f724a3..3e11810 100644 --- a/src/LivingVillage.Kernel/WorldSave.fs +++ b/src/LivingVillage.Kernel/WorldSave.fs @@ -494,6 +494,24 @@ module WorldSave = DueTick = dueTick State = state } + /// v3 backpack 尾段(design §2.4-1):玩家背包侧车,按声明顺序写入;旧 v3(无此段)读回 + /// 由 kind 的 `profileOf` 默认值补齐。 + let private writeBackpack tokens (items: (ItemKind * int) list) = + add tokens "backpack" + addInt tokens items.Length + for item, quantity in items do + writeItemKind tokens item + addInt tokens quantity + + let private readBackpack (reader: TokenReader) : (ItemKind * int) list = + let count = readCount reader "backpack.count" + [ for index in 0 .. count - 1 do + let item = readItemKind reader (sprintf "backpack[%d].item" index) + let quantity = readInt reader (sprintf "backpack[%d].quantity" index) + if quantity < 0 then + invalid (sprintf "invalid backpack[%d].quantity" index) + yield item, quantity ] + let private writeMind tokens (value: Mind) = writeNeeds tokens value.Needs writePersonality tokens value.Personality @@ -598,6 +616,7 @@ module WorldSave = match state.Today with | Some task -> writeDailyTask tokens task | None -> () + writeBackpack tokens state.Backpack | None -> () String.Join("|", tokens) @@ -634,7 +653,14 @@ module WorldSave = | "peddler" -> Some Occupation.Peddler | "scholar" -> Some Occupation.Scholar | _ -> None - occupationOption <- kind |> Option.map (fun kind -> { Profile = Occupation.profileOf kind; TaskToken = task; Today = None; StoryStage = stage }) + occupationOption <- + kind + |> Option.map (fun kind -> + { Profile = Occupation.profileOf kind + TaskToken = task + Today = None + StoryStage = stage + Backpack = (Occupation.profileOf kind).InitialInventory }) | _ -> () let tick = readInt64 reader "tick" let time = readFloat reader "time" @@ -650,17 +676,23 @@ module WorldSave = let rumorStats = rumorWorkingSetStats rumors let annalCount = readCount reader "annals" let annals = List.init annalCount (fun index -> readAnnal reader (sprintf "annal[%d]" index)) - let todayTask = - if reader.Remaining > 0 then - match reader.Take("task.today") with - | "task-today" -> Some(readDailyTask reader) + let tail = + let mutable task : Occupation.DailyTask option = None + let mutable backpack : (ItemKind * int) list option = None + while reader.Remaining > 0 do + match reader.Take("occupation.tail") with + | "task-today" -> task <- Some(readDailyTask reader) + | "backpack" -> backpack <- Some(readBackpack reader) | _ -> invalid "trailing save data" - else None + task, backpack if reader.Remaining <> 0 then invalid "trailing save data" let occupation = occupationOption - |> Option.map (fun state -> { state with Today = todayTask }) + |> Option.map (fun state -> + { state with + Today = fst tail + Backpack = snd tail |> Option.defaultValue state.Backpack }) Ok ({ Tick = tick Time = time |
