merge: 迭代18卡④生涯界面实装批·期一落籍+迭代18总收口(存档 v6=SAVE_FORMAT_VERSION 5→6+meta 终身计数两域 adventure_total〔开局即计〕/adventure_cleared〔三关全通才计,summary.cleared 直用〕+幂等迁移+写入单口=apply_adventure_summary 收束口+只读访问器+registry save_file v4→v6 换代补 v5 漏账;career_overlay.gd page_shell 全屏页六类九项两分组+主菜单营地与系统组入口钮+P3 甲登记序=暂停层后确认弹窗前+树序同步+零跳转零动效零写通路〔只读巡检恰 2 连接〕;断言面=冒烟+20〔迁移三件/收束双夹具/投影 11 件〕+ui_struct career 四契约+ui_click 生涯段+ui_contrast 三测点〔深墨跨壳误用返工亮墨族落闸〕;过程红灯三笔自救闭环全披露;闸=冒烟 834/0(基线 814+20)+run_all 17 套+probe_gate 全绿+ui_click 0 问题+ui_layout exit0+doc 三闸零新增〔07 26→22/生涯.md 7→6 净降〕+熵增存量维持+MC 零跑静态论证;生涯.md v0.2 期一已实装+07-⑲ 目检条目;随批交付用户实机目检总清单=四卡人闸汇总;worktree iter18-career 669c1c7/62d433c/e5cd9bd/dc2d514/eccdf78/f7fe3c9)
This commit is contained in:
commit
b98ea83d90
15 files changed
+678
-23
No files matched your search
@@ -174,6 +174,16 @@
|
||||
- **红灯信号**:(2,5) 只出一种敌种;敌人数 5 只以上(越 spawn 守卫应不可能——出现即报缺陷);首遇位 (2,4) 数量出现掷骰波动(应恒 2)。
|
||||
- **Boss 多行(第二批投放)六面读数清单维持**:Boss 名取首行显示 / Boss 遭遇骰逐行区间骰(每行各掷自己区间——卡① Q8 逐行骰换代口径)/ 半血解锁 / 独占技 / 难度带 / 首遇教学位复核——逐项过,随第二批任务书执行。
|
||||
|
||||
### ⑲ 生涯页目检(迭代 18 卡④生涯界面实装批·期一随批登记——主菜单新增一级只读页+存档 v6)
|
||||
|
||||
- **入口与开合**:主菜单「营地与系统」组出现「生涯」钮(营地钮与设置钮之间);点击开全屏页、点「返回」回主菜单(继续上局钮可见性随开合正确恢复)。
|
||||
- **页呈现六类九项**:组一·冒险战绩(冒险总局数 / 通关局数〔括注「三关全通」〕 / 各关通关次数〔一行三关,关名带层号〕 / Boss 首杀〔X/3 关〕 / Boss 总击杀);组二·资源与成长(钥石余额徽 / 属性锻造已购合计 / 道具工坊已解锁 X/6 件 / 天赋树已购概览)——数值与存档实况一致(对照:玩几局后总局数含放弃与失败、三关全通才计通关)。
|
||||
- **旧档载入**:v5 现役档(升级前存档)载入后生涯页正常显示,总局数/通关局数从 0 起计(终身计数域 v6 新增,缺省补零),钥石等既有进度原样。
|
||||
- **零跳转与局内零入口**:页内除「返回」外无任何前往他处的按钮;冒险进行中(战斗屏/关卡地图屏/暂停层)无生涯入口。
|
||||
- **对比度与零动效**:页文字亮墨族在深棕底上可读(机检 3 对已入 ui_contrast 闸);开页/关页无过渡动画。
|
||||
- **红灯信号**:计数与实玩局数对不上(收束入账重复或漏计);旧档载入报错或计数域显示异常;页内出现购买/跳转入口;入口在局内可点。
|
||||
- **结论回流**:呈现问题归生涯批后续修正(本批任务书 v1.2 在案);「通关局数」口径如与体感冲突=P1 甲裁决复核(三关全通才计 1,用户已裁);期二内容(历史回看/图鉴)缺位属分期计划非缺陷。
|
||||
|
||||
## 验收读数重测义务(履行留痕 + 现行义务)
|
||||
|
||||
**已履行**(按序换代,旧读数各随其批作废留痕不入本单):①验收读数重测批(2026-09-19——Boss 单独出列/承伤带/通关率基线全量重测,硬化翻倍期·乏力死效果期·充能期旧读数作废);②迭代 5 基线重测(统一随机流后 MC+verifier 双窗);③**数值修复批新尺重测(2026-10-01)**——模拟档位重构后全量重测,新锚 `sim-data/runsum_numfix_final_n200_20261001.jsonl`,全旧带作废只测不判([numfix 报告](../qa/numfix-newruler-readings-2026-10-01.md));④**迭代 10 奖励重构批重锚(2026-10-01)**——四代锚 77000/78000/79000/80000(改前/重构后/共享池后/掷定前置后,各 400 局),普通 L1 41.8%/L2 10.2% 带内([读数报告](../qa/m3-iter10-clear-rate-readings-2026-10-01.md));⑤**T19 真人标定局收口(2026-10-03 用户裁)**——有效局 2(1 通关 1 死于 L3 首战,[读数报告](../qa/t19-real-playtest-readings-2026-10-02.md)),用户裁定**佐证级收口不再补局**;k 预期带同日立(**正常 >0.5、预警 <0.3**),字段随 81000 重锚入库后补算终值。
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
# 生涯
|
||||
|
||||
> **一句话定位**:主菜单里与营地平级的**局外只读界面**——营地管「花」(花钥石买永久强化),生涯管「看」(看自己跨局攒下的一切:累计战绩、历史冒险、图鉴收集)。冒险进行中不给任何数据回看(2026-10-04 用户裁决 P-C7 的延续),生涯是历史数据唯一的家。
|
||||
> **状态**:范围草案(2026-10-06 迭代 17 卡④设计提纲批成文,待用户评审;评审通过后期一/二/三实装批另行立项,本文不预占排期)。
|
||||
> **状态**:期一已实装(2026-10-07 迭代 18 卡④生涯界面实装批·期一——跨局汇总页+主菜单入口+终身计数域存档 v6 落地;期二/期三另行立项,本文不预占排期)。
|
||||
> **来源**:[06-待办清单「『生涯』界面——冒险中数据回看的唯一承接处」条](../../06-待办清单.md)(2026-10-04 用户裁决 P-C7——冒险中不给数据回看,历史战报与结算明细的查看去向 = 新「生涯」界面)。
|
||||
|
||||
## 一、信息架构
|
||||
|
||||
生涯入口是主菜单一级按钮,与营地平级(2026-10-06 用户裁,备选案与淘汰依据见任务书 P1)。现行主菜单按钮组由 `build_start_overlay` 构造(`game/presentation/ui_assembler.gd:104`):「冒险」组(继续上局 :138 / 开始冒险 :144)与「营地与系统」组(营地 :150 / 设置 :152 / 退出游戏 :156)。生涯按钮与营地平级同列一级;具体组帽归属与按钮排位属布局细节,归期一实装批(本文不画布局稿)。
|
||||
生涯入口是主菜单一级按钮,与营地平级(2026-10-06 用户裁,备选案与淘汰依据见任务书 P1)。现行主菜单按钮组由 `build_start_overlay` 构造(`game/presentation/ui_assembler.gd:103`):「冒险」组(继续上局 / 开始冒险)与「营地与系统」组(营地 / 生涯〔期一已落位,营地钮与设置钮之间〕 / 设置 / 退出游戏)。具体行序排版属实装细节随批落位(本文不画布局稿)。
|
||||
|
||||
```
|
||||
主菜单(开始覆盖层)
|
||||
├─ 冒险组:继续上局 · 开始冒险
|
||||
└─ 营地与系统组:营地 · 生涯(本提纲新增) · 设置 · 退出游戏
|
||||
└─ 营地与系统组:营地 · 生涯(期一已实装) · 设置 · 退出游戏
|
||||
|
||||
调试浮窗(迭代 18 卡⑦ P2 甲——入口迁宿主:开始层零调试入口;DS_DEBUG=1 会话浮窗启动即开,
|
||||
战斗屏 HUD 与关卡地图屏各一枚「调试」角标可再开)
|
||||
@@ -78,7 +78,7 @@
|
||||
|
||||
| 期 | 内容 | 前置 | 建议窗口(候选) |
|
||||
|---|---|---|---|
|
||||
| 期一 | 跨局汇总页 + 主菜单生涯入口落位。总局数/通关局数两个终身计数域随该批做存档 schema 迁移 | 提纲评审通过。实装批前置义务 = 对齐迭代 16 UI 批后的现行基线:`FS_*` 六档字号 / `TG_*` 语义色 / `BUTTON_MIN_H=40`(`ui_kit.gd:437`)/ 色板单源 / `page_shell` 模态栈纪律(`ui_kit.gd:394`)——与卡③任务书同款红线,本文只登记、不展开 | Alpha 后最近一个 UI 窗口 |
|
||||
| 期一 | 跨局汇总页 + 主菜单生涯入口落位。总局数/通关局数两个终身计数域随该批做存档 schema 迁移——**✅ 已实装(2026-10-07 迭代 18 卡④)**:汇总段六类九项+营地与系统组生涯钮+存档 v6 两终身计数域〔v5 升 v6 幂等迁移〕;闸读数与代拍板追认单见 design/qa/iter18-career-exit-report-2026-10-07.md | 提纲评审通过。实装批前置义务 = 对齐迭代 16 UI 批后的现行基线:`FS_*` 六档字号 / `TG_*` 语义色 / `BUTTON_MIN_H=40`(`ui_kit.gd:437`)/ 色板单源 / `page_shell` 模态栈纪律(`ui_kit.gd:394`)——与卡③任务书同款红线,本文只登记、不展开 | Alpha 后最近一个 UI 窗口 |
|
||||
| 期二 | 历史冒险回看整段:N 扩容 + 用时埋点 + 旧档摘要迁移 + 逐局列表 + 单局明细(`settlement_review_overlay.gd` 复活承接)+ 营地条带处置(P6 裁案落地) | 期一。实装批开工前须向用户呈报两件:N 终值读数(20 / 50 / 维持 10 三选一)与「用时」埋点口径(计时起点、暂停是否计入——字段级细节本文不做) | 期一落地后独立批 |
|
||||
| 期三 | 图鉴承接(敌人优先,范围与顺序随 P3 甲);「见过」记账面 schema 义务随该批执行 | 期二或独立评估 | Beta 窗口候选(与教学引导同段评估——图鉴的「认得」轴与教学相关;06 教学引导节各条 2026-10-04 起已整体标 Beta 阶段) |
|
||||
|
||||
@@ -104,4 +104,5 @@ P0-P5 六点已于 2026-10-06 用户全裁(案甲 × 6,备选案与淘汰依
|
||||
|
||||
| 版本 | 日期 | 说明 |
|
||||
|---|---|---|
|
||||
| v0.2 | 2026-10-07 | 期一实装随批换代(迭代 18 卡④):状态行升「期一已实装」+主菜单组列生涯钮落位+§四期一行挂实装留痕。设计内容零改版——本文仍是三段内容的范围权威;期二/期三范围与 P6 待裁点维持原状 |
|
||||
| v0.1 | 2026-10-06 | 设计提纲首版(迭代 17 卡④设计批,纯文档):五节成文;P0-P5 已裁结论落文;新发现待裁点 P6(营地最近冒险条带去留);现状描述全部经代码级复核(F1-F10,见 design/qa/iter17-career-exit-report-2026-10-06.md)。状态 = 范围草案待评审 |
|
||||
@@ -0,0 +1,103 @@
|
||||
# 出口报告:生涯界面实装批·期一(迭代 18 卡④)
|
||||
|
||||
> 批次:纯呈现 + 存档 meta 域追加(数值零改动=MC 零跑;核心循环零触碰)。
|
||||
> worktree:`g-plan2-iter18-career`(分支 `iter18-career`,基点 = cf2aa03——含迭代 18 卡③⑤⑦全部落籍改动)。
|
||||
> 任务书:`design/research/任务书-生涯界面实装批-2026-10-07.md`(v1.2 裁点全裁——P1-P3 全甲,2026-10-07 用户令代解人闸)。
|
||||
> 本报告按「吸收即死」纪律属中间文档,寿命=迭代寿命;结论已同步写进生涯.md(v0.2)/07-体验验证清单⑲/roadmap 卡④行。
|
||||
> 本报告由执行 agent 产出,active.md 快照与台账条目以草稿形式供主控誊入(active.md 禁碰铁律)。
|
||||
|
||||
## 一、完成定义六条逐条判定(任务书 §1.2)
|
||||
|
||||
| # | 判定项 | 判定 | 依据 |
|
||||
|---|---|---|---|
|
||||
| 1 | 入口可达 | ✅ | 主菜单「营地与系统」组「生涯」钮(营地钮与设置钮之间,`ui_assembler.gd:154`);ui_struct 入口点击链(合成点击真路径 pressed.emit → `_open_career`)+ui_click 行为级复验全绿;关闭回返开始层断言(ui_struct/ui_click 双落) |
|
||||
| 2 | 汇总页数值逐项一致 | ✅ | 冒烟 `_career_overlay_projection` 9 断言——六类九项逐行 == SaveManager 计数访问器/MetaProgression 访问器读数(总局数/通关局数/各关通关次数/Boss 首杀总杀/钥石徽/锻造合计/工坊解锁计数/天赋树聚合);投影拼装与 `main._career_data` 同构(同访问器族) |
|
||||
| 3 | 终身计数域存档 v6 三断言 | ✅ | 升档幂等(v5 样档升 v6 写盘再载零漂移)/新档缺省(两域全零白板可玩)/收束自增恰一(apply 直呼+settle_adventure 真实收束链各一,通关局与中止局双夹具)——冒烟 ⑬⑭ 段 |
|
||||
| 4 | 生涯页零写通路 | ✅ | ui_struct ⑩只读巡检:子树游戏语义信号连接白名单外零连接、恰 2(返回钮 pressed+closed 外发——17 卡③形制);⑬零跳转契约:页内除「返回」外七导航词零钮;ui_click 局内零生涯入口件断言 |
|
||||
| 5 | 结构探针入轻闸 | ✅ | ui_struct career 屏 `_audit` 全族(互压/等宽等高/出屏/零尺寸)+⑪零动效+⑫登记序树序契约(P3 甲两序失守即红)——probe_gate 默认段绿 |
|
||||
| 6 | 旧档兼容 | ✅ | 冒烟 v5 现役档形态(计数域两键不存在)升 v6 载入成功+生涯页正常显示缺省零值+既有钥石原样(投影段末两断言);v5 档带既有值迁移只增不改(⑬首断言) |
|
||||
|
||||
## 二、任务卡完成态(T0-T5)
|
||||
|
||||
| 卡 | 状态 | 提交/落点 |
|
||||
|---|---|---|
|
||||
| T0 | ✅ | worktree 基线复跑=冒烟 814/0(与现行 master 基线同数);§2 现状逐条按卡⑦后新态实查复核(F8 装配点=:103-199/F10 登记册=:349 现役十一层/version==5 旧断言现行行号=:4751/:4849);生涯.md v0.1 对读——期一范围与任务书 §3 零出入(S1 未触发),开工 |
|
||||
| T1 | ✅ | 669c1c7——存档 v6:SAVE_FORMAT_VERSION 5→6+meta 两新域 adventure_total/adventure_cleared+_migrate_v5_v6(沿现役迁移链,_normalize 补缺省=幂等)+只读访问器两件+写入单口=apply_adventure_summary 收束口+三处同步(smoke version==6 两处/registry save_file 条目 v4→v6 换代〔v5 批漏账补齐〕/save_manager:39 版本史注释;顺手校正迁移链陈旧注释 v1→v3→v1→v6)+断言族 7 件——冒烟 821/0 |
|
||||
| T2 | ✅ | 62d433c——收束链入账断言(真实收束挂点 MetaProgression.settle_adventure 全链恰一;通关局/中止局双夹具;接线零新增代码——apply_adventure_summary 即三结局唯一收束口)——冒烟 823/0 |
|
||||
| T3 | ✅ | e5cd9bd——career_overlay.gd 新视图(page_shell 暖亮全屏页·商店同壳+汇总段六类九项两分组)+主菜单入口钮+组合根接线(暂停层后 addChild〔P3 甲树序同步〕+登记册插位+开合仿设置面先例+_career_data 快照投影)+冒烟投影断言 11 件——冒烟 834/0+.uid 边车与 class_name 编辑器扫描随批 |
|
||||
| T4 | ✅ | dc2d514——ui_struct 生涯屏四契约+ui_click 生涯段+ui_contrast 三测点随批入表;随批返工=对比度亮墨族换装(T3 初版行名/行值用深墨族压深棕页底 ~1.3:1 违 §7.2,全换 WARM/CANDLE/INK_L_GOLD 既有 token 零新色值,测点三对落闸防复发)——probe_gate 全绿+click 0 问题+layout exit 0 |
|
||||
| T5 | ✅ | 本报告+生涯.md v0.2+07-⑲ 目检条目+roadmap 卡④状态列;重闸读数见 §三 |
|
||||
|
||||
## 三、闸读数(T0 基线 → 批末)
|
||||
|
||||
| 闸 | 基线(T0) | 批末 | 判 |
|
||||
|---|---|---|---|
|
||||
| 冒烟(run_smoke 全量) | 814/0 | **834/0**(+20=T1 七件+T2 两件+T3 投影十一件) | ✅ |
|
||||
| run_all(game/tests) | 17 套全绿 | 17 套全绿(exit 0) | ✅ |
|
||||
| ui_input_probe | 十七断言 | 十七断言 PASS(本批零改动零回归) | ✅ |
|
||||
| ui_struct_probe | 全屏零红 | 全屏零红(+career 结构族+四契约) | ✅ |
|
||||
| ui_contrast_probe | 12 对测点 | **15 对测点 PASS**(+生涯页行名/行值/组帽三对,≥4.5:1) | ✅ |
|
||||
| ui_click_probe | done=true 问题=0 | done=true(budget=16260)问题=0(+生涯段) | ✅ |
|
||||
| ui_layout_probe | exit 0 | exit 0(观察型,无断言判语) | ✅ |
|
||||
| doc 三闸 | 零新增口径 | doc_link_audit 命中四处均在未触碰文件(06 待办清单×2/奇物.md×2=存量);doc_term_audit 命中存量(03/06,本批文件零命中);gdd_lint 默认域 06/07 存量红维持,本批触碰文件违例计数净降(07: 26→22/生涯.md: 7→6,零新增) | ✅(零新增口径) |
|
||||
| 熵增闸 | 存量红 | 存量红维持(design/diagrams 越界——17 卡③报告已移交披露,主区同态,本批零触碰) | 移交披露 |
|
||||
| MC | — | 零跑(论证见 §四) | ✅ |
|
||||
|
||||
## 四、MC 零跑静态论证(任务书 §6/§5-T5)
|
||||
|
||||
1. **改动面枚举**:本批全部改动=①存档 meta 域新增两计数键+读档迁移(_normalize 补缺省);②收束口自增两行(apply_adventure_summary 头部,纯计数副效应,不触碰钥石/通关次数/Boss 入账既有算式);③新 UI 视图+装配+组合根开合接线(纯呈现);④探针/冒烟断言面。
|
||||
2. **零玩法数值触碰**:data/tables 零 diff、ConfigDB/RngService/战斗/扫雷/奖励核心零 diff——MC 的测量对象(通关率/难度带/奖励期望)的输入侧无任何变化。
|
||||
3. **对局行为等价论证**:冒险内行为路径(挖雷/战斗/奖励/商店/天赋)与本批改动零交集;唯一行为差异=收束时存档多记两个计数键(不参与任何玩法判定——访问器消费面仅生涯页呈现),对局内随机流(RngService 单盐单计数器)消费序列零变化,同种子对拍预期逐位一致(未跑,静态论证;如需实证归数值批统一 MC 窗口)。
|
||||
4. **两入口铁规**:本批无数值验证场景,任务书 §6 预设 MC 零跑;未发生任何「需要跑批才能继续」情形(S 停机点零触发)。
|
||||
|
||||
## 五、代拍板追认单(白名单内决断,commit 留痕,实机目检可推翻)
|
||||
|
||||
| # | 项 | 决断 | 出处 |
|
||||
|---|---|---|---|
|
||||
| 1 | 字段命名 | `adventure_total`(总局数)/`adventure_cleared`(通关局数)——任务书 provisional 白名单命名原样采用 | T1 669c1c7 |
|
||||
| 2 | 总局数口径 | 开局即计:三结局(通关/失败/放弃)同经收束恰计一次——白名单预裁「含放弃与失败的所有开局」 | T1 669c1c7 |
|
||||
| 3 | 九项行序与分组 | 组一·冒险战绩=总局数→通关局数→各关通关次数→Boss 首杀→Boss 总击杀;组二·资源与成长=钥石余额→属性锻造→道具工坊→天赋树(「六类九项」=各类逐项一行;Boss 首杀/总杀拆两行) | T3 e5cd9bd |
|
||||
| 4 | 页内分组标题 | 「冒险战绩」「资源与成长」 | T3 e5cd9bd |
|
||||
| 5 | 各关通关次数行形态 | 一行三关「关名 ×N · 关名 ×N · 关名 ×N」(关名取 level 表 display_name 带层号) | T3 e5cd9bd |
|
||||
| 6 | 入口钮形制与文案 | 「生涯」普通钮(同设置行形制,不加图标——既有图标集无生涯语义贴切件,宁缺勿错)+tooltip;排位=营地钮后、设置钮前 | T3 e5cd9bd |
|
||||
| 7 | 页标题与顶条 | 「生 涯」(FS_TITLE·WARM,商店顶条同款);关闭钮=「返回」紧凑 90 宽(设置/暂停面先例形制) | T3 e5cd9bd |
|
||||
| 8 | 页底色与文字墨 | page_shell 暖亮底(商店同壳主菜单页族);文字=亮墨族(WARM/WARM_SOFT/CANDLE/INK_L_GOLD——深墨族对深棕底 1.3:1 违 §7.2 的返工,见 §六-3) | T4 dc2d514 |
|
||||
| 9 | 通关局数行括注 | 「N 局(三关全通)」——口径自解释(P1 甲字面口径的页内显形) | T3 e5cd9bd |
|
||||
| 10 | 天赋树空态句 | 「尚未购买任何节点」(暂停层同构但去营地指引括注——零跳转 P4 甲口径收敛) | T3 e5cd9bd |
|
||||
| 11 | 断言编号与 case 命名 | ui_struct 契约 ⑩只读⑪零动效⑫登记树序⑬零跳转;ui_click 生涯段;冒烟 `_career_overlay_projection`/⑬⑭段 | T4 dc2d514 |
|
||||
|
||||
## 六、过程红灯披露(全部自救闭环,S 停机点零触发)
|
||||
|
||||
1. **冒烟 Parse Error×2(T3 落码当日)**:`var li := i + 1` 在无类型 `db.level_count()` 循环上触发 Variant 推断失败(smoke_all.gd:4367 首发同日修)+一次编辑误合并行尾(4420)——均显式 `int` 类型化/还原换行后一轮全绿,产品代码同型写法同步修正(main.gd `_career_data`)。
|
||||
2. **class_name 全局缓存未注册风险(规范 4.5 预防性履行)**:新增 `CareerOverlay` 后跑一次 `--headless --editor --quit` 编辑器扫描刷新全局类缓存+生成 .uid 边车(随 T3 提交),探针载入 main.tscn 前置完成——零红灯发生。
|
||||
3. **对比度违例自查返工(T4,机制卡点非停机点)**:T3 初版生涯页行名/行值沿用暂停层深墨族 token(INK_LABEL/INK_TITLE),落闸自查发现其对 page_shell 深棕页底仅 ~1.3:1(暂停层系石板亮面板承载深墨、生涯页系深底全屏页——两壳底色明暗相反,照抄即违 art-bible §7.2)。返工=全页换亮墨族既有 token(零新色值)+ui_contrast 落三测点防复发。教训=「复用 UiKit 公共件」须连同其设计底色前提一起复用,跨壳搬运 token 先算对比度。
|
||||
|
||||
## 七、实机目检清单(人闸——用户执行;⑲ 条目已随批登记 07)
|
||||
|
||||
| # | 检查项 | 操作 | 合格判据 |
|
||||
|---|---|---|---|
|
||||
| A | 入口可达 | 主菜单「营地与系统」组查看并点击「生涯」 | 钮在营地与设置之间;点击开全屏页;无报错 |
|
||||
| B | 页呈现六类九项 | 开页逐行看 | 两组九行齐(组一·冒险战绩五行/组二·资源与成长四行);文字清晰可读;开/关无过渡动画 |
|
||||
| C | 数值与存档实况一致 | 对照实玩:完成一局三关全通+中途放弃一局后开页 | 总局数=2(放弃也计);通关局数=1;各关次数与实玩一致;Boss 首杀/总杀/钥石/锻造/工坊/天赋树与营地读数一致 |
|
||||
| D | 旧档载入 | 用升级前 v5 存档启动(或改版本号模拟)开页 | 正常显示无报错;总局数/通关局数从 0 起计;钥石等既有进度原样 |
|
||||
| E | 关闭回返 | 页内点「返回」 | 回主菜单;「继续上局」钮可见性正确恢复;再开营地/设置不受影响 |
|
||||
| F | 零跳转与局内零入口 | 页内找导航钮;进对局找生涯入口 | 页内除「返回」外无任何前往钮;战斗屏/地图屏/暂停层无生涯入口 |
|
||||
| G | 与他层关系(抽查) | DS_DEBUG 会话开浮窗后开生涯页、关闭生涯页 | 生涯开着时浮窗暂隐、关闭生涯后浮窗恢复(ModalStack 遮挡语义);生涯开着时棋盘输入锁定 |
|
||||
| H | 存档往返 | 开页后退出游戏重进 | 计数读数不丢(v6 写盘读回);高版本拒读行为不受影响 |
|
||||
|
||||
## 八、台账条目草稿(供主控誊入 active.md,编号请主控按序分配)
|
||||
|
||||
> **迭代 18 卡④生涯界面实装批·期一落地(worktree iter18-career,基点 cf2aa03,批内提交 669c1c7/62d433c/e5cd9bd/dc2d514/T5 收口提交)**:主菜单「营地与系统」组新增「生涯」一级入口(与营地平级)+page_shell 暖亮全屏只读页(汇总段六类九项两组逐行:总局数/通关局数〔三关全通才计,P1 甲〕/各关通关次数/Boss 首杀/总杀/钥石/锻造/工坊/天赋树)+存档 v6(meta 两新域 adventure_total〔开局即计含放弃与失败〕/adventure_cleared,v5 升 v6 幂等迁移 _normalize 补零,写入单口=apply_adventure_summary 收束口;registry save_file 条目 v4→v6 换代补 v5 漏账);生涯层登记序=营地同档(暂停层后确认弹窗前)+树序同步(P3 甲);页内零跳转+局内零入口(P4 甲);期二/期三内容零触碰。闸=冒烟 834/0(基线 814+20)+run_all 17 套+probe_gate 全绿(ui_input 十七断言/ui_struct career 四契约/ui_contrast 15 对)+ui_click 0 问题+ui_layout exit 0+doc 三闸/熵增闸零新增(触碰文件违例计数净降);MC 零跑静态论证四点随出口报告;过程红灯三笔自救闭环全披露(含对比度深墨照抄暂停层误用返工=跨壳搬 token 先算对比度)。实机人闸挂账待用户(07-⑲ 八节目检清单+代拍板追认单十一项随出口报告 design/qa/iter18-career-exit-report-2026-10-07.md)。
|
||||
|
||||
## 九、会话快照草稿(供主控誊入 active.md「当前状态快照」节)
|
||||
|
||||
> 迭代 18 卡④(生涯界面期一)已在 worktree iter18-career 全批落地待合并:主菜单生涯入口+跨局汇总只读页(六类九项)+终身计数域存档 v6 全数上闸,重闸全绿(冒烟 834/0+run_all 17 套+四探针+ui_contrast 15 对+doc/熵增零新增),MC 零跑(静态论证在报告 §四),实机目检人闸待用户(07-⑲)。下一步=主控合并落回 master+用户实机目检;期二(历史回看+N 扩容+用时埋点+P6 营地条带处置)/期三(图鉴)另行立项待用户点名。
|
||||
|
||||
## 十、存量移交(均非本批产生)
|
||||
|
||||
1. 熵增闸红:`design/diagrams` 子目录越界——17 卡③报告 §五-1 已披露移交,本批维持。
|
||||
2. gdd_lint 存量红:06/07 两文件(默认域)——本批触碰后违例计数净降(26→22),零新增。
|
||||
3. doc_link_audit 存量死链四处(06 待办清单×2/奇物.md×2)——未触碰文件,维持。
|
||||
4. registry save_file 条目 v5 漏账(v4→v5 批未同步)——**本批已顺手补齐**(T1 随批 v4→v6 一步到位),非移交项,特此记一笔销账。
|
||||
|
||||
终态 = worktree 内全部提交,**未合并、未 push**(合并落回 master 由用户/编排会话执行)。
|
||||
@@ -0,0 +1,50 @@
|
||||
# 迭代 18 四卡实机目检总清单(2026-10-07 交付)
|
||||
|
||||
迭代 18 四卡已全部落籍 master:卡③ 提案批(merge de067ae)/卡⑤ 混编投放批(merge 0dbe3c3)/卡⑦ 种子随机化批(merge b91b973)/卡④ 生涯界面批(本批)。目检归用户逐项过;每节标注详细判据所在的出口报告。目检不阻塞后续开发,但发现的问题按正常缺陷修复流程登记。
|
||||
|
||||
## 一、卡③ 武器锻造系统设计提案(纯文档批——无实机目检)
|
||||
|
||||
人闸=**提案盘问裁决**(异步,不阻塞其余卡):
|
||||
|
||||
- 提案正文:`design/research/提案-武器锻造系统-2026-10-07.md`(八节框架)。
|
||||
- 17 个设计裁点的全备选案一览表:`design/qa/iter18-forge-exit-report-2026-10-07.md` §四(推荐主线=丙案「当前武器单选+每件武器独立等级与特效」等,逐点呈裁)。
|
||||
|
||||
## 二、卡⑤ 混编遭遇首批投放批
|
||||
|
||||
目检四项(详细判据:`design/qa/iter18-mixenc-exit-report-2026-10-07.md` §7):
|
||||
|
||||
1. 第 2 关深度 5 的普通节点触发战斗:同场出现两种敌人——熊地精重击手 + 巨蜘蛛巢群(巨蜘蛛 2-3 只)。
|
||||
2. 同场敌人出场顺序与表序一致:重击手在前、巨蜘蛛巢群在后。
|
||||
3. 同场敌人实例总数不超过 4。
|
||||
4. 首遇教学位回归不变:巨蜘蛛首遇位(第 2 关节点 4)固定 2 只不加骰;钩爪恐魔(第 3 关节点 0/1)固定数量。
|
||||
|
||||
## 三、卡⑦ 种子随机化与调试浮窗升级批
|
||||
|
||||
前置:以 `DS_DEBUG=1` 启动游戏(详细判据:`design/qa/iter18-seed-exit-report-2026-10-07.md` A-I 九节):
|
||||
|
||||
1. 应用启动后调试浮窗默认打开(手动可关、角标可再开)。
|
||||
2. 主菜单连续开多次新冒险(非首局、种子框留空):各局种子互不相同(当局数据区块可查本局种子);首次冒险(新档第一局)固定种子 42。
|
||||
3. 调试种子框输入合法整数时全场景按输入值生效(含首局)。
|
||||
4. 对局中可从战斗屏 HUD 角标与关卡地图屏角标开合浮窗;其他层打开时浮窗暂隐、关闭后自动恢复。
|
||||
5. 当局数据区块六项(种子/关卡/节点/HP/GP/钥石)与实际局况逐项一致。
|
||||
6. 从浮窗发起调试对局正常;对局进行中批量模拟与调试对局两按钮禁用。
|
||||
7. 浮窗开着时棋盘输入不被锁死、暂停角标不置灰;开新冒险/续玩路径正常(浮窗自动收起)。
|
||||
8. 断点续玩逐位正常(存档种子回填)。
|
||||
- 随附:代拍板追认单六项(区块标题/占位提示词/角标落点等)见出口报告追认单节。
|
||||
|
||||
## 四、卡④ 生涯界面实装批·期一
|
||||
|
||||
目检六项(详细判据:`design/qa/iter18-career-exit-report-2026-10-07.md` A-H 八节):
|
||||
|
||||
1. 主菜单「营地与系统」组出现「生涯」钮(营地钮之后),点击开生涯全屏页、关闭返回主菜单。
|
||||
2. 汇总页六类九项数值与存档实况逐项一致:总局数/通关局数/各关通关次数/Boss 首杀/Boss 总击杀/钥石余额/属性锻造合计/道具工坊解锁计数/天赋树已购聚合。
|
||||
3. 旧档(v5 格式)载入后生涯页正常显示(终身计数缺省补零),无损坏。
|
||||
4. 生涯页开着=游戏输入锁定(与其他层同语义);与设置/确认弹窗等他层开合关系正常。
|
||||
5. 页内零「前往他处」跳转入口(只有返回);零动效。
|
||||
6. 局内(战斗屏/地图屏)无生涯入口;存档往返(退出重进)后计数不漂移。
|
||||
- 随附:代拍板追认单十一项(字段命名/文案/行序排版/分组标题等)见出口报告追认单节。
|
||||
|
||||
## 挂账提醒(非目检项)
|
||||
|
||||
- 卡⑤ 难度带 MC 取证读数:顺延 Alpha 收官 M4 数值批统一执行,届时另行报批(07-⑱ 在册)。
|
||||
- 卡⑦ 三裁决(首次固定/显式指定/种子不进玩家 UI)2026-10-07 已裁,本批即其执行。
|
||||
@@ -69,8 +69,8 @@ entities:
|
||||
attributes:
|
||||
path: user://save.json(单档 MVP——多存档槽位 P2 保留)
|
||||
format: JSON 单档(人可读可调试;字典键一律 String)
|
||||
version: SAVE_FORMAT_VERSION=4(registry schema_version 同源;v4=同调批扩域 2026-10-03 迭代 11 第①批——meta 三新域 boss_kill_count/attunement_equipped/attune_refresh_level + 断点附随件 attunement_charges,旧档缺键由 _normalize 按默认补齐;v3=断点附随件扩列+摘要 keystone_drops 2026-10-01 迭代 10;v2=断点域出生 2026-09-29 迭代 8 卡①;生产迁移链 v1→v4 链式补空;高版本拒读 + 禁写盘 + 内存默认新档运行;低版本读档时链式迁移 register_migration,任一步失败按损坏兜底)
|
||||
domains: meta 域九件——keystone_balance(元进度)/ forge_levels 三档(元进度)/ item_unlocks(元进度)/ level_clear_counts(元进度)/ boss_first_kill(元进度)/ boss_kill_count(秘宝——同调位里程碑计数源,Boss 恒唯一终点故收束入账=levels_cleared)/ attunement_equipped(秘宝——装配关系有序数组,局外进度事实非局内道具库存,装配序即呈现序)/ attune_refresh_level(秘宝——Y 刷新升级购买等级)/ recent_summaries cap 10(冒险结构,元素附 boss_drops 副本);+ breakpoint 域(断点快照:七字段拍板面+附随件〔主种子/取数计数器/钥石累计/已到节点序/道具库存/bonus_* 附随件/attunement_charges 充能余量——迭代 11 第①批 T6〕,空字典=无断点合法态,三结局清除)
|
||||
version: SAVE_FORMAT_VERSION=6(registry schema_version 同源;v6=生涯终身计数域 2026-10-07 迭代 18 卡④——meta 两新域 adventure_total〔冒险总局数,开局即计含放弃与失败〕/adventure_cleared〔通关局数,三关全通才计 1——判定字段 summary.cleared〕,旧档缺键由 _normalize 按默认补零,收束自增唯一入账=apply_adventure_summary;v5=天赋树域 2026-10-04 迭代 12 T9——meta 三新域 tree_nodes/fork_sides/migration_note;v4=同调批扩域 2026-10-03 迭代 11 第①批——meta 三新域 boss_kill_count/attunement_equipped/attune_refresh_level + 断点附随件 attunement_charges,旧档缺键由 _normalize 按默认补齐;v3=断点附随件扩列+摘要 keystone_drops 2026-10-01 迭代 10;v2=断点域出生 2026-09-29 迭代 8 卡①;生产迁移链 v1→v6 链式补空;高版本拒读 + 禁写盘 + 内存默认新档运行;低版本读档时链式迁移 register_migration,任一步失败按损坏兜底)
|
||||
domains: meta 域十一件——keystone_balance(元进度)/ forge_levels 三档(元进度)/ item_unlocks(元进度)/ level_clear_counts(元进度)/ boss_first_kill(元进度)/ boss_kill_count(秘宝——同调位里程碑计数源,Boss 恒唯一终点故收束入账=levels_cleared)/ attunement_equipped(秘宝——装配关系有序数组,局外进度事实非局内道具库存,装配序即呈现序)/ attune_refresh_level(秘宝——Y 刷新升级购买等级)/ tree_nodes+fork_sides(天赋树——迭代 12 T9 树域)/ adventure_total+adventure_cleared(生涯——终身计数域,迭代 18 卡④,写入唯一经 apply_adventure_summary)/ recent_summaries cap 10(冒险结构,元素附 boss_drops 副本);+ breakpoint 域(断点快照:七字段拍板面+附随件〔主种子/取数计数器/钥石累计/已到节点序/道具库存/bonus_* 附随件/attunement_charges 充能余量——迭代 11 第①批 T6〕,空字典=无断点合法态,三结局清除)
|
||||
write_timing: 启动读盘;正式冒险收束(adventure_finished → apply_adventure_summary)写盘;营地每笔钥石变更后即时写(元进度实现批接线);冒险选路停点断点快照写盘 + 三结局清断点写盘(迭代 8 卡①);调试两层与单关测试路径(LevelRunner.start_level,仅 QA 工具)不写档
|
||||
atomic_write: tmp + rename 原子写(写一半断电不留烂档——钥石不丢判据承载)
|
||||
corruption_policy: 坏档改名 <path>.corrupt.bak(已存在覆盖)+ 默认新档继续 + 警告留痕(不静默丢档不 crash)
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
# breakpoint.attunement_charges(主动件充能余量)——每冒险重置语义的断点瞬态附随件,内容装配归
|
||||
# AdventureRunner(随 T6 接线入断点),本类照单承载;契约 2 域界注记同断点域豁免先例
|
||||
# recent_summaries(冒险摘要五件事副本)—— 内容 owner = 冒险结构.md(摘要五件事口径)
|
||||
# adventure_total / adventure_cleared(生涯终身计数域)—— 内容 owner = 生涯.md(跨局汇总页
|
||||
# 数据源:总局数开局即计〔三结局同经收束恰计一次,含放弃与失败〕/通关局数三关全通才计 1
|
||||
# ——判定字段 summary.cleared;写入唯一经 apply_adventure_summary,迭代 18 卡④)
|
||||
# breakpoint(冒险断点快照——停点粒度续玩域)—— 内容 owner = 冒险结构.md(七字段拍板面
|
||||
# +恢复必需附随件:主种子/取数计数器/钥石累计/已到节点序/道具库存);契约 2 域界反面清单
|
||||
# 只约束 meta 永久进度域——断点域=冒险进行中瞬态快照,生命/GP/道具库存按拍板面入域
|
||||
@@ -36,7 +39,7 @@
|
||||
class_name SaveManager
|
||||
extends RefCounted
|
||||
|
||||
const SAVE_FORMAT_VERSION := 5 # registry schema_version:v5=天赋树域(迭代 12 T9——meta 三新域 tree_nodes〔node_id→已购等级〕/fork_sides〔fork_group→a|b〕/migration_note〔三体系迁移补偿注记〕——M-4 迭代 12 批次二;任务书「v3→v4」系同调批未落时行文,v4 已被同调批占用顺延 v5 披露);v4=同调批扩域(meta 三新域 boss_kill_count/attunement_equipped/attune_refresh_level——M-4 迭代 11 第①批 T2;断点充能余量随 T6 接线,旧档缺键 = 合法空态);v3=断点附随件扩列+摘要 keystone_drops(M-3 迭代 10 奖励重构);v2=断点域出生(M-3 迭代 8 卡①);v1=首版;高版本拒读 owner=存档序列化
|
||||
const SAVE_FORMAT_VERSION := 6 # registry schema_version:v6=生涯终身计数域(迭代 18 卡④——meta 两新域 adventure_total〔冒险总局数,开局即计含放弃与失败〕/adventure_cleared〔通关局数,三关全通才计 1——判定字段 summary.cleared〕,旧档缺键由 _normalize 按默认补零,收束自增唯一入账=apply_adventure_summary);v5=天赋树域(迭代 12 T9——meta 三新域 tree_nodes〔node_id→已购等级〕/fork_sides〔fork_group→a|b〕/migration_note〔三体系迁移补偿注记〕——M-4 迭代 12 批次二;任务书「v3→v4」系同调批未落时行文,v4 已被同调批占用顺延 v5 披露);v4=同调批扩域(meta 三新域 boss_kill_count/attunement_equipped/attune_refresh_level——M-4 迭代 11 第①批 T2;断点充能余量随 T6 接线,旧档缺键 = 合法空态);v3=断点附随件扩列+摘要 keystone_drops(M-3 迭代 10 奖励重构);v2=断点域出生(M-3 迭代 8 卡①);v1=首版;高版本拒读 owner=存档序列化
|
||||
const SUMMARY_CAP := 10 # 最近冒险摘要保留条数(最新在前)
|
||||
|
||||
const FORGE_ATTRS := ["max_hp", "atk", "armor_class"] # 属性锻造三档合法键(元进度.md 属性锻造柜台)
|
||||
@@ -44,7 +47,7 @@ const FORGE_ATTRS := ["max_hp", "atk", "armor_class"] # 属性锻造三档合
|
||||
var _path: String # 存档文件路径(默认 user://save.json;冒烟注入隔离路径)
|
||||
var _read_only := false # 高版本拒读置位——write_to_disk 一律拒绝(契约 4 禁写)
|
||||
var _data: Dictionary[String, Variant] = {} # 内存数据模型(_init 即内置默认;load 后为档案内容)
|
||||
var _migrations: Dictionary[int, Callable] = {} # from_version → Callable(data)->data(升一版;v1→v3 生产迁移链现行——_init 自注册)
|
||||
var _migrations: Dictionary[int, Callable] = {} # from_version → Callable(data)->data(升一版;v1→v6 生产迁移链现行——_init 自注册)
|
||||
|
||||
|
||||
func _init(path: String = "user://save.json") -> void:
|
||||
@@ -55,6 +58,7 @@ func _init(path: String = "user://save.json") -> void:
|
||||
register_migration(2, _migrate_v2_v3)
|
||||
register_migration(3, _migrate_v3_v4)
|
||||
register_migration(4, _migrate_v4_v5)
|
||||
register_migration(5, _migrate_v5_v6)
|
||||
|
||||
|
||||
# v1→v2:断点域出生(旧档无断点 = 合法空态——「继续上局」隐藏,非损坏非债务)
|
||||
@@ -97,6 +101,14 @@ func _migrate_v4_v5(data: Dictionary) -> Dictionary:
|
||||
return data
|
||||
|
||||
|
||||
# v5→v6:生涯终身计数域(迭代 18 卡④——meta 两新域 adventure_total/adventure_cleared,旧档缺键
|
||||
# 由 _normalize 按默认补零,无结构迁移体;版本号推进仅为 schema_version 对齐——v3→v4 先例。
|
||||
# 幂等性:重复迁移只覆写 version,既有值零改动;加载后 _normalize 补齐缺省——旧档可载可玩)
|
||||
func _migrate_v5_v6(data: Dictionary) -> Dictionary:
|
||||
data["version"] = SAVE_FORMAT_VERSION
|
||||
return data
|
||||
|
||||
|
||||
# ---- 默认数据模型(新档合法态——全零;白板存档 = 完整可玩〔元进度 单局循环零依赖〕)----
|
||||
|
||||
func _default_data() -> Dictionary[String, Variant]:
|
||||
@@ -115,6 +127,8 @@ func _default_data() -> Dictionary[String, Variant]:
|
||||
"fork_sides": {}, # A/B 激活侧(fork_group→"a"|"b"——营地免费切换承载)
|
||||
"recent_summaries": [],
|
||||
"first_adventure_done": false,
|
||||
"adventure_total": 0, # 生涯终身计数·冒险总局数(迭代 18 卡④——开局即计含放弃与失败,收束唯一入账)
|
||||
"adventure_cleared": 0, # 生涯终身计数·通关局数(三关全通才计 1——判定字段 summary.cleared)
|
||||
},
|
||||
"breakpoint": {}, # 冒险断点快照(空 = 无断点合法态——「继续上局」隐藏;迭代 8 卡①)
|
||||
}
|
||||
@@ -191,7 +205,7 @@ func write_to_disk() -> bool:
|
||||
|
||||
|
||||
# 迁移注册口:from_version → from_version+1 的升级函数(读档时链式调用)。fn 契约:
|
||||
# Dictionary → Dictionary,须写回 version = from_version + 1。生产迁移链现行(v1→v3,_init 自注册),
|
||||
# Dictionary → Dictionary,须写回 version = from_version + 1。生产迁移链现行(v1→v6,_init 自注册),
|
||||
# 冒烟经本口验证链式升级。
|
||||
func register_migration(from_version: int, fn: Callable) -> void:
|
||||
_migrations[from_version] = fn
|
||||
@@ -251,6 +265,20 @@ func boss_kill_count() -> int:
|
||||
return int(_data["meta"].get("boss_kill_count", 0))
|
||||
|
||||
|
||||
# ---- 生涯终身计数域(迭代 18 卡④——跨局汇总页数据源;只读面经访问器,
|
||||
# 写入唯一经 apply_adventure_summary 收束口,禁第二写入点)----
|
||||
|
||||
# 冒险总局数(口径=开局即计:三结局 completed/failed/abandoned 同经收束恰计一次,含放弃与失败)
|
||||
func adventure_total() -> int:
|
||||
return int(_data["meta"].get("adventure_total", 0))
|
||||
|
||||
|
||||
# 通关局数(口径=三关全通才计 1——判定字段 summary.cleared,adventure_runner「completed」
|
||||
# 唯一出口=末关通关)
|
||||
func adventure_cleared() -> int:
|
||||
return int(_data["meta"].get("adventure_cleared", 0))
|
||||
|
||||
|
||||
# ---- 天赋树域(迭代 12 T9——MetaProgression 树段读写面)----
|
||||
|
||||
func tree_nodes() -> Dictionary:
|
||||
@@ -321,8 +349,13 @@ func recent_summaries() -> Array:
|
||||
# 钥石入账(summary.keystone_total——迭代 10 起逐杀掉落已在冒险内计入,boss_drops 参数降级为
|
||||
# 摘要归档副本不重复入账)+ 逐通关关次 clear_count +1 与 Boss 首杀标记 + Boss 击杀总数累计
|
||||
# (迭代 11 第①批 T2——同调位里程碑计数源)+ 摘要头部插入(cap 10,最新在前,元素附
|
||||
# keystone_drops 副本——复盘可归因)。
|
||||
# keystone_drops 副本——复盘可归因)+ 生涯终身计数自增(迭代 18 卡④——总局数开局即计:
|
||||
# 三结局同经本口恰计一次;通关局数按 summary.cleared 判定三关全通才计 1。终身计数写入
|
||||
# 单口=本函数,禁第二写入点)。
|
||||
func apply_adventure_summary(summary: Dictionary, boss_drops: Array = []) -> void:
|
||||
_data["meta"]["adventure_total"] = adventure_total() + 1
|
||||
if bool(summary.get("cleared", false)):
|
||||
_data["meta"]["adventure_cleared"] = adventure_cleared() + 1
|
||||
add_keystone(int(summary.get("keystone_total", 0)))
|
||||
var cleared := int(summary.get("levels_cleared", 0))
|
||||
for li in range(1, cleared + 1):
|
||||
|
||||
@@ -120,6 +120,7 @@ var camp_overlay: CampOverlay # 营地覆盖层(元进度实现批
|
||||
var settings_store # 系统级设置独立存储(迭代 8 卡④——音量/全屏/减动效)
|
||||
var settings_overlay: SettingsOverlay # 设置覆盖层(迭代 8 卡④——最小设置面)
|
||||
var pause_overlay: PauseOverlay # 局内暂停层·只读(迭代 17 卡③——钥石余额+营地三柜台进度查看;登记设置层同档)
|
||||
var career_overlay: CareerOverlay # 生涯页·只读全屏页(迭代 18 卡④——跨局汇总六类九项;登记营地同档〔设置层旁、确认弹窗之前〕)
|
||||
var debug_overlay: DebugOverlay # 调试浮窗(迭代 14.5 调试整合批——种子/数值调整/批量模拟/两层调试入口收一)
|
||||
|
||||
var _modals = null # 模态层级状态机(modal_stack.gd——缺陷⑤纪律载体)
|
||||
@@ -248,7 +249,7 @@ func _build_ui() -> void:
|
||||
logger.ap_per_round = int(db.action_economy.ap_per_round)
|
||||
|
||||
# 模态覆盖层(登记序 = 树序 = z 遮挡序:图例 < 明细回看 < 节点 < 关卡画面 < 三选一 < 终局
|
||||
# < 商店 < 营地 < 设置 < 暂停(只读) < 确认弹窗 < 调试浮窗)
|
||||
# < 商店 < 营地 < 设置 < 暂停(只读) < 生涯页(只读·迭代 18 卡④) < 确认弹窗 < 调试浮窗)
|
||||
var overlays: Dictionary = UiAssembler.build_overlays(self, db)
|
||||
legend_overlay = overlays.legend_overlay
|
||||
node_overlay = overlays.node_overlay
|
||||
@@ -275,6 +276,12 @@ func _build_ui() -> void:
|
||||
pause_overlay = PauseOverlay.new()
|
||||
add_child(pause_overlay)
|
||||
pause_overlay.closed.connect(_on_pause_closed)
|
||||
# 生涯页·只读全屏页(迭代 18 卡④——P3 甲:登记序=营地同档,设置层旁、确认弹窗之前;
|
||||
# 树序同步=addChild 同位(登记序=树序=z 序纪律);数据=组合根开层实时读 SaveManager 计数
|
||||
# 访问器+MetaProgression 访问器喂入,本层零写通路零跳转;入口=开始层「营地与系统」组生涯钮)
|
||||
career_overlay = CareerOverlay.new()
|
||||
add_child(career_overlay)
|
||||
career_overlay.closed.connect(_on_career_closed)
|
||||
# 提升三选一覆盖层(迭代 10——z 序 = 节点层之上、终局层之下;确认后同拍推进)
|
||||
curio_overlay = CurioPickOverlay.new()
|
||||
add_child(curio_overlay)
|
||||
@@ -312,6 +319,7 @@ func _build_ui() -> void:
|
||||
camp_overlay.tree_fork_toggled.connect(_camp_pres.on_camp_fork_toggle)
|
||||
camp_overlay.closed.connect(_camp_pres.on_camp_closed)
|
||||
start.campbtn.pressed.connect(_camp_pres.open_camp)
|
||||
start.careerbtn.pressed.connect(_open_career) # 迭代 18 卡④——生涯页一级入口(营地同组)
|
||||
start.settingsbtn.pressed.connect(_open_settings) # 迭代 8 卡④——最小设置面入口
|
||||
start.quitbtn.pressed.connect(_quit_game) # 二轮修改批 D1——退出游戏提级一级菜单
|
||||
|
||||
@@ -344,9 +352,9 @@ func _build_ui() -> void:
|
||||
debug_overlay.debug_levels_requested.connect(_start_debug_levels)
|
||||
|
||||
# 模态登记(缺陷⑤纪律——登记序 = 树序:含 move_child 调位后的关卡画面/三选一终位;
|
||||
# 暂停层设置层同档、确认弹窗之前——P2 甲)
|
||||
# 暂停层设置层同档、确认弹窗之前——P2 甲;生涯页同档随暂停层之后(迭代 18 卡④ P3 甲))
|
||||
_modals = ModalStack.new()
|
||||
for m: Control in [legend_overlay, node_overlay, level_screen, curio_overlay, _end_overlay, shop_overlay, camp_overlay, settings_overlay, pause_overlay, confirm_dialog, debug_overlay]:
|
||||
for m: Control in [legend_overlay, node_overlay, level_screen, curio_overlay, _end_overlay, shop_overlay, camp_overlay, settings_overlay, pause_overlay, career_overlay, confirm_dialog, debug_overlay]:
|
||||
_register_modal(m)
|
||||
_tune_sim = TuneSimController.new(db, debug_overlay, int(db.hero.max_hp))
|
||||
|
||||
@@ -990,6 +998,50 @@ func _on_pause_closed() -> void:
|
||||
_close_modal(pause_overlay) # 模态栈单口
|
||||
|
||||
|
||||
# ---- 生涯页·只读(迭代 18 卡④——入口=开始层生涯钮;开合仿设置面先例:开始层互斥;
|
||||
# 数据快照随开随建零写通路,页内零跳转)----
|
||||
|
||||
func _open_career() -> void:
|
||||
_start_overlay.visible = false
|
||||
_open_modal(career_overlay) # 模态栈单口
|
||||
career_overlay.open_career(_career_data())
|
||||
|
||||
|
||||
func _on_career_closed() -> void:
|
||||
_close_modal(career_overlay) # 模态栈单口
|
||||
_start_overlay.visible = true
|
||||
_refresh_resume_button()
|
||||
|
||||
|
||||
# 生涯页快照投影(只读同源——每次开层实时读 SaveManager 计数访问器 + MetaProgression 访问器
|
||||
# 现值拼装(暂停层 _pause_data 同构);快照仅服务单次开层生命周期,跨开层零持有;零写调用)
|
||||
func _career_data() -> Dictionary:
|
||||
var clears: Array[Dictionary] = []
|
||||
var boss_first := 0
|
||||
for i in db.level_count():
|
||||
var li: int = i + 1
|
||||
clears.append({"display_name": String(db.level_row(li).get("display_name", "")),
|
||||
"count": save_manager.clear_count(li)})
|
||||
if save_manager.boss_first_kill_marked(li):
|
||||
boss_first += 1
|
||||
var forge_total := 0
|
||||
for attr in MetaTable.FORGE_ATTRS:
|
||||
forge_total += meta.forge_level(attr)
|
||||
return {
|
||||
"total": save_manager.adventure_total(),
|
||||
"cleared": save_manager.adventure_cleared(),
|
||||
"clears": clears,
|
||||
"boss_first_kills": boss_first,
|
||||
"boss_first_total": db.level_count(),
|
||||
"boss_kills": save_manager.boss_kill_count(),
|
||||
"keystone": meta.keystone_balance(),
|
||||
"forge_levels_total": forge_total,
|
||||
"workshop": meta.workshop_status(),
|
||||
"tree": meta.tree_camp_rows(),
|
||||
"fork_groups": meta.tree_fork_groups(),
|
||||
}
|
||||
|
||||
|
||||
# 入口角标点击(两屏同款处理器):P1 守卫兜底——其他模态开着即拒开(常态防线=角标置灰,
|
||||
# 探针 pressed.emit 绕过 disabled 时由此兜住;地图屏自身的登记开态不计——has_open_excluding)
|
||||
func _on_pause_badge_pressed() -> void:
|
||||
|
||||
@@ -92,7 +92,7 @@ static func build_overlays(host: Control, db) -> Dictionary:
|
||||
}
|
||||
|
||||
|
||||
# 开始覆盖层(返回 {overlay, box, lvbtn, resumebtn, campbtn, settingsbtn, quitbtn}——按钮接线归组合根;
|
||||
# 开始覆盖层(返回 {overlay, box, lvbtn, resumebtn, campbtn, careerbtn, settingsbtn, quitbtn}——按钮接线归组合根;
|
||||
# 迭代 14.5 调试整合批:随机种子/数值调整板/两层调试三散件撤出主按钮组,收进调试浮窗——
|
||||
# 迭代 18 卡⑦ P2 甲:右下角「调试」角标亦退役(入口迁宿主=战斗屏 HUD+关卡地图屏两枚角标,
|
||||
# DS_DEBUG=1 会话浮窗启动即开——本层零调试入口)
|
||||
@@ -150,6 +150,10 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary:
|
||||
box.add_child(UiKit.label("── 营地与系统 ──",UiKit.FS_CAPTION, false, UiKit.WARM_FAINT))
|
||||
var campbtn := UiKit.verb_button("营地", UiKit.TEX_ICON_KEYSTONE, "永久强化:钥石换永久属性——跨局成长账本") # 元进度实现批——主菜单营地入口
|
||||
box.add_child(campbtn)
|
||||
# 生涯页一级入口(迭代 18 卡④——与营地平级;页=局外只读跨局汇总,零跳转零购买)
|
||||
var careerbtn := UiKit.button("生涯")
|
||||
careerbtn.tooltip_text = "跨局生涯汇总:总局数 / 通关局数 / Boss 击杀 / 钥石余额 / 三柜台解锁概览(只读)"
|
||||
box.add_child(careerbtn)
|
||||
var settingsbtn := UiKit.button("设置") # 迭代 8 卡④——最小设置面入口
|
||||
settingsbtn.tooltip_text = "音量 / 全屏 / 减动效"
|
||||
box.add_child(settingsbtn)
|
||||
@@ -196,7 +200,8 @@ static func build_start_overlay(host: Control, db = null) -> Dictionary:
|
||||
|
||||
return {"overlay": overlay, "box": box,
|
||||
"lvbtn": lvbtn, "resumebtn": resumebtn,
|
||||
"campbtn": campbtn, "settingsbtn": settingsbtn, "quitbtn": quitbtn}
|
||||
"campbtn": campbtn, "careerbtn": careerbtn,
|
||||
"settingsbtn": settingsbtn, "quitbtn": quitbtn}
|
||||
|
||||
|
||||
# 调试两层模式的层间过渡覆盖层(历史入口专用)。返回 {overlay, label, next_btn}——接线归组合根
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# 生涯覆盖层·只读全屏页(迭代 18 卡④ 生涯界面实装批·期一 2026-10-07——任务书 v1.2 裁点全甲;
|
||||
# 设计权威 design/gdd/systems/跨局循环/生涯.md v0.1 期一范围)。
|
||||
# 裁决落形:P1/P2 甲=汇总段六类九项(冒险总局数/通关局数/各关通关次数/Boss 首杀/Boss 总击杀/
|
||||
# 钥石余额/属性锻造/道具工坊/天赋树——逐行只读);P3 甲=登记 modal_stack 营地同档(设置层旁、
|
||||
# 确认弹窗之前——登记序=树序=z 序,组合根 addChild 同位);P4 甲=零跳转(页内零「前往他处」
|
||||
# 入口,仅只读展示+关闭)+局内不放生涯入口(开始覆盖层「营地与系统」组唯一入口)。
|
||||
# 期二/期三内容(历史回看/图鉴/单局明细)零触碰——页内无任何期二占位件。
|
||||
# 只读契约(任务书契约 3/4):数据快照由组合根 open_career 喂入(每次开层实时读 SaveManager
|
||||
# 计数访问器 + MetaProgression 访问器重建——暂停层 R4 同构,快照仅单次开层生命周期,跨开层
|
||||
# 零持有);本类零核心访问、零写通路——唯一信号 closed(关闭意图,组合根经模态栈单口收口)。
|
||||
# 零动效(暂停层 P4 甲先例同款):直开直关,无 tween 无 AnimationPlayer。
|
||||
# R1 公共件单点:全部构成件经 UiKit 工厂产出(page_shell/label/button/keystone_badge),
|
||||
# 零新素材零新色值零新字体零自建样式。页壳=page_shell 暖亮底(商店同壳——主菜单页族形态)。
|
||||
class_name CareerOverlay
|
||||
extends Control
|
||||
|
||||
signal closed
|
||||
|
||||
var _total_label: Label # 冒险总局数(开局即计含放弃与失败)
|
||||
var _cleared_label: Label # 通关局数(三关全通才计 1)
|
||||
var _clears_label: Label # 各关通关次数(一行三关——display_name ×次数)
|
||||
var _boss_first_label: Label # Boss 首杀(已首杀关数/总关数)
|
||||
var _boss_kills_label: Label # Boss 总击杀(含重复)
|
||||
var _keystone_badge: UiKit.KeystoneBadge # 钥石余额(badge 工厂件——暂停层同形制)
|
||||
var _forge_label: Label # 属性锻造(已购等级合计)
|
||||
var _workshop_label: Label # 道具工坊(已解锁件数/总件数)
|
||||
var _tree_label: Label # 天赋树已购概览(聚合单条——暂停层同构)
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 全屏页壳(T6/T7 对齐批先例——暖亮底+石纹弱质感+暗角+56px 通栏顶条+内容列)
|
||||
var page: Dictionary = UiKit.page_shell(self, true)
|
||||
var top: HBoxContainer = page.top_row
|
||||
top.add_child(UiKit.label("生 涯",UiKit.FS_TITLE, true, UiKit.WARM))
|
||||
var top_sp := Control.new()
|
||||
top_sp.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
top.add_child(top_sp)
|
||||
var close_btn := UiKit.button("返回", 90.0) # 紧凑返回钮(设置/暂停面先例形制)
|
||||
close_btn.tooltip_text = "关闭生涯页,返回主菜单(本页只读,不发生任何购买或修改)"
|
||||
close_btn.pressed.connect(_emit_closed)
|
||||
top.add_child(close_btn)
|
||||
|
||||
var box: VBoxContainer = page.box
|
||||
var hint := UiKit.label("跨局生涯汇总(只读——购买与装配在营地;历史冒险回看随后续批次)",
|
||||
UiKit.FS_HINT, false, UiKit.WARM_SOFT)
|
||||
box.add_child(hint)
|
||||
|
||||
# 组一·冒险战绩(终身计数域——存档 v6:总局数开局即计、通关局数三关全通才计)
|
||||
# 对比度口径:页底=暖亮档深棕(BG_BRIGHT),文字全用亮墨族 token(WARM 9.0:1 / WARM_SOFT 8.0:1 /
|
||||
# CANDLE 7.2:1 / INK_L_GOLD 9.1:1 实测对 BG_BRIGHT 全过 §7.2 ≥4.5:1——深墨族〔INK_LABEL〕
|
||||
# 压深棕底仅 ~1.3:1 属违例,禁用)
|
||||
_section_head(box, "冒险战绩")
|
||||
_total_label = _row(box, "冒险总局数")
|
||||
_cleared_label = _row(box, "通关局数")
|
||||
_clears_label = _row(box, "各关通关次数")
|
||||
_boss_first_label = _row(box, "Boss 首杀")
|
||||
_boss_kills_label = _row(box, "Boss 总击杀")
|
||||
|
||||
# 组二·资源与成长(钥石/三柜台解锁概览——现役只读投影)
|
||||
_section_head(box, "资源与成长")
|
||||
var bal_row := HBoxContainer.new()
|
||||
bal_row.add_theme_constant_override("separation", 8)
|
||||
box.add_child(bal_row)
|
||||
var bal_name := UiKit.label("钥石余额",UiKit.FS_BODY, false, UiKit.WARM)
|
||||
bal_row.add_child(bal_name)
|
||||
_keystone_badge = UiKit.keystone_badge("钥石 0")
|
||||
bal_row.add_child(_keystone_badge)
|
||||
_forge_label = _row(box, "属性锻造")
|
||||
_workshop_label = _row(box, "道具工坊")
|
||||
_tree_label = _row(box, "天赋树")
|
||||
_tree_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
|
||||
visible = false # 显式初始化——不靠树序巧合(缺陷⑤家族纪律)
|
||||
|
||||
|
||||
# ---- 开层(组合根唯一调用口——快照随开随建,只读同源口径同暂停层 R4)----
|
||||
|
||||
func open_career(data: Dictionary) -> void:
|
||||
_total_label.text = "%d 局" % int(data.get("total", 0))
|
||||
_cleared_label.text = "%d 局(三关全通)" % int(data.get("cleared", 0))
|
||||
var parts: Array[String] = []
|
||||
for row in (data.get("clears", []) as Array):
|
||||
parts.append("%s ×%d" % [String(row.get("display_name", "")), int(row.get("count", 0))])
|
||||
_clears_label.text = " · ".join(parts) if not parts.is_empty() else "—"
|
||||
_boss_first_label.text = "%d/%d 关" % [int(data.get("boss_first_kills", 0)), int(data.get("boss_first_total", 0))]
|
||||
_boss_kills_label.text = "%d 次" % int(data.get("boss_kills", 0))
|
||||
_keystone_badge.set_text("钥石 %d" % int(data.get("keystone", 0)))
|
||||
_forge_label.text = "已购 %d 级(三属性合计)" % int(data.get("forge_levels_total", 0))
|
||||
var ws: Array = data.get("workshop", []) as Array
|
||||
var unlocked := 0
|
||||
for row in ws:
|
||||
if bool(row.get("unlocked", false)):
|
||||
unlocked += 1
|
||||
_workshop_label.text = "已解锁 %d/%d 件" % [unlocked, ws.size()] if not ws.is_empty() else "—"
|
||||
_tree_label.text = _tree_summary(data)
|
||||
visible = true
|
||||
|
||||
|
||||
# 天赋树聚合文案(暂停层 _rebuild_tree 同构——已购节点等级+Fork 激活侧;零已购=空态句)
|
||||
func _tree_summary(data: Dictionary) -> String:
|
||||
var owned: Array[String] = []
|
||||
for row in (data.get("tree", []) as Array):
|
||||
var lvl := int(row.get("level", 0))
|
||||
if lvl > 0:
|
||||
owned.append("%s Lv%d/%d" % [String(row.get("display_name", "")), lvl, int(row.get("cap", 1))])
|
||||
for fg in (data.get("fork_groups", []) as Array):
|
||||
var active := String(fg.get("active_side", ""))
|
||||
if active == "":
|
||||
continue
|
||||
var side_name := active
|
||||
for sd in (fg.get("sides", []) as Array):
|
||||
if String(sd.get("side", "")) == active:
|
||||
side_name = String(sd.get("display_name", active))
|
||||
break
|
||||
owned.append("%s·激活 %s" % [String(fg.get("display_name", "")), side_name])
|
||||
if owned.is_empty():
|
||||
return "尚未购买任何节点"
|
||||
return "已购 %d 项:%s" % [owned.size(), " · ".join(owned)]
|
||||
|
||||
|
||||
func _emit_closed() -> void:
|
||||
closed.emit()
|
||||
|
||||
|
||||
# ---- 行构件(名称列 + 数值列——暂停层行族同构;数值 Label 返回供探针/冒烟投影断言)----
|
||||
|
||||
func _section_head(box: VBoxContainer, text: String) -> void:
|
||||
box.add_child(UiKit.label(text,UiKit.FS_BODY, true, UiKit.INK_L_GOLD))
|
||||
|
||||
|
||||
func _row(box: VBoxContainer, name_text: String) -> Label:
|
||||
var line := HBoxContainer.new()
|
||||
line.add_theme_constant_override("separation", 8)
|
||||
box.add_child(line)
|
||||
var name_l := UiKit.label(name_text,UiKit.FS_BODY, false, UiKit.WARM)
|
||||
name_l.custom_minimum_size = Vector2(150, 0)
|
||||
line.add_child(name_l)
|
||||
var val_l := UiKit.label("—",UiKit.FS_BODY, true, UiKit.CANDLE)
|
||||
line.add_child(val_l)
|
||||
return val_l
|
||||
@@ -0,0 +1 @@
|
||||
uid://bt66vryciqn8v
|
||||
+146
-7
@@ -4255,6 +4255,7 @@ func _smoke_meta() -> void:
|
||||
_meta_settle_and_workshop()
|
||||
_meta_injection()
|
||||
_pause_overlay_projection()
|
||||
_career_overlay_projection()
|
||||
|
||||
|
||||
# ---- 暂停层只读投影一致性(迭代 17 卡③——R4 数据只读同源:暂停层展示值逐项 == MetaProgression
|
||||
@@ -4332,12 +4333,108 @@ func _pause_overlay_projection() -> void:
|
||||
po.free()
|
||||
|
||||
|
||||
# ---- 生涯页只读投影一致性(迭代 18 卡④——汇总段六类九项逐行 == SaveManager 计数访问器/
|
||||
# MetaProgression 访问器读数;投影拼装与 main._career_data 同构(同访问器族同序)。
|
||||
# 只读性连接巡检与零动效断言归 ui_struct_probe 呈现侧,本段只管数据面+旧档载入显示
|
||||
# (v5 样档升 v6——完成定义 6「计数域缺省补零、页正常显示」))----
|
||||
func _career_overlay_projection() -> void:
|
||||
print("--- 生涯页·只读投影一致性(隔离档 smoke_meta_career/career_v5)---")
|
||||
var sv = _meta_new_save(_META_SMOKE_PATHS[9])
|
||||
var mp = load("res://core/meta_progression.gd").new(_db, sv)
|
||||
# 已玩态夹具:两局收束(一通一止)+ 钥石/锻造/工坊首件/树首节点非零——投影可辨非全零白板
|
||||
sv.add_keystone(45)
|
||||
sv.set_forge_level("atk", 2)
|
||||
sv.set_forge_level("max_hp", 1)
|
||||
var ws0: Array = _db.meta_workshop_items()
|
||||
if not ws0.is_empty():
|
||||
sv.unlock_item(String(ws0[0].get("item_id", "")))
|
||||
sv.apply_adventure_summary({"result": "completed", "cleared": true, "levels_cleared": 3,
|
||||
"stopped_at": 0, "keystone_total": 0, "master_seed": 21})
|
||||
sv.apply_adventure_summary({"result": "abandoned", "cleared": false, "levels_cleared": 1,
|
||||
"stopped_at": 2, "keystone_total": 0, "master_seed": 22})
|
||||
var tree_rows: Array = mp.tree_camp_rows()
|
||||
var tree_node := ""
|
||||
if not tree_rows.is_empty():
|
||||
tree_node = String(tree_rows[0].get("node_id", ""))
|
||||
sv.set_tree_level(tree_node, 1)
|
||||
sv.write_to_disk()
|
||||
# 投影拼装(main._career_data 同构)+ 视图喂入
|
||||
var data := {"total": sv.adventure_total(), "cleared": sv.adventure_cleared(),
|
||||
"clears": [], "boss_first_kills": 0, "boss_first_total": _db.level_count(),
|
||||
"boss_kills": sv.boss_kill_count(), "keystone": mp.keystone_balance(), "forge_levels_total": 0,
|
||||
"workshop": mp.workshop_status(), "tree": mp.tree_camp_rows(), "fork_groups": mp.tree_fork_groups()}
|
||||
for i in _db.level_count():
|
||||
var li: int = i + 1
|
||||
data["clears"].append({"display_name": String(_db.level_row(li).get("display_name", "")),
|
||||
"count": sv.clear_count(li)})
|
||||
if sv.boss_first_kill_marked(li):
|
||||
data["boss_first_kills"] += 1
|
||||
for attr in MetaTable.FORGE_ATTRS:
|
||||
data["forge_levels_total"] += mp.forge_level(attr)
|
||||
var co = load("res://presentation/views/career_overlay.gd").new()
|
||||
co.open_career(data)
|
||||
check(co.visible, "生涯页开层可见(open_career 直开——零动效路径)")
|
||||
check(String(co._total_label.text) == "2 局",
|
||||
"总局数投影 = adventure_total() 读数(%s)" % co._total_label.text)
|
||||
check(String(co._cleared_label.text) == "1 局(三关全通)",
|
||||
"通关局数投影 = adventure_cleared() 读数(%s)" % co._cleared_label.text)
|
||||
var expect_clears: Array[String] = []
|
||||
for row in (data["clears"] as Array):
|
||||
expect_clears.append("%s ×%d" % [String(row.get("display_name", "")), int(row.get("count", 0))])
|
||||
check(String(co._clears_label.text) == " · ".join(expect_clears),
|
||||
"各关通关次数投影 = clear_count() 逐关读数(%s)" % co._clears_label.text)
|
||||
check(String(co._boss_first_label.text) == "3/3 关" and String(co._boss_kills_label.text) == "4 次",
|
||||
"Boss 首杀/总杀投影 = 首杀标记计数 + boss_kill_count()(%s / %s)" % [co._boss_first_label.text, co._boss_kills_label.text])
|
||||
check(String(co._keystone_badge.value_label.text) == "钥石 %d" % mp.keystone_balance(),
|
||||
"钥石余额徽投影 = keystone_balance() 读数(%s)" % co._keystone_badge.value_label.text)
|
||||
check(String(co._forge_label.text) == "已购 %d 级(三属性合计)" % data["forge_levels_total"],
|
||||
"属性锻造投影 = forge_level() 三属性合计(%s)" % co._forge_label.text)
|
||||
var ws_unlocked := 0
|
||||
for row in (mp.workshop_status() as Array):
|
||||
if bool(row.get("unlocked", false)):
|
||||
ws_unlocked += 1
|
||||
check(String(co._workshop_label.text) == "已解锁 %d/%d 件" % [ws_unlocked, (mp.workshop_status() as Array).size()],
|
||||
"道具工坊投影 = workshop_status() 解锁计数(%s——首件解锁夹具在列)" % co._workshop_label.text)
|
||||
var tree_expect := "尚未购买任何节点"
|
||||
if tree_node != "":
|
||||
var trow: Dictionary = tree_rows[0]
|
||||
tree_expect = "已购 1 项:%s Lv1/%d" % [String(trow.get("display_name", "")), int(trow.get("cap", 1))]
|
||||
check(String(co._tree_label.text) == tree_expect,
|
||||
"天赋树概览投影 = tree_camp_rows() 已购聚合(%s)" % co._tree_label.text)
|
||||
co.visible = false
|
||||
co.free()
|
||||
# 旧档载入显示(完成定义 6):v5 现役档形态(计数域两键不存在)升 v6 → 生涯页正常呈现缺省值
|
||||
var v5 = load("res://core/save_manager.gd").new(_META_SMOKE_PATHS[10])
|
||||
var fv5c := FileAccess.open(_META_SMOKE_PATHS[10], FileAccess.WRITE)
|
||||
fv5c.store_string(JSON.stringify({"version": 5, "meta": {"keystone_balance": 3}}))
|
||||
fv5c.close()
|
||||
check(v5.load_from_disk() and v5.adventure_total() == 0 and v5.adventure_cleared() == 0,
|
||||
"v5 现役档升 v6 载入成功(计数域缺省补零)")
|
||||
var mp_v5 = load("res://core/meta_progression.gd").new(_db, v5)
|
||||
var data_v5 := {"total": v5.adventure_total(), "cleared": v5.adventure_cleared(),
|
||||
"clears": [], "boss_first_kills": 0, "boss_first_total": _db.level_count(),
|
||||
"boss_kills": v5.boss_kill_count(), "keystone": mp_v5.keystone_balance(), "forge_levels_total": 0,
|
||||
"workshop": mp_v5.workshop_status(), "tree": mp_v5.tree_camp_rows(), "fork_groups": mp_v5.tree_fork_groups()}
|
||||
for i in _db.level_count():
|
||||
data_v5["clears"].append({"display_name": String(_db.level_row(i + 1).get("display_name", "")),
|
||||
"count": v5.clear_count(i + 1)})
|
||||
var co_v5 = load("res://presentation/views/career_overlay.gd").new()
|
||||
co_v5.open_career(data_v5)
|
||||
check(co_v5.visible and String(co_v5._total_label.text) == "0 局" \
|
||||
and String(co_v5._cleared_label.text) == "0 局(三关全通)" \
|
||||
and String(co_v5._keystone_badge.value_label.text) == "钥石 3",
|
||||
"旧档载入后生涯页正常显示(v5 升 v6:总局数/通关局数显示 0,既有钥石余额原样呈现)")
|
||||
co_v5.visible = false
|
||||
co_v5.free()
|
||||
|
||||
|
||||
# 冒烟隔离存档名册(段首清陈旧 + 段尾清理——契约:测试不污染 user://save.json 真实档)
|
||||
const _META_SMOKE_PATHS := ["user://smoke_meta_buy.json", "user://smoke_meta_dry.json",
|
||||
"user://smoke_meta_settle.json", "user://smoke_meta_workshop.json",
|
||||
"user://smoke_meta_cap.json", "user://smoke_meta_white.json",
|
||||
"user://smoke_meta_attune.json", "user://smoke_meta_attune2.json",
|
||||
"user://smoke_meta_tree.json"]
|
||||
"user://smoke_meta_tree.json", "user://smoke_meta_career.json",
|
||||
"user://smoke_meta_career_v5.json"]
|
||||
|
||||
|
||||
func _meta_smoke_cleanup() -> void:
|
||||
@@ -4655,7 +4752,7 @@ func _smoke_battle_log_view() -> void:
|
||||
|
||||
|
||||
# ---- 存档序列化冒烟(SaveManager——读写往返/新档合法/余额拒花/锻造出域拒/高版本拒读禁写/
|
||||
# 损坏兜底/迁移链/域界干净/摘要 cap/摘要集成)。测试文件统一 user://smoke_save_*.json 隔离,
|
||||
# 损坏兜底/迁移链/域界干净/摘要 cap/摘要集成/生涯终身计数域 v6)。测试文件统一 user://smoke_save_*.json 隔离,
|
||||
# 段首清场+段尾清理——绝不碰 user://save.json(红线)。
|
||||
func _smoke_save() -> void:
|
||||
print("--- SaveManager 存档读写/迁移/兜底 ---")
|
||||
@@ -4665,7 +4762,8 @@ func _smoke_save() -> void:
|
||||
"user://smoke_save_corrupt.json", "user://smoke_save_migrate.json",
|
||||
"user://smoke_save_domain.json", "user://smoke_save_cap.json",
|
||||
"user://smoke_save_integration.json", "user://smoke_save_breakpoint.json",
|
||||
"user://smoke_save_v2compat.json"]
|
||||
"user://smoke_save_v2compat.json", "user://smoke_save_v5upgrade.json",
|
||||
"user://smoke_save_v5legacy.json"]
|
||||
var stale: Array = []
|
||||
for p in paths:
|
||||
stale.append(p)
|
||||
@@ -4687,6 +4785,8 @@ func _smoke_save() -> void:
|
||||
"apply 原语入账(钥石 7+3、通关次数 1/1/0)")
|
||||
check(w.boss_first_kill_marked(1) and w.boss_first_kill_marked(2) and not w.boss_first_kill_marked(3),
|
||||
"首杀标记随通关关卡置位(1/2 有、3 无)")
|
||||
check(w.adventure_total() == 1 and w.adventure_cleared() == 0,
|
||||
"生涯终身计数随 apply 自增恰一(中止局:总局数 1、通关局数 0——迭代 18 卡④)")
|
||||
check(w.write_to_disk(), "写盘成功")
|
||||
var r = sm_script.new(paths[0])
|
||||
check(r.load_from_disk(), "读回成功")
|
||||
@@ -4697,6 +4797,7 @@ func _smoke_save() -> void:
|
||||
check(r.clear_count(1) == 1 and r.clear_count(2) == 1 and r.clear_count(3) == 0, "通关次数表往返相等")
|
||||
check(r.boss_first_kill_marked(1) and r.boss_first_kill_marked(2) and not r.boss_first_kill_marked(3),
|
||||
"首杀标记往返相等")
|
||||
check(r.adventure_total() == 1 and r.adventure_cleared() == 0, "生涯终身计数往返相等(1/0)")
|
||||
var s0: Dictionary = r.recent_summaries()[0]
|
||||
check(r.recent_summaries().size() == 1 and int(s0.get("master_seed", -1)) == 99 and int(s0.get("keystone_total", -1)) == 3,
|
||||
"冒险摘要往返相等(1 条,seed 99)")
|
||||
@@ -4706,6 +4807,8 @@ func _smoke_save() -> void:
|
||||
check(f2.load_from_disk() and f2.keystone_balance() == 0 and f2.forge_level("atk") == 0
|
||||
and not f2.item_unlocked("anything") and f2.clear_count(1) == 0 and f2.recent_summaries().is_empty(),
|
||||
"新档合法态(load true + 全零默认)")
|
||||
check(f2.adventure_total() == 0 and f2.adventure_cleared() == 0,
|
||||
"新档生涯终身计数缺省全零(迭代 18 卡④两新域——白板存档完整可玩)")
|
||||
|
||||
# ③ spend 拒绝:余额不足 false 且零副作用(钥石只增不减——消费除外)
|
||||
var f3 = sm_script.new(paths[2])
|
||||
@@ -4748,8 +4851,8 @@ func _smoke_save() -> void:
|
||||
fm.store_string(JSON.stringify({"version": 0, "keystone_old": 12}))
|
||||
fm.close()
|
||||
check(f7.load_from_disk() and f7.keystone_balance() == 12, "v0 旧档经迁移链入账(keystone_old 12 → 余额 12)")
|
||||
check(f7.write_to_disk() and int(JSON.parse_string(FileAccess.open(paths[5], FileAccess.READ).get_as_text()).get("version", -1)) == 5,
|
||||
"迁移链 0→1(测试钩)→5(生产) 写盘 version == 5(v5=天赋树域,迭代 12 T9——v4 被同调批占用顺延披露)")
|
||||
check(f7.write_to_disk() and int(JSON.parse_string(FileAccess.open(paths[5], FileAccess.READ).get_as_text()).get("version", -1)) == 6,
|
||||
"迁移链 0→1(测试钩)→6(生产) 写盘 version == 6(v6=生涯终身计数域,迭代 18 卡④——v5=天赋树域迭代 12 T9)")
|
||||
|
||||
# ⑧ 域界干净:meta 永久进度域不含局内资源键(行动点/RAP/GP/道具库存/生命账本不入档——契约 2;
|
||||
# 迭代 8 卡①修订:扫描收窄到 meta 域——断点域=冒险进行中瞬态快照,生命/GP 按拍板面入域豁免)
|
||||
@@ -4846,8 +4949,8 @@ func _smoke_save() -> void:
|
||||
fold.close()
|
||||
check(fo.load_from_disk() and fo.keystone_balance() == 4 and not fo.has_breakpoint(),
|
||||
"v1 旧档迁移 v4:断点域补空(合法空态,无断点域不炸)")
|
||||
check(fo.write_to_disk() and int(JSON.parse_string(FileAccess.open(paths[9], FileAccess.READ).get_as_text()).get("version", -1)) == 5,
|
||||
"v1 旧档迁移后写盘 version == 5(v1→v5 链式——天赋树域 2026-10-04)")
|
||||
check(fo.write_to_disk() and int(JSON.parse_string(FileAccess.open(paths[9], FileAccess.READ).get_as_text()).get("version", -1)) == 6,
|
||||
"v1 旧档迁移后写盘 version == 6(v1→v6 链式——生涯终身计数域 2026-10-07)")
|
||||
|
||||
# ⑫ v2 旧档→v3 兼容(迭代 10 g 裁——semver 向后兼容:旧断点零丢失、新代码可续玩)
|
||||
var fv2 = sm_script.new(paths[10])
|
||||
@@ -4866,6 +4969,42 @@ func _smoke_save() -> void:
|
||||
check(adr_v2.resume_adventure(fv2.breakpoint_snapshot(), {"hero_override": {}}),
|
||||
"v2 旧断点续玩受理(缺 bonus 附随件走常规重建路径——g 裁 semver 口径)")
|
||||
|
||||
# ⑬ 生涯终身计数域(迭代 18 卡④):v5 旧档升 v6 缺省补零 + 升档幂等 + 收束自增恰一
|
||||
#(真实旧档形态=计数域两键不存在;升档只增不改——既有 meta 值零触碰,存档红线 S2 断言面)
|
||||
var f13 = sm_script.new(paths[11])
|
||||
var fv5u := FileAccess.open(paths[11], FileAccess.WRITE)
|
||||
fv5u.store_string(JSON.stringify({"version": 5, "meta": {"keystone_balance": 9}}))
|
||||
fv5u.close()
|
||||
check(f13.load_from_disk() and f13.adventure_total() == 0 and f13.adventure_cleared() == 0
|
||||
and f13.keystone_balance() == 9,
|
||||
"v5 旧档升 v6:计数域缺省补零且既有余额原样(迁移只增字段不改值)")
|
||||
check(f13.write_to_disk() and f13.load_from_disk()
|
||||
and int(JSON.parse_string(FileAccess.open(paths[11], FileAccess.READ).get_as_text()).get("version", -1)) == 6
|
||||
and f13.adventure_total() == 0 and f13.adventure_cleared() == 0,
|
||||
"升档幂等:v6 档写盘再载零漂移(重复迁移零副作用)")
|
||||
var f13b = sm_script.new(paths[12])
|
||||
f13b.load_from_disk()
|
||||
f13b.apply_adventure_summary({"result": "completed", "cleared": true, "levels_cleared": 3,
|
||||
"stopped_at": 0, "keystone_total": 0, "master_seed": 1})
|
||||
check(f13b.adventure_total() == 1 and f13b.adventure_cleared() == 1,
|
||||
"收束自增恰一·通关局(三关全通 cleared=true:总局数+1 且通关局数+1)")
|
||||
f13b.apply_adventure_summary({"result": "abandoned", "cleared": false, "levels_cleared": 1,
|
||||
"stopped_at": 2, "keystone_total": 0, "master_seed": 2})
|
||||
check(f13b.adventure_total() == 2 and f13b.adventure_cleared() == 1,
|
||||
"收束自增恰一·中止局(放弃局:仅总局数+1,通关局数不动)")
|
||||
|
||||
# ⑭ 收束链入账(迭代 18 卡④ T2——真实收束挂点全链恰一:主流程 adventure_finished →
|
||||
# MetaProgression.settle_adventure → apply_adventure_summary 单口;两夹具经同链入账)
|
||||
var mp13 = load("res://core/meta_progression.gd").new(_db, f13b)
|
||||
mp13.settle_adventure({"result": "failed", "cleared": false, "levels_cleared": 2,
|
||||
"stopped_at": 3, "keystone_total": 0, "master_seed": 3})
|
||||
check(f13b.adventure_total() == 3 and f13b.adventure_cleared() == 1,
|
||||
"收束链自增·中止局(settle_adventure 真实挂点:总局数+1、通关局数不动)")
|
||||
mp13.settle_adventure({"result": "completed", "cleared": true, "levels_cleared": 3,
|
||||
"stopped_at": 0, "keystone_total": 0, "master_seed": 4})
|
||||
check(f13b.adventure_total() == 4 and f13b.adventure_cleared() == 2,
|
||||
"收束链自增·通关局(三关全通:总局数+1 且通关局数+1——全链恰一)")
|
||||
|
||||
# 段尾清理(测试文件绝不残留)
|
||||
for p in stale:
|
||||
if FileAccess.file_exists(p):
|
||||
|
||||
@@ -154,6 +154,33 @@ func _ready() -> void:
|
||||
_problems.append("开始菜单缺退出游戏按钮(二轮 D1)")
|
||||
if ProbeUiUtil.find_button(main.settings_overlay, "退出游戏", "prefix") != null:
|
||||
_problems.append("设置面仍含退出游戏按钮(二轮 D1——只在一级菜单出现)")
|
||||
# ---- 生涯页段(迭代 18 卡④——入口点击链+关闭回返,真实按钮信号路径;本页只读零写,
|
||||
# 值断言归冒烟投影段与 ui_struct 结构族,此处只验开合路径与零跳转)----
|
||||
var career_btn: Button = ProbeUiUtil.find_button(main._start_overlay, "生涯", "prefix")
|
||||
if career_btn == null:
|
||||
_problems.append("生涯入口按钮缺失(开始层 careerbtn)")
|
||||
else:
|
||||
career_btn.pressed.emit() # 真实按钮信号路径 → 组合根 _open_career
|
||||
await get_tree().process_frame
|
||||
if not main.career_overlay.visible or main._start_overlay.visible:
|
||||
_problems.append("生涯页未打开(点击路径)")
|
||||
else:
|
||||
# 零跳转契约(提纲 P4 甲):页内除「返回」外零导航钮
|
||||
for nav in ["营地", "商店", "设置", "退出", "冒险"]:
|
||||
if ProbeUiUtil.find_button(main.career_overlay, nav, "contains") != null:
|
||||
_problems.append("生涯页内出现导航入口「%s」(零跳转违约——生涯纯只读)" % nav)
|
||||
# 局内入口断言(提纲 P4 甲):生涯入口只在开始层——战斗屏/地图屏零生涯角标
|
||||
if main.board_zone.find_child("career_badge", true, false) != null \
|
||||
or main.level_screen.find_child("career_badge", true, false) != null:
|
||||
_problems.append("局内屏出现生涯入口件(局内不放生涯入口违约)")
|
||||
var career_close: Button = ProbeUiUtil.find_button(main.career_overlay, "返回", "prefix")
|
||||
if career_close == null:
|
||||
_problems.append("生涯页返回按钮缺失")
|
||||
else:
|
||||
career_close.pressed.emit()
|
||||
await get_tree().process_frame
|
||||
if main.career_overlay.visible or not main._start_overlay.visible:
|
||||
_problems.append("生涯页关闭后未恢复开始层")
|
||||
# 换回全新零档(营地购买态不泄入后续冒险段——确定性;档案残留下次段首清理兜底)
|
||||
ProbeUiUtil.isolate_save(main, "smoke_click_probe_reset", true, false, true) # 零档换注 + 继续上局按钮重刷(原三行样板收口)
|
||||
var resume_btn0: Button = ProbeUiUtil.find_button(main._start_overlay, "▶ 继续上局", "prefix")
|
||||
|
||||
@@ -29,6 +29,9 @@ func _pairs() -> Array:
|
||||
["锚·暖白/屏根", UiKit.WARM, UiKit.BG_ROOT, 1.0], # 全站锚点:暗底正文
|
||||
["锚·暖白弱/舞台底", UiKit.WARM_FAINT, UiKit.STAGE_BG, 1.0], # 全站锚点:B区辅助墨
|
||||
["钥石徽·深墨/烛光黄", UiKit.INK_ON_GOLD, UiKit.CANDLE, 1.0], # 迭代17卡③——badge 工厂件文字(营地徽+暂停层余额行同形制)
|
||||
["生涯页·行名墨/暖亮页底", UiKit.WARM, UiKit.BG_BRIGHT, 1.0], # 迭代18卡④——生涯页行名列/提示文(WARM_SOFT 同族亮墨)
|
||||
["生涯页·行值墨/暖亮页底", UiKit.CANDLE, UiKit.BG_BRIGHT, 1.0], # 迭代18卡④——生涯页数值列(烛光黄 bold)
|
||||
["生涯页·组帽墨/暖亮页底", UiKit.INK_L_GOLD, UiKit.BG_BRIGHT, 1.0],# 迭代18卡④——生涯页分组小节头(金亮 bold)
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -48,6 +48,27 @@ func _ready() -> void:
|
||||
else:
|
||||
problems.append("[camp] 营地入口按钮缺失(驱动中断)")
|
||||
|
||||
# ---- 生涯页(迭代 18 卡④):入口点击链(合成点击真路径=pressed.emit→组合根 _open_career)→
|
||||
# 结构断言族→只读巡检(契约 3)+零动效契约+登记序/树序契约(P3 甲营地同档)+零跳转契约
|
||||
#(提纲 P4 甲)→组合根真实路径关闭。----
|
||||
var careerbtn: Button = ProbeUiUtil.find_button(main._start_overlay, "生涯", "prefix")
|
||||
if careerbtn != null:
|
||||
careerbtn.pressed.emit()
|
||||
_settle()
|
||||
if not main.career_overlay.visible or main._start_overlay.visible:
|
||||
problems.append("[career] 生涯页未打开或开始层未隐藏(入口点击链断裂)")
|
||||
await _audit("career", [main.career_overlay])
|
||||
_career_readonly_contract(main)
|
||||
_career_zero_motion_contract(main)
|
||||
_career_registry_contract(main)
|
||||
_career_nojump_contract(main)
|
||||
main._on_career_closed()
|
||||
_settle()
|
||||
if main.career_overlay.visible or not main._start_overlay.visible:
|
||||
problems.append("[career] 关闭后页未隐藏或开始层未恢复(模态栈单口失守)")
|
||||
else:
|
||||
problems.append("[career] 生涯入口按钮缺失(开始层 careerbtn)")
|
||||
|
||||
main.confirm_dialog.open("结构探针采样", "确认")
|
||||
_settle()
|
||||
await _audit("confirm", [main.confirm_dialog])
|
||||
@@ -233,6 +254,75 @@ func _pause_zero_motion_contract(main: Node) -> void:
|
||||
problems.append("[pause][motion] 视图源码含「%s」(R5 零动效直开直关破——P4 甲)" % token)
|
||||
|
||||
|
||||
# ---- 生涯页契约族(迭代 18 卡④——任务书契约 3/4+提纲 P3/P4 甲)----
|
||||
|
||||
# ⑩career 只读性契约(契约 3——暂停层 ⑧ 同形制):生涯页子树全控件 × 游戏语义信号连接巡检——
|
||||
# 清单外零连接。白名单={视图自身 _emit_closed〔返回钮〕, 组合根 _on_career_closed};页内任何
|
||||
# 购买/导航/写入方向的新连接一律红,须先入册审查。
|
||||
func _career_readonly_contract(main: Node) -> void:
|
||||
var overlay: Control = main.career_overlay
|
||||
var stack: Array = [overlay]
|
||||
var conn_count := 0
|
||||
while not stack.is_empty():
|
||||
var n: Node = stack.pop_back()
|
||||
for sig_name in _PAUSE_READONLY_SIGNALS:
|
||||
for conn in n.get_signal_connection_list(sig_name):
|
||||
conn_count += 1
|
||||
var cb: Callable = conn["callable"]
|
||||
var host: Object = cb.get_object()
|
||||
var m := String(cb.get_method())
|
||||
if host == overlay and m == "_emit_closed":
|
||||
continue
|
||||
if host == main and m == "_on_career_closed":
|
||||
continue
|
||||
problems.append("[career][readonly] 非法信号连接 %s.%s → %s.%s(零写通路巡检——白名单=视图 _emit_closed/组合根 _on_career_closed)"
|
||||
% [n.name, sig_name, host, m])
|
||||
for ch in n.get_children():
|
||||
stack.append(ch)
|
||||
if conn_count != 2:
|
||||
problems.append("[career][readonly] 信号连接数=%d 应=2(返回钮 pressed+closed 外发——多连接=写通路嫌疑)" % conn_count)
|
||||
|
||||
|
||||
# ⑪career 零动效契约(暂停层 ⑨ 同形制——P4 甲直开直关)
|
||||
func _career_zero_motion_contract(main: Node) -> void:
|
||||
var overlay: Control = main.career_overlay
|
||||
var stack: Array = [overlay]
|
||||
while not stack.is_empty():
|
||||
var n: Node = stack.pop_back()
|
||||
if n is AnimationPlayer:
|
||||
problems.append("[career][motion] 子树含 AnimationPlayer(零动效破)")
|
||||
for ch in n.get_children():
|
||||
stack.append(ch)
|
||||
var src := FileAccess.get_file_as_string("res://presentation/views/career_overlay.gd")
|
||||
for token in ["create_tween", "UiKit.motion"]:
|
||||
if src.contains(token):
|
||||
problems.append("[career][motion] 视图源码含「%s」(零动效直开直关破)" % token)
|
||||
|
||||
|
||||
# ⑫career 登记/树序契约(P3 甲——登记序=营地同档:暂停层之后、确认弹窗之前;树序同步=addChild
|
||||
# 同位。登记序=树序=z 序纪律〔缺陷⑤〕——两序任一失守即红)
|
||||
func _career_registry_contract(main: Node) -> void:
|
||||
var list: Array = main._modals._list
|
||||
var ci: int = list.find(main.career_overlay)
|
||||
var pi: int = list.find(main.pause_overlay)
|
||||
var fi: int = list.find(main.confirm_dialog)
|
||||
if ci < 0 or pi < 0 or fi < 0:
|
||||
problems.append("[career][registry] 生涯页未入登记册(或暂停层/确认弹窗缺登记)")
|
||||
return
|
||||
if ci != pi + 1 or ci > fi:
|
||||
problems.append("[career][registry] 登记序违约(应=暂停层后、确认弹窗前——P3 甲营地同档;pause=%d career=%d confirm=%d)" % [pi, ci, fi])
|
||||
var ti: int = main.career_overlay.get_index()
|
||||
if ti <= main.pause_overlay.get_index() or ti > main.confirm_dialog.get_index():
|
||||
problems.append("[career][registry] 树序与登记序不同步(addChild 位应=暂停层后、确认弹窗前;tree_index=%d)" % ti)
|
||||
|
||||
|
||||
# ⑬career 零跳转契约(提纲 P4 甲——页内零「前往他处」入口:除「返回」外任何导航钮=红)
|
||||
func _career_nojump_contract(main: Node) -> void:
|
||||
for nav in ["营地", "商店", "设置", "冒险", "继续上局", "退出", "前往"]:
|
||||
if ProbeUiUtil.find_button(main.career_overlay, nav, "contains") != null:
|
||||
problems.append("[career][nojump] 页内出现导航入口「%s」(零跳转违约——生涯纯只读)" % nav)
|
||||
|
||||
|
||||
# ⑥standee 专项:B 区站桩内容矩形 ⊆ 252px 舞台矩形(内缩 8px)且不被裁切
|
||||
# (UI 设计对齐批 N2 2026-10-06——名行基线离盒底 1px 同型高危写法返修回归闸;
|
||||
# 内容矩形=StandeeBody.content_rect(),最低绘制元素=底座下缘)
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@
|
||||
| 迭代 17 | **③暂停层只读入口批(2026-10-05 用户令编入本迭代)**:新增局内暂停层,承载钥石余额与解锁态(营地三柜台进度)只读查看——事实源=06「解锁界面与钥石呈现的交互形态(残余:暂停层只读入口)」条。考证在册:现行无暂停层;模态栈/设置面/调试浮窗三先例齐;UiKit 公共件(modal_shell/bcard/verb_button/徽章形制)与色板 token 单点现成;MetaProgression 只读访问器面齐全;战斗屏 GP/钥石已迁出=局内零查看入口正是本批由来。**美术红线:复用现行公共件与色板,零新素材零新色值(2026-10-05 用户立规)**。任务书=`design/research/任务书-暂停层只读入口批-2026-10-05.md`(T0-T5≈3.0d;🔴 契约 5 条含公共件单点/模态登记纪律;**✅ 裁点全裁(2026-10-06 用户令全按推荐:P1丁/P2甲/P3甲/P4甲);开工=U0**) | 迭代 15 出口 | **✅ 已全批落码落籍(2026-10-06/07,主区 merge --no-ff c8beaa2,闸全绿,worktree g-plan2-iter17-pause 分支 iter17-pause-20261006 两会话接力完成,提交 c08a901/fc9eb1e/d44fdd5+收口笔;出口报告=[iter17-pause-exit-report](design/qa/iter17-pause-exit-report-2026-10-06.md))**:暂停层本体+badge 工厂件收编(Q10 甲,营地钥石徽同步迁移观感零变化)+两屏常驻角标入口与 has_open 守卫+四探针断言(结构/点击/输入锁 case⑯/只读巡检/零动效契约/对比度对)+冒烟投影一致性 5 断言;闸=冒烟 788/0(基线 783/0)+run_all 17 套+probe_gate --click 全绿+doc 三闸零新增+MC 零跑(纯呈现零数值);存量移交=熵增闸 design/diagrams 越界(00712d5 总图批落籍漏步,主区同红)+06/07 gdd_lint 存量注记红(本批零触碰);**人闸=用户实机目检**(design/qa/iter17-pause-human-gate-checklist-2026-10-06.md,重点含排播排空副作用确认项 D2。原估 T0-T5≈3.0d 贴软盒内) |
|
||||
| 迭代 17 | **④生涯界面设计立项(2026-10-05 用户令编入本迭代;只做设计提纲不做实装)**:事实源=06「『生涯』界面——冒险中数据回看的唯一承接处」条(P-C7 裁:M9 已退役局内结算明细回看,历史数据现无承接面=用户知情裁决)。考证在册:回看退役已落码(battle_end_overlay/battle_log_view/ui_assembler 三处注记)+settlement_review_overlay.gd 遗留件在盘+跨局持久面=save v5 meta 域+recent_summaries 现役逐局留痕(cap=10,save_manager.gd SUMMARY_CAP——2026-10-06 联审勘误:原记「无历史冒险记录面」系事实错误;真实缺口=cap 扩容+用时埋点+总局数/通关局数 lifetime 计数域〔涉存档 schema〕+营地既有最近冒险清单的去留设计)。任务书形态=设计提纲版:信息架构+承载内容清单(跨局汇总/历史冒险回看/图鉴承接)+与既有界面关系+三期实装建议+待裁点,标注「实装批另行立项」。任务书=`design/research/任务书-生涯界面设计立项-2026-10-05.md`(**v1.1 2026-10-06 联审修订**:F4 改正 recent_summaries 现役/P2 甲口径重述=扩容+用时埋点/总局数通关局数标注涉 schema/营地清单去列入设计稿必答项/N 候选补「维持 10」;T0-T2≈1.25d 纯文档零测试;**✅ 裁点全裁(2026-10-06 用户令全按推荐:P0甲/P1甲/P2甲〔N 实装期定〕/P3甲/P4甲/P5甲);开工=U0**) | 迭代 15 出口 | ✅ **设计提纲已成文待用户评审(2026-10-06 卡④设计批完成,worktree iter17-career-20261006,纯文档零代码零测试)**:提纲=design/gdd/systems/跨局循环/生涯.md v0.1(范围草案——信息架构/承载内容清单/界面关系/分期建议/待裁点五节,P0-P5 已裁结论落文,新发现待裁点 P6 营地最近冒险条带去留随评审一并裁);02 根索引补行+06 状态行换代「设计提纲已成文待评审」。**人闸=用户评审提纲**;评审通过后期一/二/三实装批另行立项(不预占排期。原估 T0-T2≈1.25d 软盒内) |
|
||||
| 迭代 18 | **③武器锻造系统设计提案批(2026-10-06 用户令入迭代 18;纯文档零代码——提案源=playnote 2026-10-06)**:用户提案=攻击力提升改造为「武器锻造」——剑(普攻)锻造升级加攻击、满级附带额外效果;后续增列长枪/法杖,攻击类型分别走穿刺/魔法;护甲由轻甲起级(先只提 AC)→解锁重甲/魔法甲(基础 AC 各异、可续升、满级各带额外效果)——武器/护甲差异化。产出=系统设计提案文档(与奇物属性值提升分类/护甲克制轴/营地柜台/锻造经济边界对齐,数值框架 provisional 终值归 Alpha 收官 M4 数值批统一调整〔未排期〕),裁点呈用户裁决;实装批另行立项。06 已登记专条。任务书=`design/research/任务书-武器锻造系统设计提案批-2026-10-07.md`(提纲版 v1.0——设计裁点在提案产物内全备选呈裁,任务书零待裁点;开工=U0) | 🔨 提案已成文交付(2026-10-07)待盘问裁决(异步不阻塞) | T0-T2≈1.5d(一轮呈裁基线,盘问轮次扩展另计) |
|
||||
| 迭代 18 | **④生涯界面实装批(2026-10-06 用户令入迭代 18)**:按迭代 17 卡④设计提纲(design/gdd/systems/跨局循环/生涯.md v0.1,master 44328b1)实装「生涯」界面——跨局汇总/历史冒险回看/图鉴承接;提纲在册要点=recent_summaries 现役 cap10 扩容+用时埋点/总局数与通关局数(涉存档 schema)/营地最近冒险清单去留(P6 必答项随评审定);分期建议随提纲。任务书=`design/research/任务书-生涯界面实装批-2026-10-07.md`(v1.0——范围=提纲期一〔汇总页+主菜单入口+终身计数域存档 v6〕,期二/期三零触碰;裁点 P1 通关局数口径/P2 汇总条目集/P3 模态登记序待裁;提纲评审若改期一范围则任务书升版) | **✅ 提纲期一追认+裁点全裁(2026-10-07 用户令代解/全甲;P6 随期二)**——开工=U0 | T0-T5≈2.5d |
|
||||
| 迭代 18 | **④生涯界面实装批(2026-10-06 用户令入迭代 18)**:按迭代 17 卡④设计提纲(design/gdd/systems/跨局循环/生涯.md v0.1,master 44328b1)实装「生涯」界面——跨局汇总/历史冒险回看/图鉴承接;提纲在册要点=recent_summaries 现役 cap10 扩容+用时埋点/总局数与通关局数(涉存档 schema)/营地最近冒险清单去留(P6 必答项随评审定);分期建议随提纲。任务书=`design/research/任务书-生涯界面实装批-2026-10-07.md`(v1.0——范围=提纲期一〔汇总页+主菜单入口+终身计数域存档 v6〕,期二/期三零触碰;裁点 P1 通关局数口径/P2 汇总条目集/P3 模态登记序待裁;提纲评审若改期一范围则任务书升版) | **✅ 已落地(2026-10-07 worktree iter18-career:提纲期一追认+裁点全裁〔2026-10-07 用户令代解/全甲;P6 随期二〕后 T0-T5 全落——生涯页六类九项+主菜单入口+终身计数域存档 v6;批末重闸全绿=冒烟 834/0〔基线 814/0,+20〕+run_all 17 套+四探针+ui_contrast 15 对+doc 三闸/熵增闸零新增;MC 零跑;实机人闸挂账待用户〔⑲目检条目随 07〕;出口报告=[iter18-career-exit-report](design/qa/iter18-career-exit-report-2026-10-07.md))** | T0-T5≈2.5d |
|
||||
| 迭代 18 | **⑤混编遭遇首批投放批(2026-10-06 用户令入迭代 18;纯内容批——机制前置=迭代 17 卡①敌人表行集多行批)**:07「后续内容批义务」落地——首个混编遭遇行+Boss 多行内容投放(敌种候选与坐标=本批裁点);首遇教学位纪律与 expect_pools 断言面逐项复核(巨蜘蛛首遇位「固定 2 不加骰」等表注释为准);难度带读数义务随批登记 07,MC 取证跑批**顺延 Alpha 收官 M4 数值批统一执行**〔未排期,届时另令——2026-10-06 用户令:数值统一调整殿后;投放本身不阻塞〕。任务书=`design/research/任务书-混编遭遇首批投放批-2026-10-07.md`(v1.0——纯内容批零代码,机制面全由卡①承载,机制缺口=L3 停机;裁点 P1 首批投放方案〔荐甲=L2 单点试水〕/P2 Boss 多行不入首批/P3 教学界保护待裁) | 迭代 17 卡①落籍(✅ 已满足 9cc4b8b)+**✅ 裁点全裁(P1-P4 甲,2026-10-07)**——开工=U0 | T0-T5≈1.75d(MC 取证顺延另计)——**✅ 已全批落表(2026-10-07,worktree g-plan2-iter18-mixenc 分支 iter18-mixenc 基点 adadf56,批内提交 ad36e35(T1 设计稿)/6272fc8(T3 落表)/43b1306(T4 断言)/⑤T5 收口批;出口报告=[iter18-mixenc-exit-report](design/qa/iter18-mixenc-exit-report-2026-10-07.md))**:(2,5) 双行混编落表〔重击手+巨蜘蛛巢群(行值复制 (2,6),P4 甲零数值新增),R6 行序=重击手在前〕;d5/d7 候选与行值来源全案留痕(d5 案选定);断言面随迁(expect_pools 三元键新池模板+行集构成/行序/Σ≤4 断言);首遇教学位 (2,4)/(3,0)/(3,1) 零触碰;07 ⑱ 目检与读数义务登记+:174 逐行骰措辞订正;闸=冒烟 814/0(基线 811/0,+3)+run_all+doc 三闸/熵增零新增(批末重闸数字见出口报告);实机目检三项归用户(同场两敌种/行序/总数 ≤4);MC 零跑(顺延 Alpha 收官 M4 数值批在案) |
|
||||
| 迭代 18 | **⑦新冒险种子随机化+调试浮窗升级(2026-10-07 用户令入迭代 18,同日两裁点全裁+浮窗目标态已定)**:**(a) 种子随机化**——现状考证 main.gd:1210 `_seed_value()` 调试种子框为空时硬编码返回 42=每次新冒险同一种子全程可复现;改法=玩家界面入口(主菜单开新冒险)默认分支随机生成;**✅ 裁点全裁(2026-10-07 用户令):①首次冒险维持固定种子(教学态可复现)/②测试脚本与调试接口维持显式指定种子(冒烟·MC·探针全链显式传种子零影响,锚零作废)/③种子不进玩家 UI**;断点续玩零影响(存档已载 master_seed 回填,main.gd:447 现役);与⑥收官批零耦合、排序自由。**(b) 调试浮窗升级**(承载「调试浮窗可查当局数据」裁点=种子的唯一查看位;**本项修订迭代 15 卡① P3 甲「仅开始菜单可开·对局不可达」裁决**)——目标态三件:独立于整体界面的**最高层浮窗**(对局中也可开)/DS_DEBUG=1 调试态下**默认打开**/新增**当局数据只读区块**(当前局种子/关卡/节点/HP/GP/钥石等——玩家 UI 不展示、调试浮窗可查)。考证在册(2026-10-07 实查):现行=开始覆盖层角标入口〔main.gd:292-293,DS_DEBUG=1 点亮〕+main.gd:1189 门禁「仅开始菜单可开」+Dialog 形态走 ModalStack 模态栈登记〔非最高层〕+visible=false 初始非默认开+五区块(胜利演出/种子输入/数值滑条/批量模拟/两层调试)无当局数据面。任务书待裁点:最高层与模态栈登记制的关系〔置顶/登记序末+move_child 或独立层〕/输入吞噬边界〔浮窗矩形外透传游戏输入〕/对局发起「随开随收」逻辑改向/ui_tune_probe 断言面换代/入口形态(角标宿主迁移或热键)。任务书=`design/research/任务书-种子随机化与调试浮窗升级批-2026-10-07.md`(v1.0——实装级裁点 P1 遮挡语义〔荐甲=维持登记制〕/P2 入口形态〔荐甲=角标迁宿主〕/P3 默认打开范围〔荐甲=启动即开〕/P4 当局数据字段集〔荐甲=六项〕/P5 首局种子值〔荐甲=沿用 42〕待裁;估时勘误 1d→2.0d 含探针换代与收口) | **✅ 已落地(2026-10-07 worktree iter18-seed:C1 种子三分+浮窗升级 P1-P6 甲全落;批末重闸全绿=冒烟 811/0+四探针+run_all 17 套+doc 三闸/熵增闸零新增;MC 零跑;实机人闸挂账待用户〔不阻塞落籍与后续卡④〕)** | T0-T5≈2.0d |
|
||||
| 迭代 19+ | **M4 数值批(**Alpha 收官位·未排期**——2026-10-05 用户令编入迭代 17 卡②;2026-10-06 用户令移出独立成批并定序「Alpha 阶段最后——内容补全先行、统一数值调整殿后」〔当日曾被编入迭代 18 为收官卡,2026-10-07 用户令撤回〕;2026-10-07 用户令:**暂不启动**,移出迭代 18,保持 Alpha 收官位待用户发令)**:四件数值欠账合一批——①削弱档位终值(weaken 现值 −65/duration 2/refresh 考证在册;叠层改续时语义已定案,差 duration 终值+当量锚复算)②调参批数值点评(06 条目现行登记五条——任务口径「八条」与条目五条不符,任务书 §2.2 已呈报差异以条目为准)③迭代 10 奖励重构联动欠账①②(钥石产出重标 boss_keystone 首杀 3/3/3·复杀 2/2/3 provisional + 通关率带重扫〔通关回血 20%+AP 件首轮 +1〕)④元进度定价剩余面(forge base 20/比 150 考证在册——06 条目文本「base 10」滞后于 2026-09-22 对齿批已呈报;Boss 两档终值)。读数义务随批=迭代 14 两件后置复算(T6 MC 四带复算+T7 技能池节奏重测,均挂 07);顺路修复 damage_probe A1 改前既有红灯(判式换代批出口报告 §四.7 在册)。**硬约束:一切 MC/verifier 跑批发起前须用户批准;调参联动禁独立调参网络(β 带 [1.2,2.5] 逐 u 检算)**。任务书=`design/research/任务书-M4数值批-2026-10-05.md`(**v1.2 2026-10-06 案C 增补+联审修订**:v1.1 三事实与第五推算件照旧;联审=P3 转正顺延至重扫读数后/检算工具 WEAKEN_PCT 入同步面/F11 两句死文本全刷/T3·T5 四带复算并账一次跑批双认账/R5 改前锚=本批新立案C 锚/估时段一勘误 4.25d;案C 增补内容照旧=§2.6 三事实〔行为换代/锚全作废/难度预判〕+T0 推算稿第五件=对拍锚按新序重推导+T6 四带复算按案C 新行为首采;T0-T8≈6.25d,天然切分点 T4 末;🔴 契约 5 条含跑批批准制;**✅ 裁点全裁(2026-10-06 用户令:P1甲=维持 2 场·magnitude [60,85] 带内当量锚复算、具体值随出口 provisional 追认/P2甲 不对称有意/P3甲 3-3-3·2-2-3 维持、转正顺延至重扫读数到账且带内(Q4 二裁)/P4甲 不立直购价);开工=U0**) | 迭代 18 全部内容卡(③④⑤⑦)出口+全部内容批行为变更落定+**用户发令(未排期)**——重锚窗口须收尽全部内容批行为变更 | T0-T8≈6.25d(超软盒预挂,段一 T0-T4≈4.25d〔v1.2 勘误,原 4.5 系加总错误〕/段二 T5-T8≈2.0d) |
|
||||
|
||||
Reference in new issue
Block a user