From d34af661b90a183f77b197738e2f55edea05190d Mon Sep 17 00:00:00 2001
From: SepComet <202308010230@stu.csust.edu.cn>
Date: Thu, 12 Mar 2026 09:36:24 +0800
Subject: [PATCH] update docs
---
docs/CodeX-TODO.md | 92 ++++-
docs/GameDesign.md | 6 +-
docs/TODO.md | 13 +-
docs/TagSystemDesign.md | 754 ++++++++++------------------------------
4 files changed, 277 insertions(+), 588 deletions(-)
diff --git a/docs/CodeX-TODO.md b/docs/CodeX-TODO.md
index abfa269..33eef2f 100644
--- a/docs/CodeX-TODO.md
+++ b/docs/CodeX-TODO.md
@@ -1,6 +1,6 @@
# CodeX TODO
-最后更新:2026-03-10
+最后更新:2026-03-12
> 目标:基于当前仓库现状,为 `docs/TODO.md` 的 M1 收口补一份更可执行的补充顺序。
> 原则:先收主流程,再补硬规则,最后统一文档与验收口径。
@@ -66,10 +66,10 @@
- `ProcedureMain + NodeMapForm` 已能创建固定 10 节点 Run,并驱动战斗 / 事件 / 商店三类节点的主流程入口。
- `RunState`、`FixedRunNodeSequenceBuilder`、`RunStateAdvanceService` 与对应 Editor 测试已存在,说明 Run 模型、固定序列、节点推进基础能力已经落地。
- 战斗节点已有结算、奖励选择、失败返回;事件和商店节点也会发出 `NodeEnterEventArgs / NodeCompleteEventArgs`,主流程闭环已能稳定走通。
-- `P0-10 ~ P0-12` 不是纯空白:
- - 出战前已有“参与区至少有 1 座塔”的最低门槛;
- - 品质 / Tag 已在组装、商店、展示链路中分散使用;
- - 耐久已有字段、展示与扣减入口。
+- `P0-10 ~ P0-12` 已完成当前 M1 口径收口:
+ - 出战前已按“三组件完整且未损坏”的统一规则校验合法参战塔;
+ - 品质 / Tag 已完成统一生成、汇总、展示与首发 7 个 Tag 的战斗生效;
+ - 耐久已完成“每场固定扣 1、归零失效、自动移出参战区”的最小闭环。
### M1 目标状态
@@ -198,11 +198,17 @@
- `Crit`、`Execution`、`Shatter` 已通过数值修正链路生效;`Shatter` 当前按“目标已减速时增伤”收口。
- `Inferno` 与 `AbsoluteZero` 已不再是独立状态效果,而是分别在 `Fire` / `Ice` 生效时读取同次命中的强化 Tag 层数,增强 DOT 时长/伤害与减速时长/强度。
-### S4 后续执行计划
+### S4 审计结论(2026-03-12)
-1. `S4-07` 已完成,当前不再继续围绕三表命名与职责拆分新任务。
-2. 后续如果要继续配置化更深层 Tag 元数据,应作为新的增强项单独立项,不回挂到当前 M1。
-3. `BurnSpread`、`IgniteBurst`、`FreezeMask`、`Pierce`、`Overpenetrate` 继续留在后续扩展阶段,不因为 `S4-07` 完成而提前进入当前迭代。
+- `S4-02 ~ S4-07` 的 M1 闭环已完成,当前不回滚其完成状态。
+- 但本轮对 Tag 系统的静态审查确认:当前实现还存在 5 个会放大后续返工成本的结构问题。
+- 这些问题分别是:
+- 配置真相源与 DataTable 加载顺序仍不稳定,`IsImplemented` 的最终结果会受加载先后影响。
+- 组件 Tag 随机口径还没有把 `RunSeed` 作为正式输入,当前“同 Run 可复现、跨 Run 可区分”的合同未完全落地。
+- `AttackPayload + HitContext` 还不是稳定的统一战斗上下文,数值类 Tag 仍依赖散装参数扩展。
+- `TagConfig.txt` 中一部分字段已进入配置层,但还没有成为运行时真实消费字段,存在“表能改、逻辑不跟”的风险。
+- `TagSystemDesign.md` 里仍混有旧的 12 Tag / 流派草稿,正式口径与历史预案没有彻底拆开。
+- 因此,`S4` 后续不再继续扩展新 Tag 功能,而是先进入新的审计整改阶段,优先修掉上述结构问题。
## 阶段 S5 - 收口耐久规则
@@ -255,7 +261,7 @@
1. `S5-01 ~ S5-04` 已按当前 M1 口径完成,不再作为 `P0-12` 的主阻塞项。
2. 当前未实现的是长期设计里的维修、自动销毁、耐久折价、连续属性衰减,这些后续若要恢复,应作为新的增强项重新拆分,而不是回滚当前 MVP 口径。
-3. `CodeX-TODO` 与 `TODO` 当前已经同步到同一执行口径;后续文档收尾应优先处理 `MVP-Scope`、`GameDesign` 等仍保留旧表述的设计文档。
+3. `CodeX-TODO`、`TODO`、`MVP-Scope`、`GameDesign`、`TagSystemDesign` 当前已经同步到同一执行口径;后续若继续调整 M1 / M2 边界,应同步回写这些设计文档。
## 阶段 S6 - 回归与文档收尾
@@ -276,19 +282,75 @@
>
> 2026-03-11 更新:`S6-04` 已完成。`MVP-Scope.md`、`GameDesign.md`、`TODO.md`、`CodeX-TODO.md` 与 `TagSystemDesign.md` 现已统一回写到当前真实实现口径:战斗奖励改为“敌人概率掉落 + 结算金币 + 满血额外 3 选 1”,商店改为“当前 M1 只保留基础购买”,并移除了“开局二选三组件组两塔”“M1 不做耐久 / 红色品质”“组件/配件混写”等已过期描述。当前 docs 下未再发现会误导 M1 开发的主冲突项,剩余内容仅保留明确标注为后续阶段的设计预案。
+## 阶段 S7 - Tag 系统审计整改
+
+| 状态 | ID | 任务 | 交付物路径 | 验收标准 |
+|-----|-------|------------------------------|---------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------|
+| [ ] | S7-01 | 收口 Tag 配置真相源与加载顺序 | `Assets/GameMain/Scripts/Procedure/`
`Assets/GameMain/Scripts/Definition/Tag/`
`Assets/Tests/EditMode/` | `IsImplemented`、默认值与运行时定义不再受 DataTable 加载顺序影响 |
+| [ ] | S7-02 | 补齐组件 Tag 随机上下文与 `RunSeed` 合同 | `Assets/GameMain/Scripts/Definition/Tag/Generation/`
`Assets/GameMain/Scripts/UI/Shop/`
`Assets/GameMain/Scripts/CustomComponent/CombatNode/`
`Assets/Tests/EditMode/` | 同 Run 可复现、跨 Run 可区分,且掉落 / 商店 / 种子共用同一随机合同 |
+| [ ] | S7-03 | 收口 `AttackPayload / HitContext` 结算合同 | `Assets/GameMain/Scripts/Definition/DataStruct/`
`Assets/GameMain/Scripts/Definition/Tag/Combat/`
`Assets/GameMain/Scripts/Entity/`
`Assets/Tests/EditMode/` | Tag 结算统一只读上下文对象,不再继续靠散装参数扩展 |
+| [ ] | S7-04 | 对齐 `TagConfig` 字段与运行时真实消费 | `Assets/GameMain/DataTables/TagConfig.txt`
`Assets/GameMain/Scripts/Definition/Tag/Metadata/`
`Assets/GameMain/Scripts/Definition/Tag/Combat/`
`Assets/Tests/EditMode/` | 保留字段要么真实生效,要么明确标注为占位且不会误导配置方 |
+| [ ] | S7-05 | 清理 Tag 设计文档中的过期草稿 | `docs/TagSystemDesign.md`
`docs/CodeX-TODO.md` | 正式口径、当前实现、后续预案三者分层清晰 |
+
+### S7 立项原因
+
+- 当前 Tag 系统已经满足 M1 最小闭环,但还没有达到“可稳定继续扩展第二批 Tag”的结构状态。
+- 如果现在直接继续做 `BurnSpread`、`Pierce`、`Overpenetrate` 一类高侵入 Tag,会把当前加载顺序、随机上下文和命中结算接口里的隐患一起放大。
+- 因此 `S7` 的目标不是新增玩法,而是先把 Tag 系统的配置真相源、随机合同、战斗上下文合同与文档口径收稳。
+
+### S7-01 整改口径
+
+- `Tag.txt`、`TagConfig.txt`、registry 默认值三处不能再各自持有一份“是否首发 / 是否启用”的真相。
+- `ProcedurePreload` 里 `Tag` 与 `TagConfig` 的加载完成顺序不能再影响 `TagDefinitionRegistry` 最终状态。
+- 至少补一组 EditMode 测试覆盖“先加载 `Tag` 再加载 `TagConfig`”与“先加载 `TagConfig` 再加载 `Tag`”两种顺序,确认结果一致。
+- 本项完成后,`ComponentTagGenerationService` 的首发过滤与展示 / 战斗的定义读取必须共享同一份最终状态。
+
+### S7-02 整改口径
+
+- `ComponentTagGenerationService` 需要正式接收并消费 `RunSeed` 或等价的显式随机上下文,而不是只依赖 `rarity + sourceType + itemInstanceId + configId`。
+- 掉落、商店、初始种子、事件奖励四条链路必须明确各自如何构造同构的 Tag 随机上下文。
+- `EnemyDropResolver` 当前按 `Reset()` 把掉落实例 Id 重置为 `1` 的做法,只能作为局部实现细节,不能继续承担跨 Run 区分责任。
+- 本项通过标准是:同一 Run 下同一实例上下文结果稳定;不同 Run 即使出现相同配置与实例序号,也能由 `RunSeed` 拉开结果空间。
+
+### S7-03 整改口径
+
+- `HitContext` 需要补齐当前文档已经承诺的统一结算上下文职责,例如目标状态、击杀结果、攻击来源与后续第二批 Tag 需要的命中信息。
+- `TagEffectResolver.ResolveBeforeHit` 不再继续新增 `targetCurrentHealth`、`targetHasSlowStatus` 这类散装参数。
+- 数值类、状态类、攻击形态类 Tag 统一从上下文对象读取所需信息,避免每补一个 Tag 就再改一轮函数签名。
+- 本项优先级高于第二批 Tag 落地;在 `S7-03` 完成前,不推进 `BurnSpread`、`Pierce`、`Overpenetrate` 的真实战斗效果。
+
+### S7-04 整改口径
+
+- `TagConfig.txt` 中当前保留的字段必须逐项确认:哪些已经是正式运行时字段,哪些只是占位。
+- 例如 `Fire.MaxEffectiveStack` 这类已经进入表与配置类、但尚未参与实际结算的字段,需要二选一:
+- 要么接入真实逻辑;
+- 要么从当前正式口径中移除,避免形成“表能改、逻辑不跟”的假配置。
+- `Inferno`、`AbsoluteZero` 这类强化 Tag 也需要明确:它们是继续走独立 `TriggerPhase` 路由,还是正式定义为“依附主状态 Tag 的修饰器”。
+- 本项完成后,`TagConfig.txt`、`TagDefinitionRegistry`、`TagEffectResolver` 与实际战斗行为必须一一对应。
+
+### S7-05 整改口径
+
+- `docs/TagSystemDesign.md` 需要把“当前正式口径”“已实现状态”“后续预案 / 历史草稿”彻底拆开。
+- 当前正式口径只保留 M1 已收口与 `S7` 审计确认后的内容,不再在同一文件主路径里混写旧的 12 Tag 流派设计草稿。
+- `CodeX-TODO.md` 继续只记录执行顺序与整改项,不重复承担大段玩法设计说明。
+- 本项完成后,后续继续改 Tag 时,开发与策划应能只看文档主干就拿到当前真实执行口径。
+
## 推荐执行顺序
1. `S1 ~ S3` 已完成,不再作为当前主阻塞项。
2. `S4` 已完成,当前不再把三表方案作为 M1 主阻塞项。
3. `S5` 已完成,当前无需继续按旧耐久设计拆任务。
-4. `S6` 转入“测试补强 + 旧文档清理”收尾;重点不再是补主功能,而是把现状固化并避免后续继续按旧口径推进。
-5. `S6` 完成后,再决定是否把维修、自动销毁、耐久折价、更多 Tag 元数据配置化等长期设计拆成新的增强阶段。
+4. `S6` 已完成本轮“测试补强 + 文档清理”收尾。
+5. 当前优先进入 `S7-01 ~ S7-03`,先收口 Tag 的配置真相源、随机合同与战斗上下文合同。
+6. 再推进 `S7-04 ~ S7-05`,把配置字段与文档口径收稳。
+7. `S7` 完成前,不提前展开 `BurnSpread`、`IgniteBurst`、`FreezeMask`、`Pierce`、`Overpenetrate` 的真实战斗效果。
+8. 后续若继续推进维修、自动销毁、耐久折价、更多 Tag 元数据配置化等长期设计,应作为新的增强阶段单独拆项。
## 本周建议开工顺序
-1. 先补 `S6-01 ~ S6-02` 的主链路 / 规则回归测试,把当前 M1 口径固化下来
-2. 再继续处理 `S6-04`,清理 `MVP-Scope`、`GameDesign` 等仍保留旧范围描述的文档
-3. 最后再决定是否开启新的增强阶段,而不是回头重开 `S4-07`
+1. 先做 `S7-01`,把 `Tag.txt / TagConfig.txt / registry` 的真相源与加载顺序问题收掉
+2. 再做 `S7-02 ~ S7-03`,补齐 `RunSeed` 随机合同和命中上下文合同
+3. 然后做 `S7-04 ~ S7-05`,把配置字段与设计文档统一回写
## 备注
diff --git a/docs/GameDesign.md b/docs/GameDesign.md
index 0d1cc28..305c43c 100644
--- a/docs/GameDesign.md
+++ b/docs/GameDesign.md
@@ -32,11 +32,11 @@
- 关卡开始有一些资源用于布置防御塔,击杀敌人获取资源来布置或升级防御塔。
- 敌人会选择最短路径由出怪口向玩家基地前进;道路阻挡与更复杂的路径改写机制保留到后续阶段
2. 击杀敌人除了获取关卡内使用的资源外,还有概率掉落防御塔组件;每个小关卡结束后也会奖励组件与金币用于后续节点
-3. 关卡内设定一个胜利波次,当玩家存活的波次达到后会根据基地生命产生不同的事件:
+3. 关卡内设定一个胜利波次,当玩家存活的波次达到后会根据基地生命产生不同的结算:
- = 100% :获得额外 30% 的金币,以及额外 1 次组件 3 选 1
- >= 80% :获得额外 10% 的金币
- >= 50% :无加成
- - < 50%:损失携带防御塔耐久
+ - < 50%:当前 M1 不再追加额外耐久惩罚;耐久已按“每场战斗结算后对本场参战塔固定扣 1”收口
4. “胜利后继续挑战”保留到后续阶段,当前 M1 以正常结算回流节点地图为准
#### 2. 事件节点
@@ -60,4 +60,4 @@
- 品质计算:每个组件提供一定的品质权重(白:1,绿:2,蓝:3,紫:4,红:5),比如三个组件是 2 绿 1 白,那么防御塔的品质是 (2+2+1)/3=1.67,四舍五入后为 2 也就是绿色品质。
- 各品质的配件槽与更深的配件系统保留到后续阶段
- 组件 Tag 当前正式采用 `Tag.txt + RarityTagBudget.txt + TagConfig.txt` 三表方案:`Tag.txt` 负责基础字典、生成门槛、权重与启用态,`RarityTagBudget.txt` 负责按品质的 Tag 数量预算,`TagConfig.txt` 负责触发阶段、描述与效果参数
-2. 拆解与耐久:当前 M1 只保留最小耐久闭环,即战斗后按参战塔真实扣减、`0` 耐久失效并拦截参战 / 战斗入口;连续属性衰减、自动销毁与维修系统保留到后续阶段
+2. 拆解与耐久:当前 M1 只保留最小耐久闭环,即每场战斗结算后按本场参战塔真实扣减 `1` 点耐久、`0` 耐久失效并拦截参战 / 战斗入口;连续属性衰减、自动销毁与维修系统保留到后续阶段
diff --git a/docs/TODO.md b/docs/TODO.md
index bdf1b0a..3d87402 100644
--- a/docs/TODO.md
+++ b/docs/TODO.md
@@ -80,12 +80,7 @@
| [ ] | D-07 | P1 | 主题地图反制机制(每主题至少 2 个可用对策) | `Assets/GameMain/Scripts/Entity/`
`Assets/GameMain/Scripts/Scene/`
`Assets/GameMain/DataTables/*.txt` | 火山与山地都存在明确反制构筑,UI 有可读提示 |
| [ ] | D-08 | P0 | 先定义数值预算(经济/敌强/掉落)再调参 | `docs/NumericBudget.md`
`Assets/GameMain/DataTables/*.txt` | 关键曲线有目标区间,3 局测试结果可与目标对比复盘 |
-## 小目标
-1. CombatNodeComponent:战斗节点的逻辑补全
- - 完整塔防流程:初始硬币,敌人掉落硬币数量、基地生命与失败设计
- - 敌人随机掉落局外资源(金币、组件)
- - 无限波次下敌人血量、资源爆率的增加
- - 基地血量满足一定条件的额外奖励
-2. ShopNodeComponent:商店节点的逻辑补全
-3. RepoForm:仓库的逻辑补全
- - 组装防御塔逻辑的落实
+## 当前收尾重点
+1. 继续补 `Assets/Tests/` 的主链路回归,优先覆盖跨节点流程编排与更完整的 PlayMode 场景验证
+2. 继续同步 `docs/MVP-Scope.md`、`docs/GameDesign.md` 等旧设计文档,避免后续按过期口径推进
+3. 将“维修系统”“商店出售与复杂定价”“更多 Tag / 主题地图机制”等长期设计拆回后续阶段,不再混入当前 M1 已收口范围
diff --git a/docs/TagSystemDesign.md b/docs/TagSystemDesign.md
index 94b5764..32529a2 100644
--- a/docs/TagSystemDesign.md
+++ b/docs/TagSystemDesign.md
@@ -1,107 +1,91 @@
# Tag System Design
-最后更新:2026-03-11
+最后更新:2026-03-12
-> 目标:固定 GeometryTD 当前 M1 的 Tag 系统正式口径,明确三表配置职责、实际消费链,以及后续增强边界。
+> 目标:这是 GeometryTD 当前 Tag 系统的唯一正式口径。
+> 本文档只记录当前真实实现、已确认的问题与后续整改边界。
+> 历史流派草稿不再作为主文档内容。
-## 1. 当前现状
+## 1. 当前范围
-当前仓库已经形成 M1 所需的 Tag 最小闭环:
+M1 已完成 Tag 最小闭环:
-- `TagType` 已定义 12 个 Tag,见 `Assets/GameMain/Scripts/Definition/Enum/TagType.cs`
-- `Tag.txt` 已定义 Tag 名称、`MinRarity`、`Weight`、`IsImplemented`
-- `MuzzleComp.txt`、`BearingComp.txt`、`BaseComp.txt` 已定义 `PossibleTag`
-- `RarityTagBudget.txt` 已定义按品质的 Tag 数量预算
-- `TagConfig.txt` 已定义触发阶段、描述与首发 Tag 的核心参数
-- 组件实例、塔实例、UI 展示链路都已接入统一的生成、汇总与说明消费口径
+- 组件实例 Tag 已统一生成,不再直接复制 `PossibleTag`
+- 塔级 Tag 已统一汇总为 `TagRuntimeData[]`
+- UI 展示已优先消费 `TagRuntimes`
+- 首发 7 个 Tag 已进入战斗实际生效
-当前 `S4-07` 收尾只处理三件事:
+当前正式首发 7 个 Tag:
-- 明确三表就是 M1 的正式配置方案,不再保留 `TagRule` 作为当前未决项
-- 统一默认值、运行时加载与文档描述,避免回退到旧口径
-- 把未首发 Tag 保持为占位扩展,而不是误判为当前必须实现的功能缺口
+- `Fire`
+- `Ice`
+- `Crit`
+- `Execution`
+- `Shatter`
+- `Inferno`
+- `AbsoluteZero`
-## 2. 设计目标
+当前明确后移的 5 个 Tag:
-Tag 系统需要同时满足四个目标:
+- `BurnSpread`
+- `IgniteBurst`
+- `FreezeMask`
+- `Pierce`
+- `Overpenetrate`
-1. 组件实例上的 Tag 来源统一,不能继续由不同链路各自硬编码
-2. Tag 随机结果可复现,掉落、商店、初始种子、存档读档后口径一致
-3. 塔由三组件组装后,Tag 汇总结果可解释,重复 Tag 的处理规则清晰
-4. 战斗中的 Tag 生效有统一挂载点,不把效果分散塞进子弹、敌人、塔控制器各处
+当前不展开:
-## 3. 核心设计问题
+- 高级传播 / 多命中 / 击杀链式效果
+- 复杂流派激活矩阵
+- Tag 等级成长
+- `TagGroup` 运行时规则
-### 3.1 Tag 类型混杂
+## 2. 正式决策
-当前 `TagType` 同时混了三类语义:
+1. Tag 在组件实例创建时随机;组塔阶段只汇总,不重新随机。
+2. 组件表的 `PossibleTag` 只表示候选池,不代表实例最终持有结果。
+3. 组塔后重复 Tag 不丢弃,而是转为塔级 `Stack`。
+4. 配置层正式采用 `Tag.txt + RarityTagBudget.txt + TagConfig.txt` 三表结构。
+5. 战斗中的 Tag 统一挂在 `AttackPayload -> HitContext -> TagEffectResolver` 链路上。
+6. 新逻辑应优先使用 `TagRuntimes`;`Tags` 只保留兼容投影职责。
+7. `TagGroup` 当前只作为展示元数据,不进入生成、汇总或战斗规则。
-- 状态类:`Fire`、`Ice`
-- 数值修正类:`Crit`、`Execution`、`Shatter`
-- 攻击形态类:`BurnSpread`、`Pierce`、`Overpenetrate`
+## 3. 配置模型
-这三类 Tag 的触发时机不同:
+### 3.1 三表职责
-- 有的在命中前生效
-- 有的在命中时生效
-- 有的在命中后挂状态
-- 有的在击杀后触发
+`Tag.txt`
-如果后续继续只用一个 `TagType[]` 直接驱动所有逻辑,代码会迅速失控。后续实现必须引入“Tag 元数据 + 触发阶段”的概念。
+- 负责基础字典与生成规则
+- 当前字段:`TagType`、`Name`、`TagGroup`、`MinRarity`、`Weight`、`IsImplemented`
-### 3.2 候选 Tag 不等于实例 Tag
+`RarityTagBudget.txt`
-组件表中的 `PossibleTag` 应理解为“这个组件可能产出的 Tag 候选池”,不是实例最终持有的 Tag 列表。
+- 负责按品质定义组件实例本次可抽取的 Tag 数量预算
+- 当前字段:`Rarity`、`MinCount`、`MaxCount`
-正确关系应为:
+`TagConfig.txt`
-- DataTable:给候选池
-- 实例生成器:按规则从候选池里抽 Tag
-- 组件实例:保存最终抽出的 Tag 结果
-- 塔实例:组装时汇总三组件 Tag
+- 负责战斗与展示相关配置
+- 当前字段:`TriggerPhase`、`Description`、`ParamJson`
-### 3.3 重复 Tag 如何处理
+### 3.2 当前消费链
-三组件组塔后,同一个 Tag 很可能在多个组件上重复出现。这里必须明确规则,否则后续实现会反复返工。
+- `Tag.txt -> DRTag -> TagGenerationRuleRegistry`
+- 当前负责 `MinRarity` 与 `Weight`
+- `Tag.txt -> DRTag -> TagDefinitionRegistry.ApplyTagRows`
+- 当前负责把 `IsImplemented` 同步到定义层
+- `RarityTagBudget.txt -> DRRarityTagBudget -> RarityTagBudgetRuleRegistry`
+- 当前负责按品质读取 `MinCount / MaxCount`
+- `TagConfig.txt -> DRTagConfig -> TagDefinitionRegistry`
+- 当前负责 `TriggerPhase`、`Description` 与各 Tag 参数配置
-固定规则:
+### 3.3 运行时结构
-- 同一组件内不允许重复同一个 Tag
-- 不同组件之间允许重复
-- 组塔时不直接丢弃重复 Tag,而是转成 `Stack`
-
-也就是说,最终塔上的 Tag 结果不应该只是简单 `TagType[]`,而应该是“Tag + 层数”。
-
-## 4. 推荐的数据模型
-
-### 4.1 配置层
-
-当前实现固定采用“`Tag.txt + RarityTagBudget.txt + TagConfig.txt`”三层结构,而不是继续把所有规则硬塞进现有 `Tag.txt`。
-
-- `Tag.txt`
- - 保留 `TagType`、`Name` 等基础字典与按 Tag 的生成规则
- - 当前实际承载:`MinRarity`、`Weight`
-- `RarityTagBudget.txt`
- - 承载按品质的数量预算
- - 当前实际承载:`Rarity`、`MinCount`、`MaxCount`
-- `TagConfig.txt`
- - 承载战斗与展示相关配置
- - 当前实际承载:`TriggerPhase`、`Description`、`ParamJson`
-
-用途:
-
-- `MinRarity`:该 Tag 最低可出现品质
-- `Weight`:同一候选池内抽取权重
-- `MinCount / MaxCount`:该品质组件本次可抽取的 Tag 数量预算
-- `TriggerPhase`:用于战斗结算路由
-- `ParamJson`:承载伤害倍率、持续时间、范围等效果参数
-
-### 4.2 运行时结构
-
-当前 M1 运行时结构固定为两层:
-
-- 组件实例继续保存 `TagType[]`
-- 塔实例保存汇总后的 `TagRuntimeData[]`
+- 组件实例保存 `TagType[]`
+- 塔实例保存 `TagRuntimeData[]`
+- 塔实例同时保留 `Tags` 作为兼容投影
+- 战斗载荷保存塔级 `TagRuntimeData[]`
```csharp
public sealed class TagRuntimeData
@@ -111,544 +95,192 @@ public sealed class TagRuntimeData
}
```
-职责划分:
+### 3.4 当前最小战斗结构
-- 组件实例保存 `TagType[]`
-- 塔实例保存汇总后的 `TagRuntimeData[]`
-- UI 展示可以继续只展示 Tag 名称,但底层不再丢失层数信息
+- `AttackPayload`
+- 当前字段:`BaseDamage`、`AttackPropertyType`、`TagRuntimes`
+- `HitContext`
+- 当前字段:`AttackPayload`、`FinalDamage`、`IsCriticalHit`、`IsKilled`
+- 这套结构已经足够承载首发 7 个 Tag
+- 但还不足以稳定承载第二批攻击形态类 Tag,详见第 7 节审计问题
-## 5. 组件上如何随机生成 Tag
+## 4. 组件 Tag 生成
-### 5.1 随机时机
-
-Tag 随机应发生在“组件实例创建时”,而不是组塔时。
-
-包括以下来源:
-
-- 初始种子生成组件
-- 战斗掉落生成组件
-- 商店刷新生成组件
-- 事件奖励生成组件
-
-这样做的好处:
-
-- 玩家拿到手的组件就是确定结果
-- 背包展示、组装预览、商店预览都能直接展示真实 Tag
-- 存档不需要二次重算
-
-### 5.2 候选池构建
-
-单个组件实例的候选池按以下规则生成:
+### 4.1 当前流程
1. 读取组件配置的 `PossibleTag`
-2. 读取 Tag 表
-3. 过滤掉 `MinRarity > 组件品质` 的 Tag
-4. 只保留同时存在于 `PossibleTag` 与 Tag 表允许范围内的 Tag
+2. 读取 `Tag.txt` 中对应的生成规则
+3. 过滤掉 `None`、非法枚举、当前未首发支持的 Tag
+4. 过滤掉 `MinRarity > 当前组件品质` 的 Tag
+5. 根据 `RarityTagBudget.txt` 决定本次抽取数量
+6. 在候选池内按 `Weight` 抽取
+7. 单组件内不重复抽取同一 Tag
+8. 候选池不足时允许少于预算,不强行补满
-结果:
+### 4.2 当前统一入口
-- `PossibleTag` 决定这个组件系列“能出什么”
-- `MinRarity` 决定当前品质“允许出到什么档位”
+- `InventorySeedUtility`
+- `ShopFormUseCase`
+- `EnemyDropResolver`
+- 事件奖励后续如生成组件,也必须走同一入口
+- 当前统一入口是 `ComponentTagGenerationService`
-### 5.3 Tag 数量预算
+### 4.3 可复现合同
-每个品质都保留独立的 Tag 数量预算,并由 `RarityTagBudget.txt` 驱动,而不是按概率硬编码在代码里。
+- 设计目标要求 Tag 结果对同一 Run 可复现,并在存档读档后保持一致
-当前正式默认值:
-
-| 品质 | 推荐数量 |
-|------|----------|
-| White | `0~1` |
-| Green | `0~2` |
-| Blue | `1~3` |
-| Purple | `1~3` |
-| Red | `2~4` |
-
-### 5.4 随机规则
-
-固定抽取流程:
-
-1. 先根据品质决定本组件本次要抽几个 Tag
-2. 从候选池中按 `Weight` 抽取
-3. 单组件内不重复抽同一个 Tag
-4. 候选池不足时允许少于目标数量,不强行补 Tag
-
-### 5.5 可复现要求
-
-Tag 随机必须可复现。
-
-统一随机种子来源:
+正式随机上下文应包含:
- `RunSeed`
- `ItemInstanceId`
- `ConfigId`
-- `SourceType`(掉落 / 商店 / 初始 / 事件)
+- `SourceType`
-原则:
+当前实现已经使用:
-- 同一个组件实例只生成一次 Tag
-- 存档与读档不重新随机
-- 商店刷新前后只有新实例才会有新结果
+- `Rarity`
+- `SourceType`
+- `ItemInstanceId`
+- `ConfigId`
+- 当前实现尚未把 `RunSeed` 作为显式输入接进 `ComponentTagGenerationService`
+- 这是当前已确认的问题,不应视为已完成能力
-## 6. 组塔后的 Tag 汇总规则
+## 5. 塔级汇总与展示
-组塔阶段不再随机,只做汇总。
+### 5.1 汇总规则
-固定流程:
+- 同一组件内不允许重复同一个 Tag
+- 不同组件之间允许重复
+- 组塔时不做重新随机
+- 汇总时按 `TagType` 分组并累加 `Stack`
-1. 收集三组件的 `TagType[]`
-2. 按 `TagType` 分组
-3. 累加 `Stack`
-4. 输出塔级别的 `TagRuntimeData[]`
+### 5.2 展示规则
-示例:
+- 组件展示仍显示组件实例自己的 `Tags`
+- 塔展示优先显示 `TagRuntimes`
+- 若缺少 `TagRuntimes`,允许通过 `Tags` 回退构建兼容结果
+- 重复 Tag 以 `xN` 文本显示,例如 `Fire x2`
-- 枪口:`Fire x1`
-- 轴承:`Fire x1`, `BurnSpread x1`
-- 底座:`Inferno x1`
+### 5.3 兼容边界
-组塔后:
+- `TowerStatsData.Tags` 不是新的真相源
+- 它只用于兼容旧展示链路与旧数据
+- 后续新增逻辑应优先读取 `TagRuntimes`
-- `Fire x2`
-- `BurnSpread x1`
-- `Inferno x1`
+## 6. 战斗模型
-这比简单去重更合理,因为后续战斗效果可以基于层数增强,而不是浪费重复结果。
+### 6.1 分类与触发阶段
-## 7. 战斗中如何生效
+| 分类 | 说明 | 当前主触发阶段 |
+|------|------|----------------|
+| `Status` | 命中后在敌人身上形成可持续状态 | `OnAfterHit` |
+| `NumericModifier` | 命中前修正最终伤害 | `OnBeforeHit` |
+| `AttackShape` | 穿透、传播、爆炸等攻击形态变化 | `OnHit` / `OnKill` |
+| `StatusModifier` | 强化同次命中的状态类 Tag,但不独立生成敌人持有状态 | 当前随主状态一起消费 |
-### 7.1 现有链路限制
+### 6.2 当前已实现的首发 7 Tag
-当前战斗链路是:
+| Tag | 分类 | 配置阶段 | 当前真实行为 |
+|-----|------|----------|--------------|
+| `Fire` | `Status` | `OnAfterHit` | 命中后施加燃烧 DOT |
+| `Ice` | `Status` | `OnAfterHit` | 命中后施加减速 |
+| `Crit` | `NumericModifier` | `OnBeforeHit` | 按概率暴击并放大伤害 |
+| `Execution` | `NumericModifier` | `OnBeforeHit` | 对低血量目标增伤 |
+| `Shatter` | `NumericModifier` | `OnBeforeHit` | 对已减速目标增伤 |
+| `Inferno` | `StatusModifier` | `OnAfterHit` | 强化同次命中的 `Fire` 时长与伤害 |
+| `AbsoluteZero` | `StatusModifier` | `OnAfterHit` | 强化同次命中的 `Ice` 时长与减速强度 |
-- `TowerController` 取塔属性
-- `BasicBaseComp` 发起攻击
-- `ShooterMuzzleComp` 创建子弹
-- `ShooterBullet` 命中后调用 `IDamageReceiver.TakeDamage(int damage, AttackPropertyType attackPropertyType)`
+### 6.3 当前已后移的 5 Tag
-这条链路只够表达:
+| Tag | 分类 | 当前状态 |
+|-----|------|----------|
+| `BurnSpread` | `AttackShape` | 仅保留元数据与占位路由,未实际生效 |
+| `IgniteBurst` | `AttackShape` | 仅保留元数据与占位路由,未实际生效 |
+| `FreezeMask` | `AttackShape` | 仅保留元数据与占位路由,未实际生效 |
+| `Pierce` | `AttackShape` | 仅保留元数据与占位路由,未实际生效 |
+| `Overpenetrate` | `AttackShape` | 仅保留元数据与占位路由,未实际生效 |
-- 伤害数值
-- 伤害属性
+### 6.4 当前运行时边界
-不够表达:
+- 数值类 Tag 当前在 `ResolveBeforeHit` 阶段生效
+- 状态类 Tag 当前通过 `EnemyTagStatusRuntime` 管理敌人持有状态
+- `Inferno` 与 `AbsoluteZero` 当前不是独立状态,而是在 `FireTagEffect`、`IceTagEffect` 中读取同次命中的强化层数
+- 攻击形态类 Tag 当前只有路由骨架,没有真实战斗效果
-- 暴击
-- 斩杀
-- 燃烧 DOT
-- 冻结层数
-- 穿透与连锁
-- 命中后爆炸
+## 7. 已确认审计问题
-所以 Tag 不能直接继续依附在 `TakeDamage(int, AttackPropertyType)` 上。
+### 7.1 配置真相源与加载顺序不稳定
-### 7.2 推荐挂载点
+- `IsImplemented` 当前同时存在于 `Tag.txt` 与定义层默认值
+- `Tag` 与 `TagConfig` 的 DataTable 加载先后会影响 `TagDefinitionRegistry` 最终状态
+- 这意味着“Tag 是否首发启用”还没有成为稳定的唯一真相源
-后续战斗入口固定引入统一的命中载荷与结算器:
+### 7.2 Tag 随机合同未完整落地
-```csharp
-AttackPayload
-```
+- 文档口径要求随机上下文包含 `RunSeed`
+- 当前 `ComponentTagGenerationService` 还没有显式接收 `RunSeed`
+- 当前掉落链路的实例 Id 也会在局部重置,不能继续承担跨 Run 区分责任
-至少包含:
+### 7.3 战斗上下文合同仍偏弱
-- `BaseDamage`
-- `AttackPropertyType`
-- `TagRuntimeData[]`
-- 攻击来源信息
+- `HitContext` 当前只够承载首发数值修正与最小状态挂载
+- 数值类 Tag 仍依赖 `targetCurrentHealth`、`targetHasSlowStatus` 这类散装参数
+- 如果直接继续做 `Pierce`、`BurnSpread` 等第二批 Tag,函数签名会继续膨胀
-命中时再构造:
+### 7.4 配置字段与真实行为还没有完全对齐
-```csharp
-HitContext
-```
+- 当前 `TagConfig.txt` 里的部分字段已经进入表与配置类
+- 但并非所有字段都成为真实运行时行为
+- 例如 `Fire.MaxEffectiveStack` 当前并未进入实际结算
+- 这类字段要么接入运行时,要么移出当前正式口径
-至少包含:
+### 7.5 主文档曾混入历史草稿
-- `Attacker`
-- `Target`
-- `AttackPayload`
-- 是否击杀
-- 命中位置
+- 本文件过去同时包含正式收口口径与旧的 12 Tag 流派草稿
+- 这种写法会让“当前真实实现”和“历史预案”混淆
+- 从本次更新开始,主文档只保留当前正式口径
-统一由:
+## 8. 审计整改顺序
-```csharp
-TagEffectResolver
-```
+### S7-01 收口配置真相源与加载顺序
-处理 Tag 逻辑。
+- 统一 `IsImplemented` 的最终真相源
+- 保证 `Tag.txt` 与 `TagConfig.txt` 的加载顺序不再影响最终定义结果
+- 补加载顺序相关 EditMode 测试
-### 7.3 触发阶段
+### S7-02 补齐随机上下文与 `RunSeed`
-Tag 触发阶段固定拆成四段:
+- 给 `ComponentTagGenerationService` 增加显式随机上下文
+- 把 `RunSeed` 纳入正式输入
+- 统一掉落、商店、种子、事件奖励四条链路的上下文构造方式
-1. `OnBeforeHit`
- - 例:`Crit`、`Execution`
-2. `OnHit`
- - 例:直接附加伤害、穿透判定
-3. `OnAfterHit`
- - 例:施加燃烧、减速、冻结层数
-4. `OnKill`
- - 例:击杀爆炸、传播
+### S7-03 收口 `AttackPayload / HitContext` 合同
-这样可以避免把所有效果都堆进一个巨大 `switch` 里。
+- 把当前散装战斗输入收回统一上下文对象
+- 为第二批攻击形态类 Tag 预留稳定上下文
+- 在本项完成前,不推进第二批 Tag 的真实战斗效果
-## 8. 当前 12 个 Tag 的效果定位
+### S7-04 对齐 `TagConfig` 与运行时真实消费
-### 8.1 第一批优先落地
+- 清点每个 `ParamJson` 字段是否真的被运行时消费
+- 已保留字段必须真实生效,或明确标记为占位
+- 明确 `StatusModifier` 的正式消费方式
-这些效果与当前伤害模型更兼容,适合作为第一批战斗 Tag:
+### S7-05 保持文档主干单一口径
-| Tag | 首发定位 |
-|-----|----------|
-| `Fire` | 命中附加燃烧 DOT |
-| `Ice` | 命中附加减速 |
-| `Crit` | 命中前按概率暴击 |
-| `Execution` | 对低血量目标增伤或直接处决 |
-| `Shatter` | 对已减速 / 已冻结目标增伤 |
-| `Inferno` | 强化燃烧伤害或持续时间 |
-| `AbsoluteZero` | 强化减速,或提高冻结触发速度 |
+- `TagSystemDesign.md` 只保留当前真实实现与整改边界
+- 新的长期预案应进入独立文档,而不是回写到本文件主干
-这些效果主要需要:
+## 9. 当前默认边界
-- 命中前倍率修正
-- 敌人状态容器
-- DOT / Slow 的 runtime tick
+- 在 `S7-01 ~ S7-04` 完成前,不新增第二批 Tag 的真实战斗效果
+- 在配置真相源收稳前,不继续增加新的“是否启用”字段来源
+- 在 `HitContext` 收稳前,不继续依赖更多散装参数扩展 Tag 逻辑
+- 在 `TagConfig` 消费对齐前,不继续向 `ParamJson` 追加没有运行时消费者的字段
-对当前战斗架构侵入相对可控。
+## 10. 非当前范围
-### 8.2 第二批再落地
-
-这些效果需要更完整的弹道 / 范围 / 状态系统,固定放到后续阶段实现:
-
-| Tag | 后续定位 |
-|-----|----------|
-| `BurnSpread` | 燃烧向邻近敌人传播 |
-| `IgniteBurst` | 燃烧结束或击杀时爆炸 |
-| `FreezeMask` | 冻结积累条 / 冻结面具机制 |
-| `Pierce` | 子弹贯穿多个目标 |
-| `Overpenetrate` | 贯穿后保留部分伤害继续飞行 |
-
-这些效果会牵动:
-
-- 子弹多命中
-- 范围查询
-- 击杀后触发
-- 敌人持续状态传播
-
-不适合在最早版本一次性塞进当前命中链路。
-
-## 9. 推荐的分阶段实施方案
-
-### Phase 1:规则入口
-
-目标:
-
-- 补齐 Tag 配置模型
-- 实现组件实例随机生成 Tag
-- 统一掉落 / 商店 / 初始种子 / 事件奖励入口
-
-交付重点:
-
-- `TagGenerationService`
-- `TagGenerationResult`
-- 组件实例保存最终 Tag 结果
-
-### Phase 2:塔级汇总
-
-目标:
-
-- 组塔时把三组件 Tag 汇总成塔级结果
-- 不再简单去重,而是保留层数
-
-交付重点:
-
-- `TowerTagAggregationService`
-- 塔实例保存 `TagRuntimeData[]`
-
-### Phase 3:战斗载荷
-
-目标:
-
-- 把塔的 Tag 结果传到子弹 / 命中链路
-- 引入统一结算入口
-
-交付重点:
-
-- `AttackPayload`
-- `HitContext`
-- `TagEffectResolver`
-
-### Phase 4:第一批战斗效果
-
-正式首发集合固定为:
-
-- `Fire`
-- `Ice`
-- `Crit`
-- `Execution`
-- `Shatter`
-- `Inferno`
-- `AbsoluteZero`
-
-这批做完后,Tag 系统就从“展示字段”升级成“有实际战斗意义的最小闭环”。
-
-### Phase 5:高级联动
-
-后续再做:
-
-- 传播
-- 爆炸
-- 冻结积累
-- 穿透与多命中
-- 更复杂的多 Tag 联动
-
-## 10. 与当前 MVP 范围的关系
-
-当前 `docs/TODO.md` 已把 `P0-11` 收口为“规则最小闭环”。本设计文档与该口径保持一致:
-
-- M1 最低要求是统一 Tag 来源与汇总规则
-- M1 不强制要求一次做完全部高级联动
-- 若要在 M1 内让 Tag 进入战斗,只做第一批效果,不同时展开高级传播 / 贯穿体系
-
-同时需要注意,`docs/MVP-Scope.md` 里写了:
-
-- 基础 Tag 系统只保留 `6~8` 个
-- 不做高级 Tag 联动
-- 不做复杂触发矩阵
-
-因此后续真正实施时,MVP 正式首发集合固定为以下 7 个:
-
-- `Fire`
-- `Ice`
-- `Crit`
-- `Execution`
-- `Shatter`
-- `Inferno`
-- `AbsoluteZero`
-
-而 `BurnSpread`、`Pierce`、`Overpenetrate`、`FreezeMask`、`IgniteBurst` 都作为后续扩展,不属于当前 `S4` 首发范围。
-
-## 11. 当前收口结论
-
-1. `S4-07` 已确认采用 `Tag.txt + RarityTagBudget.txt + TagConfig.txt` 三层表结构作为正式方案
-2. `ComponentTagGenerationService` 已收口组件实例生成,不再直接复制 `PossibleTag`
-3. `TowerTagAggregationService` 已收口塔级汇总,重复 Tag 会转为 `TagRuntimeData.TotalStack`
-4. `AttackPayload + HitContext + TagEffectResolver` 已成为当前战斗内的统一 Tag 挂载点
-5. 首发只实现固定 7 个基础 Tag,避免超出 `MVP-Scope`
-
-## 12. 默认决策
-
-若没有额外设计变更,后续默认按以下决策推进:
-
-- Tag 在组件实例创建时随机,不在组塔时随机
-- `PossibleTag` 是候选池,不是最终实例值
-- 塔级 Tag 汇总保留 `Stack`
-- 配置层正式采用 `Tag.txt + RarityTagBudget.txt + TagConfig.txt` 分层结构
-- 第一批战斗效果优先做状态类与数值修正类,不优先做穿透 / 爆炸 / 传播
-- MVP 正式首发集合固定为 `Fire`、`Ice`、`Crit`、`Execution`、`Shatter`、`Inferno`、`AbsoluteZero`
-- `BurnSpread` 明确后移,不作为当前首发集合成员
-- `TagGroup` 当前只作为分类展示元数据,不进入运行时生成、汇总或战斗规则链
-
-# 总体结构
-
-我们设计 3 个流派方向:
-
-1. 🔥 元素爆发流(AOE清场)
-
-2. ❄ 控制叠层流(减速控制)
-
-3. 🎯 穿透暴击流(单体爆发)
-
-每个流派 4 个 Tag,其中:
-
-- 2 个基础属性 Tag
-
-- 1 个机制 Tag
-
-- 1 个高阶(稀有)Tag
-
-总 Tag 数 = 12
-
-## 一、🔥 元素爆发流
-
-核心定位:
-
-> 中等频率攻击 + 元素叠层 + 击杀爆炸清场
-
-## 4 个 Tag
-### 1️⃣ Fire(基础)
-
-效果:
-
-- 攻击附带灼烧(持续伤害)
-
-- 可叠加 3 层
-
-### 2️⃣ BurnSpread(机制)
-
-触发:
-
-- 目标死亡时将灼烧传播给周围 2 个敌人
-
-### 3️⃣ IgniteBurst(组合触发)
-
-触发条件:
-
-- 同一塔 ≥2 Fire Tag
-
-效果:
-
-- 满层灼烧爆炸(小范围AOE)
-
-4️⃣ Inferno(稀有)
-
-品质限定:紫及以上
-
-效果:
-
-爆炸伤害 ×2
-
-灼烧叠层上限 +2
-
-流派触发逻辑
-条件 效果
-1 Fire 基础DOT
-2 Fire IgniteBurst 激活
-Fire + BurnSpread 爆炸后传播
-Inferno + 2 Fire 大范围爆炸
-二、❄ 控制叠层流
-
-核心定位:
-
-降速 + 冻结 + 稳定推进
-
-4 个 Tag
-1️⃣ Ice(基础)
-
-效果:
-
-攻击附带减速
-
-可叠加 5 层
-
-2️⃣ FreezeMark(机制)
-
-触发:
-
-目标叠满 5 层冻结 1 秒
-
-3️⃣ Shatter(组合触发)
-
-触发:
-
-冻结目标受到暴击时额外伤害
-
-4️⃣ AbsoluteZero(稀有)
-
-品质限定:紫及以上
-
-效果:
-
-冻结时间 +50%
-
-冻结爆裂产生小范围伤害
-
-流派触发逻辑
-条件 效果
-1 Ice 减速
-Ice + FreezeMark 满层冻结
-冻结 + Shatter 爆裂伤害
-AbsoluteZero 群控升级
-三、🎯 穿透暴击流
-
-核心定位:
-
-低频高伤 + 直线穿透 + 单体爆发
-
-4 个 Tag
-1️⃣ Pierce(基础)
-
-效果:
-
-子弹穿透 2 个敌人
-
-2️⃣ Crit(基础)
-
-效果:
-
-+15% 暴击率
-
-3️⃣ Overpenetrate(机制)
-
-触发:
-
-穿透第一个敌人后伤害提升 30%
-
-4️⃣ Execution(稀有)
-
-品质限定:紫及以上
-
-效果:
-
-暴击对生命低于30%目标伤害 ×2
-
-流派触发逻辑
-条件 效果
-Pierce 直线清场
-Crit 随机爆发
-Pierce + Crit Overpenetrate 激活
-Execution 斩杀强化
-四、品质与 Tag 关系设计
-
-建议规则:
-
-品质 Tag 数量
-白 1
-绿 1
-蓝 2
-紫 2 + 稀有概率
-红 3(含稀有)
-
-这样:
-
-低品质仍有存在价值
-
-高品质增加构筑复杂度
-
-稀有 Tag 不会泛滥
-
-五、组合系统可视化建议
-
-在组装界面显示:
-
-🔥 元素爆发(已激活)
-
-灼烧爆炸
-
-传播效果
-
-❄ 冰霜控制(未激活)
-
-需要 FreezeMark
-
-这样玩家会有“完成拼图”的感觉。
-
-六、数值安全机制(防止爆炸)
-
-每个机制必须有:
-
-触发冷却(0.5~1秒)
-
-最大叠层限制
-
-爆炸不触发爆炸(防无限连锁)
-
-群体上限目标数
-
-例如:
-
-BurnSpread 最多传播 3 次。
-
-否则后期怪物多时会帧率爆炸。
+- `BurnSpread`、`IgniteBurst`、`FreezeMask`、`Pierce`、`Overpenetrate` 的真实战斗实现
+- 更复杂的多 Tag 联动与流派激活矩阵
+- 冻结积累条、击杀爆炸传播链、多命中弹道系统
+- Tag 等级成长、TagGroup 运行时规则、额外 Tag 元数据扩展表