Files
gplan-2/design/gdd/b3-status-effect.md
T
DKChan 85841f52be docs(gdd): 13 份系统 GDD 迁移为 design/analysis 两件套 v2
- design 件只装结论:v2 骨架(设计目的/系统范围/核心循环/领域章节/依赖与输出/P0 闭环/P1·P2 后置/调参表/GWT 验收/版本历史),AC/EC/OQ/义务台账编号全部保留
- 新建 design/gdd/analysis/ 13 份推演件:候选取舍/公式推导/数值锚定论证/已裁决争议按问题节组织,文末附去向映射表(零丢失审计)
- v1 原文备份于 design/gdd/legacy-2026-09-14-v1/(13 份)
- systems-index 文档树补 analysis 目录导航行
- gdd_lint 全量 PASS(14 文件 0 不通过);迁移零裁决——19+1 项待拍板已登记各 analysis 开放问题区
2026-09-14 20:39:11 +08:00

506 lines
66 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.
# B3 增益/状态系统(Status Effect System)
> **状态**:Approved · **版本**:v2 · 2026-09-14
> **承载支柱**:P2 主(可归因兑现的机制落点)· P3(敌方增益/debuff 兑付面)· P1(时限透明的规划素材)· P4(间接)· **Layer**:1 Foundation · **Milestone**:MVP · **设计顺序**:第 4 位
> **一句话**:战斗域统一状态容器——三向效果同构实例的时限/叠层/衰减机制唯一 owner,兑付接口供 B1 结算逐行消费。
> **推演件**:`design/gdd/analysis/b3-status-effect.md`(本文件只收结论,理由在那里)
## 设计目的
战斗里不在当场一次性、而要在若干次结算里持续起作用的战斗效果(安全格增益 / 踩雷敌方增益 / 标中旗削弱 / 清图奖励 buff)需要一个统一的存放与生命周期 owner。少了它,四类效果各写一套计时叠层逻辑,结算明细无法逐行归因,"规划的延迟兑现"无从落地。
1. 玩家指着任意一行结算明细,能答出"这效果是我哪步扫雷带来的"——来源标注随行(P2)。
2. 玩家能读到每个增益"还剩几次结算、何时到期",把它纳入挖哪格的推理(P1)。
3. 叠满再拿同款时玩家看得到"这层白拿了"——浪费诚实、可规划(P2)。
4. 踩雷的敌方增益与标中旗的削弱用同一呈现语言,玩家由此学会雷的两面(P3)。
5. 结算编排只对接五个固定接口;新增效果只加表行、不改容器代码。
## 系统范围
负责:
- 状态实例生命周期(战斗域):授予受理、存续、到期移除、战斗结束清空;机制与内容分离——B3 只拥有机制,效果内容的经济归属归各锚 owner
- 时限/叠层/衰减机制语义:单一结算次数量纲、按行叠层三分支、先兑付后衰减
- 兑付接口五 API 与 P2 归因字段(实例六字段 + display_name + 授予时数值快照)
- StatusEffectTable 回填 owner:schema + 四行 MVP 初值定稿权(锚验收权留 B4/B2/B1)
- 硬约束:零随机(无 RNG 流消费)· 零 UI 依赖 · 零信号外发(纯被动容器)· 全 API 布尔/计数返回、无 await——可回放步骤流的状态侧前提
不负责:
- 效果内容经济归属——安全格 buff 与标中旗 debuff 档位锚验收(B4)、敌方增益上限(B2)
- 效果语义到结算公式的映射、兑付作用顺序、合成值地板/clamp、percent→乘数换算方向(B1 SettlementTable)
- flat 量纲定义(B2——已定稿,registry ambush_unit_definition)
- 呈现与渲染面——HUD 状态栏/结算明细呈现/图标映射(D1/B5/art-bible)、教学(D5)、本地化(D6)
- 事实产生与资格判定——开格/标中/开雷事件(A2)、标中旗兑付资格判定(A3/A2 域)、事实→授予恰一次转化(B1)
- 数据加载、校验、热重载门(D2)
- 事件外发(零——纯被动容器)
## 核心循环
```
B1 结算编排(唯一授予入口 apply_effect——A2/B4 与 B3 零直接接口)
│ 事实来源:A2 开格/标中/开雷事件 → B1 收集 round facts → 转化授予(挖掘期不直接写容器)
▼
授予(编排期入容器,无 pending 态——首个结算就是它的第一次兑付)
│ merge(effect_id) 三分支:independent 新建实例 / stack L+1(L=M 拒绝) / refresh R←D
│ 实例载荷 = 六归因字段 + display_name + 授予时数值快照 (magnitude, unit)
▼
Active(存续——跨轮次、跨扫雷图延续;换图/刷新不清空,旗标记随图消亡不影响实例)
│ 每轮结算:B1 query_active(side) 只读兑付(作用顺序归 B1 SettlementTable)
│ → decay_round() 恰一次:全实例 R−1,R=0 销毁(先兑付后衰减)
▼
出口 ─┬ R=0 → Expired:实例销毁(明细流水已由 B1 记录,B3 不留历史)
├ notify_battle_end → Cleared:全实例销毁、容器回空 → BattleClosed(不跨战斗)
└ 拒绝路径:域闭 / 未知 effect_id / 满层 → false + 容器零写(溢出行归 B1 结算明细)
```
| 出口 | 触发 | 动作/去向 | 约束 |
|---|---|---|---|
| 受理入容器 | apply_effect 受理(新实例/叠层/刷新) | 即入 Active——无 pending 态,首个结算是第一次兑付 | 域闭 / 未知 id / 满层 → false 拒绝(见边界情况) |
| 到期移除 | decay_round 后 R=0 | 实例销毁 → Expired | 明细流水已由 B1 记录,B3 不留历史 |
| 战斗清空 | notify_battle_end() | 全实例销毁、容器回空 → BattleClosed | 不跨战斗;除本 API 外无任何清空入口 |
| 满层拒绝 | stack 行 L=M 再授予 | 返回 false、容器逐字不变;"溢出未生效"行归 B1 结算明细(含来源) | 拒绝原子性——无半写、无溢出落层 |
## 实例状态
容器为纯逻辑类(非 autoload、无场景依附),每场战斗实例化一次(B1 编排前提;冒烟经 class_name 直引构造)。容器无运行时大状态机——实例生命周期四态(战斗域):
| 状态 | 进入条件 | 行为/出口 |
|---|---|---|
| BattleClosed(域闭) | 构造后未开域 / notify_battle_end() 后 | apply_effect 全拒绝(false);唯一出口 notify_battle_start() |
| Active(存续) | apply_effect 受理(新实例/叠层/刷新) | 每轮结算被 B1 兑付消费;decay_round() 后 remaining −1 |
| Expired(移除) | remaining_settlements = 0 | 实例销毁(明细流水已由 B1 记录,B3 不留历史) |
| Cleared(清空) | notify_battle_end() | 全实例销毁、容器回空 → BattleClosed(不跨战斗) |
不变式(debug 断言口径):
- remaining ∈ [0, duration_settlements];stack 行 layers ∈ [1, max_stack];stack/refresh 策略下同 id 至多一个实例——违反即 debug 断言中止
- API 违规(域闭授予、未知 effect_id、满层授予)= 拒绝(false)+ debug 诊断,不进程致命(承 A3 拒绝口径;进程致命保留给 D2 数据通道)
设计意图:四态封闭、清空入口唯一,"容器何时为空"永远可答。
## 枚举与数据字段
### source_class(封闭枚举——P2 归因字段)
| 值 | 产出点 | 语义 |
|---|---|---|
| safe_cell | 安全格奖励授予 | 主角增益来源 |
| flag_hit | 标中旗授予 | 怪物削弱来源 |
| mine_hit | 踩雷授予 | 敌方增益来源 |
| clear_reward | 清图奖励授予 | 清图槽 buff 来源(B4 期定稿) |
- 新增值 = 接口漂移;B3 不校验 source_class 与行的对应(dumb 账本——EC6 同族)
- 内容行表"来源"列为内容档案(provenance),非 schema 字段、非运行时约束
### target_side / unit / stack_policy(schema 枚举域)
| 字段 | 值域 | 语义 |
|---|---|---|
| target_side | hero / enemy | 作用侧;enemy 侧 side-wide = 全体存活敌单位(层数 = side 共享池) |
| unit | percent / flat | percent = 百分比修正(百分点线性叠加);flat = 固定值(伏击类——量纲已定稿:每层伏击为每次攻击类行为附加 m_amb 点主角 HP 伤害、后置加法不进倍乘、charge 拍零兑付,B2 GDD 定稿) |
| stack_policy | stack / refresh / independent | 同 id 重复授予的合并策略(见授予节子表) |
### StatusEffectTable schema(D2 承载,B3 回填 owner)
规则:
1. **Rule 9** 容器本身不认识任何具体数值——哪个状态加多少、活几次、最多叠几层全部写在状态表里,运行时统一从 ConfigDB 读表;代码零玩法数值字面量,调平衡只改表、不改代码。
| 字段 | 类型/范围 | 说明 |
|---|---|---|
| effect_id | String(主键唯一) | 状态标识;B1 SettlementTable 语义映射的键 |
| display_name | String | 图例/HUD/明细用名(本地化归 D6) |
| target_side | enum {hero, enemy} | 作用侧(enemy 侧 side-wide = 全体存活敌单位) |
| magnitude | int | 域随 unit:percent ∈ [-100, 100] 且 ≠0 / flat ≥ 1(跨字段校验) |
| unit | enum {percent, flat} | percent = 百分比修正;flat = 固定值(伏击类) |
| duration_settlements | int [1, 99] | 授予时初始剩余结算次数(一次性 = 1) |
| stack_policy | enum {stack, refresh, independent} | 同 id 重复授予的合并策略 |
| max_stack | int [1, 16] | 层数上限;仅 stack 消费——refresh/independent 行约定恒 1(内容约定,非校验项) |
- 表为定义表非进度成长表,无 (level_index, node_depth) 维度(D2 Rule 4 豁免,A4 先例);未来随关卡成长的效果走接口漂移加列
- 加载校验:表非空(D2 Rule 6,四行即满足);effect_id 唯一(重复键致命——本表唯一致命夹具 dup_key);枚举域校验(target_side/unit/stack_policy 出域致命);duration/max_stack 域校验;跨字段 percent ≠ 0 / flat ≥ 1
举证:Rule 9 依据 = D2 Rule 1〔数值字面量禁令〕;本 GDD 为该表回填 owner,新字段走接口漂移规则。
### StatusEffectTable MVP 内容行(四行值域快照——值全部 provisional)
规则:
1. **Rule 10** 四行 MVP 内容(增伤、减伤、伏击、削弱)的初始数值由本文档定稿;"值合不合适"的验收权留在对口系统——削弱按"必须严过最低档增益"的当量锚验收、伏击按敌方惩罚上限验收、对账由结算闭合;要改初值走接口漂移规则回写登记库(registry),不是随手调参。
| effect_id | 名称 | side | magnitude(现行值) | duration | stack/max | 来源 | provisional 依据 |
|---|---|---|---|---|---|---|---|
| attack_up | 增伤 | hero | +50 percent | 1(当次结算) | stack / 2 | safe_cell | 原型临时值 1.5× 换算(D2 knobs 占位);消费面 = 主角战斗段先手攻击(HeroTable.atk 基础攻击恒存在) |
| defense_up | 减伤 | hero | −30 percent | 1(当次结算) | stack / 2 | safe_cell | 减伤墙批 C3 投值(−50→−30,叠满两层 −60 帽——defense_scan 墙轮 39%/真人 12 轮零承伤定量坐实后回调) |
| ambush | 伏击(敌方增益) | enemy | +3 flat | 1 | stack / 16 | mine_hit | 原型临时值 +3;量纲已定稿(B2 GDD——registry ambush_unit_definition);条款 3 锚验收归 B2/B1 |
| weaken | 削弱(标中旗 debuff) | enemy | −65 percent(值域 [60, 85]) | 1 | stack / 16 | flag_hit | F0 裁决值——回执以 B1 GDD F0 为准(registry anchor_warning);须过条款 2 锚(严格 > 最低档 buff 当量,B1 对照验收) |
举证:Rule 10 依据 = A3 F1 条款 2〔debuff 严格 > 最低档 buff 当量,参照对象 = attack_up 行当量〕· 条款 3〔B2 惩罚上限〕· A3 OQ5 收编〔registry ownership_note——A3 GDD 正文不改,以本条 + registry ownership_note 为准〕;初值定稿权归本文档、锚验收权留 B4/B2/B1,是对"档位归奖励表设计"的显式收编。
设计意图:机制归容器、数值归表、档位归锚 owner——三方权责不混。
## 授予、合并与接口
规则(原编号保留):
1. **Rule 1** 战斗里不在当场一次性生效、要管上几回结算的效果——主角增益、敌人增益、敌人受到的削弱、清图奖励——全部作为同一种状态实例存进同一个容器,用同一套计时、叠层、衰减规矩管理,没有哪类效果走特殊通道;容器四条硬规矩见下表。
2. **Rule 3** 状态只在结算时发放:挖掘期的挖格、插旗、踩雷不直接改容器,棋盘只上报"发生了什么"的事实,结算编排在每轮结算时统一把事实兑换成状态发给容器——这是唯一进货口,棋盘与奖励背包都没有直通通道;每笔状态随身携带归因(来源类别四选一、来自哪个格子、第几轮);状态一经发入立即生效,没有"待生效"中间态,同一场结算就是它的第一次兑付。
3. **Rule 4** 同一种状态还没消失时又拿到一份,怎么合并由数据表每行的叠层策略字段说了算——叠加(层数 +1、寿命不动)、刷新(寿命重新计满、层数不变)、并存(各算各的一份);合并在授予那一刻由容器内部完成,多个状态在结算里按什么先后起作用是结算编排的职责,两件事互不干扰;叠加是纯加法——几层就是几倍的行值。
4. **Rule 5** 叠加型状态叠到上限再授予同款不生效:容器拒绝、内容一个字不变;但这份奖励不会被无声吞掉——结算明细多一行"溢出未生效"、连来源一起写明;无论重复来自玩家直接踩出的格子、结算转化、还是连锁展开自动开出的奖励格,都走同一个授予入口、同样产生溢出行、同样留痕;不做覆盖、不做溢出落层。
5. **Rule 6** 状态容器是纯被动的仓库,自己不主动做任何事;结算编排要用它只有五个固定接口(下表);查询返回按发放先后排列且顺序永远稳定;全部 API 布尔/计数返回、无 await、无表现面。
6. **Rule 8** 状态一旦生效,玩家没有任何手段把它摘掉、往后延、或挪给别人——容器没有提供这类接口;将来若要加驱散/延时/转移,属于新增接口的修订,不是调参数。
容器四条硬规矩:
| 规矩 | 含义 |
|---|---|
| 寿命 = 一场战斗 | 战斗开始时容器为空,战斗结束全部清空——不跨到下一场战斗 |
| 跨轮、跨图延续 | 同一场战斗里跨轮次、跨扫雷图都在;换图/刷新不清空(旗标记随旧图消亡归棋盘系统 A2 管,状态实例不随图走) |
| 全程零随机 | 容器不掷任何骰子:授予、合并、衰减、列举顺序全部确定 |
| 敌方侧共享 | MVP 敌人为 1–3 个同种敌单位(敌情系统 B2 定):对敌状态一律对全体存活敌人生效,层数全体共享一份 |
三向效果映射(授予路径):
| 事实来源 | source_class | 授予路径 | 目标侧 | MVP 行 |
|---|---|---|---|---|
| 安全格奖励 | safe_cell | A2 开格事实 → B1 转化 apply_effect | hero | attack_up / defense_up |
| 踩雷 | mine_hit | A2 开雷事实 → B1 转化 apply_effect | enemy(side-wide) | ambush |
| 标中旗 | flag_hit | A2 标中判定 → B1 转化 apply_effect;兑付资格(雷格实例键)判定在 A3/A2 域——资格判定不过 B3,B3 无从重复兑付同雷(每次 flag_hit 授予由 B1 保证资格合法) | enemy(side-wide) | weaken |
| 清图奖励 | clear_reward | B4/B1 清图槽含 buff 时授予(B4 期定稿) | 随行 | B4 差异化插槽(OQ4) |
按行叠层三分支(stack_policy——授予时合并):
| stack_policy | 重复授予行为 | 满层/溢出 | MVP 消费 |
|---|---|---|---|
| stack | 层数 +1(R 不动——只有初始授予定钟) | L=M → 拒绝 false + 容器零写,"溢出未生效"行归 B1 | 四行全用(attack_up/defense_up M=2、ambush/weaken M=16) |
| refresh | 剩余次数重置为实例授予时快照 D、层数不变(含 R 已 = D 的空刷新——恒返回 true,无满层/溢出语义、不消费 max_stack) | 无 | 语义已定义、实现承载——MVP 无内容行(零消费者) |
| independent | 并存独立实例(append 入列) | 无满层语义——实例数上界 = 受理授予数(有界确定) | 同上 |
五个固定接口:
| 接口 | 干什么 | 返回 |
|---|---|---|
| notify_battle_start() | 告知战斗开始:打开容器、进入可用状态 | 是/否 |
| apply_effect(effect_id, source) | 发一笔状态——唯一进货口:受理即新建实例/叠层/刷新 | 是/否 |
| query_active(side) | 查询生效状态:某一方当前生效清单,按发放先后排列且顺序永远稳定 | 只读清单 |
| decay_round() | 轮末衰减:全部实例寿命 −1、归 0 即销毁 | 本轮移除数 |
| notify_battle_end() | 告知战斗结束:全实例清空、容器回空 | 是/否 |
举证:
| 编号 | 举证 |
|---|---|
| Rule 1 | 无计算;"不跨战斗"为 game-concept 定稿口径;多敌共享读法按 registry single_enemy_assumption 登记,现接口零变更兼容 |
| Rule 3 | 无计算;授予动作 = apply_effect(五接口之一);四类来源授予路径与目标侧见上表;来源取值封闭枚举见 source_class 表 |
| Rule 4 | 三分支逐分支语义见上表;合并执行伪代码见 F1;"有效值 = 层数 × 行值"加算合成见 F2 |
| Rule 5 | 无计算(判定 = 一次"层数 == 上限"比较);拒绝原子性(false + 容器逐字不变、无半写无溢出落层)见 F1 Output Range;"溢出未生效"行进结算明细协议由 B1 义务⑧承载、呈现归 B5/D1 |
| Rule 6 | 五接口签名见验收标准测试口径;查询返回 = 六归因字段 + display_name + 授予时数值快照 (magnitude, unit) 只读投影(qa-lead 载荷口径);结算作用顺序(哪个效果先乘)归 B1 SettlementTable,B3 只保证枚举确定性;最后一轮(敌人全灭)是否 decay 归 B1 判定次序域——A3 EC8 同款〔末轮 decay 判定次序域〕 |
| Rule 8 | 无计算;负空间规则——验收形态 = API 面封闭枚举 + 接口漂移修订门(验收标准测试口径 out-of-scope 行) |
设计意图:授予单口、合并查表、接口封五——结算编排与效果种类解耦。
## 时限与衰减
规则:
1. **Rule 2** 每个状态实例自带一个倒数计数——剩余结算次数:它不承诺"活几轮",而是数"经历过几次结算",每轮结算先让状态起作用、随后计数减 1,减到 0 状态即被移除;一次性状态(初始计数 = 1)恰好在授予它的那轮结算里生效一次、轮末消失,MVP 四行内容全部是一次性;将来跨轮持续的增益寿命由表行初始值表达——给几就活几次结算;停手不挖的轮、弃图刷新的轮也照常算一次结算、计数照减——不做"不结算就不掉次数"的免费延时。
时限语义要点(单一结算次数量纲):
| 要点 | 内容 |
|---|---|
| 计数量纲 | remaining_settlements(剩余结算次数)——全部状态唯一时限单位 |
| 初始值 | duration_settlements = 授予时初始剩余结算次数(实例持有快照、不受表重载影响——EC9) |
| 衰减 | 每轮结算兑付后统一 −1(先兑付后衰减——B1 兑付完才调 decay_round);归 0 即移除 |
| 一次性 | duration=1 → 授予当轮编排期入容器 → 同轮兑付恰一次 → 轮末移除(MVP 四行全部 D=1——当次结算语义) |
举证:衰减的精确机制(每轮恰 −1、归 0 即销毁)与"先兑付后衰减"时序契约见 F3。
设计意图:倒计时单位与"兑付次数"同物——玩家读到的剩余次数就是规划素材本身。
## 数值结论(F0–F3)
> 本系统为数学承载系统:公式结论与表达式在此;推导过程、候选取舍与锚定论证全部在推演件。本节只含机制公式,平衡归属见显式排除声明。
### F0 weaken 锚裁决回执(m_w 值域与归一口径)
**结论**:
- m_w 值域 [60, 85]、默认 −65;归一口径 = 每结算瞬时当量(每 AP 总暴露分支被 percent schema 域禁止,排除)
- 地板交叉层数 = ⌈100/m_w⌉ = 2(值域内恒 2);B3 接口零修订、值变更走 registry 回写——**回执以 B1 GDD F0 为准**(registry status_effect.anchor_warning F0 裁决回执)
- AC-14 腿 3 非平凡性复查通过(16×65 = 1040 越出 percent 域);原 −25 值的裁决关系与修订轨迹见版本历史
### F1 同 id 叠层合并(same_id_merge,授予时执行)
**结论**:授予时按行 stack_policy 三分支合并——stack 加层不触碰 R(只有初始授予定钟)、refresh 重置 R 取实例授予时快照 D、independent 并存新实例;满层拒绝原子(false + 容器逐字不变)。
```
merge(effect_id) —— 前置拒绝(域闭 / 未知 effect_id)沿用实例状态节 API 口径,不入分支。
行 = StatusEffectTable[effect_id],按 行.stack_policy 三分支:
independent → 恒新建实例 {L=1, R=D},append 入列(同 id 并存多实例)
stack → 无存活实例 :新建 {L=1, R=D}
有存活实例 ∧ L < M :L ← L+1(R 不动——只有初始授予定钟)
有存活实例 ∧ L = M :返回 false(满层拒绝;容器零写入,溢出行归 B1 结算明细)
refresh → 无存活实例 :新建 {L=1, R=D}
有存活实例 :R ← D(L 不变;含 R 已 = D 的空刷新,恒返回 true——
refresh 无满层/溢出语义,不消费 max_stack)
```
**Variables:**
| 变量 | 符号 | 类型 | 范围 | 说明 |
|---|---|---|---|---|
| effect_id | e | String | 表主键 | StatusEffectTable 行键;未知 = 拒绝 |
| stack_policy | P | enum {stack, refresh, independent} | 表列 | 合并分支选择器 |
| max_stack | M | int [1, 16] | 表列 | 仅 stack 分支消费;refresh/independent 不读(未来 refresh 行配 M>1 时行为 = 忽略) |
| duration_settlements | D | int [1, 99] | 表列 | 新建实例初始 R;refresh 的重置目标即此值 |
| layers | L | int | stack 行 [1, M];其余恒 1 | 实例层数(越界 = debug 断言,不变式) |
| remaining | R | int | 存活态 [1, D] | 剩余结算次数;归 0 移除(F3) |
- **Output Range:** 正常域——stack/refresh 行同 id 存活实例数 ≤ 1(不变式);independent 行实例数 = 受理授予数(有界确定);返回值 bool。极端行为——满层授予恒 false 且容器逐字不变(拒绝原子性:无半写、无溢出落层);同轮批量授予的先到先得次序由调用方保证(B1 编排须按确定次序调用 apply_effect——B3 只保证插入序枚举稳定,B1 验收项义务①)。验算示例(attack_up / weaken / dur≥2 探针三例)见推演件问题 3。
### F2 有效值合成(effective_value_composition,兑付时只读)
**结论**:有效值 = L × m 加算(unit 量纲标签原样随值输出、不进乘法);合成值不 clamp、可越出 percent 域——地板/clamp 归 B1 SettlementTable。
```
effective_value(实例) = L × m (unit 随行声明,量纲标签原样随值输出、不进乘法)
stack 行:L ∈ [1, M];refresh / independent 行:L ≡ 1(每实例恒一倍)
加算语义:percent 行的 L×m 是百分点线性叠加(+50 × 2 层 = +100 个百分点);
乘算读法(1.5^L)在 B3 语义域外。
表注:行值出处(provenance,如"原型 1.5×")是数值来历标注,非合成语义。
```
**Variables:**
| 变量 | 符号 | 类型 | 范围 | 说明 |
|---|---|---|---|---|
| layers | L | int | 同 F1 | 叠层数 |
| magnitude | m | int | percent ∈ [-100,100] ∧ ≠0;flat ≥ 1(单行字段域,D2 校验) | 行值;合成值不继承此域(见 Output Range) |
| unit | u | enum {percent, flat} | 表列 | 量纲标签;percent = 百分比修正、flat = 固定值;消费语义(乘除侧、地板、单位定义)不在 B3(见排除声明) |
- **Output Range:** 正常域——percent 行有效值 ∈ [1, 100×M],**可越出 [-100, 100],B3 不 clamp**(合成值地板/clamp 归 B1 SettlementTable——B1 验收项义务③);flat 行 effective ≥ 1。极端行为——weaken 合成下界两档并列:**AP 界 = 8×m_w**(默认 65 → −520%;默认经济下 flag_hit 单轮 ≤ ap_per_round=8 次授予、dur=1 层只在单轮累积 → L=8)与**表界 = 16×m_w**(默认 65 → −1040%;仅非 AP 源如 clear_reward 授予、或 ap_per_round 调参后可达 L=16)——两档均越域,均不在本系统内收口;m_w 值域见 F0。跨 effect_id 聚合、percent 与 flat 混算 = B1 SettlementTable 域(Rule 7)。验算示例(attack_up/defense_up/weaken/ambush 四例)见推演件问题 5。
### F3 结算衰减(settlement_decay,轮末执行)
**结论**:先兑付后衰减——每实例每轮恰 −1、归 0 即销毁(不留 0 值实例)、返回本轮移除数 k;无参数、无豁免实例。
```
decay_round() -> k:
k ← 0
for 实例 ∈ 容器(插入序枚举,零随机):
R ← R − 1
if R = 0:销毁实例;k ← k + 1
return k
```
时序契约:**先兑付后衰减**——B1 经 query_active(side) 完成本轮兑付后才调用;duration=1 实例的落点由此完整确定 = 授予当轮编排期入容器 → 同轮兑付恰一次 → 轮末 R=0 移除("一次性"语义的全部机制内容)。停手轮/弃图轮同为结算、照常衰减(无免费延时);最后一轮(敌人全灭)是否 decay 归 B1 判定次序域(A3 EC8 同款——battle_end 全清兜底,两种次序产生同终态)。
**Variables:**
| 变量 | 符号 | 类型 | 范围 | 说明 |
|---|---|---|---|---|
| 容器 | — | 实例多重集 | 存活实例全体 | 枚举序 = 插入序(Rule 1 确定性) |
| remaining | R | int | 存活态 [1, D];decay 后 ∈ [0, D−1] | 单调递减;refresh 的 R←D 发生在授予时(F1),不在本式内——两序分离 |
| 返回值 | k | int | [0, 容器规模] | 本轮移除数 |
- **Output Range:** 正常域——每实例每轮恰 −1,无参数、无豁免实例;k ≤ 调用前容器规模。极端行为——空容器 → k=0;全 dur=1 轮 → k=容器规模(全清);R 恒不因 decay 变负(归 0 即销毁,不留 0 值实例——与不变式 remaining ∈ [0, D] 相容)。验算示例(轮 3 授予-兑付-移除全落点与 dur≥2 探针 R 轨迹)见推演件问题 2。
### 显式排除声明
本 GDD **无平衡公式**——F1–F3 只承载机制数学(合并/合成/衰减),不含任何"值该多大"的判断;四行 MVP 值全部 provisional。平衡与语义归属:
| 对象 | 归属 | 依据 |
|---|---|---|
| 效果档位当量对照表(四源统一当量、单一线性换算) | **B1**(出表方兼闭合对账单一签字人) | A3 F1 条款 1 |
| weaken 档位锚(debuff 当量严格 > 最低档安全格 buff 当量,参照对象 = attack_up 行当量;基准 = 连锁放大边际挖掘收益,provisional 1:1) | **B4 表设计 + B1 对照验收** | A3 F1 条款 2 |
| 挖掘风险不等式(P(安全)×buff 当量下界 > P(雷)×敌方增益当量上界;B2 惩罚上限表值) | **B2 供给上限表值,B1 单一闭合对账** | A3 F1 条款 3 |
| 奖励定价(清图奖励及 B4 三硬约束:雾内档位下界 / 锚随雾成本上浮 / 净当量优势带上界) | **B4** | A4 pricing_constraints;A3 F1 条款 4/5 |
| percent 的消费侧换算与地板(乘除侧读法、合成值越域 clamp);flat 的量纲定义 | percent → **B1 SettlementTable**;flat 量纲 → **B2**(已定稿——registry ambush_unit_definition:每层伏击为每次攻击类行为附加 3 点主角 HP 伤害、后置加法) | F2 Output Range;schema 说明列 |
| MVP 四行初值定稿权 | **B3**;B4/B2/B1 持锚验收权,修订走接口漂移回写 registry | Rule 10 |
规则:
1. **Rule 7** 容器只记录每个状态的量(幅度数值 + 量纲标签:百分比还是固定值)和还剩几次结算——"增伤加在哪个算式上、先乘后乘、地板怎么收"一律由结算编排的顺序映射表按状态 id 作答;容器知道"现在还有 +50、还剩 1 次结算",不知道这 +50 会变成主角攻击里的什么;B3 只对"L×m 线性合成 + R 计数"负责,合成值多大算强、floor 在哪、+3 打谁,均不在本 GDD 语义域。
举证:Rule 7 无计算;语义映射承载面 = B1 SettlementTable(effect_id 为键);B3 只承载 magnitude/unit 两个通用数值字段。
## 边界情况
| 编号 | 条件 | 行为 | 依据 |
|---|---|---|---|
| EC1 | 域闭状态授予(BattleClosed 下 apply_effect) | 拒绝(false)、容器不变 + debug 诊断——B1 过早/过晚调用 = 编排错误显式暴露,不静默吞 | 实例状态节 API 口径 |
| EC2 | 未知 effect_id | 拒绝(false)+ debug 诊断;表行删除/改名后旧引用的暴露点——悬空引用加载校验 = 首引激活条款:B4 RewardTable 首个 effect_id 引用已回填、校验已激活(registry dangling_ref_policy;条件性夹具 = B4 b4_dangling_effect) | A4 counter_item_ids 同款 · D2 首引兑现 |
| EC3 | 满层授予 | 恒 false 且容器逐字不变(拒绝原子性——无半写、无溢出落层);"溢出未生效"行归 B1 结算明细;同轮多授予谁被拒取决于 B1 授予次序——授予次序确定性是 B1 编排义务 | F1 Output Range · Rule 5 · 义务① |
| EC4 | 空刷新(refresh 行 R 已 = D 再授予) | 返回 true、无任何变化——合法空操作(refresh 无满层/溢出语义);MVP 无 refresh 内容行 = 该语义零消费者,首个 refresh 行上线时须补冒烟 AC;空刷新静默返 true 与 Rule 5"不静默蒸发"存在原则张力——MVP 零消费者故休眠,首个 refresh 内容行上线时其授予可见性语义由 B4/B1 随 OQ3 一并裁决 | F1 决议 · systems-index 登记 |
| EC5 | 同轮 dur=1 行多次授予 | 层在单轮授予批次内累积(L=N)→ 同轮兑付一次(合成 L×m)→ 轮末全移除;跨轮必为新实例——"N 旗 = N debuff 总吞吐"在 B3 侧的呈现 = 单轮层和,对账归 B1 | F1 Example · A3 条款 2 |
| EC6 | 同一事实被重复授予(同 effect_id + origin_cell + round_index 两次 apply) | B3 不去重——容器是 dumb 账本,无从辨别事实合法性,两次授予 = 两层/两实例;事实→授予的恰一次转化归 B1 编排义务(round_end 双发射源同族问题,A3 先例) | 义务② |
| EC7 | 合成值越域(L×m 越出 [-100, 100] 或穿越地板) | B3 不 clamp、值 + unit 标签原样输出——收口归 B1 SettlementTable(B1 验收项:percent→乘数换算方向与地板规则须成文——weaken AP 界/表界、defense_up 叠满三例已在 F2 登记) | F2 Output Range · 义务③ |
| EC8 | 清图换图/弃图刷新 | 容器不清空——状态跨图延续(战斗域非图域);旗标记随图消亡(A2 域)不影响已授予实例;已消费兑付资格的雷格随图消亡(A3 域),新图新雷自然新资格——B3 无从感知也无须感知 | Rule 1 · AC-10 |
| EC9 | 战斗中热重载 StatusEffectTable | 走 D2 既有门(战斗中 reload 拒绝);已授予实例不受任何表重载影响——实例在授予时从表行拷贝数值快照(m/D/unit),热重载只影响后续授予 | A4 EC8"快照非活引用"同款 |
| EC10 | refresh/independent 行配置 max_stack > 1 | 行为 = 忽略(F1 分支不读 M)——内容约定非校验项,validate() 不拒绝(防过度约束锁死未来内容) | F1 · AC-13 |
| EC11 | notify_battle_start / notify_battle_end 重复或错序 | Active 下再 start → false + 诊断;BattleClosed 下再 end → false + 诊断(bool 口径统一,承 A3 输入×相位矩阵同款) | A3 同款 |
| EC12 | query_active 空 side 或空容器 | 返回空 Array——合法状态非错误;D1 HUD 据此渲染"无状态" | D1 空态义务 |
| EC13 | decay_round 在域闭时被调用 | 返回 0——域闭时容器恒空(battle_end 已清),0 是自然结果、无独立分支、不诊断(幂等安全的兜底读法) | F3 极端域 |
| EC14 | independent 行被高频授予 | 实例数上界 = 受理授予数(有界、确定,无满层语义)——MVP 无此内容行;未来 DOT 类高频授予的容量语义归扩展(接口漂移),本 GDD 不预写 | F1 Output Range |
## 依赖与输出
| 方向 | 系统 | 性质 | 接口要点 |
|---|---|---|---|
| 上游 | D2 | hard(数据通道) | StatusEffectTable schema 承载 + ConfigDB 读取;本 GDD 为该表回填 owner(schema + 四行已定稿);新字段走接口漂移规则。systems-index 分层表按其惯例不列纯数据读取边(事实依赖同口径)——两处相容非矛盾 |
| 下游 | B1 | hard | 结算编排期调用五 API:notify_battle_start / apply_effect(三源授予——B1 从 A2/A3 事件收集 round facts 后转化)/ query_active(side) 兑付消费 / decay_round() 轮末衰减 / notify_battle_end() 清空;结算明细来源标注数据源 = 实例字段(P2);效果语义映射与结算作用顺序归 B1 SettlementTable(effect_id 键);F1 条款 1 对照表的"实物"供给方;最后一轮 decay 与否归 B1 判定次序域;义务清单 8 项见下表 |
| 下游 | B4 | soft | 安全格 buff 行值与 weaken 档位的锚验收权(条款 2 + A4 三定价硬约束引用"最低档安全格 buff 当量"——参照对象 = attack_up 行当量);清图奖励若含 buff 经 apply_effect(source=clear_reward,B4 期定);RewardTable 引用 effect_id 的悬空校验已随首引激活(EC2) |
| 下游 | B2 | soft | ambush 行量纲/上限验收锚(条款 3:B2 惩罚上限表 vs B3 行值,对账归 B1 闭合;量纲已定稿——registry ambush_unit_definition);未来敌人词条引用状态(免疫/抗性)为预留注记,不预写 |
| 相邻 | A3 | 契约相邻(零运行时接口) | A3 不调用 B3;条款 1 四源当量对照以 B3 实例为对照实物;标中旗兑付资格(雷格实例键)判定在 A3/A2 域,B3 只接收 B1 转化的授予——资格判定不过 B3 |
| 相邻 | A2 | 间接(零直接接口) | 开格/标中/开雷事实经事件 → B1 收集 → apply_effect;A2 不感知状态容器 |
| 下游 | D1 | soft | query_active(hero) 为 HUD 状态栏数据源(display_name/层数/剩余结算次数常显;EC12 空态渲染);层数/到期变化反馈——义务清单 ×4 见下表 |
| 下游 | B5 | soft | 结算明细/战斗动画的实例字段数据源(经 B1 结算流水;MVP 明细行即呈现,动画归垂直切片)——义务 ×2 见下表 |
| 下游 | D5 | soft | 教学口径:按结算次数计时("还剩 N 次结算"式读法随行值)、战斗结束全清(防"我的 buff 哪去了"误读——A3 RAP 清零教学同款)、满层溢出浪费提示、"同轮拿满优于跨轮叠"教学项(stack 时序补偿——OQ7 证伪项配套,证伪成立前以中性提示形态) |
### B1 侧义务清单(登记 B1 GDD 验收项,缺项即 blocking——A4 对 A1/A2 登记先例)
| 编号 | 内容 | 对侧 | 状态 |
|---|---|---|---|
| ① | 同轮多授予按确定次序调用(EC3) | B1 | 已落位 B1 GDD(履行回执) |
| ② | 事实→授予恰一次转化(EC6) | B1 | 已落位 B1 GDD(履行回执) |
| ③ | percent→乘数换算方向与合成值地板成文(EC7/F2——AP/表界数值随 F0 修订更新为 −520%/−1040%) | B1 | 已落位 B1 GDD(履行回执) |
| ④ | 最后一轮 decay 判定(F3) | B1 | 已落位 B1 GDD(履行回执) |
| ⑤ | F1 条款 1 效果档位对照表以 B3 实例为对照实物 | B1 | 已落位 B1 GDD(履行回执) |
| ⑥ | 每结算编排恰一次 decay_round()——decay 基数 = 1 是 dur=1 一次性语义与全部衰减语义的先决条件;Active 相位 double-decay 在 B3 侧无守卫(信任 B1 编排,误编排经本义务验收与可回放步骤流暴露) | B1 | 已落位 B1 GDD(履行回执) |
| ⑦ | 结算明细按授予流水逐条标注来源(F1 合并坍缩归因的兑付面补偿——合并实例只持首授 origin_cell/round_index,per-layer 来源还原的数据源 = B1 授予流水) | B1 | 已落位 B1 GDD(履行回执) |
| ⑧ | "溢出未生效"行进结算明细协议(Rule 5 后半的 B1 侧承载;呈现归 B5/D1) | B1 | 已落位 B1 GDD(履行回执) |
### 呈现与教学义务清单(已登记 systems-index,缺项即 blocking,随各 GDD 门禁评审核对)
| 编号 | 内容 | 对侧 | 状态 |
|---|---|---|---|
| D1-① | HUD 常显 + EC12 空态规格定稿(隐藏栏 vs 空槽由 D1 裁决但须成文) | D1 | 已登记 |
| D1-② | effect_id→icon 映射键契约(art-bible 形状+色相双通道) | D1 | 已登记 |
| D1-③ | 有利/有害极性呈现映射(数据源 = B1 SettlementTable 效果语义,非 magnitude 符号——负值增益存在) | D1 | 已登记 |
| D1-④ | 战斗结束全清的状态栏去留 | D1 | 已登记 |
| B5-① | 溢出行呈现(数据源 = B1 义务⑧明细协议) | B5 | 已登记 |
| B5-② | origin_cell→玩家可读形态(缩略图/格子高亮映射——坐标值本身不直接呈现) | B5 | 已登记 |
| D5 | "同轮拿满优于跨轮叠"教学项(OQ7 证伪项配套) | D5 | 已登记 |
| B4 | 奖励身份预读(stack 时序规划的推理原料——创意风险 #1 切面,OQ7 配套补偿载体) | B4 | 已登记 |
### 呈现与 UI 契约(数据面义务——B3 无自有渲染面,呈现归 D1/B5)
| # | 数据面义务 | 归属 |
|---|---|---|
| 1 | HUD 状态栏数据源三要素:图标(effect_id→icon 映射归 D1/art-bible)、层数(L)、剩余结算次数(R)必须可读——时限/剩余次数不可读 = 违反 P1 规划素材与 P2 兑现可见性 | D1 |
| 2 | 结算明细行数据源:display_name + 有效值(L×m)+ unit 标签 + 来源标注(source_class→文案映射归 B1/D1,P2 归因)——"增伤 +100%(第 3 轮 · 安全格)"式逐行读法;origin_cell 玩家可读形态(缩略图/格子高亮)归 B5(坐标值本身不直接呈现);满层溢出提示 = "溢出未生效"行含来源(Rule 5 诚实语义) | B1/D1/B5 |
| 3 | 视觉身份锚适用(game-concept):数值可读性优先于氛围(锚 1)——状态数值在暗色底上须高对比;增益/削弱图标不得只靠色相区分(锚 2 形状+颜色双通道);有利/有害极性不得由 magnitude 符号推导(负值增益存在——数据源 = B1 SettlementTable 效果语义) | D1 |
| 4 | 零信号外发:纯被动容器不发任何事件——呈现刷新点 = B1 结算编排完成后的界面刷新(D1/B5 域);到期/层数变化反馈经 decay 前后查询差分或 B1 流水(D1 裁决);无音频需求(到期/叠加音效归 D4 Alpha 期) | D1/B5/D4 |
## P0 最小闭环
1. B1 战斗开始调 notify_battle_start()——容器开域(空容器)。
2. A2 开格/标中/开雷事件 → B1 收集 round facts → 转化 apply_effect(唯一进货口)。
3. 容器按表行 stack_policy 合并受理(新建/叠层/刷新),实例即入 Active、携六归因字段与授予时数值快照。
4. B1 每轮 query_active(side) 只读兑付——有效值 = L×m(快照)加算合成。
5. 轮末 B1 调 decay_round():全实例 R−1、归 0 到期销毁(先兑付后衰减)。
6. 域闭/未知 id/满层授予被拒(false + 容器零写),"溢出未生效"行归 B1 结算明细。
7. B1 战斗结束调 notify_battle_end():全实例清空、容器回空 → BattleClosed,不跨战斗。
## P1 / P2 后置
| 优先级 | 内容 | 后置原因 |
|---|---|---|
| P1 | refresh / independent 首批内容行启用(语义已定义、实现已承载;首个 refresh 行上线时补真实内容行冒烟 AC、夹具探针退役,授予可见性语义随 OQ3 由 B4/B1 裁决) | MVP 四行全 stack、非 stack 语义零消费者——待奖励池引入非 stack 行(B4 期) |
| P1 | clear_reward 源授予路径确认(清图槽含 buff 时经 apply_effect,source=clear_reward;A3 条款 4 差异化插槽——OQ4) | B4 期定稿 |
| P1 | target_ref 单体寻址列(首个单体效果上线时补列;随批 B1 归集语义 / D1 呈现裁决——registry single_enemy_assumption 扩展位义务) | MVP 敌情 side-wide 语义够用,无单体效果内容行 |
| P2 | 驱散 / 延时 / 转移接口(Rule 8 负空间) | 省掉一整类界面与规则复杂度是明确的设计决定;新增 = 接口漂移修订,非调参 |
| P2 | independent 行高频授予(DOT 类)的容量语义(EC14——实例数上界 = 受理授予数,有界确定) | MVP 无此内容行;归扩展(接口漂移),本 GDD 不预写 |
| P2 | 敌人词条引用状态(免疫/抗性) | 预留注记,不预写(B2 域随批裁决) |
| P2 | 随关卡成长的效果行((level_index, node_depth) 维度) | 定义为表非进度成长表(Rule 4 豁免);需要时走接口漂移加列,A4 先例 |
## 调参表
| 字段 | 域 | 默认 | owner | 说明 |
|---|---|---|---|---|
| attack_up.magnitude | percent ∈ [-100,100] 且 ≠0 | +50(provisional——原型 1.5× 换算占位) | B3 定稿;B4/B1 锚验收 | 条款 2 锚参照对象;消费面 = 主角战斗段先手攻击 |
| defense_up.magnitude | percent ∈ [-100,100] 且 ≠0 | −30(provisional——减伤墙批 C3 投值,原 −50) | B3 定稿;B4/B1 锚验收 | 叠满两层 −60 帽;禁独立调参(联动网络见下) |
| ambush.magnitude | flat ≥ 1 | +3(provisional——原型临时值) | B3 定稿;B2/B1 锚验收(条款 3) | 量纲已定稿(B2):每层每攻击类行为附加 m_amb 点主角 HP、后置加法、charge 拍零兑付 |
| weaken.magnitude | percent ∈ [-100,100] 且 ≠0 | −65(provisional,值域 [60, 85]——F0 裁决) | B3 定稿;终值 B4/B1 共裁 | 回执以 B1 GDD F0 为准(registry anchor_warning);越界即破条款 2 锚 |
| duration_settlements(四行) | int [1, 99] | 1/1/1/1(当次结算;provisional) | B3 | 一次性语义;窗口拉长 = 恢复跨轮延续(规划变简单、衰减感消失) |
| max_stack(四行) | int [1, 16] | 2/2/16/16(provisional) | B3 | 仅 stack 消费;调低 = 叠层机制边缘化(重复奖励变溢出浪费) |
- **非 knob(结构冻结)**:stack_policy 三分支语义、unit 语义、source_class 枚举、时限量纲 = 剩余结算次数(game-concept 定稿)、先兑付后衰减时序、拒绝原子性、零随机——修订走本 GDD 流程非调参。
- **Knob 交互**:attack_up 与 weaken 是条款 2/3 对账的两端——禁止独立调参,联动评估归 B1 闭合对账;A3 的 ap_per_round 是 weaken 单轮层和的经济上限(F2 AP 界 8×m_w 的来源);效果档位当量对照表(B1)落定前,四行 magnitude 的任何调整都须重跑条款 2/3 锚预检并同步 registry(接口漂移义务)。
- defense_up.magnitude/duration 已纳入"禁独立调参"联动网络(m_w↔D_ref↔m_d↔duration_d,与 B1 Knob 交互同口径);减伤墙批(−50→−30)即该联动的实证回调;defense_up 叠满 −60% = 当次结算 0.4× 承伤(消费读法归 B1);免伤轮现行可达路径 = weaken 饱和(见 F2)。
- 逐 knob 调过高/调过低的后果论证见推演件。
## 验收标准
### 测试口径
| 口径 | 要点 |
|---|---|
| 测试载体 | B3 是纯行为容器——无场景、无表现面、无加载期自有校验类别。冒烟载体 = `godot --headless --script`(承 D2 冒烟框架;脚本 extends SceneTree 以获得 quit(code)、ConfigDB autoload 由脚本显式实例化);容器经 class_name 直引实例化(每用例全新实例、无跨用例状态——A4 AC-5 直引先例同款;AC-19 扫描对该实例化路径豁免) |
| 被测面 | B1 就绪前冒烟直接驱动 B3 最小 API 面(承 A3"直接驱动最小 API 面"先例);B1 就绪后改走真实调用方(结算编排),断言口径不变。API 面:notify_battle_start() · apply_effect(effect_id, source) → bool · query_active(side) → Array · decay_round() → int · notify_battle_end() → bool |
| 返回口径 | 全部布尔/计数返回 = 受理/拒绝(A3 全 API 布尔口径同款)——"拒绝"直接断言返回值,附 debug 诊断、非进程致命(承 A3 拒绝口径;进程致命保留给 D2 数据通道);decay_round 返回值 = 本轮移除数断言;apply_effect 是唯一授予入口(Rule 3),冒烟直接构造合法 source = {source_class, origin_cell, round_index}(B1 转化产物的冒烟等价——信任方向同 A3 对 chain_size/clears_map 的处理);query_active 为只读、任意相位合法 |
| 只读观测量 | 实例六字段 effect_id · layers · remaining_settlements · source_class · origin_cell · round_index;query_active(side) 元素 = 结算面向载荷投影:六字段 + display_name + 授予时数值快照 (magnitude, unit)(EC9 快照语义 + B5/D1 数据源)——有效值 = layers × 快照 magnitude、unit 标签原样随值输出(F2);枚举序 = 插入序(Rule 6)。相位无字段观测量:BattleClosed/Active 由 API 返回值推断;Expired/Cleared 为销毁态不可观测(瞬态纪律同 A3 RoundEnd) |
| 时序口径 | B3 无 round_start/settlement API——"轮边界"在冒烟中 = 相邻两次 decay_round() 调用之间的授予/查询窗口(B1 编排在 B3 侧的可见面恰为这五个 API);多步 GIVEN 均给出构造序列 |
| 期望值纪律 | magnitude / duration_settlements / max_stack 均为 knob(调参表节)——各 AC 的 THEN 具体数值按当前 ConfigDB 表值推导、不写死(正文以 D_a / M_a / m_w 等表读值记号书写);结构字段(effect_id 集合、target_side、unit、stack_policy)非 knob、定值断言合法;行表"来源"列为内容档案(provenance)非 schema 字段、非运行时约束——B3 不校验 source_class 与行的对应(EC6 dumb 账本同族) |
| 夹具策略 | ① 默认根(干净检出四行 MVP 内容)承载全部分支行为 AC;② 程序构造(schema 类 class_name 直引实例)承载 AC-13 域校验——不经 load()/preload();③ 行为夹具根经 --data-root 注入(仅 debug、不入 data/tables/——D2 夹具纪律),承载 MVP 无行的语义(refresh/independent)。显式声明:夹具测试行非 MVP 内容(Rule 10 四行全 stack;测试行仅供冒烟)。选夹具根而非程序构造注入表的理由:容器经 ConfigDB 单点读表(Rule 2/9)、无表注入 API——--data-root 是 debug/test 构建的既定注入通道;各 AC 声明其表根(默认根/下列三根),用例间无顺序依赖、每用例先 reset_diagnostics()(D2 冒烟协议,全局声明) |
| 致命类收窄 | 恰一根致命夹具 status_effect_dup_key(重复键类别):runner manifest 退出码行 dup→≠0(独立 headless 进程、游戏通道,D2 AC-2b 协议同型)——"游戏内真的会死"在本表上的落点由此腿实证;其余致命类别(枚举域/域校验/跨字段)由 D2 AC-2 同类别 loader 级夹具承载(表无关,豁免声明收窄保留);schema 侧以程序构造断言域类别(AC-13) |
| out-of-scope | deferral 生效条件 = B1 义务清单(依赖节,均已落位):① 同轮多授予先到先得次序(EC3 后半——冒烟单调用方次序即构造序,B1 编排次序 = 义务①)② 事实→授予恰一次转化(EC6 后半——义务②)③ percent→乘数换算方向与合成值地板(EC7 收口半——义务③)④ 最后一轮 decay 判定次序(F3 时序契约的 B1 半——battle_end 全清兜底使两序同终态,冒烟不构造)⑤ 效果档位对照表以 B3 实例为对照实物(义务⑤,对账归 B1)。另有:结算明细"溢出未生效"行与来源标注呈现(冒烟无明细观测量——对侧承载已登记:B1 义务⑧ + B5×2,deferral 生效条件成立);D1 HUD 状态栏与 EC12 空态渲染(D1×4 已登记);效果语义到结算公式映射(Rule 7——B1 SettlementTable 域);Rule 8 负空间(无驱散/延时/转移 API——"无对应 API"不可 GIVEN-WHEN-THEN,验收形态 = 前言 API 面封闭枚举 + 接口漂移修订门);D2 schema 校验致命端到端(双通道协议承载);悬空引用校验(EC2——D2 双通道条件性夹具);EC9 reload 门腿(D2 AC-16 既有覆盖 + B1 是置位/复位唯一调用方——B3 无断言义务);EC8 端到端换图腿(B1 编排合规,AC-10 裁决) |
### 夹具规格(登记值即相关 AC 的推导基准)
| 根 | 内容 | 用途 |
|---|---|---|
| status_effect_policy_rows | refresh_probe(display_name="刷新探针" · hero · percent · magnitude=+10 · duration=3 · stack_policy=refresh · max_stack=4——故意违反"refresh 行恒 1"内容约定)+ independent_probe(display_name="独立探针" · enemy · flat · magnitude=+2 · duration=3 · stack_policy=independent · max_stack=1)——全字段域内合法数据 | AC-5 / AC-6(EC4 / EC10 / EC14 载体) |
| status_effect_policy_rows_reloaded | 仅 fresh_probe 一行(hero · percent · magnitude=+20 · duration=9 · stack · max_stack=1);根规格 = D2 全表清单拷贝 + 仅置换 StatusEffectTable 为本单行(缺任一表文件即触发 D2 EC1 文件缺失致命、GIVEN 不可构造——"仅一行"指该表内容非根内容) | AC-15 重载腿 |
| status_effect_dup_key | D2 全表清单拷贝 + StatusEffectTable 置换为默认四行 + 追加一行与 attack_up 同 effect_id 的重复键行(其余字段域内合法)——唯一致命夹具(A4 variation_dup_key 同型):loader 集成缝(loader 是否对本表调用校验)的进程级落点 | runner manifest dup→≠0 |
### AC 清单(Given-When-Then,编号不变)
| AC | Given | When | Then |
|---|---|---|---|
| AC-1 | 全新容器(BattleClosed、空;表根 = 默认根) | ① 依次 apply_effect(attack_up, 合法 source)、query_active(hero)、query_active(enemy)、decay_round();② notify_battle_start();③ 再次 notify_battle_start() | ① apply 返回 **false**(EC1 域闭拒绝)、双侧 query 均 = **空 Array**(EC12)、decay 返回 **0** 且诊断收集器零新增(EC13——空容器域闭的兜底读法,非独立分支不诊断);② **true** 且 query 仍双侧空(战斗开始时为空——Rule 1);③ **false**、相位与容器不变(EC11 前半——Active 再 start) |
| AC-2 | Active 且已建账(构造:apply_effect(attack_up) ×1 + apply_effect(weaken) ×1,query 断言含两实例) | ① notify_battle_end();② 再次 notify_battle_end();③ decay_round();④ apply_effect(attack_up, …);⑤ notify_battle_start() | ① **true**、query 双侧空(Cleared 全清、不跨战斗——Rule 1);② **false**(EC11 后半——Closed 再 end);③ **0** 且诊断零新增(EC13 域闭腿);④ **false**(EC1 全场战后腿);⑤ **true** 且容器空(唯一出口——下一场战斗重启,实例状态表) |
| AC-3 | Active | apply_effect("attack_up", {safe_cell, (3,4), round_index=2}) | true 且 query_active(hero) 恰 1 实例,其六字段逐一相等:effect_id="attack_up"、layers=1、remaining=D_a(attack_up.duration_settlements 表读值)、source_class="safe_cell"、origin_cell=(3,4)、round_index=2(P2 归因字段授予即携带——Rule 3,结算明细逐行标注的数据源) |
| AC-4(stack 分支前两腿 + "R 不动" spec 决议) | Active;D_a / M_a 为表读值 | 腿 1:无存活实例时 apply_effect(attack_up, …);腿 2(前提 D_a ≥ 2 ∧ M_a ≥ 2——默认表值 D_a=1 不满足,本腿默认退化跳过 + 显式 SKIP 标记防 CI 静默、不假失败,前提满足时执行;构造 = 腿 1 实例经 decay_round() 一次至 R=D_a−1)再 apply_effect(attack_up, …) | 腿 1:true、新实例 **L=1、R=D_a**;腿 2:true 且 **L=2、R 仍 = D_a−1**——**stack 授予不触碰 R**(F1 注 spec 决议:只有初始授予定钟;实现若重置 R 即三分支失去区分性,本腿即其暴露点) |
| AC-5(refresh 分支 + EC4 + EC10;表根 = status_effect_policy_rows,测试行非 MVP 内容) | Active;D_f=3、m_f=+10(夹具规格登记值) | ① apply_effect(refresh_probe, …);② decay_round() 后 apply_effect(refresh_probe, …);③ R 已 = D_f 时再 apply_effect(refresh_probe, …);④ 再 apply_effect ×2;⑤ 该根经测试通道加载 | ① true、新实例 L=1、R=D_f、载荷 = 1×m_f(refresh 行 L≡1——F2);② 返回 0(R=D_f−1)后 **true、R 重置 = D_f、L 不变**(F1 refresh 正常腿);③ **true 且实例六字段 + 载荷逐字不变**(EC4 空刷新 = 合法空操作——refresh 无满层/溢出语义);④ 均 true(max_stack=4 从不被消费——**EC10 行为 = 忽略**);⑤ 诊断为零(内容约定非校验项——EC10 非校验半句) |
| AC-6(independent 分支 + EC14;同夹具根,测试行非 MVP 内容) | Active;D_i=3(夹具规格登记值) | 同轮授予批次内以互异 origin_cell((1,1)/(2,2)/(3,3)——插入序可观测的前提)apply_effect(independent_probe, …) ×3;再 decay_round() | 全部 true 且 query_active(enemy) 恰 **3 个并存独立实例**(各 L=1、R=D_i、**投影序列 = 授予序** (1,1)→(2,2)→(3,3)——互异 origin_cell 使插入序成为可判定断言,Rule 6 枚举确定性);decay 返回 0(D_i≥2 无移除)且三实例各自 R=D_i−1(F3 逐实例、无豁免);实例数上界 = 受理授予数(**EC14 有界确定**——无满层语义) |
| AC-7(EC6 不去重) | Active 且已有 attack_up 存活实例(L=1,构造同 AC-3) | 以完全相同的 (effect_id, source)(同 origin_cell、同 round_index——同一事实重复转化的模拟)再次 apply_effect | true 且同实例 **L=2**——B3 **不去重**(dumb 账本,无从辨别事实合法性,EC6);out-of-scope:事实→授予恰一次转化归 B1 编排(义务②,deferral 生效条件 = 依赖节清单) |
| AC-8(F3 主式) | Active(构造:apply_effect(weaken) ×2 → 单实例 L=2、R=1;apply_effect(attack_up) ×1 → R=D_a;前提 D_a ≥ 2——第二 WHEN 腿依赖,默认表值 D_a=1 不满足 → 本条退化跳过 + 显式 SKIP 标记(同 AC-4 口径、防 CI 静默),前提满足时执行) | ① decay_round();② 再 decay_round();③ 对空容器 decay_round() | ① 返回 **1**(= 构造中 dur=1 实例数,由表读值推导;weaken 实例移除)、attack_up R=D_a−1 仍在、容器插入序不变;② 返回 1(attack_up 移除——**R 归 0 即销毁,容器无 0 值实例**,与不变式 remaining ∈ [0, D] 相容);③ 0(F3 极端域)。R 轨迹与 k 全部由表值推导 |
| AC-9(EC5 dur=1 单轮叠层 + 一次性全落点) | Active(新轮) | 同轮授予批次内 apply_effect(weaken, …) ×3(N=3 为构造选择,≤M_w 表读值);decay_round();下一轮边界再授予 weaken ×1 | 全部 true、单实例 **L=3、R=1(=D_w 表读值)**、载荷 = 3×m_w(同轮兑付一次的合成输入;N 旗 = N debuff 总吞吐的对账归 B1 条款 2——义务⑤邻接,out-of-scope);decay 返回 1、实例移除;再授予 → **新建**实例 L=1——**跨轮必为新实例**(旧实例已销毁,F1 Example weaken 腿) |
| AC-10(EC8 跨轮/跨图延续——结构性裁决) | Active,attack_up 授予 ×1(R=D_a) | 连续多轮边界仅 decay、无新授予(停手轮/弃图轮的 B3 视角——B3 无图概念、换图/刷新零专用信号);逐步 query | 实例 R 逐轮 −1 **不停摆**(无豁免实例、无参数——**无"不结算就不掉次数"的免费延时**,Rule 2),且每步 query 断言容器非空直至 R 自然归 0——**除 notify_battle_end 外无任何 API 入口使容器清空**(先轮授予的实例按 R 存续至自然到期)。裁决:EC8 的"换图不清空"对 B3 的可测内容 = 本条两句(跨轮延续 + 唯一清空入口);"换图"事件对 B3 不可观测(零接口)——端到端"真实换图下容器仍存续"归 B1 集成(编排契约:仅 battle_over 调 end——B1 API 合规半句,B1 GDD 域,非新增义务) |
| AC-11(EC3 满层拒绝与原子性) | Active;M_a 为 attack_up.max_stack 表读值;构造叠满(M_a 次授予——次数由表值推导、不写死),前 M_a 次均 true、单实例 L=M_a | 第 M_a+1 次 apply_effect(attack_up, …) | **false** 且容器逐字不变——query_active(hero) 恰 1 实例,其六字段 + 载荷 + display_name 与授予前快照**逐项相等**(拒绝原子性:无半写、无溢出落层,F1 Output Range);"溢出未生效"明细行归 B1(out-of-scope,义务①邻接) |
| AC-12(EC2 未知 effect_id) | Active | apply_effect("no_such_effect", 合法 source);表行改名后的旧 id 同理 | **false**、容器不变。政策声明:悬空引用加载校验 = 首引激活条款——B4 RewardTable 首个 effect_id 引用已回填、校验已激活(registry dangling_ref_policy;条件性夹具 = B4 b4_dangling_effect;out-of-scope,D2 双通道) |
| AC-13(加载期域校验全谱——程序构造,class_name 直引,A4 AC-5 同型) | StatusEffectTable schema 类直引实例(不经 load()/preload()) | validate() 分别作用于非法组:percent=0(跨字段 percent≠0)/ percent=101 / percent=−101、flat=0(flat ≥ 1)、duration ∈ {0, 100}、max_stack ∈ {0, 17}、stack_policy/target_side/unit 各一出域枚举值、两行同 effect_id(重复键);再作用于域内代表值 percent ∈ {100, −100, 1, −1}、flat=1、duration ∈ {1, 99}、max_stack ∈ {1, 16} 及 stack_policy=refresh 且 max_stack=4 的行(EC10) | 非法组:各含对应域错误类别;合法组:零诊断(EC10——内容约定非校验项,防过度约束锁死未来内容) |
| AC-14(F2 合成 + EC7 不 clamp) | Active;m 各值为表读值 | 腿 1(percent·stack):apply_effect(attack_up) ×2(前提 M_a ≥ 2——默认满足,M_a=1 时退化为单层恒等断言 + SKIP 标记);腿 2(flat):apply_effect(ambush) ×3;腿 3(越域,EC7):同轮 apply_effect(weaken) ×M_w(M_w 表读值、≤16 同轮批授予合法);腿 4:refresh/independent 行载荷 L≡1 | 腿 1:载荷 = **2×m_a** 且 unit="percent" 标签随值输出(量纲标签不进乘法——F2);腿 2:载荷 = 3×m_amb、unit="flat"(B3 不解释单位——排除声明);腿 3:载荷 = **M_w×m_w 原样输出、无 clamp**("不 clamp"的可判定形式 = 载荷与表值推导值恒相等,任何地板都会使其不等;承载声明:本腿非平凡性依赖默认基线——M_w=16、m_w=−65 → −1040 越出 percent 域;knob 调参使 M_w×m_w 绝对值 ≤ 100 时退化为恒等断言、不假失败,退化时用例输出显式退化标记 SKIP 日志、CI 可见防静默失真;地板/clamp 与换算方向归 B1 SettlementTable——out-of-scope,义务③);腿 4:已由 AC-5①/AC-6 承载(引用不重复) |
| AC-15(EC9 快照 vs 表重载——机制口径) | 表根 = status_effect_policy_rows、Active、已授予 refresh_probe ×1 并 decay 一次(R=D_f−1、载荷 1×m_f) | 冒烟脚本经测试通道换根加载 status_effect_policy_rows_reloaded(load_tables(root, collect_only=true) 直调——非 D2 reload() 路径:不过 set_reload_gate、不发 config_reloaded、无 EC16 语义,门语义归 D2 AC-16/B1〔OQ5〕;reloaded 根规格 = D2 全表清单拷贝 + 仅置换 StatusEffectTable,见前言夹具规格);再 apply_effect(fresh_probe, …)(新 id、无存活实例——refresh 重置目标取实例快照 D 的口径见 F1 注,本腿不涉存活实例重置) | **已授予实例六字段与载荷逐字不变**(授予时拷贝 m/D/unit 数值快照——EC9"快照非活引用",A4 EC8 同款语义;实例为 B3 自持,故 B3 冒烟自测、无需 deferral);fresh_probe → true 且新实例 **R=9、载荷 1×(+20)**(夹具登记值)——**换根只影响后续授予** |
| AC-16(MVP 内容四行) | ConfigDB 默认根加载完成 | 读 StatusEffectTable | **恰含 4 行**、effect_id 集合 = {attack_up, defense_up, ambush, weaken}(定值);target_side:attack_up/defense_up=hero、ambush/weaken=enemy,unit:percent/percent/flat/percent,stack_policy=stack ×4(均非 knob 结构、定值断言合法——Rule 10"四行全 stack");display_name 四值非空(精确值对账归 AC-18);magnitude/duration_settlements/max_stack 仅作类型域断言、期望 = 表读值(knob 纪律——A4 AC-1 同款,防调参打假;行表"来源"列为 provenance 非表字段、不作断言) |
| AC-17(确定性——A3 AC-17 同型;可观测序腿) | 全新容器实例 ×2(同 ConfigDB 默认根;每遍新实例、无跨实例状态) | 同一定长序列驱动两遍:start → defense_up×1 → attack_up×1(同侧双实例、授予序 = 字典序**逆序**——区分"插入序实现"与"字母排序实现"的判别性前提)→ query 投影(hero 恰 2 实例,**投影序列 = [defense_up, attack_up] 定值断言**——插入序的行为级观测点)→ weaken×1 → decay → query 投影 → attack_up×1(并入腿——前提 D_a ≥ 2 成立时并入 L=2;默认表值 D_a=1 时旧实例已销毁,退化为新建 L=1 断言 + SKIP 标记,同 AC-4 口径)→ decay → end → query | 两遍的 query_active 投影序列(**含插入序**)与 decay_round 返回值序列**逐项相同**,且 hero 侧投影序恒 = 授予序(非字典序——零随机 + 插入序枚举的双重行为级证据——Rule 1;D2 AC-15 的 B3 层前身) |
| AC-18(registry 一致——A3 AC-10a 同型,无条件断言;registry 逐字段键) | ConfigDB 默认根加载完成 | 脚本解析 design/registry/entities.yaml 的 status_effect 条目(**逐字段 YAML 键**——机器对账前提,action_economy 同构) | ① fields 八键与 ConfigDB schema 字段名逐一相等、各键的类型/域/枚举描述与 schema 定稿相等(**缺任一键即失败**);② mvp_content 四键 id 集合与表行 id 集合相等,**非 knob 结构字段**(target_side/unit/stack_policy)逐一相等;③ rule4_exemption / dangling_ref_policy 注记存在性断言。knob 活值(magnitude/duration_settlements/max_stack)**不作定值对账**(A4 AC-8 同款——对账口径 = registry 随调参同步〔接口漂移义务〕,本 AC 豁免其值)。生效前提:本条目为定稿回填 + registry 逐字段键重构的产物,AC 生效前提 = 重构回填完成(不写"若存在"软口径——条件化使一致性检查落空,A3/A4 均无条件) |
| AC-19(静态扫描——D2 AC-9/AC-10 模式引用,A3 AC-10b 同型) | B3 文件集(容器/schema/冒烟脚本/夹具规格)纳入 D2 AC-9 模式项目级扫描域 | 静态扫描:randomize() / RandomNumberGenerator / ConfigDB 外 data 表加载 / extends Control / .tscn preload;+ D2 AC-14 人工三要素字面量扫描 | 全部**零命中**(schema 与容器的 class_name 直引实例化豁免——AC-13 前提,A4 AC-7 同款);字面量扫描引用不另设硬 THEN(字面量判定误报率高——D2 已定性 warning 级 + 人工复核);零随机的行为级硬证据 = AC-17 |
### 覆盖矩阵(qa-lead 交付,验收评审用)
| 类别 | 映射 |
|---|---|
| Core Rules | Rule 1→AC-1/2/10/17/19 · Rule 2→AC-8/9/10 · Rule 3→AC-3+前言 API 封闭 · Rule 4→AC-4/5/6 · Rule 5→AC-11(明细行→B1 义务⑧+B5×2 已登记)· Rule 6→AC-1/2(decay 次序 OOS)· Rule 7→OOS(载荷只读面 AC-14)· Rule 8→前言 API 封闭+OOS · Rule 9→AC-13/16/19 · Rule 10→AC-16/18 |
| Formulas | F1→AC-4/11(stack)/AC-5(refresh)/AC-6(independent)· F2→AC-14+AC-5①/AC-6 · F3→AC-8/9/10 |
| 边界情况 | EC1→AC-1/2 · EC2→AC-12 · EC3→AC-11 · EC4→AC-5③ · EC5→AC-9 · EC6→AC-7 · EC7→AC-14 腿 3 · EC8→AC-10 · EC9→AC-15 · EC10→AC-5④+AC-13 · EC11→AC-1/2 · EC12→AC-1 · EC13→AC-1/2 · EC14→AC-6——无洞 |
## 版本历史
| 版本 | 日期 | 改动 |
|---|---|---|
| v2 | 2026-09-14 | 两件套迁移:按模板 v2 重排为 design(结论)+ analysis(推演)两件——公式推导与锚定论证、数值锚定过程、体验锚点论证、候选方案取舍、已裁决设计争议、开放问题(OQ1–7)与审计注记移入 `design/gdd/analysis/b3-status-effect.md`;速览/体验锚点/核心规则两段式重排为设计目的/系统范围/领域章节;零规则变更、零数值变更、AC/EC/F/义务编号全部保留 |
| 跨评审 B3 接口漂移批 | 2026-09-14 | /review-all-gdds 🔴-1 前半(减伤墙批回写缺口,registry 同批):defense_up.magnitude −50→**−30**(减伤墙批 C3 投值——叠满两层 −60 帽,defense_scan 墙轮 39%/真人 12 轮零承伤定量坐实)——MVP 内容行/Tuning Knobs/F2 Example 同步;免伤轮叙述同步(defense_up 单侧不可达 D'=0,现行可达路径 = weaken 饱和;F2 三例第三例改 defense_up 叠满读法——对侧 B1 F2 同批);Knob 交互:defense_up.magnitude/duration 纳入"禁独立调参"联动网络(m_w↔D_ref↔m_d↔duration_d);核心规则表增依据列(lint R8 引用列迁移) |
| v1.1-lean | 2026-09-13 | 格式迁移:legacy 原稿按 lean 样例重排——修订注记出正文收敛至本表;散文/枚举/边界/AC 转表格;流程转字符画;公式本体、Variables 表与验算数据全保留;语义与 registry 现行值对齐(weaken −65 = F0 值域 [60,85] · 四行 duration 1/1/1/1 = 当次结算 · enemy 侧 side-wide 多敌读法),零规则变更 |
| 两级奖励批 | 2026-09-11 | attack_up/defense_up duration 2→1(当次结算语义:授予结算兑付后即衰减);attack_up 复活(HeroTable.atk 域 [1,999]、0 加载拒绝——基础攻击恒存在,消费面 = 主角战斗段先手攻击);条款 2 锚参照对象回迁 attack_up 当量;正文原 D=2 行注记与 Knob 表 2/2/1/1 旧行按本批现行值改写 |
| F0 裁决回执批 | 2026-09-10 | weaken −25 → 值域 [60, 85]/默认 −65(B1 GDD F0:归一口径 = 每结算瞬时当量,总暴露分支被 percent schema 域禁止排除——条款 2 锚红警关闭,锚两腿 7.8 > 6.0 / 7.8 ≥ E_dig 7.2 通过);B1 义务①–⑧履行回执落位;B3 正文回执以 B1 GDD F0 为准(registry status_effect.anchor_warning) |
| 单敌假设回验批 | 2026-09-09 | B2 定多敌模型(1–3 个同敌种敌单位)——Core Rule 1 单敌假设回验不成立,效果 side-wide 语义改"全体存活敌单位"(层数 = side 共享池,B3 现接口零变更兼容);target_ref 单体寻址 = 扩展位义务(首个单体效果上线时 B3 补列,随批 B1 归集语义/D1 呈现裁决)——registry single_enemy_assumption |
| Rev 1 | 2026-09-09 | design-review 7 项 blocking 同日核销:enemy 侧单敌假设入文(后经上批回验改写)· B1 义务 5→8 · D1/B5/D5 呈现义务登记 systems-index · AC-15 机制更正 + reloaded 根全清单规格 · 致命夹具补根 dup_key · AC-18 随 registry 逐字段键重构 · weaken 红警补修复空间不对称 + OQ1 归一口径前置 · stack-不重置 R 登记 OQ7 playtest 证伪项——明细见 reviews/b3-status-effect-review-log.md |
| v1 | 2026-09-08 | 一次会话定稿:三结构决策(单一计数/按行叠层/四行定稿权收编)用户拍板;lean 门禁 systems-designer 起草 Formulas · qa-lead 起草/验证 AC;CD-GDD-ALIGN 按 lean 跳过 |