diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-21 17:18:11 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-21 17:18:11 +0800 |
| commit | cf214889490a62ba4fe84fb0055bc2133776e8a2 (patch) | |
| tree | 0408fbd82e95ed55f39f8da3ccd3d2259e999313 /src/LivingVillage.Kernel/Occupation.fs | |
| parent | 87bdfe273555c5ae5f698b3b89fa6c39d84d0c33 (diff) | |
| download | living-village-cf214889490a62ba4fe84fb0055bc2133776e8a2.tar.gz | |
feat(occupation): 职业系统第一片 — Kernel 结构 / bootstrap 注入 / 存档 v3
Occupation.fs(Kind/Profile/State + 农夫/渔夫/货郎/书生 中文名常量,按设计 §1 表给初始 Money/Energy/Inventory);ItemKind 扩出 Fish/Spice/Scroll(basePrice 分支补齐,Food 10.0f 数值路径不变 → 无职业 digest 不动);WorldBootstrap.initialWorldWithOccupation 默认 None = 旧行为(Money/Energy 覆盖,库存字段先留数据侧、物理挂接留交易单——取舍见 design §2-C 反对加字段);WorldSave: v3 头仅在有职业时写入(保存 saveToFileWith / loadFromFileWith,v1/v2/v3 无职业类型默认,token 顺序 version|w|h|kind|task|story|…),默认路径 save 输出逐字节等同现行 v2;P10 测试 5 例(§1 表值、v3 round-trip、v1/v2 不吞档、双 seed 逐字节、中文名);Kernel.Tests 引用 Desktop 以驱动 WorldBootstrap(取舍:不做测试专用 shim)。TaskToken/StoryStage 为 v3 占位(任务系统后续单实现)。
Diffstat (limited to 'src/LivingVillage.Kernel/Occupation.fs')
| -rw-r--r-- | src/LivingVillage.Kernel/Occupation.fs | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/src/LivingVillage.Kernel/Occupation.fs b/src/LivingVillage.Kernel/Occupation.fs new file mode 100644 index 0000000..28008f5 --- /dev/null +++ b/src/LivingVillage.Kernel/Occupation.fs @@ -0,0 +1,53 @@ +namespace LivingVillage.Kernel + +/// Occupation system first slice (design §1/§2, docs/design/occupation-system-design.md). +/// Data lives beside the player only — NPCs are never occupied. +/// Nothing here runs inside Sim.step; WorldBootstrap stamps the profile onto the +/// world's avatar at creation time, which keeps the numeric state path untouched. +module Occupation = + + type Kind = + | Farmer + | Fisher + | Peddler + | Scholar + + /// Chinese labels, shared for a later UI slice (农夫 / 渔夫 / 货郎 / 书生). + let nameOf (kind: Kind) : string = + match kind with + | Farmer -> "农夫" + | Fisher -> "渔夫" + | Peddler -> "货郎" + | Scholar -> "书生" + + let saveToken (kind: Kind) : string = + match kind with + | Farmer -> "farmer" + | Fisher -> "fisher" + | Peddler -> "peddler" + | Scholar -> "scholar" + + let all : Kind list = [ Farmer; Fisher; Peddler; Scholar ] + + type Profile = + { Kind: Kind + InitialMoney: int + InitialEnergy: float32 + InitialInventory: (Sim.ItemKind * int) list } + + /// Initial values straight from the approved design §1 table. + let profileOf (kind: Kind) : Profile = + match kind with + | Farmer -> { Kind = Farmer; InitialMoney = 60; InitialEnergy = 100.0f; InitialInventory = [ Sim.Food, 12 ] } + | Fisher -> { Kind = Fisher; InitialMoney = 45; InitialEnergy = 95.0f; InitialInventory = [ Sim.Food, 8; Sim.Fish, 3 ] } + | Peddler -> { Kind = Peddler; InitialMoney = 90; InitialEnergy = 100.0f; InitialInventory = [ Sim.Food, 6; Sim.Spice, 4 ] } + | Scholar -> { Kind = Scholar; InitialMoney = 70; InitialEnergy = 100.0f; InitialInventory = [ Sim.Food, 10; Sim.Scroll, 2 ] } + + /// Placeholder carried in save v3 until the task-system slice lands (design §3). + type State = + { Profile: Profile + TaskToken: int + StoryStage: int } + + let stateOf (kind: Kind) : State = + { Profile = profileOf kind; TaskToken = 0; StoryStage = 0 } |
