Merge branch 'master' into board-material-fix
# Conflicts: # reports/需求卡片-棋盘瓦片与立体表现重做批-2026-11-07.md
No files matched your search
@@ -50,7 +50,7 @@ description: g-plan2(Dungeon Sweeper)五段流水线第四段的迭代编排
|
||||
|---|---|---|
|
||||
| 1 | 卡内一致性互证 | 🔴契约 vs 任务卡 vs 验证闸对照表 vs 落位预检互相印证——汇总级抽查即可,逐条细查归写卡段复核(req-card grilling 门) |
|
||||
| 2 | 代码现状锚实核 | 卡片「现状事实」每条 file:line 打开实读;落位预检的新名 grep 全仓应零命中;「计划新增」件核不存在、「复用既有」件核存在 |
|
||||
| 3 | 判据出处行锚实核 | 对照表每行锚所指文档行打开实读,核句子在位**且内容与该行判据匹配**——机检 C5 只查存在性,查不出内容错位;写卡后文档被其他批改动会使锚漂移(2026-11-07 退役卡 ux 四锚漂移实证) |
|
||||
| 3 | 判据出处锚实核 | 对照表每行锚按索引(节名定位、行关键词命中行)打开文档节句实读,核句子在位**且内容与该行判据匹配**——机检 C5 核到「关键词命中节内」粒度、查不出语义错位,实读兜语义(2026-11-09 内容锚改版后行号漂移面已消,句内容真改动时关键词失配机检即红) |
|
||||
| 4 | 验收协议可执行性 | 对拍/等价/重放类判据的「改前基线+改后载体」两腿齐备:基线怎么来(采集步骤在卡内)、载体在盘可跑(工具在 tools/、锚在 sim-data/、golden 基线在 game/tests/golden/) |
|
||||
| 5 | 跨卡触碰面交集与卡序语义依赖 | 点名卡集两两过文件交集;同文件改动的语义序(前卡删除面 vs 后卡引用面);卡序与卡片内取用/产出声明一致 |
|
||||
| 6 | 跨批次断言钉死面 | 在飞或刚合回批次新增的断言(词表在册、表值钉、行为断言)是否钉住本批要改的退役面 |
|
||||
|
||||
@@ -5,7 +5,7 @@ description: g-plan2 迭代开工总指挥。当用户输入 /iter <迭代号>
|
||||
|
||||
# /iter——迭代开工总指挥(g-plan2 批次执行制)
|
||||
|
||||
你(执行会话)现在就是本迭代的编排者+施工者。用户输入 `/iter <N>` 即 **U0 开工令**——门全解且零待裁点时不要再问"可以开工吗",直接按本流程执行。唯一的合法前置停顿是第 2 步检查不通过。
|
||||
你(执行会话)现在就是本迭代的编排者——施工默认外派实现子代理(派发制,见第 4 步与「子代理使用口径」)。用户输入 `/iter <N>` 即 **U0 开工令**——门全解且零待裁点时不要再问"可以开工吗",直接按本流程执行。唯一的合法前置停顿是第 2 步检查不通过。
|
||||
|
||||
> **发射形态(与内置 /goal 的组合)**:/goal 是 harness 内置命令(会话级目标+续跑提醒+完成校验),由用户侧设置。推荐发射形态=`/goal 按 iter 技能执行迭代 <N>,直至总收口全绿`——/goal 提供"不到目标不收工"的机制级驱策与完成校验,本技能提供批次流程。本技能单独调用亦自足(停机/闸纪律已内建),但目标完成校验只有 /goal 能提供。
|
||||
|
||||
@@ -27,12 +27,12 @@ description: g-plan2 迭代开工总指挥。当用户输入 /iter <迭代号>
|
||||
- **待裁点 ≠ 0**:需求卡片声明待裁点未全裁,或行内有「待用户裁甲/乙」句。
|
||||
- **迭代估时总量 <5 个工作日**:迭代行状态应处「冻结待凑批」——处待开工/进行中且总量不足即编排缺陷,拒启动并呈报凑批方案(可补卡清单)等用户裁(2026-10-25 两层模型:卡片无工作量门槛,冻结线属迭代层)。
|
||||
- **需求卡片缺失**:行内引用的需求卡片文件不存在或版本明显滞后于行内裁决记录。
|
||||
- **改动—验收对照表缺失或不闭合(2026-10-11 立,2026-10-21 升级)**:需求卡片没有改动—验收对照表,或对照表有空行(无真实入口、无判据绑定面),或 T 卡内无对应验收条目 → 不过,停工呈报。**判定口径:每个需求点至少一行;每行必须有落点、真实入口、判据绑定面**——施工性质的验证工作(如「MC 对账适配」)、完成定义里的笼统验证手段(如「MC 对拍留证」)都不算。禁拿 AGENTS.md「新功能必配新测试」红线代偿——那条只保证写了测试,不保证测得对。2026-10-21 前的旧卡缺对照表 → 停工,退回写卡段补,补完再开工。**判据出处行锚(2026-11-05 起):生效日后(文件名日期不早于该日)的卡,对照表「需求点」格须带 `<现行文档相对路径>:<行号>` 判据出处行锚(机检=pipeline_gate C5)——行缺锚或锚指向不存在=停工呈报退写卡段;旧卡不回头改,开工前由写卡段补挂**(test-conventions §8.3)。
|
||||
- **改动—验收对照表缺失或不闭合(2026-10-11 立,2026-10-21 升级)**:需求卡片没有改动—验收对照表,或对照表有空行(无真实入口、无判据绑定面),或 T 卡内无对应验收条目 → 不过,停工呈报。**判定口径:每个需求点至少一行;每行必须有落点、真实入口、判据绑定面**——施工性质的验证工作(如「MC 对账适配」)、完成定义里的笼统验证手段(如「MC 对拍留证」)都不算。禁拿 AGENTS.md「新功能必配新测试」红线代偿——那条只保证写了测试,不保证测得对。2026-10-21 前的旧卡缺对照表 → 停工,退回写卡段补,补完再开工。**判据出处锚(2026-11-05 立,2026-11-09 内容化改版):对照表「需求点」格须带 `<现行文档相对路径>「节名」<行关键词>` 判据出处锚(机检=pipeline_gate C5:内容锚形态唯一+节名在档+关键词命中节内,行号形态出现即红)——行缺锚或锚不可核=停工呈报退写卡段**(test-conventions §8.3)。
|
||||
- **自洽扫描(轻量,非拷打)**:声明零待裁点≠逻辑无冲突——读卡后快速核三类:①需求卡片内部矛盾(范围/契约/估时/裁决记录互相打架);②需求卡片与 roadmap 行冲突(两处说法不一致);③事实抽查——从需求卡片「现状考证」里抽 3-5 处关键 file:line 到现行代码核对(防需求卡片成文后代码已被其他批改掉,需求卡片变质)。发现疑似冲突 → 逐条列单呈报(哪里矛盾/两种读法各是什么/建议哪边改),**用户裁决后才开工**;零发现则直接通过,不为此拉长开工。全量拷打(/grilling)不在此步做——那是需求卡片成文时的责任,这里只兜网;但**本步必查卡里留没留复核的记录**(见下条),记录不在=上游没跑,停工退写卡段。
|
||||
- **复核记录缺失(2026-11-05 用户立规)**:需求卡片内没有「复核记录」节、或该节申报的复核报告文件在 `reports/` 盘上不存在 → 不过,停工呈报退回写卡段。本步不代跑复核、不代补记录、不把缺记录的卡当旧卡放行;生效=卡片文件名日期 ≥2026-11-06(与 `tools/pipeline_gate.py` 该条卡片判据同口径),更早的卡不回头改。
|
||||
- **真人检测遗留项不算门(2026-10-12 用户立规)**:往期迭代/批次登记未验的实机目检项(体验验证清单/实现报告总清单在册)不构成开工阻塞——开工呈报带一句提醒即可,禁为此停工等验。
|
||||
- **设计闭合核验(2026-10-18 五段流水线立规)**:逐卡核需求卡片的设计事实源声明——独立小节「## 设计事实源」或头部「来源:…(唯一事实源:…)」句,二者得一即合格(**禁按小节名字面判死:库内合规卡多数用后者写法**;全文两词皆无=不过,机检见 `tools/pipeline_gate.py` 判据 C2)——①卡片声明的事实源文件真实存在(相对仓库根);②文档源版本与待办清单对应条目状态里的闭合凭据一致(工程类卡=证据指认与待办清单条目实况一致);③roadmap 迭代行卡片列路径与卡片实际路径一致;④行内预计周期形态合规(「≈N 个工作日」)且量值合规——5–10 个工作日为常规;10–20 个工作日须随带日期特批标记;超过 20 个工作日=缺陷(硬上限,特批不放行);低于 5 个工作日=该行状态必须为「冻结待凑批」,处待开工/进行中即编排缺陷(2026-10-25 两层模型:卡片无门槛、迭代层冻结线)。任一不过 → 停工呈报——这是编排段(iter-plan)缺陷,不是本技能能修的,禁代改卡片或迭代行凑绿。
|
||||
- **执行形态判定(2026-10-22 用户立规)**:读各卡「前置依赖与并行性」节(各卡 §0)定本迭代执行形态——默认=整迭代单工作区、各卡按 roadmap 行卡片列格内顺序串行推进;仅当卡片声明可并行(且互核无同文件交集)时,该卡组走逐卡工作区例外路径(第 4 步)。判定结果在开工呈报里带一句。
|
||||
- **执行形态判定(2026-10-22 立规;2026-11-10 用户裁改派发制)**:读各卡「前置依赖与并行性」节(各卡 §0)排出派发表——零「硬等/前置门」依赖且与在飞卡零同文件交集的卡即刻派发实现子代理(在飞实现子代理 ≤2);有依赖的卡等前置卡收并落干后派发;有同文件交集的卡自然错峰,不另设串行声明。排程表(每卡:派发波次/依赖前置/状态)在开工呈报里带一句。派发制与收口机制无冲突:卡区收并保迭代分支第一-parent 线性(后收口者 rebase 后落干),重塑判据=各卡边界在链上递增(`tools/reshape_cards.py` 规则 2)。
|
||||
|
||||
呈报格式:一行一项(哪条不满足/证据在哪/需要用户做什么)。全部通过则宣布「迭代 <N> 开工(U0=本次调用)」进入第 3 步。
|
||||
|
||||
@@ -40,31 +40,37 @@ description: g-plan2 迭代开工总指挥。当用户输入 /iter <迭代号>
|
||||
|
||||
1. `git status` 归属核对:主区脏文件分两类——**本迭代定义面**(下条列名文件)与**其他在飞遗产**(其余一切)。除定义面外一律禁碰、禁代提交、禁还原。
|
||||
2. **定义面已入库**(目的:worktree 从旧 HEAD 检出必须看得到定义;后续合并不被脏 roadmap 阻塞):`git add` 仅限 roadmap.md、待办清单.md、本迭代引用的全部需求卡片文件——**指名道姓,禁扫全仓**——单独一笔提交,message=`docs: 迭代<N>定义已入库`。注意:这一步是**搬运别的会话已写好的定义文件**,不是本批撰写文档(批性质禁令照旧生效);该笔单独成提交,别和代码提交混在一起,否则合回后 CI 会把本批 diff 推定跨两域、两域都验。
|
||||
3. **建迭代工作区(整迭代只此一个)**:`git worktree add ../g-plan2-iter<N> -b iter<N>`;冷检出四件套照坑速查执行(拷主区 `game/assets/art/` 与 `*.import` 边车 → `--headless --editor --quit` 刷导入 → `tools/setup_worktree_userdir.sh` 建本区独立 user 目录;闸机 code 域起手自检会自动兜底同步素材与熵增预检——`tools/sync_worktree_assets.sh`,2026-10-30 工程批——四件套照做,脚本兜防漏)。第 4 步各卡都在此工作区内推进;整迭代禁开第二个 worktree(并行例外见第 4 步)。**检出工作区零测试,直接开工**(2026-10-22 频率规则;全量验证归合回后远端 CI——合并落地 post-merge 钩子推送自动跑,T0 不做基线复读,红绿归因由「卡内只测自己改的东西」与闸机基线比对机制承担)。
|
||||
3. **建迭代干区(整迭代只此一个,承载收并与收口)**:`git worktree add ../g-plan2-iter<N> -b iter<N>`;冷检出四件套照坑速查执行(拷主区 `game/assets/art/` 与 `*.import` 边车 → `--headless --editor --quit` 刷导入 → `tools/setup_worktree_userdir.sh` 建本区独立 user 目录;闸机 code 域起手自检会自动兜底同步素材与熵增预检——`tools/sync_worktree_assets.sh`,2026-10-30 工程批——四件套照做,脚本兜防漏)。第 4 步各卡派发至独立卡区(分支 `iter<N>-卡<序号>`、worktree `../g-plan2-iter<N>-卡<序号>`,每卡区冷检出四件套各一次;属 AGENTS「会话单区」之迭代例外——在飞卡区 ≤2,2026-11-10 用户裁);卡区收并回干区后即删。**检出工作区零测试,直接开工**(2026-10-22 频率规则;全量验证归合回后远端 CI——合并落地 post-merge 钩子推送自动跑,T0 不做基线复读,红绿归因由「卡内只测自己改的东西」与闸机基线比对机制承担)。
|
||||
|
||||
|
||||
## 第 4 步:迭代内逐卡推进(单工作区)
|
||||
## 第 4 步:迭代内逐卡推进(派发制)
|
||||
|
||||
整迭代一个工作区(第 3 步已建),各卡都在其中推进。执行顺序=roadmap 迭代行卡片列格内顺序;卡片「前置依赖与并行性」节声明可并行的卡组走下方例外路径,其余串行。何时该把活分出去见下面「子代理使用口径」。
|
||||
施工默认外派实现子代理(2026-11-10 用户裁),主会话只做编排面:排程 → 派发 → 核验 → 收并 → 下一波。在飞实现子代理 ≤2(用户既定上限,取代原并行例外 ≤3)。执行顺序按第 2 步排程表:零依赖即刻派发,有「硬等/前置门」的卡等前置落干后派发。口径细则见下面「子代理使用口径」。
|
||||
|
||||
1. **读卡施工**:需求卡片 T 卡逐轮推进——读卡→对事实源(file:line 复核)→实装(**验收测试随对应 T 卡同轮落地,禁批末补写**;同轮把实际对照表写进实现报告,测试写文件:行)→本卡验收测试跑绿、读数写进该笔提交(AGENTS 红线·改完即测铁规)→提交(代拍板随 commit 记录)→进度记录→下一轮。**卡内只测自己改的东西**(2026-10-22 频率规则):本卡新增/改动的验收测试自己跑绿、读数写进该笔提交才算这一步完成,没改的不测,轮内不跑闸壳全套。整迭代禁开第二个 worktree。**diff 里没有对照表行的行为改动必须标「非行为改动」或指向覆盖行;禁删断言、放宽阈值、缩小扫描面、把真实入口换成下层直调;判据绑不上可观测提交面=停卡呈报。**
|
||||
2. **卡间依赖**:卡片声明「硬等/前置门」的后续卡,须等前置卡收口 commit 落本迭代分支且该卡验收测试跑绿后才准开 T1——迭代内不再以「合并进 master」为门(整迭代只合并一次,见第 5 步);跨迭代依赖仍由第 2 步开工检查核。
|
||||
3. **并行例外(逐卡工作区,2026-10-22 用户立规)**:仅当卡片「前置依赖与并行性」节声明可并行、且开工检查核过无同文件交集时,该并行卡组按卡各开 worktree(`git worktree add ../g-plan2-<卡名worktree>`,冷检出四件套照坑速查),subagent 并发 ≤3(用户既定上限);并行卡各自收口合并进 master(现行逐卡机制原样保留在此例外路径),不受第 5 步「一次合并」约束。
|
||||
4. **画面类需求的黄金图基线冻结(2026-11-05 立;2026-11-08 补审核落档)**:卡触碰画面呈现面的(判据=设计段出了预览图),实现轮把该画面纳入渲染闸机器面——截图采集清单扩项+实跑截图冻结进 `game/tests/golden/`;冻结(新建与换代同口径)前呈用户对照该卡预览图**逐张审核确认**,确认后触发原因写进当批提交说明(`tools/golden_baseline_refresh.sh`);此后渲染闸逐像素自动盯、零人工。义务细则=test-conventions §8.2「golden 测试项扩项」与「基线冻结审核关卡」;预览图(HTML/SVG 效果图)禁直接充当比对基线。**确认记录落 `game/tests/golden/README.md` 审核记录节(审核人+时间+基线清单);未审核的基线禁合回**——关卡同适用于非卡片批的基线操作(目录迁移/重构/容差修订等工程批,同样逐张呈报审核)。**基线跨平台单套(2026-11-08 用户裁:跨平台渲染必须一致,全平台对拍同一份基线,跨平台锯齿噪声由容差带吸收,禁加平台基线消化差异)**。
|
||||
1. **派发(每卡一次,按排程表)**:给实现子代理开卡区(`git worktree add ../g-plan2-iter<N>-卡<序号> -b iter<N>-卡<序号>`,冷检出四件套照坑速查)并写派发指令。**派发指令带路径不转录全文**(省主会话上下文;子代理自读卡片原文与设计事实源,不靠转述),必载六项:
|
||||
- **事实源**——卡片路径+本卡「前置依赖与并行性」节要点+卡内引用的关键 file:line 锚;
|
||||
- **验收**——对照表位置(卡内节名)与验收档申报;改完即测义务:**验收测试随对应 T 卡同轮落地,禁批末补写**,本卡验收测试跑绿、读数写进该笔提交(AGENTS 红线);**卡内只测自己改的东西**(2026-10-22 频率规则),没改的不测,轮内不跑闸壳全套;
|
||||
- **施工红线**——**diff 里没有对照表行的行为改动必须标「非行为改动」或指向覆盖行;禁删断言、放宽阈值、缩小扫描面、把真实入口换成下层直调;判据绑不上可观测提交面=停手回报**;
|
||||
- **停机**——卡内分歧=停手回报,禁自答禁自裁(实现段零裁断对子代理同效);MC/verifier 跑批禁自发起(用户批准硬规对子代理同效);
|
||||
- **禁写面与提交**——`design/` 整目录、根规则文件、`game/tests/README.md` 照批性质禁令只读;代拍板随 commit 留痕,一卡多笔自由提交;
|
||||
- **返回形态限长**——commit 号+测试读数+实际对照表行+偏差清单,不贴全文;实际对照表行由主会话汇编进实现报告。
|
||||
2. **核验(收回口回报后主会话亲自动手)**:核三样——①子代理报的 commit 真在卡区分支上;②断言尾缀能 grep 到;③测试读数在该笔提交信息里。任一缺 → 打回重派或停机呈报。
|
||||
3. **收并(核验过即做,主会话执行)**:卡区分支并入迭代干区——先收口者 fast-forward,后收口者先 rebase 到干区尖再 fast-forward(保第一-parent 线性,重塑判据=各卡边界链上递增);收并后删卡区 worktree、排程表记状态,腾出在飞席位派下一卡。
|
||||
4. **卡间依赖**:卡片声明「硬等/前置门」的后续卡,须等前置卡收并落干区且验收测试跑绿(读数在案)后才派发——迭代内不以「合并进 master」为门(整迭代只合并一次,见第 5 步);跨迭代依赖仍由第 2 步开工检查核。
|
||||
5. **画面类需求的黄金图基线冻结(2026-11-05 立;2026-11-08 补审核落档)**:卡触碰画面呈现面的(判据=设计段出了预览图),实现轮把该画面纳入渲染闸机器面(采集与扩项由实现子代理执行,用户审核经主会话转呈)——截图采集清单扩项+实跑截图冻结进 `game/tests/golden/`;冻结(新建与换代同口径)前呈用户对照该卡预览图**逐张审核确认**,确认后触发原因写进当批提交说明(`tools/golden_baseline_refresh.sh`);此后渲染闸逐像素自动盯、零人工。义务细则=test-conventions §8.2「golden 测试项扩项」与「基线冻结审核关卡」;预览图(HTML/SVG 效果图)禁直接充当比对基线。**确认记录落 `game/tests/golden/README.md` 审核记录节(审核人+时间+基线清单);未审核的基线禁合回**——关卡同适用于非卡片批的基线操作(目录迁移/重构/容差修订等工程批,同样逐张呈报审核)。**基线跨平台单套(2026-11-08 用户裁:跨平台渲染必须一致,全平台对拍同一份基线,跨平台锯齿噪声由容差带吸收,禁加平台基线消化差异)**。
|
||||
|
||||
### 子代理使用口径(2026-10-21 用户立)
|
||||
### 子代理使用口径(2026-10-21 立;2026-11-10 用户裁反转:实现默认外派)
|
||||
|
||||
默认口径:**实现不外派**——写代码、写测试与对照表、合并、停机呈报一律由本会话做;可以外派的是查证与「跑命令取读数」两类主动分出的活,加上合并前那项强制分出的独立验收审计,共三类(见下)。外派出去的活都不改源码、不写实现产出物、不做裁断。并发上限只管数量,这条管范围。
|
||||
默认口径:**实现外派**——单卡实现轮(实装+验收测试与改动—验收对照表的同轮编写)整体派给实现子代理,一卡一代理一卡区(第 4 步);主会话保留:开工检查与排程、派发指令撰写、核验三样、收并动作、合并、停机呈报与用户转呈、收口五步与实现报告——这些是门与裁断面,依赖对全部卡片与迭代全局的掌握。**全局在飞子代理 ≤2**(用户既定上限,取代原 ≤3):实现代理与考证/红定位类共用额度,实现占满两席时考证类排队或并入实现代理顺手做;独立验收审计在收口期跑、实现代理已撤,天然不占额。外派出去的活一律不做裁断、不改他卡文件。
|
||||
|
||||
**可以分出去的三类**(派出前先想清楚要它返回什么,指令里写死返回形态):
|
||||
**外派四类**(派出前先想清楚要它返回什么,指令里写死返回形态):
|
||||
|
||||
1. **只读考证**——第 2 步自洽扫描的第③项(从需求卡片「现状考证」抽 3-5 处关键 file:line 到现行代码核对)、跨模块找某符号的消费方与改动面。只要它汇报「文件:行 + 一句事实」,禁它改文件、禁它下「因此该怎么改」的结论;冲突判定与裁断仍在本会话。
|
||||
2. **闸跑出红定位**——跑批输出量大,把「跑这条命令 + 报红的用例名与第一条失败断言 + 原样贴出那段读数」分出去,修复与复跑收回本会话。判「是不是本批新增红」以第 3 步基线读数为凭据,不拿子代理的「全绿」转述当凭据。
|
||||
3. **合并前的独立验收审计**——见「独立验收审计」一节,属强制分出,实现者不能自审。
|
||||
1. **卡实现轮(2026-11-10 新增,默认形态)**——按第 4 步派发指令模板执行。原「实现不外派」的顾虑(依赖卡片全文理解、转述写码无法对齐卡片)由派发指令解决:指令带卡片路径与事实源锚,子代理读卡原文,不靠转述;卡区隔离保证互不踩闸。
|
||||
2. **只读考证**——第 2 步自洽扫描的第③项(从需求卡片「现状考证」抽 3-5 处关键 file:line 到现行代码核对)、跨模块找某符号的消费方与改动面。只要它汇报「文件:行 + 一句事实」,禁它改文件、禁它下「因此该怎么改」的结论;冲突判定与裁断仍在本会话。
|
||||
3. **闸跑出红定位**——跑批输出量大,把「跑这条命令 + 报红的用例名与第一条失败断言 + 原样贴出那段读数」分出去,修复与复跑归主会话(实现期卡内红先打回实现代理自修,修后重新核验)。判「是不是本批新增红」以第 3 步基线读数为凭据,不拿子代理的「全绿」转述当凭据。
|
||||
4. **合并前的独立验收审计**——见「独立验收审计」一节,属强制分出,实现者不能自审。
|
||||
|
||||
**不分出去的**:单卡实现轮本身、验收测试与改动—验收对照表的同轮编写、合并动作、停机呈报。原因:这几项依赖对卡片全文与设计事实源的完整理解,且施工铁律写了整迭代单工作区;子代理拿到的是转述,写出来的码无法保证对齐卡片。第 4 条的并发上限与执行形态判定管的是**多张卡怎么排先后、各用哪个工作区**,不是把实现交给子代理——判定为并行时,本会话逐卡开卡、逐卡施工,分出去的仍然只有上面那三类。
|
||||
|
||||
**取回纪律**:子代理的汇报当线索不当证据。凡涉及「跑绿了」「这条断言存在」「文件在这一行」的说法,本会话自己 grep 或自己跑一次才算数——「独立验收审计」一节不采信被审对象自述「已全绿」,正是同一条口径。
|
||||
**取回纪律**:子代理的汇报当线索不当证据。凡涉及「跑绿了」「这条断言存在」「文件在这一行」的说法,主会话按第 4 步核验三样自己 grep 确认才算数——「独立验收审计」一节不采信被审对象自述「已全绿」,正是同一条口径。
|
||||
|
||||
### 闸序列(既定,禁手拼同款命令)
|
||||
|
||||
@@ -76,7 +82,7 @@ description: g-plan2 迭代开工总指挥。当用户输入 /iter <迭代号>
|
||||
|
||||
### 独立验收审计(合并前必做,2026-10-21 立)
|
||||
|
||||
由没参与实现的子代理,或用户点名的另一会话执行;只读需求卡片、实现报告里的实际对照表、本批 diff、测试文件和闸回执,不采信报告里的「已全绿」。单工作区口径(2026-10-22 起)下在迭代总收口、合并前执行一次,审计范围覆盖本迭代全部卡的 diff、对照表与验收断言。至少做三件事:
|
||||
由没参与实现的子代理,或用户点名的另一会话执行;只读需求卡片、实现报告里的实际对照表、本批 diff、测试文件和闸回执,不采信报告里的「已全绿」。派发制口径(2026-11-10 起)下在迭代总收口、合并前执行一次,审计范围覆盖本迭代全部卡的 diff、对照表与验收断言(卡区史已按卡并入迭代分支,diff 以 iter<N> 对 master 计)。至少做三件事:
|
||||
|
||||
1. 逐行核对对照表:测试存在、尾缀能 grep 到、真实入口没有绕过改动点;
|
||||
2. 抽查验收断言:每张 T 卡至少一条,核对断言在当轮真实跑批中执行且通过(闸回执与测试输出为凭);
|
||||
@@ -88,7 +94,7 @@ description: g-plan2 迭代开工总指挥。当用户输入 /iter <迭代号>
|
||||
|
||||
### 停机规则
|
||||
|
||||
- **实现段零裁断(2026-10-18 换口径,取代原「禁自答/用户门/机制卡点」三条)**:实现段的输入在编排段出口已锁死(卡片零待裁点+设计闭合凭据齐+编排五查过)。施工中冒出需求卡片没写清的分歧、冲突、模糊点(含机制卡点)=**上游缺陷**——停该卡,呈报退回上游(写卡段或设计段),随呈报附「待办清单对应条目状态回退+缺口补记」拟稿(写清差什么才能重写卡);呈报=缺陷移交不是提问,须把分歧点、两种以上读法与建议案写全,不裸呈问题。**禁自答、禁内联提问求裁断、禁 idle 等待轮**;待办清单状态回退与缺口补记的落笔归上游段或用户——本批对 `design/` 只读,批性质禁令不因停机豁免。该卡停摆不阻塞同迭代其他卡,其余卡继续(单工作区口径:停摆卡不提交,其余卡继续施工;迭代收口合并须等停摆卡闭合、或用户裁拆批后整体进行)。
|
||||
- **实现段零裁断(2026-10-18 换口径,取代原「禁自答/用户门/机制卡点」三条)**:实现段的输入在编排段出口已锁死(卡片零待裁点+设计闭合凭据齐+编排五查过)。施工中冒出需求卡片没写清的分歧、冲突、模糊点(含机制卡点)=**上游缺陷**——停该卡,呈报退回上游(写卡段或设计段),随呈报附「待办清单对应条目状态回退+缺口补记」拟稿(写清差什么才能重写卡);呈报=缺陷移交不是提问,须把分歧点、两种以上读法与建议案写全,不裸呈问题。**禁自答、禁内联提问求裁断、禁 idle 等待轮**;待办清单状态回退与缺口补记的落笔归上游段或用户——本批对 `design/` 只读,批性质禁令不因停机豁免。该卡停摆不阻塞同迭代其他卡,其余卡继续(派发制口径:停摆卡不收并、卡区留存待闭合,排程表记停摆,其余卡照常派发收并;迭代收口合并须等停摆卡闭合、或用户裁拆批后整体进行)。
|
||||
- 需求卡片内预设停机点(S1/S2…)→ 合法停机呈报等裁(裁断点在卡片审问阶段已由用户预设,属预授权面)。
|
||||
- 异常分级:L1 自救重试一次 → L2 记录继续(连续 3 次同红灯升级)→ L3 停机写报告等用户。环境故障与测试红是工程问题,走分级处置,不属裁断。
|
||||
- 代拍板白名单保留:授权发生在卡片审问阶段,实现只执行预授权(随 commit 留痕);超白名单事项记入实现报告「实现决定记录」节备案,不另立追认单。
|
||||
@@ -96,8 +102,8 @@ description: g-plan2 迭代开工总指挥。当用户输入 /iter <迭代号>
|
||||
|
||||
## 第 5 步:合并与收口
|
||||
|
||||
1. **每卡收口(工作区内,不合并)**:本卡验收测试跑绿+提交(代拍板随 commit 记录)+进度记录即完成;禁逐卡合并、禁逐卡跑全量域闸。
|
||||
2. **迭代总收口(一次合并)**:全部卡收口后 → **冻结**(代码与断言不再动)→ 全仓件核 grep → master 已被推进则在迭代工作区 `git merge master` 解冲突 → **重塑**:`python tools/reshape_cards.py --branch iter<N> --card 卡<k>=<该卡最后一笔> …`(把分支线性史压成一卡一笔+可选一笔纯文档收尾;原史自动留 backup 分支,见 process-conventions §1.3)→ **独立验收审计通过**(见上节)→ 主区 `git merge --no-ff iter<N>`(合回守卫数卡校验:卡提交数=roadmap 行卡片数,未归卡提交拦下)→ 合并落地 post-merge 钩子自动推送 origin master 触发远端 CI 全量(后台,不阻塞)→ 即向用户呈报本批总结(呈报即本回合止),结果按需现查 `tools/ci_check.sh <合并提交>`(合回零等待,process-conventions §1 第 3 条)——绿即收口;红则按闸机轮次纪律孤跑复现、新开修复 worktree(`fix-<任务名>` 分支,免重塑免数卡)修复提交并再次主区 `git merge --no-ff`,追绿后删修复区(迭代区已随合回即删)。允许的重跑只剩「验证修复」与用户自发全量回归两类,禁「跑都跑了再跑一遍保险」(process-conventions §1 第 2 条、§3 第 9 条)。
|
||||
1. **每卡收口(卡区内,不并 master)**:本卡验收测试跑绿+提交(代拍板随 commit 记录)+实际对照表行随回报交主会话即完成;禁逐卡合并进 master、禁逐卡跑全量域闸(收并进迭代干区属第 4 步常规动作,不算合并)。
|
||||
2. **迭代总收口(一次合并)**:全部卡收口且收并落干区后 → **冻结**(代码与断言不再动)→ 全仓件核 grep → master 已被推进则在迭代工作区 `git merge master` 解冲突 → **重塑**:`python tools/reshape_cards.py --branch iter<N> --card 卡<k>=<该卡最后一笔> …`(把分支线性史压成一卡一笔+可选一笔纯文档收尾;原史自动留 backup 分支,见 process-conventions §1.3)→ **独立验收审计通过**(见上节)→ 主区 `git merge --no-ff iter<N>`(合回守卫数卡校验:卡提交数=roadmap 行卡片数,未归卡提交拦下)→ 合并落地 post-merge 钩子自动推送 origin master 触发远端 CI 全量(后台,不阻塞)→ 即向用户呈报本批总结(呈报即本回合止),结果按需现查 `tools/ci_check.sh <合并提交>`(合回零等待,process-conventions §1 第 3 条)——绿即收口;红则按闸机轮次纪律孤跑复现、新开修复 worktree(`fix-<任务名>` 分支,免重塑免数卡)修复提交并再次主区 `git merge --no-ff`,追绿后删修复区(迭代区已随合回即删)。允许的重跑只剩「验证修复」与用户自发全量回归两类,禁「跑都跑了再跑一遍保险」(process-conventions §1 第 2 条、§3 第 9 条)。
|
||||
3. 账面随批:**能力清单核对(2026-10-29 起,核对义务归收尾提交)**——核对 `game/tests/README.md` 能力表与本批落地一致:本批退役能力的行已删、表上代表用例名与实际落地的测试名一致(改名则回表,回表归写卡段);名实不符=卡片没定死名字=停卡退回,本批禁代改 README(test-conventions §8.3)。体验验证清单登记目检项(真人检测只登记不阻塞——登记完批内义务即了结,禁以等目检为由延后合并/收口/下一迭代,2026-10-12 用户立规)、roadmap 行内该卡换代、术语表如涉(以上机械面文档,合并前随批更新完毕);**GDD/art-bible 等设计权威文档一律不动**——实现与设计的差异/缺口逐条记入反哺点清单(2026-10-10 用户立规:文档更新必须经用户同意)。
|
||||
4. 迭代产出物**全部落 `reports/`,禁落 `design/`**——`reports/iter<N>-实现报告-<日期>.md`(各卡状态+实际对照表+独立验收审计结论+实机目检总清单+遗留读数义务+实现决定记录)、`reports/iter<N>-反哺点-<日期>.md`(要写进 GDD/art-bible 的点逐条写清:哪个文件哪一节、改成什么、依据是什么;**不再登记待办清单**,用户在会话里裁决后由文档批写入 `design/` 并把该条清掉);stage.txt 视情移动、批末闸序列全绿留痕。待办清单条目状态推进与 roadmap 顶部「当前位」三行换代都归文档批做(本批禁写 `design/` 与根规则文件,见批性质禁令)。**roadmap 里程碑或行换代已移出本批**(属文档动作,归文档批做);若按第 3 步搬运过定义面(roadmap/待办清单/需求卡片),那笔提交单独成笔,呈报时注明是搬运既有文件、不是本批撰写文档。
|
||||
5. 红灯纪律:存量红零新增口径可继续;**新红必修或停机呈报,禁带红合并**。
|
||||
@@ -105,9 +111,9 @@ description: g-plan2 迭代开工总指挥。当用户输入 /iter <迭代号>
|
||||
## 坑速查(历史实证,开工前扫一眼)
|
||||
|
||||
- 报告写「V1 绿」不等于有 V1 的断言:先 grep 断言尾缀和真实入口,再看报告;绕过真实入口的测试(如裸 `EffectEngine` 替代 `BattleOrchestrator`)不算该接线的验收。
|
||||
- worktree 冷检出(整迭代一次;并行例外路径每卡一次):`game/assets/art/**` 与一切 `*.import` 边车都不入 git,检出后必先把主区素材拷过来(`cp -r <主区>/game/assets/art/. <本区>/game/assets/art/`),再用 **`--editor --quit`** 刷导入——`--import` 不生成新素材的 .import 边车,刷完仍报 `main_theme.tres` 解析失败、按钮样式盒全空、冒烟 V1 成片假红(2026-10-17 实测)。跑批前的素材齐盘预检会把这件事拦下来并按名列出缺件。同轮跑 `tools/setup_worktree_userdir.sh`:不建区隔离时所有 worktree 共用引擎 user 目录,测试夹具、试玩日志与截图产物互踩(并行跑闸必假红);闸壳跑批前会自检/自愈,建不起来即拒跑。
|
||||
- worktree 冷检出(干区一次;派发制下每张卡区各一次):`game/assets/art/**` 与一切 `*.import` 边车都不入 git,检出后必先把主区素材拷过来(`cp -r <主区>/game/assets/art/. <本区>/game/assets/art/`),再用 **`--editor --quit`** 刷导入——`--import` 不生成新素材的 .import 边车,刷完仍报 `main_theme.tres` 解析失败、按钮样式盒全空、冒烟 V1 成片假红(2026-10-17 实测)。跑批前的素材齐盘预检会把这件事拦下来并按名列出缺件。同轮跑 `tools/setup_worktree_userdir.sh`:不建区隔离时所有 worktree 共用引擎 user 目录,测试夹具、试玩日志与截图产物互踩(并行跑闸必假红);闸壳跑批前会自检/自愈,建不起来即拒跑。两个子代理禁共用一个工作区跑闸——user 目录与导入缓存互踩必假红(本条前科同源),每代理各持一区。
|
||||
- 合并后主区:无手工动作——类名缓存刷新由 CI 跑批起手接管(`--editor --quit`);CI 首跑即合并后验证,红项与绿证用 `tools/ci_check.sh <合并提交>` 现查(读数须是绿;「未验」=零触发批跑闸步全跳过,不算验过),修复走 `fix-<任务名>` worktree 合回自动追绿。
|
||||
- 长测试前:清残留 Godot 进程(probe_gate 自带清杀,run_all 需手动)。
|
||||
- 长测试前:清残留 Godot 进程(probe_gate 自带清杀,run_all 需手动);派发制下清杀前确认他卡区代理没在跑批,禁一把全杀。
|
||||
- 改名件:.gd/.uid/.tscn 三件同步,禁只改 .gd。
|
||||
- heredoc 内变量会被吞:复杂脚本落文件再执行。
|
||||
- CRLF:禁往核心层 .gd 带入 CRLF(battle_orchestrator 前科)。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: req-card
|
||||
description: g-plan2(Dungeon Sweeper)仓库写需求卡片的固定流程与结构。当用户要求起草/修订需求卡片、给迭代需求写实施文档、或迭代规划进入写卡阶段时使用。固化需求卡片必备结构——尤其「关联文档同步面」必填节(2026-10-17 文档同步闸 v3:卡片服务的是**代码实现批**,该批禁写 `design/` 与根规则文件,要改文档的点一律列进 `reports/` 反哺点清单,用户在会话中裁决后归文档批落文)、「改动—验收对照表」(2026-10-11 立,2026-10-21 升级:每个需求点与每个行为改动都必须有真实入口断言和判据绑定面;无验收标准的需求点=卡片不成立,/iter 开工门同规拦截)与「落位与可复用性预检」必填节(2026-10-21 立:新增文件/函数/数据件前先核仓库既有实现,能复用不新增,落点唯一、禁散落 helper、跨层交互显式声明)、「实现规范预算」必填节(2026-10-27 迭代 39 实证立规:新增件接口块/成员面先对 gdstyle 默认阈值做预算——公开方法 ≤20、类变量 ≤15、迁移函数对账基线键,超了写卡段拆件,例外走显式申报+用户特批,禁把超预算面带进实现段)与「拆分边界纪律」结构类卡必填条款(2026-10-28 用户裁立:拆分边界沿职责轴不沿阈值轴——拆出单元须有职责语句/单一变化原因/集体身份,凑计数袋禁、阈值只作发现信号、拆不出内聚单元停卡呈报走豁免通道,判据权威=code-conventions §1.1)。任务卡 T0..Tn 的步骤写作遵循 superpowers:writing-plans 方法论(2026-10-19 起按本项目适配内联:卡前文件结构图/范围检查/任务右尺寸/步骤粒度/步骤内容四分/接口声明/禁行句式/自审六查)。复核门含判据出处行锚逐行实读(2026-11-07 起,对照表每行锚所指文档行实读核句子在位且内容匹配——机检 C5 只查存在性)与引擎技术面三查(2026-11-04 起,godot-master 窄口径:NEVER/Gotchas/性能预算+按需领域 reference,权威仍在项目规范)。复核发现按四类去向处置(2026-11-05 立:自判=查规范或查代码有唯一答案,复核者自己改卡;补写=卡里漏写,回炉补全;待裁=多种做法都不违规且代价不同,才交用户;退回上游=文档线或美术线未闭合、或架构与代码规范本身冲突);卡片必带「复核记录」节(缺节=不成立,机检=pipeline_gate),复核先于提交、提交先于合回,顺序没走完禁对用户称完成。
|
||||
description: g-plan2(Dungeon Sweeper)仓库写需求卡片的固定流程与结构。当用户要求起草/修订需求卡片、给迭代需求写实施文档、或迭代规划进入写卡阶段时使用。固化需求卡片必备结构——尤其「关联文档同步面」必填节(2026-10-17 文档同步闸 v3:卡片服务的是**代码实现批**,该批禁写 `design/` 与根规则文件,要改文档的点一律列进 `reports/` 反哺点清单,用户在会话中裁决后归文档批落文)、「改动—验收对照表」(2026-10-11 立,2026-10-21 升级:每个需求点与每个行为改动都必须有真实入口断言和判据绑定面;无验收标准的需求点=卡片不成立,/iter 开工门同规拦截)与「落位与可复用性预检」必填节(2026-10-21 立:新增文件/函数/数据件前先核仓库既有实现,能复用不新增,落点唯一、禁散落 helper、跨层交互显式声明)、「实现规范预算」必填节(2026-10-27 迭代 39 实证立规:新增件接口块/成员面先对 gdstyle 默认阈值做预算——公开方法 ≤20、类变量 ≤15、迁移函数对账基线键,超了写卡段拆件,例外走显式申报+用户特批,禁把超预算面带进实现段)与「拆分边界纪律」结构类卡必填条款(2026-10-28 用户裁立:拆分边界沿职责轴不沿阈值轴——拆出单元须有职责语句/单一变化原因/集体身份,凑计数袋禁、阈值只作发现信号、拆不出内聚单元停卡呈报走豁免通道,判据权威=code-conventions §1.1)。任务卡 T0..Tn 的步骤写作遵循 superpowers:writing-plans 方法论(2026-10-19 起按本项目适配内联:卡前文件结构图/范围检查/任务右尺寸/步骤粒度/步骤内容四分/接口声明/禁行句式/自审六查)。复核门含判据出处锚逐行实读(2026-11-07 起;2026-11-09 内容锚改版后按索引实读——节名定位、行关键词命中行,核句子在位且内容匹配——机检 C5 核到关键词命中节内粒度、语义错位归实读)与引擎技术面三查(2026-11-04 起,godot-master 窄口径:NEVER/Gotchas/性能预算+按需领域 reference,权威仍在项目规范)。复核发现按四类去向处置(2026-11-05 立:自判=查规范或查代码有唯一答案,复核者自己改卡;补写=卡里漏写,回炉补全;待裁=多种做法都不违规且代价不同,才交用户;退回上游=文档线或美术线未闭合、或架构与代码规范本身冲突);卡片必带「复核记录」节(缺节=不成立,机检=pipeline_gate),复核先于提交、提交先于合回,顺序没走完禁对用户称完成。
|
||||
---
|
||||
|
||||
# 需求卡片写作规范(g-plan2)
|
||||
@@ -37,7 +37,7 @@ description: g-plan2(Dungeon Sweeper)仓库写需求卡片的固定流程与
|
||||
5. **范围边界**——做什么不做什么;明示不收件的去向(待办清单登记/后续批)。
|
||||
6. **关联文档同步面(必填,2026-10-17 改口径:实现批禁写文档)**——三列:文档|关联点(本批实现会改变它的哪条陈述)|同步义务。同步义务分三层标注:**设计权威文档**(GDD/art-bible)与**机械面文档**(roadmap 行/术语表/体验验证清单/README)对代码实现批**一律不直改**——实现批**禁写 `design/` 整个目录与根规则文件**,把该改哪一节、改成什么、依据是什么逐条列进 `reports/iter<N>-反哺点-<日期>.md`,由用户在会话中裁决后归文档批落文(不设文档 skill,文档靠会话讨论落地)。实现批唯一可写目录=`reports/`(2026-10-18 用户裁:根目录会话状态文件已废除,无任何例外)。写卡时就要把「实现会影响哪些文档的哪些说法」查全;查不出也要写「无关联文档」四字,不许省略本节。**机检(2026-10-18 卡片冲突修订批补)**=`tools/pipeline_gate.py` 判据 C1「文档义务口径」:同步面表内目标格指向 `design/`(含 `../gdd/` 等相对写法)或根规则文件、而义务格仍写「随批」者红——旧口径措辞「机械面随批」自 2026-10-17 起作废,写卡禁沿用;生效=文件名日期 ≥2026-10-17。
|
||||
7. **任务卡 T0..Tn**——逐卡估时;**末卡必含「产出物落位卡」**:轻闸全绿后、合并前,把 `reports/` 两份写齐——实现报告(各卡状态+实机目检总清单+遗留读数义务+实现决定记录)、反哺点清单(同步面所列每条都要有落点),方算收口。**禁把任何 `design/` 文件或根规则文件的编辑写进实现批的任务卡**(那是文档批的活)(AGENTS.md 批次工作流 §3.13)。(T 卡内步骤说明的写作纪律见下文「任务卡写作纪律」节,2026-10-19 立。)
|
||||
8. **验证闸(改动—验收对照表,2026-10-11 立,2026-10-21 升级;2026-10-28 判据口径换代)**——每个需求点列明验收测试内容;每个行为改动也要有一行。表列至少七格:需求点|改动(文件:行/行为)|验收测试(名称+落点+尾缀)|层级(单元/接口/集成/探针)|真实入口|判据绑定面|能力行(2026-10-29 起:`既有:<能力名>/新增:<能力名>`;两形态的名称都须在 `game/tests/README.md` 能力表在场,机检=pipeline_gate)。**能力行当场入表(2026-10-29 用户裁,废「滞后一个迭代」)**:写卡时同批维护能力清单(`game/tests/README.md`,四列=能力|系统|真实入口|代表用例)——本批新增能力当场增行(真实入口取自设计文档已定的入口;代表用例=本卡定死的计划测试 `文件:函数` 名);受影响存量行(入口/用例名变更)同批更新;能力退役删行。**实现照单落名**:测试函数名以清单为唯一依据,名实不符=本卡没写清=停卡退回;实现批禁写 README 的红线不变,批末收尾只核对表上名字与实际落地一致(改名则回表)。落点位置二选一:写在对应 T 卡里,或集中列在验证闸节逐条编号、由 T 卡交叉引用。**每个需求点至少一行;每行必须有真实入口和判据绑定面——缺任一项=该需求点未验收,卡片不成立**。**判据出处行锚(2026-11-05 起,对文件名日期不早于该日的卡生效)**:「需求点」格每行必须带判据出处行锚——该行验收判据所依据的现行文档句子,格式 `<文档相对路径>:<行号>`(如 `design/gdd/ux/camp.md:16`);已退役卡片不算现行文档;规格缺席写不出锚=停卡退回需求澄清(test-conventions §8.3,机检=pipeline_gate C5)。画面类需求的锚指向 ux/ 文档内嵌预览节的判据句(预览图=设计段已人审的目标画面效果图,也是实现批基线冻结时用户对照的参照——test-conventions §8.2)。**基线审核关卡特殊标注(2026-11-08 用户立)**:需求点触碰渲染黄金图基线(新增锚面/换代/迁移/容差修订)时,该行验收标准必须显式标注「触发基线审核关卡」——基线逐张呈报用户审核确认后才入库生效,T 卡步骤须含呈报审核点;漏标=复核门退回补写(test-conventions §8.2 审核关卡)。承接 AGENTS.md 硬红线「新功能必配新测试」:那条只兜「有没有」,本表兜「测得对不对、是不是钉在这个改动上」——写卡期不定稿,实现期就自由发挥。
|
||||
8. **验证闸(改动—验收对照表,2026-10-11 立,2026-10-21 升级;2026-10-28 判据口径换代)**——每个需求点列明验收测试内容;每个行为改动也要有一行。表列至少七格:需求点|改动(文件:行/行为)|验收测试(名称+落点+尾缀)|层级(单元/接口/集成/探针)|真实入口|判据绑定面|能力行(2026-10-29 起:`既有:<能力名>/新增:<能力名>`;两形态的名称都须在 `game/tests/README.md` 能力表在场,机检=pipeline_gate)。**能力行当场入表(2026-10-29 用户裁,废「滞后一个迭代」)**:写卡时同批维护能力清单(`game/tests/README.md`,四列=能力|系统|真实入口|代表用例)——本批新增能力当场增行(真实入口取自设计文档已定的入口;代表用例=本卡定死的计划测试 `文件:函数` 名);受影响存量行(入口/用例名变更)同批更新;能力退役删行。**实现照单落名**:测试函数名以清单为唯一依据,名实不符=本卡没写清=停卡退回;实现批禁写 README 的红线不变,批末收尾只核对表上名字与实际落地一致(改名则回表)。落点位置二选一:写在对应 T 卡里,或集中列在验证闸节逐条编号、由 T 卡交叉引用。**每个需求点至少一行;每行必须有真实入口和判据绑定面——缺任一项=该需求点未验收,卡片不成立**。**判据出处锚(2026-11-05 立;2026-11-09 用户裁内容化改版——内容节锚唯一形态,行号形态废止)**:「需求点」格每行必须带判据出处锚——该行验收判据所依据的现行文档句子,格式 `<文档相对路径>「节名」<行关键词>`(如 `design/ux/camp.md「Navigation Position」开始冒险`);节名=判据句所在节标题词(首段「·」前须命中目标文档标题行),行关键词=判据句上的无空白子串(须落在节块内);锚指向内容不指向行号,文档增删行不牵动卡片;已退役卡片不算现行文档;规格缺席写不出锚=停卡退回需求澄清(test-conventions §8.3,机检=pipeline_gate C5:内容锚形态唯一+节名在档+关键词命中节内,行号形态出现即红)。画面类需求的锚指向 ux/ 文档内嵌预览节的判据句(预览图=设计段已人审的目标画面效果图,也是实现批基线冻结时用户对照的参照——test-conventions §8.2)。**基线审核关卡特殊标注(2026-11-08 用户立)**:需求点触碰渲染黄金图基线(新增锚面/换代/迁移/容差修订)时,该行验收标准必须显式标注「触发基线审核关卡」——基线逐张呈报用户审核确认后才入库生效,T 卡步骤须含呈报审核点;漏标=复核门退回补写(test-conventions §8.2 审核关卡)。承接 AGENTS.md 硬红线「新功能必配新测试」:那条只兜「有没有」,本表兜「测得对不对、是不是钉在这个改动上」——写卡期不定稿,实现期就自由发挥。
|
||||
- **测试方式两分法**(2026-10-11 用户定):能力验证=调试接口直改游戏数据(改钥石/槽位/解锁状态等,不走正常资源积累流程,沿用现役 DebugOverlay/DS_DEBUG 门控);正常流程体验验证=用户目检,观测项写进 `reports/iter<N>-实现报告-<日期>.md` 的实机目检总清单(2026-10-17 起:`体验验证清单.md` 属设计文档,实现批禁写,入册该体验验证清单的条目作为反哺点由文档批落)。每张卡写明哪些点归调试接口验、哪些点归用户目检验。**用户目检一律「登记不阻塞」(2026-10-12 用户立规)**:登记完成即卡内义务了结,验收时间由用户自行安排,不得作为批末收尾、合并或下一迭代开工的前置条件。
|
||||
- **闸口径(2026-10-17 改按域;2026-10-26 判据改按文件性质)**:轻闸/重闸按 AGENTS.md 分级周期口径——**重闸=`tools/run_all_gates.sh` 按本批改动域选档**(改动含 `game/` 下非 `.md` 的行为载体 → `--code`;只有文档件——`game/` 内 `.md`、`design/`、根规则文件、`tools/` 工具脚本 → `--docs`;两类都有或改闸件本身 → 不带参数全量),所选域全绿才合并。**卡内禁写死闸件名单与"全量档"字样**(域划分的唯一出处在脚本里);批末四闸语义改述为「代码域闸全绿(冒烟+单元+探针+渲染/静态)+改前改后读数对拍」。改完即测铁规照履行:卡内改动落笔即测自己改过的那部分,不请示。
|
||||
- **回归措辞模板(2026-10-14 闸机轮次纪律,AGENTS.md 同源)**:禁用「每步对拍+全量回归」「每轮全量回归」类措辞——会被执行侧解读成每次修复跑全套;改用模板句:「里程碑步(波/T 段)出口跑一次全套闸;波内修复只做出红最小单元的最窄确认;新增测试/工具先行孤立验证再并入全套」。
|
||||
@@ -105,7 +105,7 @@ description: g-plan2(Dungeon Sweeper)仓库写需求卡片的固定流程与
|
||||
- 平实中文,禁自造缩写与名词堆叠;仓库既有术语照用。
|
||||
- 估时给区间+切分预案(超软盒预挂)。
|
||||
- **任务卡自审七查(2026-10-19 立五查,2026-10-21 补第六查,2026-10-27 补第七查;借自 superpowers:writing-plans 自审节适配)**:任务卡写完、交 grilling 复核前必跑——①规格覆盖:逐条过「目标与完成定义」的规格项/需求点,每条都能指到一张 T 卡,并指到验收对照表的一行,指不到的补卡/补行;②步骤扫描:每步只能让实施者写出一个合情合理的东西、且一步不多带——不决定事的行是缺口,签名与验收已定的函数体是抄写,两样都就地改;③类型一致性:后卡引用的签名/属性名与早卡定义逐字一致;④审查焦点+改动覆盖:规格暗示、但没有任何 T 卡测试覆盖的失败模式——对照「验证闸」节逐条过,把最可能坑到玩家的列出来、挂到责任 T 卡补验收条目;同时核文件结构图里的每个行为改动都能指到对照表行,指不到的补测试或标非行为改动;查完确实没有才写「无」;⑤篇幅比例:卡片比它实现的规格长几倍=在抄程序,代码块占大半就把函数体换成签名+断言名,再验每步仍无歧义;⑥落位与复用(2026-10-21 用户立规):逐条过本批每个新增文件、新增函数、新增数据件——**盘上是否已有做同样事的东西(grep 同职责实现、grep 同名与同义标识符)?该功能是否已有唯一落点?同一事实是否只在一处定义、有无 helper 散落「就近的文件」?新增件之间的调用路径与跨层出口是否显式声明?**答案写进卡内「落位与可复用性预检」节并与文件结构图对得上(标「新增」的必须能指到不能复用的理由);对不上就改成复用既有件、或把重复的落点并进唯一一处;⑦指标预算(2026-10-27 迭代 39 实证立规):逐条过本批每个新增文件——「实现规范预算」节三查一查的数字与接口块/文件结构图实数一致(数接口块 func 行、数成员 var 行、迁移函数逐个对 `tools/gdstyle_baseline.txt` 源键),少报、漏对账或预算节缺失的回炉补节,存量触面写明「S13 键只降不升」预期。七查发现问题就地改完再交复核,不用再自审一轮;自审在 grilling 之前跑,不替代 grilling 对抗复核。
|
||||
- **grilling 复核门(2026-10-10 用户立规;2026-11-05 补处置登记义务)**:卡片成文后必经 grilling 多轮复核,裁决全落、零待裁点,卡片才算成立;每轮发现与处置逐条写进卡内「复核记录」节(必备结构第 17 节)。**复核审点含验收清单:逐需求点过「测什么/怎么测/谁验」三问,答不上来的需求点回炉(2026-10-11 用户立规);并核对照表两端是否对得上、真实入口是否绕过改动点、判据绑定面是否绑被测改动特有的可观测提交面(2026-10-21 立);再核「落位与可复用性预检」节与文件结构图是否对得上——每个标「新增」的件都要有不能复用的理由与唯一落点,给不出的回炉改成复用(2026-10-21 用户立规);再核「实现规范预算」节数字与接口块/文件结构图实数一致——少报方法数、漏迁移函数对账、预算节缺失的回炉(2026-10-27 用户立规);再核「拆分边界纪律」条款在位、每个拆出单元有职责语句与集体身份——凑计数袋形态回炉(2026-10-28 用户立规);再核「验证闸」对照表每行**判据出处行锚逐行实读**(2026-11-07 用户立)——打开锚所指文档行,核句子在位且内容与该行判据匹配;机检 C5 只查存在性、查不出内容错位,写卡后文档被其他批改动会使锚漂移(2026-11-07 退役卡 ux 四锚漂移实证);锚失位=发现清单一条,按四类分流处置;再核引擎技术面三查(接口与边界见下条):①卡内签名与实装步骤涉及的 Godot API 在 4.7 存在且行为如卡所述;②实装步骤不踩 godot-master NEVER list 与 Gotchas;③热路径/批量/线程形态匹配其性能预算——产出发现清单,逐条按「复核发现四类分流」处置(2026-11-04 用户立规;2026-11-05 补去向口径:只有待裁类归用户裁决,自判与补写两类由复核者自己落卡,退回上游类退对应段)。**
|
||||
- **grilling 复核门(2026-10-10 用户立规;2026-11-05 补处置登记义务)**:卡片成文后必经 grilling 多轮复核,裁决全落、零待裁点,卡片才算成立;每轮发现与处置逐条写进卡内「复核记录」节(必备结构第 17 节)。**复核审点含验收清单:逐需求点过「测什么/怎么测/谁验」三问,答不上来的需求点回炉(2026-10-11 用户立规);并核对照表两端是否对得上、真实入口是否绕过改动点、判据绑定面是否绑被测改动特有的可观测提交面(2026-10-21 立);再核「落位与可复用性预检」节与文件结构图是否对得上——每个标「新增」的件都要有不能复用的理由与唯一落点,给不出的回炉改成复用(2026-10-21 用户立规);再核「实现规范预算」节数字与接口块/文件结构图实数一致——少报方法数、漏迁移函数对账、预算节缺失的回炉(2026-10-27 用户立规);再核「拆分边界纪律」条款在位、每个拆出单元有职责语句与集体身份——凑计数袋形态回炉(2026-10-28 用户立规);再核「验证闸」对照表每行**判据出处锚逐行实读**(2026-11-07 用户立)——按锚索引(节名定位、行关键词命中行)打开文档节句,核句子在位且内容与该行判据匹配;机检 C5 核到「关键词命中节内」粒度、查不出语义错位(句被改写而关键词仍为其子串时机器盲),实读兜语义;锚失位=发现清单一条,按四类分流处置;再核引擎技术面三查(接口与边界见下条):①卡内签名与实装步骤涉及的 Godot API 在 4.7 存在且行为如卡所述;②实装步骤不踩 godot-master NEVER list 与 Gotchas;③热路径/批量/线程形态匹配其性能预算——产出发现清单,逐条按「复核发现四类分流」处置(2026-11-04 用户立规;2026-11-05 补去向口径:只有待裁类归用户裁决,自判与补写两类由复核者自己落卡,退回上游类退对应段)。**
|
||||
- **引擎技术面复核接口(2026-11-04 立,godot-master 窄口径接入)**:本条是 req-card 对 godot-master 技能的唯一引用面,四条收窄——①取用白名单:只取其 SKILL.md 内三块——Part 4 NEVER list(33 条)、Part 8 Gotchas(8 条)、Part 5 性能预算表;卡涉及具体领域(物理/动画/UI/存档/寻路等)时另按其 Part 2 决策矩阵加载与改动面直接相关的 reference,至多 2 个;禁加载工作流链、genre 蓝图与其余整库。②权威边界:只取引擎事实(API 行为、已知坑、预算数字),不取其工程组织主张(目录结构、autoload/signal bus 模式)——架构/分层/数值判断权威仍是本项目 architecture.md、code-conventions 与 data/tables;两者冲突时项目规范赢,冲突本身当轮作为待裁点呈报用户,禁按任一方默默改卡。③输出形态:复核产出=发现清单(卡内位置+违反条目号如 NEVER-7/Gotcha-1+一句依据)+四类去向之一,其中待裁与退回上游两类不改写方案,自判与补写两类的处置就是把卡改对;引用条目须给编号,判不了标「未判」禁硬判。④成本约束:成本地板=hub SKILL.md 单文件;卡内 T 步不含节点/信号/Tween/Resource/物理/线程/渲染面时只跑②清单对照,不加载领域 reference;每个领域 reference 一轮复核只加载一次。
|
||||
- **复核发现四类分流(2026-11-05 用户立规)**:复核者每拿到一条发现,先问「答案从哪来」,四选一登记去向(写进卡内「复核记录」节的去向格);前两类的处置由复核者自己完成,禁转成问句向用户求裁:
|
||||
- **自判**——查权威文档或查代码现状就能得到唯一答案。权威文档=本卡设计事实源那一份 owner 文档+`design/engineering/` 五份规约与 architecture+术语表+在册先例(git 提交信息与库内已入库实现)。处置=复核者当场下结论并把卡改成那个答案,处置格写结论+`文件:行号` 依据。**禁问用户**:这类问题问出去等于把可查的事推给人决策。
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
| 概念切分与互链 | `design/engineering/concept-conventions.md`——概念封装 / 跨文档引用 / 归档与事实源 |
|
||||
| 系统设计 / 增删文档 | `design/gdd/02-系统清单.md`——根索引 + 中文规范名↔英文代号对照 |
|
||||
| 架构(唯一事实源) | `design/engineering/architecture/architecture.md`(只写依赖规则面:分层/目录归属/数据流/架构原则;模块级归属归代码头注,闸清单归 `game/tests/README.md`)——历史决策沿革查 git commit log,不另设决策文档;修订须用户发令 |
|
||||
| 术语与已锁数值 | 规范名与定义 = `design/gdd/术语表.md`(全库唯一对照表,仅 owner 文档可修订);现行数值 = `game/data/tables/*.tres`;规则(概念面)= 各系统 owner 文档;取值域与字段契约 = `game/data/schemas/*.gd`。冲突须显式提出,禁默默改值 |
|
||||
| 术语与已锁数值 | 规范名与定义 = `design/gdd/术语表.md`(全库唯一对照表,仅 owner 文档可修订);现行数值 = `game/data/tables/*.tres`;玩家可见文案 = `game/data/l10n/strings.csv`(key→文案,细则 = code-conventions §2.5);规则(概念面)= 各系统 owner 文档;取值域与字段契约 = `game/data/schemas/*.gd`。冲突须显式提出,禁默默改值 |
|
||||
| 现在做什么 / 待办与待裁 | 根 `roadmap.md` 顶部「当前位」节+迭代总表六列 · 待办唯一登记处 `待办清单.md` · 批次过程与结论查 git 提交信息与 `reports/` |
|
||||
|
||||
## 回答风格规则(只管对话输出;文档写作归 doc-conventions §2–§4)
|
||||
@@ -105,7 +105,7 @@
|
||||
|
||||
## 硬性红线(勿违反;操作细则在 process-conventions.md 与各规约)
|
||||
|
||||
- 车道铁律(2026-10-31 用户裁恢复)——主工作区只作合并落点,一切开发/设计改动走独立 worktree:`git worktree add ../g-plan2-<任务名> -b <任务分支>`(建区即跑 `tools/setup_worktree_userdir.sh`),收口=冻结→件核→并 master→重塑→主区 `git merge --no-ff`→删区(合回即删,2026-09-19 原裁),CI 红不回滚合并——新开修复 worktree(`fix-<任务名>` 分支,免重塑免数卡)修复合回追绿;会话单区(2026-11-04 用户裁)——同一时刻每会话至多一个 worktree 在役,同会话追加事项并入在役区、只做一次合入(一次 CI),合回后用户再发令=新回合另开区,迭代实现批独占回合(细则见 process-conventions §1 第 5 条);主区唯一合法写动作=合并,agent 侧由 worktree-guard 拦主区 Edit/Write 与一切 git commit;豁免面仅 `.zcode/`、`.qoder/`(不入 git,主区直改);commit 点零钩子检查(pre-commit 直改闸已退役);合回 merge 点另有前置检查钩子(pre-merge-commit,2026-11-06 用户裁,见「运行与验证」首条);全量验证归合回后远端 CI(post-merge 钩子推送触发,见「运行与验证」首条);`--no-verify` 仅属用户,agent 禁用(细则见 process-conventions §1)
|
||||
- 车道铁律(2026-10-31 用户裁恢复)——主工作区只作合并落点,一切开发/设计改动走独立 worktree:`git worktree add ../g-plan2-<任务名> -b <任务分支>`(建区即跑 `tools/setup_worktree_userdir.sh`),收口=冻结→件核→并 master→重塑→主区 `git merge --no-ff`→删区(合回即删,2026-09-19 原裁),CI 红不回滚合并——新开修复 worktree(`fix-<任务名>` 分支,免重塑免数卡)修复合回追绿;会话单区(2026-11-04 用户裁)——同一时刻每会话至多一个 worktree 在役,同会话追加事项并入在役区、只做一次合入(一次 CI),合回后用户再发令=新回合另开区,迭代实现批独占回合(细则见 process-conventions §1 第 5 条);主区唯一合法写动作=合并,agent 侧由 worktree-guard 拦主区 Edit/Write 与一切 git commit;豁免面仅未入库目录(`.zcode/plans/`、`.zcode/tmp/` 与 `.zcodeignore`——被 .gitignore 在排、检出区里不存在,只能主区直改);`.zcode/` 其余件(skills、hooks)与 `.qoder/` 均已入 git(`git ls-files` 在册可核),改动同走本车道;commit 点零钩子检查(pre-commit 直改闸已退役);合回 merge 点另有前置检查钩子(pre-merge-commit,2026-11-06 用户裁,见「运行与验证」首条);全量验证归合回后远端 CI(post-merge 钩子推送触发,见「运行与验证」首条);`--no-verify` 仅属用户,agent 禁用(细则见 process-conventions §1)
|
||||
- **仓库根禁止设会话状态文件**(`active.md` 已废除)——现状看 roadmap「当前位」,待办看待办清单,过程看 git 提交信息,产出物看 `reports/`;任何文档禁止另设「当前状态快照」节,两处记同一件事必然漂移(细则见 doc-conventions 第 10 节)
|
||||
- **改完即测铁规(2026-11-05 用户裁,取代原「测试执行两入口铁规」)**——任何会话里的任何改动,落笔之后立刻跑一遍覆盖该改动面的验证并跑绿、读数写进这一步的提交信息,这一步才算完成;验证载体一律按 `tools/run_all_gates.sh` 的域划分与该件自身的直跑方式,不扩出改动面、不请示、不等点名,未改动的面不测,合回后远端 CI 的全量跑批不替代本条。读数类采集(MC/verifier)不在该域划分内,不属本条义务
|
||||
- **红账不清不开新批**——上一批远端跑批有真红未闭合不开新批;假红(导入缓存、user 目录未隔离那类在册环境坑)走异常分级处置,不算未闭合
|
||||
@@ -121,6 +121,7 @@
|
||||
- 真人检测只登记不阻塞——登记进体验验证清单/实现报告即完成义务,禁以等目检为停工理由或当作合回的前置条件
|
||||
- 文件头 = `##` 文档注释,介绍本模块是什么;禁写变更叙事(改动史查 git log);禁文档反向链接(code-conventions §1.4.1)
|
||||
- 数值单一事实源——玩法数值只存 `data/tables/`(.tres)经 ConfigDB 单点读取;禁数值字面量与自建 `load()` 表路径
|
||||
- 文案单一事实源——玩家可见文案值只存 `data/l10n/strings.csv`(key→文案),数据表行与代码只持文案 key、取文案只经 `tr()`/`atr()`;禁文案字面量与文案入数值表;诊断日志豁免(细则 = code-conventions §2.5)
|
||||
- RNG 单点——禁 `randomize()`/自建 RandomNumberGenerator,随机只经 `RngService` 统一流
|
||||
- 架构事实唯一源——架构事实只认 `design/engineering/architecture/architecture.md`(只写依赖规则面:分层/目录归属/数据流/架构原则;模块级归属归代码头注);禁立第二架构文档或决策文档体系,历史决策记录只进 git commit log;架构文档写权限=用户专属,agent 与技能只读(2026-11-07 用户裁)
|
||||
- Core 层零 UI 依赖——完整战斗必须可 `--headless --script` 跑通;fail-fast——数据校验错误一律致命中止,无软回退
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
> **性质**:表现层升级批与战斗表现批的生产侧清单——把散在战斗表现 / HUD框架 / 关卡节点地图 / 敌人系统里的资产需求收拢成一张可执行的工单视图,**兼资产维度单一登记处**。**规范效力归各 owner 文档**(战斗表现、美术圣经、04-美术音频方向),本文只补「生产视角的需求规格」,冲突时以 owner 文档为准。
|
||||
> **建立**:场景一(战斗画面呈现)讨论产物;本文为唯一清单。历次修订明细见 git 提交史。
|
||||
> **更新纪律**:各条目「现状」行顺带更新(未开始 / 候选已出 / 已裁决 / 已交付);做完不删条目,改状态。与待办清单的联动:本文是资产维度明细,待办清单只留指路存根。
|
||||
> **状态**:现行为 v1.0(2026-11-01)。
|
||||
|
||||
## 0. 生产渠道、规格与风格宪法
|
||||
|
||||
@@ -94,7 +95,7 @@
|
||||
- **风格/规格**:三档在**灰度/剪影层也可辨**(双通道纪律);每档动画时长与结算节拍对齐(预告时序 = 下一拍、挖掘期全程可见)。
|
||||
- **联动**:HUD框架「意图徽标不预告技能名与数值」条款由本拍板承接为动画承载(文字与技能名彻底退出);战斗表现「特殊技两型动画」输入清单按三档改写;映射按 enemy_id 全局恒定(跨 run 禁重掷);契约锚 = art-bible §4.6.4 意图姿态行。
|
||||
- **来源**:✦/⚙ 自产——三档表演层挂在我们自己的精灵图上,动画本体不可复用;通用蓄力/施法光效素材(♻)仅可作参考与粒子底料,过复用闸。
|
||||
- **现状**:占位符号已落地(普通攻击「—」/ ⚔ / ✦ / 重击类「蓄力」,技能名退出徽标);终稿动画待样张后开工。
|
||||
- **现状**:占位符号已落地(普通攻击「—」/ 伤害技 ⚔ / 增益技 ✦ / 妨害技 ☠——攻击系内部分档不作预告,重击与普通伤害技同呈现,技能名退出徽标);终稿动画待样张后开工。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
> **性质**:美术圣经 §5(角色设计)的独立承载文档——**人设高频改动、独立成档免动圣经**;圣经 §5 自此为引用存根指向本文件,**小节号 §5.1–§5.6 沿用不变**(跨文档引用经圣经 §5 存根仍可达,新引用直指本文件)。
|
||||
> **边界**:本文件只定角色呈现;角色承载的机制语义(护甲克制矩阵、技能与状态)以 GDD 为准(敌人系统/增益状态/战斗结算)。色彩系统、形状语言总纲引用美术圣经 [art-bible](art-bible.md) §4/§3,冲突以圣经为准。提示词执行侧(可直贴串)归 [art-prompts](art-prompts.md),本文件是它的规格上游。
|
||||
> **状态**:现行为 v1.0(2026-11-01)。
|
||||
|
||||
---
|
||||
|
||||
@@ -21,7 +22,7 @@
|
||||
## 5.2 头身比与体量档位
|
||||
|
||||
- **头身比**:全角色 2~3 头身(chibi)两档——小人剪影须在两档下均成立(§5.1);敌种按 archetype 取档,同一敌种恒定一档(enemy_id 键恒定纪律,圣经 §4.6.4)。←风格基调
|
||||
- **体量档位 = 生物体型通道(原「强度先验·普通 < 精英 < Boss 单调递增」读法已弃用)**:体量按**物种天性**定,禁按强度档位线性映射——小体型精英与大体型普通怪并存(锁定实例:钩爪恐魔 > 灰矮人、灰矮人 < 熊地精、食人魔酋长 > 熊地精);「大个子多半有重击」的强度先验读法改由意图徽标(§5.6)与甲档(§5.3)承担,体量不再报强度;图像不报数,精确数值只在结算明细。
|
||||
- **体量档位 = 生物体型通道(原「强度先验·普通 < 精英 < Boss 单调递增」读法已弃用)**:体量按**物种天性**定,禁按强度档位线性映射——小体型精英与大体型普通怪并存(锁定实例:钩爪恐魔 > 灰矮人、灰矮人 < 熊地精、食人魔酋长 > 熊地精);「大个子多半有重击」的强度先验读法改由意图准备动画(§5.6)与甲档(§5.3)承担,体量不再报强度;图像不报数,精确数值只在结算明细。
|
||||
- 像素画布/精灵尺寸**不在本节**——归圣经 §8 资产规范;本节只锁比例关系与档位次序。
|
||||
|
||||
## 5.3 护甲类型视觉区分
|
||||
@@ -77,6 +78,6 @@
|
||||
- **三档**:① 普通攻击 = 常态待机(待机即预示,零独立资产);② 攻击技能 = 特殊准备动画(放光/高举武器等"摇号感"动作);③ 重击/硬化类 = 蓄力动作或防御姿态。
|
||||
- **双通道纪律**:三档在灰度/剪影层可辨(色弱安全,圣经 §4.5 同款要求)。
|
||||
- **呈现纪律**:不显示文字与技能名(文字与技能名彻底退出预告);映射按 enemy_id **全局恒定、跨 run 禁重掷**;预告时序 = 下一拍,挖掘期全程可见,结算不另设独立意图播片。契约锚 = 圣经 §4.6.4 意图姿态行。
|
||||
- **终稿帧规格**(帧数/时长/结算节拍对齐)归圣经 §8 资产规范与战斗一屏样张(清单 §2.3);占位符号(—/⚔/✦/蓄力)现行使用,动画到位后原位替换。
|
||||
- **终稿帧规格**(帧数/时长/结算节拍对齐)归圣经 §8 资产规范与战斗一屏样张(清单 §2.3);占位符号(—/伤害技 ⚔/增益技 ✦/妨害技 ☠——攻击系内部分档不作预告)现行使用,动画到位后原位替换。
|
||||
|
||||
---
|
||||
@@ -0,0 +1,32 @@
|
||||
# 冒险前资源配比预设退役素材库
|
||||
|
||||
> 所属线=跨局循环(元进度·冒险开始参数面)。退役内容留底(活文档,落 `design/content-archive/`,身份判据见 doc-conventions §11)。来源=原待办清单「冒险前资源配比预设(构筑提案)」条(2026-09-18 登记,来源=会话提及)。
|
||||
> 用途:已退役的构筑提案留底,供日后重新过准入时查证。本文件不是待办——不排期、不占迭代;重启须用户发令立项,按现行元进度与冒险开始参数面口径重走设计讨论,不默认继承原案。
|
||||
|
||||
## 原案
|
||||
|
||||
**机制**:[元进度](../gdd/systems/跨局循环/元进度.md)「冒险开始参数面与覆盖值通道」——零新机制。玩家在冒险开始前调整资源配比,经既有参数面注入开局。
|
||||
|
||||
**裁决与挂起**:八项裁决 2026-10-04 全裁;2026-10-05 起挂起,重启须用户另行发令。立项提案与需求卡片已于 2026-11-04 按用户令删除,八项裁决与全案依据随件入 git 历史可考。
|
||||
|
||||
**原启用条件**:用户发令重启(挂起冻结期内零动作);原条带两条特批——〔用户特批 2026-11-04 退役卡片与提案回退待写卡〕〔用户特批 2026-11-05 后置 Beta——Alpha 阶段不排期〕。
|
||||
|
||||
**原状态**:文档设计已闭合+待写卡(备选)。原改动面=文档。
|
||||
|
||||
**原关联文档清单**:
|
||||
- [元进度](../gdd/systems/跨局循环/元进度.md)(设计闭合凭据;现行 v1.25 已复核在役)
|
||||
- [地图战斗资源](../gdd/systems/战斗循环/地图战斗资源.md)(基础配比的权重覆盖语义)与 [元进度](../gdd/systems/跨局循环/元进度.md)(解锁容量与注入生产者)共裁
|
||||
- 呈现面归 [HUD 框架](../gdd/systems/表现与支撑/HUD框架.md) 与 [教学引导](../gdd/systems/表现与支撑/教学引导.md)
|
||||
|
||||
## 交汇面(原锻造工坊边界条留底)
|
||||
|
||||
原 [锻造工坊](../gdd/systems/跨局循环/锻造工坊.md)「与相邻系统的边界」节为该批挂了两处重启核对项,随提案退役一并迁此留底:
|
||||
|
||||
1. 预算包络是否把武器类型计入克制注。
|
||||
2. 容量柜台与锻造工坊工作间(同在营地)的资源竞争关系。
|
||||
|
||||
原条口径=本设计不预设该批的重启口径、不占用其任何冻结裁决、不改其冻结文本。
|
||||
|
||||
## 退役裁定
|
||||
|
||||
2026-11-09 用户裁「这个东西现在也不做了」——Alpha 与 Beta 均不做;待办清单条目整条删除,[08-Alpha版本标准](../gdd/08-Alpha版本标准.md)「六 · Alpha 不含」条与锻造工坊边界条改指本文件。现行事实源仍为 [元进度](../gdd/systems/跨局循环/元进度.md) 与 [08-Alpha版本标准](../gdd/08-Alpha版本标准.md);本文件不构成现行设计,不得据此开卡、不得据此重启。
|
||||
@@ -0,0 +1,14 @@
|
||||
# 格面资源池退役素材库
|
||||
|
||||
> 所属线=地图战斗资源(格面资源池)。退役内容留底(活文档,落 `design/content-archive/`,身份判据见 doc-conventions §11)。来源=原待办清单「袋装摇号」条(2026-10-07 登记,来源=会话提及)。
|
||||
> 用途:已退役的格面资源池结构备选留底,供日后重新过准入时查证。本文件不是待办——不排期、不占迭代;重启任何一件须用户发令立项,按现行摇号结构与保底口径重走设计讨论,不默认继承原案。
|
||||
|
||||
## 袋装摇号(格面资源池结构备选)
|
||||
|
||||
**原案**:装板时按各档配额数好牌再洗开发放,一格发一张;相对现行「逐格摇号 + 摇完整板校验补签」,保底天然成立、各档分布精确。
|
||||
|
||||
**原启用条件**:保底登记型增多、补签逻辑复杂化时。
|
||||
|
||||
**代价**:摇号结构重写;订阅加权与 board_skew 两路权重投影须改为按袋面张数投影。
|
||||
|
||||
**退役裁定**:2026-11-09 用户裁——Alpha 阶段与 Beta 阶段均不做,待办清单条目删除,想法只在此留底。现行结构继续以 [地图战斗资源](../gdd/systems/战斗循环/地图战斗资源.md)「四档概率结构与保底」节为事实源;本文件不构成现行设计,不得据此开卡。
|
||||
@@ -56,6 +56,9 @@
|
||||
### 2.4 状态字段语义显式
|
||||
跨战斗/跨场景携带或恢复的状态字段,其语义来源必须显式(表值 / 明确入参),禁止用入参隐式定义。
|
||||
|
||||
### 2.5 玩家可见文案承载——key 单点,文案值住翻译文件
|
||||
玩家看得见的文字(界面标签、toast、明细行显示名、卡面摘要等)一律两件分离:**文案值只住 `game/data/l10n/strings.csv`**(key 列+`zh_CN` 列,加语言=加列),代码与数据表行只持**文案 key**(全库唯一,点分命名如 `clear_reward.title`);取文案只经 `tr()`(Node 语境)/`atr()`(非 Node 语境),禁在 `.gd`/`.tscn` 内联写死文案字串,禁把文案值塞进 `data/tables/*.tres`(数值表只管数值)。场景静态 `text` 按 key 写入、经 Godot 场景自动翻译解析;数据表文案字段更名 `display_key`/`desc_key`(值域=文案 key,不是文案本身)。豁免面:开发者诊断文字(`push_error`/`assert`/日志)与 `game/sim`/`game/probe`/`game/tests` 的文字不属玩家可见面,不受本条约束。
|
||||
|
||||
---
|
||||
|
||||
## 3. 测试纪律
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|---|---|---|---|
|
||||
| 一·登记 | 无(闸管格式) | 待办清单条目 | 条目=标题登记元数据(日期/来源/可选优先级)+正文四属性(实况/缺口/改动面/状态);标题登记后不再变,正文随进程演进。格式与状态机权威=doc-conventions 第 12 节 |
|
||||
| 二·文档设计/美术设计 | doc-design(文档线,兼任反哺点写入)/asset-ingest(美术录入;样张素材由用户主导产出) | GDD 文档或 art-bible/过审样张素材;画面类需求另出预览图(文档线,2026-11-05 用户裁) | 用户提起或从待办清单取出;会话内进行、用户主导、禁无监管自跑;经用户点头确认心智一致才许写入文档;完成判据=待裁点清零,带未裁点的是讨论稿;设计线闭合凭据记入待办清单实况清单(文档线=文档路径+版本号,美术线=art-bible 条款版本);缺哪条线写在缺口属性,闭合与否写在状态段。画面类需求(新增画面要素/布局/配色/动效等触碰画面呈现规格的改动)设计段先出预览图=目标画面的 HTML/SVG 效果图(diagram-design 通道,AGENTS.md 图优先的同款载体),经用户人审通过才许进写卡段;预览图内嵌对应 ux/ 规格文档并随附像素级视觉判据句(§7 第 2 条同款写法);缺陷修复以现行规格与在库基线为准,不触发新预览 |
|
||||
| 三·写需求卡片 | req-card | 需求卡片 | 设计线闭合后用户发令;新玩法/新系统/新内容必须有设计定稿前置,例外=需求性工程条目(缺陷修复/重构等改游戏行为)凭实况里的证据指认跳过设计线;配套维护类(工程债/测试基建/工具维护,不动游戏行为)=工程改动直改类,不走本段,由用户发令直改;卡片必经 grilling 多轮复核、零待裁点才成立;复核发现按四类去向处置(2026-11-05 用户立规,定义在 req-card 技能「复核发现四类分流」:自判=查权威文档或查代码现状有唯一答案,复核者自己下结论改卡;补写=卡里漏写,回炉补全;待裁=几种做法都不违规且代价不同、影响玩法取向,才交用户;退回上游=文档设计线未闭合、美术设计线未闭合、或架构与代码规范本身冲突,停笔退对应段);成立凭据=卡内「复核记录」节(2026-11-06 用户裁:不另设复核报告文件),顺序未走完禁对用户称完成、禁落 commit(同 §1 第 2 条卡片复核前置判据);写完在待办清单状态记「已写卡」,卡片路径记入实况清单(防遗忘);画面类需求卡片必引设计段已人审的预览图(验收判据的判据出处行锚指向 ux/ 内嵌预览节,test-conventions §8.3 锚口径不变) |
|
||||
| 三·写需求卡片 | req-card | 需求卡片 | 设计线闭合后用户发令;新玩法/新系统/新内容必须有设计定稿前置,例外=需求性工程条目(缺陷修复/重构等改游戏行为)凭实况里的证据指认跳过设计线;配套维护类(工程债/测试基建/工具维护,不动游戏行为)=工程改动直改类,不走本段,由用户发令直改;卡片必经 grilling 多轮复核、零待裁点才成立;复核发现按四类去向处置(2026-11-05 用户立规,定义在 req-card 技能「复核发现四类分流」:自判=查权威文档或查代码现状有唯一答案,复核者自己下结论改卡;补写=卡里漏写,回炉补全;待裁=几种做法都不违规且代价不同、影响玩法取向,才交用户;退回上游=文档设计线未闭合、美术设计线未闭合、或架构与代码规范本身冲突,停笔退对应段);成立凭据=卡内「复核记录」节(2026-11-06 用户裁:不另设复核报告文件),顺序未走完禁对用户称完成、禁落 commit(同 §1 第 2 条卡片复核前置判据);写完在待办清单状态记「已写卡」,卡片路径记入实况清单(防遗忘);画面类需求卡片必引设计段已人审的预览图(验收判据的判据出处锚指向 ux/ 内嵌预览节,test-conventions §8.3 锚口径不变) |
|
||||
| 四·迭代编排 | iter-plan | roadmap 迭代行 | **开工前预检(2026-11-07 用户立)**:收令点名拟编卡集后、五查与落表前,对卡集做一轮只读事实面预检——八类检查、P1/P2/P3 分级去向与只读子代理执行方式=iter-plan 技能「第 3 步·开工前预检」;P1 红项停编排、退回写卡段,禁编入。预检目标=尽量减少实现期停工、非杜绝——环境漂移与卡片并行修改仍可在实现期停工,由实现段异常分级与 iter T0 开工日窄复核兜底。编排五查:①每卡卡片文件存在 ②每卡设计闭合凭据齐(或需求性工程条目的证据指认)③估时与冻结线——所选卡估时按区间**中值**求和(单位工作日、写精确值不取整):**卡片任何工作量均可编入**(2026-10-25 用户立:工作量限制属迭代层、非卡片层);编入后迭代总量 <5 个工作日=迭代行状态「冻结待凑批」、不可开工,凑批 ≥5 后由编排段改「待开工」(迭代体量偏好,2026-10-21 用户立、2026-10-25 改冻结制);5–10 个工作日为常规区间;超过 10 个工作日须经用户确认(确认前呈报整批/拆批两案等裁,禁自行拆分或塞入),确认后迭代行随带日期特批标记;超过 20 个工作日禁止编(硬上限,用户确认也不放行,必须拆批)④每卡复核记录在位(2026-11-05 用户立规;2026-11-06 用户裁凭据换代——复核凭据=「复核记录」节自身,不另查报告文件)——卡内有「复核记录」节;缺节或节内任一条发现没有去向标记则呈报退回写卡段,禁编入,本段不代跑复核也不代补记录(生效=卡片文件名日期 ≥2026-11-06,旧卡不回头改)⑤写完 roadmap 行后跑流水线闸确认绿;编入未完成迭代,新开迭代行经用户确认 |
|
||||
| 五·实现 | iter | 代码与配置,可运行的游戏 | 需求卡片永不单独施工,统一由用户指定迭代号触发(=U0 开工令),按 iter 技能与本文 §3 执行;**本段是代码实现批:禁写 `design/` 与根规则文件,产出物只落 `reports/`(见 §3 第 12 条)**;设计权威文档(GDD/art-bible)批内一律不更新;完成人闸=实机目检清单+实现决定记录写齐即完成批内义务;画面类需求实现批另按 test-conventions §8.2 黄金图基线冻结口径执行(实跑截图入基线前用户逐张审核确认+审核记录落档,此后渲染闸自动盯);**golden 基线改动批(含非卡片批的迁移/重构/容差修订)merge 前须用户审核通过(test-conventions §8.2 审核关卡),未审核的基线禁合回** |
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# 测试规范(Dungeon Sweeper)
|
||||
|
||||
> 现行为 v1.0(2026-11-09)
|
||||
> 约束范围:`game/probe/ 与 game/sim/`、`game/tests/` 与一切场景探针的编写与验收。
|
||||
> 分工:测试**执行义务**(改完必须测什么)归 AGENTS.md「硬性红线·改完即测铁规」与 `process-conventions.md` §4;**跑什么闸、什么顺序**归 `tools/run_all_gates.sh`(脚本即清单,本文与 AGENTS.md 均不另列);本文管测试怎么写、怎么算合格。每件测试工具**是什么、判什么、怎么单独跑、什么时候适合单独用**——见 `game/tests/README.md`(测试工具手册),本文不重复工具介绍。
|
||||
> 归属:随游戏逻辑写/改的测试=需求改动的一部分(随需求卡片同批落地);不伴随逻辑改动的纯测试维护=工程改动(不写卡,用户发令直改)。
|
||||
@@ -34,7 +35,7 @@
|
||||
|
||||
凡模态覆盖层,探针必须断言:打开后自身 visible 且遮挡物已隐藏(模态被遮挡 = 功能存在但不可达)。
|
||||
|
||||
**UI 驱动断言须走真输入管线(2026-11-06 立)**:探针里「点按钮/点场景物件」类驱动断言,一律经引擎输入管线承载(合成 InputEvent 走 `push_input`,press+release 成对;合成滚轮同样必须 press+release 成对——只发 press 会把鼠标焦点钉死在按下点控件上,后续点击全部失效);信号直发(`pressed.emit()` 等)绕过命中测试,保不了「玩家点击可达」,只许用于真输入到不了的面并当场标〔接线断言〕(现役例:置灰态穿透钉处理器兜底)。折叠区控件先以真输入滚轮滚入可视区再点。每个动线断言钉「落点」判定(点了之后到哪个屏/哪层可见),防驱动中断后的空转假绿。真输入命中控件时自动登记控件覆盖(探针共用面登记件落 `.gates/` 观测产物),覆盖面生长不靠人记。
|
||||
**UI 驱动断言两段式:先接线、后真输入(2026-11-06 立;2026-11-09 用户裁两段式)**:探针里「点按钮/点场景物件」类驱动断言按先后两段执行——**第一段接线断言**:信号直发(`pressed.emit()` 等)验证信号接线与处理器逻辑,快速失败(接线不通即红,不必等真输入段定位);**第二段真输入断言**:经引擎输入管线承载(合成 InputEvent 走 `push_input`,press+release 成对;合成滚轮同样必须 press+release 成对——只发 press 会把鼠标焦点钉死在按下点控件上,后续点击全部失效),验证玩家点击可达。真输入绕过不得——信号直发绕过命中测试,保不了「玩家点击可达」;真实入口只认第二段(§8.3 口径不变),第一段不充当能力行的真实入口。真输入到不了的面(现役例:置灰态穿透钉处理器兜底)止于第一段并当场标〔接线断言〕。折叠区控件先以真输入滚轮滚入可视区再点。每个动线断言钉「落点」判定(点了之后到哪个屏/哪层可见),防驱动中断后的空转假绿。真输入命中控件时自动登记控件覆盖(探针共用面登记件落 `.gates/` 观测产物),覆盖面生长不靠人记。
|
||||
|
||||
## 3. 缺陷修复必须沉淀回归断言
|
||||
|
||||
@@ -62,7 +63,7 @@
|
||||
| 重放 | 同种子断点回放、改前改后配对 |
|
||||
| 状态/计数器断言 | 条件解锁、限次、充能——置数据→走路径→断计数值 |
|
||||
|
||||
4. **调试注入两层(能力测试与流程体验两分法的落码面)**:自动化测试=测试代码直调核心层写口构造状态(直改数据表行/计数器/存档域,不经 UI、不走正常资源积累流程——冒烟现役做法);人工体验=DebugOverlay/DS_DEBUG 调试面,服务用户目检(发布态该面恒隐、无 UI 开启口,开发期临时启用=本地改 `_debug_entry` 缺省、不提交;能力测试不经 UI,本条口径不受影响)。清单条目的「怎么测」必须写到数据面粒度:改哪张表哪行、置哪个计数、调哪个核心写口。
|
||||
4. **调试注入两层(能力测试与流程体验两分法的落码面)**:自动化测试=测试代码直调核心层写口构造状态(直改数据表行/计数器/存档域,不经 UI、不走正常资源积累流程——冒烟现役做法);人工体验=DebugOverlay 调试面,服务用户目检(2026-11-09 用户裁:调试入口常驻——「调试」角标恒亮、浮窗经角标真点开启;能力测试不经 UI,本条口径不受影响)。清单条目的「怎么测」必须写到数据面粒度:改哪张表哪行、置哪个计数、调哪个核心写口。
|
||||
5. **换代批旧验证约束同生死**:删除旧数据行/旧实现代码的批次,必须同批摘除只验证旧实现的断言与护栏校验,由新断言替代——旧件断言残留=冒烟假绿来源;合并后冒烟全绿且全仓无旧件残留引用为证。
|
||||
6. **违约通道类需求点必须落独立负面套件(2026-10-28 立)**:预期运行期违约/致命路径的需求点(handler 通道、fail-fast 分支)一律落独立负面套件并按 manifest 登记 `expect=1, negative=true`,禁落现役非负面套件——headless 下 assert 失败必产不可捕获的 SCRIPT ERROR,非负面套件的输出被错误扫描命中即假红(先例=reward_dangling_treasure/counter_prefix_fatal/extended_row_violation/run_time_fatal 四件)。
|
||||
|
||||
@@ -97,7 +98,7 @@
|
||||
- **接口**:模块边界的公开契约——数据表加载、存档与断点、事件载荷、命令接口;测试从公开入口进出。接口级断言随单元套件落(`unit/contracts/`),不另设承载目录。
|
||||
- **跨宿主**:跨宿主的接线、持久、生命周期——例如 LevelRunner 把 level_counters 传给 BattleOrchestrator、两场战斗共享同一个桶、断点续玩;测试必须实例化真实宿主链,禁止用裸 EffectEngine 代替。断言载体归单元层跨系统闭环套件(§1.1 三元组表),验收入口不变。
|
||||
- **探针/golden**:玩家可达性与观感;真实实例化场景、驱动真实输入。
|
||||
- **golden 测试项扩项(2026-11-05 立)**:触碰画面呈现规格的需求批(新增画面要素/布局/配色/动效;判据=设计段出了预览图),实现段把该画面纳入渲染闸机器面:截图采集清单扩项+实跑截图冻结进 `game/tests/golden/`(基线属入库测试资产,render_gate.sh 在册例外)。黄金图=游戏真实渲染截屏冻结的逐像素基准,比对器与容差口径见 render_gate.sh 头注释(脚本即清单,本文不另列)。基线冻结(新建与换代同口径)=**用户逐张审核确认后执行**,触发原因写进当批提交说明(`tools/golden_baseline_refresh.sh` 现役义务);此后渲染闸逐像素自动盯、零人工。预览图(HTML/SVG 效果图)与引擎渲染是两套管线,禁直接充当比对基线——预览图只作人审参照与验收判据句的出处(判据出处行锚指向 ux/ 内嵌预览节);缺陷修复以现行规格与在库基线为准,不触发新预览。
|
||||
- **golden 测试项扩项(2026-11-05 立)**:触碰画面呈现规格的需求批(新增画面要素/布局/配色/动效;判据=设计段出了预览图),实现段把该画面纳入渲染闸机器面:截图采集清单扩项+实跑截图冻结进 `game/tests/golden/`(基线属入库测试资产,render_gate.sh 在册例外)。黄金图=游戏真实渲染截屏冻结的逐像素基准,比对器与容差口径见 render_gate.sh 头注释(脚本即清单,本文不另列)。基线冻结(新建与换代同口径)=**用户逐张审核确认后执行**,触发原因写进当批提交说明(`tools/golden_baseline_refresh.sh` 现役义务);此后渲染闸逐像素自动盯、零人工。预览图(HTML/SVG 效果图)与引擎渲染是两套管线,禁直接充当比对基线——预览图只作人审参照与验收判据句的出处(判据出处锚指向 ux/ 内嵌预览节);缺陷修复以现行规格与在库基线为准,不触发新预览。
|
||||
- **golden 基线冻结审核关卡(2026-11-08 用户立)**:基线=人定标准、机器守标准——**任何基线的新建/换代/迁移/容差修订,呈报用户逐张审核、确认后才能提交入库生效**;该关卡适用于两类批:①画面类需求批(候选基线对照该卡预览图逐张呈报)②**非卡片批的基线操作**(目录重构/平台迁移/容差修订等工程批——同样逐张呈报审核,禁以「纯搬运/纯工程」为由跳过)。确认记录登记于 `game/tests/golden/README.md` 审核记录节(审核人+时间+基线清单),**未审核的基线禁合回**。机器侧前置:探针自检 PASS(结构断言在案)才允许出候选图,采集失败不得送审。基线**跨平台单套**(同日用户裁:跨平台渲染必须一致,全平台对拍同一份基线,跨平台字形锯齿噪声由容差带吸收,禁以加基线方式消化差异;细则=golden/README「基线冻结与审核」节)。
|
||||
|
||||
分层不是形式。改动发生在哪一层,验收就必须从那一层的真实入口进入。测试绕过了改动点,就不算这个改动的验收——这正是「断言存在、接线坏了却不红」的来源。
|
||||
@@ -115,9 +116,11 @@
|
||||
- **反向**:diff 里每个行为改动至少一行;没有对应行的改动,必须写明「非行为改动」或「由第 X 行覆盖」。
|
||||
- **测试侧**:新增或改写的每条断言至少挂一行;挂不上的孤儿断言删掉或补挂到需求点。
|
||||
|
||||
**判据出处行锚(2026-11-05 立,自 2026-11-05 起对文件名日期不早于该日的需求卡片生效;旧卡不回头改,被编入迭代开工前由写卡段按本粒度补挂)**:对照表「需求点」列每行必须带**判据出处行锚**——该行验收判据所依据的现行文档句子,格式「`<文档相对路径>:<行号>`」。现行文档=`design/` 全域现行文档(含 `ux/` 交互规格与 art-bible 的判据行);已退役的需求卡片不是现行文档,不得充当判据出处。作用=断言预期值从规格句抄出,不从实现反推:实现行为与规格句冲突时断言红;规格缺席的行写不出锚,即停卡退回写卡段(那是需求澄清缺口,不是测试缺口)。机检=`tools/pipeline_gate.py` 判据 C5(锚格式与指向存在性,按卡文件名日期分流)+`tools/capability_audit.py` 链式锚检查(断言→套件→能力行→系统文档,见 §8.9)。
|
||||
**判据出处锚(2026-11-05 立;2026-11-09 用户裁内容化改版——行号形态废止,内容节锚为唯一形态)**:对照表「需求点」列每行必须带**判据出处锚**——该行验收判据所依据的现行文档句子,格式「`<文档相对路径>「节名」<行关键词>`」。现行文档=`design/` 全域现行文档(含 `ux/` 交互规格与 art-bible 的判据行);已退役的需求卡片不是现行文档,不得充当判据出处。节名=判据句所在节的标题词(节名首段「·」前须命中目标文档标题行);行关键词=判据句上的无空白子串(须落在该节块内)。锚指向内容不指向行号——文档增删行不牵动锚与测试代码,只有判据句内容真被改动才使锚失配;失配(节名不在档/关键词不命中)=红,改动该句的文档批同批改锚。作用=断言预期值从规格句抄出,不从实现反推:实现行为与规格句冲突时断言红;规格缺席的行写不出锚,即停卡退回写卡段(那是需求澄清缺口,不是测试缺口)。机检=`tools/pipeline_gate.py` 判据 C5(内容锚形态唯一+节名在档+关键词命中节内,核验口径归 `tools/anchor_util.py` 共用件;行号形态出现即红)+`tools/capability_audit.py` 链式锚检查(断言→套件→能力行→系统文档,见 §8.9)。
|
||||
|
||||
**测试函数的判据出处注记(2026-11-06 立)**:`game/tests/**` 与 `game/probe/**` 内每个**验证函数**(函数体含 `check(`/`check_quiet(`/`_problems.append(`/`push_error(` 判定调用的函数——定义行与 `_check(` 前缀不作判定计)必须带至少一条**判据出处注记**,格式「`# 判据出处: <design/相对路径>:<行号> <判据一句>`」——指针在前、判据摘要句在后;锚形态两档:行号锚(默认)与节锚(`<design/相对路径>「节名」<行关键词>`)——所指文档整节重排时同批把行号锚重锚为节锚,免行号漂移(2026-11-07 架构收窄批立),断言预期值的出处随断言走:断言红时读注记即达出处文档句,零查表。指针空间=`design/` 全域现行文档(行为测试锚 owner 系统文档「验收标准」句或 `ux/` 规格句;惯例类测试〔封装扫描、判定通道纪律、驱动契约〕锚规约条款行;测量面驱动契约锚 `game/sim/` 实现件文件头注——规范句在哪锚哪,2026-11-09 架构收敛批立);`game/sim/` 不进扫描面(测量面直构惯例)。与链式锚的分工:链式锚(断言→套件→能力行→系统文档)不变、属义务清单层;本注记属执行证据层、写在断言文件内,非独立账本(§8.9 法则 4 不变)。写新测试函数时当场挂注记;被指规格句改行号时随批维护指针——死指针即红。局限如实声明:注记是被动文本,句内容改而行数不变时机检抓不到(与卡片判据 C5 同限)。机检=`tools/capability_audit.py` 判据出处注记道(覆盖检查+指针存在性;扫描面零文件自检红)。规格缺席写不出锚=发现规格缺口:记发现不造锚、收尾呈报,禁锚到非现行文档凑数。
|
||||
**测试函数的判据出处注记(2026-11-06 立;2026-11-09 内容化改版——内容节锚唯一形态)**:`game/tests/**` 与 `game/probe/**` 内每个**验证函数**(函数体含 `check(`/`check_quiet(`/`_problems.append(`/`push_error(` 判定调用的函数——定义行与 `_check(` 前缀不作判定计)必须带至少一条**判据出处注记**,格式「`# 判据出处: <design/相对路径>「节名」<行关键词> <判据一句>`」——指针在前、判据摘要句在后;节名与行关键词口径同上(卡片判据锚同款,`game/sim/` 测量面实现件无标题结构,节名与关键词按文件内子串命中),断言预期值的出处随断言走:断言红时读注记即达出处文档句,零查表。指针空间=`design/` 全域现行文档(行为测试锚 owner 系统文档「验收标准」句或 `ux/` 规格句;惯例类测试〔封装扫描、判定通道纪律、驱动契约〕锚规约条款行;测量面驱动契约锚 `game/sim/` 实现件文件头注或本节「批量模拟测量语义」句——规范句在哪锚哪,2026-11-09 架构收敛批立);`game/sim/` 不进扫描面(测量面直构惯例)。与链式锚的分工:链式锚(断言→套件→能力行→系统文档)不变、属义务清单层;本注记属执行证据层、写在断言文件内,非独立账本(§8.9 法则 4 不变)。写新测试函数时当场挂注记;判据句被改动使关键词失配时,改动该句的文档批同批改锚——失配即红。局限如实声明:注记核验到「关键词命中节内」粒度,判据句被改写而关键词仍为其子串时语义漂移机检抓不到,由复核门实读兜(与卡片判据 C5 同限)。机检=`tools/capability_audit.py` 判据出处注记道(覆盖检查+内容锚核验,行号形态出现即红;扫描面零文件自检红)。规格缺席写不出锚=发现规格缺口:记发现不造锚、收尾呈报,禁锚到非现行文档凑数。
|
||||
|
||||
**批量模拟测量语义(测量面驱动契约,2026-11-09 用户裁落文)**:调试浮窗批量模拟(tune_sim,呈现层调参测量件)与 headless 扫描同口径(同款自动策略驱动);逐帧步进每局恰占一帧——第 0 局在调用点同步段执行,第 i 局(i≥1)在第 i 帧信号发射点执行,收尾恒在第 n 帧发射点;n=0 退化路径为调用点同步收尾零帧;进度逐局更新,报告注入与运行态复位在整批收尾之后。双实现对拍套件(产品码帧步进形态 vs 旧 await 形态夹具)以本句为判据出处。
|
||||
|
||||
**验收档申报(2026-11-04 立,自 2026-11-05 起对文件名日期不早于该日的需求卡片生效;旧卡不回头改)**:每张需求卡片在头部信息区(与设计事实源声明同区)申报一个验收档,三档:高/中/低。判据=失败代价单维——这条改动做错了,后果随存档或结算传播的(存档写读与迁移、RNG 流、战斗结算公式与乘区、经济入账、数值表结构校验)=高;后果玩家可见但不损持久状态的(常规玩法逻辑、门控、交互逻辑、呈现数据面)=中;后果即看即知且无状态残留的(文案、纯呈现样式、布局微调)=低。一张卡触多档按最高档申报;申报由写卡段落笔,用户批卡(U0)时确认或改判。档位只调节 §8.7 审计深度——闸机与 CI 的域划分、选闸算法、全量强制档一概不因档位变化,真实入口、判据绑定面、禁削弱等验收闭合判据全部照旧。未申报档位的卡一律按高档全量审计。机检=`tools/pipeline_gate.py` 判据 C4:卡内须含「验收档:高/中/低」申报行。
|
||||
|
||||
@@ -153,7 +156,7 @@
|
||||
2. 抽查判据绑定面:断言从真实入口进入、钉在被测改动的特有可观测提交面上,且当轮真实跑批执行过;
|
||||
3. 检查测试削弱:删除断言、放宽阈值、缩小扫描面、换下层直调,逐处要卡片申报或用户批准。
|
||||
4. 核对内部字段直查的受控例外:直查行是否已在对照表注明理由(该行为无公开可观测面可钉)。
|
||||
5. 核对判据出处:抽查断言的预期值能否从其判据出处行锚(§8.3)的规格句独立写出——预期值只在实现里有的(同义反复,判据镜像实现),判红。
|
||||
5. 核对判据出处:抽查断言的预期值能否从其判据出处锚(§8.3)的规格句独立写出——预期值只在实现里有的(同义反复,判据镜像实现),判红。
|
||||
|
||||
**审计深度分级(2026-11-04 立)**:审计按卡内申报的验收档(§8.3)逐卡定深度;梯度只落在昂贵的判断件上,机械且堵造假向量的两件(削弱检查、例外核对)三档全保留不抽。中/低档省略的测试复跑以远端 CI 读数为执行证据——`tools/ci_check.sh <合并提交>` 的现查输出(commit+run 号+conclusion)是机器产物,run 号在远端永久可复核,审计报告照抄该行即可;照抄前先核对读数必须是「绿」——「未验」(零触发批跑闸步全跳过)与「不可判」不作证据,那种批的回补办法是等一次含代码面的合回或用户自发全量回归(2026-11-04 用户裁:回执等待件退役,证据由落盘文件改为现查读数;「不采信实现者自述已全绿」的口径不变):
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ MVP 不加新敌种,也不做同深度多敌种混搭;敌种扩容走 `enemy
|
||||
|
||||
## 棋盘
|
||||
|
||||
**尺寸按关配置**(板形随关卡行投值,不再固定两档;Boss 战的台阶靠换更大的板制造):现行第一关 10×10 / 12×12 两档、第二关全关 12×12、第三关 13×13(Boss 14×14)。具体尺寸面值与雷密度读 `data/tables/board_gen.tres`(以表为准)。密度全程一档,不做密度爬坡;可推理率目标全程恒定,目标值归[排雷玩法](systems/排雷循环/排雷玩法.md)口径。
|
||||
**尺寸按关配置**(板形随关卡行投值,不再固定两档;Boss 战的台阶靠换更大的板制造):现行第一关 10×10 / 12×12 两档、第二关全关 12×12、第三关 13×13(Boss 14×14)。具体尺寸面值与雷密度读 `data/tables/board_gen.tres`(以表为准)。密度全程一档,不做密度爬坡。
|
||||
|
||||
地形变异现行六类型、两轴 × 三关已落地:荆棘丛/藤蔓缠绕(第一关)+ 岩浆/烬覆(第二关)+ 落石/矿尘(第三关),行值见 `data/tables/variation.tres`。
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ Alpha 内以玩法循环本身的内容与表现为主(棋盘、关卡、战
|
||||
| 素材升档重产 | 排 Beta;原始动机已由八敌逐键定档解决,剩余提灯候选随 Beta 资产批重议([待办清单](../../待办清单.md)) |
|
||||
| 站桩帧动画 | 排 Beta(用户裁);三路线与「立绘→派生形态」管线前置依赖见 [待办清单](../../待办清单.md)「站桩帧动画」条 |
|
||||
| 元进度件贴图终稿 | 排 Beta;元进度图标在 Alpha 保留占位,不碍在役判定([美术资产清单](../art/art-assets-checklist.md))——营地场景图已列入 Alpha(见「三 · 界面」表) |
|
||||
| 冒险前资源配比预设(构筑提案) | 排 Beta(用户裁 2026-11-05);Alpha 不排期,设计闭合凭据与重启条件见 [待办清单](../../待办清单.md)「冒险前资源配比预设(构筑提案)」条 |
|
||||
| 冒险前资源配比预设(构筑提案) | 不做(用户裁 2026-11-09);原案留底见 [冒险前资源配比预设退役素材库](../content-archive/冒险前资源配比预设退役素材库.md) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 难度曲线与Boss
|
||||
|
||||
> 一句话:难度曲线、期望值带与 Boss 设计
|
||||
> 状态:已定稿;现行为 v1.6
|
||||
> 状态:已定稿;现行为 v1.8
|
||||
|
||||
## 设计目的
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
| 不负责 | 归谁 |
|
||||
|---|---|
|
||||
| 生成算法与可推理率度量 | [棋盘生成](../排雷循环/棋盘生成.md)(本文只投参数行值,禁反向调用生成) |
|
||||
| 生成算法 | [棋盘生成](../排雷循环/棋盘生成.md)(本文只投参数行值,禁反向调用生成) |
|
||||
| 结算规则、伤害合成与护甲克制矩阵本体 | [战斗结算](../战斗循环/战斗结算.md)(本文只投矩阵数值) |
|
||||
| 敌种机制、技能池语义与表结构 | [敌人系统](../战斗循环/敌人系统.md)(本文只投行值) |
|
||||
| 奖励机制、库存与注入机制 | [地图战斗资源](../战斗循环/地图战斗资源.md)(本文只投权重、威力、注入参数) |
|
||||
@@ -187,7 +187,7 @@ boss_hp ≈ round( Σ普通战斗敌方生命期望 × r_boss ) r_boss
|
||||
|
||||
Σ 的逐数闭合口径:数量走开战掷骰的区间期望(区间中点),教学位同样掷骰、按区间期望计入;各坐标行值一律读敌人表,本文不重复登记具体数值——防与配置双写失同步。
|
||||
|
||||
Boss 战的棋盘用本关最大板形(板形行值读棋盘参数表),板参数仍受[棋盘生成](../排雷循环/棋盘生成.md)的可推理率绝对锚约束——加难不许加到不可推理。Boss 战胜利即关卡完成,编排归[冒险结构](冒险结构.md);登场仪式感归[战斗表现](../战斗循环/战斗表现.md)。
|
||||
Boss 战的棋盘用本关最大板形(板形行值读棋盘参数表)。Boss 战胜利即关卡完成,编排归[冒险结构](冒险结构.md);登场仪式感归[战斗表现](../战斗循环/战斗表现.md)。
|
||||
|
||||
### 护甲克制:本文锁行值,矩阵本体归战斗结算
|
||||
|
||||
@@ -203,14 +203,14 @@ Boss 战的棋盘用本关最大板形(板形行值读棋盘参数表),板
|
||||
|---|---|---|
|
||||
| 敌方生命 ↔ 奖励供给 | [地图战斗资源](../战斗循环/地图战斗资源.md) | 单边移动必须走关级恒等式的联合检算 |
|
||||
| 数量区间 ↔ 棋盘密度与惩罚上限 | [棋盘生成](../排雷循环/棋盘生成.md)、[战斗结算](../战斗循环/战斗结算.md) | 成群行上线前强制复算挖掘风险不等式 |
|
||||
| 密度 ↔ 可推理率 ↔ 生成尝试上限 | [棋盘生成](../排雷循环/棋盘生成.md) | 三元组联动;禁止为难度牺牲可推理率绝对锚 |
|
||||
| 密度 ↔ 板形 | [棋盘生成](../排雷循环/棋盘生成.md) | 板形与密度行值联动;尺寸与密度域校验归对方参数表 |
|
||||
| 每轮行动点 ↔ 停手转存规模 | [行动经济](../排雷循环/行动经济.md) | 联动评估记录归本文,调参所有权在行动经济 |
|
||||
| 削弱强度 ↔ 当量锚 | [增益状态](../战斗循环/增益状态.md)、[战斗结算](../战斗循环/战斗结算.md) | 联动值禁独立调参,修订须重跑锚对照 |
|
||||
| 护甲类型 ↔ 克制矩阵 | [战斗结算](../战斗循环/战斗结算.md) | 敌种护甲变更须复算击杀区间 |
|
||||
| 护甲等级 ↔ 攻击基线 ↔ 区间带宽 | [战斗结算](../战斗循环/战斗结算.md) | 敌种与主角的护甲等级行值变更须复算生存链区间(掷点带宽随折扣档位与攻击基线同向放大);掷点形式与档位已定稿(d20 三档——档位读 `settlement.tres`;nat20 暴击形式留档,倍率同表),护甲等级行值变更仍须复算生存链区间——现行行值读 `hero.tres` / `enemy.tres` 的 armor_class 列(均暂定),敌方正式行值随怪物设定批投值、与加难杠杆扫描合并调 |
|
||||
| GP 供给 ↔ 商品定价 | [冒险结构](冒险结构.md)、[关卡节点地图](关卡节点地图.md) | 供给 × 定价 = 入关属性参数,单边移动须复算分层关卡完成率带(商店与 GP 经济杠杆节)——动供给必复算分层带,禁独立调参 |
|
||||
| 封印溢价系数 δ ↔ 完美乘数 p_perfect ↔ ap_per_round | [战斗结算](../战斗循环/战斗结算.md)、[行动经济](../排雷循环/行动经济.md) | 封印激励三件套同窗检算(防封印 rush 复发:δ 与 ×2 叠加通胀、AP 吞吐上限)——任一变动须重跑双画像封印率读数 |
|
||||
| η 读数 ↔ 模拟画像定义 ↔ 可推理率 ι ↔ min_safe_count/生成尝试上限 | sim 档位、[棋盘生成](../排雷循环/棋盘生成.md) | η 是画像条件量:画像重构即锚漂移,重锚顺带;可推理率三元组联动 |
|
||||
| η 读数 ↔ 模拟画像定义 | sim 档位 | η 是画像条件量:画像重构即锚漂移,重锚顺带 |
|
||||
| β 带端点 β_lo/β_hi ↔ D_ref ↔ hero max_hp ↔ AC 折算档(5pp 系数) | [战斗结算](../战斗循环/战斗结算.md) | 带是 D_ref 的函数:换锚(D_ref/max_hp)须全带重推;AC 档值变更改 5pp 系数,同罪 |
|
||||
| 直伤雷三行(6/8/8) ↔ 正向同轴行(heal_minor/pierce_strike/magic_bolt) | [地图战斗资源](../战斗循环/地图战斗资源.md) | **同轴镜像比入对账面**:负向/正向比超出 β 带内推导区间即越带;单边动负向三行今后必须带正向镜像行联合检算 |
|
||||
| clear_blast 区间(24/40/32) ↔ p_perfect | [地图战斗资源](../战斗循环/地图战斗资源.md) | 完美封印第二份的补贴基数进封印激励对账;单边动清图奖励 = 变相动封印 |
|
||||
@@ -282,13 +282,14 @@ Boss 战的棋盘用本关最大板形(板形行值读棋盘参数表),板
|
||||
|
||||
群伤负向 = 警觉(敌方护甲等级 +1);一轮踩雷数由行动点预算天然封顶。攻击浮动开战时掷定一次、整战持久;数量区间同流掷定,教学位与首遇位都不豁免——没有区间上界的行自然取定值,那不是豁免,是区间宽度为零。
|
||||
|
||||
技能池投值(池权重/冷却/保底/触发条件的所有权本文,机制归[敌人系统](../战斗循环/敌人系统.md);行值读 `skills.tres` 与 `enemy.tres` 的 pool,全部 provisional):
|
||||
技能池投值(池权重/冷却/保底/特殊间隔/触发条件的所有权本文,机制归[敌人系统](../战斗循环/敌人系统.md);行值读 `skills.tres` 与 `enemy.tres` 的 pool,全部 provisional):
|
||||
|
||||
| 参数 | 说明 |
|
||||
|---|---|
|
||||
| 池权重 | 权重即旋钮:抬特殊技权重 = 抬输出频率,EV 随之重锚;各敌种行集读表 |
|
||||
| 技能冷却(拍) | 逐技能行读表;普攻冷却恒 0 不可配(空池不可能的结构前提——域校验锁死);撕咬 = 与突刺同倍率错开冷却轴的高频小爆发轮廓;毒爆 = 蛛化卓尔精灵专属池独占技 |
|
||||
| 保底 M | 全局单旋钮,读技能表 pity_threshold;连续 M 拍执行普攻 → 下拍必出特殊技;单特殊技低权重池受保底支配 |
|
||||
| 特殊间隔 K | 全局单旋钮,读技能表 special_interval;任一特殊技兑现后该敌连续 K 拍只能执行普通攻击(闸期内特殊技不进可摇与保底集合,保底顺延),0=关闭;与保底 M 同读一表、合闸期口径见敌人系统「三道闸」表 |
|
||||
| 触发条件 | 情境技与闩型解锁的 fact 阈值读技能表 trigger 行值(词表与机制归敌人系统「触发条件」节);情境技的池内份额照走池权重行。**已投放两示范(provisional)**:地精池孤注守势(self_hp_pct lte 35,纯增益技)+ L2/L3 群行位趁隙偷袭(last_round_end eq 停手,伤害技)——fact 阈值、权重、倍率与冷却逐行读表,本表零复制;地精池投放稀释含闸长期速率,EV 抽样锚已换代(带宽注记随 `enemy.tres` 表注) |
|
||||
| 池 EV 锚 | 静态份额与含闸长期速率实测读数登记于调参日志(EV 重锚与权重投值随本表修订)。节奏实测判读口径:种子数下限 50 判读;20 种子以下批次有种子偏置假象;过旱按用户判读带集中在短命杂鱼(生存时长问题非池配置——见待办清单 Alpha 条目移交注记) |
|
||||
|
||||
@@ -297,7 +298,7 @@ Boss 战的棋盘用本关最大板形(板形行值读棋盘参数表),板
|
||||
| 表 | 字面 |
|
||||
|---|---|
|
||||
| 主角表 | 生命上限 / 基础攻击 / 护甲等级(armor_class) |
|
||||
| 棋盘参数 | 板形 / 雷密度 / 可推理率目标 / 生成尝试上限(按关卡 × 节点深度坐标行存放;奖励点/恢复点不开战斗无板行) |
|
||||
| 棋盘参数 | 板形 / 雷密度(按关卡 × 节点深度坐标行存放;奖励点/恢复点不开战斗无板行) |
|
||||
|
||||
战斗侧与奖励侧的关键投值(机制归对方、数值所有权本文;行值读 `settlement.tres` / `reward.tres` / `status_effects.tres`,全部 provisional——本文只登记口径与取值域):
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 增益状态
|
||||
|
||||
> 一句话:增益/减益的状态池、叠层与衰减
|
||||
> 状态:已定稿;现行为 v1.7
|
||||
> 状态:已定稿;现行为 v1.8
|
||||
|
||||
## 设计目的
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
| 字段 | 取值 | 说明 |
|
||||
|---|---|---|
|
||||
| effect_id | 文本,全表唯一 | 状态标识 |
|
||||
| display_name | 文本 | 界面与结算明细用名 |
|
||||
| display_key | 文案 key | 界面与结算明细用名的索引,文案值住 strings.csv(code-conventions §2.5) |
|
||||
| target_side | hero / enemy | 作用侧 |
|
||||
| magnitude | 整数 | 幅度:百分比行 ∈ [−100,100] 且非 0;固定值行 ≥ 1;护甲等级行 ∈ [−20,20] 且非 0 |
|
||||
| unit | percent / flat / ac | 百分比修正 / 固定值 / 护甲等级(掷点折扣判定阈值轴) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 战斗结算
|
||||
|
||||
> 一句话:轮末结算的编排与逐行兑现
|
||||
> 状态:已定稿;现行为 v2.0
|
||||
> 状态:已定稿;现行为 v2.1
|
||||
|
||||
## 设计目的
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
| 判定行 | 胜 / 负 / 继续各一行;终局判定行同时是胜负画面的数据锚 |
|
||||
| 高光行 | 完美封印成立时一行,只记实际有效兑付 |
|
||||
|
||||
每行还携带公共字段:来源类别、来源格、轮次、显示名、数值,以及可空的高光标记(用于强调封印标中、清图奖励这类值得高亮的结果)。**显示名等玩家可见文案是数据面字段:文案值登记在数据表行,代码按来源类别与效果身份读表拼行,不在代码里写死文案字串**(2026-11-06 用户裁——文案归属数据表承载;承载表与字段形态归表结构设计段定,设计闭合后由实装批落表)。奖励直伤行的数值字段沿用 `effectiveness` 键名、值为整数点数——键名与量纲是数据导出与分析工具的兼容契约,改动须连动分析工具面。没生效也要留痕:奖励未生效行如实记录四类合法例外(reason 键封闭:full_layers/full_hp/no_enemy_alive/hero_down),呈现面按 reason 归因(聚合计数呈现已随明细带退役)。**日志落盘零文案:text 与 display_name 不落盘**,玩家可见文案仅呈现面消费。
|
||||
每行还携带公共字段:来源类别、来源格、轮次、显示名、数值,以及可空的高光标记(用于强调封印标中、清图奖励这类值得高亮的结果)。**显示名等玩家可见文案是数据面字段:数据表行只登记文案 key,文案值登记在 strings.csv(data/l10n/),代码按 key 从翻译文件取文案拼行,不在代码里写死文案字串**(2026-11-09 用户裁——文案值归 strings.csv 承载;承载细则与字段形态 = `design/engineering/code-conventions.md` §2.5,实装批落表)。奖励直伤行的数值字段沿用 `effectiveness` 键名、值为整数点数——键名与量纲是数据导出与分析工具的兼容契约,改动须连动分析工具面。没生效也要留痕:奖励未生效行如实记录四类合法例外(reason 键封闭:full_layers/full_hp/no_enemy_alive/hero_down),呈现面按 reason 归因(聚合计数呈现已随明细带退役)。**日志落盘零文案:text 与 display_key 不落盘**,玩家可见文案仅呈现面消费。
|
||||
|
||||
任何一行找不到来源即断言失败——宁可返回错误,也不让"合并到看不出来源"的呈现混过数据层。但有些行天然没有棋盘来源,断言为此留了两层豁免,豁免集合是封闭清单,改动同样走本文修订。
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 敌人系统
|
||||
|
||||
> 一句话:敌人数据、技能池出招、意图呈现
|
||||
> 状态:已定稿;现行为 v1.9
|
||||
> 状态:已定稿;现行为 v2.2
|
||||
|
||||
## 设计目的
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
| 字段 | 适用类型 | 说明 |
|
||||
|---|---|---|
|
||||
| skill_id | 全部 | 主键,池条目引用键 |
|
||||
| display_name | 全部 | 玩家可见名(明细行与动画共用) |
|
||||
| display_key | 全部 | 玩家可见名的文案 key(明细行与动画共用),文案值住 strings.csv(code-conventions §2.5) |
|
||||
| type | 全部 | 封闭枚举 {普通攻击, 伤害, 增益, 妨害}(现行事实源=敌人系统.md 词汇表/增益状态.md;多段命中经用户拍板退役不入枚举);新类型走本文修订 |
|
||||
| damage_mult | 仅伤害 | 伤害倍率;域 [1.1, 16] provisional。普通攻击恒 1、不可配 |
|
||||
| rider_mult | 仅伤害、可省 | **必中附加分量**:域 (0, 1],缺省无字段 = 无附加;分量值 = max(伤害下限, floor(攻击基线 × rider_mult))——随施放者攻击基线缩放,后置加法、必中全额、不进乘区、不出暴击(后置加法同族);价位锚 0.75 = AC 折扣档最轻档"不掉档的稳定伤害" |
|
||||
@@ -110,19 +110,20 @@
|
||||
|
||||
池构成纪律(加载校验,违规拒绝入表):**每池恰一行普通攻击**(普攻冷却恒 0 → 可摇集合恒非空,"空池不可能"由结构保证,最坏情况怪物平砍等待——那是玩家的反打窗口而非死拍);**每池增益类技能 ≤1**(非 RPG,怪物连出不同增益显得呆);**每池妨害类技能 ≤1**;**每池至少一行不带触发条件的特殊技**(普攻不算——保底特殊技集合恒非空的结构保证);池条目 skill_id 悬空致命;权重 > 0、冷却 ≥ 0。
|
||||
|
||||
两道闸(表值 provisional,投值归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md),行值读技能表):
|
||||
三道闸(表值 provisional,投值归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md),行值读技能表):
|
||||
|
||||
| 闸 | 语义 |
|
||||
|---|---|
|
||||
| 技能冷却 | 每技能行带冷却拍数;施放后连续 N 拍不可摇中——普攻恒 0 不可配,其余行值读技能表 |
|
||||
| 保底 | 连续 M 拍执行的都是普通攻击 → 下一拍必出特殊技(特殊技内按权重,不受冷却限制);M 读技能表 pity_threshold |
|
||||
| 保底 | 连续 M 拍执行的都是普通攻击 → 下一拍必出特殊技(条件满足且不在间隔闸期内的特殊技内按权重,不受冷却限制;闸期内保底顺延);M 读技能表 pity_threshold |
|
||||
| 全局特殊间隔 | 任一特殊技兑现后,该敌接下来 K 拍只能执行普通攻击——闸期内特殊技不进可摇集合与保底集合;K 读技能表 special_interval,0=关闭 |
|
||||
|
||||
结构红利:增益存续期内下一拍必是伤害技(池里其余全是伤害技、增益自身还在冷却)——**增益不可能白白过期**,"连出不同增益"被池构成纪律结构性消除。同一技能连发不可能(自身冷却杜绝);异名特殊技背靠背概率低(是变化不是失控,全局特殊间隔闸登记 P1 备用旋钮)。
|
||||
结构红利:特殊技兑现后强制普攻 K 拍(全局特殊间隔闸),增益窗首拍必有普攻承接——**增益不可能白白过期**;"连出不同增益"被池构成纪律结构性消除(增益 ≤1、自身进冷却)。同一技能连发不可能(自身冷却杜绝);异名特殊技背靠背不可能(闸期内特殊技不进可摇集合)。
|
||||
|
||||
开轮摇号时序(随机消费全部在[战斗结算](战斗结算.md)换算层):
|
||||
|
||||
```
|
||||
开轮(轮次开始):排除冷却中与触发条件不满足的技能 → 按行序逐敌摇定本拍行动(behavior_roll 封闭流,每敌独立子流)→ 冷却递减
|
||||
开轮(轮次开始):排除冷却中、间隔闸期内与触发条件不满足的技能 → 按行序逐敌摇定本拍行动(behavior_roll 封闭流,每敌独立子流)→ 冷却与间隔闸计数递减
|
||||
挖掘期:按摇定结果播类型级动画(特殊技)/ 零表示(普通攻击)
|
||||
结算段:按技能行兑现——掷点、乘区、增益挂接、明细落行
|
||||
判定段之后进入下一轮开轮……
|
||||
@@ -136,7 +137,7 @@
|
||||
|
||||
Boss 专属身份 = 专属池承载:独占技能 + 权重轮廓(**技能错峰两轨口径**:**Boss 轨** = L1 酋长池含独占增益技"硬化"〔敌方防御池词汇载体〕+ 半血解锁伤害技"震地怒击";L2 卓尔池独占妨害技"蛛网束缚"+伤害技"毒爆"+ 半血解锁"遏毒";L3 石君王池独占妨害技"大地脉动"+ 半血解锁"岩崩"——独占技随关错峰投放,三行解锁技=每 Boss 一行新独占伤害技〔用户裁案甲,2026-10-04〕;**普通敌轨** = L2/L3 普通敌种技能随关错峰投放(巨蜘蛛族+毒吐〔(2,5)/(2,6)/(2,7),首遇教学位 (2,4) 不投〕、灰矮人族+盾击〔(3,0)/(3,5)/(3,7)〕)——第一关不见的招式第二/三关普通战可见;增益 ≤1 纪律下蓄力拍不进 Boss 池)。
|
||||
|
||||
举证:**摇定结果 = 可摇集合按权重份额归一的一次抽签;当前可摇集合 = 实例池排除冷却中与触发条件不满足的技能(保底命中时 = 条件满足的全部特殊技)。**连带可判别:把权重当固定百分比、把冷却当只锁高伤技、把蓄力当重击前奏,都是与本规约相悖的旧口径。
|
||||
举证:**摇定结果 = 可摇集合按权重份额归一的一次抽签;当前可摇集合 = 实例池排除冷却中、间隔闸期内与触发条件不满足的技能(保底命中时 = 条件满足且不在间隔闸期内的全部特殊技——闸期内保底集合可为空,保底不兑现、顺延到闸后)。**连带可判别:把权重当固定百分比、把冷却当只锁高伤技、把蓄力当重击前奏,都是与本规约相悖的旧口径。
|
||||
|
||||
### 精英行:现役敌种的强化版,池=继承基础池+附加技
|
||||
|
||||
@@ -176,15 +177,15 @@ Boss 专属身份 = 专属池承载:独占技能 + 权重轮廓(**技能错
|
||||
| 机制 | 规则 |
|
||||
|---|---|
|
||||
| 冷却 | 照常——条件与冷却各自独立排除,同一拍可叠加 |
|
||||
| 保底 | 保底特殊技集合同样排除条件不满足的技能(保底禁止逼出条件不满足的技);池构成纪律"每池至少一行无条件特殊技"保证该集合恒非空 |
|
||||
| 保底 | 保底特殊技集合同样排除条件不满足的技能(保底禁止逼出条件不满足的技);池构成纪律"每池至少一行无条件特殊技"保证该集合闸外恒非空——间隔闸期内可被闸排空,保底顺延(见「三道闸」表) |
|
||||
| 死亡作废 | 照常——摇定后兑现前死亡,本拍作废、不进冷却不进保底计数 |
|
||||
| 意图呈现 | 三档规格不变——情境技属特殊技,走类型级预告+结算明细具名,因果由技能名承载(如"趁隙偷袭");闩型保留解锁弹出规格(见"目标顺位与意图线索"节) |
|
||||
| 意图呈现 | 三档规格不变——情境技属特殊技,走类型级预告+结算明细具名,因果由技能名承载(如"趁隙偷袭");闩型解锁拍零新增呈现,告知归既有意图预告承载(见"目标顺位与意图线索"节) |
|
||||
|
||||
半血解锁:Boss 解锁技=trigger {fact: self_hp_pct, op: lte, value: 行值, latch: 真}——解锁弹出规格(归因明细行+一次性技能名 toast)、单向闩语义、双面过滤。
|
||||
半血解锁:Boss 解锁技=trigger {fact: self_hp_pct, op: lte, value: 行值, latch: 真}——解锁拍零新增呈现(归因明细行照记数据面)、单向闩语义、双面过滤。
|
||||
|
||||
首批落地(已实装):①三 Boss 解锁技为闩型条件;②两个示范投放——地精池+低血防御增益「孤注守势」(self_hp_pct lte 35,纯增益)、L2/L3 群行位+停手偷袭伤害技「趁隙偷袭」(last_round_end eq 停手)。投放敌种、权重与阈值投值归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md);"每池增益≤1"纪律不动,条件技照常计入预算。
|
||||
|
||||
举证:触发条件为门槛过滤规则,无计算——可摇集合 = 实例池排除冷却中与触发条件不满足的技能(保底命中时 = 条件满足的全部特殊技)。
|
||||
举证:触发条件为门槛过滤规则,无计算——可摇集合 = 实例池排除冷却中、间隔闸期内与触发条件不满足的技能(保底命中时 = 条件满足且不在间隔闸期内的全部特殊技)。
|
||||
|
||||
### 伏击(已退役)与群伤负向现况
|
||||
|
||||
@@ -202,9 +203,9 @@ Boss 专属身份 = 专属池承载:独占技能 + 权重轮廓(**技能错
|
||||
| 特殊技 | 技能动画占位(攻击系 / 增益系 / 妨害系三族)——纯类型级提醒,不预告技能名与数值 | 明细行具名技能 + 数值 |
|
||||
| nat20 暴击 | 无前置表示(掷点层,与技能重击严格区分) | 明细行"(暴击)"标注 |
|
||||
|
||||
即:普攻完全不可预测;特殊技有一次类型级预告,不可撤销,但给"继续挖还是停手"的决策依据。
|
||||
即:普攻完全不可预测;特殊技有一次类型级预告,不可撤销,但给"继续挖还是停手"的决策依据。攻击系内部不分档预告——重击与普通伤害技的预告呈现完全相同,强度差异的感知通道是敌人本体的准备动画(规格见[角色设计](../../../art/character-design.md) §5.6 意图准备动画三档)。
|
||||
|
||||
**半血解锁弹出规格(解锁判定点=通用事件「血量阈值 `enemy_hp_threshold`」的发射点,对所有带闩型血量触发条件的敌人逐个发射、非 Boss 专属——Boss 语义留给订阅条件判定;条件载体=技能行 trigger 闩型,见「触发条件」节)**:Boss 血量降至解锁阈值(trigger 行值,域 [1,99],缺省无字段=无门槛)时,下一个开轮摇号前出一次归因明细行「XX 解锁了 YY」(高光键为技能解锁,行型复用高光行零新增);呈现层对该行弹**一次性技能名 toast**(轻量提示,非演出——零动画资产、不改演出规格),只报技能名不报数值,池与权重不公开纪律不变。解锁=单向闩(治疗抬血不解锁);锁定条目双面过滤(不进可摇集合与保底特殊技集合——保底禁止逼出未解锁技);解锁后冷却初值 0 即可摇。投放纪律=机制通用、闩型解锁用例仅 Boss 专属技投放(enemy 表无 boss 编码位,硬闸须跨表查节点类型——不做硬闸,本句即文档纪律登记)。技能动画的攻/防系映射归[战斗表现](战斗表现.md),敌人侧摇定动画位归[HUD 框架](../表现与支撑/HUD框架.md)(呈现载体 = 站桩立绘,2026-09-20 全站桩拍板),本系统只锁上面这张三档规格。
|
||||
**半血解锁呈现规格(解锁判定点=通用事件「血量阈值 `enemy_hp_threshold`」的发射点,对所有带闩型血量触发条件的敌人逐个发射、非 Boss 专属——Boss 语义留给订阅条件判定;条件载体=技能行 trigger 闩型,见「触发条件」节)**:Boss 血量降至解锁阈值(trigger 行值,域 [1,99],缺省无字段=无门槛)时,下一个开轮摇号前出一次归因明细行「XX 解锁了 YY」(高光键为技能解锁,行型复用高光行零新增——数据面照记,玩家不可见面)。**解锁拍零新增呈现(2026-11-10 用户裁,替代原一次性技能名 toast)**:血条跌破本身即视觉事件,新增提示条、弹窗、浮字一概不做——玩家刚把 Boss 打进阈值,「它亮新招」因果自明;新技的玩家告知由既有意图预告承载(下一拍开轮摇中即类型级徽标顶头,具名随预告),与杀戮尖塔敌人能力变化走头顶意图的惯例同轨。池与权重不公开纪律不变。解锁=单向闩(治疗抬血不解锁);锁定条目双面过滤(不进可摇集合与保底特殊技集合——保底禁止逼出未解锁技);解锁后冷却初值 0 即可摇。投放纪律=机制通用、闩型解锁用例仅 Boss 专属技投放(enemy 表无 boss 编码位,硬闸须跨表查节点类型——不做硬闸,本句即文档纪律登记)。技能动画的攻/防系映射归[战斗表现](战斗表现.md),敌人侧摇定动画位归[HUD 框架](../表现与支撑/HUD框架.md)(呈现载体 = 站桩立绘,2026-09-20 全站桩拍板),本系统只锁上面这张三档规格。
|
||||
|
||||
| 规格 | 含义 |
|
||||
|---|---|
|
||||
@@ -237,7 +238,7 @@ Boss 专属身份 = 专属池承载:独占技能 + 权重轮廓(**技能错
|
||||
## P0 最小闭环
|
||||
|
||||
1. 战斗开始:战斗结算按遭遇坐标调本系统生成单位——读表快照实例化本战数量的敌人(池模板快照成实例池、冷却全零),主角以血量入参生成。
|
||||
2. 开轮摇号:战斗结算换算层排除冷却中技能、按行序逐敌摇定本拍动作写入实例池,随后冷却递减(首轮同样摇;轮内刷新换图不重摇)。
|
||||
2. 开轮摇号:战斗结算换算层排除冷却中与间隔闸期内技能、按行序逐敌摇定本拍动作写入实例池,随后冷却与间隔闸计数递减(首轮同样摇;轮内刷新换图不重摇)。
|
||||
3. 挖掘期踩雷:事实经战斗结算转化为警觉施加——每颗雷恰一次、逐层记账(无上限)。
|
||||
4. 每轮结算战斗段:主角先基础攻击顺位最前的存活敌人,随后每个存活敌人按摇定技能行兑付(伤害技 = 基线 × 倍率,增益技 = 施放行 + 状态授予);地图奖励与惩罚的伤害兑付殿后到战斗段末统一落地(案C 2026-10-06 用户裁,见战斗结算)。
|
||||
5. 受击上报、血量递减;归 0 即移出顺位(摇定后兑现前死亡 → 本拍作废不进账)。
|
||||
@@ -252,7 +253,6 @@ Boss 专属身份 = 专属池承载:独占技能 + 权重轮廓(**技能错
|
||||
| P1 | 情境条件触发器(低血触发防御、玩家停手时偷袭技等) | 已实装(三 Boss 闩型+两示范投放,见「触发条件」节与「首批落地」段) |
|
||||
| P1 | 个体化变体池(同种个体分型:A 型好斗 / B 型守势) | 共识点 A 的 A2 案;排期 Beta,登记[待办清单](../../../../待办清单.md) |
|
||||
| P1 | 精英遭遇接线、精英底座光环与描边变色、精英钥石掉落 | 精英行已落表静置(见「精英行」节);接线归[待办清单](../../../../待办清单.md)「战斗节点遭遇编排方式」条目,视觉二件随怪物设定批,钥石随接线批 |
|
||||
| P1 | 全局特殊间隔旋钮 | 特殊技背靠背实测仍嫌时的备用闸;登记[待办清单](../../../../待办清单.md) |
|
||||
| P1 | 新效应词汇(妨害技 + 必中附加分量已实装——实装面 = L2 Boss 卓尔;多段命中经用户拍板退役) | 妨害类型 + rider_mult 字段已落地;登记[待办清单](../../../../待办清单.md)(已解决移除,去向见状态记录) |
|
||||
| P1 | 敌种扩容与投放节奏(含第二关池与投放) | 投放节奏是关卡命脉,归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md) |
|
||||
| P1 | 单体寻址("只打某一个敌人"的目标指定) | 归集语义与呈现已裁定(语义归[增益状态](增益状态.md)〈单体寻址扩展位〉节);实现随首个单体效果的内容批落地 |
|
||||
@@ -291,6 +291,7 @@ Boss 专属身份 = 专属池承载:独占技能 + 权重轮廓(**技能错
|
||||
| cooldown_beats | [0, 99] | 施放后连续 N 拍不可摇中;普通攻击恒 0 不可配(域校验锁死——空池不可能的结构前提) |
|
||||
| buff_ref / buff_duration | 效果引用 / [1, 99] | 仅增益与妨害技(target_side 路由);悬空引用加载期拒绝 |
|
||||
| pity_threshold(保底 M) | [1, 99] | 全局单旋钮:连续 M 拍执行普攻 → 下拍必出特殊技 |
|
||||
| special_interval(特殊间隔 K) | [0, 99] | 全局单旋钮:任一特殊技兑现后该敌连续 K 拍只能执行普通攻击,0=关闭(旧口径等价);投值归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md) |
|
||||
| trigger | {fact, op, value, latch},词表见核心规则「触发条件」节;value 类型随 fact(数值事实整数、百分比事实域 [1,99]、枚举事实枚举串) | 全部可省,缺省=无条件技;出域加载期拒绝;情境技与解锁阈值的行值投值归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md) |
|
||||
|
||||
主角表(单行全局):
|
||||
@@ -305,13 +306,13 @@ Boss 专属身份 = 专属池承载:独占技能 + 权重轮廓(**技能错
|
||||
|
||||
各敌种行值、池权重与池 EV 读数(含闸长期速率实测)一律读配置表与调参日志,本文不登记具体数值;EV 重锚与权重投值归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)。
|
||||
|
||||
结构冻结(非调参项,修订走本文流程):技能类型枚举封闭、每池恰一普攻、每池增益 ≤1、死亡即不动手(摇定后兑现前死亡作废不进账)、每结算每存活敌恰行动一次、行序、先作用后推进、固定顺位、**行集构成纪律(行集内 enemy_id 唯一 + 同带键多行文件内相邻且行序 = 声明序 = 生成序 + 行集实例总数 ≤ 4)**、零随机(本系统自身语义零随机不变——摇号与掷点随机一律在[战斗结算](战斗结算.md)结算换算层按封闭随机流掷定,可回放契约 = 同种子同输入逐位复现,单敌出招轨迹可独立复放)。联动纪律:技能倍率 × 攻击(伤害拍支配)、权重 × 冷却 × 保底(池节奏三联动)禁止独立调参,联调须重跑方向性预检并同步登记册(登记 [待办清单](../../../../待办清单.md))。
|
||||
结构冻结(非调参项,修订走本文流程):技能类型枚举封闭、每池恰一普攻、每池增益 ≤1、死亡即不动手(摇定后兑现前死亡作废不进账)、每结算每存活敌恰行动一次、行序、先作用后推进、固定顺位、**行集构成纪律(行集内 enemy_id 唯一 + 同带键多行文件内相邻且行序 = 声明序 = 生成序 + 行集实例总数 ≤ 4)**、零随机(本系统自身语义零随机不变——摇号与掷点随机一律在[战斗结算](战斗结算.md)结算换算层按封闭随机流掷定,可回放契约 = 同种子同输入逐位复现,单敌出招轨迹可独立复放)。联动纪律:技能倍率 × 攻击(伤害拍支配)、权重 × 冷却 × 保底 × 特殊间隔(池节奏四联动)禁止独立调参,联调须重跑方向性预检并同步登记册(登记 [待办清单](../../../../待办清单.md))。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- 开战生成:按遭遇坐标取出该坐标行集(一行或多行,逐行实例化——行序 = 文件序),实例化数量与数值投影同行值快照;行集实例总数(各行骰后)≤ 4;池模板快照成实例池且冷却全零;主角以血量入参,越界(高于上限或不超过 0)拒绝且不留半实例。
|
||||
- 摇号确定性:同种子回放逐位复现(步骤流与各实例摇定动作序列逐位相同);单敌轨迹独立复放——只喂该敌子流(scope = 生成序 × 派生向量 + 摇号序)即可逐位重建其出招序列、互不穿插。
|
||||
- 池节奏:中签率 = 权重 ÷ 可摇权重合计(排除冷却中与触发条件不满足的技能后归一);施放后连续 N 拍不可摇中;连续 M 拍执行普攻 → 下拍必出特殊技(条件满足的特殊技内按权重、不受冷却限制);同技能连发不可能;首轮摇号、每轮恰摇一次、轮内刷新不重摇。
|
||||
- 池节奏:中签率 = 权重 ÷ 可摇权重合计(排除冷却中、间隔闸期内与触发条件不满足的技能后归一);施放后连续 N 拍不可摇中;任一特殊技兑现后该敌连续 K 拍只执行普通攻击(K=0 关闭=旧口径);连续 M 拍执行普攻 → 下拍必出特殊技(条件满足且不在间隔闸期内的特殊技内按权重、不受冷却限制,闸期内顺延);同技能连发不可能;异名特殊技背靠背不可能(K ≥ 1);首轮摇号、每轮恰摇一次、轮内刷新不重摇。
|
||||
- 触发条件:条件不满足的技能不进可摇集合与保底集合(保底禁止逼出条件不满足的技);条件求值零随机、同种子回放逐位复现;闩型条件首次为真后整场保持(治疗抬血不回锁);每池至少一行无条件特殊技(加载校验);缺省无 trigger 字段=无条件技,旧表零变化。
|
||||
- 死亡即不动手:摇定后、兑现前被杀——本拍技能作废(零行动明细行),不进冷却、不进保底计数;行动完成后才死——已兑付已进账;对已死亡单位上报受击被拒绝且状态不变。
|
||||
- 空池不可能:每池恰一行普通攻击(域校验),普攻冷却恒 0 → 任意实例任意拍可摇集合恒非空。
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
# 棋盘生成
|
||||
|
||||
> 一句话:棋盘怎么生成、怎么保证可推理可清图
|
||||
> 状态:已定稿;现行为 v1.3
|
||||
> 一句话:棋盘怎么生成——确定性随机布雷,不做质量承诺
|
||||
> 状态:已定稿;现行为 v1.4
|
||||
|
||||
## 设计目的
|
||||
|
||||
棋盘生成是全项目扫雷图的唯一生产者:战斗结算每要一张新图,它就按关卡序号与节点深度对应的参数行,确定性造出一张可推理、可清图的雷图。它在生成时刻就作出质量承诺——玩家只会输给自己选的赌(比如终局只能猜的一格),不会拿到大面积无解的局;这是核心循环里"推理的确定性"卖点的生成端保障。同种子同参数必产同图,回放、测试、复盘都能精确复现——确定性既是卖点,也是调试工具。
|
||||
棋盘生成是全项目扫雷图的唯一生产者:战斗结算每要一张新图,它就按关卡序号与节点深度对应的参数行,确定性造出一张雷图。生成端不做质量承诺——不担保"好推理"、不担保"不用猜",随机布雷允许猜局,猜是玩法的一部分(踩雷不是死亡是事实上报,归[排雷玩法](排雷玩法.md))。同种子同参数必产同图,回放、测试、复盘都能精确复现——确定性既是卖点,也是调试工具。
|
||||
|
||||
## 系统范围
|
||||
|
||||
边界这样划:本系统管"图从哪来、生成时承诺什么质量"。图上的动作怎么执行归[排雷玩法](排雷玩法.md),什么时候换图归[战斗结算](../战斗循环/战斗结算.md)编排,数值定多少归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)(本系统只提供参数表给数值落点),变异内容是什么归[地形变异](地形变异.md)(本系统不为变异做任何工作——变异格赋予在战斗初始化第 4 步执行,生成器产物恒零变异格)。本系统是个无状态的生产者:进参数与种子,出棋盘与指标,自己不留任何记忆。
|
||||
边界这样划:本系统管"图从哪来"。图上的动作怎么执行归[排雷玩法](排雷玩法.md),什么时候换图归[战斗结算](../战斗循环/战斗结算.md)编排,数值定多少归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)(本系统只提供参数表给数值落点),变异内容是什么归[地形变异](地形变异.md)(本系统不为变异做任何工作——变异格赋予在战斗初始化第 4 步执行,生成器产物恒零变异格)。本系统是个无状态的生产者:进参数与种子,出棋盘与指标,自己不留任何记忆。
|
||||
|
||||
负责:
|
||||
|
||||
| 负责 | 说明 |
|
||||
|---|---|
|
||||
| 四阶段确定性生成管线 | 读参数 → 布雷 → 生成-验证 → 产出上报;顺序冻结,不调换、不跳步(变异布置段已移出管线) |
|
||||
| 四阶段确定性生成管线 | 读参数 → 布雷 → 出板检查 → 产出上报;顺序冻结,不调换、不跳步(变异布置段已移出管线) |
|
||||
| 棋盘生成参数表 | 全项目第一张按进度键(关卡序号 × 节点深度)回填的配置表;表结构归本系统定 |
|
||||
| 可推理率度量与达标判定 | 生成时刻的质量承诺,含计算口径与定义版本号 |
|
||||
| 出生区与反退化保证 | 出生 3×3 无雷、最小安全格数、开局白给板拒绝、清图可达性(变异不落出生区与展开域由布置段顺序保障) |
|
||||
| 加载期参数校验 | 参数域、布雷数下限、可行性与成本闸校验;违例加载期致命 |
|
||||
| 生成期指标集产出 | 实测可推理率、实际雷数等,供调参与下游对账 |
|
||||
| 出生区与反退化保证 | 出生 3×3 无雷、开局白给板拒绝(变异不落出生区与展开域由布置段顺序保障) |
|
||||
| 加载期参数校验 | 参数域与布雷数下限校验;违例加载期致命 |
|
||||
| 生成期指标集产出 | 实际雷数、安全格数、重摇次数等,供调参与下游对账 |
|
||||
|
||||
不负责:
|
||||
|
||||
@@ -56,93 +55,51 @@
|
||||
│ 在"全格 − 出生 3×3"范围均匀布雷
|
||||
│ 开局免费展开域外扩一圈,圈内的雷移除(只减不增、不重投、无迭代)
|
||||
▼
|
||||
③ 生成-验证 ── 实测可推理率;不达标在同一张图的随机数配额内重试,至上限按出口分发
|
||||
③ 出板检查 ─── 只查两条:出生区无雷、开局不全开;白给板同流重摇,直到不全开
|
||||
▼
|
||||
④ 产出上报 ─── 交出棋盘 + 生成期指标集
|
||||
```
|
||||
|
||||
生成期间的每一次随机取数——布雷、重试——都从本图专属的一条"棋盘生成随机流"按固定顺序取:一张图只开一条流、用到底,重试不开新流;流之外零随机,全局随机函数一律禁用。参数行开始时一次快照,配置表中途热重载不影响进行中的生成。管线本身无状态——这些合起来就是"同种子同参数必产同图"的根基。(变异布置不消费本流——其取数走专用 variant_place 流,归战斗结算 布置段。)
|
||||
生成期间的每一次随机取数——布雷、重摇——都从本图专属的一条"棋盘生成随机流"按固定顺序取:一张图只开一条流、用到底,重摇不开新流;流之外零随机,全局随机函数一律禁用。参数行开始时一次快照,配置表中途热重载不影响进行中的生成。管线本身无状态——这些合起来就是"同种子同参数必产同图"的根基。(变异布置不消费本流——其取数走专用 variant_place 流,归战斗结算 布置段。)
|
||||
|
||||
各阶段的失败都有明确语义,全部失败路径都不让玩家卡死(本节为纯流程规则,无计算;数值与校验式见后续各节):
|
||||
各阶段的失败都有明确语义(本节为纯流程规则,无计算;数值与校验式见后续各节):
|
||||
|
||||
| 阶段 | 失败情形 | 语义 |
|
||||
|---|---|---|
|
||||
| 参数解析 | 行缺失或域违例 | 加载期校验已拦,运行期不会失败 |
|
||||
| 布雷 | 雷数为 0 | 不会发生(零雷板加载期已拒) |
|
||||
| 生成-验证 | 重试耗尽 | 按三分支出图(见"生成重试与成本闸") |
|
||||
| 出板检查 | 开局白给板 | 同流重摇,直到不全开——这是唯一的重摇理由 |
|
||||
| 产出 | —— | 无失败路径,交出棋盘与指标 |
|
||||
|
||||
### 出生区安全与反退化布雷:脚下无雷、废板不出厂
|
||||
### 出生区安全与反退化布雷:脚下无雷、白给板不出厂
|
||||
|
||||
玩家开局站在棋盘上的 3×3 出生区,开局不花行动点就能看到一片区域——出生 3×3 加上从它出发经连锁展开(翻到八邻无雷的格时整片免费翻开的机制,玩家可见名"坍塌显形")免费带出的格,下文称**开局免费展开域**。本规则保证两件事:其一,脚下永远安全——出生区与开局免费展开域内恒无雷(变异亦然——变异格赋予在初始展开之后执行,天然不落已开区,见[地形变异](地形变异.md)布置段);其二,流出的每张图都可正常游玩——零雷板、安全格寥寥的板、开局白给的板、带孤岛安全格的板,都在生成期被拦下或整张弃用。
|
||||
玩家开局站在棋盘上的 3×3 出生区,开局不花行动点就能看到一片区域——出生 3×3 加上从它出发经连锁展开(翻到八邻无雷的格时整片免费翻开的机制,玩家可见名"坍塌显形")免费带出的格,下文称**开局免费展开域**。本规则保证两件事:其一,脚下永远安全——出生区与开局免费展开域内恒无雷(变异亦然——变异格赋予在初始展开之后执行,天然不落已开区,见[地形变异](地形变异.md)布置段);其二,开局不全开——开局免费展开域覆盖全部安全格的板等于白给,重摇弃用。
|
||||
|
||||
**结论**:雷数先定数、再落位;零雷板与安全格不足的参数组合在加载期就被拒绝。
|
||||
**结论**:雷数先定数、再落位;零雷板的参数组合在加载期就被拒绝。
|
||||
|
||||
```
|
||||
布雷数 N = round(mine_density × (board_width × board_height − 出生格数)) (出生格数 = 出生区边长²,读表;出生区恒排除)
|
||||
下限校验:N ≥ 1(零雷板加载期拒绝)
|
||||
计数可行:board_width × board_height − N ≥ min_safe_count(加载期校验)
|
||||
产物断言:实际安全格数 ≥ min_safe_count;实际雷数 ≤ N(先布后删只减不增)
|
||||
产物断言:实际雷数 ≤ N(先布后删只减不增)
|
||||
```
|
||||
|
||||
| 符号 | 含义 |
|
||||
|---|---|
|
||||
| mine_density | 雷密度参数,与图尺寸解耦 |
|
||||
| board_width / board_height | 图尺寸参数 |
|
||||
| min_safe_count | 最小安全格数下限参数——对冲"图上没几格安全、随便挖挖就清图领奖励"的刷奖励打法 |
|
||||
| N | 该参数行每张图的目标雷数 |
|
||||
|
||||
| 反退化规则 | 内容 |
|
||||
|---|---|
|
||||
| 先布后删 | 先把 N 颗雷在"全格 − 出生 3×3"上布完,再把剃雷域内的雷移除——只减不增、不重投、无迭代,必然终止且可复现;实际雷数与 N 的差额随指标观测。**剃雷域**:「出生 3×3 ∪ 外扩 r 环」(切比雪夫距离 ≤1+r,r=shave_ring_radius 现行 1 → 5×5=25 格)——全域剃雷=开局免费展开巨大(10×10 板 R₀ 均值 68.6=板面 68.6%)的根因;现口径下开局免费展开=出生邻域剃雷诱发的自然连锁,均值降至板面约四成(10×10 实测 39.7) |
|
||||
| 出生区安全 | 出生 3×3 与开局免费展开域内恒无雷;变异不落两域由布置段顺序保障(非本管线义务) |
|
||||
| 开局白给板拒绝 | 开局免费展开域禁止覆盖全部安全格——等于即退化板,尝试弃用重试;运行期另有同义兜底不变式,归[排雷玩法](排雷玩法.md) |
|
||||
| 清图可达性 | 每个安全格都必须能从出生区沿安全格八向连通走到;带孤岛安全格的板判非法,不进降级候选 |
|
||||
| R₀≤cap 重掷闸 | 每次尝试出板后实测自然 R₀(开局免费展开格数),超过该行 r0_max_cap 即整板作废同流重试——合法性先于质量评分(同白给板先例);全部尝试超阈 → 既有三分出口接受最不坏+非法产物标记诚实降级,玩家永不卡死;闸触发次数随指标集 r0_cap_rejected 观测(占比过高=剃雷半径与闸配比失衡信号) |
|
||||
| 开局白给板拒绝 | 开局免费展开域禁止覆盖全部安全格——等于即退化板,同流重摇弃用;运行期另有同义兜底不变式,归[排雷玩法](排雷玩法.md) |
|
||||
|
||||
清图可达性与可推理率是两道独立的闸:合法性先查、质量分后算——一张"分高但通不了"的图没有意义。另一条推理前提也由本系统保证:数字恒真,每个非危险格的数字恒等于它的八邻雷数,整局推理都建立在这句话上。
|
||||
数字恒真是布雷算法的本分:每个非危险格的数字由八邻雷数直接算出,构造上恒成立,不设运行期检查——算错了是算法缺陷,修算法,不是加检查。
|
||||
|
||||
### 可推理率承诺:生成时就担保玩家算得对
|
||||
### 不做质量承诺:猜局是玩法的一部分
|
||||
|
||||
可推理率(inferability)回答一个问题:这张图上有多少安全格,玩家不靠赌、纯凭逻辑就能挖开?它是整张图的"不靠赌占比":把开局免费展开、连锁展开、数字推导三种通道能确定挖开的安全格数,除以安全格总数。生成端承诺每张图实测占比不低于该行及格线——玩家可以输给自己选的赌,但不会拿到一张大面积无解的图。
|
||||
|
||||
**结论**:每张图生成时实测可推理率,实测值 ≥ 该行及格线;及格线取值域 [0.85, 1],域下限 0.85 是"不许纯猜局"的绝对锚(结构冻结——调整走文档修订,不是调参)。
|
||||
|
||||
```
|
||||
可推理率(图) = 不靠赌能确定挖开的安全格数 ÷ 安全格总数
|
||||
不靠赌揭示闭包:从开局免费展开域出发,交替应用两条规则直到不再新增——
|
||||
① 连锁:翻到 0 格(八邻无雷的数字格)→ 其八邻安全格全部计入
|
||||
② 推导:与已揭示区八向相邻的安全格,求解器凭可见数字能唯一断定其非雷 → 计入
|
||||
```
|
||||
|
||||
| 口径 | 内容 |
|
||||
|---|---|
|
||||
| 与玩家信息同步 | 评分模拟只看玩家能看见的盘面:没开的格看不见,危险格位置不许偷看 |
|
||||
| 三通道计入 | 免费展开、连锁、推导挖开的格都算"不靠赌";免费展开格同时计入分子与分母 |
|
||||
| 次序无关 | 先连锁还是先推导,闭包结果相同——分数与玩家的操作顺序无关 |
|
||||
| 版本防漂移 | 指标输出带定义版本号(当前 1);改推理定义 = 文档修订 + 黄金图向量重制,版本号随之跳变 |
|
||||
|
||||
推理规则域 solver_rules 冻结为 single_subset(单点规则加子集消减——经典扫雷式确定性推理:凭单个数字、以及两组数字的差能唯一断定的格)。它是可推理率定义的一部分,不是调参项;放宽或收紧它都等于改"算得对"的定义,须走文档修订。
|
||||
|
||||
### 生成重试与成本闸:重试有上限、降级必上报
|
||||
|
||||
一张图生成后先实测可推理率,不达标就在同一张图的随机数配额内重试——不开新图、不换种子。重试不是无限的:总取数规模受成本闸约束,且禁止拿真实耗时当逃生阀——否则同一颗种子在快慢机器上会产出不同的图,"同种子同图"就不成立了。
|
||||
|
||||
**结论**:重试次数与图尺寸联合受成本闸约束。
|
||||
|
||||
```
|
||||
成本闸:max_gen_attempts × board_width × board_height ≤ 成本闸护栏常数 (结构护栏常数,见棋盘参数表字段定义;provisional 量级,正式值待实现期定)
|
||||
```
|
||||
|
||||
| 出口 | 何时走 | 发生什么 |
|
||||
|---|---|---|
|
||||
| 达标即出 | 重试中出现合法且达标的图 | 出最早达标的那张,不追求全场最高分 |
|
||||
| 接受最优 | 重试耗尽,有合法图但无一达标 | 出合法图中可推理率最高的一张(并列取最早)+ 强告警 + 降级标记 |
|
||||
| 接受最不坏 | 重试耗尽且一张合法图都没有 | 按确定性劣度排序出最不坏的一张 + 最高级告警 + 非法产物标记 |
|
||||
|
||||
最后一条出口是诚实降级:玩家永不卡死——哪怕找不到合法板也照常出图;但绝不静默——非法产物标记随指标集上抛,由[战斗结算](../战斗循环/战斗结算.md)编排、经 [HUD 框架](../表现与支撑/HUD框架.md)诚实告知玩家(提示、补偿还是回退,呈现细节归下游)。运行期安全网兜住体验,质量红线靠调参期批量断言守住:非法产物严格零容忍、低于及格线的板数严格为零——两层不许互相折算。
|
||||
|
||||
每次尝试先过合法性关——清图可达、安全格数达标、结构不变式全过——再谈质量分;非法尝试弃用重试。合法性闸在质量评分之前,质量分禁止掩盖功能残废。
|
||||
生成端不度量"好不好推理"、不筛选"够不够好推理"的板:经典扫雷式随机布雷天然允许猜局,玩家靠数字推理推进,推不动的格子自己权衡赌不赌(挖开危险格不是死亡是事实上报,归[排雷玩法](排雷玩法.md))。推理求解程序(凭可见数字做确定性推导的程序)只保留在离线模拟测量(MC 批量模拟)中作测量工具,不参与生成管线。
|
||||
|
||||
### 图类型标签与第三轴预留:主题恒定、Boss 板有座位
|
||||
|
||||
@@ -165,8 +122,7 @@
|
||||
| 上游 | [数据配置](../表现与支撑/数据配置.md) | 参数表承载、类型化读取与加载期校验通道;棋盘生成随机流的种子派生(每图开一次流) |
|
||||
| 相邻 | [地形变异](地形变异.md) | 相邻事实依赖:布置执行位在战斗初始化第 4 步(战斗结算 编排段),生成器产物恒零变异格;出生区/展开域"无变异"承诺由该顺序结构保障 |
|
||||
| 下游 | [排雷玩法](排雷玩法.md) | 棋盘产物消费方;开局免费展开由对方执行,展开域口径按双方登记的回验条款对齐 |
|
||||
| 下游 | [战斗结算](../战斗循环/战斗结算.md) | 换图调用方与指标对账方;零合法板的玩家侧诚实告知由其编排 |
|
||||
| 下游 | [行动经济](行动经济.md) | 单向事实依赖:P(安全)(挖掘目标格为安全格的概率)是对方挖掘风险不等式的概率锚,锚值由本系统供给——实测可推理率分布的低分位值,不是及格线参数 |
|
||||
| 下游 | [战斗结算](../战斗循环/战斗结算.md) | 换图调用方与指标对账方 |
|
||||
| 下游 | [难度曲线与Boss](../冒险循环/难度曲线与Boss.md) | 参数数值所有权方;只按表调参,禁反向调用生成 |
|
||||
| 下游 | [关卡节点地图](../冒险循环/关卡节点地图.md) | 第三轴 Boss 板落点约定的共同输入 |
|
||||
| 下游 | [地图战斗资源](../战斗循环/地图战斗资源.md) | board_type 作图类型上下文(行参数静态恒定) |
|
||||
@@ -174,27 +130,23 @@
|
||||
| 对外接口 | 形态 |
|
||||
|---|---|
|
||||
| 生成入口 | 生成(关卡序号, 节点深度, 种子) → 棋盘 + 生成期指标集;无状态纯函数 |
|
||||
| 生成期指标集 | 实测可推理率(带定义版本号)、实际雷数与安全格数、重试次数、降级/非法产物标记 |
|
||||
|
||||
措辞登记(防口径混写):可推理率是整图级的"不靠赌占比",生成侧口径;P(安全) 是单格认知概率,决策侧口径——免赌集内 P(安全) 恒为 1,风险全部收缩到剩余盲猜集。本系统供给前者,不定义后者。
|
||||
| 生成期指标集 | 实际雷数与安全格数、目标雷数、重摇次数、剃雷数、开局免费展开格数 |
|
||||
|
||||
## P0 最小闭环
|
||||
|
||||
1. 战斗结算以(关卡序号,节点深度)调用生成,本系统开一条棋盘生成随机流。
|
||||
2. 读取并快照参数行(加载期校验已通过)。
|
||||
3. 先定数布雷、先布后删;出生区安全与反退化不变式全过。
|
||||
4. 实测可推理率,不达标在流内重试至上限,按三分支出图(变异布置不在本管线——装板后由战斗结算 布置段执行)。
|
||||
3. 先定数布雷、先布后删;出生区无雷检查过。
|
||||
4. 开局白给板检查,违例同流重摇直到不全开(变异布置不在本管线——装板后由战斗结算 布置段执行)。
|
||||
5. 交出棋盘 + 指标集:排雷玩法消费棋盘,战斗结算消费指标对账——循环闭合于下一次换图请求。
|
||||
|
||||
## P1 / P2 后置
|
||||
|
||||
| 优先级 | 内容 | 后置原因 |
|
||||
|---|---|---|
|
||||
| P1 | 调参期批量断言工具全量交付(逐行数百样本;可推理率零违例、及格线下限、非法产物零容忍、难度方向 advisory 与分位报告) | 调参期离线工具域;冒烟只载缩样 |
|
||||
| P1 | 与战斗结算的接线断言(图内重试不当作新流事件、对账消费实测分布) | 断言登记在对方验收清单 |
|
||||
| P1 | 调参期批量断言工具全量交付(逐行数百样本;确定性复现、出生区安全、白给板零容忍) | 调参期离线工具域;冒烟只载缩样 |
|
||||
| P1 | 与战斗结算的接线断言(图内重摇不当作新流事件、对账消费实测分布) | 断言登记在对方验收清单 |
|
||||
| P1 | 与排雷玩法的展开域回验集成 | 回验两臂登记在对方文档,集成随对方排期 |
|
||||
| P2 | 推理域扩展(solver_rules 启用其他规则集或新增信息源) | 改可推理率定义 = 文档修订,MVP 冻结 |
|
||||
| P2 | 生成异步化与成本闸正式值定稿 | 实现期决策,随性能预算批 |
|
||||
| P2 | ~~变异布置内容接入~~(已完成——布置执行位在战斗初始化第 4 步,管线零布置义务) | — |
|
||||
|
||||
## 调参表
|
||||
@@ -205,31 +157,20 @@
|
||||
|---|---|---|---|
|
||||
| board_width / board_height | int [8, 64] | 两档结构,现行面值见 board_gen.tres(provisional 参考行) | 图尺寸 |
|
||||
| mine_density | float (0, 0.5] | 现行值见 board_gen.tres | 雷密度,与尺寸解耦 |
|
||||
| inferability_target | float [0.85, 1] | 现行值见 board_gen.tres | 可推理率及格线;域下限 0.85 绝对锚 |
|
||||
| solver_rules | enum {single, single_subset} | single_subset(冻结,非调参) | 推理规则域 |
|
||||
| min_safe_count | int [1, 999] | 现行值见 board_gen.tres | 最小安全格数下限 |
|
||||
| max_gen_attempts | int [1, 32] | 域 [1, 32],现行按行取值见 board_gen.tres | 生成-验证重试上限;受成本闸联合约束 |
|
||||
| board_type | String,词表 {dungeon, underdark, deep_underdark} | 现行值见 board_gen.tres(词表 v1.1) | 图类型标签(玩家侧「地图类型」);域校验 = 词表成员检查 |
|
||||
| shave_ring_radius | int [0, 2] | 现行 1(board_gen.tres 全行) | 先布后删剃雷半径:剃雷域=距出生中心切比雪夫距离 ≤1+r 的格(r=1 → 5×5=25 格;r=0 即只剃出生 3×3 本身=无环剃雷)。调参项非结构冻结 |
|
||||
| r0_max_cap | int [出生格数, 板格数一半](护栏,违例加载期致命;出生格数=出生区边长自乘,读出生区行) | 现行按板形:10×10=45 / 12×12=43 / 13×13=51 / 14×14=59(board_gen.tres) | 自然 R₀(开局免费展开格数)上限闸=合法性门;超阈整板重掷、耗尽走三分出口。板面锚现行值 = 45/43/51/59(10×10 行经用户裁上调——r=1 自然均值 39>30 结构性倒挂;其余行维持 30% 锚) |
|
||||
| 出生区边长 | int [3, 5],奇数(中心对称,side = 2r+1);现行值读 board_gen.tres 表头 | 表头全局单值(非逐行) | 玩家出生区为以出生中心对称的 side×side 方区,区内恒无雷;布雷域基与 r0_max_cap 护栏下限均由它导出(格数 = side²)。入表后格数零字面量 |
|
||||
| 出生区边长 | int [3, 5],奇数(中心对称,side = 2r+1);现行值读 board_gen.tres 表头 | 表头全局单值(非逐行) | 玩家出生区为以出生中心对称的 side×side 方区,区内恒无雷;布雷域基由它导出(格数 = side²)。入表后格数零字面量 |
|
||||
|
||||
结构冻结(非调参项):键结构与每关深度 0 锚行、四阶段顺序(变异布置段已移出管线)、solver_rules、可推理率的合法信息源枚举、及格线域下限 0.85、成本闸常数(结构护栏,登记在案,调整走文档修订)、先布后删语义。
|
||||
结构冻结(非调参项):键结构与每关深度 0 锚行、四阶段顺序(变异布置段已移出管线)、先布后删语义、出板检查只两条(出生区无雷、开局不全开)。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- 确定性复现:同参数行同种子生成两遍,格状态与指标集逐位相同;换种子产物不全同。
|
||||
- 出生区安全:出生 3×3 与开局免费展开域内零雷(零变异由布置段顺序保障——生成器产物恒零变异格)。
|
||||
- 数字恒真:每个非危险格的数字恒等于其八邻雷数。
|
||||
- 布雷纪律:N ≥ 1、实际雷数 ≤ N、实际安全格数 ≥ min_safe_count。
|
||||
- 无开局白给板:开局免费展开域 ≠ 全部安全格,违例尝试弃用重试。
|
||||
- 可清图:每个安全格都能从出生区沿安全格八向连通到达;合法性闸先于质量评分。
|
||||
- 及格线:每张图实测可推理率 ≥ 该行及格线;任何行及格线 ≥ 0.85。
|
||||
- 重试有界:实际重试次数落在 [1, max_gen_attempts];同一次生成内的重试不开新随机流。
|
||||
- 成本闸:max_gen_attempts × 宽 × 高超过成本闸护栏常数(结构护栏常数,见棋盘参数表字段定义)的行加载期被拒;同种子同参数在任意机器上出图逐位一致。
|
||||
- 降级诚实:零合法板照常出图,必带非法产物标记与最高级告警;进程不死锁,玩家界面得到诚实告知。
|
||||
- 加载期校验:布雷数下限、计数可行性、标签非空等违例组合加载期致命。
|
||||
- 黄金图回归:手工核验小板集的可推理率输出与登记整数对逐位相等(整数对比对,禁浮点容差);换生成参数(推理定义、信息源、定义版本号)必须重制向量并入版本库。
|
||||
- R₀≤cap 闸:每张出图自然 R₀ ≤ 该行 r0_max_cap(合法板),或带非法产物标记(接受最不坏·诚实降级);闸触发次数入指标集 r0_cap_rejected。
|
||||
- 布雷纪律:N ≥ 1、实际雷数 ≤ N。
|
||||
- 无开局白给板:开局免费展开域 ≠ 全部安全格,违例同流重摇。
|
||||
- 重摇同流:同一次生成内的重摇不开新随机流;重摇次数入指标集。
|
||||
- 加载期校验:布雷数下限、尺寸与密度域、标签词表等违例组合加载期致命。
|
||||
- 黄金图回归:手工核验小板集的整板格状态与登记向量逐位相等;换生成参数必须重制向量并入版本库。
|
||||
- 剃雷域参数化:剃雷域=出生中心切比雪夫 ≤1+shave_ring_radius 的方域,出图 ring_removed ≤ 域内候选危险格数 (3+2r)²−9。
|
||||
- 表实一致:配置表字段与棋盘参数表字段定义一致。
|
||||
- 表实一致:配置表字段与棋盘参数表字段定义一致。
|
||||
@@ -1,7 +1,7 @@
|
||||
# 行动经济
|
||||
|
||||
> 一句话:每轮行动点怎么花、停手与刷新的代价
|
||||
> 状态:已定稿;现行为 v1.7
|
||||
> 状态:已定稿;现行为 v1.8
|
||||
|
||||
## 设计目的
|
||||
|
||||
@@ -180,7 +180,7 @@ action 型格面资源:正向行 ap_up = 下轮行动点 +1,负向行 ap_dra
|
||||
<text x="340" y="348" text-anchor="middle" dominant-baseline="central" font-family="sans-serif" font-size="12" fill="#B5D4F4">弃图刷新=推理死路的退路,不是更划算的打法</text>
|
||||
</svg>
|
||||
|
||||
**结论**:前四条契约由战斗结算作为唯一对账责任方闭合验收;第五条是行为说明,不设对账读数。概率侧由棋盘生成的可推理率参数锚定;条款3 数值层由 β 比值带 [1.2, 2.5] 判读看护(清图支配性审计为常设重跑项),封印边际结构层由条件二封印溢价接替(机制载体 settlement.flag_hit_premium)。
|
||||
**结论**:前四条契约由战斗结算作为唯一对账责任方闭合验收;第五条是行为说明,不设对账读数。条款3 数值层由 β 比值带 [1.2, 2.5] 判读看护(清图支配性审计为常设重跑项),封印边际结构层由条件二封印溢价接替(机制载体 settlement.flag_hit_premium)。
|
||||
|
||||
推导:
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ HUD框架站在玩家与全部玩法系统之间:挖掘期它是输入的翻
|
||||
|
||||
| 区 | 位置与几何 | 管什么 |
|
||||
|---|---|---|
|
||||
| B 战斗画面 | 全宽,高读布局表 `stage_h`(背景三关变体+连续地面层高另读 `ground_h`) | 三关舞台背景+连续地面层、主角站桩立绘、敌人站桩立绘 ×1–3(**全站桩形态,2026-09-20 用户拍板:无框立绘+底座、状态小图标挂血条下,英雄卡/敌人卡退役**)、轮次阶段指示、结算明细带 |
|
||||
| B 战斗画面 | 全宽,高读布局表 `stage_h`(背景三关变体+连续地面层高另读 `ground_h`) | 三关舞台背景+连续地面层、主角站桩立绘、敌人站桩立绘 ×1–3(**全站桩形态,2026-09-20 用户拍板:无框立绘+底座、状态小图标挂血条下,英雄卡/敌人卡退役**)、轮次阶段指示(结算明细带已退役,2026-11-10 用户裁——B 区零文字带,规格见 [battle.md](../../../ux/battle.md)「即时反馈画面化预览」节) |
|
||||
| C 角色信息 | 左下,宽读 `info_panel_w`,高 = 基准屏高 − B 区高 | 生命 / 攻击 / 储备数据框、状态效果槽、小人立绘 |
|
||||
| D 扫雷图 | 中下,宽 = 基准屏宽 − C 区宽 − 列间距,高同 C 区(2026-11-07 顶栏搬两侧:D 区全高归棋盘) | 左/右行动资源侧栏、棋盘本体、toast 槽(棋盘底常驻操作提示条退役) |
|
||||
|
||||
@@ -80,7 +80,7 @@ HUD框架站在玩家与全部玩法系统之间:挖掘期它是输入的翻
|
||||
|
||||
### 提示与弹层:轻提示随起随消、重弹层排队进出
|
||||
|
||||
界面弹出的东西分两族。toast(从棋盘区上缘内侧浮出的轻提示条)是非模态的:弹出期间玩家照常操作棋盘,约 2.5 秒自动消退、不劫持输入。模态覆盖层(弹出期间挡住下方操作、要先处理才能继续的那种弹层)则相反,图例面板、结算明细回看、胜负终局画面都属于这族。
|
||||
界面弹出的东西分两族。toast(从棋盘区上缘内侧浮出的轻提示条)是非模态的:弹出期间玩家照常操作棋盘,约 2.5 秒自动消退、不劫持输入。模态覆盖层(弹出期间挡住下方操作、要先处理才能继续的那种弹层)则相反,图例面板、胜负终局画面都属于这族(结算明细回看覆盖层已随明细带退役报废,2026-11-10 用户裁)。
|
||||
|
||||
| 弹出物 | 模态性 | 进出规则 |
|
||||
|---|---|---|
|
||||
@@ -195,12 +195,12 @@ HUD框架站在玩家与全部玩法系统之间:挖掘期它是输入的翻
|
||||
|---|---|---|
|
||||
| 上游 | [排雷玩法](../排雷循环/排雷玩法.md) | 棋盘只读投影(格态、数字、封印印记、小人)与移动路径查询;玩家意图批次经组合根提交 |
|
||||
| 上游 | [行动经济](../排雷循环/行动经济.md) | 行动点 / 储备 / 相位只读值;刷新入口可用性预判加返回值兜底 |
|
||||
| 上游 | [战斗结算](../战斗循环/战斗结算.md) | 明细流水是结算明细带的统一数据源(现行 9 类行封闭协议);段序编排信号经组合根接线 |
|
||||
| 上游 | [战斗结算](../战斗循环/战斗结算.md) | 明细流水 9 类行封闭协议(明细带已退役——流水消费面=日志落盘与回放对账,HUD 不再消费);段序编排信号经组合根接线 |
|
||||
| 上游 | [敌人系统](../战斗循环/敌人系统.md) | 英雄与敌人的只读投影(血量、顺位、摇定动作〔技能标识·类型·名称〕、敌方增益、存活——经战斗结算呈现快照;敌人技能池定稿:当前拍/行动环进度字段拆除,池与权重不公开) |
|
||||
| 上游 | [增益状态](../战斗循环/增益状态.md) | 状态投影经战斗结算呈现面取得,零直读 |
|
||||
| 上游 | [地图战斗资源](../战斗循环/地图战斗资源.md) | 已开格奖励身份投影(只读回调,组合根注入)零直读 |
|
||||
| 上游 | [关卡节点地图](../冒险循环/关卡节点地图.md) | 节点链、当前节点、跨战斗生命携带的读数;胜利后推进 |
|
||||
| 下游 | [战斗表现](../战斗循环/战斗表现.md) | 交付三区布局、明细带呈现位、敌人呈现语义(站桩形态);它只叠加动画密度与演出 |
|
||||
| 下游 | [战斗表现](../战斗循环/战斗表现.md) | 交付三区布局、敌人呈现语义(站桩形态);它只叠加动画密度与演出(明细带呈现位随带退役,2026-11-10 用户裁) |
|
||||
| 下游 | [音频](音频.md) | 挂点事件源(明细行类型流、toast 触发);MVP 无音频 |
|
||||
| 下游 | [教学引导](教学引导.md) | toast 与图例面板两个承载位——教学内容装进这两个容器 |
|
||||
| 下游 | [设置与本地化](设置与本地化.md) | 中文字体随包、按钮宽度等契约的消费方 |
|
||||
@@ -225,7 +225,7 @@ HUD框架站在玩家与全部玩法系统之间:挖掘期它是输入的翻
|
||||
1. 进入战斗屏:三区同屏就绪,半秒内首格可点。
|
||||
2. 挖掘期鼠标操作经单意图帧整批提交(唯一写路径,经组合根)。
|
||||
3. 回执链:组合根重查只读面,界面字段级就地刷新。
|
||||
4. 轮末进入结算:棋盘区锁输入,明细带展开逐行兑现(战斗结算流水驱动)。
|
||||
4. 轮末进入结算:棋盘区锁输入,结算演出在棋盘与立绘上逐段兑现(战斗结算段序驱动;明细带已退役)。
|
||||
5. 终局呈现(胜利 / 失败)伴随状态全清与储备清零反馈。
|
||||
6. 关卡末清库反馈:义务载体 = 秘宝背包(关卡域库存——秘宝过渡形态机械惰性承载,投放渠道全退役后恒空;拆线归实装批,见[战斗结算](../战斗循环/战斗结算.md)「轮次生命周期」节注)。
|
||||
|
||||
@@ -244,7 +244,7 @@ HUD框架站在玩家与全部玩法系统之间:挖掘期它是输入的翻
|
||||
|
||||
## 调参表
|
||||
|
||||
本系统的参数全部是呈现节奏与可读性常量,不是玩法数值——玩法数值一律归[数据配置](数据配置.md)的表,与本表无关。修订本文常量走文档修订流程。**本表常量无数据表承载,为文档面唯一事实源;入驻 .tres 时本列改指路。** 布局几何(B 区高 / B 区连续地面层高 / C 区宽 / D 区侧栏宽 / 明细带两态高)已入驻 `game/data/tables/battle_layout.tres`,不在本表重复。
|
||||
本系统的参数全部是呈现节奏与可读性常量,不是玩法数值——玩法数值一律归[数据配置](数据配置.md)的表,与本表无关。修订本文常量走文档修订流程。**本表常量无数据表承载,为文档面唯一事实源;入驻 .tres 时本列改指路。** 布局几何(B 区高 / B 区连续地面层高 / C 区宽 / D 区侧栏宽 / 明细带两态高〔已不被游戏视图读取,字段删除归工具批〕)已入驻 `game/data/tables/battle_layout.tres`,不在本表重复。
|
||||
|
||||
| 参数 | 域 | 现行值(文档自持,无表承载) | 说明 |
|
||||
|---|---|---|---|
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 数据配置
|
||||
|
||||
> 一句话:数值表与单一事实源管线
|
||||
> 状态:已定稿;现行为 v1.4
|
||||
> 状态:已定稿;现行为 v1.5
|
||||
|
||||
## 设计目的
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
| 表 | 载什么 | 回填责任方 |
|
||||
|---|---|---|
|
||||
| 行动经济表 | 每轮行动点、动作价目、停手与刷新门槛 | [行动经济](../排雷循环/行动经济.md) |
|
||||
| 棋盘生成参数表 | 板尺寸、雷密度、可推理率目标等(进度键表) | [棋盘生成](../排雷循环/棋盘生成.md) |
|
||||
| 棋盘生成参数表 | 板尺寸、雷密度、图类型等(进度键表) | [棋盘生成](../排雷循环/棋盘生成.md) |
|
||||
| 变异表 | 变异类型清单(现行六行:region 六行两轴×三关;global 整图型贫矿脉行已删,global 型机制代码保留) | [地形变异](../排雷循环/地形变异.md) |
|
||||
| 敌人表 | 敌种基线数值、遭遇数量区间、护甲类型、技能池模板(进度键表) | [敌人系统](../战斗循环/敌人系统.md) |
|
||||
| 技能表 | 技能行定义(类型/倍率/冷却/增益引用/触发条件)与保底阈值 | [敌人系统](../战斗循环/敌人系统.md) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 设置与本地化
|
||||
|
||||
> 一句话:设置项与多语言
|
||||
> 状态:范围草案·最小设置面已兑现;现行为 v1.2
|
||||
> 状态:范围草案·最小设置面已兑现;现行为 v1.3
|
||||
|
||||
## 设计目的
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
| 设置项清单与语义 | 收拢全游戏的可调选项;目前能确证的输入见核心规则一节,全集待设计 |
|
||||
| 减动效开关 | 可访问性基线已承诺的选项:开启后动画有时长减半或直达终态的通路 |
|
||||
| 音量控制入口 | 音量在设置里调(接口位,白话:给对方预留的接入位置;生效侧归音频系统) |
|
||||
| 多语言生产流程 | 全部玩家可见文案的翻译生产与语言切换——教学引导已在"不负责"表登记归本文 |
|
||||
| 多语言生产流程 | 全部玩家可见文案的翻译生产与语言切换——教学引导已在"不负责"表登记归本文;文案承载细则(key 单点、strings.csv 承载)已闭合,归 `design/engineering/code-conventions.md` §2.5 |
|
||||
| 调试面板退役后的常规设置 | 切片调试面板 TunePanel 正式版退役,其常规设置部分归本文(见核心规则) |
|
||||
|
||||
不负责:
|
||||
@@ -119,6 +119,6 @@ MVP 不要求本系统的闭环:[不做清单](../../05-不做清单.md)把设
|
||||
1. 设置项全集:画面、键位、可访问性、语言各类别各收哪些项——目前有来源的只有减动效与音量入口两条。
|
||||
2. 设置持久化(已拍板 2026-09-19):独立存储,不随存档——系统级设置一安装一份;具体文件格式与读写时机随存档序列化对齐(设置域归本系统所有)。
|
||||
3. 语言清单与字体覆盖:做哪些语言,字体对相应字符集的覆盖怎么保证。
|
||||
4. 文案生产流程:文本键(每条文案在工程里的唯一编号,机器据此找到译文)怎么管理、谁负责校对、翻译在流程的哪一步介入。
|
||||
4. 文案生产流程:文本键(每条文案在工程里的唯一编号,机器据此找到译文)的管理规则已闭合——文案 key 单点、文案值住 strings.csv(data/l10n/),细则 = `design/engineering/code-conventions.md` §2.5;尚待设计的是谁负责校对、翻译在流程的哪一步介入。
|
||||
5. 设置界面的入口与形态:从哪里打开、什么时刻可以打开——与 HUD 框架协作定。
|
||||
6. 键位映射表是否转化为改键设置项。
|
||||
@@ -1,7 +1,7 @@
|
||||
# 秘宝
|
||||
|
||||
> 一句话:营地装配、整局冒险生效的角色机能件——操作包络加强(视野/行动点/刷新/挖掘距离等),不出角色战斗属性值、不改战斗结算机制(经济与操作参数——视野/距离/行动点/刷新/转存率——属操作包络;分界规则归[核心循环](../../01-核心循环.md)「道具三层职责与分界」节)
|
||||
> 状态:已定稿(现行形态=局外同调件);现行为 v1.3
|
||||
> 状态:已定稿(现行形态=局外同调件);现行为 v1.5
|
||||
> 定位与形态:见下节
|
||||
> 术语:本文件的项目术语(同调位/RAP/GP/真视/危险格/整图等)定义见[术语表](../../术语表.md)
|
||||
|
||||
@@ -145,18 +145,7 @@
|
||||
|
||||
凡是"直接告诉你危险格在哪"的效果(下文称真视),一次最多照亮 3×3 的窗口,任何道具都不允许全图看雷。全图级范围只留给恢复推理原料类的效果——显影、预读这类把已有事实交还玩家的信息,允许大范围(原则上被允许,见不做清单的边界锚)。这条限制写进数据校验:任何真视类道具的目标域字段超过 3×3,加载数据时直接返回错误并拒绝——护栏由加载期强制,不靠运行时拦截。
|
||||
|
||||
**道具的收益在"少赌",不在"单赌更安全"**:信息类道具不改变棋盘,只减少玩家必须盲赌的次数。真视把 k 格移出盲挖候选域——这 k 格从"要赌"变成"必避或必封印"的确定决策;情报类道具抬高棋盘可推理率,收缩"只能赌"的格子池。单次盲赌的命中率会随格子池收缩而上升,这是正常读数——收益按"赌的次数变少、期望踩雷下降"计,不按单次命中率计。
|
||||
|
||||
```
|
||||
残余盲赌安全格数 n_s = (1 − ι) × |S|
|
||||
单次盲赌踩雷概率 P(雷) = |M| ÷ (|M| + n_s)
|
||||
```
|
||||
|
||||
| 变量 | 含义 | 来源 |
|
||||
|---|---|---|
|
||||
| ι | 棋盘可推理率(不必赌、可直接推理开挖的格子占比) | [棋盘生成](../排雷循环/棋盘生成.md)的整图实际值 |
|
||||
| \|M\| / \|S\| | 板上危险格数 / 安全格数 | 棋盘事实 |
|
||||
| n_s | 推理覆盖之外、只能盲赌的安全格数 | 上式派生 |
|
||||
**道具的收益在"少赌",不在"单赌更安全"**:信息类道具不改变棋盘,只减少玩家必须盲赌的次数。真视把 k 格移出盲挖候选域——这 k 格从"要赌"变成"必避或必封印"的确定决策;情报类道具收缩"只能赌"的格子池。收益按"赌的次数变少、期望踩雷下降"计,不按单次命中率计。
|
||||
|
||||
设计意图一句话:恢复推理的效果可以大,代替推理的效果必须小而贵——花钱全图看雷,等于把扫雷换成走格子。定量当量换算归[战斗结算](../战斗循环/战斗结算.md)的效果对照表,MVP 不入表。
|
||||
|
||||
@@ -236,7 +225,7 @@
|
||||
|
||||
结构冻结(非调参项,改动走本文修订流程):真视窄域护栏、零信息目标不消耗、边缘窗口照常受理、使用零行动点成本、同调位装配与充能每冒险重置、用后不可逆、零随机。
|
||||
|
||||
效果声明形态(在役沿用):被动件的效果行为=**订阅行**——行内声明**订阅哪个事件(on)/ 什么条件(when)/ 什么效果(do)**,由效果引擎统一解释执行;主动件按效果类型通用分发(受理闸=使用事件订阅);常时参数面件(阔视野带/储备罐/远程镐/信标网络/刷新练习/刷新执照六件)effect_kinds 挂参数 kind、由注入面按装配集分发读取;试炼镐=自动兑付(ap_charge_safe 满 charge_n 直接 grant_ap)。事件/效果类型/条件事实/算子四词表封闭(效果引擎单一事实源);卡面效果摘要=行 `desc` 字段直读(文案表值化)。现行目录 14 件的效果行已落地登记。
|
||||
效果声明形态(在役沿用):被动件的效果行为=**订阅行**——行内声明**订阅哪个事件(on)/ 什么条件(when)/ 什么效果(do)**,由效果引擎统一解释执行;主动件按效果类型通用分发(受理闸=使用事件订阅);常时参数面件(阔视野带/储备罐/远程镐/信标网络/刷新练习/刷新执照六件)effect_kinds 挂参数 kind、由注入面按装配集分发读取;试炼镐=自动兑付(ap_charge_safe 满 charge_n 直接 grant_ap)。事件/效果类型/条件事实/算子四词表封闭(效果引擎单一事实源);卡面效果摘要=行 `desc_key` 经 strings.csv 取文案(code-conventions §2.5)。现行目录 14 件的效果行已落地登记。
|
||||
|
||||
playtest 预警(预注册,归难度曲线与Boss):
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 锻造工坊
|
||||
|
||||
> 一句话:营地的武器与护甲成长——武器锻造区三条路线、护甲锻造区三条路线各练各的,钥石消费,一次冒险各选一件,满级特效留位本期不做
|
||||
> 状态:**v0.13**——全部数值 provisional,终值归 Alpha 收官 M4 数值批〔未排期〕
|
||||
> 状态:**v0.14**——全部数值 provisional,终值归 Alpha 收官 M4 数值批〔未排期〕
|
||||
## 设计目的
|
||||
|
||||
用户原案(playnote 2026-10-06):把现役"营地花钱买攻击 +1"改造成有等级、有成长、有满级特效的**武器升级路线**;新增长枪(穿刺)与法杖(魔法)实现武器间差异化;护甲同理——初始只有轻甲(升级只提 AC),最高等级后解锁重甲/魔法护甲,基础 AC 各异、各带满级特效。
|
||||
@@ -126,10 +126,10 @@
|
||||
- **奇物属性件**:分层并存,互不侵入。武器/护甲锻造动的是**账号层基础值**(营地永久强化,冒险开始时经参数面传入);奇物属性件动的是**单次冒险加算区**(关间不清零、冒险结束清零)。本设计不扩奇物"生命/AC/攻击"三轴封闭分类、不动渠道开关表、不往局内池加任何东西。入战 AC 的三层语义清晰可加:甲型基础 AC + 营地甲路线等级加值 + 局内加算区累加。
|
||||
- **克制矩阵(2a 裁:伪裁点消解)**:**伤害结算只有一套,类型不是待仲裁的槽位**。每份伤害单据自带攻击类型栏——主角基础攻击单据取当前武器的攻击类型,棋盘格面直伤件(穿刺弹 / 魔法矢)取奖励表自身的类型——各自按**同一张 3×3 克制矩阵**取克制修正。因此"叠加 / 替代 / 互斥"三分法不成立:两根参数之间无冲突可裁,也不需要任何共存规则。二者的真实差异只在**单据形态与生命周期**(主角基础攻击走掷点折扣 + 暴击;棋盘克制直伤走必中全额不掷点;且前者 = 账号层永久、后者 = 局内一次性)——那是两条不同的伤害来源,不是两种类型语义。矩阵九格满格结构冻结(2b 随 3a 自动消解:魔法护甲 = 现役 ward,不存在第四甲型)。
|
||||
- **工作间两区定名 + 路线行名(8a 裁)**:锻造工坊工作间内先立两个分区,各装三条锻造路线(路线行名统一为"件名 + 锻造")——①**武器锻造区**:长剑锻造 / 长枪锻造 / 法杖锻造;②**护甲锻造区**:轻甲锻造 / 重甲锻造 / 魔法护甲锻造。两区并列、机制层面零顺序门槛(A③ 裁),区内路线各自独立升级。
|
||||
- **局内不存在武器/护甲的提升(8a 裁连带核结)**:用户指出"局内没有可以提升武器的地方"——**属实**。查实:局内商店货架的三行(现名"攻击祝福 / 生命祝福 / 护甲祝福"),**正是奇物「属性值提升」三轴(攻击 / 生命上限 / AC)的货架前台标签**——`shop.tres` pool_shelf 六行用种类字段指向冒险表的奇物种类词表(其中凭证行为显式豁免种、不入该词表,六行中五行命中),`display_name` 只是这层的前台名;买到的东西进**冒险加算区**、冒险结束清零。所以它们是**奇物属性件**,既不是武器也不是护甲,局内不改变任何锻造等级。命名上的隐患确凿:行名里的"锻"字与营地锻造同字,是误读的直接来源。**命名(2026-10-12 用户裁)**:三行按「属性 + 后缀」改名,后缀取 **祝福** ⇒ **攻击祝福 / 生命祝福 / 护甲祝福**(D&D 参照调研:Blessing 为"神赐恩惠"义;用户同时裁定——参考书目里出现过「祝福」一词不构成禁用)。**改名后这三条在语感上彻底脱离"锻造"一词,与营地工作间不再有字面关联**,而结构关系不变(仍是奇物「属性值提升」三轴,机制分类名不动,只改玩家向显示名)。改名已执行完毕(shop.tres 六行锻升→祝福;reward.tres / status_effects.tres 护甲强化→盾牌加护)。
|
||||
- **局内不存在武器/护甲的提升(8a 裁连带核结)**:用户指出"局内没有可以提升武器的地方"——**属实**。查实:局内商店货架的三行(现名"攻击祝福 / 生命祝福 / 护甲祝福"),**正是奇物「属性值提升」三轴(攻击 / 生命上限 / AC)的货架前台标签**——`shop.tres` pool_shelf 六行用种类字段指向冒险表的奇物种类词表(其中凭证行为显式豁免种、不入该词表,六行中五行命中),`display_key` 只是这层的前台名索引(文案值住 strings.csv,code-conventions §2.5);买到的东西进**冒险加算区**、冒险结束清零。所以它们是**奇物属性件**,既不是武器也不是护甲,局内不改变任何锻造等级。命名上的隐患确凿:行名里的"锻"字与营地锻造同字,是误读的直接来源。**命名(2026-10-12 用户裁)**:三行按「属性 + 后缀」改名,后缀取 **祝福** ⇒ **攻击祝福 / 生命祝福 / 护甲祝福**(D&D 参照调研:Blessing 为"神赐恩惠"义;用户同时裁定——参考书目里出现过「祝福」一词不构成禁用)。**改名后这三条在语感上彻底脱离"锻造"一词,与营地工作间不再有字面关联**,而结构关系不变(仍是奇物「属性值提升」三轴,机制分类名不动,只改玩家向显示名)。改名已执行完毕(shop.tres 六行锻升→祝福;reward.tres / status_effects.tres 护甲强化→盾牌加护)。
|
||||
- **专长联动**:现役专长均为跨攻击类型通用件(不按 attack_type 分系——既无 normal 条件件、也无 pierce/magic 条件件,`feats.tres` 29 行实证),武器类型差异只经克制矩阵的 matchup 行体现;「选某类型激活某系专长」在本项目专长体系下不成立。现有死条件 `magic_vs_magic`(魔法打"魔法甲"——现行甲域无此型,永不可触发 = 废卡):**复活作废**——所属件魔网织者在素材库表二退役名单,该行已随专长退役消解,本系统零触碰。「魔法打魔法护甲」的克制语义由矩阵九格承载(magic vs ward = −1),新专长框架如需同类件 = 彼批的新卡设计题。
|
||||
- **天赋树**:同钥石经济;注入面分层叠加且**所有权切分**(2026-10-11 裁)——树脊柱只持生命/命中淬炼(树零攻防来源),攻/AC 唯一入口=本系统路线加值(只按当前选中武器/甲生效)。
|
||||
- **冒险前资源配比预设批(挂起冻结中)**:本设计不预设该批的重启口径、不占用其任何冻结裁决、不改其冻结文本。该批重启时须显式核对两处交汇面:①预算包络是否把武器类型计入克制注;②容量柜台与锻造工坊工作间(同在营地)的资源竞争关系。
|
||||
- **冒险前资源配比预设批(已退役)**:2026-11-09 用户裁该提案不做,原案留底见 [冒险前资源配比预设退役素材库](../../../content-archive/冒险前资源配比预设退役素材库.md);本设计不再挂该批的重启口径与两处交汇面核对义务。
|
||||
|
||||
## 裁决结果清单
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 术语表
|
||||
|
||||
> 全库专用术语的唯一对照表(2026-10-11 用户令建立)。规矩:新术语先登记本表、再在文档使用;退役词见文末对照表,文档正文一律使用现行词。文档中遇到看不懂的词,查本表。用词纪律(禁用词、替换值、豁免范围)见「用语规范」节。
|
||||
> 状态:**现行 v1.29**——2026-10-11 建立;历次升版明细见 git 提交史。
|
||||
> 状态:**现行 v1.30**——2026-10-11 建立;历次升版明细见 git 提交史。
|
||||
|
||||
## 格与棋盘
|
||||
|
||||
@@ -122,6 +122,13 @@
|
||||
| 逐需求点验收清单 | 需求卡片验证闸的必备清单:每个需求点列明测什么(具体断言或行为)/怎么测(测试落点与注入方式)/谁验(自动闸或用户目检);查不出验收条目的需求点=卡片不成立(规矩见 req-card 技能,测试落码写法见 [code-conventions](../engineering/code-conventions.md) §3.5) |
|
||||
| 测试方式两分法 | 能力验证与体验验证分开走(2026-10-11 用户定):能力验证=通过调试接口直接修改游戏数据(改钥石/槽位/解锁状态等,不走正常资源积累流程);体验验证=用户目检完整流程,登记体验验证清单观测项 |
|
||||
|
||||
## 文案承载(2026-11-09 用户裁立)
|
||||
|
||||
| 术语 | 定义 |
|
||||
|---|---|
|
||||
| 文案 key | 玩家可见文案的唯一索引键(点分命名如 `clear_reward.title`):数据表行与代码只持 key,文案值住 strings.csv(data/l10n/,key 列+`zh_CN` 列),取文案走承载细则的单点接口;硬纪律原文 = [code-conventions](../engineering/code-conventions.md) §2.5 |
|
||||
| strings.csv | 文案值的唯一承载文件(data/l10n/strings.csv):第一列文案 key、第二列中文文案,Alpha 单中文列;加语言=加列,多语言生产仍归[设置与本地化](systems/表现与支撑/设置与本地化.md)后置排期 |
|
||||
|
||||
## 用语规范(2026-10-15 用户令立)
|
||||
|
||||
词面纪律的登记处。通用禁用词与选词以**简明技术中文(STC)词表**为权威:外部同名词表,约 170 条,配检查脚本。
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> **Status**: Complete(现行)
|
||||
> **Author**: user + ux-designer
|
||||
> **Last Updated**: 2026-11-09
|
||||
> **Last Updated**: 2026-11-10
|
||||
> **Platform Target**: PC (Steam)——Keyboard/Mouse 主(全部操作纯鼠标可完成)、Gamepad Partial 非 MVP、Touch None(同 technical-preferences)
|
||||
> **上游修订依赖**: 弃图刷新挖掘期受理依赖上游现行规则(行动经济 Active 受理 + 每轮上限 2 次、排雷玩法 Active·仅刷新路径装板、战斗结算的挖掘期刷新编排 + 恒同盘不变、系统索引的刷新规则同步——见布局决策 4 与 OQ11)
|
||||
> **Template**: UX Spec
|
||||
@@ -100,7 +100,7 @@
|
||||
- **B 区战斗画面**
|
||||
- 主角站桩:立绘、HP 血条、状态效果小图标行 ← **HP 与状态的唯一展示面**(2026-09-26 拍板:C 区同信息展示退役)
|
||||
- 敌人站桩 ×1–3:HP 血条、顺位徽标、状态小图标行、意图徽标、护甲类型图标(AC 数值不展示——2026-09-26 终裁)
|
||||
- 兑现演出区 / 结算明细带 / 轮次·阶段指示
|
||||
- 兑现演出区 / 轮次·阶段指示(结算明细带已退役,2026-11-10 用户裁)
|
||||
- **C 区角色信息(规划数据框)**
|
||||
- 攻击值 + 修正来源角标(战斗在消费、且站桩上无展示)
|
||||
- 护甲 AC(2026-09-26 二轮拍板补入——我方 AC 的唯一展示面;掷点判定轴,受击侧可读性)
|
||||
@@ -115,11 +115,11 @@
|
||||
|
||||
### Layout Zones
|
||||
|
||||
采用用户拍板的布局图(2026-09-12),按 1280×800 基座落尺寸。**分区几何的唯一事实源 = `game/data/tables/battle_layout.tres`**(经 `ConfigDb.presentation.battle_layout` 读取;字段 `stage_h` / `ground_h`(B 区连续地面层高)/ `info_panel_w` / `side_rail_w`(D 区行动资源侧栏宽,2026-11-07 顶栏搬两侧后新增)/ `log_band_h_dig` / `log_band_h_settle`;游戏视图不再读 `ap_bar_h`;布局表字段暂留供样张渲染工具,删除归工具批)。本节只写结构关系与内容职责,不复写数值;任何文档与代码不另立第二份布局值。
|
||||
采用用户拍板的布局图(2026-09-12),按 1280×800 基座落尺寸。**分区几何的唯一事实源 = `game/data/tables/battle_layout.tres`**(经 `ConfigDb.presentation.battle_layout` 读取;字段 `stage_h` / `ground_h`(B 区连续地面层高)/ `info_panel_w` / `side_rail_w`(D 区行动资源侧栏宽,2026-11-07 顶栏搬两侧后新增)/ `log_band_h_dig` / `log_band_h_settle`;游戏视图不再读 `ap_bar_h` 与 `log_band_h_dig`/`log_band_h_settle`(明细带退役,2026-11-10 用户裁);布局表字段暂留供样张渲染工具,删除归工具批)。本节只写结构关系与内容职责,不复写数值;任何文档与代码不另立第二份布局值。
|
||||
|
||||
| 区 | 位置与几何 | 内容 |
|
||||
|---|---|---|
|
||||
| **B 战斗画面** | 全宽,高读 `stage_h`(2026-10-06 方案二拍板:演出 ≈1/3 屏) | 主角站桩立绘(左)+ 兑现演出区(中)+ 敌人站桩立绘 ×1–3(右)——**全站桩形态(2026-09-20 用户拍板):主角与敌人均为无框立绘+底座,零卡片**;主角与敌人站桩 = **HP 与状态效果的唯一展示面(2026-09-26 信息归属拍板)**;底部结算明细带(挖掘期收起高读 `log_band_h_dig`,结算期展开高读 `log_band_h_settle`);顶部中央轮次·阶段指示 |
|
||||
| **B 战斗画面** | 全宽,高读 `stage_h`(2026-10-06 方案二拍板:演出 ≈1/3 屏) | 主角站桩立绘(左)+ 兑现演出区(中)+ 敌人站桩立绘 ×1–3(右)——**全站桩形态(2026-09-20 用户拍板):主角与敌人均为无框立绘+底座,零卡片**;主角与敌人站桩 = **HP 与状态效果的唯一展示面(2026-09-26 信息归属拍板)**;结算明细带已退役(2026-11-10 用户裁,B 区零文字带,规格见「即时反馈画面化预览」节);顶部中央轮次·阶段指示 |
|
||||
| **C 角色信息** | 左下,宽读 `info_panel_w`,高 = 基准屏高 − B 区高 | 攻击值(含修正显示)、护甲 AC;秘宝槽、奇物列表(现行标题「特性」)——HP 条/RAP 池/状态效果槽/立绘占位/钱包行退役(2026-09-26 信息归属拍板:HP 与状态唯一展示面 = B 区站桩;RAP 迁 D 区右栏;GP/钥石迁出战斗屏) |
|
||||
| **D 扫雷图** | 中下,宽 = 基准屏宽 − C 区宽 − 列间距,高同 C 区(2026-11-07 顶栏搬两侧:**D 区全高归棋盘**,不再让出 AP 条高度;棋盘不缩,格边按公式现算) | 左栏(宽读 `side_rail_w`,贴棋盘左缘):AP 点阵 + 停手按钮;右栏(同宽,贴棋盘右缘):RAP 点阵+数字 + 图例按钮 + 弃图刷新按钮(RAP 贴唯一消费口,2026-09-26 拍板);棋盘主体居中(格边长见下方「棋盘格尺寸公式」;上方留 44px 给浮空数字越出棋盘,下方 12px+悬崖 8px);toast 槽(D 区上缘内侧左栏顶部,不覆盖棋盘与浮空数字);棋盘底常驻操作提示条退役(2026-11-07 用户裁,不占棋盘高度) |
|
||||
|
||||
@@ -190,6 +190,69 @@
|
||||
|
||||
算例不入文档:棋盘区可用面积随布局表与板型变化,不是契约值——现算并绘在整屏样张上,本文件不复写。
|
||||
|
||||
### 即时反馈画面化预览(2026-11-10 用户裁:明细带退役+清图兑付浮字+Boss 解锁技零提示;三屏预览 2026-11-10 用户人审通过)
|
||||
|
||||
**清图兑付浮字**:全图最后一块安全格开启的瞬间,在既有金粒喷泉+彩纸(§2.3)之上,兑付内容以**单行浮字**自棋盘中央上方升起——只写兑付值(例:「全体敌人 14 伤害」),无「清图奖励」标题、无底牌、不遮棋盘任何格;替代退役前的「清图奖励:××」toast。浮字规格:字高 17px(基座档)、暖白字芯+2px 深墨描边+微金光晕,约 2.5s 内上浮约 40px 并渐隐,时序落在喷泉 3–5s 窗口内、先于换新图 install。
|
||||
像素判据:浮字全程不与棋盘格面重叠(浮字底缘恒在棋盘上缘上方 ≥6px);渐隐连续无跳变(帧间 alpha 步进 ≤0.1);兑付值在浮字生命期 ≥60% 时长内保持全可读。
|
||||
|
||||
**Boss 解锁技零提示**:解锁拍(Boss 血量跌破闩阈值)**不新增任何 UI 元素**——血条跌破本身即视觉事件,「我把它打到半血 → 它亮新招」因果自明;下一拍开轮摇中新技时,既有意图徽标(类型级预告,敌人系统 Rule 8⑤)按现行规格自然顶头,具名随预告承载。原「一次性技能名 toast」规格退役([敌人系统](../gdd/systems/战斗循环/敌人系统.md) v2.1 同步改写)。
|
||||
像素判据:解锁拍 B 区新增可见元素数为 0(与前一帧逐元素比对);意图徽标几何沿用现行规格(悬浮头顶上方、探顶档压胸),零新增资产。
|
||||
|
||||
**战斗屏纵向**:明细带退役后 B 区舞台(高读 `stage_h`)直连 D 区——挖掘期 D 区可用高 +24、结算期 +84,棋盘格边按「棋盘格尺寸公式」现算放大,公式与垂直预留(上 44 / 下 12)不变;`log_band_h_dig`/`log_band_h_settle` 不再被游戏视图读取。
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 920 240" width="920" height="240">
|
||||
<rect x="0" y="0" width="920" height="240" fill="#2E2620"/>
|
||||
<g font-family="sans-serif" font-size="12" fill="#C9AF83">
|
||||
<text x="150" y="20" text-anchor="middle">清图兑付浮字</text>
|
||||
<text x="460" y="20" text-anchor="middle">解锁拍(零新增)</text>
|
||||
<text x="770" y="20" text-anchor="middle">下拍开轮(意图徽标顶头)</text>
|
||||
</g>
|
||||
<!-- 屏1 棋盘+浮字 -->
|
||||
<g>
|
||||
<rect x="30" y="60" width="240" height="150" fill="#3A332A" stroke="#55483A" stroke-width="2"/>
|
||||
<g fill="#57503F">
|
||||
<rect x="38" y="68" width="28" height="26"/><rect x="70" y="68" width="28" height="26"/><rect x="102" y="68" width="28" height="26"/><rect x="134" y="68" width="28" height="26"/><rect x="166" y="68" width="28" height="26"/><rect x="198" y="68" width="28" height="26"/><rect x="230" y="68" width="28" height="26"/>
|
||||
<rect x="38" y="98" width="28" height="26"/><rect x="70" y="98" width="28" height="26"/><rect x="102" y="98" width="28" height="26"/><rect x="134" y="98" width="28" height="26"/><rect x="166" y="98" width="28" height="26"/><rect x="198" y="98" width="28" height="26"/><rect x="230" y="98" width="28" height="26"/>
|
||||
<rect x="38" y="128" width="28" height="26"/><rect x="70" y="128" width="28" height="26"/><rect x="102" y="128" width="28" height="26"/><rect x="134" y="128" width="28" height="26"/><rect x="166" y="128" width="28" height="26"/><rect x="198" y="128" width="28" height="26"/><rect x="230" y="128" width="28" height="26"/>
|
||||
<rect x="38" y="158" width="28" height="26"/><rect x="70" y="158" width="28" height="26"/><rect x="102" y="158" width="28" height="26"/><rect x="134" y="158" width="28" height="26"/><rect x="166" y="158" width="28" height="26"/><rect x="198" y="158" width="28" height="26"/><rect x="230" y="158" width="28" height="26"/>
|
||||
</g>
|
||||
<g fill="#F0C75E"><circle cx="70" cy="82" r="2"/><circle cx="130" cy="74" r="2"/><circle cx="200" cy="88" r="2"/><circle cx="100" cy="140" r="2"/><circle cx="220" cy="168" r="2"/></g>
|
||||
<g fill="#E06050"><rect x="90" y="70" width="5" height="7" transform="rotate(20 92 73)"/></g>
|
||||
<g fill="#5AA0D8"><rect x="160" y="66" width="5" height="7" transform="rotate(-15 162 69)"/></g>
|
||||
<text x="150" y="52" text-anchor="middle" font-family="sans-serif" font-size="15" font-weight="500" fill="#F5EAD0" stroke="#17130F" stroke-width="0.8" paint-order="stroke">全体敌人 14 伤害</text>
|
||||
<text x="150" y="228" text-anchor="middle" font-family="sans-serif" font-size="10" fill="#8A7D68">浮字底缘恒在棋盘上缘上方 ≥6px</text>
|
||||
</g>
|
||||
<!-- 屏2 解锁拍零新增 -->
|
||||
<g>
|
||||
<rect x="340" y="60" width="240" height="150" fill="#241F19"/>
|
||||
<rect x="340" y="158" width="240" height="52" fill="#443B2C"/>
|
||||
<rect x="376" y="94" width="56" height="60" rx="6" fill="#4D443A"/>
|
||||
<rect x="376" y="158" width="56" height="5" fill="#33291F"/><rect x="376" y="158" width="40" height="5" fill="#B8483D"/>
|
||||
<text x="404" y="176" text-anchor="middle" font-family="sans-serif" font-size="11" fill="#C9BDA1">探险者</text>
|
||||
<rect x="516" y="88" width="68" height="66" rx="6" fill="#5A4436"/>
|
||||
<rect x="516" y="158" width="68" height="5" fill="#33291F"/><rect x="516" y="158" width="29" height="5" fill="#D8863D"/>
|
||||
<text x="550" y="176" text-anchor="middle" font-family="sans-serif" font-size="11" fill="#C9BDA1">石君王 42%</text>
|
||||
<text x="460" y="120" text-anchor="middle" font-family="sans-serif" font-size="11" fill="#6B6052">(无任何新增元素)</text>
|
||||
<text x="460" y="228" text-anchor="middle" font-family="sans-serif" font-size="10" fill="#8A7D68">血条跌破即视觉事件 · B 区新增元素数 = 0</text>
|
||||
</g>
|
||||
<!-- 屏3 意图徽标顶头 -->
|
||||
<g>
|
||||
<rect x="650" y="60" width="240" height="150" fill="#241F19"/>
|
||||
<rect x="650" y="158" width="240" height="52" fill="#443B2C"/>
|
||||
<rect x="686" y="94" width="56" height="60" rx="6" fill="#4D443A"/>
|
||||
<rect x="686" y="158" width="56" height="5" fill="#33291F"/><rect x="686" y="158" width="40" height="5" fill="#B8483D"/>
|
||||
<text x="714" y="176" text-anchor="middle" font-family="sans-serif" font-size="11" fill="#C9BDA1">探险者</text>
|
||||
<rect x="820" y="88" width="68" height="66" rx="6" fill="#5A4436"/>
|
||||
<rect x="820" y="158" width="68" height="5" fill="#33291F"/><rect x="820" y="158" width="29" height="5" fill="#D8863D"/>
|
||||
<text x="854" y="176" text-anchor="middle" font-family="sans-serif" font-size="11" fill="#C9BDA1">石君王</text>
|
||||
<rect x="838" y="46" width="32" height="32" rx="5" fill="#2C2415" stroke="#B8483D" stroke-width="2"/>
|
||||
<text x="854" y="68" text-anchor="middle" font-size="15" fill="#F0C75E">⛰</text>
|
||||
<rect x="834" y="82" width="40" height="16" rx="3" fill="#000000" fill-opacity="0.55"/>
|
||||
<text x="854" y="94" text-anchor="middle" font-family="sans-serif" font-size="10" fill="#D8C9A1">岩崩</text>
|
||||
<text x="770" y="228" text-anchor="middle" font-family="sans-serif" font-size="10" fill="#8A7D68">既有意图徽标规格 · 几何零改动</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
### Component Inventory
|
||||
|
||||
| 区 | 组件 | 类型 | 内容 | 交互 | 载体 |
|
||||
@@ -197,8 +260,8 @@
|
||||
| B | 主角站桩立绘 | 站桩(无框立绘+落影) | HP 条落底盘(2026-10-06 方案二拍板:站桩排式 = **立绘→血条→状态**,全场血条对齐一线;血条嵌石板位、台缘线留作地面线;不悬浮头顶——高盒下血条-立绘空洞,用户点名否决)、状态效果小图标一排挂血条正下方(形状+色相双通道、层数角标;空态不占位退化为空行)——**HP 与状态效果的唯一展示面(2026-09-26 信息归属拍板;悬停 tooltip〔来源+语义+剩余结算次数〕职责在本组件)**;攻击值等规划数据仍归 C 区数据框(2026-09-20 全站桩拍板,英雄卡退役) | 悬停状态小图标看 tooltip | HUD 视图拆分改造 |
|
||||
| B | 敌人站桩立绘 ×1–3 | 站桩(无框立绘+落影) | 血条+顺位徽标落底盘(同主角排式,2026-10-06 方案二;**大体档〔显示 >150px 级:drider/duergar_king〕允许向上溢出盒顶 N px(N 由实装实算,溢出判定与背景无关),血条仍落底**)、状态小图标挂血条正下方(敌方增益按个体呈现——各立绘只显示它自己名下的状态实例〔蓄力/硬化/削弱/暴走/警觉,2026-11-02 个体化裁〕;数据源 = 战斗结算流水经增益状态投影,敌人系统×4④;无行为环点〔proposal §2.4〕,意图占位 = 本拍摇定结果的动画占位——普通攻击零表示 / 特殊技类型级提示,**意图徽标悬浮头顶上方,探顶档压胸**,敌方增益〔蓄力/硬化〕入状态图标行);死亡灰化加碎裂退场直接演在立绘上(2026-09-20 全站桩拍板,敌人卡退役);血条下名字行 = 纯名字 + 护甲类型图标(形状+色相双通道,与状态图标同行共存,状态空时为纯名字),AC 数值不展示——2026-09-26 终裁(用户口径:HP 信息已足够,攻防数值不直接写上;护甲类型图标保留克制对策可读性——类型可读、数值隐藏) | 只读 | 新建 |
|
||||
| B | 轮次·阶段指示 | 标签 | "第 N 轮 · 挖掘中/结算中"(终局定格「战斗结束」;Boss 变体附 Boss 名) | 只读 | 新建 |
|
||||
| B | 结算明细带 | 摘要位+叙述行 | 逐行流水文字呈现已退役(2026-11-07 用户裁):挖掘期显示上轮摘要 1 行与冒险叙述行,结算期空带+FX 排播链承接演出;流水协议保留在数据面([战斗结算](../gdd/systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋) 9 类行协议,供日志落盘与回放对账) | 无明细回看——带保留单行摘要,冒险中回看归「生涯」 | 改造 |
|
||||
| B | 结算明细回看(已退役) | —— | 冒险中回看归「生涯」;回看覆盖层为未接线遗留件(待办清单登记) | —— | 未接线 |
|
||||
| B | 结算明细带(已退役) | —— | 明细带整条退役(2026-11-10 用户裁):挖掘期摘要位为恒空死区(写入函数随 2026-11-07 逐行退役批删除)、冒险叙述行对玩家零信息增量——舞台底高归还(挖掘期 +24 / 结算期 +84 归 D 区棋盘区,格边按「棋盘格尺寸公式」现算);冒险叙述行六类随带全砍——关卡开场数字归 C 区数据框(同值重复)、恢复点回血归节点弹窗、商店 GP 归商店浮层、钥石结算归胜负浮层账行、节点横幅与岔路口文字砍(节点类型与可选交互自明);逐行流水文字呈现此前已退役(2026-11-07 用户裁);流水协议保留在数据面([战斗结算](../gdd/systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋) 9 类行协议,供日志落盘与回放对账) | —— | 退役 |
|
||||
| B | 结算明细回看(已退役) | —— | 冒险中回看归「生涯」;回看覆盖层为未接线遗留件,与明细带同批报废(2026-11-10 用户裁) | —— | 退役 |
|
||||
| C | 攻击数据框 | 直角细线数据框 | 攻击值 + 修正来源角标 + 护甲 AC(AC 二轮拍板 2026-09-26 补入——我方 AC 唯一展示面;HP 与状态归 B 区站桩、RAP 归 D 区右栏,不在本组件) | 只读 | HUD 视图拆分 |
|
||||
| C | 秘宝槽 | 图标槽 ×4 | 四槽壳在役、空槽占位(标题「秘宝」,悬停「秘宝槽(空)」);局内两步使用与关卡域库存随秘宝过渡形态退役——现行秘宝 = 营地同调装配件(秘宝.md),本区展示重接归装配面 | 悬停 tooltip | 已实装 |
|
||||
| C | 奇物列表(现行标题「特性」) | 列表/图标行 | 已实装——逐件行「件名 ×N」呈现、零内部分类字样;锻造/大奖励/关卡奖励节点获得的属性提升——中循环数据,因改变战斗数学且无其他展示面准入战斗屏;与战斗内状态效果(B 区站桩)分区,防「战斗结束被清」误读 | 只读 | 已实装 |
|
||||
@@ -214,6 +277,8 @@
|
||||
| 全屏 | 胜利/失败 overlay | 模态 | 金蜡封/暮蓝收印 + 判定行(无明细回看入口——回看归「生涯」) | 继续/下一节点 | 已实装 |
|
||||
| 调试 | 调试浮窗 | 调试面板 | 种子/数值调整/批量模拟/两层调试入口(发布态恒隐,无 UI 开启口;调试开关门控口径见「调试变体」行;调参面板已退役入调试浮窗) | 调试 | 调试浮窗 |
|
||||
|
||||
> **按钮组等宽纪律(2026-11-09 用户裁)**:同一直接父容器内 ≥2 个可见按钮,宽度必须相等(差 ≤1px)——组内等宽,结构探针 equal_width 审计按本句全站执行。现行例:AP 条停手钮与图例钮同横排容器,两钮宽度统一 64px。
|
||||
|
||||
**布局决策 2 —(已删除,编号留空)**:编号留空,免布局决策 3/4 的既有交叉引用失锚。
|
||||
|
||||
**布局决策 3 — 移动路径预览 = 合法性指示**(排雷玩法×6⑤ 悬案裁决):悬停已开格时高亮 BFS 路径(小人蓝细线点迹),移动执行为 ≤150ms 短滑。
|
||||
@@ -247,9 +312,7 @@
|
||||
│ (落影) [ 兑现演出区 ] /蛆虫\ /蛆虫\ │
|
||||
│ HP▓▓▓▓░ (结算期: 光带→弹道→受击) ①HP▓▓▓░ ②HP▓▓░░ │
|
||||
│ ⬆2 🛡1 ←血条状态落底排·全场对齐(状态空 = 名字行)〔意图徽标悬浮头顶上方〕 │
|
||||
│ ├─ 结算明细带 ────────────────────────────────────────────────────────────┤ │
|
||||
│ │ ▸上轮: 主角攻击3→蛆虫-3 | 攻击+50%(1结算) | 警觉+1×2 … │ │
|
||||
│ └────────────────────────────────────────────────────────────────────────┘ │
|
||||
│ (明细带已退役——舞台直连 D 区,挖掘期 +24 / 结算期 +84 归棋盘区) │
|
||||
├─[C] 角色信息 ─────────┬─[D] 扫雷图(顶栏已搬两侧) ───────────────────────────┤
|
||||
│ ┌──────────────────┐ │ ┌──────┐ ┌───────────────────────────┐ ┌──────┐ │
|
||||
│ │ 攻击 6 (+50%) │ │ │ AP │ │ (上方 44px 留白) │ │ RAP │ │
|
||||
@@ -373,8 +436,8 @@
|
||||
| State / Variant | Trigger | What Changes |
|
||||
|---|---|---|
|
||||
| **挖掘阶段(默认态)** | 轮次开始 / 结算完毕回 Active 相位 | B 区敌人待机(意图徽标全程可见——敌人系统 Rule 8⑤),D 区棋盘可交互,左右行动资源侧栏点亮;能量 2/10,唯悬停呼吸微光在动(§2.1) |
|
||||
| **结算阶段** | round_end 触发(AP 尽/停手/清图) | D 区锁输入(棋盘去饱和 + 金橙色相偏移,明度不变,数字保持全对比);B 区播放五段编排演出(授予段 → 增益/减益段 → 战斗段 → 衰减段 → 判定段,战斗结算 段序冻结);明细带按结算期档展开(高读 `log_band_h_settle`)——settle 态空带+叙述行承载,零逐行文字;阶段指示→"结算中";能量 7/10 |
|
||||
| **清图瞬间** | 全部安全格开完 | 金粒喷泉 + 彩纸 3–5s 即收(§2.3);清图奖励行强调呈现(H2,地图战斗资源×④——金框高亮行);随后换新图 install |
|
||||
| **结算阶段** | round_end 触发(AP 尽/停手/清图) | D 区锁输入(棋盘去饱和 + 金橙色相偏移,明度不变,数字保持全对比);B 区播放五段编排演出(授予段 → 增益/减益段 → 战斗段 → 衰减段 → 判定段,战斗结算 段序冻结);明细带已退役——结算演出全程在棋盘与立绘上,零文字带;阶段指示→"结算中";能量 7/10 |
|
||||
| **清图瞬间** | 全部安全格开完 | 金粒喷泉 + 彩纸 3–5s 即收(§2.3);兑付浮字随喷泉升起——只写兑付内容(如「全体敌人 14 伤害」),无标题、无底牌、不遮棋盘(规格与像素判据见「即时反馈画面化预览」节);随后换新图 install |
|
||||
| **完美封印高光** | 战斗结算高光判定(全图标中/零误标类) | 全屏喝彩级反馈(§2.2 最高档):金光带加倍扫射 + 「完美封印 ×2」横幅——P2 爆发兑现节点(创意风险 #2 落点) |
|
||||
| **封印标中高光** | 封印判定·标中 | 该印记化暴击弹道加重 + 明细行金框——chord 缺席的即时兑现补偿(创意风险 #3 落点) |
|
||||
| **敌人死亡呈现** | 敌 hp=0(流水行击杀标记) | 该敌人立绘血条归零 → 立绘灰化 + 碎裂退场(**禁瞬消**——敌人系统资产下限「死亡瞬间须可辨识、禁止直接消失」,同等 blocking);战斗段短路的重击被掐灭不产行动明细行,由行序可推断(战斗结算);动画密度归战斗表现,呈现语义在本 spec |
|
||||
@@ -440,7 +503,7 @@
|
||||
| 时刻 | 过渡 | 依据 |
|
||||
|---|---|---|
|
||||
| 进入战斗屏 | 棋盘 install 淡入(200ms)+ 初始 3×3 展开涟漪 + Boss 战先播紫赤影子爬棋盘(§2.6) | 棋盘生成 install / §2.6 |
|
||||
| 挖掘→结算 | 明细带自底展开(150ms)+ 棋盘去饱和 + 金橙色相偏移 + 阶段指示翻转 | §2.2 色彩转金橙主导、饱和拉高、明度不变(状态区分经饱和/色相——art-bible §2) |
|
||||
| 挖掘→结算 | 棋盘去饱和 + 金橙色相偏移 + 阶段指示翻转 | §2.2 色彩转金橙主导、饱和拉高、明度不变(状态区分经饱和/色相——art-bible §2) |
|
||||
| 结算逐行兑现 | 光带自棋盘行起点横扫 → 开格化箭雨/印记化暴击弹道飞向敌人立绘 → 受击闪白 + 血条直角递减 | §2.2 承载元素;因果全程可见可归因(P2) |
|
||||
| 清图换新图 | 金粒喷泉 3–5s → 旧图碎裂淡出 → 新图 install 淡入 | §2.3 短促丰收不拖节奏 |
|
||||
| RAP 清零(冒险收束) | RAP 数字滚动归零(D 区右栏)+「随冒险结束消散」微文案 | 行动经济可见反馈义务 |
|
||||
@@ -495,7 +558,6 @@
|
||||
|
||||
- **源语言中文(CJK)**:运行时默认字体无 CJK 字形——**CJK 字体随包为硬性前置**(已锁),实现 AC 覆盖
|
||||
- **按钮文案单行约束**:「停手」「弃图刷新」——按钮宽度按 4 汉字上限设计;译为英文("Hold"/"Reroll")不超 1.6× 不破版;德语长词("Aufgeben+Neu"类复合词)风险 HIGH——弃图刷新按钮允许两行或图标+缩写
|
||||
- **明细带行文案**:来源标注格式「{行为} {值} → {目标}(来源)」为模板插值,最长 token = 来源标签(4 汉字,如「清图奖励」「封印未中」——战斗结算的来源标签封闭枚举);行模板预留 40% 膨胀宽度(固定槽高 + 裁剪兜底)
|
||||
- **数字格式**:全部整数,无本地化格式需求;AP 点阵为图形载体不依赖文本
|
||||
- **术语表锚定**:封印/雷/停手/弃图刷新/轮次/结算 已在 GDD 体系内定名,译文须同步 `design/gdd/术语表.md`
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
1. 用 Godot 4.7.2 打开本目录(含 `project.godot` 的文件夹)
|
||||
2. 按 F5 运行(主场景 `presentation/main.tscn`)
|
||||
3. **主入口:`▶ 开始冒险(三关连探:地精洞窟 → 幽暗地域 → 灰矮人矿城)`**——一条命走完三关(生命/GP/加算区跨关同账、非末关的关卡完成发大奖励〔上限提升+血回满+钥石〕、任意战斗倒下冒险终、结算屏出冒险摘要五件事;选路停点可「放弃冒险」(同失败结算));首关节点链:战→战→赏→战→战→疗→王。唯一试玩入口 = 完整冒险——单关测试直入口(L2/L3)已退役(2026-09-23 用户拍板)
|
||||
4. 调试浮窗(功能面:攻击/生命百分比加成〔模拟天赋树解锁〕+ 批量模拟〔输出关卡完成率/承伤期望/败北节点分布〕+ 两层调试入口)——发布态入口恒隐(调试角标不显示、浮窗无 UI 开启口;开发期临时启用改 `_debug_entry` 缺省本地不提交),浮窗体系整体退役属发布工程批
|
||||
4. 调试浮窗(功能面:攻击/生命百分比加成〔模拟天赋树解锁〕+ 批量模拟〔输出关卡完成率/承伤期望/败北节点分布〕+ 两层调试入口)——调试入口常驻(右下角「调试」角标恒亮、真点开浮窗;2026-11-09 用户特批恢复批)
|
||||
|
||||
headless 冒烟(断言计数随断言面增减浮动,以当次跑测打印为准,含关卡线性推进/满配冒险成功/裸装败北/回放确定性):
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ var meta: MetaProgressionCore:
|
||||
get:
|
||||
return get_node(AUTOLOAD_PATH_META)
|
||||
var logger = null # 试玩日志器(JSONL 持久化 + 卡死诊断转储——呈现层组件)
|
||||
var _debug_entry := false # 调试会话门控(缺省 false=发布态:角标恒隐、浮窗无 UI 开启口;沿革查 git log)
|
||||
var _debug_entry := false # 调试会话门控(写死=true——恒开:角标常驻点亮、浮窗入口常在;_ready 赋值;2026-11-09 用户特批恢复批——常驻调试入口,无发布前清理义务)
|
||||
var ui: UiRegistry # 界面注册面(ui_registry.gd——界面句柄/层序合同/模态编排句柄的单点宿主)
|
||||
var _confirm_consumer := "" # 确认弹窗消费方状态量(契约 3 编排——open 前设、分派后清)
|
||||
var _confirm_consumer_slot := 0 # 消费方附随槽号(delete_slot 消费方专用)
|
||||
@@ -135,7 +135,8 @@ func _ready() -> void:
|
||||
_build_ui()
|
||||
begin_session(false) # 闲时会话(gp_ledger 等探针注入面自 _ready 起恒在——ui_probe 合成段时序)
|
||||
ui.screens.start_overlay.visible = true
|
||||
ui.screens.debug_badge.visible = _debug_entry # 浮层角标可见性须门控落定后赋值(构建/连接在 _build_ui);_debug_entry 缺省 false=发布态恒隐
|
||||
_debug_entry = true # 调试入口门控写死=true(2026-10-16 用户令常量门控、2026-11-09 用户特批恢复——常驻调试入口,无发布前清理义务)
|
||||
ui.screens.debug_badge.visible = _debug_entry # 浮层角标可见性须门控落定后赋值(构建/连接在 _build_ui)
|
||||
# boot 菜单优先——启动不自动开浮窗(开始屏不得被调试面板盖住);
|
||||
# 调试入口=UI 最顶层全局浮层角标(LAYER_CONTRACT 末位 float 类,任何 UI 不遮挡)
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ func _mark_domain_counts(view: Node, tag: String) -> Dictionary:
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:84 (棋盘截图取证——渲染闸采集组)
|
||||
# 判据出处: design/engineering/test-conventions.md「7. 判定可靠性优先于覆盖率」跑一遍没崩 跑一遍没崩(棋盘截图取证——渲染闸采集组)
|
||||
# 运行前提=窗口化真渲染面(shot_probe 同款护栏——headless 下 frame_post_draw 永不触发+视口纹理恒空)
|
||||
if DisplayServer.get_name() == "headless":
|
||||
print("[board_shot] FAIL — 本探针必须窗口化运行(headless 无渲染面,截图必空);现行事实源=tools/render_gate.sh 取证段")
|
||||
@@ -259,7 +259,7 @@ func _ready() -> void:
|
||||
# 判据:环外径像素 ÷ 格边 落 0.82±1px;封印格最外圈 1px 框最暗值与相邻未封印未开格同位框最暗值差 ≤1/255
|
||||
#(halo 在 0.455×格边归零——格边框不应被压暗;相邻未开格同砖纹理同套瓦片为无封印参照)。
|
||||
func _seal_evidence(tag: String, view: Node, settlement: Object, off_img: Image, out: String) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:84 (封印印记像素取证组)
|
||||
# 判据出处: design/engineering/test-conventions.md「7. 判定可靠性优先于覆盖率」跑一遍没崩 跑一遍没崩(封印印记像素取证组)
|
||||
var ms = settlement.minesweeper
|
||||
var seal_cell := Vector2i(-9, -9)
|
||||
var ref_cell := Vector2i(-9, -9)
|
||||
@@ -367,7 +367,7 @@ func _probe_identity_lookup(c: Vector2i):
|
||||
# 双帧逐像素比对:所有变化像素必须落在生效格的内缘带内
|
||||
# (de < cell÷8——带外含砖心零侵入=禁整格染色/禁越圈);每个生效格须有实绘像素(不空转)。
|
||||
func _check_dual_frames(tag: String, view, glow_cells: Dictionary, off_img: Image, on_img: Image) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
var board = view.board()
|
||||
if board == null:
|
||||
_problems.append("%s 双帧比对取板失败(view.board() 为 null)" % tag)
|
||||
|
||||
@@ -8,7 +8,7 @@ extends Node
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗表现.md:148 (结算演出——挖掘期零打扰组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗表现.md「验收标准」挖掘期零打扰 (结算演出——挖掘期零打扰组)
|
||||
await get_tree().process_frame
|
||||
var problems: Array = []
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ var _problems: Array = []
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:84 (特效截图取证——渲染闸采集组)
|
||||
# 判据出处: design/engineering/test-conventions.md「7. 判定可靠性优先于覆盖率」跑一遍没崩 跑一遍没崩(特效截图取证——渲染闸采集组)
|
||||
var args := OS.get_cmdline_user_args()
|
||||
out_dir = args[0] if args.size() >= 1 and args[0] != "" else "user://qa-fx"
|
||||
DirAccess.make_dir_recursive_absolute(out_dir)
|
||||
@@ -108,7 +108,7 @@ func _ready() -> void:
|
||||
|
||||
|
||||
func _snap(tag: String) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
await RenderingServer.frame_post_draw
|
||||
var img: Image = get_viewport().get_texture().get_image()
|
||||
if img == null or img.is_empty():
|
||||
@@ -118,7 +118,7 @@ func _snap(tag: String) -> void:
|
||||
|
||||
|
||||
func _fail(msg: String) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
_problems.append(msg)
|
||||
push_error("[fx_shot_probe] FAIL — " + msg)
|
||||
get_tree().quit(1)
|
||||
@@ -19,7 +19,7 @@ var _est_reads: Dictionary = {} # 逐档 13/14 板推定读数留痕(label
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:264 (战斗屏三区几何与棋盘格边长——分辨率档位组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(战斗屏三区几何与棋盘格边长——分辨率档位组)
|
||||
await get_tree().process_frame
|
||||
var main: Node = load("res://presentation/main.tscn").instantiate()
|
||||
add_child(main)
|
||||
@@ -59,7 +59,7 @@ func _ready() -> void:
|
||||
|
||||
# 一份不变量断言,逐档代入——代码量与档数无关
|
||||
func _check_one(label: String, main: Node) -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:264 (单档几何断言组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(单档几何断言组)
|
||||
var vr: Rect2 = get_viewport().get_visible_rect()
|
||||
if vr.size != Vector2(VIEWPORTS[0]["size"]) and vr.size.y < 1.0:
|
||||
_problems.append("[%s] 逻辑视口退化 %s" % [label, vr.size])
|
||||
|
||||
@@ -11,7 +11,7 @@ extends Node
|
||||
const SEED_L3 := 910212 # 深图固定种子(与 level_map_viewport_probe 同源——图确定性承载)
|
||||
|
||||
func _ready() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:84 (关卡画面截图取证——载入守卫组)
|
||||
# 判据出处: design/engineering/test-conventions.md「7. 判定可靠性优先于覆盖率」跑一遍没崩 跑一遍没崩(关卡画面截图取证——载入守卫组)
|
||||
var args := OS.get_cmdline_user_args()
|
||||
var out_dir := args[0] if args.size() > 0 else "user://"
|
||||
await get_tree().process_frame
|
||||
@@ -45,7 +45,7 @@ func _settle() -> void:
|
||||
|
||||
|
||||
func _make_runner(entry: bool, node_id: int):
|
||||
# 判据出处: design/engineering/test-conventions.md:84 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「7. 判定可靠性优先于覆盖率」跑一遍没崩 跑一遍没崩(判定上报通道——验证函数组)
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
rng.new_adventure(SEED_L3)
|
||||
var runner = load("res://core/level_runner.gd").new(get_node("/root/ConfigDB"), rng)
|
||||
@@ -85,7 +85,7 @@ func _deepest_with_outs(screen, runner) -> int:
|
||||
|
||||
|
||||
func _shot(out_dir: String, fname: String) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:84 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「7. 判定可靠性优先于覆盖率」跑一遍没崩 跑一遍没崩(判定上报通道——验证函数组)
|
||||
DirAccess.make_dir_recursive_absolute(out_dir) # 落盘目录自建(save_png 对缺目录静默失败——刷新链不预建)
|
||||
var img := get_viewport().get_texture().get_image()
|
||||
var err := img.save_png(out_dir.path_join(fname))
|
||||
|
||||
@@ -22,14 +22,14 @@ var _runner # 当前停点的单关 runner(open_choices 驱动随记——
|
||||
|
||||
|
||||
func _check(desc: String, ok: bool) -> void:
|
||||
# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(判定上报通道——验证函数组)
|
||||
_checks += 1
|
||||
if not ok:
|
||||
_problems.append(desc)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# 判据出处: design/ux/level-map.md:3 (关卡画面视口跟随——卷轴视口组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(关卡画面视口跟随——卷轴视口组)
|
||||
await get_tree().process_frame
|
||||
await get_tree().process_frame
|
||||
var host := Control.new()
|
||||
@@ -62,7 +62,7 @@ func _ready() -> void:
|
||||
|
||||
## R1 浅图整幅居中无裁切+画布入视口件承载(画布=视口首子件——setup 注入序)
|
||||
func _probe_shallow_no_crop(screen, vp) -> void:
|
||||
# 判据出处: design/ux/level-map.md:3 (浅层不裁切组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(浅层不裁切组)
|
||||
_runner = _make_runner_entry(1, SEED_L1)
|
||||
screen.open_choices(_cand_nodes(_runner), _runner)
|
||||
await get_tree().process_frame
|
||||
@@ -81,7 +81,7 @@ func _probe_shallow_no_crop(screen, vp) -> void:
|
||||
|
||||
## R5 前置+深图入口停点:锚点=入口组包围盒中心夹紧(spec :101——多入口并列取包围盒居中)
|
||||
func _probe_deep_entry_clamp(screen, vp) -> void:
|
||||
# 判据出处: design/ux/level-map.md:3 (深层入口钳制组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(深层入口钳制组)
|
||||
_runner = _make_runner_entry(3, SEED_L3)
|
||||
screen.open_choices(_cand_nodes(_runner), _runner)
|
||||
await get_tree().process_frame
|
||||
@@ -175,7 +175,7 @@ func _probe_clamp_bounds_and_columns(screen, vp) -> void:
|
||||
|
||||
## R6 拖拽不触发选路提交;阈值另一侧完整点击仍提交(提交语义零改动)
|
||||
func _probe_drag_no_submit(screen, vp) -> void:
|
||||
# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(判定上报通道——验证函数组)
|
||||
# 重建到中段可居中停点(候选=停点出边——候选节点居屏中可拖可达)
|
||||
var stops := _centerable_stops(screen, vp)
|
||||
if stops.size() < 3:
|
||||
@@ -214,7 +214,7 @@ func _probe_drag_no_submit(screen, vp) -> void:
|
||||
|
||||
## R2 停点切换后当前节点居中(视口中线投影 x=640±2——视口满屏宽即屏中线)
|
||||
func _probe_follow_anchor(screen, vp) -> void:
|
||||
# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(判定上报通道——验证函数组)
|
||||
var stops := _centerable_stops(screen, vp)
|
||||
if stops.size() < 3:
|
||||
_problems.append("R2 可居中停点不足(=%d)" % stops.size())
|
||||
@@ -230,7 +230,7 @@ func _probe_follow_anchor(screen, vp) -> void:
|
||||
|
||||
## R7 平滑滚动有 tween 中间帧;减动效开=位置即达(画布坐标域判定)
|
||||
func _probe_smooth_scroll_reduced_motion(screen, vp) -> void:
|
||||
# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(判定上报通道——验证函数组)
|
||||
var saved_scale: float = UiKit.motion_scale
|
||||
UiKit.motion_scale = 1.0
|
||||
var stops := _centerable_stops(screen, vp)
|
||||
@@ -270,7 +270,7 @@ func _probe_smooth_scroll_reduced_motion(screen, vp) -> void:
|
||||
|
||||
## R8 指引件可见性与几何(深图超窗——像素级判据②③)
|
||||
func _probe_guidance_chrome(screen, vp) -> void:
|
||||
# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(判定上报通道——验证函数组)
|
||||
var band_l: Control = vp.get_node_or_null(NodePath("FadeL"))
|
||||
var band_r: Control = vp.get_node_or_null(NodePath("FadeR"))
|
||||
var chip: Control = vp.get_node_or_null(NodePath("PanHint"))
|
||||
@@ -302,7 +302,7 @@ func _probe_shallow_guidance_hidden(screen, vp) -> void:
|
||||
|
||||
## 入口停点 runner(defer_entry——选路态挂起、候选=入口节点)
|
||||
func _make_runner_entry(level_index: int, seed_val: int):
|
||||
# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(判定上报通道——验证函数组)
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
rng.new_adventure(seed_val)
|
||||
var runner = load("res://core/level_runner.gd").new(get_node("/root/ConfigDB"), rng)
|
||||
@@ -313,7 +313,7 @@ func _make_runner_entry(level_index: int, seed_val: int):
|
||||
|
||||
## 中段停点 runner(断点续玩重建——图由种子+参数档重生成同图,零 RNG 消耗)
|
||||
func _make_runner_at_stop(level_index: int, seed_val: int, node_id: int):
|
||||
# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(判定上报通道——验证函数组)
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
rng.new_adventure(seed_val)
|
||||
var runner = load("res://core/level_runner.gd").new(get_node("/root/ConfigDB"), rng)
|
||||
@@ -388,7 +388,7 @@ func _extreme_node(pos: Dictionary, nodes: Array, first: bool) -> Dictionary:
|
||||
|
||||
|
||||
func _finish() -> void:
|
||||
# 判据出处: design/ux/level-map.md:3 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(判定上报通道——验证函数组)
|
||||
if _checks == 0:
|
||||
_problems.append("零断言执行(断言数下限闸——三硬闸③)")
|
||||
if _problems.is_empty():
|
||||
|
||||
@@ -234,7 +234,7 @@ func _seen_into(node: Node, keys: Array[String]) -> void:
|
||||
# ---- 落盘(JSONP 式 .js——file:// 页面 <script src> 直载)----
|
||||
|
||||
func dump_js() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:30 (覆盖登记落盘守卫——判定上报通道组)
|
||||
# 判据出处: design/engineering/test-conventions.md「2. 场景级探针标配」每新增一个可交互 每新增一个可交互(覆盖登记落盘守卫——判定上报通道组)
|
||||
var dir := DirAccess.open("res://")
|
||||
if dir == null:
|
||||
push_error("[coverage] res:// 打不开,登记未落盘")
|
||||
|
||||
@@ -76,14 +76,14 @@ func _seals_text(f: Dictionary) -> String:
|
||||
|
||||
# ---- 流程状态位(与可见性是两回事,逐步单独判)----
|
||||
func _expect_adventure_seal(step: String, expect: bool) -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「呈现层装配与会话生命周期」 (状态位判据组)
|
||||
# 判据出处: design/engineering/architecture/architecture.md「呈现层装配与会话生命周期」呈现场景拆为三屏壳 呈现场景拆为三屏壳(状态位判据组)
|
||||
var got: bool = main.run_scope != null and main.run_scope.is_adventure
|
||||
if got != expect:
|
||||
_problems.append("%s:流程状态位 is_adventure 应为 %s,实测 %s" % [step, str(expect), str(got)])
|
||||
|
||||
|
||||
func _expect_exclusive(step: String, expect: String) -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「呈现层装配与会话生命周期」 (屏级互斥组)
|
||||
# 判据出处: design/engineering/architecture/architecture.md「呈现层装配与会话生命周期」呈现场景拆为三屏壳 呈现场景拆为三屏壳(屏级互斥组)
|
||||
var f: Dictionary = _screen_seals()
|
||||
var pairs := [["菜单", "营地"], ["菜单", "冒险"], ["营地", "冒险"], ["终局", "营地"], ["终局", "菜单"]]
|
||||
for pair in pairs:
|
||||
@@ -110,7 +110,7 @@ func _frames(n: int = 2) -> void:
|
||||
|
||||
# ---- ① boot:菜单独占 ----
|
||||
func _step_boot_menu() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:49 (boot 组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(boot 组)
|
||||
_expect_exclusive("①boot", "菜单")
|
||||
_expect_adventure_seal("①boot", false)
|
||||
if main.ui.modals.menu.debug_overlay != null and main.ui.modals.menu.debug_overlay.visible:
|
||||
@@ -119,7 +119,7 @@ func _step_boot_menu() -> void:
|
||||
|
||||
# ---- ② 菜单 → 营地(真实按钮信号路径)----
|
||||
func _step_menu_to_camp() -> void:
|
||||
# 判据出处: design/ux/camp.md:10 (菜单→营地组)
|
||||
# 判据出处: design/ux/camp.md「定位」存档内的局外枢纽 存档内的局外枢纽(菜单→营地组)
|
||||
# 营地经进档开层(卡② mn9 新路径——campbtn 已撤;槽模板注入隔离命名空间)
|
||||
if not await ProbeUiUtil.open_camp_via_savesel(main, "smoke_screen_flow_camp"):
|
||||
_problems.append("②菜单→营地:选档层新档钮缺失(新路径驱动中断)")
|
||||
@@ -130,7 +130,7 @@ func _step_menu_to_camp() -> void:
|
||||
|
||||
# ---- ③ 营地 → 菜单(回退路径:篝火二次确认动线——卡④ 营地唯一回菜单出口;选档层随关层收闭同收)----
|
||||
func _step_camp_back_to_menu() -> void:
|
||||
# 判据出处: design/ux/camp.md:22 (营地→菜单组)
|
||||
# 判据出处: design/ux/camp.md「场景构成与七物件绑定」半开的门扇 半开的门扇(营地→菜单组)
|
||||
if main.ui.modals.camp.scene == null:
|
||||
_problems.append("③营地→菜单:营地场景根句柄缺失〔句柄子容器批 V1〕")
|
||||
return
|
||||
@@ -147,7 +147,7 @@ func _step_camp_back_to_menu() -> void:
|
||||
# ---- 选档界面开合(卡③ sl10):函数直调开层(「进入存档」钮归卡② mn3)→屏级互斥采样→
|
||||
# 返回钮真实信号路径关闭→ESC 语境不响应(卡⑤ 契约 2 范围外——零实现即断言)。----
|
||||
func _step_save_select_open_back() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:61 (选档开合组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「系统范围」边界这样划 边界这样划(选档开合组)
|
||||
ProbeUiUtil.isolate_save(main, "smoke_screen_flow_savesel", false, false, true)
|
||||
main.save_manager.slots.attach_slot_template("user://smoke_screen_flow_savesel_slot_%d.json")
|
||||
var esb: Button = ProbeUiUtil.find_button(main.ui.screens.start_overlay, "进入存档", "prefix")
|
||||
@@ -194,7 +194,7 @@ func seals_check_single(f: Dictionary) -> bool:
|
||||
|
||||
|
||||
func _step_menu_to_adventure() -> void:
|
||||
# 判据出处: design/ux/level-map.md:11 (菜单→冒险组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(菜单→冒险组)
|
||||
# 开始冒险钮已随三入口化撤出——函数直调中间态(卡② mn10;卡④ 大门两分支换代)
|
||||
main._start_adventure_from_menu()
|
||||
await _frames(3)
|
||||
@@ -208,7 +208,7 @@ func _step_menu_to_adventure() -> void:
|
||||
|
||||
# ---- ⑤ 冒险内屏切换:关卡地图屏 ⇄ 战斗屏(屏内两态,屏级仍独占)----
|
||||
func _step_level_to_battle_and_back() -> void:
|
||||
# 判据出处: design/ux/battle.md:57 (冒险内切换组)
|
||||
# 判据出处: design/ux/battle.md「Entry & Exit Points」Entry Entry(冒险内切换组)
|
||||
if not main.ui.modals.run.level_screen.visible:
|
||||
_problems.append("⑤冒险内切换:前置不在关卡地图屏")
|
||||
return
|
||||
@@ -228,7 +228,7 @@ func _step_level_to_battle_and_back() -> void:
|
||||
|
||||
# ---- ⑥ 放弃 → 终局(放弃路径=回退路径的非正常出口)----
|
||||
func _step_abandon_to_end() -> void:
|
||||
# 判据出处: design/ux/level-map.md:42 (放弃→终局组)
|
||||
# 判据出处: design/ux/level-map.md「Navigation Position」放弃冒险 (放弃→终局组)
|
||||
if main.run_scope == null or main.run_scope.adventure == null:
|
||||
_problems.append("⑥放弃→终局:前置无冒险实例")
|
||||
return
|
||||
@@ -241,7 +241,7 @@ func _step_abandon_to_end() -> void:
|
||||
|
||||
# ---- ⑦ 终局 → 菜单(终局出口返回开始界面)----
|
||||
func _step_end_back_to_menu() -> void:
|
||||
# 判据出处: design/ux/settlement-summary.md:24 (终局→菜单组)
|
||||
# 判据出处: design/ux/settlement-summary.md「定位」承载两个 承载两个(终局→菜单组)
|
||||
if main.ui.modals.run.end_overlay == null or not main.ui.modals.run.end_overlay.visible:
|
||||
_problems.append("⑦终局→菜单:前置不在终局")
|
||||
return
|
||||
@@ -254,7 +254,7 @@ func _step_end_back_to_menu() -> void:
|
||||
|
||||
# ---- ③' 营地 Esc 浮窗+HUD(卡⑤——真实键盘合成路径 push_input;四态路由+三出口+语境分支+余额单口)----
|
||||
func _step_camp_esc_and_hud() -> void:
|
||||
# 判据出处: design/ux/camp.md:45 (Esc 段组)
|
||||
# 判据出处: design/ux/camp.md「叠层与开合」各界面开合走模态栈单口 各界面开合走模态栈单口(Esc 段组)
|
||||
ProbeUiUtil.isolate_save(main, "smoke_screen_flow_esc", false, false, true)
|
||||
if not await ProbeUiUtil.open_camp_via_savesel(main, "smoke_screen_flow_esc"):
|
||||
_problems.append("[esc] 营地入口缺失(选档层新档钮驱动中断)〔ESC批 V1〕")
|
||||
@@ -320,7 +320,7 @@ func _step_camp_esc_and_hud() -> void:
|
||||
# 判的是呈现形态换壳(近全屏面板→居中定尺寸窗壳 720×640):窗几何/场景根留底/遮罩 0.6/关闭钮/
|
||||
# 互斥单开/ESC 优先序/窗内滚动/生涯同壳——行为面(开合路由)零改,只钉窗壳可观测提交面。
|
||||
func _step_camp_window_shell() -> void:
|
||||
# 判据出处: design/ux/camp.md:45 (窗壳 V1–V8 组)
|
||||
# 判据出处: design/ux/camp.md「叠层与开合」各界面开合走模态栈单口 各界面开合走模态栈单口(窗壳 V1–V8 组)
|
||||
ProbeUiUtil.isolate_save(main, "smoke_screen_flow_winshell", false, false, true)
|
||||
if not await ProbeUiUtil.open_camp_via_savesel(main, "smoke_screen_flow_winshell"):
|
||||
_problems.append("[winshell] 营地入口缺失(选档层新档钮驱动中断)〔窗口化批 V1〕")
|
||||
@@ -478,7 +478,7 @@ func _step_camp_window_shell() -> void:
|
||||
|
||||
# 清窗经真实钮(逐窗巡检 visible→钮 pressed——栈 close 恢复账随层清空)
|
||||
func _close_all_windows(views: Dictionary) -> void:
|
||||
# 判据出处: design/ux/camp.md:45 (清窗组)
|
||||
# 判据出处: design/ux/camp.md「叠层与开合」各界面开合走模态栈单口 各界面开合走模态栈单口(清窗组)
|
||||
for k: StringName in [&"forge", &"chest", &"dummy", &"board"]:
|
||||
var w: Control = views[k]
|
||||
if not w.visible:
|
||||
|
||||
@@ -47,7 +47,7 @@ func _ready() -> void:
|
||||
await get_tree().process_frame
|
||||
# ① 菜单(启动态)——无帮助文腿(玩法速览牌不在画面,checker 无对应断言段);
|
||||
# 无副标题件,菜单文字锚只剩标题
|
||||
# 判据出处: design/engineering/code-conventions.md:54 模态覆盖层层级规则——boot 态顶层=start_overlay、菜单文字在屏(菜单组)
|
||||
# 判据出处: design/engineering/code-conventions.md「2.3 模态覆盖层层级规则」打开任何模态覆盖层时 打开任何模态覆盖层时、菜单文字在屏(菜单组)
|
||||
# 自检一:boot 态顶层可见全屏层=start_overlay(内容层树遍历——屏壳是容器不当候选:
|
||||
# camp 壳 boot 态 vis=true 但成员恒隐,裸树遍历自顶向下会先命中透明壳)
|
||||
var top: Node = null
|
||||
@@ -84,7 +84,7 @@ func _ready() -> void:
|
||||
_meta[String(pair[0])] = ProbeUiUtil.label_rect(main.ui.screens.start_overlay, String(pair[1]))
|
||||
await _snap("menu")
|
||||
# ①b 设置面(settingsbtn 真实信号路径,开合同款真实钮)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/设置与本地化.md:95 最小设置面已兑现:音量/减动效/全屏/退出,载体=独立设置存储+设置界面视图(设置组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/设置与本地化.md「P1 / P2 后置」独立设置存储 独立设置存储,载体=独立设置存储+设置界面视图(设置组)
|
||||
var setbtn: Button = ProbeUiUtil.find_button(main.ui.screens.start_overlay, "设置", "prefix")
|
||||
if setbtn == null:
|
||||
_problems.append("设置入口缺失(开始层 settingsbtn)")
|
||||
@@ -104,7 +104,7 @@ func _ready() -> void:
|
||||
ProbeUiUtil.push_click(main, set_close)
|
||||
await get_tree().process_frame
|
||||
# ①c 生涯页(函数直调中间态——卡② mn10:careerbtn 已撤,卡④ 笔记本改挂前无 UI 路径)
|
||||
# 判据出处: design/ux/camp.md:45 生涯页与四子界面同壳同形态(生涯组)
|
||||
# 判据出处: design/ux/camp.md「叠层与开合」各界面开合走模态栈单口 各界面开合走模态栈单口(生涯组)
|
||||
if true:
|
||||
main._open_career()
|
||||
for i in 3:
|
||||
@@ -124,14 +124,14 @@ func _ready() -> void:
|
||||
if main.ui.modals.menu.career_overlay.visible or not main.ui.screens.start_overlay.visible:
|
||||
_problems.append("生涯页关闭后页未隐藏或开始层未恢复")
|
||||
# ② 营地场景图(进档开层新路径——卡② mn9;截图=可点击场景图形态——卡④ 契约 9 V1 验收载体)
|
||||
# 判据出处: design/ux/camp.md:16 营地=可点击场景图(七物件命中区表——场景图形态组)
|
||||
# 判据出处: design/ux/camp.md「场景构成与七物件绑定」半开的门扇 半开的门扇(七物件命中区表——场景图形态组)
|
||||
if not await ProbeUiUtil.open_camp_via_savesel(main, "smoke_shot_probe_camp"):
|
||||
_problems.append("营地入口缺失(选档层新档钮——新路径驱动中断)〔句柄子容器批 V1〕")
|
||||
else:
|
||||
await get_tree().process_frame
|
||||
await _snap("camp")
|
||||
# ②b 营地五窗打开态(真点热点开窗→截→「返回」前缀真点关——screen_flow_probe 窗壳链同款)
|
||||
# 判据出处: design/ux/camp.md:45 五窗统一窗壳形态·互斥单开(营地窗态组)
|
||||
# 判据出处: design/ux/camp.md「叠层与开合」各界面开合走模态栈单口 各界面开合走模态栈单口(营地窗态组)
|
||||
for k: StringName in [&"forge", &"chest", &"dummy", &"board", &"notebook"]:
|
||||
ProbeUiUtil.push_click_at(main, main.ui.modals.camp.scene.get_hotspot_rect(k).get_center())
|
||||
for i in 3:
|
||||
@@ -157,16 +157,16 @@ func _ready() -> void:
|
||||
ProbeUiUtil.push_click_at(main, main.ui.modals.camp.scene.get_hotspot_rect(&"campfire").get_center()) # 收闭改接篝火动线(营地根态无关闭钮——卡④ T5)
|
||||
await get_tree().process_frame
|
||||
ProbeUiUtil.push_click(main, main.ui.modals.menu.confirm_dialog._confirm_btn) # 二次确认离场(关层收闭——选档层随收)
|
||||
# 判据出处: design/ux/camp.md:22 篝火=离开营地回主菜单、必须二次确认(篝心动线组)
|
||||
# 判据出处: design/ux/camp.md「场景构成与七物件绑定」必须二次确认 必须二次确认、必须二次确认(篝心动线组)
|
||||
await get_tree().process_frame
|
||||
# ③ 关卡画面(开始冒险→停点出图——入口停点语义;函数直调中间态 mn10)
|
||||
# 判据出处: design/ux/level-map.md:11 入口停点候选数=入口个数(关卡画面出图组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(关卡画面出图组)
|
||||
main._start_adventure_from_menu()
|
||||
for i in 4:
|
||||
await get_tree().process_frame
|
||||
await _snap("level")
|
||||
# GP 常驻徽章断言(读数=runner.gp 现值,刷新=写路径回执后重查〔open_choices〕)
|
||||
# 判据出处: design/ux/level-map.md:77 GP 常驻徽章=GP 图标+数字(冒险钱包读数;写路径回执后重查)
|
||||
# 判据出处: design/ux/level-map.md「Component Inventory」冒险钱包读数 冒险钱包读数(冒险钱包读数;写路径回执后重查)
|
||||
var gp_label: Label = ProbeUiUtil.find_label(main.ui.modals.run.level_screen, "◈ ")
|
||||
if gp_label == null or not gp_label.is_visible_in_tree():
|
||||
_problems.append("GP 徽章不可见(关卡画面顶栏)")
|
||||
@@ -175,7 +175,7 @@ func _ready() -> void:
|
||||
if gp_label.text != expect:
|
||||
_problems.append("GP 徽章读数不符: %s != %s" % [gp_label.text, expect])
|
||||
# ④ 战斗(节点一——candidate_rect 命中矩形真点选路提交,ui_click_probe 同款)
|
||||
# 判据出处: design/ux/battle.md:122 B 区构建:站桩/明细带/轮次指示(战斗出图与几何锚组)
|
||||
# 判据出处: design/ux/battle.md「Layout Zones」采用用户拍板的布局图 采用用户拍板的布局图(战斗出图与几何锚组)
|
||||
if main.ui.modals.run.level_screen != null and main.ui.modals.run.level_screen.visible:
|
||||
# 接触带呼吸相位冻结(board_shot_probe 同款:motion_scale<1.0 ⇒ 施静态带色)——
|
||||
# golden 基线逐像素比对禁动画相位抖动;必须在进战 rebuild 前置位(rebuild/带色施用按当时相位取样)
|
||||
@@ -192,14 +192,14 @@ func _ready() -> void:
|
||||
_meta["stage_view"] = _node_rect(main.ui.battle.stage)
|
||||
_meta["board_zone"] = _node_rect(main.ui.battle.board_zone)
|
||||
# draw calls 真机测量(基线 270→目标 <200;窗口化渲染帧读数,
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:264 同屏 draw calls < 200(战斗屏性能预算组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(战斗屏性能预算组)
|
||||
# 取值时机=战斗截图同帧后一帧——呈现终态满负荷)
|
||||
await get_tree().process_frame
|
||||
var dc := int(Performance.get_monitor(Performance.RENDER_TOTAL_DRAW_CALLS_IN_FRAME))
|
||||
_meta["battle_draw_calls"] = dc
|
||||
print("[shot_probe] battle draw_calls=%d(基线 270/目标 <200)" % dc)
|
||||
# ⑤ 状态面板(战斗屏状态角标真实信号路径;层在战斗屏之上开合)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:277 模态打开遮挡或输入锁定、关闭逐层恢复(状态面板组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」关闭逐层恢复 关闭逐层恢复、关闭逐层恢复(状态面板组)
|
||||
var pb: Button = main.ui.battle.board_zone.status_badge
|
||||
if pb == null or not pb.visible or pb.disabled:
|
||||
_problems.append("状态面板入口角标缺失/置灰(战斗屏 board_zone)")
|
||||
@@ -221,7 +221,7 @@ func _ready() -> void:
|
||||
if main.ui.modals.run.status_panel.visible:
|
||||
_problems.append("状态面板关闭后未隐藏(继续钮路径)")
|
||||
# ⑤b 图例浮窗(战斗屏 AP 条真点开→截→close() 关——ui_click_probe 真点先例)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:88 图例面板=模态族(图例组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「提示与弹层:轻提示随起随消、重弹层排队进出」界面弹出的东西分两族 界面弹出的东西分两族(图例组)
|
||||
var lgb: Button = main.ui.battle.board_zone.ap_bar._btn_legend
|
||||
if lgb == null or not lgb.visible:
|
||||
_problems.append("图例钮缺失/不可见(战斗屏 AP 条)")
|
||||
@@ -237,7 +237,7 @@ func _ready() -> void:
|
||||
for i in 3:
|
||||
await get_tree().process_frame
|
||||
# ⑤c 战末结算浮层(直调 open_victory 喂真实形态摘要——ui_struct_probe 合成先例)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:276 终局:胜利金蜡封(战末结算组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(战末结算组)
|
||||
main.ui.modals.run.end_overlay.open_victory("胜利", "继续", Rect2(200, 200, 400, 300),
|
||||
{"gp_summary": "GP +3", "ks_summary": "击杀 2", "bonus_summary": "无伤奖励", "gp_gain": 3, "gp_total": 3})
|
||||
for i in 3:
|
||||
@@ -250,7 +250,7 @@ func _ready() -> void:
|
||||
for i in 3:
|
||||
await get_tree().process_frame
|
||||
# ⑤d 三选一浮层(直调 open_pick 喂真实形态卡——ui_struct_probe 合成先例)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md:166 三选一呈现(三选一组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取」令牌牌库 令牌牌库(三选一组)
|
||||
main.ui.modals.run.curio_overlay.open_pick("三选一", [
|
||||
{"id": "probe_heal", "text": "回血\n恢复 3 点"},
|
||||
{"id": "probe_magic", "text": "爆裂轰击\n下一击 +5"},
|
||||
@@ -266,7 +266,7 @@ func _ready() -> void:
|
||||
for i in 3:
|
||||
await get_tree().process_frame
|
||||
# ⑤e 调试浮窗(函数直调开/关——ui_struct_probe/ui_tune_probe 先例;对局中可开)
|
||||
# 判据出处: design/engineering/test-conventions.md:65 人工体验=DebugOverlay/DS_DEBUG 调试面(调试浮窗组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(调试浮窗组)
|
||||
main._show_debug_overlay()
|
||||
for i in 3:
|
||||
await get_tree().process_frame
|
||||
@@ -300,7 +300,7 @@ func _ready() -> void:
|
||||
|
||||
|
||||
func _snap(key: String) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:84 golden 测试项扩项——截图采集清单扩项、实跑截图冻结(截图采集组)
|
||||
# 判据出处: design/engineering/test-conventions.md「7. 判定可靠性优先于覆盖率」跑一遍没崩 跑一遍没崩、实跑截图冻结(截图采集组)
|
||||
await RenderingServer.frame_post_draw
|
||||
await RenderingServer.frame_post_draw
|
||||
var img: Image = get_viewport().get_texture().get_image()
|
||||
|
||||
@@ -13,7 +13,7 @@ var _problems: Array = []
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# 判据出处: design/ux/battle.md:122 (明细带挖掘期收起——T17 视觉扩展时序组)
|
||||
# 判据出处: design/ux/battle.md「Purpose & Player Need」战斗屏是 战斗屏是(明细带挖掘期收起——T17 视觉扩展时序组)
|
||||
await get_tree().process_frame
|
||||
main = load("res://presentation/main.tscn").instantiate()
|
||||
add_child(main)
|
||||
|
||||
@@ -30,7 +30,7 @@ var _hero_pos := Vector2i.ZERO
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:84 (微光截图取证——渲染闸采集组)
|
||||
# 判据出处: design/engineering/test-conventions.md「7. 判定可靠性优先于覆盖率」跑一遍没崩 跑一遍没崩(微光截图取证——渲染闸采集组)
|
||||
if DisplayServer.get_name() == "headless":
|
||||
print("[type_glow_shot] FAIL — 本探针必须窗口化运行(headless 无渲染面,截图必空)")
|
||||
get_tree().quit(1)
|
||||
|
||||
@@ -64,7 +64,7 @@ func _ready() -> void:
|
||||
if main.ui.modals.menu.debug_overlay.visible:
|
||||
_problems.append("调试浮窗 boot 自动开(菜单优先失守)")
|
||||
# ---- 营地购买合成点击路径(选档进档开层→购买→关闭全走真实按钮信号路径;
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:198 (营地购买段——单币购买只扣钥石组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「验收标准」结构封闭 结构封闭(营地购买段——单币购买只扣钥石组)
|
||||
# 隔离存档换注 main.meta 保确定性(禁碰真实档 user://save.json);陈旧档段首清理)----
|
||||
for p0 in ["user://smoke_click_probe_reset.json", "user://smoke_click_probe_reset.json.tmp"]:
|
||||
if FileAccess.file_exists(p0):
|
||||
@@ -143,7 +143,7 @@ func _ready() -> void:
|
||||
if String(iso_fk.meta_state.tree_state().fork_sides.get("fg_posture", "")) != "b":
|
||||
_problems.append("Fork 切态未持久(reload 后激活态 != b)〔句柄子容器批 V1〕")
|
||||
# ---- 树面高档钮扩面段(迭代 55 B5——购买0/20/40/60 档经调试注钥后真点+先手压制 A 侧回切)----
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:198 (营地购买段——购买面真输入扩面组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「验收标准」结构封闭 结构封闭(营地购买段——购买面真输入扩面组)
|
||||
iso_c.meta_state._add_keystone(9999)
|
||||
main.ui.modals.camp.tree.refresh_camp(main._camp_data())
|
||||
await get_tree().process_frame
|
||||
@@ -238,7 +238,7 @@ func _ready() -> void:
|
||||
ProbeUiUtil.push_click(main, treasure_back) # 真点返回(closed 同源钮)
|
||||
await get_tree().process_frame
|
||||
# ---- 秘宝架扩面段(迭代 55 B5——购买10/购买25/装配/升级30 真点;钥匙门先经树购 ks_workshop 点亮)----
|
||||
# 判据出处: design/gdd/systems/跨局循环/秘宝.md:246 (秘宝匣柜台——购买/装配/升级真输入扩面组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/秘宝.md「验收标准」护栏强制 护栏强制(秘宝匣柜台——购买/装配/升级真输入扩面组)
|
||||
ProbeUiUtil.push_click_at(main, main.ui.modals.camp.scene.get_hotspot_rect(&"dummy").get_center()) # 木桩→树界面
|
||||
await get_tree().process_frame
|
||||
var ks_btn: Button = null
|
||||
@@ -364,7 +364,7 @@ func _ready() -> void:
|
||||
ProbeUiUtil.push_click(main, codex_back) # 真点返回(closed 同源钮)
|
||||
await get_tree().process_frame
|
||||
# ---- 营地 Esc 浮窗设置动线(迭代 55 B5——Esc 真键唤起浮窗→设置钮真点开设置层)----
|
||||
# 判据出处: design/ux/camp.md:45 (Esc 段组——三出口真输入扩面)
|
||||
# 判据出处: design/ux/camp.md「叠层与开合」各界面开合走模态栈单口 各界面开合走模态栈单口(Esc 段组——三出口真输入扩面)
|
||||
var esc_ev := InputEventKey.new()
|
||||
esc_ev.keycode = KEY_ESCAPE
|
||||
esc_ev.physical_keycode = KEY_ESCAPE
|
||||
@@ -400,7 +400,7 @@ func _ready() -> void:
|
||||
if main.ui.modals.camp.scene.visible or not main.ui.screens.start_overlay.visible:
|
||||
_problems.append("营地关闭后未恢复开始层〔句柄子容器批 V1〕")
|
||||
# ---- 选档界面行为走查(迭代 33 卡③):sl5 空槽新档链/sl6 有档槽进档链/sl7 删档二次确认双路径
|
||||
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:61 (选档走查段——激活态建立组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「系统范围」边界这样划 边界这样划(选档走查段——激活态建立组)
|
||||
# /sl8 消费方分派单口/sl12 动线序不回闪。开层=函数直调(「进入存档」钮归卡② mn3——中间态在案);
|
||||
# 隔离=attach_slot_template 注入命名空间,夹具按槽直写(卡① 注入口)。----
|
||||
var csel_tpl := "user://smoke_click_probe_savesel_slot_%d.json"
|
||||
@@ -504,7 +504,7 @@ func _ready() -> void:
|
||||
_problems.append("[savesel] 关闭后层未隐藏或开始层未恢复(模态栈单口失守)")
|
||||
|
||||
# ---- 设置面段(隔离 store 换注禁碰真实 user://settings.cfg;真实按钮信号路径)----
|
||||
# 判据出处: design/gdd/systems/表现与支撑/设置与本地化.md:4 (设置面段——最小设置面组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/设置与本地化.md「设置与本地化」设置项与多语言 设置项与多语言(设置面段——最小设置面组)
|
||||
for p0 in ["user://smoke_click_probe_settings.cfg"]:
|
||||
if FileAccess.file_exists(p0):
|
||||
DirAccess.remove_absolute(p0)
|
||||
@@ -563,10 +563,11 @@ func _ready() -> void:
|
||||
_problems.append("音量滑杆未实时生效(master bus db %f ≠ %f)" % [AudioServer.get_bus_volume_db(master_idx), expect_db])
|
||||
if absf(iso_s.volume_linear - 0.3) > 0.001:
|
||||
_problems.append("音量未入 store(%f ≠ 0.3)" % iso_s.volume_linear)
|
||||
# 调试入口断言(卡⑦ c4 发布态换代——角标恒隐;原「最顶层浮层不被遮挡」
|
||||
# 回归语义随调试浮层发布态退役,申报见迭代 38 实现报告 §8.2)
|
||||
if main.ui.screens.debug_badge == null or main.ui.screens.debug_badge.visible:
|
||||
_problems.append("设置面开中调试角标可见(发布态恒隐失守)")
|
||||
# 调试入口断言(全局浮层角标=UI 最顶层、任何 UI 不遮挡——本段设置面
|
||||
# 开中正是遮挡场景:浮层角标此时仍应可见;点击开浮窗路径归 tune_probe;
|
||||
# 2026-11-09 特批恢复批——发布态恒隐语义退役)
|
||||
if main.ui.screens.debug_badge == null or not main.ui.screens.debug_badge.visible:
|
||||
_problems.append("设置面开中调试浮层角标不可见(最顶层浮层失守——被遮挡)")
|
||||
var settings_close: Button = ProbeUiUtil.find_button(main.ui.modals.menu.settings_overlay, "返回", "prefix")
|
||||
if settings_close == null:
|
||||
_problems.append("设置面返回按钮缺失")
|
||||
@@ -585,7 +586,7 @@ func _ready() -> void:
|
||||
if ProbeUiUtil.find_button(main.ui.modals.menu.settings_overlay, "退出游戏", "prefix") != null:
|
||||
_problems.append("设置面仍含退出游戏按钮(二轮 D1——只在一级菜单出现)")
|
||||
# ---- 生涯页段(入口点击链+关闭回返,真实按钮信号路径;本页只读零写,
|
||||
# 判据出处: design/ux/camp.md:45 (生涯页段——同壳同形态组)
|
||||
# 判据出处: design/ux/camp.md「叠层与开合」各界面开合走模态栈单口 各界面开合走模态栈单口(生涯页段——同壳同形态组)
|
||||
# 值断言归冒烟投影段与 ui_struct 结构族,此处只验开合路径与零跳转)----
|
||||
# 生涯页驱动=函数直调中间态(卡② mn10——careerbtn 已撤,卡④ 笔记本改挂前无 UI 路径)
|
||||
if true:
|
||||
@@ -902,7 +903,7 @@ func _ready() -> void:
|
||||
_run_modal_probes_once()
|
||||
_play_one_action()
|
||||
# ---- 预算耗尽收口(T17 硬锁批适配):选件变强后 probe 可能活过预算不再战败——断点段前提
|
||||
# 判据出处: design/ux/level-map.md:11 (主循环选路段——入口候选组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(主循环选路段——入口候选组)
|
||||
# (冒险终局面在案)须主动满足。收口驱动:任何停点层逐个推进(复用主循环分支语义)至
|
||||
# level_screen 选路停点→真实放弃二击→终局面。战斗中则继续 autoplay 打完。
|
||||
if not _done and not main.ui.modals.run.end_overlay.is_open():
|
||||
@@ -951,7 +952,7 @@ func _ready() -> void:
|
||||
_play_one_action()
|
||||
# 排播期/Waiting 等待态=自然流逝(演播秒级、锁随队列空解除)
|
||||
# T17 适配:战败或放弃二途皆达终局面(放弃=预算耗尽收口路径——见上),断点段前提不变。
|
||||
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:180 (断点段——断点域与续玩组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「验收标准」往返一致 往返一致(断点段——断点域与续玩组)
|
||||
await get_tree().process_frame
|
||||
var bp_file := "user://smoke_click_probe_reset.json"
|
||||
var iso_chk = load("res://core/save_manager.gd").new(bp_file)
|
||||
@@ -983,7 +984,7 @@ func _ready() -> void:
|
||||
# ① 战斗收口断点写盘断言保留(上方——冒险流直调中间态 mn10)。
|
||||
|
||||
# ---- 迭代 55 B5 扩面收尾段(地图放弃动线——主循环流不定达放弃,独立新局确定性驱动)----
|
||||
# 判据出处: design/ux/level-map.md:11 (主循环选路段——放弃二击真输入组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(主循环选路段——放弃二击真输入组)
|
||||
ProbeUiUtil.isolate_save(main, "smoke_click_probe_expansion", true, false, true)
|
||||
main.ui.modals.menu.debug_overlay.set_sliders(2000, 2000) # 高加成上限(与主循环同口径——层速推进保放弃停点快达)
|
||||
main.ui.modals.menu.debug_overlay.seed_edit.text = "44"
|
||||
@@ -1031,7 +1032,7 @@ func _ready() -> void:
|
||||
await get_tree().process_frame
|
||||
|
||||
# ---- 大门两分支断言段(卡④ T5 接收——卡② 移交落点;V3 断言面)----
|
||||
# 判据出处: design/ux/camp.md:16 (大门段——点大门先出确认组)
|
||||
# 判据出处: design/ux/camp.md「场景构成与七物件绑定」半开的门扇 半开的门扇(大门段——点大门先出确认组)
|
||||
# 驱动=营地场景根点选信号(真实路由)→组合根 _on_camp_object_pressed→确认弹窗。
|
||||
# 无断点=两出口(是/否);有断点=三出口(set_breakpoint 注入选路停点形——同下方开场行③先例)。
|
||||
# 判据绑可观测提交面:点大门不直接进冒险(is_adventure 翻转只在 confirmed 后);cancelled 恒=
|
||||
@@ -1056,7 +1057,7 @@ func _ready() -> void:
|
||||
await get_tree().process_frame
|
||||
# R4 位次真点(营地交互修复批——位次与语义绑定钉):真点前消费方前置读(gate_new 在册)→
|
||||
# 按类型定位按钮行 child(0) 全局矩形中心真点——位次若错接,此点命中「否」,下方主证(翻转)即红。
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:90 确认弹窗位次定值:推进在左、维持居右(R4 位次真点)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「提示与弹层:轻提示随起随消、重弹层排队进出」界面弹出的东西分两族 界面弹出的东西分两族、维持居右(R4 位次真点)
|
||||
if String(main._confirm_consumer) != "gate_new":
|
||||
_problems.append("R4 前置:确认消费方非 gate_new(分派面漂移)〔营地交互批 V3〕")
|
||||
var gate_row := _first_hbox(main.ui.modals.menu.confirm_dialog)
|
||||
@@ -1071,7 +1072,7 @@ func _ready() -> void:
|
||||
if String(main._confirm_consumer) != "":
|
||||
_problems.append("R4 主证:确认后消费方未清零〔营地交互批 V3〕")
|
||||
# 开局终态两钉(营地交互修复批——开始层隐藏收一处后的落点断言):
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:78 关卡开始 → 呈现节点图选路停点(开局终态两钉)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「行进与选路:兑付后确认,选路就是行进」关卡里没有一次自动前进 关卡里没有一次自动前进(开局终态两钉)
|
||||
# R1=确认后开始层不可见(被测改动特有提交面——修复前该句恒红=「开局被开始层盖住」缺陷本体);
|
||||
# R2=关卡画面(选路停点)在位(开局终态呈现面,与既有 is_adventure 断言同批缺一即红)
|
||||
if main.ui.screens.start_overlay.visible:
|
||||
@@ -1180,10 +1181,10 @@ func _ready() -> void:
|
||||
|
||||
|
||||
# ---- 模态/tooltip/刷新链一次性覆盖(真实信号路径驱动) ----
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:277 (模态/tooltip 段——遮挡与输入锁组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「提示与弹层:轻提示随起随消、重弹层排队进出」界面弹出的东西分两族 界面弹出的东西分两族(模态/tooltip 段——遮挡与输入锁组)
|
||||
|
||||
func _run_modal_probes_once() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:277 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「提示与弹层:轻提示随起随消、重弹层排队进出」界面弹出的东西分两族 界面弹出的东西分两族(判定上报通道——验证函数组)
|
||||
# ⓪ 玩家面文案真实入口断言(迭代36 卡A wa1——C 区两段头随战斗常驻)
|
||||
if not _tested_copy and main.ui.battle.info_panel != null and main.ui.battle.info_panel.visible:
|
||||
_tested_copy = true
|
||||
@@ -1376,7 +1377,7 @@ func _labels_with_text(labels: Array, needle: String) -> Array:
|
||||
|
||||
|
||||
func _play_one_action() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:236 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」每条都可单独验证 每条都可单独验证(判定上报通道——验证函数组)
|
||||
var settlement = main.run_scope.settlement
|
||||
if settlement == null:
|
||||
return # 结算竞态防抖:battle_finished 与本轮动作调度同帧到达时 settlement 可能已被置空(基线既有噪声——加固)
|
||||
@@ -1413,7 +1414,7 @@ func _play_one_action() -> void:
|
||||
|
||||
|
||||
func _random_unknown_adjacent(minesweeper) -> Vector2i:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:236 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」每条都可单独验证 每条都可单独验证(判定上报通道——验证函数组)
|
||||
var hero: Vector2i = minesweeper.hero_pos()
|
||||
var cands: Array = []
|
||||
for dy in range(-1, 2):
|
||||
@@ -1429,13 +1430,13 @@ func _random_unknown_adjacent(minesweeper) -> Vector2i:
|
||||
|
||||
|
||||
func _click_stop() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:262 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P1 / P2 后置」后置原因 后置原因(判定上报通道——验证函数组)
|
||||
# 停手走真实点击路径(AP 条「停手」钮 → 组合根 settle_batch——排雷玩法 D1×6① 回归载体)
|
||||
ProbeUiUtil.push_click(main, main.ui.battle.board_zone.ap_bar._btn_stop)
|
||||
|
||||
|
||||
# ---- T1 D1:锁期/重放断言(每 run 一次,脚本化场景——演播期豁免的断言化承载) ----
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:236 (锁期/重放段——拒绝与锁组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」每条都可单独验证 每条都可单独验证(锁期/重放段——拒绝与锁组)
|
||||
# 锁期断言(排播队列活跃=锁面):注入封印击 → 直落被冻结不受理(封印未置)+ `_locked_click`
|
||||
# 缓存命中且为本注入(「最后一次」语义——注入帧内无并发点击)。
|
||||
# 重放断言(演播完边沿 pump_ended→_replay_locked_click 重入唯一动作通道):缓存清空 +
|
||||
@@ -1443,7 +1444,7 @@ func _click_stop() -> void:
|
||||
# 前提消失守卫:等重放期间出现停点层/战斗收场(注入时点恰逢终结演播)→ 静默弃测不计
|
||||
# problem(封印动作不杀伤,正常局不触发;断言实现形态取舍在代拍白名单内)。
|
||||
func _locktest_tick() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:236 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」每条都可单独验证 每条都可单独验证(判定上报通道——验证函数组)
|
||||
if _locktest_state == 2:
|
||||
return
|
||||
var settlement = main.run_scope.settlement
|
||||
@@ -1500,7 +1501,7 @@ func _locktest_tick() -> void:
|
||||
|
||||
|
||||
func _locktest_pick_cell(minesweeper) -> Vector2i:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:236 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」每条都可单独验证 每条都可单独验证(判定上报通道——验证函数组)
|
||||
var hero: Vector2i = minesweeper.hero_pos()
|
||||
for dy in range(-1, 2):
|
||||
for dx in range(-1, 2):
|
||||
@@ -1518,7 +1519,7 @@ func _locktest_pick_cell(minesweeper) -> Vector2i:
|
||||
# 断言两钉:①覆盖登记件停手键在场(零命中=驱动空转假绿,即红);②相位离开 Active(停手
|
||||
# 收轮)。前提消失守卫:点击后战局收场(终结演播竞态)→ 静默弃测不计 problem(正常局不触发)。
|
||||
func _stoptest_tick() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:167 (停手=玩家主动收轮——判定上报通道)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「一帧一个意图、对外只有三种事件:批次仲裁与事件面」玩家主动收轮 玩家主动收轮(停手=玩家主动收轮——判定上报通道)
|
||||
if _stoptest_state == 2:
|
||||
return
|
||||
var settlement = main.run_scope.settlement
|
||||
@@ -1555,7 +1556,7 @@ func _stoptest_tick() -> void:
|
||||
|
||||
|
||||
func _stoptest_assert_hit() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:167 (停手钮真输入命中登记——判定上报通道)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「一帧一个意图、对外只有三种事件:批次仲裁与事件面」玩家每帧只提交一个意图 玩家每帧只提交一个意图(停手钮真输入命中登记——判定上报通道)
|
||||
var stop_btn: Button = main.ui.battle.board_zone.ap_bar._btn_stop
|
||||
var stop_key := String(_recorder._node_keys.get(stop_btn.get_instance_id(), ""))
|
||||
if stop_key == "" or not _recorder._hits.has(stop_key):
|
||||
@@ -1573,7 +1574,7 @@ func _latest_open_line(main: Node) -> String:
|
||||
|
||||
|
||||
func _first_hbox(node: Node) -> HBoxContainer:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:90 (位次真点定位——R4 判据面辅助)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「提示与弹层:轻提示随起随消、重弹层排队进出」界面弹出的东西分两族 界面弹出的东西分两族(位次真点定位——R4 判据面辅助)
|
||||
if node is HBoxContainer:
|
||||
return node
|
||||
for ch in node.get_children():
|
||||
@@ -1584,7 +1585,7 @@ func _first_hbox(node: Node) -> HBoxContainer:
|
||||
|
||||
|
||||
func _report_stall(st: Dictionary) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:30 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「2. 场景级探针标配」每新增一个可交互 每新增一个可交互(判定上报通道——验证函数组)
|
||||
var why := ""
|
||||
if st.phase == "Waiting":
|
||||
why = "结算停滞:Waiting 相位无推进(结算应同步走完——窗口段已删除)"
|
||||
@@ -1600,7 +1601,7 @@ func _report_stall(st: Dictionary) -> void:
|
||||
|
||||
|
||||
func _dump_state() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:30 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「2. 场景级探针标配」每新增一个可交互 每新增一个可交互(判定上报通道——验证函数组)
|
||||
var diag: Dictionary = main.run_scope.settlement.diagnostic_snapshot() # 诊断观测面(私有字段零直读)
|
||||
print(" node_index=%s round=%s phase=%s ap=%s rap=%s" % [
|
||||
str(main.run_scope.runner.node_index), str(main.run_scope.settlement.round_index),
|
||||
|
||||
@@ -88,7 +88,7 @@ func _ratio(a: Color, b: Color) -> float:
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:281 (UI 文字对比度机检 ≥4.5:1 无区域例外——对比度组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(UI 文字对比度机检 ≥4.5:1 无区域例外——对比度组)
|
||||
var problems: Array = []
|
||||
var pairs := _pairs()
|
||||
for p in pairs:
|
||||
|
||||
@@ -242,7 +242,7 @@ func _ready() -> void:
|
||||
_pre_fail("目标格选取失败 seal=%s dig=%s forbid=%s reveal=%s" % [seal_t, dig_t, forbid_t, reveal_t])
|
||||
return
|
||||
# ---- case① 悬停可挖域:motion → 悬停态到达(金框 + 十字光标)----
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:269 悬停光标三语义随目标切换、已开格路径预览、可挖域常驻微光(case①-③ 输入面)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测、已开格路径预览、可挖域常驻微光(case①-③ 输入面)
|
||||
_push_motion(_pos(bv, seal_t))
|
||||
await get_tree().process_frame
|
||||
if bv.hover_probe() != seal_t:
|
||||
@@ -271,7 +271,7 @@ func _ready() -> void:
|
||||
if bv.mouse_default_cursor_shape != Input.CURSOR_ARROW:
|
||||
_problems.append("case③ 移动光标缺失(%d)" % bv.mouse_default_cursor_shape)
|
||||
# ---- case④ 右键封印:seal_place 到达组合根 + 核心封印态落位 ----
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:52 封印受理即揭示、受理零兑付零事件(case④/④b——受理即揭示改版换代)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「挖、封印、移动:每个动作怎么才算合法」玩家对棋盘只做三件事 玩家对棋盘只做三件事、受理零兑付零事件(case④/④b——受理即揭示改版换代)
|
||||
_push_click(_pos(bv, seal_t), MOUSE_BUTTON_RIGHT)
|
||||
await get_tree().process_frame
|
||||
if not _has_action(seal_t, "seal_place"):
|
||||
@@ -285,7 +285,7 @@ func _ready() -> void:
|
||||
if seal_unit == null or not seal_unit.seal_on:
|
||||
_problems.append("case④b 封印印记未下发(seal_on=%s)" % ["无单元" if seal_unit == null else str(seal_unit.seal_on)])
|
||||
# ---- case④c(V9 新增)已封印格零动作:真输入左/右键 → action_requested 零发射、光标态=禁止 ----
|
||||
# 判据出处: design/ux/battle.md Interaction Map 已封印格行——已封印格无动作(左右键同零意图)
|
||||
# 判据出处: design/ux/battle.md「Interaction Map」输入前提 输入前提
|
||||
var acts_before_v9: int = _actions.size()
|
||||
_push_motion(_pos(bv, seal_t))
|
||||
await get_tree().process_frame
|
||||
@@ -311,14 +311,14 @@ func _ready() -> void:
|
||||
if not legend_seal_line.contains("受理即揭示"):
|
||||
_problems.append("case④c 悬停说明在册缺新口径(图例封印行=%s)〔封印改 V9〕" % legend_seal_line)
|
||||
# ---- case⑤ 双击 chord:禁入格双左击(核心拒挖零副作用)→ chord_attempted ----
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:236 拒绝三源可辨、任何拒绝零副作用(case⑤ chord)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」任何拒绝零副作用 任何拒绝零副作用、任何拒绝零副作用(case⑤ chord)
|
||||
_push_click(_pos(bv, forbid_t), MOUSE_BUTTON_LEFT)
|
||||
_push_click(_pos(bv, forbid_t), MOUSE_BUTTON_LEFT)
|
||||
await get_tree().process_frame
|
||||
if _chords.is_empty() or _chords[_chords.size() - 1] != forbid_t:
|
||||
_problems.append("case⑤ chord_attempted 未达(chords=%s)" % [str(_chords)])
|
||||
# ---- case⑥ 左键挖:dig 到达组合根 + 核心揭格落位 ----
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:231 挖掘受理与揭格落位(case⑥)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」每条都可单独验证 每条都可单独验证(case⑥)
|
||||
_push_click(_pos(bv, dig_t), MOUSE_BUTTON_LEFT)
|
||||
await get_tree().process_frame
|
||||
if not _has_action(dig_t, "dig"):
|
||||
@@ -327,7 +327,7 @@ func _ready() -> void:
|
||||
if not ms.is_revealed(dig_t):
|
||||
_problems.append("case⑥ 核心揭格未落位(目标=%s)" % dig_t)
|
||||
# ---- case⑦ 英雄精灵世界落位(回归闸):精灵在 SubViewport 世界内,
|
||||
# 判据出处: design/ux/battle.md:154 主角站桩立绘带落影、贴脚与缩放档(case⑦-⑩ 呈现落位)
|
||||
# 判据出处: design/ux/battle.md「封印格呈现预览」封印受理后格子进入 封印受理后格子进入、贴脚与缩放档(case⑦-⑩ 呈现落位)
|
||||
# 落位 = 格×步距 + 脚底锚(横=格中线/纵=格底往上 25% 线=HERO_GROUND_FRAC 自底边口径——「脚踩
|
||||
# 格子 1/4 处·从下往上数」;禁带壳层 _svp_container.position 居中偏移——上批误用壳层
|
||||
# cell_origin 实测右偏 ~7 格+偏离格心,实机截图用户报缺陷)。素材缺位树(hero==null,字形
|
||||
@@ -394,7 +394,7 @@ func _ready() -> void:
|
||||
if bv._world.hero.position.distance_to(expect10b) > 0.5:
|
||||
_problems.append("case⑩ 还原后英雄未复位(pos=%s expect=%s)" % [str(bv._world.hero.position), str(expect10b)])
|
||||
# ---- case⑪ 贴图缺位回退(字形「人」回归闸):texture 置 null + refresh → 英雄格数字 0 时字形
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:264 棋盘格子与数字完整可见——贴图缺位回退字形保可读(case⑪)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(case⑪)
|
||||
# 必须回退「人」(数字格仍显数字——回退判据与抑制判据同源);验毕还原纹理重绘。 ----
|
||||
if bv._world.hero != null:
|
||||
var hp11: Vector2i = ms.hero_pos()
|
||||
@@ -411,7 +411,7 @@ func _ready() -> void:
|
||||
bv._hero_sprite.tex_idle = tex_saved
|
||||
bv.refresh()
|
||||
# ---- case⑭ 变异角标(flat_damage 未开格视觉标记;resolver 注入面+落位+复位) ----
|
||||
# 判据出处: design/gdd/systems/排雷循环/地形变异.md:154 呈现按 effect/trigger/placement 数据路由、零特判(case⑭ 角标)
|
||||
# 判据出处: design/gdd/systems/排雷循环/地形变异.md「验收标准」候选池空合法 候选池空合法、零特判(case⑭ 角标)
|
||||
var mark_t: Vector2i = _pick_forbidden(bv, ms) # 任一未开格(禁入=未开非相邻)
|
||||
if mark_t.x >= 0:
|
||||
bv.set_variant_mark_resolver(func(_c): return "flat_damage")
|
||||
@@ -425,7 +425,7 @@ func _ready() -> void:
|
||||
else:
|
||||
_problems.append("case⑭ 无未开格可验(板面异常)")
|
||||
# ---- case⑮ 视野迷雾(三态呈态/半径圈/移动跟随/开关两态零扰动/提灯插值位;
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:268 视野迷雾:灯光区随移动跟随、开关两态结算逐位一致(case⑮)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测、开关两态结算逐位一致(case⑮)
|
||||
# 纯呈现零逻辑——迷雾开关切换前后 minesweeper 状态摘要逐位一致) ----
|
||||
var fogp: Dictionary = bv.fog_params_probe()
|
||||
if int(bv.FOG_RADIUS) != 8 or int(fogp["lantern"]) != 0 or not fogp["enabled"]:
|
||||
@@ -521,7 +521,7 @@ func _ready() -> void:
|
||||
# attune_param_sum 只读出口→set_fog_glow_bonus〕→视野 +4 生效与卸装复原。
|
||||
# settlement.attunement 手动注入=模拟 begin_battle enc 注入后的运行态〔注入面本体归
|
||||
# 冒烟+单测覆盖〕;不重启冒险——case⑯ 起既有板面继续用)
|
||||
# 判据出处: design/gdd/systems/跨局循环/元进度.md:156 解锁可见:装配强化下一局生效(case⑮ 装配链)
|
||||
# 判据出处: design/gdd/systems/跨局循环/元进度.md「验收标准」钥石不丢 钥石不丢(case⑮ 装配链)
|
||||
main.save_manager.meta_state.set_attunement_equipped(["wide_scout_band"])
|
||||
var p_lantern: Dictionary = main.build_adventure_params(main.save_manager, main.meta)
|
||||
if not (p_lantern.get("attunement", []) as Array).has("wide_scout_band"):
|
||||
@@ -540,7 +540,7 @@ func _ready() -> void:
|
||||
_problems.append("case⑮ 卸装后 dist==R+1 格未复原遮蔽")
|
||||
main.save_manager.meta_state.set_attunement_equipped([])
|
||||
# ---- case⑯ 状态面板输入锁语义(R3——开层锁棋盘、关层恢复无残留;真实 push_input
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:277 模态打开输入锁定、关闭逐层恢复(case⑯ R3)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」关闭逐层恢复 关闭逐层恢复、关闭逐层恢复(case⑯ R3)
|
||||
# 路径:入口角标本体 press+release 真点击 → 状态面板开;锁期挖掘点击零穿透;「继续」关层后
|
||||
# 同格挖掘重新到达——锁语义与既有模态同款,无状态残留。置于全 case 之尾:取格若需前沿移位
|
||||
#(真实点击 move 扩大可挖域),其板面扰动不再波及任何既有断言——域恰 2 枚时 seal_t 带封印+
|
||||
@@ -596,7 +596,7 @@ func _ready() -> void:
|
||||
if not _has_action(status_dig, "dig") or not ms.is_revealed(status_dig):
|
||||
_problems.append("case⑯ 关闭后挖掘未到达(恢复无残留验证失守)")
|
||||
# ---- case⑰ 未开格类型微光(活板面走查:作用集恒等/开格灭/移动复亮
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:267 类型微光出圈即灭入圈即亮、已开与封锁格恒无微光(case⑰)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测、已开与封锁格恒无微光(case⑰)
|
||||
# 与出圈灭/相位门控/开关两态零扰动。与冒烟段数据面断言分工:此处走真实点击路径) ----
|
||||
if not bool(bv.type_glow_probe().get("enabled", false)):
|
||||
_problems.append("case⑰ 微光默认态非开(生产默认开——Q4 丙案)")
|
||||
@@ -785,7 +785,7 @@ func _push_release(pos: Vector2, btn: int) -> void:
|
||||
|
||||
|
||||
func _pre_fail(why: String) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
push_error("[ui_input_probe] FAIL — " + why)
|
||||
print("[ui_input_probe] FAIL — " + why)
|
||||
get_tree().quit(1)
|
||||
@@ -16,7 +16,7 @@ func _ready() -> void:
|
||||
await get_tree().process_frame
|
||||
var problems: Array = []
|
||||
# ---- 放弃入口(台账 119):默认隐藏(非冒险模式无冒险可放弃——开始层/调试两层)----
|
||||
# 判据出处: design/ux/level-map.md:59 放弃冒险入口=边缘动作、任意选路停点承载——非冒险模式无入口(默认隐藏)
|
||||
# 判据出处: design/ux/level-map.md「Information Hierarchy」本屏必须传达的全部信息 本屏必须传达的全部信息、任意选路停点承载——非冒险模式无入口(默认隐藏)
|
||||
if main.ui.modals.run.level_screen.abandon_btn == null or main.ui.modals.run.level_screen.abandon_btn.visible:
|
||||
print("[ui_probe] FAIL — 放弃按钮默认应隐藏(非冒险模式关)")
|
||||
get_tree().quit(1)
|
||||
@@ -24,7 +24,7 @@ func _ready() -> void:
|
||||
# ---- 营地覆盖层(主菜单入口/开合/余额文案/购买禁用态;
|
||||
# 隔离存档换注 main.meta 保确定性(禁碰真实档 user://save.json——SaveManager 路径注入纪律;
|
||||
# 营地先行段只换 meta 不换 save_manager——冒险段换注零档在前)----
|
||||
# 判据出处: design/ux/camp.md:45 五功能窗统一窗壳、五窗互斥单开、各窗自带关闭钮(营地开合组)
|
||||
# 判据出处: design/ux/camp.md「叠层与开合」五窗互斥单开 五窗互斥单开、五窗互斥单开、各窗自带关闭钮(营地开合组)
|
||||
ProbeUiUtil.isolate_save(main, "smoke_ui_probe_camp", false, false, false)
|
||||
if not await ProbeUiUtil.open_camp_via_savesel(main, "smoke_ui_probe_camp"):
|
||||
problems.append("营地入口缺失(选档层新档钮——mn9 新路径驱动中断)〔句柄子容器批 V1〕")
|
||||
@@ -36,12 +36,12 @@ func _ready() -> void:
|
||||
problems.append("营地层打开时开始层未隐藏(规范 2.3 遮挡纪律)〔句柄子容器批 V1〕")
|
||||
else:
|
||||
# 天赋树子界面(场景点选真实路由——木桩命中区进树界面;卡④ T5 深员改指)
|
||||
# 判据出处: design/ux/camp.md:20 木桩命中区→天赋树界面入口(场景点选路由)
|
||||
# 判据出处: design/ux/camp.md「场景构成与七物件绑定」半开的门扇 半开的门扇(场景点选路由)
|
||||
ProbeUiUtil.push_click_at(main, main.ui.modals.camp.scene.get_hotspot_rect(&"dummy").get_center())
|
||||
await get_tree().process_frame
|
||||
if not main.ui.modals.camp.tree.visible:
|
||||
problems.append("天赋树子界面未打开(场景点选路由中断)〔营地图批 V2〕")
|
||||
# 判据出处: design/ux/camp.md:41 钥石余额常驻画面顶部 HUD 栏(余额文案组)
|
||||
# 判据出处: design/ux/camp.md「顶栏」钥石余额常驻画面顶部一行小 钥石余额常驻画面顶部一行小(余额文案组)
|
||||
if not String(main.ui.modals.camp.tree._balance_label.text).begins_with("钥石"):
|
||||
problems.append("营地余额文案缺失(%s)〔句柄子容器批 V1〕" % main.ui.modals.camp.tree._balance_label.text)
|
||||
if main.ui.modals.camp.tree._tree_buy_btns.is_empty():
|
||||
@@ -57,7 +57,7 @@ func _ready() -> void:
|
||||
ProbeUiUtil.push_click(main, ProbeUiUtil.find_button(main.ui.modals.camp.tree, "返回营地")) # 真点底栏返回钮→_emit_closed(camp_sub_view_base.gd:66-84)
|
||||
await get_tree().process_frame
|
||||
# 秘宝匣子界面(场景点选真实路由——宝箱命中区)
|
||||
# 判据出处: design/ux/camp.md:18 宝箱命中区→秘宝匣界面入口
|
||||
# 判据出处: design/ux/camp.md「场景构成与七物件绑定」半开的门扇 半开的门扇
|
||||
ProbeUiUtil.push_click_at(main, main.ui.modals.camp.scene.get_hotspot_rect(&"chest").get_center())
|
||||
await get_tree().process_frame
|
||||
if main.ui.modals.camp.treasure._workshop_rows.size() != 12:
|
||||
@@ -76,7 +76,7 @@ func _ready() -> void:
|
||||
await get_tree().process_frame
|
||||
# ---- 入口选路停点(关卡开始即出节点图——level_started 后、首战前弹选路层;
|
||||
# candidate_rect 命中矩形真点 pick 入口单候选进首战)----
|
||||
# 判据出处: design/ux/level-map.md:11 入口停点候选数=入口个数(入口单候选断言)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(入口单候选断言)
|
||||
# ---- 独立性断言(独立屏激活期战斗屏宿主整体隐藏,零透出)----
|
||||
if not main.ui.modals.run.level_screen.visible:
|
||||
problems.append("关卡开始未弹入口选路停点(level_screen 应可见)")
|
||||
@@ -92,7 +92,7 @@ func _ready() -> void:
|
||||
if not main.ui.screens.battle_root.visible or main.ui.modals.run.level_screen.visible:
|
||||
problems.append("选路提交战斗节点后未切回战斗屏(屏级互斥恢复失守)")
|
||||
# ---- 放弃入口·冒险模式可见 + 战斗中按下被拒(真实按钮路径——入口挂选路停点,战斗中拒绝为防御分支)----
|
||||
# 判据出处: design/ux/level-map.md:42 放弃冒险(任意选路停点)→ 冒险落幕——战斗域单事务在飞时拒绝
|
||||
# 判据出处: design/ux/level-map.md「Navigation Position」任意选路停点 任意选路停点(任意选路停点)→ 冒险落幕——战斗域单事务在飞时拒绝
|
||||
if main.ui.modals.run.level_screen.abandon_btn == null or not main.ui.modals.run.level_screen.abandon_btn.visible:
|
||||
problems.append("冒险模式放弃按钮未开放(选路停点入口在案)")
|
||||
else:
|
||||
@@ -101,7 +101,7 @@ func _ready() -> void:
|
||||
if main.run_scope.adventure == null or String(main.run_scope.adventure.state) != "running":
|
||||
problems.append("首战中放弃未被拒(战斗域单事务在飞——state 应保持 running)")
|
||||
# ---- 既有断言(回归基线;A 区无进度条——节点链进度由关卡画面独立屏承载)----
|
||||
# 判据出处: design/ux/battle.md:122 B 区构建组:主角与敌人站桩、明细带挖掘期收起、轮次指示、棋盘与 C 区/秘宝槽、首战进行中
|
||||
# 判据出处: design/ux/battle.md「Layout Zones」采用用户拍板的布局图 采用用户拍板的布局图、明细带挖掘期收起、轮次指示、棋盘与 C 区/秘宝槽、首战进行中
|
||||
if main.ui.battle.board_zone.board_view.cells_probe().is_empty():
|
||||
problems.append("棋盘格未生成(cells=0)")
|
||||
if main.ui.battle.board_zone.board_view.board() == null:
|
||||
@@ -119,7 +119,7 @@ func _ready() -> void:
|
||||
problems.append("B 区敌方站桩未构建(%d 个)" % main.ui.battle.stage.enemy_box.get_child_count())
|
||||
if main.ui.battle.board_zone.ap_bar._dots.get_child_count() != int(main.db.run.action_economy.ap_per_round):
|
||||
problems.append("D 区 AP 点阵数量错误(%d)" % main.ui.battle.board_zone.ap_bar._dots.get_child_count())
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:258 开轮硬重置:行动点回到表值(AP 点阵数=ap_per_round)
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P0 最小闭环」战斗结算发开轮通知 战斗结算发开轮通知(AP 点阵数=ap_per_round)
|
||||
if main.ui.battle.board_zone.ap_bar.refresh_remaining_text() == "":
|
||||
problems.append("D 区弃图刷新按钮文案缺失")
|
||||
if main.ui.battle.board_zone.toast == null:
|
||||
@@ -136,7 +136,7 @@ func _ready() -> void:
|
||||
# E 区无道具面板——四区构建由其余断言覆盖
|
||||
|
||||
# ---- 敌方站桩投影(顺位徽标/意图三档动作动画占位——敌人系统×4,全站桩)----
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:275 敌人呈现:意图占位三档可见性——普通攻击零表示、类型级提示(站桩投影组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」类型级提示 类型级提示、类型级提示(站桩投影组)
|
||||
# B 区站桩子件伴随件化(壳层 tooltip 载体)——断言口径见台账 171:
|
||||
# 伴随件化(壳层 tooltip 载体),穿透明(子件 _name_label/_armor_icon/_intent_badge)改本体
|
||||
# 探针出口 stage.enemy_body_at(i).name_line_probe()/intent_probe()——呈现口径逐字保持
|
||||
@@ -163,7 +163,7 @@ func _ready() -> void:
|
||||
elif not bool(main.ui.battle.stage.hero_standee.portrait_probe().get("has_tex", false)):
|
||||
problems.append("主角立绘纹理未落位(显示档 hero=144——显示档批)")
|
||||
# ---- BUG-0001 回归(tooltip 入树后 set_effects 槽位不错位——结算软锁修复沉淀)----
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:274 状态槽图标+层数+剩余次数、悬停见来源(tooltip 回归组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」悬停见来源 悬停见来源、悬停见来源(tooltip 回归组)
|
||||
var slots_row = main.ui.battle.stage.hero_standee.slot_row # BUG-0001 回归随组件迁入站桩(tooltip/槽位错位同源)
|
||||
var probe_eff: Array = [{"effect_id": "attack_up", "display_name": "增伤", "layers": 1,
|
||||
"remaining_settlements": 1, "source_class": "safe_cell", "round_index": 1, "effective_value": 50}]
|
||||
@@ -189,7 +189,7 @@ func _ready() -> void:
|
||||
# ---- 图标键回归(HUD框架 图标键契约:状态表九行全映射〔定稿 PNG 纹理〕、
|
||||
# 格面资源 cell_type 九型全映射〔含 gp 键〕;查不到的键 fail-fast + ? 占位
|
||||
# ——此处钉死映射不残缺,未知键断言由 _icon_tex/_badge_glyph 承担)----
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:274 极性按键级表呈现——状态图标键映射不残缺(图标键回归组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(图标键回归组)
|
||||
for eid in ["attack_up", "ac_up", "alert", "weaken", "enrage", "off_guard", "sapped", "empower", "fortify"]:
|
||||
if not StatusSlotRow.EFFECT_ICON.has(eid) or StatusSlotRow.EFFECT_ICON[eid] == null:
|
||||
problems.append("状态图标九键纹理映射缺失(%s)" % eid)
|
||||
@@ -214,7 +214,7 @@ func _ready() -> void:
|
||||
# ---- L2 单场段(debug_session 单场原语 + 去饱和接口可用性;雾格机制已整体移除,不再断言变体呈现)----
|
||||
# 单场无用户入口——探针直调 debug_session 原语(battle_created/ready 仍经组合根接线;
|
||||
# _reset_run_scope 复现 _start_single 的提示去重复位)
|
||||
# 判据出处: design/gdd/systems/排雷循环/地形变异.md:156 布置域:变异格全在初始展开区外(L2 布置域组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/地形变异.md「验收标准」候选池空合法 候选池空合法(L2 布置域组)
|
||||
main.begin_session(false)
|
||||
main._debug.start_single(2)
|
||||
await get_tree().process_frame
|
||||
@@ -237,7 +237,7 @@ func _ready() -> void:
|
||||
# ---- GP 终局行:summary gp_final 键取数+胜利面板 GP 行呈现(C5:GP 行只上冒险终局面板;
|
||||
# 断言面 = summary 键,无影子账清零转存)----
|
||||
# (置于战斗态断言之后——合成收束会灰化站桩并清 settlement 引用,具污染性)
|
||||
# 判据出处: design/ux/settlement-summary.md:20 战利品行=GP 增量+总量(冒险终局面板 GP 行组)
|
||||
# 判据出处: design/ux/settlement-summary.md「战斗总结结算」冒险模式战斗胜利 冒险模式战斗胜利(冒险终局面板 GP 行组)
|
||||
var meta_saved = main.meta.save
|
||||
for p2 in ["user://smoke_ui_probe_settle_scratch.json", "user://smoke_ui_probe_settle_scratch.json.tmp"]:
|
||||
if FileAccess.file_exists(p2):
|
||||
|
||||
@@ -89,7 +89,7 @@ func _ready() -> void:
|
||||
# ---- 生涯页:入口=帐篷旁笔记本(卡④ T3 改挂——场景点选信号真实路由→组合根 _open_career)→
|
||||
# 结构断言族→只读巡检(契约 3)+零动效契约+零跳转契约(提纲 P4 甲)→组合根真实路径关闭。
|
||||
#(登记序/树序契约统一在全模态 _modal_registry_contract——boot 段跑)----
|
||||
# 判据出处: design/ux/camp.md:19 帐篷旁笔记本→生涯记录;生涯页返回钮口径由结构校验兜底(生涯段)
|
||||
# 判据出处: design/ux/camp.md「场景构成与七物件绑定」半开的门扇 半开的门扇;生涯页返回钮口径由结构校验兜底(生涯段)
|
||||
# 营地语境:开始层全程隐藏(笔记本入口在营地场景根——关生涯回营地不回开始层,卡④ T3 语境分支)
|
||||
main._camp_pres.open_camp() # 重开营地场景根(笔记本入口语境)
|
||||
_settle()
|
||||
@@ -106,7 +106,7 @@ func _ready() -> void:
|
||||
if main.ui.modals.menu.career_overlay.visible or main.ui.screens.start_overlay.visible:
|
||||
problems.append("[career] 关闭后页未隐藏或开始层回弹(营地语境分支失守)〔营地图批 V5〕")
|
||||
# ---- Esc 浮窗结构段(卡⑤——三钮在位且仅三+零动效契约+登记序在册+debug_badge 不波及)----
|
||||
# 判据出处: design/ux/camp.md:45 ESC 优先序:有窗先关最上层窗、无窗才进浮窗;各窗自带关闭钮(Esc 段)
|
||||
# 判据出处: design/ux/camp.md「叠层与开合」各窗自带关闭钮 各窗自带关闭钮、无窗才进浮窗;各窗自带关闭钮(Esc 段)
|
||||
main._camp_pres.open_camp()
|
||||
_settle()
|
||||
var gpos_gate: Vector2 = main.ui.modals.camp.scene.get_hotspot_rect(&"gate").get_center()
|
||||
@@ -159,8 +159,10 @@ func _ready() -> void:
|
||||
var quit_chain := FileAccess.get_file_as_string("res://presentation/main.gd") + FileAccess.get_file_as_string("res://presentation/main_esc_flow.gd")
|
||||
if not quit_chain.contains("MainEscFlow.on_quit(self)") or not quit_chain.contains("root.quit_game()"):
|
||||
problems.append("[esc] 退出调用链断裂(_on_esc_quit→_on_quit→_quit_game)〔ESC批 V5〕")
|
||||
if main.ui.screens.debug_badge.visible:
|
||||
problems.append("[esc] 浮窗开态 debug_badge 可见(发布态恒隐——float 类不注册 ModalStack 应零波及)〔ESC批 V8〕")
|
||||
# 调试入口断言(V8 随恢复批换代——全局浮层角标=UI 最顶层、任何 UI 不遮挡,浮窗开态仍应可见;
|
||||
# 2026-11-09 特批恢复批——发布态恒隐语义退役,原「浮窗开态不可见」预期过期漏翻,CI run 152 红实证)
|
||||
if main.ui.screens.debug_badge == null or not main.ui.screens.debug_badge.visible:
|
||||
problems.append("[esc] 浮窗开态调试角标不可见(全局浮层最顶层失守——被遮挡)〔ESC批 V8〕")
|
||||
push_esc.call()
|
||||
_settle()
|
||||
if main.ui.modals.camp.esc_overlay.visible:
|
||||
@@ -213,7 +215,7 @@ func _ready() -> void:
|
||||
_settle()
|
||||
|
||||
# ---- 冒险簇(真流推进:开冒险→地图选路态→选战斗节点→战斗 HUD)----
|
||||
# 判据出处: design/ux/level-map.md:3 图上点击选路·候选按钮退役(冒险簇选路真点组)
|
||||
# 判据出处: design/ux/level-map.md「UX Spec: 关卡画面」四项设计拍板 四项设计拍板(冒险簇选路真点组)
|
||||
ProbeUiUtil.isolate_save(main, "smoke_ui_struct_probe_adv", true, false, true)
|
||||
main.ui.modals.menu.debug_overlay.seed_edit.text = "42" # 种子钉死(种子框默认为空=非首局随机,结构采样确定性禁依赖默认分支)
|
||||
main._start_adventure_from_menu()
|
||||
@@ -243,7 +245,7 @@ func _ready() -> void:
|
||||
# ---- 图例层(旧模态、首过结构族):ap_bar legend_toggled
|
||||
# 信号真路径开(board_zone 信号→组合根 _on_legend_toggled→_open_modal)→结构断言族→
|
||||
# closed 信号真路径关(close()→组合根 _on_modal_closed)。
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:88 图例面板=模态族:统一登记序栈、入栈出栈、关闭逐层恢复(图例组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「提示与弹层:轻提示随起随消、重弹层排队进出」入栈出栈 入栈出栈、入栈出栈、关闭逐层恢复(图例组)
|
||||
main.ui.battle.board_zone.ap_bar._btn_legend.pressed.emit() # 前提注入(保留 emit):emit 选路路径下 battle_root 未及显示且输入锁在(实证在案),真点不可达——图例开启的真输入承载随「route 信号路径屏幕切换时序」发现一并呈报待裁
|
||||
_settle()
|
||||
if not main.ui.modals.run.legend_overlay.visible:
|
||||
@@ -406,7 +408,7 @@ const _PAUSE_READONLY_SIGNALS: Array[String] = [
|
||||
|
||||
|
||||
func _status_readonly_contract(main: Node) -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:21 视图零核心写调用、依赖单向(status 只读巡检组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.3 依赖单向,核心写调用完成」依赖单向 依赖单向、依赖单向(status 只读巡检组)
|
||||
var overlay: Control = main.ui.modals.run.status_panel
|
||||
var stack: Array = [overlay]
|
||||
var conn_count := 0
|
||||
@@ -453,7 +455,7 @@ func _status_zero_motion_contract(main: Node) -> void:
|
||||
# 清单外零连接。白名单={视图自身 _emit_closed〔返回钮〕, 组合根 _on_career_closed};页内任何
|
||||
# 购买/导航/写入方向的新连接一律红,须先入册审查。
|
||||
func _career_readonly_contract(main: Node) -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:21 视图零核心写调用、依赖单向(career 只读巡检组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.3 依赖单向,核心写调用完成」依赖单向 依赖单向、依赖单向(career 只读巡检组)
|
||||
var overlay: Control = main.ui.modals.menu.career_overlay
|
||||
var stack: Array = [overlay]
|
||||
var conn_count := 0
|
||||
@@ -500,7 +502,7 @@ func _career_zero_motion_contract(main: Node) -> void:
|
||||
# _career_registry_contract 的断言(career=状态面板后/确认弹窗前、树序同步)由本全量合同覆盖)
|
||||
# ⑭选档界面契约(卡③ sl1/sl2/sl3/sl4/sl9——呈现面全部来自喂入数据,视图零自判)
|
||||
func _save_select_contract(main: Node, tpl: String) -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:61 三存档位独立文件、激活态由选档界面建立(选档契约组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「存什么:表与档分家,局内系统资源不入档」第一条边界 第一条边界、激活态由选档界面建立(选档契约组)
|
||||
var sso: Node = main.ui.modals.menu.save_select_overlay
|
||||
# sl1 三槽呈现:槽卡计数==3+零滚动容器(禁滚动长列表形态——契约 1)
|
||||
var rows: VBoxContainer = sso._rows_box
|
||||
@@ -580,7 +582,7 @@ func _collect_labels(node: Node, out: Array[String]) -> void:
|
||||
|
||||
|
||||
func _modal_registry_contract(main: Node) -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:54 模态覆盖层层级规则——新增覆盖层必须登记 z 序位置(登记序契约组)
|
||||
# 判据出处: design/engineering/code-conventions.md「2.3 模态覆盖层层级规则」打开任何模态覆盖层时 打开任何模态覆盖层时(登记序契约组)
|
||||
var list: Array = main.ui.flow.stack._list
|
||||
# ① 登记册序==合同模态序(逐位点名——合同是登记序唯一事实源)
|
||||
var contract_modals: Array = []
|
||||
@@ -648,7 +650,7 @@ func _modal_registry_contract(main: Node) -> void:
|
||||
|
||||
# ⑬career 零跳转契约(提纲 P4 甲——页内零「前往他处」入口:除「返回」外任何导航钮=红)
|
||||
func _career_nojump_contract(main: Node) -> void:
|
||||
# 判据出处: design/ux/camp.md:19 生涯记录入口与返回钮口径由结构校验兜底——页内零导航入口(零跳转契约组)
|
||||
# 判据出处: design/ux/camp.md「场景构成与七物件绑定」半开的门扇 半开的门扇(零跳转契约组)
|
||||
for nav in ["营地", "商店", "设置", "冒险", "继续上局", "退出", "前往"]:
|
||||
if ProbeUiUtil.find_button(main.ui.modals.menu.career_overlay, nav, "contains") != null:
|
||||
problems.append("[career][nojump] 页内出现导航入口「%s」(零跳转违约——生涯纯只读)" % nav)
|
||||
@@ -658,7 +660,7 @@ func _career_nojump_contract(main: Node) -> void:
|
||||
# (名行基线离盒底 1px 同型高危写法返修回归闸;
|
||||
# 内容矩形=StandeeBody.content_rect(),最低绘制元素=底座下缘)
|
||||
func _standeefit_contract(main: Node) -> void:
|
||||
# 判据出处: design/ux/battle.md:154 主角站桩立绘(无框立绘+落影)——站桩内容矩形⊆舞台(站桩适配组)
|
||||
# 判据出处: design/ux/battle.md「封印格呈现预览」封印受理后格子进入 封印受理后格子进入(无框立绘+落影)——站桩内容矩形⊆舞台(站桩适配组)
|
||||
var st: Node = main.ui.battle.stage
|
||||
if st == null or st.hero_standee == null:
|
||||
problems.append("[standee] 舞台/主角站桩缺失(断言中断)")
|
||||
@@ -743,7 +745,7 @@ func _in_scroll(c: Control) -> bool:
|
||||
|
||||
|
||||
func _audit(screen: String, roots: Array) -> void:
|
||||
# 判据出处: design/engineering/architecture/architecture.md「三屏壳与组合根」(组合根交接面) 组合根交接面与呈现装配——屏结构审计宿主面(结构审计组)
|
||||
# 判据出处: design/engineering/architecture/architecture.md「三屏壳与组合根」呈现场景拆为三屏壳 呈现场景拆为三屏壳(组合根交接面) 组合根交接面与呈现装配——屏结构审计宿主面(结构审计组)
|
||||
for r in roots:
|
||||
if r != null and is_instance_valid(r):
|
||||
_force_layout(r)
|
||||
|
||||
@@ -43,8 +43,8 @@ func _ready() -> void:
|
||||
# ① 全局浮层角标开窗(调试入口=UI 最顶层浮层,任何 UI 不遮挡——
|
||||
# main 直接子层、LAYER_CONTRACT 末位 float 类;boot 菜单优先不开浮窗,角标真实点击路径开窗;
|
||||
# 悬浮于菜单之上——开始层不隐藏;树序新基准=登记册末位(确认弹窗之后=绘制序最上))
|
||||
# 判据出处: design/engineering/test-conventions.md:49 调试面=DebugOverlay/DS_DEBUG——发布态恒隐无 UI 开启口、开发期临时启用(①开窗层级组)
|
||||
main._show_debug_overlay() # 发布态角标恒隐(main.gd:138 _debug_entry 缺省 false)——角标信号路径已退役(:123 同款先例),开窗经组合根直调承载
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」2026 2026(2026-11-09 特批恢复批,①开窗层级组)
|
||||
main.ui.screens.debug_badge.pressed.emit() # 角标真实信号路径 → 组合根 _on_debug_badge_pressed → C6 单口(2026-11-09 恢复)
|
||||
await get_tree().process_frame
|
||||
if not main.ui.modals.menu.debug_overlay.visible:
|
||||
problems.append("调试浮层角标点击后浮窗未开(全局浮层入口失守)")
|
||||
@@ -57,7 +57,7 @@ func _ready() -> void:
|
||||
if str(boosted_atk) not in main.ui.modals.menu.debug_overlay.effect_text() or str(boosted_hp) not in main.ui.modals.menu.debug_overlay.effect_text():
|
||||
problems.append("生效预览未联动(%s)" % main.ui.modals.menu.debug_overlay.effect_text())
|
||||
# ③ 应用(真实信号路径:apply_requested → 组合根)——E4 后加成零表写,生效断言移至 ⑧ 战斗快照
|
||||
# 判据出处: design/engineering/test-conventions.md:49 调试面加成链路:滑条联动/应用/重置、hero 表运行期只读(②③④⑦组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片、hero 表运行期只读(②③④⑦组)
|
||||
var apply_btn: Button = ProbeUiUtil.find_button(main.ui.modals.menu.debug_overlay, "应用并关闭")
|
||||
if apply_btn == null:
|
||||
problems.append("调试浮窗「应用并关闭」钮缺失")
|
||||
@@ -72,7 +72,7 @@ func _ready() -> void:
|
||||
ProbeUiUtil.push_click(main, reset_btn)
|
||||
# ⑤ 批量模拟全链路(N=10——走 level_autoplay 与 headless 扫描同口径;表基线由组合根复位;
|
||||
# 菜单态上下文未锁定=按钮可点,is_running 语义=模拟在跑〔18卡⑦ 与对局禁用态拆分〕)
|
||||
# 判据出处: design/engineering/test-conventions.md:49 调试面批量模拟链路:N=10 输出关卡完成率/剩余 HP/败北节点(⑤组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(⑤组)
|
||||
main.ui.modals.menu.debug_overlay.set_sliders(100, 0)
|
||||
main.ui.modals.menu.debug_overlay.set_sim_count(10)
|
||||
# 折叠区控件真输入通道(test-conventions §2——先滚轮滚入可视区再点):sim 钮在滚动列表 boot
|
||||
@@ -155,12 +155,14 @@ func _ready() -> void:
|
||||
# ⑨ 对局中可开(18卡⑦ P2 甲/T2 防护——S1+ 停机点回归闸):战斗屏角标真实信号路径开窗;
|
||||
# 棋盘输入不锁、状态角标不置灰(「默认开×遮挡复活」下必锁死的破约回归面);
|
||||
# 对局中批量模拟/两层调试两钮禁用;当局数据六项与只读访问器逐项一致;关闭钮真实路径收窗恢复
|
||||
# 判据出处: design/engineering/test-conventions.md:49 调试面对局态:不锁棋盘输入/两钮禁用/当局数据只读一致(⑨组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(⑨组)
|
||||
var dbg_badge: Button = main.ui.screens.debug_badge
|
||||
if dbg_badge == null or dbg_badge.visible:
|
||||
problems.append("对局中调试浮层角标非恒隐(发布态语义失守——卡⑦ 删写死行批)")
|
||||
if dbg_badge == null or not dbg_badge.visible:
|
||||
problems.append("对局中调试浮层角标未点亮(全局浮层最顶层失守)")
|
||||
else:
|
||||
main._show_debug_overlay() # 对局中开浮窗回归经直调承载(:61 既有直调先例——发布态角标恒隐,按钮信号路径退役)
|
||||
if dbg_badge.disabled:
|
||||
problems.append("战斗屏调试角标被置灰(T2 排除式判据失守)")
|
||||
dbg_badge.pressed.emit() # 真实按钮信号路径 → 组合根 _on_debug_badge_pressed → C6 单口(2026-11-09 特批恢复批)
|
||||
if not main.ui.modals.menu.debug_overlay.visible:
|
||||
problems.append("对局中角标开浮窗失败(P2 甲对局中可达失守)")
|
||||
if main.ui.flow.locks_input():
|
||||
@@ -199,7 +201,7 @@ func _ready() -> void:
|
||||
_overlay_zero_motion_contract(main, problems)
|
||||
# ⑩ 种子三分单点断言(18卡⑦ C1——判定只落 _seed_value() 单点;对局态不影响本判定面):
|
||||
# 显式合法整数全场景优先(含首局)→ 首局(存档布尔 false)恒 42 → 非首局空框引擎熵连抽不全等 42
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「主种子」(组合根交接面) seed_value=组合根公开服务面(⑩种子三分判定单点组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「失败重开与主种子:倒下即终,重开即全新一轮」失败没有中间态 失败没有中间态(组合根交接面) seed_value=组合根公开服务面(⑩种子三分判定单点组)
|
||||
main.ui.modals.menu.debug_overlay.seed_edit.text = "777"
|
||||
if main.seed_value() != 777:
|
||||
problems.append("显式种子输入未优先(_seed_value != 777——C1 ①失守)")
|
||||
@@ -240,7 +242,7 @@ func _ready() -> void:
|
||||
# 全连接巡检——白名单={视图自身八方法 + 注册面模态编排口 ui.flow.close(closed 外发消费——
|
||||
# 注册面批把该连接目标从组合根转发壳改为 flow 真方法,机检白名单随批登记同一连接)};
|
||||
# 当局数据区块=纯标签零连接在此被一并约束(新增任何连接=红须入册审查)。
|
||||
# 判据出处: design/engineering/code-conventions.md:21 视图零核心写调用、依赖单向(白名单外零连接巡检组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.3 依赖单向,核心写调用完成」依赖单向 依赖单向、依赖单向(白名单外零连接巡检组)
|
||||
func _overlay_readonly_contract(main: Node, problems: Array) -> void:
|
||||
var overlay: Control = main.ui.modals.menu.debug_overlay
|
||||
var stack: Array = [overlay]
|
||||
|
||||
@@ -84,6 +84,7 @@ tests/
|
||||
| 效果发射端口单点 | 战斗结算 | `BattleOrchestrator.begin_battle()`(真实装配链端口接线+合成行闭面守卫经 `DamageController.flush_submit()` 承伤路径) | `effect_port_test.gd:_smoke_effect_port_wiring`;`effect_port_test.gd:_test_business_classes_engine_free`;`effect_port_test.gd:_test_biz_fact_face_closed` |
|
||||
| 轮内流与结算五段全序 | 战斗结算 | `BattleOrchestrator.begin_battle()` | `round_flow_skill_pool_test.gd:_smoke_full_battle`;`round_flow_skill_pool_test.gd:_smoke_settlement_segments`;`settle_segments_test.gd:_init`;`settlement_wiring_snapshot_test.gd:_init`;`encapsulation_sweep_test.gd:_init` |
|
||||
| 技能池数据面与回放独立 | 敌人系统 | `BattleOrchestrator.begin_battle()`(技能池抽号/校验) | `round_flow_skill_pool_test.gd:_smoke_skill_pool_data`;`round_flow_skill_pool_test.gd:_smoke_skill_pool_replay_independence`;`trigger_cond_test.gd:_init`;`pool_case_d_test.gd:_init` |
|
||||
| 全局特殊间隔闸 | 敌人系统 | `BattleOrchestrator.begin_battle()`(开轮摇号池节奏闸——特殊技兑现后强制普攻) | `round_flow_skill_pool_test.gd:_smoke_skill_pool_interval_gate`;`round_flow_skill_pool_test.gd:_smoke_skill_pool_interval_pity`(计划——需求卡片「全局特殊间隔闸批」2026-11-09 锚定) |
|
||||
| Boss 半血解锁技门控 | 敌人系统 | `BattleOrchestrator.begin_battle()`(Boss 行) | `skill_unlock_test.gd:_test_gate_predicate`;`skill_unlock_test.gd:_test_latch_irreversible` |
|
||||
| 封印与极性路由/不可逆 | 地图战斗资源×战斗结算 | 效果引擎 × `BattleOrchestrator.begin_battle()` | `seal_polarity_test.gd:_smoke_seal_ap_exhausted`;`seal_polarity_test.gd:_smoke_seal_irreversible_quadrants`;`seal_polarity_test.gd:_smoke_polarity_routing` |
|
||||
| 状态效果施加与行值(减伤/持续/叠层读表) | 战斗结算 | `BattleOrchestrator.begin_battle()`(状态施加段) | `round_flow_skill_pool_test.gd:_check_defensive_stance_values`(计划——需求卡片「QA覆盖余量收口批」2026-11-07 锚定) |
|
||||
@@ -112,7 +113,8 @@ tests/
|
||||
| 棋盘按参数行出图、数字恒真 | 棋盘生成 | `BoardGenerator.generate()` | `board_generator_test.gd:_test_generate_shape_and_mines`;`board_generator_test.gd:_test_digits_equal_neighbor_mine_count`;`board_generator_test.gd:_test_spawn_edge_from_table` |
|
||||
| 出生区边长表单点(布雷域基/R₀ 下限/剃雷域半径全由 spawn_edge 导出) | 棋盘生成 | `BoardGenerator.generate()`/`BoardGenTable.validate()` | `board_generator_test.gd:_test_spawn_edge_from_table` |
|
||||
| 同参数同种子逐位复现、异种子不退化 | 棋盘生成 | `BoardGenerator.generate()` | `board_generator_test.gd:_test_same_seed_bit_identical`;`board_gen_reward_test.gd:_smoke_board_generator` |
|
||||
| 可推理率与清图可达(合法性先于质量分)、重试有界、降级诚实 | 棋盘生成 | `BoardGenerator.measure_inferability()`/`BoardGenerator.is_clearable()` | `board_generator_test.gd:_test_clearable_and_inferability_selfconsistent`;`board_generator_test.gd:_test_target_mine_count_single_source`;`board_gen_reward_test.gd:_smoke_board_generator` |
|
||||
| 出板检查(出生区无雷/开局不全开、白给板同流重摇、指标集换代) | 棋盘生成 | `BoardGenerator.generate()` | `board_generator_test.gd:_test_board_check_and_reroll`(计划——需求卡片「可推理率退役批」2026-11-09 锚定);`board_gen_reward_test.gd:_smoke_board_generator`(键集断言段) |
|
||||
| 棋盘可推理率离线测量(仅 sim,不入生成管线) | 棋盘生成 | `SimInferabilityMeasure.measure()`(类计划——本卡 T2 落件;经 `res://sim/calibrate_boards.gd` 缩样直跑消费) | `inferability_measure.gd:measure`(工具直跑读数——登记进实现报告,不进闸)(计划——需求卡片「可推理率退役批」2026-11-09 锚定) |
|
||||
| 装板与开局免费展开(封锁格无资源、计入清图) | 排雷玩法 | `MinesweeperRules.install_board()` | `minesweeper_rules_test.gd:_test_install_invariants`;`seal_polarity_test.gd:_smoke_resource_surface` |
|
||||
| 挖/封印合法性与可辨拒绝(拒绝零副作用、挖封印格被拒) | 排雷玩法 | `MinesweeperRules.settle_batch()` | `minesweeper_rules_test.gd:_test_dig_face_rules`;`minesweeper_rules_test.gd:_test_seal_place`;`minesweeper_rules_test.gd:_test_reject_out_of_catalog`;`minesweeper_rules_test.gd:_test_dig_sealed_rejected`;`minesweeper_rules_test.gd:_test_classify_seal_clears`(计划——需求卡片「封印动作改版批」2026-11-07 锚定) |
|
||||
| 棋盘揭示预览只读口(零状态写入/与实挖揭示集同口径) | 排雷玩法 | `MinesweeperRules.preview_reveal()` | `minesweeper_rules_test.gd:_test_preview_reveal_readonly` |
|
||||
@@ -122,6 +124,8 @@ tests/
|
||||
| 棋盘格面绘制显示(渲染闸棋盘三图 golden 逐像素——变异标记/奖励徽章/移除退色) | 排雷玩法 | `board_shot_probe.tscn` 窗口化真渲染(`BoardView.rebuild()` 固定种子单关直构)→`golden_compare.py` 逐像素 | `board_shot_probe.gd:_ready`(棋盘三图采集——渲染闸基线面)(计划——需求卡片「QA覆盖余量收口批」2026-11-07 锚定) |
|
||||
| AP 扣费、末点耗尽即收轮与战斗收束清零 | 行动经济 | `MinesweeperRules.settle_batch()`(→`ActionEconomy.try_spend()`/`ActionEconomy.notify_combat_end()`) | `seal_polarity_test.gd:_smoke_seal_ap_exhausted`;`round_flow_skill_pool_test.gd:_smoke_full_battle`;`round_flow_skill_pool_test.gd:_smoke_active_refresh` |
|
||||
| 停手转存储备与轮内刷新(上限/AP 不重置/刷新图零清图奖励) | 行动经济 | `BattleOrchestrator.player_request_refresh()`/`MinesweeperRules.settle_batch()` | `round_flow_skill_pool_test.gd:_smoke_active_refresh`;`seal_polarity_test.gd:_smoke_refresh_provenance_guard`;`refresh_feats_test.gd:test_no_feats_baseline` |
|
||||
| 储备点整局冒险携带与冒险收束清零 | 行动经济 | `AdventureRunner.adventure_counters["rap"]`→`BattleOrchestrator.begin_battle()`/`AdventureRunner._settle()` | `round_flow_skill_pool_test.gd:_test_rap_carries_across_battles`;`round_flow_skill_pool_test.gd:_test_rap_cleared_on_adventure_settle`;`feat_vouchers_test.gd:_test_rap_breakpoint_roundtrip`(计划——需求卡片「刷新经济改版批」2026-11-09 锚定) |
|
||||
| 储能秘宝关首注入与正确动作产储备点 | 行动经济×秘宝 | `BattleOrchestrator._begin_battle_preview_economy()`/`GrantSegment._apply_rap_hits()` | `treasure_effects_test.gd:_test_level_start_rap_grant`;`treasure_effects_test.gd:_test_correct_action_rap`;`treasure_effects_test.gd:_test_wrong_action_gives_no_rap`(计划——需求卡片「刷新经济改版批」2026-11-09 锚定) |
|
||||
| 换图系刷新链路与效果词表接线 | 行动经济×战斗结算×奇物 | `MinesweeperRules.settle_batch()`/`BattleOrchestrator.player_request_refresh()` | `effect_words_t1_test.gd:_init`;`forge_table_test.gd:_test_effect_kinds_closed`;`refresh_feats_test.gd:test_board_refresh_fact_only_on_success` |
|
||||
| 换图基座:挖格产 RAP 与刷新折扣 | 行动经济×奇物 | `MinesweeperRules.settle_batch()`/`BattleOrchestrator.player_request_refresh()` | `refresh_feats_test.gd:test_reserve_on_accepted_dig`;`refresh_feats_test.gd:test_refresh_discount_gate_and_charge`;`refresh_feats_test.gd:test_double_base_stack` |
|
||||
| 换图输出:刷新群伤与蓄力攻击 | 战斗结算×奇物 | `BattleOrchestrator.player_request_refresh()`→轮末 `MinesweeperRules.settle_batch(stop)` | `refresh_feats_test.gd:test_blast_defers_to_combat_segment`;`refresh_feats_test.gd:test_charge_layers_consumed_same_round`;`run_time_fatal_test.gd:_init` |
|
||||
@@ -152,15 +156,22 @@ tests/
|
||||
| 站桩敌人呈现与结算演出落点 | 战斗表现 | `BattleStageView.enemy_standee_center()`/`BattleEndOverlay.open_victory()` | `standee_fx_sweep_test.gd:_init`;`pacing_queue_test.gd:_init` |
|
||||
| 站桩呈现定值与素材绑定 | 战斗表现 | `UiKit.load_tex()`/`StandeeBody.name_line_probe()` | `standee_present_values_test.gd:_init` |
|
||||
| 站桩显示档与素材分辨率绑定 | 战斗表现 | `StandeeBody.portrait_probe()`/`StandeeMotion.PORTRAIT_DISPLAY_H` | `standee_present_values_test.gd:_check_display_tier` |
|
||||
| 敌方意图徽标类型级预告 | 战斗表现 | `StandeeBody.set_pending()` → `StandeeBody.intent_probe()` | `standee_fx_sweep_test.gd:_init` |
|
||||
| B 区舞台背景三关变体与连续地面层(按 board_type 选图/地面层高度读布局表/四柱光柱退役) | HUD框架 | `BattleStageView.set_board_type()` | `stage_background_test.gd:_test_background_selection`;`stage_background_test.gd:_test_ground_layer_geometry`;`stage_background_test.gd:_test_beams_retired` |
|
||||
| 动画帧数规格(待机/攻击/受击;现役单帧形制锚定) | 战斗表现 | `UiKit.load_tex()`(`TEX_HERO_*` 四态件装载链——棋盘站立/行走与舞台三态同源) | `animation_frame_spec_test.gd:_test_spec_table`;`animation_frame_spec_test.gd:_test_current_form` |
|
||||
| 战斗屏三区几何与棋盘格边长(分辨率两档×四档板型) | HUD框架 | `BoardView.set_cell_area()`(D 区可用面积 → 格边长);读面 `BoardView.cell_size` | `layout_probe.gd:_ready`;`board_gen_reward_test.gd:_smoke_layout_cell_formula`;`stage_background_test.gd:_test_side_rail_width_from_table`/`_test_log_band_settle_height`(计划——需求卡片「QA覆盖余量收口批」2026-11-07 锚定) |
|
||||
| 战斗屏三区几何与棋盘格边长(分辨率两档×四档板型) | HUD框架 | `BoardView.set_cell_area()`(D 区可用面积 → 格边长);读面 `BoardView.cell_size` | `layout_probe.gd:_ready`;`board_gen_reward_test.gd:_smoke_layout_cell_formula`;`stage_background_test.gd:_test_side_rail_width_from_table`(`_test_log_band_settle_height` 计划用例随明细带退役作废——需求卡片「明细带退役呈现改版批」2026-11-10) |
|
||||
| 调参测速批量模拟(逐帧步进与统计读数) | 调参测量 | `TuneSimController.run()`(调试浮窗批量模拟入口) | `tune_sim_batch_parity_test.gd:_init`(配对对拍套件) |
|
||||
| sim 驱动循环单点(缺省零变化与策略/日志回调形态) | 调参测量 | `BattleDriver.drive_round()`(两参缺省与五参回调两形态) | `battle_driver_drive_test.gd:_smoke_drive_round_contract` |
|
||||
| 模拟玩家 0 格连锁算子(经真实闭包,零盲挖语义保持) | 调参测量×排雷玩法 | `AutoPlayer._deduce()`(经 `perfect_action()` 装配链) | `auto_player_deduce_test.gd:_smoke_zero_chain_rule` |
|
||||
| 刷新提示文案读表拼接(RAP 不足/轮上限两 toast 零字面量) | HUD框架 | `Main._on_refresh_confirmed()`(两 toast 装配面)+`player_copy_sweep` 源扫描 | `player_copy_sweep_test.gd:_sweep_refresh_toast_no_literals` |
|
||||
| 试玩日志器 ap_per_round 必填注入守卫(未注入拒绝开会话) | 表现与支撑 | `PlaytestLogger.start_session()` | `playtest_logger_guard_test.gd:_smoke_required_injection` |
|
||||
| 战斗叙述与终局文案(数值带入/胜负互异) | HUD框架 | `BattleNarrator.battle_end_text()`/`BattleNarrator.boss_name()` | `battle_narrator_test.gd:_test_numeric_lines_carry_values`;`battle_narrator_test.gd:_test_end_text_differs_by_result`;`battle_narrator_test.gd:_test_boss_name_uses_boss_rowset` |
|
||||
| 终局判定文案与战末账行 | HUD框架 | `BattleEndOverlay.open_victory()`/`open_defeat()`(verdict_line 由组合根直拼传入) | `ui_click_probe.gd:_ready`(终局浮层段) |
|
||||
| B 区零文字带 | HUD框架 | `Main._ready()`(组合根场景树装配)+节点推进/恢复/商店/终局真实流 | `log_band_retired_test.gd:_test_no_log_view_node`;`log_band_retired_test.gd:_test_b_zone_zero_text` |
|
||||
| 清图兑付浮字 | HUD框架 | `BoardZoneView.spawn_clear_reward_text()`(round_end clear 分支装配) | `clear_reward_text_test.gd:_test_spawn_and_decay`;`clear_reward_text_test.gd:_test_no_overlap`;`clear_reward_text_test.gd:_test_decay_curves` |
|
||||
| 解锁拍零新增呈现 | HUD框架 | `RowPacer.enqueue()`→`consume_now()`(skill_unlock 高光行消费流,快照取消费时刻) | `unlock_zero_ui_test.gd:_test_zero_delta` |
|
||||
| 文案承载单点 | 数据配置与跨系统契约 | `TranslationServer.set_locale()` 后场景 `Label.tr()` 真实查表 | `player_copy_sweep_test.gd:_sweep_tr_roundtrip` |
|
||||
| 表行文案 key 化 | 数据配置与跨系统契约 | `ConfigDB._ready()`(autoload 加载真实表+schema 校验闸) | `config_table_key_test.gd:_test_display_key_format` |
|
||||
| 文案漏网清零 | 数据配置×表现与支撑 | `Main._ready()`(组合根装配链全量加载)+`player_copy_sweep` 源扫描 | `player_copy_sweep_test.gd:_sweep_zero_product_literals` |
|
||||
| 玩家面文案与危险格格面字形 | HUD框架 | `BoardView.rebuild()`/`StatusSlotRow.set_effects()` | `player_copy_sweep_test.gd:_sweep_board_glyph`;`player_copy_sweep_test.gd:_sweep_legend`;`player_copy_sweep_test.gd:_sweep_hero_panel` |
|
||||
| 营地场景图十层铺底与门洞留空呈现 | 营地场景视图 | 进入存档→选档→进档→营地场景屏(`CampSceneView.setup_layers()` 驱动);单元测试载入 `camp_scene_layout.tres` | `shot_probe.gd:_ready`(camp 截图段);`camp_scene_layout_test.gd:_test_layout_hotspot_geometry` |
|
||||
| 营地七物件命中区点选与分界面可达 | 营地场景视图 | 七物件命中区 → 合成鼠标事件经 `push_input` 真点(`ProbeUiUtil.push_click_at` 热点中心)→ `CampSceneView._gui_input()`(命中发 `object_pressed` 信号) → 组合根开界面(2026-11-06 真输入化,残险登记撤) | `ui_click_probe.gd:_ready`(七物件合成点击段——真输入驱动) |
|
||||
@@ -182,6 +193,8 @@ tests/
|
||||
| 停手钮真输入命中与停手收轮落效 | 行动经济 | ui_click_probe 使能窗真输入点击(AP 条停手钮经 `ProbeUiUtil.push_click()`)+journey_player 全线跑批(sim) | `ui_click_probe.gd:_stoptest_tick`(计划测试——需求卡片「QA harness 缺陷与覆盖遗漏收口批」2026-11-06 锚定) |
|
||||
| 停点链与控件级真输入命中 | HUD框架 | 探针与测试宿主真输入驱动(节点继续/三选一选卡·确认/弃图刷新确认/奖励刷新/地图候选矩形中心/调试浮窗钮,一律经 `ProbeUiUtil.push_click()`/`push_click_at()` 进 `push_input`) | `ui_click_probe.gd:_ready`(停点链段——计划测试,需求卡片「QA harness 缺陷与覆盖遗漏收口批」2026-11-06 锚定) |
|
||||
| 控件动线扩面真输入可达(图例关闭/节点继续/三选一与商店/秘宝架/树高档与先手/弃图链/地图放弃/Esc 设置/减动效开关) | HUD框架×各屏 | 合成 InputEvent 经 Viewport push_input 真点注入(`ProbeUiUtil.push_click_at()`;扩面十一段,高档钮经调试注钥使能) | `ui_click_probe.gd:_ready`(动线扩面段)(计划——需求卡片「QA覆盖余量收口批」2026-11-07 锚定) |
|
||||
| 冒险簇选路两段式与战斗HUD实采样结构审计 | HUD框架×关卡画面 | 合成鼠标事件经 Viewport push_input 真点候选命中矩形中心(`ProbeUiUtil.push_click_at()`)→ `LevelMapScreen._submit_choice()` → `route_chosen` → 组合根回战斗屏;第一段 emit 接线断言快速失败、不充当真实入口 | `ui_struct_probe.gd:_adventure_wiring_stage`/`ui_struct_probe.gd:_adventure_real_stage`(计划——需求卡片「测试面四项收口批」2026-11-10 锚定) |
|
||||
| 图例层两段式开合 | HUD框架 | AP 条图例钮 `ProbeUiUtil.push_click()` 真点开层 → 「关闭」钮真点收层(`find_button()` 寻钮);第一段 `pressed.emit()` 标〔接线断言〕 | `ui_struct_probe.gd:_legend_two_stage`(计划——需求卡片「测试面四项收口批」2026-11-10 锚定) |
|
||||
|
||||
**旅程段七:数据配置与跨系统契约**
|
||||
|
||||
@@ -193,7 +206,7 @@ tests/
|
||||
| 运行期越域致命与进程非 0 退出 | 数据配置 | `BoardGenTable.resolve_row()`/`ConfigDbResolver.resolve_enemy_rowset()` | `config_db_fatal_oob_test.gd:_trigger_oob`;`config_db_resolver_test.gd:_test_request_oob` |
|
||||
| 加载期违规表拒绝:跨表悬空/计数器前缀/真视窄域/效果类型出域 | 数据配置×秘宝×奇物 | `ConfigDB.load_tables()` | `reward_dangling_treasure_test.gd:_init`;`counter_prefix_fatal_test.gd:_assert_rejected`;`treasure_target_violation_test.gd:_init`;`effect_kind_retired_test.gd:_assert_rejected`;`extended_row_violation_test.gd:_init` |
|
||||
| 表结构守卫:域校验/行序键/跨字段互锁/配额锚 | 数据配置×敌人系统×地形变异×冒险结构 | `EnemyTable.validate()`/`VariationTable.variant_pool()`/`AdventureTable.validate()` | `table_structure_guard_test.gd:_smoke_enemy_bands`;`table_structure_guard_test.gd:_smoke_variation_framework`;`table_structure_guard_test.gd:_smoke_adventure_table`;`table_structure_guard_test.gd:_test_feat_cap_required` |
|
||||
| schema 违约词拒绝路径与关键表值钉(空表/冻结/出域/白名单/settlement 钉/cap 段七槽钉) | 数据配置×战斗结算 | 各表 schema `validate()` 直调注入坏行(`BoardGenTable.validate()` 同款面)/表行读值 | `schema_vocab_violation_test.gd:_check_empty_tables`;`table_structure_guard_test.gd:_check_settlement_pin_values`;`table_structure_guard_test.gd:_check_curio_cap_segment_pins`(计划——需求卡片「QA覆盖余量收口批」2026-11-07 锚定) |
|
||||
| schema 违约词拒绝路径与关键表值钉(空表/出域/白名单/settlement 钉/cap 段七槽钉+退役列零违例钉) | 数据配置×战斗结算 | 各表 schema `validate()` 直调注入坏行(`BoardGenTable.validate()` 同款面)/表行读值 | `schema_vocab_violation_test.gd:_check_empty_tables`;`table_structure_guard_test.gd:_check_settlement_pin_values`;`table_structure_guard_test.gd:_check_curio_cap_segment_pins`(计划——需求卡片「QA覆盖余量收口批」2026-11-07 锚定) |
|
||||
| 变异表头域校验(地形变异) | 地形变异 | `VariationTable.validate()` | `table_structure_guard_test.gd:_test_variation_header_domains` |
|
||||
| 难度修饰套乘:空表零行为/套乘生效/越域 clamp | 难度曲线与Boss | `UnitContainer.spawn()`/`ConfigDbResolver.resolve_difficulty_modifiers()` | `table_structure_guard_test.gd:_smoke_difficulty_table`;`config_db_resolver_test.gd:_test_difficulty_clamp` |
|
||||
| Boss 出场门控(每区域恰一 Boss 终点/Boss 节点开战必选 Boss 行集) | 难度曲线与Boss | `NodeMapGenerator.generate()`/`BattleOrchestrator.begin_battle()` | `node_map_generator_test.gd:_test_boss_exit_per_region`;`boss_gate_test.gd:_test_boss_node_spawns_boss_rowset` |
|
||||
@@ -219,13 +232,13 @@ tests/
|
||||
| 战斗循环 | 地图战斗资源.md | 清图奖励双份与零路径;GP 钱包/escrow/商店收口/共享池;封印与极性路由/不可逆 | 已覆盖 | — |
|
||||
| 战斗循环 | 增益状态.md | 系统间契约词表与受理口径:五配方互异/掷点标签成员性/增益布尔受理;同名状态合并策略(叠加/累加/并存)与剩余次数语义;状态效果结算链(逐值衰减/到期移除/战斗结束全清/满层拒绝/独立并存/首授快照);状态实例按个体归属:个体隔离/全体授予逐体发/死亡即清/同体合并照旧;敌方增益自体落点与乘区池按个体;封印与极性路由/不可逆 | 部分覆盖 | 结算链剩余缺口由「断言补齐批」承接;见待办清单「能力清单覆盖缺口补齐」条 |
|
||||
| 战斗循环 | 战斗结算.md | 伤害公式与掷点乘区;伤害单据编排与回放;轮内流与结算五段全序 | 已覆盖 | — |
|
||||
| 战斗循环 | 战斗表现.md | 站桩敌人呈现与结算演出落点;站桩呈现定值与素材绑定;站桩显示档与素材分辨率绑定 | 已覆盖 | 死亡灰化与减动效演出档以探针+人工目检为终态(2026-11-02 用户裁除名,不再补自动断言) |
|
||||
| 战斗循环 | 战斗表现.md | 站桩敌人呈现与结算演出落点;站桩呈现定值与素材绑定;站桩显示档与素材分辨率绑定;敌方意图徽标类型级预告 | 已覆盖 | 死亡灰化与减动效演出档以探针+人工目检为终态(2026-11-02 用户裁除名,不再补自动断言) |
|
||||
| 战斗循环 | 敌人系统.md | 技能池数据面与回放独立;Boss 半血解锁技门控;敌人技能池跨表链接校验;精英行:池继承合并、加载期校验与暂不接线 | 部分覆盖 | 精英行「开战快照拿到合并后池」随接线批验收;见待办清单「战斗节点遭遇编排方式」条 |
|
||||
| 排雷循环 | 地形变异.md | 变异布置门控;表结构守卫:域校验/行序键/跨字段互锁/配额锚 | 已覆盖 | — |
|
||||
| 排雷循环 | 排雷玩法.md | 装板与开局免费展开(封锁格无资源、计入清图);挖/封印合法性与可辨拒绝(拒绝零副作用、挖封印格被拒);封印受理即揭示(身份可查、受理零事件);清图口径换代(挖开∪封印、封印可完成清图) | 已覆盖 | — |
|
||||
| 排雷循环 | 棋盘生成.md | 棋盘按参数行出图、数字恒真;同参数同种子逐位复现、异种子不退化;可推理率与清图可达(合法性先于质量分)、重试有界、降级诚实 | 已覆盖 | — |
|
||||
| 排雷循环 | 棋盘生成.md | 棋盘按参数行出图、数字恒真;同参数同种子逐位复现、异种子不退化;出板检查(出生区无雷/开局不全开、白给板同流重摇、指标集换代);棋盘可推理率离线测量(仅 sim,不入生成管线) | 已覆盖 | — |
|
||||
| 排雷循环 | 行动经济.md | AP 扣费、末点耗尽即收轮与战斗收束清零;停手转存储备与轮内刷新(上限/AP 不重置/刷新图零清图奖励);下轮行动点修正排队与兑现 | 已覆盖 | — |
|
||||
| 表现与支撑 | HUD框架.md | 拒绝反馈分面可辨与未知兜底文案;结算期零逐行文字与 FX 排播链保持;模态覆盖层编排与输入锁;未开格类型微光(8 邻作用集、五组色相、零玩法写入);UI 全局主题与按钮五态(含对比度锚);中文字体随包与字形覆盖;地形瓦片套与格面数字可读(旧行保留,删行归写卡段后续,实现批禁写);棋盘合并岩体与连续地面(深度遮挡、投影、崖面);棋盘浮空数字与引导线(最顶层、顶部预留);D 区行动资源侧栏(AP 左栏、RAP 右栏、全高棋盘);棋盘点击命中与格边公式(逻辑格矩形);旧瓦片退役与普通数字零底牌;棋盘顶面锚点与迷雾几何(微光、变异岩顶偏移,封印格心);战斗叙述与终局文案(数值带入/胜负互异);玩家面文案与危险格格面字形;战斗屏三区几何与棋盘格边长(分辨率两档×四档板型);B 区舞台背景三关变体与连续地面层(按 board_type 选图/地面层高度读布局表/四柱光柱退役);模态句柄分域寻址面 | 已覆盖 | — |
|
||||
| 表现与支撑 | HUD框架.md | 拒绝反馈分面可辨与未知兜底文案;结算期零逐行文字与 FX 排播链保持;模态覆盖层编排与输入锁;未开格类型微光(8 邻作用集、五组色相、零玩法写入);UI 全局主题与按钮五态(含对比度锚);中文字体随包与字形覆盖;地形瓦片套与格面数字可读(旧行保留,删行归写卡段后续,实现批禁写);棋盘合并岩体与连续地面(深度遮挡、投影、崖面);棋盘浮空数字与引导线(最顶层、顶部预留);D 区行动资源侧栏(AP 左栏、RAP 右栏、全高棋盘);棋盘点击命中与格边公式(逻辑格矩形);旧瓦片退役与普通数字零底牌;棋盘顶面锚点与迷雾几何(微光、变异岩顶偏移,封印格心);终局判定文案与战末账行;B 区零文字带;清图兑付浮字;解锁拍零新增呈现;玩家面文案与危险格格面字形;战斗屏三区几何与棋盘格边长(分辨率两档×四档板型);B 区舞台背景三关变体与连续地面层(按 board_type 选图/地面层高度读布局表/四柱光柱退役);模态句柄分域寻址面 | 已覆盖 | — |
|
||||
| 表现与支撑 | 存档序列化.md | 存档写盘⇄读回往返保真;三槽位隔离与激活失败回滚;槽位摘要窥视与坏槽三态;启动态无激活不写盘;旧档迁移链与断点续玩零跳号;存档⇄RNG 快照往返保真 | 已覆盖 | — |
|
||||
| 表现与支撑 | 教学引导.md | — | 未覆盖 | 教学形态与首遇时机待设计;见待办清单「教学形态未定」条 |
|
||||
| 表现与支撑 | 数据配置.md | 全表装载、就绪态与表清单目录对账;进度坐标查行:精确命中/向上取整/封顶/警告去重;运行期越域致命与进程非 0 退出;加载期违规表拒绝:跨表悬空/计数器前缀/真视窄域;表结构守卫:域校验/行序键/跨字段互锁/配额锚 | 已覆盖 | — |
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
|---|---|---|---|
|
||||
| 2026-11-08 | 棋盘三图+menu_boot+lmap 两 Shot+单基线合并(6 张) | DKChan | 确认 |
|
||||
| 2026-11-08 | 屏态五锚+营地窗态五锚+浮层四锚(14 张补锚) | DKChan | 确认 |
|
||||
| 2026-11-09 | menu_boot 换代(调试角标恢复批——右下角「调试」角标重现,预期面视觉变化显式重制) | DKChan | 确认 |
|
||||
| 2026-11-09 | 全屏 14 锚换代(调试角标恢复批后续——角标入帧,实测 0.06–0.15% 容差内;逐张差异包围盒同一 44×36 角标区,画面其余零变化;棋盘三图与 lmap 两 Shot 实测 0.00% 不动) | DKChan | 确认 |
|
||||
|
||||
## 时效判定纪律
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 216 KiB After Width: | Height: | Size: 217 KiB |
|
Before Width: | Height: | Size: 310 KiB After Width: | Height: | Size: 311 KiB |
|
Before Width: | Height: | Size: 251 KiB After Width: | Height: | Size: 251 KiB |
|
Before Width: | Height: | Size: 248 KiB After Width: | Height: | Size: 249 KiB |
|
Before Width: | Height: | Size: 252 KiB After Width: | Height: | Size: 252 KiB |
|
Before Width: | Height: | Size: 260 KiB After Width: | Height: | Size: 260 KiB |
|
Before Width: | Height: | Size: 493 KiB After Width: | Height: | Size: 494 KiB |
|
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 217 KiB After Width: | Height: | Size: 218 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 243 KiB |
|
Before Width: | Height: | Size: 311 KiB After Width: | Height: | Size: 331 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 194 KiB After Width: | Height: | Size: 195 KiB |
@@ -16,7 +16,7 @@ var _checks: int = 0
|
||||
|
||||
|
||||
func check(cond: bool, label: String) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md「测试层三元组」冒烟测试行 (测试层三元组——冒烟存活检查组)
|
||||
# 判据出处: design/engineering/test-conventions.md「1.1 测试层三元组」测试层三元组 测试层三元组(测试层三元组——冒烟存活检查组)
|
||||
_checks += 1
|
||||
if cond:
|
||||
print(" [PASS] " + label)
|
||||
@@ -35,7 +35,7 @@ func _ready() -> void:
|
||||
|
||||
# 开机前置面:autoload 注册与资源可加载(挂主屏之前先查,失败时主屏断言整段跳过)
|
||||
func _check_autoloads() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md「测试层三元组」冒烟测试行 (测试层三元组——冒烟存活检查组)
|
||||
# 判据出处: design/engineering/test-conventions.md「1.1 测试层三元组」测试层三元组 测试层三元组(测试层三元组——冒烟存活检查组)
|
||||
for autoload_name in ["ConfigDB", "RngService", "SaveManager", "MetaProgression"]:
|
||||
var node: Node = get_node_or_null(NodePath("/root/" + autoload_name))
|
||||
check(node != null, "autoload %s 在位" % autoload_name)
|
||||
@@ -64,7 +64,7 @@ func _boot_main_scene() -> Node:
|
||||
|
||||
# 主屏存活面:组合根装配句柄在位(main.X 一级句柄契约,探针挂载假设的启动侧证明)
|
||||
func _check_main_scene(main: Node) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md「测试层三元组」冒烟测试行 (测试层三元组——冒烟存活检查组)
|
||||
# 判据出处: design/engineering/test-conventions.md「1.1 测试层三元组」测试层三元组 测试层三元组(测试层三元组——冒烟存活检查组)
|
||||
check(main != null and main.is_inside_tree(), "主屏场景已实例化并在树")
|
||||
if main == null:
|
||||
return
|
||||
|
||||
@@ -34,7 +34,7 @@ func _initialize() -> void:
|
||||
# (自 game/smoke/smoke_all.gd 剪切迁入——断言 label 逐字原样;G12 两套调用不随迁,
|
||||
# 归 source_guard_test.gd,断言迁移批 B G1)
|
||||
func _split_tail() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
await process_frame
|
||||
await process_frame
|
||||
var autoload_ok: bool = get_root().get_node_or_null("/root/ConfigDB") != null and get_root().get_node_or_null("/root/SaveManager") != null
|
||||
@@ -54,7 +54,7 @@ func _split_tail() -> void:
|
||||
# ---- 三屏场景化断言(V2——独立实例化+关键节点在位+组合根树序/z 序保序)----
|
||||
# (自 game/smoke/smoke_all.gd 剪切迁入——label 与 cond 逐字原样,断言迁移批 B G1)
|
||||
func _smoke_scene_split() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
print("--- 迭代27 T1 三屏场景化(V2:屏壳独立实例化+组合根装配保序)---")
|
||||
# ① 三屏壳独立实例化(F6 等价——headless 直挂;视图代码构建在屏壳 _ready)
|
||||
var menu: Node = load("res://presentation/scenes/menu_screen.tscn").instantiate()
|
||||
@@ -151,7 +151,7 @@ func _count_visible_buttons(node: Node) -> int:
|
||||
|
||||
# ---- boot 链路时序后置条件(启动态六断言;只立行为可判断言,不造假时序)----
|
||||
func _smoke_boot_chain() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
print("--- 迭代28 T2 boot 链路时序后置条件(V2:六断言)---")
|
||||
var main: Node = load("res://presentation/main.tscn").instantiate()
|
||||
root.add_child(main)
|
||||
@@ -206,8 +206,8 @@ func _smoke_boot_chain() -> void:
|
||||
# 入口=开始屏右下角「调试」角标+对局中两屏角标)
|
||||
check(not main.ui.modals.menu.debug_overlay.visible,
|
||||
"V2f 调试浮窗 boot 不自动开(菜单优先)〔2026-10-16 用户令〕")
|
||||
check(main.ui.screens.debug_badge != null and not main.ui.screens.debug_badge.visible,
|
||||
"V2f 调试浮层角标发布态恒隐(2026-10-25 删写死行批)")
|
||||
check(main.ui.screens.debug_badge != null and main.ui.screens.debug_badge.visible,
|
||||
"V2f 调试浮层角标 boot 可见(全局浮层入口在座——2026-11-09 特批恢复批)")
|
||||
main.queue_free()
|
||||
await process_frame
|
||||
for p in ["user://smoke_boot_chain.json", "user://smoke_boot_chain.json.tmp"]:
|
||||
@@ -216,7 +216,7 @@ func _smoke_boot_chain() -> void:
|
||||
|
||||
|
||||
func _smoke_run_lifecycle() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
print("--- 迭代27 T1 会话物化(V3:两连局复位+脏状态不残留)---")
|
||||
var main: Node = load("res://presentation/main.tscn").instantiate()
|
||||
root.add_child(main)
|
||||
@@ -274,7 +274,7 @@ func _smoke_run_lifecycle() -> void:
|
||||
|
||||
# ---- d6/d7 批量模拟互斥守卫(wd6/wd7——白盒置态直调入口,以守卫早退的可见后果为断言面)----
|
||||
func _smoke_sim_guards() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
print("--- 卡① T2:批量模拟互斥两守卫(d6/d7)---")
|
||||
var main: Node = load("res://presentation/main.tscn").instantiate()
|
||||
root.add_child(main)
|
||||
@@ -348,7 +348,7 @@ func _face_snapshot(main: Node) -> Dictionary:
|
||||
# 阶段面断言:adv/run/set=alive|null|both(会话三面存活态);恒活面每阶段必查;
|
||||
# 现值回调与 run_scope 成员必须同源(回调链无悬挂铁证);extra=阶段附加判据。
|
||||
func _stage_faces(main: Node, tag: String, adv: String, run: String, set: String, extra: Dictionary = {}) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
var snap := _face_snapshot(main)
|
||||
var bad := ""
|
||||
for k in ["bonus_meta", "bonus_save", "camp_meta", "camp_save", "rp_stage", "rp_board_zone", "rp_fx", "rp_board"]:
|
||||
@@ -417,7 +417,7 @@ func _face_liveness(name: String, v, want: String) -> String:
|
||||
#(level_started→choices_presented 同步到达,无可观测中间态)——合并为 V3b 一处断言。
|
||||
# (自 game/smoke/smoke_all.gd 剪切迁入——label 与 cond 逐字原样,断言迁移批 B G1)
|
||||
func _smoke_lifecycle_matrix() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md:284 (生命周期矩阵——三关序列组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「验收标准」开始新冒险 开始新冒险(生命周期矩阵——三关序列组)
|
||||
print("--- 迭代28 T3 生命周期存活性矩阵(V3:九阶段×五引用面)---")
|
||||
var main: Node = load("res://presentation/main.tscn").instantiate()
|
||||
root.add_child(main)
|
||||
@@ -608,7 +608,7 @@ func _smoke_lifecycle_matrix() -> void:
|
||||
|
||||
|
||||
func _smoke_camp_hud_band() -> void:
|
||||
# 判据出处: design/ux/camp.md:41 (营地顶栏栏体定值与落座——几何/色值/吃点击五钉组)
|
||||
# 判据出处: design/ux/camp.md「顶栏」钥石余额常驻画面顶部一行小 钥石余额常驻画面顶部一行小(营地顶栏栏体定值与落座——几何/色值/吃点击五钉组)
|
||||
print("--- 营地交互修复批 T3 顶栏栏体(R5:色值/铺满/不吃点击/首子件/徽章落座)---")
|
||||
var main: Node = load("res://presentation/main.tscn").instantiate()
|
||||
root.add_child(main)
|
||||
|
||||
@@ -8,13 +8,13 @@ const Kit := preload("res://tests/unit/test_kit.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:293 Boss 节点开战行集宿主(装载组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「调参表」配置表共三张 配置表共三张(装载组)
|
||||
_test_boss_node_spawns_boss_rowset()
|
||||
quit(Kit.finish("boss_gate_test"))
|
||||
|
||||
|
||||
func _test_boss_node_spawns_boss_rowset() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:295 开战生成按遭遇坐标取行集(Boss 行集组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「调参表」Boss Boss(Boss 行集组)
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
var load_ok: bool = db.load_tables("res://data/tables", true) and db.diagnostics_count("error") == 0
|
||||
Kit.check("前置:表加载零 error", load_ok)
|
||||
|
||||
@@ -23,7 +23,7 @@ var _rows: Array = [] # 当前 run 的行协议收集(_on_row 绑定法—
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 伤害单据编排宿主(装载组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(装载组)
|
||||
var db = ConfigDBScript.new()
|
||||
var load_ok: bool = db.load_tables("res://data/tables", true)
|
||||
Kit.check("前置:表加载零 error", load_ok and db.diagnostics_count("error") == 0)
|
||||
@@ -71,7 +71,7 @@ func _row_by_display_prefix(prefix: String) -> Dictionary:
|
||||
# ---- 五配方一次全流程 + 双跑逐位复现 ----
|
||||
|
||||
func _run_recipe_sequence(db) -> Array:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (五段全序——配方序列组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(五段全序——配方序列组)
|
||||
_rows = []
|
||||
var h = _harness(db)
|
||||
var units = h.units
|
||||
@@ -178,7 +178,7 @@ func _run_recipe_sequence(db) -> Array:
|
||||
|
||||
|
||||
func _test_five_recipes_and_replay(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:363 (同种子回放逐行相同组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「明细流水:每一行都能指回你刚才的哪一步棋」结算过程中每一件事都写一行明细 结算过程中每一件事都写一行明细(同种子回放逐行相同组)
|
||||
var run1: Array = _run_recipe_sequence(db)
|
||||
Kit.check("五配方序列产出 5 行伤害行", run1.size() == 5)
|
||||
var run2: Array = _run_recipe_sequence(db)
|
||||
@@ -188,7 +188,7 @@ func _test_five_recipes_and_replay(db) -> void:
|
||||
# ---- A 模式(开单即结——回切位) ----
|
||||
|
||||
func _test_policy_immediate_mode(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (结算策略即时面组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(结算策略即时面组)
|
||||
_rows = []
|
||||
var h = _harness(db)
|
||||
if not h.spawn_ok:
|
||||
@@ -204,7 +204,7 @@ func _test_policy_immediate_mode(db) -> void:
|
||||
# ---- 来源敌死亡:队列中未结单据作废(死亡即不动手) ----
|
||||
|
||||
func _test_source_death_void(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:133 (摇定后兑现前被杀本拍作废组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「技能池:每敌种一张带权技能池,每拍开轮摇号出招」每种敌人有一张技能池 每种敌人有一张技能池(摇定后兑现前被杀本拍作废组)
|
||||
_rows = []
|
||||
var h = _harness(db)
|
||||
if not h.spawn_ok:
|
||||
@@ -238,7 +238,7 @@ func _unit_fixture() -> Dictionary:
|
||||
|
||||
|
||||
func _test_identical_content_dual_enemy(db: ConfigDb) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:303 (双敌同内容顺位组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「开战生成:主角数据行与一场 1–4 个敌人」战斗开始时 战斗开始时(双敌同内容顺位组)
|
||||
var a := _unit_fixture()
|
||||
var b := _unit_fixture()
|
||||
Kit.check("前置:双敌字典内容全同且非同一实例", a == b and not is_same(a, b))
|
||||
@@ -268,7 +268,7 @@ func _test_identical_content_dual_enemy(db: ConfigDb) -> void:
|
||||
|
||||
# d12 产发端增键:目标身份随行/随载荷下发(同名敌按 id 精确解析的产发半)
|
||||
func _test_target_id_payload(db: ConfigDb) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
_rows = []
|
||||
var h = _harness(db)
|
||||
if not h.spawn_ok:
|
||||
@@ -291,7 +291,7 @@ func _test_target_id_payload(db: ConfigDb) -> void:
|
||||
|
||||
|
||||
func _test_requires_gate_and_zero(db) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
_rows = []
|
||||
var h = _harness(db)
|
||||
if not h.spawn_ok:
|
||||
@@ -318,7 +318,7 @@ func _test_requires_gate_and_zero(db) -> void:
|
||||
# ---- 主角倒下:flush 余单全部作废(_halted 终止) ----
|
||||
|
||||
func _test_hero_death_halt(db) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
_rows = []
|
||||
var h = _harness(db)
|
||||
if not h.spawn_ok:
|
||||
@@ -336,7 +336,7 @@ func _test_hero_death_halt(db) -> void:
|
||||
# ---- AC 合流:override 入参 / 表值兜底 / ac 型状态叠层(不入池) ----
|
||||
|
||||
func _test_ac_merge(db) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
_rows = []
|
||||
var h = _harness(db)
|
||||
if not h.spawn_ok:
|
||||
@@ -364,7 +364,7 @@ func _test_ac_merge(db) -> void:
|
||||
# ---- 池乘区收口:池内加算 → clamp;ac 型不入池 ----
|
||||
|
||||
func _test_pool_clamp(db) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
_rows = []
|
||||
var h = _harness(db)
|
||||
if not h.spawn_ok:
|
||||
@@ -422,7 +422,7 @@ func _test_pool_clamp(db) -> void:
|
||||
# ---- 个体池读数 / 个体 AC 合流(增益状态 v1.5——敌方状态个体化批)----
|
||||
|
||||
func _test_pool_consumption_per_unit(db) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
var h = _harness(db, 3) # depth 3 = 混编行集(熊地精 1 + 地精 1–2,最少 2 只——个体对照面需 ≥2 敌)
|
||||
if not h.spawn_ok:
|
||||
return
|
||||
@@ -442,7 +442,7 @@ func _test_pool_consumption_per_unit(db) -> void:
|
||||
|
||||
|
||||
func _test_defender_ac_per_unit(db) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
var h = _harness(db, 3)
|
||||
if not h.spawn_ok:
|
||||
return
|
||||
|
||||
@@ -12,7 +12,7 @@ var db
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (伤害公式宿主——装载组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(伤害公式宿主——装载组)
|
||||
db = ConfigDBScript.new()
|
||||
var load_ok: bool = db.load_tables("res://data/tables", true)
|
||||
Kit.check("前置:settlement 表加载零 error", load_ok and db.diagnostics_count("error") == 0)
|
||||
@@ -31,7 +31,7 @@ func _floor_val() -> int:
|
||||
# ---- F2 乘区:池内加算 → 池间乘算 → floor(单一取整规则)----
|
||||
|
||||
func _test_pool_damage() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (池伤害公式组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(池伤害公式组)
|
||||
var d := _floor_val() + 9 # 表值推导的任意正探针量(非玩法行值)
|
||||
Kit.check("中性双池 (0,0) 原样透传", DamageMathScript.pool_damage(d, 0, 0) == d)
|
||||
Kit.check("负敌方池压低不增高", DamageMathScript.pool_damage(d, 0, int(db.combat.settlement.core.pool_clamp_lo)) <= d)
|
||||
@@ -44,7 +44,7 @@ func _test_pool_damage() -> void:
|
||||
# ---- 克制分量:空桶不吃修正恒 0;落地下限保底([1,+∞) 全来源)----
|
||||
|
||||
func _test_counter_component() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (计数器分量组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(计数器分量组)
|
||||
var floor_v := _floor_val()
|
||||
Kit.check("空桶(点数≤0)恒 0 不吃修正", DamageMathScript.counter_component(0, floor_v, floor_v) == 0
|
||||
and DamageMathScript.counter_component(-1, 5, floor_v) == 0)
|
||||
@@ -56,7 +56,7 @@ func _test_counter_component() -> void:
|
||||
# ---- 掷点折扣查档(纯函数):满阈值恒全额;档位边界/末档语义与表数组一致 ----
|
||||
|
||||
func _test_roll_discount_percent() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (乘区折扣组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(乘区折扣组)
|
||||
var threshold := 10 # 查档探针阈值(夹具值——档位参数本身全部来自表)
|
||||
var bounds: Array = db.combat.settlement.damage_roll.roll_tier_bounds
|
||||
var discounts: Array = db.combat.settlement.damage_roll.roll_tier_discounts
|
||||
@@ -81,7 +81,7 @@ func _test_roll_discount_percent() -> void:
|
||||
# ---- 吃掷点分量算术:折扣→(暴击)→floor→+克制修正(单一取整链)----
|
||||
|
||||
func _test_rolled_component() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (掷点分量组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(掷点分量组)
|
||||
var base := float(_floor_val() + 7) # 表值推导探针基线
|
||||
var crit_mult: int = int(db.combat.settlement.damage_roll.crit_multiplier)
|
||||
Kit.check("满额折扣无暴击 = floor(基线) + 修正 0", DamageMathScript.rolled_component(base, 100, false, crit_mult, 0) == int(floor(base)))
|
||||
|
||||
@@ -19,7 +19,7 @@ var _db
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「扩展行:专长插入的结算效果」 (效果端口宿主——装载组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「扩展行:专长插入的结算效果」类写的是裸机制的账 类写的是裸机制的账(效果端口宿主——装载组)
|
||||
_db = ConfigDBScript.new()
|
||||
var load_ok: bool = _db.load_tables("res://data/tables", true)
|
||||
Kit.check("前置:表加载零 error", load_ok and _db.diagnostics_count("error") == 0)
|
||||
@@ -54,7 +54,7 @@ func _hero_attack_value(rows: Array) -> int:
|
||||
# ---- V1 端口单实例与真实发射路由 ----
|
||||
|
||||
func _smoke_effect_port_wiring() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「扩展行:专长插入的结算效果」 (端口单实例与六 Callable 路由组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「扩展行:专长插入的结算效果」类写的是裸机制的账 类写的是裸机制的账(端口单实例与六 Callable 路由组)
|
||||
print("--- 效果端口:装配链单实例+真实发射路由 ---")
|
||||
# 充能跑(蓄力周转 charge_rotation 在册——attack_commit 订阅行 attack_bonus per 蓄力周转计数器)
|
||||
var orch_c = _orch(TEST_SEED)
|
||||
@@ -88,7 +88,7 @@ func _smoke_effect_port_wiring() -> void:
|
||||
# ---- V2 业务类零引擎直连(源码契约锚——theme_projection_test 源码锚惯例)----
|
||||
|
||||
func _test_business_classes_engine_free() -> void:
|
||||
# 判据出处: design/gdd/术语表.md「效果端口件」 (业务类零引擎直连组)
|
||||
# 判据出处: design/gdd/术语表.md「战斗与效果」效果端口件 效果端口件(业务类零引擎直连组)
|
||||
print("--- 效果端口:业务类零引擎直连源码锚 ---")
|
||||
for path in ["res://core/damage_controller.gd", "res://core/action_economy.gd"]:
|
||||
var src := FileAccess.get_file_as_string(path)
|
||||
@@ -100,7 +100,7 @@ func _test_business_classes_engine_free() -> void:
|
||||
# ---- V3 伤害域事实面闭集(合成行两对照——damage_taken 真实单据流)----
|
||||
|
||||
func _test_biz_fact_face_closed() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「扩展行:专长插入的结算效果」 (闭面四键 biz_fact 组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「扩展行:专长插入的结算效果」类写的是裸机制的账 类写的是裸机制的账(闭面四键 biz_fact 组)
|
||||
print("--- 效果端口:业务发射事实面闭集 ---")
|
||||
var orch = _orch(TEST_SEED)
|
||||
Kit.check("V3 begin_battle 受理", orch.begin_battle(_enc([])))
|
||||
|
||||
@@ -11,7 +11,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:199 (扩展行必载 effect_id——加载致命组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(扩展行必载 effect_id——加载致命组)
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
if not db.load_tables("res://data/tables", false):
|
||||
push_error("[extended_row_violation_test] 表加载失败")
|
||||
|
||||
@@ -154,7 +154,7 @@ func _seal_direct_with_expansion(orch) -> Vector2i:
|
||||
# 四条真实路径(敌方攻击/危险格/错误封印/地形)逐路驱动:每条至少一张主角承伤单据在案,
|
||||
# 且承伤计数器 == 主角承伤单据行数(每单据恰发射一次的全量判据——重复发射即计数器>行数)。
|
||||
func test_all_hero_damage_paths_emit_once() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (换图生存:全局固定减伤全伤害路径恰一次组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(换图生存:全局固定减伤全伤害路径恰一次组)
|
||||
print("--- V5 全局 damage_taken:四路径逐路恰一次 ---")
|
||||
# ① 敌方攻击路径(Boss 战零挖掘连停三轮——干净样本:零地形零资源单据;多轮保证伤害技在案)
|
||||
var orch1 = _orch(46001)
|
||||
@@ -224,7 +224,7 @@ func _plan_seal(orch, target: Vector2i) -> Dictionary:
|
||||
# 同一伤害不得出现两次消费(重复发射=计数器>行数):敌方路径与地形路径两样本逐位核对——
|
||||
# 地形单据带 hero_damage_consumed 标记,战斗段末 _resolve_board_flat_hero 跳过二次发射由此钉住。
|
||||
func test_no_duplicate_damage_taken_event() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (受击事件零重复组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(受击事件零重复组)
|
||||
print("--- V5 全局 damage_taken:无重复消费 ---")
|
||||
var orch1 = _orch(46011)
|
||||
var rows1 := _collect_hero_rows(orch1)
|
||||
@@ -266,7 +266,7 @@ func _auto_dig(orch) -> void:
|
||||
|
||||
# V2 矿脉储能:受理的付费挖格 RAP 恰 +1、AP 按表扣、板资源不变
|
||||
func test_reserve_on_accepted_dig() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:256 (换图基座:挖格产 RAP 组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P0 最小闭环」战斗结算发开轮通知 战斗结算发开轮通知(换图基座:挖格产 RAP 组)
|
||||
print("--- V2 矿脉储能:付费挖格产 RAP ---")
|
||||
var orch = _orch(46021)
|
||||
Kit.check("V2 前置:战斗受理", orch.begin_battle(_enc(["vein_reserve"])))
|
||||
@@ -304,7 +304,7 @@ func _drain_round_rap_accounting(orch) -> bool:
|
||||
|
||||
# V3 省力周转:折价门槛与扣费(can 与执行同源;base 8→扣 4)
|
||||
func test_refresh_discount_gate_and_charge() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:256 (刷新折扣门控与充能组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P0 最小闭环」战斗结算发开轮通知 战斗结算发开轮通知(刷新折扣门控与充能组)
|
||||
print("--- V3 省力周转:折价门槛与扣费 ---")
|
||||
var orch = _orch(46022)
|
||||
Kit.check("V3 前置:战斗受理", orch.begin_battle(_enc(["easy_swap"])))
|
||||
@@ -326,7 +326,7 @@ func test_refresh_discount_gate_and_charge() -> void:
|
||||
|
||||
# V3 双基座叠加:挖格产 RAP 与刷新折价同场生效
|
||||
func test_double_base_stack() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (双基座叠加组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(双基座叠加组)
|
||||
print("--- V3 双基座叠加 ---")
|
||||
var orch = _orch(46023)
|
||||
Kit.check("V3 前置:战斗受理", orch.begin_battle(_enc(["vein_reserve", "easy_swap"])))
|
||||
@@ -343,7 +343,7 @@ func test_double_base_stack() -> void:
|
||||
|
||||
# V12(refresh_feats 侧):无专长基线——挖格零产 RAP、刷新按表基线扣、AP 保留、上限照旧
|
||||
func test_no_feats_baseline() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (零专长基线组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(零专长基线组)
|
||||
print("--- V12 无专长基线(refresh_feats 侧) ---")
|
||||
var orch = _orch(46024)
|
||||
Kit.check("V12 前置:战斗受理", orch.begin_battle(_enc([])))
|
||||
@@ -379,7 +379,7 @@ func _br_count(orch) -> int:
|
||||
|
||||
# V4 成功事实只在新板就位后发射:成功恰一次;非 Active/每轮上限/RAP 不足三拒面全零事实零换图
|
||||
func test_board_refresh_fact_only_on_success() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:256 (弃图刷新事实面仅成功态组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P0 最小闭环」战斗结算发开轮通知 战斗结算发开轮通知(弃图刷新事实面仅成功态组)
|
||||
print("--- V4 成功刷新事实:拒绝零事实 ---")
|
||||
_install_br_probe()
|
||||
var orch = _orch(46031)
|
||||
@@ -414,7 +414,7 @@ func test_board_refresh_fact_only_on_success() -> void:
|
||||
|
||||
# V10 矿道红利:每次成功刷新 escrow 恰 +1 且 fx_grant_gp 行在案;拒绝零变化
|
||||
func test_mine_profit_gp() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (换图资源:刷新固定 GP 收益组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(换图资源:刷新固定 GP 收益组)
|
||||
print("--- V10 矿道红利:刷新固定 GP ---")
|
||||
var orch = _orch(46032)
|
||||
var gp_rows := {"n": 0}
|
||||
@@ -461,7 +461,7 @@ func _damage_rows_by_source(rows: Array, source: String) -> Array:
|
||||
# V6 石层缓冲:全局固定减伤(危险格 pierce 8→6 两档钉死:单刷减 2·同轮多刷不叠加·未刷新轮不减;
|
||||
# 地形路径减后值=max(下限, effect_value−2)——含下限保持;敌方路径照常单次发射)
|
||||
func test_stone_mitigation_all_damage() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (全局减伤全覆盖组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(全局减伤全覆盖组)
|
||||
print("--- V6 石层缓冲:全局固定减伤 ---")
|
||||
# S1 同轮双刷 → 危险格 pierce 8 减 2=6(叠加即 4——多刷不增钉死)
|
||||
var orch1 = _orch(46041)
|
||||
@@ -517,7 +517,7 @@ func test_stone_mitigation_all_damage() -> void:
|
||||
# V9 坑道小憩:轮末合计回复(白盒预置承载上限 3——计数器直改属数据面注入;
|
||||
# 自然累计 2 与满血未生效两形态分战场钉死)
|
||||
func test_rest_rotation_cap_and_clear() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (轮末恢复 cap 与清账组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(轮末恢复 cap 与清账组)
|
||||
print("--- V9 坑道小憩:轮末恢复 ---")
|
||||
# R1 白盒预置 3 层 + 刷新闸(when<3 拒第 4 层)→ 停手回复 min(3, 缺血)——护甲降档保缺血 ≥3
|
||||
var orch1 = _orch(46051)
|
||||
@@ -575,7 +575,7 @@ func test_rest_rotation_cap_and_clear() -> void:
|
||||
|
||||
# V8 蓄力周转:当轮攻击消费全部层数(上限 3 闸=白盒预置;战斗新建自然清空)
|
||||
func test_charge_layers_consumed_same_round() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (充能当轮消耗组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(充能当轮消耗组)
|
||||
print("--- V8 蓄力周转:攻击消费层 ---")
|
||||
var orch1 = _orch(46061)
|
||||
var rows1 := _collect_damage_rows(orch1)
|
||||
@@ -602,7 +602,7 @@ func test_charge_layers_consumed_same_round() -> void:
|
||||
|
||||
# V7 崩壁冲击:延迟群伤单(刷新时点零伤害行——战斗段末按存活目标结账)
|
||||
func test_blast_defers_to_combat_segment() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (刷新群伤让位战斗段组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(刷新群伤让位战斗段组)
|
||||
print("--- V7 崩壁冲击:延迟群伤 ---")
|
||||
var orch = _orch(46071)
|
||||
var rows := _collect_damage_rows(orch)
|
||||
@@ -621,7 +621,7 @@ func test_blast_defers_to_combat_segment() -> void:
|
||||
|
||||
# 七件 validate/在册/稀有度 cap 对表/跨表计数器引用闭合/desc 禁词
|
||||
func test_seven_feats_validate_and_pool() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (换图系七件校验与池组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(换图系七件校验与池组)
|
||||
print("--- V11 七件数据与池 ---")
|
||||
var seven := {"vein_reserve": "excellent", "easy_swap": "excellent", "wall_blast": "excellent",
|
||||
"charge_rotation": "excellent", "stone_mitigation": "common", "tunnel_rest": "common", "mine_profit": "rare"}
|
||||
|
||||
@@ -16,8 +16,8 @@ var _db
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:80 奖励未生效行=满层拒收、满血治疗等合法例外一行
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:87 显示名等玩家可见文案是数据面字段(日志消费端零文案——reason 结构化替代)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「明细流水:每一行都能指回你刚才的哪一步棋」结算过程中每一件事都写一行明细 结算过程中每一件事都写一行明细、满血治疗等合法例外一行
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「明细流水:每一行都能指回你刚才的哪一步棋」reason reason(日志消费端零文案——reason 结构化替代)
|
||||
_db = ConfigDBScript.new()
|
||||
if not _db.load_tables("res://data/tables", true):
|
||||
print("[reward_ineffective_reason_test] FAIL — 数值表加载失败")
|
||||
@@ -61,7 +61,7 @@ func _ineffective_rows(rows: Array) -> Array:
|
||||
|
||||
# 四类 reason 逐一命中(断言前提=各类未生效行在案;reason 键取值=分析判读契约四值)
|
||||
func _assert_four_reasons() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:80 奖励未生效行四类合法例外
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「明细流水:每一行都能指回你刚才的哪一步棋」结算过程中每一件事都写一行明细 结算过程中每一件事都写一行明细
|
||||
print("--- 奖励未生效 reason 四类逐一命中 ---")
|
||||
|
||||
# ---- ① full_hp:满血主角 + heal 型格正向(_flat_heal 满血分支即时兑付)----
|
||||
|
||||
@@ -19,7 +19,7 @@ var _db
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (掷点与乘区宿主——装载组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(掷点与乘区宿主——装载组)
|
||||
_db = ConfigDBScript.new()
|
||||
# 表加载失败不中止(承 G2/G3 同款:表损坏的红落在具体断言上——
|
||||
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
|
||||
@@ -44,7 +44,7 @@ func _init() -> void:
|
||||
# 受理后不变量(encounter 受理后只读)。攻击单 base_value 贯通由 _smoke_damage_types 的
|
||||
# hero_atk_val=100 全链路行值承载(同夹具既有覆盖——派生读在攻击链上工作即行值随 override 走)----
|
||||
func _smoke_hero_atk_derived() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (英雄攻击派生组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(英雄攻击派生组)
|
||||
var rng_a = load("res://core/rng_service.gd").new()
|
||||
rng_a.set_master_seed(4242)
|
||||
var s_a = load("res://core/battle_orchestrator.gd").new(_db, rng_a)
|
||||
@@ -67,7 +67,7 @@ func _smoke_hero_atk_derived() -> void:
|
||||
# → heavy 伤害 == light −1、ward == light +1(要求基线伤害 ≥ 2——地板 1 会吞 −1 位移)。
|
||||
# 承伤位移红线(卡片 §8 L3):全局位移只允许 ±1 量级——非此量级 = 矩阵消费面有未盘点的第二落点(停机)。
|
||||
func _smoke_enemy_attack_type() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:295 (敌攻击类型行集组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「调参表」配置表共三张 配置表共三张(敌攻击类型行集组)
|
||||
print("--- 敌方攻击类型轴(迭代 24 N3)---")
|
||||
# ① 表列:20 行全填 normal(N3 全填不做差异化——Q9)
|
||||
var at_ok := true
|
||||
@@ -126,7 +126,7 @@ func _smoke_enemy_attack_type() -> void:
|
||||
# ---- 护甲等级掷点·行为面(折扣档分布 / nat20 暴击 / 伤害下限 / 棋盘来源必中)----
|
||||
|
||||
func _smoke_armor_roll() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:254 (护甲掷点与叠层合并组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(护甲掷点与叠层合并组)
|
||||
print("--- 护甲等级掷点(查档纯函数 + 暴击 + 伤害下限 + AC12 分布 + 棋盘必中)---")
|
||||
# ① 查档纯函数:全掷点域逐位对照(AC10 / AC12)+ EV 锚(AC10 期望减免 21.25% —— registry 参考数)
|
||||
var expect_ac10 := {100: 11, 75: 3, 50: 4, 25: 2} # 掷 10-20 全额 / 7-9 / 3-6 / 1-2
|
||||
@@ -345,7 +345,7 @@ func _auto_play_round(settlement, out: Dictionary) -> void:
|
||||
# 基线构成:基线 100——hero 攻击类型=normal(锻造工坊配置默认值,
|
||||
# hero.tres 无两轴字段)对轻甲中性 0 修正(目标 = L1 地精轻甲;AC 0 恒全额非暴击种子)。
|
||||
func _smoke_pool_wiring() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
print("--- 主角乘区接线 + 硬化折半方向 ---")
|
||||
var base_row := _hero_attack_row_with({}, 100, 20260918)
|
||||
var up_row := _hero_attack_row_with({"effects": ["attack_up"]}, 100, 20260918)
|
||||
@@ -387,7 +387,7 @@ func _hero_attack_row_with(opts: Dictionary, hero_atk_val: int, seed_val: int) -
|
||||
# ---- 攻击类型 × 护甲克制 + 标错惩罚冒烟(护甲快照/克制矩阵/充能/反噬三选一)----
|
||||
|
||||
func _smoke_damage_types() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
print("--- 攻击类型 × 护甲克制 + 标错惩罚 ---")
|
||||
# ① 护甲类型快照传播(spawn 行值 → 单位字典)
|
||||
var enemy_system = load("res://core/unit_container.gd").new(_db)
|
||||
@@ -482,7 +482,7 @@ func _find_seal_target(minesweeper, want_mine: bool) -> Dictionary:
|
||||
# d_tick = max(damage_floor, pool_damage(floor(基线×档位%), 0, 0)),档位读数随行重建可归因)----
|
||||
|
||||
func _smoke_attack_chain_fresh_pool() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
print("--- 战斗结算·fresh 池攻击链回归(Bug#2·掷点口径)---")
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
rng.set_master_seed(20260913)
|
||||
|
||||
@@ -22,7 +22,7 @@ var _db
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (轮内流与技能池宿主——装载组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(轮内流与技能池宿主——装载组)
|
||||
_db = ConfigDBScript.new()
|
||||
# 表加载失败不中止(承 G2/G3/G4/G5 同款:表损坏的红落在具体断言上——
|
||||
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
|
||||
@@ -49,7 +49,7 @@ func _init() -> void:
|
||||
# ---- 完整战斗回放(自动玩家,确定性)——回放断言:同种子两遍步骤流逐行相同 ----
|
||||
|
||||
func _smoke_full_battle(L: int, D: int, label: String) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (全战斗回放——五段全序组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(全战斗回放——五段全序组)
|
||||
print("--- 完整战斗回放:%s ---" % label)
|
||||
var run1 = _run_battle(L, D)
|
||||
var run2 = _run_battle(L, D)
|
||||
@@ -84,7 +84,7 @@ func _smoke_full_battle(L: int, D: int, label: String) -> void:
|
||||
|
||||
|
||||
func _run_battle(L: int, D: int, axes: Dictionary = {}) -> Dictionary:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (战斗驱动组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(战斗驱动组)
|
||||
# 每遍全新 RngService(同 master 种子)——回放断言的隔离前提(地图战斗资源 AC"两套全新 RngService+地图战斗资源"同款)
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
rng.set_master_seed(42)
|
||||
@@ -149,7 +149,7 @@ func _auto_play_round(settlement, out: Dictionary) -> void:
|
||||
# ---- 行动经济·轮内刷新冒烟(方案 A:Active 相位当场换图继续挖)----
|
||||
|
||||
func _smoke_active_refresh() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:262 (停手转存储备与轮内刷新组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P1 / P2 后置」后置原因 后置原因(停手转存储备与轮内刷新组)
|
||||
print("--- 行动经济·轮内刷新(方案 A)---")
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
rng.set_master_seed(20260912)
|
||||
@@ -256,7 +256,7 @@ func _active_refresh_replay() -> Array:
|
||||
# ---- 遭遇随机化冒烟(难度曲线与Boss Core Rule 8:区间骰/encounter 流/可回放/空表定值路径)----
|
||||
|
||||
func _smoke_encounter_roll() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:296 (遭遇区间骰——摇号确定性组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「调参表」配置表共三张 配置表共三张(遭遇区间骰——摇号确定性组)
|
||||
print("--- 遭遇随机化(unit_count 区间骰)---")
|
||||
var counts: Array = []
|
||||
for i in range(20):
|
||||
@@ -391,7 +391,7 @@ func _encounter_replay(seed_val: int) -> Array:
|
||||
|
||||
# 五段全序断言(战斗结算 验收"五段全序"+ 行型封闭 10 类):逐轮行相位序 = 授予 → 增益/减益 → 战斗 → 衰减 → 判定。
|
||||
func _smoke_settlement_segments() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
print("--- 五段全序 + 行型封闭 ---")
|
||||
Kit.check("segment_order 五段冻结在位(表值 = 拍板序恒等)",
|
||||
Array(_db.combat.settlement.segment_order) == SettlementTable.FROZEN_SEGMENT_ORDER
|
||||
@@ -510,7 +510,7 @@ func _smoke_skill_pool() -> void:
|
||||
|
||||
# ① 数据面:技能表行集 + 普攻锁死 + 建议池行值 + 空池不可能(结构断言)
|
||||
func _smoke_skill_pool_data() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
Kit.check("技能表十六行(普攻/突刺/蓄力/重击/硬化 + 撕咬/毒爆/蛛网束缚 + 大地脉动 + 震地怒击/遏毒/岩崩 + 毒吐/盾击——前三批 + Boss 半血解锁技三行〔迭代14④ T5〕+ 普通敌错峰两行〔迭代 24 N2〕+ 触发条件批示范两行〔孤注守势/趁隙偷袭〕)", _db.combat.skill.rows.size() == 16)
|
||||
var basic: Dictionary = _db.combat.skill.row_by_id("attack")
|
||||
Kit.check("普攻行:倍率恒 1 · 冷却恒 0(域校验锁死——池恒非空的结构前提)",
|
||||
@@ -727,7 +727,7 @@ func _fresh_rng(seed_val: int):
|
||||
# 单敌轨迹不独立复放——轨迹取数与其它流交错,无法脱离全序重建;
|
||||
# 同种子全战斗逐位复现由 ② 全对拍承载,单点定位归事件日志。
|
||||
func _smoke_skill_pool_replay_independence() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
var seed_val := -1
|
||||
for s in range(1, 60):
|
||||
var seqs := _record_pool_trajectories(s, 1)
|
||||
@@ -781,7 +781,7 @@ func _record_pool_trajectories(seed_val: int, rounds: int) -> Dictionary:
|
||||
# 2026-10-28 重锚 [0.82, 1.02](照酋长先例 ±0.10 绝对幅度,中值取理论稳态 0.92;旧带 [1.00,1.20] 系触发器前
|
||||
# 唯一特殊技=突刺的池结构下登记,随池构成换代作废;撤销证明=带宽回退旧值本断言复红)→ 宽带登记。
|
||||
func _smoke_skill_pool_ev_anchor() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
var bands := {"goblin": [0.82, 1.02], "bugbear": [0.97, 1.03], "ogre_chief": [1.10, 1.30]} # 地精重锚 2026-10-28(触发条件批孤注守势入池稀释,无情境口径实测 0.9148;EV 锚注 enemy.tres)· 酋长重锚(震地怒击半血解锁入池,含闸长期速率上移:实测 1.1948;EV 锚注 enemy.tres)
|
||||
var species := ["goblin", "bugbear", "ogre_chief"]
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
@@ -837,7 +837,7 @@ func _smoke_skill_pool_ev_anchor() -> void:
|
||||
|
||||
# ⑤ 死亡打断作废(摇定后、兑现前死亡 → 本拍技能作废、不动手、不进账)
|
||||
func _smoke_skill_pool_death_void() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
var void_seed := -1
|
||||
for s in range(1, 400):
|
||||
var rg = load("res://core/rng_service.gd").new()
|
||||
@@ -877,7 +877,7 @@ func _smoke_skill_pool_death_void() -> void:
|
||||
|
||||
# ⑥ 加载校验拒绝(单表域校验 + 跨表池构成纪律)
|
||||
func _smoke_skill_pool_validation_reject() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
var skill_table = load("res://data/schemas/skill_table.gd").new()
|
||||
var enemy_table = load("res://data/schemas/enemy_table.gd").new()
|
||||
enemy_table.rows.assign([{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "ghost", "weight": 1}]}])
|
||||
@@ -936,7 +936,7 @@ func _has_err_category(errs: Array, category: String) -> bool:
|
||||
# 停手轮驱动 (2,9)——零挖掘零封印 → 零池,伤害行可逐拍精确复算;种子 hunt 至少各命一粒毒爆伤害行
|
||||
# 与蛛网束缚施放行;毒分量随开战掷定的攻击基线缩放(atk 区间 2–4 → rider 1–3)。
|
||||
func _smoke_debuff_rider() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
var venom_seed := -1
|
||||
var venom_check_ok := true
|
||||
var venom_rows_seen := 0
|
||||
@@ -1007,7 +1007,7 @@ func _smoke_debuff_rider() -> void:
|
||||
# ---- 天赋树六键行为冒烟(V10:开局姿态窗/危险直觉限次/财富之道聚散/守侧失误补偿;
|
||||
# 引擎直构 + 编排授予段直注(_grant_seg._judge_seal=结算授予段封印判定单口))----
|
||||
func _smoke_counter_buckets() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
print("--- 效果引擎无状态化四桶正向验收(卡② §9 V1/V6)---")
|
||||
# V1——adventure 桶跨战持久:同一宿主字典下两战各真实 request_dig 一次,
|
||||
# 断付费计数经 ctx 就地写入宿主字典并跨战累积(副本搬运态:读不到上一战值→第 2 战仍 1,此断言会红)。
|
||||
@@ -1070,7 +1070,7 @@ func _smoke_counter_buckets() -> void:
|
||||
# V6 形态先例同源:直入真实管线缝(_judge_seal 直调同款口径)。
|
||||
|
||||
func _smoke_extended_rows() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
print("--- 扩展行收敛:fx_reveal 兑付/落空 ---")
|
||||
var RigS = load("res://core/battle_orchestrator.gd") # 局部装配别名(_smoke_counter_buckets 同款——跨函数不共享局部量)
|
||||
var enc_fx = {"level_index": 1, "node_depth": 0, "hero_hp": 40, "hero_atk": 8, "hero_max_hp": 40,
|
||||
@@ -1116,7 +1116,7 @@ func _smoke_extended_rows() -> void:
|
||||
# 蓄力表值 2 拍衰减后剩 1 拍仍在池)→ 逐敌读敌方输出池。判据=施放者与被他敌的池读数差。
|
||||
|
||||
func _smoke_enemy_buff_targets_self() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
var emp_mag: int = int(_db.combat.status_effects.row_by_id("empower").magnitude)
|
||||
var sc_script = load("res://core/status_container.gd")
|
||||
var found_seed := -1
|
||||
@@ -1165,7 +1165,7 @@ func _smoke_enemy_buff_targets_self() -> void:
|
||||
# 种子狩猎沿 _smoke_enemy_buff_targets_self 同款;叠层行为=容器级再授(roll_multiplier 先例形态)。
|
||||
|
||||
func _check_defensive_stance_values() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
var row: Dictionary = _db.combat.status_effects.row_by_id("defensive_stance")
|
||||
Kit.check("defensive_stance 生产行值:magnitude=-25 percent/duration_settlements=2/accumulate max_stack=1〔QA余 V9〕",
|
||||
int(row.get("magnitude", 0)) == -25 and String(row.get("unit", "")) == "percent"
|
||||
|
||||
@@ -22,7 +22,7 @@ var _db
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:231 (封印与极性宿主——装载组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「调参表」本系统无自有参数 本系统无自有参数(封印与极性宿主——装载组)
|
||||
_db = ConfigDBScript.new()
|
||||
# 表加载失败不中止(承 G2/G3/G4 同款:表损坏的红落在具体断言上——
|
||||
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
|
||||
@@ -48,8 +48,8 @@ func _init() -> void:
|
||||
# ---- 末点 AP 封印轮末结算(playtest 缺陷②回归:末点 AP 花在封印必须终结轮次进入下一轮)----
|
||||
|
||||
func _smoke_seal_ap_exhausted() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:139 封印判定批与溢价兑付链照常(保留组——封印受理即揭示改版零改动)〔封印改 V5〕
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:260 (末点 AP 耗尽即收轮组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「授予段兑付:极性路由,四类动作各归各系统资源」授予段消费结算队列 授予段消费结算队列(保留组——封印受理即揭示改版零改动)〔封印改 V5〕
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P1 / P2 后置」后置原因 后置原因(末点 AP 耗尽即收轮组)
|
||||
print("--- 排雷玩法·封印动作耗尽末点 AP 回归 ---")
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
rng.set_master_seed(20260911)
|
||||
@@ -327,8 +327,8 @@ func _rows_at(rows: Array, source_class: String, cell) -> Array:
|
||||
|
||||
|
||||
func _smoke_clear_reward_chain() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:235 (清图奖励链——清图槽对象身份组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:235 (清图奖励链——清图槽对象身份组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「格面资源:每个非封锁格都带一个,摇号纪律不变」每张雷图装上时 每张雷图装上时(清图奖励链——清图槽对象身份组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「格面资源:每个非封锁格都带一个,摇号纪律不变」每张雷图装上时 每张雷图装上时(清图奖励链——清图槽对象身份组)
|
||||
print("--- 清图奖励·双份兑付链(完美封印 / 零兑付 / 第二份被拒 / 高光记实)---")
|
||||
# ① 真实流完美封印:标中一面真雷封印 + 零误标 + 清全图 → grant_clear 身份(clear_blast)双份真实兑付
|
||||
var rows: Array = []
|
||||
@@ -357,8 +357,8 @@ func _smoke_clear_reward_chain() -> void:
|
||||
# 弱形式登记:正常战斗流下"授段时刻无存活敌"不可达——敌全灭当轮判定段即判胜并终止战斗,而清图批在判定段之前,
|
||||
# 恒有存活敌;故本组直调编排私有面构造状态,只断言"路径存在 + 行为符合契约"(构造手法见各行注释)。
|
||||
func _smoke_clear_reward_zero_paths() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:240 (无存活敌群伤记「奖励未生效」组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:240 (无存活敌群伤记「奖励未生效」组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「验收标准」奖励未生效 奖励未生效(无存活敌群伤记「奖励未生效」组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「验收标准」奖励未生效 奖励未生效(无存活敌群伤记「奖励未生效」组)
|
||||
# ②-a 首份零兑付判定(无存活敌)→ first_ok=false + 未生效行
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
rng.set_master_seed(20260915)
|
||||
@@ -413,8 +413,8 @@ func _smoke_clear_reward_zero_paths() -> void:
|
||||
|
||||
# 轮内刷新 provenance 守卫:刷新换来的图同轮清图不发清图奖励(_board_from_midround_refresh 守卫)
|
||||
func _smoke_refresh_provenance_guard() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:237 (换图重置:旧封印印记先判定后消失组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:237 (换图重置:旧封印印记先判定后消失组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」换图重置 换图重置(换图重置:旧封印印记先判定后消失组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」换图重置 换图重置(换图重置:旧封印印记先判定后消失组)
|
||||
print("--- 轮内刷新 provenance 守卫(刷新图清图不发清图奖励)---")
|
||||
var rows: Array = []
|
||||
var run := _run_full_clear(20260916, true, rows)
|
||||
@@ -441,9 +441,9 @@ func _smoke_refresh_provenance_guard() -> void:
|
||||
|
||||
|
||||
func _smoke_polarity_routing() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:139 封印判定批与溢价兑付链照常(保留组——封印受理即揭示改版零改动)〔封印改 V5〕
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:366 (极性路由:正向只兑正向、负向只兑负向组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:366 (极性路由:正向只兑正向、负向只兑负向组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「授予段兑付:极性路由,四类动作各归各系统资源」授予段消费结算队列 授予段消费结算队列(保留组——封印受理即揭示改版零改动)〔封印改 V5〕
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「轮末五段结算:一轮从收场走到判定」玩家行动点花完 玩家行动点花完(极性路由:正向只兑正向、负向只兑负向组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「轮末五段结算:一轮从收场走到判定」玩家行动点花完 玩家行动点花完(极性路由:正向只兑正向、负向只兑负向组)
|
||||
print("--- 极性路由(挖安全格正向 / 挖危险格负向 / 标中正向 / 标空负向)---")
|
||||
# 战斗随机值面随全局序漂移——构造种子按行为面扫描(谓词见 _polarity_probe_accepts)
|
||||
var probe := {}
|
||||
@@ -581,8 +581,8 @@ func _smoke_polarity_routing() -> void:
|
||||
# 场景 B(② 改判〔封印改 V2〕):标危险格 → 挖封印格被拒 → 收轮(标中判定照发)。
|
||||
# 场景 C(①③):标安全格 + 标危险格 → 不挖收轮 → 标空/标中判定照常。
|
||||
func _smoke_seal_irreversible_quadrants() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:231 (封印不可逆四情况组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:231 (封印不可逆四情况组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「调参表」本系统无自有参数 本系统无自有参数(封印不可逆四情况组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「调参表」本系统无自有参数 本系统无自有参数(封印不可逆四情况组)
|
||||
print("--- 封印不可逆四情况(禁撤封印 + 挖封印格兑付改判)---")
|
||||
# 场景 A:安全格直挖(情况④)+ seal_pull/重复封印拒绝面
|
||||
var rng_a = load("res://core/rng_service.gd").new()
|
||||
@@ -696,8 +696,8 @@ func _smoke_seal_irreversible_quadrants() -> void:
|
||||
# 负向字典逐型直验(类型化兑付行协议):找真实板上各型非封锁格,直调 grant_routed 负向路由(att 归因束形态),
|
||||
# 断言每型的兑付形态(enrage/off_guard/sapped 效果行、heal 直伤行、blast 警觉行、action 行动点排队)。
|
||||
func _smoke_negative_dictionary() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:256 (下轮行动点修正排队与兑现组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:256 (下轮行动点修正排队与兑现组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P0 最小闭环」战斗结算发开轮通知 战斗结算发开轮通知(下轮行动点修正排队与兑现组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P0 最小闭环」战斗结算发开轮通知 战斗结算发开轮通知(下轮行动点修正排队与兑现组)
|
||||
print("--- 负向字典逐型直验(sapped 在位 / heal 直伤 / blast 警觉 / action 行动点)---")
|
||||
# 数据面:sapped 行在位(状态表七行 + effect_pool_map 映射在位)
|
||||
var sapped: Dictionary = _db.combat.status_effects.row_by_id("sapped")
|
||||
@@ -791,8 +791,8 @@ func _smoke_negative_dictionary() -> void:
|
||||
# 资源面断言:chain/dig 事件恒携带 resource=true(危险格同权);initial 恒 false(封锁格);
|
||||
# 封锁格查询 = null、危险格未开恒可查。
|
||||
func _smoke_resource_surface() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:235 (资源面只读查询组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:235 (资源面只读查询组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「格面资源:每个非封锁格都带一个,摇号纪律不变」每张雷图装上时 每张雷图装上时(资源面只读查询组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「格面资源:每个非封锁格都带一个,摇号纪律不变」每张雷图装上时 每张雷图装上时(资源面只读查询组)
|
||||
print("--- 格面资源资格面(危险格携带 / 封锁格无资源)---")
|
||||
var run1 = _run_battle(1, 0)
|
||||
var run2 = _run_battle(2, 0)
|
||||
@@ -843,7 +843,7 @@ func _smoke_resource_surface() -> void:
|
||||
# 断言真值依赖生产行值(行值变更即红)。合成行旧断言保留并存(零删除)。
|
||||
|
||||
func _check_enemy_alert_production_row() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:133 (真实入口断言——生产行值驱动)
|
||||
# 判据出处: design/engineering/test-conventions.md「8.4 真实入口断言」真实入口断言 真实入口断言(真实入口断言——生产行值驱动)
|
||||
var row: Dictionary = _db.run.reward.row_by_id("enemy_alert")
|
||||
Kit.check("enemy_alert 生产行值:blast 负向 effect=alert power0 weight0(不入池警觉行)〔QA余 V12〕",
|
||||
String(row.get("cell_type", "")) == "blast" and String(row.get("polarity", "")) == "negative"
|
||||
@@ -863,7 +863,7 @@ func _check_enemy_alert_production_row() -> void:
|
||||
|
||||
|
||||
func _check_ap_drain_production_row() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:133 (真实入口断言——生产行值驱动)
|
||||
# 判据出处: design/engineering/test-conventions.md「8.4 真实入口断言」真实入口断言 真实入口断言(真实入口断言——生产行值驱动)
|
||||
var row: Dictionary = _db.run.reward.row_by_id("ap_drain")
|
||||
Kit.check("ap_drain 生产行值:action 负向 power=1 weight0〔QA余 V12〕",
|
||||
String(row.get("cell_type", "")) == "action" and String(row.get("polarity", "")) == "negative"
|
||||
|
||||
@@ -419,8 +419,8 @@ var _db
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (结算接线同种子逐项 golden 对拍组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:134 受理零兑付、改判路径死——流水零「奖励作废(封印格直接挖开)」行、
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(结算接线同种子逐项 golden 对拍组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「授予段兑付:极性路由,四类动作各归各系统资源」授予段消费结算队列 授予段消费结算队列、改判路径死——流水零「奖励作废(封印格直接挖开)」行、
|
||||
# 同种子驱动序 golden 实测零漂移零重录(挖封印格被拒——驱动序不含该路径)〔封印改 V6〕
|
||||
_db = ConfigDBScript.new()
|
||||
var load_ok: bool = _db.load_tables("res://data/tables", true)
|
||||
|
||||
@@ -13,7 +13,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:293 Boss 半血解锁技宿主(装载组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「调参表」配置表共三张 配置表共三张(装载组)
|
||||
var db = ConfigDBScript.new()
|
||||
var load_ok: bool = db.load_tables("res://data/tables", true)
|
||||
Kit.check("前置:表加载零 error", load_ok and db.diagnostics_count("error") == 0)
|
||||
@@ -26,7 +26,7 @@ func _init() -> void:
|
||||
|
||||
# 门谓词:卓尔 (2,9) hp 130(×mult 1.0)→ venom_curb unlock 50 → 阈值 round(130×0.5)=65
|
||||
func _boss(db, L: int, D: int, kind := "boss"):
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
var ec = UnitContainerScript.new(db)
|
||||
var ok: bool = ec.spawn({"level_index": L, "node_depth": D, "hero_hp": int(db.combat.hero.max_hp), "row_kind": kind})
|
||||
Kit.check("前置:spawn (%d,%d) 受理" % [L, D], ok)
|
||||
@@ -45,7 +45,7 @@ func _has_sid(arr: Array, sid: String) -> bool:
|
||||
|
||||
|
||||
func _test_gate_predicate(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:143 (门谓词:条件不满足不进可摇集合组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「精英行:现役敌种的强化版,池=继承基础池+附加技」精英怪是某个现役敌种的强化版本 精英怪是某个现役敌种的强化版本(门谓词:条件不满足不进可摇集合组)
|
||||
var ec = _boss(db, 2, 9)
|
||||
var u: Dictionary = _boss_u(ec)
|
||||
var mhp: int = int(u.max_hp)
|
||||
@@ -74,7 +74,7 @@ func _test_gate_predicate(db) -> void:
|
||||
|
||||
# 闩不可逆:解锁后治疗抬回满血 → 复查零新解锁、可摇集合不回退
|
||||
func _test_latch_irreversible(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:143 (闩型条件首次为真整场保持组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「精英行:现役敌种的强化版,池=继承基础池+附加技」精英怪是某个现役敌种的强化版本 精英怪是某个现役敌种的强化版本(闩型条件首次为真整场保持组)
|
||||
var ec = _boss(db, 2, 9)
|
||||
var u: Dictionary = _boss_u(ec)
|
||||
ec.apply_damage(u, int(u.max_hp) / 2) # → 半血触发
|
||||
@@ -86,7 +86,7 @@ func _test_latch_irreversible(db) -> void:
|
||||
|
||||
# 普通行无字段逐位零扰动:地精 (1,0) 池快照零 unlock 键、过滤恒空转、可摇=全池
|
||||
func _test_plain_rows_zero_drift(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:301 (普攻倍率 1 特例——零漂移组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「开战生成:主角数据行与一场 1–4 个敌人」战斗开始时 战斗开始时(普攻倍率 1 特例——零漂移组)
|
||||
var ec = load("res://core/unit_container.gd").new(db)
|
||||
Kit.check("零扰动前置:巨蜘蛛首遇带 spawn(池三行全无 trigger——快照键策略钉死载体)", ec.spawn({"level_index": 2, "node_depth": 1, "hero_hp": int(db.combat.hero.max_hp)}))
|
||||
var u: Dictionary = ec.all_enemies()[0]
|
||||
|
||||
@@ -9,7 +9,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:143 (触发条件机制 V1–V10 组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「精英行:现役敌种的强化版,池=继承基础池+附加技」精英怪是某个现役敌种的强化版本 精英怪是某个现役敌种的强化版本(触发条件机制 V1–V10 组)
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
if not db.load_tables("res://data/tables", false):
|
||||
print("[trigger_cond_test] FAIL — 数值表加载失败")
|
||||
|
||||
@@ -15,7 +15,7 @@ var _db
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/地形变异.md:151 变异布置宿主(装载组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/地形变异.md「验收标准」候选池空合法 候选池空合法(装载组)
|
||||
_db = ConfigDBScript.new()
|
||||
# 表加载失败不中止(承 G2/G3/G4/G5 同款:表损坏的红落在具体断言上——
|
||||
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
|
||||
@@ -55,7 +55,7 @@ class _CountVariantRng extends RngServiceCore:
|
||||
# 本段经 begin_battle 走完整初始化序后断言:门控一致性 / 布置域 / 数量公式 / 连通片上限 / 确定性。
|
||||
|
||||
func _smoke_variant_placement(L: int) -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/地形变异.md:63 (战内布置段门控组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/地形变异.md「变异框架与类型清单」每种变异是配置表里的一行具名声明 每种变异是配置表里的一行具名声明(战内布置段门控组)
|
||||
print("--- 地形变异 布置段(L%d)---" % L)
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
rng.set_master_seed(42)
|
||||
@@ -149,7 +149,7 @@ func _variant_dump(b) -> String:
|
||||
|
||||
|
||||
func _smoke_global_variant() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/地形变异.md:74 (全局替换制与回落组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/地形变异.md「全局作用域型」型变异是 型变异是(全局替换制与回落组)
|
||||
print("--- 全局作用域变异(门控三维 + 全局池空兜底回落 + 资源面偏斜)---")
|
||||
# ① 跨字段互锁负样本(resource_face ⟺ scope=global 三条 + effect_value 新域 [0,50])
|
||||
var vt = load("res://data/schemas/variation_table.gd").new()
|
||||
@@ -344,7 +344,7 @@ func _errs_has_cross_field(errs: Array) -> bool:
|
||||
# 全称不可断)。可达判据=①静态(布置面零字面量下界)+②同种子改值产物互异(真实入口=begin_battle 布置段)。
|
||||
|
||||
func _test_pack_min_from_table() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/地形变异.md:63 (连通片格数 [pack_min,pack_max] 读表组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/地形变异.md「变异框架与类型清单」每种变异是配置表里的一行具名声明 每种变异是配置表里的一行具名声明(连通片格数 [pack_min,pack_max] 读表组)
|
||||
# ① 静态:布置面零字面量下界(randi_range(2, 退役——下界读 pack_min 表头单点)
|
||||
var src := FileAccess.get_file_as_string("res://core/board_installer.gd")
|
||||
Kit.check("布置面零字面量下界(randi_range(2, 退役、下界读表单点在位)〔架构整改 V10·静态〕",
|
||||
@@ -376,7 +376,7 @@ func _test_pack_min_from_table() -> void:
|
||||
# 授予段地形批(on_open 兑现 flat_damage);mine_dust=信息型遮蔽解析数据面(board.variant_ids×表行 effect)。
|
||||
|
||||
func _test_l3_rockfall_minedust_rows() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/地形变异.md:63 (L3 布置段门控与效果兑现组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/地形变异.md「变异框架与类型清单」每种变异是配置表里的一行具名声明 每种变异是配置表里的一行具名声明(L3 布置段门控与效果兑现组)
|
||||
var pool := {}
|
||||
for r in _db.combat.variation.variant_pool(3, "deep_underdark"):
|
||||
pool[String(r.variant_id)] = r
|
||||
|
||||
@@ -27,7 +27,7 @@ func _init() -> void:
|
||||
# ---- 类型闸断言(V7——project.godot warning 配置在位〔源码断言〕+审计器脚本在位;
|
||||
# 审计器归零判定走 static_scan S9 闸机,此处兜配置面)----
|
||||
func _smoke_type_gate() -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (封装边界——类型闸源码扫描组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」封装边界 封装边界(封装边界——类型闸源码扫描组)
|
||||
var pj: String = FileAccess.get_file_as_string("res://project.godot")
|
||||
Kit.check("V7 类型闸 warning 配置在位(untyped_declaration=1 显形)〔迭代27 T5〕",
|
||||
pj.contains("gdscript/warnings/untyped_declaration=1"))
|
||||
@@ -38,7 +38,7 @@ func _smoke_type_gate() -> void:
|
||||
|
||||
# ---- 卫生件 grep 闸(V8——死代码/字符串 Callable/影子账残留零命中;源码扫描面)----
|
||||
func _smoke_hygiene_gates() -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:54 (模态覆盖层层级与登记纪律——卫生闸组)
|
||||
# 判据出处: design/engineering/code-conventions.md「2.3 模态覆盖层层级规则」打开任何模态覆盖层时 打开任何模态覆盖层时(模态覆盖层层级与登记纪律——卫生闸组)
|
||||
var callables := 0
|
||||
for d in ["res://core", "res://presentation", "res://data"]:
|
||||
var dir := DirAccess.open(d)
|
||||
|
||||
@@ -18,7 +18,7 @@ const Kit := preload("res://tests/unit/test_kit.gd") # T6 收口:_check/汇
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
var db = ConfigDBScript.new()
|
||||
var load_ok: bool = db.load_tables("res://data/tables", true)
|
||||
Kit.check("前置:表加载零 error", load_ok and db.diagnostics_count("error") == 0)
|
||||
@@ -41,8 +41,8 @@ func _init() -> void:
|
||||
# ---- B1 兑付配方词表:五配方/三目标规则/双结账政策——常量非空且互异(封闭枚举负空间) ----
|
||||
|
||||
func _test_damage_controller_vocabularies() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「伤害单据与伤害控制器」 (事件/事实/效果类型/算子四词表封闭——契约词表组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「伤害单据与伤害控制器」 (事件/事实/效果类型/算子四词表封闭——契约词表组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「伤害单据与伤害控制器:所有伤害走同一道门」游戏里的每一份伤害 游戏里的每一份伤害(事件/事实/效果类型/算子四词表封闭——契约词表组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「伤害单据与伤害控制器:所有伤害走同一道门」游戏里的每一份伤害 游戏里的每一份伤害(事件/事实/效果类型/算子四词表封闭——契约词表组)
|
||||
var kinds: Array = [
|
||||
DamageControllerScript.KIND_HERO_ATTACK, DamageControllerScript.KIND_ENEMY_SKILL,
|
||||
DamageControllerScript.KIND_BOARD_TYPED, DamageControllerScript.KIND_BOARD_BLAST,
|
||||
@@ -72,8 +72,8 @@ func _test_damage_controller_vocabularies() -> void:
|
||||
# ---- D2↔B1:掷点用途标签 ∈ RngService 封闭词表(EC12——跨系统字面量契约的成员性断言) ----
|
||||
|
||||
func _test_rng_tag_closure(db) -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流」 (流 scope 封闭词表组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流」 (流 scope 封闭词表组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流:随机只从一个服务按号取,同种子必同局」用户两轮复裁 用户两轮复裁(流 scope 封闭词表组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流:随机只从一个服务按号取,同种子必同局」用户两轮复裁 用户两轮复裁(流 scope 封闭词表组)
|
||||
var stream_label: String = String(db.combat.settlement.damage_roll.armor_roll_stream)
|
||||
Kit.check("settlement.armor_roll_stream ∈ RngService 封闭标签词表(EC12)",
|
||||
RngServiceScript.PURPOSE_TAGS.has(stream_label))
|
||||
@@ -87,8 +87,8 @@ func _test_rng_tag_closure(db) -> void:
|
||||
# ---- B1→D1 行协议:单据九栏缺省齐备 + 协议公共键形态 ----
|
||||
|
||||
func _test_ticket_nine_columns() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (单据九列协议组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (单据九列协议组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(单据九列协议组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(单据九列协议组)
|
||||
var ctrl = _bare_controller()
|
||||
var t: Dictionary = ctrl.open_ticket(DamageControllerScript.KIND_BOARD_FLAT_HERO, "mine_hit", "契约探针",
|
||||
{"channel": "棋盘兑付", "base_value": 1, "target_rule": DamageControllerScript.TARGET_HERO, "ri": 0})
|
||||
@@ -118,8 +118,8 @@ func _bare_controller():
|
||||
# ---- B4→B3:增益授予布尔受理口径(受理/拒绝二元面 + 投影一致性) ----
|
||||
|
||||
func _test_status_boolean_acceptance(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:250 (受理布尔面组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:250 (受理布尔面组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(受理布尔面组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(受理布尔面组)
|
||||
var effects = StatusContainerScript.new(db)
|
||||
# EC1 域闭:notify_battle_start 前授予 = false(受理面封闭)
|
||||
var any_row: Dictionary = {}
|
||||
@@ -146,8 +146,8 @@ func _test_status_boolean_acceptance(db) -> void:
|
||||
# 个体键直传字面量("e1"/"e2"/"e3"——拼写约定单点在 StatusContainer.owner_key_for,测试面模拟授予路径逐只授)
|
||||
|
||||
func _test_status_individual_isolation(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:251 (按个体归属组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:251 (按个体归属组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(按个体归属组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(按个体归属组)
|
||||
var effects = StatusContainerScript.new(db)
|
||||
effects.notify_battle_start()
|
||||
var src := {"source_class": "seal_hit", "origin_cell": Vector2i(-1, -1), "round_index": 0}
|
||||
@@ -169,8 +169,8 @@ func _test_status_individual_isolation(db) -> void:
|
||||
|
||||
|
||||
func _test_status_grant_all_per_unit(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:252 (授予即生效组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:252 (授予即生效组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(授予即生效组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(授予即生效组)
|
||||
var effects = StatusContainerScript.new(db)
|
||||
effects.notify_battle_start()
|
||||
var src := {"source_class": "mine_hit", "origin_cell": Vector2i(-1, -1), "round_index": 0}
|
||||
@@ -197,8 +197,8 @@ func _test_status_grant_all_per_unit(db) -> void:
|
||||
|
||||
|
||||
func _test_status_death_clears(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:250 (战斗结束清空组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:250 (战斗结束清空组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(战斗结束清空组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(战斗结束清空组)
|
||||
var effects = StatusContainerScript.new(db)
|
||||
effects.notify_battle_start()
|
||||
var src := {"source_class": "seal_hit", "origin_cell": Vector2i(-1, -1), "round_index": 0}
|
||||
@@ -212,8 +212,8 @@ func _test_status_death_clears(db) -> void:
|
||||
|
||||
|
||||
func _test_status_merge_per_unit(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:253 (只登记不去重组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:253 (只登记不去重组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(只登记不去重组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(只登记不去重组)
|
||||
var effects = StatusContainerScript.new(db)
|
||||
effects.notify_battle_start()
|
||||
var src := {"source_class": "enemy_action", "origin_cell": Vector2i(-1, -1), "round_index": 0}
|
||||
@@ -236,8 +236,8 @@ func _test_status_merge_per_unit(db) -> void:
|
||||
# ---- B4 结算链契约(断言补齐批——①增益状态结算链):衰减逐值/战斗结束全清/满层拒绝/独立并存/首授快照 ----
|
||||
|
||||
func _test_status_decay_and_clear(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:21 (先兑付后衰减组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:21 (先兑付后衰减组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「系统范围」边界这样划 边界这样划(先兑付后衰减组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「系统范围」边界这样划 边界这样划(先兑付后衰减组)
|
||||
var effects = StatusContainerScript.new(db)
|
||||
effects.notify_battle_start()
|
||||
var src := {"source_class": "seal_hit", "origin_cell": Vector2i(-1, -1), "round_index": 0}
|
||||
@@ -258,8 +258,8 @@ func _test_status_decay_and_clear(db) -> void:
|
||||
|
||||
|
||||
func _test_status_stack_full_reject(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:255 (满层拒绝原子且留痕组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:255 (满层拒绝原子且留痕组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(满层拒绝原子且留痕组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(满层拒绝原子且留痕组)
|
||||
var effects = StatusContainerScript.new(db)
|
||||
effects.notify_battle_start()
|
||||
var src := {"source_class": "seal_hit", "origin_cell": Vector2i(-1, -1), "round_index": 0}
|
||||
@@ -277,8 +277,8 @@ func _test_status_stack_full_reject(db) -> void:
|
||||
|
||||
|
||||
func _test_status_independent_branch(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:257 (合成不设上下限组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:257 (合成不设上下限组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(合成不设上下限组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(合成不设上下限组)
|
||||
var effects = StatusContainerScript.new(db)
|
||||
effects.notify_battle_start()
|
||||
var probe := {
|
||||
@@ -303,8 +303,8 @@ func _test_status_independent_branch(db) -> void:
|
||||
|
||||
|
||||
func _test_status_snapshot_first_grant(db) -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:258 (快照抗重载组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:258 (快照抗重载组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(快照抗重载组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(快照抗重载组)
|
||||
var effects = StatusContainerScript.new(db)
|
||||
effects.notify_battle_start()
|
||||
var src_first := {"source_class": "seal_hit", "origin_cell": Vector2i(3, 4), "round_index": 1}
|
||||
|
||||
@@ -17,7 +17,7 @@ var _db
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md:281 冒险结构与专长宿主(装载组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「验收标准」开始新冒险 开始新冒险(装载组)
|
||||
_db = ConfigDBScript.new()
|
||||
# 表加载失败不中止(承 G2/G3/G4/G5 同款:表损坏的红落在具体断言上——
|
||||
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
|
||||
@@ -59,7 +59,7 @@ func _hits_kind(hits: Array, kind: String) -> Array:
|
||||
|
||||
# ② 冒险结构 API 闸(状态机受理面——重复开始拒绝 / 入口停点 / 放弃两态)
|
||||
func _smoke_adventure_api() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md:283 (冒险 API 组:开始受理/序列/回调)
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「冒险的一生:开始、推进与三种结局」在本文是一个计量单位 在本文是一个计量单位(冒险 API 组:开始受理/序列/回调)
|
||||
print("--- 冒险结构 API 闸(重复开始拒绝 · 入口停点 · 放弃两态受理)---")
|
||||
var adr = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(42))
|
||||
adr.set_hero_override(900, 400) # 首战速胜档(放弃的非战斗受理要走到选路态)
|
||||
@@ -122,7 +122,7 @@ func _api_mark_node(_node: Dictionary, _info: Dictionary, seq: Array) -> void:
|
||||
# ③ 冒险验收断言(映射 冒险结构.md 验收标准——表覆盖/满配冒险成功/种子复现/大奖励/败北线/
|
||||
# 重复拒绝/GP 跨关延续/加算区同账/恢复数学/放弃)
|
||||
func _smoke_adventure() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md:284 (冒险生命周期组:推进/末关/倒下/重开/生命账)
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「验收标准」开始新冒险 开始新冒险(冒险生命周期组:推进/末关/倒下/重开/生命账)
|
||||
print("--- 冒险结构验收(三关序列 · 大奖励 · 摘要五件事 · 账本封闭)---")
|
||||
var autoplay = load("res://sim/level_autoplay.gd")
|
||||
# ① 表与覆盖义务(序列关数 = 行集关数;节点源 = 参数档在固定种子下的生成图,
|
||||
@@ -465,7 +465,7 @@ func _smoke_adventure() -> void:
|
||||
# ---- 专长冒烟(feats 四级 · 案D 池接线 · V3 订阅面逐件三列)----
|
||||
|
||||
func _smoke_feats() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (奇物授予与凭证保底组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(奇物授予与凭证保底组)
|
||||
print("--- 专长重设计实装(feat_table 四级 · 专长带池接线 · 订阅面逐件)---")
|
||||
# ① 现行表牌库构成:36 件全量入池(破封一击随封印受理即揭示退役〔退役改 V7〕)——102 数值令牌+36 relic 令牌(四级 rarity 直映射)
|
||||
Kit.check("feat_table 已加载(36 件=基础 27+迁入 2+完美保险 1+迭代 46 换图系七件−破封一击退役〔退役改 V7〕——换代)", _db.crossrun.feats != null and (_db.crossrun.feats.rows as Array).size() == 36)
|
||||
@@ -920,7 +920,7 @@ func _level_active_nodes(level_index: int) -> Array:
|
||||
# 生产 feat_ticket_quota==2 读表驱动;保底同置满使 false 只能来自配额分支(先于概率掷点)。
|
||||
# 真实入口链 = node_curio_candidates→draw_candidates("reward_node")→feat_ticket_consider。
|
||||
func _check_ticket_quota_exhausted(a_t) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:133 (真实入口断言——配额满分支售满后恒 false)
|
||||
# 判据出处: design/engineering/test-conventions.md「8.4 真实入口断言」真实入口断言 真实入口断言(真实入口断言——配额满分支售满后恒 false)
|
||||
Kit.check("生产配额值在役:feat_ticket_quota==2〔QA余 V4〕", int(a_t.db.run.adventure.feat_ticket_quota) == 2)
|
||||
a_t.stop()._deck.ticket_appeared = int(a_t.db.run.adventure.feat_ticket_quota) # 配额满注入(A6 同款测试通道直填)
|
||||
a_t.stop()._deck.ticket_pity = int(a_t.db.run.adventure.feat_ticket_pity_step) # 保底同置满——false 唯一来源=配额分支
|
||||
|
||||
@@ -16,7 +16,7 @@ func _init() -> void:
|
||||
|
||||
|
||||
func _smoke_zero_chain_rule() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:230 (0 格连锁传播闭包——模拟玩家算子组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」每条都可单独验证 每条都可单独验证(0 格连锁传播闭包——模拟玩家算子组)
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
var load_ok: bool = db.load_tables("res://data/tables", true) and db.diagnostics_count("error") == 0
|
||||
Kit.check("前置:表加载零 error", load_ok)
|
||||
|
||||
@@ -55,7 +55,7 @@ func _init() -> void:
|
||||
|
||||
# ① 缺省两参(真编排器):同种子两跑整轮驱动逐位(确定性自证——动作序列快照经 cell_revealed 事件流)
|
||||
func _smoke_drive_round_contract() -> void:
|
||||
# 判据出处: design/gdd/术语表.md「效果端口件」 (效果端口件:收事件交结算取回命中批——驱动循环契约组)
|
||||
# 判据出处: design/gdd/术语表.md「战斗与效果」效果端口件 效果端口件(效果端口件:收事件交结算取回命中批——驱动循环契约组)
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
var load_ok: bool = db.load_tables("res://data/tables", true) and db.diagnostics_count("error") == 0
|
||||
Kit.check("前置:表加载零 error", load_ok)
|
||||
@@ -81,7 +81,7 @@ func _smoke_drive_round_contract() -> void:
|
||||
|
||||
# ② provider 形态:策略回调产出 dig/seal_place/refresh 各一——提交与日志回调四元组在案
|
||||
func _provider_shapes() -> void:
|
||||
# 判据出处: game/sim/battle_driver.gd「战斗驱动循环单点」 (端口应答束形状组)
|
||||
# 判据出处: game/sim/battle_driver.gd「战斗驱动循环单点」族探针共用的 族探针共用的(端口应答束形状组)
|
||||
var st := _StubSettlement.new()
|
||||
var script := [ {"kind": "dig", "cell": Vector2i(1, 1)}, {"kind": "seal", "cell": Vector2i(2, 2)}, {"kind": "refresh"}, {"kind": "stop"} ]
|
||||
var logs: Array = []
|
||||
@@ -102,7 +102,7 @@ func _provider_shapes() -> void:
|
||||
|
||||
# ③ max_rejects:策略恒返被拒动作——第 3 拒后停手出环(循环次数=3)
|
||||
func _max_rejects() -> void:
|
||||
# 判据出处: game/sim/battle_driver.gd「战斗驱动循环单点」 (拒绝通道组)
|
||||
# 判据出处: game/sim/battle_driver.gd「战斗驱动循环单点」族探针共用的 族探针共用的(拒绝通道组)
|
||||
var st := _StubSettlement.new()
|
||||
st.minesweeper.accept = false
|
||||
st.minesweeper.reject_cells = {Vector2i(9, 9): true}
|
||||
@@ -122,7 +122,7 @@ func _max_rejects() -> void:
|
||||
|
||||
# ④ 合步 next:move 后相位变更即断弃 dig(桩 on_submit 钩子把 phase 推离 Active)
|
||||
func _combined_step_next() -> void:
|
||||
# 判据出处: game/sim/battle_driver.gd「战斗驱动循环单点」 (合并步进组)
|
||||
# 判据出处: game/sim/battle_driver.gd「战斗驱动循环单点」族探针共用的 族探针共用的(合并步进组)
|
||||
var st := _StubSettlement.new()
|
||||
st.minesweeper.on_submit = func(action: String) -> void:
|
||||
if action == "move":
|
||||
|
||||
@@ -18,7 +18,7 @@ var _rng
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:219 棋盘生成宿主(装载组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「验收标准」确定性复现 确定性复现(装载组)
|
||||
_db = ConfigDBScript.new()
|
||||
# 表加载失败不中止(承 G2 同款:表损坏的红落在具体断言上——
|
||||
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
|
||||
@@ -52,7 +52,7 @@ func _mk_stream(stream_name: String, scope: int) -> RandomNumberGenerator:
|
||||
# 公式 N×cell ≤ 可用高−12 必须计入 (N−1)×2px 网格间距,否则网格实高溢出被 clip_contents 裁掉;
|
||||
# 现公式 = 计入间距 + 垂直预留 24px〔上 12/下 12——底部不贴 D 区边框〕)----
|
||||
func _smoke_layout_cell_formula() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:75 (出生区边长表单点——格边长公式组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「出生区安全与反退化布雷:脚下无雷、白给板不出厂」玩家开局站在棋盘上的 玩家开局站在棋盘上的(出生区边长表单点——格边长公式组)
|
||||
print("--- 棋盘布局格边长公式(底部预留回归·四档板型)---")
|
||||
var board_generator = load("res://core/board_generator.gd").new()
|
||||
var board_view = load("res://presentation/views/board_view.gd").new()
|
||||
@@ -82,7 +82,7 @@ func _smoke_layout_cell_formula() -> void:
|
||||
# ---- 地图战斗资源·身份面单元冒烟(格面资源:roll 恰一次 / 雷安同池 / 幂等 / 清图批尾)----
|
||||
|
||||
func _smoke_reward_identity_unit() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:233 (格面资源身份——三分出口与资源身份组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「验收标准」每格必有货 每格必有货(格面资源身份——三分出口与资源身份组)
|
||||
print("--- 地图战斗资源·格面资源身份面 ---")
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
rng.set_master_seed(20260911)
|
||||
@@ -144,7 +144,7 @@ class _BoardRowStub:
|
||||
|
||||
|
||||
func _smoke_board_generator() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:221 (确定性复现+布雷纪律组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「P1 / P2 后置」确定性复现 确定性复现(确定性复现+布雷纪律组)
|
||||
print("--- 棋盘生成 ---")
|
||||
var board_generator = load("res://core/board_generator.gd").new()
|
||||
for L in [1, 2]:
|
||||
@@ -239,7 +239,7 @@ func _board_dump(b) -> String:
|
||||
# ---- 地图战斗资源·伤害量值区间冒烟(roll 域内 + 中点锚 + 变异实际流动 + 定值行不受扰)----
|
||||
|
||||
func _smoke_power_interval() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:233 (资源量值区间——伤害量值区间组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「验收标准」每格必有货 每格必有货(资源量值区间——伤害量值区间组)
|
||||
print("--- 地图战斗资源·伤害量值区间(上阶/下阶随机)---")
|
||||
# ① 表侧静态锚(配置推导——改表不断锚):凡带 power_min/power_max 的行 = 区间行,
|
||||
# 校验配对齐全(lo ≤ hi)+ power = floor 中点(行动经济 条款①期望当量锚);其余行必须零区间字段。
|
||||
|
||||
@@ -13,7 +13,7 @@ var _db: ConfigDb
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:219 棋盘生成(装载组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「验收标准」确定性复现 确定性复现(装载组)
|
||||
_db = load("res://core/config_db.gd").new() as ConfigDb
|
||||
if not _db.load_tables("res://data/tables", false):
|
||||
Kit.check("数值表加载", false)
|
||||
@@ -40,7 +40,7 @@ func _generate(L: int, D: int, seed0: int) -> BoardData:
|
||||
|
||||
|
||||
func _test_generate_shape_and_mines() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:224 (布雷纪律组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「验收标准」确定性复现 确定性复现(布雷纪律组)
|
||||
var b := _generate(1, 0, 71000)
|
||||
if b == null:
|
||||
Kit.check("生成返回棋盘", false)
|
||||
@@ -61,7 +61,7 @@ func _test_generate_shape_and_mines() -> void:
|
||||
|
||||
# 目标雷数公式单点(d14):同参同值对拍原式 + 真实产图指标读数同源
|
||||
func _test_target_mine_count_single_source() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:224 (雷数单源组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「验收标准」确定性复现 确定性复现(雷数单源组)
|
||||
var bad := 0
|
||||
var checked := 0
|
||||
for L in [1, 2, 3]:
|
||||
@@ -92,7 +92,7 @@ func _test_target_mine_count_single_source() -> void:
|
||||
|
||||
|
||||
func _test_digits_equal_neighbor_mine_count() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:223 (数字恒真组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「出生区安全与反退化布雷:脚下无雷、白给板不出厂」玩家开局站在棋盘上的 玩家开局站在棋盘上的(数字恒真组)
|
||||
var b := _generate(1, 1, 72000)
|
||||
if b == null:
|
||||
Kit.check("生成返回棋盘(数字段)", false)
|
||||
@@ -113,7 +113,7 @@ func _test_digits_equal_neighbor_mine_count() -> void:
|
||||
|
||||
|
||||
func _test_same_seed_bit_identical() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:221 (同种子逐位复现组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「P1 / P2 后置」后置原因 后置原因(同种子逐位复现组)
|
||||
var a := _generate(2, 0, 73000)
|
||||
var b := _generate(2, 0, 73000)
|
||||
if a == null or b == null:
|
||||
@@ -124,7 +124,7 @@ func _test_same_seed_bit_identical() -> void:
|
||||
|
||||
|
||||
func _test_clearable_and_inferability_selfconsistent() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:226 (可清图与及格线自洽组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「棋盘生成」棋盘怎么生成 棋盘怎么生成(可清图与及格线自洽组)
|
||||
var b := _generate(1, 0, 74000)
|
||||
if b == null:
|
||||
Kit.check("生成返回棋盘(可推理段)", false)
|
||||
@@ -140,7 +140,7 @@ func _test_clearable_and_inferability_selfconsistent() -> void:
|
||||
# ---- V8 出生区边长表单点(架构整改——spawn_edge 表头驱动布雷域基/几何/护栏全导出)----
|
||||
|
||||
func _test_spawn_edge_from_table() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:75 (出生区边长读表组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「出生区安全与反退化布雷:脚下无雷、白给板不出厂」玩家开局站在棋盘上的 玩家开局站在棋盘上的(出生区边长读表组)
|
||||
# ① 纯函数对拍:edge=5 夹具 → target = round(d×(W×H−25))(25 格布雷域基可观测)
|
||||
var p5 := {"w": 12, "h": 12, "density": 0.15, "spawn_edge": 5}
|
||||
Kit.check("V8 纯函数:edge=5 布雷域基 25 格(target=round(d×(144−25)))〔架构整改 V8〕",
|
||||
|
||||
@@ -15,7 +15,7 @@ var _bp_path := "user://test_breakpoint_resume.json"
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:180 (断点域契约:七字段往返/续玩确定性/幂等/三结局清除组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「验收标准」断点域契约 断点域契约(断点域契约:七字段往返/续玩确定性/幂等/三结局清除组)
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
if not db.load_tables("res://data/tables", false):
|
||||
print("[breakpoint_resume_test] FAIL — 数值表加载失败")
|
||||
|
||||
@@ -13,7 +13,7 @@ const StatusTableScript := preload("res://data/schemas/status_effect_table.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:195 (跨表校验宿主——装载组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「P1 / P2 后置」后置原因 后置原因(跨表校验宿主——装载组)
|
||||
_test_all_links_valid()
|
||||
_test_dangling_skill_id()
|
||||
_test_cast_side_mismatch()
|
||||
@@ -47,7 +47,7 @@ func _cats(errs: Array) -> Array[String]:
|
||||
|
||||
# ---- 正向:技能池全对齿(普攻恰一行、buff 挂敌方侧)应零错,防校验误伤 ----
|
||||
func _test_all_links_valid() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:195 (悬空引用类别:跨表链接全有效组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「P1 / P2 后置」后置原因 后置原因(悬空引用类别:跨表链接全有效组)
|
||||
var skills := _skill([
|
||||
{"skill_id": "attack", "type": "basic"},
|
||||
{"skill_id": "raise_morale", "type": "buff", "buff_ref": "st_strong"},
|
||||
@@ -63,7 +63,7 @@ func _test_all_links_valid() -> void:
|
||||
|
||||
# ---- 负向:技能池引用表里不存在的 skill_id 必须报 ----
|
||||
func _test_dangling_skill_id() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:195 (悬空引用类别:skill_id 悬空组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「P1 / P2 后置」后置原因 后置原因(悬空引用类别:skill_id 悬空组)
|
||||
var skills := _skill([{"skill_id": "attack", "type": "basic"}])
|
||||
var enemies := _enemy([
|
||||
{"level_index": 1, "row_kind": "battle", "depth_band": 0, "enemy_id": "goblin", "pool": [
|
||||
@@ -76,7 +76,7 @@ func _test_dangling_skill_id() -> void:
|
||||
|
||||
# ---- 负向:buff 挂到主角侧状态(side 反向)必须报 ----
|
||||
func _test_cast_side_mismatch() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:195 (side 反向校验组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「P1 / P2 后置」后置原因 后置原因(side 反向校验组)
|
||||
var skills := _skill([{"skill_id": "raise_morale", "type": "buff", "buff_ref": "st_hero_side"}])
|
||||
var enemies := _enemy([
|
||||
{"level_index": 1, "row_kind": "battle", "depth_band": 0, "enemy_id": "goblin", "pool": [
|
||||
|
||||
@@ -12,7 +12,7 @@ var _resolver: ConfigDbResolver
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:202 (解析器宿主——装载组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(解析器宿主——装载组)
|
||||
_resolver = ResolverScript.new(
|
||||
func(level, category, message) -> void: # 诊断通道签名按调用实参收(首参为表 id 字符串)
|
||||
_diags.append("%s/%s/%s" % [str(level), str(category), str(message)]),
|
||||
@@ -55,7 +55,7 @@ func _difficulty_table():
|
||||
|
||||
|
||||
func _test_band_hit() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:202 (精确命中零警告组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(精确命中零警告组)
|
||||
var hit: Array = _resolver.resolve_enemy_rowset(1, 4, "battle")
|
||||
Kit.check("带命中取偏难一侧:请求深度 4 命中带 5(逐字不回带 0)〔fv1〕",
|
||||
hit.size() == 1 and String((hit[0] as Dictionary).get("enemy_id", "")) == "giant_spider")
|
||||
@@ -65,7 +65,7 @@ func _test_band_hit() -> void:
|
||||
|
||||
|
||||
func _test_rowset_order_preserved() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:202 (行集寻址与行序保序组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(行集寻址与行序保序组)
|
||||
var rows: Array = _resolver.resolve_enemy_rowset(1, 0, "battle")
|
||||
var ids: Array[String] = []
|
||||
for r in rows:
|
||||
@@ -75,7 +75,7 @@ func _test_rowset_order_preserved() -> void:
|
||||
|
||||
|
||||
func _test_top_band_clamp() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:202 (超最大行走封顶取最大行组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(超最大行走封顶取最大行组)
|
||||
_diags.clear()
|
||||
var rows: Array = _resolver.resolve_enemy_rowset(1, 99, "battle")
|
||||
Kit.check("越顶带 clamp 取顶带行集(battle 顶带 5)〔fv3〕",
|
||||
@@ -91,7 +91,7 @@ func _test_top_band_clamp() -> void:
|
||||
|
||||
|
||||
func _test_row_kind_routing() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:202 (行类别路由组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(行类别路由组)
|
||||
var battle_rows: Array = _resolver.resolve_enemy_rowset(1, 0, "battle")
|
||||
var boss_rows: Array = _resolver.resolve_enemy_rowset(1, 0, "boss")
|
||||
Kit.check("行类路由:同请求深度 battle 与 boss 命中不同键域〔fv4〕",
|
||||
@@ -100,7 +100,7 @@ func _test_row_kind_routing() -> void:
|
||||
|
||||
|
||||
func _test_request_oob() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:203 (越域致命中止组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(越域致命中止组)
|
||||
_diags.clear()
|
||||
_resolver.resolve_enemy_rowset(0, 0, "battle")
|
||||
Kit.check("关卡序号 <1 → fatal request_oob〔fv5〕", _has_fatal_oob())
|
||||
@@ -120,7 +120,7 @@ func _has_fatal_oob() -> bool:
|
||||
|
||||
|
||||
func _test_difficulty_clamp() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:202 (难度 clamp 组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(难度 clamp 组)
|
||||
var m: Dictionary = _resolver.resolve_difficulty_modifiers(1, 0)
|
||||
Kit.check("难度乘数越域被 clamp:hp 99 → 上限 10", absf(float(m.get("hp_mult", 0.0)) - 10.0) < 0.001)
|
||||
Kit.check("难度乘数越域被 clamp:atk 0.01 → 下限 0.1", absf(float(m.get("atk_mult", 0.0)) - 0.1) < 0.001)
|
||||
|
||||
@@ -8,7 +8,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/秘宝.md「定位与形态」 (CurioDeck:三选一/商店共享池、抽签、cap 库存——刷新付费组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/秘宝.md「定位与形态」现行形态 现行形态(CurioDeck:三选一/商店共享池、抽签、cap 库存——刷新付费组)
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
if not db.load_tables("res://data/tables", false):
|
||||
print("[curio_refresh_paid_test] FAIL — 数值表加载失败")
|
||||
|
||||
@@ -11,7 +11,7 @@ const EffectEngineScript = preload("res://core/effect_engine.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「扩签登记」 (效果词表封闭——扩签封闭性组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「扩签登记」落地结果 落地结果(效果词表封闭——扩签封闭性组)
|
||||
# ① 词表在册断言(扩签面:2 事件+8 事实+7 效果类型+1 算子)
|
||||
Kit.check_quiet(EffectEngineScript.EVENTS.has("dig_stop") and EffectEngineScript.EVENTS.has("battle_won"),
|
||||
"新事件在册:dig_stop/battle_won〔专长批 V1〕")
|
||||
|
||||
@@ -11,34 +11,34 @@ const Kit := preload("res://tests/unit/test_kit.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (封装边界:跨对象往来只走公开方法与属性——P2 词表单点扫描组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」封装边界 封装边界(封装边界:跨对象往来只走公开方法与属性——P2 词表单点扫描组)
|
||||
_sweep_generator()
|
||||
_sweep_production_face()
|
||||
quit(Kit.finish("encapsulation_p2_sweep_test"))
|
||||
|
||||
|
||||
func _src(path: String) -> String:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (源码采样组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(源码采样组)
|
||||
var src := FileAccess.get_file_as_string(path)
|
||||
Kit.check("扫描面非空前置:%s" % path, src.length() > 0)
|
||||
return src
|
||||
|
||||
|
||||
func _zero(pattern: String, src: String, label: String) -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (零命中扫描组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(零命中扫描组)
|
||||
var re := RegEx.create_from_string(pattern)
|
||||
Kit.check("%s:%s 零命中〔架构P2〕" % [label, pattern], re.search(src) == null)
|
||||
|
||||
|
||||
func _anchor(pattern: String, src: String, label: String) -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (正锚存在组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(正锚存在组)
|
||||
var re := RegEx.create_from_string(pattern)
|
||||
Kit.check("%s:%s 正锚在案〔架构P2〕" % [label, pattern], re.search(src) != null)
|
||||
|
||||
|
||||
# ① V1 生成器词表定义删除与改指
|
||||
func _sweep_generator() -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (生成器本地副本归零组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(生成器本地副本归零组)
|
||||
var src := _src("res://core/node_map_generator.gd")
|
||||
if src.length() == 0:
|
||||
return
|
||||
@@ -48,7 +48,7 @@ func _sweep_generator() -> void:
|
||||
|
||||
# ② V2 生产三目录定义唯一性(递归扫 .gd,恰好 1 处且落 level_table.gd)
|
||||
func _sweep_production_face() -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (schema 唯一定点组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(schema 唯一定点组)
|
||||
var files: Array[String] = []
|
||||
for dir_path in ["res://core", "res://data", "res://presentation"]:
|
||||
_collect_gd(dir_path, files)
|
||||
|
||||
@@ -14,7 +14,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (封装边界——五处结构性零命中扫描组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」封装边界 封装边界(封装边界——五处结构性零命中扫描组)
|
||||
_sweep_settlement_segments()
|
||||
_sweep_orchestrator_methods()
|
||||
_sweep_breakpoint_pair()
|
||||
@@ -26,7 +26,7 @@ func _init() -> void:
|
||||
|
||||
# 源文件读取+非空前置(返 "" 即已判红——调用侧跳过后续正则断言)
|
||||
func _src(path: String) -> String:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (源码采样组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(源码采样组)
|
||||
var src := FileAccess.get_file_as_string(path)
|
||||
Kit.check("扫描面非空前置:%s" % path, src.length() > 0)
|
||||
return src
|
||||
@@ -34,21 +34,21 @@ func _src(path: String) -> String:
|
||||
|
||||
# 正则零命中断言(-pattern 意图写入断言文案——可 grep 定位)
|
||||
func _zero(pattern: String, src: String, label: String, path: String) -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (零命中扫描组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(零命中扫描组)
|
||||
var re := RegEx.create_from_string(pattern)
|
||||
Kit.check("%s:%s 零命中〔封装5.1〕" % [label, pattern], re.search(src) == null)
|
||||
|
||||
|
||||
# 正锚在案断言(正则命中 ≥1——新公开面/新形态在用)
|
||||
func _anchor(pattern: String, src: String, label: String, path: String) -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (正锚存在组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(正锚存在组)
|
||||
var re := RegEx.create_from_string(pattern)
|
||||
Kit.check("%s:%s 正锚在案〔封装5.1〕" % [label, pattern], re.search(src) != null)
|
||||
|
||||
|
||||
# ① V2 settlement 七文件(束注入换代——对编排器引用归零)
|
||||
func _sweep_settlement_segments() -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (结算段封装扫描组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(结算段封装扫描组)
|
||||
var classes := {
|
||||
"res://core/settlement/grant_segment.gd": "GrantSegment",
|
||||
"res://core/settlement/combat_segment.gd": "CombatSegment",
|
||||
@@ -68,7 +68,7 @@ func _sweep_settlement_segments() -> void:
|
||||
|
||||
# ② V3 编排器搬家五方法零残留
|
||||
func _sweep_orchestrator_methods() -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (编排器方法面扫描组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(编排器方法面扫描组)
|
||||
var src := _src("res://core/battle_orchestrator.gd")
|
||||
if src.length() == 0:
|
||||
return
|
||||
@@ -78,7 +78,7 @@ func _sweep_orchestrator_methods() -> void:
|
||||
|
||||
# ③ V4 断点域(adventure_runner → BreakpointStore 公开面)
|
||||
func _sweep_breakpoint_pair() -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (断点对封装扫描组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(断点对封装扫描组)
|
||||
var src := _src("res://core/adventure_runner.gd")
|
||||
if src.length() == 0:
|
||||
return
|
||||
@@ -88,7 +88,7 @@ func _sweep_breakpoint_pair() -> void:
|
||||
|
||||
# ④ V5 存档双向公开面(save_manager↔slot_store)
|
||||
func _sweep_save_pair() -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (存档对封装扫描组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(存档对封装扫描组)
|
||||
var src_m := _src("res://core/save_manager.gd")
|
||||
if src_m.length() > 0:
|
||||
_zero("slots\\._", src_m, "save_manager 对槽位件私取归零", "res://core/save_manager.gd")
|
||||
@@ -102,7 +102,7 @@ func _sweep_save_pair() -> void:
|
||||
|
||||
# ⑤ V6 效果宿主累积面(grant → BattleFxHost 公开累积方法)
|
||||
func _sweep_fx_host_accumulators() -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (特效宿主累积面扫描组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(特效宿主累积面扫描组)
|
||||
var src := _src("res://core/settlement/grant_segment.gd")
|
||||
if src.length() == 0:
|
||||
return
|
||||
@@ -112,7 +112,7 @@ func _sweep_fx_host_accumulators() -> void:
|
||||
|
||||
# ⑥ V7 配置挂载面(config_db → 三 schema bind_resolver)
|
||||
func _sweep_config_resolver() -> void:
|
||||
# 判据出处: design/engineering/code-conventions.md:41 (配置挂载面扫描组)
|
||||
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(配置挂载面扫描组)
|
||||
var src := _src("res://core/config_db.gd")
|
||||
if src.length() == 0:
|
||||
return
|
||||
|
||||
@@ -16,7 +16,7 @@ func EffectEngineKindProbe(_db) -> bool:
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (奇物凭证五件与留任二件组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(奇物凭证五件与留任二件组)
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
if not db.load_tables("res://data/tables", false):
|
||||
print("[feat_vouchers_test] FAIL — 数值表加载失败")
|
||||
|
||||
@@ -14,7 +14,7 @@ const LevelRunnerScript := preload("res://core/level_runner.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md:288 (生命一致性:三写入口封顶 [0,生效上限]——主角账组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「验收标准」生命一致性 生命一致性(生命一致性:三写入口封顶 [0,生效上限]——主角账组)
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
if not db.load_tables("res://data/tables", false):
|
||||
print("[hero_ledger_test] FAIL — 数值表加载失败")
|
||||
|
||||
@@ -10,7 +10,7 @@ const LevelTableScript := preload("res://data/schemas/level_table.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (信息迷雾类型可见性宿主——装载组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(信息迷雾类型可见性宿主——装载组)
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
var loaded: bool = db.load_tables("res://data/tables", false)
|
||||
Kit.check_quiet(loaded, "可见性用例:数值表加载成功")
|
||||
@@ -103,7 +103,7 @@ func _runner(db, nodes: Array, anchor_id: int, candidates: Array, n: int = 2):
|
||||
# ---- ⑥ N 进数据表(含越域校验)〔fv6〕----
|
||||
|
||||
func _test_field_in_table(db) -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (迷雾参数读表——字段在表组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(迷雾参数读表——字段在表组)
|
||||
var n_in_table: int = int(db.run.level.info_visible_layers)
|
||||
Kit.check("N 落表:level.tres 读数 2(实际 %d)〔fv6〕" % n_in_table, n_in_table == 2)
|
||||
var t := LevelTableScript.new()
|
||||
@@ -127,7 +127,7 @@ func _has_n_domain_err(errs: Array) -> bool:
|
||||
# ---- ① 邻近 N 层见类型(层距边界)〔fv1〕----
|
||||
|
||||
func _test_layer_distance(db) -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (层距 N 可见性组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(层距 N 可见性组)
|
||||
var nodes := _graph_nodes()
|
||||
var r = _runner(db, nodes, 1, [nodes[2]]) # 锚 = 节点 1(层 1),候选 = 节点 2
|
||||
var vis: Array = r.type_visible_ids()
|
||||
@@ -139,7 +139,7 @@ func _test_layer_distance(db) -> void:
|
||||
# ---- ② 下一跳恒可见(跨层跳边候选)〔fv4〕----
|
||||
|
||||
func _test_candidate_exempt(db) -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (候选豁免组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(候选豁免组)
|
||||
var nodes := _graph_nodes()
|
||||
var r = _runner(db, nodes, 6, [nodes[3]]) # 锚 = 节点 6(层 5),候选 = 节点 3(层 2,层距 3)
|
||||
var vis: Array = r.type_visible_ids()
|
||||
@@ -150,7 +150,7 @@ func _test_candidate_exempt(db) -> void:
|
||||
# ---- ③ Boss/终点不入雾+⑤ 入口停点锚层 0〔fv3〕〔fv1〕----
|
||||
|
||||
func _test_boss_exempt(db) -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (Boss 豁免组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」Boss Boss(Boss 豁免组)
|
||||
var nodes := _graph_nodes()
|
||||
var r = _runner(db, nodes, -1, [nodes[0]]) # 入口停点(无当前节点,锚层 0)
|
||||
var vis: Array = r.type_visible_ids()
|
||||
@@ -163,7 +163,7 @@ func _test_boss_exempt(db) -> void:
|
||||
# ---- ④ 单圈回雾(visited 不豁免)〔fv7〕----
|
||||
|
||||
func _test_single_circle(db) -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (单圈可见组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(单圈可见组)
|
||||
var nodes := _graph_nodes()
|
||||
var r = _runner(db, nodes, 6, [nodes[7], nodes[3]])
|
||||
r.visited.assign([nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], nodes[6]])
|
||||
@@ -176,7 +176,7 @@ func _test_single_circle(db) -> void:
|
||||
# ---- ⑤ 单链退化形态(出度 ≤1 图,编号 = id 句柄)〔fv1〕----
|
||||
|
||||
func _test_single_chain_entry(db) -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (单链入口组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(单链入口组)
|
||||
var nodes := _chain_nodes()
|
||||
var r = _runner(db, nodes, -1, [nodes[0]])
|
||||
var vis: Array = r.type_visible_ids()
|
||||
@@ -189,7 +189,7 @@ func _test_single_chain_entry(db) -> void:
|
||||
# ---- ⑥ N 读表:可见窗随表值随动〔fv6〕----
|
||||
|
||||
func _test_n_from_table(db) -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (N 读表组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(N 读表组)
|
||||
var nodes := _graph_nodes()
|
||||
var r = _runner(db, nodes, 1, [nodes[2]]) # 锚层 1
|
||||
db.run.level.info_visible_layers = 1
|
||||
@@ -207,7 +207,7 @@ func _test_n_from_table(db) -> void:
|
||||
# ---- ⑦ 续玩重建同值〔fv7〕----
|
||||
|
||||
func _test_resume_rebuild(db) -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
var t := LevelTableScript.new()
|
||||
t.info_visible_layers = 2
|
||||
t.rows = [{"level_index": 1, "display_name": "夹具关", "rest_heal_pct": 30}]
|
||||
|
||||
@@ -232,7 +232,7 @@ func _board_row_exact(level_index: int, depth: int) -> bool:
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
_db = ConfigDBScript.new()
|
||||
# 表加载失败不中止(承 G2/G3/G4/G5 同款:表损坏的红落在具体断言上——
|
||||
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
|
||||
@@ -262,7 +262,7 @@ func _init() -> void:
|
||||
# ---- 数值入表等价证明(d11/d16a——原字面量迁移:表值 == 迁移前字面量,消费端读表)----
|
||||
|
||||
func _smoke_table_migration() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:195 (行集纪律——表迁移组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「P1 / P2 后置」后置原因 后置原因(行集纪律——表迁移组)
|
||||
print("--- 数值入表(shop 两 knob + hero 显示名 · 原值迁移)---")
|
||||
Kit.check("shop.relic_base_price 表值 == 迁移前字面量(15.0)〔wd11〕", _db.run.shop.relic_base_price == 15.0)
|
||||
Kit.check("hero.display_name 表值 == 迁移前字面量(探险者)〔wd16〕", _db.combat.hero.display_name == "探险者")
|
||||
@@ -277,7 +277,7 @@ func _smoke_table_migration() -> void:
|
||||
# 敌侧/板侧解析一律走 ConfigDB 真实消费链,禁直读行集自算)----
|
||||
|
||||
func _smoke_generated_coverage() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:184 (每终点前恰一店——生成覆盖扫描组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(每终点前恰一店——生成覆盖扫描组)
|
||||
var enemy_ok := true
|
||||
var board_ok := true
|
||||
var boss_band_ok := true
|
||||
@@ -328,7 +328,7 @@ func _smoke_generated_coverage() -> void:
|
||||
# ---- 关卡节点图·生成图推进冒烟(图 = 该关参数档 × 种子)----
|
||||
|
||||
func _smoke_level() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (关卡图校验推进组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(关卡图校验推进组)
|
||||
print("--- 关卡节点图·生成图推进(参数档×种子产图·满配冒险成功/恢复公式/败北线/回放确定性)---")
|
||||
var autoplay = load("res://sim/level_autoplay.gd")
|
||||
var hero_base := {"atk": int(_db.combat.hero.atk), "hp": int(_db.combat.hero.max_hp), "ac": int(_db.combat.hero.armor_class)} # 配置基线快照——⑤ 回基线对比用(改表自动跟随,不再硬编码)
|
||||
@@ -442,7 +442,7 @@ func _drive_to_rest(level_index: int, seed_val: int, gap: int) -> Dictionary:
|
||||
# ---- 分支节点图冒烟:图合法性校验 + L2 幽暗地域生成图行进(图 = 参数档 × 种子)----
|
||||
|
||||
func _smoke_level_graph() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (图结构与行进纪律组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(图结构与行进纪律组)
|
||||
print("--- 关卡节点图·分支节点图(L2 幽暗地域·生成图)---")
|
||||
var autoplay = load("res://sim/level_autoplay.gd")
|
||||
# ① 关卡表行级校验零错误(关卡表只承载序号/显示名/恢复比例——图合法性由 validate_graph 在起关时承担)
|
||||
@@ -801,7 +801,7 @@ func _fresh_rng(seed_val: int):
|
||||
# ---- ① GP 冒险钱包·到账 ----
|
||||
|
||||
func _smoke_gp_wallet() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:233 (GP 钱包入账组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「验收标准」每格必有货 每格必有货(GP 钱包入账组)
|
||||
print("--- GP 冒险钱包·到账(战斗完成入账恰一次 + Boss 加值)---")
|
||||
var autoplay = load("res://sim/level_autoplay.gd")
|
||||
# ① L1 首战(普通战档——掷定 [2,4] + 关级加值 0):runner 驱动,收集 battle_finished 与钱包事件
|
||||
@@ -867,7 +867,7 @@ func _escrow_sum_of(rows: Array) -> int:
|
||||
# ---- ② escrow 隔离(GP安全格兑付 / 破财直验 / 钱包 clamp)----
|
||||
|
||||
func _smoke_gp_escrow() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:233 (GP escrow 组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「验收标准」每格必有货 每格必有货(GP escrow 组)
|
||||
print("--- GP escrow 隔离(GP安全格兑付入缓冲 · 破财不透支)---")
|
||||
# ① 种子扫描:找GP 袋(gp 型安全格)可挖掘局——挖开兑付 +3 入 escrow,战斗末随 gp_dropped 一次上抛
|
||||
var scan := {}
|
||||
@@ -981,7 +981,7 @@ func _find_gp_dig(minesweeper, settlement) -> Dictionary:
|
||||
# ---- ③ 商店房三收口 ----
|
||||
|
||||
func _smoke_shop_room() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:184 (商店房呈现组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(商店房呈现组)
|
||||
print("--- 商店房三收口(现价/加算区/余额不足拒/离开回选路/收束清零)---")
|
||||
var autoplay = load("res://sim/level_autoplay.gd")
|
||||
# 行进到商店房(按图型别定位商店节点——候选取最小句柄行进,到达即停):
|
||||
@@ -1115,7 +1115,7 @@ func _shop_products_by_id(prods: Array) -> Dictionary:
|
||||
# ---- ④ 商店编排性质(生成图扫描面——三条性质 + 终点跨表解析)----
|
||||
|
||||
func _smoke_shop_graph() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:184 (必经恰一店图纪律组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(必经恰一店图纪律组)
|
||||
print("--- 商店编排性质(每终点前一位恰一店 · 店数=终点数 · 全路径恰穿一店)---")
|
||||
var pred_bad := 0
|
||||
var term_total := 0
|
||||
@@ -1186,7 +1186,7 @@ func _smoke_shop_graph() -> void:
|
||||
|
||||
# ---- ⑥ 大岔口分区域兑付(V3——多终点图走哪条路决定打谁,任一 Boss 胜即收束恰一次)----
|
||||
func _smoke_multi_terminal_settlement() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:185 (多终局收束组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(多终局收束组)
|
||||
print("--- 大岔口分区域兑付(L2 两轴各打各的终点)---")
|
||||
var autoplay = load("res://sim/level_autoplay.gd")
|
||||
var nodes: Array = _generated_graph(2, 42).get("nodes", [])
|
||||
@@ -1254,7 +1254,7 @@ func _paths_all_one_shop(nodes: Array) -> bool:
|
||||
# ---- ⑤ 商店共享池(三选一同构/乘法价/跨渠道共账/切边/断点扩键)----
|
||||
|
||||
func _smoke_shop_pool() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「共享池账本」 (商店共享池组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「GP:战斗掉落的局内钱包与统一冒险加算区」是冒险内的一次性属性提升货币 是冒险内的一次性属性提升货币(商店共享池组)
|
||||
print("--- 商店共享池(抽3买1全重抽 · 乘法定价 ceil · 池空硬闸 · 切边零入店)---")
|
||||
var autoplay = load("res://sim/level_autoplay.gd")
|
||||
var shelf_kinds: Array = []
|
||||
@@ -1417,7 +1417,7 @@ func _smoke_shop_pool() -> void:
|
||||
# ---- 商店房 node_entered 载荷(尾波 V1——_enter_node pool/legacy 双发射路径归一后的行为保持断言)----
|
||||
|
||||
func _test_shop_node_entered_payload() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:184 (行进至此打开商店覆盖层——载荷组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行进至此打开商店覆盖层 行进至此打开商店覆盖层(行进至此打开商店覆盖层——载荷组)
|
||||
print("--- 商店房 node_entered 载荷(pool 含 shelf:true+gp 现值/legacy 无 shelf 键)---")
|
||||
var autoplay = load("res://sim/level_autoplay.gd")
|
||||
# pool 态:载荷字典经信号闭包当场取样(字典为引用累积器——lambda 按值捕获标量的绕行惯例)
|
||||
@@ -1576,7 +1576,7 @@ func _has_err_category(errs: Array, category: String) -> bool:
|
||||
# ---- 货架位数读表(架构整改——shelf_size 表头单点:进店与重抽同源)----
|
||||
|
||||
func _test_shelf_size_from_table() -> void:
|
||||
# 判据出处: design/ux/shop.md:13 (货架位数读表组)
|
||||
# 判据出处: design/ux/shop.md「布局与交互」模态覆盖层 模态覆盖层(货架位数读表组)
|
||||
var autoplay = load("res://sim/level_autoplay.gd")
|
||||
var st = _db.run.shop
|
||||
var saved: int = int(st.shelf_size)
|
||||
@@ -1598,7 +1598,7 @@ func _test_shelf_size_from_table() -> void:
|
||||
# ---- 散折价收回规则键(架构整改 R2——shop.spend_discount 表字段退役,折价读 economy_spend.discount_pct)----
|
||||
|
||||
func _test_spend_discount_from_rule_key() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:256 (换图基座:挖格产 RAP 与刷新折扣组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P0 最小闭环」战斗结算发开轮通知 战斗结算发开轮通知(换图基座:挖格产 RAP 与刷新折扣组)
|
||||
# 字段真删:shop.tres 加载零诊断 + spend_discount 属性不在位
|
||||
Kit.check("shop.tres 加载零诊断(spend_discount 字段真删——schema 与表行同卸)〔架构整改 V2〕",
|
||||
_db.diagnostics_count("error") == 0 and _db.run.shop.get("spend_discount") == null)
|
||||
|
||||
@@ -11,7 +11,7 @@ const LevelTableScript := preload("res://data/schemas/level_table.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (关卡表消费侧校验宿主)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(关卡表消费侧校验宿主)
|
||||
_test_positive()
|
||||
_test_negative()
|
||||
_test_scope_not_extended()
|
||||
@@ -38,7 +38,7 @@ func _has(errs: Array, cat: String, needle: String = "") -> bool:
|
||||
# ---- 正例(四检全过)----
|
||||
|
||||
func _test_positive() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (良构基底正向组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(良构基底正向组)
|
||||
# 多入口多终点:两入口共汇入一岔口,两终点各在互异深度
|
||||
var multi := [
|
||||
_n(0, "battle", 0, [2]), _n(1, "battle", 0, [2]),
|
||||
@@ -61,7 +61,7 @@ func _test_positive() -> void:
|
||||
# ---- 负例九类(各报对应类别与判据消息)----
|
||||
|
||||
func _test_negative() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (违规配置加载期致命——负向组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」违规配置加载期致命 违规配置加载期致命(违规配置加载期致命——负向组)
|
||||
var non_boss_end := [_n(0, "battle", 0, [1]), _n(1, "battle", 1, [])]
|
||||
Kit.check("负例:终点非 Boss 命中「终点恒为 Boss」〔v1〕",
|
||||
_has(_errs(non_boss_end), "structural", "终点 1 非 Boss"))
|
||||
@@ -95,7 +95,7 @@ func _test_negative() -> void:
|
||||
# ---- 「勿扩勿缩」反证:本检不含商店位与个数对参数档的核对 ----
|
||||
|
||||
func _test_scope_not_extended() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (校验范围不外扩组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(校验范围不外扩组)
|
||||
# 合法形状但全程无商店/三个终点同入口图——四检不该因此报错(商店位归冒烟断言、个数归产出侧)
|
||||
var no_shop := [_n(0, "battle", 0, [1, 2]), _n(1, "battle", 1, [3]), _n(2, "rest", 1, [3]), _n(3, "boss", 2, [])]
|
||||
Kit.check("范围反证:无商店图不在加载校验内报错(商店位由冒烟断言把关)〔v1〕", _errs(no_shop).is_empty())
|
||||
|
||||
@@ -21,7 +21,7 @@ var _db
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/元进度.md:148 元进度与锻造宿主(装载组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/元进度.md「验收标准」钥石不丢 钥石不丢(装载组)
|
||||
_db = ConfigDBScript.new()
|
||||
# 表加载失败不中止(承 G2/G3/G4/G5 同款:表损坏的红落在具体断言上——
|
||||
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
|
||||
@@ -139,7 +139,7 @@ func _auto_play_round(settlement, out: Dictionary) -> void:
|
||||
# ---- 元进度 ②树购买面(购买受理/持久/余额不足拒绝/未知节点拒绝;
|
||||
# 行价=表值 flat 单价)----
|
||||
func _meta_pricing_and_buy() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:198 (单币可判:购买只扣钥石、余额不足拒绝零变化组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「验收标准」单币可判 单币可判(单币可判:购买只扣钥石、余额不足拒绝零变化组)
|
||||
print("--- 元进度·树购买面(隔离档 smoke_meta_buy/dry)---")
|
||||
_meta_smoke_cleanup()
|
||||
var sv = _meta_new_save(_META_SMOKE_PATHS[0])
|
||||
@@ -166,7 +166,7 @@ func _meta_pricing_and_buy() -> void:
|
||||
|
||||
# ---- 元进度 ⑥Boss 两档 ⑦钥石不丢 ⑧工坊解锁 ⑩摘要副本与 cap(合成摘要驱动——settle 纯账面零跑局)----
|
||||
func _meta_settle_and_workshop() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/元进度.md:150 (钥石收束入账不丢组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/元进度.md「验收标准」钥石不丢 钥石不丢(钥石收束入账不丢组)
|
||||
print("--- 元进度·收束入账与工坊(隔离档 smoke_meta_settle/workshop/cap)---")
|
||||
var sv = _meta_new_save(_META_SMOKE_PATHS[2])
|
||||
var mp = load("res://core/meta_progression.gd").new(_db, sv)
|
||||
@@ -359,7 +359,7 @@ func _meta_settle_and_workshop() -> void:
|
||||
|
||||
# ---- 元进度 ④注入可见 + 白板成立(验收 4/2/3——程序面;MC 逐位回归归 T7 全量验证)----
|
||||
func _meta_injection() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:201 (注入可判:开局覆盖值分层可加组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「验收标准」注入可判 注入可判(注入可判:开局覆盖值分层可加组)
|
||||
print("--- 元进度·注入可见与白板(隔离档 smoke_meta_white/dry)---")
|
||||
var sv = _meta_new_save(_META_SMOKE_PATHS[1])
|
||||
var mp = load("res://core/meta_progression.gd").new(_db, sv)
|
||||
@@ -403,7 +403,7 @@ func _meta_injection() -> void:
|
||||
# ---- 锻造工坊·两根类型轴所有权移交(V5 前半:hero.tres 两轴删除+锻造配置默认值)----
|
||||
# 后半(build_adventure_params 注入默认值/选中覆盖)随 T4 注入接线同批断言;写口/解锁面归 T3。
|
||||
func _smoke_forge_axes() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md:220 (锻造两轴单选注入与树零攻防组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「验收标准」本节判据全部绑结构与关系 本节判据全部绑结构与关系(锻造两轴单选注入与树零攻防组)
|
||||
print("--- 锻造工坊·类型轴所有权移交(T2)---")
|
||||
# V5:hero.tres 静态表两轴已删(全表加载零违例——config_db_test 同款闸;此处钉字段不在位)
|
||||
Kit.check("hero.tres 无 attack_type/armor_type 字段(契约 2——静态表两轴删除)〔锻造工坊批 V5〕",
|
||||
@@ -566,7 +566,7 @@ func _smoke_forge_axes() -> void:
|
||||
# ---- 天赋树冒烟(v0.8 12 节点:schema/购买面/Fork 一节点双态/彩蛋特化)----
|
||||
|
||||
func _smoke_tree() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:194 (天赋树购买与六键合成组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「验收标准」结构封闭 结构封闭(天赋树购买与六键合成组)
|
||||
print("--- 天赋树(12 节点 · 购买面 · Fork 双态 · 彩蛋觉醒)---")
|
||||
# 〔V1〕结构:12 行 + schema 零违例
|
||||
Kit.check("meta_tree 已加载(12 节点=脊柱 2〔生命/命中淬炼一线一节点 cap4〕+锻造 2〔钥匙+彩蛋——彩蛋含在锻造 2 内非第 13 行〕+钥石 2〔秘宝匣/刷新升级〕+同调 6〔socket 3+Fork 3 双态〕——v0.8 终态)〔天赋树批 V1〕",
|
||||
@@ -649,7 +649,7 @@ func _smoke_tree() -> void:
|
||||
# ---- 天赋树六键行为冒烟(V10:开局姿态窗/危险直觉限次/财富之道聚散/守侧失误补偿;
|
||||
# 引擎直构 + 编排授予段直注(_grant_seg._judge_seal=结算授予段封印判定单口))----
|
||||
func _smoke_tree_rules() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:194 (规则键参数读表组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「验收标准」结构封闭 结构封闭(规则键参数读表组)
|
||||
print("--- 天赋树六键行为(V10:窗/限次/聚散/守侧)---")
|
||||
# 开局姿态组:每关首轮窗(battle_index 事实——引擎直构 + 自建 ctx)
|
||||
var fx = load("res://core/effect_engine.gd").new(null)
|
||||
@@ -790,7 +790,7 @@ func _smoke_tree_rules() -> void:
|
||||
# ---- 锻造契约补齐(断言补齐批——⑥锻造工坊):拒购零副作用/祝福件零泄漏/默认值解耦/甲型双轴 ----
|
||||
|
||||
func _test_forge_buy_reject() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md:222 (钥石不足购买被拒、余额与等级零变化组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「验收标准」本节判据全部绑结构与关系 本节判据全部绑结构与关系(钥石不足购买被拒、余额与等级零变化组)
|
||||
var sv = _meta_new_save("user://smoke_meta_reject.json")
|
||||
var mp = load("res://core/meta_progression.gd").new(_db, sv)
|
||||
sv.meta_state._add_keystone(10) # 低于首购价 20——余额不足面
|
||||
@@ -805,7 +805,7 @@ func _test_forge_buy_reject() -> void:
|
||||
|
||||
|
||||
func _test_blessing_no_forge_leak() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md:220 (树淬炼对攻击与 AC 零贡献组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「验收标准」树淬炼对攻击与 树淬炼对攻击与(树淬炼对攻击与 AC 零贡献组)
|
||||
var sv = _meta_new_save("user://smoke_meta_blessing.json")
|
||||
var mp = load("res://core/meta_progression.gd").new(_db, sv)
|
||||
var fs0: Dictionary = sv.meta_state.forge_state().duplicate(true)
|
||||
@@ -824,7 +824,7 @@ func _test_blessing_no_forge_leak() -> void:
|
||||
|
||||
|
||||
func _test_default_axes_pre_key() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md:217 (未点亮期间默认值照常注入组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「验收标准」本节判据全部绑结构与关系 本节判据全部绑结构与关系(未点亮期间默认值照常注入组)
|
||||
var sv = _meta_new_save("user://smoke_meta_axesw.json")
|
||||
var mp = load("res://core/meta_progression.gd").new(_db, sv)
|
||||
var ax: Dictionary = mp.hero_type_axes()
|
||||
@@ -833,7 +833,7 @@ func _test_default_axes_pre_key() -> void:
|
||||
|
||||
|
||||
func _test_armor_switch_dual_axes() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md:221 (换装不丢级不生效——双轴组)
|
||||
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「验收标准」换装不丢级不生效 换装不丢级不生效(换装不丢级不生效——双轴组)
|
||||
var sv = _meta_new_save("user://smoke_meta_axesw.json")
|
||||
sv.meta_state._add_keystone(1000)
|
||||
var mp = load("res://core/meta_progression.gd").new(_db, sv)
|
||||
@@ -863,7 +863,7 @@ func _test_armor_switch_dual_axes() -> void:
|
||||
# ---- G5 天赋树行与投影断言(迭代 55「QA覆盖余量收口批」T5——ks_workshop/ks_refresh/fork 两行/侧投影+spine 读行)----
|
||||
|
||||
func _check_ks_workshop_row() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:30 (钥匙门行——前置/零价/柜台展开)
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「系统范围」边界这样划 边界这样划(钥匙门行——前置/零价/柜台展开)
|
||||
var row: Dictionary = _db.crossrun.meta_tree.row_by_id("ks_workshop")
|
||||
Kit.check("ks_workshop 行值:keystone 脉络 unlock 行且前置=[sp_hp](脊柱生命第 1 级)〔QA余 V7〕",
|
||||
String(row.get("vein", "")) == "keystone" and String(row.get("kind", "")) == "unlock"
|
||||
@@ -892,7 +892,7 @@ func _ks_row_level(mp, node_id: String) -> int:
|
||||
|
||||
|
||||
func _check_ks_refresh_row() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:30 (刷新升级行——同账路由与零刷新分支)
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「系统范围」边界这样划 边界这样划(刷新升级行——同账路由与零刷新分支)
|
||||
var row: Dictionary = _db.crossrun.meta_tree.row_by_id("ks_refresh")
|
||||
Kit.check("ks_refresh 行值:rule 行 keystone 币 price=30 cap=2 前置=[ks_workshop]〔QA余 V7〕",
|
||||
String(row.get("kind", "")) == "rule" and String(row.get("currency", "")) == "keystone"
|
||||
@@ -915,7 +915,7 @@ func _check_ks_refresh_row() -> void:
|
||||
|
||||
|
||||
func _check_fork_rows() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:30 (fork 一节点双态行——行值经购买面驱动)
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「系统范围」fork fork(fork 一节点双态行——行值经购买面驱动)
|
||||
for spec in [{"id": "fork_sense", "group": "fg_sense", "na": "锋", "nb": "守"},
|
||||
{"id": "fork_economy", "group": "fg_economy", "na": "聚", "nb": "散"}]:
|
||||
var row: Dictionary = _db.crossrun.meta_tree.row_by_id(String(spec["id"]))
|
||||
@@ -941,7 +941,7 @@ func _check_fork_rows() -> void:
|
||||
|
||||
|
||||
func _check_fork_side_projection() -> void:
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:30 (组侧投影与脉络行板——真实表行读出)
|
||||
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「系统范围」边界这样划 边界这样划(组侧投影与脉络行板——真实表行读出)
|
||||
var sv = _meta_new_save("user://smoke_meta_fork_side.json")
|
||||
var mp = load("res://core/meta_progression.gd").new(_db, sv)
|
||||
sv.meta_state._add_keystone(1000)
|
||||
|
||||
@@ -17,7 +17,7 @@ var _ae: ActionEconomy
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:224 (排雷规则宿主——装载组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」每条都可单独验证 每条都可单独验证(排雷规则宿主——装载组)
|
||||
_db = load("res://core/config_db.gd").new() as ConfigDb
|
||||
if not _db.load_tables("res://data/tables", false):
|
||||
Kit.check("数值表加载", false)
|
||||
@@ -50,7 +50,7 @@ func _init() -> void:
|
||||
|
||||
|
||||
func _test_install_invariants() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:228 (装板四不变式组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「挖开空地整片塌开:数字提示与连锁展开」每个已开安全格都亮着一个数字 每个已开安全格都亮着一个数字(装板四不变式组)
|
||||
_rules.install_board(_board)
|
||||
Kit.check("装板后 current_board 即所装棋盘", _rules.current_board() == _board)
|
||||
var opened: int = _rules.revealed_cells().size()
|
||||
@@ -74,7 +74,7 @@ func _unrevealed_safe() -> Vector2i:
|
||||
|
||||
|
||||
func _test_dig_face_rules() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:231 (挖/封印合法性与可辨拒绝组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「调参表」本系统无自有参数 本系统无自有参数(挖/封印合法性与可辨拒绝组)
|
||||
var revealed_first = _rules.revealed_cells()[0] as Vector2i
|
||||
var out: Array = _rules.settle_batch([{"action": "dig", "cell": revealed_first}])
|
||||
var o: Dictionary = (out[0] as Dictionary) if not out.is_empty() else {}
|
||||
@@ -89,7 +89,7 @@ func _test_dig_face_rules() -> void:
|
||||
|
||||
|
||||
func _test_reveal_advances() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:230 (揭示推进与连锁组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」每条都可单独验证 每条都可单独验证(揭示推进与连锁组)
|
||||
var c := _unrevealed_safe()
|
||||
if c == Vector2i(-1, -1):
|
||||
Kit.check("存在未揭示安全格(揭示推进前置)", false)
|
||||
@@ -103,7 +103,7 @@ func _test_reveal_advances() -> void:
|
||||
|
||||
|
||||
func _test_seal_place() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:231 (重复封印拒绝组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「调参表」本系统无自有参数 本系统无自有参数(重复封印拒绝组)
|
||||
var c := _unrevealed_safe()
|
||||
if c == Vector2i(-1, -1):
|
||||
Kit.check("存在未揭示安全格(封印前置)", false)
|
||||
@@ -116,7 +116,7 @@ func _test_seal_place() -> void:
|
||||
|
||||
|
||||
func _test_reject_out_of_catalog() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:236 (目录外拒绝组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」每条都可单独验证 每条都可单独验证(目录外拒绝组)
|
||||
var out: Array = _rules.settle_batch([{"action": "not_a_real_action", "cell": Vector2i(0, 0)}])
|
||||
var o: Dictionary = (out[0] as Dictionary) if not out.is_empty() else {}
|
||||
Kit.check("目录外意图被拒(不静默吞掉)——实际载荷 %s" % str(o).substr(0, 80),
|
||||
@@ -126,7 +126,7 @@ func _test_reject_out_of_catalog() -> void:
|
||||
# ---- V14 棋盘揭示预览只读口(架构整改——preview_reveal 与实挖揭示集同口径、零状态写入零事件)----
|
||||
|
||||
func _test_preview_reveal_readonly() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「核心规则」 (preview_reveal 只读预览口——零写入零事件组)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「核心规则」玩家对棋盘只做三件事 玩家对棋盘只做三件事(preview_reveal 只读预览口——零写入零事件组)
|
||||
var events := 0
|
||||
_rules.cell_revealed.connect(func(_evt): events += 1) # 零发射哨兵(preview 全程不触发揭示事件)
|
||||
# 形态 A:封印在场——preview(未开格) 不越封印且零状态写入
|
||||
@@ -199,7 +199,7 @@ func _unrevealed_unsealed_safe() -> Vector2i:
|
||||
|
||||
# V1 封印受理即揭示:身份当场可查(sealed_identity 与板事实逐位一致)、受理零事件零兑付
|
||||
func _test_seal_reveal_identity() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:52 封印受理那一刻身份当场可见、受理当场零兑付零事件
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「挖、封印、移动:每个动作怎么才算合法」玩家对棋盘只做三件事 玩家对棋盘只做三件事、受理当场零兑付零事件
|
||||
_ae.grant_ap(20)
|
||||
_rules.seal_range_free = true
|
||||
var safe_c := _unrevealed_unsealed_safe()
|
||||
@@ -232,7 +232,7 @@ func _test_seal_reveal_identity() -> void:
|
||||
|
||||
# V2 挖已封印格被拒:原因可辨 target_sealed、封印/揭示/AP 三态零变化
|
||||
func _test_dig_sealed_rejected() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:56 动作合法性表——挖的拒绝情形含已封印
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「挖、封印、移动:每个动作怎么才算合法」玩家对棋盘只做三件事 玩家对棋盘只做三件事
|
||||
var sealed_c := Vector2i(-1, -1)
|
||||
for c in _board.all_cells():
|
||||
if _rules.has_seal(c) and not _rules.is_revealed(c):
|
||||
@@ -253,7 +253,7 @@ func _test_dig_sealed_rejected() -> void:
|
||||
|
||||
# V3 清图口径换代:封印可完成清图(封掉最后安全格→cleared 收束);非末封印不清图
|
||||
func _test_clear_by_seal() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:139 清图=全部安全格完成,完成=挖开或封印
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「封印立得住、也带不走:封印印记的生命周期与换图重置」挖开或封印 挖开或封印,完成=挖开或封印
|
||||
_ae.grant_ap(20)
|
||||
_rules.seal_range_free = true
|
||||
# 阶段 a:封一张非末安全格 → clear_map_cleared 仍 false(封印计入完成但未清完)
|
||||
@@ -290,7 +290,7 @@ func _test_clear_by_seal() -> void:
|
||||
|
||||
# V4 批次语义序:同批「停手 + 能清图的封」提交 → 赢家=清图收束而非停手
|
||||
func _test_classify_seal_clears() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:167 最先=能清图的挖或封——防耗尽优先把清图高光结算成最差结局
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「一帧一个意图、对外只有三种事件:批次仲裁与事件面」玩家每帧只提交一个意图 玩家每帧只提交一个意图
|
||||
# 收敛未完成格到恰 1 格(封它即清图;fx_reveal 连锁不可控——逐格揭至剩 1,连锁越格则换种子重试)
|
||||
var left: Array = []
|
||||
var last_c := Vector2i(-1, -1)
|
||||
|
||||
@@ -16,7 +16,7 @@ var _gen
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
|
||||
_db = ConfigDBScript.new()
|
||||
var load_ok: bool = _db.load_tables("res://data/tables", true)
|
||||
if not load_ok:
|
||||
@@ -78,7 +78,7 @@ func _max_depth(g: Dictionary) -> int:
|
||||
# ---- V1 产出合格:三档×种子扫描,自证零错误 ----
|
||||
|
||||
func _test_output_ok() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:129 (产出约束六条+结构铁律组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「验收标准」产出约束六条 产出约束六条(产出约束六条+结构铁律组)
|
||||
var all_ok := true
|
||||
var entry_exit_ok := true
|
||||
for L in [1, 2, 3]:
|
||||
@@ -96,7 +96,7 @@ func _test_output_ok() -> void:
|
||||
# ---- V3 可复现:纯函数+counter 无关 ----
|
||||
|
||||
func _test_reproducible() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:134 (同种子同参数同图组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「图的规格:什么算一张合法的图」合法图是一张岔路发散式道路系统 合法图是一张岔路发散式道路系统(同种子同参数同图组)
|
||||
var same := true
|
||||
for L in [1, 2, 3]:
|
||||
if _sig(_graph(L, 42)) != _sig(_graph(L, 42)):
|
||||
@@ -127,7 +127,7 @@ func _test_reproducible() -> void:
|
||||
# ---- V5 岔路取舍两条 ----
|
||||
|
||||
func _test_fork_rules() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:88 (岔路取舍组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「节点类型配比:类型分布怎么掷、内容归谁」配比是生成旋钮 配比是生成旋钮(岔路取舍组)
|
||||
var next_hop_ok := true
|
||||
var comp_ok := true
|
||||
for L in [1, 2, 3]:
|
||||
@@ -203,7 +203,7 @@ func _branch_types(g: Dictionary, head_id: int, sibling_outs: Array) -> Array:
|
||||
# ---- V6 必经恰一店+归属锁定+多终点深度互异 ----
|
||||
|
||||
func _test_shop_and_attribution() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:48 (必经恰一店与归属锁定组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「图的规格:什么算一张合法的图」合法图是一张岔路发散式道路系统 合法图是一张岔路发散式道路系统(必经恰一店与归属锁定组)
|
||||
var paths_ok := true
|
||||
var lock_ok := true
|
||||
var depth_ok := true
|
||||
@@ -256,7 +256,7 @@ func _all_paths(g: Dictionary) -> Array:
|
||||
# ---- V7 战斗保底 ----
|
||||
|
||||
func _test_battle_floor() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:129 (战斗保底组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「验收标准」产出合格 产出合格(战斗保底组)
|
||||
var ok := true
|
||||
for L in [1, 2, 3]:
|
||||
for s in range(42, 52):
|
||||
@@ -268,7 +268,7 @@ func _test_battle_floor() -> void:
|
||||
# ---- V9 含岔口与出口结构 ----
|
||||
|
||||
func _test_exit_structure() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:48 (出口结构与分支互斥组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「图的规格:什么算一张合法的图」合法图是一张岔路发散式道路系统 合法图是一张岔路发散式道路系统(出口结构与分支互斥组)
|
||||
var fork_all := true
|
||||
var l1_single := true
|
||||
var big_fork_ok := true
|
||||
@@ -315,7 +315,7 @@ func _terminals_reachable(g: Dictionary, id: int) -> int:
|
||||
# ---- V9 Boss 出场门控(难度曲线与Boss——每区域恰一 Boss 终点)----
|
||||
|
||||
func _test_boss_exit_per_region() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:48 (每区域 Boss 出口组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「图的规格:什么算一张合法的图」Boss Boss(每区域 Boss 出口组)
|
||||
# 真实生成多区域图:全部终点 type=="boss"、boss 终点数==exit_count、深度=L−r(r∈[0,exit_count)
|
||||
# ——每区域恰一 boss、深度互异即分属不同区域)
|
||||
# 节点 depth 字段=入口起最长路径深(生成器校验轴);区域序号 r 的可观测形态=最深 boss(r=0)
|
||||
@@ -351,7 +351,7 @@ func _test_boss_exit_per_region() -> void:
|
||||
# ---- V10 RNG 单点(纯流面 counter 不变)----
|
||||
|
||||
func _test_rng_single_point() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:134 (RNG 单点流组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「图的规格:什么算一张合法的图」合法图是一张岔路发散式道路系统 合法图是一张岔路发散式道路系统(RNG 单点流组)
|
||||
var svc = RngScript.new()
|
||||
svc.new_adventure(4242)
|
||||
var before: int = svc.counter()
|
||||
@@ -366,7 +366,7 @@ func _test_rng_single_point() -> void:
|
||||
# ---- V1 违规夹具:各报对应错误类别 ----
|
||||
|
||||
func _test_negative_fixtures() -> void:
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:198 (无解 fail-fast 夹具组)
|
||||
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(无解 fail-fast 夹具组)
|
||||
# 夹具构造器:手写 nodes/entries/terminals
|
||||
var dup := _fx([
|
||||
{"id": 0, "type": "battle", "depth": 0, "next": [1]},
|
||||
@@ -493,7 +493,7 @@ func _has_msg(errs: Array, needle: String) -> bool:
|
||||
# ---- V6 节点图三参数表值驱动(架构整改——fork_third_way_pct/fill_rest_first_pct/width_max 入 level_gen_params)----
|
||||
|
||||
func _test_gen_params_table_driven() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:129 (参数档读表驱动组)
|
||||
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「验收标准」产出合格 产出合格(参数档读表驱动组)
|
||||
# ① 同种子真实表行产图逐位(表值驱动回归锚)
|
||||
var g1 := _graph(2, 42)
|
||||
var g2 := _graph(2, 42)
|
||||
|
||||