Files
ImmortalSect/doc/弟子管理.md
T

118 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 弟子管理模块设计
模块位置:P1 核心循环(见 `doc/Roadmap.md`)。本文档描述弟子数据模型与弟子管理器的设计。
## 1. 结构:数据类 + 管理器
弟子模块拆分为两层:
| 层 | 文件 | 类型 | 职责 |
| --- | --- | --- | --- |
| 弟子数据类 | `src/Data/Models/Disciple.gd` | RefCounted | 持有弟子的所有信息,纯数据,无逻辑 |
| 弟子管理器 | `src/Character/DiscipleManager.gd` | Node | 添加、删除、查询、修改弟子属性 + 领域操作(修炼结算) |
## 2. 设计模式
| 角色 | 模式 | 说明 |
| --- | --- | --- |
| 弟子数据类 | 纯数据模型 | RefCounted,运行时可变数据,不依赖场景树,可脱离场景单测 |
| 弟子管理器 | 仓储模式(Repository) | CRUD + 查询的集中入口,是弟子数据的唯一管理者 |
| 变化通知 | 观察者模式(Observer) | 管理器发信号,UI/其他系统订阅实时刷新 |
| 弟子创建 | 工厂方法(Factory) | 初始弟子/收徒的创建逻辑收在管理器内 |
**明确不用的方案**
- 不用 ECS:弟子属性固定(境界/技艺/忠诚…),无动态组件需求,是过度设计。
- 不用 Resource/.tres:弟子是运行时可变数据,RefCounted 类最轻量,不走序列化资源。
- 不把所有逻辑塞进数据类:领域操作归管理器,保证修改只有单一入口,信号好通知,测试好做。
## 3. Disciple 数据类(RefCounted,纯数据)
```gdscript
var name: String
var is_mortal: bool # 凡人弟子
var realm_level: int = 1 # 境界 1-9
var cultivation_skill: int = 1 # 种植技艺 1-10
var alchemy_skill: int = 1 # 炼丹技艺 1-10
var loyalty: int = 50 # 忠诚 0-100P1 仅存字段)
var cultivation_exp: int = 0 # 修为进度
```
只读派生(不存储,由属性计算):
- `monthly_cost() -> int`:每月修炼灵石消耗(凡人弟子为 0
- `realm_name() -> String`:境界显示名(凡人 / 炼气X层…)
- `exp_to_next() -> int`:升到下一境界所需修为
## 4. DiscipleManager 管理器(Node,仓储)
```gdscript
signal disciple_added(disciple)
signal disciple_removed(disciple)
signal disciple_attr_changed(disciple, attr_name, old_value, new_value)
func add_disciple(d) -> void
func remove_disciple(d) -> void
func get_disciple(id) -> Disciple
func get_all() -> Array[Disciple]
func get_by_realm(level) -> Array[Disciple]
func count_mortals() -> int
func set_attr(d, attr, value) -> void # 修改唯一入口,内部发信号
func settle_month() -> void # 修炼结算(领域操作)
func to_dict() -> Dictionary # 存档网关
func load_from_dict(d) -> void
```
## 5. 关键设计决策
1. **修改只走管理器**——`set_attr()` 是唯一变更入口,内部统一发 `disciple_attr_changed`。UI 订阅它实时刷新,也为以后忠诚度/事件系统留监听点。
2. **查询返回引用**——性能好(P1 规模无碍),但禁止外部直接写属性;要写必须走管理器。
3. **管理器是 Node,数据类是 RefCounted**——管理器可挂 MainGame/测试场景;数据类脱离场景树也能单测。
4. **领域操作在管理器**——`settle_month()`(修炼消耗灵石、增加修为、境界提升)归管理器,数据类不碰业务逻辑。
5. **存档网关(Unit of Work**——序列化/恢复只经过管理器 `to_dict()/load_from_dict()`,为 SaveSystem 注册预留。
## 6. 测试方式
独立测试场景 `src/Character/test_disciple.tscn`
1. 实例化 DiscipleManager(不依赖其他模块)
2. `_ready()` 中自动执行用例:
- 添加/删除弟子 → 信号是否正确发出
- 查询(get_by_realm / count_mortals
- `set_attr` → 信号带旧值/新值
- `settle_month` → 境界提升/灵石消耗正确
- `to_dict / load_from_dict` 往返一致
3. `print` 输出 PASS/FAIL,编辑器直接运行场景验证
# 弟子属性
## 属性列表
|名称|范围|说明|
|:---|:---|:---|
|metal|[0, 100]|金属性值|
|wood|[0, 100]|木属性值|
|water|[0, 100]|水属性值|
|fire|[0, 100]|火属性值|
|earth|[0, 100]|土属性值|
|efficiency|[1, 100]|灵气吸收效率,决定修炼速度,隐藏属性|
|realm_level|[0, 5]|大境界,凡人、练气、筑基、金丹、元婴、化神|
|sub_realm_level|[1, 13]|凡人只有一个小境界;练气13个小境界,其他各有前、中、后、大圆满四个小境界|
|cultivation_exp|[0, 2147483647]|修炼经验|
|farming_skill_exp|[0, 2147483647]|耕作技能经验|
|farming_skill_level|[0, 10]|炼丹技能等级|
|herb_farming_skill_exp|[0, 2147483647]|药草耕作技能经验|
|herb_farming_skill_level|[0, 10]|炼丹技能等级|
|alchemy_skill_exp|[0, 2147483647]|炼丹技能经验|
|alchemy_skill_level|[0, 10]|炼丹技能等级|
|loyalty|[0, 100]|忠诚度|
- **修炼经验说明**:每个小境界都有一个经验上限,跨越小境界,溢出部分会继承到下一个小境界。跨越大境界,溢出部分清零。
- **技能经验说明**:耕作技能经验、药草耕作技能经验、炼丹技能经验,每跨越一个等级,溢出的经验会继承到下一个等级,直到升满为止,不会有任何经验提升。每个等级所需的经验为需要在文件中配置。
## 初始分配方式
```mermaid
graph TD
A[分配属性总量,按正正态分布] --> B[随机分配5种属性,属性之和为1] --> C[分配灵气利用率]
```