Compare commits

..
Author SHA1 Message Date
DKChan a0f24502f1 fixup! iter45-卡②T2: 断点域拆件 breakpoint_store(R2整族归件v1.1)——六成员(save_manager/resume_bp/pending_next_level/last_level_payload/last_treasure_cleared/loadout_seeded)+BREAKPOINT_FIELDS 27键冻结+函数族九个归件:纯读侧三函数与_bp_parts/snapshot body逐字(宿主输入state/level_index/master_seed/runner/counters逐调传参——件禁反向持宿主),四_resume_*按所有权缝语句分家:件侧(主角账三件restore_fragment/curio池与特性还原/stop与bank片段回填/数值账规范化钳制)迁store五个回填函数,宿主侧(八项重绑定与_reset_curio_state/_attune_refresh_x_total调用)按原语句序吸收进resume_adventure壳,引用束九引用解包为原名成员保body逐字(6+9=15贴顶);宿主留_snapshot_breakpoint一行委托壳(CurioStop的Callable目标零改)与set_save_manager转发件,断点键面零变化,语句序逐步保形;测试:185改址BreakpointStoreScript.BREAKPOINT_FIELDS(判据零变化——第14节申报)〔补件 V2〕;验证:run_all三套件全绿+run_smoke 15项0失败 2026-10-31 00:03:24 +08:00
DKChan d0b832ec46 fixup! iter45-卡①T3: ui_input_probe 直读改址 u.face.*——四处断言(case①②③⑭ hl_visible/hl_color/dot_visible/mutation_mark,11处)+case④b封印纹理槽 st.tex_seal 两处(设计文档§1.4直读面清单漏计的第五处,L1就地修复)——断言条件与期望值零变化,只改读路径;T0定谳绿凭据下的改址义务落码收口〔状态件 V4〕;验证:probe_gate --click --full 全绿+render_gate golden三张0.00%复跑 2026-10-31 00:03:22 +08:00
DKChan 039caf15e4 iter45-卡②T2: 断点域拆件 breakpoint_store(R2整族归件v1.1)——六成员(save_manager/resume_bp/pending_next_level/last_level_payload/last_treasure_cleared/loadout_seeded)+BREAKPOINT_FIELDS 27键冻结+函数族九个归件:纯读侧三函数与_bp_parts/snapshot body逐字(宿主输入state/level_index/master_seed/runner/counters逐调传参——件禁反向持宿主),四_resume_*按所有权缝语句分家:件侧(主角账三件restore_fragment/curio池与特性还原/stop与bank片段回填/数值账规范化钳制)迁store五个回填函数,宿主侧(八项重绑定与_reset_curio_state/_attune_refresh_x_total调用)按原语句序吸收进resume_adventure壳,引用束九引用解包为原名成员保body逐字(6+9=15贴顶);宿主留_snapshot_breakpoint一行委托壳(CurioStop的Callable目标零改)与set_save_manager转发件,断点键面零变化,语句序逐步保形;测试:185改址BreakpointStoreScript.BREAKPOINT_FIELDS(判据零变化——第14节申报)〔补件 V2〕;验证:run_all三套件全绿+run_smoke 15项0失败 2026-10-30 23:55:39 +08:00
DKChan eec93e09a8 iter45-卡②T1: 悬停域拆件 board_hover——11函数族+_hover/_last_click两成员迁出(函数体逐字,三处机械改写:_cell_at→_cb_cell_at.call带类型标注/hover_forbidden与chord_attempted.emit→注入Callable.call/mouse_default_cursor_shape写入→_cb_cursor.call),COL_HL_TARGET/CURSOR_DIG/CURSOR_MOVE_SEM/CHORD_WINDOW_MS随函数迁常量、COL_SEAL双侧服役各自alias UiKit单源,三入站口(_gui_input/_on_cell_input/click_cell)与hover_probe读面留宿主委托,_r0留宿主;构造=引用束字典注入(cells/minesweeper/diggable共享引用+格命中换算/光标写入/两信号发射Callable)防max-parameters新键,minesweeper重绑由rebuild同拍回写件成员〔补件 V1〕;验证:probe_gate --click --full全绿+render_gate golden 8屏OK;键账board_view类变量32→31(只降不升)/公开方法27持平 2026-10-30 08:49:52 +08:00
DKChan 7c8f0c2832 iter45-卡①T3: ui_input_probe 直读改址 u.face.*——四处断言(case①②③⑭ hl_visible/hl_color/dot_visible/mutation_mark,11处)+case④b封印纹理槽 st.tex_seal 两处(设计文档§1.4直读面清单漏计的第五处,L1就地修复)——断言条件与期望值零变化,只改读路径;T0定谳绿凭据下的改址义务落码收口〔状态件 V4〕;验证:probe_gate --click --full 全绿+render_gate golden三张0.00%复跑 2026-10-30 08:38:59 +08:00
DKChan a7f3d92e88 iter45-卡①T2: 站桩两状态件建件与宿主改造——_StandeeState 真实25成员沿身份命值/资产演出缝拆 standee_vitals(12成员,apply_hp=_set_hp整体搬移,hp_value setter逐字)/standee_motion(11成员,六迁入函数:set_portrait_texture(tex,flip,box)/register_hero_state/apply_hero_state(is_hero参判,三连早退序逐字)/reset_state(RESET绕同态早退两拍封装)/play_intent_motion(charge参判)/state_probe),HeroState枚举与_HS_NAME/_HS_VALUE随三态机归motion(全仓零外部消费实测);宿主10成员(五冻结var+st/mo+三演出探针计数器上收),转调壳三入口外形零变,fx_probe改读宿主计数器,tween路径串st.hp_value/mo._intent_scale/mo._glyph_rot,源码锚三函数(_draw_hp_bar/_draw_armor_name_line/set_pending)留宿主且锚行逐字(st=vitals名沿用故血条/名字行零改写)〔状态件 V3〕;battle_stage_view一行未改实测;孤立验证run_all两套件全绿+run_smoke 2026-10-30 08:26:46 +08:00
DKChan 2b26cae9e4 iter45-卡①T1: 单格两绘制域件建件与宿主瘦身——_CellPaintState 27成员沿绘制层域轴拆 cell_base_layer(12成员+九函数+九常量,draw_base入口)/cell_mark_overlay(13成员+六函数段+draw_centered_text单点化,四绘制入口),宿主退六步时序器类变量33→10(edge/cell/glow_group上收+glyph/glyph_color/plate/fog_state/_glow_layer冻结面原位+base/face两实例),board_view写入面49处改址(u.st.X→u.base./u.face./u.edge/u.glow_group,u.st.清零)〔状态件 V1/V2〕;逐字搬运+三处机械改写(st.X→裸成员/draw_X→canvas.draw_X/st.edge→rect.size.x),draw_glyph_layer增plate第5参(设计文档§2.1'plate绘制侧零消费'系413124b0恢复守卫前的过时实查——现行if plate:守卫在位,迁出即随行,保golden 0.00%零漂移);孤立验证:render_gate golden三张0.00%+run_all四套件全绿+run_smoke 15项0失败 2026-10-30 08:17:58 +08:00
DKChan 14054d9dfb 注销(待办): 技术债观察登记条目整条删除(lambda连接防回归)——三层社区标准方案已闭环:①预防层code-conventions §4.1两条明文纪律在册(多行lambda禁嵌match/信号处理体一律命名方法+bind;捕获循环变量先落地再捕获)②体外扫描层error_scan.py三段扫日志命中即红在役③捕获语义类静默错误由测试断言承接;静态层确有缝(gdstyle 23条quality规则无lambda专项)但本事项仅是数数观察不拦任何坑,补缝唯一方式=闸件加规则,而危险形态(多行lambda嵌match)全库117处实测零存量、登记半月零事故,为零命中形态写闸件属过度工程;社区论证凭据=官方提案godot-proposals #4736永久拒绝try/catch、错误码哲学为设计决策非版本bug 2026-10-30 06:38:33 +08:00
DKChan d2f282d9bc 登记(待办): 棋盘封印印记图形换代一条——现件 seal_mark.png 仍是经典扫雷旗形(旗面+旗杆),2026-09-28 只换色未换形;用户欲改法阵或锁链,形未定故只登记待美术设计,缺口列五待裁点(形/封印黑不变槽是否松动/32px 内是否侵入数字字形区/战末金蜡封徽记与悬停印记形光标两处连带件/与施印特效+印记常显两件的合并关系),实况记消费面两处与文档侧仍写「旗」的口径点(art-bible §4.1 旗杆前提+§3.2、art-assets-checklist §3.3/§4、battle.md:128/:270),改动面=文档+美术素材;格式与退役词闸全绿 2026-10-30 06:16:13 +08:00
DKChan ab3b4a9d80 同步(工程批收尾): test-conventions §7覆盖率句两处旧口径随a2ec3e8b裁决换代——「是否引入待办清单在册待裁」改直陈不引入(条目已删裁决已落),「现行补洞=零指名单测清单」改能力清单覆盖域表(零指名机制已被能力清单模型取代);规约修订经doc-design入口落笔,零待裁点,用户已发令;断链面已核仅此一处 2026-10-30 06:10:21 +08:00
DKChan fbed817fbe 注销(待办): qa/收尾孤儿遗留余二项整条删除——第5项字面量墨收测前置登记两头失效:主任务(iter19卡②墨色收测)随卡退役无现役承接,前置立常量不成立(实测bcard四处色值仅选中底#8A5A34在art-bible色板在册[木色§7.2],✓章#3A2A08/描述#4A3A28/脚注#6E4534三处游离色板外,真要动第一步是美术线色板准入/换色合并非ui_kit常量化);第7项商店房截图纳屏诉求剩余面只剩像素级(结构面ui_struct_probe _audit(shop)与交互面ui_click_probe已覆盖),像素面shot_probe头注已定谳不纳屏(真实路径不可达+合成投喂违反该探针口径),真缺口(商店屏文字对比度无机检)按未实测不启用不立新条,试玩出观感问题再按当时形态登记 2026-10-30 06:00:04 +08:00
DKChan 0caa2f5b7c 刷新(待办): 技术债观察条目长函数半边核销——点名四件(level_map_screen选路装配原155行/camp_overlay_view原152行/debug_overlay原114行/treasure_item_table schema校验群)实测现各文件最长函数仅25-44行全部消解,S13质量闸扫面覆盖core+data+presentation基线冻结禁恶化已接管防回归;条目缩为lambda连接观察(76处读数归属2026-10-15,测试面其后多轮重组分布口径未重测) 2026-10-30 05:54:45 +08:00
DKChan 30fdec1a62 写卡(迭代 44 卡③测速循环批 v1.1 停卡重裁): 实现段 T0 三重证据定谳卡③核心前提已被迭代 41 测试债批消化——215da315 提交信息明载「tune_sim 运行态收尾归还 run」+wd8 三断言(现位 :145-147)与 ui_tune_probe 全链路实跑两面全绿(停卡呈报=iter44 worktree reports/iter44-实现报告-2026-10-30.md §5),按停卡呈报建议案重写卡片——剥离已申报行为改动 V3(收尾置假还原无对象,还原已由迭代 41 完成并申报;完成定义改「diff 中行为改动零处」,对照表 V3 行改定义为非行为改动行=收尾四语句同帧同相位迁入 _finish_batch 的回归锚面,wd8/probe 判据「零改动转绿」改「零改动保持绿」),T0 义务改现状复核(两面实跑应绿——绿=按无行为改动形态开工,红=停卡呈报),夹具=现行产品码 await 形态逐字副本、与产品码新形态申报差异两处减一处(只余夹具暴露 stats 供对拍),全部 file:line 按 2026-10-30 master 重锚(run :36-54/_run_one_level :58-68 尾部实为败局记账/wd8 :139-147/基线键 :15;S8 九文件漂移订正十文件),architecture v1.25 S13 注销句保持(注销对象是 await 豁免不依赖行为改动申报,句内申报半句随实现批现状化——同步面注记),§16/§17/§13 随动;待办清单条目实况同批订正该失效申报句并登记重裁凭据(状态行维持已写卡+已编迭代 44——v1.1 落定即重立),roadmap 迭代 44 行不动 2026-10-30 05:52:44 +08:00
DKChan a2ec3e8b94 工程(渲染闸脚本错误扫描): 三段探针日志逐段过 tools/error_scan.py 补三硬闸之二——shot(shot_checker 之后)/fx/board 各一次,命中或日志不可读即红,标记与 run_smoke 同源;头注补⑤与「新增日志段必须同步加扫描」纪律
验证=合成日志三分支(clean 0/命中 1/不可读 2)+真跑 render_gate exit=0 全绿(三段零命中、残留 Godot=0、golden changed 0.00%)+文档域闸五件 PASS。
文档同步=architecture 测试域两处「SCRIPT ERROR 扫描缺失」换代、game/tests/README.md 工具行补判定面。
清单=「测试域遗留」整条删除(第 1 项被能力清单模型取代/第 3 项与 test-conventions §6 存量不清扫口径冲突且多进程分片后前提消失/第 4 项行覆盖率用户裁无意义/第 2 项即本批);基线条目扩为 02/05/09 三键(05 主区实测绿,baseline 红键属代码面,随下一代码批在 worktree 内重生成)
2026-10-30 05:39:33 +08:00
DKChan 2a5174d2a9 文档设计(美术出图登记轻量化): 出图登记义务四字段(模型名/分辨率/seed/对话日期)缩为必注两项「用途+生成时间(YYYY-MM-DD HH:MM)」,参数有则记、无则不填,登记不再作正稿遴选前置——旧口径卡住用户在途出图管线(线上对话式生图拿不到模型名与seed,分辨率与时间文件属性自带);立规处remote-gen-prompts头注改写(标题复现性→出处备查),转抄两处同步(art-assets-checklist §3.5/art-prompts §5流程注),手绘件登记项(手绘者/日期/源档尺寸)并入同一轻量口径(作者有则记);art-prompts版本号v2.10→v2.11;待办清单条目同批登记并删除(net-zero) 2026-10-30 04:52:50 +08:00
DKChan 3607271575 注销(待办): 在途草稿整理批(3349 失管草稿)整条删除——审计 P2-1 口径错配:ui-reuse-2026-09-23 系下载的第三方 CC0/OFL 素材包(占 3043/91%),vN 命名率与冗余量法对第三方包不适用,实测重复文件仅浪费 0.1MB;artwork/ 与 archive/ 均 gitignored,不进提交/构建/交付,不构成维护成本;用户裁不处理。留档约束:该包不可整删——quantize_ui_skin/render_sample_sheet/render_sample_sheet_v3/render_level_map_sheet 四个工具脚本按路径引用其中的字体/面板/图标/石纹 2026-10-30 04:30:19 +08:00
DKChan 9154f03b48 收尾(场景探针闸合并批): 待办条目完成整条删除——03/04并「03 场景探针」一行,窄试车十段exit0 2m22s,worktree全量闸all_green=True 3m25s,基线两键随批换代(b1e0f29f);引用面三处同步(README/process-conventions/iter技能) 2026-10-30 04:29:01 +08:00
DKChan b1e0f29fe3 合回(工程批·场景探针闸合并·基线换代): baseline.json两旧键(03探针--click/04探针--full)换「03 场景探针」green键;worktree全量闸复跑all_green=True(15闸全0,03场景探针真跑十件)——批本体55a8f270,验证3m25s 2026-10-30 04:28:39 +08:00
DKChan cfb528b917 工程(场景探针闸合并·基线换代): baseline.json删「03 探针 --click」「04 探针 --full」两旧键、预置「03 场景探针」green键(实测真值=本worktree全量闸03场景探针exit0十件全跑);02/05/09存量红键未动——归「闸基线两键换代」在册条目 2026-10-30 04:20:46 +08:00
DKChan 55a8f27026 工程(场景探针闸合并): 03/04两闸并一行「03 场景探针」——gate调用probe_gate.sh --click --full一次跑齐十件(公共五件只跑一遍,窄试车2m22s十段exit0),04号让空不重排;影响面SKIP块与头注/影响面注释同步;README闸03/04提法与process-conventions影响面句换代;probe_gate.sh零改动(--click/--full保留为开发期单跑开关) 2026-10-30 04:08:48 +08:00
DKChan f9fa8d85fa 登记(工程批): 场景探针闸合并——03/04两闸并一行+闸名换代(probe_gate.sh零改动,公共五件去重复跑) 2026-10-30 04:05:02 +08:00
DKChan c8f5091d0f 收尾(迭代43批后收尾): 反哺点13条处置闭合——落文四处(art-bible v3.23 §1.4样张登记句与§6.1素底牌实装事实/art-prompts v2.10 §5产出状态/战斗表现 v1.2五项过闸状态/test-conventions粒度句撤销措辞按§8.4口径清偿),消解三条(AGENTS红线已换禁变异禁撤销新口径/血条tween缺陷已由迭代41测试债批修复/该条留档备查),移交两条目(批后待裁三点=B区高度270vs252对齐方向·名字行12px档位归属·换色常量退役/批后小件=能力清单补行归写卡段·意图徽标四色墨CHECKS补断言),方向稿目检登记体验验证清单㊶(方向稿气质/改前改后对照/类型微光provisional观感复核并入,㉘节陈旧批指订正)——产出物退役:iter43实现报告/反哺点/验收审计/代拍板追认单与两卡需求卡片(2026-10-28定稿卡+2026-10-16旧v1.4卡)按吸收即死删除;二三关棋盘观感条目陈旧前置句换代(样张目标规格清单已落art-bible v3.22)——账面换代:待办清单样张条目整条删除+roadmap迭代43行已完成(2026-10-30)/卡片报告列退役保留字+当前位换代(迭代位1–43全完成,下一步=迭代44开工前宜裁PARITY查因重锚与待裁三点) 2026-10-30 03:23:05 +08:00
DKChan d3b977480e 合并工程批(parity-rm-20261030): 对拍闸退役批合回——回放确定性对拍闸(原11号条件闸)整闸退役:闸脚本6c段删除/PARITY_TOUCH_FACES改名CROSSCUT_TOUCH_FACES(02横切回落保留)/基线删条目/parity_anchor.py+parity_compare.py+evidence/parity锚三件删除/tests README能力行与工具行删/架构文档闸清单与验收红线清理/待办清单对拍挂账清理(含并行收尾批新登记的查因重锚条目注销)/迭代44在册卡V0验收载体随退役换代七处(用户裁:整局重放对拍代价不可承受,正确性由既有单测/集成/探针/渲染golden承载);两度并master(闸机提速批+迭代42批后收尾)零冲突;全量域闸全绿回执e79c04e8(domain=full,scope=full,changed=[]) 2026-10-30 02:59:54 +08:00
DKChan e79c04e891 工程(对拍闸退役批·连带二): 删除并行收尾批新登记的「PARITY对拍锚漂移查因与重锚」条目——退役批已删锚与工具,条目主体不存在,查因重锚随闸退役一并注销 2026-10-30 02:56:22 +08:00
DKChan 05d1988fcd 并master(迭代42批后收尾)——架构v1.26反哺点落文+批末移交小件登记 2026-10-30 02:55:50 +08:00
DKChan 7ec2af581a 收尾(迭代42批后收尾): 反哺点两处分置闭合(反哺点1落文=architecture v1.26 ShopSession行对外暴露格按委托壳拆除后实测直连面重写——直连方法清单16+白盒2与set_shop_pool调用面改述;反哺点2豁免登记被零豁免裁决消解不落,v1.25豁免注销在先)——产出物退役:iter42实现报告/反哺点清单/验收审计与两卡需求卡片按吸收即死删除(卡片死期=实现批合回;报告遗留义务先迁:S13重锚6键离账折入零豁免条目收账句、PARITY对拍锚漂移查因与重锚新立条目、批末小件四条新立条目)——账面换代:待办清单尾波清偿批与商店委托层拆除两条目整条删除+roadmap迭代42行已完成/卡片报告列退役保留字+iter41注脚152死键refresh已执行订正(fafb4fee)+当前位换代(迭代位1–42全完成、迭代43已合回待收尾、下一步=iter43收尾与迭代44开工) 2026-10-30 02:54:15 +08:00
DKChan 6b17d8f307 并master(闸机提速与防作废批合回)——02分片并行+代码域起手自检+worktree素材同步,与对拍退役批同改闸脚本,冲突就地解 2026-10-30 02:46:54 +08:00
DKChan 42c7d879ed 工程(对拍闸退役批·连带): 迭代44在册卡「战斗编排归约批」七处对拍引用随退役换代——V0验收主载体由PARITY对拍改挂关联套件并集(用户裁:其他测试函数保证正确性)、能力行引用换代、§2待裁点⑤注销、§3触面句与§4契约句、§13零触碰声明、§14 L3条款④⑤重排、§16审计凭据句——pipeline_gate 13卡全过 2026-10-30 02:38:57 +08:00
DKChan 8491505929 工程(对拍闸退役批): 删除回放确定性对拍闸及全部配套件——闸脚本6c段整删、PARITY_TOUCH_FACES改名CROSSCUT_TOUCH_FACES(02横切回落判定保留)、回执指纹NEED-APPROVAL分支清理、基线删11号条目、parity_anchor.py/parity_compare.py两件删除、evidence/parity锚删除、tests README能力行与工具行删行、adventure_monte_carlo台账行换代、架构文档闸清单删条件件与验收红线史句清理、待办清单数值窗口删对拍锚重锚句与触面粗粒度挂账行删、settle_segments_test头注去失指句——用户裁决:整局重放对拍代价不可承受,正确性由既有单测/集成/探针/渲染golden承载 2026-10-30 02:28:28 +08:00
DKChan db5abb8527 收尾(闸机提速与防作废批): 待办条目完成整条删除——实测全量闸3分29秒全绿66套件(对照基线约24分);窄试车6态;素材同步实战补拷247件;iter技能合回段三连成文;C批探针渲染并行未立项 2026-10-30 02:23:57 +08:00
DKChan 4ecdcf444f 合回(工程批): 闸机提速与防作废——02分片并行(run_all.gd加--shard/--shard-count,串行道=RNG日志会话六套件钉第1片防同种子日志互踩,空片放行,逐套件日志_s<k>防覆写)+gate_unit多进程(GATE_SHARDS默认4,=1回落原路径,片序合并日志供错误扫描与指纹取材——指纹绿记green红取FAIL排序集,免记账换代)+code域起手自检(熵增预检红灯即止/master推进黄牌/素材自动同步)+tools/sync_worktree_assets.sh(增量拷assets与.import边车,缺件或缺.godot时编辑器导入刷新,相对路径防杂散目录);窄试车6态+全量闸实测3分29秒全绿66套件(基线24分) 2026-10-30 02:23:18 +08:00
DKChan 1ee65d854b 工程(闸机提速批): 02分片并行+代码域起手自检+worktree素材同步——run_all.gd加--shard/--shard-count分片(串行道=RNG日志会话六套件钉第1片防同种子日志互踩;空片放行;逐套件日志_s<k>段防跨片覆写)+gate_unit多进程并行(GATE_SHARDS默认4,=1回落单进程原路径;日志按片序合并供错误扫描与指纹取材——指纹绿闸记green红闸取FAIL行排序集合,不受片序影响)+run_all_gates.sh code域起手自检(熵增预检红灯即止/master推进黄牌/worktree素材自动同步)+tools/sync_worktree_assets.sh(主区→worktree增量拷assets art与.import边车、缺件或缺.godot时编辑器导入刷新;相对路径拷贝防杂散顶层目录) 2026-10-30 02:17:05 +08:00
DKChan 31c801cd5a 登记(工程批): 闸机提速与防作废批——02分片并行+代码域起手自检+worktree素材同步(来源=迭代42合回六轮重跑复盘会话; C批探针渲染并行缓做不立项) 2026-10-30 02:11:47 +08:00
DKChan 65dff22fcf 合并迭代42: gdstyle尾波清偿批+level_runner商店委托层拆除 2026-10-30 01:42:26 +08:00
DKChan 0fc656c6ac iter42-收尾: 实现报告反哺点验收审计落reports+PARITY归因落档(迭代40/41存量) 2026-10-30 01:37:01 +08:00
DKChan 9c12d0a683 iter42-卡2: level_runner委托壳19枚拆除+shop公开化直连键7=33+残留零真残留+基线记账03/04/05(用户裁) 2026-10-30 01:34:06 +08:00
DKChan 66e6d0452a iter42-卡1: gdstyle尾波清偿批——board_view五段拆分与构建器/装板域拆BoardInstaller/wr5改址,键1-4+9+10归绿 2026-10-30 01:33:47 +08:00
DKChan 3b66d1a689 合回(迭代43): 战斗一屏样张批单卡合回——五项实装定值(血条#A8321F/条底收常量/徽标FS_HINT/护甲三枚PNG/名字行素底不压地台/地台件九宫格接装)+样张脚本扩展(两版出口/整屏四项S1–S4/战斗表现五项P1–P5/V1/V10/A5b,机检30/30全绿)+新单元套件standee_present_values(V5–V9十八断言)+theme_projection V4锚换代(§5.5同生死,双半强替代);全量双域闸全绿回执34eba7a3(domain=full,scope=related,16闸15绿+对拍SKIP);独立验收审计通过(三自查跑批原样绿,V1–V10十行全过,削弱零缺漏);批件三份+审计报告落reports,反哺点13条归文档批 2026-10-30 00:23:22 +08:00
DKChan 0c5eb2133d 审计(迭代43): 独立验收审计通过可合回——审计报告落reports(三自查跑批原样全绿:样张30/30、单测18/18、theme_projection164/164;V1–V10十行全过;削弱检查零缺漏,V4锚换代证实双半强替代);实现报告§7结论落位+V6行号笔误订正;反哺点13补意图徽标四色墨机检断言(审计附注,复算4.97–5.62全过) 2026-10-30 00:22:31 +08:00
DKChan 34eba7a332 iter43-卡1:战斗一屏样张批:五项实装定值落码——血条填充#A8321F经UiKit.HP_BAR_FILL(§4.2语义物件,#689CE8退役值零残留)/条底收HP_BAR_TRACK/顺位徽标提档FS_HINT/护甲三键换24×24 PNG(UiKit.TEX_ARMOR_*单点,缺位回退字形)/名字行垫HP_BAR_BACK素底牌且基线上移地台顶上方(§6.1/§7.2,几何单点_name_plate_rect+name_line_probe扩出口)/地台件TEX_STAGE_PLAZA九宫格横向拉伸接装(缺位回退程序化三段)——样张脚本扩展:draw_base两版画布出口(1280×800基座+1920×1080全局等比1.35×左右黑边96px)/B区按代码252出样/mockup镜像五项定值/S3b色板变体第二套/S5三组关键帧条/S6剪影三语境+描边对照+遮挡对照组/整屏四项断言S1–S4/战斗表现五项P1–P5/A7护甲对比锚/V1两版尺寸/V10基线并排/A5b成稿净空(机检30/30全绿)+--gen-assets四件素材产出入包;新单元套件standee_present_values(V5–V9真实入口断言18条全绿)登记manifest;三枚护甲PNG入包;批件三份落reports(实现报告/反哺点12条/追认单11条);并master合入态订正(迭代41测试债批清偿存量红与tween缺陷) 2026-10-30 00:00:01 +08:00
DKChan d9e5c019fd 收尾(迭代 41 测试债批): 待办条目「迭代 41 测试债修复」完成整条删除+收尾实现报告落 reports/(登记范围完成度+实测扩出的四处迭代 41 特许合回遗留产品回归:数字色牌守卫/open_victory opts 改型/站桩补间目标/调参模拟运行态收尾,含 golden 2.74%→0.00% 与墨族自适应读数证据+闸回执读数+实机目检三项);新立条目「闸基线 02/09 两键换代」承接已归绿存量红指纹的重生成(代码面,随下一代码批落) 2026-10-29 23:07:39 +08:00
DKChan 43906cdd8c 合回(迭代 41 测试债批): 代码域闸全绿回执 afd1a41f(域=code、scope=full、02/09 基线红→现绿、零新增红)——9 套件+S9/S10/S11 归零+死常量 SCHEMA_VERSION 删除+iter41 特许合回遗留的四处产品回归修复(数字色牌守卫/open_victory opts/standee 补间目标/调参模拟运行态收尾)+探针与测试面随拆件改址 2026-10-29 23:03:57 +08:00
DKChan afd1a41feb 修复(迭代 41 测试债批·02 收口): config_db_test meta 行族改直读表成员(_meta_rows 访问器随 iter41 退役)——02 单元与集成全套件归绿 2026-10-29 22:54:37 +08:00
DKChan 413124b0b8 修复(迭代 41 测试债批·闸面续修): 03/04/05 三闸归绿——①board_cell_unit 数字色牌守卫恢复(iter41 卡2 分层拆分丢 if plate: 致 dungeon 数字一律垫牌,L1 棋盘 golden 由 2.74% 回 0.00% 逐像素复现基线);②curio_interact_controller.open_victory 第 4 参随 opts 改型(字符串→{"gp_summary":…},胜利总结面续玩恢复路径运行期断链);③探针随 iter41 拆件改址(ui_input_probe 格面成员入 st 六处、ui_struct_probe level_screen._runner→._map._runner);④config_db_test 商店行族改直读表成员(_shop_rows 访问器已退役) 2026-10-29 22:45:09 +08:00
DKChan 39c1fc69fb chore(todo): format 2026-10-29 22:29:36 +08:00
DKChan 833d483ef8 编排(迭代44/45): 零豁免五键四卡+补件批按用户裁编法编入——迭代44=组合根注册面批+战斗编排归约批+测速循环批(中值合计≈7.875个工作日,卡序A/B/D),迭代45=呈现层状态件批+gdstyle尾波补件批(≈7个工作日,卡序C先/补件后-board_hover半边硬前置);编排四查过(五卡在盘/凭据齐=architecture v1.25+设计文档+grilling复核过/估时常规区间/闸PASS交叉核7链);战斗域结构深拆批条目状态累积已写卡+已编迭代44两段(专指宿主瘦身子项,其余两子项仍待文档设计);编入不等于开工,实现段由用户/iter发令 2026-10-29 21:58:36 +08:00
DKChan 9855bf0a10 复核(grilling五卡)+修正: 复核报告落盘——五卡全部有条件成立/零回炉,file:line抽验约90处命中,键账成员迁移账全平,与五项用户裁决零冲突;blocker1项修正(卡A与iter42文件交叠失实声明改为如实+开工前置=iter42合回);应修9项全落——卡A/B互写ui_input_probe共享触面禁并行,卡一board_hover半边硬前置升格+resume_adventure行号订正:141+V1判据面改型后口径+引用束计数实数,卡一表D补_flush_row_queue转发壳归宿,卡二对照表行2/11静态判据移域口径申报(行2改回归主证/行11改全量闸半边),卡三算术订正(删24项=37-22-2+2新=15账平),卡五测量面专属能力行「调参测速批量模拟」当场入表并改锚三行(废悬置) 2026-10-29 21:06:12 +08:00
DKChan 755dd8232c 写卡(零豁免五键·后两卡): 《呈现层状态件批》v1.0(单格两层域件+站桩两件并一卡,30→10/19→10真实25成员纠偏,潜伏红T0定谳随批修复,估时3-5天)+《测速循环批》v1.0(process_frame信号步进状态机,申报行为改动=收尾置假还原,双实现对拍入批,估时1-1.5天)——均零待裁点开工门U0;五键批条目翻已写卡(四卡路径逐行入实况,战斗编排归约批记账归战斗域结构深拆批条目);测量面能力行锚定按库内先例申报,专属行入表列写卡段后续 2026-10-29 20:30:37 +08:00
DKChan 672407dd5a 写卡(零豁免五键·前两卡): 《组合根注册面批》v1.0(main 49→15,ui_registry+三域容器,867改址,估时3-4天)+《战斗编排归约批》v1.0(RoundCycle/BattleFacts,38→15,估时2.5-3.75天,编队前置=iter42合回)——均零待裁点开工门U0;卡B接收方=在册条目「战斗域结构深拆批」宿主瘦身子项(实况补承接更新:设计闭合v1.25轴丁+豁免第三条注销,其余两子项仍待文档设计);卡B静态键账判据按test-conventions §8.4出口移散文申报 2026-10-29 20:05:45 +08:00
DKChan 183f4da3a4 设计闭合(零豁免五键+补件批): architecture v1.25落文——S13三条豁免注销(main/battle_orchestrator/tune_sim),七新件登记行(ui_registry/board_hover/RoundCycle/BattleFacts/cell两层域件/standee两件/breakpoint_store),轴丁两件设计闭合,attune改判,gdstyle inner-class计数截断缺陷登记;用户再裁恢复D2/D4拆件并按D5留债写入尾波条目(批末豁免登记步骤不执行);新卡《gdstyle尾波补件批》v1.0(零待裁点,估时2.5-3.5天,待iter42合回编入);待办清单新增补件批与零豁免五键两条目;roadmap迭代42状态按用户口述订正为进行中 2026-10-29 19:49:43 +08:00
DKChan ee4efad54e rules(行为提醒精简): AGENTS.md「主动检索提醒」节改一句话版(用户裁定)——「训练记忆缺失或可能过时的问题,先搜最新主流的答案再回答。」触发判据由轨迹数据导出:四类实例(引擎 4.7 迁移指南核实/gdUnit4 选型/Godot 4.7 最佳实践判据轨/art-bible 参考池误判勘误)共同点=答案在仓库外且训练记忆缺失或过时,故弃「不确定」自判与题材枚举两版草案;首版四条细则随精简删除——引擎指针已在 Engine Version Reference 节、外查证据纪律各红线已覆盖,均属重复 2026-10-29 07:42:19 +08:00
DKChan e8c6f9e572 编排(迭代43): 战斗一屏样张批单卡编入——中值≈6.5个工作日(区间5.5–7.5)处5–10常规区间,状态待开工;编排四查过(卡片在盘=合回提交cc0627ba入库版/美术线凭据齐=实况2026-10-28美术设计段闭合+art-bible v3.22条款版本在关联文档清单/估时常规档/流水线闸PASS总表43行交叉核3链);零待裁点开工门U0;用户2026-10-29点名编入迭代43 2026-10-29 07:25:12 +08:00
DKChan 517412c7e9 登记(零豁免五键设计): 五份设计方案落盘——组合根注册面(main 49→15,一门面+三域容器,867探针改址)/战斗编排归约(38→15,RoundCycle+BattleFacts)/单格状态件(30→10,两层域件)/站桩状态件(19→10,vitals+motion)/测速去await(process_frame信号步进状态机);两代理独立实证gdstyle inner-class计数截断缺陷(基线登记值欠估);两处疑似潜伏红待T0核实(ui_input_probe inner成员直读/tune_sim收尾置假与wd8矛盾);待裁点21条呈主会话汇总 2026-10-29 07:22:50 +08:00
DKChan 33d6a2a6e9 rules(行为提醒): AGENTS.md 新增「主动检索提醒」软提醒节(非硬性红线)——版本敏感/时效敏感知识(引擎 API/设计模式/架构实践/行业惯例/工具链)或自判没把握处,即使训练记忆有现成答案也先 WebSearch/WebFetch 查证再下结论;来源取官方与主流现行实践、日期版本须匹配项目环境、过期内容不采信;外查结论只作呈报与待裁点证据,要进文档走 doc-design、要进代码走五段流水线,不越数值/架构单源,库内事实查规范导航不外查;引擎 API 专项规则维持 engine-reference 不变,本节为其通用版——源起=用户 2026-10-29 裁:engine-reference 旧规则触达不可靠且只覆盖 API,需常载入面的通用提醒;登记与完成同会话坍缩条目免落 2026-10-29 07:22:18 +08:00
DKChan 14a10e5e74 编排(迭代42): gdstyle尾波清偿批+level_runner商店委托层拆除两卡编入——中值合计≈5.375个工作日(3.625+1.75)处5–10常规区间,状态待开工;编排四查过(卡片在盘/凭据齐:gdstyle设计段裁决D1–D6 2026-10-29用户裁闭合+architecture v1.24轴丙BoardInstaller落文,level_runner第〇步2026-10-29放行零待裁点;估时常规档;流水线闸PASS交叉核2链);卡序=gdstyle先(T0十一键对账按基线原值全数对上,键7终值33由后段并排卡兑现——D6裁定两卡同迭代并排编队先后皆可、交叠区段不相邻零冲突);战斗一屏样张批(已写卡在册)经用户2026-10-29裁不编入本迭代留待后续编排。附记:按文件名暂存连带带入并行会话(架构审查批)当时未提交的待办清单登记条目「架构审查优化讨论——全库架构审计读数的逐条裁决与整改分批」(状态待文档设计)约10行——属登记处活文档合法内容、闸45条目全过,登记沿革自本提交起算,其审计报告件仍归该会话自提 2026-10-29 06:33:24 +08:00
DKChan cc0627ba6d 美术(战斗一屏样张批·合回): 样张需求卡片 + art-bible v3.22 定值(第二道门口径/血条危险红/素底深档/护甲三档/地台独立件/三关色板终值程序) + 三关色相互辨抽测方案设计闭合;冲突解决取格式层 master 整备成果 + 定值层本批成果,合回前补 req-card §8 判据绑定面列与整备批退役词清理 2026-10-29 06:28:50 +08:00
DKChan 76425feb6e 美术(战斗一屏样张批·合回前闸红修复): 收口前补三处 master 换代/整备批后新暴露的合规红——①卡片验收对照表补「判据绑定面」列(req-card §8 判据口径换代硬性列,逐行填可观测提交面);②art-prompts §5.4/§5.5 清 R3 正文修订注记与「随裁定作废」注记(440/516/531);③art-bible 第二道门口径退役词「不得」→「禁止」三处(2026-10-15 退役);④art-assets-checklist §3.7/§4 清本轮新增的日期批名注记(不把脚印留进 master 存量债)。文档域闸验收通过无新增红 2026-10-29 06:28:26 +08:00
DKChan b314269b05 Merge branch 'master' into art-splash-doc-20261028
# Conflicts:
#	design/art/art-assets-checklist.md
#	design/art/art-bible.md
#	design/art/art-prompts.md
#	design/art/asset-path-map.md
#	design/art/character-design.md
#	待办清单.md
2026-10-29 06:22:36 +08:00
DKChan 215da31591 修复(迭代 41 测试债批): 9 套件归绿+静态扫描 S9/S10/S11 清零+删死常量 SCHEMA_VERSION——两个产品回归随批修(standee 补间目标改子对象 st/tune_sim 运行态收尾归还 run),测试面按 iter41 拆件改址(slots/meta_state/crossrun/_forge/_side);S9 类型闸 24 处(node_map 三处给 Array[int] 真类型,其余动态边界 type-hint: ignore 逐处注记)+S10 头注日期 4 处+S11 退役词 1 处;config_db 头注「--script 无 autoload」订正为实测事实(autoload 并存、共享 .tres resolver 归最后装载者) 2026-10-29 06:04:40 +08:00
DKChan 6dea23729b 收尾(合回闸关联档+闸机编排快速失败批): 待办清单两条目完成整条删除的收尾报告落 reports/——改动文件清单、关联档选闸算法说明(三件保险恒跑/02 申报∪推导并集/横切回落全量/回执 scope 字段)、快速失败行为、孤立验证证据(沙箱七场景+闸源选跑 9/65+2s 连击中止)、闸机证据与存量债记账(9 套件+S 域红=迭代 41 在册债非本批新增;指纹 pid 归一化;基线 02/09 实测重生成凭据=用户 2026-10-29 带红合并裁;master 推进作废重做经过;最终回执 tree 与 master^{tree} 校验一致)——报告接收方=已删除的两条待办条目,随批入库 2026-10-29 05:28:30 +08:00
DKChan 8bb3541c5c 合并分支 gaterel-20261029(合回闸关联档+闸机编排快速失败)入 master:①收口跑批按改动关联面选测——00 冒烟/01 系统测试/09 静态扫描三件保险恒跑,02 单元与集成改「选套件跑」(卡片申报∪diff 推导并集,横切回落全量),回执加 scope 字段;②run_all 连续 3 套件超时快速失败中止整轮;③AGENTS/process-conventions §3/test-conventions §4/code-conventions §3/game tests README 规则同批同步;④待办清单两条目销条;⑤收口修正:红项指纹 pid 归一化+基线 02/09 存量红按实测重生成(凭据=待办清单迭代 41 测试债修复条 2026-10-29 用户裁带红合并承接);已并入 master 60c1a962 后重跑全量刷新回执;收口回执 game/tests/.gates/receipt.json(域=full、scope=full、存量红零新增全绿,tree=分支尖内容树) 2026-10-29 05:26:15 +08:00
DKChan 0f9d1c857b 并入 master(60c1a962 尾波清偿批登记)——合回前刷新回执前置步骤 2026-10-29 05:16:24 +08:00
DKChan 80b49c0f96 工程(合回闸关联档批·基线记账): 存量基线 02/09 两键按实测重生成——02 记存量红 fp f9865f1a5a44(9 套件失败,逐项对上待办清单「迭代 41 测试债修复」条)、09 改记现行红项指纹 1a9ad773489f(S9 24 处+S10 4 处+S11 1 处;旧指纹 8467b4588a20 所记 gdstyle 存量红已随迭代 41 还清过期);人工确认凭据=该条目 2026-10-29 用户裁带红合并(代码域现存红全部由该条目承接);基线滞后成因=迭代 41 两卡特许直接合回未重跑代码域闸。记账依据=本批 worktree 收口全量闸实测(commit 117a37e2 域=full,本批改动零新增红);此账使后续跑批按「存量红·对基线零新增」判定,修复批实测归绿后再换代 2026-10-29 05:05:45 +08:00
DKChan 60c1a962ab 登记(尾波清偿批·v2.0定稿): 设计段裁决闭合D1-D6——D1装板域拆新件BoardInstaller两修正(复位块留宿主薄壳/_board_generator随件退役,architecture v1.24轴丙与功能层行落文)·D2悬停域不拆·D4断点域不拆·D5五降值键豁免终局·D6写卡期修正改判并排编队(原吸收案否决:落笔发现该域已有定稿卡v1.1零待裁点且契约精度更高,销之重写属损耗;两卡同迭代各执各合同,level_runner交叠为不相邻区段);卡v2.0删T6/V6,估时3–4.25工作日,归绿6豁免5,零待裁点可编排;待办条目状态=文档设计已闭合+已写卡 2026-10-29 05:05:29 +08:00
DKChan b0e3353103 美术(三关色相互辨抽测·美术设计段闭合): 抽测三件缺口定稿——①取样面=3关×5组15对×3格+9基准=54格,画布640×1120,正图段+灰度副本段,装饰变体底带而迷雾记忆态底不带(§4.2/§4.6.3/§6.5 三者永不同格);②判据=目检四条+机检四条并用(沿 §1.4 目检先行机检冻结),机检阈值全取本作在役值(合成对比≥1.20/格底-微光三通道差不得全部<8/样图读数与合成模型差≤±2/255/铺底准入 L≥0.30 饱和≤0.55 避300-345),色相通道刻意不设机检阈值(圣经无条文,自造等于把观感问题伪装成可机检);③产物形态=并列样图+逐对读数表兼有,故改动面补「美术素材」与「工具代码」两档。新增色值 0 枚——tile_closed/wall_ambient 属 §4.1 分层②场景环境子板不占 48 额度,终值从已在役的三关瓦片色表墙顶受光档槽取。同批改待办清单:条目状态推进为美术设计已闭合+待执行,按状态机删除已闭合条目的缺口属性(三件定值已并入闭合段),改动面改写为文档+美术素材+工具代码,记设计轮闭合凭据与方案路径 2026-10-29 04:59:12 +08:00
DKChan 117a37e2a5 工程(合回闸关联档批·收口修正): 红项指纹归一化超时挂死行的 pid——fingerprint 只取 FAIL 关键行哈希,注释自陈「忽略时序/耗时噪声」,但超时行内嵌 pid=NNNN 逐轮变化使存量红指纹无法稳定登记(首跑实测:02 的 forge_workbench 超时行带 pid 使指纹不可复现);归一化 pid=N 后再入哈希,判定口径(FAIL 行集合)不变。首跑另测得:02 现红 9 套件+09 红项清单变化均系 master 在册存量债(待办清单「迭代 41 测试债修复」条 2026-10-29 用户裁带红合并承接:config_db 解析错/ooob 退出码 2/table_structure_guard/treasure_items/standee_fx/forge_workbench 超时/tree_requires_level/save_manager_domain/theme_projection+S9 24 处+S10 4 处+S11 adventure_table:55),非本批新增——基线滞后的成因=迭代 41 特许直接合回未重跑代码域闸,处置见下一笔基线记账提交 2026-10-29 04:51:29 +08:00
DKChan cf0e40cca8 复核(level_runner 商店委托层拆除): 卡片 v1.1 grilling 复核门通过——跨类同名扫描判类归属(BattleOrchestrator.player_request_refresh/CurioDeck.pool_stock 排除面)、_shop 词级归零判据、set_shop_pool 陈旧调用方陈述订正(构造 ctx 供给,产品码零调用方)、测试面精确计数(27 命中=25 实改+2 同名);零待裁点放行 2026-10-29 04:49:34 +08:00
DKChan c4862e7d04 写卡(level_runner 商店委托层拆除): 需求卡片 v1.0——19 委托壳拆除+调用面直连 ShopSession 零行为改动;能力清单 GP 钱包行入口列随改址形态换代;待办条目推进已写卡 2026-10-29 04:40:00 +08:00
DKChan 9f94c9e100 工程(合回闸关联档+闸机编排快速失败): 收口跑批按改动关联面选测+红树快速失败——①tools/run_all_gates.sh 关联档选闸(推广 2026-10-28 影响面选闸):00 冒烟/01 系统测试/09 静态扫描三件保险恒跑不降(测量面批不再免 00);03/04 探针与 05 渲染闸维持影响面口径;02 单元与集成改「选套件跑」——套件集=需求卡片申报∪diff 推导并集(申报=本批 diff 触及卡片∪roadmap 进行中行登记卡片的对照表「验收测试」列测试文件名;推导=脚本内套件族映射表按 game/ 代码面文件归族,映射不到一律横切),横切(公共件前缀 config_db*/rng_service*/save_manager*/meta_progression*/main*、project.godot autoload 注册面、game/data/tables、PARITY 触面表)→ 02 回落全部套件;PARITY 触面表上移单点定义(gate 11 与横切判定共用同一清单);回执加 scope(full|related)与 scope_terms 字段,worktree-guard 校验逻辑不动——②game/tests/run_all.gd 快速失败:连续 3 个套件超时(可调常量 CONSECUTIVE_TIMEOUT_ABORT 初值 3)即中止整轮、汇总已见失败与超时清单、退出码非 0,不连续超时照旧逐个回收;_run_suite 改返 {fail, timed_out};新增 --only-source=gates 来源标记(关联档选跑横幅,区别于开发期选跑免责句),无选跑参数时行为与现状完全一致——③规则同批同步(禁只改闸不改规则):AGENTS.md「交付前验收」句与硬性红线改按关联档选测口径(所选域绿即可合回,全量回归由用户自发、合入后无自动兜底,2026-10-29 用户裁)+规范导航行同步;process-conventions §3 第 8 条合回闸细则同口径;test-conventions §4 改「提交前验证」、code-conventions §3 主题行随改;game/tests/README.md 工具速查 run_all.gd 行(快速失败+闸机关联档选跑+manifest 实数 65)与挂死防护注、门禁/本地闸回执字段句同步——④待办清单「合回闸关联档」「闸机编排快速失败」两条目完成整条删除。孤立验证:推导沙箱七场景(行为面归族/触面横切/测量面批/main* 横切/project.godot 横切/申报并集/横切优先)+run_all 闸源选跑 9/65 绿+2s 截止连续超时第 3 个中止(exit 1 带汇总) 2026-10-29 04:36:26 +08:00
DKChan bf63a77fa9 美术(战斗一屏样张批·写卡段): 重新立需求卡片(旧卡 v1.4 已于 2026-10-17 裁定非有效卡)——十二节齐备,含样张两版产出、整屏四闸与战斗表现五项断言、五项代码定值落码(血条换 #A8321F/站桩名字行垫 HP_BAR_BACK 素底且不压地台/顺位徽标提档 FS_HINT/护甲图标换三枚 24×24 PNG/地台件独立引用)、程序化产出两件入包、改前改后并排对拍图;现状事实代码级实查 file:line(血条填充裸字面量 standee_body.gd:444、徽标裸 13px :437-438、名字行基线 box.y-13 与地台 box.y-18..box.y-6 重叠、B 区代码 252 对设计文 270、立绘与瓦片不入 git 靠 asset_root 两级回退取用、站桩实装仍字形回退);设计契约立十条含 2026-10-28 新验证口径(禁变异/撤销取证,须真实入口真实跑批通过)与「样张不判定立绘精细度」。同批改待办清单:样张条目状态推进为已写卡、卡片路径记入实况关联文档清单,修两处死指(引用已按吸收即死删除的过程稿)与两处过期版本号(v3.21→v3.22) 2026-10-29 04:34:09 +08:00
DKChan 04127485f6 登记(尾波清偿批): 需求卡片v1.0草稿落盘——S13基线重锚后11键定向清偿(board_view 6/level_runner 3/battle_orchestrator文件长/adventure_runner类变量),归绿6降值5不承诺清零;四拆件项(装板域/悬停域/商店域/断点域)备选案并列待设计段裁决D1-D6,编入迭代前置=待裁点清零;发现ShopSession件已在位(迭代37建),商店域=删委托壳,与在册条目「商店委托层拆除」同面(D6并案/剔除待裁);能力清单同批入「棋盘悬停反馈」行(写卡同批义务,流水线闸能力行可核);待办清单新增条目(状态=文档设计中+待写卡) 2026-10-29 04:33:33 +08:00
DKChan 6abaf67dd5 合并分支 caplist-20261029(能力清单改版——验证账本改实现指导地图)入 master:能力清单四列制义务声明定位(写卡当场入表+实现照单落名+收尾核对,废滞后一个迭代)+test-conventions §8.3/§8.9 改写+capability_audit 双通道判据+pipeline_gate 新增行收紧;收口回执 game/tests/.gates/receipt.json(域=docs 全绿,tree=分支尖内容树) 2026-10-29 04:06:03 +08:00
DKChan b96aab8a5a 合并 master(6690c2a7 文档纯度批)入 caplist-20261029——capability_audit.py 冲突解法=保留 master 反引号调用形态判红(CALL_FORM_RE)与本批四列双通道判据;docstring A 条两侧合写 2026-10-29 04:05:25 +08:00
DKChan 21d40a5388 收尾(能力清单改版批): 待办清单「能力清单改版——验证账本改实现指导地图」条完成即整条删除+改动报告落 reports/(改动面、判据变更前后对照、真实入口双通道延伸申报、闸机验证与回执证据)——报告接收方=该条目,随批入库 2026-10-29 04:04:08 +08:00
DKChan 2a087c9ead 工程(能力清单改版——验证账本改实现指导地图): 能力清单定位改实现指导+阅读导航+义务声明,只宣布「要验证什么」不记验证状态(落地账归改动—验收对照表+合回前独立审计)——game/tests/README.md 八张能力表瘦身四列(能力|系统|真实入口|代表用例,删「最后验证批次」「缺口」两列,存量行内容保留不回溯验证)、引区块改版(义务清单定位+写卡当场入表+实现照单落名+收尾核对,废「滞后一个迭代」),覆盖域表保留现状不动;test-conventions §8.3 维护锚整段改写、§8.9 三层模型中层「覆盖索引」改「义务清单」并同步法则与机器闸句;tools/capability_audit.py 判据随改(CAP_COLS 收窄四列含系统列非空、删「最后验证批次=真实 commit」检查、代表用例与真实入口改双通道=代码在或卡在 reports/需求卡片*.md——两头都无=红、条件闸行豁免保留代表用例口径);tools/pipeline_gate.py 对照表能力行收紧(「新增:<能力名>」同样要求该能力行已在清单在场——写卡与入表同 commit)。新判据经造红探针孤立验证(两头无=红/卡在=绿/代码在=绿;新增不在表=红) 2026-10-29 04:02:20 +08:00
DKChan 6690c2a75b 文档(实现指证清理): GDD 全树纯代码指证换代中文设计表述+纯度闸新增反引号调用形态判红——六类清算(方法/信号/类/常量/探针/调试与遥测入口名/提交号与运行时文件路径),保留面=数据索引(.tres 表路径与表名、表字段、表内枚值、存档键、封闭词表标签)并在 doc-conventions §5 明文写死;能力审计闸加 CALL_FORM_RE 窄规则兜底;顺修 §5 表两行误合并 2026-10-29 03:58:14 +08:00
DKChan fafb4fee0a 工程(gdstyle基线死键清账): 基线按实测重锚168→16键——152死键随迭代39–41还债消失清账,3条活键只降不升重锚(battle_orchestrator文件长1037→1035、board_cell_unit类变量31→30、standee_body类变量29→19),16键与迭代41键账终局构成逐键吻合,S13闸转绿(126文件16命中基线内零新增零恶化);待办清单条目完成即删 2026-10-29 03:43:19 +08:00
DKChan 4a7565592e 订正(表结构版本): 数据配置删「当前 = 2」版本行与配套验收/依赖表述——用户裁甲案,存档版本为唯一现役版本常量
- 数据配置.md:删调参表「表结构版本」行、验收标准「版本常量在位」条,依赖表与不负责表去掉「版本常量」表述(19 张表与 schema 均无版本字段,原表述三处失实)
- 存档序列化.md:迁移链「版本号推进仅为表结构版本对齐」改「仅随表结构变化」,消掉已退役概念
- architecture.md:save_system 契约锚与 RNG 快照节两处 SCHEMA_VERSION 改现役 SAVE_FORMAT_VERSION
- 待办清单:迭代 41 测试债条追加死常量 SCHEMA_VERSION(全仓零引用)随该批删除的登记
2026-10-29 03:31:36 +08:00
DKChan 0c33c3df12 登记(会话三裁决): 待办清单新增三条——①合回闸关联档: 收口跑批按「卡片申报∪diff推导」选关联测试族,三件保险恒跑,横切面回落全量,回执加scope,合入后全量兜底待裁;②闸机编排快速失败: 连续N套件超时中止整轮,红树不再磨2h;③能力清单改版: 验证账本改实现指导地图,四列制删批次/缺口列,废滞后一个迭代,写卡时本批能力行入表且测试名卡里定死,实现照单落名;三条均待用户发令,清单改版试点=下次写卡 2026-10-29 02:58:56 +08:00
DKChan 3dbbbf43bc 登记(验证与清单体系·阶段1收口): 五批落地凭据入实况——03 能力审计接闸上电(915222fa)、05 GDD 清理 124 处实现指证归零;迭代41测试债条目标明带红合并裁(代码域红由该条承接,本批零新增) 2026-10-29 02:55:52 +08:00
DKChan af853b62d5 登记(迭代41测试债修复·待执行): 9 个单元套件失败+静态扫描 S9/S10/S11 三项红——能力审计上电批全量复跑首次暴露,来源=迭代 41 测试特许移交;实况带逐套件证据与红项清单,改动面=游戏代码,只修测试与注解不改行为 2026-10-29 02:55:07 +08:00
DKChan 915222fa0a 工程(能力审计闸上电): tools/capability_audit.py 接入文档域 08e——GDD 纯度+能力清单与覆盖域表结构由机检兜底;baseline 加 08e 绿记录、07/08d 条目随批 5 文档清理实测归绿;test-conventions §8.9 与 doc-conventions §5 补闸件指路句(闸件清单唯一出处=run_all_gates.sh 头部) 2026-10-29 02:55:06 +08:00
DKChan a10bf92656 收尾(迭代41批后收尾): 反哺点落文对账闭合(A1–A6=提交 3213722f;B7/B8/B9 随并行文档纯度批 00312e12 入库——B7 引用块整删承载、B8/B9 三行随批;C10 核对结论=两豁免段在位/模块归属表零行变化零落文动作)——产出物退役:iter41 实现报告/反哺点清单与两卡需求卡片按吸收即死删除(卡片死期=实现批合回、报告遗留义务先迁:四项实机目检入体验验证清单 ㊵、golden 改前锚未建让步入 golden README 备案、152 死键 refresh 换入待办清单新条目)——账面换代:待办清单 gdstyle 存量债条目整条删除(键账终局 16 在册构成随新条目留档)+roadmap 迭代 41 行已完成/卡片与报告列退役保留字+收口注脚(测试特许移交+直接合回)+当前位换代(迭代位 1–41 全完成、下一步=待编池+refresh 可裁事项) 2026-10-29 02:16:50 +08:00
DKChan 3213722fed docs(迭代41反哺落文): architecture v1.23——全清定稿注记转现状登记(ConfigDB 三域容器 7/7/5 与公开面 8、SlotStore 10/4 经 save.slots 直连、MetaStateStore 写口13+读投影6 经 save.meta_state 直连、meta_progression 公开面 20 定稿三并组)+minesweeper_rules 消费依赖补 last_round_end 方法形态注记;B7/B8/B9 三条已随并行文档纯度批 00312e12 入库(B7 引用块整删承载、B8/B9 调参表落点改段路径三行随批入库) 2026-10-29 02:13:17 +08:00
DKChan 00312e12f4 清理(GDD 实现内容·批5): 30 篇 GDD 去 124 处代码指证——能力审计纯度红项归零
- `.gd`/`.py`/`.sh` 路径(含 data/schemas 脚本路径)、测试与探针名、代码行号、提交号全部清出 design/gdd/;唯一保留=game/data/tables/*.tres 表索引(用户裁:GDD 禁实现内容,仅配置索引例外)
- 锻造工坊:删「现役代码事实」「实装边界」两节——实装已随迭代 23 收官、设计事实正文已有(默认值所有权/敌方攻击轴未开/存档域/满级不实装),无独有事实需迁 architecture;正文去指证并清交叉引用
- UX 三份 spec 的「> 事实源=代码路径」体例统一改指设计件;battle/level-map/interaction-patterns 三张组件表的「现有 demo 组件/现有实现锚/状态」列改「载体」,只留状态与设计载体名
- 术语表与 08-Alpha 的事实源列去闸件路径,改指 process-conventions 运行与验证节;08 v1.19→v1.20 与 02 根索引指针随动
- 事实订正三处:存档调参表版本 6→7、数据模型样本 version 6→7(v7 锻造域已落地);冒险结构调参表冒险表字段名按现行表结构对齐(value_segment/quota_segment);删除「存档版本=表结构版本常量同源」这一错误断言(实为两个独立常量)
- 架构文档的未提交改动(迭代 41 反哺落文)非本批产物,未纳入本提交
2026-10-29 02:07:56 +08:00
DKChan f32634446e 工程(流水线闸): 验收对照表加「能力行」列——2026-10-29 起生效,既有名回核 game/tests/README.md 能力表
check_ledger 增第七列:每行写 既有:<能力名> 或 新增:<能力名>(分号可多段)。既有名须在能力表首列可查,新增放行(新能力行由写卡段落表,test-conventions §8.9 滞后一迭代)。日期门控对齐 BINDING_RULE_DATE 同构:文件名日期早于 2026-10-29 的旧卡不回头改。自测四况通过(既有命中/新增放行/既有不存在红/格式错红/缺列红/旧卡免检)。req-card 与 iter 两技能本地件同批同步(不进 git):对照表改七格、写卡段增删能力行并刷最后验证批次、实现批禁写 README。
2026-10-29 01:55:59 +08:00
DKChan ae3c99e34e 工程(能力审计工具): capability_audit.py 入库——七组机检覆盖三层模型的机检半边,本批不接闸
检查组:A 文档纯度(design/gdd 全树禁 .gd/.py/.sh 路径与断言名,围栏块跳过,.tres 表索引放行)/B 系统文档验收标准非空(豁免两件具名附理由)/C 能力行六列结构与格非空/D 代表用例三核(文件存在、在 run_all.gd manifest、func 函数名可达)/E 真实入口方法在产品码有定义(static func 兼容)/F 最后验证批次为真实 commit/G 覆盖域表 25 篇逐篇登记、状态三档、非未覆盖行能力行可回指能力表、部分/未覆盖行缺口指待办清单。自检四道防扫描面空转(文档数/能力行数/套件数/覆盖表行数任一为零 exit 2)。当前实测:能力行 59 全过、覆盖域表 25 行全过,仅余纯度红 124 处(GDD 存量实现细节,归清理批)。接闸与基线登记待清理批之后单独批执行。
2026-10-29 01:54:45 +08:00
DKChan 5377b2ce2e 文档(能力清单v2): 三段扩面+覆盖域表——排雷循环9行/表现与支撑10行/数据配置与契约10行入清单,25 篇系统文档逐篇对照;修两处真实入口笔误与 manifest 计数 64→65
能力清单从核心四域扩到七段(58 能力行+条件闸 1 行),维护规则改写为写卡段维护、实现批禁写(test-conventions §8.9);新增覆盖域表按 25 篇系统文档逐篇对照(已覆盖/部分覆盖/未覆盖),八处缺口指待办清单(新登记「能力清单覆盖缺口补齐」条承接六项,教学与生涯归各自在册条目)。修两处与产品码失配的真实入口(SaveManagerCore.add_keystone/tree_nodes → MetaStateStore/MetaProgression 实有方法);manifest 计数行按实数订正 64→65(62 单元+3 集成),对应待办条目完成即删。pipeline_gate 绿。
2026-10-29 01:54:33 +08:00
DKChan 032d923c7e 文档(验证与清单体系·阶段1): 三层模型入法——验收意图/覆盖索引/执行证据分层,四法则与写卡段维护时序落三份规约+AGENTS.md 红线
test-conventions 新增 §8.9(三层表+四法则=每格非空/每条断言有归属/数量不守恒覆盖守恒/无全局对账总账,含维护时序与文档纯度);§8.3 能力清单维护锚改写为写卡段维护、实现批禁写。doc-conventions §5 增「禁实现内容」行(代码路径/测试文件名/断言名全文禁写,例外=配置文件索引),§6 骨架验收标准口径同步。process-conventions §3 第 11 条与 AGENTS.md 改动四类红线补 `game/tests/README.md` 禁写面。待办条目 5 实况记 2026-10-29 用户三裁与五批落地计划,状态维持文档设计已闭合。pipeline_gate 绿(42 条目/41 行/7 卡)。
2026-10-29 01:48:40 +08:00
DKChan eb9bb53752 合并(迭代41 gdstyle存量债清偿两卡): 卡①核心数据面结构收敛批(85键全清——校验族13文件/生成器族2文件/效果引擎四域拆域+config_db归位三域容器+存档拆件SlotStore/MetaStateStore+meta_progression瘦身20+adventure_table拆段3段件+action_economy删并+spawn签名束化,行为零变化,8新件键账在阈)+卡②呈现层结构收敛批(67清+2豁免在册+2展平改善——视图拆私有族+六状态件+ui_kit公开面26→20+flow context三束+print×3删除;含u14补做与并master并案)——用户2026-10-29裁直接合回 2026-10-29 01:37:25 +08:00
DKChan 2789adf606 iter41-卡2:呈现层结构收敛批:67清+2豁免+2展平改善——拆私有族+六状态件+ui_kit收敛+束收拢+print删;含u14补做、并master并案与批末运行期断链修复 2026-10-29 01:33:51 +08:00
DKChan a613a3cb90 iter41-卡1:核心数据面结构收敛批:85键全清——三族拆域+config_db归位容器+存档拆件+meta瘦身+adventure拆段+spawn束化;行为零变化,8新件在阈 2026-10-29 01:33:50 +08:00
DKChan 10d7c82b6a 美术(战斗一屏样张批·色值裁定落位): 素底明暗档裁深档 #282220——站桩名字行与魔法甲暖白维持不动(12.26:1)、轻甲木色按合并裁定改 WARM_FAINT #CDB88C(8.08:1);额度接受五处换色合并(铲刃→FOG_MEMORY_INK #C4C4C4/提灯→GOLD_DEEP #B07A14/食人魔酋长暖褐皮→暖石 #B8A582/石君王灰皮→STONE #786E62 按次级皮口径/轻甲木色→WARM_FAINT),新增两枚(重甲冷灰 #868C9A 对深素底 4.65:1 对舞台底 3.52:1、卓尔浅紫灰皮 #A79CB8 6.04:1 与 4.57:1,均过图形 3:1),48 色余量 2→0 额度用尽;石君王岩石板甲与重甲冷灰同一枚不另计。art-bible 升 v3.22(动文首版本号与 §4.1:增列两枚并标注过门与语义检查结论、换色合并登记五处、增量纪律条余量归零并立后续新增须先压缩的呈报口径);art-prompts §5 九件工单判据由双档并列收成深档单档、§5.5 缺口 1/2/4 转已裁指路、余量口径三处一致;同批修一处术语闸红(主角形象描述用退役词「插旗」,改「配朱红矩形旗」)。遗留(下一批):#B07A14/#B8A582/#786E62 三枚合并目标色未在 §4.1 表逐字在册,须随色板检查器建成后对账 2026-10-28 05:50:05 +08:00
DKChan 50702ea506 美术(战斗一屏样张批·设计段闭合): 样张目标规格定值落 art-bible v3.21——§6.1 背景契约订正为 scene_stage_bg.png 并新增地台独立件/§4.1 第二道门按用户裁改宽松口径(不得三通道全<8)、清偿 6 对换色合并欠账、色板增列 #A61D37 转正与三处换色合并、余量 3→2/§4.2 血条填充显式归危险红 #A8321F、#689CE8 登记违例退役/§7.4 顺位徽标不增列豁免面、字重重开钩子注销/§8.2 护甲图标 24×24 与地台件 48×12、棋盘小人 32px 源档终值/§2 世界底层拆两子带(解决同层两底难辨,非 §1.4②项成立要件)/§8.4 方向集代拟口径追认/§6.3 三关色板终值取值程序登记/§7.6(三) 平滑件并存登记/§1.4 样张产出手段不进圣经;character-design §5.3 护甲三档转定稿;资产清单与路径图新增四件资产行与 scene/ 域键;待办清单样张条目记美术线闭合凭据(art-bible v3.21)并推进至待写卡,新登记三关色相×五组微光互辨抽测。定值推导链见 2026-10-28 设计轮过程稿(按吸收即死不入库,沿革以本条 commit 为准) 2026-10-28 04:32:31 +08:00
159 changed files with 6972 additions and 4058 deletions

No files matched your search

+8 -4
View File
@@ -16,7 +16,7 @@
## 运行与验证(工作目录 = 含 project.godot 的切片目录)
- **交付前验收 = 跑 `tools/run_all_gates.sh`,按本批改动域选档(`--code` 只跑代码域/`--docs` 只跑文档域/不带参数=两域全量),所选域全绿才合回 master**——它是全部验证闸的唯一入口与唯一清单,**域划分也只写在它这一个地方**,闸件增减与分域调整都只改它,文档禁另列清单。域按**文件性质**判:代码域=`game/` 下非 `.md` 的行为载体(代码/测试脚本/探针/场景/数据表/素材),`game/` 内 `.md` 与 `game/` 外一切路径=文档域;同批两类都有时跑全量档。跑完写回执 `game/tests/.gates/receipt.json`(含 `domain` 字段),合回时由 worktree-guard 按 diff 文件性质推出该验哪个域再校验回执(六况拦截细则见 process-conventions §3.9);非代码面的直改批验收=commit 点 git 钩子自动跑 `--docs`,无 worktree 与回执流程
- **交付前验收 = 跑 `tools/run_all_gates.sh`,按本批改动域选档(`--code` 只跑代码域/`--docs` 只跑文档域/不带参数=两域全量),所选域全绿才合回 master**——它是全部验证闸的唯一入口与唯一清单,**域划分与选闸算法也只写在它这一个地方**,闸件增减与分域调整都只改它,文档禁另列清单。域按**文件性质**判:代码域=`game/` 下非 `.md` 的行为载体(代码/测试脚本/探针/场景/数据表/素材),`game/` 内 `.md` 与 `game/` 外一切路径=文档域;同批两类都有时跑全量档。代码域按**关联档选测**(2026-10-29 用户裁):02 单元与集成只跑「需求卡片申报 ∪ diff 推导」并集的套件(关联档=只跑与本批改动关联的那部分测试),00 冒烟/01 系统测试/09 静态扫描三件保险恒跑不降,横切面改动(公共件/数据表/autoload/数值·存档·RNG·结算触面)回落全部套件;算法与套件族映射表只在闸脚本内定义。所选域全绿即可合回;全量回归由用户自发发起,合入后无自动兜底。跑完写回执 `game/tests/.gates/receipt.json`(含 `domain` 与 `scope` 字段),合回时由 worktree-guard 按 diff 文件性质推出该验哪个域再校验回执(六况拦截细则见 process-conventions §3.9);非代码面的直改批验收=commit 点 git 钩子自动跑 `--docs`,无 worktree 与回执流程
- 单件直跑(调试期最窄确认用,**不构成验收**):冒烟测试 `python tools/run_smoke.py`(`game/tests/smoke_boot.tscn` 极小启动场景)· 系统测试 `python tools/run_system_test.py`(宿主 `game/tests/system_test.gd`)· 场景探针 `…console.exe --headless --path . res://probe/ui_probe.tscn` · 单元与集成 `… --script res://tests/run_all.gd`
- 调参批量:`--script res://sim/adventure_monte_carlo.gd`(全冒险期望)· `res://sim/reward_expectation.gd`(奖励期望);关卡完成率/难度类测量一律走全冒险
- 数值验证:`python tools/balance_verifier.py`(采集端 `res://sim/verifier_batch.gd`,报告与原始数据落 `sim-data/`)
@@ -43,7 +43,7 @@
| 批次开工 / 流程纪律 | `design/engineering/process-conventions.md`——车道铁律(代码面 worktree 批/其余主区直改)、五段流水线、批次清单、测试两入口与 MC/闸机细则、像素纪律 |
| 流水线段入口 | 技能对照——doc-design=文档设计(兼任反哺点落文)/asset-ingest=美术录入/req-card=写卡/iter-plan=迭代编排/iter=实现(五者均装于项目 `.zcode/skills/`);登记不立技能;批后收尾与中间文档退役=batch-closure(同一目录);格式与状态机权威=`design/engineering/doc-conventions.md` §12 |
| 定代码方案 / 写代码 / 改代码前 | `design/engineering/code-conventions.md`——结构/契约/语言/数值/流程五类硬纪律(反例库 = 同目录 code-conventions-cases.md) |
| 定测试方案 / 写测试 / 改测试前 | `design/engineering/test-conventions.md`——探针标配 / 回归断言 / 全量验证 / 验收清单落码 |
| 定测试方案 / 写测试 / 改测试前 | `design/engineering/test-conventions.md`——探针标配 / 回归断言 / 提交前验证 / 验收清单落码 |
| 定文档方案 / 写文档 / 改文档前 | `design/engineering/doc-conventions.md`——白话写作 / 载体分工 / 用语 / 结构骨架 / 会话记录与生命周期 |
| 概念切分与互链 | `design/engineering/concept-conventions.md`——概念封装 / 跨文档引用 / 归档与事实源 |
| 系统设计 / 增删文档 | `design/gdd/02-系统清单.md`——根索引 + 中文规范名↔英文代号对照 |
@@ -79,13 +79,17 @@
枚举用列表,二维对照用表格,按内容形态选;散文是最后手段。
## 主动检索提醒
- 训练记忆缺失或可能过时的问题,先搜最新主流的答案再回答。
## 硬性红线(勿违反;操作细则在 process-conventions.md 与各规约)
- 车道铁律(判据与改动域划分同一,按文件性质切)——代码面(`game/` 下非 `.md` 的行为载体)唯一强制独立 worktree(迭代批全套仪式不变);其余一切面(含 `game/` 内 `.md` 与 `.zcode/`、`.qoder/` 等不入 git 面)主工作区直改+直提,commit 点由 git pre-commit 钩子(`tools/hooks/pre-commit`,`core.hooksPath` 挂载)现场跑文档域闸,绿落地红拦;主区直提代码面被该钩子拦;`--no-verify` 仅属用户,agent 禁用(细则见 process-conventions §1)
- **仓库根禁止设会话状态文件**(`active.md` 已废除)——现状看 roadmap「当前位」,待办看待办清单,过程看 git 提交信息,产出物看 `reports/`;任何文档禁止另设「当前状态快照」节,两处记同一件事必然漂移(细则见 doc-conventions 第 10 节)
- 测试执行两入口铁规——只有迭代 loop 开发与用户点名两个触发入口;其余会话零测试,需测试支撑先请示并注明未跑测
- 交付前验收 = 跑 `tools/run_all_gates.sh` **按改动域**全绿(唯一入口、唯一闸清单、唯一域划分,禁在文档另列);合回 master 由 worktree-guard 按 diff 文件性质推域校验回执强制(process-conventions §3);非代码面直改批的验收=commit 点 git 钩子自动跑 `--docs`(process-conventions §1)
- **改动四类**——**需求改动**(游戏代码,含随逻辑写/改的测试代码):唯一走「写需求卡片+编入迭代批次」通道;迭代实现批禁写 `design/` 整个目录与两份根流程清单(`待办清单.md`/`体验验证清单.md`)(含新增/修改/删除),设计文档对它只读、是写测试与实现代码的输入依据;两份流程清单的条目状态只由流水线各段推进,实现批禁止顺手改;产出物只准写 `reports/`;批末只跑代码域闸。**工程改动**(tools/、闸件、模拟测量工具、纯测试维护——不改变游戏行为的配套代码)、**文档设计改动**、**美术素材改动**:不写需求卡片、不编迭代批次,登记在案后由用户发令在主工作区直改+直提(commit 点 git 钩子自动跑文档域闸),完成即删条目;触及代码面的工程改动(如纯测试维护)仍走 worktree 批;文档设计类写入走 doc-design 技能(登记条目格式由流水线闸强制)
- 交付前验收 = 跑 `tools/run_all_gates.sh` **按改动域**全绿(唯一入口、唯一闸清单、唯一域划分与选闸算法,禁在文档另列);代码域按**关联档选测**——02 单元与集成跑「卡片申报 ∪ diff 推导」并集套件、三件保险(冒烟/系统测试/静态扫描)恒跑、横切面回落全量,所选域绿即可合回,全量回归由用户自发(2026-10-29 用户裁,合入后无自动兜底)(算法见闸脚本);合回 master 由 worktree-guard 按 diff 文件性质推域校验回执强制(process-conventions §3);非代码面直改批的验收=commit 点 git 钩子自动跑 `--docs`(process-conventions §1)
- **改动四类**——**需求改动**(游戏代码,含随逻辑写/改的测试代码):唯一走「写需求卡片+编入迭代批次」通道;迭代实现批禁写 `design/` 整个目录、两份根流程清单(`待办清单.md`/`体验验证清单.md`)与 `game/tests/README.md`(能力清单,归写卡段维护)(含新增/修改/删除),设计文档对它只读、是写测试与实现代码的输入依据;两份流程清单的条目状态只由流水线各段推进,实现批禁止顺手改;产出物只准写 `reports/`;批末只跑代码域闸。**工程改动**(tools/、闸件、模拟测量工具、纯测试维护——不改变游戏行为的配套代码)、**文档设计改动**、**美术素材改动**:不写需求卡片、不编迭代批次,登记在案后由用户发令在主工作区直改+直提(commit 点 git 钩子自动跑文档域闸),完成即删条目;触及代码面的工程改动(如纯测试维护)仍走 worktree 批;文档设计类写入走 doc-design 技能(登记条目格式由流水线闸强制)
- 五段流水线铁律——**需求改动**(游戏代码)按「登记 → 文档设计/美术设计 → 写需求卡片 → 迭代编排 → 实现」五段推进,段间不自动流转、每段转进由用户发令;编入迭代的卡片必须设计闭合+零待裁点——需求卡片任何工作量皆可写、皆可编入迭代,工作量限制只属迭代层(迭代估时总量 <5 个工作日=「冻结待凑批」、不可开工);流水线闸 `tools/pipeline_gate.py` 强制(已注册进 run_all_gates.sh 文档域);实现段零裁断——卡片没写清=上游缺陷,停该卡退回上游,禁内联求裁(process-conventions §2,格式与状态机=doc-conventions §12)。工程/文档设计/美术素材三类改动不走写卡与编排段:登记 →(如需设计讨论)→ 用户发令直改 → 主区直改+commit 点闸 → 完成删条目(车道细则=process-conventions §1)
- MC/模拟:无数值改动零跑;档位硬闸见 `sim-data/README.md`「MC 采集档位表」,一档只能由用户发起
- 闸机轮次纪律:新码先孤立验证 → 出红只跑红件最小单元 → 长批先最小参数试车 → 开工扫坑册(process-conventions §6)
+12 -3
View File
@@ -81,7 +81,7 @@
| 钩爪恐魔 hook_horror | 普通怪(钩爪/多足轮廓注意凹凸计数控制) | light | 第三关群行捕食者,小体量可辨 |
| 灰矮人石君王 duergar_king | **Boss:锐角与不对称**,体量最大 | heavy | 第三关 Boss;紫赤色相独占+形状独占双通道 |
- **通用规格**:亮色描边+落影底盘轮廓通道硬规则;透明底 PNG;每敌种 2–3 版候选;护甲类型视觉区分方案已落 art-bible §5.3(候选方案,样张冻结终稿)。
- **通用规格**:亮色描边+落影底盘轮廓通道硬规则;透明底 PNG;每敌种 2–3 版候选;护甲类型视觉区分方案已落 art-bible §5.3(已定稿)。
- **来源**:✦ ComfyUI(prompt 卡 v2.0 §3,八敌种+L2 熊地精变体共 9 卡);理由同 §2.1——不复用。
- **联动**:显示名以 `data/tables/enemy.tres` 与敌人系统文档为准(L2 熊地精=bugbear 复用,显示名熊地精系)。
@@ -131,7 +131,7 @@
### 3.5 营地场景图
- **要什么**:营地场景图 9 张——`scene_camp_bg`(背景)+ `scene_camp_gate / forge / chest / notebook / dummy / board / campfire`(七个可点物件)+ `scene_camp_tent`(承载件)。钥石顶栏图标沿用现役 `icon_keystone`。
- **来源/规格**:**✦ 插画级**(作者自跑远程生图管线);烛光黄 `#F6C667` + 木色 `#8A5A34`(art-bible §6.2);2× 源档出图、最近邻降采样到 1280×800;后处理=抠底/降采样/色板量化/描边统一。**每张出图须登记模型名+分辨率+seed+对话/日期**。
- **来源/规格**:**✦ 插画级**(作者自跑远程生图管线);烛光黄 `#F6C667` + 木色 `#8A5A34`(art-bible §6.2);2× 源档出图、最近邻降采样到 1280×800;后处理=抠底/降采样/色板量化/描边统一。**出图登记照 [remote-gen-prompts](remote-gen-prompts.md) 头注轻量口径执行:用途+生成时间必注,其余参数有则记。**
- **排期**:营地交互重做**美术自立批**(不占迭代位;UI 贴图重构批已搁置)。终稿落 `game/assets/art/scene/`,消费常量 `UiKit.TEX_CAMP_*`。
- **现状**:全占位。
@@ -141,6 +141,13 @@
- **来源/规格**:♻ 复用开源——缝合像素字体(Fusion Pixel,SIL OFL 1.1,授权总表在册);墨色走主墨系(art-bible §7.2)。换字体是全局决策;样张用字即此定稿件,过样张闸第 1 项(数字可读性 ≥4.5:1,禁以换字形逃避)。
- **现状**:✅ 已定稿在役(现状即终稿)。
### 3.7 护甲类型图标三枚 ♻优先/⚙兜底
- **要什么**:`ui_armor_light.png` / `ui_armor_ward.png` / `ui_armor_heavy.png` 三枚,站桩名字行与护甲图标同排挂载(原为 ◇/◆ 字形占位)。
- **风格/规格**:源 24×24、显示 24px = 1×(甲类整数倍缩放纪律,art-bible §8.2);形状 + 色彩双通道,灰度下按甲面覆盖率三档可辨(character-design §5.3 已定稿:轻甲覆盖率≈0/魔法护甲符纹饰带/重甲金属甲板);不触 §5.1 剪影 archetype。
- **来源**:♻ 素材站通用护甲/符纹图标改色优先,过 §0 复用闸四道;⚙ 兜底程序化。
- **现状**:未开始(占位 = 站桩名字行裸 12px 字形 ◇/◆,随本条到位后改挂图形件并把名字行提到 `FS_HINT` 14)。
---
## 4. P3 —— 演出类(战斗打磨项,样张后排期)
@@ -148,6 +155,8 @@
| 资产 | 需求 | 风格/规格要点 | 来源 |
|---|---|---|---|
| 受击反馈 / 死亡表现 / 顺位标记 | 敌人系统登记的资产需求**下限三类** | 死亡=血条归零后**灰化+碎裂退场,禁止瞬间消失**;顺位标记需在敌多时可读 | ⚙/✦ 挂自产精灵——死亡灰化碎裂是语义硬规则,不可整包复用;烟尘碎屑粒子可 ♻ 改色 |
| B 区舞台背景插画 `scene_stage_bg.png` | 战斗舞台背景(art-bible §6.1 资产契约) | **✦ 插画级**;源 1280×270、B 区全高含明细带底、显示 1×;**只出远景 + 中景两带**(近景带在结算期被 84px 明细带底整条盖住);三关换挡走 §4.3 `wall_ambient` tint 槽,不按板出三张 | ✦ 插画级(作者自跑远程生图管线) |
| 站桩石板地台件 `scene_stage_plaza.png` | 近景地台独立件(art-bible §6.1/§8.2) | 源 48×12、九宫格横向拉伸、顶缘受光线 2px 不随拉伸变形;跨三关恒定,不吃 `wall_ambient` tint | ⚙/✦ 自产 |
| 特殊技动画终稿 | 并入 §2.3 三档意图动画,不另起体系 | 攻/防两型旧口径由三档替代 | ✦/⚙ 自产(同 §2.3) |
| 连锁坍塌显形演出 | 连锁展开触发时的连锁演出 | 与音频方向同批配对登记;「坍塌显形」=连锁展开的玩家可见名 | ♻ 粒子/碎块改色 + ⚙ 坍塌结构自产 |
| 封印特效 | 该动作的呈现名 = **封印**(art-bible §3.2):**施印瞬间特效 + 印记常显形态**两件 | 印记旗面走封印黑 `#000000`(现行封印色,色史归 art-bible §4.1);特效走运动+色相(§2:状态/情绪不走明度,空间光照可走);现行占位 = 封印黑「旗」字形;印记常显形态可与 §3.3 旗面像素化合并出 | ✦/⚙ 自产(精灵+粒子,烟尘光点可 ♻ 改色) |
@@ -161,7 +170,7 @@
- **秘宝图标**:内容归 Alpha 秘宝整体重设计,内容未定不能先做;渠道届时按 ♻/✦ 另评。
- **封面图/宣传图**:Alpha 后另批,不阻塞切片;需项目角色出镜,素材站合成观感差,宜 ✦。
- **地形变异专属纹理**:六类型已定稿,纹带需求 = 2 纹形(伤害轴刺缺形/信息轴遮蔽形)× 3 图类型色板,**样张后可排产**;形状通道规则见 art-bible §3.2。
- **精英/Boss 护甲类型视觉区分**:已落 art-bible §5.3(候选方案:甲面覆盖率×甲材质色三档,样张冻结终稿)。
- **精英/Boss 护甲类型视觉区分**:已落 art-bible §5.3(甲面覆盖率×甲材质色三档,已定稿)。
## 6. 执行顺序(依赖链)
+32 -17
View File
@@ -1,6 +1,6 @@
# 美术圣经(Art Bible)— Dungeon Sweeper
> 项目:Dungeon Sweeper(扫雷 × 自动战斗 闯关 Roguelike)· 状态:**第 1–9 节定稿**;现行为 v3.21,历次修订明细见 git 提交史
> 项目:Dungeon Sweeper(扫雷 × 自动战斗 闯关 Roguelike)· 状态:**第 1–9 节定稿**;现行为 v3.23,历次修订明细见 git 提交史
>
> **Art Director Sign-Off(AD-ART-BIBLE)**:历次批均未签核——此为 Lean/Solo 模式(非 PHASE-GATE)下的现行治理状态;full 门禁签核时机待用户表态。
> 风格基调:地牢题材但**非暗黑风**——轻快明亮的幻想冒险风,全年龄;像素风;角色 2~3 头身。
@@ -57,7 +57,9 @@
**判定与回退**:第 1 项不过时按原则二设计测试回退——先调格底明度档,复杂格底垫色牌后备,禁止缩字号换字形逃避;第 2–4 项不过时修形不修数。样张通过 = 砖面形态与色板冻结;新增图类型/变异色板须重跑本测试(§4.3)。执行时机:正式砖面资产开工前;《HUD框架》以本节为引用依据。验收:机检〈样张机检断言集全绿后方可冻结砖面形态与色板〉
**整屏样张闸**:格子样张验"格",整屏样张验"屏"——战斗屏/关卡屏/菜单屏/营地屏各出一张整屏样张,验收四项:①全部文字(含菜单/说明/tooltip/按钮)对其直接背景 ≥4.5:1(WCAG AA),大字(≥18px 或加粗档)底线 3:1、目标 4.5:1;②明度分层三档带成立(信息面层 > 世界中层 > 世界底层,层间灰度可分);③整屏焦点预算(§3.4:首焦唯一——数字区/立绘/主按钮,无第二焦点竞争;负空间服务焦点,不属空窗);④文字禁直接压纹理底(垫容器或罩层)。验收顺序 = **方向稿目检先行**(防"机检过闸但气质否决"式返工),目检过后机检冻结。执行时机 = 屏级视觉落码开工前;过闸前一切屏级视觉为占位临时态(§7.1 完成条款)。验收:机检〈整屏样张四项断言全绿,且目检先行过审〉
**整屏样张闸**:格子样张验"格",整屏样张验"屏"——战斗屏/关卡屏/菜单屏/营地屏各出一张整屏样张,验收四项:①全部文字(含菜单/说明/tooltip/按钮)对其直接背景 ≥4.5:1(WCAG AA),大字(≥18px 或加粗档)底线 3:1、目标 4.5:1;②明度分层三档带成立(信息面层 > 世界中层 > 世界底层,层间灰度可分);③整屏焦点预算(§3.4:首焦唯一——数字区/立绘/主按钮,无第二焦点竞争;负空间服务焦点,不属空窗);④文字禁直接压纹理底(垫容器或罩层)。验收顺序 = **方向稿目检先行**(防"机检过闸但气质否决"式返工),目检过后机检冻结。执行时机 = 屏级视觉落码开工前;过闸前一切屏级视觉为占位临时态(§7.1 完成条款)。**样张判定物的产出手段与素材输入级别不进圣经定值**——圣经只定样张要验什么,不定样张以何种手段产出、也不定它取哪一级别素材输入。验收:机检〈整屏样张四项断言全绿,且目检先行过审〉
**战斗一屏样张登记(合并提交 3b66d1a6)**:战斗一屏样张批整屏四项机检全绿——抽样读数:文字对比最弱 5.34:1;舞台底 L0.036/已开格底 L0.089 落两子带、间隔 0.053;首焦=数字区高对比能量占比 59%;名字行素底牌平底零地台色。样张整体过闸待方向稿目检先行(真人检测,登记于体验验证清单 ㊶)
**样张现状**:格子样张已冻结,冻结凭据 = git 提交 7a847c7(机检报告)与 §4.1/§8.2 定值表;样张 v3 产物原件已丢失、未入 git。现行冻结态:色板与帧数档维持冻结;数字形制 = 亮墨三档直画 + 色牌后备(值见 §4.1);新增图类型/变异色板须重跑本节测试。验收:机检〈冻结项定值均以 §4.1/§8.2 对应 owner 表为准〉
@@ -68,6 +70,8 @@
> 本节服从第 1 节宣言「明快的地牢,轻快的扫荡,仔细的推理」。能量值为全作统一 0–10 刻度:0 静谧,10 沸腾。
>
> **明度分层(硬规则)**:明度按视觉层分带——**信息面层**(数字/UI 数据/预告/语义标识)最高、**世界中层**(格底顶面/角色/物件)居中、**世界底层**(背景/纵深/远景/已开空间)可更低;层间明度差服务空间纵深与光照(Moonlighter 式洞穴层次)。**情绪明暗禁令**:明度变化禁止用于**情绪表达**——画面禁止靠压暗/渐晕阴沉下来;roguelike 失败重开,世界无光暗记忆;Darkest Dungeon 式压暗仍在 §9.2 反面清单。**状态表达不受本禁令约束**:状态可用明度、色相、饱和、运动、元素任一手段承载。**允许域**:空间纵深、光照氛围、形体塑造。类型微光的明度梯度(§4.2)属信息面层内梯度,不扰世界层明度档。验收:目检〈情绪表达不走压暗/渐晕;三档明度带层间灰度可分〉
>
> **世界底层两子带**:世界底层拆两条子带——**底层下沿带 L 0.014–0.06**(远景、洞窟纵深、B 区舞台底、屏幕根底)与**底层上沿带 L 0.08–0.14**(已开格底、迷雾记忆态合成底),子带间隔 ≥0.02。拆两子带用于解决**世界底层内部** B 区舞台底(L=0.036)与 D 区已开格底(L≈0.10)同层难辨的问题——两者同属世界底层,单带下跨度 0.126 吃掉层间间隔 0.08,灰度图上会表现为两个不同的底。§1.4 整屏②项约束的是层间可分(底层上沿 0.14 对世界中层下沿 0.22,差 0.08 本就满足),②项不约束同层内可分,故本条不属②项的成立要件,而是世界底层内部的可读性纪律。验收:机检〈同一屏的世界底层成员全部落进两条子带之一,两子带 L 区间不重叠且间隔 ≥0.02〉
### 2.1 挖掘阶段(核心状态,占时最长)
@@ -203,18 +207,27 @@
- **收益金亮档 `#E0B860`(GOLD_BRIGHT)**|UI 徽标可读性亮档 token:敌顺位徽标①②③与重甲徽标对舞台底 6.47:1(GOLD_DEEP 3.26:1 不达 §7.2 带,故另立亮档);金族亮档,与奖励金 #F0A828 同族不同岗——奖励金 = 已兑现收益语义(§4.2 金条),本 token 只承载徽标可读性、不占收益语义。GOLD_DEEP/HERO_BLUE 常量本尊不动(standee 意图判据等语义岗现行使用)。验收:机检〈GOLD_BRIGHT 对舞台底 ≥4.5:1〉
- **小人蓝亮档 `#7EBAF0`(HERO_BLUE_BRIGHT)**|魔法护甲徽标对舞台底 5.88:1(HERO_BLUE 3.23:1 不达带,故另立亮档);蓝族亮档,与小人蓝 #2E86DE 同族不同岗——本 token 只承载徽标可读性,不占用「蓝只说己方」的语义。验收:机检〈HERO_BLUE_BRIGHT 对舞台底 ≥4.5:1〉
- **图标槽柔和档 `#806A4E`(SLOT_BACKDROP_SOFT)**|BCard 图标槽底:对米色卡面 PANEL_DATA 3.69:1(深档 SLOT_BACKDROP #3E362C 8.53:1 过强、像硬贴补丁,故槽底另立柔和档),槽内白图标 5.14:1,满足 ≥3:1 图形参考线硬约束;仅 BCard 图标槽换档,B 区状态槽仍用深档 SLOT_BACKDROP。验收:机检〈槽内白图标对槽底 ≥3:1〉
- **群伤微光暗档 `#A61D37`(TG_GLOW_AOE)**|类型微光群伤组的**明度档**(UI token 板,占 1 枚额度,**余量 3→2**):色相 349° 与亮档 `#FF2D55` 零移动,明度落 V=0.65 档——即 §4.2「微光 = 色相+明度双码」里明度侧的落法;与 §4.2「红只说危险」不相撞(微光组色相刻意错开语义红,见 §4.2「类型微光色带」条)。已在役(`ui_kit.gd` 常量与 `type_glow_test.gd` 守门断言),本节为登记转正。验收:机检〈ui_kit.gd TG_GLOW_AOE 与 type_glow_test 断言的 H/S 逐位一致、V 落 0.65 档〉
- **站桩石板地台板身 `#968264`(STAND_STONE)**|战斗屏场景环境子板(分层②,不占 48 token 额度):B 区站桩地台板身与顶缘的材质色,跨三关恒定、不吃 §4.3 `wall_ambient` tint(地台是 §6.1 定死的世界中层承载面,随关卡变会破 §2 明度分层的层间关系)。转正前即在役。验收:机检〈战斗屏场景环境子板色数 ≤32 且本值在册〉
- **重甲冷灰金属材质色 `#868C9A`(ARMOR_PLATE_COLD,token 名暂拟、随实装批登记)**|语义/UI token 板(**分层①**,占 1 枚额度,**余量 2→1**;用户裁):重甲档甲材质色;character-design §5.3 通道 = 甲面覆盖率 × 甲材质色,甲材质色按甲档统一,故石君王岩石板甲**同引本枚、不另计额度**;材质色跨屏恒定,落分层①不落分层②(环境色才随场景走)。过门情况:第二道门按宽松口径(禁止三通道全 <8)与在册色逐一比对,**无三通道全 <8 的对 → 过门**;§4.2 语义检查过门(色相 222°,不占红/金/蓝/紫赤/绿语义段、不在 300°–345° 禁入带;材质色不进信息层与语义物件岗)。对比实测:对深素底 `#282220` 4.65:1、对舞台底 `#3E362C` 3.52:1(图形 ≥3:1 门槛);相对亮度 L≈0.261 落 §2 世界中层 0.22–0.45 带。验收:机检〈本值入板后全板色对中三通道差全部 <8/255 的对数 = 0〉
- **卓尔浅紫灰皮 `#A79CB8`(DRIDER_SKIN,token 名暂拟、随实装批登记)**|语义/UI token 板(**分层①**,占 1 枚额度,**余量 1→0,额度用尽**;用户裁):蛛化卓尔精灵上体皮色(体块主色,L≈0.355 落 §2 世界中层带)。过门情况:第二道门同上行口径,**无三通道全 <8 的对 → 过门**;§4.2 语义检查过门(色相 264°,避开 300°–345° 禁入带,紫赤独占仍归 `#8F2F6A`;不占本节五语义段)。对比实测:对深素底 `#282220` **6.04:1**、对舞台底 `#3E362C` **4.57:1**——**两处均过图形 ≥3:1 门槛**(本轮新算)。验收:机检〈本值入板后全板色对中三通道差全部 <8/255 的对数 = 0〉
- **换色合并登记五处(用户裁,部件色落值)**|按本表「不过门即触发换色合并、禁加色绕行」执行,五处**零新增额度**(各件原拟新增候选一律不取):① 主角铲刃浅铁灰(原拟 `#A8AEB8`)→ 并入 `FOG_MEMORY_INK #C4C4C4`,**部件取值 = `#C4C4C4`**;② 主角提灯铜色(原拟 `#C08A3A`)→ 并入 `GOLD_DEEP #B07A14`,**部件取值 = `#B07A14`**;③ 食人魔酋长暖褐皮(原拟 `#B08050` / `#A97C4E`)→ 并入 `暖石 #B8A582`,**部件取值 = `#B8A582`**;④ 石君王灰皮(原拟 `#9A968C` / `#949089`,按**次级皮**口径——板甲视同体块主色、灰皮属次级皮故不受 L 0.22–0.45 约束)→ 并入 `STONE #786E62`,**部件取值 = `#786E62`**;⑤ 轻甲护甲图标木色 `#8A5A34`(深素底下 2.72:1 不过门;原拟新增木色亮档 `#C49A5E`)→ 并入 `WARM_FAINT #CDB88C`,**部件取值 = `#CDB88C`**(8.08:1)。**一色两岗代价已随裁定接受**:① 的 `#C4C4C4` 语义岗 = 迷雾记忆墨(§6.5)、② 的 `#B07A14` 属金族(§4.2 金只说收益与兑现)——两者均作角色随身件材质色用,不进信息层与语义物件岗;③④⑤ 无语义岗冲突。验收:机检〈五处部件取值点全部改指合并目标色,四枚原拟新增候选值零入板〉
- **换色合并登记三处**|按本表「不过门即触发换色合并、禁加色绕行」执行,三处零新增额度:`#3E342A`(舞台底,代码 `STAGE_BG`)→ 并入 `#3E362C`(状态槽底);`#C4AC84`(地台顶缘受光线,代码 `STAND_STONE_RIM`)→ 并入 `#C9AF83`(掩尘,并与 §8.2 高墙口沿高光 `Color8(196,172,132)` 统一为同一枚);`#5A4C3A`(地台描边,代码 `STAND_STONE_EDGE`)→ 并入 `#4C4038`。验收:机检〈全仓三枚源常量零引用,绘制点全部改指合并目标色〉
**对比硬指标(可测)**:数字可读性由**格底明度分档**承载——棋盘数字亮墨 **L≥0.75** 对**已开格底 L 0.08–0.14** ⇒ 直画对比 **≥4.5:1 恒成立**(WCAG AA,样张逐组合抽测冻结);**色牌后备**:色牌素色恒定 **L≥0.70**、牌上数字深墨 **L≤0.027** ⇒ 任意牌墨组合 ≥4.5:1(实测样例:#33261B/#F5EAD3 = 12.3:1)。未开格底槽(含全部图类型)相对亮度 **L≥0.30**(墙顶面受光档)、HSV 饱和 **≤0.55**、避 Boss 禁入色相带;已开格底走世界底层档(见上)。物件识别不依赖格底(§5.1 轮廓通道),旗面、金色不作识别依赖。验收:机检〈亮墨对已开格底 ≥4.5:1;未开格底 L≥0.30、饱和 ≤0.55;任意牌墨组合 ≥4.5:1〉 ←原二;地形变异 AC-9
**色板增量纪律(数值状态 = 待定现用)**:全作色板硬上限 **48 色**(防色板无限膨胀的封口条款;额度余量以色板检查器实报为准);新色入板须同时过两道门:①§4.2 语义检查(不占语义色段/禁入带);②**与既有任一色的 RGB 三通道差 ≥8/255**——反例实证:#3A2E22 ↔ #362B20 三通道差均 <5,肉眼不可辨,同板共存只增噪。不过门即触发「换色合并」(把意图色并进最近既有色),**禁加色绕行**;加色义务同时登记于本表修订。**「待定现用」态释义**:数值**现行即执法**(色板检查器按此拦,§8.3)——非候选(不存在"等冻结"空窗)、非死规(后续需求引入时可变);调整走本节修订并登记,改值 = 修订不是违约。验收:机检〈色板总数 ≤48;新色入板过两道门〉
**色板增量纪律(数值状态 = 待定现用)**:全作色板硬上限 **48 色**(防色板无限膨胀的封口条款;**额度已用尽、余量 0**,后续余量以色板检查器实报为准);新色入板须同时过两道门:①§4.2 语义检查(不占语义色段/禁入带);②**与既有任一色的 RGB 三通道差禁止全部 <8/255**——即三通道里至少一通道 ≥8/255 即过门,「三通道差全部 <8」才算不过门(条文原写的「三通道差 ≥8/255」有「逐通道全过」与「禁止全灭」两种互斥读法,前者下现行色板 247 对不达标、与本节自认的「现行即执法」合规状态不能同真,故取后者;用户裁)。**额度已用尽:后续任何新增须先压缩或合并既有色**——按本节「额度不足时呈报作者」口径呈报,**压缩或合并哪几枚由作者裁,本节不代裁、不预指对象**。反例实证:#3A2E22 ↔ #362B20 三通道差均 <5,肉眼不可辨,同板共存只增噪。不过门即触发「换色合并」(把意图色并进最近既有色),**禁加色绕行**;加色义务同时登记于本表修订。**「待定现用」态释义**:数值**现行即执法**(色板检查器按此拦,§8.3)——非候选(不存在"等冻结"空窗)、非死规(后续需求引入时可变);调整走本节修订并登记,改值 = 修订不是违约。验收:机检〈色板总数 ≤48;新色入板过两道门〉
- **色板分层**:色板分两层管理——① **语义/UI token 板**:全作共享,硬上限 **48 色**,管 UI 语义色、墨色、材质色,跨屏恒定;② **场景环境子板**:**每屏一套,≤32 色,允许跨屏不共享**(环境色 = 天空、地面、植被、石材、火焰等随场景走的颜色)。新增环境色仍须过两道门(§4.2 语义检查 + 与既有任一色 RGB 三通道差 ≥8/255),但**不占用 48 token 额度**;不过门照旧走「换色合并」,**禁加色绕行**。单张 PNG 的像素域色数上限 **≤32 色**另由 `standee_asset_check` 执法(按单图像素域取值方式计数,与本表 token 计数互不干扰)。额度不足时向作者报告,由作者决定压缩或合并既有色。验收:机检〈token 板 ≤48;每屏环境子板 ≤32〉
- **换色合并欠账清单(全板重扫 6 对不达标,逐对清偿)**:`#18120C` ↔ `#181410`、`#33261B` ↔ `#362B20`、`#362B20` ↔ `#3A2E22`、`#3E362C` ↔ `#3E3731`、`#3E4048` ↔ `#3F4147`、`#453723` ↔ `#4A3B2A`——六对按「不过门即换色合并」纪律逐对清偿(并进最近既有色);清偿前该对不视作合规,清偿动作落本节修订。**本节所举反例 `#3A2E22` ↔ `#362B20` 正在这 6 对之内**,与本口径自洽。验收:机检〈全板色对中三通道差全部 <8/255 的对数 = 0〉
- **色板分层**:色板分两层管理——① **语义/UI token 板**:全作共享,硬上限 **48 色**,管 UI 语义色、墨色、材质色,跨屏恒定;② **场景环境子板**:**每屏一套,≤32 色,允许跨屏不共享**(环境色 = 天空、地面、植被、石材、火焰等随场景走的颜色)。新增环境色仍须过两道门(§4.2 语义检查 + 与既有任一色 RGB 三通道差禁止全部 <8/255),但**不占用 48 token 额度**;不过门照旧走「换色合并」,**禁加色绕行**。单张 PNG 的像素域色数上限 **≤32 色**另由 `standee_asset_check` 执法(按单图像素域取值方式计数,与本表 token 计数互不干扰)。额度不足时向作者报告,由作者决定压缩或合并既有色。验收:机检〈token 板 ≤48;每屏环境子板 ≤32〉
### 4.2 语义色彩规则
> **适用域**:本节「X 只说 Y」约束**信息层**(格内信息/UI 数据/预告/语义标识)与**语义物件**(GP=收益金、血条=危险红等);**纯环境氛围**(背景/装饰变体/远景/非语义物件)不受色相独占约束,改受 §3.4 焦点预算与低饱和后退约束(不抢读即可用色)。禁入带 300°–345°:信息层与语义物件禁入不变;环境层可入但限低饱和(高饱和紫赤仍 Boss 独占,§2.6)。验收:目检〈信息层与语义物件不落禁入带、不占语义独占色相;环境层用色低饱和〉
- **红只说危险**:危险红 = 兑现档,红族单档。禁(信息层域):红禁止用于奖励、装饰性标识与常规 UI(微光群伤组除外——见「类型微光色带」条,其色相刻意错开语义红)。验收:目检〈信息层域红色仅出现在危险语义与微光群伤组〉 ←原三;P2;§2.1
- **血条填充 = 危险红 `#A8321F`**(语义物件显式落法):血条是本节适用域点名的语义物件,填充色族一律归危险红,不因敌我分色、不因关卡换族。读数不依赖填充色对比——血量数字 11px 压 `HP_BAR_BACK` 素牌(§7.4 豁免①,14.3:1),填充只承载「剩余比例」的形状语义。**蓝族引擎默认近似值 `#689CE8` 登记为违例值、已退役**:它同时撞本条「血条=危险红」与蓝条「蓝禁止表示敌方危险」,禁再入任何血条绘制点。验收:机检〈血条填充绘制点取值为 #A8321F 且全仓零 #689CE8 字面量〉
- **金只说收益与兑现**(奖励、结算、胜利)。禁(信息层与语义物件域):金禁止作危险障碍色、不上格底、不作日常 UI 强调(防通胀;微光通用增益组的芥末黄属「类型微光色带」条色带,非收益语义金)。验收:目检〈信息层与语义物件域金色仅承载收益与兑现〉 ←P2;P3;§2.2–2.4
- **蓝只说己方与冷静信息**(小人、光标、工具信息——含可挖域接触带呼吸微光,蓝族浅一档 `#D6ECFF`)。禁(信息层域):蓝禁止表示敌方危险;暮蓝 `#5A6C8C` 为失败独占(§2.5),只作全屏氛围,不作物件色。验收:目检〈信息层域蓝色仅承载己方与冷静信息;敌方危险无蓝色〉 ←P1;§2.5
- **紫赤只说 Boss 与精英** `#8F2F6A`(色相 323°):郑重来自色相独占,不来自压暗。禁:**HSV 色相 300°–345° 为信息层与语义物件禁入带**——UI、粒子、类型微光、语义物件及图类型色板信息面禁止落入;环境层(背景/装饰)可入但限低饱和,高饱和紫赤仍 Boss 独占。验收:机检〈信息层与语义物件色值色相不落 300°–345°;高饱和紫赤仅 Boss 战〉 ←§2.6;原三
@@ -337,7 +350,7 @@
| 线索通道 | 冻结内容 |
|---|---|
| 意图姿态 | **动画三档**:① 普通攻击 = 常态待机(零独立资产);② 攻击技能 = 特殊准备动画(放光/高举武器);③ 重击/硬化类 = 蓄力动作或防御姿态。不显示文字与技能名(信息定义见《敌人系统》意图线索节);三档在灰度/剪影层可辨(双通道纪律) |
| 强度档位 | 体量通道:§5.1 archetype 体量/垂直延伸("大个子多半有重击");护甲类型(light/ward/heavy)视觉区分方案已落 §5.3(候选,样张验收时冻结) |
| 强度档位 | 体量通道:§5.1 archetype 体量/垂直延伸("大个子多半有重击");护甲类型(light/ward/heavy)视觉区分方案已落 §5.3(已定稿) |
| 预告时序 | 预告语义见《敌人系统》意图线索节,呈现义务(挖掘期全程可见)见《HUD框架》;本表只锁「结算不另设独立意图播片」的动画形态 |
| 恒定义务 | enemy_id 键映射跨 run 恒定、禁重掷;图像不报数——精确数值的明细承载见《战斗结算》。验收:机检〈enemy_id 键映射跨 run 恒定、禁重掷〉 |
@@ -352,7 +365,7 @@
> **本节内容已整体迁至独立文档 [`character-design.md`](character-design.md)**(小节号 §5.1–§5.6 在该文档中沿用不变)。迁移动机:人设高频改动,独立成档免动圣经;本存根保证既有 "art-bible §5.x" 式引用(§4.1/§4.5/§4.6.4、art-assets-checklist、战斗表现)经此仍可达,新引用直指该文档。
内容速览:§5.1 角色剪影与轮廓通道 · §5.2 头身比与体量档位 · §5.3 护甲类型视觉区分(候选,样张冻结终稿) · §5.4 主角三态规格(形象锚 = 蓝兜帽披肩的暖装小冒险者:圆头挖掘铲 + 冒险背包插朱红矩形旗(与棋盘封印色脱钩) + 护目镜腰灯) · §5.5 八敌种逐卡 · §5.6 意图准备动画三档。
内容速览:§5.1 角色剪影与轮廓通道 · §5.2 头身比与体量档位 · §5.3 护甲类型视觉区分(已定稿) · §5.4 主角三态规格(形象锚 = 蓝兜帽披肩的暖装小冒险者:圆头挖掘铲 + 冒险背包插朱红矩形旗(与棋盘封印色脱钩) + 护目镜腰灯) · §5.5 八敌种逐卡 · §5.6 意图准备动画三档。
---
@@ -363,10 +376,11 @@
### 6.1 战斗舞台背景(B 区环境)
- **双舞台常驻下的 B 区环境**:战斗画面区(站桩立绘所在)的背景 = 明亮地窟,与 §1 风格基调同源——暖倾向、无压抑;背景整体**低对比自然后退**(§3.4 焦点预算延伸):背景禁止构成完整凸形、禁止抢 B 区立绘与 D 区数字的焦点,识别层级恒为 立绘 > 背景。验收:目检〈背景无完整凸形、立绘最抢眼〉
- **舞台正面目标**:B 区 = **地窟看台**——立绘脚下地台/落影承载(世界中层),背景环境层低饱和后退、明度走世界底层档,允许光源氛围(洞顶光柱/暖光晕候选);角色禁止直接贴平色底。规格与终值归整屏样张闸(§1.4)冻结。验收:目检〈立绘脚下有地台/落影,非贴平色底〉
- **舞台正面目标**:B 区 = **地窟看台**——立绘脚下地台/落影承载(世界中层),背景环境层低饱和后退、明度走世界底层档,允许光源氛围(洞顶光柱/暖光晕候选);角色禁止直接贴平色底。规格与终值归整屏样张闸(§1.4)冻结。**地台面上零文字**——暖白 `#F0E2C8` 对地台板身 `#968264` 实测仅 2.89:1,已越 §7.2 的 4.5:1 硬指标,落法按 §7.2「文字禁直接压纹理底」(垫容器、素牌或罩层),非新条款;站桩文字位改垫素底或落进结算明细带(实装=站桩名字行垫 `HP_BAR_BACK` 深档素底牌、文字基线上移至地台顶上方——2026-10-30 落地)。验收:目检〈立绘脚下有地台/落影,非贴平色底〉+机检〈B 区站桩文字位正下方像素非地台板身色 #968264〉
- **明度分层适用**:背景氛围的情绪表达仍禁止以压暗/渐晕实现(§2 禁令);空间纵深与洞穴感走明度分层允许域——世界底层档、光照氛围、色相饱和与形体承载(§3.2 同款逻辑)。验收:方向性
- **图类型联动**:背景 tint 走 §4.3 `wall_ambient` 槽,随三关换挡(方向候选见 §6.3);紫赤仅 Boss 战允许短暂进入背景氛围纹样(§2.6 色相独占的舞台侧延伸,高饱和独占不变),非 Boss 战高饱和紫赤禁入。验收:机检〈背景吸色无非 Boss 高饱和紫赤〉
- **资产渠道**:✦ 插画级(演出类场景贴图,清单 §4 联动登记);战斗一屏样张(§1.4 清单 1.2)含背景出样。**资产契约(尺寸候选,样张冻结终稿)**:基准一张 = `stage/stage_bg.png`(源 1280×270,B 区全高含明细带底;三关换挡走 §4.3 `wall_ambient` tint 槽,不按板出三张——换皮成本复用棋盘同款逻辑),显示 1×;呈现约束按本节各条(低对比后退/明度世界底层档/光柱氛围保留)。程序化平色+光柱现行使用 = 占位;插画工单归 PRD,交付后 art-status-checklist 同步 ✅。
- **资产渠道**:✦ 插画级(演出类场景贴图,清单 §4 联动登记);战斗一屏样张(§1.4 清单 1.2)含背景出样。**资产契约(尺寸候选,样张冻结终稿)**:基准一张 = `scene_stage_bg.png`(源 1280×270,B 区全高含明细带底;三关换挡走 §4.3 `wall_ambient` tint 槽,不按板出三张——换皮成本复用棋盘同款逻辑),显示 1×;呈现约束按本节各条(低对比后退/明度世界底层档/光柱氛围保留)。程序化平色+光柱现行使用 = 占位;插画工单归 PRD,交付后 art-status-checklist 同步 ✅。**出图只出远景 + 中景两带**:结算期明细带底 84px 会盖住 B 区 78%–100% 段(约 59px),近景带在结算期整条不可见——画进背景等于画一件永远看不见的东西。远景/中景的构图占比归整屏样张(§1.4)。验收:目检〈背景插画内零地台结构件〉
- **近景地台走独立件**:`scene_stage_plaza.png`,源 48×12、九宫格横向拉伸、顶缘受光线 2px 不随拉伸变形(规格见 §8.2)。独立的两条理由——① 上条的 84px > 59px 覆盖账;② §4.3 `wall_ambient` tint 作用于整张背景,地台若画进背景会随三关换明度,而 §6.1 舞台正面目标把地台定死为世界中层承载面,随关卡变会破 §2 明度分层的层间关系。独立件跨关恒定。验收:机检〈地台件按九宫格拉伸后顶缘受光线宽度恒为 2px〉
### 6.2 营地场景
@@ -381,7 +395,7 @@
### 6.3 三关图类型色板候选(board_type 换挡方向)
- **模板与不变槽**:换皮只换 §4.3 四槽(`tile_closed`/`tile_open`/`wall_ambient`/`variant_tint`),信息与语义层全图类型恒定——本节只给三关**方向性候选**,终值按 §4.3 现行规则重跑 §1.4 格子样张冻结。
- **模板与不变槽**:换皮只换 §4.3 四槽(`tile_closed`/`tile_open`/`wall_ambient`/`variant_tint`),信息与语义层全图类型恒定——本节只给三关**方向性候选**,终值按 §4.3 现行规则重跑 §1.4 格子样张冻结。**终值的取值程序**:先跑「三关色相 × 五组类型微光」互辨抽测(抽测任务登记在待办清单),再按 §4.3 现行规则重跑 §1.4 格子样张冻结——本节不填终值色值,待该抽测与格子样张重跑后落本节修订。验收:机检〈本节三关行无 `tile_closed`/`wall_ambient` 终值色值字面量(终值未冻结前禁填)〉
- **深度轴叙事**(§2.7 下探过渡):色相层进预告「更深更险」,明度档不动——
- **dungeon 地精洞窟**(第一关):现行掩尘系暖石棕(`#C9AF83` 基)即基准档,`wall_ambient` 暖棕;
- **underdark 幽暗地域**(第二关;方向:**冷调幽暗**):主调**灰白蓝**候选(低饱和蓝灰域,`tile_closed`),少量紫黑倾向点缀——紫系取紫罗兰域(≈256°)候选,禁入带 300°–345° 不变;`wall_ambient` 冷蓝灰;
@@ -424,7 +438,7 @@
### 7.2 UI 色板细则(自 §4.4 迁入)
**全局文字可读性硬指标**:**一切文字**(含菜单/说明/tooltip/按钮/底栏,无区域例外)对其直接背景 **≥4.5:1**(WCAG AA);大字(≥18px 或加粗档)底线 3:1、目标 4.5:1;**文字禁直接压纹理底**——垫容器或罩层。核验闸 = §1.4 整屏样张。验收:机检〈ui_contrast_probe 全文字位 ≥4.5:1〉
**全局文字可读性硬指标**:**一切文字**(含菜单/说明/tooltip/按钮/底栏,无区域例外)对其直接背景 **≥4.5:1**(WCAG AA);大字(≥18px 或加粗档)底线 3:1、目标 4.5:1;**文字禁直接压纹理底**——垫容器或罩层。**站桩石板地台面同理**(显式落法):地台板身 `#968264` 是 §6.1 定死的世界中层承载面,暖白 `#F0E2C8` 对其实测仅 2.89:1,文字禁直接压地台面——须垫容器、素牌或罩层,或落进结算明细带的素底。核验闸 = §1.4 整屏样张。验收:机检〈ui_contrast_probe 全文字位 ≥4.5:1;B 区站桩文字位正下方像素非地台板身色 #968264〉
**数据素面的墨来自世界的墨**:UI 数字、进度、准线一律主墨 `#33261B` 系——棋盘与面板读同一种墨;容器穿木石材质色,数据只穿墨。**营地与棋盘**:菜单容器背景用全作最暖的烛光黄 `#F6C667` 与木色 `#8A5A34`(§2.8;场景构成 §6.2);战斗容器转中性石色,防暖色渗入棋盘分走数字对比预算——氛围色向可读色让路。UI 不新增语义色,一切强调沿用 §4.2。**暗底呈现态双色墨制**(样张冻结):暗底系(已过/未来/候选/Boss 方块、暗数据框)图标与读数一律暖白 `#F0E2C8`(WARM)、亮底(当前金 `#F0A828`)转深墨 `#181410`(INK_ROUTE)——各态对比 ≥4.5:1;已过节点暗金冻结 `GOLD_DONE #68562C`(专用呈现态值;旧 GOLD_DIM 对双色墨不达标、已退出该呈现位);Boss 描边 = 紫赤 2px + 外缘 1px 深墨环(灰度冗余通道——§4.2 色相独占本色不变,§4.5 灰度可分类承载)。验收:机检〈暗底/亮底各态文字对比 ≥4.5:1〉
@@ -441,8 +455,8 @@
- **字体**:全局一套像素字,单套即终稿——缝合像素字体 Fusion Pixel(OFL,已接入 `game/assets/fonts/ui_font_fusion_pixel_zh_hans.ttf`),拉丁字符与数字沿用其自带拉丁字形,不另设拉丁专件(现状即终稿;旧拉丁候选 Kenney Fonts 已弃;生产工单=清单 §3.6);墨色走主墨系(§7.2);换字体 = 全局决策。验收:机检〈主题字体指向 Fusion Pixel 件〉
- **字号**:像素字体**整数倍缩放,禁非整数缩放**(像素模糊);下限(1280×800 基座):棋盘数字 ≥18px(公式 = `max(18, ceil(格边长 × 0.5))`不变)、**正文/明细 ≥16px、tooltip ≥14px**(1280×800 低于 1080p 基准,同字号实际更小)。验收:机检〈静态文字位点字号 ≥ 档位表值〉
- **字号档位表(六档)**:全站 UI 文字字号只经 `UiKit.FS_*` 单点取值,裸数字字号弃用——`FS_CAPTION 12`/`FS_HINT 14`/`FS_BODY 16`/`FS_SUB 18`/`FS_TITLE 24`/`FS_H1 34`。旧实测档按就近归档收编(10/11/12→CAPTION、13/14→HINT、15/16→BODY、17/18/20→SUB、21/22/24/26→TITLE、32/40→H1;静态位点全归档,数据驱动动态字号位点除外);棋盘数字公式 `maxi(18, ceil(格边长×0.5))` 与站桩血数 11px(条带内读数豁免)不入表。注:六档相邻比 12→14→16→18 三段 <1.25×,系裁决值优先于字重纪律的档差参考线,该参考线对新层级设计仍有效。验收:机检〈全站无裸数字字号,位点走 FS_*〉
- **小字号豁免条款(合并单条不开两口子)**:下款两类**豁免于本节下限**——①**条带内读数**:压在窄条带(血条/进度条等 ≤12px 高带)内居中的数字,受条带高度物理约束,维持 11px 下限,且必须按 §7.2 垫素色牌后计对比(实装=B 区站桩血数 11px 压 HP_BAR_BACK 牌 14.3:1);②**装饰性 overline/caption**:不承载须精确读取的信息、仅作分区标题或氛围小字者,可至 **12px**。**豁免逐处清单(撤除史归 git 提交史,余清单如下)**:条带内读数=B 区站桩血数一处;装饰 caption 档(FS_CAPTION)在册面=棋盘底操作提示条/营地柜台说明文与结构位预留注记/图例 RAP 词条说明/设置警示文两处/关卡地图底栏组标(生命/属性/特性)与分隔系/站桩消散提示/B 区状态槽微计数(×N●○)/bcard 脚注/RAP 反馈行/刷新余量徽标——清单外 11-13px 文字一律按正文/tooltip 下限提档,新增 caption 位须同批增补本清单。验收:机检〈豁免文字位均可对上本清单,清单外无 <14px〉
- **字重纪律(字重两档不启用)**:层级手段为两件——**字号档差(相邻层级 ≥1.25×)+ 墨色深浅**;全局单字重,不上第二个字重(重开钩子:战斗一屏样张设计轮若实证标题层级不足,字重议题随该轮重开,不另立条目);数字禁描边/阴影伪加粗不变(字形为唯一数值载体,§4.1 同源纪律)。验收:机检〈主题仅注册单字重〉
- **小字号豁免条款(合并单条不开两口子)**:下款两类**豁免于本节下限**——①**条带内读数**:压在窄条带(血条/进度条等 ≤12px 高带)内居中的数字,受条带高度物理约束,维持 11px 下限,且必须按 §7.2 垫素色牌后计对比(实装=B 区站桩血数 11px 压 HP_BAR_BACK 牌 14.3:1);②**装饰性 overline/caption**:不承载须精确读取的信息、仅作分区标题或氛围小字者,可至 **12px**。**豁免逐处清单(撤除史归 git 提交史,余清单如下)**:条带内读数=B 区站桩血数一处;装饰 caption 档(FS_CAPTION)在册面=棋盘底操作提示条/营地柜台说明文与结构位预留注记/图例 RAP 词条说明/设置警示文两处/关卡地图底栏组标(生命/属性/特性)与分隔系/站桩消散提示/B 区状态槽微计数(×N●○)/bcard 脚注/RAP 反馈行/刷新余量徽标——清单外 11-13px 文字一律按正文/tooltip 下限提档,新增 caption 位须同批增补本清单。**站桩顺位徽标 ①②③ 不增列本清单**:该处原为 13px 字形,既不在①条带内读数在册面、也不在②装饰 caption 在册面,属「清单外 11–13px 文字」,按本条纪律提档至 `FS_HINT` 14 即归六档;为它单独入册等于开第二口子,与「合并单条不开两口子」的立条理由正面相撞。②装饰 caption 在册面逐处维持不变。验收:机检〈豁免文字位均可对上本清单,清单外无 <14px;站桩顺位徽标绘制点取 UiKit.FS_HINT,且②在册面不含该位〉
- **字重纪律(字重两档不启用)**:层级手段为两件——**字号档差(相邻层级 ≥1.25×)+ 墨色深浅**;全局单字重,不上第二个字重(**重开钩子已注销**——整屏样张设计轮已重开并复核:屏内各级文字全部能归进本节六档字号,顺位徽标与站桩名字行两处按本节纪律提档即可,屏内实测对比全部达标(暖白对舞台底 9.49:1、GOLD_BRIGHT 6.47:1、血数 14.3:1),**未实证标题层级不足**,维持单字重,不另立条目);数字禁描边/阴影伪加粗不变(字形为唯一数值载体,§4.1 同源纪律)。验收:机检〈主题仅注册单字重〉/目检〈屏内标题与正文层级仅靠字号档差与墨色深浅两件即可分辨,无一处需要第二字重才读得清〉
### 7.5 营地界面
@@ -473,7 +487,7 @@
**(三)氛围层平滑件与抖动派并存**
- vignette / gradient_base / beams 三件程序化平滑渐变件**保平滑连续 alpha**(已裁),与卡顶类型色带 DitherBand 的 Bayer 有序抖动派**并存不一致**——两派统一裁决留**整屏样张**(§1.4;战斗一屏样张未开工,待办清单在册),本节只登记并存事实与裁决去向,不提前统一。验收:方向性
- vignette / gradient_base / beams 三件程序化平滑渐变件**保平滑连续 alpha**(已裁),与卡顶类型色带 DitherBand 的 Bayer 有序抖动派**并存不一致**——**整屏样张已裁:维持三件保平滑,并存事实按本节登记,不再统一**。裁定的依据:三件保平滑有用户裁背书、且已在 §8.2 显式 LINEAR 豁免清单在册(该清单写的是「怎么继续维护」不是「要不要取消」),统一派等于推翻用户裁并清空该清单;「把两派调参拉到同一颗粒感知档」在圣经里无任何条款依据,属自造动作。本节只登记并存事实,不统一。验收:方向性(目检复核:三件氛围件与卡顶抖动带同屏时,两派颗粒语言差异不构成观感冲突)
> **主题色值双源注记**:主题色值现存两处——`main_theme.tres` 字面量与 ui_kit 常量(README 溯源表缓解)。长期收敛候选 = 程序化 Theme 生成回代码单点,属重构面、未排期;新增色值仍按现状双落并同批登 README 溯源表。
@@ -495,15 +509,16 @@
- **缩放纪律(硬规则,按资产两类分级;不做个案豁免)**:
- **甲类·文本与语义件**(数字、图标、旗、格面纹样):维持严格整数倍缩放硬规则——可读性与语义精确性优先,**禁非整数缩放不变**。砖面 tile 不属本类,随格边长整格铺满(见 §8.1)。验收:机检〈甲类件显示尺寸为源整数倍〉
- **全局纹理过滤与平滑渐变件例外**:`project.godot` `default_texture_filter=0`(Nearest)全局——像素风 UI 皮(九宫格/主题石纹样式盒/滑轨抓子/勾选/箭头图标)翻 Nearest=意图面;**显式 LINEAR 豁免清单(有意例外)= vignette / gradient_base / beams 三件程序化平滑渐变件**——保平滑连续 alpha 的程序化氛围件(§7.6 三已裁);新增平滑件须同批入册本清单,禁静默挂 LINEAR。翻转面枚举与冒烟断言(6 条)在闸。验收:机检〈过滤面枚举与 LINEAR 清单逐项一致〉
- **显示档登记例外(64 源 0.5×,待素材批消除)**:柜台四枚 `icon_forge/workshop/atlas/keystone`(64×64 源)显示档统一 **32px = 0.5×**;状态九枚(32×32 源)mini(站桩)档 **16px = 0.5×**。两处均系「显示尺寸侧唯一可调、素材一字节禁改」红线下的人工检整数半倍档,登记为**待消除例外**——素材设计出 32px 源后回归 1×。常规档显示一律 1×(状态九枚 32px、手绘十枚 20px/40px 双档、BCard 图标槽 40px=2×)。验收:机检〈显示档与登记表一致〉
- **显示档登记例外(64 源 0.5×,待素材批消除)**:柜台四枚 `icon_forge/workshop/atlas/keystone`(64×64 源)显示档统一 **32px = 0.5×**;状态九枚(32×32 源)mini(站桩)档 **16px = 0.5×**。两处均系「显示尺寸侧唯一可调、素材一字节禁改」红线下的人工检整数半倍档,登记为**待消除例外**——素材设计出 32px 源后回归 1×。常规档显示一律 1×(状态九枚 32px、手绘十枚 20px/40px 双档、BCard 图标槽 40px=2×、**护甲类型图标三枚 24px=1×**——源 24×24,归甲类整数倍纪律)。验收:机检〈显示档与登记表一致〉
- **乙类·角色与单位精灵**(有机形体、非文字):允许运行时非整数倍缩放(NEAREST 过滤不变),容忍轻度像素宽窄不均;判据 = 实机目检,可感不适即回整数档。乙类免逐案豁免。验收:目检〈立绘无可感拉花〉
- **站桩立绘槽位=高定宽随**:立绘/精灵槽位只定「高度的整数倍档」,宽度随源图宽高比自适应——**禁止把全部立绘塞进统一方框强拉**(纵横倍率必须恒等)。反面实例:统一方框把窄条生物源(细长本体裁掉透明边)按主角比例横拉压扁发花。乙类的非整数豁免只覆盖**等比**缩放,不含纵横异倍变形。验收:机检〈立绘纵横倍率恒等〉
- **1920×1080 档策略**:全局等比(stretch=canvas_items+aspect **keep**)——16:10 设计在 16:9 窗口=等比 1.35×+左右黑边各 ~96px,构图与 1280×800 基准档完全一致;甲类 1.35 非整数缩放例外注记:轻度宽窄不均系本档位接受代价(像素游戏 shipped 常态),实机目检可感不适→回乙案(1920 独立 2× 基准)重议;乙类同前款。验收:目检〈1920 档构图与 1280 档一致〉
- **画布基准(暂定值)**:
- **主角人设原图 = 48×72**(1× 基准,暂定;与站姿降采样可读性验证一致);
- **棋盘小人 = 32×32 二头身派生版(暂定,允许更小)**——独立资产,自人设定稿压缩派生(character-design §5.4),不吞数字位、占位 ≤ 0.75× 格边长;板越小占比摩擦越大(13×13 / 14×14 更小,算例见 [battle.md](../gdd/ux/battle.md)「棋盘格尺寸公式」),32px 源档沿「独立小源档」路线在样张定终值;
- **棋盘小人 = 32×32 二头身派生版(暂定,允许更小)**——独立资产,自人设定稿压缩派生(character-design §5.4),不吞数字位、占位 ≤ 0.75× 格边长;板越小占比摩擦越大(13×13 / 14×14 更小,算例见 [battle.md](../gdd/ux/battle.md)「棋盘格尺寸公式」),32px 源档的去留已定终值 = **保留 32×32 源档**(沿「独立小源档」路线;N=12 板下显示占位上限 27px = 0.84 倍,正落本节乙类非整数缩放许可范围,**连豁免都不用再办**),待决标注注销;
- **站桩立绘源档 = 八敌逐键定档**:主角 48 不变;八敌源档高 = goblin 36 / giant_spider 38 / duergar 46 / hook_horror 58 / bugbear 62 / ogre_chief 74 / drider 90 / duergar_king 94,显示一律 **×2 整数档(NEAREST)** = 72–188。定档依据 = 生物体型三约束(钩爪恐魔>灰矮人、灰矮人<熊地精、食人魔>熊地精——体量=物种体型,非强度线性映射,见 character-design §5.2);可读性实测门槛 = 源高 ≥32(24 糊/32 可读/48 清楚/64 细节完整),全阶梯 36–94 达标;派生管线 = pixel-1.png 紧裁 → 等比缩至档高 → dom_block_resize 块内众数降采样(tools/pixelize_candidates.py `STANDEE_TIER_H`,`SIZES` 降格为管线上游中间分辨率表);体量存在感经整屏对比校验(B 区 270/立绘显示上限 188)。验收:机检〈standee_asset_check 逐键档高校验〉
- **站桩立绘排版**:① 区高 B 区 270(≈1/3)/C 区 530(≈2/3),**扫雷盘 438×438 原尺寸不缩、格子不变**(区高事实源 battle.md 区表;压缩由 C 区面板空档吸收);② 站桩内部重排——立绘双脚落石台上缘(弃盒内居中)、**血条+状态/名字行落底排**(立绘→血条→状态 顺序,全场血条对齐一线;血条嵌石板位、台缘线留作地面线、落影保留接地感),状态空时该行退化为名字行;③ 大体档(显示 >150px 级:drider/duergar_king)**允许向上溢出盒顶 N px**(N 由实装批按实测尺寸算定,**与背景/光柱无关**——现行溢出区恰为临时光柱氛围层〔§6.1 方向稿四柱,x 基准 110/900/1055/1210@1280,`battle_stage_view.gd:55-63`〕,正式舞台背景插画 `stage/stage_bg.png` 到位后该层由背景绘制吸收,**溢出判定不随之变更**;横向禁止压到顶部中央轮次·阶段指示,溢出上限由实装批用真图复算 x 区间定),血条仍落底(落底排的第二个收益=头部探顶不带出血条);意图徽标悬浮头顶上方(探顶档压胸);④ 「血条悬浮头顶+立绘盒内居中」排式已弃——盒顶固定 y 与盒内居中在高盒下拉开血条-立绘空洞。验收:目检〈血条一线对齐、大体档溢出不压轮次指示〉
- **站桩立绘排版**:① 区高 B 区 270(≈1/3)/C 区 530(≈2/3),**扫雷盘 438×438 原尺寸不缩、格子不变**(区高事实源 battle.md 区表;压缩由 C 区面板空档吸收);② 站桩内部重排——立绘双脚落石台上缘(弃盒内居中)、**血条+状态/名字行落底排**(立绘→血条→状态 顺序,全场血条对齐一线;血条嵌石板位、台缘线留作地面线、落影保留接地感),状态空时该行退化为名字行;③ 大体档(显示 >150px 级:drider/duergar_king)**允许向上溢出盒顶 N px**(N 由实装批按实测尺寸算定,**与背景/光柱无关**——现行溢出区恰为临时光柱氛围层〔§6.1 方向稿四柱,x 基准 110/900/1055/1210@1280,`battle_stage_view.gd:55-63`〕,正式舞台背景插画 `scene_stage_bg.png` 到位后该层由背景绘制吸收,**溢出判定不随之变更**;横向禁止压到顶部中央轮次·阶段指示,溢出上限由实装批用真图复算 x 区间定),血条仍落底(落底排的第二个收益=头部探顶不带出血条);意图徽标悬浮头顶上方(探顶档压胸);④ 「血条悬浮头顶+立绘盒内居中」排式已弃——盒顶固定 y 与盒内居中在高盒下拉开血条-立绘空洞。验收:目检〈血条一线对齐、大体档溢出不压轮次指示〉
- **站桩石板地台件**:`scene_stage_plaza.png`,源 48×12、九宫格横向拉伸、顶缘受光线 2px 不随拉伸变形;跨三关恒定、不吃 §4.3 `wall_ambient` tint(独立理由见 §6.1 近景地台独立件条)。验收:机检〈地台件按九宫格拉伸后顶缘受光线宽度恒为 2px〉
### 8.3 导出格式与命名规范
@@ -515,7 +530,7 @@
### 8.4 帧数规格(样张冻结)
- **帧数规格(样张冻结)**:待机循环 4 帧;攻击/技能准备 6 帧单次;受击 2 帧;死亡 = 灰化+碎裂退场(§4.6.4 语义硬规则),序列帧归 ✦ 缺料清单;帧时长与结算节拍对齐(预告时序见 §4.6.4)。验收:机检〈序列帧数与档位一致〉
- **方向集**:棋盘小人=**4 向**(下/上/侧,侧向左右镜像共用一份画稿);斜向移动/挖掘按**主导轴吸附最近正交向**呈现,不出 45° 斜向帧(斜向信息由位移轨迹与目标格预告承载,ITB 实态同款)。镜像与「旗面恒画右」纪律(character-design.md 冒险背包条)的相容归属:棋盘小人默认镜像豁免、旗右纪律限立绘侧——代拟规则,样张确认。验收:目检〈四向帧齐、侧向镜像无破绽〉
- **方向集**:棋盘小人=**4 向**(下/上/侧,侧向左右镜像共用一份画稿);斜向移动/挖掘按**主导轴吸附最近正交向**呈现,不出 45° 斜向帧(斜向信息由位移轨迹与目标格预告承载,ITB 实态同款)。镜像与「旗面恒画右」纪律(character-design.md 冒险背包条)的相容归属:棋盘小人默认镜像豁免、旗右纪律限立绘侧——代拟口径已追认(棋盘小人朝左时旗面朝左,与立绘侧「旗面恒画右」并存;画稿维持一份 + 镜像,零新增资产)。验收:目检〈四向帧齐、侧向镜像无破绽〉
### 8.5 结构件完整性与参考核验
+257 -4
View File
@@ -1,8 +1,8 @@
# 生图提示词卡(角色级资产)v2.9
# 生图提示词卡(角色级资产)v2.11
> **性质**:美术清单生图通道(✦ 用户自跑,现走线上 API)的执行侧文件——每资产一段**自包含完整提示词**:正向 = 通用底座+主体+动作已拼妥、负向 = 通用底座+增补已并妥,整段复制直接贴进工作流即可,**不需要读其他文件、不需要拼装**。人物规格转写自 [character-design.md](character-design.md)(人物设计 v1.0,自 art-bible §5 迁出,圣经 §5 为存根),风格/色彩条款转写自 [art-bible](art-bible.md)(§4.1 主色板 / §4.2 语义色规则);冲突时人物规格以 character-design 为准、色彩以 art-bible 为准。
> **边界**:本文件只管**角色级**资产的生图通道。图标/格面/样张走脚本管线(⚙ 代理出),规格在 art-bible §4.6 与 [art-assets-checklist](art-assets-checklist.md),不需要提示词。**场景级资产(营地场景图的背景层与八个物件层)另立 [camp-scene-prompts](camp-scene-prompts.md),本文件不覆盖**;两卡的角色/场景分工以「谁的资产谁出卡」为界,同一段提示词不两处维护。意图动画三档是动画资产,等一屏样张锁方案后另立规格卡,本文件不覆盖。
> **状态**:提示词卡成文,出图未开始;按「美术圣经 §5 现行」重生成(正序:B 路线),继承 seed 纪律 / 色相禁入带 / `#F2F2F2` 生成底色;沿革见 git 提交史。
> **边界**:本文件只管**角色级**资产的生图通道。图标/格面/样张走脚本管线(⚙ 代理出),规格在 art-bible §4.6 与 [art-assets-checklist](art-assets-checklist.md),不需要提示词。**场景级资产(营地场景图的背景层与八个物件层)另立 [camp-scene-prompts](camp-scene-prompts.md),本文件不覆盖**;两卡的角色/场景分工以「谁的资产谁出卡」为界,同一段提示词不两处维护。战斗舞台的场景级两件与护甲类型图标三枚的**出图工单**登记在本文件 §5(camp-scene-prompts 只管营地场景图,战斗屏这两类无处可落);§5 只把各权威节的定值收进逐件工单,不立新值。意图动画三档是动画资产,等一屏样张锁方案后另立规格卡,本文件不覆盖。
> **状态**:提示词卡成文,出图未开始;按「美术圣经 §5 现行」重生成(正序:B 路线),继承 seed 纪律 / 色相禁入带 / `#F2F2F2` 生成底色;沿革见 git 提交史。
---
@@ -284,7 +284,260 @@ Seamless tileable pixel art texture of dry dirt ground, top-down, for a dungeon
后处理(程序侧,生成器脚本归档 zip 内〔archive 备选案-terrain-walls〕):周期对齐无缝裁剪→BOX 降采样 32×32→环绕混合→量化(12 色)→结构件合成;②③亦可由①程序加纹理级裂纹/浅斑替代(实证更稳)。
## 5. 明确不在本文件
## 5. 资产出图工单(四组九件)
> **范围注**:本文件原定位角色级(见文件头边界句),§4bis 已有「地形类同库登记」的先例,本节循同一先例补登记战斗屏两类——战斗舞台的场景级两件(① ②)与护甲类型图标三枚(③),两组在营地卡与清单里都无处落工单;角色级立绘重产(④)是本文件的本职。四组的规格定值清单 §4 已有登记,本节补的是「逐件照着就能出件」那一层。
> **定值纪律(§8 头注 定值单点纪律)**:本节**指路不立值**——色值 = 圣经 §4.1(含场景环境子板)、尺寸与缩放 = §8.2、明度带 = §2、甲档 = character-design §5.3、命名 = §8.3 + asset-path-map。本节新增零定值;凡圣经未定的值,一律进本节 §5.5 缺口,不在本节填空。
> **验收标注纪律**:逐条按三档标 `←机检: <断言>` / `←目检: <判据>` / `←方向性`,照圣经头注 2026-10-06 用户拍板的写法。
> **流程**:出图前后一律走 §0 五步;出图登记义务照 remote-gen-prompts 头注轻量口径(用途+生成时间必注,其余参数有则记),随候选图存 `artwork/candidates/<资产名>/`;登记不作正稿遴选前置。
> **产出状态**:组二地台件与组三护甲三枚已按各节 ⑤「程序化产出即终稿」产出入包(`scene_stage_plaza.png` 48×12、`ui_armor_light/ward/heavy.png` 24×24,路径见各组 ① 字段;登记=战斗一屏样张批,合并提交 3b66d1a6);组一背景插画与组四立绘重产仍待出图。
### 5.1 组一 · B 区舞台背景插画(1 件)
| 字段 | 值 |
|---|---|
| ① 路径与命名 | `game/assets/art/scene/scene_stage_bg.png`——域键 `scene`(asset-path-map §3),命名照 §8.3 `<域>_<对象键>_<状态\|变体>[_<序号>].png`。**三关不按板出三张,文件名不带 `_dungeon`/`_underdark`/`_deep_underdark` 后缀**(三关换挡走 §4.3 `wall_ambient` tint 槽,与棋盘同款换皮逻辑) |
| ② 尺寸档与像素网格 | 源 1280×270(B 区全高含明细带底),显示 1×;九宫格 = 否。甲/乙两分类不覆盖环境件(§8.2 甲类 = 文本与语义件、乙类 = 角色与单位精灵),本件在 1280×800 基座下满幅铺 1×、不缩放;1920 档口径见 §8.2「1920×1080 档策略」条,本节不另立值 |
| ③ 色板约束 | 进**战斗屏场景环境子板**(§4.1 分层②:每屏一套 ≤32 色、跨屏不共享、**不占 48 token 额度**——48 额度余量现为 0(2026-10-28 用尽),本件不动它)。**零新增**——主体三色:远景最深 `#282220`(默认;备选 `#3A2E22`,二选一,选后者则图内禁用 `#362B20`,两者三通道差 4/3/2 全部 <8,是 §4.1 欠账清单六对之一);中景洞壁 `#3E362C` 与中景受光壁面 `#453723` 交替,**两色只靠笔触与纹理分出块面,不靠第三个色**;需过渡色时只从在册的 `#362B20`/`#4C4038` 取。单张 PNG 像素域色数 ≤32。第二道门 = 与既有任一色三通道差不得全部 <8/255(§4.1 增量纪律),不过门即换色合并、禁加色绕行 |
| ④ 明度带归属 | **世界底层下沿子带 L 0.014–0.06**(§2 世界底层两子带)——全图落该子带,不得越进上沿子带 L 0.08–0.14(那是已开格底与迷雾记忆态合成底的地盘)。三色实测: `#282220` L≈0.016 / `#3E362C` L≈0.039 / `#453723` L≈0.042 |
| ⑤ 是否程序化件 | 否 → **须出图**(✦ 插画级,清单 §4 已定来源 = 作者自跑远程生图管线)。现行程序化平色 + 光柱 = 占位(◐),按 §7.1 占位完成条款须在终稿闸前换代 |
| ⑥ 验收判据 | 见下方逐条判据 |
| ⑦ 出图操作要点 | 见下方提示词与负面约束 |
**逐条判据**
- 构图只出远景 + 中景两带:远景 0–35%、中景 35–78%,78%–100% 段不画 ←机检: 画布 1280×270 逐位相符;`y ≥ 210`(78%) 段内 `#968264` 像素数 = 0 且该段与中景段无独立地台结构件
- 三关只走 tint 槽 ←机检: 仓内 `scene_stage_bg*` 文件名无 board_type 后缀变体(三关方向指路 §6.3,该节终值未冻结,属实装批,不阻塞本件出图)
- 色板零新增 ←机检: 单张像素域色数 ≤32 且逐色在 §4.1 战斗屏场景环境子板在册
- 明度带 ←机检: 全图取样点相对亮度 L 全部落 [0.014, 0.060]
- 禁入带 ←机检: 全图无 HSV 色相 300°–345° 像素(清单 §0 复用闸②吸色检查同口径)
- 临时光柱层退役 ←机检: 本件入包后 `battle_stage_view.gd` 四柱临时光柱层退役(§8.2 站桩排版③条;该条的立绘溢出判定不随之变更)
- 背景自然后退 ←目检: 立绘与 C 区数字在前,本件不构成完整凸形、无第二焦点(§3.4 焦点预算 / §6.1 低对比后退)
- 气质 ←方向性: 明亮地窟、暖倾向、无压抑(§1 风格基调;§9.2 Darkest Dungeon 式压暗在反面清单)
**出图画布**:2560×540(终稿 2×,保证整数倍降采样;平台不支持该宽高比时取可用的最宽档出图、按上下居中裁到 4.74:1,禁横向拉伸变形)。
**正向提示词(整段可贴)**:
```
Pixel art style. True pixel art game background illustration drawn with chunky square pixels, strict pixel grid alignment, hard edges, no anti-aliasing, no gradients, flat colors only, a limited palette of about eight colors, retro 16-bit look, Aseprite style, all ages, bright cheerful fantasy cavern, not dark and not grim, flat side view, orthographic, no perspective distortion, very wide horizontal band about 4.7 to 1 aspect ratio. This is the BACK WALL of a bright underground cavern arena seen straight on, and it is a BACKGROUND ONLY: it must contain no characters, no creatures, no floor platform and no props, because the standing stone platform and the characters are drawn on top of it as separate pieces. TWO BANDS ONLY, and the bottom twenty-two percent of the frame stays completely empty. FAR BAND (the top zero to thirty-five percent of the frame height): the deepest hollow of the cavern, a flat dark far wall receding into shadow, one or two rows of very simple flat stalactite silhouettes hanging from the top edge, the darkest area of the picture, its darkest value is hex color #282220, no light sources, no small detail, everything reduced to a few large flat shapes. MIDDLE BAND (thirty-five to seventy-eight percent of the frame height): the cavern wall, broad flat facets of stone alternating between hex colors #3E362C and #453723, the facets separated only by their brush texture and by a few slightly darker seam lines, with two or three soft vertical light shafts falling from the cave roof across the wall, the shafts being flat low-contrast bands of light and not beams of particles. WHOLE IMAGE: every color is very dark and low in contrast, the entire background recedes behind the characters, there are no bright highlights and no rim lights, no single element forms a complete solid shape that competes for attention, and all wall facets stay large and simple.
```
**负向提示词(整段可贴)**:
```
Do not add any of the following: realistic, photorealistic or 3D rendering; painterly brushwork, smooth anti-aliased lines, gradient or dithered shading, glossy highlights; blur or compression artifacts; a vignette, dark corners, or any mood darkening; any purple or magenta anywhere, any color with a hue between 300 and 345 degrees; any text, letters, numbers, watermark, signature or logo; any frame, border, panel, arrow or UI element; any characters, people, creatures or animals; any floor, ground plane, stone platform, pedestal, stage floor or baseboard in the lower part of the frame, because the bottom twenty-two percent of the frame must stay completely empty; any torch, brazier, lantern, candle or glowing object as an object, only the flat light shafts described above; bright or saturated colors, any area lighter than hex #453723; high contrast edges, rim lights, black outlines; rubble, chains, bones, murals, paintings, furniture or any extra prop.
```
**后处理**:§0 五步第 4 步——本件是**不透明全幅件**,去底与四联底测试条两步不适用,只走最近邻降采样到 1280×270 + 色板量化到本节 ③ 所列色;终稿入包后走 §1.4 整屏样张闸。
### 5.2 组二 · 近景地台件(1 件)
| 字段 | 值 |
|---|---|
| ① 路径与命名 | `game/assets/art/scene/scene_stage_plaza.png`——域键 `scene`(asset-path-map §3),命名照 §8.3。**跨三关恒定,文件名不带 board_type 后缀** |
| ② 尺寸档与像素网格 | 源 48×12;**九宫格横向拉伸**,顶缘受光线 2px 不随拉伸变形(§8.2 / §6.1 定值);高度维持源档 12px、横向拉至站桩宽。九宫格件不在甲/乙两分类内(§8.2 甲类 = 文本与语义件、乙类 = 角色与单位精灵),本件高度恒为整数像素、横向拉伸区只取纯色 |
| ③ 色板约束 | 进**战斗屏场景环境子板**(§4.1 分层②,不占 48 额度,余量 0 不动)。**零新增**——板身 `#968264`(STAND_STONE,§4.1 已转正进本子板)/ 顶缘受光线 `#C9AF83`(掩尘;2026-10-28 合并登记把地台顶缘受光线并进掩尘,并与 §8.2 高墙口沿高光 `Color8(196,172,132)` 统一为同一枚)/ 描边 `#4C4038`(2026-10-28 合并登记把地台描边并入此值)。单张像素域色数 ≤32。第二道门同本节 5.1 |
| ④ 明度带归属 | **世界中层 L 0.22–0.45**(§2)——判定对象 = 板身 `#968264`(实测 L≈0.234)与顶缘受光线 `#C9AF83`(实测 L≈0.449,材质受光属 §2 形体塑造允许域)。§6.1 把地台定死为世界中层承载面,就是本件的立法理由。描边 `#4C4038` 是结构墨线(§3.2 高墙墨线同族,职责 = 分隔),不按明度带判定 |
| ⑤ 是否程序化件 | 是 → **程序化直出即终稿,不须出图**。本件只有三块纯色 + 一条 2px 缘线,无材质纹理需求,按 §8.5「材质归模型、结构归程序」落脚本绘制即成立;它不属 §7.1 占位态 |
| ⑥ 验收判据 | 见下方逐条判据 |
| ⑦ 出图操作要点 | 见下方工艺要点(手绘/程序化,无须 AI 生图) |
**独立成件的两条理由(§6.1「近景地台走独立件」条,写进工单备查)**:① 结算期明细带底 84px 会盖住 B 区 78%–100% 段(约 59px),84 > 59,近景带在结算期整条不可见——画进背景等于画一件永远看不见的东西;② §4.3 `wall_ambient` tint 作用于整张背景,地台若画进背景会随三关换明度,而 §6.1 舞台正面目标把地台定死为世界中层承载面,随关卡变会破 §2 明度分层的层间关系。
**逐条判据**
- ←机检: 九宫格横向拉伸后顶缘受光线宽度恒为 2px(§6.1 / §8.2 既有定值断言,本节不另立值)
- ←机检: 单张像素域色数 ≤32,且三个色值逐位等于 `#968264` / `#C9AF83` / `#4C4038`
- ←机检: 地台绘制点取常量、不进 §4.3 `wall_ambient` tint 槽(跨三关恒定)
- ←机检: 板身色相对亮度 L 落 [0.22, 0.45]
- ←目检: 横向拉到站桩全宽后端头与板身无纹理接缝、无错位;横向拉伸区零纹理
- ←方向性: 落影接地感成立(立绘双脚落石台上缘,§8.2 站桩排版条)
**工艺要点(⚙ 脚本绘制)**
1. 源 48×12 的十二行 = 1px 上描边 `#4C4038` + 2px 顶缘受光线 `#C9AF83` + 8px 板身 `#968264` + 1px 下描边 `#4C4038`;左右各 1px 描边,全周闭合。
2. 九宫格切片:顶缘 2px 受光线**整行落进上切片**(九宫格的上下边只横向缩放、纵向不缩放),左右切片取端头纯板身段——端头与板身同为纯色,切片取值无视觉后果,取多少都行;**顶缘线绝不能落进可纵向缩放的中间段**,否则拉伸后厚度会变。
3. 本件不参与 §6.1 的三关 tint:入包后绘制点直取 ③ 的三色常量。
### 5.3 组三 · 护甲类型图标三枚(3 件)
**三件共用字段**
| 字段 | 值 |
|---|---|
| ① 路径与命名 | `game/assets/ui/icons/ui_armor_light.png` / `ui_armor_ward.png` / `ui_armor_heavy.png`——域键 `ui`,落 `game/assets/ui/icons/`(与现役九枚状态图标同目录,asset-path-map §1);命名照 §8.3,对象键 = `armor`、变体 = 甲档键,与清单 §3.7 逐字一致 |
| ② 尺寸档与像素网格 | 源 24×24,显示 24px = 1×;九宫格 = 否;**甲类**(§8.2 甲类 = 文本与语义件,图标在列)→ 维持严格整数倍缩放硬规则,禁非整数缩放 |
| ③ 色板约束 | 进**语义/UI token 板**(§4.1 分层①),**占 48 额度——余量 0**(2026-10-28 用户裁:本组新增重甲冷灰 1 枚 + 5.4 组四新增卓尔浅紫灰皮 1 枚,全板余量 2 → 0,额度已用尽)。逐件取在册色(**素底明暗档已裁深档 `#282220`**,见 §5.5 缺口 2 已裁条):轻甲 = `WARM_FAINT #CDB88C`(深档下 8.08:1;原木色 `#8A5A34` 深档仅 2.72:1 不过门,按合并裁定改值、零额度)/ 魔法护甲 = 暖白 `#F0E2C8`(12.26:1,深档下本值不动)/ 重甲 = `#868C9A`(新入板,占 1 枚额度,深档下 4.65:1)。单张像素域色数 ≤32。第二道门同本节 5.1 |
| ④ 明度带归属 | **信息面层**(§2:信息面层 = 数字 / UI 数据 / 预告 / 语义标识)——图标是语义标识,与站桩名字行同排挂载。**信息面层 L 区间维持定性、不新增区间**(§5.5 缺口 3 核实结论:执法已被 §7.2 文字 ≥4.5:1 与 §4.1 图形 ≥3:1 两条相对判据覆盖,层间序关系由 §1.4 整屏②项断言,不需要绝对区间),本节落地判据走 §4.1 图形对比 ≥3:1 |
| ⑤ 是否程序化件 | 是 → **程序化产出即终稿**。来源照清单 §3.7:♻ 素材站通用护甲/符纹图标改色优先、⚙ 兜底程序化;♻ 件须过清单 §0 复用闸四道才入包 |
| ⑥ 验收判据 | 见下方共用验收 + 逐件验收 |
| ⑦ 出图操作要点 | 见逐件的来源与工艺要点 |
**共用验收(三件都要过)**
- ←机检: 源 24×24、显示 1× 整数倍(§8.2 显示档登记例外条:素材一字节禁改)
- ←机检: 文件名逐位等于 `ui_armor_light` / `ui_armor_ward` / `ui_armor_heavy`
- ←机检: 单张像素域色数 ≤32
- ←机检: 三枚对其实际挂载底色的图形对比 ≥3:1(§4.1 图标槽柔和档条的图形参考线硬约束)。**挂载底色 = 站桩名字行的素底,不是舞台底也不是地台面**——站桩名字行是文字,§7.2「一切文字(含菜单/说明/tooltip/按钮/底栏,**无区域例外**)」+「文字禁直接压纹理底——垫容器或罩层」两条覆盖它;§6.1 舞台正面目标条(2026-10-28 v3.22 定值)已就站桩文字位显式落法:「站桩文字位改垫素底或落进结算明细带」,并明写「**非新条款**」,§7.2 同批加「站桩石板地台面同理」句、两处机检断言同文。舞台背景插画 `scene_stage_bg.png` 的中景两色只靠笔触与纹理分块面(5.1 ③),属纹理底,落法门触发。**故「站桩名字行落法 = 垫素底」是既有条款的落法,本节不立新条款**(§5 头注定值纪律:本节指路不立值)。素底明暗档 **2026-10-28 已裁 = 深档 `#282220`**(§7.4 血数垫牌 `HP_BAR_BACK` 在册同款,零新增;浅档 `#F5EAD3` 落选,两档对照与理据见 §5.5 缺口 2 已裁条)
- ←机检: B 区站桩名字行与护甲图标正下方像素非地台板身色 `#968264`(§6.1 / §7.2 同文断言)
- ←目检: 灰度下按甲面覆盖率三档可辨——无甲板 → 符纹带 → 大面积甲板(character-design §5.3 灰度通道条)
- ←目检: 三枚互辨,身份只靠形状不靠色相(§4.5 ⑨ 图标键族:色相不承载身份)
- ←方向性: 甲档不触 §5.1 剪影 archetype——不加肩甲外扩之类的轮廓改动,体量与凹凸计数仍由 archetype 独占承载
**5.3.1 轻甲 `ui_armor_light`(轻甲档)**
- 形状:甲面覆盖率 ≈ 0——一枚**皮条 / 布带**记号(斜跨的皮带扣或系带),主体留空,零甲板(character-design §5.3)
- 色:**`WARM_FAINT #CDB88C`**(2026-10-28 用户裁:素底取深档后原皮革木色 `#8A5A34`〔§7.2 木色〕仅 2.72:1 不过门,按 §4.1「不过门即换色合并、禁加色绕行」并入本值——**零额度**;代价 = 暖白族非木色族,已随裁定接受)
- **对比判据**(挂载底色 = 站桩名字行素底,2026-10-28 裁深档 `#282220`):**8.08:1 ✓**(≥3:1 图形门槛);对舞台底 `#3E362C` 6.12:1。木色族路线(新增木色亮档 `#C49A5E` 6.07:1)未取——须 +1 额度而余量已为 0
- ←机检: 本枚对其实际挂载深素底 ≥3:1(实测 8.08:1);入板后全板色对中三通道差全部 <8/255 的对数 = 0
- ←目检: 换色后本枚仍读作皮革/皮条,不与 5.3.2 符纹带、5.3.3 甲板在灰度下混读(character-design §5.3 灰度通道:三档按甲面覆盖率可辨)
- 来源与工艺:♻ 素材站 belt / strap 类图标改色,过清单 §0 复用闸四道(色板量化 / 禁入带吸色 / 灰度可辨 / 授权干净);⚙ 兜底按 24×24 网格手修——3px 带宽、1px 深墨描边,不画甲板
**5.3.2 魔法护甲 `ui_armor_ward`(魔法护甲档)**
- 形状:**符纹饰带**——一条走轮廓的发光符纹带,覆盖率居中,零金属甲板(character-design §5.3)
- 色:暖白 `#F0E2C8`(与轮廓描边同族,不占任何语义色,§5.3)
- 来源与工艺:♻ 素材站 rune / glyph band 类图标改色 → 闸四道;⚙ 兜底 24×24 内一条横向符纹带 + 两枚符点,符点不超 3×3
**5.3.3 重甲 `ui_armor_heavy`(重甲档)**
- 形状:**金属甲板**覆盖肩与胸,覆盖率三档中最大(character-design §5.3)
- 色:冷灰金属材质色 = **`#868C9A`**(2026-10-28 用户裁转定稿,见 §5.5 缺口 1 已裁条;新入 §4.1 分层①,占 1 枚额度)。**与 5.4.4 石君王岩石板甲是同一枚**——character-design §5.3 通道 = 甲面覆盖率 × 甲材质色,甲材质色按甲档统一,故石君王工单**直接引本枚 `#868C9A`、不另计额度**
- **对比判据**(挂载底色 = 站桩名字行素底,2026-10-28 裁深档 `#282220`):须同时满足 §5.4 ④ 立绘体块主色带 L 0.22–0.45 与本节 ≥3:1 —— 深档窗 = **[0.220, 0.450]**;本值 L≈0.261 落窗,**对深素底 4.65:1 ✓、对舞台底 3.52:1 ✓**
- ←机检: 本枚对其实际挂载深素底 ≥3:1(实测 4.65:1)且相对亮度 L 落 [0.220, 0.450](实测 0.261);入板后全板色对中三通道差全部 <8/255 的对数 = 0
- ←目检: 灰度下本枚甲板覆盖率三档最大,与 5.3.1 无甲板、5.3.2 符纹带可辨(character-design §5.3 灰度通道)
- ←方向性: 冷灰与全作暖底成材质对比(§5.3),不靠明度差与地台 `#968264`(L≈0.234)抢读——立绘与地台的可辨归 §5.1 轮廓通道
- 来源与工艺:♻ 素材站 plate armor 肩甲/胸甲类图标改色 → 闸四道;⚙ 兜底 24×24 内肩 + 胸两块甲板,与全作暖底成材质对比(§5.3 冷灰金属与暖底对比)
### 5.4 组四 · 主角与三 Boss 立绘重产(4 件)
**四件共用字段**
| 字段 | 值 |
|---|---|
| ① 路径与命名 | `game/assets/art/character/character_hero_portrait.png` + `game/assets/art/character/character_enemy_<enemy_id>.png`(域键 `character`,对象键 = `hero` / enemy_id,命名照 §8.3 与 asset-path-map §3 现役写法) |
| ② 尺寸档与像素网格 | **源档高逐键** = 主角 48 / ogre_chief 74 / drider 90 / duergar_king 94(§8.2 立绘源档表,逐件值见本节 5.4.1–5.4.4);**宽随源图宽高比,纵横倍率恒等**(§8.2 站桩立绘槽位 = 高定宽随条,禁把立绘塞进统一方框强拉);九宫格 = 否;显示一律 **×2 整数档** = 96 / 148 / 180 / 188;**乙类**(角色与单位精灵)——乙类允许非整数,本批按 §8.2 定案走 ×2 整数档 |
| ③ 色板约束 | 进**语义/UI token 板**(§4.1 分层①);**48 余量 0**(2026-10-28 用户裁:本组新增卓尔浅紫灰皮 1 枚,全板余量 2 → 0,额度已用尽)。逐件沿用 character-design §5.4 / §5.5 已登记色值;该两节只给形容词未给色值的部件,**2026-10-28 用户裁已落值**——四处换色合并(零额度)+ 卓尔浅紫灰皮新增 1 枚,逐件取值见本节 5.4.1–5.4.4,额度账见 §5.5 缺口 4。**石君王岩石板甲 = 重甲甲材质色、与 §5.3.3 同一枚,工单直接引 `#868C9A`、不另计额度**。单张像素域色数 ≤32。第二道门同本节 5.1 |
| ④ 明度带归属 | **世界中层 L 0.22–0.45**(§2 世界中层 = 格底顶面 / 角色 / 物件)——判定对象 = 角色体块主色。描边与落影底盘属轮廓通道(character-design §5.1)、紫赤点缀属 §4.2 色相独占的语义色,两者都不按明度带判定 |
| ⑤ 是否程序化件 | 否 → **须手绘**。口径 = **精细手绘像素**(2026-10-14 用户裁:仍是像素风,手绘像素簇 + 更高源密度;不是插画、不是 HD-2D、不回退高清图);**禁 AI 降采样当终稿**。现行 AI 降采样立绘 = 占位态,按 §7.1 占位完成条款须在终稿闸前换代 |
| ⑥ 验收判据 | 见下方共用验收 |
| ⑦ 出图操作要点 | 见下方工艺要点(手绘,不产生图提示词) |
**共用验收(四件都要过)**
- ←机检: 源档高逐位等于 48 / 74 / 90 / 94,显示 = 源 ×2(96 / 148 / 180 / 188),过滤 = NEAREST
- ←机检: 单张像素域色数 ≤32
- ←机检: 脚底基线对齐(派生管线四条:等比整数缩放 + 降色 ≤32 + 脚底基线对齐 + 命名合规)
- ←机检: 主角描边 = `(40,19,13)`;敌方描边取暖白族(非黑、非深褐)—— character-design §5.1 主角描边例外条
- ←机检: Alpha 直出——不透明区外缘 1px 环内无生成底残留(无 R/G/B 三通道均 ≥230 且 alpha > 0 的像素),防抠图白边
- ←机检: 零 HSV 300°–345° 像素(drider / duergar_king 两 Boss 除外,§4.2 独占)
- ←机检: 落影底盘在位(character-design §5.1 轮廓通道)
- ←目检: 放大 4 倍,轮廓与衣服是成组的像素,不是降采样噪点(三判据①)
- ←目检: 显示 96–188px 下脸、铲、旗、物种能认出来,不必先读名字(三判据②)
- ←目检: 显示仍用邻近采样,不出现插画那种平滑渐变(三判据③)
- ←方向性: 精细手绘像素气质——不是插画、也不是半像素半高清
三判据出处 = `reports/美术审计-cursor会话存档-2026-10-14.md` §2.2。
**工艺要点(手绘)**
1. 出件顺序 = 先主角、再三 Boss(Alpha 范围 = 主角 + 三 Boss 重产,其余敌种当前可读则保留到 Beta)。
2. **源密度判据 = 三判据②**:显示 96–188px 下脸、铲、旗、物种可认——照这条反推源档即可,逐键定档已完成(§8.2),本批不必再猜档位。
3. 手绘起稿顺序 = 剪影(§5.1 archetype)→ 体块主色 → 暗部与受光 → 描边 → 落影底盘。
4. 逐件 2–3 版候选;登记照 remote-gen-prompts 头注轻量口径(用途+生成时间必注,手绘作者有则记),随候选图存 `artwork/candidates/<资产名>/`。
5. 候选评审 = 并排横评,**隐去文件名与来源后按三判据逐条判读**(§0 五步第 1 步「便于横评」的手绘侧落法),不靠记忆与印象拍板。
6. 出件 = 透明 PNG(Alpha 直出,禁先出白底图再抠);入包前过 §8.3 色板检查器(报新增色 / 近色告警 / 超 48 上限拦截)。
**5.4.1 主角(源 48 / 显示 96)**
- 形象 = character-design §5.4 形象锚逐字执行:蓝兜帽取下披肩、暖米白上衣、深棕工装裤、额前护目镜、半指手套、卷裤脚皮护膝、圆头挖掘铲、结构式冒险背包配朱红矩形旗、腰挂提灯
- 已登记色:兜帽 `#2E86DE` / 上衣 `#EFE3C8` / 长裤 `#6B4A2E` / 皮革 `#8A5A34` / 眼 `#33261B` / 旗 `#C63D22` / 描边 `(40,19,13)`
- 已落值(2026-10-28 用户裁):**铲刃浅铁灰 = `FOG_MEMORY_INK #C4C4C4`**;**提灯铜色 = `GOLD_DEEP #B07A14`**——两件均走换色合并、零额度(character-design §5.4 对这两件只有形容词,账见 §5.5 缺口 4)。代价已随裁定接受:`#C4C4C4` 一色两岗(语义岗 = 迷雾记忆墨 §6.5)、`#B07A14` 属金族(§4.2 金只说收益与兑现);两者均为角色随身件材质色,不进信息层与语义物件岗
- 破例记账:背包 + 旗 = 主角对 §5.1「对称」的唯一破例组,旗面朝向恒定画右;轮廓凹凸预算按背包 + 旗整组记账
- 朝向:战斗画面的侧身面向怪物形象属状态图(§5.4 生成顺序口径);重产沿用现役朝向,不重新裁定
**5.4.2 食人魔酋长 ogre_chief(源 74 / 显示 148)**
- 档位 = 精英档(形状仍守精英档:普通怪形 + 恰一处垂直延伸 = 头顶骨与羽冠,底盘不变;第一关关底 Boss 战,不升 Boss 形)
- 甲档 = 轻甲 → 甲面覆盖率 ≈ 0:皮条 / 骨饰点缀、裸身为主,零甲板零符纹
- 主色域 = 暖褐皮、圆肚;**暖褐皮 = `暖石 #B8A582`**(2026-10-28 用户裁:换色合并、零额度;体块主色带 §5.4 ④ L 0.22–0.45 校验 L≈0.387 ✓;character-design §5.5 该行原只有形容词)
**5.4.3 蛛化卓尔精灵 drider(源 90 / 显示 180)**
- 档位 = Boss(敌类中唯一允许锐角与不对称者,体量最大)
- 甲档 = 魔法护甲 → 符纹饰带(暖白,覆盖率居中);蛛腹几丁质属天然甲壳,不计甲档
- 独占:紫赤 `#8F2F6A`(色相 323°)+ 形状独占双通道;全项目色相 300°–345° 只许本件与 5.4.4 出现
- **卓尔上体浅紫灰皮 = `#A79CB8`**(2026-10-28 用户裁:**新增 1 枚**,入 §4.1 分层①——在册紫族四枚全部语义岗占用且 L <0.22,无一可复用)。体块主色带 L 0.22–0.45 校验 L≈0.355 ✓;色相 264° 避 300°–345° 禁入带,紫赤独占仍归 `#8F2F6A`。**对比实测(本节新算,此前未给值)**:对深素底 `#282220` **6.04:1**、对舞台底 `#3E362C` **4.57:1**——两处均过 §4.1 图形 ≥3:1 门槛
- 大体档:显示 180 > 150 → 允许向上溢出盒顶(§8.2 站桩排版③ 甲案;溢出量 N 由实装批用真图复算 x 区间定,血条仍落底)
**5.4.4 灰矮人石君王 duergar_king(源 94 / 显示 188)**
- 档位 = Boss(锐角与不对称,体量最大档)
- 甲档 = 重甲 → 金属甲板(冷灰,覆盖率最大)
- 独占:紫赤 `#8F2F6A` + 形状独占双通道;大地 / 岩石主题
- 岩石板甲与灰皮(2026-10-28 用户裁,character-design §5.5 该行原只有形容词):**岩石板甲 = 重甲甲材质色,与 §5.3.3 同一枚 → 直接引 `#868C9A`,不另计额度**;**灰皮 = `STONE #786E62`**(按**次级皮**口径——石君王重甲覆盖率最大、板甲视同体块主色,故灰皮属次级皮、不受 L 0.22–0.45 约束;换色合并、零额度)
- 大体档:显示 188 > 150 → 溢出盒顶同 5.4.3
### 5.5 缺口(四条 · 缺口 1/2/4 于 2026-10-28 已裁转指路,缺口 3 结论已立)
> **核销口径(依 art-bible v3.22 现行条款)**:四条逐条先过「§4.1 在册既有色能否换色合并」——不过门即换色合并、禁加色绕行(§4.1 色板增量纪律)。**48 色余量:裁定前 2 → 2026-10-28 裁定后 0(额度已用尽)**;本节给的是「哪几枚必须新增 / 哪几枚可合并 / 合并后余量 / 全新增要压缩哪几枚」的账,**不替作者拍板**(§4.1:额度不足时呈报作者,由作者决定压缩或合并既有色)。本节所举候选色值,**缺口 1 / 2 / 4 已随 2026-10-28 用户裁落定(见各条「已裁」注,本节只留裁定依据账并指路 §5.3 / §5.4)**;其余仍为候选,落定须过 §4.1 两道门(①§4.2 语义检查;②与既有任一色 RGB 三通道差不得全部 <8/255——宽松口径)。
1. **重甲冷灰金属材质色——已裁(2026-10-28)= `#868C9A`**,本节转指路(原「阻塞 5.3.3 上色」状态解除——出形与上色均不再阻塞;**与 5.4.4 石君王岩石板甲同一枚**——character-design §5.3 通道 = 甲面覆盖率 × 甲材质色,甲材质色按甲档统一,两处只占一枚额度)。character-design §5.3 只写「冷灰金属材质色」;**落法见 §5.3.3(本组载值)与 §5.4.4(直接引 §5.3.3 同一枚、不另计额度),色值账见 art-bible §4.1 本枚条目**。
- **换色合并逐枚核查——在册冷/中性灰全部不合格,无复用者**:`#3E4048` L≈0.052 / `#3F4147` L≈0.053(两者正在 §4.1 六对欠账清单内,清偿后只留一枚)/ `#3A3A3A` L≈0.042——三枚均越世界中层下沿 0.22;`#C4C4C4` L≈0.552 越上沿 0.45,且语义岗 = 迷雾记忆墨(§6.5);`#8A9AB0` L≈0.317 本落在带内,但色相 ≈215° 属蓝族,§5.4 语义约束 + §5.5「蓝族禁入敌方主色」拦;`#5A6C8C` 暮蓝为失败独占(§4.2);`#808080` L≈0.216 越下沿 0.004,且是引擎默认灰(§7.6 点名须接管,不宜作角色材质色)。
- **归属板**:进 §4.1 **分层① 语义/UI token 板,占 48 额度**。理由:甲材质色 = 材质色、跨屏恒定,不属分层② 环境色(环境色随场景走);5.3 与 5.4 两组工单第 ③ 字段均已登记为分层①。
- **裁定值(2026-10-28 用户裁,原候选值即本值,落定后转定稿)**:`#868C9A`(L≈0.261 / H≈222° / S≈0.13)。第二道门按宽松口径与在册色逐一比对,**无三通道全 <8 的对 → 过门**;§4.2 语义检查过门(不占红/金/蓝/紫赤/绿语义段,222° 不在 300°–345° 禁入带)。对比实测:对深素底 `#282220` 4.65:1、对舞台底 `#3E362C` 3.52:1、对浅素底 `#F5EAD3` 2.82:1(浅档已落选,不受该读数的门限约束)。
- **风险(已随 2026-10-28 裁定接受)**:本值与地台板身 `#968264`(L≈0.234)灰度差仅 0.028、对比 1.10:1。立绘与地台的可辨归 §5.1 轮廓通道(亮描边 + 落影)与冷/暖材质对比承载,不靠明度差——§5.3 明写「冷灰与全作暖底成材质对比」;§2 只在世界底层内部立了「同层内两底难辨」的子带纪律(该条立法理由明写为解决底层内部问题),世界中层无同款要求。
- ←机检: 本值入板后全板色对中三通道差全部 <8/255 的对数 = 0
2. **站桩名字行的落法 + 素底明暗档——已裁(2026-10-28)= 垫素底、素底取深档 `#282220`**,本节转指路(原记为「轻甲木色在深底上不过 3:1」;核出落法是它的前置,故先落这一条)。
- **推导核实 = 成立,且是既有条款的落法、非新条款**:站桩名字行是文字,§7.2「一切文字(含菜单/说明/tooltip/按钮/底栏,**无区域例外**)」+「文字禁直接压纹理底——垫容器或罩层」两条覆盖它;§6.1 舞台正面目标条(2026-10-28 v3.22 定值)已就站桩文字位显式落法——「站桩文字位改垫素底或落进结算明细带」并明写「**非新条款**」,§7.2 同批加「站桩石板地台面同理」句,两处机检断言同文。舞台背景插画 `scene_stage_bg.png` 中景两色只靠笔触与纹理分块面(5.1 ③),属纹理底 → 落法门触发。**已回填**:站桩名字行落法 = **垫素底**(§5.3 共用验收条 + 5.3.1 / 5.3.3 对比判据)。
- **原冲突 = 素底明暗档圣经未定死(2026-10-28 已由作者裁,本节不替裁的冲突至此闭合)**:§4.1 只在册浅档 `#F5EAD3`(数字色牌,圣经唯一素色牌值),§7.4 血数垫牌在用的深档 `HP_BAR_BACK #282220` 亦在册。两档后果**相反**(下表留作裁定依据账):
| 受影响的位 | 浅档 `#F5EAD3` | 深档 `#282220` |
|---|---|---|
| 站桩名字行墨(现役暖白 `#F0E2C8`) | 1.08:1 ✗ → 按 §7.2 双色墨制「亮底转深墨」改主墨 `#33261B`(12.3:1) | 12.26:1 ✓ 不动 |
| 5.3.2 魔法甲暖白 `#F0E2C8` | 1.08:1 ✗ → 同须换深墨 | 12.26:1 ✓ 不动 |
| 5.3.1 轻甲木色 `#8A5A34` | 4.87:1 ✓ 不动 | 2.72:1 ✗ → 须换色合并(`WARM_FAINT #CDB88C` 8.08:1,零额度)或新增木色亮档(`#C49A5E` 6.07:1,占 1 枚) |
| 5.3.3 重甲冷灰 | 须 L ≤0.245,与 5.4 立绘体块主色带求交 → 窗 **[0.220, 0.245]**(候选 `#7E8492` L≈0.230,3.14:1) | 须 L ≥0.151 → 窗 **[0.220, 0.450]**(候选 `#868C9A` L≈0.261,4.65:1) |
- **裁定结论(2026-10-28 用户裁,取深档一列)**:① 站桩名字行墨(暖白 `#F0E2C8`)**不动**(12.26:1);② 5.3.2 魔法护甲暖白 `#F0E2C8` **不动**(12.26:1);③ 5.3.1 轻甲木色 → **接受换色合并 `WARM_FAINT #CDB88C`(8.08:1,零额度)**,不取新增木色亮档 `#C49A5E` 路线(须 +1 额度而余量为 0);④ 5.3.3 重甲冷灰 → 按深档窗 **[0.220, 0.450]** 落 **`#868C9A`**(4.65:1)。**素底值恒定 = `HP_BAR_BACK #282220`**(§7.4 血数垫牌同款,零新增)
- **推荐 = 深档 `#282220`**(四条理据)——**2026-10-28 用户采纳本推荐,裁定落深档**:① 与 §7.4 血数垫牌同款、既有素底,零新增;② 与 §4.1 在役亮档 token 同向——顺位徽标 `GOLD_BRIGHT` 对舞台底 6.47:1、魔法护甲徽标 `HERO_BLUE_BRIGHT` 5.88:1,现行徽标体系整体按暗底设计;③ 与 §7.4 v3.22 实测记录「暖白对舞台底 9.49:1 达标」不冲突,深档更暗则暖白更稳;④ 只动 5.3.1 一枚,名字行墨与 5.3.2 全部不动。**代价**:5.3.1 须换色(换色合并不需要额度,新增木色亮档要 1 枚)。**浅档的代价**:名字行墨与 5.3.2 两处换墨(零额度),但 5.3.3 被挤进 0.025 宽的窄窗,且与石君王灰皮(若亦须落 0.22–0.45)撞窗。
- ←机检: B 区站桩名字行与护甲图标正下方像素非地台板身色 `#968264`(§6.1 / §7.2 同文断言)
- ←目检: 名字行与三枚甲档图标同排挂载后,素底边缘与舞台底、地台轮廓不打架,不构成第二焦点(§3.4)
3. **信息面层 L 区间未定值**(5.3 明度带字段无区间可填):**结论 = 维持定性,不新增区间**——不为了与世界底层两子带对称而硬定一个区间。
- 理由一:**执法已被三处既有数值判据全覆盖**——文字 ≥4.5:1(§7.2)、图形 ≥3:1(§4.1 图标槽柔和档条)、数字墨/色牌的 L 界(§4.1:亮墨 L≥0.55 / 色牌 L≥0.70 / 深墨 L≤0.027)。三者都是「对其直接背景」的**相对判据**,信息面层成员恒压在具体底上,相对判据比绝对区间更贴执法面。
- 理由二:§1.4 整屏样张②项验的是**层间序关系**(信息面层 > 世界中层 > 世界底层),是相对断言,不需要信息面层的绝对上界。
- 理由三:世界底层拆两子带的立法理由 = 解决**同层内**两底(舞台底 L≈0.036 与已开格底 L≈0.10)灰度难辨(§2 该条明写),信息面层**无同款实证问题**(成员尺寸与位置差异大,且有墨/牌强对比),无对称立法理由。
- 理由四:硬定上界会误伤在册高亮档——`#F5EAD3` 色牌 L≈0.83、纯白 L=1.0 都在信息面层内,上界定死(如 0.90)会把它们拦在层外。
- **机检断言写得出来(证明不定值也能执法)**:←机检: 屏内信息面层取样点 L > 同屏世界中层取样点 L > 同屏世界底层取样点 L(§1.4②项同口径);←机检: 信息面层成员对其直接背景,文字位 ≥4.5:1、图形位 ≥3:1(§7.2 / §4.1)
4. **五处角色部件色值——2026-10-28 用户裁已落值**(不阻塞开工;手绘口径下必须落值,现已落)。**逐件取值见 §5.4.1(铲刃 / 提灯)、5.4.2(食人魔皮)、5.4.3(卓尔皮)、5.4.4(石君王灰皮)**;下表留作裁定依据账,色值已逐件落定(见上),不再以「待裁」表述:
| 部件 | §5.4 ④ 明度带归属 | 换色合并候选(在册,零额度)**——2026-10-28 裁定采纳** | 合并代价 / 淘汰理由 | 新增候选(**未取**,裁定走合并路线) | 第二道门 |
|---|---|---|---|---|---|
| 主角铲刃浅铁灰 | 手持件,不属「体块主色」判定面 | `FOG_MEMORY_INK #C4C4C4`(L≈0.552,中性灰 S=0) | 一色两岗(语义岗 = 迷雾记忆墨 §6.5,与 §4.1「常量本尊不动」先例相左);若后续纳入明度带判定则越上沿 0.45 | `#A8AEB8`(L≈0.421 / H≈218° / S≈0.09) | 过门(无三通道全 <8 的对);非语义段 |
| 主角提灯铜色 | 同上 | `GOLD_DEEP #B07A14`(L≈0.232 / H≈39°,落世界中层) | 金族语义岗(§4.2 金只说收益与兑现、禁作日常强调防通胀);与皮革木色 `#8A5A34`(L≈0.130)明度差 0.10,可辨 | `#C08A3A`(L≈0.297 / H≈36°) | 过门 |
| 食人魔酋长暖褐皮 | **体块主色 → 须落 L 0.22–0.45** | `暖石 #B8A582`(L≈0.387 / H≈39°,在册于 theme README 溯源表) | 一色两岗(该值现为滑轨槽字面量);已排除 `#968264`(地台承载面 §6.1)、`#B39A78`/`#C9AF83`(格底语义,§5.1 剪影禁借格底成立)、`#8A5A34`(L 0.130 越下沿) | `#B08050`(L≈0.253)/ `#A97C4E`(L≈0.234) | 过门 |
| 卓尔精灵浅紫灰皮 | **体块主色 → 须落 L 0.22–0.45** | **无可复用**:在册紫族四枚全部语义岗占用且 L <0.22——`#7C3AA8` 封印紫(退役)、`#7A4294` 妨害紫(§4.6.1 语义)、`#8A72C4` / `#7B5BD6` 类型微光族(§4.2 分域纪律:微光色相禁迁移复用为物件/阵营/UI 语义色) | — | `#A79CB8`(L≈0.355 / H≈264° / S≈0.15;避 300°–345°,紫赤独占仍归 `#8F2F6A`) | 过门 |
| 石君王岩石板甲 | 与缺口 1 同一枚,**不另计额度** | 见缺口 1 | 见缺口 1 | 见缺口 1 | 见缺口 1 |
| 石君王灰皮 | **口径已裁(2026-10-28)= 次级皮**:石君王重甲覆盖率最大(§5.3),板甲视同体块主色 → 灰皮属次级皮、不受 0.22–0.45 约束 | 不受约束口径下可合 `STONE #786E62`(L≈0.160 / S≈0.18 近中性暖灰) | 若按体块主色口径则 L 越下沿 0.06,不可合 | `#9A968C`(L≈0.306)/ `#949089`(L≈0.281 / S≈0.07) | 过门;两候选与地台 `#968264` 灰度差 ≥0.047 |
**额度账(48 余量:裁定前 2 → 2026-10-28 裁定后 0,额度已用尽)**
- **必须新增 = 2 枚(已裁落定)**:① 重甲冷灰金属材质色(缺口 1,在册冷灰全部不合格)= **`#868C9A`**;② 卓尔浅紫灰皮(在册紫族全占岗且过暗)= **`#A79CB8`**。→ 余量 2 → **0**,额度用尽;后续新增须先压缩或合并既有色(压缩哪几枚由作者裁)。
- **可合并 = 5 处,零额度(已裁接受)**:铲刃 → `FOG_MEMORY_INK #C4C4C4`;提灯 → `GOLD_DEEP #B07A14`;食人魔皮 → `暖石 #B8A582`;石君王灰皮 → `STONE #786E62`(按**次级皮**口径);轻甲木色 → `WARM_FAINT #CDB88C`。
- **浮动一枚 = 5.3.1 轻甲木色(已裁)**:深档素底下**接受换色合并 `WARM_FAINT #CDB88C`**,零额度,余量不击穿;新增木色亮档 `#C49A5E` 路线未取。
- (原「若作者选全部新增(7 枚)」一支,留作依据账):击穿 5 枚。压缩只能从既有色里腾——优先合「宽松口径下仍未清偿的在册近色对」,每合一对腾 1 枚。机检扫到的**活值**近色对(须先剔除退役值与场景环境子板成员再计数;本清单未逐枚核语义岗,合哪几对由作者裁):`GOLD_BRIGHT #E0B860 ↔ GOLD_LIT #E6BE5A`(差 6/6/6);`WARM #F0E2C8 ↔ MAP_BAR_PLATE #F0E4C8`(差 0/2/0);`RAP_DOT_CORE_WARM #F8E2A8 ↔ INK_L_GOLD #F8E3A8`(差 0/1/0);`DIGIT_PLATE #F5EAD3 ↔ CAMP_ROW_PLATE #F0E6CE`(差 5/4/5)。**注:这四对均不在 §4.1 已列六对欠账清单内**,属该清单未扫到的部分——按 §4.1 现有断言「全板色对中三通道差全部 <8/255 的对数 = 0」,它们同样在清偿范围内;是否随本批一并清偿由作者裁。
- **本节不替作者决定压缩或合并哪几枚既有色**。
- ←机检: 本节候选值落定后,全板色对中三通道差全部 <8/255 的对数 = 0,且板内色数 ≤48
- ←目检: 五处部件色上稿后,灰度下铲 / 提灯 / 皮 / 甲互相可辨,不靠色相单独承载(§5.1 轮廓通道;§4.5 色弱清单)
- ←方向性: 五处部件色服务于「随身件画得出来、认得出」(character-design §5.4 秘宝形象候选池条),不抢体块主色的读序
---
## 6. 明确不在本文件
- **意图准备动画三档、战斗演出类**:动画序列帧,等一屏样张锁动画方案后另立规格卡。
- **格面徽章 19 枚 / 关卡节点图图标 / 砖面终稿 / 地形变异纹带**:脚本管线,规格锚 art-bible §4.6(图标键契约)、§1.4(样张验收)与 §3.2,不需要生成提示词。
+1 -1
View File
@@ -27,7 +27,7 @@
|---|---|---|
| `character/` | 角色棋盘帧 + B 区立绘 | character_hero_idle/walk(棋盘 32×32 朝左基准)、character_hero_portrait(B 区立绘 46×48)+ character_enemy_<键> 八敌 |
| `fx/` | 特效帧 | shovel_swing_f0/f1/f2(挥铲三帧,握把锚 (18,12)) |
| `scene/` | **场景图**(背景层 + 可点物件层;营地场景图首批) | `scene_camp_bg`(背景)+ `scene_camp_gate / forge / chest / notebook / dummy / board / campfire`(七个可点物件)+ `scene_camp_tent`(承载件,不可点)——登记超前:营地场景图批落地前盘上未建 |
| `scene/` | **场景图**(背景层 + 可点物件层;营地场景图首批) | `scene_camp_bg`(背景)+ `scene_camp_gate / forge / chest / notebook / dummy / board / campfire`(七个可点物件)+ `scene_camp_tent`(承载件,不可点)+ `scene_stage_bg`(B 区战斗舞台背景,✦ 插画级,只出远景+中景两带)+ `scene_stage_plaza`(B 区近景地台,48×12 九宫格件)——登记超前:营地场景图批落地前盘上未建 |
| `board/` | 砖面/封印印记(三关换皮 + 封印印记件) | terrain_floor_<board_type>_<n>.png(三关地面系)、seal_mark.png |
## 4. 坐标/朝向等工程侧约定备查
+2 -2
View File
@@ -24,11 +24,11 @@
- **体量档位 = 生物体型通道(原「强度先验·普通 < 精英 < Boss 单调递增」读法已弃用)**:体量按**物种天性**定,禁按强度档位线性映射——小体型精英与大体型普通怪并存(锁定实例:钩爪恐魔 > 灰矮人、灰矮人 < 熊地精、食人魔酋长 > 熊地精);「大个子多半有重击」的强度先验读法改由意图徽标(§5.6)与甲档(§5.3)承担,体量不再报强度;图像不报数,精确数值只在结算明细。
- 像素画布/精灵尺寸**不在本节**——归圣经 §8 资产规范;本节只锁比例关系与档位次序。
## 5.3 护甲类型视觉区分(候选方案,样张冻结终稿)
## 5.3 护甲类型视觉区分
> **白话**:敌方有三种护甲类型——轻甲(light)/魔法护甲(ward)/重甲(heavy),克制博弈需要玩家从画面读出"这只怪穿什么甲";本节定三档甲怎么画。键与命名事实源 = `data/schemas/enemy_table.gd` 的 `armor_type` 枚举与 [术语表](../gdd/术语表.md)(轻甲/魔法护甲/重甲)。
- **通道 = 甲面覆盖率 × 甲材质色**,不触 §5.1 剪影 archetype(底盘与体量轴不动)——「重甲语义走色板不作形状独占」的落法:甲档不新增独占通道(独占 = Boss 双通道专属),装备配件画法不属独占。
- **通道 = 甲面覆盖率 × 甲材质色**,不触 §5.1 剪影 archetype(底盘与体量轴不动)——「重甲语义走色板不作形状独占」的落法:甲档不新增独占通道(独占 = Boss 双通道专属),装备配件画法不属独占。**本节已定稿**(候选标注注销):三档画法逐字按本节执行,甲档不触 §5.1 剪影 archetype——不加肩甲外扩之类的轮廓改动,体量与凹凸计数仍由 §5.1 archetype 独占承载。
- **轻甲 light**:甲面覆盖率≈0——皮条/布带点缀或裸露,体表以物种本色为主。
- **魔法护甲 ward**:甲面覆**符纹饰带**——发光符纹走轮廓描边同族暖白,不占任何语义色(圣经 §4.2),覆盖率居中。
- **重甲 heavy**:**金属甲板**覆盖肩/胸/盾沿,冷灰金属材质色(与全作暖底成材质对比),覆盖率最大。
+1 -1
View File
@@ -2,7 +2,7 @@
> **渠道定位**:生图渠道 = **远程对话式生图为主,本地 ComfyUI 为备选**;本文件是**对话操作单**(怎么开对话/贴什么参考图/怎么续写),提示词正文词库归 [art-prompts](art-prompts.md)——分工:词库改词库、操作单改流程,同一段正文不双处维护。
> **冲突优先级**:画法与色彩以 [art-bible](art-bible.md) 为准,人物规格以 [character-design](character-design.md) 为准;本单为执行侧操作单,不另立规格。
> **出图登记义务(复现性)**:每张产出登记 **模型名 + 分辨率 + seed(可取则取)+ 对话/日期**,随候选原图同存 `artwork/candidates/<资产名>/`;缺登记的候选不入正稿遴选。
> **出图登记义务(出处备查)**:每张产出随图注明 **用途**(备选/参考/其他什么用)与 **生成时间**(YYYY-MM-DD HH:MM 格式),随候选原图同存 `artwork/candidates/<资产名>/`;模型名、seed、分辨率等参数有则随手记、无则不填,分辨率这类文件属性里自带的值不必抄。登记不作正稿遴选前置——缺注明不落选,遴选时问清用途即可。
> 开新对话出图:同一角色 2–3 版候选各开新对话(同对话续写=修图);同角色换姿势在同对话续写。分辨率开大档;候选原图存 `artwork/candidates/<资产名>/`。
## 1. 主角战斗立绘
+33 -21
View File
@@ -2,8 +2,8 @@
## 文档状态
- 版本:1.22
- 最近更新:2026-10-28(迭代 40 拆件批反哺落文——编排域拆件定稿节转现状登记:reward_economy 消费依赖改注入 Callable 口径、BattleFxHost 补 luck_bias_for 查询口、接线款补注入 Callable 款与 battle_hooks 三键回调束形态、补 RunLedger 退役后战斗域读面款、S13 豁免登记补第三条 battle_orchestrator 类变量键)
- 版本:1.26
- 最近更新:2026-10-30(迭代 42 反哺点落文——ShopSession 行对外暴露格按委托壳拆除后实测直连面重写:完整直连方法清单+set_shop_pool 调用面改述;沿革查 git)
- 引擎:Godot 4.7.2-stable(GDScript 单语言;2026-09-07 锁定)
- 评审模式:solo(`review-mode.txt`,2026-09-12 用户拍板——TD/LP 门禁按 solo 跳过,用户授权架构产出自主推进、迭代期回调)
- 覆盖 GDD:现行全集(根索引=`design/gdd/02-系统清单.md`,文档树构成以根索引为准)
@@ -85,15 +85,15 @@
| 模块 | 独占职责 | 对外暴露 | 消费依赖 | 引擎 API |
|---|---|---|---|---|
| **ConfigDB**(autoload,D2) | 全部玩法数值表(`data/tables/*.tres` + `data/schemas/*.gd`);SCHEMA_VERSION;加载/校验/override/诊断状态机。**2026-10-27 全清设计定稿:行族访问器归位各 schema 表类(表管自己的行查询),本类只留加载/校验/override/诊断门面(≤20);表持有成员按域收进域容器 Resource(分组建档于实现卡,消费方改址随该批)**——红线不变:本类仍是唯一加载与持有单点,"经 ConfigDB 单点读取"=经其持有的表对象 | 类型化域容器属性(每域一张容器);`load_tables(root, collect_only)`;诊断门面;`set_reload_gate()`;`reload` | 无(基础层顶点) | Resource/.tres 加载、autoload 生命周期——LOW |
| **SlotStore**(`core/slot_store.gd`,D3 存档槽位域件,2026-10-27 全清设计定稿——实现批建件) | 存档三槽位文件域唯一所有者(自 save_manager 收编槽位族):槽位挂载与模板、激活与建删、槽位摘要窥视(peek 族) | 槽位读写原语族+摘要投影(SaveManager 与菜单消费方直连) | save_manager(注入路径与模板配置);FileAccess——LOW |
| **MetaStateStore**(`core/meta_state_store.gd`,D3 存档内元进度数据件,2026-10-27 全清设计定稿——实现批建件) | 存档内元进度数据的读写唯一层(自 save_manager 收编 accessor 族:钥石/道具解锁/树节点与叉侧/锻造路线/同调/真视/计数器/摘要——数据读写原语,不含业务规则);save_manager 与 meta_progression 双 God Class 的共同病根=该数据域摊在两文件,本件即其归一 | 数据读写原语族+只读投影(MetaProgression 业务层与营地/锻造 UI 消费方直连;meta 的纯转发读方法随件退役) | save_manager(序列化接线);FileAccess——LOW |
| **ConfigDB**(autoload,D2) | 全部玩法数值表(`data/tables/*.tres` + `data/schemas/*.gd`);SCHEMA_VERSION;加载/校验/override/诊断状态机。**行族访问器归位各 schema 表类(表管自己的行查询),本类只留加载/校验/override/诊断门面;表持有成员按域收进三张域容器 Resource(`config_domain_combat/run/crossrun.gd`——已建件(迭代 41),类型化成员 7/7/5);三张 resolver 表(board_gen.resolve_row/enemy.resolve_rowset/difficulty.resolve_modifiers)经 `load_tables` 装配段注入各容器,resolver 文件与键零搬移**——红线不变:本类仍是唯一加载与持有单点,"经 ConfigDB 单点读取"=经其持有的表对象 | 类型化域容器属性(每域一张容器);公开面 8(push_diag/is_fatal/reset_diagnostics/diagnostics/diagnostics_count/load_tables/set_reload_gate/reload)、类变量 9 | 无(基础层顶点) | Resource/.tres 加载、autoload 生命周期——LOW |
| **SlotStore**(`core/slot_store.gd`,D3 存档槽位域件,已建件——迭代 41 存量债批) | 存档三槽位文件域唯一所有者(自 save_manager 收编槽位族):槽位挂载与模板、激活与建删、槽位摘要窥视(peek 族);改名覆盖原语(_rename_overwrite)留 save_manager(IO 原语单点) | 槽位读写原语族+摘要投影(公开 10/类变量 4;SaveManager 与菜单消费方经 `save.slots.` 直连) | save_manager(注入路径与模板配置);FileAccess——LOW |
| **MetaStateStore**(`core/meta_state_store.gd`,D3 存档内元进度数据件,已建件——迭代 41 存量债批) | 存档内元进度数据的读写唯一层(自 save_manager 收编 accessor 族:钥石/道具解锁/树节点与叉侧/锻造路线/同调/真视/计数器/摘要——数据读写原语,不含业务规则);save_manager 与 meta_progression 双 God Class 的共同病根=该数据域摊在两文件,本件即其归一 | 写口原语 13+只读投影 6(tree_state/forge_state/attune_state/career_state 四投影+keystone_balance/item_unlocked)=公开 19(add_keystone 私有 `_add_keystone`),零 _data 副本零缓存;MetaProgression 业务层与营地/锻造 UI 消费方经 `save.meta_state.` 直连(meta 的纯转发读方法已退役) | save_manager(序列化接线);FileAccess——LOW |
| **RngService**(autoload,D2) | master_seed、各流 scope 计数器(封闭流词表现值以 `RngServiceCore.PURPOSE_TAGS` 为准;增流走 P1 评审) | `set_master_seed()`(唯一调用方 C2);`open_stream(stream)` 有状态门面;`derive_at(stream, scope)` 纯函数;只读计数器 | ConfigDB(无) | 无——纯逻辑 |
| **action_economy**(A3) | AP/RAP 账本、last_round_end、轮次相位机 {Idle, Active, Waiting}、结束仲裁 | 意图与通知布尔面:notify_round_start / request_dig / request_stop / request_refresh / notify_settlement_done / notify_combat_end;预授权通道:grant_reserve_ap / finish_round_stop;ap/rap/phase 只读 | ConfigDB(ActionEconomyTable);effect_engine(事件发射 dispatch——基础层内同层引用);B1 回发 next_round_mode/battle_over | 无 |
| **variation 定义**(A4) | VariationTable schema(现行 6 行:六 region——贫矿脉 global 行 2026-10-16 用户令屏蔽删行,global 型机制代码保留)与 F1 候选池门控谓词 | `variant_pool(level_index, board_type, node_type="")`(门控三维:unlock+board_types+节点身份——global 行仅 boss/elite 入池,缺省跳过零扰动);`global_variant_row(level_index, board_type, node_type)`(全局型单行决议访问器) | ConfigDB(VariationTable) | 无 |
| **status_container**(B3) | 状态实例容器(战斗域生命周期、跨轮跨图延续) | 5 API:notify_battle_start / apply_effect / query_active / decay_round / notify_battle_end | ConfigDB(StatusEffectTable) | 无(RefCounted) |
| **effect_engine**(内容数据驱动扩展批 iter17 建域) | 零运行时可变状态的系统(见「架构原则」条 8):全同步解释器——事件由宿主在明确代码点位显式调 dispatch 进件,命中序=装载声明序(feats→treasure→树规则)写死保种子复放,不是事件总线/事件循环;事件/事实/效果类型/算子四词表封闭 + 树规则合成订阅六键(posture 每关首轮窗/sense 两组限次 counter 闸·adv_ 前缀走冒险桶跨战斗持久) | rebuild(每战重建订阅表)/`dispatch(ctx, event, payload, facts)`/`validate_trigger_row` + 静态计数口 `counter`·`counter_add`·`counter_spend`·`bucket_of`·`counter_id_legal`(计数器读写只经 EffectContext 引用束,无导出/灌入接口) | ConfigDB(feats/treasure 行集)、EffectContext(四桶引用由宿主持有:round/battle 桶归编排器、level 桶归关卡域、adventure 桶归应用层——RunLedger 已随迭代 39 拆件批退役,桶字典由 adventure_runner 持有) | 无(零随机全确定) |
| **save_system**(D3,Alpha;iter27 已升格 autoload「SaveManager」) | 存档格式与版本比较 | (契约规范源:`../../gdd/systems/表现与支撑/存档序列化.md`——契约锚:SCHEMA_VERSION + master_seed + 各流 scope 计数器快照,须在无正在执行中的 open_stream 实例时切出) | ConfigDB、RngService 只读计数器 | FileAccess——LOW |
| **save_system**(D3,Alpha;iter27 已升格 autoload「SaveManager」) | 存档格式与版本比较 | (契约规范源:`../../gdd/systems/表现与支撑/存档序列化.md`——契约锚:SAVE_FORMAT_VERSION + master_seed + 各流 scope 计数器快照,须在无正在执行中的 open_stream 实例时切出) | ConfigDB、RngService 只读计数器 | FileAccess——LOW |
| **settings/localization**(D6,愿景) | 设置项、翻译数据 | (契约规范源:`../../gdd/systems/表现与支撑/设置与本地化.md`) | ConfigDB | 无 |
### 核心层
@@ -101,29 +101,33 @@
| 模块 | 独占职责 | 对外暴露 | 消费依赖 | 引擎 API |
|---|---|---|---|---|
| **board_generator**(A1) | 生成算法(五阶段管线)、BoardGenTable 回填、生成期指标集、合法性谓词(clearable / R₀≠S / min_safe)、可推理率度量(metric_version);生成姿态 = MVP 同步生成 + 加载幕(切片实证 10×10/12×12 同步可接受,WorkerThread 留扩展) | `generate(L, D, rng) -> Board`;度量独立入口×3(推理器 / F3 度量 / 合法性谓词——独立纯函数、同一实现) | ConfigDB(BoardGenTable/VariationTable);board_gen 流(一次 open_stream = 一张图);dig_ap_cost 只读 | 无 |
| **minesweeper_rules**(A2) | 棋盘状态(已开集 O / 封印集 G / 小人位)、三事件面、批次仲裁、install 四不变式 | `install_board(board)`;`settle_batch(intents)`(唯一提交入口);查询只读面(current_board / hero_pos / is_revealed / has_seal 等);`compute_move_path(cell)` 只读;`retire_board()`;三源拒绝(board_face / resource_face / phase)+ sub_reason 封闭枚举 | A1 产物(Board class_name 数据契约);A3 try_spend / last_round_end / 相位 | 无(零表读取、零 UI——切片实证) |
| **minesweeper_rules**(A2) | 棋盘状态(已开集 O / 封印集 G / 小人位)、三事件面、批次仲裁、install 四不变式 | `install_board(board)`;`settle_batch(intents)`(唯一提交入口);查询只读面(current_board / hero_pos / is_revealed / has_seal 等);`compute_move_path(cell)` 只读;`retire_board()`;三源拒绝(board_face / resource_face / phase)+ sub_reason 封闭枚举 | A1 产物(Board class_name 数据契约);A3 try_spend / last_round_end(迭代 41 由属性改方法)/ 相位 | 无(零表读取、零 UI——切片实证) |
| **unit_container**(B2) | hero/enemy 单位实例(hp/atk/实例池:池快照+冷却+摇定动作+保底计数)、行值快照 | spawn / query_alive / rollable_skills / special_skills / check_trigger_unlocks / set_pending_action / pending_action / basic_streak / commit_action / tick_cooldowns / apply_damage / heal / default_target / check_skill_unlocks / despawn_all(2026-09-16 敌人技能池批:query_beat/query_attack/advance 随行为环退役;rollable_skills/special_skills/check_trigger_unlocks 带 facts 参——2026-10-27 情境条件触发器实装,事实缺键=条件假拦下,百分比事实走阈值式折算) | ConfigDB(EnemyTable/SkillTable/HeroTable) | 无 |
| **reward_economy**(B4) | 格面资源身份映射(install 期预分配、Ready 只读、换图映射消亡)、极性路由字典面((类型, 极性)→ 字典行查询;路由执行归 B1 授予段)、F6 当量供给投影 | 封闭 API:roll_board / query_identity / query_full_snapshot / grant / grant_clear / retire_mapping / polarity_row / phase / weighted_pick;另有 is_mapped 静默布尔投影(批量工具用) | ConfigDB(RewardTable);BattleFxHost 经注入 Callable `luck_bias_query` 取偏运合计(reward_roll 发射与 bias_rewards 求和移至效果层完成);reward_roll 流(scope = 每次 install 批) | 无 |
| **helper_items**(A5,切片已实装秘宝域) | HelperItemTable、探测显影语义 | (契约规范源:`../../gdd/systems/跨局循环/秘宝.md`——桥接位:A2 查询接口 + A4 counter_item_ids) | A2 / A4 / B4 | 无 |
| **CurioDeck**(`core/curio_deck.gd`,A5 秘宝域令牌池件,迭代 37 自 AdventureRunner 拆出) | 三选一/商店共享池的持久多重集、抽签(候选抽取)、cap 库存与专长凭证三计数与判定唯一所有者——件只管池与判定,停点编排与兑付推进留冒险编排器 | `draw_candidates(channel)` 抽签;`consume_deck_token` / `consume_pool_purchase` 池消耗;`cap_ok` 上限判定;`feat_ticket_consider` 凭证判定;`stock_snapshot` / `pool_stock` 只读投影;商店购买消费经注入 Callable 链至 CurioStop 兑付单点(迭代 39 起转纯池——bind_handlers 反向回调已退役) | ConfigDB(秘宝令牌行集);注入 RngServiceCore(reward_pick 封闭流,禁自建随机) | 无(RefCounted 纯逻辑) |
| **ShopSession**(`core/shop_session.gd`,商店会话件,迭代 37 自 LevelRunner 拆出) | 关卡商店双模式(legacy 固定三件加定价/pool 共享令牌池)的货架、定价、购买与刷新唯一宿主——账本/钱包/装配集归宿主 LevelRunner(共享引用经 `bind` 注入,出账直接落同一引用改写宿主账本);legacy 模式零 RNG 零池消费(off 对照承载) | 货架与定价只读面(`shop_products` / `shop_shelf` / `current_price` / `shop_refresh_cost`)+写入口(`buy_product` / `buy_pool_item` / `shop_refresh` / `player_request_refresh` / `open_pool`);外部调用面由 LevelRunner 同签名委托承载(外部零变化) | ConfigDB(商店行集);注入 RngServiceCore;宿主钱包/账本引用;pool 模式令牌消耗与判定经注入 Callable 转 CurioDeck | 无 |
| **ShopSession**(`core/shop_session.gd`,商店会话件,迭代 37 自 LevelRunner 拆出) | 关卡商店双模式(legacy 固定三件加定价/pool 共享令牌池)的货架、定价、购买与刷新唯一宿主——账本/钱包/装配集归宿主 LevelRunner(共享引用经 `bind` 注入,出账直接落同一引用改写宿主账本);legacy 模式零 RNG 零池消费(off 对照承载) | 货架与定价只读面(`shop_products` / `shop_shelf` / `current_price` / `shop_refresh_cost`)+写入口(`buy_product` / `buy_pool_item` / `shop_refresh` / `player_request_refresh` / `open_pool`);外部调用面=调用方经宿主 LevelRunner 公开成员 `shop` 直连(调用直连不留委托壳,2026-10-26 Middle Man 裁定;迭代 42 拆除),直连消费的方法=`shop_products`/`current_price`/`purchased_tier`/`buy_product`/`player_request_refresh`/`set_shop_pool`/`pool_price`/`shop_shelf`/`shop_refresh_free_left`/`shop_refresh_cost`/`shop_refresh`/`spend_gp`/`buy_pool_item`/`is_shop_pool`/`shop_bp_shelf`/`shop_bp_visit_buys`(另白盒两入口仅测试侧:`_draw_shelf`/`_spend_discounted`);set_shop_pool 调用面=pool 注入经 LevelRunner 构造 ctx 供给(构造期内部直调,原委托块注释「AdventureRunner._start_current_level 唯一调用方」系陈旧表述、随壳删除作废),测试面直连 `shop.set_shop_pool` | ConfigDB(商店行集);注入 RngServiceCore;宿主钱包/账本引用;pool 模式令牌消耗与判定经注入 Callable 转 CurioDeck | 无 |
| **HeroLedger**(`core/hero_ledger.gd`,冒险域主角实体账,已实装(2026-10-27 迭代 39 拆件批)) | 冒险生命周期主角数值与获得记录唯一所有者:生命与 GP 钱包(gain/spend/clear 单写原语,钱包事件发射点归件)、锻造强化快照、调试百分比、攻击/甲类型轴快照、特性持有集(活引用注入——关内兑付当关生效)、本局钥石增量与逐杀明细、真视使用记录;获得记录三层结构=获得记录列表(三选一件/商店购买/战末奖励各一条)→属性增益明细(带来源指回)→四轴汇总(由明细推导);生效上限与回血封顶公式单点归件 | 构造注入;单写原语族+只读投影;断点自交片段(账本键+获得日记键) | ConfigDB(表值读取);由 AdventureRunner 冒险开始创建、注入 CurioStop/level_runner/ShopSession/战斗 encounter | 无(RefCounted 纯逻辑) |
| **AttuneLoadout**(`core/attune_loadout.gd`,同调配装件,已实装(2026-10-27 迭代 39 拆件批)) | 装备中的秘宝件对象集唯一所有者(每件内含充能单位与重置周期);同调充能的物化行为唯一事实源——种行/补行改写时同步(RunLedger 充能字典轨与差额对账函数退役);旧档 aux_items 同调行迁移归件 | 构造注入;充能查询/消耗/按周期重置原语;断点自交片段(attunement_charges 键,键名与策略不变) | ConfigDB(秘宝行集);TreasureItems(同调行投放面);注入战斗使用路径 | 无 |
| **CurioStop**(`core/curio_stop.gd`,三选一停点件,已实装(2026-10-27 迭代 39 拆件批)) | 三选一停点编排唯一所有者(架构原则 9 本域承载):停点三态(关卡完成三选一在途/已兑付待推进/奖励节点三选一在途)、刷新三源账(刷新件 X/营地池 Y/刷新券存量/付费刷新计数)、兑付方法族(pick/refresh/redeem/skip)、凭证出箱(RAP/时沙待注入);三选一信号面自带;零自动推进停点语义承载 | 对外=开停点/刷新/兑付/放行谓词/交断点片段五组入口+信号面(curio_choice_presented/curio_resolved);由 AdventureRunner 关卡完成受理时调用 | ConfigDB;注入 CurioDeck(抽签/摘牌)与 HeroLedger(落账);随机只经 CurioDeck 的 reward_pick 封闭流 | 无 |
| **breakpoint_store**(`core/breakpoint_store.gd`,冒险域·断点组装与回放件,2026-10-29 零豁免裁设计闭合——实现批建件) | 存档断点组装与回放唯一承载(自 adventure_runner 收编 6 成员+函数族):断点快照拼盘、回放回填、读侧策略分发;`BREAKPOINT_FIELDS` 27 键登记单源随件(键名/策略标签/键序冻结) | 构造=引用束注入;`resume_adventure` 留宿主薄壳;断点键面零变化 | adventure_runner(宿主);注入主角账三件与 curio/stop/bank/loadout 引用 | 无(RefCounted 纯逻辑) |
### 功能层
| 模块 | 独占职责 | 对外暴露 | 消费依赖 | 引擎 API |
|---|---|---|---|---|
| **battle_orchestrator**(B1) | 段序骨架(七段结构冻结)、轮 facts 缓冲、可回放步骤流、[明细行协议](../../gdd/systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋)(基础行型+扩展行两层 + 字段分层,词表以 owner「明细流水」节为准)、条款③⑤闭合对账、**战斗域全部跨系统调用权**、效果引擎宿主面与树规则挂点施加面(**已拆出 BattleFxHost 并实装(2026-10-28 迭代 40——battle_fx_host.gd/reward_grant.gd 两件在库,效果引擎宿主面归 BattleFxHost 行承载,拆件细则见「战斗编排域拆件定稿」节)**) | `begin_battle(encounter)`;窗口/刷新意图提交面(扮演 D1);`level_clear()`;步骤流(输出契约) | B2/B3/B4 全调用面(**唯一调用方=B1 域文件集:battle_orchestrator.gd + settlement/ 五段段类 + damage_controller + 拆件后两新件**);A3 request_refresh 代理 + 回发;A2 install/retire + 三事件订阅;A1 generate(attempt 非 scope 事件);D2 SettlementTable + set_reload_gate | 无(零随机、禁 await——切片 88 冒烟实证可回放) |
| **battle_orchestrator**(B1) | 段序骨架(七段结构冻结)、轮 facts 缓冲、可回放步骤流、[明细行协议](../../gdd/systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋)(基础行型+扩展行两层 + 字段分层,词表以 owner「明细流水」节为准)、条款③⑤闭合对账、**战斗域全部跨系统调用权**、效果引擎宿主面与树规则挂点施加面(**已拆出 BattleFxHost 并实装(2026-10-28 迭代 40——battle_fx_host.gd/reward_grant.gd 两件在库,效果引擎宿主面归 BattleFxHost 行承载,拆件细则见「战斗编排域拆件定稿」节);2026-10-29 零豁免裁设计闭合:RoundCycle/BattleFacts 两新件随批(宿主 38→15、S13 豁免第三条注销——见下两行与定稿节轴丁)**) | `begin_battle(encounter)`;窗口/刷新意图提交面(扮演 D1);`level_clear()`;步骤流(输出契约) | B2/B3/B4 全调用面(**唯一调用方=B1 域文件集:battle_orchestrator.gd + settlement/ 五段段类 + damage_controller + 拆件后三新件**);A3 request_refresh 代理 + 回发;A2 install/retire + 三事件订阅;A1 generate(attempt 非 scope 事件);D2 SettlementTable + set_reload_gate | 无(零随机、禁 await——切片 88 冒烟实证可回放) |
| **BattleFxHost**(`core/battle_fx_host.gd`,B1 域·效果引擎宿主件,2026-10-26 编排域拆件设计定稿——实现批建件) | 效果引擎挂点施加面唯一承载(自 battle_orchestrator 收编 fx 族):事件发射与事实判定(_fx_emit/_fx_fact)、主角 AC 基线与本轮/本战 AC 累积、bonus_delta 四轴累积(战末宿主 drain 汇入账本)、揭示待兑队列与兑付(含 _fx_revealing 再入闸——同步信号回环防二次缓冲二次兑付)、树规则合成订阅的 round/battle 桶计数器持有(桶随编排器生灭语义不变) | 构造=引用束注入(防 _init max-parameters 新键);bind 时注入 emit Callable(行发射经宿主协议面单点)与兑付 Callable(RewardGrant 授予面——揭示队列 flush 回调);只读投影分两类消费方:AC 累积/bonus_delta 供宿主呈现快照与战末 drain,揭示态供宿主 A2 订阅旁路判定;`luck_bias_for(cell_count) -> int` 偏运合计查询口(体内三参形 dispatch——reward_roll 发射与 bias_rewards 求和自 RewardEconomy 收回本件,RewardEconomy 经注入 Callable 消费) | EffectEngine(EffectContext 引用束);RngServiceCore(fx_reveal 封闭流——除该流外零随机);A2 minesweeper(板读与 fx_reveal 调用);A3 action_economy(queue_ap_delta/charge_layers 读);B3 status_container 读;B2 unit_container 读(hp_ratio);DamageController(set_hero_ac_override);ConfigDB;encounter 引用 | 无(零 await——效果引擎全同步解释器) |
| **RewardGrant**(`core/reward_grant.gd`,B1 域·奖励授予件,2026-10-26 编排域拆件设计定稿——实现批建件) | 奖励授予唯一兑付管线(自 battle_orchestrator 收编 grant 族):极性字典路由与封印溢价兑付(_grant_routed)、三种行应用(flat/percent/gp)、伤害单据提交面(_submit 族)、清图奖励与身份授予、秘宝使用编排(use_treasure 四步)、战斗域 GP 缓冲 escrow 与授予段暂存伤害闸(_defer_board_damage/_deferred_board) | use_treasure 编排入口(treasure_interact_controller 经组合根现值回调直连);授予入口(结算段类直调);只读投影(escrow 读与 GP 掉落合计——宿主呈现快照与 _roll_gp_drop 消费) | B4 RewardEconomy(polarity_row/grant);B1 域 DamageController(开单);BattleFxHost 引用(treasure_used 事件发射与计数器消耗);A2 minesweeper(校验回调/fx_reveal/remove_mines_in);A3 action_economy(相位闸/grant_ap/queue_ap_delta);B3 status_container(apply_effect/池读);B2 unit_container(hero_unit/heal);ConfigDB;注入 emit Callable、宿主 fatal Callable(battle_result 状态机唯一写点留宿主)、宿主 attune 读投影(_attune_safe_seen)、encounter 账本引用;TreasureItems 经宿主 setter 转发注入(库存注入时序在宿主构造之后) | 无(零随机零 await——授予期零随机口径,roll 值授予前已定) |
| **damage_controller**(B1 域·伤害单据管线) | 伤害单据唯一兑现管线(单据九栏目声明→分量掷点/克制修正/伤害下限归一→明细行发射;双方同规) | 兑付入口(编排侧开单)+ fx 揭示回调注入位 | B2 单位实例(单据目标传入);B1 注入(EffectContext 引用束与编排回调) | 无 |
| **BoardInstaller**(`core/board_installer.gd`,B1 域·装板域件,2026-10-29 尾波清偿批设计闭合——实现批建件,细则见「战斗编排域拆件定稿」节轴丙) | 棋盘安装与变异布置域唯一承载(自 battle_orchestrator 收编装板族六函数):生成受理、全局作用域变异决议、资源摇号资格域组装(roll_board 恰一次)、region 变异决议与连通片布置;BoardGenerator 实例随件自建自接线(宿主成员退役)——宿主侧装板后状态复位(封印/完美计数清零、板序推进、board_changed 发射、秘宝叠加层退役)留宿主薄壳,时序逐字保持 | `install(during_round) -> bool` 单入口;构造=引用束注入(rng/db/minesweeper/reward_economy/encounter 只读引用+宿主 fatal Callable——防 _init max-parameters 新键) | A1 board_generator(件内持有);A2 install_board;B4 roll_board/board_skew 写;A4 变异决议行集经 ConfigDB;board_gen/variant_place 两封闭流随件、流名与开流时点零漂移 | 无(零 await——装板全同步) |
| **RoundCycle**(`core/round_cycle.gd`,B1 域·轮循环驱动件,2026-10-29 设计闭合——实现批建件) | 轮循环驱动域唯一承载(自宿主收编 7 成员):结算五段段件持有与驱动、重入门闸、开轮摇号、踩雷账 | 构造=引用束注入;段驱动入口由宿主接线调用 | B1 宿主;settlement/ 五段段类;A3 相位读 | 无 |
| **BattleFacts**(`core/battle_facts.gd`,B1 域·战斗事实件,2026-10-29 设计闭合——实现批建件) | 战斗事实域唯一承载(自宿主收编 14 成员):受理事实(encounter)、轮 facts 缓冲(reveals/seals/path)、封印判定账、事实溯源、同调快照读面;attune 状态两成员随件(行为函数留宿主) | 构造=引用束注入;宿主与段类经注入引用读写 | B1 宿主;A2/A3 只读 | 无 |
| **settlement/ 五段段类**(B1 域·结算段件) | B1 每轮结算序列的五段逻辑件(授予/增益减益/战斗/衰减/判定——细则见下「战斗域装配现状」节) | 段处理入口(B1 接线调用);可直接 `new()` 单测 | B2/B3/B4 兑付面与 B1 轮 facts 缓冲(各段按职责) | 无 |
| **level_runner**(C1-lite,切片已建) | 关卡域生命周期(节点链推进、共享 B4 + HP 携带、关卡末 level_clear) | 节点推进接口;LevelTable(`level.tres`——节点 enum {battle,reward,rest,boss}、末节点必须 Boss、ConfigDB 跨表校验⑧) | B1(直构 BattleOrchestrator 接线战斗)、ConfigDB LevelTable | 无 |
| **run_structure**(C2) | 冒险/关卡序列、失败重开、**master_seed 唯一接线方** | (契约规范源:`../../gdd/systems/冒险循环/冒险结构.md`) | RngService.set_master_seed、C3/D2 | 无 |
| **difficulty**(C3) | DifficultyTable 回填、全部曲线数值调参所有权、战斗期望表(切片 monte_carlo 为工具原型) | 调参输出(经 D2 R1 解析/编排器传递,禁反向调用生成) | ConfigDB、B1 对账输出(调参约束清单)、A1 报告 C | 无 |
| **meta_progression**(C4,Alpha) | MetaTable、钥石账本、天赋树域(MetaTreeTable 12 节点 v0.8——Fork 一节点双态/row 字段退役/RULE_KEYS 六键/彩蛋特化觉醒,迭代 21 T1 换代)+ 同调位槽位判定(树点亮数单源——T4 槽位收编)。**2026-10-27 全清设计定稿:存档内元进度数据读写原语归 MetaStateStore(新件),本类纯转发读方法随件退役(消费方直连 store),业务规则与写口编排留本类(≤20)** | tree_can_buy/tree_buy/tree_buy_fork/tree_toggle_fork(写口唯一)、hero_override 注入(树淬炼 flat+锻造路线加值位预留 0)、tree_rule_keys | D3、C2、ConfigDB | 无 |
| **meta_progression**(C4,Alpha) | MetaTable、钥石账本、天赋树域(MetaTreeTable 12 节点 v0.8——Fork 一节点双态/row 字段退役/RULE_KEYS 六键/彩蛋特化觉醒,迭代 21 T1 换代)+ 同调位槽位判定(树点亮数单源——T4 槽位收编)。**存档内元进度数据读写原语归 MetaStateStore——已落地(迭代 41):本类纯转发读已退役(消费方直连 meta_state),业务规则与写口编排留本类;hero_override 内联锻造加值与树淬炼 flat;并组三组(forge_select(kind,route_id)/hero_type_axes()→{attack,armor}/tree_camp_status()→{rows,fork_groups});补 meta_state 成员装配** | 公开面 20 定稿:buy_treasure_unlock / refresh_treasure_unlocks / treasure_shop_status / forge_buy_level / forge_buy_unlock / forge_select / hero_type_axes / forge_shop_status / settle_adventure / hero_override / tree_can_buy / tree_buy / tree_toggle_fork / tree_buy_fork / tree_rule_keys / tree_camp_status / toggle_attunement / attune_camp_status / attune_refresh_charges / buy_attune_refresh | D3、C2、ConfigDB | 无 |
### 战斗域装配现状(迭代 27——2026-10-17 用户裁写入;RunLedger 段已随迭代 39 拆件批退役,四账去向见下「冒险域拆分(现状登记)」节)
@@ -132,14 +136,16 @@
### 战斗编排域拆件定稿(2026-10-26 用户裁写入——gdstyle 存量债波 1 设计闭合;同日独立审查(grilling+godot-master 双子代理)阻断 8 条去重 6 组全折入本节,v1.18;2026-10-28 迭代 40 实现批合回(合并提交 514457d1),本节为现状登记)
- **轴甲两件**:battle_orchestrator(1313 行/50 成员,S13 全库单文件最大户)按变化原因拆出 BattleFxHost(效果引擎宿主域)与 RewardGrant(奖励授予域)两协作件;宿主保留架构在册职责全部——战斗状态机与生命周期、轮 facts 缓冲(_facts_reveals/seals/path)、A2 三事件订阅、结算五段驱动、attune 族原位、行发射基建(_emit_row/_assert_row_source/_fatal)、呈现投影(presentation/diagnostic_snapshot 唯一出口不变)、刷新面、nest_preview_count(巢穴预告读数口——外部直读面 main.gd 与 treasure_effects_test 随批点名冻结)。拆件动机与残留债口径见待办清单「gdstyle 存量债全量清偿」条目。
- **轴丙一件(2026-10-29 尾波清偿批设计闭合——实现批建件)**:battle_orchestrator 装板域六函数(`_install_new_board`/`_resolve_global_variant`/`_place_variants`/`_place_variants_apply`/`_variants_fringe`/`_adjacent_to_packs`,约 140 行;全仓仅宿主三调用点——begin_battle/中途刷新受理/player_request_refresh,实查零外部调用)按变化原因拆出 BoardInstaller,职责语句「棋盘安装与变异布置域」(生成→全局变异决议→装板受理→资源摇号→变异布置;单一变化原因=棋盘设置顺序与变异布置算法)。形态两修正(实测裁,与初案「逐字搬运」之差):①宿主复位块不随件——`_install_new_board` 体内五处计数清零、板序推进、board_changed 发射与秘宝叠加层退役留宿主薄壳 `_install_and_reset`,三调用点改调薄壳、时序逐字;②`_board_generator` 全文件仅装板族使用——实例随件自建自接线(fatal 经注入 Callable),宿主成员退役(类变量 38→37,禁无效成员义务)。encounter(23 处跨宿主)与 _reward_economy(18 处)确认留宿主、经引用束注入。文件长键(1035/1000)随本件迁出归绿;attune 族与 begin_battle 受理段序禁动不变。
- **轴丁两件(2026-10-29 零豁免裁设计闭合——实现批建件)**:RoundCycle(轮循环驱动件)与 BattleFacts(战斗事实件)见功能层表两行——宿主 38(轴丙落地后 37)→15,S13 豁免第三条注销;宿主保留面改登记为「战斗状态机与生命周期、行发射基建(_emit_row/_assert_row_source/_fatal)、呈现投影(两快照出口签名不变)、刷新面、nest_preview_count」;attune 族处置由下一条改判;treasure_inventory 注入改址追认——原「外部赋值路径零改址」句失效,level_runner 经 RewardGrant 出口直注;成员级对账以需求卡片为卡内契约(开工 T0 复核)。
- **跨件单向接线**:RewardGrant 持 BattleFxHost 引用(treasure_used 事件发射与计数器消耗);BattleFxHost 对授予面走 bind 时注入的兑付 Callable(揭示队列 flush 回调)——禁双向强引用(两件均 RefCounted,环引用随每战新建泄漏)。行发射经 bind 时注入的 emit Callable(协议面单点留宿主——CurioDeck bind_handlers 同款先例,禁件回调宿主私有族);轮 facts 缓冲留宿主、fx 件经注入取值;_seal_consumed 留宿主(与 A2 seal_judged 订阅同域);fatal 经注入 Callable 转宿主 _fatal(battle_result 状态机唯一写点不变)。注入 Callable 亦属接线面、同单向纪律——禁为省参数改持对象引用。授予件对账本零强引用:战斗期消费经 `battle_hooks` 三键回调束(attune_consume/vision_add/negative_blast,bind_battle 缺键 assert),宿主侧三单点记账(2026-10-28 迭代 40 合并适配实装——RunLedger 类已随迭代 39 退役,直持对象引用无处可指)。
- **战斗域读面(RunLedger 退役后)**:账本读经编排器 `_journal()`/`_attune_loadout()` 现值派生(GainJournal/AttuneLoadout,enc 派生、无成员接收);冒险桶经 `enc["adv_bucket"]` 下传 `battle_fx_host.mount_buckets`;战末 bonus 四轴经 `GainJournal.gain_bonus` 汇入(2026-10-27 迭代 39 主角账三件落地、迭代 40 合并适配承接)。
- **settlement/ 段类随动**:段类构造注入直持宿主+两新件三引用(Middle Man 禁令封转发壳——调用点改指),授予段读写面点名:_grant_routed×5/_submit×6/escrow 写/_fx_new_resource_types/_feat_first_dig_used/_fx_bonus_delta 写/_apply_ac_bonus/_fx_enqueue_reveal/_flush_pending_reveals/_grant_clear_reward/counters_ctx;战斗段 _defer_board_damage 复位与 _deferred_board 结账改指 RewardGrant。四个授予段 helper(_feat_yield_adjust/_harmful_variants/_harmful_adjacent/_hits_of)与 _pool_effective/perfect_sweep_earned 留宿主(段类经宿主引用直调,现状形态)。
- **attune 族原位保留**:同调配装 8 成员不进新件——迭代 39 副卡(AttuneLoadout 充能单源化)语义领地,两批零冲突;本波残留债归尾波。RewardGrant 经宿主 attune 读投影取 _attune_safe_seen。
- **attune 族处置(2026-10-29 零豁免裁改判,原「原位保留」失效)**:attune 状态两成员归 BattleFacts、行为函数留宿主——迭代 39 副卡(AttuneLoadout 充能单源化)语义领地不破,外部三面消费点零改址;RewardGrant 经宿主 attune 读投影取 _attune_safe_seen 形态不变。
- **呈现零变化**:两快照出口签名与载荷逐字不变,内部改读两件只读投影(快照本体不读揭示态——揭示态投影消费方=宿主 A2 订阅旁路判定);treasure_interact_controller 三触点分家——use_treasure 经组合根现值回调改注 RewardGrant(每战新建编排器,禁一次性直引防悬挂),minesweeper 读与 attune_convert_state 仍走宿主取值回调(双取值面);nest_preview_count 直读面零变化。
- **S13 键账收敛义务**:12 个超标键随函数迁入新文件=基线外 NEW(use_treasure 长度/分支/局部/返回×4、_grant_routed 参数 8、_dispatch_row 参数 6、_apply_percent_row 参数 6、_apply_gp_row 参数 6、_apply_flat_row 参数 7+返回 9、_submit_flat_hero 参数 7、_fx_fact 返回 7)——卡内同步收敛为本波义务(_grant_routed 等签名随引用束注入改形、use_treasure 体拆分),禁波 0 合并 refresh 吸收新文件未还键;新件 _init 引用束注入防 max-parameters 新键。
- **验收红线**:游戏行为零变化(RNG 消费序零漂移——fx_reveal 封闭流随件迁移取号序不变、信号顺序契约冻结、明细行协议词表零触碰、同种子逐位一致);battle_orchestrator 头注发射点指址随拆件改写(词表不动,指址须真);行数恶化债清偿义务(迭代 38 特批带红合并挂账 c4c69701——本波还债归绿);PARITY 触面(battle_orchestrator.gd 被改)实跑对拍须经用户批准、不得借机重锚;S13 改善非清零口径(宿主残留 8–10 键+随迁键卡内收敛后新件零残留为达标线)。
- **S7/S8 随动**:RewardGrant 调 B4 API,两新件一并登记进 S7 B1 域文件集与 S8 结算路径 await 文件集(static_scan.sh 两清单独立、同批更新——防 await 面漏闸)。
- **验收红线**:游戏行为零变化(RNG 消费序零漂移——fx_reveal 封闭流随件迁移取号序不变、信号顺序契约冻结、明细行协议词表零触碰、同种子逐位一致);battle_orchestrator 头注发射点指址随拆件改写(词表不动,指址须真);行数恶化债清偿义务(迭代 38 特批带红合并挂账 c4c69701——本波还债归绿);S13 改善非清零口径(宿主残留 8–10 键+随迁键卡内收敛后新件零残留为达标线)。
- **S7/S8 随动**:RewardGrant 调 B4 API,两新件一并登记进 S7 B1 域文件集与 S8 结算路径 await 文件集(static_scan.sh 两清单独立、同批更新——防 await 面漏闸);轴丙 BoardInstaller 同规(调 B4 roll_board,实现批随批增行)。
### 冒险域拆分(现状登记——2026-10-26 设计闭合,2026-10-27 迭代 39 拆件批实装,本节各条即现行形态)
@@ -147,7 +153,7 @@
- **CurioDeck 转纯池**:bind_handlers 反向回调退役;商店购买消费经注入 Callable 链至 CurioStop 兑付单点——牌库只管抽签/消耗/cap 判定/凭证计数。
- **RunLedger 退役**:四账各归其主——加算区/购买记录/钥石增量/特性集/真视记录归 HeroLedger,充能归 AttuneLoadout,冒险桶字典归应用层持有;战斗侧 encounter 注入面由单一账类引用改为多路(桶字典+实体账+配装件);ShopSession 账本引用面同步换代,商店属性商品加算改经 HeroLedger 单写原语。
- **level_runner**:依赖改构造注入一次给齐(后置 setter 群与商店重绑机制退役;注入活引用禁快照——特性集共享引用语义保留);商店白盒转发属性撤除;战斗→关卡信号转发族保留(战斗实例每节点新建,关卡层做战斗域稳定面)。
- **断点片段化**:各件自写自读自己的键(关卡层交关卡域五键片段:node_id/visited_ids/aux_items/shop_shelf/shop_visit_buys),缺键回退策略随领域知识归各件;应用层唯一落盘口(收齐各件片段拼成顶层快照后写盘),写触发点不变(五处);既有 27 键逐键冻结;新增获得日记键沿扩列不升版先例——旧档缺日记回退汇总键直载并跳过比对,日记在档时由日记推导汇总、与留存值不符即报错中止(迁移正确性自检)。
- **断点片段化**:各件自写自读自己的键(关卡层交关卡域五键片段:node_id/visited_ids/aux_items/shop_shelf/shop_visit_buys),缺键回退策略随领域知识归各件;应用层唯一落盘口(收齐各件片段拼成顶层快照后写盘),写触发点不变(五处);既有 27 键逐键冻结;新增获得日记键沿扩列不升版先例——旧档缺日记回退汇总键直载并跳过比对,日记在档时由日记推导汇总、与留存值不符即报错中止(迁移正确性自检)。2026-10-29 零豁免裁随动:拼盘与读侧策略机组拆出 breakpoint_store(核心层表新行),应用层落盘口与写触发点不变——宿主经件组装快照后写盘,27 键冻结不变。
- **信号直连**:adventure_runner 六转发信号族(node_entered/choices_presented/step_row/round_started/board_changed/wallet_changed)退役;呈现层在 level_started 重取点重订阅关卡对象信号(旧实例连接随引用释放消亡);「关卡开始信号前零发射」契约写进关卡件头注;「恰好连接一次」断言用 is_connected 守卫(release 模板剥 assert);三选一信号面归 CurioStop。
- **调用直连**:不留中间人委托壳(纯转传=Middle Man 反模式,2026-10-26 用户裁定);呈现控制器经取值回调持件——回调只许捕获长活根对象,禁件方法 Callable(防悬挂);约 30 个调用文件改址;测试/探针直连件读写。
- **验收红线**:游戏行为零变化(RNG 流名 reward_pick 与消费序零漂移、信号顺序契约冻结、同种子逐位一致);gdstyle 基线禁改(类变量计数下降属改善);怪物寻址 resolve_enemy_rowset 调用面与关卡参数档装配零变化(未来关卡主题的数据缝不堵)。
@@ -158,6 +164,10 @@
|---|---|---|---|---|
| **D1 HUD**(呈现面拆分持续换代:组合根 main.gd + 三屏壳(MenuScreen/CampScreen/AdventureScreen)+ views/ 视图单元(现行承载面见「呈现层装配与会话生命周期」节;早期 9 单元清单与 LevelStripView 已随场景换代退役);营地覆盖层=四柜台并排〔树淬炼主界面/锻造工坊·秘宝匣钥匙门/图鉴常开——迭代 21 T6 程序占位重排〕) | 全部 Control/CanvasLayer(例外:BoardView 棋盘本体与 BattleStageView 站桩本体 = Control 壳 + SubViewportContainer + SubViewport + Node2D 世界〔BoardWorld/CellUnit;StageWorld/StandeeBody——B 区 slot_row 伴随件留壳层〕,探针契约面不变——棋盘 Node2D 迁移批 Phase A 2026-09-23 / 战斗舞台 Phase B 2026-09-26)、输入→意图翻译(**唯一提交路径 = settle_batch,不直调 A3**)、呈现义务状态记录(A2×6 / B2×4 / B3×4 / B4×5 / B1×3) | 视图单元接口(信号外发、setter 只读注入) | A2 compute_move_path / ActionOutcome;A3 ap/rap;B1 步骤流行协议(数据源);ConfigDB display_name | **MEDIUM**:Control / CanvasLayer / draw_* / InputEvent / RichTextLabel——对照 breaking-changes.md 4.5–4.7 条目(CanvasItem 线条无抗锯齿羽化、设备 ID 常量、RichTextLabel 图片参数两轮变化) |
| **组合根拆件**(呈现侧写口子件:curio_interact_controller / camp_shop_presenter / treasure_interact_controller) | 代组合根执行核心写调用(冒险节点后续推进/营地购买与刷新/道具使用——依赖与回调由 main 构造注入) | 各拆件的写入口(仅组合根装配面可达;视图零直连) | 构造注入的核心写引用(推进/商店/道具各域——详见各拆件头注) | 无 |
| **ui_registry**(`presentation/ui_registry.gd`,界面注册面,2026-10-29 零豁免裁设计闭合——实现批建件) | 呈现层接口面唯一承载:层序合同(LAYER_CONTRACT)迁驻与合同寻址、三域句柄容器 ui_screens(9 屏壳与覆盖层句柄)/ui_battle(5 战区句柄)/ui_modals(13 模态句柄+ModalFlow);组合根经其一级寻址接线,探针挂载假设迁移为 `main.ui.<域容器>.<句柄>`;七个探针别名/转发成员随批消灭 | 三容器属性+合同寻址口(RefCounted 门面,不挂树、零会话期引用) | 构造注入:三屏壳、覆盖层、战区句柄、ModalFlow(main_ui_build 交付随之改型) | 无(RefCounted) |
| **board_hover**(`views/board_hover.gd`,悬停预承诺呈现域件,尾波清偿批 D2 设计闭合——实现批建件) | 悬停反馈域唯一承载(自 board_view 收编 11 函数族+_hover/_last_click 两成员):三语义光标、目标格边框、BFS 路径预览、chord 双击首遇锚;_r0 出生展开区成员留宿主 | 构造=引用束注入(cells/minesweeper/diggable 引用+光标写入与 hover_forbidden 注入回调);三入站口留宿主委托;hover_probe 读面留宿主 | board_view(宿主);输入事件经宿主入站口 | 无(RefCounted) |
| **cell_base_layer/cell_mark_overlay**(`views/`,单格两绘制域件,2026-10-29 设计闭合——实现批建件) | 单格绘制域拆分(自 board_cell_unit 状态件 `_CellPaintState` 收编,入参与该层绘制命令同件):基座层(底面/描边/立面/投影/接触带/倒角,12 成员)与标识叠加层(标记/字形/徽章/封印/点迹/高亮/退色,13 成员);宿主 _draw 退为六步时序器,类变量 30→10 | 构造注入;绘制命令由宿主 _draw 按层序调用 | board_cell_unit(宿主);gdstyle 键各文件独立计数(12/13 均 ≤15) | 无(RefCounted) |
| **standee_vitals/standee_motion**(`views/`,站桩两状态件,2026-10-29 设计闭合——实现批建件) | 站桩状态域拆分(自 `_StandeeState` 真实 25 成员收编):身份命值(hp/atk/状态值族,12 成员)与资产演出(动作/姿态/位移演出族,11 成员);三个演出探针计数器留宿主,宿主类变量 19→10 | 构造注入;st(沿用)/mo 两实例由宿主持有 | standee_body(宿主);battle_stage_view 写入面逐字保持 | 无(RefCounted) |
| **HudPresenter**(`presentation/hud_presenter.gd`,迭代 37 加注) | 战斗屏**数据投影+文案拼装静态族**——核心状态→呈现文案的全部翻译集中于此(B/C/D 区文案与投影),静态无状态 | `refresh(…)` 全量重查装配(组合根每次动作/结算返回后调用,漏调即陈旧呈现)+只读静态投影族 | 核心读取只走 `settlement.presentation_snapshot()` 成文快照面(禁链式穿透结算内部);ConfigDB display_name | 无(RefCounted 静态) |
| **board_resolvers**(`presentation/board_resolvers.gd`,迭代 37 拆出) | 棋盘每格渲染数据的只读解析回调四函数(奖励徽章身份——挖掘期 Active 相位内、地形变异数字遮蔽与角标、调试加成生效值)——有态绑定件,与无态静态投影族 HudPresenter 职责互斥 | 构造注入 db、调试浮窗与结算活态取值,产出绑定 Callable 供组合根接线 | ConfigDB / DebugOverlay / 结算活态取值 Callable | 无(纯投影) |
| **main_ui_build**(`presentation/main_ui_build.gd`,迭代 37 拆出) | `_build_ui` 八步拆分件——组合根 UI 装配分步承接(三屏壳实例化、视图句柄接线、覆盖层装配与模态编排注入按步拆开);main 侧留同名薄委托,装配序与 z 序零改动 | 分步静态函数(成员访问经 root 显式传入) | 层序逻辑不在此件——唯一事实源仍是 `main.LAYER_CONTRACT` + `_apply_layer_contract()` | 同 D1(Control 装配面) |
@@ -180,7 +190,7 @@
### 三屏壳与组合根句柄面
- 呈现场景拆为三屏壳:MenuScreen(开始菜单屏)/CampScreen(营地屏)/AdventureScreen(冒险屏——内含关卡地图与战斗两容器)。
- 屏成员经组合根 main.gd 一级句柄暴露(探针挂载假设 `main.X` 路径零迁移;**S13 豁免登记 2026-10-27:组合根类变量面即探针契约面——约 46 个句柄成员被探针挂载假设钉死,max-class-variables 对本件按架构契约豁免(键永久基线内、禁再恶化),豁免理由在册本节,禁为清键改写探针挂载契约**);局态一律住 RunScope 节点,禁在屏/视图侧持有局态引用。
- 屏成员寻址自实现批起迁经界面注册面(**2026-10-29 零豁免裁+注册面设计闭合——实现批建件**):探针挂载假设 `main.X` 迁移为 `main.ui.<域容器>.<句柄>`(ui_screens/ui_battle/ui_modals 三域容器,约 867 处探针与系统测试引用随批改址);原 S13 豁免登记〔2026-10-27「组合根类变量面即探针契约面」〕注销;main.gd 类变量 49→15,注册面形态见「模块归属·呈现层」表 ui_registry 行;局态一律住 RunScope 节点,禁在屏/视图侧持有局态引用。
- **组合根拆件**=组合根构造注入、代组合根执行核心写调用的呈现侧子件(现行三件:curio_interact_controller/camp_shop_presenter/treasure_interact_controller——冒险节点后续推进、营地购买与刷新、道具使用)。视图禁直连拆件;核心写调用的可达路径仍是「视图→信号→组合根(含拆件)→核心」,依赖规则与组合根单点装配不变。成员见「模块归属·呈现层」表。
### 视觉层装配合同
@@ -228,14 +238,14 @@
| **run_system_test**(系统测试运行器) | `tools/run_system_test.py` | 系统测试总入口:headless 跑真实玩法路径断言面(宿主=`res://tests/system_test.gd`)+ 三闸判定(口径同 run_smoke,摘要行兼容两种宿主格式) | 进程退出码(0=PASS / 1=FAIL) | 三闸齐备(同 run_smoke:退出码/摘要失败数/脚本错误扫描;wall-clock 超时在位) |
| **run_all**(单元与集成测试) | `game/tests/run_all.gd` | 64 套统一入口(61 单元+3 集成,2026-10-28 实数):套件 manifest 逐条「套件 → 期望退出码」,致命类 expect=1 独立子进程实跑;`negative` 字段标负面套件(仅豁免错误扫描一闸);选跑态 `--only=<词[,词…]>`(直跑形态对套件路径子串匹配只跑命中套件,零命中=用法错 quit(2),仅供开发期最窄确认——不产闸回执、不作验收凭据,批末全量闸不经选跑分支) | 逐套件结果 + 汇总退出码(任一套件失败 quit(1)) | 套件级退出码协议在位;三硬闸齐备(入口内扫子套件输出 + 编排层扫 `unit.log`;`Kit.finish` 零断言返回专用码 2)。子进程输出须经系统命令解释器重定向落盘再读——`OS.execute` 的输出管道在本机恒空 |
| **probe_gate**(场景探针) | `tools/probe_gate.sh` | headless 场景探针段编排:默认段 ui_input_probe / ui_struct_probe / layout_probe / ui_contrast_probe / **screen_flow_probe**(屏壳切换),`--click` 加跑 ui_click_probe,`--full` 加跑 ui_probe / ui_tune_probe / t17_defer_probe / fx_probe;孤儿 Godot 预清 + 批末残留清点(必须 0) | 段级 FAIL 输出 + 汇总退出码 | 每段 timeout 守卫在位(挂死 124/137 = FAIL,不静默);判定统一走 `verdict` 函数——退出码为唯一权威判据,PASS 串降级为附加判据,逐段跑 `tools/error_scan.py` |
| **render_gate**(视觉 golden) | `tools/render_gate.sh` | 窗口化渲染闸:①shot_probe 七屏截图 → shot_checker A-D 语义断言;②fx_shot_probe / board_shot_probe 取证(超时/零字节/文件缺失任一 = FAIL);③棋盘 golden 逐像素容差比对(差 ≤16 / changed ≤2%,provisional)+ 菜单 golden;④批末孤儿残留清零 | 段级 FAIL 输出 + 汇总退出码 | 查退出码在位(每段 timeout 守卫 + 退出码/取证文件双检);**SCRIPT ERROR 扫描缺失**;断言数下限不适用(判定主体 = golden 容差与取证文件存在性,非断言计数) |
| **render_gate**(视觉 golden) | `tools/render_gate.sh` | 窗口化渲染闸:①shot_probe 七屏截图 → shot_checker A-D 语义断言;②fx_shot_probe / board_shot_probe 取证(超时/零字节/文件缺失任一 = FAIL);③棋盘 golden 逐像素容差比对(差 ≤16 / changed ≤2%,provisional)+ 菜单 golden;④批末孤儿残留清零;⑤三段探针日志逐段脚本错误扫描 | 段级 FAIL 输出 + 汇总退出码 | 查退出码在位(每段 timeout 守卫 + 退出码/取证文件双检);SCRIPT ERROR 扫描在位(逐段 `tools/error_scan.py`,标记与 run_smoke 同源);断言数下限不适用(判定主体 = golden 容差与取证文件存在性,非断言计数) |
| **static_scan**(静态扫描域) | `game/tests/static_scan.sh` | 静态扫描域 S1–S10 可执行载体(grep 规则 + `tools/audit_type_hints.py`〔S9〕+ `tools/audit_file_headers.py`〔S10〕) | fail 聚合退出码(任一硬失败规则命中即 exit 1) | 查退出码在位;SCRIPT ERROR 扫描与断言数下限不适用(逐规则命中即红,无运行时错误面与断言计数);S3 现为 warning 级、不参与 fail 判定(见下表) |
### 改动域划分(2026-10-17 用户裁「代码批只跑代码闸、文档批只跑文档闸」)
| 域 | 闸 | 本批改动落在这些路径即属该域 |
|---|---|---|
| **代码域** | run_smoke、run_system_test、run_all、probe_gate `--click`、probe_gate `--full`、render_gate、static_scan、回放确定性对拍(条件件) | **唯一触发=`game/` 下非 `.md` 的行为载体**(代码、测试脚本、探针、场景、数据表、素材)。`game/` 内的 `.md`(README、生成清单)归文档域——2026-10-26 用户裁:判据按文件性质,不按路径前缀。2026-10-18 用户裁「跨领域执法禁绝」(提交 `7bdf53e3`)后,原 `tools/`、`artwork/` 两前缀不再把改动拉进代码域 |
| **代码域** | run_smoke、run_system_test、run_all、probe_gate `--click`、probe_gate `--full`、render_gate、static_scan | **唯一触发=`game/` 下非 `.md` 的行为载体**(代码、测试脚本、探针、场景、数据表、素材)。`game/` 内的 `.md`(README、生成清单)归文档域——2026-10-26 用户裁:判据按文件性质,不按路径前缀。2026-10-18 用户裁「跨领域执法禁绝」(提交 `7bdf53e3`)后,原 `tools/`、`artwork/` 两前缀不再把改动拉进代码域 |
| **文档域** | gdd_lint、doc_link_audit、doc_term_audit、流水线闸 | `game/` 内的 `.md` 与 `game/` 外的一切路径:`design/`、根规则文件(`AGENTS.md`/`roadmap.md`/`待办清单.md`/`体验验证清单.md`)、`tools/` 工具脚本、`.zcode/` 配置、`sim-data/`、`reports/` |
| **两域都含** | repo_structure_audit(熵增闸:顶层目录/根文件/图像白名单/退役路径/design 子目录五查——文档批新增或挪动 `.md` 同样会绊它;纯文本扫描秒级) | — |
@@ -257,7 +267,7 @@
| 硬闸 | run_smoke | run_system_test | run_all | probe_gate | render_gate | static_scan |
|---|---|---|---|---|---|---|
| **退出码优先** | 已落实(闸①) | 已落实(闸①,口径同 run_smoke) | 已落实(套件 manifest expect 协议) | 已落实(`verdict` 函数逐段判退出码,PASS 串不作判据) | 已落实(段级退出码 + 取证双检) | 已落实(fail 聚合退出) |
| **SCRIPT ERROR 扫描** | 已落实(闸③,外部扫描——GDScript 无脚本错误陷阱 API,闸设在外部包装) | 已落实(闸③,标记清单与 run_smoke 同源) | 已落实(入口内扫子套件输出;子进程的 stdout/stderr 须先落盘——`OS.execute` 管道在本机恒空) | 已落实(逐探针段 `tools/error_scan.py`,标记与 run_smoke 同源) | **缺失**(本批未收——判定主体是 golden 容差与取证存在性;登记待办清单) | 不适用(静态域无运行时错误面) |
| **SCRIPT ERROR 扫描** | 已落实(闸③,外部扫描——GDScript 无脚本错误陷阱 API,闸设在外部包装) | 已落实(闸③,标记清单与 run_smoke 同源) | 已落实(入口内扫子套件输出;子进程的 stdout/stderr 须先落盘——`OS.execute` 管道在本机恒空) | 已落实(逐探针段 `tools/error_scan.py`,标记与 run_smoke 同源) | 已落实(三段探针日志逐段 `tools/error_scan.py`,标记与 run_smoke 同源) | 不适用(静态域无运行时错误面) |
| **断言数下限** | 无独立下限(闸②摘要行必须在案,防「跑一半仍 PASS」;脚本错误吞断言路径由闸③兜住) | 同 run_smoke(过渡期宿主摘要行必须在案) | 已落实(`Kit.finish` 零断言返回专用退出码 2——与「断言失败=1」区分,防致命类套件的 expect 协议放过) | 已落实(退出码 0 但无该探针签名标记亦判红——防静默退出) | 不适用(golden 容差 + 取证存在性判定) | 不适用(逐规则命中判定;另有扫描面为空即判红的零命中自检) |
背景事实(run_smoke 头注在案):GDScript 运行时脚本错误不改进程退出码、不计入冒烟失败数、且静默中断所在函数剩余断言——2026-09-19 状态记录 83 实证「309 项 0 失败」实为断言未跑全。这是 SCRIPT ERROR 扫描必须存在于判定层的原因。
@@ -308,9 +318,11 @@
本节为测试域(测试载体、判定口径、静态扫描域)的事实源。新增违规案例仍须先补 static_scan 规则再修码(code-conventions 缺陷-规范对照表纪律)。
**S13 测量面豁免登记(2026-10-27)**:`game/presentation/tune_sim_controller.gd` 的循环内 `await`(测速循环逐帧让出)是调参测量的 wall-clock 步进承载语义——重构即测量口径漂移,违行为零变化红线。该键按架构豁免(键永久基线内),豁免理由在册本段;同件 `print` 残留不豁免(信息已由 toast/JSONL 承载,随全清批删除)。
**S13 测量面豁免注销(2026-10-29 零豁免裁)**:原循环内 `await` 豁免〔2026-10-27〕注销——tune_sim_controller 改 process_frame 信号常驻连接+步进状态机(每帧一局、帧相位逐点对齐,设计闭合、实现批建件);随批申报行为改动一处:运行态收尾由「每局置假」还原为「整批收尾单次置假」(消除与 wd8/ui_tune_probe 断言面的静态矛盾)。
**S13 豁免登记第三条(2026-10-28 迭代 40 卡①)**:`game/core/battle_orchestrator.gd` 的 max-class-variables 键——宿主保留面为「战斗编排域拆件定稿」节第 1 款锁定的职责承载面(状态机与生命周期、账本读面、attune 族原位、行发射基建、呈现投影),类变量阈值 15 在保留面锁定下不可达,按全清口径第二支臂登记架构豁免(键永久基线内、禁再恶化;实测键账 50→38)。
**S13 豁免第三条注销(2026-10-29 零豁免裁)**:原 battle_orchestrator max-class-variables 豁免〔2026-10-28 迭代 40 卡①〕注销——RoundCycle/BattleFacts 两新件设计闭合(宿主 38→15,实现批建件,见「战斗编排域拆件定稿」节轴丁)。
**gdstyle 计数截断缺陷登记(2026-10-29 两设计批独立实证)**:gdstyle v0.4.0 对文件内 inner class 的成员计数存在截断——内嵌类中带行尾注释的属性声明截断其后续成员计数(standee_body 实测 31 声明仅记 19、board_cell_unit 33 仅记 30)。基线登记值属欠估;闸机扫描与基线同源、判定口径自洽不误报,债的真值以实查为准——零豁免各批按真实口径设计(实数低于阈值,不依赖解析缺陷)。登记待办:向 gdstyle 上游报 issue。
---
@@ -346,7 +358,7 @@ D1 ◀──呈现数据源:A2 事件流 / B1 步骤流 / A3 ap-rap / ConfigDB
### 3. 存档/读档路径
- 存档系统已实装:格式、三槽位、断点域与迁移链的现行契约以 `design/gdd/systems/表现与支撑/存档序列化.md`(owner)为准。
- RNG 快照契约(现行仍成立):断点续玩回填 = master_seed + 各流 scope 计数器;快照切出须发生在无正在执行中的 open_stream 实例时(scope 事件边界外——B1 编排保证:切点 = board install 边界);SCHEMA_VERSION 高版本拒读。
- RNG 快照契约(现行仍成立):断点续玩回填 = master_seed + 各流 scope 计数器;快照切出须发生在无正在执行中的 open_stream 实例时(scope 事件边界外——B1 编排保证:切点 = board install 边界);SAVE_FORMAT_VERSION 高版本拒读。
### 4. 打包与字体(CJK 随包发行)
+1 -1
View File
@@ -54,7 +54,7 @@
## 3. 测试纪律
已独立成文:`design/engineering/test-conventions.md`(探针标配 / 回归断言 / 提交前全量验证 / 验收清单落码规范)。
已独立成文:`design/engineering/test-conventions.md`(探针标配 / 回归断言 / 提交前验证 / 验收清单落码规范)。
---
+4 -2
View File
@@ -67,8 +67,10 @@
| 一页纸节点 | 一节、一条规则 ≤一页纸(约 ≤80 行);装不下就拆节 |
| 一系统一文档 | 不建 analysis 推演件;两三句能说清的"为什么"直接写进设计目的或规则正文 |
| 正文只写现行规则 | 禁删除线、"(作废)"、"(日期+拍板)"式注记;审计信息入对应文档附录 |
| 禁实现内容 | 系统文档与概念文档全文禁写实现细节——代码路径(`.gd`/`.py`/`.sh` 与运行时文件路径)、测试文件名、断言名、类名/方法名/信号名/常量名/调试与遥测入口名、提交号一律不出现;唯一例外=数据索引(`game/data/tables/*.tres` 这类表路径与表名、表字段名与表内枚值、存档键、封闭词表标签)。实现事实归 `architecture.md`;验收标准只写玩家或系统可观测面。本行由文档域闸的能力审计机检两个可判死的面(带后缀路径、反引号调用形态),其余靠写卡段人工核对;闸件清单与域划分的唯一出处=`tools/run_all_gates.sh` 头部 |
| 正文单点维护 | 一条规则句只写在定义它的那份文档(owner 文档);其他文档要引用时写指针或语义概括,禁复制色值、尺寸、路径等可核对的具体值——上一句管不住数值之外的双写,本句补上。豁免面 = 执行侧文件必须带字面值才能工作时(生图提示词里的十六进制色、脚本参数),转写不算双写,但该文件头部必须写明"冲突时以 owner 文档为准" |
| 禁写变更记录 | 文档与代码文件内一律禁设「版本历史/修订记录/变更记录/修改记录/更新记录/更新日志」节或表格,禁逐版本叙述「改了哪些条款」;沿革与改动明细只进 git commit log。版本号可作为文档现行身份标记出现在文首状态行与正文引用中,但不得再挂变更表 || 后置 ≠ 删除 | P1/P2 后置内容逐条列出;复活后置项 = 修订文档,禁静默加回 |
| 禁写变更记录 | 文档与代码文件内一律禁设「版本历史/修订记录/变更记录/修改记录/更新记录/更新日志」节或表格,禁逐版本叙述「改了哪些条款」;沿革与改动明细只进 git commit log。版本号可作为文档现行身份标记出现在文首状态行与正文引用中,但不得再挂变更表 |
| 后置 ≠ 删除 | P1/P2 后置内容逐条列出;复活后置项 = 修订文档,禁静默加回 |
| 活体清单不冻结计数 | 对会生长的清单(文档树构成、UI 层项、RNG 流词表等)不写死计数与枚举——写指针到 owner(根索引/常量表/实现文件),现状值由 owner 承载;历史计数只进 git 提交信息 |
**数值纪律**:正文定规则、取值域、单位;平衡值进 `data/tables/`,provisional 必须标注;已锁数值事实源 = `game/data/tables/*.tres`(现行值)与 owner 文档正文(规则、取值域、单位)。
@@ -96,7 +98,7 @@
| `待办清单.md`(仓库根) | 流水线唯一登记处:条目=登记元数据标题+四属性正文,状态随流水线段推进(格式与状态机见第 12.1 节);各系统文档「待办」节只留指路存根 |
| `roadmap.md`(根目录) | 里程碑表+迭代总表,一行一迭代,记录编排与实现进度(六列格式见第 12.2 节) |
**系统文档骨架**(`systems/` 下统一采用):文首引言(一句话定位+状态)/设计目的(2-4 句白话)/系统范围(负责/不负责两表)/在核心循环中的位置(字符画一行+两句白话)/核心规则(领域章节 ×2–6,每节一页纸)/依赖与输出(表格;引用纪律见 concept-conventions)/P0 最小闭环与 P1·P2 后置/调参表(取值域+provisional 标注)/验收标准(可验证判据)/待办(指路存根)。
**系统文档骨架**(`systems/` 下统一采用):文首引言(一句话定位+状态)/设计目的(2-4 句白话)/系统范围(负责/不负责两表)/在核心循环中的位置(字符画一行+两句白话)/核心规则(领域章节 ×2–6,每节一页纸)/依赖与输出(表格;引用纪律见 concept-conventions)/P0 最小闭环与 P1·P2 后置/调参表(取值域+provisional 标注)/验收标准(玩家或系统可观测的判据,禁实现细节)/待办(指路存根)。
**命名**:中文、见名知意;禁 a1_/b1_ 编号前缀;不留纯空目录。正文指代子系统一律用中文规范名;英文代号对照表见 `02-系统清单.md`,旧代号(a1–d6)仅限解读归档。
+2 -2
View File
@@ -48,10 +48,10 @@
7. **验收改动先行声明**——验收变化(基线换代/探针增改/旧断言改判)预先写进需求卡片,禁事后补
**完成**
8. **批末按域验收才合并(worktree 批;直改车道无批末动作,验收在 commit 点由 git 钩子执行,见 §1 第 3 条)**——在任务 worktree 内跑 `tools/run_all_gates.sh`,**按本批改动域选档**:按文件性质判——代码面=`game/` 下非 `.md` 的行为载体(代码、测试脚本、探针、场景、数据表、素材)→ `--code`;文档件=`game/` 内 `.md`(README、生成清单)与 `game/` 外一切路径(`design/`、根规则文件、`tools/` 工具脚本、`.zcode/` 配置等)→ `--docs`;两类同批都有 → 全量档不带参数。所选域全绿才合回 master。合回前独立验收审计通过(iter 技能第 5 步),未过不合回。该脚本是全部验证闸的**唯一入口、唯一清单与唯一域划分**,闸件增减、分域调整都只改它;**本文与其他文档禁另列闸件清单**(清单散落多处正是 iter27 漏跑 `probe_gate --full` 的成因)。跑完写回执 `game/tests/.gates/receipt.json`(含 `domain` 与 `dirty_game` 字段),合回时由 worktree-guard 按 diff 文件性质推域强制校验(六况拦截:缺回执/quick 模式/回执未覆盖分支尖=回执 commit 之后代码面又有改动、或跑闸时代码面带着未提交改动(`dirty_game`)/域不覆盖本次改动/含新增红/master HEAD 非回执 commit 祖先=合并将产出未测内容)。回执与分支尖的对齐判据是**代码面**不是 commit 号:回执之后只追加文档件(`game/` 内 `.md`、`reports/`、`design/` 等)提交,回执照样有效,不构成复跑理由。闸件(`tools/` 下机检脚本与闸壳)自身的改动不占合回全量——其质量义务=落批时人工确认闸可跑通且判据口径未变,闸真崩溃时合回闸 fail-closed(跑不出回执即拦),不以合回全量为兜底
8. **批末按域验收才合并(worktree 批;直改车道无批末动作,验收在 commit 点由 git 钩子执行,见 §1 第 3 条)**——在任务 worktree 内跑 `tools/run_all_gates.sh`,**按本批改动域选档**:按文件性质判——代码面=`game/` 下非 `.md` 的行为载体(代码、测试脚本、探针、场景、数据表、素材)→ `--code`;文档件=`game/` 内 `.md`(README、生成清单)与 `game/` 外一切路径(`design/`、根规则文件、`tools/` 工具脚本、`.zcode/` 配置等)→ `--docs`;两类同批都有 → 全量档不带参数。代码域按**关联档选测**(2026-10-29 用户裁):02 单元与集成只跑「需求卡片申报 ∪ diff 推导」并集的套件——申报=在册需求卡片对照表「验收测试」列提到的测试文件名,推导=闸脚本内套件族映射表按改动文件归族;改动命中公共件/数据表/autoload/数值·存档·RNG·结算触面或映射不到 → 横切回落全部套件;00 冒烟/01 系统测试/09 静态扫描三件保险恒跑不降;03 场景探针与 05 渲染闸维持影响面口径(本批 game/ 改动全在测量面 game/tests、game/sim 时记 SKIP)。所选域全绿即可合回 master,全量回归由用户自发发起(合入后无自动兜底)。合回前独立验收审计通过(iter 技能第 5 步),未过不合回。该脚本是全部验证闸的**唯一入口、唯一清单与唯一域划分(含选闸算法与套件族映射表)**,闸件增减、分域调整都只改它;**本文与其他文档禁另列闸件清单**(清单散落多处正是 iter27 漏跑 `probe_gate --full` 的成因)。跑完写回执 `game/tests/.gates/receipt.json`(含 `domain`、`scope`(full|related,02 跑子集=related)与 `dirty_game` 字段),合回时由 worktree-guard 按 diff 文件性质推域强制校验(六况拦截:缺回执/quick 模式/回执未覆盖分支尖=回执 commit 之后代码面又有改动、或跑闸时代码面带着未提交改动(`dirty_game`)/域不覆盖本次改动/含新增红/master HEAD 非回执 commit 祖先=合并将产出未测内容;guard 只验域覆盖与全绿,不复核选套件清单)。回执与分支尖的对齐判据是**代码面**不是 commit 号:回执之后只追加文档件(`game/` 内 `.md`、`reports/`、`design/` 等)提交,回执照样有效,不构成复跑理由。闸件(`tools/` 下机检脚本与闸壳)自身的改动不占合回全量——其质量义务=落批时人工确认闸可跑通且判据口径未变,闸真崩溃时合回闸 fail-closed(跑不出回执即拦),不以合回全量为兜底
9. **合并后主区零复跑**(2026-10-24 用户裁:合回重跑验的是与回执同一份字节,零信息)——合回落地后 code 批只做两件秒级事:`--editor --quit` 重刷类名缓存(在册坑:.godot 缓存不入 git,与合并后代码失配会假红假绿)+冒烟启动确认可开机(合计约 1 分钟);docs 批零动作。全量验证**每批跑一次**=worktree 批末按域闸,顺序是「先并入 master、再跑闸」(§1 第 2 条);只有两种情形允许把这次跑作废重来——① 闸红且修法动了 `game/`,② 闸已开跑后 master 又被推进(合并将产出未测内容,由合回闸祖先判定拦下,§3.9 第六况)。「跑都跑了再跑一遍保险」「闸后顺手改点 `game/` 再补一跑」都不构成复跑理由;master 上永不跑全量
10. **批次完成后的登记义务**——合回 master 后按 doc-conventions §12.1 推进待办清单条目状态(做完整条删除),涉及迭代编排的在 roadmap 迭代总表与顶部「当前位」节换代——执行入口=项目技能 batch-closure(批后收尾与中间文档退役),跨会话教训写记忆库。批次过程与结论由 git 提交信息承载,禁止再写会话状态文件(见 doc-conventions 第 10 节)。`design/` 与根规则文件(`AGENTS.md`/`roadmap.md`/`待办清单.md`/`体验验证清单.md`)实现批禁写,见 §12
11. **文档同步闸(实现批禁写文档)**——实现批**禁写 `design/` 整个目录与根规则文件**,要往外交代的东西一律落 `reports/`:实现报告 `reports/iter<N>-实现报告-<日期>.md`(各卡状态+实机目检总清单+遗留读数义务+实现决定记录——超白名单/超卡片明列范围事项逐条记「决了什么/为什么/代价/撤销方式」,全部按卡执行时只写一行「零拍板」)、GDD 反哺点清单 `reports/iter<N>-反哺点-<日期>.md`(每条写清哪个文件哪一节、改成什么、依据是什么)。设计权威文档(GDD/art-bible)**任何批都不直改**:用户在会话中逐点裁决后,由工程/文档设计改动批(直改类)写入 `design/`(执行入口=doc-design 技能),并把反哺条目从 `reports/` 清掉(吸收即死;退役执行=batch-closure 技能)。机械面文档(roadmap 行/术语表/README 工具注)同样归工程/文档设计改动批在合并前更新。反哺点未落地期间相关 GDD 节视为待反哺,读前先查 `reports/` 与待办清单;需求卡片必列「关联文档同步面」按两层标注
11. **文档同步闸(实现批禁写文档)**——实现批**禁写 `design/` 整个目录与根规则文件**,**另禁写 `game/tests/README.md`(能力清单,归写卡段维护,test-conventions §8.9)**,要往外交代的东西一律落 `reports/`:实现报告 `reports/iter<N>-实现报告-<日期>.md`(各卡状态+实机目检总清单+遗留读数义务+实现决定记录——超白名单/超卡片明列范围事项逐条记「决了什么/为什么/代价/撤销方式」,全部按卡执行时只写一行「零拍板」)、GDD 反哺点清单 `reports/iter<N>-反哺点-<日期>.md`(每条写清哪个文件哪一节、改成什么、依据是什么)。设计权威文档(GDD/art-bible)**任何批都不直改**:用户在会话中逐点裁决后,由工程/文档设计改动批(直改类)写入 `design/`(执行入口=doc-design 技能),并把反哺条目从 `reports/` 清掉(吸收即死;退役执行=batch-closure 技能)。机械面文档(roadmap 行/术语表/README 工具注)同样归工程/文档设计改动批在合并前更新。反哺点未落地期间相关 GDD 节视为待反哺,读前先查 `reports/` 与待办清单;需求卡片必列「关联文档同步面」按两层标注
12. **实机目检归用户,只登记不阻塞**——真人检测项登记进实现报告目检总清单与体验验证清单即完成批内义务;禁把等目检当停工理由或完成前置
13. **中间产物吸收即死**——细则见 AGENTS.md 硬性红线与 doc-conventions 第 11 节
14. **改动级验收闭合**——写卡期列需求侧对照表,实现期补实际对照表(测试文件:行),每个行为改动的验收断言从真实入口进入、在当轮真实跑批中执行并通过(判据绑定面口径=test-conventions §8.4;禁变异类测试与撤销类取证,2026-10-24/28 用户两裁);合回前独立验收审计。细则=test-conventions §8
+28 -5
View File
@@ -25,9 +25,9 @@
每个缺陷修复必须在探针或冒烟中留下能抓住该缺陷的断言(例:封印动作耗尽 AP → 必须进入第 2 轮;
选用道具 → 库存态必须变 Used)。没有回归断言的修复视为未完成。
## 4. 提交前全量验证
## 4. 提交前验证
交付前跑 `tools/run_all_gates.sh`(不带 `--quick`)全绿——该脚本是全部验证闸的唯一入口与唯一清单,本文禁另列闸件清单。闸件增减只改脚本。
交付前跑 `tools/run_all_gates.sh`(不带 `--quick`),按改动域选档、所选域全绿——该脚本是全部验证闸的唯一入口与唯一清单,域划分与选闸算法只写在脚本里,本文禁另列闸件清单。闸件增减只改脚本。代码域按**关联档选测**(2026-10-29 用户裁):02 单元与集成只跑「需求卡片申报 ∪ diff 推导」并集的套件,00 冒烟/01 系统测试/09 静态扫描三件保险恒跑不降,横切面改动(公共件/数据表/autoload/数值·存档·RNG·结算触面)回落全部套件;所选域全绿即可合回,全量回归由用户自发发起(合入后无自动兜底)。
行为探针使用随机化玩家行为(封印/停手/刷新/无效点击)——自动玩家不做的动作就是测试盲区。
## 5. 测试函数怎么写——验收清单条目的落码规范
@@ -35,7 +35,7 @@
需求卡片 §8「改动—验收对照表」每一条都要落成可执行的验证;本文定统一写法,卡里定每批的具体内容(测什么/注入哪里)。写卡期查不出执行载体的条目=不可测,当场呈报,禁拖到实现期。
1. **执行载体五选一,逐条声明**:单元测试(`tests/run_all`)/系统测试断言(`tests/system_test.gd`)/场景探针(`probe/` 下 `*_probe`)/MC 同种子逐项比对/人工核对(仅限无法自动化的纪律类需求点,如命名锁定、数值占位)。行为类条目以自动化载体为主。
2. **粒度与对应关系**:每条清单条目至少一个自动断言,且断言必须从该条目的真实入口进入;多条条目可合用一个测试函数,但撤销对应改动时每条都要能单独变红。断言失败消息末尾带编号尾缀〔卡短名 Vn〕(如〔秘宝批 V3〕)——断言与卡片清单可互相 grep 查找。**工具面局限备案(2026-10-27 迭代 39 验收审计)**:`Kit.check_quiet` 静默收集形态(计数不入判定即打印、失败消息进 problems 汇总)的断言消息不进 `tools/extract_checks.py` 扫描面——验收尾缀 grep 对该通道失效;如需覆盖属提取器改版(工程批)。
2. **粒度与对应关系**:每条清单条目至少一个自动断言,且断言必须从该条目的真实入口进入;多条条目可合用一个测试函数,但每条都要有自己单独可判红的判据(取证口径见 §8.4 唯一口径——禁变异/禁撤销)。断言失败消息末尾带编号尾缀〔卡短名 Vn〕(如〔秘宝批 V3〕)——断言与卡片清单可互相 grep 查找。**工具面局限备案(2026-10-27 迭代 39 验收审计)**:`Kit.check_quiet` 静默收集形态(计数不入判定即打印、失败消息进 problems 汇总)的断言消息不进 `tools/extract_checks.py` 扫描面——验收尾缀 grep 对该通道失效;如需覆盖属提取器改版(工程批)。
3. **断言词汇按验证对象五选一**:
| 词汇 | 适用场景 |
@@ -67,7 +67,7 @@
- 「跑一遍没崩=通过」无效:测试绿只证明**当前代码没犯这个错**,不证明**犯了这个错会被抓住**;断言存在不等于断言执行。
- **脚本错误会静默中断所在函数的剩余断言,而套件仍报全绿**(机制事实):GDScript 无脚本错误陷阱 API,错误不改进程退出码、不计失败数。三处实证:①2026-09-19「309 项 0 失败」实为断言未跑全(状态记录 83);②敌人表行集纪律 10 条断言因定型数组赋值错误从未执行(迭代 29 修复后两条正向见红=夹具本缺锚行);③`Callable` 形参类型写错致解析函数返回 null、后续断言整段蒸发。
- 由此产生两条义务:**写闸件**按 §6 配三硬闸;**写验收函数**必须自证断言全数执行——真实入口断言在当轮执行并通过(§8.4)为主证,零命中自检(扫描面为空即判红)为辅证。
- **覆盖率不是目标**:行覆盖率度量缺失(Godot 无内建,第三方属新基建,是否引入待办清单在册待裁);现行补洞=零指名单测清单+人工判定,判定可靠性靠上列自证手段,不靠覆盖率数字。
- **覆盖率不是目标**:不引入行覆盖率度量(Godot 无内建,第三方属新基建);现行补洞=能力清单覆盖域表+人工判定,判定可靠性靠上列自证手段,不靠覆盖率数字。
## 8. 改动级验收闭合(2026-10-21 立)
@@ -97,7 +97,7 @@
- **反向**:diff 里每个行为改动至少一行;没有对应行的改动,必须写明「非行为改动」或「由第 X 行覆盖」。
- **测试侧**:新增或改写的每条断言至少挂一行;挂不上的孤儿断言删掉或补挂到需求点。
**能力清单维护锚(2026-10-28 用户裁,验证与清单体系整改阶段 1;阶段 2 后定稿)**:逐断言账本 `game/tests/验证集清单.md` 已随阶段 2「存量断言精简」完成退役——冻结对账基准(基点 `b9260138`/1587 条)与精简对账结果(33 站点并为 7、1587→1561,合回 `87d241c1`)留 git 历史。覆盖索引由 `game/tests/README.md`「能力清单 v1」唯一承担:每行一个能力,给真实入口与 2–3 个代表用例(`文件:函数`)。维护义务——**每批收口核对本批受影响能力行**:代表用例可 grep、在本批真实跑批中执行、真实入口未绕过改动点,并刷新「最后验证批次」;新增能力加行,能力退役删行。改动—验收对照表纪律不变:新增或改写的每条断言仍须挂一行(上文「测试侧」);断言改判仍受 §8.4 真实入口口径约束。
**能力清单维护锚(2026-10-29 用户裁改版定稿)**:`game/tests/README.md`「能力清单」是**实现指导+阅读导航+义务声明**——只宣布「要验证什么」,不记「是否已验证/是否跑过」;落地账归现行验收闭合链(改动—验收对照表逐条挂断言+合回前独立验收审计),本清单不承载验证状态。表为四列:能力|系统|真实入口|代表用例(`文件:函数`)。**维护归写卡段,当场入表**:写需求卡片时,本批新增能力当场写入能力行——真实入口取自设计文档已定的入口,代表用例=卡里定死的计划测试(`文件:函数`);受影响存量行(入口/用例名变更)同批更新;能力退役删行。**实现照单落名**:测试函数名以清单为唯一依据,名实不符=卡片没写清=停卡退回。**收尾核对**:批末收尾只核对表上名字与实际落地一致(改名则回表),不刷任何批次字段;实现批禁写该文件的现行红线不变(process-conventions §3 第 11 条),核对义务归收尾提交。三层模型见 §8.9。改动—验收对照表纪律不变:新增或改写的每条断言仍须挂一行(上文「测试侧」);断言改判仍受 §8.4 真实入口口径约束。
### 8.4 真实入口断言(验收闭合的主判据)
@@ -129,3 +129,26 @@
### 8.8 生效与旧卡
本规自 2026-10-21 起对文件名日期不早于该日的需求卡片生效;旧卡不回头改。旧卡在开工前缺对照表的,由写卡段补,补完再开工。
### 8.9 三层模型(验收意图·义务清单·执行证据,2026-10-29 定稿)
验收体系分三层,各层各管一件事,互不代行:
| 层 | 载体 | 切分轴 | 一行是什么 |
|---|---|---|---|
| 验收意图 | 系统文档「验收标准」节 | 按 owner 文档 | 一条玩家或系统可观测的判据 |
| 义务清单 | `game/tests/README.md`「能力清单」 | 按玩家旅程与系统归属 | 一条待验证义务:能力+真实入口+代表用例(`文件:函数`) |
| 执行证据 | 测试套件断言 | 按代码归属 | 一条从真实入口进入的断言 |
四条法则:
1. **每格非空**:每个系统文档有验收标准节;每个能力行有真实入口与至少一个代表用例;每条断言挂在某个需求点或能力行上。
2. **每条断言有归属**:孤儿断言删掉或补挂;不建无归属断言。
3. **数量不守恒、承接守恒**:三层条数天然不等——一条验收意图可由多个能力承接,一条能力义务由多条断言覆盖。要守的是两个满射:每条验收意图至少有一条能力义务承接,每条能力义务至少有一条真实入口断言落地。数量对账只在批内做,见第 4 条。
4. **无全局对账总账**:不建逐断言账本,不做跨层条数对账;对账只在每批的改动—验收对照表里做(§8.3)。历史教训:阶段 2 退役的逐断言账本正因把义务清单层与证据层压成一本账而失修。
**维护时序(2026-10-29 改版:废「滞后一个迭代」)**:能力清单归写卡段维护——写需求卡片时当场入表:本批新增能力当场增行(真实入口取自设计文档已定的入口,代表用例=卡内定死的计划测试 `文件:函数`),受影响存量行(入口/用例名变更)同批更新,能力退役删行;实现批禁写该文件(process-conventions §3 第 11 条)。实现照单落名:测试函数名以清单为唯一依据,名实不符=卡片没写清=停卡退回。批末收尾只核对表上名字与实际落地一致(改名则回表),不刷任何批次字段——清单不记「是否已验证/是否跑过」,落地账在改动—验收对照表(§8.3)与独立验收审计(§8.7)。
**文档纯度**:验收意图与能力描述只写玩家或系统可观测面,禁写代码路径(`.gd`/`.py`/`.sh`)、测试文件名、断言名;唯一例外=配置文件索引(`game/data/tables/*.tres` 这类表路径与表名)。规则正文见 doc-conventions §5「禁实现内容」。
**机器闸**:本节的结构由文档域闸「能力审计」机检——GDD 纯度(同款禁实现内容口径)、系统文档验收标准节非空、能力行四列与非空、代表用例(`文件:函数`)与真实入口可核(双通道:代码在或卡在——计划中的用例与入口由需求卡片锚定)、覆盖域表与能力行对得上;红项按新增红处理。闸件清单与域划分的唯一出处=`tools/run_all_gates.sh` 头部。
+1 -1
View File
@@ -59,4 +59,4 @@
注意:上表六件秘宝为旧目录,已全数退役、只作素材库(新现行事实源=[秘宝](systems/跨局循环/秘宝.md)「目录(重设计 v1)」节——新目录 15 件为代号制、正式命名归用户);新目录正式命名定稿后本表同步。
另:元进度系统资源定名**钥石**——每一层关底 Boss 看守他那块区域的钥石,击杀即取走,用于在存档内解锁永久提升(属性 / 怪物遭遇 / 道具池)。2026-09-14 用户拍板,registry 术语登记随元进度设计批补登。
另:元进度系统资源定名**钥石**——每一层关底 Boss 看守他那块区域的钥石,击杀即取走,用于在存档内解锁永久提升(属性 / 怪物遭遇 / 道具池)。2026-09-14 用户拍板,登记册术语登记随元进度设计批补登。
+1 -1
View File
@@ -15,7 +15,7 @@
| `术语表.md` | 全库专用术语的唯一对照表——危险格/安全格/同调位/RAP/GP/真视等定义+退役词对照(2026-10-11 建立,v1.23) |
| `待办清单.md`(仓库根,不属本树) | 全项目待办事项的唯一登记处;各系统文档的「待办」节只留指路存根 |
| `体验验证清单.md`(仓库根,不属本树) | 需要真人试玩观测的验证项登记处(与待办清单分工:待办清单是"要拍板的事",本篇是"要玩过才知道的事");每条注明结论回流路径 |
| `08-Alpha版本标准.md` | Alpha 版本包含哪些东西的清单——里程碑 M3 的完成标准;只列条目不写内容,定义一律指路各权威文档(**已定稿 v1.19**,2026-10-13) |
| `08-Alpha版本标准.md` | Alpha 版本包含哪些东西的清单——里程碑 M3 的完成标准;只列条目不写内容,定义一律指路各权威文档(**已定稿 v1.20**,2026-10-13) |
## systems/ 五个循环
+8 -8
View File
@@ -2,7 +2,7 @@
> **一句话定位**:本文定义这个项目的 **Alpha 版本包含哪些东西**——它是里程碑 M3 的完成标准,也是判断"还差什么"的对照表。
> **本文只列条目,不写内容**:每样东西是什么、规则怎么走,一律归各自的权威文档,本文只给指路链接。想知道某样东西的定义,请点链接,不要在本文里找解释。
> **状态**:**已定稿(v1.19)**——2026-10-13 用户令定稿,历次升版明细见 git 提交史。Alpha 的内容范围自此冻结:增删条目一律须经用户裁决。
> **状态**:**已定稿(v1.20)**——2026-10-13 用户令定稿,历次升版明细见 git 提交史。Alpha 的内容范围自此冻结:增删条目一律须经用户裁决。
> **成文**:2026-10-13。
## 本文怎么用
@@ -110,14 +110,14 @@ Alpha 内以玩法循环本身的内容与表现为主(棋盘、关卡、战
| 战斗屏 | [battle](ux/battle.md) | 在役 |
| 战斗结算总结框 | [settlement-summary](ux/settlement-summary.md) | 在役 |
| 关卡结算屏 | [level-clear](ux/level-clear.md) | 在役 |
| 三选一(奖励节点 / 关卡完成) | [node-reward](ux/node-reward.md) | 在役(两渠道均三选一停点:关卡完成与奖励节点各停一次,奖励节点经 present_node_curio 拉起兑付) |
| 三选一(奖励节点 / 关卡完成) | [node-reward](ux/node-reward.md) | 在役(两渠道均三选一停点:关卡完成与奖励节点各停一次,奖励节点经兑付拉起开三选一) |
| 商店 | [shop](ux/shop.md) | 在役 |
| 状态面板(局内) | [元进度](systems/跨局循环/元进度.md)(「解锁界面:双入口框架」节) | 在役 |
| 冒险终局面板 | —— | 在役 |
| 图例面板 | —— | 在役 |
| 设置面 | [设置与本地化](systems/表现与支撑/设置与本地化.md) | 在役 |
| 调试浮窗 | —— | 在役 |
| UI 全局主题资源(引擎原生控件接管皮肤) | —— | 在役(迭代 25 · 2026-10-13 入库:game/assets/theme/main_theme.tres 挂 gui/theme/custom) |
| UI 全局主题资源(引擎原生控件接管皮肤) | —— | 在役(迭代 25 · 2026-10-13 入库:主题资源(theme 主资源)挂 gui/theme/custom) |
| UI 按钮状态矩阵(悬停 / 按下 / 禁用 / 键盘焦点补齐) | [待办清单](../../待办清单.md) | 在役(迭代 26 入库:五态矩阵逐实例 override 补齐——悬停 modulate 提亮/禁用 α0.45 幽灵化/焦点 INK 2px 内缩 1px 环/危险钮本族按压态;键盘导航批量面归 Beta「棋盘战斗键盘/手柄输入」条连带点③) |
---
@@ -128,11 +128,11 @@ Alpha 内以玩法循环本身的内容与表现为主(棋盘、关卡、战
|---|---|---|
| 存档与版本迁移 | [存档序列化](systems/表现与支撑/存档序列化.md) | 在役 |
| 冒险中断续玩断点 | [存档序列化](systems/表现与支撑/存档序列化.md) | 在役 |
| 冒烟套件 | `game/tests/` | 在役 |
| 单元测试套件 | `game/tests/` | 在役 |
| 界面探针 | `tools/probe_gate.sh` | 在役 |
| 渲染闸(截图与黄金图比对) | `tools/render_gate.sh` | 在役 |
| 机器可读的呈现断言(对比度 / 结构) | `game/tests/` | 在役 |
| 冒烟套件 | ——(清单唯一出处=process-conventions 运行与验证节) | 在役 |
| 单元测试套件 | ——(清单唯一出处=process-conventions 运行与验证节) | 在役 |
| 界面探针 | ——(闸件清单唯一出处=process-conventions 运行与验证节) | 在役 |
| 渲染闸(截图与黄金图比对) | ——(闸件清单唯一出处=process-conventions 运行与验证节) | 在役 |
| 机器可读的呈现断言(对比度 / 结构) | ——(清单唯一出处=process-conventions 运行与验证节) | 在役 |
| 分辨率两档(1280×800 / 1920×1080) | [HUD框架](systems/表现与支撑/HUD框架.md) | 在役 |
| 绘制调用数达标 | —— | 在役 |
| 真人试玩轮次 | [体验验证清单](../../体验验证清单.md) | 在役(义务维持;当前轮次未清:㉚/㉛ 未核销,迭代 34 三条目检项待登记) |
@@ -60,7 +60,7 @@
| 不合格产出禁止进玩法 | 产出不过产出规格即无效,无效图绝不上给玩家 |
| 无兜底图 | 不设固定兜底图——软回退一律禁止 |
| 参数无解即中止 | 参数档本身给不出合法图=配置错误,致命中止 |
| 同种子同图 | 同种子+同参数档产出同一张图;随机只经 RngService 统一流 |
| 同种子同图 | 同种子+同参数档产出同一张图;随机只经统一随机流服务 |
### 生成参数:五个旋钮与三套关卡参数档
@@ -104,7 +104,7 @@
## 调参表
数值事实源=game/data/tables(定值批落表);本表只留取值域与设计意图。
数值事实源=data/tables(定值批落表);本表只留取值域与设计意图。
| 参数 | 取值域 | 设计意图 | 状态 |
|---|---|---|---|
@@ -123,7 +123,7 @@ Boss 兑付(胜利或英雄死亡)触发关卡收束点,此后不再有选
第二关的"新内容 = 既有池新技能"(技能池构成已定稿入[敌人系统](../战斗循环/敌人系统.md)技能池节)投放时,改的是战斗侧行里引用的技能池内容——节点图结构原样不动,本文无需为投放留任何新结构位。
**节点奖励 = 提升三选一(迭代 10 追加批——用户 2026-10-01 拍板:与通关三选一共享同池)**:奖励节点到达即开三选一(呈现 = 提升三选一覆盖层共用面,spec:[node-reward.md](../../ux/node-reward.md) v2.0)——从提升池七种(攻击/生命上限/护甲/GP 袋/行动点件/恢复件/刷新件)按同一令牌库洗牌不放回抽 3(同 kind 去重、同 reward_pick 封闭流),玩家点选一件兑付(选中踢池、未选回池;秘宝件已随迭代 11 第①批出池,满位替换子交互随之不再触发)。件获取次数计数与令牌库为冒险级单例——两渠道同一令牌库合计消耗。原「秘宝投放渠道三选一」(迭代 7 拍板②丙过渡形态)顺带退役;秘宝局外同调件形态已随同调实施批落地(迭代 11 第①批;原提案 §9,git 57da58c 已退役)。「池空直通」为合法态——池耗即枯竭,空库 = 零候选合法态直通(见[冒险结构](冒险结构.md)令牌池节)。
**节点奖励 = 提升三选一(迭代 10 追加批——用户 2026-10-01 拍板:与通关三选一共享同池)**:奖励节点到达即开三选一(呈现 = 提升三选一覆盖层共用面,spec:[node-reward.md](../../ux/node-reward.md) v2.0)——从提升池七种(攻击/生命上限/护甲/GP 袋/行动点件/恢复件/刷新件)按同一令牌库洗牌不放回抽 3(同 kind 去重、同一封闭随机流),玩家点选一件兑付(选中踢池、未选回池;秘宝件已随迭代 11 第①批出池,满位替换子交互随之不再触发)。件获取次数计数与令牌库为冒险级单例——两渠道同一令牌库合计消耗。原「秘宝投放渠道三选一」(迭代 7 拍板②丙过渡形态)顺带退役;秘宝局外同调件形态已随同调实施批落地(迭代 11 第①批;原提案 §9 已退役)。「池空直通」为合法态——池耗即枯竭,空库 = 零候选合法态直通(见[冒险结构](冒险结构.md)令牌池节)。
### 关卡收束点:先清库、后宣布
+13 -13
View File
@@ -1,7 +1,7 @@
# 冒险结构
> 一句话:整局冒险的关卡序列、失败与大奖励
> 状态:已定稿(自旧体系迁移);现行为 v1.1
> 状态:已定稿(自旧体系迁移);现行为 v1.3
## 设计目的
@@ -142,17 +142,17 @@ GP(显示名「GP」)是冒险内的一次性属性提升货币:战斗胜
| 收支口 | 方向 | 规则 |
|---|---|---|
| 战斗完成 | 入 | 每完成一场战斗统一到账一次:金额 = 掉落掷定 + 关级掉落加值 + 本战战斗内缓冲,随战斗结束信号携带的 gp_dropped 一笔入账 |
| 战斗完成 | 入 | 每完成一场战斗统一到账一次:金额 = 掉落掷定 + 关级掉落加值 + 本战战斗内缓冲,随战斗结束信号携带的掉落额一笔入账 |
| 商店购买 | 出 | 商店房购买按现行价扣减钱包,余额不足拒绝。价格公式(**v0.13 换代——pool 模式现行**):ceil(基价 × b^(关序−1) × A^(本次进店已购次数)),A=店内递增/b=跨关递增表因子(provisional 1.8/1.1),ceil 向上单一取整(玩家不利向,杜绝「差 1 GP 反复钓」套利角);legacy 固定三件模式(shop=off 对照承载)沿用旧式 = 基价 + 关级价格加成 + 步长 × 已购档数 |
| 冒险收束 | 清零 | 完成 / 失败 / 放弃三种结局都清零;重开后钱包从零开始 |
**战斗内缓冲隔离**:战斗进行中从格面兑付拿到的 GP(GP 袋正向、破财负向——字典归[地图战斗资源](../战斗循环/地图战斗资源.md))不直接进钱包,而是记入战斗域的中间态缓冲;战斗完成时缓冲随掉落掷定与关级加值一并折进 gp_dropped 统一到账。钱包只在战斗边界变动,战斗域自身零钱包状态——这条隔离让战斗结算保持"折算归我、GP 归冒险结构"的既有边界。
**战斗内缓冲隔离**:战斗进行中从格面兑付拿到的 GP(GP 袋正向、破财负向——字典归[地图战斗资源](../战斗循环/地图战斗资源.md))不直接进钱包,而是记入战斗域的中间态缓冲;战斗完成时缓冲随掉落掷定与关级加值一并折进掉落额统一到账。钱包只在战斗边界变动,战斗域自身零钱包状态——这条隔离让战斗结算保持"折算归我、GP 归冒险结构"的既有边界。
**统一冒险加算区**:商店购买的属性提升与奖励节点三选一的属性件记**同一笔**——加算区四轴 {攻击, 生命上限, 护甲等级, 行动点},入战参数 = 基础表值 + 加算区累加,经战斗开始入参的覆盖值通道生效(与生命的上参同一条通道)。购买生命上限时:pool 模式(v0.13——货架件=奖励件本体)只加上限不回当前生命(与三选一件同语义);legacy 模式当前生命与上限同步 +Δ(生命的连带写入口)。属性轴累加源 = 商店购买与奖励节点三选一属性件两类;行动点轴累加源 = 奖励节点三选一 AP 件与商店 AP 件两类(每场战斗开始的首轮行动点基线 +1,语义细节归[行动经济](../排雷循环/行动经济.md)跨冒险加成轴节;~~全冒险获取次数上限最紧 provisional 2 次~~——v0.14 次数上限退役,池消耗即上限,pool 模式下商店购买与三选一共用令牌库,见下)。
掉落掷定消费 gp_drop 封闭随机流(主种子派生、可回放)。**商店货架抽签消费 shop_draw 封闭随机流**(v0.13 扩签——每次抽 3〔进店+每次买后重抽〕恰一 scope,与 reward_pick 分签防取数序互扰)。掉落与价格的现行行值读商店表,数值所有权归[难度曲线与Boss](难度曲线与Boss.md)曲线调参批——本批骨架先行,全部数值 provisional。
掉落掷定消费 gp_drop 封闭随机流(主种子派生、可回放)。**商店货架抽签消费 shop_draw 封闭随机流**(v0.13 扩签——每次抽 3〔进店+每次买后重抽〕恰一 scope,与三选一抽签分签防取数序互扰)。掉落与价格的现行行值读商店表,数值所有权归[难度曲线与Boss](难度曲线与Boss.md)曲线调参批——本批骨架先行,全部数值 provisional。
**共享池账本(v0.13 P1 共享池单点;v0.14 令牌库换代;迭代 20 案D 四级 104 张——池机制事实源=[奇物](奇物.md)「池结构与抽取」节)**:商店货架与奖励节点三选一是**同一个池**——货架候选 = 池∖{GP 袋, 刷新件}∪{凭证} = {攻击, 生命上限, 护甲, 行动点, 回复, 凭证} 六种(GP 袋计价物不自售切边、刷新件不上货架、秘宝件已随同调批出池;凭证与回复随迭代15② 入架——shop.tres pool_shelf 六行);**库存 = 剩余令牌数**(TP0——「池消耗即上限」,种类次数上限退役,与奖励兑付摘牌同一令牌库承载,全冒险一次性跨关卡不补给):商店买一件,奖励面就少一枚;「无限购买」收敛为**钱尽或池空为止**(池空=硬闸、A 链爬价=软闸),空货架合法态。货架 = **令牌级抽签**(同 kind 去重每 kind 至多一卡,价格公式 tier-blind 维持批②裁定,购买消费在架令牌本体 kind+tier)。禁止两渠道各自私记库存——消费走同一入口写同一令牌库(实现=CurioDeck 件(`core/curio_deck.gd`)的令牌多重集单点——池与判定归件,AdventureRunner 为宿主构造与持有、停点编排留宿主;商店货架/定价/购买/刷新归 ShopSession 件(`core/shop_session.gd`),外部调用面由 LevelRunner 同签名委托承载;kind 维度派生计数 taken(件内成员)承载断点附随件与读数)。**货架独立刷新(v0.15 MC-1 2026-10-04——P-C2+Q2 裁)**:进店免费刷新次数(基础 0,天赋/营地侧增益位预留)用尽后 GP 付费刷新(ceil(20×1.8^已付费刷) provisional——调参表旋钮 shop_refresh_*);重抽=同 pool_draw 共享池抽签(shop_draw 恰一新 scope),池空=不可刷新合法态;进店/离开双向清零付费刷计数。**三选一同款付费档(v0.16 2026-10-06 用户令——刷新对齐商店)**:三选一免费双源(刷新件 X/冒险池 Y,机制现行事实源=[秘宝](../跨局循环/秘宝.md)三选一刷新双源节)用尽后 GP 付费刷新——读同 shop_refresh_* 两旋钮(单点调参)、扣同一 GP 冒险账本(LevelRunner.spend_gp 单口)、重抽同 reward_pick 共享池抽签;付费刷计数每停点清零(与进店清零同构);钮常驻选择态、免费与付费两源皆穷=禁用。
**共享池账本(v0.13 P1 共享池单点;v0.14 令牌库换代;迭代 20 案D 四级 104 张——池机制事实源=[奇物](奇物.md)「池结构与抽取」节)**:商店货架与奖励节点三选一是**同一个池**——货架候选 = 池∖{GP 袋, 刷新件}∪{凭证} = {攻击, 生命上限, 护甲, 行动点, 回复, 凭证} 六种(GP 袋计价物不自售切边、刷新件不上货架、秘宝件已随同调批出池;凭证与回复随迭代15② 入架——shop.tres pool_shelf 六行);**库存 = 剩余令牌数**(TP0——「池消耗即上限」,种类次数上限退役,与奖励兑付摘牌同一令牌库承载,全冒险一次性跨关卡不补给):商店买一件,奖励面就少一枚;「无限购买」收敛为**钱尽或池空为止**(池空=硬闸、A 链爬价=软闸),空货架合法态。货架 = **令牌级抽签**(同 kind 去重每 kind 至多一卡,价格公式 tier-blind 维持批②裁定,购买消费在架令牌本体 kind+tier)。禁止两渠道各自私记库存——消费走同一入口写同一令牌库(令牌多重集单点:池与判定归该单点持有,各 kind 的派生计数与断点附随件同在这一点上承载)。**货架独立刷新(v0.15 MC-1 2026-10-04——P-C2+Q2 裁)**:进店免费刷新次数(基础 0,天赋/营地侧增益位预留)用尽后 GP 付费刷新(ceil(20×1.8^已付费刷) provisional——调参表旋钮 shop_refresh_*);重抽=共享池抽签(shop_draw 恰一新 scope),池空=不可刷新合法态;进店/离开双向清零付费刷计数。**三选一同款付费档(v0.16 2026-10-06 用户令——刷新对齐商店)**:三选一免费双源(刷新件与冒险池两笔,机制现行事实源=[秘宝](../跨局循环/秘宝.md)三选一刷新双源节)用尽后 GP 付费刷新——读同 shop_refresh_* 两旋钮(单点调参)、扣同一 GP 冒险账本(同一扣账入口)、重抽同三选一共享池抽签;付费刷计数每停点清零(与进店清零同构);钮常驻选择态、免费与付费两源皆穷=禁用。
### 关卡大奖励:关卡完成回血 + 专长三选一(钥石退役出大奖励)
@@ -168,9 +168,9 @@ GP(显示名「GP」)是冒险内的一次性属性提升货币:战斗胜
兑付次序:部分回血先行(按当刻生命与上限结算),随后呈现三选一**选择停点**——零自动推进,必须玩家点选才兑付,重复兑付被拒(结算受理只算一次语义同族)。选择停点可中断:断点附随件扩「奖励选择态 + 件获取次数计数」,续玩已选件不静默丢失;**候选逐位一致系停点快照承载的实现现状、非验收义务**(不一致不影响玩法——2026-10-01 用户裁决,见「冒险断点」节)。
**奖励节点三选一池(结构层——池机制事实源=[奇物](奇物.md)「池结构与抽取」节,2026-10-11 迭代 20 案D 换代)**:池 = 四级令牌库(案D——普通打底/优秀·稀有做翼/传说惊喜位空集;曝光槽 = 三选一 2 格全池 + 1 格优秀档以上子池,令牌 = 出现次数上限、概率与已拿上限解耦;构成数字与抽取细节全读[奇物](奇物.md)与 `adventure.tres`,provisional 归[难度曲线与Boss](难度曲线与Boss.md)曲线调参批,本节零复制)。**池为冒险级单例**(迭代 10 追加批):关卡内奖励节点的三选一与商店货架共享同一令牌库(同库同摘牌),库存 = 剩余令牌数;消费 reward_pick 封闭随机流(主种子派生、[数据配置](../表现与支撑/数据配置.md)口径),同种子同操作序列同三选项可复放;**MC 策略 316-f**:autoplay 1 级优先度=最稀有(rarest>rare>common)、2 级=最左。断点附随件承载池余库逐枚还原;兑付语义归[关卡节点地图](关卡节点地图.md)。
**奖励节点三选一池(结构层——池机制事实源=[奇物](奇物.md)「池结构与抽取」节,2026-10-11 迭代 20 案D 换代)**:池 = 四级令牌库(案D——普通打底/优秀·稀有做翼/传说惊喜位空集;曝光槽 = 三选一 2 格全池 + 1 格优秀档以上子池,令牌 = 出现次数上限、概率与已拿上限解耦;构成数字与抽取细节全读[奇物](奇物.md)与 `adventure.tres`,provisional 归[难度曲线与Boss](难度曲线与Boss.md)曲线调参批,本节零复制)。**池为冒险级单例**(迭代 10 追加批):关卡内奖励节点的三选一与商店货架共享同一令牌库(同库同摘牌),库存 = 剩余令牌数;消费三选一封闭随机流(主种子派生、[数据配置](../表现与支撑/数据配置.md)口径),同种子同操作序列同三选项可复放;**MC 策略 316-f**:自动游玩 1 级优先度=最稀有(rarest>rare>common)、2 级=最左。断点附随件承载池余库逐枚还原;兑付语义归[关卡节点地图](关卡节点地图.md)。
**秘宝件受同调位约束**(2026-10-09 注:道具件已随迭代 11 第①批 T7 出池——三选一/奖励节点/战斗内渠道现行零道具件投放,下述渠道约束与替换交互无现役触发面,保留作渠道恢复时的契约口径;同调位读数现行事实源=attunement_growth.tres 谓词表实时求值):道具持有上限 = 同调位数。读数源 = 同调位里程碑谓词表 attunement_growth.tres 实时求值(0 起步、硬上限 3、增长 = 通关次数 + Boss 击杀数——同调实施批 2026-10-03 落地,过渡读数源 transitional_sync_slots 已顺带退役;原提案八拍板 git 57da58c 已退役)。获取渠道约束形态(迭代 10 过渡承载):三选一道具件超位触发**替换交互**(现有件与新件 N+1 选 N——丢任一原有件腾位收新,或放弃新件不获取;终态恒 ≤ 同调位);奖励节点与战斗内渠道超位**不授予**(候选拒绝 + 掉落沉没,逐行归因留痕)——停点渠道全覆盖的替换交互随同调实施批统一完成(原待办清单条目已随完成移除)。
**秘宝件受同调位约束**(2026-10-09 注:道具件已随迭代 11 第①批 T7 出池——三选一/奖励节点/战斗内渠道现行零道具件投放,下述渠道约束与替换交互无现役触发面,保留作渠道恢复时的契约口径;同调位读数现行事实源=attunement_growth.tres 谓词表实时求值):道具持有上限 = 同调位数。读数源 = 同调位里程碑谓词表 attunement_growth.tres 实时求值(0 起步、硬上限 3、增长 = 通关次数 + Boss 击杀数——同调实施批 2026-10-03 落地,过渡读数源已顺带退役;原提案八拍板已退役)。获取渠道约束形态(迭代 10 过渡承载):三选一道具件超位触发**替换交互**(现有件与新件 N+1 选 N——丢任一原有件腾位收新,或放弃新件不获取;终态恒 ≤ 同调位);奖励节点与战斗内渠道超位**不授予**(候选拒绝 + 掉落沉没,逐行归因留痕)——停点渠道全覆盖的替换交互随同调实施批统一完成(原待办清单条目已随完成移除)。
末关完成不发三选一与部分回血:没有下一战可受益——只做冒险完成结算,末关 Boss 钥石照常入账。设计意图:清库之后才兑付、末关不兑付,都是从「奖励只朝下一战生效」这一条推出来的。
@@ -233,7 +233,7 @@ GP(显示名「GP」)是冒险内的一次性属性提升货币:战斗胜
|---|---|---|
| 上游 | [难度曲线与Boss](难度曲线与Boss.md) | 逐关关卡完成率带是序列难度排布的输入;三关序列均已生效(地精洞窟→幽暗地域→灰矮人矿城),无未落前置;大奖励与恢复点数值的联动复验归它 |
| 上游 | [数据配置](../表现与支撑/数据配置.md) | 关卡表与冒险表(单行全局)的承载与统一读取,本文是两表的内容与回填责任方;主种子的注入入口(随机服务) |
| 上游 | [战斗结算](../战斗循环/战斗结算.md) | 主角战斗入参覆盖值通道(本文供生命与上限);关卡收束接口由关卡节点地图收束点调用,本文零直调;战后生命终值与本战 GP 掉落(gp_dropped)经上报读回 |
| 上游 | [战斗结算](../战斗循环/战斗结算.md) | 主角战斗入参覆盖值通道(本文供生命与上限);关卡收束接口由关卡节点地图收束点调用,本文零直调;战后生命终值与本战 GP 掉落(掉落额)经上报读回 |
| 下游 | [关卡节点地图](关卡节点地图.md) | 接口契约四件套 + 收束点语义,本文是定义源,也是其文档的强制输入 |
| 下游 | [元进度](../跨局循环/元进度.md) | 冒险摘要承载钥石入账合计(元进度是消费方);冒险开始参数面预留(未来跨局加成在此注入,MVP 空参数) |
| 下游 | [存档序列化](../表现与支撑/存档序列化.md) | 快照契约域单位 = 冒险(主种子 + 随机流计数器);摘要含主种子供复盘;断点域 `breakpoint` 内容 owner = 本文(迭代 8 卡①——七字段+附随件,见「冒险断点」节) |
@@ -258,16 +258,16 @@ GP(显示名「GP」)是冒险内的一次性属性提升货币:战斗胜
## 调参表
全部数值存配置表、经统一读取口读入,代码里零数值字面量;表本体与读取机制归[数据配置](../表现与支撑/数据配置.md)。已锁字段以 `data/schemas/level_table.gd`/`adventure_table.gd` 声明与对应 `.tres` 行值为准。
全部数值存配置表、经统一读取口读入,代码里零数值字面量;表本体与读取机制归[数据配置](../表现与支撑/数据配置.md)。已锁字段以关卡表与冒险表的字段声明及对应表行为准。
| 参数 | 域 | 现行值 | 说明 |
|---|---|---|---|
| 关卡行集(关数与图的参数档) | 关卡表逐关行 | 三关现行(图由生成器按参数档产出,见[关卡节点图生成](关卡节点图生成.md)) | 加关 = 内容批(参数档 + 敌我数值 + 新元素同批);确定性 = 固定种子+固定参数档(首局教学与存档复现的固定图由此承载,无兜底模板) |
| 恢复比例 | int [0,100],逐关行 | 见 level.tres rest_heal_pct(provisional) | 恢复点回复生效上限的百分比;随上限加成同步放大;100 = 恢复点变全满泉,0 = 死节点 |
| 上限提升 | int [0,999],冒险表逐件列 | adventure_table bonus_attack_flat / bonus_max_hp_flat / bonus_armor_flat(provisional) | 三选一属性件各自兑付值;值锚与上调约束归难度曲线与Boss |
| 三选一件值(其余) | int [0,999],冒险表 kind×tier 列族 | adventure_table curio_value_*(GP 袋 / AP 件 / 恢复 / 刷新,provisional) | 令牌件值读表;道具件授予件数随秘宝件出池退役 |
| 上限提升 | int [0,999],冒险表逐件列 | adventure_table value_segment.curio_value_attack/max_hp/armor_{common,excellent}(provisional) | 三选一属性件各自兑付值;值锚与上调约束归难度曲线与Boss |
| 三选一件值(其余) | int [0,999],冒险表 kind×tier 列族 | adventure_table value_segment.curio_value_*(GP 袋 / AP 件 / 恢复 / 刷新,provisional) | 令牌件值读表;道具件授予件数随秘宝件出池退役 |
| ~~三选一权重~~(v0.14 退役——令牌池档位配额即分布、无独立权重 knob) | — | — | E-S 加权洗牌不放回抽样权重随 TP0 令牌池换代退役 |
| 件次数上限 | ~~int [0,99],冒险表逐件键~~(v0.14 退役——池消耗即上限) | adventure_table token_* 配额列族(TP0 令牌池——kind×tier 配额) | 达上限件先剔出牌库永不再现 → 池耗即枯竭 |
| 件次数上限 | ~~int [0,99],冒险表逐件键~~(v0.14 退役——池消耗即上限) | adventure_table quota_segment.curio_quota_*(TP0 令牌池——kind×tier 配额) | 达上限件先剔出牌库永不再现 → 池耗即枯竭 |
| 关卡完成回血比例 | int [0,100],冒险表单行全局 | adventure_table clear_heal_pct(provisional 20) | 关卡完成部分回血回复生效上限的百分比;封顶上限不回满 |
| ~~同调位过渡键~~(已退役——迭代 11 第①批 T7,过渡键随表退役) | — | 同调位读数源 = attunement_growth.tres 谓词表实时求值(slot_cap 3) | 切换义务已随 2026-10-03 同调实施批清偿 |
| Boss 钥石掉落 | int [0,999],meta 表逐关行 | meta.tres boss_keystone 首杀 3 / 复杀 2(provisional) | 逐杀实时入账;精英怪掉 1 预留;消费方归元进度 |
@@ -287,7 +287,7 @@ GP(显示名「GP」)是冒险内的一次性属性提升货币:战斗胜
- 生命一致性:每战开始的上参 = 生命当前值与生效上限;战后生命 = 上报终值;三处写入口均封顶在 [0, 生效上限]。
- 恢复点:回复 = floor(生效上限 × 恢复比例 ÷ 100) 后封顶;满血腿回复 0 合法。
- 大奖励覆盖:三选一兑付后首战的入参 = 基础表值 + 加算区累加含选中件(覆盖值通道);AP 件兑付后每场战斗开始首轮行动点基线 +1。
- 抽签封闭:三选一掷 3 消费 reward_pick 封闭流,同种子同操作序列同三选项;单次零重复;令牌耗尽快即枯竭、不再出现在候选(池消耗即上限)。
- 抽签封闭:三选一掷 3 消费三选一封闭流,同种子同操作序列同三选项;单次零重复;令牌耗尽快即枯竭、不再出现在候选(池消耗即上限)。
- 同调位约束:道具终态持有恒 ≤ 同调位(谓词表实时求值);超位时停点渠道触发替换交互(丢旧收新 / 放弃新件两路),战斗内渠道沉没不入;奖励节点渠道同受约束。(现行零道具件投放——约束保留作契约,见「秘宝件受同调位约束」节注。)
- 钥石逐杀:Boss 击杀后钥石累计增量 = boss_keystone 行值(首杀/复杀两档);大奖励面钥石入账零残留。
- 收束次序:关卡完成宣布到达时库存已被关卡节点地图先行清空;重复的关卡结束宣布被拒绝,状态与摘要零变化。
+13 -15
View File
@@ -11,9 +11,9 @@
>
> **兑付频率(先看这条,它是三条渠道的共同前提)**:奇物**不是打一场战斗给一份**。关内的普通战斗节点打完了什么也不给;一关之内奇物**只兑付一次**,触发点是**关底 Boss 被击败**——而按 [冒险结构](冒险结构.md) 的定义,打掉关底 Boss 恰好就等于"通过这一关",这两件事是同一个时刻,不是一条链上的两步。
>
> 状态:**已实现**(2026-10-04 双层 BD 实施批落地)。本文件是奇物的唯一定义文档。
> 状态:**已实现**(2026-10-04 双层 BD 实施批落地);现行为 v1.1。本文件是奇物的唯一定义文档。
>
> 数值纪律:本文件只写概念、取值域与指路;每件给多少、效果是什么一律不进正文,事实源是 `game/data/tables/feats.tres` 与 `game/data/tables/adventure.tres`。
> 数值纪律:本文件只写概念、取值域与指路;每件给多少、效果是什么一律不进正文,事实源是 `data/tables/feats.tres` 与 `data/tables/adventure.tres`。
## 专长(重设计·基础框架 v1)
@@ -27,7 +27,7 @@
4. **信息红线**:禁止任何效果让数字说谎(信息规则不豁免);揭示类效果只揭真格。
5. **防兑换环**:互相转换的通道必须有损耗或每轮上限;单向通道优先。
> **落行注记(迭代 20 反哺写入,2026-10-12 追认⑤)**:「每第 N 次 / 积满触发」的数据行条件写 **N−1**——效果引擎 dispatch 时 when 先于 do 读计数器现值(预评估),故「满 N 触发」落行写 N−1(例:地质学家「满 4 种」写 eq 3、封印匠「每第 3 次」写 mod_eq ref 2、双管镐「每第 2 次」写 mod_eq ref 1)。行为仍为每第 N 次准点触发,单元测试钉住;新件落行照此口径。
> **落行注记(迭代 20 反哺写入,2026-10-12 追认⑤)**:「每第 N 次 / 积满触发」的数据行条件写 **N−1**——效果引擎分发时 when 先于 do 读计数器现值(预评估),故「满 N 触发」落行写 N−1(例:地质学家「满 4 种」写 eq 3、封印匠「每第 3 次」写 mod_eq ref 2、双管镐「每第 2 次」写 mod_eq ref 1)。行为仍为每第 N 次准点触发,单元测试钉住;新件落行照此口径。
### 基础件表(27 件,五族 + 跨族桥 + 契约尖点)
@@ -93,7 +93,7 @@
| 代号 | 契约 | 账 |
|---|---|---|
| 血税 | 本局:踩雷 −2 最大生命;标中 +1 攻击(**均下一战起生效**——战末汇入冒险加算区) | 双向都痛都爽,一句话讲得清;双向同账、本局累积、冒险收束清零。max_hp/攻击系战界重建属性,即时改会被重建冲掉,故滞后一战兑付(2026-10-12 追认⑨回写;卡面 desc 同步补「下一战起生效」) |
| 血税 | 本局:踩雷 −2 最大生命;标中 +1 攻击(**均下一战起生效**——战末汇入冒险加算区) | 双向都痛都爽,一句话讲得清;双向同账、本局累积、冒险收束清零。生命上限/攻击系属战界重建属性,即时改会被重建冲掉,故滞后一战兑付(2026-10-12 追认⑨回写;卡面 desc 同步补「下一战起生效」) |
### 迁入登记(秘宝域迁出件;实装批落地后并入件表)
@@ -104,11 +104,11 @@
惊巢反制=退役进素材库(不迁入)。
**资源类迁出件(2026-10-18 用户裁)**:完美保险自资源类迁入专长——理由:它给的是**规则豁免**而非可调动的余量(§1.1 判据「给规则的是专长」),效果=本场首次封印落空不计入完美封印判定。旧「资源类成员」归类系 2026-10-08 框架批写入、无用户裁断支撑,随本次改判注销。专长行已于迭代 31 卡② 落表(合并 `3e076e22`):`feats.tres` 单行 `when counter(insurance_used) lt 1` 承载「本场首次」,效果类型 `forgive_seal_miss` 随引擎扩签;稀有档配额随净删重裁下调,现行值读 `game/data/tables/adventure.tres`。
**资源类迁出件(2026-10-18 用户裁)**:完美保险自资源类迁入专长——理由:它给的是**规则豁免**而非可调动的余量(§1.1 判据「给规则的是专长」),效果=本场首次封印落空不计入完美封印判定。旧「资源类成员」归类系 2026-10-08 框架批写入、无用户裁断支撑,随本次改判注销。专长行已于迭代 31 卡② 落表:`feats.tres` 单行 `when counter(insurance_used) lt 1` 承载「本场首次」,效果类型 `forgive_seal_miss` 随引擎扩签;稀有档配额随净删重裁下调,现行值读 `data/tables/adventure.tres`。
### 扩签登记(迭代 20 实装已承载——2026-10-12 追认④写入文档换代)
- **落地结果**:事实候选 10 条中 6 条落 FACTS 词位(边缘格判定/空白连锁判定/单次伤害量/被挖格当时有封印印记/雷罚伤害量/生命比例),4 条改道 adventure 域计数器(类型集合计数器/本轮挖格花费/本轮开格数/本轮踩雷数计数器——跨事件累积量走计数器+value_event 比较,不占 fact 词位,T0 定架构);停手事件已落(dig_stop);实现随裁补位=battle_won 事件(战地包扎所需,登记未列)、mod_eq 算子(周期触发)、hp_ratio(百分比 int 口径)等 3 项事实、新效果类型 7 项。
- **落地结果**:事实候选 10 条中 6 条落事实词位(边缘格判定/空白连锁判定/单次伤害量/被挖格当时有封印印记/雷罚伤害量/生命比例),4 条改道 adventure 域计数器(类型集合计数器/本轮挖格花费/本轮开格数/本轮踩雷数计数器——跨事件累积量走计数器+value_event 比较,不占 fact 词位,T0 定架构);停手事件已落(dig_stop);实现随裁补位=battle_won 事件(战地包扎所需,登记未列)、mod_eq 算子(周期触发)、hp_ratio(百分比 int 口径)等 3 项事实、新效果类型 7 项。
- **连带**:净化工兵退役,rewrite_board 效果类型自引擎除名(扩签「暂缓:清图事件」不受影响,继续挂起)。
- **暂缓**:清图事件(随清图奖励题)。
@@ -122,13 +122,13 @@
### 凭证件表(新 3 + 留任 2;代号制命名归用户;稀有度档、配额与面值数值归调参批)
> **2026-10-18 用户裁削两件**:**同调电池**删除——秘宝是「局外同调件」、冒险中零更换途径,与 `cf04bd66` 撤换装券/删回能器同一原则(且 UI 层从未接线选件入口);**完美保险**迁出资源类改归专长——它给的是规则豁免,不是余量,见 §1.4 判据。两件原职责账(秘宝充能/完美资格)同步自 §1.3 账清单注销。
> **2026-10-18 用户裁削两件**:**同调电池**删除——秘宝是「局外同调件」、冒险中零更换途径,与撤换装券/删回能器同一原则(且 UI 层从未接线选件入口);**完美保险**迁出资源类改归专长——它给的是规则豁免,不是余量,见 §1.4 判据。两件原职责账(秘宝充能/完美资格)同步自 §1.3 账清单注销。
| 代号 | 写进哪笔系统资源(寿命档) | 一句话 | 备注 |
|---|---|---|---|
| 刷新券 | 刷新存量账(冒险级) | 存量刷新次数 +1 | 语义=存量加仓(已裁);实现依赖刷新件写错账修复(同批) |
| 储备金袋 | 储备池 RAP(节点级) | 储备池 +N | 给停手/刷新雷图经济加燃料;战斗结束清零系既有语义,兼容 |
| 时沙 | 下一战首轮 AP 队列(拾取挂账,兑付即消尽) | 下一战首轮 AP +2 | 一次性节奏件;与「AP 上限+1」(属性轴)不撞——一个改池子、一个改上限(落法=hero_ap_bonus 既有通道,2026-10-12 追认⑦回写;拾取时战斗在途同样等下一战首轮) |
| 时沙 | 下一战首轮 AP 队列(拾取挂账,兑付即消尽) | 下一战首轮 AP +2 | 一次性节奏件;与「AP 上限+1」(属性轴)不撞——一个改池子、一个改上限(落法=AP 加成既有通道,2026-10-12 追认⑦回写;拾取时战斗在途同样等下一战首轮) |
| 小 GP 袋 | GP 钱包(冒险级) | (留任)+20 / +50 | 计价物不自售维持(不进商店) |
| 应急口粮 | 生命账(冒险级) | (留任)回复 +6 | 在商店内(默认原则) |
@@ -230,7 +230,7 @@
**补给类内部的异质性(统一表述)**:凭证全部即时消尽——不存在「持有凭证」这种状态;异质性不在凭证上,而在**被写入的系统资源的寿命**上:GP 钱包 / 生命 / 刷新存量 = 冒险级,储备池 = 节点级,时沙暂记 = 至下一战首轮兑付(系统资源清单对齐「凭证件表(新 3+留任 2)」节;「AP 上限」已归属性值提升轴,见 1.2)。
- 原在册的「秘宝充能」「完美资格」两笔随 2026-10-18 两件裁削注销——`attune_charges` 账本本身仍为秘宝基础设施保留(迭代 11,主动件充能每冒险重置),本次只删奇物侧写它的入口。
- 原在册的「秘宝充能」「完美资格」两笔随 2026-10-18 两件裁削注销——充能账本本身仍为秘宝基础设施保留(迭代 11,主动件充能每冒险重置),本次只删奇物侧写它的入口。
- 完美资格的豁免走**订阅式自有累加账**:授予段在 `seal_missed` 命中时累加豁免数,判定取「误标总数 − 豁免数」得有效数;**不改写误标账本身、不拦截事件**(迭代 31 卡② 契约 2/3)。
- 登记此节防止把凭证当成会持续生效的东西去结算。
@@ -263,8 +263,6 @@
**为什么两层都要有**:分类名在卡面上不出现,不等于玩家对它没有概念——帮助手册、百科条目、成就名称三处一定会用到它(「首次集齐 4 件专长」「三件属性值提升」),效果描述里出现指代时也需要名字(如「本项属专长」类归类指代)。所以它必须是一个**玩家读得懂、读一遍就懂**的正式名词,不能是内部描述或自造词。
**代码侧词族对应**(本批只做命名对齐,代码改动见需求卡片):顶层 `curio_*`(奇物总称)/ 专长 `feat_*` / 属性值提升 `asi_*` / 资源 `res_*`。`reward_*` 已被既有标识符占用(`reward_pick` / `reward_node` / `reward_preview`),**禁止使用**。
### 2. 渠道轴:与分类的交叉
三个渠道各只取走分类的一部分。这张表是奇物概念的第二个维度——它和分类轴互不决定,改其中一根不必动另一根。
@@ -433,12 +431,12 @@
| 参数 | 取值域 | 事实源 |
|---|---|---|
| 专长定义行(标识 / 显示名 / 稀有度 / 效果说明 / 订阅行〔订阅哪个事件 on / 什么条件 when / 什么效果 do〕) | 各字段封闭枚举,行键白名单封闭;事件 / 效果类型 / 条件事实 / 算子四词表封闭(效果引擎单一事实源);稀有度档=新四级(普通/优秀/稀有/传说),schema 字段双脱钩(字段在、设计面按档配比加权) | `game/data/tables/feats.tres` |
| 专长凭证(出现概率 / 配额 / 限购次数 / 保底计数阈值) | 整数,四参数全 provisional | 已入表(迭代15② 凭证行——`shop.tres` + `adventure_table.gd`) |
| 属性值提升种类 | 封闭三项:生命上限 / AC / 攻击,扩项走文档修订 | `game/data/schemas/adventure_table.gd` |
| 专长定义行(标识 / 显示名 / 稀有度 / 效果说明 / 订阅行〔订阅哪个事件 on / 什么条件 when / 什么效果 do〕) | 各字段封闭枚举,行键白名单封闭;事件 / 效果类型 / 条件事实 / 算子四词表封闭(效果引擎单一事实源);稀有度档=新四级(普通/优秀/稀有/传说),schema 字段双脱钩(字段在、设计面按档配比加权) | `data/tables/feats.tres` |
| 专长凭证(出现概率 / 配额 / 限购次数 / 保底计数阈值) | 整数,四参数全 provisional | 已入表(`shop.tres` 凭证行 + 冒险表凭证三计数行) |
| 属性值提升种类 | 封闭三项:生命上限 / AC / 攻击,扩项走文档修订 | 冒险表结构声明 |
| 补给种类 | 种类现行事实源=「凭证件表(新 3+留任 2)」节;凭证已入表(迭代15②) | 同上 |
| 稀有度档位 | 封闭四级(普通 / 优秀 / 稀有 / 传说);配额是结构锚,改总量须重新拍板而非调参 | 同上 |
| 各分类种类 × 档位的配额与值 | 整数 | `game/data/tables/adventure.tres` |
| 各分类种类 × 档位的配额与值 | 整数 | `data/tables/adventure.tres` |
| 专长获取的全局限量 | 整数(一局内可获得的次数上限) | 同上 |
| 一次三选一的候选展示数 | [1,6] | 同上 |
@@ -1,7 +1,7 @@
# 难度曲线与Boss
> 一句话:难度曲线、期望值带与 Boss 设计
> 状态:已定稿(自旧体系迁移);现行为 v1.1
> 状态:已定稿(自旧体系迁移);现行为 v1.2
## 设计目的
@@ -57,7 +57,7 @@
| 关内坡度(节点深度) | 同敌种数值平缓上移,深度也可表达为敌人成群 | 数量是比单体质变更优先的深度表达:保持技能池 EV 读数不变(权重即旋钮、EV 重锚顺带登记)、总量受控 |
| Boss 与精英修饰(预留第三轴) | Boss 走最深深度直填行;精英只有字段命名空间预留 | Boss 不走修饰表;修饰乘数表 MVP 为空表、零行为,首个使用场景 = 精英节点(随[关卡节点地图](关卡节点地图.md)定稿联动);数值所有权在本系统,[棋盘生成](../排雷循环/棋盘生成.md)只按表生成。精英怪设定已登记预留(迭代 10 奖励重构批——与其他普通小怪同一立绘 + 附加特征标记 + 数值更强;视觉特征三件 = 名称前后缀「精英·」+ 底座光环 + 描边变色,色板合规与样张闸义务随怪物设定批实装) |
**结论**:关内坡度 = 每深一档同敌种基准上移,或按"深度也可表达为敌人成群"改由数量承载——单体生命随深度的具体走向以 `enemy.tres` 行值为准(数量优先于单体;s_hp 线性式为建模工具,现行行值不承诺随深度单调上移);关间台阶 = 相邻关同敌种基准乘 1.3–1.6(域语义如上;s_hp / k_L 现行行值读 `enemy.tres`,域见 `data/schemas/enemy_table.gd`)。
**结论**:关内坡度 = 每深一档同敌种基准上移,或按"深度也可表达为敌人成群"改由数量承载——单体生命随深度的具体走向以 `enemy.tres` 行值为准(数量优先于单体;s_hp 线性式为建模工具,现行行值不承诺随深度单调上移);关间台阶 = 相邻关同敌种基准乘 1.3–1.6(域语义如上;s_hp / k_L 现行行值读 `enemy.tres`,取值域归敌人表字段定义)。
```
hp_D = round( hp_0 × (1 + s_hp × D) ) s_hp ∈ [0.05, 0.20]
@@ -111,7 +111,7 @@ MVP 行值并不逐式现算,而是按此式量级直填经切片验证过的
| 带 | 定稿口径 | 含义 |
|---|---|---|
| 通关率带 | 口径已换代·现行带 = 四带甲案(2026-10-03 用户拍板):带 A 白板完美执行战役全通率 [0%,10%] / 带 B 白板第一关通过率 [50%,85%] / 带 C 营地满成长战役全通率 [30%,60%](预立) / 带 D 响应曲线每雷边际 ≤15pp·S 形——旧普通档 L1 [35,55] / L2 [10,15] 与完美档 [35,65] 正式作废,全文见本节末「带换代」条。实证:直入口 L2 普通 5% vs 冒险条件口径 L2 90% 同期并存〔「营地检查点」= balance_verifier 营地循环判定段旧称(现名营地循环战役)——2026-09-30 词源考证完成,见审计报告 git 提交 c095916 拍板点 9(已按生命周期条款退役);与冒险结构「没有检查点」铁律的字面相撞就此解除〕 | 四带按类型基准锚定、每条带均有外部锚点:带 B 管首关 = 过滤器不是墙;带 A 管白板全通的顶尖难度;带 C 留元进度爬升空间(满成长实装后启用);带 D 管响应曲线无悬崖 |
| 通关率带 | 口径已换代·现行带 = 四带甲案(2026-10-03 用户拍板):带 A 白板完美执行战役全通率 [0%,10%] / 带 B 白板第一关通过率 [50%,85%] / 带 C 营地满成长战役全通率 [30%,60%](预立) / 带 D 响应曲线每雷边际 ≤15pp·S 形——旧普通档 L1 [35,55] / L2 [10,15] 与完美档 [35,65] 正式作废,全文见本节末「带换代」条。实证:直入口 L2 普通 5% vs 冒险条件口径 L2 90% 同期并存〔「营地检查点」= 数值验证工具营地循环判定段旧称(现名营地循环战役)——2026-09-30 词源考证完成,见审计报告拍板点 9(已按生命周期条款退役);与冒险结构「没有检查点」铁律的字面相撞就此解除〕 | 四带按类型基准锚定、每条带均有外部锚点:带 B 管首关 = 过滤器不是墙;带 A 管白板全通的顶尖难度;带 C 留元进度爬升空间(满成长实装后启用);带 D 管响应曲线无悬崖 |
| 关卡完成余量带 | 关卡完成者关卡完成时剩余生命的 p90 / p10 按现生命轴上限百分比表达(压缩前绝对血量带已作废;界值重标随验收批) | **关卡完成余量** = 关卡完成瞬间还剩多少血。余量太肥说明赢得太从容,压生存侧;太瘦说明"剩一两滴血惨胜"成常态,抬治疗供给或恢复点收益 |
| 第一关形态带 | 教学位绿档 + 中段黄档 + Boss 黄档不红 | **形态带**管一关内各战三档判定的排布形状:第一战必须稳过,中段有输的可能,Boss 战紧但不许是配置事故 |
@@ -123,7 +123,7 @@ MVP 行值并不逐式现算,而是按此式量级直填经切片验证过的
**迭代 24 敌人表内容修批读数(只测不判——2026-10-14 反哺写入批登记,用户裁「全部按呈报写入文档」;数值终值归 M4 数值批)**:同种子配对 seed0=9000(沿用迭代 23 配对种子)改前/改后各 40 局×both——①**N2 普通敌技能投放**(毒吐/盾击两新行六池)后 perfect L2 通关 8/20→13/20(+25pp)、L3 全通 6/20→10/20(+20pp)——方向符合预期(L1 减压后更健康抵达 L2/L3),量级低于二档配对判读带 ~30pp,倍率 provisional 归 M4;normal 档基率地板(0/20)无判读力;②**N3 敌方攻击类型轴**(20 行全填 normal+敌方兑付路径克制消费)后全局平移 = 主角穿重甲受伤点数 −1 / 魔法护甲 +1 / 轻甲 0(V5 冒烟同种子三甲型配对实测单发恒 ±1:heavy 2==light 3−1 · ward 4==light 3+1);taken 中位 normal 29.5→27.5、perfect 76.5→97.0——后者系**构成效应**(全通 6→10 局通关更深自然累计更多承伤),非单发异常;③N1 (1,2) 降档(hp 50→22·ac 3→2)后 perfect L1 通关 19/20→20/20——5 倍墙消除方向符合预期。判读与带重锚随 M4 数值批,本注记只登记不判读。
**判读口径同步(迭代 5 基线重测批,2026-09-28)**:通关率带的测量口径 = 冒险条件通关率(打通 k−1 关才到达第 k 关,balance_verifier 冒险段派生;单关直入口口径已随 2026-09-23 拍板退役)——带值沿用 2026-09-20 分带修正(普通档 L1 [35,55] / L2 [25,45]、完美档 [35,65];迭代 5 计划书 C4 冻结:改带=用户拍板)。上方行 115 的「带退役待重锚、重锚前只测不判」注记按本条同步理解:迭代 5 基线重测已按现行带对冒险条件口径判读(读数报告见 git 提交 e55dc10,已按生命周期条款退役);是否在新口径上重取带值,归迭代 5 出口判读由用户拍板,本批不动带数字。
**判读口径同步(迭代 5 基线重测批,2026-09-28)**:通关率带的测量口径 = 冒险条件通关率(打通 k−1 关才到达第 k 关,由数值验证工具冒险段派生;单关直入口口径已随 2026-09-23 拍板退役)——带值沿用 2026-09-20 分带修正(普通档 L1 [35,55] / L2 [25,45]、完美档 [35,65];迭代 5 计划书 C4 冻结:改带=用户拍板)。上方行 115 的「带退役待重锚、重锚前只测不判」注记按本条同步理解:迭代 5 基线重测已按现行带对冒险条件口径判读(读数报告已按生命周期条款退役);是否在新口径上重取带值,归迭代 5 出口判读由用户拍板,本批不动带数字。
> **⚠ 带失效待重锚(2026-10-01 数值修复批)**:模拟档位重构(普通档 v2 新手画像→v3=完美策略+受控失误注入;完美档补元游戏选路与商店购买)+数值三刀(hero max_hp 20→26/直伤雷 4/5/5→6/8/8/L1 系敌 atk 2→1)后,上方三条验收带的测量基准已失义——旧普通档=比真人弱 20 倍的新手画像(真人实证推翻),旧带值系照坏尺子校定。新尺读数(N=100/200)与调优轨迹见 `数值修复批读数(已退役,git 历史可查)`;~~新带值须新尺重测后用户拍板,重锚前只测不判~~(已由下行带换代完成)。
@@ -175,7 +175,7 @@ GP 与商店房随 2026-09-20 GP+商店房批落地,给难度引入第三族
公式语义与 GP 归[冒险结构](冒险结构.md)(GP 节),商店房编排归[关卡节点地图](关卡节点地图.md);行值读 `data/tables/shop.tres`,全部 provisional 归本文曲线调参批。
**分层验收 defer(2026-09-20 用户拍板成文)**:按"商店存在与否"分层的通关率验收——MC 双格(shop=off 现行基线 / shop=on 购买画像)、shop=on 的带平移量、商店属性提升的换算率登记(换算率强条目纪律同类)——**全部随曲线调参批执行**,与「基线通关率越带」同窗(原「L2 Boss 承伤微越带」「大奖励数值随难度曲线联动」两待办清单条目已完成移除——前者 2026-09-28 读数自愈、后者随迭代 10 大奖励退役失义)。执行前 shop=off 续用现行带判读,shop=on 读数只登记不判读、禁止用 shop=off 读数外推 shop=on。L3 首遇绿档冒烟断言仍按成长代理档口径,不因商店批改判。**v0.22 注记(迭代 11 第②批)**:shop=off 对照 = legacy 固定三件模式(MC 逐项比对 off_n60 逐位,迭代 11 第②批 T5);shop=on 首锚 = 共享池货架面 N=60 双策略(`runsum_m4iter11b_t5shopon_n60_20261003.jsonl`,attune=off 同种子配对)——带平移判读仍归调参批,终局池读数(pool_stock)随行只测不判。
**分层验收 defer(2026-09-20 用户拍板成文)**:按"商店存在与否"分层的通关率验收——MC 双格(shop=off 现行基线 / shop=on 购买画像)、shop=on 的带平移量、商店属性提升的换算率登记(换算率强条目纪律同类)——**全部随曲线调参批执行**,与「基线通关率越带」同窗(原「L2 Boss 承伤微越带」「大奖励数值随难度曲线联动」两待办清单条目已完成移除——前者 2026-09-28 读数自愈、后者随迭代 10 大奖励退役失义)。执行前 shop=off 续用现行带判读,shop=on 读数只登记不判读、禁止用 shop=off 读数外推 shop=on。L3 首遇绿档冒烟断言仍按成长代理档口径,不因商店批改判。**v0.22 注记(迭代 11 第②批)**:shop=off 对照 = legacy 固定三件模式(MC 逐项比对 off_n60 逐位,迭代 11 第②批 T5);shop=on 首锚 = 共享池货架面 N=60 双策略(同调关闭同种子配对)——带平移判读仍归调参批,终局池读数(pool_stock)随行只测不判。
### Boss 设计:食人魔酋长与关底血量锚
@@ -220,13 +220,13 @@ Boss 战的棋盘用本关最大板形(板形行值读棋盘参数表),板
| 封印溢价系数 δ ↔ 完美乘数 p_perfect ↔ ap_per_round | [战斗结算](../战斗循环/战斗结算.md)、[行动经济](../排雷循环/行动经济.md) | 封印激励三件套同窗检算(防封印 rush 复发:δ 与 ×2 叠加通胀、AP 吞吐上限)——任一变动须重跑双画像封印率读数(2026-10-05 判式换代批新增) |
| η 读数 ↔ 模拟画像定义 ↔ 可推理率 ι ↔ min_safe_count/生成尝试上限 | sim 档位、[棋盘生成](../排雷循环/棋盘生成.md) | η 是画像条件量:画像重构即锚漂移,重锚顺带;可推理率三元组既有联动扩一员(2026-10-05 判式换代批新增) |
| β 带端点 β_lo/β_hi ↔ D_ref ↔ hero max_hp ↔ AC 折算档(5pp 系数) | [战斗结算](../战斗循环/战斗结算.md) | 带是 D_ref 的函数:换锚(D_ref/max_hp)须全带重推;AC 档值变更改 5pp 系数,同罪(2026-10-05 判式换代批新增) |
| 直伤雷三行(6/8/8) ↔ 正向同轴行(heal_minor/pierce_strike/magic_bolt) | [地图战斗资源](../战斗循环/地图战斗资源.md) | **同轴镜像比入对账面**:负向/正向比超出 β 带内推导区间即越带;单边动负向三行今后必须带正向镜像行联合检算(2026-10-05 判式换代批新增——d70f6c3/数值修复批两先例的单边动教训成文) |
| 直伤雷三行(6/8/8) ↔ 正向同轴行(heal_minor/pierce_strike/magic_bolt) | [地图战斗资源](../战斗循环/地图战斗资源.md) | **同轴镜像比入对账面**:负向/正向比超出 β 带内推导区间即越带;单边动负向三行今后必须带正向镜像行联合检算(2026-10-05 判式换代批新增——数值修复批两先例的单边动教训成文) |
| clear_blast 区间(24/40/32) ↔ p_perfect | [地图战斗资源](../战斗循环/地图战斗资源.md) | 完美封印第二份的补贴基数进封印激励对账;单边动清图奖励 = 变相动封印(2026-10-05 判式换代批新增) |
| 标中强化池权重 ↔ 正向池权重(77 分母) ↔ 关级恒等式奖励占比 [15,40%] | [地图战斗资源](../战斗循环/地图战斗资源.md) | 形态 (b) 专属池重摇启用时生效(现行不启):双池分布变动 = E_dig 与 W 同时漂移,须联合检算 + 恒等式占比复核(2026-10-05 判式换代批新增,条件生效行) |
五条经济契约的对账由[战斗结算](../战斗循环/战斗结算.md)闭合验收;挖掘风险不等式已于 2026-10-05 判式换代批重立(三层口径+β 带+条件二封印溢价——结构层接替与数值层带判读详见行动经济 F1 条款3 推导节),本系统的对账义务转为按 β 带逐 u 检算(常设重跑入口 `tools/clear_dominance_audit.py`,现行 u=3 β=1.17 微破下限登记态);清图支配性已于 2026-09-19 按现行值链重跑、裁决②"非支配设计态"维持(回执见 git 提交 2ca3e20,报告已退役)——判式换代后的全套判值重跑随本系统下一次调参批顺带执行。完美封印乘数的调参权在本系统。
五条经济契约的对账由[战斗结算](../战斗循环/战斗结算.md)闭合验收;挖掘风险不等式已于 2026-10-05 判式换代批重立(三层口径+β 带+条件二封印溢价——结构层接替与数值层带判读详见行动经济 F1 条款3 推导节),本系统的对账义务转为按 β 带逐 u 检算(清图支配性审计为常设重跑项,现行 u=3 β=1.17 微破下限登记态);清图支配性已于 2026-09-19 按现行值链重跑、裁决②"非支配设计态"维持——判式换代后的全套判值重跑随本系统下一次调参批顺带执行。完美封印乘数的调参权在本系统。
元进度接口预留:**结论——元进度解锁对难度的影响,以生存链区间的平移换算率接入;接口启用形态已定稿(2026-09-18 元进度定稿批,用户拍板):永久强化影响折算为通关率带平移量,判读口径不变;换算率表首版三行(生命上限 / 基础攻击 / 护甲等级——护甲行强条目,验收读数须按解锁后参数重测)与键结构见 `data/schemas/meta_table.gd`,数值行读 `data/tables/`、标定随元进度设计批。** 元进度数值行落地前,本系统不为它预留任何数值行。
元进度接口预留:**结论——元进度解锁对难度的影响,以生存链区间的平移换算率接入;接口启用形态已定稿(2026-09-18 元进度定稿批,用户拍板):永久强化影响折算为通关率带平移量,判读口径不变;换算率表首版三行(生命上限 / 基础攻击 / 护甲等级——护甲行强条目,验收读数须按解锁后参数重测)与键结构见元进度表字段定义,数值行读 `data/tables/`、标定随元进度设计批。** 元进度数值行落地前,本系统不为它预留任何数值行。
## 依赖与输出
@@ -260,7 +260,7 @@ Boss 战的棋盘用本关最大板形(板形行值读棋盘参数表),板
| 优先级 | 内容 | 后置原因 |
|---|---|---|
| P1 | 加难杠杆扫描落带 | 候选杠杆已登记(血量锚走廊、群战上探、注入衰减上调候选),域内取样扫描已执行(迭代 5——r_boss 0.8 档,见「Boss 设计」节加难走廊行),全杠杆落带扫描未完成;护甲等级换装点锚定(基准护甲等级自带敌方输出期望的结构性削减 + 减伤墙退役 + 伤害下限)的方向性偏移并入本扫描一并调带(带宽补扫含暴击档与折扣档);落带前现行行值维持 provisional-pending-scan。第二关行集随分支节点图批落地后并入本扫描(L2 读数基线/加成档已顺带实测,见 v0.7) |
| P1 | 挖掘风险不等式与清图支配性对账重跑 | **挖掘风险不等式半边已完成(2026-10-05 判式换代批,迭代14②号卡)**——判式三层重立写入文档+条件二封印溢价机制闭合+β 带判读制度化(残留=u=3 β=1.17 微破下限登记态,不强制回滚;δ 敏感度判读顺带出口报告),本行对挖掘风险不等式的「重跑义务」改判读回执:后续调参按 β 带检算执行,不再立独立重跑批。清图支配性已于 2026-09-19 按现行值链重跑(裁决②"非支配设计态"维持——缺口收窄主读数 L1≈24/L2≈45 当量〔u=1〕,设计权威回执=git 提交 2ca3e20,重跑入口 tools/clear_dominance_audit.py);调参批执行时按当期行值顺带重跑 |
| P1 | 挖掘风险不等式与清图支配性对账重跑 | **挖掘风险不等式半边已完成(2026-10-05 判式换代批,迭代14②号卡)**——判式三层重立写入文档+条件二封印溢价机制闭合+β 带判读制度化(残留=u=3 β=1.17 微破下限登记态,不强制回滚;δ 敏感度判读顺带出口报告),本行对挖掘风险不等式的「重跑义务」改判读回执:后续调参按 β 带检算执行,不再立独立重跑批。清图支配性已于 2026-09-19 按现行值链重跑(裁决②"非支配设计态"维持——缺口收窄主读数 L1≈24/L2≈45 当量〔u=1〕,重跑入口=清图支配性审计(常设重跑项));调参批执行时按当期行值顺带重跑 |
| P1 | 真人冒险成功率修正系数标定 | 带按模拟口径定义;试玩批次实测真人显著强于模拟者,系数待后续试玩批次定量 |
| P1 | 迭代 10 奖励重构带重扫义务 | 恢复经济收紧(关卡完成回满血→部分回血 20%,难度上压方向)+ 局内成长节奏变动(三选一件值/权重/次数上限 knob 全读冒险表;AP 件 = 每场战斗开始首轮 +1 AP 的强度敏感轴)——关卡完成率带重扫随曲线调参批现行窗执行;Boss 钥石掉落重锚(首杀 3/复杀 2)连带元进度产出标定义务重开(归元进度设计批) |
| P1 | 完美策略档的结构性加难杠杆 | 数值杠杆对完美档已被实测证伪,结构候选未裁决(登记 [待办清单](../../../../待办清单.md)) |
@@ -270,7 +270,7 @@ Boss 战的棋盘用本关最大板形(板形行值读棋盘参数表),板
## 调参表
本系统是全项目行值最多的系统。数值纪律(2026-09-17 降级批定稿):**正文与调参表只定规则、取值域与口径,具体行值一律读配置表(切片 `game/data/tables/` 的 enemy / skills / hero / board_gen / reward / settlement / status_effects 等),已锁数值以 `data/tables/` 对应表为准,本文不登记具体数值——防双写失同步**(切片 `.tres` 数值压缩批后文档行值滞后,双写失同步已被实证)。
本系统是全项目行值最多的系统。数值纪律(2026-09-17 降级批定稿):**正文与调参表只定规则、取值域与口径,具体行值一律读配置表(切片 `data/tables/` 的 enemy / skills / hero / board_gen / reward / settlement / status_effects 等),已锁数值以 `data/tables/` 对应表为准,本文不登记具体数值——防双写失同步**(切片 `.tres` 数值压缩批后文档行值滞后,双写失同步已被实证)。
首发行值几乎全部 provisional,其中加难相关数值处于 provisional-pending-scan(扫描未执行);完整行集读表,不在此整表搬运。
@@ -296,7 +296,7 @@ Boss 战的棋盘用本关最大板形(板形行值读棋盘参数表),板
| 技能冷却(拍) | 逐技能行读表;普攻冷却恒 0 不可配(空池不可能的结构前提——域校验锁死);撕咬 = 与突刺同倍率错开冷却轴的高频小爆发轮廓;毒爆 = 蛛化卓尔精灵专属池独占技 |
| 保底 M | 全局单旋钮,读技能表 pity_threshold;连续 M 拍执行普攻 → 下拍必出特殊技;单特殊技低权重池受保底支配 |
| 触发条件 | 情境技与闩型解锁的 fact 阈值读技能表 trigger 行值(2026-10-26 触发条件批设计闭合——词表与机制归敌人系统「触发条件」节);情境技的池内份额照走池权重行。**已投放两示范(2026-10-27 迭代 39,provisional)**:地精池孤注守势(self_hp_pct lte 35,纯增益技)+ L2/L3 群行位趁隙偷袭(last_round_end eq 停手,伤害技)——fact 阈值、权重、倍率与冷却逐行读表,本表零复制;地精池投放稀释含闸长期速率,EV 抽样锚已随重锚批换代(带宽注记随 `enemy.tres` 表注) |
| 池 EV 锚 | 静态份额与含闸长期速率实测读数登记于调参日志(EV 重锚与权重投值随本表修订)。**2026-09-19 节奏体验验证批登记**(60 distinct seeds × 双策略 × 两关,tools/skill_rhythm_audit.py——20 种子以下批次有种子偏置假象,读数须 ≥50 种子):特殊技执行份额 对表成立——地精 10.4%(静态 10%)/ 地精一伙 8.4% / 熊地精系 28.9–42.4% / 巨蜘蛛 34.8% / 酋长 28.9% / 卓尔 35.4%;**L2 池含闸速率抽样复核完成**(上项即含闸读数);保底越界 0/247(间隔 4 = M=4 合法上界);过涝信号 8/1440 场(最长连击 3);过旱按用户判读带集中在短命杂鱼(生存时长问题非池配置——见待办清单清单 Alpha 条目移交注记) |
| 池 EV 锚 | 静态份额与含闸长期速率实测读数登记于调参日志(EV 重锚与权重投值随本表修订)。**2026-09-19 节奏体验验证批登记**(60 组独立种子 × 双策略 × 两关的节奏实测,种子数下限 50 判读;20 种子以下批次有种子偏置假象):特殊技执行份额 对表成立——地精 10.4%(静态 10%)/ 地精一伙 8.4% / 熊地精系 28.9–42.4% / 巨蜘蛛 34.8% / 酋长 28.9% / 卓尔 35.4%;**L2 池含闸速率抽样复核完成**(上项即含闸读数);保底越界 0/247(间隔 4 = M=4 合法上界);过涝信号 8/1440 场(最长连击 3);过旱按用户判读带集中在短命杂鱼(生存时长问题非池配置——见待办清单清单 Alpha 条目移交注记) |
主角表与棋盘参数表(行值分别读 `hero.tres` 与 `board_gen.tres`,provisional):
@@ -325,7 +325,7 @@ Boss 战的棋盘用本关最大板形(板形行值读棋盘参数表),板
- 零红档:全部行集经区间扫描,不存在"最好情况也打不过"的战斗组合。
- 教学位绿档:第一关第一战与各新敌种首遇位的区间判定为绿档。
- 形态带成立:第一关形态 = 教学位绿 + 中段黄 + Boss 黄不红。
- 通关率带:**2026-10-03 带换代(用户拍板四带甲案)**——带 A 白板完美执行战役 [0,10%] / 带 B 白板 L1 [50,85%] / 带 C 满成长 [30,60%] 预立 / 带 D 响应曲线 ≤15pp·S 形;旧普通 L1 [35,55] / L2 [10,15]、完美 [35,65] 正式作废。测量口径维持冒险条件通关率(balance_verifier 冒险段派生);四带定稿全文见「期望值带」节「带换代」条。
- 通关率带:**2026-10-03 带换代(用户拍板四带甲案)**——带 A 白板完美执行战役 [0,10%] / 带 B 白板 L1 [50,85%] / 带 C 满成长 [30,60%] 预立 / 带 D 响应曲线 ≤15pp·S 形;旧普通 L1 [35,55] / L2 [10,15]、完美 [35,65] 正式作废。测量口径维持冒险条件通关率(由数值验证工具冒险段派生);四带定稿全文见「期望值带」节「带换代」条。
- 关卡完成余量带:关卡完成者剩余生命 p90 / p10 按现生命轴上限百分比表达,界值重标随验收批。
- 恒等式闭合:关级恒等式逐项对账闭合,残差 <5%(provisional 阈值);奖励输出占比 ∈ [15%, 40%]。
- Boss 锚在案:每个 Boss 行的血量锚比率记录在案且落在现行带内;越带须登记,不静默变更。
@@ -1,11 +1,11 @@
# 地图战斗资源
> 一句话:格面资源的产出、极性字典与清图奖励封装
> 状态:已定稿(自旧体系迁移)
> 状态:已定稿(自旧体系迁移);现行为 v1.1
## 设计目的
地图战斗资源是战斗域的资源层:每张雷图上每个格子携带什么资源、资源怎么摇定、正向与负向各兑付成什么效果、清图时整张板发什么,由它统一裁决。核心抽象是**格面资源(CellResource)**——关联到格子上的资源对象:装板时摇定类型身份,安全格与危险格一视同仁、同一类型池;资源本身不分好坏,被当成奖励还是惩罚,由玩家对这一格做的动作在结算期决定——开安全格、标中雷是正向,开危险格、标错安全格是负向(极性矩阵的定义归本文,路由执行归[战斗结算](战斗结算.md))。开局初始展开白送的那批格是**封锁格**——恒无资源,不再有任何加成(定义见[排雷玩法](../排雷循环/排雷玩法.md))。
地图战斗资源是战斗域的资源层:每张雷图上每个格子携带什么资源、资源怎么摇定、正向与负向各兑付成什么效果、清图时整张板发什么,由它统一裁决。核心抽象是**格面资源**——关联到格子上的资源对象:装板时摇定类型身份,安全格与危险格一视同仁、同一类型池;资源本身不分好坏,被当成奖励还是惩罚,由玩家对这一格做的动作在结算期决定——开安全格、标中雷是正向,开危险格、标错安全格是负向(极性矩阵的定义归本文,路由执行归[战斗结算](战斗结算.md))。开局初始展开白送的那批格是**封锁格**——恒无资源,不再有任何加成(定义见[排雷玩法](../排雷循环/排雷玩法.md))。
它守住三件事:每个非封锁格都有资源可兑(结构保证,不靠逐次掷运气);类型身份在装板期一次摇定、全程只读(在"数字恒真"的推理之外,类型是第二层规划素材);每个兑付都能在结算明细里指回挖开的哪一格。缺了这一层,挖格没有收益语言,"扫雷攒因、战斗结果"的兑现就断在最后一环。
@@ -70,7 +70,7 @@
### 候选集合:安全格与危险格的资源池
格面资源在每非封锁格上摇定身份时不区分格型——`_rollable_rows()` 把 cell 池正向行全集作为权重表,对所有非封锁格一视同仁地 `weighted_pick`。安全格与危险格候选集相同,权重分布相同,类型频次合计 = reward.tres cell 池正向行 weight 之和(现行值读表):
格面资源在每非封锁格上摇定身份时不区分格型——候选集合 = 格面资源池中全部正极性、权重大于零的类型行,不分格型一律参与摇号;负向兑付归战斗结算按极性路由。安全格与危险格候选集相同,权重分布相同,类型频次合计 = reward.tres cell 池正向行 weight 之和(现行值读表):
| 格型 | 候选集合(cell 池正向行,weight>0) | 类型频次合计 |
|---|---|---|
@@ -79,11 +79,6 @@
清图槽(clear_default 池,clear_blast)独立于格面资源——作用域为整张板,不挂任何一格。
引用(代码事实源):
- `game/core/reward_economy.gd#roll_board`:`_rollable_rows()` 第 207-213 行收 `pool_tag=cell & polarity=positive & weight>0` 全集;循环第 65-67 行对 `eligible` 清单(全部非封锁格)一视同仁。
- `game/core/minesweeper_rules.gd#_do_dig` 第 256-264 行:chain/dig 通道 `cell_revealed` 事件 `resource=true` 字段对安全格与危险格一致——注释明确"安全格与危险格一视同仁(危险格亦携带,负向兑付归 战斗结算 极性路由)"。
- `game/data/tables/reward.tres`:9 行正向行 weight 现行值读 `data/tables/reward.tres`。
候选集合具体行值(power / power_min / power_max / stacks / effect_id)随行更新——以 `data/tables/reward.tres` 为现行值源;GDD 表格只锁行集与权重分布语义。负向 9 行(enrage / off_guard / heal_backlash / enemy_alert / ap_drain / sapped / pierce_snare / magic_recoil / gp_loss——2026-09-20 八型批 ambush_double→enemy_alert 换装 + ap_drain 新增、同日 GP+商店房批 +gp_loss)weight=0 不参与摇号,按(类型, 极性)查表取用,不在候选集合内。
举证:本节为候选集合枚举,无计算。
@@ -101,7 +96,7 @@
- **档由两个参数定义:概率位 + 保底上限**。「永不保底」不单立规则——T4 的保底上限 = 0 即其统一表达;T1/T2 上限同为 0。
- **保底数量挂在型上、不挂在档上**:每个型各自登记「每板至少出几个」。档内登记保底的型数 ≤ 档上限 → 全部兑现;> 上限 → 每板从登记型中随机选定「上限」个兑现,其余型该板按普通概率出现、不保底。
- **补签纪律**:执行序 = 装板摇号(含偏运硬币/board_skew 投影)→ 按上限定本期保底型集合 → 校验补签 → 板上全程只读。补签只改类型身份:危险格与安全格不动(补签格可为雷可为安全格,危险格与安全格同池不破)、不消费权重(补签不是一次取号)、清图判定不动、不泄露元信息(补签格与摇号格不可区分)。粒度 = 板,换板重新校验。
- **补签纪律**:执行序 = 装板摇号(含偏运硬币投影)→ 按上限定本期保底型集合 → 校验补签 → 板上全程只读。补签只改类型身份:危险格与安全格不动(补签格可为雷可为安全格,危险格与安全格同池不破)、不消费权重(补签不是一次取号)、清图判定不动、不泄露元信息(补签格与摇号格不可区分)。粒度 = 板,换板重新校验。
- **GP 数值锚**:以战斗结束 GP 奖励为锚——小 GP 袋 ≈ 其 1/10、大宝箱 ≈ 其 1 倍(具体数值归调参批)。
- 大宝箱为枚举新增(九型→十型走本文修订流程,不随手加行);微光归通用增益组(五色相不变,组内不细分正好容下)。
- **对外稀有度映射**(现行事实源=[核心循环](../../01-核心循环.md)「档位与获取规则」节):T1=普通 / T2=优秀 / T3=稀有 / T4=传说;任何概率提升禁止改变本档保底承诺(保底=承诺非概率)。
@@ -128,13 +123,13 @@
| 类型 | 正向(奖励) | 负向(惩罚) |
|---|---|---|
| attack 增伤 | attack_up(hero_offense 池)——幅度/上限/权重见 `reward.tres` | enrage(enemy_output 池)——幅度/上限见 `status_effects.tres` enrage 行 |
| defense 护甲 | ac_up 盾牌加护(AC 掷点阈值轴——2026-09-16 换装,不入池)——幅度/上限/权重见 `reward.tres` | off_guard 失衡(AC 掷点阈值轴负向——2026-09-18 换装,不入池、退出 hero_defense 池)——幅度/上限见 `status_effects.tres` off_guard 行 |
| attack 增伤 | attack_up(主角输出池)——幅度/上限/权重见 `reward.tres` | enrage(敌方输出池)——幅度/上限见 `status_effects.tres` enrage 行 |
| defense 护甲 | ac_up 盾牌加护(AC 掷点阈值轴——2026-09-16 换装,不入池)——幅度/上限/权重见 `reward.tres` | off_guard 失衡(AC 掷点阈值轴负向——2026-09-18 换装,不入池、退出主角防御池)——幅度/上限见 `status_effects.tres` off_guard 行 |
| heal 回血 | heal_minor(满血零兑付照旧)——威力/权重见 `reward.tres` | heal_backlash 直伤:战斗结算直接扣血,不经增益状态——威力见 `reward.tres` |
| blast 群伤 | spark_aoe 全体存活敌各吃一笔——威力/权重见 `reward.tres` | enemy_alert 警觉:敌方全体护甲等级 +1/层(`status_effects.tres` alert 行)——见 `reward.tres` |
| weaken 削弱 | weaken(enemy_output 池;同名重复授予只刷新剩余次数——2026-09-18 续时定案)——幅度见 `status_effects.tres` weaken 行 | sapped(hero_offense 池)——幅度见 `status_effects.tres` sapped 行 |
| weaken 削弱 | weaken(敌方输出池;同名重复授予只刷新剩余次数——2026-09-18 续时定案)——幅度见 `status_effects.tres` weaken 行 | sapped(主角输出池)——幅度见 `status_effects.tres` sapped 行 |
| action 行动点 | ap_up:下轮行动点 +1——见 `reward.tres` | ap_drain 迟滞:下轮行动点 −1——见 `reward.tres` |
| gp 财货 | gp_gain GP 袋:战斗内 GP 缓冲 +power,战斗完成随 gp_dropped 统一入钱包账本(兑付编排归[战斗结算](战斗结算.md)、账本归[冒险结构](../冒险循环/冒险结构.md))——威力/权重见 `reward.tres` | gp_loss 破财:战斗内 GP 缓冲 −power,weight=0 纯字典不参与摇号——见 `reward.tres` |
| gp 财货 | gp_gain GP 袋:战斗内 GP 缓冲 +power,战斗完成随 GP 掉落统一入钱包账本(兑付编排归[战斗结算](战斗结算.md)、账本归[冒险结构](../冒险循环/冒险结构.md))——威力/权重见 `reward.tres` | gp_loss 破财:战斗内 GP 缓冲 −power,weight=0 纯字典不参与摇号——见 `reward.tres` |
| pierce 穿刺 | pierce_strike 穿刺弹:单目标克制直伤(attack_type=pierce 查克制矩阵,必中全额不掷点;目标 = 固定顺位最前存活敌)——威力/权重见 `reward.tres` | pierce_snare 穿刺陷阱:主角直伤,不经增益状态——威力见 `reward.tres` |
| magic 魔法 | magic_bolt 魔法矢:单目标克制直伤(attack_type=magic,同上)——威力/权重见 `reward.tres` | magic_recoil 魔法反噬:主角直伤,不经增益状态——威力见 `reward.tres` |
@@ -146,7 +141,7 @@
### 负向恒即时:惩罚没有库存语义
负向兑付的账户动作全部在授予段受理,不入库、不出窗口——惩罚不设库存、不留存量;其中**伤害形态(群伤/直伤类负向行)的扣血落地殿后到战斗段末**(2026-10-06 用户裁,单据暂存,见[战斗结算](战斗结算.md));主角在敌方还手中倒下则地图伤害账整体不兑(逐单留「未生效」行)。正向里的 percent 类(增益行)进[增益状态](增益状态.md)的状态池;heal 正向当场结算;gp 正负两向(GP 袋 / 破财)当场执行——记入战斗内 GP 缓冲,战斗完成随 gp_dropped 与钱包结算(账本归[冒险结构](../冒险循环/冒险结构.md)),同样无库存语义。叠层饱和由战斗结算既有池 clamp 承载;blast 负向(警觉)与 action 负向(迟滞)直授无上限。
负向兑付的账户动作全部在授予段受理,不入库、不出窗口——惩罚不设库存、不留存量;其中**伤害形态(群伤/直伤类负向行)的扣血落地殿后到战斗段末**(2026-10-06 用户裁,单据暂存,见[战斗结算](战斗结算.md));主角在敌方还手中倒下则地图伤害账整体不兑(逐单留「未生效」行)。正向里的 percent 类(增益行)进[增益状态](增益状态.md)的状态池;heal 正向当场结算;gp 正负两向(GP 袋 / 破财)当场执行——记入战斗内 GP 缓冲,战斗完成随 GP 掉落与钱包结算(账本归[冒险结构](../冒险循环/冒险结构.md)),同样无库存语义。叠层饱和由战斗结算既有池 clamp 承载;blast 负向(警觉)与 action 负向(迟滞)直授无上限。
举证:本节为兑付语义,无计算。
@@ -215,23 +210,23 @@
| 行 | 类型 | 极性 | 取值域 / 字段语义 | 现行值 | 所在池 |
|---|---|---|---|---|---|
| attack_up | attack | 正向 | weight [0,999] · power 不消费(percent 行 effect_id → StatusEffectTable attack_up 引用) | 见 `data/tables/reward.tres` | 格面池 |
| ac_up | defense | 正向 | weight [0,999] · power 不消费(percent 行 effect_id → StatusEffectTable ac_up 引用) | 同上 | 同上 |
| attack_up | attack | 正向 | weight [0,999] · power 不消费(percent 行 effect_id → 状态效果表 attack_up 引用) | 见 `data/tables/reward.tres` | 格面池 |
| ac_up | defense | 正向 | weight [0,999] · power 不消费(percent 行 effect_id → 状态效果表 ac_up 引用) | 同上 | 同上 |
| spark_aoe | blast | 正向 | power [0,999]·power_min/power_max 可选区间·weight [0,999](flat 行 effect_id 恒空) | 同上 | 同上 |
| heal_minor | heal | 正向 | power [0,999]·power_min/power_max 可选区间·weight [0,999](flat 行 effect_id 恒空) | 同上 | 同上 |
| weaken | weaken | 正向 | weight [0,999] · power 不消费(percent 行 effect_id → StatusEffectTable weaken 引用) | 同上 | 同上 |
| enrage | attack | 负向 | weight=0 不参与摇号·power 不消费(percent 行 effect_id → StatusEffectTable enrage 引用) | 同上 | 同上 |
| off_guard | defense | 负向 | weight=0 不参与摇号·power 不消费(percent 行 effect_id → StatusEffectTable off_guard 引用) | 同上 | 同上 |
| weaken | weaken | 正向 | weight [0,999] · power 不消费(percent 行 effect_id → 状态效果表 weaken 引用) | 同上 | 同上 |
| enrage | attack | 负向 | weight=0 不参与摇号·power 不消费(percent 行 effect_id → 状态效果表 enrage 引用) | 同上 | 同上 |
| off_guard | defense | 负向 | weight=0 不参与摇号·power 不消费(percent 行 effect_id → 状态效果表 off_guard 引用) | 同上 | 同上 |
| heal_backlash | heal | 负向 | weight=0 不参与摇号·power [0,999](flat 行 effect_id 恒空) | 同上 | 同上 |
| enemy_alert | blast | 负向 | weight=0 不参与摇号·effect_id=alert(敌方护甲等级 +1——effect 引用行,unit=ac) | 同上 | 同上 |
| ap_up | action | 正向 | weight [0,999] 参与摇号 | 同上 | 同上 |
| ap_drain | action | 负向 | weight=0 不参与摇号 | 同上 | 同上 |
| gp_gain | gp | 正向 | weight [0,999] 参与摇号 · power [0,999]·power_min/power_max 可选区间(flat 行 effect_id 恒空) | 同上 | 同上 |
| gp_loss | gp | 负向 | weight=0 不参与摇号 · power [0,999](flat 行 effect_id 恒空) | 同上 | 同上 |
| sapped | weaken | 负向 | weight=0 不参与摇号·power 不消费(percent 行 effect_id → StatusEffectTable sapped 引用) | 同上 | 同上 |
| sapped | weaken | 负向 | weight=0 不参与摇号·power 不消费(percent 行 effect_id → 状态效果表 sapped 引用) | 同上 | 同上 |
| clear_blast | blast | 正向 | clear_default 池·power [0,999]·power_min/power_max 可选区间·weight [0,999] | 同上 | 清图槽 |
摇号只消费正向格面池的权重(类型频次由此涌现——具体权重读 `reward.tres`);负向行是纯兑付字典,按(类型,极性)查表取用,不消费权重。权重分布按四档概率结构组织(档成员与保底规则见「四档概率结构与保底」节;现行权重为基准锚,数值调整归调参批)。clear_blast 对全体存活敌各吃一笔当场兑付的 flat 伤害。RewardConfigTable 已随可选类删除下线——注入概率、按板保底等参数全部失义(旧「按板保底」指已删除的可选类道具注入保底,与四档结构的型级保底无关)。
摇号只消费正向格面池的权重(类型频次由此涌现——具体权重读 `reward.tres`);负向行是纯兑付字典,按(类型,极性)查表取用,不消费权重。权重分布按四档概率结构组织(档成员与保底规则见「四档概率结构与保底」节;现行权重为基准锚,数值调整归调参批)。clear_blast 对全体存活敌各吃一笔当场兑付的 flat 伤害。奖励配置表已随可选类删除下线——注入概率、按板保底等参数全部失义(旧「按板保底」指已删除的可选类道具注入保底,与四档结构的型级保底无关)。
结构冻结(改动走本文修订流程,不走调参):九型封闭枚举(伤害道具批 2026-09-18 修订五→七、格面资源八型批 2026-09-20 修订七→八、同日 GP+商店房批修订八→九)、危险格与安全格同池、极性矩阵、装板期预分配且无重摇、负向恒即时无库存、清图恒非空、除摇号外零随机(四档保底补签属装板期校验环节,消费摇号环节随机流,非重摇——补签后身份全程只读)。
@@ -244,7 +239,7 @@
- 类型封闭与字典完整:表里出现九型之外的类型、或任一型缺正向/负向行,加载拒绝。
- 未生效可见:满层增益、满血正向治疗、无存活敌的群伤,各自在结算明细记"奖励未生效"行,零折算、零补偿。
- 加载护栏:池空、清图池无正当量、增益引用悬空——任一命中即加载时返回错误并中止;默认内容加载通过。
- 表实一致:数据表字段与 `data/schemas/reward_table.gd` 逐字段一致。
- 表实一致:数据表字段与奖励表字段定义逐字段一致。
## 待办
+10 -10
View File
@@ -1,7 +1,7 @@
# 增益状态
> 一句话:增益/减益的状态池、叠层与衰减
> 状态:已定稿(自旧体系迁移);现行为 v1.1
> 状态:已定稿(自旧体系迁移);现行为 v1.2
## 设计目的
@@ -168,11 +168,11 @@
| weaken 削弱 | 敌方攻击被削弱(同名重复标中只刷新剩余次数、层数恒 1) | 敌方 | 见 `status_effects.tres` weaken 行(取值域 [60,85],取负生效) | 时限读表 / 刷新(2026-09-18 续时定案) | 封印标中 |
| enrage 暴走 | 敌方攻击提升 | 敌方 | 见 `status_effects.tres` enrage 行 | 时限/上限读表 / 叠加 | 标空封印反噬 / 踩雷(attack 型负向) |
| off_guard 失衡 | 主角护甲等级降低(AC 轴——掷点判定阈值下调、更易被命中;2026-09-18 换装,原百分比承伤池已退) | 主角 | 见 `status_effects.tres` off_guard 行 | 时限/上限读表 / 叠加 | 标空封印反噬 / 踩雷(defense 型负向)/ 敌方妨害技(2026-09-19 新效应词汇批——蛛网束缚载体,duration 由技能行覆盖) |
| sapped 乏力 | 主角输出降低(weaken 型负向,hero_offense 池) | 主角 | 见 `status_effects.tres` sapped 行 | 时限/上限读表 / 叠加 | 危险格负向 / 标空封印(2026-09-15 格面资源批)/ 敌方妨害技(大地脉动——L3 Boss 石君王独占,2026-09-20 第三关内容批) |
| empower 蓄力 | 敌方输出倍率增益(enemy_output 池——蓄力技载体;幅度读表) | 敌方 | 见 `status_effects.tres` empower 行 | duration 读表 = 1 个有效增益拍 / 刷新 | 敌方技能施放(2026-09-16 敌人技能池批) |
| fortify 硬化 | 敌方防御提升(**敌方防御池 enemy_defense**——硬化技载体;负值入池 = 主角攻击折半,2026-09-18 符号纠正——旧正值实际翻倍) | 敌方 | 见 `status_effects.tres` fortify 行 | duration 读表 = 1 个有效增益拍 / 刷新 | 敌方技能施放(2026-09-16 敌人技能池批) |
| sapped 乏力 | 主角输出降低(weaken 型负向,主角输出池) | 主角 | 见 `status_effects.tres` sapped 行 | 时限/上限读表 / 叠加 | 危险格负向 / 标空封印(2026-09-15 格面资源批)/ 敌方妨害技(大地脉动——L3 Boss 石君王独占,2026-09-20 第三关内容批) |
| empower 蓄力 | 敌方输出倍率增益(敌方输出池——蓄力技载体;幅度读表) | 敌方 | 见 `status_effects.tres` empower 行 | duration 读表 = 1 个有效增益拍 / 刷新 | 敌方技能施放(2026-09-16 敌人技能池批) |
| fortify 硬化 | 敌方防御提升(**敌方防御池**——硬化技载体;负值入池 = 主角攻击折半,2026-09-18 符号纠正——旧正值实际翻倍) | 敌方 | 见 `status_effects.tres` fortify 行 | duration 读表 = 1 个有效增益拍 / 刷新 | 敌方技能施放(2026-09-16 敌人技能池批) |
empower 与 fortify 是敌方技能池增益技在状态池侧的数据落点(技能行 buff_ref 引用,施放时长由技能行覆盖——技能冷却与增益持续是两个计时器):两行 duration 表值(读表)的口径是"先兑付后衰减含施放当轮"——施放发生在第 N 结算战斗段,存活到第 N+1 结算战斗段才兑付"下一拍",即"持续 1 个有效结算"(proposal 语义的状态池落地)。敌方防御池(enemy_defense)是第四个乘区池:敌方作为防守方的百分比修正池,消费面 = [战斗结算](战斗结算.md)主角攻击的池乘区——四池对称(敌打主角 = hero_defense × enemy_output,主角打敌 = hero_offense × enemy_defense),状态池语义零延伸:仍是同构实例、side-wide 加算、不封顶不保底。
empower 与 fortify 是敌方技能池增益技在状态池侧的数据落点(技能行 buff_ref 引用,施放时长由技能行覆盖——技能冷却与增益持续是两个计时器):两行 duration 表值(读表)的口径是"先兑付后衰减含施放当轮"——施放发生在第 N 结算战斗段,存活到第 N+1 结算战斗段才兑付"下一拍",即"持续 1 个有效结算"(proposal 语义的状态池落地)。敌方防御池是第四个乘区池:敌方作为防守方的百分比修正池,消费面 = [战斗结算](战斗结算.md)主角攻击的池乘区——四池对称(敌打主角 = 主角防御池 × 敌方输出池,主角打敌 = 主角输出池 × 敌方防御池),状态池语义零延伸:仍是同构实例、side-wide 加算、不封顶不保底。
削弱行是当量锚在状态池侧的数据落点:封印标中的收益折算成统一价值后,必须严格高于最低档主角增益——"封印标中必须比随便挖一格更值",否则没人愿意封印。这条锚的契约归[行动经济](../排雷循环/行动经济.md),对照验收归[战斗结算](战斗结算.md);暴走与失衡两行分别是 attack/defense 型负向(极性矩阵"标错/踩雷"分支兑付)在状态池侧的数据落点:行内容与载体裁决归它,本表只承载行值(失衡已换装 AC 轴不入池——2026-09-18 结构修复批)。**失衡另有第二来源**:敌方妨害技(2026-09-19 新效应词汇批——蛛化卓尔精灵"蛛网束缚",敌方技能施放来源、duration 由技能行 buff_duration 覆盖)——状态池零新语义,同构实例照常受理;乏力 sapped = 妨害第二词汇,载体已落地(L3 Boss 灰矮人石君王独占妨害技「大地脉动」,2026-09-20 第三关内容批)。
@@ -226,16 +226,16 @@ empower 与 fortify 是敌方技能池增益技在状态池侧的数据落点(
| alert 幅度 | [0, 4] | ac 行 magnitude | 警觉(敌方护甲等级 +1/层 provisional);消费 = 战斗结算护甲等级掷点判定 |
| weaken 幅度 | 百分比取值域 [60,85],取负生效 | percent 行 magnitude | 削弱;须过"封印标中锚"对照 |
| enrage 幅度 | 百分比 [−100,100] 且非 0 | percent 行 magnitude | 暴走;attack 型负向行,进敌方输出修正池 |
| off_guard 幅度 | 护甲等级 [−20,20] 且非 0 | ac 行 magnitude | 失衡;标空封印反噬载体,掷点判定阈值逐层下调(2026-09-18 换装 AC 轴,不入池、退出 hero_defense 池) |
| off_guard 幅度 | 护甲等级 [−20,20] 且非 0 | ac 行 magnitude | 失衡;标空封印反噬载体,掷点判定阈值逐层下调(2026-09-18 换装 AC 轴,不入池、退出主角防御池) |
| sapped 幅度 | 百分比 [−100,100] 且非 0 | percent 行 magnitude | 乏力;危险格负向 weaken 型,进主角输出修正池(2026-09-15 格面资源批补登记) |
| empower 幅度 | 百分比 [−100,100] 且非 0 | percent 行 magnitude | 蓄力;敌方技能池增益技载体,进敌方输出修正池 |
| fortify 幅度 | 百分比 [−100,100] 且非 0 | percent 行 magnitude | 硬化;敌方技能池增益技载体,进**敌方防御池 enemy_defense**(负值 = 减伤方向——2026-09-18 符号纠正) |
| 初始剩余次数 | 整数 [1,99] | duration_settlements | 一次性语义行逐行读表;续时行 = weaken(2026-09-18 定案,duration 2)+ empower/fortify(1 个有效增益拍——先兑付后衰减含施放当轮)+ **attack_up / ac_up(2026-09-20 主角增益续时批,duration 表值 1 维持——续时语义在 dur=1 下表现为重复拿重置当轮倒数;跨轮延续随将来 duration 拉长自然显形,数值归状态层重设计批)**;拉长 = 恢复跨轮延续、规划变简单 |
| fortify 幅度 | 百分比 [−100,100] 且非 0 | percent 行 magnitude | 硬化;敌方技能池增益技载体,进**敌方防御池**(负值 = 减伤方向——2026-09-18 符号纠正) |
| 初始剩余次数 | 整数 [1,99] | duration_settlements | 一次性语义行逐行读表;续时行 = weaken(2026-09-18 定案,duration 2)+ empower/fortify(1 个有效增益拍——先兑付后衰减含施放当轮)+ **attack_up / ac_up(2026-09-20 主角增益续时批,duration 表值 1 维持——续时语义在 duration=1 下表现为重复拿重置当轮倒数;跨轮延续随将来 duration 拉长自然显形,数值归状态层重设计批)**;拉长 = 恢复跨轮延续、规划变简单 |
| 叠层上限 | 整数 [1,16] | max_stack | 仅叠加策略消费;刷新行层数恒 1——weaken / attack_up / ac_up 表值上限在续时语义下不消费(2026-09-18 / 2026-09-20),empower/fortify ×1(冷却闸下不可能自叠加) |
非调参的冻结项:三类合并策略语义、两种量纲语义、来源类别枚举、"先兑付后衰减"时序、拒绝原子性、零随机——改动走本文修订流程,不走调参。
联动纪律:增伤与削弱是当量锚的两端;盾牌加护与[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)的承伤预期联动(掷点折扣轴——AC 行值变更须复算生存链区间;2026-09-20 主角增益续时批后 ac_up 层数恒 1、局内可达 AC 上限 11,复算随调参批);削弱改续时后"单轮层数上限受[行动经济](../排雷循环/行动经济.md)行动点约束"的联动随之失效(2026-09-18 续时定案——同名重复标中只刷新剩余次数、层数恒 1;2026-09-20 起主角侧 attack_up / ac_up 同口径)。这些联动值禁止独立调参,修订须重跑锚对照并同步 registry。
联动纪律:增伤与削弱是当量锚的两端;盾牌加护与[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)的承伤预期联动(掷点折扣轴——AC 行值变更须复算生存链区间;2026-09-20 主角增益续时批后 ac_up 层数恒 1、局内可达 AC 上限 11,复算随调参批);削弱改续时后"单轮层数上限受[行动经济](../排雷循环/行动经济.md)行动点约束"的联动随之失效(2026-09-18 续时定案——同名重复标中只刷新剩余次数、层数恒 1;2026-09-20 起主角侧 attack_up / ac_up 同口径)。这些联动值禁止独立调参,修订须重跑锚对照并同步登记册。
## 验收标准
@@ -249,7 +249,7 @@ empower 与 fortify 是敌方技能池增益技在状态池侧的数据落点(
- 合成不设上下限:状态池输出的有效值恒等于层数 × 行值,越出百分比域不封顶不保底;地板在战斗结算侧。
- 快照抗重载:已授予实例的数值在战斗中不受配置表重载影响,只影响后续授予。
- 确定性回放:同一授予序列驱动两个独立状态池实例,生效清单(含排列顺序)与衰减轨迹逐项相同。
- 表实一致:配置表字段与 `data/schemas/status_effect_table.gd` 逐字段一致。
- 表实一致:配置表字段与状态表的字段定义逐字段一致。
## 待办
+20 -20
View File
@@ -1,7 +1,7 @@
# 战斗结算
> 一句话:轮末结算的编排与逐行兑现
> 状态:已定稿(自旧体系迁移);现行为 v1.1
> 状态:已定稿(自旧体系迁移);现行为 v1.2
## 设计目的
@@ -64,7 +64,7 @@
| ④ 衰减段 | 移除到期的临时效果;每轮恰好一次,含末轮——清图奖励先兑付、效果后衰减 |
| ⑤ 判定段 | 先判主角倒下(负),再判敌人清空(胜),都不满足则继续下一轮 |
结算本体是纯逻辑步骤流:零界面依赖、禁止动画等待,随机消费只走封闭随机流。触发只读行动经济的相位读数与轮末标记,这条消息有棋盘路径和停手路径两个发射源,到达先后不承载语义。这些性质共同保证结算可回放:同样的种子、同样的事件序列,跑出的步骤流逐位复现——录像回放与断言复测都建立在它上面。随机消费恰七处(2026-09-16 敌人技能池批由两处扩为三处;2026-09-17 分支节点图批换板入编排后扩为五处;2026-09-20 地形变异首批类型定稿批扩为六处——变异布置;同日 GP+商店房批扩为七处——战斗结束掉落掷定):战斗开始掷骰定敌方实际数量与攻击基线浮动,属于初始化随机、发生在结算步骤流之外;技能摇号属于回合内随机,但时点前置到每轮开轮、同样发生在结算步骤流之外(消费专用 `behavior_roll` 封闭流,每敌按生成序派生独立子流,单敌出招轨迹可独立复放、互不穿插);护甲等级掷点属于回合内随机、发生在步骤流之内(消费专用 `armor_roll` 封闭流,逐次掷逐次取号,可逐位回放);奖励格摇号(消费 `reward_roll` 封闭流,装板期格面资源批派发)、变异布置(消费 `variant_place` 封闭流,装板与资源预分配之后——棋盘设置顺序第 4 步)与换板棋盘生成(消费 `board_gen` 封闭流,清图轮换板时点)均属初始化随机、发生在结算步骤流之外;战斗结束掉落掷定属出口随机(消费 `gp_drop` 封闭流,按战斗节点身份查商店表掷定 GP 掉落,与关级加值、战斗内缓冲合成本战 gp_dropped),发生在结算步骤流之外。七处皆封闭随机流,同种子同输入逐位复现。
结算本体是纯逻辑步骤流:零界面依赖、禁止动画等待,随机消费只走封闭随机流。触发只读行动经济的相位读数与轮末标记,这条消息有棋盘路径和停手路径两个发射源,到达先后不承载语义。这些性质共同保证结算可回放:同样的种子、同样的事件序列,跑出的步骤流逐位复现——录像回放与断言复测都建立在它上面。随机消费恰七处(2026-09-16 敌人技能池批由两处扩为三处;2026-09-17 分支节点图批换板入编排后扩为五处;2026-09-20 地形变异首批类型定稿批扩为六处——变异布置;同日 GP+商店房批扩为七处——战斗结束掉落掷定):战斗开始掷骰定敌方实际数量与攻击基线浮动,属于初始化随机、发生在结算步骤流之外;技能摇号属于回合内随机,但时点前置到每轮开轮、同样发生在结算步骤流之外(消费专用 `behavior_roll` 封闭流,每敌按生成序派生独立子流,单敌出招轨迹可独立复放、互不穿插);护甲等级掷点属于回合内随机、发生在步骤流之内(消费专用 `armor_roll` 封闭流,逐次掷逐次取号,可逐位回放);奖励格摇号(消费 `reward_roll` 封闭流,装板期格面资源批派发)、变异布置(消费 `variant_place` 封闭流,装板与资源预分配之后——棋盘设置顺序第 4 步)与换板棋盘生成(消费 `board_gen` 封闭流,清图轮换板时点)均属初始化随机、发生在结算步骤流之外;战斗结束掉落掷定属出口随机(消费 `gp_drop` 封闭流,按战斗节点身份查商店表掷定 GP 掉落,与关级加值、战斗内缓冲合成本战 GP 掉落),发生在结算步骤流之外。七处皆封闭随机流,同种子同输入逐位复现。
举证:五段为流程编排,无计算;段序常量存配置表,加载时校验与定稿顺序完全一致,不一致拒绝启动。
@@ -79,7 +79,7 @@
| 治疗行 | 治疗生效一行:封顶后的真实回复量 |
| 奖励未生效行 | 满层拒收、满血治疗等合法例外一行 |
| 封印未中行 | 封印落空的零值归因行,每颗雷只记一次;标错的负向兑付另记效果行 |
| 蓄力行 | 敌人本拍蓄力不动手(攒下一击)时记一行 **(2026-09-16 敌人技能池批改型为施放行 `cast`:敌人本拍施放增益技——0 伤害动作、具名技能、不掷不折〔原"不兑付伏击"读怪奖励语义随 2026-09-20 八型批伏击退役作废〕;蓄力语义改写为纯攻击增益技,见[敌人系统](敌人系统.md))** |
| 蓄力行 | 敌人本拍蓄力不动手(攒下一击)时记一行 **(2026-09-16 敌人技能池批改型为施放行:敌人本拍施放增益技——0 伤害动作、具名技能、不掷不折〔原"不兑付伏击"读怪奖励语义随 2026-09-20 八型批伏击退役作废〕;蓄力语义改写为纯攻击增益技,见[敌人系统](敌人系统.md))** |
| 衰减行 | 到期临时效果移除一行 |
| 判定行 | 胜 / 负 / 继续各一行;终局判定行同时是胜负画面的数据锚 |
| 高光行 | 完美封印成立时一行,只记实际有效兑付 |
@@ -100,7 +100,7 @@
基础 9 类写的是裸机制的账:玩家没有任何专长时,结算流水的每一行都出得了这九类。有了专长之后,效果引擎会在段内挂点插入额外的结算效果,这类效果写**扩展行**。扩展行是**一个**行型,不是每种专长效果各占一个行型——具体插的是哪种效果,由行携带的效果身份(effect_id 载荷)说明,呈现层按身份取各自的行文案。专长会不断增加、效果种类不可穷举,行型词表因此对扩展类封口:新增专长效果只新增载荷身份,不再新增行型。
扩展行与基础行共用同一套行协议:公共字段、来源归因、两层豁免、无来源即炸,全部照常生效。发射时点由段序骨架的挂点决定(时序与挂点施加面归架构文档「模块归属·战斗域装配现状」节),本节只管这行是什么、带什么字段。实现已收敛为单一扩展行型(`extended`)+效果身份载荷(`effect_id`);效果身份清单与发射点以实现侧 `battle_orchestrator.gd` 文件头注为准。
扩展行与基础行共用同一套行协议:公共字段、来源归因、两层豁免、无来源即炸,全部照常生效。发射时点由段序骨架的挂点决定(时序与挂点施加面归架构文档「战斗域装配现状」节),本节只管这行是什么、带什么字段。扩展行携带效果身份(effect_id 载荷);效果身份清单与各发射点归架构文档「战斗域装配现状」与「战斗编排域拆件定稿」节登记。
举证:本节为行协议约定,无计算。
@@ -123,7 +123,7 @@ percent 类(每结算、每层): E = |层数 × 行值| ÷ 100 ×
| 层数 × 行值 | 单条效果的叠层数与行值,读[增益状态](增益状态.md)的实例数据 | 行值归该系统 |
| 完美乘数 | 完美封印给清图奖励的乘数,配置值 | 读 `settlement.tres` p_perfect(现行值读表) |
**gp / ap 当量口径注记(2026-10-05 判式换代批 T3——口径空白登记)**:上式 flat 类枚举(直伤、治疗、行动点)不含 gp——现行对账按 **gp 当量 = flat power 代理**计(GP 袋 3 / 破财 2,方案报告假设 A5);ap 当量 = flat 表值 1,机会成本口径(+1AP ≈ 多挖一格 ≈ E_dig + 进度 + 信息价值)更高,差异仅登记不进主算(假设 A6)。gp 的精确口径应经商店定价换算(1 GP 的边际属性当量),归状态层/商店批复核后换代。封印溢价兑付(条款3 条件二形态 a,`settlement.tres` flag_hit_premium=125 provisional)按同型正向 ×(1+δ) 兑付——当量换算随同型行口径同步放大,整数量级取整四舍五入(与伤害管线 round_direction=floor 分域,registry 顺带登记)。
**gp / ap 当量口径注记(2026-10-05 判式换代批 T3——口径空白登记)**:上式 flat 类枚举(直伤、治疗、行动点)不含 gp——现行对账按 **gp 当量 = flat power 代理**计(GP 袋 3 / 破财 2,方案报告假设 A5);ap 当量 = flat 表值 1,机会成本口径(+1AP ≈ 多挖一格 ≈ E_dig + 进度 + 信息价值)更高,差异仅登记不进主算(假设 A6)。gp 的精确口径应经商店定价换算(1 GP 的边际属性当量),归状态层/商店批复核后换代。封印溢价兑付(条款3 条件二形态 a,`settlement.tres` flag_hit_premium=125 provisional)按同型正向 ×(1+δ) 兑付——当量换算随同型行口径同步放大,整数量级取整四舍五入(与伤害管线向下取整口径分域,登记册顺带登记)。
### 授予段兑付:极性路由,四类动作各归各系统资源
@@ -138,7 +138,7 @@ percent 类(每结算、每层): E = |层数 × 行值| ÷ 100 ×
| ① 插危险格、留到轮末判定 | 标中照常(该危险格资源正向) |
| ② 插危险格、再直接挖开 | 只受挖雷一层惩罚(该危险格资源负向照常兑付;挖雷惩罚因惊动触发);标中不发(封印已随挖掘消失、不入判定基线) |
| ③ 插安全格、留到轮末判定 | 标空惩罚照常(该安全格资源负向) |
| ④ 插安全格、再直接挖开 | 零惩罚零奖励——正向兑付作废,记「奖励作废(封印格直接挖开)」归因行(reward_ineffective 行型);标空判定同②自然缺席 |
| ④ 插安全格、再直接挖开 | 零惩罚零奖励——正向兑付作废,记「奖励作废(封印格直接挖开)」归因行;标空判定同②自然缺席 |
| 批 | 兑付 |
|---|---|
@@ -157,8 +157,8 @@ percent 类(每结算、每层): E = |层数 × 行值| ÷ 100 ×
| 即时治疗(flat) | heal 正向 | 主角按表值回复并封顶上限 | 满血时零兑付,记"奖励未生效"行 |
| 直伤(flat) | heal 负向 | 主角在战斗段末扣表值生命(暂存单殿后统一落地),不经增益状态 | 主角倒下则地图账整体不兑,逐单留"未生效"行 |
| 警觉加层 | blast 负向 | 敌方全体护甲等级 +1/层(读 `reward.tres` enemy_alert 行 → `status_effects.tres` alert 行),入状态池 | 直授无上限;战斗段由防守方护甲等级读数消费 |
| GP 缓冲(flat) | gp 正 / 负向 | GP 袋 / 破财按 power 记入战斗内 GP 缓冲(+power / −power);缓冲随战斗完成折进 battle_finished 的 gp_dropped 统一到账(GP 归[冒险结构](../冒险循环/冒险结构.md)) | 无拒收态——缓冲只在战斗边界与钱包结算,战斗域零钱包状态 |
| 行动点修正 | action 正/负向 | 下轮行动点 ±power(action_economy 排队,下一轮开始兑现后清零;下限 0) | 排队净值不跨轮保留;明细记效果行(effect_id=ap_delta) |
| GP 缓冲(flat) | gp 正 / 负向 | GP 袋 / 破财按 power 记入战斗内 GP 缓冲(+power / −power);缓冲随战斗完成折进战斗结束信号的 GP 掉落统一到账(GP 归[冒险结构](../冒险循环/冒险结构.md)) | 无拒收态——缓冲只在战斗边界与钱包结算,战斗域零钱包状态 |
| 行动点修正 | action 正/负向 | 下轮行动点 ±power(行动经济排队,下一轮开始兑现后清零;下限 0) | 排队净值不跨轮保留;明细记效果行(effect_id=ap_delta) |
警觉(blast 负向——2026-09-20 八型批伏击退役换装)为敌方 side-wide 状态:多个敌人共享同一状态值、互不消耗,只活一轮、轮末清零;战斗段由防守方护甲等级读数消费(我打敌 = 敌方 armor_class + Σ敌方侧 ac 型状态)。其余各型负向受池 clamp 与叠层上限承载。
@@ -216,7 +216,7 @@ percent 类(每结算、每层): E = |层数 × 行值| ÷ 100 ×
| 穿刺 | 被克 | 克制 | 中性 | 对魔法护甲克制;对轻甲被克;**重甲中性**(挡得住刀刃、不排斥穿刺——2026-09-18 用户拍板;现行无重甲敌种,纯结构位) |
| 魔法 | 中性 | 被克 | 克制 | 绕得过重甲,被魔法护甲吸收 |
修正三档:克制 +1 / 中性 0 / 被克 −1(加法点数,九格分布读 `settlement.tres` 甲效矩阵——2026-09-18 加法核换装:量纲由百分比改点数、五档词表退役;三档而非五档的理由 = 攻击基线个位数刻度下 ±2 触伤害下限或翻倍超重,假粒度;攻击成长后可扩弱档)。攻击类型是分量的固有属性(每个分量恒属普通 / 穿刺 / 魔法 之一),护甲类型是防守单位的固有属性,两者都不随层数、来源与轮次漂移;基础分量的类型归属是主角表的可配置值(营地永久强化的换型落点),矩阵键集 3×3 满格、结构冻结,数值 provisional。矩阵消费面 = 主角侧(奖励直伤道具 / 主角攻击基础分量)——敌方攻击现行不查矩阵,主角 armor_type 轴仍休眠、生效待敌方技能攻击类型批。主角增益与乏力经 hero_offense 池修正攻击合计(2026-09-18 结构修复批:普通分量直乘旁路退役;2026-09-19 充能退役后合计 = 单分量,见池乘区公式行)。
修正三档:克制 +1 / 中性 0 / 被克 −1(加法点数,九格分布读 `settlement.tres` 甲效矩阵——2026-09-18 加法核换装:量纲由百分比改点数、五档词表退役;三档而非五档的理由 = 攻击基线个位数刻度下 ±2 触伤害下限或翻倍超重,假粒度;攻击成长后可扩弱档)。攻击类型是分量的固有属性(每个分量恒属普通 / 穿刺 / 魔法 之一),护甲类型是防守单位的固有属性,两者都不随层数、来源与轮次漂移;基础分量的类型归属是主角表的可配置值(营地永久强化的换型落点),矩阵键集 3×3 满格、结构冻结,数值 provisional。矩阵消费面 = 主角侧(奖励直伤道具 / 主角攻击基础分量)——敌方攻击现行不查矩阵,主角 armor_type 轴仍休眠、生效待敌方技能攻击类型批。主角增益与乏力经主角输出池修正攻击合计(2026-09-18 结构修复批:普通分量直乘旁路退役;2026-09-19 充能退役后合计 = 单分量,见池乘区公式行)。
主角攻击 = 单一基础分量(2026-09-19 充能退役批):量 = 攻击力基线(表值),类型 = 主角表 `attack_type`(营地永久强化换型 = 改字段;未来冒险前参数面承接"按关配型"的策略位)。原"普通 + 穿刺/魔法充能三分量"模型整体退役——挖掘期与战斗期之间不再有弹药供给线,克制应对从局内攒桶改为冒险前配型 + 棋盘火力(穿刺弹/魔法矢等直伤奖励道具,消费面不变)。
@@ -228,9 +228,9 @@ EV 参考数不入正文(派生读数,需要时按判定式与现行表值
```
敌方一次技能攻击 = max(damage_floor, floor( 掷点档位技能基础分量 ) × 主角防御乘数 × 敌方输出乘数 ) + 必中附加分量 rider(若有——2026-09-19 新效应词汇批:max(damage_floor, floor(攻击基线 × rider_mult)),rider 为后置加法不进乘区不掷不折);增益/妨害技 = 0 伤害施放行(不掷不折),妨害状态按状态行 target_side 落主角
主角一次攻击 = max(damage_floor, floor( 攻击合计 × (100 + 主角输出乘数池合成值) ÷ 100 × (100 + 敌方防御乘数池合成值) ÷ 100 ) )——hero_offense(增伤/乏力载体)与 enemy_defense(硬化载体)两池串乘在攻击合计之后(2026-09-19 充能退役后合计 = 单分量)
主角一次攻击 = max(damage_floor, floor( 攻击合计 × (100 + 主角输出乘数池合成值) ÷ 100 × (100 + 敌方防御乘数池合成值) ÷ 100 ) )——主角输出池(增伤/乏力载体)与敌方防御池(硬化载体)两池串乘在攻击合计之后(2026-09-19 充能退役后合计 = 单分量)
粒度口径:增益池乘区作用在攻击合计层——合计为个位数时百分比档存在粒度取整(如合计 2 点 ×0.75 → 1,实际约 −33% 大于名义 −25%),为已知行为、接受现状;2026-09-18 数值语言拍板后百分比仅保留增益池 / AC 折扣档 / 暴击三处既有粗档,终值与量纲复核归状态层重设计批
乘数 = 1 + 池合成值 ÷ 100;池内加算、每池独立封顶 ±100 百分点 → 乘数域 [0, 2];四池对称:敌打主角 = hero_defense × enemy_output,主角打敌 = hero_offense × enemy_defense(2026-09-18 结构修复批:hero_offense 乘区接线落地——attack_up 普通分量直乘旁路退役,旧"切片现状"注记销项)
乘数 = 1 + 池合成值 ÷ 100;池内加算、每池独立封顶 ±100 百分点 → 乘数域 [0, 2];四池对称:敌打主角 = 主角防御池 × 敌方输出池,主角打敌 = 主角输出池 × 敌方防御池(2026-09-18 结构修复批:主角输出池乘区接线落地——attack_up 普通分量直乘旁路退役,旧"切片现状"注记销项)
护甲等级掷点:掷单骰(骰面读表),掷点 ≥ 护甲等级 + 攻击加成 → 全额;低掷按缺口查减伤档位表(边界与档值读表,无零档)
暴击:天然最大面(读表)→ 该次基础攻击分量 ×暴击倍率(读表)且恒全额(双方同规;掷点层概念,与技能重击严格区分)
伤害下限:任何来源的伤害落地 ≥ damage_floor(读表,全局 max(damage_floor, ·)——折扣与池归零都不产生 v=0 伤害行;2026-09-20 扩全来源,取值域 [1, +∞))
@@ -262,7 +262,7 @@ EV 参考数不入正文(派生读数,需要时按判定式与现行表值
└─ 关卡结束(上层显式调用)→ 清空秘宝背包,给出可见反馈
```
停手与耗尽收轮的回合恒为同图继续;换图指令只允许出现在清图轮,其他轮发换图属于程序错误、立即上抛。秘宝背包以关卡为界:战斗结束不清背包,跨战斗延续;关卡结束时一次性清空,清空前先返回快照计数,作为"剩余秘宝随关卡结束清空"的可见反馈。战斗道具背包已随可选类删除(2026-09-15)下线。(2026-10-09 注:清空对象 = 关卡域库存 treasure_inventory——秘宝过渡形态的机械惰性承载,其投放渠道已随迭代 11 第①批全退役、现行恒空;现行秘宝=营地同调装配件、整局冒险生效不经此域,拆线归实装批——见[秘宝](../跨局循环/秘宝.md)沿革节。)
停手与耗尽收轮的回合恒为同图继续;换图指令只允许出现在清图轮,其他轮发换图属于程序错误、立即上抛。秘宝背包以关卡为界:战斗结束不清背包,跨战斗延续;关卡结束时一次性清空,清空前先返回快照计数,作为"剩余秘宝随关卡结束清空"的可见反馈。战斗道具背包已随可选类删除(2026-09-15)下线。(2026-10-09 注:清空对象 = 关卡域秘宝库存——秘宝过渡形态的机械惰性承载,其投放渠道已随迭代 11 第①批全退役、现行恒空;现行秘宝=营地同调装配件、整局冒险生效不经此域,拆线归实装批——见[秘宝](../跨局循环/秘宝.md)沿革节。)
挖掘期刷新是玩家在挖掘中途主动换图,经[行动经济](../排雷循环/行动经济.md)扣费:扣费成功后按"旧板退役、生成新板、装板、资源预分配恰一次、变异布置"编排,本轮不打断——没有结算段、没有轮次结束。储备不足被拒是玩家决策的合法结果,不是编排错误。刷新图不发清图奖励,完美封印计数随装板重置。
@@ -294,13 +294,13 @@ EV 参考数不入正文(派生读数,需要时按判定式与现行表值
| 呈现面 | 形态 | 载荷与语义 |
|---|---|---|
| 呈现状态快照 `presentation_snapshot` | 只读函数,全量 | 轮次、战斗结果、相位、行动点与储备、刷新可用性、主角(生命/上限/攻击/存活)、敌人数组(顺位/显示名/生命/敌种/护甲类型/护甲等级/摇定动作〔pending_skill/type/name〕/敌方增益 effects/存活)、主角活跃效果投影——呈现层唯一的状态读取出口(敌人技能池批批 2 定稿:行为环当前拍/环进度字段随行为环退役拆除——2026-09-16,池与权重不公开) |
| 战斗进行中谓词 `is_battle_live` | 只读函数,布尔 | 战斗未出结果且主角在场——组合根高频相位判断的低成本面 |
| 奖励身份查询 `query_reward_identity` | 只读函数,单格 | 已开格奖励身份解析的代理,转[地图战斗资源](地图战斗资源.md)的身份查询(就绪相位守卫归对方)——组合根注入棋盘徽章回调 |
| 结算快照信号 `settlement_snapshot` | 信号,每次结算末 | 对象销毁前组装的全量状态快照(终局含胜负结果)——测试记录与数值分析消费 |
| 战斗结束信号 `battle_finished` | 信号,战斗结束时 | 载荷 = 胜负结果、主角余量生命与本战 GP 掉落 `gp_dropped`(掉落掷定 + 关级加值 + 战斗内缓冲的合计;销毁前捕获)——呈现层在核心对象销毁后读状态的时序防护,钱包入账归[冒险结构](../冒险循环/冒险结构.md) |
| 呈现状态快照 | 只读函数,全量 | 轮次、战斗结果、相位、行动点与储备、刷新可用性、主角(生命/上限/攻击/存活)、敌人数组(顺位/显示名/生命/敌种/护甲类型/护甲等级/摇定动作〔技能编号/类型/名〕/敌方增益/存活)、主角活跃效果投影——呈现层唯一的状态读取出口(敌人技能池批批 2 定稿:行为环当前拍/环进度字段随行为环退役拆除——2026-09-16,池与权重不公开) |
| 战斗进行中谓词 | 只读函数,布尔 | 战斗未出结果且主角在场——组合根高频相位判断的低成本面 |
| 奖励身份查询 | 只读函数,单格 | 已开格奖励身份解析的代理,转[地图战斗资源](地图战斗资源.md)的身份查询(就绪相位守卫归对方)——组合根注入棋盘徽章回调 |
| 结算快照信号 | 信号,每次结算末 | 对象销毁前组装的全量状态快照(终局含胜负结果)——测试记录与数值分析消费 |
| 战斗结束信号 | 信号,战斗结束时 | 载荷 = 胜负结果、主角余量生命与本战 GP 掉落(掉落掷定 + 关级加值 + 战斗内缓冲的合计;销毁前捕获)——呈现层在核心对象销毁后读状态的时序防护,钱包入账归[冒险结构](../冒险循环/冒险结构.md) |
另设一个诊断观测面(诊断快照 `diagnostic_snapshot`)供组合根诊断转储与行为探针消费:它暴露编排内部状态,不属于呈现契约,不作其他用途。
另设一个诊断观测面(诊断快照)供组合根诊断转储与行为探针消费:它暴露编排内部状态,不属于呈现契约,不作其他用途。
## P0 最小闭环
@@ -321,7 +321,7 @@ EV 参考数不入正文(派生读数,需要时按判定式与现行表值
## 调参表
结算用到的全部数值——当量、封顶、乘数、段序常量、甲效与护甲等级掷点参数——都存结算配置表,代码里零数值字面量;改数值就是改表回填。表值以快照进结算,战斗中途改表不生效。已锁字段与数值以 `data/schemas/settlement_table.gd` 与 `data/tables/settlement.tres` 为准。
结算用到的全部数值——当量、封顶、乘数、段序常量、甲效与护甲等级掷点参数——都存结算配置表,代码里零数值字面量;改数值就是改表回填。表值以快照进结算,战斗中途改表不生效。已锁字段与数值以结算表的字段定义与表行为准。
| 参数 | 域 | 现行值 | 说明 |
|---|---|---|---|
@@ -360,7 +360,7 @@ EV 参考数不入正文(派生读数,需要时按判定式与现行表值
- 无来源即炸:每行明细都能指回一个来源事实(棋盘格、单位、清图或段级结论);找不到来源即断言失败,行型与来源类别两层豁免清单见明细流水一节,豁免行仍受其它契约约束。
- 行型封闭:流水行型只出现本文登记的基础 9 类与扩展行;行型词表改动必须走本文修订并同步呈现层行格式化,未登记行型禁止落行。
- 伤害单据管线(2026-09-24):全部伤害(主角先手、敌方伤害技、棋盘克制直伤、群伤、反噬、地形变异)经伤害控制器单据管线兑现,兑付配方封闭五种;目标在结账时刻照规则解析;死亡事件由单位自行宣布——怪死其未结单据作废(零行、不进冷却不进保底计数)、主角死兑付终止;段界结账为现行口径、开单即结为回切结构位,两模式各自同种子同输入逐位复现。
- 条款3 对账(2026-10-05 判式换代批 T3——与行动经济 F1 条款3 重立同步):①聚合健康式 (1−ρ̂)·E_dig(u) − ρ̂·V_mine(u) ≥ 0 与 β 比值带 [1.2, 2.5] 判读逐 u 检算(常设重跑入口 `tools/clear_dominance_audit.py`,读数快照归 registry clause3 重立条);②封印溢价兑付正确:封印标中正向兑付 = 同型正向 ×(1+δ)(δ 读 `settlement.tres` flag_hit_premium,100=无溢价直通零扰动),三类形态全覆盖(flat power / percent 幅度 / gp 缓冲)、标空与挖格兑付不乘溢价、危险格与安全格同池结构零触碰。
- 条款3 对账(2026-10-05 判式换代批 T3——与行动经济 F1 条款3 重立同步):①聚合健康式 (1−ρ̂)·E_dig(u) − ρ̂·V_mine(u) ≥ 0 与 β 比值带 [1.2, 2.5] 判读逐 u 检算(清图支配性审计为常设重跑项,读数快照登记归 clause3 重立条);②封印溢价兑付正确:封印标中正向兑付 = 同型正向 ×(1+δ)(δ 读 `settlement.tres` flag_hit_premium,100=无溢价直通零扰动),三类形态全覆盖(flat power / percent 幅度 / gp 缓冲)、标空与挖格兑付不乘溢价、危险格与安全格同池结构零触碰。
## 待办
@@ -1,7 +1,7 @@
# 战斗表现
> 一句话:战斗动画与演出(旧体系未单独成文)
> 状态:范围草案(待设计)
> 状态:范围草案(待设计);现行为 v1.2
## 设计目的
@@ -74,7 +74,7 @@
附着在同一次样张上的还有一项已登记的裁决(登记出处 = 敌人系统的呈现契约):敌人层绘制优先级的插入位置——白话就是敌人的姿态精灵画在绘制顺序的哪一层,会不会、以及如何与棋盘上的数字、封印印记、小人发生遮挡。它随美术测试一并裁决,不在本文提前定。
两项相邻裁定已有结论,设计时直接继承:**敌人呈现形态已裁决(2026-09-20 用户看对照样张拍板)——全站桩式(无框立绘+底座),主角同样站桩、状态小图标挂血条正下方,卡片式整体退役**(待办清单「敌人卡形态」解决移除,状态记录 99;battle.md 起草条款已随裁决改写,对照样张存档 `production/mockups/`);art-bible 的图标键契约已冻结,动画设计不必等图标终稿。
两项相邻裁定已有结论,设计时直接继承:**敌人呈现形态已裁决(2026-09-20 用户看对照样张拍板)——全站桩式(无框立绘+底座),主角同样站桩、状态小图标挂血条正下方,卡片式整体退役**(待办清单「敌人卡形态」解决移除,状态记录 99;battle.md 起草条款已随裁决改写,对照样张已在案存档);art-bible 的图标键契约已冻结,动画设计不必等图标终稿。
### 一屏样张的验收标准
@@ -92,6 +92,8 @@
判定与回退:第 1 项不过即演出元素回炉,禁止以牺牲可读性换氛围(改演出、不动数字口径);第 2–4 项不过对应资产或方案回炉重交,已过项结果保留。第 5 项(敌层插入位置)不产生过/不过,产出一条裁决记录:插入位置结论由[敌人系统](敌人系统.md)的呈现契约登记(~~敌人卡形态对照~~半边已于 2026-09-20 提前裁决完成——全站桩定稿,结论已回写 battle.md 起草条款)。样张通过 = 角色剪影、动画方案、战斗空间、敌层插入位置四件锁定物冻结;通过前不启动任何终稿资产与动画设计。
**现行状态(2026-10-30 战斗一屏样张批)**:五项验收的机检断言已随该批全绿(机器代理口径与实测读数查战斗一屏样张批 git 提交史,合并提交 3b66d1a6);样张整体过闸仍差方向稿目检先行(art-bible §1.4 闸形,目检项登记体验验证清单 ㊶)。
### 演出服从信息与可读性
两条现行硬约束,将来任何动画方案都禁止越过。其一,数字可读性高于氛围:挖掘期画面无杂音,动画禁止遮挡数字、禁止在挖掘期抢焦;结算期的色彩与能量走向以 art-bible 第 2 节为权威。其二,结算逐行兑现是信息载体:battle.md 已承诺不可整体跳过、只提供减动效选项(时长减半或直达终态,逐行兑现可加速不可省略),本文将来兑现其动画侧。
@@ -100,13 +102,13 @@
**定义**:轮末结算的呈现节奏规则——结算行按演出层排播队列分组依次呈现、轮切换以「第 N 轮」横幅驻留,把核心层一帧同步跑完的结算翻译成玩家可跟读的逐行过程;与结算演出覆盖层(光带横扫/跨区弹道,迭代 6)共同构成结算期的演出面。
**作用对象与范围**:只作用于演出层——排播常量在 `main.gd`(`PACE_SEGMENT_GAP` / `PACE_ROW_GAP`)与 `settlement_fx_view.gd`(`BANNER_DWELL`),横幅与节奏经 settlement_fx_view 呈现。核心层零触碰:`battle_orchestrator` 的「零 await」契约与「MC 与基线数据逐项比对」口径不受扰(T1 态 400/400 逐位实证在案)。
**作用对象与范围**:只作用于演出层——排播常量(段间间隔/段内间隔/横幅驻留)归演出层单点持有,本文登记现行值,横幅与节奏在演出层呈现。核心层零触碰:结算零界面等待、零动画等待,且「MC 与基线数据逐项比对」口径不受扰(T1 态 400/400 逐位实证在案)。
**生命周期**:进结算期起播——结算行按五段分组依序进明细带(段间 0.3s、段内 0.22s;段内值 0.06→0.22 系迭代 8 三轮修改批用户裁决「逐条演出可感知」);轮切换横幅驻留 0.6s 后消隐进下一轮;战斗结束排播收尾。**减动效双态**:开关开启 = 延迟归零同帧直落 + 横幅静态化(与设置面减动效联动——「可加速不可整体跳过」承诺的节奏侧兑现)。
**关联与边界**:结算顺序与结果归[战斗结算](战斗结算.md)(本节零触碰,逻辑先行、演出后行);减动效开关归[设置与本地化](../表现与支撑/设置与本地化.md);节奏常量以代码为事实源(上列三常量),本文登记现行值与沿革,表值化随演出批再议;fx_probe 轮横幅发射计数为验收断言面。
**关联与边界**:结算顺序与结果归[战斗结算](战斗结算.md)(本节零触碰,逻辑先行、演出后行);减动效开关归[设置与本地化](../表现与支撑/设置与本地化.md);节奏常量由演出层单点持有,本文登记现行值与沿革,表值化随演出批再议;横幅发射计数构成验收判据。
**状态**:已实装(2026-09-29 迭代 8 卡⑦已入库、三轮修改批调参追认;pacing_queue_test 第 15 套在册)。本节是本文第一块已落地内容,其余部分维持范围草案。
**状态**:已实装(2026-09-29 迭代 8 卡⑦已入库、三轮修改批调参追认;验收套件第 15 套在册)。本节是本文第一块已落地内容,其余部分维持范围草案。
## 依赖与输出
+11 -11
View File
@@ -1,7 +1,7 @@
# 敌人系统
> 一句话:敌人数据、技能池出招、意图呈现
> 状态:已定稿(自旧体系迁移);现行为 v1.3
> 状态:已定稿(自旧体系迁移);现行为 v1.4
## 设计目的
@@ -71,7 +71,7 @@
| 规则 | 含义 |
|---|---|
| 敌方效果对全体生效 | 范围效果作用于所有存活敌人——混编放开后(2026-10-07 行集多行批)场上可多种敌种共存,结算语义按存活单位逐一生效、不依赖"场上全同种"前提;"只打某一个"的单体寻址接口已在[增益状态](增益状态.md)〈单体寻址扩展位〉节定稿,随首个单体效果的内容批开放(见 P1) |
| 行集构成纪律 | 敌人表按(关卡序号 × 深度带)存放;深度带=节点深度的区间——逐局生成使单点深度不再固定,配池按带不按点,难度坡随带递增。同一带键行集允许多行、允许不同敌种混编;Boss 行按终点配置,多终点各配一行(走哪条路决定打谁)。纪律三条,违规加载期返回错误并止动:①行集内 enemy_id 唯一(同一敌种在同行集仍只许一行);②同带键多行必须表文件内相邻,行序 = 声明序 = 生成序(行序即契约);③行集实例总数(各行骰后数量求和)≤ 4,单行数量域 [1,3] 不变(UNIT_COUNT_MAX 语义 = 单种数)。行数不设上限;同关随深度换敌种合法 |
| 行集构成纪律 | 敌人表按(关卡序号 × 深度带)存放;深度带=节点深度的区间——逐局生成使单点深度不再固定,配池按带不按点,难度坡随带递增。同一带键行集允许多行、允许不同敌种混编;Boss 行按终点配置,多终点各配一行(走哪条路决定打谁)。纪律三条,违规加载期返回错误并止动:①行集内 enemy_id 唯一(同一敌种在同行集仍只许一行);②同带键多行必须表文件内相邻,行序 = 声明序 = 生成序(行序即契约);③行集实例总数(各行骰后数量求和)≤ 4,单行数量域 [1,3] 不变(单行数量上限语义 = 单种数)。行数不设上限;同关随深度换敌种合法 |
| 主角数据行 | 主角战斗数值单独放一张全局单行表:生命上限、基础攻击力、护甲等级三字段(见调参表) |
| 基础攻击恒存在 | 基础攻击不许配 0(配置为 0 加载期拒绝)——零基线乘任何百分比增益恒为零,"胜利路径恒有"的保障从数据层杜绝死锁 |
| 先手攻击不是敌方技能拍 | 每次结算战斗段主角先手攻击顺位最前的存活敌人,这是固定动作;奖励侧的道具与增益是基础攻击之外的规划面伤害,归[地图战斗资源](地图战斗资源.md) |
@@ -91,7 +91,7 @@
| 钩爪恐魔 | 普通攻击 + 撕咬 + 蓄力 | 行值读表 | 行值读表 | L2/L3 群行位(蜘蛛同构池) |
| 灰矮人石君王 | 普通攻击 + 重击 + 大地脉动 + **岩崩**(半血解锁) | 行值读表 | 行值读表 | L3 关底 Boss;大地脉动独占 |
护甲类型(轻甲 / 魔法护甲 / 重甲)与攻击类型的克制结算矩阵归[战斗结算](战斗结算.md),本系统只提供每个敌种的护甲类型数据——**护甲列自 2026-10-05 技能池执行批起改读表口径**(本表轮廓列不再记具体甲型:现行 L1 全轻甲 / L2 仅 Boss 魔法甲 / L3 heavy 登台的错峰投放以 `enemy.tres` 行值为准;历史「本表写魔甲/重甲」与表失同步的欠账顺带清偿)。护甲等级是另一条数值轴(防守方字段,基础攻击掷点的折扣判定读数):敌人表与主角表各增 `armor_class` 一列(域 [0, 999]),掷点与折扣的结算归[战斗结算](战斗结算.md),行值投值归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)——三敌种首关与主角的护甲等级行值读配置表(第一关怪物 AC 相对较低,正式行值待怪物设定投值,登记[待办清单](../../../../待办清单.md)),两条轴的概念与字段禁止混用。举证:生成与护甲为数据面规则,无计算。
护甲类型(轻甲 / 魔法护甲 / 重甲)与攻击类型的克制结算矩阵归[战斗结算](战斗结算.md),本系统只提供每个敌种的护甲类型数据——**护甲列自 2026-10-05 技能池执行批起改读表口径**(本表轮廓列不再记具体甲型:现行 L1 全轻甲 / L2 仅 Boss 魔法甲 / L3 重甲登台的错峰投放以 `enemy.tres` 行值为准;历史「本表写魔甲/重甲」与表失同步的欠账顺带清偿)。护甲等级是另一条数值轴(防守方字段,基础攻击掷点的折扣判定读数):敌人表与主角表各增 `armor_class` 一列(域 [0, 999]),掷点与折扣的结算归[战斗结算](战斗结算.md),行值投值归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)——三敌种首关与主角的护甲等级行值读配置表(第一关怪物 AC 相对较低,正式行值待怪物设定投值,登记[待办清单](../../../../待办清单.md)),两条轴的概念与字段禁止混用。举证:生成与护甲为数据面规则,无计算。
### 技能池:每敌种一张带权技能池,每拍开轮摇号出招
@@ -111,12 +111,12 @@
|---|---|---|
| skill_id | 全部 | 主键,池条目引用键 |
| display_name | 全部 | 玩家可见名(明细行与动画共用) |
| type | 全部 | 封闭枚举 {普通攻击, 伤害, 增益, 妨害}——**新效应词汇批 2026-09-19 由三扩四**(设计权威 proposal-status-vocabulary.md〔提案已吸收退役 git a6833b6a——现行事实源=敌人系统.md 词汇表/增益状态.md〕 v1.0;多段命中经用户拍板退役不入枚举);新类型走本文修订 |
| type | 全部 | 封闭枚举 {普通攻击, 伤害, 增益, 妨害}——**新效应词汇批 2026-09-19 由三扩四**(设计权威 proposal-status-vocabulary.md〔提案已吸收退役——现行事实源=敌人系统.md 词汇表/增益状态.md〕 v1.0;多段命中经用户拍板退役不入枚举);新类型走本文修订 |
| damage_mult | 仅伤害 | 伤害倍率;域 [1.1, 16] provisional。普通攻击恒 1、不可配 |
| rider_mult | 仅伤害、可省 | **必中附加分量(2026-09-19 新增)**:域 (0, 1],缺省无字段 = 无附加;分量值 = max(伤害下限, floor(攻击基线 × rider_mult))——随施放者攻击基线缩放,后置加法、必中全额、不进乘区、不出暴击(后置加法同族);价位锚 0.75 = AC 折扣档最轻档"不掉档的稳定伤害" |
| cooldown_beats | 全部 | 施放后连续 N 拍不可摇中;普通攻击恒 0、不可配 |
| buff_ref / buff_duration | 仅增益与妨害 | 效果引用(指向状态效果行)与持续回合数;**落点由状态行 target_side 路由**(增益 → 敌方侧 / 妨害 → 主角侧,施放类 side 守卫加载拒绝)——妨害技零新授予通道 |
| trigger(触发条件) | 全部,可省 | {fact, op, value, latch} 四键——fact 与 op 取「触发条件」节封闭词表,value 类型与域随 fact,出域加载期拒绝;缺省无字段=无条件技,旧行为零变化(2026-10-26 情境条件触发器批立列、2026-10-27 迭代 39 实装落地;原池条目字段 unlock_hp_pct 收编为本字段闩型首用例) |
| trigger(触发条件) | 全部,可省 | {fact, op, value, latch} 四键——fact 与 op 取「触发条件」节封闭词表,value 类型与域随 fact,出域加载期拒绝;缺省无字段=无条件技,旧行为零变化(2026-10-26 情境条件触发器批立列、2026-10-27 迭代 39 实装落地;原池条目的血量百分比字段收编为本字段闩型首用例) |
| P1 字段位 | — | 命中段数、目标数——随对应后置批加列(触发条件位已由 trigger 立列收编——2026-10-26 立列、2026-10-27 实装;原"固定值分量"位已由 rider_mult 实装收编——2026-09-19;多段命中「命中段数」保留以防复活) |
普通攻击也是一行技能行,两条域校验锁死它的特殊性:倍率恒 1、冷却恒 0——想配倍率或冷却的就不是普攻,是伤害技。技能伤害存倍率、不存固定值:伤害 = 施放者攻击基线 × 技能倍率——同一行"重击",不同敌种按各自攻击基线缩放 = 基线 A × 技能倍率 M(行值读 enemy.tres / skills.tres),深层强化行自动缩放,这是共享技能表成立的前提;**固定的绝对值伤害不满足该前提**(不随基线缩放、跨关稀释——Brotato 教训),"固定值伤害"的合法形态是**必中附加分量 rider_mult**(×攻击基线的必中小倍率,2026-09-19 实装)。增益技带效果引用与持续回合,百分比天然按施放者同池生效,无缩放问题;妨害技同构,落点由状态行 target_side 路由到主角。
@@ -179,7 +179,7 @@ Boss 专属身份 = 专属池承载:独占技能 + 权重轮廓(**技能错
| 死亡作废 | 照常——摇定后兑现前死亡,本拍作废、不进冷却不进保底计数 |
| 意图呈现 | 三档规格不变——情境技属特殊技,走类型级预告+结算明细具名,因果由技能名承载(如"趁隙偷袭");闩型保留解锁弹出规格(见"目标顺位与意图线索"节) |
半血解锁的收编:原池条目字段 unlock_hp_pct(2026-10-05 技能池执行批)收编为本字段闩型首用例——Boss 解锁技=trigger {fact: self_hp_pct, op: lte, value: 行值, latch: 真};解锁弹出规格(归因明细行+一次性技能名 toast)、单向闩语义、双面过滤行为全部不变(字段换代与三 Boss 行值迁移已随 2026-10-27 迭代 39 实装落地)。
半血解锁的收编:原池条目的血量百分比字段(2026-10-05 技能池执行批)收编为本字段闩型首用例——Boss 解锁技=trigger {fact: self_hp_pct, op: lte, value: 行值, latch: 真};解锁弹出规格(归因明细行+一次性技能名 toast)、单向闩语义、双面过滤行为全部不变(字段换代与三 Boss 行值迁移已随 2026-10-27 迭代 39 实装落地)。
首批落地(已实装——2026-10-27 迭代 39):①三 Boss 解锁技迁移为闩型条件(行为零变化);②两个示范投放——地精池+低血防御增益「孤注守势」(self_hp_pct lte 35,纯增益)、L2/L3 群行位+停手偷袭伤害技「趁隙偷袭」(last_round_end eq 停手)。投放敌种、权重与阈值投值归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md);"每池增益≤1"纪律不动,条件技照常计入预算。
@@ -203,7 +203,7 @@ Boss 专属身份 = 专属池承载:独占技能 + 权重轮廓(**技能错
即:普攻完全不可预测;特殊技有一次类型级预告,不可撤销,但给"继续挖还是停手"的决策依据。
**半血解锁弹出规格(2026-10-05 技能池执行批,D8 用户裁;内容数据驱动扩展批 T1 补登记——解锁判定点=通用事件「血量阈值 `enemy_hp_threshold`」的发射点,对所有带闩型血量触发条件的敌人逐个发射、非 Boss 专属——Boss 语义留给订阅条件判定;条件载体 2026-10-26 触发条件批起改技能行 trigger 闩型〔原池条目字段 `unlock_hp_pct` 收编,行为零变化,见「触发条件」节〕)**:Boss 血量降至解锁阈值(trigger 行值,域 [1,99],缺省无字段=无门槛)时,下一个开轮摇号前出一次归因明细行「XX 解锁了 YY」(高光键 `skill_unlock`,行型复用 highlight 零新增);呈现层对该行弹**一次性技能名 toast**(轻量提示,非演出——零动画资产、不改演出规格),只报技能名不报数值,池与权重不公开纪律不变。解锁=单向闩(治疗抬血不解锁);锁定条目双面过滤(不进可摇集合与保底特殊技集合——保底禁止逼出未解锁技);解锁后冷却初值 0 即可摇。投放纪律=机制通用、闩型解锁用例仅 Boss 专属技投放(enemy 表无 boss 编码位,硬闸须跨表查节点类型——不做硬闸,本句即文档纪律登记)。旧环"下一拍全程亮出(意图徽标 + 环点)"的预告粒度随行为环退役。技能动画的攻/防系映射归[战斗表现](战斗表现.md),敌人侧摇定动画位归[HUD 框架](../表现与支撑/HUD框架.md)(呈现载体 = 站桩立绘,2026-09-20 全站桩拍板),本系统只锁上面这张三档规格。
**半血解锁弹出规格(2026-10-05 技能池执行批,D8 用户裁;内容数据驱动扩展批 T1 补登记——解锁判定点=通用事件「血量阈值 `enemy_hp_threshold`」的发射点,对所有带闩型血量触发条件的敌人逐个发射、非 Boss 专属——Boss 语义留给订阅条件判定;条件载体 2026-10-26 触发条件批起改技能行 trigger 闩型〔原池条目的血量百分比字段收编,行为零变化,见「触发条件」节〕)**:Boss 血量降至解锁阈值(trigger 行值,域 [1,99],缺省无字段=无门槛)时,下一个开轮摇号前出一次归因明细行「XX 解锁了 YY」(高光键为技能解锁,行型复用高光行零新增);呈现层对该行弹**一次性技能名 toast**(轻量提示,非演出——零动画资产、不改演出规格),只报技能名不报数值,池与权重不公开纪律不变。解锁=单向闩(治疗抬血不解锁);锁定条目双面过滤(不进可摇集合与保底特殊技集合——保底禁止逼出未解锁技);解锁后冷却初值 0 即可摇。投放纪律=机制通用、闩型解锁用例仅 Boss 专属技投放(enemy 表无 boss 编码位,硬闸须跨表查节点类型——不做硬闸,本句即文档纪律登记)。旧环"下一拍全程亮出(意图徽标 + 环点)"的预告粒度随行为环退役。技能动画的攻/防系映射归[战斗表现](战斗表现.md),敌人侧摇定动画位归[HUD 框架](../表现与支撑/HUD框架.md)(呈现载体 = 站桩立绘,2026-09-20 全站桩拍板),本系统只锁上面这张三档规格。
| 规格 | 含义 |
|---|---|
@@ -251,7 +251,7 @@ Boss 专属身份 = 专属池承载:独占技能 + 权重轮廓(**技能错
| P1 | 情境条件触发器(低血触发防御、玩家停手时偷袭技等) | 已实装(2026-10-27 迭代 39——三 Boss 闩型迁移+两示范投放,见「触发条件」节与「首批落地」段) |
| P1 | 个体化变体池(A 型好斗 / B 型守势、精英专属池) | 共识点 A 的 A2 案;登记[待办清单](../../../../待办清单.md) |
| P1 | 全局特殊间隔旋钮 | 特殊技背靠背实测仍嫌时的备用闸;登记[待办清单](../../../../待办清单.md) |
| P1 | 新效应词汇批(妨害技 + 必中附加分量已实装 2026-09-19——设计权威 proposal-status-vocabulary.md〔提案已吸收退役 git a6833b6a——现行事实源=敌人系统.md 词汇表/增益状态.md〕 v1.0,实装面 = L2 Boss 卓尔;多段命中经用户拍板退役) | 妨害类型 + rider_mult 字段已落地;登记[待办清单](../../../../待办清单.md)(已解决移除,去向见状态记录) |
| P1 | 新效应词汇批(妨害技 + 必中附加分量已实装 2026-09-19——设计权威 proposal-status-vocabulary.md〔提案已吸收退役——现行事实源=敌人系统.md 词汇表/增益状态.md〕 v1.0,实装面 = L2 Boss 卓尔;多段命中经用户拍板退役) | 妨害类型 + rider_mult 字段已落地;登记[待办清单](../../../../待办清单.md)(已解决移除,去向见状态记录) |
| P1 | 敌种名录扩容与投放节奏(含第二关池与投放) | 投放节奏是关卡命脉,归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md) |
| P1 | 单体寻址("只打某一个敌人"的目标指定) | 归集语义与呈现已裁定(2026-10-26;语义归[增益状态](增益状态.md)〈单体寻址扩展位〉节);实现随首个单体效果的内容批落地 |
| P2 | 敌方技能图鉴 / 学习呈现(玩家侧技能知识系统) | 池不公开口径下的进阶信息面;登记[待办清单](../../../../待办清单.md) |
@@ -269,7 +269,7 @@ Boss 专属身份 = 专属池承载:独占技能 + 权重轮廓(**技能错
| unit_count_max | [unit_count, 3],可省略 | 数量区间上界;开战时在区间内掷定本战实际数量;缺省 = 定值 |
| atk_min / atk_max | [0, 999] 可选配对 | 攻击基线区间:开战掷定一次、整战持久;缺省 = 定值行 |
| armor_type | {轻甲, 魔法护甲, 重甲},缺省轻甲 | 克制结算归[战斗结算](战斗结算.md) |
| attack_type | {普通, 穿刺, 魔法},缺省普通 | 敌方攻击类型轴(**2026-10-13 迭代 24 N3 开列实装**:20 行全填 normal,ATTACK_TYPES 闭集枚举+缺省回退向后兼容,与 armor_type 同位同款);消费面 = 战斗结算敌方技兑付路径的护甲克制矩阵查表(敌方开单第 9 参传值+克制消费点,见战斗结算);行值投值归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md) |
| attack_type | {普通, 穿刺, 魔法},缺省普通 | 敌方攻击类型轴(**2026-10-13 迭代 24 N3 开列实装**:20 行全填 normal,攻击类型闭集枚举+缺省回退向后兼容,与 armor_type 同位同款);消费面 = 战斗结算敌方技兑付路径的护甲克制矩阵查表(敌方开单第 9 参传值+克制消费点,见战斗结算);行值投值归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md) |
| armor_class(护甲等级) | int [0, 999],缺省 0 | 防守方护甲等级——基础攻击掷点的折扣判定读数,掷点结算归[战斗结算](战斗结算.md);与 armor_type(克制属性轴)两概念禁止混用;行值投值归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md) |
| hp | [1, 999] | 单位生命基线(难度修饰前) |
| atk | [0, 999] | 攻击基线 |
@@ -298,7 +298,7 @@ Boss 专属身份 = 专属池承载:独占技能 + 权重轮廓(**技能错
各敌种行值、池权重与池 EV 读数(含闸长期速率实测)一律读配置表与调参日志,本文不登记具体数值;EV 重锚与权重投值归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)。
结构冻结(非调参项,修订走本文流程):技能类型枚举封闭、每池恰一普攻、每池增益 ≤1、死亡即不动手(摇定后兑现前死亡作废不进账)、每结算每存活敌恰行动一次、行序、先作用后推进、固定顺位、**行集构成纪律(2026-10-07 行集多行批换代——原「每坐标恰一敌种」退役:行集内 enemy_id 唯一 + 同带键多行文件内相邻且行序 = 声明序 = 生成序 + 行集实例总数 ≤ 4)**、零随机(本系统自身语义零随机不变——摇号与掷点随机一律在[战斗结算](战斗结算.md)结算换算层按封闭随机流掷定,可回放契约 = 同种子同输入逐位复现,单敌出招轨迹可独立复放)。联动纪律:技能倍率 × 攻击(伤害拍支配)、权重 × 冷却 × 保底(池节奏三联动)禁止独立调参,联调须重跑方向性预检并同步 registry(登记 [待办清单](../../../../待办清单.md))。
结构冻结(非调参项,修订走本文流程):技能类型枚举封闭、每池恰一普攻、每池增益 ≤1、死亡即不动手(摇定后兑现前死亡作废不进账)、每结算每存活敌恰行动一次、行序、先作用后推进、固定顺位、**行集构成纪律(2026-10-07 行集多行批换代——原「每坐标恰一敌种」退役:行集内 enemy_id 唯一 + 同带键多行文件内相邻且行序 = 声明序 = 生成序 + 行集实例总数 ≤ 4)**、零随机(本系统自身语义零随机不变——摇号与掷点随机一律在[战斗结算](战斗结算.md)结算换算层按封闭随机流掷定,可回放契约 = 同种子同输入逐位复现,单敌出招轨迹可独立复放)。联动纪律:技能倍率 × 攻击(伤害拍支配)、权重 × 冷却 × 保底(池节奏三联动)禁止独立调参,联调须重跑方向性预检并同步登记册(登记 [待办清单](../../../../待办清单.md))。
## 验收标准
@@ -314,7 +314,7 @@ Boss 专属身份 = 专属池承载:独占技能 + 权重轮廓(**技能错
- 快照抗改表:实例化后修改敌人表,已生成单位的数值投影与实例池逐字不变;新实例才用新表值。
- 表校验:越域值、池权重 ≤ 0、空池、普攻配倍率/冷却、池增益 > 1、skill_id 悬空、行集构成违例(行集内同敌种第二行 / 同带键多行不相邻)均在加载期返回错误并止动;域内合法极端(攻击基线 0)不拒;主角表恰一行、攻击配 0 拒绝。
- 零随机回放:同一动作与受击序列驱动两个独立实例,存活投影、逐实例摇定轨迹、顺位返回序列逐项相同。
- 表实一致:三张配置表字段与 `data/schemas/enemy_table.gd`/`hero_table.gd`/`skill_table.gd` 逐字段一致。
- 表实一致:敌人表、主角表、技能表三张配置表的字段与各自字段定义逐字段一致。
## 待办
@@ -1,7 +1,7 @@
# 地形变异
> 一句话:格子的非雾变异(荆棘丛/藤蔓缠绕/岩浆/烬覆/落石/矿尘)与 Boss 图整图变异(贫矿脉),挖掘中可遭遇的地貌偏离
> 状态:已定稿(首批类型随 2026-09-19 定稿批落地,第三关一对随 2026-09-20 第三关内容批落地;首个整图变异随 2026-10-04 全局作用域变异首发批落地)
> 状态:已定稿(首批类型随 2026-09-19 定稿批落地,第三关一对随 2026-09-20 第三关内容批落地;首个整图变异随 2026-10-04 全局作用域变异首发批落地);现行为 v1.1
## 设计目的
@@ -69,11 +69,11 @@
- 直伤量为加法核小整数(effect_value ∈ [1,9],行值 provisional 归难度曲线与Boss);每格携带单类型单 id。
- 变异格未开时无预告呈现(遭遇式;视觉标识归表现层升级批)。
候选池门控(框架级现行机制):一种变异要进入本关的布置候选,须同时满足三个条件——它的解锁关号不大于当前关卡序号(直接整数比较)、它声明的地形(board_types)与本地形有交集(声明为空集等于通配)、且节点身份匹配(scope=global 行仅 Boss/精英节点入池,普通战斗节点静默跳过——2026-10-04 全局作用域变异批增第三维;elite 系前向词位,首发零表行)。候选池为空是合法状态:静默布置一张无变异的普通图,不返回错误、不警告。门控谓词与取值域见本文候选池门控节与 `data/schemas/variation_table.gd`。
候选池门控(框架级现行机制):一种变异要进入本关的布置候选,须同时满足三个条件——它的解锁关号不大于当前关卡序号(直接整数比较)、它声明的地形(board_types)与本地形有交集(声明为空集等于通配)、且节点身份匹配(scope=global 行仅 Boss/精英节点入池,普通战斗节点静默跳过——2026-10-04 全局作用域变异批增第三维;elite 系前向词位,首发零表行)。候选池为空是合法状态:静默布置一张无变异的普通图,不返回错误、不警告。门控谓词与取值域见本文候选池门控节与变异表字段定义。
### 全局作用域型(scope=global——Boss 图整图变异)
region 型变异是「格子级」的:布置段往候选格域写格子快照。global 型变异是「整图」的:整图一个类型生效,不落任何格子(棋盘持有整图 `board_variants` 字段,逐格 `variants` 恒空)。**每图一型的整图推广(2026-10-04 用户裁决)**:普通图带 region 片,Boss/精英图带 global 型——两类图各自至多一型。
region 型变异是「格子级」的:布置段往候选格域写格子快照。global 型变异是「整图」的:整图一个类型生效,不落任何格子(棋盘持有整图变异记录,逐格变异记录恒空)。**每图一型的整图推广(2026-10-04 用户裁决)**:普通图带 region 片,Boss/精英图带 global 型——两类图各自至多一型。
**替换制**:Boss/精英图命中全局型时,布置段跳过 region 布置(该图既无 region 片、也无格子级变异标记)——L2 完美 Boss 承伤已越 ≤50% 带,region 叠全局的叠加制火上浇油,不采纳。**兜底回落**:Boss/精英图的全局候选池为空时(含第 1 关 Boss 解锁门控未达=免疫,第 1 关是过滤器不是墙的教学保护)回落 region 布置,即回批前行为(保守向后兼容,防配置缺行静默裸奔——provisional)。
@@ -130,7 +130,7 @@ region 型变异是「格子级」的:布置段往候选格域写格子快照
| 优先级 | 内容 | 后置原因 |
|---|---|---|
| 迭代 12(调研前置) | 反制路径重定(原:首批四类型的反制道具兑现,counter_items 回填——已作废) | 2026-10-03 用户终裁:同调位反制件=层级错配失败设计,义务作废;变异应对是否以局内形态补入,待双层 BD 调研仲裁后重新立项 |
| ~~Alpha~~ **已落地** | 全局作用域变异(精英/Boss 图整图生效的变异形态) | **2026-10-04 全局作用域变异首发批落地**(迭代 14 ③号卡)——首批型=贫矿脉(案A 资源面·微贫向偏斜,替换制/恒定制/L1 Boss 免疫/三层预告);裁决全录见调研报告 §7(全局作用域设计空间调研(已退役,git 历史可查);原需求卡片已退役,git b3bbea5/01bfc15);带 A 杠杆注册全局难度批(Beta 阶段,未排期)顺带读数只测不判;精英图留词表前向位(首发零表行) |
| ~~Alpha~~ **已落地** | 全局作用域变异(精英/Boss 图整图生效的变异形态) | **2026-10-04 全局作用域变异首发批落地**(迭代 14 ③号卡)——首批型=贫矿脉(案A 资源面·微贫向偏斜,替换制/恒定制/L1 Boss 免疫/三层预告);裁决全录见调研报告 §7(全局作用域设计空间调研(已退役,git 历史可查);原需求卡片已退役);带 A 杠杆注册全局难度批(Beta 阶段,未排期)顺带读数只测不判;精英图留词表前向位(首发零表行) |
| P2 | "地形成本修饰"价目钩子启用 | 由行动经济持有;启用须随变异类型扩展,与行动经济重议按格定价的接口 |
| P2 | 变异解锁节奏复核 | "每关至少引入一个新元素"的推进节奏,随[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)定稿复核 |
| P2 | 变异格视觉标识与预告呈现 | 首批为遭遇式(未开无预告);标识位随表现层升级批 |
@@ -145,7 +145,7 @@ region 型变异是「格子级」的:布置段往候选格域写格子快照
| 直伤量 effect_value | 荆棘丛 1 / 岩浆 2 / 落石 3 | 难度曲线与Boss(provisional,加法核 [1,9]) |
| 资源面偏斜 effect_value | 贫矿脉 30(生存族下调百分比;0=中性 off 锚;总期望微降 3-5% 为 provisional 设计目标——精确方向与幅度归读数批判读只测不判) | 难度曲线与Boss(provisional,域 [0,50]——2026-10-04 首发批投值) |
变异表的结构历史(字段定义、条目归属)见 `data/schemas/variation_table.gd` 与 `data/tables/variation.tres`。字段集现行口径:标识 / 玩家可见名 / 解锁关号 / 作用域 / 效果 / 效果量 / 触发 / 布置约束 / 地形(board_types)/ 反制道具绑定(counter_items,恒空保留——回填义务 2026-10-03 作废,承载形态待迭代 12 重定)。
变异表字段集的现行口径(字段定义归变异表,条目归属即表行):标识 / 玩家可见名 / 解锁关号 / 作用域 / 效果 / 效果量 / 触发 / 布置约束 / 地形(board_types)/ 反制道具绑定(counter_items,恒空保留——回填义务 2026-10-03 作废,承载形态待迭代 12 重定)。
## 验收标准
@@ -214,7 +214,7 @@
| 优先级 | 内容 | 后置原因 |
|---|---|---|
| P2 | 探测类道具的查询接口 | 接口已由 `query_reward_identity` 只读面桥接,本系统不预写 |
| P2 | 探测类道具的查询接口 | 接口已由身份解析只读面桥接,本系统不预写 |
| P2 | 地形变异接入的格面规则 | 地形变异已定稿落地(2026-09-19 四类型两轴×两关、2026-09-20 枚举化 schema 扩批),新增类型走双方修订流程 |
## 调参表
@@ -1,7 +1,7 @@
# 棋盘生成
> 一句话:棋盘怎么生成、怎么保证可推理可清图
> 状态:已定稿(自旧体系迁移)
> 状态:已定稿(自旧体系迁移);现行为 v1.1
## 设计目的
@@ -131,7 +131,7 @@
**结论**:重试次数与图尺寸联合受成本闸约束。
```
成本闸:max_gen_attempts × board_width × board_height ≤ 成本闸护栏常数 (结构护栏常数,见 `data/schemas/board_gen_table.gd`;provisional 量级,正式值待实现期定)
成本闸:max_gen_attempts × board_width × board_height ≤ 成本闸护栏常数 (结构护栏常数,见棋盘参数表字段定义;provisional 量级,正式值待实现期定)
```
| 出口 | 何时走 | 发生什么 |
@@ -146,7 +146,7 @@
### 图类型标签与第三轴预留:主题恒定、Boss 板有座位
每张图带一个图类型标签(board_type 字段;图类型即图的主题、题材,玩家侧显示名「地图类型」)。同关卡的所有图,主题静态恒定——不存在逐图重掷主题的接口,"不会上钓鱼的当"是结构保证而非文案。词表现行 v1.1(2026-09-20 第三关内容批增补;v1.0 两词 2026-09-19 定稿):**dungeon(地牢基线)/ underdark(幽暗地域)/ deep_underdark(灰矮人矿道方向)**,现行值见 board_gen.tres(L1 = dungeon,L2 = underdark,L3 = deep_underdark);域校验 = 词表成员检查(board_gen_table.gd 词表常量),扩词随内容批走修订。这组标签是表现侧换色板与[地图战斗资源](../战斗循环/地图战斗资源.md)图类型差异化插槽的数据源。本节为数据约定,无计算。
每张图带一个图类型标签(board_type 字段;图类型即图的主题、题材,玩家侧显示名「地图类型」)。同关卡的所有图,主题静态恒定——不存在逐图重掷主题的接口,"不会上钓鱼的当"是结构保证而非文案。词表现行 v1.1(2026-09-20 第三关内容批增补;v1.0 两词 2026-09-19 定稿):**dungeon(地牢基线)/ underdark(幽暗地域)/ deep_underdark(灰矮人矿道方向)**,现行值见 board_gen.tres(L1 = dungeon,L2 = underdark,L3 = deep_underdark);域校验 = 词表成员检查(词表归棋盘参数表,扩词随内容批走修订)。这组标签是表现侧换色板与[地图战斗资源](../战斗循环/地图战斗资源.md)图类型差异化插槽的数据源。本节为数据约定,无计算。
参数表的键是关卡序号 × 节点深度,难度沿这两条轴雕刻;精英与 Boss 修饰是预留的第三条轴。本系统不定任何修饰数值,只锁定落点约定——这也是[关卡节点地图](../冒险循环/关卡节点地图.md)与[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)两份文档的输入:
@@ -213,7 +213,7 @@
| shave_ring_radius | int [0, 2] | 现行 1(board_gen.tres 全行) | 先布后删剃雷半径:剃雷域=距出生中心切比雪夫距离 ≤1+r 的格(r=1 → 5×5=25 格;r=0 即只剃出生 3×3 本身=无环剃雷)。**2026-10-05 初始展开收窄批新参数**(调参项非结构冻结) |
| r0_max_cap | int [出生格数 9, 板格数一半](护栏,违例加载期致命) | 现行按板形:10×10=45 / 12×12=43 / 13×13=51 / 14×14=59(board_gen.tres) | 自然 R₀(开局免费展开格数)上限闸=合法性门;超阈整板重掷、耗尽走三分出口。板面 30% 锚(30/43/51/59)经 S1 停机呈报用户裁上调:10×10→45(r=1 自然均值 39>30 结构性倒挂;其余行 30% 锚维持)。**2026-10-05 初始展开收窄批新参数** |
结构冻结(非调参项):键结构与每关深度 0 锚行、四阶段顺序(变异布置段 2026-09-20 已移出管线)、solver_rules、可推理率的合法信息源枚举、及格线域下限 0.85、成本闸常数(结构护栏,登记于 registry board_gen_table 条目,调整走文档修订)、先布后删语义。
结构冻结(非调参项):键结构与每关深度 0 锚行、四阶段顺序(变异布置段 2026-09-20 已移出管线)、solver_rules、可推理率的合法信息源枚举、及格线域下限 0.85、成本闸常数(结构护栏,登记在案,调整走文档修订)、先布后删语义。
## 验收标准
@@ -225,10 +225,10 @@
- 可清图:每个安全格都能从出生区沿安全格八向连通到达;合法性闸先于质量评分。
- 及格线:每张图实测可推理率 ≥ 该行及格线;任何行及格线 ≥ 0.85。
- 重试有界:实际重试次数落在 [1, max_gen_attempts];同一次生成内的重试不开新随机流。
- 成本闸:max_gen_attempts × 宽 × 高超过成本闸护栏常数(结构护栏常数,见 `data/schemas/board_gen_table.gd`)的行加载期被拒;玩法代码零墙钟依赖、零全局随机函数。
- 成本闸:max_gen_attempts × 宽 × 高超过成本闸护栏常数(结构护栏常数,见棋盘参数表字段定义)的行加载期被拒;同种子同参数在任意机器上出图逐位一致。
- 降级诚实:零合法板照常出图,必带非法产物标记与最高级告警;进程不死锁,玩家界面得到诚实告知。
- 加载期校验:布雷数下限、计数可行性、标签非空等违例组合加载期致命。
- 黄金图回归:手工核验小板集的可推理率输出与登记整数对逐位相等(整数对比对,禁浮点容差);换生成参数(推理定义、信息源、定义版本号)必须重制向量并入版本库。
- R₀≤cap 闸(2026-10-05 初始展开收窄批):每张出图自然 R₀ ≤ 该行 r0_max_cap(合法板),或带非法产物标记(accept_worst 诚实降级);闸触发次数入指标集 r0_cap_rejected。
- R₀≤cap 闸(2026-10-05 初始展开收窄批):每张出图自然 R₀ ≤ 该行 r0_max_cap(合法板),或带非法产物标记(接受最不坏·诚实降级);闸触发次数入指标集 r0_cap_rejected。
- 剃雷域参数化(同批):剃雷域=出生中心切比雪夫 ≤1+shave_ring_radius 的方域,出图 ring_removed ≤ 域内候选危险格数 (3+2r)²−9;同种子布雷序列与收窄前逐位一致(零 RNG 消费变化)。
- 表实一致:配置表字段定义与 `data/schemas/board_gen_table.gd` 一致。
- 表实一致:配置表字段与棋盘参数表字段定义一致。
+10 -10
View File
@@ -1,7 +1,7 @@
# 行动经济
> 一句话:每轮行动点怎么花、停手与刷新的代价
> 状态:已定稿(自旧体系迁移)
> 状态:已定稿(自旧体系迁移);现行为 v1.1
## 设计目的
@@ -79,7 +79,7 @@
### 停手与储备行动点
停手是玩家在挖掘期任意时刻的主动决定:立即结束本轮,剩余行动点按 1:1 原值存入储备池——基线没有乘数、没有加成。图没开完,下一轮接着在同一张图上挖。停手不是收入来源,而是纯粹的风险管理工具:它买到的是"退出权",不是战斗收益。停手意图经排雷玩法的批次提交入口进入账本(保证单一结算序),由账本仲裁后自行外发轮次结束消息。**转存率参数化(迭代 22 秘宝批反哺写入,2026-10-12)**:转存率实现为 `finish_round_stop(transfer_pct)` 参数面——缺省 100=1:1 与旧口径逐位一致;秘宝「储备罐」注入 125=1.25:1(整数除法向下取整——每 4 点剩余 AP 多转 1 点 RAP,零头顺延向下);无装配时行为与参数化前逐位相同。转存率归秘宝操作包络参数,本账本的仲裁与发射结构不变。
停手是玩家在挖掘期任意时刻的主动决定:立即结束本轮,剩余行动点按 1:1 原值存入储备池——基线没有乘数、没有加成。图没开完,下一轮接着在同一张图上挖。停手不是收入来源,而是纯粹的风险管理工具:它买到的是"退出权",不是战斗收益。停手意图经排雷玩法的批次提交入口进入账本(保证单一结算序),由账本仲裁后自行外发轮次结束消息。**转存率参数化(迭代 22 秘宝批反哺写入,2026-10-12)**:转存率实现为停手收轮时的转存率参数——缺省 100=1:1 与旧口径逐位一致;秘宝「储备罐」注入 125=1.25:1(整数除法向下取整——每 4 点剩余 AP 多转 1 点 RAP,零头顺延向下);无装配时行为与参数化前逐位相同。转存率归秘宝操作包络参数,本账本的仲裁与发射结构不变。
储备池的生命周期以一场战斗为界:战斗内跨轮次、跨雷图一直累积;战斗结束立刻清零。清零必须在界面上可见,防止玩家觉得"攒的钱凭空没了"。MVP 阶段储备池没有上限。
@@ -93,7 +93,7 @@
### 下轮行动点修正(格面资源八型批 2026-09-20)
格面资源八型批(2026-09-20)新增 action 型格面资源:正向行 ap_up = 下轮行动点 +1,负向行 ap_drain(迟滞)= 下轮行动点 −1。修正不在授予当轮生效:结算期经 `action_economy.queue_ap_delta` 排队(同轮多笔按净值累加),下一轮开始时(notify_round_start)一次性兑现——兑现值 = 基线 ap_per_round + 排队净值,下限 0,兑现后队列清零;排队净值不跨轮保留。明细在结算流水记效果行(effect_id=ap_delta)。
格面资源八型批(2026-09-20)新增 action 型格面资源:正向行 ap_up = 下轮行动点 +1,负向行 ap_drain(迟滞)= 下轮行动点 −1。修正不在授予当轮生效:结算期经行动经济的行动点修正队列登记(同轮多笔按净值累加),下一轮开始时(开轮通知)一次性兑现——兑现值 = 基线 ap_per_round + 排队净值,下限 0,兑现后队列清零;排队净值不跨轮保留。明细在结算流水记效果行(effect_id=ap_delta)。
跨轮携带量口径随之改写:RAP 仍是唯一显式携带的系统资源(停手转存、玩家可见可花),行动点修正队列是第二携带量——一次性、自动清零、不可主动消费。
@@ -132,13 +132,13 @@
4. **清图奖励大于零**,并预留按图类型差异化分支的结构位。
5. **清图支配性**:推到底清图的期望收益,不低于"确定格挖完就弃图刷新"的期望收益——否则清图玩法会被刷新策略淘汰。
**结论**:五条契约由战斗结算作为唯一对账责任方闭合验收;概率侧由棋盘生成的可推理率参数锚定;条款3 数值层由 β 比值带 [1.2, 2.5] 判读看护(常设重跑入口 `tools/clear_dominance_audit.py`),封印边际结构层由条件二封印溢价接替(机制载体 settlement.flag_hit_premium)。
**结论**:五条契约由战斗结算作为唯一对账责任方闭合验收;概率侧由棋盘生成的可推理率参数锚定;条款3 数值层由 β 比值带 [1.2, 2.5] 判读看护(清图支配性审计为常设重跑项),封印边际结构层由条件二封印溢价接替(机制载体 settlement.flag_hit_premium)。
推导:
```
条款 3(2026-10-05 判式换代批重立——三层口径并行立,2026-10-04 用户裁 P2;
设计权威 = 方案报告 §四/§九(已退役,git 1da9a41;现行判式口径=本文条款③))
设计权威 = 方案报告 §四/§九(已退役;现行判式口径=本文条款③))
条款 2(封印标中锚,既有不动):封印标中的减益档位必须严格高于最低档安全格增益。
@@ -172,7 +172,7 @@
η 读数(行为面,非判式——2026-10-04 用户裁 P1 乙降格读数):
η = flag_hit ÷ flag_placed(分母 = 全部封印数,2026-10-04 grill Q5 裁),
标空率 = flag_miss ÷ flag_placed 次读数分列。字段随 runsum 五字段承载
标空率 = flag_miss ÷ flag_placed 次读数分列。字段随结算摘要五字段承载
(flag_placed/flag_hit/flag_miss/标中兑付合计/标空惩罚合计——结算流水聚合)。
条款 5(清图支配性,不动):
@@ -181,9 +181,9 @@
| 变量 | 含义 | 锚定来源 |
|---|---|---|
| E_dig(u) | 单安全格期望收益当量(77 权重池加权,随敌方单位数 u 缩放 side-wide 项) | 战斗结算的效果对照表 + `tools/clear_dominance_audit.py` |
| E_dig(u) | 单安全格期望收益当量(77 权重池加权,随敌方单位数 u 缩放 side-wide 项) | 战斗结算的效果对照表 + 清图支配性审计读数 |
| V_mine(u) | 单雷期望惩罚当量(九型负向字典同池加权) | 同上 |
| ρ̂ | 雷率:名义 0.25 与实测幸存雷率(10×10 ≈ 0.129 / 12×12 ≈ 0.157)双口径并报,主表用名义(保守) | board_gen.tres + board_stat_probe 读数 |
| ρ̂ | 雷率:名义 0.25 与实测幸存雷率(10×10 ≈ 0.129 / 12×12 ≈ 0.157)双口径并报,主表用名义(保守) | board_gen.tres + 棋盘统计读数 |
| q | 玩家对目标格为雷的置信 | 玩家侧行为量(可推理格 q ∈ {0,1}) |
| β 带 | V_mine/E_dig 判读带 [1.2, 2.5] | 本文条款③重立条 |
| δ | 封印溢价系数 0.25 provisional | settlement.tres flag_hit_premium = 125 |
@@ -238,7 +238,7 @@
| refresh_cap_per_round | int | 表值(provisional,结构位预留) | 每轮刷新上限,开轮重置计数 |
| (跨表)跨冒险行动点加成 | int [0,10] / int [0,99],冒险表 | adventure_table bonus_ap_flat / bonus_cap_ap(provisional) | 三选一 AP 件兑现值与全冒险次数上限;加成轴语义见「跨冒险行动点加成轴」节 |
字段名注记:2026-09-18 措辞完成批已全链对齐正式名——表字段与本文行名统一为 `refresh_cap_per_round`,行动点入口统一为 `request_refresh`(registry naming_unification 兑现,切片临时名零残留)。
字段名注记:2026-09-18 措辞完成批已全链对齐正式名——表字段与本文行名统一为 `refresh_cap_per_round`,刷新入口命名与表字段口径对齐(命名统一登记兑现,切片临时名零残留)。
跨字段校验:任一动作成本禁止超过每轮预算,违反即加载期致命(fail-fast)。各域上界(8 / 64)是 MVP 量级护栏而非推导界,随调参需要修订。
@@ -253,7 +253,7 @@
- 储备清零:战斗结束信号到达后储备池归 0,行动点进入休眠。
- 跨字段校验:任一动作成本配置超过每轮预算时,加载期致命中止。
- 零随机:同一动作序列驱动两个独立行动点实例,轮次结束记录与储备轨迹逐项相同。
- 表实一致:配置表字段与 `data/schemas/action_economy_table.gd` 逐字段一致。
- 表实一致:配置表字段与行动经济表字段定义逐字段一致。
## 待办
@@ -102,7 +102,7 @@ HUD框架站在玩家与全部玩法系统之间:挖掘期它是输入的翻
| 棋盘(封印印记、小人位置) | 意图批次调用返回后重查 |
| 行动点 / 储备 | 每次写路径回执后重读 |
| 状态效果 | 绑定结算编排完成时点 |
| 已开格奖励身份 | 已开格揭显时经身份解析只读回调查询(`query_identity`,组合根注入) |
| 已开格奖励身份 | 已开格揭显时经身份解析只读回调查询(组合根注入) |
就地更新指只改变化的字段、不整块重建界面——整块重建会把敌人立绘死亡灰化这类就地状态吞掉。
@@ -134,7 +134,7 @@ HUD框架站在玩家与全部玩法系统之间:挖掘期它是输入的翻
| 信息内容 | 只表达格面资源的类型(九类格面资源归五组色相呈现,色相/明度/画法规格归 [art-bible](../../../art/art-bible.md) §4.2);不表达极性(安全/雷)、不表达具体收益档位 |
| 生命周期 | 资源身份装板期摇定(微光只是显示,不改任何游戏数据)→ 未开 ∧ 在 8 格内 → 亮;格子被挖开/连锁开/踩雷 → 灭;角色走远出圈 → 灭,走回 → 复亮;换图随旧图全重置 |
| 关联与边界 | 信息本体(格面资源身份)归[地图战斗资源](../战斗循环/地图战斗资源.md);棋盘格态与动作合法性归[排雷玩法](../排雷循环/排雷玩法.md);与「接触带微光」同圈不同职责——接触带微光=可挖域的交互反馈光(「这里能挖」),类型微光=相邻格的类型先读(「这格是什么类型」) |
| 实装状态 | 呈现契约已定稿(五组色相经样张 v2 冻结 2026-09-28);**已实装(迭代 30 卡① 2026-10-17 入库,合并 `7ffd1dc0`)**——2026-09-30 核证的「呈现层仅接触带微光在跑,类型微光无独立实现」状态自此注销;在役实现(五组色相 = ui_kit TG_GLOW_*、格面微光子件 + 距离场 shader)与验收转正见本节末「验收标准」类型微光行,登记面归 [待办清单](../../../../待办清单.md)「未开格类型徽章呈现时机」条(已完成) |
| 实装状态 | 呈现契约已定稿(五组色相经样张 v2 冻结 2026-09-28);**已实装(迭代 30 卡① 2026-10-17 入库)**——2026-09-30 核证的「呈现层仅接触带微光在跑,类型微光无独立实现」状态自此注销;在役实现(五组色相 = 呈现套件色相常量、格面微光子件 + 距离场渲染)与验收转正见本节末「验收标准」类型微光行,登记面归 [待办清单](../../../../待办清单.md)「未开格类型徽章呈现时机」条(已完成) |
口径史注记(防复发):本概念曾只活在待办清单登记与 art-bible 复述里,「常显」「全部未开格」等无范围表述于 2026-09-30 酿成理解事故;用户裁决「英雄周围 8 格」为正确口径并落位本节。教训=概念必须落地权威文档,零散复述不是定义。
@@ -148,7 +148,7 @@ HUD框架站在玩家与全部玩法系统之间:挖掘期它是输入的翻
|---|---|
| 定义与作用范围 | 接触带微光 = 可挖域的交互反馈光(「这里能挖」)——英雄格与可挖域(8 向相邻未开格;概念本体与动作合法性归[排雷玩法](../排雷循环/排雷玩法.md))接触面上的呼吸微光;与「未开格类型微光」同圈不同职责(类型微光=「这格是什么类型」,本光=「这里能挖」) |
| 画法 | 光画英雄格周界空间侧:正交邻墙=该侧整条边,斜向邻墙=共享角点+向两侧各延伸半条边;光只画英雄格一侧、不进墙格;色相=蓝族浅一档——画法细则归 [art-bible](../../../art/art-bible.md) §3.2 |
| 生命周期 | 挖掘期呈现且呼吸(挖掘期唯一在动元素——art-bible §2.1;相位门控 `set_dig_glow_enabled`,结算期停息);减动效开启=呼吸停格(静态保留指界功能);换图/装板随新可挖域重算 |
| 生命周期 | 挖掘期呈现且呼吸(挖掘期唯一在动元素——art-bible §2.1;相位门控,结算期停息);减动效开启=呼吸停格(静态保留指界功能);换图/装板随新可挖域重算 |
| 关联与边界 | 逐格指认=悬停金框(pattern 4 悬停预承诺——微光是常驻指界、悬停是意图预承诺,两概念分工);不携带类型/极性信息(那是类型微光的职责);零信息写入(纯呈现层) |
| 实装状态 | 已实装(呈现层现行在跑——2026-09-30 核证;程序化占位,画法终稿随样张批) |
@@ -163,9 +163,9 @@ HUD框架站在玩家与全部玩法系统之间:挖掘期它是输入的翻
| 关联与边界 | 与「未开格类型微光」同边界——灯光区起步半径=微光环 8 格(同圈起步,实测后可调);格态数据归[排雷玩法](../排雷循环/排雷玩法.md);黑暗区域渲染规格(暗淡态明度、迷雾过渡)归 [art-bible](../../../art/art-bible.md) 修订随实施批;初始展开收窄不在本案(后置与 Alpha 差异化批窗口合并再议) |
| 实装状态 | **已实装**(2026-10-03 迭代 11 第④批已入库;四裁决逐条对账与验收线转正见本节末「实施状态」注记;渲染规格 = [art-bible](../../../art/art-bible.md) §6.5) |
配套拍板(同日):魔法提灯=灯甲形态(光照圈外扩 +2 格,flat 整数档)随迷雾立项;**类型微光不随视野扩大**(类型先读仍只贴身 8 格,微光锚=可挖域);提灯载体归 aux_items 新行(登记原文——2026-10-07 用户令改道为独立卡,2026-10-08 裁案A=秘宝·同调位新行落位,见下方实施状态注记;**2026-10-09 用户裁退役**——新目录 15 件未收提灯,fog_lantern 数据行与卡④接线拆除归退役删行批〔实装批〕,功能由新目录普通档「阔视野带」承接,待办清单登记条在册),呈现面挂「资产升档重产批」(挂账不动)。
配套拍板(同日):魔法提灯=灯甲形态(光照圈外扩 +2 格,flat 整数档)随迷雾立项;**类型微光不随视野扩大**(类型先读仍只贴身 8 格,微光锚=可挖域);提灯载体归 aux_items 新行(登记原文——2026-10-07 用户令改道为独立卡,2026-10-08 裁案A=秘宝·同调位新行落位,见下方实施状态注记;**2026-10-09 用户裁退役**——新目录 15 件未收提灯,提灯数据行与卡④接线拆除归退役删行批〔实装批〕,功能由新目录普通档「阔视野带」承接,待办清单登记条在册),呈现面挂「资产升档重产批」(挂账不动)。
**实施状态(2026-10-03 迭代 11 第④批已入库)**:迷雾遮蔽+菱形灯光区跟随+暗淡记忆态上线,探针断言顺带扩(ui_input_probe case⑮)。四裁决逐条对账——①案甲视野迷雾立项(纯呈现层):迷雾开关分层验证可用(呈现态布尔,off 态=无迷雾基线),同板同动作序列与 MC 逐项比对逐位一致;②暗淡记忆态:区外已开格灰显+数字可读,明度按 [art-bible](../../../art/art-bible.md) §6.5 写入文档值(记忆板 #3A3A3A/记忆墨 #C4C4C4,provisional);③灯光半径=微光环 8 格同圈:LIGHT_RADIUS=8 参数化(曼哈顿菱形,常量);④提灯 +2、微光不扩:FOG_LANTERN_BONUS=+2(落码常量实名——本条旧记 LIGHT_RADIUS_LANTERN_BONUS 系文档侧拟名,随卡④入库对齐),类型微光仍贴身 8 邻格零改动。**〔2026-10-05 迭代14⑤接线注记〕公共接线面已就位**——`board_view.set_fog_lantern(enabled)`(true=半径 8+2、false=复原 0;写入即 refresh 重算雾态),半径算式消费 `_fog_lantern` 迷雾批已在位;ui_input_probe case⑮ 增接线断言(开=dist 9 格转可见+lantern=2/关=复原)。**〔2026-10-08 迭代 19 卡④入库注记〕载体到位+接线闭环=功能可达**——载体=秘宝·同调位新行 `fog_lantern`「魔法提灯」(treasure_items.tres 表尾追加,desc「灯光区半径+2」,slot_cost 1、营地秘宝匣同调装配获渠,行字段=用户「按推荐」全收);生产路径=runner set_attunement→enc.attunement→begin_battle 注入 orchestrator 装配集→公共只读出口 `attune_has`→组合根呈现桥 `main._sync_fog_lantern` 每战首轮装配链**显式重算含否**(🔴 复原语义=禁战斗结束隐式复原——卸装/未装配写 0,断点续玩/跨关天然正确);未装配=false 写 0=缺省零扰动基线逐位不变。顺带测试:case⑮ 载体级段(装配→lantern=2+dist R+1 转可见+卸装复原)+smoke 行字段/同调目录投影(九件→十件)/装配贯通断言+存档回归 Part 6+单测 fog_lantern_wiring(run_all 17→18 套)。原「提灯载体归 aux_items 新行随 Alpha 信息件重定批」登记去向就此注销(改道留痕=需求卡片-提灯载体道具批-2026-10-07 §一)。验收线(本篇「验收标准」视野迷雾行)逐条转正式验收:区内完整渲染/区外已开格灰显可读/区外未开格不可见/灯光区随移动跟随/两态结算逐位一致;实机目检人闸(迷雾观感/记忆态可读性/移动跟随流畅度)随出口闸。黑暗区域渲染规格承载 = art-bible §6.5(v3.5)。
**实施状态(2026-10-03 迭代 11 第④批已入库)**:迷雾遮蔽+菱形灯光区跟随+暗淡记忆态上线,输入探针断言顺带扩(迷雾案)。四裁决逐条对账——①案甲视野迷雾立项(纯呈现层):迷雾开关分层验证可用(呈现态布尔,off 态=无迷雾基线),同板同动作序列与 MC 逐项比对逐位一致;②暗淡记忆态:区外已开格灰显+数字可读,明度按 [art-bible](../../../art/art-bible.md) §6.5 写入文档值(记忆板 #3A3A3A/记忆墨 #C4C4C4,provisional);③灯光半径=微光环 8 格同圈:半径 8 参数化(曼哈顿菱形,常量);④提灯 +2、微光不扩:提灯加成 +2,类型微光仍贴身 8 邻格零改动。**〔2026-10-05 迭代14⑤接线注记〕公共接线面已就位**——公共提灯开关接口(开=半径 8+2、关=复原 0;写入即重算雾态),迷雾批已在位消费该值;输入探针增接线断言(开=距离 9 格转可见+提灯 2/关=复原)。**〔2026-10-08 迭代 19 卡④入库注记〕载体到位+接线闭环=功能可达**——载体=秘宝·同调位新行「魔法提灯」(treasure_items.tres 表尾追加,desc「灯光区半径+2」,slot_cost 1、营地秘宝匣同调装配获渠,行字段=用户「按推荐」全收);生产路径=冒险装配→战斗装配集注入→公共只读出口查装配含否→组合根呈现桥每战首轮装配链**显式重算含否**(🔴 复原语义=禁战斗结束隐式复原——卸装/未装配写 0,断点续玩/跨关天然正确);未装配=零加成(缺省零扰动基线逐位不变)。顺带测试:载体级迷雾案(装配→提灯 2+距离 R+1 转可见+卸装复原)+冒烟行字段/同调目录投影(九件→十件)/装配贯通断言+存档回归 Part 6+单测提灯接线(全套 17→18 套)。原「提灯载体归 aux_items 新行随 Alpha 信息件重定批」登记去向就此注销(改道留痕=需求卡片-提灯载体道具批-2026-10-07 §一)。验收线(本篇「验收标准」视野迷雾行)逐条转正式验收:区内完整渲染/区外已开格灰显可读/区外未开格不可见/灯光区随移动跟随/两态结算逐位一致;实机目检人闸(迷雾观感/记忆态可读性/移动跟随流畅度)随出口闸。黑暗区域渲染规格承载 = art-bible §6.5(v3.5)。
### 营地:可点击场景图(旧四柜台并排形态已随卡④改版取代)
@@ -196,9 +196,9 @@ HUD框架站在玩家与全部玩法系统之间:挖掘期它是输入的翻
| 上游 | [排雷玩法](../排雷循环/排雷玩法.md) | 棋盘只读投影(格态、数字、封印印记、小人)与移动路径查询;玩家意图批次经组合根提交 |
| 上游 | [行动经济](../排雷循环/行动经济.md) | 行动点 / 储备 / 相位只读值;刷新入口可用性预判加返回值兜底 |
| 上游 | [战斗结算](../战斗循环/战斗结算.md) | 明细流水是结算明细带的统一数据源(现行 9 类行封闭协议);段序编排信号经组合根接线 |
| 上游 | [敌人系统](../战斗循环/敌人系统.md) | 英雄与敌人的只读投影(血量、顺位、摇定动作〔pending_skill/type/name〕、敌方增益 effects、存活——经战斗结算呈现快照;敌人技能池批批 2 定稿:当前拍/行动环进度字段拆除,池与权重不公开) |
| 上游 | [敌人系统](../战斗循环/敌人系统.md) | 英雄与敌人的只读投影(血量、顺位、摇定动作〔技能标识·类型·名称〕、敌方增益、存活——经战斗结算呈现快照;敌人技能池批批 2 定稿:当前拍/行动环进度字段拆除,池与权重不公开) |
| 上游 | [增益状态](../战斗循环/增益状态.md) | 状态投影经战斗结算呈现面取得,零直读 |
| 上游 | [地图战斗资源](../战斗循环/地图战斗资源.md) | 已开格奖励身份投影(`query_identity` 只读回调,组合根注入)零直读 |
| 上游 | [地图战斗资源](../战斗循环/地图战斗资源.md) | 已开格奖励身份投影(只读回调,组合根注入)零直读 |
| 上游 | [关卡节点地图](../冒险循环/关卡节点地图.md) | 节点链、当前节点、跨战斗生命携带的读数;胜利后推进 |
| 下游 | [战斗表现](../战斗循环/战斗表现.md) | 交付三区布局、明细带呈现位、敌人呈现语义(站桩形态);它只叠加动画密度与演出 |
| 下游 | [音频](音频.md) | 挂点事件源(明细行类型流、toast 触发);MVP 无音频 |
@@ -218,7 +218,7 @@ HUD框架站在玩家与全部玩法系统之间:挖掘期它是输入的翻
| [地图战斗资源](../战斗循环/地图战斗资源.md) | 已开格的奖励身份常读;未开格类型微光(英雄周围 8 格内的未开格显示资源类型——概念定义见本篇「未开格类型微光」节) |
| [秘宝](../跨局循环/秘宝.md) | 装配件与充能常读;使用交互与目标拾取;整图叠加层信息呈现(在役旧框架——随实装批整体替换,秘宝.md v1.7 同款口径) |
| [棋盘生成](../排雷循环/棋盘生成.md) | 零合法板的诚实告知(数据面经战斗结算上抛,本系统只管提示形态) |
| [地形变异](../排雷循环/地形变异.md) | 全局作用域型三层预告(2026-10-04 首发批——语义现行事实源=地形变异 §全局作用域型):①开战横幅一行(整图变异非空时显示;减动效=静态驻留,轮横幅先例同款双态)②HUD 常驻角标(C 区战斗全程可见防中局遗忘,空态整节隐藏=奇物段先例;摆位 provisional)③帮助手册一行(零交互教学,承载=玩法帮助文案块);数据面经呈现快照 board_variants 投影(核心→呈现唯一读取面),普通图三层恒空态零打扰 |
| [地形变异](../排雷循环/地形变异.md) | 全局作用域型三层预告(2026-10-04 首发批——语义现行事实源=地形变异 §全局作用域型):①开战横幅一行(整图变异非空时显示;减动效=静态驻留,轮横幅先例同款双态)②HUD 常驻角标(C 区战斗全程可见防中局遗忘,空态整节隐藏=奇物段先例;摆位 provisional)③帮助手册一行(零交互教学,承载=玩法帮助文案块);数据面经呈现快照的整图变异投影(核心→呈现唯一读取面),普通图三层恒空态零打扰 |
## P0 最小闭环
@@ -1,13 +1,13 @@
# 存档序列化
> 一句话:存档契约与版本迁移
> 状态:已定稿(2026-09-21 存档序列化批落地);现行为 v1.1
> 状态:已定稿(2026-09-21 存档序列化批落地);现行为 v1.2
## 设计目的
本系统管的是"关掉游戏之后,玩家的东西还在不在"。序列化(本文含义:把游戏运行中的数据写成可存盘的档案,下次启动再原样读回来)与版本迁移(本文含义:游戏更新后,旧版本写下的存档要能被新版本继续读懂,必要时把旧结构改写成新结构)合起来,就是"存档契约"这门生意的全部。
这件事是[核心循环](../../01-核心循环.md)里"存档在变厚"那条故事线的底层承载:钥石攒进存档、倒下也不丢——写在纸面上就是本系统的职责。本系统在切片里的落地面是 `core/save_manager.gd`(SaveManager,Core 层零 UI、零玩法依赖),本文描述的就是这份契约:存什么、何时读写、版本怎么走、坏了怎么办。
这件事是[核心循环](../../01-核心循环.md)里"存档在变厚"那条故事线的底层承载:钥石攒进存档、倒下也不丢——写在纸面上就是本系统的职责。本系统在切片里的落地面是存档管理器:Core 层,零界面依赖、零玩法依赖。本文描述的就是这份契约:存什么、何时读写、版本怎么走、坏了怎么办。
## 系统范围
@@ -48,7 +48,7 @@
### 基础层身份:无上游依赖的承载方
SaveManager 不依赖任何玩法系统就能工作:它是被动的承载方,任何系统要把数据活过单局,都向本系统登记持久化归属,而不是本系统去追认每个系统。这条身份可验证:SaveManager 不引入任何玩法脚本、不碰数值表(ConfigDB)与随机服务(RngService),可以独立实例化、独立读写验证(冒烟独立段承载)。
存档系统不依赖任何玩法系统就能工作:它是被动的承载方,任何系统要把数据活过单局,都向本系统登记持久化归属,而不是本系统去追认每个系统。这条身份可验证:存档系统不引入任何玩法脚本、不碰数值表与随机服务,可以独立实例化、独立读写验证(冒烟独立段承载)。
### 存什么:表与档分家,局内系统资源不入档
@@ -56,13 +56,13 @@ SaveManager 不依赖任何玩法系统就能工作:它是被动的承载方
第二条边界是反面清单:局内资源不入存档。行动点、储备行动点、道具库存、生命、GP 全部单局清零——各归各的系统管,没有局内数值需要持久化。若未来某局内资源要开放跨局携带(如储备行动点跨战斗携带),须修订其池规则并向本系统登记持久化归属,禁止静默超域。
**唯一豁免 = `breakpoint` 断点域**(2026-09-29 迭代 8 卡①顺带修订):断点是冒险进行中的瞬态快照,不是跨局携带——里面的生命/GP/道具库存只在「续玩上局」时还原进局内,冒险收束(通关/失败/放弃)即整域清除,永远不会渗进永久进度。反面清单的管辖对象因此收窄为 `meta` 永久进度域(冒烟域界扫描顺带收窄到 meta 域);断点域自身的字段口径归[冒险结构](../冒险循环/冒险结构.md)登记。断点顶层键(27 键+2026-10-27 迭代 39 获得日记键扩列至 28)的登记单源=`core/adventure_runner.gd` 内 `const BREAKPOINT_FIELDS`(键→回退策略标签);写读已换代为各件自交片段——主角账/停点件/关卡件各自写读自己的键(缺键回退策略随领域知识归各件),冒险应用层是唯一拼盘落盘口(收齐各件片段拼成顶层快照后写盘,写触发点不变)。**关卡完成停点的同调未用行留存**(2026-10-27 迭代 39 副卡边界裁定):`aux_items` 键在此停点形态含同调未用行(关卡末清空改选择性保留——「同调行始终留在 treasure_inventory」与「键值形态逐位不变」在关卡完成停点互斥,采行留存;玩家可见 C 区投影零变化,24 停点充能读数逐位一致)。
**唯一豁免 = `breakpoint` 断点域**(2026-09-29 迭代 8 卡①顺带修订):断点是冒险进行中的瞬态快照,不是跨局携带——里面的生命/GP/道具库存只在「续玩上局」时还原进局内,冒险收束(通关/失败/放弃)即整域清除,永远不会渗进永久进度。反面清单的管辖对象因此收窄为 `meta` 永久进度域(冒烟域界扫描顺带收窄到 meta 域);断点域自身的字段口径归[冒险结构](../冒险循环/冒险结构.md)登记。断点顶层键(27 键+2026-10-27 迭代 39 获得日记键扩列至 28)的登记单源=冒险应用层的断点键表(键→回退策略;现行契约见架构文档「冒险域拆分」节);写读已换代为各件自交片段——主角账/停点件/关卡件各自写读自己的键(缺键回退策略随领域知识归各件),冒险应用层是唯一拼盘落盘口(收齐各件片段拼成顶层快照后写盘,写触发点不变)。**关卡完成停点的同调未用行留存**(2026-10-27 迭代 39 副卡边界裁定):`aux_items` 键在此停点形态含同调未用行(关卡末清空改选择性保留——「同调行始终留在 treasure_inventory」与「键值形态逐位不变」在关卡完成停点互斥,采行留存;玩家可见 C 区投影零变化,24 停点充能读数逐位一致)。
**三存档位(迭代 33 卡①,2026-10-22 反哺写入)**:存档是 3 个独立的 JSON 文件(`user://save_slot_1/2/3.json`,槽文件名只经 `slot_path()` 单点派生,槽 1 禁复用旧单档名),字典键一律字符串。写盘目标=当前激活槽的文件;启动(boot)不读任何槽文件——启动态=无激活态,不读写;激活态由选档界面的「新档」(`create_slot`)或「进档」(`activate_slot`)建立(选档界面归迭代 33 卡③)。数据模型(现行 = v6;示例值全为零值默认态):
**三存档位(迭代 33 卡①,2026-10-22 反哺写入)**:存档是 3 个独立的 JSON 文件(三个独立存档文件,槽文件名只经存档系统单点派生,槽 1 禁复用旧单档名),字典键一律字符串。写盘目标=当前激活槽的文件;启动(boot)不读任何槽文件——启动态=无激活态,不读写;激活态由选档界面的「新档」或「进档」建立(选档界面归迭代 33 卡③)。数据模型(现行 = v7;示例值全为零值默认态):
```json
{
"version": 6,
"version": 7,
"meta": {
"keystone_balance": 0,
"item_unlocks": {},
@@ -95,28 +95,28 @@ SaveManager 不依赖任何玩法系统就能工作:它是被动的承载方
| `attune_refresh_level` | 营地刷新升级(Y 源)等级(v4) | [秘宝](../跨局循环/秘宝.md)(三选一刷新双源) |
| `tree_nodes` | 天赋树已购等级(node_id→int,v5) | [天赋树](../跨局循环/天赋树.md) |
| `fork_sides` | Fork 组激活侧(fork_group→a/b,v5) | [天赋树](../跨局循环/天赋树.md) |
| `tree_struct` | 树结构版本标记(=TREE_STRUCT_VERSION,迭代 21 T5;缺失 = 换代前结构,加载废弃重置) | [天赋树](../跨局循环/天赋树.md) |
| `tree_struct` | 树结构版本标记(迭代 21 T5;缺失 = 换代前结构,加载废弃重置) | [天赋树](../跨局循环/天赋树.md) |
| `recent_summaries` | 最近冒险摘要副本,最新在前,最多 10 条 | [冒险结构](../冒险循环/冒险结构.md) |
| `first_adventure_done` | 首冒险完成标记(新档默认 false;旧档缺省按已完成兜底) | [元进度](../跨局循环/元进度.md) |
| `adventure_total` | 冒险总局数终身计数(开局即计、含放弃与失败,v6) | [生涯](../跨局循环/生涯.md) |
| `adventure_cleared` | 冒险成功局数终身计数(三关全通才计 1,v6;秘宝条件解锁计数键) | [生涯](../跨局循环/生涯.md) |
| `vision_used` | 真视类工具累计使用次数终身计数(迭代 22 新增——信标网络解锁行为条件;**v6 域后扩列补零、不升版本**;写入唯一经 `add_vision_used`,冒险收束聚合入账;断点随件键=`vision_counter_used`,续玩回填缺省 0) | [秘宝](../跨局循环/秘宝.md) |
| ~~`forge_levels`~~ | ~~属性锻造三档等级~~ | **已退役**(迭代 21 T5:行族/访问器/域随攻防所有权切分删除——`save_manager.gd:12-14/:399-401` 白名单收窄;继任 = 锻造工坊路线等级域,见下行计划登记) |
| `vision_used` | 真视类工具累计使用次数终身计数(迭代 22 新增——信标网络解锁行为条件;**v6 域后扩列补零、不升版本**;写入唯一经真视计数入口,冒险收束聚合入账;断点随件键=`vision_counter_used`,续玩回填缺省 0) | [秘宝](../跨局循环/秘宝.md) |
| ~~`forge_levels`~~ | ~~属性锻造三档等级~~ | **已退役**(迭代 21 T5:域与访问器随攻防所有权切分删除;继任 = 锻造路线等级域) |
| `forge_routes`(**已落地 v7——锻造工坊实装批 T5,迭代 23**) | {levels: 六路线等级(sword/spear/staff/light/heavy/ward), unlocked: 直购解锁路线 id 清单, weapon: 当前武器路线 id, armor: 当前甲路线 id};无特效域;旧档缺键补齐 = 初始持有态 | [锻造工坊](../跨局循环/锻造工坊.md) |
| `breakpoint` | 冒险断点快照(停点粒度续玩域;空字典 = 无断点合法态——「继续上局」隐藏) | [冒险结构](../冒险循环/冒险结构.md) |
v4/v5/v6 各域缺键由读取方按默认值补齐(空集合/0),旧档零迁移损失;收束自增域(通关次数/Boss 计数/终身计数/真视使用计数)的唯一入账点 = `apply_adventure_summary`(vision_used 走 `add_vision_used` 收束)。**v6 域后扩列不升版先例**:`vision_used`(迭代 22,2026-10-12——迭代 21 同款口径;断点随件 `vision_counter_used` 同批新增;旧断点随件键 `bonus_aux_carry` 已随替换子交互拆除退役,迭代 22 T5)。
v4/v5/v6 各域缺键由读取方按默认值补齐(空集合/0),旧档零迁移损失;收束自增域(通关次数/Boss 计数/终身计数/真视使用计数)的唯一入账点 = 冒险摘要入账(vision_used 走真视计数入口收束)。**v6 域后扩列不升版先例**:`vision_used`(迭代 22,2026-10-12——迭代 21 同款口径;断点随件 `vision_counter_used` 同批新增;旧断点随件键 `bonus_aux_carry` 已随替换子交互拆除退役,迭代 22 T5)。
消费面纪律:其他系统只经 SaveManager 的类型化访问器(读余额/加钥石/花钥石、读写树等级等)与域更新原语(`apply_adventure_summary`)操作存档,不碰内部数据结构。三条槽位纪律(迭代 33 卡①):一、无激活态下一切写盘路径拒绝并返回 false(boot 后未进档/未新档即结算或购买=不落盘,激活后照常);二、槽文件名单点派生——消费方禁各自拼槽文件名,测试与探针的隔离走注入口(`attach_slot_template`/`peek_summary_at`);三、UI 读别槽摘要只走窥视 API `peek_slot_summary(slot)`(不激活、不写内存、零盘面副作用),返回结构 `{"readable", "has_file", "keystone", "cleared", "total"}`——`readable`=槽文件可读(空槽=零值合法态可读;损坏/高版本/缺版本字段=不可读标记),`has_file`=槽主文件在盘与否(空槽/有档的操作集二分判定来处;非摘要第四项、零 UI 语义),三项摘要值(`keystone`/`cleared`/`total`)只在 `readable=true` 时有意义。
消费面纪律:其他系统只经存档系统的类型化访问器(读余额/加钥石/花钥石、读写树等级等)与域更新原语(冒险摘要入账)操作存档,不碰内部数据结构。三条槽位纪律(迭代 33 卡①):一、无激活态下一切写盘路径拒绝并返回 false(boot 后未进档/未新档即结算或购买=不落盘,激活后照常);二、槽文件名单点派生——消费方禁各自拼槽文件名,测试与探针的隔离走注入口(槽模板注入/摘要窥视);三、UI 读别槽摘要只走窥视 API(不激活、不写内存、零盘面副作用),返回结构 = 可读标记 + 三项摘要值(钥石/通关数/总局数)——可读标记 = 槽文件可读(空槽=零值合法态可读;损坏/高版本/缺版本字段=不可读标记);槽主文件在盘与否不作摘要项、只供操作集二分判定(零 UI 语义),三项摘要值只在可读时有意义。
### 读写时机
```
启动 ──▶ 不读盘(boot 无激活态,不读写任何槽;只做一次旧单档迁移,见「版本与迁移」节)
选档界面「新档」/「进档」──▶ create_slot / activate_slot(读盘=该槽文件,建立激活态;迭代 33 卡①/卡③)
正式冒险收束(adventure_finished)──▶ apply_adventure_summary 入账 ──▶ 原子写盘(落当前激活槽)
选档界面「新档」/「进档」──▶ 建立激活态(读盘=该槽文件;迭代 33 卡①/卡③)
正式冒险收束 ──▶ 冒险摘要入账 ──▶ 原子写盘(落当前激活槽)
营地钥石消费(元进度实现批接线)──▶ 每笔变更后即时写盘(落当前激活槽)
冒险停点(choices_presented 选路停点)──▶ 断点快照写盘(迭代 8 卡①)
冒险停点(选路停点)──▶ 断点快照写盘(迭代 8 卡①)
冒险三结局收束(冒险成功/失败/放弃)──▶ 清除断点 + 原子写盘(迭代 8 卡①/T3 退出口径)
```
@@ -124,13 +124,13 @@ v4/v5/v6 各域缺键由读取方按默认值补齐(空集合/0),旧档零
断点写盘纪律(迭代 8 卡①):停点快照在每个选路停点(战斗胜利/兑付确认/入口呈现后的选路态)整体覆写——战斗进行中不写(棋盘中局不入档,续玩恢复至最近停点、当场战斗从头打)。因为快照总在每个停点即时落盘,「关游戏走人」在任何停点都不丢续玩进度,无需窗口关闭钩子。
写盘是原子操作:先写临时文件(`<路径>.tmp`),写完改名覆盖正式档——写一半断电不留烂档。
写盘是原子操作:先写同目录临时文件,写完改名覆盖正式档——写一半断电不留烂档。
单局测试入口不写档:调试两层与 headless 单关测试路径(LevelRunner.start_level,仅 QA 工具使用)不接写盘——测试模式不污染生涯数据;只有正式冒险(AdventureRunner)收束才入账。
单局测试入口不写档:调试两层与 headless 单关测试路径(仅 QA 工具使用)不接写盘——测试模式不污染生涯数据;只有正式冒险收束才入账。
### 版本与迁移
存档带版本字段(`version`,当前 = **7**;版本沿革:v2 = 断点域出生〔迭代 8 卡①〕→ v3 = 断点附随件扩列 + 摘要 keystone_drops〔迭代 10 奖励重构〕→ v4 = 同调批扩域〔boss_kill_count / attunement_equipped / attune_refresh_level,迭代 11 第①批〕→ v5 = 天赋树域〔tree_nodes / fork_sides,迭代 12〕→ v6 = 生涯终身计数域〔adventure_total / adventure_cleared,迭代 18 卡④〕→ **v7 = 锻造工坊域〔forge_routes,迭代 23 T5——已落地:{levels 六路线等级 + unlocked 直购解锁清单 + weapon/armor 当前选中标记},无特效域;旧档缺键由 _normalize 按默认补齐 = 初始持有态(sword/light 在档、余四锁、选中=初始路线),v6→v7 空迁移 = 缺键补齐模式(v3→v4 先例);开发阶段禁迁移禁折算——契约 4〕**;与 `game/core/config_db.gd` 的 SCHEMA_VERSION 同源)。三条走向:
存档带版本字段(`version`,当前 = **7**;版本沿革:v2 = 断点域出生〔迭代 8 卡①〕→ v3 = 断点附随件扩列 + 摘要 keystone_drops〔迭代 10 奖励重构〕→ v4 = 同调批扩域〔boss_kill_count / attunement_equipped / attune_refresh_level,迭代 11 第①批〕→ v5 = 天赋树域〔tree_nodes / fork_sides,迭代 12〕→ v6 = 生涯终身计数域〔adventure_total / adventure_cleared,迭代 18 卡④〕→ **v7 = 锻造工坊域〔forge_routes,迭代 23 T5——已落地:{levels 六路线等级 + unlocked 直购解锁清单 + weapon/armor 当前选中标记},无特效域;旧档缺键按默认补齐 = 初始持有态(sword/light 在档、余四锁、选中=初始路线),v6→v7 空迁移 = 缺键补齐模式(v3→v4 先例);开发阶段禁迁移禁折算——契约 4〕**)。三条走向:
| 情形 | 处置 |
|---|---|
@@ -138,13 +138,13 @@ v4/v5/v6 各域缺键由读取方按默认值补齐(空集合/0),旧档零
| 版本更高(未来版本的档) | **拒读且禁写**:不加载、后续写盘一律拒绝、内存以默认新档运行——保护未来版本的档不被当前版本覆写 |
| 版本更低(旧档) | 读档时逐级迁移:从旧版本起逐个调用注册的迁移函数升到当前版本;任一步失败按损坏兜底处理 |
迁移函数经 `register_migration(旧版本号, 函数)` 注册:函数把数据从「旧版本」改写成「旧版本 + 1」。生产迁移链现行六件(v2 起自注册):v1→v2 = 断点域补空;v2→v3 = 断点附随件与摘要 keystone_drops 补键(读取方 .get 兜底);v3→v4 = 同调三域补键;v4→v5 = 树域两键补齐(原挂接的「三体系迁移」体已随迭代 21 T5 攻防所有权切分删除——`save_manager.gd:96-98`、`meta_progression.gd:294-295` 实证;forge_levels 旧域同批清退,加载时按默认模型键集白名单收窄,`save_manager.gd:399-401`);v5→v6 = 生涯两终身计数域补零;**v6→v7 = 锻造工坊域 forge_routes 缺键补齐(迭代 23 T5——无结构迁移体,版本号推进仅为 schema_version 对齐;解锁态派生不落档:初始持有〔表 initial_owned〕∨ 直购〔unlocked 清单〕∨ 练满前一档〔levels[prereq]≥cap〕)**。任一步失败按损坏兜底处理。
迁移函数按旧版本号逐一注册:函数把数据从「旧版本」改写成「旧版本 + 1」。生产迁移链现行六件(v2 起自注册):v1→v2 = 断点域补空;v2→v3 = 断点附随件与摘要 keystone_drops 补键(读取方 .get 兜底);v3→v4 = 同调三域补键;v4→v5 = 树域两键补齐(原挂接的「三体系迁移」体已随迭代 21 T5 攻防所有权切分删除;forge_levels 旧域同批清退,加载时按默认模型键集白名单收窄);v5→v6 = 生涯两终身计数域补零;**v6→v7 = 锻造工坊域 forge_routes 缺键补齐(迭代 23 T5——无结构迁移体,版本号推进仅随表结构变化;解锁态派生不落档:初始持有〔表 initial_owned〕∨ 直购〔unlocked 清单〕∨ 练满前一档〔levels[prereq]≥cap〕)**。任一步失败按损坏兜底处理。
旧单档一次性迁移(迭代 33 卡①,用户裁决 Q1 甲):本系统从单档制换代为 3 存档位制时,盘上残留的旧单档 `user://save.json` 在启动时被处理——文件**字节级原样搬运**进槽 1(`user://save_slot_1.json`,零解析零改造:损坏或高版本的旧档也原样迁入,之后由该槽进档时的损坏兜底/高版本拒读接管,不静默丢数据),源文件改名 `user://save.json.migrated.bak` 留痕不删;槽 1 文件已存在则不重迁(幂等,二次启动零操作);迁移失败(拷贝或改名失败)源文件保留、下次启动重试。留痕与结果记在启动日志(开发者向,非玩家面)。
旧单档一次性迁移(迭代 33 卡①,用户裁决 Q1 甲):本系统从单档制换代为 3 存档位制时,盘上残留的旧单档文件在启动时被处理——文件**字节级原样搬运**进槽 1(零解析零改造:损坏或高版本的旧档也原样迁入,之后由该槽进档时的损坏兜底/高版本拒读接管,不静默丢数据),源文件改名留痕不删;槽 1 文件已存在则不重迁(幂等,二次启动零操作);迁移失败(拷贝或改名失败)源文件保留、下次启动重试。留痕与结果记在启动日志(开发者向,非玩家面)。
### 损坏兜底
档案读不开(文件损坏、JSON 解析失败、结构出域、缺版本字段)时:原文件改名为 `<路径>.corrupt.bak`(已有同名备份则覆盖)留下现场,游戏用默认新档继续运行,并留下警告日志。两条底线:不静默丢档(坏档永远可人工找回)、不崩溃(坏档不挡玩)。
档案读不开(文件损坏、JSON 解析失败、结构出域、缺版本字段)时:原文件改名留一份坏档备份(已有同名备份则覆盖)留下现场,游戏用默认新档继续运行,并留下警告日志。两条底线:不静默丢档(坏档永远可人工找回)、不崩溃(坏档不挡玩)。
## 依赖与输出
@@ -164,12 +164,12 @@ MVP 不要求本系统的闭环([不做清单](../../05-不做清单.md)把单
| 优先级 | 内容 | 后置原因 |
|---|---|---|
| ~~P1~~ | ~~快照与复盘的持久化承接~~ | **已兑现**(2026-09-29 迭代 8 卡①:断点域承载 + rng「主种子+计数器」快照契约回填面 `restore_adventure`) |
| ~~P1~~ | ~~快照与复盘的持久化承接~~ | **已兑现**(2026-09-29 迭代 8 卡①:断点域承载 + rng「主种子+计数器」快照契约回填面) |
| ~~P2~~ | ~~多存档槽位~~ | **已实现**(2026-10-22 迭代 33 卡①——3 存档位三文件制落地,口径见「三存档位」段;原「单档 MVP(2026-09-21 裁决)」后置条随兑现注销) |
## 调参表
本系统没有玩法调参数值。两个结构常量:存档版本号(=6,与 `game/core/config_db.gd` 的 SCHEMA_VERSION 同源)、最近摘要保留条数(10)。二者是结构契约不是平衡值,改动属于版本迁移事件,不走调参批。
本系统没有玩法调参数值。两个结构常量:存档版本号(当前 7)、最近摘要保留条数(10)。二者是结构契约不是平衡值,改动属于版本迁移事件,不走调参批。
## 验收标准
@@ -179,7 +179,7 @@ MVP 不要求本系统的闭环([不做清单](../../05-不做清单.md)把单
- 改版不弃档:旧版本档经迁移链读回;低版本档缺新域按默认补齐,既有值保留(冒烟承载)。
- 断点域契约(迭代 8 卡①):七字段拍板面写读往返逐位一致;旧档无断点域迁移为合法空态;三结局清除(冒烟+单测承载)。
- 域界干净:meta 永久进度域不含局内系统资源键(行动点/储备行动点/道具库存/生命/GP)——断点域按豁免条款单列(冒烟承载,2026-09-29 卡①修订)。
- 零玩法依赖:SaveManager 不引入任何玩法脚本、不碰数值表与随机服务,可独立实例化验证(冒烟独立段承载)。
- 零玩法依赖:存档系统不引入任何玩法脚本、不碰数值表与随机服务,可独立实例化验证(冒烟独立段承载)。
## 待办
@@ -1,7 +1,7 @@
# 数据配置
> 一句话:数值表与单一事实源管线
> 状态:已定稿(自旧体系迁移);现行为 v1.0
> 状态:已定稿(自旧体系迁移);现行为 v1.1
## 设计目的
@@ -18,7 +18,7 @@
| 负责 | 说明 |
|---|---|
| 全部数值表的结构与数据 | 表结构类(声明每列的类型、取值域与默认值)与数据文件成对交付;结构先行,数值由各回填责任方回填 |
| 全局读取口与随机服务 | 两个进程级单例:类型化读取口(代码标识符 ConfigDB)与统一随机流服务(代码标识符 RngService) |
| 全局读取口与随机服务 | 两个进程级单例:类型化读取口与统一随机流服务 |
| 加载、校验与热重载管线 | 启动加载、fail-fast 校验、调试构建热重载的状态管理 |
| 进度坐标查行 | 进度键表(跟着冒险进度成长的表)按(关卡序号 × 节点深度)两维坐标解析取行 |
| 表清单与对账 | 表路径固定、清单封闭;表实与 schema 声明逐字段对账 |
@@ -28,7 +28,7 @@
| 不负责 | 归谁 |
|---|---|
| 各表数值定值与玩法公式 | 各回填责任方(清单见核心规则的表清单),平衡总归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md) |
| 存档格式与版本比较逻辑 | [存档序列化](存档序列化.md),本系统只出版本常量与随机快照契约 |
| 存档格式与版本比较逻辑 | [存档序列化](存档序列化.md),本系统只出随机快照契约 |
| 界面呈现 | [HUD 框架](HUD框架.md) |
| 随机用途的设计合理性 | 消费方系统自证(随机须有界、可见或可推理),新增随机走扩签通道 |
@@ -52,24 +52,24 @@
一句话总结这条规则:改数值 = 改表回填,不动代码;表不变,行为逐位相同。仅调试构建存在两个额外通道:从命令行注入的根目录加载测试夹具表;调试覆盖值可临时改读数、不回写表文件,正式构建结构性不存在覆盖源。
现行表集合如下(表结构类名供代码标识与工具链检索):
现行表集合如下:
| 表 | 载什么 | 回填责任方 |
|---|---|---|
| 行动经济表 `ActionEconomyTable` | 每轮行动点、动作价目、停手与刷新门槛 | [行动经济](../排雷循环/行动经济.md) |
| 棋盘生成参数表 `BoardGenTable` | 板尺寸、雷密度、可推理率目标等(进度键表) | [棋盘生成](../排雷循环/棋盘生成.md) |
| 变异表 `VariationTable` | 变异类型清单(现行六行:region 六行两轴×三关〔2026-09-20 落地〕;首发 global 整图型贫矿脉 2026-10-16 用户令屏蔽删行,global 型机制代码保留) | [地形变异](../排雷循环/地形变异.md) |
| 敌人表 `EnemyTable` | 敌种基线数值、遭遇数量区间、护甲类型、技能池模板(进度键表) | [敌人系统](../战斗循环/敌人系统.md) |
| 技能表 `SkillTable` | 技能行定义(类型/倍率/冷却/增益引用/触发条件)与保底阈值 | [敌人系统](../战斗循环/敌人系统.md) |
| 主角表 `HeroTable` | 主角生命上限、基础攻击与护甲等级(armor_class)等单行战斗数值 | [敌人系统](../战斗循环/敌人系统.md) |
| 状态效果表 `StatusEffectTable` | 增益/减益效果定义行 | [增益状态](../战斗循环/增益状态.md) |
| 奖励表 `RewardTable` | 奖励条目、类别、权重与档位 | [地图战斗资源](../战斗循环/地图战斗资源.md) |
| 结算表 `SettlementTable` | 结算段序、当量参考敞口、封顶与克制矩阵(单行全局) | [战斗结算](../战斗循环/战斗结算.md) |
| 秘宝表 `TreasureItemTable`(`treasure_items.tres`) | 秘宝定义行 | [秘宝](../跨局循环/秘宝.md) |
| 难度表 `DifficultyTable` | 难度修饰乘数(占位空表) | [难度曲线与Boss](../冒险循环/难度曲线与Boss.md) |
| 关卡表 `LevelTable` | 逐关节点图与层名 | [冒险结构](../冒险循环/冒险结构.md) |
| 冒险表 `AdventureTable` | 关卡大奖励与钥石入账(单行全局) | [冒险结构](../冒险循环/冒险结构.md) |
| 元进度表 `MetaTable` | 元进度字段(已建表 2026-09-21——现行五行族:属性锻造 / Boss 钥石 / 工坊阈值 / 换算率 / 同调刷新升级行族,顺带扩列) | [元进度](../跨局循环/元进度.md) |
| 行动经济表 | 每轮行动点、动作价目、停手与刷新门槛 | [行动经济](../排雷循环/行动经济.md) |
| 棋盘生成参数表 | 板尺寸、雷密度、可推理率目标等(进度键表) | [棋盘生成](../排雷循环/棋盘生成.md) |
| 变异表 | 变异类型清单(现行六行:region 六行两轴×三关〔2026-09-20 落地〕;首发 global 整图型贫矿脉 2026-10-16 用户令屏蔽删行,global 型机制代码保留) | [地形变异](../排雷循环/地形变异.md) |
| 敌人表 | 敌种基线数值、遭遇数量区间、护甲类型、技能池模板(进度键表) | [敌人系统](../战斗循环/敌人系统.md) |
| 技能表 | 技能行定义(类型/倍率/冷却/增益引用/触发条件)与保底阈值 | [敌人系统](../战斗循环/敌人系统.md) |
| 主角表 | 主角生命上限、基础攻击与护甲等级(armor_class)等单行战斗数值 | [敌人系统](../战斗循环/敌人系统.md) |
| 状态效果表 | 增益/减益效果定义行 | [增益状态](../战斗循环/增益状态.md) |
| 奖励表 | 奖励条目、类别、权重与档位 | [地图战斗资源](../战斗循环/地图战斗资源.md) |
| 结算表 | 结算段序、当量参考敞口、封顶与克制矩阵(单行全局) | [战斗结算](../战斗循环/战斗结算.md) |
| 秘宝表(`treasure_items.tres`) | 秘宝定义行 | [秘宝](../跨局循环/秘宝.md) |
| 难度表 | 难度修饰乘数(占位空表) | [难度曲线与Boss](../冒险循环/难度曲线与Boss.md) |
| 关卡表 | 逐关节点图与层名 | [冒险结构](../冒险循环/冒险结构.md) |
| 冒险表 | 关卡大奖励与钥石入账(单行全局) | [冒险结构](../冒险循环/冒险结构.md) |
| 元进度表 | 元进度字段(已建表 2026-09-21——现行五行族:属性锻造 / Boss 钥石 / 工坊阈值 / 换算率 / 同调刷新升级行族,顺带扩列) | [元进度](../跨局循环/元进度.md) |
举证:本节为数据纪律约定,无计算。违规检测 = 静态扫描加人工复核,随各表回填定稿与里程碑检查执行。
@@ -88,11 +88,11 @@
取数有两个入口。玩法代码用取号入口:每调用一次,全局计数器加一并派生新种子,同一事件内共享同一实例。测试与预览用纯函数入口:按指定全局序号计算种子、不推计数器——预览不污染正式序列。种子由登记的派生公式计算(单盐),纯函数、跨引擎版本恒定,并登记了可复算的黄金向量。
全事件日志(并流批新增):冒险开始即开日志会话(user://logs/rng_log_<主种子>.jsonl),每次取数落一行——全局序号、用途标签、派生种子。号位在全序账本下不再单独回答"第 N 次某类事件"(路线依赖为已裁决代价),单点定位与复盘由日志承载。写盘失败只告警降级,不致命、不影响玩法随机。
全事件日志(并流批新增):冒险开始即开日志会话(随机事件日志文件,每主种子一份),每次取数落一行——全局序号、用途标签、派生种子。号位在全序账本下不再单独回答"第 N 次某类事件"(路线依赖为已裁决代价),单点定位与复盘由日志承载。写盘失败只告警降级,不致命、不影响玩法随机。
生命周期:进程启动后流待命(未注入主种子就取数,致命中止,禁止默认种子兜底)→ 冒险开始注入主种子并开日志会话 → 冒险中按事件取号(全局计数器只增不重置)→ 冒险结束流保留供复盘。续玩与复盘的快照 = 主种子加全局取数计数器,由[存档序列化](存档序列化.md)消费;快照切出须发生在没有在用取号实例的时刻。要新增随机用途(含战斗内随机),走扩签通道:改代码加用途标签并通过评审——词表封闭是刻意的设卡。
举证:派生公式与实现规约见 `game/core/rng_service.gd`(盐与派生常量为代码事实),黄金向量断言见 `game/tests/unit/data_config/rng_stream_boot_test.gd`;本文不转载。
举证:派生公式(单盐)由随机服务持有,本文不转载;黄金向量已登记可复算,逐向量复算相等即验收判据。
### fail-fast 校验:宁可启动失败,不带病运行
@@ -110,7 +110,7 @@
热重载(不重启进程、当场重新加载表文件的调试手段,仅调试构建)单独一套处置:战斗进行中的重载请求被闸门拒绝(闸门由[战斗结算](../战斗循环/战斗结算.md)在战斗开始时置位、结束复位),重载校验失败时保留旧表继续运行并给出错误清单——不杀调试会话,这是全部规则里唯一的软着陆。调试构建之外,加载与校验在任何构建形态一律致命。随机服务的状态线独立于表加载:重载成败都不触碰主种子与计数器。
举证:本节为处置纪律约定,无计算。校验双通道(正式通道致命、测试通道收集供冒烟逐类断言)与夹具注入为实现参照,见 `game/core/config_db.gd` 实现。
举证:本节为处置纪律约定,无计算。校验双通道与夹具注入为实现参照,本文不转载。
### 悬空引用校验:跨表引用指到的键必须存在
@@ -155,7 +155,7 @@
| 下游 | [冒险结构](../冒险循环/冒险结构.md) | 关卡表与冒险表承载(登记现状见「待办」);主种子注入入口 |
| 下游 | [难度曲线与Boss](../冒险循环/难度曲线与Boss.md) | 难度表承载(占位);进度坐标查行的消费方 |
| 下游 | [元进度](../跨局循环/元进度.md) | 元进度表占位承载 |
| 下游 | [存档序列化](存档序列化.md) | 表结构版本常量;随机快照契约(主种子 + 全局取数计数器) |
| 下游 | [存档序列化](存档序列化.md) | 随机快照契约(主种子 + 全局取数计数器) |
| 下游 | [HUD 框架](HUD框架.md) | 调试热重载完成通知(仅调试构建) |
| 外发 | 无订阅 | 本系统不订阅任何玩法事件 |
@@ -186,7 +186,6 @@
| 参数 | 现行值 | 说明 |
|---|---|---|
| 表路径清单 | data/tables/ 固定(调试注入根除外) | 冻结:散装路径破坏单点访问 |
| 表结构版本常量 `SCHEMA_VERSION` | 当前 = 2(v2=断点域出生,迭代 8 卡①,与存档 SAVE_FORMAT_VERSION 同源) | 全部表结构携带版本字段;高于当前支持的版本拒读,比较逻辑归[存档序列化](存档序列化.md) |
| 随机流口径 | 统一流单盐单计数器 + 七用途标签封闭词表 | 统一口径为 2026-09-27 裁决;扩签 = 改代码 + 评审,有意设卡 |
| 进度坐标解析策略 | 可取范围内向上取整 + 警告(保证偏难);超出最大行封顶取最大值 + 警告;域越界致命(2026-09-18 两段拍板,原「就近向下」退役) | 冻结:静默降难会掩盖难度断档 |
| 入口锚行校验 | 写死开 | 非调参项;重议走文档修订流程 |
@@ -200,12 +199,11 @@
- 黄金向量:随机派生纯函数对登记向量逐个复算相等;同输入恒同输出;同序号重复调用恒等。
- 计数器纪律:连续取号跨模拟关卡切换,计数器单调不重置;热重载成败都不改变主种子与计数器。
- 向上取整解析:请求无精确行时返回**不低于**请求坐标的最近行并留一条警告;请求超出最大已有行时封顶取最大行并留警告;同类警告去重;精确命中零警告。
- 越域与未播种:坐标低于合法域(关卡序号 <1、节点深度 <0)在进入解析前致命中止(Fatal 级诊断 + 进程退出码 1,致命类单测 `tests/unit/data_config/config_db_fatal_oob_test.gd` 验证——迭代 19 卡① T4 探针退役顺带改指,原切片探针断言面与 run_all 致命类单测重复故退役);高于最大已有行走封顶取最大行(警告留痕,不致命);未设主种子就取随机数致命中止,无默认种子兜底。
- 越域与未播种:坐标低于合法域(关卡序号 <1、节点深度 <0)在进入解析前致命中止(Fatal 级诊断 + 进程非 0 退出,无兜底);高于最大已有行走封顶取最大行(警告留痕,不致命);未设主种子就取随机数致命中止,无默认种子兜底。
- 热重载门:战斗中重载被拒绝且读数不变、不发通知;门未置位时新值可读且通知恰一次;校验失败保留旧表停留就绪态。
- 版本常量在位:表结构版本常量存在且全部表结构携带版本字段(高版本拒读判定归存档序列化)。
- 零字面量、零第二路径:静态扫描加人工复核确认玩法代码无数值字面量、无读取口之外的表加载、无全局随机函数调用。
- 零界面依赖:本系统代码不引用任何界面类,无窗口实跑通过(静态扫描与实跑两项合成判定)。
- 表实一致:各表结构与已锁字段和 `data/schemas/` 对应声明逐字段一致。
- 表实一致:各表结构与已锁字段和表结构声明逐字段一致。
## 待办
@@ -1,7 +1,7 @@
# 设置与本地化
> 一句话:设置项与多语言
> 状态:范围草案·最小设置面已兑现(2026-09-29 迭代 8 卡④)
> 状态:范围草案·最小设置面已兑现(2026-09-29 迭代 8 卡④);现行为 v1.1
## 设计目的
@@ -92,7 +92,7 @@ MVP 不要求本系统的闭环:[不做清单](../../05-不做清单.md)把设
| 优先级 | 内容 | 后置原因 |
|---|---|---|
| ~~P1~~ | ~~已承诺设置项落位:减动效开关、音量控制入口~~ | **已兑现**(2026-09-29 迭代 8 卡④最小设置面:音量 master bus 实时+持久、减动效开关转正〔测试调整板旧开关退役,设置面唯一入口〕、全屏切换、退出游戏;载体 presentation/settings_store.gd 独立存储 + views/settings_overlay.gd 视图;键位映射/多语言仍按后置表排期) |
| ~~P1~~ | ~~已承诺设置项落位:减动效开关、音量控制入口~~ | **已兑现**(2026-09-29 迭代 8 卡④最小设置面:音量 master bus 实时+持久、减动效开关转正〔测试调整板旧开关退役,设置面唯一入口〕、全屏切换、退出游戏;载体=独立设置存储 + 设置界面视图(一安装一份,不进存档);键位映射/多语言仍按后置表排期) |
| P1 | 多语言生产流程与首批语言清单 | 生产流程未定:文案怎么管理、谁负责校对 |
| P2 | 设置项全集(画面 / 键位 / 可访问性 / 语言各类别) | 全集无来源,待设计问题清单裁决后展开 |
| P2 | 结算风味词输入的承接 | 归档只登记了存在,各归各的时机 |
+10 -10
View File
@@ -1,7 +1,7 @@
# 元进度
> 一句话:跨局成长——钥石在营地换成永久强化,存档随冒险变厚
> 状态:**已定稿(现行为 v1.25)**——2026-09-18 元进度定稿批用户拍板;历次升版明细见 git 提交史。
> 状态:**已定稿(现行为 v1.26)**——2026-09-18 元进度定稿批用户拍板;历次升版明细见 git 提交史。
## 设计目的
@@ -62,18 +62,18 @@
| 功能界面 | 内容 | 解锁渠道 |
|---|---|---|
| 属性锻造 | 生命上限、基础攻击、护甲等级——三档可重复升级的属性强化 | 钥石直购 |
| 秘宝匣 | 秘宝解锁与同调装配——**件的目录与效果权威定义在[秘宝](秘宝.md)「目录(重设计 v1)」**(12 件三档〔2026-10-11 裁回能器删/换装券撤/第四只手删〕;旧目录全退役只作素材库) | 解锁=混合制(基础件钥石购买/特定件条件解锁——见秘宝.md「道具从哪来」;装配只在冒险开始前配置,冒险中零更换途径〔2026-10-11 终裁〕);**迭代 22 实装批落地(2026-10-12)**:购买钮(余额不足禁用态)+条件解锁进度呈现+分档装配呈现(名后缀·档位/未解锁禁装)+空目录合法态;界面数据投影=`treasure_shop_status`(解锁态/条件进度/价格单点);旧道具工坊渠道面(行族/词表/解锁函数)已顺带退役;钥石定价与阈值 provisional 归调参批 |
| 秘宝匣 | 秘宝解锁与同调装配——**件的目录与效果权威定义在[秘宝](秘宝.md)「目录(重设计 v1)」**(12 件三档〔2026-10-11 裁回能器删/换装券撤/第四只手删〕;旧目录全退役只作素材库) | 解锁=混合制(基础件钥石购买/特定件条件解锁——见秘宝.md「道具从哪来」;装配只在冒险开始前配置,冒险中零更换途径〔2026-10-11 终裁〕);**迭代 22 实装批落地(2026-10-12)**:购买钮(余额不足禁用态)+条件解锁进度呈现+分档装配呈现(名后缀·档位/未解锁禁装)+空目录合法态;界面数据投影=秘宝匣柜台状态(解锁态/条件进度/价格单点);旧道具工坊渠道面(行族/词表/解锁函数)已顺带退役;钥石定价与阈值 provisional 归调参批 |
| 奖励格图鉴 | 特殊奖励格的解锁——更强效果的格面 | 结构位现定;格子内容排 Alpha,随[地图战斗资源](../战斗循环/地图战斗资源.md)差异化批落地 |
属性锻造的树形节点结构已随迭代 12 落地在役——**结构/节点/数值的现行事实源 = [天赋树](天赋树.md),本文不复制树侧内容、只作指路**;本界面三档直线强化与树淬炼 flat 在注入面叠加生效(注入口径见下文「跨局注入」节)。
属性锻造的攻击、护甲两档已按[锻造工坊](锻造工坊.md) v0.6(成文时名「武器锻造」,2026-10-11 更名)设计定案转为武器与护甲的独立等级路线——**行族本体随迭代 21 T5 退役、路线为新建行族,已随迭代 23 实装入库(2026-10-12,新表 `forge.tres`)**。营地钥石入口族换代(2026-10-13 v1.18 迭代 23 反哺写入):buy_forge 随 forge_products 退役删除后,本柜台钥石消费写口 = **forge_buy_level(逐级锻造价)/ forge_buy_unlock(一次性解锁价)/ forge_select_weapon·armor(免费选中)**——写口唯一经 MetaProgression 锻造写口族(契约 9 写口单点,UI 只发意图);钥石定价历史考古参数 20 钥石/150% 公比见 `meta.tres:82-84` 退役批注,provisional 投值终值归 M4。
属性锻造的攻击、护甲两档已按[锻造工坊](锻造工坊.md) v0.6(成文时名「武器锻造」,2026-10-11 更名)设计定案转为武器与护甲的独立等级路线——**行族本体随迭代 21 T5 退役、路线为新建行族,已随迭代 23 实装入库(2026-10-12,新表 `forge.tres`)**。营地钥石入口族换代(2026-10-13 v1.18 迭代 23 反哺写入):原逐级购买写口随 forge_products 退役删除后,本柜台钥石消费写口 = **逐级锻造价 / 一次性解锁价 / 免费选中武器·甲**——写口唯一经元进度锻造写口族(契约 9 写口单点,UI 只发意图);钥石定价历史考古参数 20 钥石/150% 公比见 `meta.tres` 退役批注,provisional 投值终值归 M4。
**营地统一(2026-10-11 天赋树设计会话裁案甲;2026-10-13 v1.20 迭代 21 反哺写入——「落地前维持现役」过渡态终结)**:树=营地本体,本属性锻造柜台已随迭代 21 退役、属性升级唯一入口=树脊柱淬炼节点(四柜台并排已实装,2026-10-12 入库)。**完整模型(四柜台并排/钥匙工作间/图鉴常开)唯一事实源 = [天赋树](天赋树.md)「营地=树:统一模型」节——本文只登记本柜台在系统内的去留,不复制树侧内容。**
**投值语言锁定(2026-09-18 数值语言拍板)**:营地属性强化一律 **flat 整数加减**("每级 +1 基础攻击"式,而非"+50% 攻击"式)——避开百分比词条被数值成长稀释的先例陷阱、守住数字可读性锚;具体每级数值仍归元进度设计批投值。
各界面定价纪律:**定价曲线一律几何递增**(每级费用按公比上浮——原则已拍板,起步价与公比数字归设计批配读数),与产出逻辑配套:深层关钥石产出多、后级强化贵,逼玩家往深处走。~~秘宝匣首版只挂通关次数渠道~~(历史排期裁决已消解:秘宝匣现役=钥石直购+条件解锁混合制,迭代 22 落地,2026-10-12)。**存档义务随柜台产生**:钥石余额、永久强化等级表、每关通关次数表、Boss 首杀标记位——四件已逐域登记在 registry `save_file` 条目(内容 owner = 元进度,承载 owner = [存档序列化](../表现与支撑/存档序列化.md))。
各界面定价纪律:**定价曲线一律几何递增**(每级费用按公比上浮——原则已拍板,起步价与公比数字归设计批配读数),与产出逻辑配套:深层关钥石产出多、后级强化贵,逼玩家往深处走。~~秘宝匣首版只挂通关次数渠道~~(历史排期裁决已消解:秘宝匣现役=钥石直购+条件解锁混合制,迭代 22 落地,2026-10-12)。**存档义务随柜台产生**:钥石余额、永久强化等级表、每关通关次数表、Boss 首杀标记位——四件已逐域登记在存档登记条目(内容 owner = 元进度,承载 owner = [存档序列化](../表现与支撑/存档序列化.md))。
护甲等级进首版属性柜台是 2026-09-18 拍板(用户选 A),其代价条款见下方换算率节的强条目登记。
@@ -81,7 +81,7 @@
解锁让玩家变强,难度验收区间随之需要平移——双方约定(难度曲线与Boss 定稿口径)永久强化的影响**不直接改难度判据**,而是按统一换算率折算成关卡完成率带的平移量后套用:完美档 gate 与 normal 目标带的判读口径不变,带随解锁等级平移。
换算率表(registry 键 `meta_progression_conversion_table`,数值行读 `data/tables/meta.tres` conversion 行族)登记三个属性维度(2026-09-18 拍板;"行" = 表内一条记录,一个属性维度即一行条目,全仓与"行值"同义)。现行表值(2026-09-23 换算率标定批投值——OFAT 冒险注入档与白板同种子配对的逐关条件通关率差实测,冒险条件口径 + 当日数值包现行态;报告=git 提交 7f24b64(已按生命周期条款退役),判定端 ④ 段可复判):
换算率表(数值行读 `data/tables/meta.tres` conversion 行族)登记三个属性维度(2026-09-18 拍板;"行" = 表内一条记录,一个属性维度即一行条目,全仓与"行值"同义)。现行表值(2026-09-23 换算率标定批投值——OFAT 冒险注入档与白板同种子配对的逐关条件通关率差实测,冒险条件口径 + 当日数值包现行态;报告已按生命周期条款退役,判定端 ④ 段可复判):
| 换算行 | 折算语义 | 每级带平移量(现行表值) |
|---|---|---|
@@ -89,17 +89,17 @@
| 基础攻击强化 | 每级折算为关卡完成率带平移量 | **9 点** |
| 护甲等级强化 | 每级折算为关卡完成率带平移量 | **1 点** |
判定端(tools/balance_verifier.py)表值驱动消费:验收带按解锁状态 flat÷每级flat×表值平移后套用,表改则判定随动。护甲行强条目重测义务已于标定批履行(解锁后参数实测,非基线外推);标定同时暴露并修复护甲断链(begin_battle `hero_armor_class` 参数零消费——主角护甲锻造与加算区护甲轴的生效值此前未进战斗),修复见 battle_orchestrator `_defender_ac` 批注。
判定端按表值驱动消费:验收带按解锁状态折算后套用,表改则判定随动。护甲行强条目重测义务已于标定批履行(解锁后参数实测,非基线外推);标定同时暴露并修复一处缺口:主角护甲锻造与局内加算区护甲轴的生效值此前未进战斗(该轴此前无消费方=已知缺口,已随标定批修复并登记)。
后续柜台商品(秘宝匣钥石价、奖励格图鉴)上架时逐条补行——每次上架新商品伴随一行换算登记,逐行归因纪律不破。
### 跨局注入:解锁怎么进下一局
注入通道沿用两处预留位(2026-09-18 拍板确认):[冒险结构](../冒险循环/冒险结构.md)的**冒险开始参数面**(无解锁时为空参数)+ registry `hero_override_parameter_passing`(begin_battle 显式入参,-1 = 表值兜底)。
注入通道沿用两处预留位(2026-09-18 拍板确认):[冒险结构](../冒险循环/冒险结构.md)的**冒险开始参数面**(无解锁时为空参数)+ 英雄覆盖参数传递通道(战斗初始化显式入参,-1 = 表值兜底)。
执行口径:开始一次新冒险时,本系统按存档内的永久强化状态算好一份 override,逐字段显式传给战斗初始化——配置因此不是完全静态的,随游戏进程动态改变(用户拍板原话口径)。字段清单随柜台扩展:道具池、遭遇权重、奖励格解锁是集合操作,参数面登记**追加 / 替换**两种语义。
**开局属性四层叠加(2026-10-12 v1.16 补登记——事实源=[锻造工坊](锻造工坊.md)「注入衔接」节 v0.6 / [天赋树](天赋树.md);原「属性锻造三档是数值覆盖」随迭代 21 T5 行族退役换代为下述分层;2026-10-13 v1.18 迭代 23 反哺写入补终态句)**:开局属性 = 角色基础值 + 树生命/命中淬炼 flat + 锻造路线加值(当前选中武器的攻击加值 + 当前甲的 AC 加值——默认值由锻造工坊配置常驻持有、与柜台解锁状态解耦,当前选中读存档域)+ 局内加算区 flat。入战 AC 三层可加 = 甲型基础 AC + 甲路线等级加值 + 局内加算区累加——**第一层「甲型基础 AC」= 选中甲路线行 `base_ac`(`forge.tres`,轻 10/重 12/魔法护甲 9 provisional),已随迭代 23 实装在役(`effective_ac` 三层公式第一层,树 flat + 锻造路线加值同批在役)**。
**开局属性四层叠加(2026-10-12 v1.16 补登记——事实源=[锻造工坊](锻造工坊.md)「注入衔接」节 v0.6 / [天赋树](天赋树.md);原「属性锻造三档是数值覆盖」随迭代 21 T5 行族退役换代为下述分层;2026-10-13 v1.18 迭代 23 反哺写入补终态句)**:开局属性 = 角色基础值 + 树生命/命中淬炼 flat + 锻造路线加值(当前选中武器的攻击加值 + 当前甲的 AC 加值——默认值由锻造工坊配置常驻持有、与柜台解锁状态解耦,当前选中读存档域)+ 局内加算区 flat。入战 AC 三层可加 = 甲型基础 AC + 甲路线等级加值 + 局内加算区累加——**第一层「甲型基础 AC」= 选中甲路线行 `base_ac`(`forge.tres`,轻 10/重 12/魔法护甲 9 provisional),已随迭代 23 实装在役(入战 AC 三层公式第一层,树 flat + 锻造路线加值同批在役)**。
### 解锁界面:双入口框架
@@ -132,7 +132,7 @@ MVP 不要求本系统的闭环([不做清单](../../05-不做清单.md)整体
| P1 | 营地功能界面内容铺量与定价数字 | 界面结构已定稿;清单明细、几何定价的起步价与公比、Boss 两档产出数值,随设计批配读数投值 |
| P1 | 秘宝匣钥石直购价 | **已投 provisional 占位**(普通档 10/优秀档 25 钥石,迭代 22 落地,2026-10-12);终值归调参批(原「首版只挂通关次数渠道」排期态随混合制落地消解) |
| P1 | 奖励格图鉴的格子内容 | 排 Alpha,随[地图战斗资源](../战斗循环/地图战斗资源.md)差异化批 |
| P1 | 换算率表数值行标定 | **已完成**(2026-09-23 换算率标定批——首版三行投值 6/9/1,护甲行强条目重测顺带履行并修复护甲断链)(原系笔误孤例,registry 与 meta.tres 均为 6/9/1——2026-09-30 勘误) |
| P1 | 换算率表数值行标定 | **已完成**(2026-09-23 换算率标定批——首版三行投值 6/9/1,护甲行强条目重测顺带履行并修复护甲断链)(原系笔误孤例,换算率登记与 meta.tres 均为 6/9/1——2026-09-30 勘误) |
| P2 | 营地界面与解锁呈现实现 | 归[HUD 框架](../表现与支撑/HUD框架.md)协作批,以表现层样张过审为前置 |
## 调参表
@@ -141,7 +141,7 @@ MVP 不要求本系统的闭环([不做清单](../../05-不做清单.md)整体
| 表 | 键结构归属 | 数值行 |
|---|---|---|
| 换算率表(`meta_progression_conversion_table`) | 本文 owner,键结构见 `data/schemas/meta_table.gd` | `data/tables/`,设计批投值(首版三行,护甲行强条目) |
| 换算率表 | 本文 owner,键结构见元进度表结构声明 | `data/tables/`,设计批投值(首版三行,护甲行强条目) |
| 定价表(属性锻造 / 秘宝匣 / 奖励格图鉴费用曲线) | 随设计批建表 | `data/tables/`,几何递增参数 |
| 钥石产出(Boss 首杀额 / 重复杀小额) | 入账挂点见[冒险结构](../冒险循环/冒险结构.md)调参表(boss_keystone 行);Boss 两档归本文设计批(每关入账值 keystone_per_level 已随迭代 10 奖励重构退役) | `data/tables/` |
+27 -29
View File
@@ -1,9 +1,9 @@
# 天赋树
> 一句话:营地本身——跨局成长的结构承载:钥石逐节点点亮一棵树,属性淬炼、工作间解锁、规则抉择与同调挂载全部组织在树上
> 状态:**v0.10 R1 机制位批(2026-10-13,用户推翻迭代 21 追认单 #1 裁撤案)**——「等级阈值前置」以机制位形态顺带重立:schema 新增 `requires_level: {node_id: n}`(前置节点等级 ≥ n 才可购;键悬空/阈值 <1/类型错加载即拒)+ 购买判定分支 + 行板门槛呈现(未达标 🔒 标+悬停门槛文案)+ 单测八断言;**现役 12 行零配置=机制位空转零行为影响**,配置归表行随需填。承 v0.9 迭代 21 反哺写入(2026-10-13,用户裁「按呈报写入文档」)——全文档换代为 12 节点落地实态:头部实装态 / 节点总表前言 / schema 连带 / 已建未接面(三条→两接一维持)/ P0 段 / 依赖表 / 验收实态七处换代;「设计避让」句按卡片 v1.7 ⑪②裁决改写为折扣定义边界口径。承 v0.8 Fork 一节点双态换代(2026-10-11 用户裁——开局姿态/危险直觉/财富之道三天赋=三节点、购买解锁后 A/B 双态可切,现役 A/B 双行结构收编、全树 15→12)
> 状态:**已定稿(现行为 v0.11)**——12 节点结构在役(脊柱=生命/命中一线一节点,Fork 三节点双态);「等级阈值前置」为机制位(前置节点等级 ≥ n 才可购;键悬空 / 阈值 <1 / 类型错加载即拒;未达标节点锁标 + 悬停门槛文案),现役 12 行零配置=零行为影响;全部数值行 provisional,归数值批。
> **📖 节点状态记录指引(读这份文档先看这里)**:本树全部 12 个节点=下方「核心规则 → 节点总表」,逐节点列名称/脉/类型/前置/效果方向;**全部数值行(价格 / 等级上限 / 每级效果取值 / 限次值)不在本文**,事实源 = 配置文件 `game/data/tables/meta_tree.tres`(provisional 归数值批)。要查"有哪些节点、怎么连"看本文总表,要查"多少钱、加多少"开配置文件。
> **📖 节点状态记录指引(读这份文档先看这里)**:本树全部 12 个节点=下方「核心规则 → 节点总表」,逐节点列名称/脉/类型/前置/效果方向;**全部数值行(价格 / 等级上限 / 每级效果取值 / 限次值)不在本文**,事实源 = 配置文件 `data/tables/meta_tree.tres`(provisional 归数值批)。要查"有哪些节点、怎么连"看本文总表,要查"多少钱、加多少"开配置文件。
## 设计目的
@@ -19,7 +19,7 @@
| 负责 | 说明 |
|---|---|
| 节点结构与解锁规则 | 12 节点的一脊三脉构成、脊柱行门槛(节点第 N 级)、点亮前置(requires)+ **等级阈值前置(requires_level——R1 机制位 2026-10-13 顺带重立,现役零配置空转)**、Fork 一节点双态与免费切换、彩蛋觉醒——结构事实源 = `data/tables/meta_tree.tres` + schema MetaTreeTable(**已实装在役,迭代 21 T1**) |
| 节点结构与解锁规则 | 12 节点的一脊三脉构成、脊柱行门槛(节点第 N 级)、点亮前置(requires)+ **等级阈值前置(requires_level——R1 机制位 2026-10-13 顺带重立,现役零配置空转)**、Fork 一节点双态与免费切换、彩蛋觉醒——结构事实源 = `data/tables/meta_tree.tres`(**已实装在役,迭代 21 T1**) |
| 树的购买与货币规则 | 全树钥石单币;free 节点零币;购买校验四件套(等级上限 / 行门槛 / 前置 / 未解锁) |
| 营地统一模型 | 树=营地本体(呈现=四柜台并排):生命/命中淬炼唯一入口=树脊柱淬炼节点,攻/AC 唯一入口=锻造工坊路线(所有权切分,2026-10-11 裁);工作间钥匙模型(锻造工坊 / 秘宝匣);图鉴常开;旧属性锻造柜台退役(生命归脊柱、攻防归锻造工坊) |
| 树域存档的内容语义 | tree_nodes(node_id→已购等级)与 fork_sides(fork_group→激活态)两域语义;旧档废弃规则(开发阶段无迁移——2026-10-11 用户裁) |
@@ -58,20 +58,20 @@
### 一脊三脉:节点构成
天赋树(玩家可见名;代码面 `meta_tree`)换代后 12 节点,按脉(vein)分四族:
天赋树(玩家可见名)换代后 12 节点,按脉(vein)分四族:
| 脉 | 节点数 | 内容 | 结构要点 |
|---|---|---|---|
| 主干脊柱(spine) | 2 | 生命淬炼 / 命中淬炼——一线一节点(kind=stat),每节点内 4 个等级状态 | 行门槛:节点第 N 级可购需全树已购总等级 ≥ 4×(N−1)。2026-10-11 一线一节点换代(用户裁:一个内容一个节点、等级在节点内、不拆多节点)——原「一线 4 层×层内 3 购」收编为单节点 4 级(层=级),SPINE_ROW_GATE=4 公式平移到等级轴,row 字段随层行退役;达成节奏重算=注记在册、值归数值批 |
| 主干脊柱(spine) | 2 | 生命淬炼 / 命中淬炼——一线一节点(kind=stat),每节点内 4 个等级状态 | 行门槛:节点第 N 级可购需全树已购总等级 ≥ 4×(N−1)。2026-10-11 一线一节点换代(用户裁:一个内容一个节点、等级在节点内、不拆多节点)——原「一线 4 层×层内 3 购」收编为单节点 4 级(层=级),行门槛常量=4 的公式平移到等级轴,row 字段随层行退役;达成节奏重算=注记在册、值归数值批 |
| 锻造脉(forge) | 2 | 锻造工坊(kind=unlock,free,工作间钥匙)+ 彩蛋节点地脉共鸣(kind=easter) | 锻造工坊前置 = **无**(free,直接可点亮——2026-10-11 攻防所有权切分裁,原「攻击淬炼累计 ≥2 且 护甲淬炼累计 ≥2」等级阈值前置随两线砍除作废);彩蛋挂本脉 |
| 钥石脉(keystone) | 2 | 秘宝匣(kind=unlock,free,工作间钥匙)/ 刷新升级(kind=rule) | 前置链:秘宝匣 ← 脊柱生命第 1 级;刷新升级 ← 秘宝匣 |
| 同调脉(attune) | 6 | 同调位 1/2/3 三节点(kind=socket)+ Fork 3 节点(kind=fork,一节点双态)= **3 同调位 + 3 双态开关节点** | **同调位 1 为根节点、无前置**,其后逐级前置(1→2→3);全部 Fork 前置 = 同调位 1;Fork=开局姿态/危险直觉/财富之道各一节点(2026-10-11 用户裁:一节点双态、解锁后 A/B 可切——非六节点) |
节点类型是封闭枚举六类:stat(生命/命中两线数值)/ rule(全局规则)/ unlock(内容解锁)/ socket(同调位)/ fork(一节点双态开关)/ easter(彩蛋觉醒)。字段、词表与跨字段约束由 schema 校验(MetaTreeTable.validate:脉 / 类型 / 币出域即拒、effects 键封闭、Fork 三组每组恰一节点、彩蛋 ≤3、禁 archetype 键——加载期校验)。**schema 连带已随迭代 21 T1 落地**:Fork 由 A/B 双行改单行双态(行持 a/b 双效果键 effects_a/b+name_a/b,效果按激活态取值;Fork 组词表 4→3 组)、规则键词表 2→6 键(见 Fork 节)、row 字段随一线一节点退役;「等级阈值前置」机制位 **2026-10-13 顺带重立**(requires_level 字段+加载校验,现役零配置——见头部状态行)。
节点类型是封闭枚举六类:stat(生命/命中两线数值)/ rule(全局规则)/ unlock(内容解锁)/ socket(同调位)/ fork(一节点双态开关)/ easter(彩蛋觉醒)。字段、词表与跨字段约束由 schema 校验(加载期校验:脉 / 类型 / 币出域即拒、effects 键封闭、Fork 三组每组恰一节点、彩蛋 ≤3、禁 archetype 键)。**schema 连带已随迭代 21 T1 落地**:Fork 由 A/B 双行改单行双态(行持 a/b 双效果键 effects_a/b+name_a/b,效果按激活态取值;Fork 组词表 4→3 组)、规则键词表 2→6 键(见 Fork 节)、row 字段随一线一节点退役;「等级阈值前置」机制位 **2026-10-13 顺带重立**(requires_level 字段+加载校验,现役零配置——见头部状态行)。
### 节点总表(12 节点)
换代后全名单(2026-10-11 Fork 一节点双态批换代:15→12)。数值行(价格/上限/效果取值)不在此表,读配置文件 `game/data/tables/meta_tree.tres`(**12 行结构已实装在役——迭代 21 T1,33 行旧结构已废弃重置不迁移**):
换代后全名单(2026-10-11 Fork 一节点双态批换代:15→12)。数值行(价格/上限/效果取值)不在此表,读配置文件 `data/tables/meta_tree.tres`(**12 行结构已实装在役——迭代 21 T1,33 行旧结构已废弃重置不迁移**):
| 节点 | 脉 | 类型 | 前置 | 效果方向 |
|---|---|---|---|---|
@@ -94,9 +94,9 @@
所有付费节点只收钥石(2026-10-07 用户裁甲落定;行内 currency 字段保留为呈现元数据)。free 节点零币:两枚工作间钥匙(锻造工坊 / 秘宝匣)与彩蛋(觉醒)不经购买消费。
购买校验四件套,全部通过才受理:①当前等级未满上限;②行门槛——脊柱节点第 N 级需全树已购总等级 ≥ 4×(N−1)(总等级口径 = tree_nodes 全部节点等级之和,免费点亮与分叉激活均计入——2026-10-11 歧义扫描裁甲沿现役实态;常量 SPINE_ROW_GATE=4;2026-10-11 一线一节点换代后门槛主语=节点目标等级,原层行判定作废;达成节奏重算归数值批);③requires 前置满足——点亮前置(前置节点全部已点亮)+ **等级阈值前置(requires_level:指定前置节点等级 ≥ n——R1 机制位 2026-10-13 顺带重立,2026-10-12 曾按卡片默认裁撤案执行、用户推翻补机制位;现役 12 行零配置空转,配置归表行随需填)**;④Fork 节点未解锁(一节点双态——解锁后的态切换走零币切换口,不经购买)。执行购买时另查钥石余额:余额不足则购买失败,存档零副作用(等级、余额、激活态均不动)。
购买校验四件套,全部通过才受理:①当前等级未满上限;②行门槛——脊柱节点第 N 级需全树已购总等级 ≥ 4×(N−1)(总等级口径 = tree_nodes 全部节点等级之和,免费点亮与分叉激活均计入——2026-10-11 歧义扫描裁甲沿现役实态;常量行门槛=4;2026-10-11 一线一节点换代后门槛主语=节点目标等级,原层行判定作废;达成节奏重算归数值批);③requires 前置满足——点亮前置(前置节点全部已点亮)+ **等级阈值前置(requires_level:指定前置节点等级 ≥ n——R1 机制位 2026-10-13 顺带重立,2026-10-12 曾按卡片默认裁撤案执行、用户推翻补机制位;现役 12 行零配置空转,配置归表行随需填)**;④Fork 节点未解锁(一节点双态——解锁后的态切换走零币切换口,不经购买)。执行购买时另查钥石余额:余额不足则购买失败,存档零副作用(等级、余额、激活态均不动)。
写口唯一:营地界面只发购买意图信号(tree_buy_requested),扣币、升级、写盘全部经 MetaProgression.tree_buy;Fork 节点购买走 tree_buy_fork(购即解锁、默认 A 态),态切换走 tree_toggle_fork(零币、只改激活态)。
写口唯一:营地界面只发购买意图信号,扣币、升级、写盘全部经元进度系统的树上购买写口;Fork 节点购买走树上分叉购买写口(购即解锁、默认 A 态),态切换走树上分叉切换写口(零币、只改激活态)。
### Fork 三组:一节点双态与免费切换
@@ -108,11 +108,11 @@ Fork 组是封闭词表三组(2026-10-11 裁:克制专精整组砍除,类
|---|---|---|---|
| fg_posture 开局姿态 | 先手压制 = 每关首轮 AP +1 | 稳健拓荒 = 每关首轮内受击减伤 | 两侧同收**每关首轮窗**(每关第一场战斗的第一轮,第二关自动刷新——时间范围一致性裁甲) |
| fg_sense 危险直觉 | 锋 = 踩中危险格伤害减半·每关限次 | 守 = 危险格标记错误返还行动点·每关限次 | 唯一根植排雷半边的组;玩家文案沿用「危险格 / 安全格」正主词,不出现雷字、不另造别名(2026-10-11 歧义扫描裁甲,废「陷阱/危险标记」自造词)。**前提核实在册**:标记错误机制存在性随实装批 T0 实查,查无则守侧换安全网向等价效果经用户裁 |
| fg_economy 财富之道 | 聚 = 战斗掉落 GP 增益 | 散 = GP 消费折价 | 范围(2026-10-11 歧义扫描裁):聚 = **仅战斗掉落渠道**;散 = **全部 GP 消费面**。**折扣定义边界(2026-10-12 卡片 v1.7 ⑪②裁决写入文档——原「设计避让」句按裁决改写)**:散的折价只覆盖商品购买价(键 `gp_cost_mult`),不含三选一付费刷新与商店刷新(`shop_refresh_cost` 不折)——这是折扣的定义边界本身,非对外两处旋钮的临时避让 |
| fg_economy 财富之道 | 聚 = 战斗掉落 GP 增益 | 散 = GP 消费折价 | 范围(2026-10-11 歧义扫描裁):聚 = **仅战斗掉落渠道**;散 = **全部 GP 消费面**。**折扣定义边界(2026-10-12 卡片 v1.7 ⑪②裁决写入文档——原「设计避让」句按裁决改写)**:散的折价只覆盖商品购买价(消费折价系数),不含三选一付费刷新与商店刷新(`shop_refresh_cost` 不折)——这是折扣的定义边界本身,非对外两处旋钮的临时避让 |
「每关限次」的计数生命周期(2026-10-11 歧义扫描裁甲):限次计数随单次冒险持久、按关重置、新冒险清零、断点续玩保留。
A/B 态只放规则面:节点行持 a/b 双效果键(封闭规则键词表 RULE_KEYS 六键——**已随迭代 21 T3 扩签落地**:posture 双键收每关首轮窗、sense 锋/守双键限次按关重置、economy 聚/散双键接线),效果按激活态取值,不接数值线。两侧的设计判据是「不同强、非强弱」:MC 配对锚验收两侧关卡完成率差 <~3pp(**迭代 21 V19 已验:perfect+max 档三组配对差全部 0.0pp 在带**)。
A/B 态只放规则面:节点行持 a/b 双效果键(封闭规则键词表六键——**已随迭代 21 T3 扩签落地**:posture 双键收每关首轮窗、sense 锋/守双键限次按关重置、economy 聚/散双键接线),效果按激活态取值,不接数值线。两侧的设计判据是「不同强、非强弱」:MC 配对锚验收两侧关卡完成率差 <~3pp(**迭代 21 V19 已验:perfect+max 档三组配对差全部 0.0pp 在带**)。
层级纪律(红线):局外树只放全局规则件——effects 禁 archetype 键(schema 加载致命);规则改写型特性(流派件)只走局内随机渠道,永不入树。
@@ -124,40 +124,40 @@ A/B 态只放规则面:节点行持 a/b 双效果键(封闭规则键词表 R
存档 v5 起树域两键(meta 域下):tree_nodes = node_id→已购等级(Fork 节点购买态=1 级解锁标记);fork_sides = fork_group→激活态("a" / "b")。承载与读写归[存档序列化](../表现与支撑/存档序列化.md),本文登记内容语义。
**旧档废弃(2026-10-11 用户裁:开发阶段无迁移)**——Alpha 未出、无存量玩家,结构换代 = 破坏性废弃:加载检测到换代前结构(已删节点 id 残留)即废弃树域重置(或整档废弃),**禁做数据迁移与折算**;三体系迁移函数 `migrate_tree` 与旧域 `forge_levels` 随实装批清退删除。
**旧档废弃(2026-10-11 用户裁:开发阶段无迁移)**——Alpha 未出、无存量玩家,结构换代 = 破坏性废弃:加载检测到换代前结构(已删节点 id 残留)即废弃树域重置(或整档废弃),**禁做数据迁移与折算**;三体系迁移函数与旧域 `forge_levels` 随实装批清退删除。
### 跨局注入:树效果怎么进下一局
树的效果经两条通道随冒险开始参数面下传(通道现行事实源 = [元进度](元进度.md)「跨局注入」节):
① 属性通道——开局属性 = **角色基础值 + 树生命/命中淬炼 flat(Σ 节点 effects × 等级)+ 锻造路线加值(当前武器攻击加值 + 当前甲 AC 加值,只按当前选中生效,正主 = [锻造工坊](锻造工坊.md))+ 局内加算区 flat**(2026-10-11 攻防所有权切分叠加公式换代:树脊柱只持生命/命中,攻/AC 唯一来源=锻造路线——每根数值轴全游戏单一来源;旧「柜台三档 flat」项随柜台退役移除,树淬炼成账号全局基础层、锻造路线成专精层,两层相加)。写入覆盖值通道(atk / max_hp / armor_class),开局显式传入战斗初始化。命中线已购等级已记但未入注入面——消费面(命中折扣档)归数值批(代码批注在册披露)。
① 属性通道——开局属性 = **角色基础值 + 树生命/命中淬炼 flat(Σ 节点 effects × 等级)+ 锻造路线加值(当前武器攻击加值 + 当前甲 AC 加值,只按当前选中生效,正主 = [锻造工坊](锻造工坊.md))+ 局内加算区 flat**(2026-10-11 攻防所有权切分叠加公式换代:树脊柱只持生命/命中,攻/AC 唯一来源=锻造路线——每根数值轴全游戏单一来源;旧「柜台三档 flat」项随柜台退役移除,树淬炼成账号全局基础层、锻造路线成专精层,两层相加)。写入覆盖值通道(攻击 / 生命上限 / 护甲等级),开局显式传入战斗初始化。命中线已购等级已记但未入注入面——消费面(命中折扣档)归数值批(代码批注在册披露)。
② 规则通道——tree_rule_keys = 各 Fork 组激活态的效果键集,经冒险开始参数面 tree_rules 下传;每场战斗 begin_battle 时由效果引擎 rebuild 合成订阅行生效。开新冒险与继续上局两入口同参同值。
② 规则通道——各 Fork 组激活态的效果键集经冒险开始参数面下传;每场战斗开始时由效果引擎重建合成订阅行生效。开新冒险与继续上局两入口同参同值。
### 已建未接面(接线落地态——2026-10-13 迭代 21 反哺写入换代)
三条原「已建表/已可购但消费面未接」的实态,**两条已随迭代 21 接线在役、一条维持纪律**:
- 同调位数量判定源——**已接(迭代 21 T4)**:`Attunement.slots` 判定源已切树点亮数(att_socket1..3),旧条件表(按 Boss 击杀次数自动涨)已随迭代 21 T5 删除(attunement_growth.tres 谓词表退役)。
- 刷新升级节点——**已接(迭代 21 T4)**:树上购买(ks_refresh)同路由 `buy_attune_refresh`,价格/cap 单一事实源 = Y 行表值;双入口并存(树上节点与秘宝匣装配段升级钮写同一笔,Q1 裁)。
- 命中线 flat 不入注入面——**维持(契约 6 纪律)**:override 无 hit 字段,命中未注入;消费面开启归数值批(M4)。
- 同调位数量判定源——**已接(迭代 21 T4)**:同调位判定源已切树点亮数(同调位 1/2/3 三节点),旧条件表(按 Boss 击杀次数自动涨)已随迭代 21 T5 删除(attunement_growth.tres 谓词表退役)。
- 刷新升级节点——**已接(迭代 21 T4)**:树上购买(刷新升级节点)同路由营地刷新升级写口,价格/cap 单一事实源 = Y 行表值;双入口并存(树上节点与秘宝匣装配段升级钮写同一笔,Q1 裁)。
- 命中线 flat 不入注入面——**维持(契约 6 纪律)**:注入参数面无命中字段,命中未注入;消费面开启归数值批(M4)。
## 依赖与输出
| 方向 | 系统 / 文档 | 接口要点 |
|---|---|---|
| 上游 | [元进度](元进度.md) | 钥石——树是永久强化的承载结构与营地本体;消费经钥石余额(写口 SaveManager),注入通道现行事实源在对方;旧柜台退役面在对方登记 |
| 上游 | [元进度](元进度.md) | 钥石——树是永久强化的承载结构与营地本体;消费经钥石余额(写口存档系统),注入通道现行事实源在对方;旧柜台退役面在对方登记 |
| 上游 | [数据配置](../表现与支撑/数据配置.md) | meta_tree.tres 承载与 schema 校验机制——本系统为结构 owner、数值回填归数值批 |
| 上游 | [存档序列化](../表现与支撑/存档序列化.md) | tree_nodes / fork_sides 持久化与旧档废弃承载 |
| 上游 | [秘宝](秘宝.md) | 同调位槽位判定源 = 树点亮数(**已切换在役,迭代 21 T4**;旧条件表已删);秘宝匣工作间内目录与装配现行事实源在彼 |
| 上游 | [锻造工坊](锻造工坊.md) | 武器/护甲路线升级现行事实源在彼——树持钥匙节点(无前置),工作间柜台=钥匙展开面板;攻/AC 数值唯一来源在彼(所有权切分红线) |
| 下游 | [冒险结构](../冒险循环/冒险结构.md) | 冒险开始参数面——树生命/命中淬炼 flat(叠加进覆盖值通道)与 tree_rules 键集的注入通道 |
| 下游 | [HUD 框架](../表现与支撑/HUD框架.md) | 营地四柜台并排呈现——树淬炼柜台=树脊柱界面形态(案甲);信号 = tree_buy_requested / tree_fork_toggled |
| 下游 | 战斗侧效果引擎 | 规则键消费面——begin_battle rebuild 合成订阅(机制硬编码,无表行) |
| 下游 | [冒险结构](../冒险循环/冒险结构.md) | 冒险开始参数面——树生命/命中淬炼 flat(叠加进覆盖值通道)与规则键集的注入通道 |
| 下游 | [HUD 框架](../表现与支撑/HUD框架.md) | 营地四柜台并排呈现——树淬炼柜台=树脊柱界面形态(案甲);信号 = 树上购买意图 / 树上分叉切换意图 |
| 下游 | 战斗侧效果引擎 | 规则键消费面——每场战斗开始时重建合成订阅(机制硬编码,无表行) |
## P0 最小闭环
**P0 语义已随迭代 21 全量落地(2026-10-12 入库;2026-10-13 反哺写入换代——原「33 节点现役态维持」过渡态终结)**:12 节点结构(脊柱 = 生命/命中一线一节点、Fork = 三节点双态)+ 营地统一(树 = 营地本体、生命/命中唯一入口、攻防归锻造工坊、工作间钥匙、四柜台呈现)+ 三组 Fork 双态真效果 + 购买/切换/门槛/彩蛋/注入/旧档废弃全链,机检 = 冒烟 886/0 + run_all 22 套 + probe 全绿 + MC 三组配对差 0.0pp(迭代 21 出口闸读数);残留人闸 = 实机目检营地四柜台(体验验证清单 ⑳)。旧 33 节点结构随 `TREE_STRUCT_VERSION=2` 废弃重置(禁迁移,Q3 裁)。
**P0 语义已随迭代 21 全量落地(2026-10-12 入库;2026-10-13 反哺写入换代——原「33 节点现役态维持」过渡态终结)**:12 节点结构(脊柱 = 生命/命中一线一节点、Fork = 三节点双态)+ 营地统一(树 = 营地本体、生命/命中唯一入口、攻防归锻造工坊、工作间钥匙、四柜台呈现)+ 三组 Fork 双态真效果 + 购买/切换/门槛/彩蛋/注入/旧档废弃全链,逐条判据见「验收标准」节;残留人闸 = 实机目检营地四柜台(体验验证清单 ⑳)。旧 33 节点结构随树结构版本换代废弃重置(禁迁移,Q3 裁)。
## P1 / P2 后置
@@ -174,23 +174,21 @@ A/B 态只放规则面:节点行持 a/b 双效果键(封闭规则键词表 R
| 表 / 常量 | 键结构归属 | 数值行 |
|---|---|---|
| 节点表 `data/tables/meta_tree.tres`(换代后 12 行:价格 / 等级上限 / requires(点亮前置)/ **requires_level(等级阈值前置——R1 机制位,现役零配置)** / effects 取值(Fork 行持 a/b 双效果键)/ 限次值;row 字段随一线一节点退役) | schema MetaTreeTable,本文 owner | 全 provisional,归数值批投值 |
| 脊柱行门槛常量 SPINE_ROW_GATE = 4 | `meta_tree_table.gd` 常量,本文 owner | 常量即规则(节点第 N 级需全树总等级 ≥ 4×(N−1)) |
| Fork 组词表 FORK_GROUPS(三组)/ 规则键词表 RULE_KEYS(换代后六键,扩表随实装批) | `meta_tree_table.gd` 封闭词表 | 词表即规则;规则键效果值硬编码于效果引擎 rebuild |
| 节点表 `data/tables/meta_tree.tres`(换代后 12 行:价格 / 等级上限 / requires(点亮前置)/ **requires_level(等级阈值前置——R1 机制位,现役零配置)** / effects 取值(Fork 行持 a/b 双效果键)/ 限次值;row 字段随一线一节点退役) | schema 声明,本文 owner | 全 provisional,归数值批投值 |
| 脊柱行门槛 = 4 | 节点表结构声明持有,本文 owner | 规则即门槛(节点第 N 级需全树总等级 ≥ 4×(N−1)) |
| Fork 组词表(三组)/ 规则键词表(换代后六键,扩表随实装批) | 三组 Fork 词表与六键规则词表由节点表结构声明持有(封闭词表) | 词表即规则;规则键效果值由效果引擎合成 |
| 钥石产出、刷新升级行族 | 现行事实源 = [元进度](元进度.md)调参表 | `data/tables/meta.tres` |
## 验收标准
> **落地实态(2026-10-13 反哺写入注)**:下列各条已随迭代 21 实装并过出口闸——机检 = 冒烟 886/0(V1-V10/V16 断言顺带)+ run_all 22 套(tree_rules_v11_test 六键闭集)+ probe --click/--full 八探针 + render_gate + MC 三组同种子配对差 0.0pp(V19);残留人闸 = 实机目检营地四柜台(体验验证清单 ⑳)。命中线「暂不注入」括注 = 契约 6 纪律维持(非缺陷——消费面开启归数值批)。
- 结构封闭:meta_tree.tres 通过 schema 校验零违例——12 节点、脉 / 类型 / 币词表出域即拒、Fork 三组每组恰一节点且持 a/b 双效果键、彩蛋 ≤3、effects 键封闭、零 archetype 键。
- 行门槛可判:全树已购总等级 < 4×(N−1) 时脊柱节点第 N 级不可购;总等级达标当刻该级开放购买。
- 前置可判(点亮前置):requires 任一未点亮则节点不可购,逐一点亮后可购;锻造工坊钥匙无前置——初始即可点亮(free 零币)。**等级阈值前置(requires_level):配置了该键的节点,指定前置节点等级 < n 时不可购、达标当刻开放(单测八断言承载——schema 四拒一过+判定三态+投影两态;现役零配置,判定面经测试夹具直构行验证)。**
- 前置可判(点亮前置):requires 任一未点亮则节点不可购,逐一点亮后可购;锻造工坊钥匙无前置——初始即可点亮(free 零币)。**等级阈值前置:配置了该键的节点,指定前置节点等级 < n 时不可购、达标当刻开放(现役零配置,判定面已单独验证)。**
- 工作间可判:钥匙节点(锻造工坊 / 秘宝匣)未点亮时对应柜台锁定态、工作间不可进入;点亮后展开;图鉴无门槛常开。
- 单币可判:任一付费节点购买只扣钥石;余额不足购买失败,且存档零变化(等级、余额、激活态均不动)。
- 双态可判:Fork 节点购买解锁后默认 A 态;切换零币,切换后规则键集=新激活态效果键;同态重复切换零操作;未解锁 Fork 不可切换、不可重复购买。
- 彩蛋可判:生命/命中两节点均买满(4 级拉满)且同调位 1/2/3 全部解锁时彩蛋节点自动点亮且零消费;任一条件不满足则不亮。
- 注入可判:开局覆盖值 = 角色基础值 + 树生命/命中淬炼 flat(命中未注入)+ 锻造路线加值 + 局内加算区(各层语义清晰可加);tree_rules = 全部 Fork 组激活态效果键集;开新冒险与继续上局两入口参数同值;全新存档(树全零)开局与零树状态完全一致。
- 注入可判:开局覆盖值 = 角色基础值 + 树生命/命中淬炼 flat(命中暂不注入——消费面开启归数值批,契约 6 纪律维持、非缺陷)+ 锻造路线加值 + 局内加算区(各层语义清晰可加);规则键集 = 全部 Fork 组激活态效果键集;开新冒险与继续上局两入口参数同值;全新存档(树全零)开局与零树状态完全一致。
- 旧档废弃可判:加载换代前结构存档 → 树域废弃重置 → 后续游玩正常且无残留脏节点(开发阶段纪律,禁迁移);全新存档(树全零)开局与零树状态完全一致。
## 待办
+20 -20
View File
@@ -1,12 +1,12 @@
# 生涯
> **一句话定位**:营地里与三柜台平级的**局外只读界面**——营地管「花」(花钥石买永久强化),生涯管「看」(看自己跨局攒下的一切:累计战绩、历史冒险、图鉴收集)。冒险进行中不给任何数据回看(2026-10-04 用户裁决 P-C7 的延续),生涯是历史数据唯一的家。
> **状态**:期一已实装(2026-10-07 迭代 18 卡④生涯界面实装批·期一——跨局汇总页+主菜单入口+终身计数域存档 v6 落地;期二/期三另行立项,本文不预占排期)。入口拓扑已随迭代 33 卡② 三入口化换代、营地里经笔记本接入归迭代 34 卡④(信息架构节 v1.1,2026-10-22 反哺写入)。现行为 v1.2(2026-10-28 迭代 39 反哺——历史回看节行号指路句改语义指认)。
> **状态**:期一已实装(2026-10-07 迭代 18 卡④生涯界面实装批·期一——跨局汇总页+主菜单入口+终身计数域存档 v6 落地;期二/期三另行立项,本文不预占排期)。入口拓扑已随迭代 33 卡② 三入口化换代、营地里经笔记本接入归迭代 34 卡④(信息架构节 v1.1,2026-10-22 反哺写入)。现行为 v1.3。
> **来源**:[待办清单「『生涯』界面——冒险中数据回看的唯一承接处」条](../../../../待办清单.md)(2026-10-04 用户裁决 P-C7——冒险中不给数据回看,历史战报与结算明细的查看去向 = 新「生涯」界面)。
## 一、信息架构
生涯入口经营地接入(目标结构=营地笔记本,迭代 34 卡④承载;迭代 33 卡② 三入口化后主菜单无生涯钮,现期无玩家可见入口,内部路径直调可达)。现行主菜单按钮组由 `build_start_overlay` 构造(`game/presentation/ui_assembler.gd:97`),只有三个一级钮(迭代 33 卡②,用户裁决 1):「进入存档」「设置」「退出游戏」——「进入存档」为唯一进度入口,点击打开选档界面(3 存档位,迭代 33 卡③)。
生涯入口经营地接入(目标结构=营地笔记本,迭代 34 卡④承载;迭代 33 卡② 三入口化后主菜单无生涯钮,现期无玩家可见入口,内部路径直调可达)。现行主菜单只有三个一级钮(迭代 33 卡②,用户裁决 1):「进入存档」「设置」「退出游戏」——「进入存档」为唯一进度入口,点击打开选档界面(3 存档位,迭代 33 卡③)。
```
主菜单(开始覆盖层,三入口)
@@ -15,8 +15,8 @@
├─ 设置
└─ 退出游戏
调试浮窗(发布态恒隐:`_debug_entry` 写死行已随迭代 38 卡⑦ 删除,开始层与战斗屏/关卡地图屏均零调试入口与角标;
开发期临时启用=本地改 `_debug_entry` 缺省、不提交)
调试浮窗(发布态恒隐:调试入口的写死行已随迭代 38 卡⑦ 删除,开始层与战斗屏/关卡地图屏均零调试入口与角标;
开发期临时启用=本地改调试入口缺省、不提交)
营地(存档内,进档/新档落点)
└─ 生涯(局外只读面;入口=营地笔记本,迭代 34 卡④承载)
@@ -40,24 +40,24 @@
| 内容 | 数据源 | 现状 |
|---|---|---|
| 冒险总局数 / 通关局数 | `adventure_total` / `adventure_cleared` 两终身计数域(save v6——期一已落地) | 现成(2026-10-07 迭代 18 卡④期一实装) |
| 各关完成次数 | `clear_count(level_index)`(`save_manager.gd:238`) | 现成 |
| Boss 首杀与总击杀 | `boss_first_kill_marked`(`save_manager.gd:242`)/ `boss_kill_count`(`:250`) | 现成 |
| 钥石余额 | `keystone_balance`(`save_manager.gd:202`) | 现成。累计收支流水不在存(加钥石与花钥石只动余额,`:206`/`:211`)——如要做属新增流水域,期一实装批另呈报,本文只登记 |
| ~~三柜台解锁完成度概览~~ | (整行删——2026-10-12 用户裁:生涯页不统计天赋树与账号成长态,只统计终身计数;数据源 forge_level/workshop_status/tree_nodes 三投影随天赋树实装批退役,体验验证清单⑲两观测项同步摘除) | — |
| 各关完成次数 | 存档域 `level_clear_counts`(按关卡序号计) | 现成 |
| Boss 首杀与总击杀 | Boss 首杀标记(存档域 `boss_first_kill`)/ Boss 击杀总数(存档域 `boss_kill_count`) | 现成 |
| 钥石余额 | 存档域 `keystone_balance`;累计收支流水不入存档 | 现成。加钥石与花钥石只动余额——如要做属新增流水域,期一实装批另呈报,本文只登记 |
| ~~三柜台解锁完成度概览~~ | (整行删——2026-10-12 用户裁:生涯页不统计天赋树与账号成长态,只统计终身计数;数据源属性锻造等级/工坊状态/树节点三投影随天赋树实装批退役,体验验证清单⑲两观测项同步摘除) | — |
### 历史冒险回看(期二)
数据面现役事实:每局冒险收束时已有逐局摘要自动入档——`recent_summaries`(默认域 `save_manager.gd:116`、值拷贝访问器 `:316`、入账原语 `:325-338` 逐局插最前并按上限截断),上限 `SUMMARY_CAP := 10`(`:40`)。摘要字段在冒险收束时组装(`adventure_runner` 冒险收束受理 `_settle`:结局 result、完成关数 levels_cleared、止步关 stopped_at、钥石合计 keystone_total、本局主种子 master_seed,另附逐杀掉落 keystone_drops 与终局专长持有集 relics(存档键名沿用历史形态)等;钥石与逐杀明细、真视计数、特性持有集取数经主角账两件〔HeroStats/GainJournal〕只读投影——2026-10-27 迭代 39 拆件后形态);摘要的内容口径 owner = [冒险结构](../冒险循环/冒险结构.md),本文不复述其口径。
数据面现役事实:每局冒险收束时已有逐局摘要自动入档——存于存档域 `recent_summaries`:新局插最前、按上限截断,上限 10 条。摘要字段在冒险收束时组装(冒险收束受理:结局 result、完成关数 levels_cleared、止步关 stopped_at、钥石合计 keystone_total、本局主种子 master_seed,另附逐杀掉落 keystone_drops 与终局专长持有集 relics(存档键名沿用历史形态)等;钥石与逐杀明细、真视计数、特性持有集取数经主角账两件〔属性账 / 获得日记〕只读投影——2026-10-27 迭代 39 拆件后形态);摘要的内容口径 owner = [冒险结构](../冒险循环/冒险结构.md),本文不复述其口径。
2026-10-06 用户裁(P2 甲):每局一行摘要,行内给**结局 / 到达关卡 / 钥石收入 / 用时**四件事,上限存最近 N 局。对应三件实绩(本批代码级复核确认的缺口,非新建数据面):
1. **扩容**:cap 10 → N。N 候选 20 / 50 / 维持 10,实装期按存档体积读数三选一;读数方法与列表形态的参数化维度由设计稿给出、实装期执行。
2. **补「用时」埋点**:全仓现在没有任何用时采集点(`game/core/` 内 grep elapsed / ticks / duration / Time 零命中;摘要字段集〔`adventure_runner` 收束受理组装面〕无此项)——属新增埋点,随期二。
2. **补「用时」埋点**:全仓现在没有任何用时采集点(摘要字段集〔冒险收束受理组装面〕无此项)——属新增埋点,随期二。
3. **旧档迁移**:旧档既有 ≤10 条摘要原样保留迁移,向后兼容。
单局结算明细回看:遗留件 `settlement_review_overlay.gd`(`game/presentation/views/`,文件本体在盘、全仓无实例化引用——仅 `ui_kit.gd:356` 样式注记提及)由期二实装批复活承接,改挂生涯(2026-10-06 用户裁 P5 甲)。
单局结算明细回看:遗留的单局结算明细界面本体仍在、未接入任何入口,由期二复活承接,改挂生涯(2026-10-06 用户裁 P5 甲)。
可选增强(不占期、不上列):关键构筑列——摘要已附终局专长持有集 relics(`adventure_runner.gd:825`——存档键名沿用历史形态),实装期评估是否呈现。
可选增强(不占期、不上列):关键构筑列——摘要已附终局专长持有集(存档键 relics,存档键名沿用历史形态),实装期评估是否呈现。
### 图鉴(期三)
@@ -69,11 +69,11 @@
| 界面 | 管什么(现状指证) | 与生涯的边界 |
|---|---|---|
| 营地([camp UX spec](../../ux/camp.md)) | 跨局成长**操作**面(花钥石买强化 / 装配 / 点树)+ 底栏「最近冒险」条带——`camp_overlay_view.gd:431` `_rebuild_recent()` 逐局拼行(`:442`「完成/放弃/失败 · 通关 N 关 · 钥石 +N · 种子 N」,无截断上限),数据源 = `camp_shop_presenter.gd:85` 投影的同一份 `recent_summaries` | 营地不改生涯只读定位;生涯不做任何购买入口,也不放「去买」按钮。营地条带的去留是本提纲必答项——见 §五 P6 |
| 营地([camp UX spec](../../ux/camp.md)) | 跨局成长**操作**面(花钥石买强化 / 装配 / 点树)+ 底栏「最近冒险」条带——营地底栏把摘要逐局拼行(行模板「完成/放弃/失败 · 通关 N 关 · 钥石 +N · 种子 N」)、无截断上限,数据源与生涯历史回看同属一份最近摘要 | 营地不改生涯只读定位;生涯不做任何购买入口,也不放「去买」按钮。营地条带的去留是本提纲必答项——见 §五 P6 |
| 状态面板(迭代 17 卡③,并行批开发中) | **局内**只读查看这一局进行中的钥石与本局冒险进度 | 状态面板看当局当前值,生涯看跨局累计与历史;局内无生涯入口(P4 甲) |
| 结算屏([settlement-summary UX spec](../../ux/settlement-summary.md)) | 冒险收束当下的入账明细——`main.gd:408` 的 `_on_adventure_finished`(实体在 `main_adventure_flow.gd:84`)收束时呈现摘要与钥石明细(复用终局面账行,`battle_end_overlay.gd:118-129`) | 收束当下的呈现保留不动;生涯承接的是收束之后的任意时刻回看 |
| 帮助手册(Beta 批,未实装——教学内容归 Beta 帮助手册,`ui_assembler.gd:99` 注记) | 讲「怎么玩」 | 生涯讲「我玩过什么」。图鉴条目文案与手册是否共用内容源,接口登记归 Beta 批一并裁 |
| 图例面板(legend_overlay) | 局内符号/徽标即时解码 | 不合并——图例是局内解码面,图鉴是跨局收集面 |
| 结算屏([settlement-summary UX spec](../../ux/settlement-summary.md)) | 冒险收束当下的入账明细——冒险收束时由结算屏呈现入账明细与钥石明细(复用终局面账行的呈现形态) | 收束当下的呈现保留不动;生涯承接的是收束之后的任意时刻回看 |
| 帮助手册(Beta 批,未实装——教学内容归 Beta 帮助手册) | 讲「怎么玩」 | 生涯讲「我玩过什么」。图鉴条目文案与手册是否共用内容源,接口登记归 Beta 批一并裁 |
| 图例面板 | 局内符号/徽标即时解码 | 不合并——图例是局内解码面,图鉴是跨局收集面 |
## 四、分期实装建议
@@ -81,11 +81,11 @@
| 期 | 内容 | 前置 | 建议窗口(候选) |
|---|---|---|---|
| 期一 | 跨局汇总页 + 主菜单生涯入口落位。总局数/通关局数两个终身计数域随该批做存档 schema 迁移——**✅ 已实装(2026-10-07 迭代 18 卡④)**:汇总段六类九项+营地与系统组生涯钮+存档 v6 两终身计数域〔v5 升 v6 幂等迁移〕;闸读数与代拍板追认单原记于该批出口报告,该件已按「吸收即死」在提交 8e02dcf0 删除,读数以本行与该批提交信息为准 | 提纲评审通过。实装批前置义务 = 对齐迭代 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 三选一)与「用时」埋点口径(计时起点、暂停是否计入——字段级细节本文不做) | 期一落地后独立批 |
| 期一 | 跨局汇总页 + 主菜单生涯入口落位。总局数/通关局数两个终身计数域随该批做存档 schema 迁移——**✅ 已实装(2026-10-07 迭代 18 卡④)**:汇总段六类九项+营地与系统组生涯钮+存档 v6 两终身计数域〔v5 升 v6 幂等迁移〕;闸读数与代拍板追认单原记于该批出口报告,该件已按「吸收即死」删除,读数以本行与该批提交信息为准 | 提纲评审通过。实装批前置义务 = 对齐迭代 16 UI 批后的现行基线:字号六档 / 语义色 / 按钮最小高 40 点等现行界面基线 / 色板单源 / 页面壳的模态栈纪律——与卡③需求卡片同款红线,本文只登记、不展开 | Alpha 后最近一个 UI 窗口 |
| 期二 | 历史冒险回看整段:N 扩容 + 用时埋点 + 旧档摘要迁移 + 逐局列表 + 单局明细(遗留明细界面复活承接)+ 营地条带处置(P6 裁案落地) | 期一。实装批开工前须向用户呈报两件:N 终值读数(20 / 50 / 维持 10 三选一)与「用时」埋点口径(计时起点、暂停是否计入——字段级细节本文不做) | 期一落地后独立批 |
| 期三 | 图鉴承接(敌人优先,范围与顺序随 P3 甲);「见过」记账面 schema 义务随该批执行 | 期二或独立评估 | Beta 窗口候选(与教学引导同段评估——图鉴的「认得」轴与教学相关;待办清单教学引导节各条 2026-10-04 起已整体标 Beta 阶段) |
本地化文案权:生涯界面本体按钮、页签、空态文案归[设置与本地化](../表现与支撑/设置与本地化.md)线(全仓无多语言实装——`game/` 内 grep TranslationServer 零命中;文案权先例 = 教学文案定稿权登记于待办清单),实装批承接。
本地化文案权:生涯界面本体按钮、页签、空态文案归[设置与本地化](../表现与支撑/设置与本地化.md)线(全仓无多语言实装;文案权先例 = 教学文案定稿权登记于待办清单),实装批承接。
## 五、待裁点
@@ -93,7 +93,7 @@ P0-P5 六点已于 2026-10-06 用户全裁(案甲 × 6,备选案与淘汰依
### P6 · 营地底栏「最近冒险」条带去留(期二必答项)
**现状与问题**:营地底栏「最近冒险」条带把传入的摘要逐行全部拼进一个 Label(`camp_overlay_view.gd:431-443`,`:442` 行模板,无截断上限),数据源与生涯历史回看是同一份 `recent_summaries`(`camp_shop_presenter.gd:85`)。生涯期二把上限扩到 N 后,条带按现行逻辑会把 N 行全拼进底栏——这是本批复核发现的实际耦合点,期二落地时必须给条带一个去处。
**现状与问题**:营地底栏「最近冒险」条带把摘要逐行全部拼进同一个标签(行模板「完成/放弃/失败 · 通关 N 关 · 钥石 +N · 种子 N」,无截断上限),数据源与生涯历史回看同属一份最近摘要。生涯期二把上限扩到 N 后,条带按现行逻辑会把 N 行全拼进底栏——这是本批复核发现的实际耦合点,期二落地时必须给条带一个去处。
| 案 | 内容 | 淘汰/保留依据 |
|---|---|---|
+4 -4
View File
@@ -1,13 +1,13 @@
# 秘宝
> 一句话:营地装配、整局冒险生效的角色机能件——操作包络加强(视野/行动点/刷新/挖掘距离等),不出角色战斗属性值、不改战斗结算机制(经济与操作参数——视野/距离/行动点/刷新/转存率——属操作包络;分界规则归[核心循环](../../01-核心循环.md)「道具三层职责与分界」节)
> 状态:已定稿(现行形态=局外同调件——2026-10-03 迭代 11 第①批同调实施批已入库)
> 状态:已定稿(现行形态=局外同调件——2026-10-03 迭代 11 第①批同调实施批已入库);现行为 v1.1
> 定位与形态:见下节
> 术语:本文件的项目术语(同调位/RAP/GP/真视/危险格/整图等)定义见[术语表](../../术语表.md)
## 定位与形态
**现行形态 = 局外同调件**:开局前在营地装配(营地·秘宝匣柜台「同调装配」段)、占同调位(0 起步、固定 3 格,每件固定占 1 格)、被动件整局生效/主动件每冒险充能(冒险开始重置)。实现面 = `treasure_items.tres` + `game/core/attunement.gd`(同调位数量判定源=天赋树同调位节点点亮数——2026-10-11 Q2 裁甲、迭代 21 T4 槽位收编落地;原 `attunement_growth.tres` 谓词表已顺带退役;解锁条件=数据行内 `unlock_requires` 字段承载——迭代 22 实装落地,2026-10-12)。**新目录 12 件已随迭代 22 实装批全量落地(2026-10-12,T1-T7)**,逐件实录见「目录(重设计 v1)」各表实态列。
**现行形态 = 局外同调件**:开局前在营地装配(营地·秘宝匣柜台「同调装配」段)、占同调位(0 起步、固定 3 格,每件固定占 1 格)、被动件整局生效/主动件每冒险充能(冒险开始重置)。实现面 = `treasure_items.tres` + 同调系统件(同调位数量判定源=天赋树同调位节点点亮数——2026-10-11 Q2 裁甲、迭代 21 T4 槽位收编落地;原 `attunement_growth.tres` 谓词表已顺带退役;解锁条件=数据行内解锁条件字段承载——迭代 22 实装落地,2026-10-12)。**新目录 12 件已随迭代 22 实装批全量落地(2026-10-12,T1-T7)**,逐件实录见「目录(重设计 v1)」各表实态列。
**沿革一句话**:本系统前身为切片期掉落消耗品形态(2026-09-29 迭代 7),2026-10-03 随同调实施批整体替换为现行形态;旧目录九件已全数退役入素材库(2026-10-08/10 用户裁)。历史细节见 git 提交史。
@@ -15,7 +15,7 @@
- **同调位分档**(2026-10-07 用户裁):同调位分三档=普通格/优秀格/稀有格;装配规则=**槽位可装 ≤ 槽位档位的件**(向下兼容,不惩罚早解锁);格品质随天赋树同调位节点递增(1=普通格/2=优秀格/3=稀有格,2026-10-10 用户裁;树侧接线=迭代 21 T4 槽位收编落地)。装配面呈现槽位档位(迭代 22 秘宝匣柜台落地)。
- **旧目录退役指针**:旧目录九件、魔法提灯、机制向三件处置已全数退役入素材库(表一 14 件)——现行目录见下方「目录(重设计 v1)」节;代码旧行已全数删除(迭代 20 先行删 2 行+迭代 22 T1 删 12 行,2026-10-12)。
- **三选一刷新双源**:刷新能力=**存量+临时**两笔系统资源——存量=持久(开局注入基值 0;来源=秘宝匣刷新升级行购买〔meta.tres attune_refresh_upgrade 行族〕+刷新练习件加仓;跨呈现持续、用完即无)、临时量=每次三选一呈现重置为基线 0(来源=效果件的临时注入,未用不结转);**消耗顺序=先扣临时、不足再扣存量**(2026-10-10 用户复述定案;代码字段名 X/Y 与两笔的字母对表归实装批 T0,正文不依赖字母)。重抽复用现有洗牌逻辑(reward_pick),池规则全保留;自动游玩模式默认不刷。**GP 付费档(2026-10-06 用户令)**:免费双源用尽后可 GP 付费刷新,价=ceil(20×1.8^本次停点已付费刷) provisional(与商店货架刷新读同两个调参参数 shop_refresh_*,单点调参);付费刷计数每停点清零;钱包=冒险 GP 同一笔系统资源(唯一入口 LevelRunner.spend_gp);余额不足=钮禁用(不隐藏)。店内专长凭证三选一暂不挂刷新面(扩面须先裁凭证保底计数交互)。**两笔语义**两笔语义的框架定义见[核心循环](../../01-核心循环.md)「生命周期轴」节。「三选一呈现」是比节点更细的事件——奖励节点、Boss 通关奖励、商店(凭证)三处都触发。奇物「刷新次数+1」类资源件的语义=存量一次性加仓。
- **三选一刷新双源**:刷新能力=**存量+临时**两笔系统资源——存量=持久(开局注入基值 0;来源=秘宝匣刷新升级行购买〔meta.tres attune_refresh_upgrade 行族〕+刷新练习件加仓;跨呈现持续、用完即无)、临时量=每次三选一呈现重置为基线 0(来源=效果件的临时注入,未用不结转);**消耗顺序=先扣临时、不足再扣存量**(2026-10-10 用户复述定案;代码字段名 X/Y 与两笔的字母对表归实装批 T0,正文不依赖字母)。重抽复用现有洗牌逻辑,池规则全保留;自动游玩模式默认不刷。**GP 付费档(2026-10-06 用户令)**:免费双源用尽后可 GP 付费刷新,价=ceil(20×1.8^本次停点已付费刷) provisional(与商店货架刷新读同两个调参参数 shop_refresh_*,单点调参);付费刷计数每停点清零;钱包=冒险 GP 同一笔系统资源(唯一入口=冒险 GP 扣账口);余额不足=钮禁用(不隐藏)。店内专长凭证三选一暂不挂刷新面(扩面须先裁凭证保底计数交互)。**两笔语义**两笔语义的框架定义见[核心循环](../../01-核心循环.md)「生命周期轴」节。「三选一呈现」是比节点更细的事件——奖励节点、Boss 通关奖励、商店(凭证)三处都触发。奇物「刷新次数+1」类资源件的语义=存量一次性加仓。
- **🔴 承重契约**(红线;其中真视范围等由数据加载校验强制):效果不允许写成直接加减属性的裸数值——效果类型只能取封闭白名单;真视(直接标出危险格的效果,定义见「核心规则」)单次范围 ≤3×3;核心逻辑不做异步等待;零随机;排雷玩法零特判;危险格与安全格的分布同池冻结——资源类件只能调整权重投影、不能改池结构;**棋盘事实不可变**(秘宝效果不移除、不增改危险格位置与邻接数字——效果形态只允许信息呈现与开格动作;2026-10-10 用户裁,原爆破工兵包「中立移除」即违规形态、随件退役废止)。
- **验收分层**:难度验收分两层——同调系统关闭时沿用现行关卡完成率验收带;开启时验收带按投值平移(归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)投值;商店开关分层同法)。
@@ -228,7 +228,7 @@
## 调参表
道具定义表的全部数值均为 provisional,归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)调参;registry `aux_items` 条目已随迭代 22 换代为新目录 12 件登记(2026-10-12);表 schema 归[数据配置](../表现与支撑/数据配置.md)承载、本系统回填。
道具定义表的全部数值均为 provisional,归[难度曲线与Boss](../冒险循环/难度曲线与Boss.md)调参;`aux_items` 条目已随迭代 22 换代为新目录 12 件登记(2026-10-12);表 schema 归[数据配置](../表现与支撑/数据配置.md)承载、本系统回填。
结构冻结(非调参项,改动走本文修订流程):真视窄域护栏、零信息目标不消耗、边缘窗口照常受理、使用零行动点成本、同调位装配与充能每冒险重置、用后不可逆、零随机。
+17 -44
View File
@@ -1,9 +1,7 @@
# 锻造工坊
> 一句话:营地的武器与护甲成长——武器锻造区三条路线、护甲锻造区三条路线各练各的,钥石消费,一次冒险各选一件,满级特效留位本期不做
> 状态:**v0.9(2026-10-26 迭代 37 结项:实现载体行号引用改指现址,规则与数值零变化);承 v0.8 迭代 21 反哺④残余写入文档(2026-10-13)**——「树侧钥匙」句换代:钥匙节点 forge_workshop 已随迭代 21 实装在役(free 无前置、点亮展开本柜台、锁定态零购买路径),原「实装归待办清单」悬置指针终结。承 v0.7 迭代 23 反哺写入(2026-10-13)——正文补 Q1 等级语义衔接(0 = 未练合法态)、效果类型闭集 24→31 订正、实装边界 1 回填实装实态(已随迭代 23 入库)。承 v0.6 完备性检查批(承 v0.5 B 组定案——**17 裁点全数清零**:1 丙 / 1a 一次冒险一件武器+一件甲 / 1b 营地可换·战斗禁换 / 1c 免费 / 2a 伪裁点消解 / 2b 随 3a 消解 / 3a 魔法护甲统一命名 / 3b 敌方攻击缺省普通·克制反向当下生效 / 3c 每型独立路线 / 4a 前缓后陡 / 4b 锻造内自闭环 / 4b-1 并联双通道 / 5b 纯钥石 / 5c 零材料 / 6 满级特效本期不做留扩展位 / 8a 工作间两区定名;2c、5a 已于 v0.4 结案)。**v0.6 变更(2026-10-12 完备性检查批·grilling 用户逐条裁)**:现役事实基线换代(forge_products 行族已随迭代 21 T5 退役、定价参数改历史考古口径);**两根类型轴所有权移交**(默认值归锻造工坊配置常驻持有、hero.tres 静态表两轴删除、选中态写存档+参数面注入);「与秘宝混合制同构」与「激活穿刺系专长」两处无依据表述订正删除。**满级特效本期不做**(只留扩展位);全部数值 provisional,终值归 Alpha 收官 M4 数值批〔未排期〕;实装已随迭代 23 入库(2026-10-12)
> 成文底稿:提案过程稿《提案-武器锻造系统-2026-10-07》(**已退役**——中间产物吸收即死,2026-10-22 删除;全部备选案与淘汰依据、用户原案逐条对照已逐条落进本文,结论不依赖过程稿;**满级特效候选池已于 2026-10-21 迁入本文「满级特效扩展位」节**;考古=git 历史——删除批 603eba31,删除前全稿见历史版本 f958a03f)
> 状态:**v0.10(2026-10-29 实现内容清理:删「现役代码事实」「实装边界」两节与正文代码指证,规则与数值零变化)**——全部数值 provisional,终值归 Alpha 收官 M4 数值批〔未排期〕
## 设计目的
用户原案(playnote 2026-10-06):把现役"营地花钱买攻击 +1"改造成有等级、有成长、有满级特效的**武器升级路线**;新增长枪(穿刺)与法杖(魔法)实现武器间差异化;护甲同理——初始只有轻甲(升级只提 AC),最高等级后解锁重甲/魔法护甲,基础 AC 各异、各带满级特效。
@@ -29,7 +27,7 @@
|---|---|
| 钥石与营地柜台结构 | [元进度](元进度.md)——本系统即属性锻造柜台攻击/护甲两档的改造,消费货币与柜台框架归彼 |
| 数值终值(每级增量/等级上限/价格/基础 AC/特效值) | Alpha 收官 M4 数值批——本文全部数值只有量纲与锚点,标 provisional |
| 代码与数据表落地 | 实装批(待办在册待办清单)——迁移面见下文,含数值验证义务 |
| 代码与数据表落地 | 实装批(已入库) |
| 克制矩阵与伤害结算 | [战斗结算](../战斗循环/战斗结算.md)——矩阵九格结构冻结是既有条款,本系统零改动 |
| 局内属性奖励件 | [奇物](../冒险循环/奇物.md)——账号层永久强化与单冒险加算区分层并存,互不侵入 |
| 存档读写 | [存档序列化](../表现与支撑/存档序列化.md)——实装后新增等级与当前选中域,旧档废弃口径随实装批(开发阶段无迁移) |
@@ -51,11 +49,11 @@
**工作间内两区并列**(A③ 裁):武器区/护甲区并列呈现,机制层面零顺序门槛;同屏分栏或页签切换=呈现细节归 HUD 批。
**树侧钥匙(2026-10-11 裁:无前置)**:本柜台由天赋树「锻造工坊」钥匙节点展开——free 节点、**无前置条件、直接可点亮**(原「攻击淬炼累计 ≥2 级 且 护甲淬炼累计 ≥2 级」等级阈值前置,随树脊柱砍攻/护两线作废);未点亮时本柜台锁定态,点亮后开放。树侧结构换代(脊柱砍攻/护两线 + 一线一节点 + Fork 一节点双态,三轮换代 **29→21→15→12**,地脉共鸣条件效果随之换代——2026-10-12 订正:原记「29→21」系 v0.6 时点旧数,树侧现行终态 12 节点)设计权威文档 = [天赋树](天赋树.md);**钥匙节点 forge_workshop 已随迭代 21 实装在役(2026-10-12 入库——free 无前置、点亮展开本柜台、锁定态零购买路径),2026-10-13 反哺写入换代原「实装归待办清单」悬置指针**。
**树侧钥匙(2026-10-11 裁:无前置)**:本柜台由天赋树「锻造工坊」钥匙节点展开——free 节点、**无前置条件、直接可点亮**(原「攻击淬炼累计 ≥2 级 且 护甲淬炼累计 ≥2 级」等级阈值前置,随树脊柱砍攻/护两线作废);未点亮时本柜台锁定态,点亮后开放。树侧结构换代(脊柱砍攻/护两线 + 一线一节点 + Fork 一节点双态,三轮换代 **29→21→15→12**,地脉共鸣条件效果随之换代——2026-10-12 订正:原记「29→21」系 v0.6 时点旧数,树侧现行终态 12 节点)设计权威文档 = [天赋树](天赋树.md);**钥匙节点已随迭代 21 实装在役(2026-10-12 入库——free 无前置、点亮展开本柜台、锁定态零购买路径),2026-10-13 反哺写入换代原「实装归待办清单」悬置指针**。
**注入衔接(所有权切分,2026-10-11 裁)**:每根数值轴全游戏单一来源——生命/命中唯一入口=树脊柱;**攻击唯一入口=武器路线、AC 唯一入口=甲路线(本系统)**,树零攻防来源(红线)。锻造路线加值 = 当前武器攻击加值 + 当前甲路线 AC 加值,与树淬炼 flat、局内加算区在开局属性注入面分层相加(通道现行事实源 = [元进度](元进度.md)「跨局注入」节);锻造加值只按**当前选中**的武器/甲生效(长剑的练度在换带长枪后回家待命,不丢级、不生效)。
**两根类型轴的所有权(2026-10-12 v0.6 订正,用户裁)**:`attack_type` / `armor_type` 的默认值由锻造工坊配置**常驻持有**(默认值 = 现役静态表现役值 normal / light),hero.tres 静态表两轴随实装删除——静态表不再存放这两项。冒险开始时参数面读「锻造工坊配置默认值 + 存档当前选中覆盖」注入。**默认值与柜台解锁状态解耦**:树钥匙节点未点亮时柜台为锁定态(玩家无交互入口),但配置表常驻可读、默认值照常注入——不存在「锻造工坊解锁前读不到默认值」的窗口。选中态写存档(与等级域同批新增),与现役「表运行期只读、永久强化写存档」纪律一致(`meta_progression.gd:12-13/119`)。
**两根类型轴的所有权(2026-10-12 v0.6 订正,用户裁)**:`attack_type` / `armor_type` 的默认值由锻造工坊配置**常驻持有**(默认值 = 现役静态表现役值 normal / light),hero.tres 静态表两轴随实装删除——静态表不再存放这两项。冒险开始时参数面读「锻造工坊配置默认值 + 存档当前选中覆盖」注入。**默认值与柜台解锁状态解耦**:树钥匙节点未点亮时柜台为锁定态(玩家无交互入口),但配置表常驻可读、默认值照常注入——不存在「锻造工坊解锁前读不到默认值」的窗口。选中态写存档(与等级域同批新增),与现役「表运行期只读、永久强化写存档」纪律一致。
### 三件武器
@@ -65,10 +63,10 @@
| 长枪 | **长枪锻造** | 穿刺 | 解锁后从 1 级练起 |
| 法杖 | **法杖锻造** | 魔法 | 解锁后从 1 级练起 |
> **改名注(2026-10-12,8a 裁·Y 层)**:六条路线的行名统一为「件名 + 锻造」——长剑锻造 / 长枪锻造 / 法杖锻造、轻甲锻造 / 重甲锻造 / 魔法护甲锻造。其中第一件武器的正式显示名由「剑」改「长剑」(用户原话口径)。`attack_type` 字段值、矩阵语义、registry 攻击类型词条均不受此改名影响——改的只是显示名。
> **改名注(2026-10-12,8a 裁·Y 层)**:六条路线的行名统一为「件名 + 锻造」——长剑锻造 / 长枪锻造 / 法杖锻造、轻甲锻造 / 重甲锻造 / 魔法护甲锻造。其中第一件武器的正式显示名由「剑」改「长剑」(用户原话口径)。`attack_type` 字段值、矩阵语义、攻击类型词条登记均不受此改名影响——改的只是显示名。
- 每件武器有**独立等级**(1 到上限,锚点 5 级量级,provisional;**0 级 = 未练合法态**——未解锁或已解锁未锻造均为 0 加值裸体态,锻出第 1 级 = 首个 +1,Q1 裁 2026-10-12)、独立成长曲线、独立的满级特效挂位(**本期为空位**——6 裁,见「满级特效扩展位」节)——三件武器的等级各自保留,换当前武器不丢任何进度。
- **当前武器单选出场**:类型由武器决定(选长枪=穿刺)。选中态写**存档域**(与等级域同批新增),冒险开始经参数面注入;`attack_type` 的默认值归锻造工坊配置常驻持有、hero.tres 静态表该轴随实装删除(2026-10-12 v0.6 订正:原「写入 hero.tres 休眠轴」口径与现役「表运行期只读、永久强化写存档」纪律冲突——`meta_progression.gd:12-13/119`,且与本文存档域条目自相矛盾;现役静态值 normal 由锻造工坊配置默认值接管)。
- **当前武器单选出场**:类型由武器决定(选长枪=穿刺)。选中态写**存档域**(与等级域同批新增),冒险开始经参数面注入;`attack_type` 的默认值归锻造工坊配置常驻持有、hero.tres 静态表该轴随实装删除(原「写入 hero.tres 休眠轴」口径与现役「表运行期只读、永久强化写存档」纪律冲突,且与本文存档域条目自相矛盾;现役静态值 normal 由锻造工坊配置默认值接管)。
- **一次冒险 = 一个武器类型 + 一个甲型(1a 裁)**:同一时刻只有一件武器、一件甲生效(出场行显示"当前:长剑锻造 + 轻甲锻造")。多持轮换淘汰——棋盘穿刺/魔法直伤件已承载"对不同甲型换着打"的战术价值,战斗内换械要给结算管线新开"类型可变"维度,收益不成比例。(原裁点只问武器携带数,本裁把它扩到"一次冒险"粒度并同时覆盖甲侧。)
- **营地内随时切换、免费(1b / 1c 裁)**:等级都是玩家花资源练出来的,切换只是决定"今天带谁出门";二次收费会惩罚尝试性构筑,与成长曲线诉求(低成本试错找匹配武器)相逆。**冒险开始后锁死**:伤害单据的类型在开单时声明、管线内不变。
@@ -83,7 +81,7 @@
- **命名统一(3a / 2b 裁)**:**只有「魔法护甲」这一个名字**(= 现役甲域 ward)。用户原案里的「魔法甲」是**笔误**,不是别名、不做简称退役处理——正文与界面文案一律写「魔法护甲」([术语表](../../术语表.md) 已登记);仅历史版本行与过程稿引用原文时按记载保留。"第四甲型"不存在也不需要讨论(2b 随之自动消解)。
- **每型独立等级路线(3c 裁)**:与武器路线同构;"当前甲"单选与"当前武器"单选同构,营地内免费切换。
- **甲型差异当下双轴可感(3b 裁——推翻原「显式边界·诚实收窄」条款)**:**敌方攻击是有类型的**;未显式设置的敌方攻击一律按**默认普通(normal)**参与结算(用户裁)。矩阵 normal 行取值 = 轻甲 0 / 重甲 −1 / 魔法护甲 +1(整数点数:+1 被克 / 0 中性 / −1 挡住)。所以甲型差异不是"只有基础 AC 可感",而是 **基础 AC + 克制修正两轴当下同时生效**——不再有"克制反向要等敌方攻击类型批"的推迟。
- **现役实态与本裁定的落差(跨系统汇合点,本系统只登记需求)**:现役敌方攻击单据的 `attack_type` 栏为 `""`(空串恒不查克制矩阵,`damage_controller.gd:19/:550-552`;该栏注释把"敌方技"列入无类型族),`enemy.tres:527` 登记「敌方技能攻击类型轴仍未开(全部 normal 档)」——轴未开、开了也全 normal。**按 3b 裁执行 = 把该轴按「缺省填 normal」启用**;填值动作面落在敌人系统 / 战斗结算侧,不在本工作间内。锻造工坊实装批只登记该需求与它的数值影响(见「实装边界」第 6 条)。
- **现役实态与本裁定的落差(跨系统汇合点,本系统只登记需求)**:现役敌方攻击单据的攻击类型栏为空(空串恒不查克制矩阵,与"群伤/反噬/地形/敌方技"同列无类型族),敌人表登记「敌方技能攻击类型轴仍未开(全部 normal 档)」——轴未开、开了也全 normal。**按 3b 裁执行 = 把该轴按「缺省填 normal」启用**;填值动作面落在敌人系统 / 战斗结算侧,不在本工作间内。本系统只登记该需求与它的数值影响。
- **连带后果(3b 裁的前置信息,用户裁定:不在本批考虑,留作后续开发改造的输入)**:按"敌方攻击缺省普通"落定后,现行数据下三型会成**纯序**——重甲(AC +2 且挡普通 −1)= 双正、轻甲 = 中性、魔法护甲(AC −1 且被普通克 +1)= 负向,且因现行敌方无魔法攻击而暂无优势窗口。这是**后续开发改造的前置事实**不是缺陷裁定:敌方攻击类型的差异化、魔法护甲的正当性由后续批次负责(含 M4 在基础 AC / 解锁价上的取值);本批只需按统一伤害轴把结构与字段落对即可。
- 每 1 点 AC 的期望减伤约 3.75% 量级(现役 EV 复算锚:AC10 期望减免 21.25%、AC11 25%),终值归 M4。
@@ -97,7 +95,7 @@
### 经济
- **纯钥石(5b 裁)**:与现役属性锻造、天赋树(树全钥石单币)、同调刷新升级同币同柜。原案语义是"攻击力提升改造"——同一笔钱换个花法。GP = 局内一次性货币、局内清零不入存档、与钥石永不互兑,两币分工是拍板条款,不引入局外 GP 余额域或第三货币。(用户裁定注:当前没有其他材料,钥石就是统一货币;**后续若要分出专用币或材料,届时再重构设计,不预先建面**。)
- **几何递增定价**:每级价格 = 基础价 × 150%^(已购级数)(历史考古参数:单次 20 钥石、公比 150%——`meta.tres:82-84` 退役批注;forge_products 行族已随迭代 21 T5 退役、无现役计价字段可沿,实装投值归 M4 从零标定);路线解锁 = 一次性解锁价(量纲 ≈ 中段几级锻造花费)。全部终值归 M4。
- **几何递增定价**:每级价格 = 基础价 × 150%^(已购级数)(历史考古参数:单次 20 钥石、公比 150%——退役行批注;forge_products 行族已随迭代 21 T5 退役、无现役计价字段可沿,实装投值归 M4 从零标定);路线解锁 = 一次性解锁价(量纲 ≈ 中段几级锻造花费)。全部终值归 M4。
- **零材料经济(5c 裁)**:不引入账号层锻造材料。现役效果引擎的 grant_material 是**局内**材料计数器(如雷区图谱),不是账号层库存;账号层材料=全新经济面(存档域/获取渠道/囤积规则全套新建),原案全文只字未提材料,武器差异化的价值轴是类型(与预留的特效位)不是采集刷料。
### 满级特效扩展位(本期不启用——6 裁)
@@ -112,55 +110,30 @@
| 路线 | 候选特效(量纲方向) | 实现代价分档(2026-10-21 按现役代码复核) |
|---|---|---|
| 长剑 | 破甲:命中重甲时克制修正额外 +1 点量级 | 零新代码——`modify_ticket` 效果类型与 matchup 条件算子均在现役闭集 |
| 长剑(第二条) | 暴击面扩大:暴击骰面 −1 量级 | **需新参数位**——暴击面现役是表上恒定值(`settlement.tres:52 crit_roll=20`),改成武器级可变=实装批改读表面 |
| 长剑(第二条) | 暴击面扩大:暴击骰面 −1 量级 | **需新参数位**——暴击面现役是表上恒定值(`settlement.tres` 的 `crit_roll=20`),改成武器级可变=实装批改读表面 |
| 长枪 | 先手连击:战斗开场追加一次普攻量级的攻击 | 零新代码——`attack_segments` 在册 |
| 法杖 | 开局魔法矢:每场战斗开场自动对最前敌人放一次魔法直伤(必中全额量级) | 零新代码——`spawn_spell` 在册(次数/回合数 provisional) |
| 轻甲 | 灵巧:掷点折扣临界档再缓一档量级 | **需新参数位**——折扣档现役读表恒定(`settlement.tres:51 roll_tier_discounts=[75,50,25]`) |
| 轻甲 | 灵巧:掷点折扣临界档再缓一档量级 | **需新参数位**——折扣档现役读表恒定(`settlement.tres` 的 `roll_tier_discounts=[75,50,25]`) |
| 重甲 | 反震:被命中时对攻击者反贴 1 点量级伤害 | 零新代码——`spike` 在册 |
| 魔法护甲 | 护盾:每场战斗开场自带护盾(层数 X 量级,终值归 M4) | 零新代码+参数面桥接——`shield` 在册,护盾层数进战斗开场参数需接线 |
- 候选池的实现深度前提(沿用过程稿结论并经现役复核):七条全部可用现役 `EFFECT_KINDS` 闭集词或参数位表达,**无一条需要往闭集加新效果类型词**——加词是高代价变更面(加载校验/文档词表/回归测试三处连带),启用时禁走此路。
- 候选池的实现深度前提(沿用过程稿结论并经现役复核):七条全部可用现役效果类型闭集词或参数位表达,**无一条需要往闭集加新效果类型词**——加词是高代价变更面(加载校验/文档词表/回归测试三处连带),启用时禁走此路。
**对相邻口径的三处连带**:① 设计目的节"能力解锁的节奏"台阶收缩为新武器 / 新甲型解锁(不再含特效);② 实装边界不再有"特效三条新参数位"条目;③ 存档域不设特效域。
**对相邻口径的两处连带**:① 设计目的节"能力解锁的节奏"台阶收缩为新武器 / 新甲型解锁(不再含特效);② 存档域不设特效域。
## 与相邻系统的边界
- **奇物属性件**:分层并存,互不侵入。武器/护甲锻造动的是**账号层基础值**(营地永久强化,冒险开始时经参数面传入);奇物属性件动的是**单次冒险加算区**(关间不清零、冒险结束清零)。本设计不扩奇物"生命/AC/攻击"三轴封闭分类、不动渠道开关表、不往局内池加任何东西。入战 AC 的三层语义清晰可加:甲型基础 AC + 营地甲路线等级加值 + 局内加算区累加。
- **克制矩阵(2a 裁:伪裁点消解)**:**伤害结算只有一套,类型不是待仲裁的槽位**。每份伤害单据自带 `attack_type` 栏(`damage_controller.gd:19` 单据九栏之一)——主角基础攻击单据取 `hero.tres` 的 attack_type(由当前武器决定),棋盘格面直伤件(穿刺弹 / 魔法矢)取 reward 表自身的类型(预期 `reward.tres:131/142`)——各自按**同一张 3×3 矩阵** `armor_effectiveness` 取克制修正(`_counter_delta`)。因此"叠加 / 替代 / 互斥"三分法不成立:两根参数之间无冲突可裁,也不需要任何共存规则。二者的真实差异只在**单据形态与生命周期**(主角基础攻击走掷点折扣 + 暴击;棋盘克制直伤走必中全额不掷点 `_resolve_board_typed`;且前者 = 账号层永久、后者 = 局内一次性)——那是两条不同的伤害来源,不是两种类型语义。矩阵九格满格结构冻结(2b 随 3a 自动消解:魔法护甲 = 现役 ward,不存在第四甲型)。
- **克制矩阵(2a 裁:伪裁点消解)**:**伤害结算只有一套,类型不是待仲裁的槽位**。每份伤害单据自带攻击类型栏——主角基础攻击单据取当前武器的攻击类型,棋盘格面直伤件(穿刺弹 / 魔法矢)取奖励表自身的类型——各自按**同一张 3×3 克制矩阵**取克制修正。因此"叠加 / 替代 / 互斥"三分法不成立:两根参数之间无冲突可裁,也不需要任何共存规则。二者的真实差异只在**单据形态与生命周期**(主角基础攻击走掷点折扣 + 暴击;棋盘克制直伤走必中全额不掷点;且前者 = 账号层永久、后者 = 局内一次性)——那是两条不同的伤害来源,不是两种类型语义。矩阵九格满格结构冻结(2b 随 3a 自动消解:魔法护甲 = 现役 ward,不存在第四甲型)。
- **工作间两区定名 + 路线行名(8a 裁)**:锻造工坊工作间内先立两个分区,各装三条锻造路线(路线行名统一为"件名 + 锻造")——①**武器锻造区**:长剑锻造 / 长枪锻造 / 法杖锻造;②**护甲锻造区**:轻甲锻造 / 重甲锻造 / 魔法护甲锻造。两区并列、机制层面零顺序门槛(A③ 裁),区内路线各自独立升级。
- **局内不存在武器/护甲的提升(8a 裁连带核结)**:用户指出"局内没有可以提升武器的地方"——**属实**。查实:局内商店货架的三行(现役旧名"攻击锻升 / 生命锻升 / 护甲锻升"——**2026-10-12 已改名,见下**),**正是奇物「属性值提升」三轴(攻击 / 生命上限 / AC)的货架前台标签**——`shop.tres` pool_shelf 六行用 `kind_id` 指向 `adventure_table.gd:29` 的 CURIO_KINDS 常量(其中 feat_ticket 为显式豁免种、不入该词表,5/6 命中——`config_db_cross_validator.gd:109-110`),`display_name` 只是这层的前台名;买到的东西进**冒险加算区**、冒险结束清零。所以它们是**奇物属性件**,既不是武器也不是护甲,局内不改变任何锻造等级。命名上的隐患确凿:行名里的"锻"字与营地锻造同字,是误读的直接来源。**2026-10-12 用户裁决(8a 连带·C 项)**:三行按「属性 + 后缀」改名,后缀取 **祝福** ⇒ **攻击祝福 / 生命祝福 / 护甲祝福**(D&D 参照调研:Blessing 为"神赐恩惠"义;用户同时裁定——参考书目里出现过「祝福」一词不构成禁用)。**改名后这三条在语感上彻底脱离"锻造"一词,与营地工作间不再有字面关联**,而结构关系不变(仍是奇物「属性值提升」三轴,机制分类名不动,只改玩家向显示名)。**执行归独立改名小批**(待办清单在册)——**已于 2026-10-12 执行完毕并合入 master**(commit `0c93a71` / `0144f60`:shop.tres 六行锻升→祝福;reward.tres / status_effects.tres 护甲强化→盾牌加护;smoke_all.gd:1199 断言同步;注记段四处残留肃清;冒烟两跑 864 项 0 失败)。
- **局内不存在武器/护甲的提升(8a 裁连带核结)**:用户指出"局内没有可以提升武器的地方"——**属实**。查实:局内商店货架的三行(现役旧名"攻击锻升 / 生命锻升 / 护甲锻升"——**2026-10-12 已改名,见下**),**正是奇物「属性值提升」三轴(攻击 / 生命上限 / AC)的货架前台标签**——`shop.tres` pool_shelf 六行用种类字段指向冒险表的奇物种类词表(其中凭证行为显式豁免种、不入该词表,六行中五行命中),`display_name` 只是这层的前台名;买到的东西进**冒险加算区**、冒险结束清零。所以它们是**奇物属性件**,既不是武器也不是护甲,局内不改变任何锻造等级。命名上的隐患确凿:行名里的"锻"字与营地锻造同字,是误读的直接来源。**2026-10-12 用户裁决(8a 连带·C 项)**:三行按「属性 + 后缀」改名,后缀取 **祝福** ⇒ **攻击祝福 / 生命祝福 / 护甲祝福**(D&D 参照调研:Blessing 为"神赐恩惠"义;用户同时裁定——参考书目里出现过「祝福」一词不构成禁用)。**改名后这三条在语感上彻底脱离"锻造"一词,与营地工作间不再有字面关联**,而结构关系不变(仍是奇物「属性值提升」三轴,机制分类名不动,只改玩家向显示名)。**改名已于 2026-10-12 执行完毕并合入 master**(shop.tres 六行锻升→祝福;reward.tres / status_effects.tres 护甲强化→盾牌加护)。
- **专长联动**:现役专长均为跨攻击类型通用件(不按 attack_type 分系——既无 normal 条件件、也无 pierce/magic 条件件,`feats.tres` 29 行实证),武器类型差异只经克制矩阵的 matchup 行体现;「选某类型激活某系专长」在本项目专长体系下不成立(2026-10-12 v0.6 订正:原「选长枪激活穿刺系专长的价值」为无现役对应物的表述,删除)。现有死条件 `magic_vs_magic`(魔法打"魔法甲"——现行甲域无此型,永不可触发 = 废卡):**改值复活案已作废(2026-10-11 D 组核结——所属件魔网织者在素材库表二专长 27 件退役删除名单)**,该行随专长退役删行批整体消解,本系统零触碰(2026-10-12 订正:本节原写"推荐复活"与实装边界第 3 条结案口径冲突,随本批对齐)。「魔法打魔法护甲」的克制语义由矩阵九格承载(magic vs ward = −1),新专长框架如需同类件 = 彼批的新卡设计题。
- **天赋树**:同钥石经济;注入面分层叠加且**所有权切分**(2026-10-11 裁)——树脊柱只持生命/命中淬炼(树零攻防来源),攻/AC 唯一入口=本系统路线加值(只按当前选中武器/甲生效)。
- **冒险前资源配比预设批(挂起冻结中)**:本设计不预设该批的重启口径、不占用其任何冻结裁决、不改其冻结文本。该批重启时须显式核对两处交汇面:①预算包络是否把武器类型计入克制注;②容量柜台与锻造工坊工作间(同在营地)的资源竞争关系。
## 现役代码事实(设计所依据的实态,2026-10-07 复核)
| 事实 | 出处 |
|---|---|
| 局内商店货架三行 = 奇物「属性值提升」三轴的货架前台标签(攻击/生命/护甲祝福);营地属性锻造行族已随迭代 21 T5 退役,无"武器"实体 | `shop.tres:68-92`、`meta.tres:73-76` 退役登记 |
| 主角攻击类型轴现役值 normal(枚举 normal/pierce/magic)——默认值所有权随本设计移交锻造工坊配置、hero.tres 该轴随实装删除 | `hero.tres:11`、`hero_table.gd:13` |
| 主角甲型结构位现役值 light(域 light/ward/heavy);AC=10 现役生效——默认值所有权随本设计移交锻造工坊配置、hero.tres 该轴随实装删除 | `hero.tres:9-10` |
| 克制矩阵 3×3 九格满格(普通/穿刺/魔法 × 轻甲/魔法护甲/重甲),结构冻结 | `settlement.tres:31-47` |
| 敌方装甲分布:轻甲×14 / 重甲×4 / 魔法护甲×1(L2 Boss 蛛化卓尔精灵) | `enemy.tres` |
| 甲效矩阵 normal 行取值:轻甲 0 / 魔法护甲 +1 / 重甲 −1(整数点数:+1 被克 / 0 中性 / −1 挡住) | `settlement.tres:31-47` |
| 敌方攻击类型轴**未开**——单据 `attack_type` 栏现役为 `""`(空串恒不查矩阵,`""` 与"群伤/反噬/地形/敌方技"同列无类型族);`enemy.tres` 登记「敌方技能攻击类型轴仍未开(全部 normal 档)」 | `damage_controller.gd:19/:550-552`、`enemy.tres:527` |
| 效果引擎效果类型闭集 **31 种**(原记 24 系 2026-10-07 旧快照——迭代 20 T1 +7、迭代 22 T3 +1,2026-10-13 迭代 23 反哺写入订正;冒烟断言钉 31,将来加词即转红提示复核) | `effect_engine.gd` |
| 营地消费货币=钥石(现役入口 tree_buy / buy_attune_refresh → spend_keystone——buy_forge 随 forge_products 退役删除);GP=局内一次性货币,开局清零不入存档 | `meta_progression.gd:175/:354`、`adventure_runner.gd:100` |
## 实装边界(执行归实装批,本文只登记方案)
1. **锻造路线行族(新建)**:现役 `meta.tres` forge_products 行族已随迭代 21 T5 攻防所有权切分整体退役(`meta.tres:73-76`、`meta_table.gd:15-16`、`meta_progression.gd:33-35` 三处退役登记,buy_forge/forge_price 访问器随删)——武器/护甲路线为**新建行族**,行族命名、字段结构与落表位置归实装批定义,本文只登记内容口径(三武器/三甲各自等级、定价、解锁通道,见「工作间内容清单」);生命项不在本批(生命强化唯一入口=树脊柱生命线,2026-10-11 A① 裁)。同表 boss_keystone / workshop_items / conversion / attune_refresh_upgrade 四行族零触碰。**实态回填(2026-10-13 迭代 23 实装兑现)**:落表=新表 `data/tables/forge.tres`(ForgeTable:默认两轴常驻持有 + 六路线行族,`meta.tres` 三行族零触碰);路线 id = sword/spear/staff/light/heavy/ward(甲路线 id=甲型值本身);字段闭集 12 项;访问器 = `ConfigDB.forge_*` 六个(迭代 23 T1/T2 交付)。
2. **两根类型轴的所有权移交**:`attack_type` / `armor_type` 的默认值由锻造工坊配置常驻持有,hero.tres 静态表两轴**删除**;营地选中态写存档域,冒险开始经参数面注入(与现役「表运行期只读、永久强化写存档」纪律一致——`meta_progression.gd:12-13/119`;原「写 hero.tres 休眠轴」口径随 v0.6 订正,见「注入衔接」节)。
3. **`feats.tres` magic_vs_magic 死行**:复活案作废(2026-10-11 核结——所属件魔网织者已在素材库表二专长 27 件退役删除名单),随专长退役删行批整体消解,本批零触碰;「魔法打魔法护甲」克制语义由矩阵九格承载,新专长框架如需同类件=彼批新卡设计题。
4. **存档域**:新增三武器等级 + 三甲等级 + 当前选中标记(各 1 个);**不设特效域**(6 裁)。旧档按开发阶段无迁移红线破坏性废弃(2026-10-11 用户裁,禁迁移/折算)。**已于 2026-10-12 v0.6 完备性检查批预登记**(存档序列化.md 域清单表 + 版本沿革 v7 计划行——用户令文档批次即登记、不等实装批)。
5. **满级特效:本期不实装**(6 裁)——不开三条新参数位(暴击面 / 折扣档 / 护盾量),不加效果类型词,扩展位留空。
6. **敌方攻击类型轴填值(3b 裁连带,跨系统汇合点)**:敌方攻击单据 `attack_type` 按「未设置 = 默认 normal」填值,使其参与克制矩阵查表(现役为 `""` 恒不查)。**执行面归敌人系统 / 战斗结算侧**,锻造工坊实装批只登记该需求与其数值影响——该改动会全局平移主角受伤点数(穿重甲 −1、穿魔法护甲 +1),属数值敏感变更,须纳入第 8 条的配对读数验证。敌方 attack_type 是敌方定义数据(enemy.tres / skills.tres 行级,与敌种名字/血量同批同时读写、无独立时序),填值归敌人系统/战斗结算侧自然推进——本批只按 3b 裁落结构面(矩阵查表现役已支持),与锻造工坊批期无耦合(2026-10-12 订正:原「两批排期协商(可同批做,也可先行)」句删除——用户裁:时序问题不存在)。
7. **术语登记**:三型甲统一命名——**只有「魔法护甲」(「魔法甲」系笔误,不登记为别名)**;连同工作间两区定名(武器锻造区 / 护甲锻造区)顺带登记 `design/gdd/术语表.md`。
8. **数值验证义务**:实装批必须带改前/改后同随机种子配对读数验证难度影响;统一调整归 Alpha 收官 M4 数值批。
## 裁决结果清单(17 裁点全表·2026-10-12 清零)
17 裁点全部拍板,本表即终态(含本会话呈报的两条子问 4a-1 / 4b-1,共 19 行)。「推翻推荐」四行已同步改正文对应节。实装批以本表 + 下节「工作间内容清单」为需求卡片输入。
17 裁点全部拍板,本表即终态(含本会话呈报的两条子问 4a-1 / 4b-1,共 19 行)。「推翻推荐」四行已同步改正文对应节。
| # | 裁点 | 裁决结果 | 写入处 | 备注 |
|---|---|---|---|---|
@@ -182,7 +155,7 @@
| 5b | 货币 | 纯钥石(用户注:当前无其他材料,钥石 = 统一货币;后续若要区分再重构,不预先建面) | 「经济」节 | 按推荐案(且受两币分工条款锁定) |
| 5c | 材料经济 | 纯钥石零材料 | 「经济」节 | 按推荐案 |
| 6 | 满级特效深度 | **本期不做,只留扩展位**——不设计清单 / 不定数值 / 不实装 / 不开参数位 | 「满级特效扩展位」节 | **推翻推荐案**(原 = 复用为主 + 三条新参数位) |
| 8a | 货架现名 → 实裁 = 工作间命名(区名 + 路线行名)+ 局内核结 | **区名**:武器锻造区 / 护甲锻造区;**路线行名**统一「件名 + 锻造」= 长剑锻造 / 长枪锻造 / 法杖锻造、轻甲锻造 / 重甲锻造 / 魔法护甲锻造(第一件武器显示名 剑 → **长剑**)。**局内核结**:局内不存在武器 / 护甲的提升——商店货架三行「攻击锻升 / 生命锻升 / 护甲锻升」即奇物「属性值提升」三轴的货架前台标签(`shop.tres` pool_shelf kind_id → `adventure.tres` CURIO_KINDS),与锻造无关;是否去"锻"字归实装批呈现面 | 「与相邻系统的边界·工作间两区定名 / 局内不存在武器提升」 | 裁点重定向 + Y 层命名 |
| 8a | 货架现名 → 实裁 = 工作间命名(区名 + 路线行名)+ 局内核结 | **区名**:武器锻造区 / 护甲锻造区;**路线行名**统一「件名 + 锻造」= 长剑锻造 / 长枪锻造 / 法杖锻造、轻甲锻造 / 重甲锻造 / 魔法护甲锻造(第一件武器显示名 剑 → **长剑**)。**局内核结**:局内不存在武器 / 护甲的提升——商店货架三行「攻击锻升 / 生命锻升 / 护甲锻升」即奇物「属性值提升」三轴的货架前台标签(`shop.tres` pool_shelf 种类字段 → `adventure.tres` 奇物种类词表),与锻造无关;是否去"锻"字归实装批呈现面 | 「与相邻系统的边界·工作间两区定名 / 局内不存在武器提升」 | 裁点重定向 + Y 层命名 |
## 工作间内容清单(实装批需求卡片输入)
@@ -229,7 +202,7 @@
- 入战 AC 三层可加:甲型基础 AC + 甲路线等级加值 + 局内加算区累加。
### 8 · 存档域
三武器等级 + 三甲等级 + 当前武器标记 + 当前甲标记;**无特效域**。旧档破坏性废弃(禁迁移 / 折算)。**已于 2026-10-12 预登记存档序列化.md**(域清单 + 版本沿革 v7 计划行)。
三武器等级 + 三甲等级 + 当前武器标记 + 当前甲标记;**无特效域**。旧档破坏性废弃(禁迁移 / 折算)。存档域见[存档序列化](../表现与支撑/存档序列化.md)(域清单与版本沿革 v7 行)。
### 9 · 本期明确不做
① 满级特效(清单 / 数值 / 参数位 / 存档域全不做);② 敌方攻击类型轴填值——跨系统需求,执行面在敌人系统 / 战斗结算侧,本批只登记。
+72 -72
View File
@@ -1,10 +1,10 @@
# UX Spec: 战斗屏(Battle Screen)
> **Status**: Complete — /ux-review 修订落稿(2026-09-12,blocking 7 项已修,待复检)
> **Status**: Complete(现行)
> **Author**: user + ux-designer
> **Last Updated**: 2026-10-26(迭代 38 卡⑦ 调试入口发布态恒隐:DS_DEBUG 门控表述换代——见元素表「调试浮窗」行与「调试变体」行)
> **Last Updated**: 2026-10-29
> **Platform Target**: PC (Steam)——Keyboard/Mouse 主(全部操作纯鼠标可完成)、Gamepad Partial 非 MVP、Touch None(同 technical-preferences)
> **上游修订依赖**: 弃图刷新挖掘期受理已随布局决策 4 落稿上游(2026-09-12:行动经济 Active 受理 + 每轮上限 2 次、排雷玩法 Active·仅刷新路径装板、战斗结算 `refresh_board` 编排 + 恒 same_board、registry `rap_rules` 同步——见 OQ11)
> **上游修订依赖**: 弃图刷新挖掘期受理已随布局决策 4 落稿上游(2026-09-12:行动经济 Active 受理 + 每轮上限 2 次、排雷玩法 Active·仅刷新路径装板、战斗结算的挖掘期刷新编排 + 恒同盘不变、系统索引的刷新规则同步——见 OQ11)
> **Template**: UX Spec
> **覆盖子屏**: 挖掘阶段主界面 · 轮末自动战斗结算(战斗结算明细屏) · 胜利/失败终局 · ~~结算明细回看~~(2026-10-04 P-C7 裁:冒险中回看退役归「生涯」——待办清单登记)
> **输入义务**: 排雷玩法×6 + 行动经济 + 战斗结算×3 + 敌人系统×4 + 增益状态×4 + 地图战斗资源×5(旧版 systems-index 门禁增补记录,缺项即 blocking——承接落点见 §13 义务对照表)
@@ -28,7 +28,7 @@
## Player Context on Arrival
- **首次到达**:从关卡首节点(战×2 的第一战)进入。MVP 无引导流,chord 肌肉记忆提示等非模态提示承担首次教学(见 §States)
- **到达前刚在做**:关卡画面(独立屏)上点击战斗节点(LevelRunner 推进);或上一场战斗胜利后返回关卡画面再选下一节点
- **到达前刚在做**:关卡画面(独立屏)上点击战斗节点(关卡推进方受理);或上一场战斗胜利后返回关卡画面再选下一节点
- **情绪状态**:棋手式清明专注(art-bible §2.1,能量 2/10)——挖掘期画面必须无杂音;结算期转为清算爽感(7/10)
- **到达方式**:游戏推进送入(非自愿导航),进入即处于挖掘阶段(棋盘已 install、初始 3×3 已展开、小人出生)
@@ -41,14 +41,14 @@
```
存档 → 冒险 → 关卡(关卡画面 = 节点图选路常驻枢纽) → 【战斗屏】
├─ 胜利 → 返回关卡画面选下一节点(落地奖励/恢复节点时开节点覆盖层确认 → 下一场战斗屏)
├─ 胜利(末节点 Boss)→ 关卡结算(level_clear,spec:[level-clear.md](level-clear.md))→ 下关
├─ 胜利(末节点 Boss)→ 关卡结算(关卡完成,spec:[level-clear.md](level-clear.md))→ 下关
└─ 失败 → 冒险落幕 → 返回存档/营地
```
战斗屏是**上下文相关屏**(仅由战斗节点进入),非顶层常驻。关卡内节点进度常驻关卡画面(独立屏的常驻枢纽形态,节点态即进度呈现:已过暗金、当前金、候选通道亮金、Boss 紫赤描边),战斗屏零进度承载——战斗结束返回关卡画面,玩家始终知道自己身处图中第几环。
- 上游屏:关卡画面(选路枢纽,屏级 spec:[level-map.md](level-map.md)——2026-09-27 建档;分支节点图形态,切片第一关为单链特例)
- 下游屏:关卡画面(选路枢纽,spec:[level-map.md](level-map.md))——战斗胜利后返回选路;落地奖励/恢复节点时由关卡画面域开节点覆盖层(NodeOverlay,恢复点全量服务、奖励点=三选一构筑点)确认兑付——节点奖励屏 spec 已出生:[node-reward.md](node-reward.md) v1.0(2026-09-29 迭代 7 T5 顺带出生,待办清单条目兑现;2026-09-27「不立独立 spec」拍板随之被取代)
- 下游屏:关卡画面(选路枢纽,spec:[level-map.md](level-map.md))——战斗胜利后返回选路;落地奖励/恢复节点时由关卡画面域开节点覆盖层(恢复点全量服务、奖励点=三选一构筑点)确认兑付——节点奖励屏 spec 已出生:[node-reward.md](node-reward.md) v1.0(2026-09-29 迭代 7 T5 顺带出生,待办清单条目兑现;2026-09-27「不立独立 spec」拍板随之被取代)
- 下游屏:关卡结算([level-clear.md](level-clear.md),末节点 Boss 胜利——2026-09-27 建档)
- 平行屏:图例面板 overlay(本屏内域屏);~~结算明细回看 overlay~~(2026-10-04 P-C7 退役——冒险中回看归「生涯」)
@@ -60,16 +60,16 @@
| Entry Source | Trigger | Player carries this context |
|---|---|---|
| 关卡战斗节点 | 点击节点(LevelRunner 推进 encounter) | 携带 HP(跨战斗延续)、RAP=0(战斗域新开) |
| 关卡战斗节点 | 点击节点(关卡推进方受理本场遭遇) | 携带 HP(跨战斗延续)、RAP=0(战斗域新开) |
| 上一场战斗胜利 → 返回关卡画面 → 选下一节点 | 同上 | 同上 |
**离开**:
| Exit Destination | Trigger | Notes |
|---|---|---|
| 关卡画面(选路枢纽) | 敌方全灭(战斗结算判定段 verdict=win)且非末节点 | 不可逆:battle_over 已发生,RAP 清零;落地奖励/恢复节点时开节点覆盖层确认(NodeOverlay,关卡画面域) |
| 关卡结算 | Boss 战胜利 → level_clear(spec:[level-clear.md](level-clear.md)) | 不可逆:~~关卡收束清库义务载体 = 秘宝背包~~(秘宝过渡形态〔关卡域库存/局内两步使用〕已随迭代 11 第①批退役——现行形态 = 营地同调装配、整局冒险生效,无关卡域清库面〔旧关卡域库存 treasure_inventory 为投放渠道全退役后恒空的机械惰性承载,拆线归实装批——见战斗结算「轮次生命周期」节注〕,见秘宝.md) |
| 冒险落幕 | 主角 HP=0(verdict=lose) | 不可逆:Roguelike 死亡重开(art-bible §2.5 温柔惋惜调性) |
| 关卡画面(选路枢纽) | 敌方全灭(战斗结算判定段判胜)且非末节点 | 不可逆:战斗结束已发生,RAP 清零;落地奖励/恢复节点时开节点覆盖层确认(关卡画面域) |
| 关卡结算 | Boss 战胜利 → 关卡完成(spec:[level-clear.md](level-clear.md)) | 不可逆:~~关卡收束清库义务载体 = 秘宝背包~~(秘宝过渡形态〔关卡域库存/局内两步使用〕已随迭代 11 第①批退役——现行形态 = 营地同调装配、整局冒险生效,无关卡域清库面〔旧关卡域库存 treasure_inventory 为投放渠道全退役后恒空的机械惰性承载,拆线归实装批——见战斗结算「轮次生命周期」节注〕,见秘宝.md) |
| 冒险落幕 | 主角 HP=0(判负) | 不可逆:Roguelike 死亡重开(art-bible §2.5 温柔惋惜调性) |
| 无中途退出 | — | MVP 不设战斗内放弃/暂停菜单(回合制无时间压力;如需暂停留 Playtest 诊断按钮,调试用) |
---
@@ -125,7 +125,7 @@
> 布局为 B/C/D 三区——关卡进度条不在战斗屏(节点链进度常驻关卡画面,见 Navigation Position;字母不重编沿用 B/C/D)。
> 呈现术语注记(2026-09-25):封印 = 正式动作名(全库统一;registry terminology 与术语表 v1.13;印记 = 封印印记,art-bible §3.2)——机制与键名不变;封印特效未实装,占位 = 封印黑「封」字形(board_view 程序化占位,现行代码仍为旧「旗」字形、随代码术语批换代,贴图在位=字形退役;旗朱→封印紫 2026-09-26→封印黑 2026-09-28 用户拍板)。
> 呈现术语注记(2026-09-25):封印 = 正式动作名(全库统一;登记册术语与术语表 v1.13;印记 = 封印印记,art-bible §3.2)——机制与键名不变;封印特效未实装,占位 = 封印黑「封」字形(棋盘视图程序化占位,现行代码仍为旧「旗」字形、随代码术语批换代,贴图在位=字形退役;旗朱→封印紫 2026-09-26→封印黑 2026-09-28 用户拍板)。
> 可挖域微光画法定稿(2026-09-25 用户拍板):**接触带·空间侧 + 蓝族**——光画英雄格周界接触面(正交邻墙=整边,斜向邻墙=角点+两半边),详见 art-bible §3.2;现行墙格整框绿相呼吸为待退役占位,实现切换归表现批(探针断言顺带)。
@@ -153,25 +153,25 @@
### Component Inventory
| 区 | 组件 | 类型 | 内容 | 交互 | 现有 demo 组件 |
| 区 | 组件 | 类型 | 内容 | 交互 | 载体 |
|---|---|---|---|---|---|
| B | 主角站桩立绘 | 站桩(无框立绘+落影) | HP 条落底盘(2026-10-06 方案二拍板:站桩排式 = **立绘→血条→状态**,全场血条对齐一线;血条嵌石板位、台缘线留作地面线;原「悬浮头顶」退役——高盒下血条-立绘空洞,用户点名否决)、状态效果小图标一排挂血条正下方(形状+色相双通道、层数角标;空态不占位退化为空行)——**HP 与状态效果的唯一展示面(2026-09-26 信息归属拍板,原 C 区状态槽职责〔悬停 tooltip 来源+语义+剩余结算次数〕并入本组件)**;攻击值等规划数据仍归 C 区数据框(2026-09-20 全站桩拍板,英雄卡退役) | 悬停状态小图标看 tooltip | HUDView 拆分改造 |
| B | 主角站桩立绘 | 站桩(无框立绘+落影) | HP 条落底盘(2026-10-06 方案二拍板:站桩排式 = **立绘→血条→状态**,全场血条对齐一线;血条嵌石板位、台缘线留作地面线;原「悬浮头顶」退役——高盒下血条-立绘空洞,用户点名否决)、状态效果小图标一排挂血条正下方(形状+色相双通道、层数角标;空态不占位退化为空行)——**HP 与状态效果的唯一展示面(2026-09-26 信息归属拍板,原 C 区状态槽职责〔悬停 tooltip 来源+语义+剩余结算次数〕并入本组件)**;攻击值等规划数据仍归 C 区数据框(2026-09-20 全站桩拍板,英雄卡退役) | 悬停状态小图标看 tooltip | HUD 视图拆分改造 |
| B | 敌人站桩立绘 ×1–3 | 站桩(无框立绘+落影) | 血条+顺位徽标落底盘(同主角排式,2026-10-06 方案二;**大体档〔显示 >150px 级:drider/duergar_king〕允许向上溢出盒顶 N px(N 由实装批 C0 实算,与背景/光柱无关——现行溢出区为临时光柱氛围层,正式舞台背景插画到位后该层退役,判定不变),血条仍落底**)、状态小图标挂血条正下方(敌方 side-wide 增益各立绘同值呈现——蓄力/硬化/削弱/暴走/警觉;伏击层数通道随 2026-09-20 八型批退役——数据源 = 战斗结算流水经增益状态投影,敌人系统×4④;2026-09-16 敌人技能池批改型:行为环点拆除〔proposal §2.4〕,意图占位 = 本拍摇定结果的动画占位——普通攻击零表示 / 特殊技类型级提示,**意图徽标悬浮头顶上方,探顶档压胸**,敌方增益〔蓄力/硬化〕入状态图标行);死亡灰化加碎裂退场直接演在立绘上(2026-09-20 全站桩拍板,敌人卡退役);血条下名字行 = 纯名字 + 护甲类型图标(形状+色相双通道,与状态图标同行共存,状态空时为纯名字;原「底座下」随石板退位改落底排),AC 数值不展示——2026-09-26 终裁(用户口径:HP 信息已足够,攻防数值不直接写上;护甲类型图标保留克制对策可读性——类型可读、数值隐藏) | 只读 | 新建 |
| B | 轮次·阶段指示 | 标签 | "第 N 轮 · 挖掘中/结算中"(终局定格「战斗结束」;Boss 变体附 Boss 名) | 只读 | 新建 |
| B | 结算明细带 | 滚动列表 | 结算期逐行流水([战斗结算](../systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋) 9 类行协议);挖掘期收起为上轮摘要 1 行 | 点击展开明细回看 overlay(2026-10-04 P-C7 退役——带保留单行摘要,回看归「生涯」) | battle_log_view.gd 改造 |
| B | ~~结算明细回看~~(已退役) | —— | 2026-10-04 P-C7 裁:冒险中回看退役归「生涯」——settlement_review_overlay.gd 为未接线遗留件(待办清单登记) | —— | —— |
| C | 攻击数据框 | 直角细线数据框 | 攻击值 + 修正来源角标 + 护甲 AC(AC 二轮拍板 2026-09-26 补入——我方 AC 唯一展示面;原「HP/攻击/RAP 显示」——HP 与 RAP 随信息归属拍板迁出本组件) | 只读 | HUDView 拆分 |
| C | 秘宝槽 | 图标槽 ×4 | 四槽壳在役、空槽占位(标题「秘宝」,悬停「秘宝槽(空)」);局内两步使用与关卡域库存随秘宝过渡形态退役——现行秘宝 = 营地同调装配件(秘宝.md),本区展示重接归装配面批次 | 悬停 tooltip | hero_info_panel_view.gd |
| C | 奇物列表(现行标题「特性」) | 列表/图标行 | 已实装(迭代 9 卡⑫ 接线、迭代 12 呈现补齐;2026-10-12 呈现修复批整改——逐件行「件名 ×N」,零内部分类字样);锻造/大奖励/关卡奖励节点获得的属性提升——中循环数据,因改变战斗数学且无其他展示面准入战斗屏;与战斗内状态效果(B 区站桩)分区,防「战斗结束被清」误读 | 只读 | hero_info_panel_view.gd |
| D | AP 条 | 点阵 + 按钮组 | 本轮 AP 点阵、停手按钮(左)、**RAP 点阵+数字(自 C 区迁入 2026-09-26——RAP 唯一消费口 = 弃图刷新,资源数字贴消费按钮;RAP 清零可见反馈〔行动经济〕载体随迁)**、弃图刷新按钮(右端·雷图右上角;RAP−8 · 本轮剩 N 次——上限 2 次已随行动经济 2026-09-12 修订生效) | 点击提交意图 | HUDView 拆分 |
| D | BoardView | 网格 | 棋盘全部格态 + 小人 + 封印印记 + 变异纹带 + 奖励身份 icon(已开格;绘制优先级 数字>小人>封印印记>奖励徽章>变异纹带>底色——徽章不进数字区,样张验收项) | 左/右键意图提交 | ✅ board_view.gd 迁移 |
| B | 结算明细带 | 滚动列表 | 结算期逐行流水([战斗结算](../systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋) 9 类行协议);挖掘期收起为上轮摘要 1 行 | 点击展开明细回看 overlay(2026-10-04 P-C7 退役——带保留单行摘要,回看归「生涯」) | 改造 |
| B | ~~结算明细回看~~(已退役) | —— | 2026-10-04 P-C7 裁:冒险中回看退役归「生涯」——回看覆盖层为未接线遗留件(待办清单登记) | —— | 未接线 |
| C | 攻击数据框 | 直角细线数据框 | 攻击值 + 修正来源角标 + 护甲 AC(AC 二轮拍板 2026-09-26 补入——我方 AC 唯一展示面;原「HP/攻击/RAP 显示」——HP 与 RAP 随信息归属拍板迁出本组件) | 只读 | HUD 视图拆分 |
| C | 秘宝槽 | 图标槽 ×4 | 四槽壳在役、空槽占位(标题「秘宝」,悬停「秘宝槽(空)」);局内两步使用与关卡域库存随秘宝过渡形态退役——现行秘宝 = 营地同调装配件(秘宝.md),本区展示重接归装配面批次 | 悬停 tooltip | 已实装 |
| C | 奇物列表(现行标题「特性」) | 列表/图标行 | 已实装(迭代 9 卡⑫ 接线、迭代 12 呈现补齐;2026-10-12 呈现修复批整改——逐件行「件名 ×N」,零内部分类字样);锻造/大奖励/关卡奖励节点获得的属性提升——中循环数据,因改变战斗数学且无其他展示面准入战斗屏;与战斗内状态效果(B 区站桩)分区,防「战斗结束被清」误读 | 只读 | 已实装 |
| D | AP 条 | 点阵 + 按钮组 | 本轮 AP 点阵、停手按钮(左)、**RAP 点阵+数字(自 C 区迁入 2026-09-26——RAP 唯一消费口 = 弃图刷新,资源数字贴消费按钮;RAP 清零可见反馈〔行动经济〕载体随迁)**、弃图刷新按钮(右端·雷图右上角;RAP−8 · 本轮剩 N 次——上限 2 次已随行动经济 2026-09-12 修订生效) | 点击提交意图 | HUD 视图拆分 |
| D | 棋盘视图 | 网格 | 棋盘全部格态 + 小人 + 封印印记 + 变异纹带 + 奖励身份 icon(已开格;绘制优先级 数字>小人>封印印记>奖励徽章>变异纹带>底色——徽章不进数字区,样张验收项) | 左/右键意图提交 | ✅ 已实装 |
| D | 悬停预承诺光标 | 光标态 | 移动/挖/封印三语义光标 + 目标格边框高亮 | 自动 | 新建(排雷玩法×6③) |
| D | 可挖域指示 | 常驻微高亮 | 小人 8 向相邻可操作格 | 自动 | 新建(排雷玩法×6③) |
| D | 移动路径预览 | 路径高亮 | 悬停已开格显示 BFS 路径(合法性指示) | 自动 | 新建(排雷玩法×6⑤,裁决见下) |
| D | toast 槽 | 非模态提示 | 拒绝原因(双源)、voided、满层溢出、chord 提示、零合法板告知 | 自动消退 2.5s | 新建 |
| D | 图例按钮 + 面板 | 按钮+模态 overlay | 格态/变异语义图例 | 开/关 | 新建 |
| 全屏 | 胜利/失败 overlay | 模态 | 金蜡封/暮蓝收印 + 判定行(明细回看入口已随 P-C7 退役——回看归「生涯」) | 继续/下一节点 | battle_end_overlay.gd |
| 调试 | 调试浮窗 | 调试面板 | 种子/数值调整/批量模拟/两层调试入口(发布态恒隐,无 UI 开启口——写死行已随迭代 38 卡⑦ 删除,DS_DEBUG 门控口径见「调试变体」行;TunePanel 已随迭代 15 卡①吸收退役) | 调试 | debug_overlay.gd |
| 全屏 | 胜利/失败 overlay | 模态 | 金蜡封/暮蓝收印 + 判定行(明细回看入口已随 P-C7 退役——回看归「生涯」) | 继续/下一节点 | 已实装 |
| 调试 | 调试浮窗 | 调试面板 | 种子/数值调整/批量模拟/两层调试入口(发布态恒隐,无 UI 开启口——写死行已随迭代 38 卡⑦ 删除,调试开关门控口径见「调试变体」行;调参面板已随迭代 15 卡①吸收退役) | 调试 | 调试浮窗 |
**布局决策 2 —(已删除,编号留空)**:原「窗口形态 = 右栏原位激活」决策随可选类道具整体下线(2026-09-15 格面资源批)。编号留空,免布局决策 3/4 的既有交叉引用失锚。
@@ -179,10 +179,10 @@
- 备选(登记不采纳):穿行动画轨道——移动免费高频,动画时间税违反 P4 点击摩擦护栏(每轮输入动作:AP ≤2 的观测假设);正式版若 playtest 反馈"移动太瞬"再议(留痕)
**布局决策 4 — 弃图刷新 = 挖掘期当场换图(2026-09-12 用户拍板,同日落稿上游)**:按钮置 AP 条右端(雷图右上角)。点击即当轮就地换新图继续挖——AP 不重置、剩余 AP 保留,RAP−8,本轮上限 2 次。
- **上游修订(2026-09-12 已落稿,OQ11)**:① 行动经济 `request_refresh` Active 相位受理 + 每轮上限 2 次(Waiting 代理退役)② 排雷玩法装板受理域增 Active·仅刷新路径 ③ 编排 owner = **战斗结算 `refresh_board`**(行动经济扣费 → 排雷玩法 retire → 棋盘生成 generate → 排雷玩法 install → 地图战斗资源 roll_board 恰一次;无结算段、无 round_end——战斗结算编排唯一性原则保持)④ 旧板封印印记随旧板**作废**(零兑付、封印 AP 不返还——排雷玩法 EC11 全量重置承载;确认微交互须显式提示)。**经济预警**:当场刷新无结算发生,原「敌方时间税」自惩失效——行动经济 OQ3 弃图率/刷新率预警阈值联动复核。
- **上游修订(2026-09-12 已落稿,OQ11)**:① 行动经济 Active 相位受理刷新意图 + 每轮上限 2 次(Waiting 代理退役)② 排雷玩法装板受理域增 Active·仅刷新路径 ③ 编排 owner = **战斗结算的挖掘期刷新编排**(行动经济扣费 → 排雷玩法退役旧板 → 棋盘生成出新图 → 排雷玩法装板 → 地图战斗资源摇奖励恰一次;无结算段、无轮次结束——战斗结算编排唯一性原则保持)④ 旧板封印印记随旧板**作废**(零兑付、封印 AP 不返还——排雷玩法 EC11 全量重置承载;确认微交互须显式提示)。**经济预警**:当场刷新无结算发生,原「敌方时间税」自惩失效——行动经济 OQ3 弃图率/刷新率预警阈值联动复核。
- 备选(已否决):结算期决策提示(Waiting 内联)——结算期不做刷新决策(用户拍板);挖掘期预承诺 stop+reroll 复合——决策即终轮,不符「换图继续挖」语义。
**敌人意图线索映射目录(敌人系统×4① 成文占位,2026-09-12;2026-09-16 敌人技能池批改型注记:行为环三态〔攻击/蓄力/重击〕预告随行为环退役——现行数据面 = 敌人系统三档可见性规格〔普攻零表示 / 特殊技类型级动画〔攻击系/增益系两型〕/ 暴击掷点层无前置〕,池与权重不公开;下表 grub/ambusher 三态清单留档作废,终稿资产目录随战斗表现样张批重立;**命名双轨完成注记 2026-10-06**:grub/ambusher 两键本身已随敌人系统八型批退役——现行键集 = 八敌 registry〔goblin/bugbear/ogre_chief/giant_spider/drider/duergar/hook_horror/duergar_king〕,本表键名仅为历史留痕、禁止作为现行 enemy_id 引用)**:
**敌人意图线索映射目录(敌人系统×4① 成文占位,2026-09-12;2026-09-16 敌人技能池批改型注记:行为环三态〔攻击/蓄力/重击〕预告随行为环退役——现行数据面 = 敌人系统三档可见性规格〔普攻零表示 / 特殊技类型级动画〔攻击系/增益系两型〕/ 暴击掷点层无前置〕,池与权重不公开;下表 grub/ambusher 三态清单留档作废,终稿资产目录随战斗表现样张批重立;**命名双轨完成注记 2026-10-06**:grub/ambusher 两键本身已随敌人系统八型批退役——现行键集 = 八敌登记表〔goblin/bugbear/ogre_chief/giant_spider/drider/duergar/hook_horror/duergar_king〕,本表键名仅为历史留痕、禁止作为现行敌种 id 引用)**:
| enemy_id | 视觉状态(意图线索) | 强度档位编码 | 环长编码 |
|---|---|---|---|
@@ -235,16 +235,16 @@
| **结算阶段** | round_end 触发(AP 尽/停手/清图) | D 区锁输入(棋盘去饱和 + 金橙色相偏移,明度不变,数字保持全对比);B 区播放五段编排演出(授予段 → 增益/减益段 → 战斗段 → 衰减段 → 判定段,战斗结算 段序冻结);明细带展开 84px 逐行滚动;阶段指示→"结算中";能量 7/10 |
| **清图瞬间** | 全部安全格开完 | 金粒喷泉 + 彩纸 3–5s 即收(§2.3);清图奖励行强调呈现(H2,地图战斗资源×④——金框高亮行);随后换新图 install |
| **完美封印高光** | 战斗结算高光判定(全图标中/零误标类) | 全屏喝彩级反馈(§2.2 最高档):金光带加倍扫射 + 「完美封印 ×2」横幅——P2 爆发兑现节点(创意风险 #2 落点) |
| **封印标中高光** | flag_judged{hit=true} | 该印记化暴击弹道加重 + 明细行金框——chord 缺席的即时兑现补偿(创意风险 #3 落点) |
| **封印标中高光** | 封印判定·标中 | 该印记化暴击弹道加重 + 明细行金框——chord 缺席的即时兑现补偿(创意风险 #3 落点) |
| **敌人死亡呈现** | 敌 hp=0(流水行击杀标记) | 该敌人立绘血条归零 → 立绘灰化 + 碎裂退场(**禁瞬消**——敌人系统资产下限「死亡瞬间须可辨识、禁止直接消失」,同等 blocking);战斗段短路的重击被掐灭不产行动明细行,由行序可推断(战斗结算);动画密度归战斗表现,呈现语义在本 spec |
| **胜利终局** | verdict=win | 金蜡封落于**扫雷图区中央**(§2.4 字面锚定),全屏暖白金 overlay;判定行 + 「下一节点」;明细回看入口;状态图标行全清可见反馈(增益状态×4④——B 区主角站桩图标逐枚化光收回 + 微文案「状态随战斗结束消散」,防「我的增益哪去了」误读) |
| **失败终局** | verdict=lose(hero hp=0,战斗段短路) | 明度不变的暮蓝 #5A6C8C 氛围 overlay(全作唯一暮蓝档);小人坐砖掸灰、落下的封印印记逐枚化光点收回(§2.5);判定行 +「返回」(明细回看已随 P-C7 退役——回看归「生涯」);状态图标行全清可见反馈(增益状态×4④,同胜利) |
| **胜利终局** | 判定胜利 | 金蜡封落于**扫雷图区中央**(§2.4 字面锚定),全屏暖白金 overlay;判定行 + 「下一节点」;明细回看入口;状态图标行全清可见反馈(增益状态×4④——B 区主角站桩图标逐枚化光收回 + 微文案「状态随战斗结束消散」,防「我的增益哪去了」误读) |
| **失败终局** | 判定失败(主角生命归零,战斗段短路) | 明度不变的暮蓝 #5A6C8C 氛围 overlay(全作唯一暮蓝档);小人坐砖掸灰、落下的封印印记逐枚化光点收回(§2.5);判定行 +「返回」(明细回看已随 P-C7 退役——回看归「生涯」);状态图标行全清可见反馈(增益状态×4④,同胜利) |
| **Boss 遭遇变体** | encounter=boss(遗迹守卫) | 战斗开始一次性演出:紫赤 #8F2F6A 影子爬过棋盘(§2.6);敌人立绘体量最大+锐角剪影;阶段指示附 Boss 名 |
| **空态:无状态效果** | 增益状态 EC12 | 状态小图标行隐藏(B 区主角站桩血条下图标行零图标时不占位;落底排〔2026-10-06 方案二〕后该行退化为名字行——主角无名字行则整行空置);原「C 区状态槽隐藏、HP/攻击/RAP 上移补位」裁决随 C 区槽退役(2026-09-26 信息归属拍板)作废;图例面板载空态说明(增益状态×① 成文项) |
| **调试变体** | 测试模式 | 调试浮窗入口发布态恒隐(`_debug_entry` 写死行已删,无 UI 开启口;开发期临时启用=本地改该字段缺省、不提交——TunePanel 已随迭代 15 卡①退役);Playtest 诊断按钮(卡死转储) |
| **调试变体** | 测试模式 | 调试浮窗入口发布态恒隐(调试入口开关为写死行、已删,无 UI 开启口;开发期临时启用=本地改该字段缺省、不提交——调参面板已随迭代 15 卡①退役);Playtest 诊断按钮(卡死转储) |
**拒绝/作废子态**(排雷玩法×6⑥、行动经济双源——每次拒绝玩家可感知):
- 棋盘面拒绝(sub_reason:非相邻/挖封印格等)→ 目标格 危险红 #A8321F 边框闪 + toast 文案(拒绝语义红族——旗朱已退役归封印色〔现行封印黑〕)(图标+文案冗余,色弱清单 #7)
- 棋盘面拒绝(细分原因:非相邻/挖封印格等)→ 目标格 危险红 #A8321F 边框闪 + toast 文案(拒绝语义红族——旗朱已退役归封印色〔现行封印黑〕)(图标+文案冗余,色弱清单 #7)
- 资源面拒绝(AP 不足/RAP 不足)→ AP/RAP 数字脉冲 + toast「AP 不足 · 剩 0 点」
- voided(stop 被作废等)→ toast「本轮已清图,停手未执行 · 剩余 AP 已作废」——防静默改判读感欺骗
@@ -256,15 +256,15 @@
| 组件 | 动作 | 输入 | 即时反馈 | 结果(经组合根) |
|---|---|---|---|---|
| 未开相邻格 | 挖掘 | 左键 | 格碎裂 + 连锁展开(免费)+ 奖励身份揭显 | 意图入当帧批次 → 排雷玩法 `settle_batch` |
| 未开相邻格 | 挖掘 | 左键 | 格碎裂 + 连锁展开(免费)+ 奖励身份揭显 | 意图入当帧批次 → 排雷玩法的意图批次提交 |
| 已开格 | 移动 | 左键 | 悬停时路径预览高亮(布局决策 3);执行 ≤150ms 短滑 | 意图入批(BFS 移动,免费) |
| 未开格 | 封印 | 右键 | 封印印记落下(封印黑) | 意图入批(1 AP / 免费;已封印格右键无操作——封印印记无移除手段,封印不可逆批 2026-09-19) |
| 停手按钮 | 主动结束轮次 | 左键 | 按钮下压 + AP→RAP 飞行数字 | `settle_batch([stop])`(**经排雷玩法批次,不直调行动经济**——单意图帧批次契约) |
| 弃图刷新按钮(雷图右上角) | 当轮就地换图继续挖 | 左键 | 确认微交互(RAP−8 代价显式 + 旧板弃置提示);RAP<8 → 资源面拒绝可见(行动经济 EC13) | `request_refresh`(**Active 相位当场换图继续挖**——AP 不重置、本轮剩 N 次扣减;**上游已修订受理——见布局决策 4/OQ11**) |
| 停手按钮 | 主动结束轮次 | 左键 | 按钮下压 + AP→RAP 飞行数字 | 停手随当帧意图批次提交(**经排雷玩法批次,不直调行动经济**——单意图帧批次契约) |
| 弃图刷新按钮(雷图右上角) | 当轮就地换图继续挖 | 左键 | 确认微交互(RAP−8 代价显式 + 旧板弃置提示);RAP<8 → 资源面拒绝可见(行动经济 EC13) | 刷新意图提交(**Active 相位当场换图继续挖**——AP 不重置、本轮剩 N 次扣减;**上游已修订受理——见布局决策 4/OQ11**) |
| 图例按钮 | 开图例 | 左键 | 模态 overlay | 恒可开(图例条目恒在) |
| 结算明细带 | ~~展开回看~~(已随 P-C7 退役——带保留单行摘要,回看归「生涯」) | —— | —— | —— |
| 状态小图标(B 区站桩) | 悬停 | hover | 状态 tooltip(来源+语义+剩余结算次数) | 只读 |
| 胜利 overlay | 下一节点 | 左键 | → 关卡画面(选路枢纽)/ 关卡结算(末节点) | LevelRunner 推进 |
| 胜利 overlay | 下一节点 | 左键 | → 关卡画面(选路枢纽)/ 关卡结算(末节点) | 关卡推进方推进 |
| 失败 overlay | 返回 | 左键 | → 存档/营地 | 冒险落幕 |
**单意图帧纪律**(排雷玩法×6⑥):一帧内 collected 意图整批提交,stop 点击终结当帧收集;F4 语义序仲裁为防御性兜底。悬停预承诺三态光标:移动(箭头)/挖(镐)/封印(印记形)——左键双义(移动 vs 挖)的消歧完全依赖格态一瞥可辨 + 光标区分(误挖不可逆的感知保险)。
@@ -279,18 +279,18 @@
## Events Fired
项目无分析系统;本节 = **呈现层订阅的核心信号**(组合根直连 signal)+ playtest 遥测义务(playtest_logger.gd 已有五类行)。呈现层新遥测(写 playtest JSONL `ux` 行):
项目无分析系统;本节 = **呈现层订阅的核心信号**(组合根直连信号)+ 逐局遥测义务(逐局遥测日志已有五类行)。呈现层新遥测(写入逐局遥测的呈现层行):
| Player Action | Event Fired | Payload / Data |
| 事件(中文名) | 采集内容 | 载荷 / 数据 |
|---|---|---|
| 每轮结束 | `ux_round_input_ratio` | 原始输入动作数∶AP 消耗(行动经济 P4 ≤2 护栏观测,排雷玩法遥测义务) |
| 停手/清图 | `ux_round_exit` | path_tag {stopped, ap_exhausted, cleared}(对齐上游封闭枚举)——弃图率(难度曲线与Boss OQ4)观测 |
| 弃图刷新(挖掘期,非轮出口) | `ux_refresh_attempt` | {result: accepted/rejected_rap/rejected_cap, round_refresh_index: 1..2}——刷新使用(难度曲线与Boss OQ6)与行动经济 OQ3 预警阈值观测;每轮 0–2 次(布局决策 4 cap=2) |
| 拒绝/voided | `ux_reject` | {source: board/resource/phase, sub_reason} |
| 提示触发/关闭 | `ux_hint_shown` | {hint_id: chord/no_adjacent} |
| 呈现订阅(不改核心) | 排雷玩法三事件 / [战斗结算](../systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋)步骤流(9 类行协议,含终局判定行) / battle_over / level_clear | 载荷 schema 成文义务见 §Data Requirements——旧版状态记录 entry 17①(HUD框架硬性要求) |
| 每轮结束 · 轮次输入比遥测 | 原始输入动作数∶AP 消耗(行动经济 P4 ≤2 护栏观测,排雷玩法遥测义务) | —— |
| 停手/清图 · 轮次出口遥测 | 弃图率(难度曲线与Boss OQ4)观测;出口路径对齐上游封闭枚举 | 出口路径标签 {停手 / AP 耗尽 / 清图} |
| 弃图刷新(挖掘期,非轮出口) · 刷新尝试遥测 | 刷新使用(难度曲线与Boss OQ6)与行动经济 OQ3 预警阈值观测;每轮 0–2 次(布局决策 4 cap=2) | {受理结果: 受理 / 拒因 RAP 不足 / 拒因触上限, 本轮第几次刷新: 1..2} |
| 拒绝/voided · 拒绝遥测 | 拒绝来源(板面/资源/相位三源)与细分原因 | {拒绝来源: 板面/资源/相位, 细分原因} |
| 提示触发/关闭 · 提示展示遥测 | 提示类型 | {提示类型: chord 提示 / 无相邻可挖格} |
| 呈现订阅(不改核心) | 排雷玩法三事件 / [战斗结算](../systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋)步骤流(9 类行协议,含终局判定行) / 战斗结束 / 关卡完成 | 载荷 schema 成文义务见 §Data Requirements——旧版状态记录 entry 17①(HUD框架硬性要求) |
**持久状态写入**全部经组合根唯一路径(settle_batch / request_refresh / runner 推进)——UI 层禁直调核心写(架构七原则"依赖单向组合根")。
**持久状态写入**全部经组合根唯一路径(意图批次提交 / 刷新意图提交 / 关卡推进)——UI 层禁直调核心写(架构七原则"依赖单向组合根")。
---
@@ -302,13 +302,13 @@
| 挖掘→结算 | 明细带自底展开(150ms)+ 棋盘去饱和 + 金橙色相偏移 + 阶段指示翻转 | §2.2 色彩转金橙主导、饱和拉高、明度不变(状态区分经饱和/色相——art-bible §2 合规化 2026-09-12) |
| 结算逐行兑现 | 光带自棋盘行起点横扫 → 开格化箭雨/印记化暴击弹道飞向敌人立绘 → 受击闪白 + 血条直角递减 | §2.2 承载元素;因果全程可见可归因(P2) |
| 清图换新图 | 金粒喷泉 3–5s → 旧图碎裂淡出 → 新图 install 淡入 | §2.3 短促丰收不拖节奏 |
| RAP 清零(battle_over) | RAP 数字滚动归零(D 区 AP 条)+ 「随战斗结束消散」微文案 | 行动经济可见反馈义务 |
| RAP 清零(战斗结束) | RAP 数字滚动归零(D 区 AP 条)+ 「随战斗结束消散」微文案 | 行动经济可见反馈义务 |
| 敌人死亡 | 血条直角递减至零 → 卡体灰化 + 碎裂退场(禁瞬消) | 敌人系统资产下限(同等 blocking);动画密度归战斗表现 |
| 状态图标行全清(battle_over) | 状态逐枚化光收回(B 区站桩图标行)+ 「状态随战斗结束消散」微文案 | 增益状态×4④;RAP 清零同款先例 |
| 状态图标行全清(战斗结束) | 状态逐枚化光收回(B 区站桩图标行)+ 「状态随战斗结束消散」微文案 | 增益状态×4④;RAP 清零同款先例 |
| ~~关卡收束清库~~ | 义务随秘宝过渡形态退役消解——现行形态 = 营地同调装配、整局冒险生效,无关卡域清库面(秘宝.md) | —— |
| 胜利 | 蜡封自上落下弹跳定格 → 碎砖拼纹章 → overlay 暖金渐显 | §2.4 克制不狂欢 |
| 失败 | 全屏明度不变转暮蓝色相 → 印记化光点 800ms 逐枚收回 → overlay | §2.5 最静一拍 |
| 减动效选项 | 上述全部动画提供时长减半/直接跳终态开关(基线权威 = HUD框架「可访问性基线」节;开关承载 = 设置面(迭代 8 卡④已转正,settings_overlay)——2026-09-27 拍板不另立无障碍专项文档) | 动议:结算逐行兑现为信息载体不可整体跳过,可加速 |
| 减动效选项 | 上述全部动画提供时长减半/直接跳终态开关(基线权威 = HUD框架「可访问性基线」节;开关承载 = 设置面(迭代 8 卡④已转正)——2026-09-27 拍板不另立无障碍专项文档) | 动议:结算逐行兑现为信息载体不可整体跳过,可加速 |
---
@@ -316,24 +316,24 @@
| Data | Source System | Read / Write | Notes |
|---|---|---|---|
| 棋盘格态/数字/可挖域 | 排雷玩法 只读面(query) | Read | 呈现刷新面 = 排雷玩法 三事件信号(载荷 schema 成文——旧版状态记录 entry 17①) |
| BFS 移动路径 | 排雷玩法 `compute_move_path` | Read | 布局决策 3 合法性指示消费 |
| 拒绝原因 | 排雷玩法 `sub_reason` 封闭枚举 + 行动经济 资源面 | Read | 三源(board/resource/phase)映射文案——呈现层契约成文;资源面原因无上游载荷(行动经济 仅 bool + debug 诊断),客户端按动作上下文推断 |
| AP / RAP / 本轮刷新计数 | 行动经济 | Read | 常显;刷新入口可用性 = RAP 读数客户端预判(RAP≥8)+ `request_refresh` 返回值(行动经济 无 `can_request_refresh` API——仅 bool 返回 + 只读观测量;行动经济 EC13 拒绝合法可见) |
| 棋盘格态/数字/可挖域 | 排雷玩法 只读查询面 | Read | 呈现刷新面 = 排雷玩法 三事件信号(载荷 schema 成文——旧版状态记录 entry 17①) |
| BFS 移动路径 | 排雷玩法 路径规划只读面 | Read | 布局决策 3 合法性指示消费 |
| 拒绝原因 | 排雷玩法 细分原因封闭枚举 + 行动经济 资源面 | Read | 三源(板面/资源/相位)映射文案——呈现层契约成文;资源面原因无上游载荷(行动经济仅回受理与否,细分原因仅调试诊断可见),客户端按动作上下文推断 |
| AP / RAP / 本轮刷新计数 | 行动经济 | Read | 常显;刷新入口可用性 = RAP 读数客户端预判(RAP≥8)+ 刷新意图提交的受理回执(行动经济 无刷新可用性预查询——仅受理与否的回执 + 只读观测量;行动经济 EC13 拒绝合法可见) |
| 结算流水行(9 类封闭协议) | [战斗结算](../systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋) 流水协议 | Read | 逐行来源标注(P2);未生效类行(奖励未生效)聚合计数呈现 |
| 判定 verdict | 战斗结算 判定段 | Read | 终局画面数据锚 |
| 敌单位 hp/顺位/摇定动作(pending_skill/type/name)/敌方增益/enemy_id/存活 | 敌人系统 只读面(经战斗结算呈现快照) | Read | 意图线索映射全局恒定(敌人系统×4②,技能池批三档口径);**despawn 前捕获**(旧版状态记录 entry 17③——缺陷②教训) |
| 状态效果投影(含空态/极性/溢出) | 增益状态 投影口径 | Read | 极性映射数据源 = 战斗结算 SettlementTable 效果语义,非 magnitude 符号(增益状态×③) |
| 已开格奖励身份(奖励徽章) | 地图战斗资源 `query_identity`(经 board_view 身份解析只读回调,组合根注入) | Read | 已开格身份常读——挖掘期 Active 相位内有效;reward_id 全局恒定、禁止重掷;徽章绘制优先级见 §Component Inventory BoardView 行 |
| 节点图/当前节点/HP 携带 | 关卡节点地图 lite · LevelRunner | Read | 关卡画面(独立屏)节点态呈现(战斗屏零进度承载) |
| 意图提交 | 排雷玩法 | **Write** | `settle_batch`(stop 亦经此——不直调行动经济) |
| 弃图刷新 | 行动经济 | **Write** | `request_refresh`(挖掘期 Active 当场受理——布局决策 4 2026-09-12 上游已落稿;战斗结算 `refresh_board` 编排承载) |
| 节点推进 | LevelRunner | **Write** | 胜利 overlay「下一节点」 |
| 终局画面数据锚 | 战斗结算 判定行(流水行协议) | Read | 「终局判定行 = 胜负画面的数据锚」(战斗结算 UI Requirements);despawn 前状态可见性纪律 = 旧版状态记录 entry 17③(销毁前捕获、**载荷数据自包含**、禁呈现层回读核心生命周期状态);若需独立终局快照信号,须回战斗结算 GDD 修订补登记(战斗结算 现无 `settlement_snapshot` 契约——2026-09-12 评审修正) |
| 判定胜负 | 战斗结算 判定段 | Read | 终局画面数据锚 |
| 敌单位 生命/顺位/摇定动作(技能标识·类型·名称)/敌方增益/敌单位标识/存活 | 敌人系统 只读面(经战斗结算呈现快照) | Read | 意图线索映射全局恒定(敌人系统×4②,技能池批三档口径);**销毁前捕获**(旧版状态记录 entry 17③——缺陷②教训) |
| 状态效果投影(含空态/极性/溢出) | 增益状态 投影口径 | Read | 极性映射数据源 = 战斗结算效果表语义,非幅度符号(增益状态×③) |
| 已开格奖励身份(奖励徽章) | 地图战斗资源 身份解析只读回调(经棋盘视图,组合根注入) | Read | 已开格身份常读——挖掘期 Active 相位内有效;reward_id 全局恒定、禁止重掷;徽章绘制优先级见 §Component Inventory 棋盘视图行 |
| 节点图/当前节点/HP 携带 | 关卡节点地图轻量读面 · 关卡推进方 | Read | 关卡画面(独立屏)节点态呈现(战斗屏零进度承载) |
| 意图提交 | 排雷玩法 | **Write** | 意图批次提交(stop 亦经此——不直调行动经济) |
| 弃图刷新 | 行动经济 | **Write** | 刷新意图提交(挖掘期 Active 当场受理——布局决策 4 2026-09-12 上游已落稿;战斗结算的挖掘期刷新编排承载) |
| 节点推进 | 关卡推进方 | **Write** | 胜利 overlay「下一节点」 |
| 终局画面数据锚 | 战斗结算 判定行(流水行协议) | Read | 「终局判定行 = 胜负画面的数据锚」(战斗结算 UI Requirements);销毁前状态可见性纪律 = 旧版状态记录 entry 17③(销毁前捕获、**载荷数据自包含**、禁呈现层回读核心生命周期状态);若需独立终局快照信号,须回战斗结算 GDD 修订补登记(战斗结算 现无结算快照契约——2026-09-12 评审修正) |
**架构注记**:UI 不拥有任何游戏状态——全部读经核心只读面,全部写经组合根。呈现层信号载荷 schema 须在《HUD框架》成文(旧版状态记录 entry 17①,缺项即 blocking);场景级 headless 测试进 AC(entry 17②);覆盖层层级断言(缺陷⑤——任何模态覆盖层必须有"打开时遮挡物隐藏"断言)。
**更新触发注记(2026-09-12 评审增补——防实现层等待不存在的信号,旧版状态记录 entry 17 教训同类)**:封印与移动成功反馈**零事件外发**(排雷玩法发射面封闭)——经意图调用 `ActionOutcome` 返回值命令式驱动;AP/RAP 读数:行动经济无推送信号——组合根每次调用返回后重查;状态效果:增益状态为纯被动状态池、零信号——状态栏刷新绑战斗结算的编排完成时点;奖励徽章:地图战斗资源 身份解析经 `query_identity` 只读回调(组合根注入 board_view),已开格揭显时查询——写路径回执后重查。
**更新触发注记(2026-09-12 评审增补——防实现层等待不存在的信号,旧版状态记录 entry 17 教训同类)**:封印与移动成功反馈**零事件外发**(排雷玩法发射面封闭)——经意图调用的返回值命令式驱动;AP/RAP 读数:行动经济无推送信号——组合根每次调用返回后重查;状态效果:增益状态为纯被动状态池、零信号——状态栏刷新绑战斗结算的编排完成时点;奖励徽章:地图战斗资源 身份解析经只读回调(组合根注入棋盘视图),已开格揭显时查询——写路径回执后重查。
---
@@ -355,7 +355,7 @@
- **源语言中文(CJK)**:运行时默认字体无 CJK 字形——**CJK 字体随包为硬性前置**(已锁),实现 AC 覆盖
- **按钮文案单行约束**:「停手」「弃图刷新」——按钮宽度按 4 汉字上限设计;译为英文("Hold"/"Reroll")不超 1.6× 不破版;德语长词("Aufgeben+Neu"类复合词)风险 HIGH——弃图刷新按钮允许两行或图标+缩写
- **明细带行文案**:来源标注格式「{行为} {值} → {目标}(来源)」为模板插值,最长 token = 来源标签(4 汉字,如「清图奖励」「封印未中」——settlement source_label_map 封闭枚举);行模板预留 40% 膨胀宽度(固定槽高 + clip 兜底)
- **明细带行文案**:来源标注格式「{行为} {值} → {目标}(来源)」为模板插值,最长 token = 来源标签(4 汉字,如「清图奖励」「封印未中」——战斗结算的来源标签封闭枚举);行模板预留 40% 膨胀宽度(固定槽高 + 裁剪兜底)
- **数字格式**:全部整数,无本地化格式需求;AP 点阵为图形载体不依赖文本
- **术语表锚定**:封印/雷/停手/弃图刷新/轮次/结算 已在 GDD 体系内定名,译文须同步 `design/gdd/术语表.md`
@@ -374,11 +374,11 @@
**交互与反馈**
- [ ] 挖/移/封印/停手/刷新全部操作纯鼠标可完成;stop 意图经 `settle_batch` 提交(代码走查 + 探针断言)
- [ ] 挖/移/封印/停手/刷新全部操作纯鼠标可完成;stop 意图经意图批次提交(代码走查 + 探针断言)
- [ ] 每次拒绝(棋盘面/资源面/相位)玩家可感知且两源可区分;voided(至少 stop 作废)可感知(排雷玩法×6⑥、行动经济双源)
- [ ] 弃图刷新消耗 RAP 8 点、本轮上限 2 次可见(按钮文案实时「剩 N 次」;上限已随行动经济 2026-09-12 修订生效);RAP<8 资源面拒绝可见(行动经济 EC13);确认交互与常规确认不同位;换图后 AP 不重置、剩余次数扣减可见(**上游已修订受理——2026-09-12 布局决策 4 落稿**)
- [ ] battle_over 时 RAP 清零有可见反馈(行动经济);~~关卡收束清库反馈~~(义务随秘宝过渡形态退役消解——现行 = 营地同调装配整局生效,秘宝.md)
- [ ] battle_over 时状态图标行全清有可见反馈(B 区站桩逐枚化光 + 微文案)(增益状态×④)
- [ ] 战斗结束时 RAP 清零有可见反馈(行动经济);~~关卡收束清库反馈~~(义务随秘宝过渡形态退役消解——现行 = 营地同调装配整局生效,秘宝.md)
- [ ] 战斗结束时状态图标行全清有可见反馈(B 区站桩逐枚化光 + 微文案)(增益状态×④)
- [ ] 敌人死亡瞬间可辨识(卡体灰化 + 碎裂退场,禁瞬消);战斗段短路被掐灭的重击由行序可推断(敌人系统资产下限)
**信息与归因**
@@ -388,17 +388,17 @@
- [ ] 状态效果:极性呈现映射成文且非 magnitude 符号;空态渲染成文(裁决:图标行隐藏——B 区站桩血条下零图标时不占位);满层溢出经明细行可见(增益状态×①③④)
- [ ] 图例面板条目恒在可随时回看、非模态提示不劫持输入
- [ ] 零合法板(棋盘生成 EC5 降级)出现时玩家侧诚实提示(toast,非静默)
- [ ] 效果行 value 为单次贡献值,禁止与 pool_value(池合成值)相加呈现;零值伤害行可见不被吞;衰减行按聚合计数呈现(战斗结算 呈现细则)
- [ ] 效果行数值为单次贡献值,禁止与池合成值相加呈现;零值伤害行可见不被吞;衰减行按聚合计数呈现(战斗结算 呈现细则)
- [ ] 未生效类行(奖励未生效)携带形状冗余(icon/划线),非色相独载
- [ ] 奖励徽章绘制优先级:封印印记之下、变异纹带之上、不进数字区;拾取瞬间 tier 档位可读(地图战斗资源 H1)
**场景级测试**(旧版状态记录 entry 17②③,缺项即 blocking)
- [ ] 场景级 headless 测试:真实实例化战斗屏场景 + 驱动完整对局 + 断言零脚本错误(ui_click_probe 模式扩展)
- [ ] 场景级 headless 测试:真实实例化战斗屏场景 + 驱动完整对局 + 断言零脚本错误(呈现层点击探针模式扩展)
- [ ] 任何模态覆盖层(图例/胜利/失败——明细回看已退役)有「打开时遮挡物隐藏/输入锁定」场景级断言(缺陷⑤对照)
- [ ] 动态区全部固定槽高 + clip_contents——悬停文案换行不推挤布局(缺陷①回归)
- [ ] 动态区全部固定槽高 + 裁剪兜底——悬停文案换行不推挤布局(缺陷①回归)
- [ ] CJK 字体随包,全部中文文案渲染非豆腐块
- [ ] 敌人 despawn 后呈现层不回读核心生命周期状态(快照纪律,缺陷②回归)
- [ ] 敌人销毁后呈现层不回读核心生命周期状态(快照纪律,缺陷②回归)
---
@@ -407,14 +407,14 @@
1. **Player journey map——已完成(2026-09-27 欠账处置拍板:不建)**:实现前补建的前提随战斗屏实装失效;情绪曲线事实源 = art-bible §2 能量档,真人体验观测与结论回流 = [体验验证清单](../../../体验验证清单.md)
2. **无障碍专项文档——已完成(2026-09-27 拍板:不另立 design/accessibility-requirements.md)**:基线(对比/色弱/字号/闪烁/减动效/纯鼠标/中文字体)权威 = [HUD框架](../systems/表现与支撑/HUD框架.md)「可访问性基线」节;正式分层(文本缩放/色盲模式/按键重映射)归 [设置与本地化](../systems/表现与支撑/设置与本地化.md) 待设计问题清单 #1(设置项全集裁决时定);本 spec §Accessibility 为呈现侧落地承诺
3. **interaction-patterns.md——已建成**(2026-09-12 /team-ui 批当日落稿,本条「未建」系过期陈述):本 spec 引入的四 pattern(双源拒绝反馈/逐行兑现明细带/悬停预承诺光标/点阵资源显示)均已入库成文(pattern 1/3/4/5)
4. **战斗表现美术测试**(game-concept 已登记,战斗表现批次前强制):本 spec 的常驻双舞台分屏(布局决策 1)是测试的布局输入——**敌人卡形态已裁决(2026-09-20 用户看对照样张拍板):全站桩式(无框立绘+底座),主角同样站桩、状态小图标挂血条下,卡片式整体退役**;本 spec 已随裁决改写(原"按卡片式起草"条款作废),站桩式不改变分区结构。对照样张存档 `production/mockups/enemy-card-vs-standee-mockup.html`
4. **战斗表现美术测试**(game-concept 已登记,战斗表现批次前强制):本 spec 的常驻双舞台分屏(布局决策 1)是测试的布局输入——**敌人卡形态已裁决(2026-09-20 用户看对照样张拍板):全站桩式(无框立绘+底座),主角同样站桩、状态小图标挂血条下,卡片式整体退役**;本 spec 已随裁决改写(原"按卡片式起草"条款作废),站桩式不改变分区结构。对照样张已存档(敌人卡与站桩式对照样张)
5. **移动动画形态**(布局决策 3):≤150ms 短滑为推荐值,playtest 观测「移动太瞬/太拖」反馈后调
6. **明细带挖掘期是否常驻上轮摘要**:常驻(现方案)vs 结算后即收起——playtest 观测回看频率
7. **Gamepad 导航序**:Partial 支持(非 MVP 门禁)——焦点环顺序待 gamepad 批次定
8. **NodeOverlay / 关卡结算屏——已完成(2026-09-27 欠账处置拍板;节点奖励屏部分被 2026-09-29 迭代 7 取代)**:关卡结算屏 spec 已建 [level-clear.md](level-clear.md)(本 spec 只锁出口锚点不变);节点奖励屏 spec 已出生 [node-reward.md](node-reward.md) v1.0(原「不立独立 spec、随秘宝内容重定批交付」拍板随之取代;NodeOverlay 现行:恢复点全量服务、奖励点=三选一构筑点)
9. **TunePanel 退役计划——已完成(迭代 15 卡①,2026-10-05)**:TunePanel 类整体吸收退役入调试浮窗 DebugOverlay(DS_DEBUG=1 门控);正式侧归元进度(天赋树)不变(门控表述属当期留痕——调试入口现发布态恒隐,现行口径见元素表「调试浮窗」行与「调试变体」行)
8. **NodeOverlay / 关卡结算屏——已完成(2026-09-27 欠账处置拍板;节点奖励屏部分被 2026-09-29 迭代 7 取代)**:关卡结算屏 spec 已建 [level-clear.md](level-clear.md)(本 spec 只锁出口锚点不变);节点奖励屏 spec 已出生 [node-reward.md](node-reward.md) v1.0(原「不立独立 spec、随秘宝内容重定批交付」拍板随之取代;节点覆盖层现行:恢复点全量服务、奖励点=三选一构筑点)
9. **调参面板退役计划——已完成(迭代 15 卡①,2026-10-05)**:调参面板类整体吸收退役入调试浮窗(调试开关=1 门控);正式侧归元进度(天赋树)不变(门控表述属当期留痕——调试入口现发布态恒隐,现行口径见元素表「调试浮窗」行与「调试变体」行)
10. **提示文案定稿**:chord 提示/空态文案归实现期文案 pass,本 spec 只锁必含要点与形态约束
11. **弃图刷新上游修订(已落稿 2026-09-12,布局决策 4)**:行动经济(Active 相位受理 + 每轮上限 2 次 + Waiting 代理退役 + 旧旗作废裁决 + 时间税失效预警)、排雷玩法(Active·仅刷新路径装板受理)、战斗结算(stopped/ap_exhausted 恒 same_board + `refresh_board` 挖掘期刷新编排;AC-29 改写/AC-30 恒 same_board)、registry `rap_rules` 同步、旧版 systems-index 修订块登记。遗留观察项:当场刷新的节奏健康由行动经济 OQ3 弃图率/刷新率预警承载,playtest 复核
11. **弃图刷新上游修订(已落稿 2026-09-12,布局决策 4)**:行动经济(Active 相位受理 + 每轮上限 2 次 + Waiting 代理退役 + 旧旗作废裁决 + 时间税失效预警)、排雷玩法(Active·仅刷新路径装板受理)、战斗结算(停手与 AP 耗尽两出口恒同盘不变 + 挖掘期刷新编排;AC-29 改写/AC-30 恒同盘不变)、系统索引的刷新规则同步、旧版 systems-index 修订块登记。遗留观察项:当场刷新的节奏健康由行动经济 OQ3 弃图率/刷新率预警承载,playtest 复核
12. **教学引导缺口挂靠(成文时教学引导 GDD 尚未建,留痕)**:挖到雷 = 敌方优势而非死亡(排雷玩法登记「经典扫雷玩家最大预期违背」)、旗挡链(连锁止于旗属正常)、首次蓄力姿态一次性提示(敌人系统)——本屏 toast 体系为落点候选,随教学引导批次定
13. **敌方 AC 展示——已终裁完成(2026-09-26)**:用户终裁——敌方 AC 数值**全屏不展示**(任何区均不直接写上);护甲类型改**图标方式**展示(形状+色相双通道,终稿图标资产归美术批);敌人站桩底座下名字行退回**纯名字 + 护甲类型图标**。与旧「克制对策可读性义务」(敌人技能池批)的关系 = **义务降级承载**:类型保留(图标可读,对策判断仍可做)、数值退役(不再直接展示);敌人技能池批相关义务措辞由并行代码批同步。我方 AC 仍按 2026-09-26 二轮拍板保留于 C 区攻击数据框(唯一展示面)
14. **GP/钥石迁出战斗屏后的展示面归属——已拍板完成(2026-09-26 二轮)**:GP = 关卡画面常驻总量 + 战斗总结结算(总量+增量);钥石 = 冒险总结结算 + 营地。呈现 spec 已出生:[settlement-summary.md](settlement-summary.md) v1.0(2026-09-30——两面分节轻量 spec,本 OQ 为其命名与分工依据;「战斗结算画面」「结算画面」旧措辞随 spec 命名完成退役)
@@ -437,7 +437,7 @@
| 战斗结算×3 | ①高光行强调呈现(封印标中金框行/清图 H2 金框行)②完美封印呈现形态 ③棋盘生成 EC5 零合法板提示/补偿/回退形态(toast 提示;补偿/回退不提供——三形态选型留痕 2026-09-12) | §States 高光/清图 + §States 拒绝子态 + §AC;注:结算明细屏 = 战斗结算 UX Flag 事项(本 spec 即其 /ux-design 产物),非 战斗结算×3 状态记录 |
| 敌人系统×4 | 意图映射/恒定/顺位/敌方池 | §Component Inventory 敌人站桩立绘 + **意图线索映射目录(敌人系统×4① 成文占位,资产定稿归战斗表现)** + AC |
| 增益状态×4 | 常显+空态/来源标注/溢出/去留 | §States 空态 + §AC |
| 地图战斗资源×5 | 身份恒读/明细行/清图强调(旧版状态记录五条中「窗口」「清空反馈」随格面资源批下线——清空反馈义务后载秘宝背包、复随秘宝过渡形态退役消解(现行 = 营地同调装配,秘宝.md)) | §Component Inventory BoardView 奖励徽章 + §States 清图/高光 + §Data Requirements query_identity + AC |
| 地图战斗资源×5 | 身份恒读/明细行/清图强调(旧版状态记录五条中「窗口」「清空反馈」随格面资源批下线——清空反馈义务后载秘宝背包、复随秘宝过渡形态退役消解(现行 = 营地同调装配,秘宝.md)) | §Component Inventory 棋盘视图奖励徽章 + §States 清图/高光 + §Data Requirements 身份解析只读回调 + AC |
| 棋盘生成 | EC5 零合法板诚实呈现(数据面经 战斗结算×3③ 上抛) | §States 拒绝子态(toast)+ AC |
| 敌人系统资产下限 | 受击反馈/死亡表现/顺位标记 | §Transitions 受击 + §States 敌人死亡呈现(禁瞬消)+ §Component 顺位徽标;呈现语义在本 spec(同等 blocking),动画密度归战斗表现 |
+5 -5
View File
@@ -1,6 +1,6 @@
# 营地场景 UX spec(camp)
> 状态:v2.1(2026-10-24 营地场景图美术设计段;取代旧「四柜台覆盖层」形态)
> 状态:v2.1(现行)
> 事实源:本 spec(呈现)+ [元进度](../systems/跨局循环/元进度.md)(机制)
> 美术画法:[art-bible](../../art/art-bible.md) §6.2/§7.5;素材命名与路径:[asset-path-map](../../art/asset-path-map.md)
> 相邻:[level-map.md](level-map.md)(主菜单语境)
@@ -16,7 +16,7 @@
| 大门(半开的门扇,门洞内一条通向远处的小路) | 冒险 | 点大门永远先出确认:有未完冒险=三出口(继续上一段/开始新冒险/取消);无=是否开始新冒险 |
| 锻炉·铁砧 | 锻造工坊 | **未解锁=禁用态**(降明度+去饱和) |
| 宝箱 | 秘宝匣 | **未解锁=禁用态**(同上) |
| 帐篷旁笔记本 | 生涯记录 | 生涯页返回钮文案**禁含「营地」字样**(`ui_struct_probe.gd` nojump 禁词表) |
| 帐篷旁笔记本 | 生涯记录 | 生涯页返回钮文案**禁含「营地」字样**(由呈现层结构校验兜底,口径见测试规约) |
| 木桩 | 天赋树 | |
| 布告板 | 奖励格图鉴 | 内容冻结未激活,点进看占位——**不是禁用态** |
| 篝火 | 离开营地回主菜单 | **必须二次确认**;命中区只含火堆、不含火焰 |
@@ -30,7 +30,7 @@
## 点选反馈(根态)
悬停=**轮廓亮边 + 浮动**(浮动须整像素吸附)+物件**名牌**(物件下方 8px 居中,FS_HINT 14,对比 ≥4.5:1);按下=位移 1px;禁用=降明度+去饱和;已解锁=常态。**四态零新素材**(全部程序化)。
悬停=**轮廓亮边 + 浮动**(浮动须整像素吸附)+物件**名牌**(物件下方 8px 居中,提示字号 14,对比 ≥4.5:1);按下=位移 1px;禁用=降明度+去饱和;已解锁=常态。**四态零新素材**(全部程序化)。
命中区:七件两两不相交、不越出画面、**不侵入顶栏禁区(y ≤ 48)**。
@@ -40,10 +40,10 @@
## 叠层与开合
各界面开合走模态栈单口,层序入 `LAYER_CONTRACT`。**承载形态(独立全屏页 vs 单一内页切换)与叠层规则归卡④ §9 代拍板域,本 spec 不预设值**;派生规则:独立全屏页=场景根隐藏/单一内页切换=场景根留底(「缩放虚化」为第三形态,禁批内自选)。ESC 浮窗(返回主菜单/设置/退出游戏)归卡⑤。
各界面开合走模态栈单口,层序按模态栈契约登记。**承载形态(独立全屏页 vs 单一内页切换)与叠层规则归卡④ §9 代拍板域,本 spec 不预设值**;派生规则:独立全屏页=场景根隐藏/单一内页切换=场景根留底(「缩放虚化」为第三形态,禁批内自选)。ESC 浮窗(返回主菜单/设置/退出游戏)归卡⑤。
## 口径
- 呈现数据源=MetaProgression 只读投影经组合根喂入;本层不持有系统资源、不算价。
- 呈现数据源=元进度系统只读投影经组合根喂入;本层不持有系统资源、不算价。
- 「最近冒险」条带已撤下(卡④ Q4=甲),逐局历史回看归生涯。
- 秘宝匣界面内部呈现(解锁面+同调装配段)保留为附录,待该界面立独立 spec 后迁出。
+23 -23
View File
@@ -2,7 +2,7 @@
> **Status**: Complete(核心 8 成文〔2 号已退役留档〕+ 12 目录占位)
> **Author**: user + ux-designer
> **Last Updated**: 2026-10-15(简明技术中文用语规范批:词面修正 6 处)
> **Last Updated**: 2026-10-29
> **Template**: Interaction Pattern Library
> **来源**: `design/gdd/ux/battle.md`(2026-09-12 /ux-review APPROVED)已拍板内容的成文固化——本库不引入新设计决策
@@ -29,18 +29,18 @@
| 6 | 模态 overlay 层级纪律 | Modal | **成文 ✓** |
| 7 | 破坏性确认异位 | Feedback | **成文 ✓** |
| 8 | 禁用态即理由 | Feedback | **成文 ✓** |
| 9 | 常驻意图徽标 | Data Display | **已实现**(enemy_card_view.gd——规格全文待补) |
| 9 | 常驻意图徽标 | Data Display | **已实现**(意图徽标呈现件——规格全文待补) |
| 10 | 一次性非模态教学提示 | Feedback | **已实现**(chord 提示——规格全文待补) |
| 11 | tooltip 规范 | Feedback | **已实现**(状态/道具悬停——规格全文待补) |
| 12 | 单意图帧批次提交 | Input | **已实现**(main.gd 组合根——规格全文待补) |
| 13 | 状态效果槽 | Data Display | **已实现**(status_slot_row.gd——规格全文待补;载体变更留档:C 区四槽已退役,现役载体=B 区站桩伴随件) |
| 14 | 步进进度条 | Navigation | **已退役留档**(level_strip_view 已删,节点态承载进度) |
| 15 | 移动路径预览 | Input | **已实现**(board_view.gd BFS 蓝点——规格全文待补) |
| 16 | 清图/换图演出编排 | Feedback | **已实现·占位级**(board_fx_view.gd 金粒彩纸——规格随战斗表现 美术批补) |
| 17 | 胜利/失败终局编排 | Feedback | **已实现·占位级**(battle_end_overlay.gd——规格随战斗表现补) |
| 12 | 单意图帧批次提交 | Input | **已实现**(组合根——规格全文待补) |
| 13 | 状态效果槽 | Data Display | **已实现**(状态图标行呈现件——规格全文待补;载体变更留档:C 区四槽已退役,现役载体=B 区站桩伴随件) |
| 14 | 步进进度条 | Navigation | **已退役留档**(步进进度条呈现件已删,节点态承载进度) |
| 15 | 移动路径预览 | Input | **已实现**(棋盘视图 BFS 蓝点——规格全文待补) |
| 16 | 清图/换图演出编排 | Feedback | **已实现·占位级**(棋盘演出呈现件 金粒彩纸——规格随战斗表现 美术批补) |
| 17 | 胜利/失败终局编排 | Feedback | **已实现·占位级**(战斗终局覆盖层——规格随战斗表现补) |
| 18 | Boss 遭遇演出 | Feedback | **已实现·占位级**(紫赤影子——规格随战斗表现补) |
| 19 | 库存常读列表 | Data Display | **占位失效**(所记载体 inventory_panel_view.gd 从未入库〔git 全史零记录,2026-10-09 复核〕;库存面已随秘宝过渡形态退役——C 区现行秘宝槽=装配呈现面、重接归装配面批次,见 battle.md 组件清单) |
| 20 | 标准控件组(button/progress bar/list) | Control | **已实现**(ui_kit.gd 直角细线/凸圆角——规格全文待补) |
| 19 | 库存常读列表 | Data Display | **占位失效**(所记载体从未入库;库存面已随秘宝过渡形态退役——C 区现行秘宝槽=装配呈现面、重接归装配面批次,见 battle.md 组件清单) |
| 20 | 标准控件组(button/progress bar/list) | Control | **已实现**(标准控件组 直角细线/凸圆角——规格全文待补) |
MVP 未使用标准控件(不入库):toggle / dropdown / input field / tab bar——战斗屏无此需求;TunePanel slider 为调试专用。
@@ -53,11 +53,11 @@ MVP 未使用标准控件(不入库):toggle / dropdown / input field / tab
**Category**: Feedback
**Used In**: 战斗屏(棋盘/资源全部意图动作)
**Description**: 玩家意图被核心拒绝时,反馈必须同时做到:(a) 每次拒绝玩家可感知(防静默拒绝读感欺骗);(b) 来源可区分——棋盘面(排雷玩法判,携 sub_reason 封闭枚举)/资源面(行动经济判,客户端推断)/相位(排雷玩法 ActionOutcome)三源各异;(c) 图标+文案双通道,非色相独载。
**Description**: 玩家意图被核心拒绝时,反馈必须同时做到:(a) 每次拒绝玩家可感知(防静默拒绝读感欺骗);(b) 来源可区分——棋盘面(排雷玩法判,携细分原因封闭枚举)/资源面(行动经济判,客户端推断)/相位(排雷玩法意图回执)三源各异;(c) 图标+文案双通道,非色相独载。
**Specification**:
- 触发:`ActionOutcome{accepted=false, reject_reason, sub_reason}` **返回值驱动**(拒绝无事件外发——排雷玩法发射面封闭,实现层禁止等待拒绝信号)
- 反馈映射:board_face → 目标格危险红 `#A8321F` 边框闪(拒绝语义红族——旗朱→封印紫→封印黑 #000000,2026-09-28 用户拍板现行) + toast 具体原因(sub_reason→文案映射表:not_adjacent/target_revealed/target_concealed/flag_present/flag_absent/no_path/out_of_catalog);resource_face → 对应资源数字脉冲(AP/RAP)+「AP 不足 · 剩 0 点」式文案;phase → toast(结算中/非挖掘期)
- 触发:意图回执(受理标志 + 拒绝原因 + 细分原因)**返回值驱动**(拒绝无事件外发——排雷玩法发射面封闭,实现层禁止等待拒绝信号)
- 反馈映射:棋盘面 → 目标格危险红 `#A8321F` 边框闪(拒绝语义红族——旗朱→封印紫→封印黑 #000000,2026-09-28 用户拍板现行) + toast 具体原因(细分原因→文案映射表:非相邻 / 目标已开格 / 目标未开格 / 该格已有封印 / 该格无封印 / 无可达路径 / 坐标越界);资源面 → 对应资源数字脉冲(AP/RAP)+「AP 不足 · 剩 0 点」式文案;相位 → toast(结算中/非挖掘期)
- 即时性:拒绝当帧呈现;toast 自动消退 2.5s
- **voided 区分**:作废 ≠ 拒绝(零效果零扣费零事件)——须独立文案如「本轮已清图,停手未执行 · 剩余 AP 已作废」,至少 stop 作废可感知
- Accessibility:危险红边框闪为形状+运动通道;文案常驻
@@ -84,11 +84,11 @@ MVP 未使用标准控件(不入库):toggle / dropdown / input field / tab
**Description**: 轮末结算逐行流水实时呈现 + 可回看——「扫雷之因逐行兑现为战果」(P2 归因)的承载面。挖掘期收起为 1 行上轮摘要;结算期展开 84px 实时流;点击开完整回看 overlay。
**Specification**:
- 数据源:[战斗结算](../systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋)步骤流(9 类行封闭协议(现行);公共字段 `type/source_class/origin_cell/round_index/display_name/value/highlight?`);**无来源行 = 断言失败**
- 数据源:[战斗结算](../systems/战斗循环/战斗结算.md#明细流水每一行都能指回你刚才的哪一步棋)步骤流(9 类行封闭协议(现行);公共字段:来源类别 / 来源格 / 轮次 / 显示名 / 数值 / 可空高光标记);**无来源行 = 断言失败**
- 行模板:「{行为} {值} → {目标}(来源)」——来源标注(第 N 轮 · 安全格式);行文案最长 token = 来源标签(4 汉字封闭枚举),模板预留 40% 膨胀宽度
- 聚合纪律:未生效类行(奖励未生效——现行 9 类行协议唯一未生效型,2026-09-20 收敛)按聚合计数呈现(防逐行惩罚轰炸);衰减行聚合计数;效果行 value=单次贡献值、禁与 pool_value(池合成值)相加呈现;零值行可见不吞(免伤轮归因不断点)
- 高亮:highlight 字段 {flag_hit, clear_reward_h2, perfect_broken} → 金框强调;完美封印 = 独立高光行 + 全屏喝彩级反馈。`perfect_broken` 的判据句读作「本板首次标错受检」,不等于完美资格已失——专长「完美保险」可在本场首次标错时豁免,实际资格按有效误标(误标总数 − 豁免数)判定
- 布局:固定槽高 + clip_contents;正文 ≥14px;数值暗底高对比;未生效类行带 icon/划线形状冗余
- 聚合纪律:未生效类行(奖励未生效——现行 9 类行协议唯一未生效型,2026-09-20 收敛)按聚合计数呈现(防逐行惩罚轰炸);衰减行聚合计数;效果行数值 = 单次贡献值、禁与池合成值相加呈现;零值行可见不吞(免伤轮归因不断点)
- 高亮:高亮标记(封印标中、清图奖励、完美破除) → 金框强调;完美封印 = 独立高光行 + 全屏喝彩级反馈。「完美破除」的判据句读作「本板首次标错受检」,不等于完美资格已失——专长「完美保险」可在本场首次标错时豁免,实际资格按有效误标(误标总数 − 豁免数)判定
- 布局:固定槽高 + 裁剪兜底;正文 ≥14px;数值暗底高对比;未生效类行带 icon/划线形状冗余
- 击杀标记呈现(H3 数据源 = 战斗结算流水击杀结果字段)
**When to Use**: 任何「因果可归因」的逐行流水呈现
@@ -101,7 +101,7 @@ MVP 未使用标准控件(不入库):toggle / dropdown / input field / tab
### 4. 悬停预承诺光标(hover pre-commitment cursor)
**Category**: Input
**Used In**: 扫雷图 BoardView
**Used In**: 扫雷图(棋盘视图)
**Description**: 左键双义(已开格=移动 / 未开相邻格=挖)的消歧完全依赖格态一瞥可辨 + 悬停光标区分——**误挖不可逆**(1 AP + 可能触雷)的感知保险。
@@ -130,7 +130,7 @@ MVP 未使用标准控件(不入库):toggle / dropdown / input field / tab
**Specification**:
- 形态:`●●●●●○○○` + 「5/8」;直角细线数据框(信息=直线直角,art-bible §3.3)
- 更新触发:组合根每次调用返回后重查(**行动经济无推送信号**——实现层禁止等待资源变更事件)
- 拒绝反馈:资源不足时数字脉冲(pattern 1 的 resource_face 腿)
- 拒绝反馈:资源不足时数字脉冲(pattern 1 的资源面腿)
- Accessibility:点阵=形状通道、数字=文本通道;对比 ≥4.5:1
**When to Use**: 小整数离散资源(≤16 量级)
@@ -150,7 +150,7 @@ MVP 未使用标准控件(不入库):toggle / dropdown / input field / tab
**Specification**:
- 打开:遮挡物隐藏或禁用 + 输入锁定;单一模态栈(无叠模态)
- 关闭:恢复被遮挡物;关闭按钮/再点入口切换
- 内容:固定槽高 + clip_contents(缺陷①——悬停文案换行禁止推挤布局)
- 内容:固定槽高 + 裁剪兜底(缺陷①——悬停文案换行禁止推挤布局)
- 验收:**场景级断言「打开时遮挡物隐藏/输入锁定」为每个模态 overlay 的强制 AC**(battle.md 场景级测试节)
**When to Use**: 全屏打断级信息、只读回看、仪式性终局
@@ -170,7 +170,7 @@ MVP 未使用标准控件(不入库):toggle / dropdown / input field / tab
**Specification**:
- 弃图刷新:确认微交互显式呈现全部代价(RAP−8 · **旧板封印印记随旧板作废**提示);确认交互位置与常规确认不同位
- 双通道:图标 + 文案冗余
- 拒绝路径:RAP<8 → pattern 1 resource_face(EC13 合法拒绝可见)
- 拒绝路径:RAP<8 → pattern 1 的资源面(EC13 合法拒绝可见)
**When to Use**: 任何消耗资源/不可逆的操作确认
**When NOT to Use**: 无代价操作(直接执行 + 直接反馈)
@@ -189,7 +189,7 @@ MVP 未使用标准控件(不入库):toggle / dropdown / input field / tab
**Specification**:
- 形态:灰置 + tooltip「HP 已满 · 禁选」;点击无效 + 原因 toast 兜底
- 语义区分:满血 = 零收益守卫(禁选、不烧包)≠ 缺血不足(超量 clamp 部分回复,**不**禁选)
- usable_now 由战斗结算组装进窗口载荷(地图战斗资源零跨系统读)——呈现层只消费不推断
- 「当前可用」标记由战斗结算组装进窗口载荷(地图战斗资源零跨系统读)——呈现层只消费不推断
**When to Use**: 任何可见但不可交互的元素
**When NOT to Use**: 完全隐藏的不可用功能(不存在的东西无需解释)
@@ -201,7 +201,7 @@ MVP 未使用标准控件(不入库):toggle / dropdown / input field / tab
## Gaps & Patterns Needed
- **目录 #9–#20 已全部实现**(2026-09-12 战斗屏实现批,冒烟 149/149 + 三探针全绿);规格全文回写 = HUD框架正式化批义务
- 实现期新增技术件(不单独立 pattern,规格归并):去饱和+金橙状态切换 = 逐格共享 ShaderMaterial(明度不变,gl_compatibility 安全);敌人死亡残位 = 卡体灰化+碎裂禁瞬消(归入 #17 终局编排规格)
- 实现期新增技术件(不单独立 pattern,规格归并):去饱和+金橙状态切换 = 逐格共享 ShaderMaterial(明度不变,兼容渲染器下安全);敌人死亡残位 = 卡体灰化+碎裂禁瞬消(归入 #17 终局编排规格)
- **MVP 未使用标准控件**:toggle / dropdown / input field / tab bar(无需求不设占位);TunePanel slider 为调试专用不入库
- **实现偏差规则**:pattern 近似但不完全适配时,实现层禁止静默变体——登记偏差交 ux-designer 复核后回写
+14 -14
View File
@@ -1,8 +1,8 @@
# UX Spec: 关卡结算屏(Level Clear)——提升三选一选择面
> **Status**: v2 义务锁定版(2026-10-01 迭代 10 奖励重构批重写——三件套快照展示退役,改三选一选择交互;呈现形态随实装批定,视觉终稿以表现层样张为前置,见 P1/OQ4;**本批渲染层验证冻结——目检清单顺带交付、实机目检待用户批准**)
> **Status**: v2 义务锁定版
> **Author**: user + ZCode(UX 文档欠账处置批;迭代 10 重写)
> **Last Updated**: 2026-10-15(简明技术中文用语规范批:词面修正 4 处;原标 2026-10-01 滞后于 2026-10-09 两条修订记录,本批一并对齐)
> **Last Updated**: 2026-10-29
> **Platform Target**: PC (Steam)——Keyboard/Mouse 主,全部操作纯鼠标可完成(同 battle.md)
> **Template**: UX Spec
> **来源**: battle.md OQ8 欠账处置(2026-09-27 用户拍板建档)+ 迭代 10 奖励重构批(2026-09-30 用户拍板案丙——三选一/部分回血/钥石挪转,计划书 m3-iter10-loop-plan-2026-09-30.md)
@@ -28,13 +28,13 @@
| 时刻 | 载体(目标形态,迭代 10 实装) | 呈现内容 |
|---|---|---|
| Boss 战胜利(非末关) | 战斗总结结算([settlement-summary.md](settlement-summary.md))→ 确认后进**本屏** | 战利品行含钥石增量行 → 本屏:部分回血反馈 + 三选一三卡 |
| 非末关完成(本屏默认态) | 三选一覆盖层(curio_pick_overlay——与奖励节点共用面) | 部分回血兑付行 + 三张专长选项卡(点选+确认+兑付反馈) |
| 非末关完成(本屏默认态) | 三选一覆盖层(与奖励节点共用面) | 部分回血兑付行 + 三张专长选项卡(点选+确认+兑付反馈) |
| 末关完成 / 失败 / 放弃 | 冒险结算(复用战斗终局 overlay) | 冒险摘要五件事 + 钥石入账明细——**相邻域**(冒险落幕面,非本屏职责) |
## Navigation Position
```
战斗屏 ──胜利(末节点 Boss)──▶ 战斗总结结算(GP/钥石增量行)──确认──▶ 【关卡结算(level_clear)】
战斗屏 ──胜利(末节点 Boss)──▶ 战斗总结结算(GP/钥石增量行)──确认──▶ 【关卡结算(关卡完成)】
├─ 非末关:回血反馈 + 三选一点选兑付 → 下一关开始(→ 关卡画面选路)
└─ 末关完成:直通冒险结算(相邻域)→ 返回存档/营地
失败不经本屏(战斗屏失败分支直达冒险落幕)。
@@ -47,7 +47,7 @@
| 方向 | 触发 | 携带语境 |
|---|---|---|
| 进入 | 战斗总结结算确认 → 关卡收束(先清库后宣布)→ 非末关兑付部分回血 → 三选一候选呈现(bonus_pick 信号) | 三候选(件 id + 名称 + 效果行值);部分回血前后生命读数;GP 账本余额(跨关延续) |
| 进入 | 战斗总结结算确认 → 关卡收束(先清库后宣布)→ 非末关兑付部分回血 → 三选一候选呈现(奖励三选一拉起信号) | 三候选(件 id + 名称 + 效果行值);部分回血前后生命读数;GP 账本余额(跨关延续) |
| 离开 | 三选一确认兑付 → 继续钮(唯一出口) | 兑付反馈载荷 → 下一关开始 |
零自动推进(冒险结构 契约 4):三选一呈现后必须玩家点选才兑付,确认前玩家不被推着走;重复兑付被拒。选择停点可中断:断点附随件扩「奖励选择态」,续玩回到本屏同一候选(不重抽)。
@@ -70,7 +70,7 @@
| 三选一选择态(默认) | 非末关完成,候选已抽定 | 三卡呈现(零自动推进)→ 点选 → 确认 → 兑付反馈 → 继续 |
| ~~同调位替换子态~~ | ~~点选秘宝件且库存满位~~ | 已随渠道退役(秘宝件出池、关卡完成候选 = 纯专长——本屏无道具件候选) |
| 兑付反馈态 | 确认兑付后 | 选中件效果一行 + 丢弃提示 → 继续钮点亮 |
| 末关完成 | level_clear 且末关 | 直通冒险结算——不发三选一与回血(奖励只朝下一战生效);本屏不出现 |
| 末关完成 | 关卡完成且末关 | 直通冒险结算——不发三选一与回血(奖励只朝下一战生效);本屏不出现 |
| Boss 入口语境 | 击杀 Boss(恒为本屏入口前置) | 入口演出归战斗屏;钥石增量行归战斗总结结算——本屏不另设 |
## Interaction Map
@@ -78,23 +78,23 @@
| 组件 | 动作 | 输入 | 即时反馈 | 结果(经组合根) |
|---|---|---|---|---|
| 提升选项卡 ×3 | 点选(单选高亮) | 左键 | 选中卡高亮、确认钮点亮 | 选中态暂存(未确认可改选) |
| 确认钮 | 兑付选中件 | 左键 | 兑付反馈(效果一行) | AdventureRunner 兑付恰一件(重复兑付被拒);另两件丢弃不可反悔 |
| 继续钮 | 接受结算、推进 | 左键 | 按钮下压 | 下一关开始(AdventureRunner.continue_to_next_level——兑付后受理) |
| 确认钮 | 兑付选中件 | 左键 | 兑付反馈(效果一行) | 冒险编排兑付恰一件(重复兑付被拒);另两件丢弃不可反悔 |
| 继续钮 | 接受结算、推进 | 左键 | 按钮下压 | 下一关开始(推进到下一关——兑付后受理) |
| ~~替换子面板钮~~ | —— | —— | —— | 已随渠道退役(本屏无道具件候选) |
复用既有交互范式,零新增原语:三卡点选 = 奖励节点 choice_box 按钮数组同族(node_overlay.show_reward_items 先例)+ 选路覆盖层点选确认两段式(level_map_screen 先例);覆盖层容器 = 中场确认覆盖层位置复用。
复用既有交互范式,零新增原语:三卡点选 = 奖励节点 选择框 按钮数组同族(由节点覆盖层展示奖励三选一 先例)+ 选路覆盖层点选确认两段式(关卡地图屏 先例);覆盖层容器 = 中场确认覆盖层位置复用。
## Data Requirements
| Data | Source System | Read / Write | Notes |
|---|---|---|---|
| 三候选(件 id/名称/效果行值) | 冒险结构 bonus_pick 信号(令牌池洗牌不放回抽 3〔同 kind 去重——v0.14 令牌池换代口径,原「加权洗牌」退役〕,reward_pick 封闭流) | Read | 载荷自包含、despawn 前捕获;同种子同三候选(可复放) |
| 三候选(件 id/名称/效果行值) | 冒险结构 奖励三选一拉起信号(令牌池洗牌不放回抽 3〔同 kind 去重——v0.14 令牌池换代口径,原「加权洗牌」退役〕,奖励抽取封闭流) | Read | 载荷自包含、销毁前捕获;同种子同三候选(可复放) |
| 部分回血读数(回血前后生命) | 冒险结构生命账本(clear_heal_pct 兑付) | Read | 满血回 0 合法态文案化 |
| 兑付反馈载荷 | 冒险结构 bonus_resolved 信号 | Read | 选中件 id + 生效值 |
| 兑付反馈载荷 | 冒险结构 奖励兑付完成信号 | Read | 选中件 id + 生效值 |
| ~~同调位库存~~ | —— | —— | 替换子态随渠道退役;过渡键 transitional_sync_slots 已退役(迭代 11① T7——同调位现行事实源 = attunement_growth.tres 谓词表实时求值) |
| 冒险摘要(五件事) | 冒险结构 adventure_finished 载荷 | Read | 末关分支数据锚(相邻域冒险结算屏消费) |
| 冒险摘要(五件事) | 冒险结构的冒险收束载荷 | Read | 末关分支数据锚(相邻域冒险结算屏消费) |
| GP 账本 | 冒险结构 GP 冒险账本 | — | 不进本屏(维持 2026-09-27 拍板) |
| 钥石入账 | 元进度 settle_adventure | Write(相邻域) | 唯一写档点不变;**本屏零钥石元素**(迭代 10 起,增量行迁战斗总结结算) |
| 钥石入账 | 元进度 冒险结算入账 | Write(相邻域) | 唯一写档点不变;**本屏零钥石元素**(迭代 10 起,增量行迁战斗总结结算) |
## Accessibility
@@ -103,7 +103,7 @@
## Acceptance Criteria
- [ ] 非末关完成必经本屏:三选一恰呈现一次(零自动推进)、点选后恰兑付一件(重复兑付被拒)、未选项零生效
- [ ] 三候选读数可见且与 bonus_pick 载荷一致(件名称 + 效果行值);同种子同三候选
- [ ] 三候选读数可见且与奖励三选一拉起载荷一致(件名称 + 效果行值);同种子同三候选
- [ ] 部分回血兑付行可见且封顶上限;满血回 0 呈合法态文案
- [ ] ~~同调位替换子交互~~(已随渠道退役——本屏无道具件候选,见 Information Hierarchy 第 4 条注)
- [ ] 末关完成分支正确直通冒险结算(不发三选一与回血),冒险摘要五件事完整
+27 -27
View File
@@ -1,8 +1,8 @@
# UX Spec: 关卡画面(选路枢纽,Level Map)
> **Status**: 定稿版——三项设计提案已拍板完成(2026-09-27:底栏状态展示 / 图上点击选路·候选按钮退役 / 放弃二次确认);**形态已升格独立屏(2026-09-28 用户裁决:独立存在为最终形态)**;**视觉终稿已冻结(2026-09-28 关卡画面样张 v1 机检 11/11 全绿,闸形 A——冻结值见 Layout/组件清单与样张机检报告,迭代 4)**
> **Status**: 定稿版(现行——三项设计提案已拍板:底栏状态展示 / 图上点击选路·候选按钮退役 / 放弃二次确认;形态为独立屏;视觉终稿已冻结)
> **Author**: user + ZCode(关卡画面 UX 批)
> **Last Updated**: 2026-10-25(迭代 35 生成图换代:呈现面随动登记)
> **Last Updated**: 2026-10-29
> **Platform Target**: PC (Steam)——Keyboard/Mouse 主,全部操作纯鼠标可完成(同 [battle.md](battle.md))
> **Template**: UX Spec
> **覆盖范围**: 独立屏形态(关卡停点全景)· 入口停点 · 岔路停点 · 单链停点 · 放弃冒险入口
@@ -61,24 +61,24 @@
### Layout Zones
按 1280×800 基座(2026-09-12 定)。本屏为独立屏独占呈现:屏底(深底 `BG_ROOT` + 石纹底噪〔迭代 2 框材组冻结件,缺位纯色回退〕)铺满,内容居中三段。
按 1280×800 基座(2026-09-12 定)。本屏为独立屏独占呈现:屏底(深底背景色 + 石纹底噪〔迭代 2 框材组冻结件,缺位纯色回退〕)铺满,内容居中三段。
| 区 | 位置与尺寸 | 内容 |
|---|---|---|
| **顶栏语境** | 居中横排,图区上方,高约 32px | 左:关卡名(`level_row.display_name`,如「第二层 · 幽暗地域」);右:GP 常驻徽章(GP 图标+数字,直角细线数据框——GP 值域超点阵适用档,走 pattern 5 的 When-NOT-to-Use 路线);HP 归底部状态栏(2026-09-27 拍板完成) |
| **节点图区** | 居中 | 整幅节点图自绘:节点方块 + 通道折线 + 节点态着色 + Boss 紫赤描边。画布随图自适应(**冻结公式**:宽 = 70+层深×122+44.5、高 = 52+槽位×58+25+24,下限 620×256——routebug 83c11a1 根修件);通道折线**冻结 2/3/4px**(未点亮石灰 STONE/候选亮金 GOLD_LIT/悬停加粗);节点方块 52×36 内**节点图标 20px 烘焙 1:1**(♻ kenney 五键:战=弓/赏=桂冠/疗=篝火/王=王冠/商=钱袋,WARM 单色、当前金底转深墨——双色墨制)+ 编号(图内句柄 id)10px 右上角 |
| **顶栏语境** | 居中横排,图区上方,高约 32px | 左:关卡名(关卡表 `display_name` 行值,如「第二层 · 幽暗地域」);右:GP 常驻徽章(GP 图标+数字,直角细线数据框——GP 值域超点阵适用档,走 pattern 5 的 When-NOT-to-Use 路线);HP 归底部状态栏(2026-09-27 拍板完成) |
| **节点图区** | 居中 | 整幅节点图自绘:节点方块 + 通道折线 + 节点态着色 + Boss 紫赤描边。画布随图自适应(**冻结公式**:宽 = 70+层深×122+44.5、高 = 52+槽位×58+25+24,下限 620×256——路线缺陷根修后定值);通道折线**冻结 2/3/4px**(未点亮石灰 STONE/候选亮金 GOLD_LIT/悬停加粗);节点方块 52×36 内**节点图标 20px 烘焙 1:1**(♻ kenney 五键:战=弓/赏=桂冠/疗=篝火/王=王冠/商=钱袋,WARM 单色、当前金底转深墨——双色墨制)+ 编号(图内句柄 id)10px 右上角 |
| **底部状态栏** | 图区下方横排,高约 48px | 左-中:状态数据框组(直角细线,pattern 5 族)——生命(当前/上限 + 迷你血条)、属性(攻击 / 护甲 AC,有效值 + 加成角标)、本关加成(攻+X · 上限+Y · AC+Z,零加成隐藏);右端:放弃冒险按钮(危险红族文字,与状态数据框保持间距——破坏性确认异位,pattern 7) |
### Component Inventory
| 组件 | 类型 | 内容 | 交互 | 现有实现锚 |
|---|---|---|---|---|
| 关卡名标签 | 文本 | `level_row.display_name`(关卡表行读数) | 只读 | 新建(现行标题位升级) |
| GP 常驻徽章 | 直角细线数据框 | GP 图标 + 数字(`runner.gp`,冒险钱包读数;刷新经 `wallet_changed` 信号投影〔gain/buy/clear 三事件〕或写路径回执后重查) | 只读 | 新建(GP 去向拍板落地面) |
| 节点图画布 | 自绘 Control | 节点图标(五键 20px 烘焙,双色墨制)+ 编号(图内句柄 id)、通道折线、节点态着色、Boss 紫赤描边+深墨环(BOSS_PURPLE——2026-09-26 封印紫批语义:紫赤本色) | 悬停预承诺 / 点击提交选路(唯一通道) | ✅ level_map_screen.gd `_draw_graph`(视觉终稿已落码——迭代 4 T2/T3) |
| 关卡名标签 | 文本 | 关卡表 `display_name` 行值(关卡表行读数) | 只读 | 新建(现行标题位升级) |
| GP 常驻徽章 | 直角细线数据框 | GP 图标 + 数字(冒险钱包读数;刷新经钱包变动信号投影〔gain/buy/clear 三事件〕或写路径回执后重查) | 只读 | 新建(GP 去向拍板落地面) |
| 节点图画布 | 自绘 Control | 节点图标(五键 20px 烘焙,双色墨制)+ 编号(图内句柄 id)、通道折线、节点态着色、Boss 紫赤描边+深墨环(BOSS_PURPLE——2026-09-26 封印紫批语义:紫赤本色) | 悬停预承诺 / 点击提交选路(唯一通道) | ✅ 已实装(视觉终稿已落码——迭代 4 T2/T3) |
| 状态数据框组 | 直角细线数据框 ×3 | 生命(当前/上限 + 迷你血条)、属性(攻击 / 护甲 AC 有效值 + 加成角标)、本关加成(加算区增量列表,零加成隐藏) | 只读 | 新建(2026-09-27 拍板:底栏状态展示) |
| 放弃冒险按钮 | 按钮(危险红族) | 「放弃冒险(同失败结算——已获大奖励保留)」;二次确认态已拍板(见布局决策 3) | 点击(首击转确认态、二击提交) | ✅ level_map_screen.gd(可见性归组合根,仅冒险模式开) |
| 标题行 | 文本 | 停点语境提示(见布局决策 1 三停点标题) | 只读 | ✅ level_map_screen.gd `_title`(措辞已按布局决策 1 改稿) |
| 放弃冒险按钮 | 按钮(危险红族) | 「放弃冒险(同失败结算——已获大奖励保留)」;二次确认态已拍板(见布局决策 3) | 点击(首击转确认态、二击提交) | ✅ 已实装(可见性归组合根,仅冒险模式开) |
| 标题行 | 文本 | 停点语境提示(见布局决策 1 三停点标题) | 只读 | ✅ 已实装(措辞已按布局决策 1 改稿) |
**布局决策 1 —— 停点标题措辞修正(清偿状态记录 143 遗留)**:现行入口停点标题沿用「继续前进(战斗房)」,与「尚未走出第一步」的语境矛盾。三停点标题定稿:
@@ -88,7 +88,7 @@
| 单链停点 | 1 | 「继续前进」 |
| 岔路停点 | ≥2 | 「选择下一节点」 |
**布局决策 2 —— 图上直接点击选路(2026-09-27 拍板)**:候选节点的亮金描边本身是可点目标,悬停预承诺(pattern 4)后点击即提交——**候选按钮整列退役,图上点击为唯一提交通道**。实装注记:route_overlay.gd 现行候选按钮列与 `press_candidate` 探针入口随实装批拆除改造(图上命中换整图公式族命中),ui_click_probe 选路段同步改写。
**布局决策 2 —— 图上直接点击选路(2026-09-27 拍板)**:候选节点的亮金描边本身是可点目标,悬停预承诺(pattern 4)后点击即提交——**候选按钮整列退役,图上点击为唯一提交通道**。
**布局决策 3 —— 放弃冒险二次确认(2026-09-27 拍板)**:放弃 = 整局冒险落幕,不可逆(pattern 7 破坏性确认)。首击转入确认态(按钮文案变「再点一次确认放弃——不可逆」,危险红边框脉冲约 3 秒,超时回落),二击才提交。代价语义(已获大奖励保留、同失败结算)常驻按钮文案。
@@ -123,7 +123,7 @@
| **单链停点** | 兑付确认后、恰 1 个下一跳 | 标题「继续前进」;单候选节点图上点击提交(候选按钮已退役——图上点击为唯一通道) |
| **岔路停点** | 兑付确认后、≥2 个下一跳 | 标题「选择下一节点」;候选节点图上点击提交(候选按钮已退役——图上点击为唯一通道);亮金通道与候选描边逐一分叉可辨 |
| **悬停预承诺** | 悬停候选节点 | 该节点亮金描边加粗 + 所属通道增亮 + 光标切指针态;移出即回落(仅预承诺,点击才提交) |
| **放弃确认态** | 首击放弃按钮 | 文案转确认语 + 危险红边框脉冲约 3 秒;超时或移出回落;二击提交 `abandon_requested` |
| **放弃确认态** | 首击放弃按钮 | 文案转确认语 + 危险红边框脉冲约 3 秒;超时或移出回落;二击提交放弃请求 |
| **换层进入** | 上一关结算确认 → 新关开始 | 本屏以新关卡数据淡入;屏底世界侧随层进换挡(**换层色板渐变挂点**——§2.7 切片档:只动色相/饱和、明度带归一,level_index→tint 表候选值 = art-bible §6.3 三关方向,终值归色板样张批;M-2 迭代 4 落挂点) |
| **减动效** | 设置开关(设置面——迭代 8 卡④已转正,TunePanel 已退役) | 淡入、描边脉冲等全部 tween 时长减半或跳终态(UiKit.motion 单点包装,同 battle.md 通道) |
@@ -135,8 +135,8 @@
| 组件 | 动作 | 输入 | 即时反馈 | 结果(经组合根) |
|---|---|---|---|---|
| 候选节点(图上,唯一通道) | 提交选路 | 左键 | 悬停预承诺(描边加粗 + 通道增亮 + 指针)→ 点击本屏关闭 | `route_chosen(node_id)` → `LevelRunner.pick_next_node`——到达即兑付,无进入前确认步 |
| 放弃冒险按钮 | 终结整局冒险 | 左键(二击提交——首击转确认态,2026-09-27 布局决策 3) | 危险红族反馈 | `abandon_requested` → 组合根走冒险落幕(同失败结算——已获大奖励保留) |
| 候选节点(图上,唯一通道) | 提交选路 | 左键 | 悬停预承诺(描边加粗 + 通道增亮 + 指针)→ 点击本屏关闭 | 选路提交 → 关卡推进方受理——到达即兑付,无进入前确认步 |
| 放弃冒险按钮 | 终结整局冒险 | 左键(二击提交——首击转确认态,2026-09-27 布局决策 3) | 危险红族反馈 | 放弃请求 → 组合根走冒险落幕(同失败结算——已获大奖励保留) |
**零自动推进纪律**(关卡节点地图 定稿):本屏是唯一的行进发起口——不选就停在图上;没有任何定时、默认或顺延的自动前进路径。兑付后确认挂各兑付面(战斗总结结算〔settlement-summary.md〕/ 节点覆盖层 / 商店覆盖层离开动作),本屏不重复确认步。
@@ -146,13 +146,13 @@
| Data | Source System | Read / Write | Notes |
|---|---|---|---|
| 节点图结构 / 当前节点 / 已到序列 / 候选集 | LevelRunner 只读成文出口:`nodes()` / `current_node_id()` / `visited_ids()` / `next_candidate_ids()` / `node_id_of()` / `node_out_ids()` | Read | 呈现只读(关卡节点地图 验收「呈现只读」条);节点态四色直接读图 |
| GP 常驻总量 | `runner.gp`(冒险钱包) | Read | 刷新经 `wallet_changed` 信号投影(gain/buy/clear 三事件)或写路径回执后重查;冒险收束清零后本屏不可达(收束即离屏) |
| 关卡名 | `level_row.display_name`(关卡表行) | Read | 字段名实现期核对(level.tres 行键 `display_name` 在案) |
| 生命读数 | `runner.hero_hp` / `runner.effective_max_hp()`(跨战斗生命携带) | Read | 已拍板(2026-09-27):底栏状态栏承载 |
| 属性与本关加成 | `runner.effective_atk() / effective_ac() / effective_max_hp()` 与 `bonus` 统一冒险加算区(锻造/大奖励/商店购买/节点奖励同账) | Read | 已拍板:底栏承载;无推送信号——组合根打开本屏 / 兑付确认回执后重查(命令式刷新纪律,同行动经济) |
| 选路提交 | LevelRunner | **Write** | 唯一写路径 = `route_chosen` → 组合根 → `pick_next_node`;本屏零其他写面 |
| 放弃请求 | 组合根 | **Write** | `abandon_requested` → 冒险落幕流程(归冒险结构) |
| 节点图结构 / 当前节点 / 已到序列 / 候选集 | 关卡推进方只读成文出口:全节点集 / 当前节点 / 已到序列 / 候选集 / 节点编号 / 节点出边 | Read | 呈现只读(关卡节点地图 验收「呈现只读」条);节点态四色直接读图 |
| GP 常驻总量 | 冒险钱包读数 | Read | 刷新经钱包变动信号投影(gain/buy/clear 三事件)或写路径回执后重查;冒险收束清零后本屏不可达(收束即离屏) |
| 关卡名 | 关卡表 `display_name` 行值(关卡表行) | Read | 字段名实现期核对(level.tres 行键 `display_name` 在案) |
| 生命读数 | 主角当前生命 / 有效生命上限(跨战斗生命携带) | Read | 已拍板(2026-09-27):底栏状态栏承载 |
| 属性与本关加成 | 有效攻击 / 有效护甲 / 有效生命上限,以及统一冒险加算区(锻造/大奖励/商店购买/节点奖励同账) | Read | 已拍板:底栏承载;无推送信号——组合根打开本屏 / 兑付确认回执后重查(命令式刷新纪律,同行动经济) |
| 选路提交 | 关卡推进方 | **Write** | 唯一写路径 = 选路提交 → 组合根 → 关卡推进方受理;本屏零其他写面 |
| 放弃请求 | 组合根 | **Write** | 放弃意图 → 冒险落幕流程(归冒险结构) |
**架构注记**:与 battle.md 同族——UI 不拥有任何游戏状态,全部读经核心只读面,全部写经组合根;呈现层直接订阅的推进信号属 HUD框架 已锁两线之一(战斗结算明细流水 + 关卡节点地图推进信号)。
@@ -197,21 +197,21 @@
- [ ] 关卡开始即出图(停点前移语义),入口节点不自动进入;每次兑付确认后回到本屏
- [ ] 1280×800 与 16:9 全屏下顶栏/图区/动作栏无遮挡、无重叠、无内容裁切;节点图完整可见(含 Boss)
- [ ] 节点四态(已过/当前/候选/未来)+ Boss 描边在灰度截图下可分类;色值对 art-bible §4.1 色板在案
- [ ] 顶栏关卡名与 GP 常驻徽章可见、读数与 `runner` 现值一致(GP 经 gain/buy/clear 事件刷新)
- [ ] 顶栏关卡名与 GP 常驻徽章可见、读数与关卡推进方现值一致(GP 经 gain/buy/clear 事件刷新)
**交互与流程**
- [ ] 三停点标题按布局决策 1 呈现(入口停点不再出现「继续前进(战斗房)」措辞——状态记录 143 遗留清偿)
- [ ] 候选提交经组合根唯一写路径(`route_chosen` → `pick_next_node`),到达即兑付;零自动推进(无任何不选而行的路径)
- [ ] 图上点击为唯一选路提交通道(候选按钮退役,2026-09-27 拍板);悬停预承诺反馈可见;ui_click_probe 选路段随实装批改造后全绿
- [ ] 底部状态栏三组读数可见且与 runner 现值一致(生命当前/上限、攻击/AC 有效值、本关加成增量——零加成隐藏);兑付确认返回后读数刷新
- [ ] 候选提交经组合根唯一写路径(选路提交 → 关卡推进方受理),到达即兑付;零自动推进(无任何不选而行的路径)
- [ ] 图上点击为唯一选路提交通道(候选按钮退役,2026-09-27 拍板);悬停预承诺反馈可见;图上选路段随实装批改造后复核通过
- [ ] 底部状态栏三组读数可见且与关卡推进方现值一致(生命当前/上限、攻击/AC 有效值、本关加成增量——零加成隐藏);兑付确认返回后读数刷新
- [ ] 放弃按钮仅冒险模式可见(调试两层不可达);单击不提交、确认态超时回落、二击才终结(已拍板)
- [ ] 放弃后走冒险落幕(同失败结算),已获大奖励保留语义可见
**模态与测试**
- [ ] **独立性断言**:本屏激活期战斗屏宿主整体隐藏(`visible=false` 级互斥,零透出);选路提交至战斗节点后战斗屏恢复;兑付覆盖层(节点/商店)关闭后本屏恢复——场景级断言
- [ ] 场景级 headless 测试:真实实例化本屏 + 驱动选路全程 + 断言零脚本错误(ui_probe 家族扩展)
- [ ] **独立性断言**:本屏激活期战斗屏宿主整体隐藏(整屏隐藏级互斥,零透出);选路提交至战斗节点后战斗屏恢复;兑付覆盖层(节点/商店)关闭后本屏恢复——场景级断言
- [ ] 场景级 headless 测试:真实实例化本屏 + 驱动选路全程 + 断言零脚本错误(场景探针家族扩展)
- [ ] 中文渲染无豆腐块;像素字体整数倍缩放;全部操作纯鼠标可完成
---
+7 -7
View File
@@ -1,23 +1,23 @@
# 节点奖励屏 UX spec(node-reward)
> 状态:v2.9(池与交互形态同 v2.4;档名对齐四级档位框架、配额对齐现行结构锚)
> 事实源:`game/presentation/views/curio_pick_overlay.gd`(三选一覆盖层共用面)+ `main.gd`(奖励节点分支——`adventure.node_bonus_candidates/apply_node_bonus`)+ `battle_narrator.gd`(node_bonus_header)
> 状态:v2.9(现行)
> 事实源:本 spec(呈现)+ 三选一覆盖层(共用呈现件)+ 头部行文案(旁白条目)
> 相邻:[level-clear](level-clear.md)(关卡完成三选一面——同一覆盖层的另一上下文)/ [level-map](level-map.md)(关卡画面)/ [秘宝](../systems/跨局循环/秘宝.md)(道具件内容权威——本批起为局外同调件,不再入三选一牌库)/ [冒险结构](../systems/冒险循环/冒险结构.md)(共享池令牌库账本)
## 定位
奖励节点(reward node)到达即开的**提升三选一选择面**:**七种×档位**令牌池(攻击/生命上限/护甲/GP 袋/行动点件/恢复件/刷新件 × 普通/优秀/稀有(+传说头奖位留空)——v2.2 起秘宝件随同调批退役出池;v2.4 起=固定配额令牌池;刷新件随迭代15② T6 入池〔优秀档 2,恢复件同批挤占收窄——adventure_table CURIO_KINDS 第七类〕),与商店货架同库同账(v2.3)、同池耗语义、同 reward_pick 封闭流。**关卡完成三选一自迭代 15② 渠道分离起候选 = 纯专长,与本面不再同池**;与关卡完成面的差异另在上下文:无部分回血、无钥石增量行,兑付后「继续」回图选路(不推进关卡)。
奖励节点(reward node)到达即开的**提升三选一选择面**:**七种×档位**令牌池(攻击/生命上限/护甲/GP 袋/行动点件/恢复件/刷新件 × 普通/优秀/稀有(+传说头奖位留空)——v2.2 起秘宝件随同调批退役出池;v2.4 起=固定配额令牌池;刷新件随迭代15② T6 入池〔优秀档 2,恢复件同批挤占收窄——冒险表的令牌类型闭集第七类〕),与商店货架同库同账(v2.3)、同池耗语义、同奖励抽取封闭流。**关卡完成三选一自迭代 15② 渠道分离起候选 = 纯专长,与本面不再同池**;与关卡完成面的差异另在上下文:无部分回血、无钥石增量行,兑付后「继续」回图选路(不推进关卡)。
## 布局与交互
- 载体 = 提升三选一覆盖层(CurioPickOverlay——curio_pick_overlay.gd,与 [level-clear](level-clear.md) 共用组件——零新增交互原语)。
- 头部行:「关卡奖励点 / 从冒险牌库抽三选一(属性值提升与补给;与通关专长三选一同库分流):选择一件带走:」(Narrator.node_bonus_header)。
- 载体 = 提升三选一覆盖层(与 [level-clear](level-clear.md) 共用组件——零新增交互原语)。
- 头部行:「关卡奖励点 / 从冒险牌库抽三选一(属性值提升与补给;与通关专长三选一同库分流):选择一件带走:」(旁白条目)。
- 三卡点选(✓ 高亮,确认前可改选)→「确认选择」→ 兑付反馈(选中件效果 + 丢弃提示)→「继续」→ 回图选路(零自动推进同款)。
- ~~秘宝件直显/满位替换~~(v2.1 两面随池种退役——迭代 11 第①批 T7;秘宝改走营地同调装配面,见[秘宝](../systems/跨局循环/秘宝.md))。
- **三选一刷新**(v2.2 新增——P1 甲 X/Y 双源;机制现行事实源=[秘宝](../systems/跨局循环/秘宝.md)「三选一刷新双源」节,X 源承载件已随新目录批换代〔旧目录「三选一刷新件」退役→新目录「刷新练习」〕):装配「三选一刷新件」给 X 次(每次碰三选一重给、优先消耗、不结转)+ 营地「刷新升级」给 Y 次(每冒险开局注入冒险周期池、用完即无);刷新钮余量 >0 时现形,点按重抽三候选(reward_pick 既有洗牌流,池规则全保留:不放回/达上限剔牌/掷定前置直显/停点可中断)。autoplay 默认不刷(钓鱼归玩家)。
- **三选一刷新**(v2.2 新增——P1 甲 X/Y 双源;机制现行事实源=[秘宝](../systems/跨局循环/秘宝.md)「三选一刷新双源」节,X 源承载件已随新目录批换代〔旧目录「三选一刷新件」退役→新目录「刷新练习」〕):装配「三选一刷新件」给 X 次(每次碰三选一重给、优先消耗、不结转)+ 营地「刷新升级」给 Y 次(每冒险开局注入冒险周期池、用完即无);刷新钮余量 >0 时现形,点按重抽三候选(奖励抽取既有洗牌流,池规则全保留:不放回/达上限剔牌/掷定前置直显/停点可中断)。自动演示默认不刷(钓鱼归玩家)。
## 口径
- **同库同池耗(v2.4)**:池=固定配额令牌库(档位=四级框架 普通/优秀/稀有/传说,传说=头奖位留空〔稀有档现投放为行动点件〕;各 kind 现行配额读 `game/data/tables/adventure.tres`——「道具件 2」原列稀有档,随 aux_item 池种退役〔迭代 11 第①批 T7,落地晚于追认 b〕收窄——状态记录自决披露项);洗牌不放回抽 3(**同 kind 去重每 kind 至多一枚**——「三种不同选项」体验延续,kind 出现率∝剩余令牌数)、选中踢池未选回池、池耗即枯竭(余库不足出齐剩余,空库=零候选合法态直通);**种类次数上限退役**(池消耗即上限)。数值对:小GP 20/大GP 50、小增伤 +1/大 +2、小护甲 +1/大 +2、小生命 +5/大 +10、恢复 +6 当即回血(封顶生效上限)、AP +1。**MC 策略 316-f**:1 级优先度=最稀有(legendary>rare>excellent>common,头奖位现行留空)、2 级=最左(并列同档取最左)。配额结构锚与档位构成读冒险表(schema 硬断言配额结构锚——见 `data/schemas/adventure_table.gd`)。**v2.3 第三渠道并账维持**:商店货架=同库付费渠道(令牌级货架,买一件=奖励面少一件),库存=剩余令牌数,账本语义与切边注记归[冒险结构](../systems/冒险循环/冒险结构.md)共享池账本节。
- **同库同池耗(v2.4)**:池=固定配额令牌库(档位=四级框架 普通/优秀/稀有/传说,传说=头奖位留空〔稀有档现投放为行动点件〕;各 kind 现行配额读 `game/data/tables/adventure.tres`——「道具件 2」原列稀有档,随 aux_item 池种退役〔迭代 11 第①批 T7,落地晚于追认 b〕收窄——状态记录自决披露项);洗牌不放回抽 3(**同 kind 去重每 kind 至多一枚**——「三种不同选项」体验延续,kind 出现率∝剩余令牌数)、选中踢池未选回池、池耗即枯竭(余库不足出齐剩余,空库=零候选合法态直通);**种类次数上限退役**(池消耗即上限)。数值对:小GP 20/大GP 50、小增伤 +1/大 +2、小护甲 +1/大 +2、小生命 +5/大 +10、恢复 +6 当即回血(封顶生效上限)、AP +1。**MC 策略 316-f**:1 级优先度=最稀有(legendary>rare>excellent>common,头奖位现行留空)、2 级=最左(并列同档取最左)。配额结构锚与档位构成读冒险表(结构校验归实现侧)。**v2.3 第三渠道并账维持**:商店货架=同库付费渠道(令牌级货架,买一件=奖励面少一件),库存=剩余令牌数,账本语义与切边注记归[冒险结构](../systems/冒险循环/冒险结构.md)共享池账本节。
- ~~道具件入本关库存~~(v2.2 退役——秘宝局内不掉落机制道具,三轴 doctrine 锁死)。
- ~~「池空直通」合法态~~(v2.4 随令牌池换代退役又回归异形:旧口径=GP 无上限保证牌库恒非空;现口径=固定配额池(现行值读冒险表)真可耗尽,空库=零候选直通合法态——池耗即枯竭既定后果)。
+8 -8
View File
@@ -1,7 +1,7 @@
# 结算总结 UX spec(settlement-summary)
> 状态:v1.4(2026-10-26 迭代 37 结项:事实源行号引用改指拆件后现址,呈现设计与规则零变化;承 v1.3(2026-10-15 简明技术中文用语规范(用户令)批:词面修正 8 处——两面分节、纯呈现轻量 spec 不变;无新概念))
> 事实源:`game/presentation/views/battle_end_overlay.gd`(胜利金蜡封 / 失败暮蓝双形态载体)+ `main.gd`(胜利接线:调试 `main.gd:455-461`、冒险主路径 `main_adventure_flow.gd:165`;冒险终局接线:`main_adventure_flow.gd:19` 的 `adventure_finished.connect`)
> 状态:v1.4(现行)
> 事实源:本 spec(呈现)+ 战斗终局覆盖层(胜利金蜡封 / 失败暮蓝双形态)
> 相邻:[battle.md](battle.md)(战斗屏出口锚与信息归属两原则)/ [level-clear.md](level-clear.md)(关卡结算屏——Boss 胜利走大奖励面,非本 spec)/ [level-map.md](level-map.md)(GP 常驻徽章)
## 定位
@@ -15,17 +15,17 @@
## 战斗总结结算(战斗胜利面)
- 触发:冒险模式战斗胜利(verdict=win)含 Boss 胜利——迭代 10 起 Boss 胜利也经本面(钥石逐杀掉落增量在此呈现,确认后进[关卡结算屏](level-clear.md)三选一面;原「Boss 胜利走大奖励面不经本面」口径随大奖励重构退役)。非 Boss 接线 2026-09-29 迭代 8 卡⑥。
- 载体:battle_end_overlay 胜利形态(金蜡封)。
- 触发:冒险模式战斗胜利(判胜)含 Boss 胜利——迭代 10 起 Boss 胜利也经本面(钥石逐杀掉落增量在此呈现,确认后进[关卡结算屏](level-clear.md)三选一面;原「Boss 胜利走大奖励面不经本面」口径随大奖励重构退役)。非 Boss 接线 2026-09-29 迭代 8 卡⑥。
- 载体:战斗结束覆盖层胜利形态(金蜡封)。
- 呈现内容(2026-09-27 拍板面 + 迭代 10 扩):金蜡封 + 判定行 + 战利品行(GP 增量 + 总量;Boss/精英击杀追加**钥石增量行**——首杀/复杀档位读 meta.tres boss_keystone)+「下一节点」钮(明细回看入口已随 2026-10-04 P-C7 退役——冒险中回看归「生涯」)。
- 数据锚:增量 = `battle_finished` 载荷 `gp_dropped`;总量 = runner.gp 现值(LevelRunner 入账先于呈现连接——次序依赖在案,M-1 迭代 2 T5 接线)。
- 数据锚:增量 = 战斗结束信号的掉落载荷;总量 = 关卡推进方 GP 现值(关卡推进方入账先于呈现连接——次序依赖在案,M-1 迭代 2 T5 接线)。
- 出口:「下一节点」→ 关卡画面选路(零自动推进)。
## 冒险总结结算(冒险落幕面)
- 触发:主角倒下(verdict=lose)/ 末关完成 / 玩家放弃——三结局同面(`adventure_finished` 收束)。
- 载体:与战斗面同一个 battle_end_overlay(2026-09-29 迭代 6 T7 接线)——末关通关走 `open_victory`(金蜡封 +「本局 GP 入账 · 合计 N」行,GP 收束清零前的呈现侧影子账);倒下 / 放弃走 `open_defeat`(暮蓝)。无独立「冒险终局面板」实体,待办清单状态记录旧称随本条完成。
- 呈现内容:冒险摘要五件事(定义归[冒险结构](../systems/冒险循环/冒险结构.md))+ 钥石写入明细(= 本局逐杀 Boss 掉落合计;消费归[元进度](../systems/跨局循环/元进度.md) settle_adventure——迭代 10 起大奖励面不再产钥石)+ GP 合计行。
- 触发:主角倒下(判负)/ 末关完成 / 玩家放弃——三结局同面(由冒险收束信号统一触发)。
- 载体:与战斗面同一个战斗结束覆盖层(2026-09-29 迭代 6 T7 接线)——末关通关走胜利态开屏(金蜡封 +「本局 GP 入账 · 合计 N」行,GP 收束清零前的呈现侧影子账);倒下 / 放弃走失败态开屏(暮蓝)。无独立「冒险终局面板」实体,待办清单状态记录旧称随本条完成。
- 呈现内容:冒险摘要五件事(定义归[冒险结构](../systems/冒险循环/冒险结构.md))+ 钥石写入明细(= 本局逐杀 Boss 掉落合计;消费归[元进度](../systems/跨局循环/元进度.md) 的冒险结算入账——迭代 10 起大奖励面不再产钥石)+ GP 合计行。
- 出口:确认 → 回存档首页。
## 口径
+3 -3
View File
@@ -1,7 +1,7 @@
# 商店覆盖层 UX spec(shop)
> 状态:v1.1(2026-09-30 审计拍板点 4B 用户裁决写入文档——甲+乙并行:编排面小节落关卡节点地图、呈现面独立成文)
> 事实源:`game/presentation/views/shop_overlay_view.gd`(ShopOverlay)
> 状态:v1.1(现行)
> 事实源:本 spec(呈现)+ 商店覆盖层(呈现件)
> 机制权威:[关卡节点地图](../systems/冒险循环/关卡节点地图.md)(商店房编排:每关恰 1/Boss 前一位必经/兑付触发);定价数值归[难度曲线与Boss](../systems/冒险循环/难度曲线与Boss.md)(shop.tres,provisional)
## 定位
@@ -11,7 +11,7 @@
## 布局与交互
- 模态覆盖层(dim + 居中):标题「商店」/ GP 余额读数/ 令牌级货架卡(进店自共享池抽 3 张:显示名·效果·现价——六行池面含回复与专长凭证;买一件 = 池少一件、货架随即全架重抽)/ 购买按钮(余额不足禁用置灰——pattern 8 禁用态即理由)/ 刷新按钮(GP 付费刷新,价 = ceil(20×1.8^本次进店已付费刷) provisional,余额不足禁用)/ 离开按钮。
- 购买意图 `buy_requested` 经组合根转发 runner(pool 模式载荷 = kind_id);成功后货架整架重建(买 1 全重抽反馈)。刷新意图 `refresh_requested` 经组合根转发 presenter。
- 购买意图经组合根转发(pool 模式载荷 = kind_id);成功后货架整架重建(买 1 全重抽反馈)。刷新意图经组合根转交商店呈现件受理。
- 离开 → 关卡画面兑付确认回选路(零自动推进)。
- 刷新与货架口径(2026-10-04 P-C2+Q2 裁决,SR-1 落码):基础免费 0 次 + GP 付费刷新 + 池源同源(与三选一同一令牌库本)——原「无独立刷新、全陈列」裁决随该批被推翻;天赋侧「刷新次数」增益预留 free_count 位(待办清单登记条在册)。
+11 -11
View File
@@ -1,7 +1,7 @@
# 术语表
> 全库专用术语的唯一对照表(2026-10-11 用户令建立)。规矩:新术语先登记本表、再在文档使用;退役词见文末对照表,文档正文一律使用现行词。文档中遇到看不懂的词,查本表。用词纪律(禁用词、替换值、豁免范围)见「用语规范」节。
> 状态:**现行 v1.24**——2026-10-11 建立;历次升版明细见 git 提交史。
> 状态:**现行 v1.25**——2026-10-11 建立;历次升版明细见 git 提交史。
## 格与棋盘
@@ -12,18 +12,18 @@
| 安全格 | 没有惩罚的格子——挖开安全并获得其上信息与收益 |
| 整图 | 单张棋盘(的整个范围)——原「整图」退役(2026-10-11 用户裁)。例:整图叠加层、整图作用域 |
| 叠加层(整图叠加层) | 秘宝产生的信息的自持容器:按效果分类的格集,随图消亡、不回写棋盘(见[秘宝](systems/跨局循环/秘宝.md)) |
| 封印 / 控制 | 封印动作的机制名/玩家名:封印印记落在危险格上为「标中」(危险格被控制、化险为利),封错为「标空」(原「旗 / 控制」,2026-10-18 用户裁:「旗」概念不存在——动作=封印、印记=封印印记);代码契约键与标识符统一用 `seal_*`(原 `flag_*` 全族换代),板面单字字形=「封」 |
| 封印 / 控制 | 封印动作的机制名/玩家名:封印印记落在危险格上为「标中」(危险格被控制、化险为利),封错为「标空」(原「旗 / 控制」,2026-10-18 用户裁:「旗」概念不存在——动作=封印、印记=封印印记),板面单字字形=「封」 |
| 真视 | 直接告诉玩家某范围内哪些格是危险格的效果(秘宝承重契约:一次最多 3×3,见[秘宝](systems/跨局循环/秘宝.md)核心规则) |
| 类型微光 | 棋盘上按格子类型显示的提示光效(视野参数控制其显示范围) |
| 换图 / 弃图刷新 | 清完一图进入下一图 / 花储备放弃当前图重开一张(代价见[行动经济](systems/排雷循环/行动经济.md)) |
| 装板(装板期) | 把地图战斗资源摇定的类型身份铺设到棋盘格子上的布置动作(阶段);由战斗结算的布置段执行,随机取数标签为 `variant_place` |
| 摇号 / 摇定 | 按池配置用随机数决定结果(资源身份、遭遇抽取、货架抽签);随机服务实现见 `game/core/rng_service.gd`(流标签为代码事实) |
| 摇号 / 摇定 | 按池配置用随机数决定结果(资源身份、遭遇抽取、货架抽签);随机服务为全库单点(流标签为既有事实,归属见架构文档) |
## 关卡与地图
| 术语 | 定义 |
|---|---|
| 信息迷雾 | 关卡节点图上按邻近层数隐藏节点类型的可见性机制——只隐藏类型,结构(节点、连线、入口、终点位置)恒可见;与「视野迷雾」(战斗棋盘按英雄曼哈顿半径遮挡格子)同词根易混,代码标识符一律不用 `fog_` 前缀。参数 N=信息可见层数(`level.tres` 的 `info_visible_layers`),机制见[关卡节点地图](systems/冒险循环/关卡节点地图.md) |
| 信息迷雾 | 关卡节点图上按邻近层数隐藏节点类型的可见性机制——只隐藏类型,结构(节点、连线、入口、终点位置)恒可见;与「视野迷雾」(战斗棋盘按英雄曼哈顿半径遮挡格子)同词根易混。参数 N=信息可见层数(`level.tres` 的 `info_visible_layers`),机制见[关卡节点地图](systems/冒险循环/关卡节点地图.md) |
## 系统资源与经济
@@ -67,7 +67,7 @@
| 魔法护甲 | 三型甲之一(= 现役甲域 ward,基础 AC 最低、被普通攻击克);「魔法甲」系笔误、非别名,不单独登记 |
| 并联双通道 | 待解锁路线的解锁结构:练满前一档 **OR** 一次性解锁价,两通道互不影响、玩家自选其一、不设串联门槛 |
| 出场选择 | 一次冒险 = 一个武器类型 + 一个甲型;营地内免费切换、冒险开始后锁死 |
| 路线 id / 存档域键名 | 锻造工坊实现层词汇(非玩家可见,2026-10-13 迭代 23 反哺落文登记):六路线 id = sword/spear/staff/light/heavy/ward(甲路线 id = 甲型值本身);存档域 `forge_routes = {levels〔六路线等级〕, unlocked〔直购解锁清单〕, weapon/armor〔当前选中〕}`——初始持有与练满前一档为派生解锁不落档(派生单点 = forge_route_unlocked) |
| 路线 id / 存档域键名 | 锻造工坊实现层词汇(非玩家可见,2026-10-13 迭代 23 反哺落文登记):六路线 id = sword/spear/staff/light/heavy/ward(甲路线 id = 甲型值本身);存档域 `forge_routes = {levels〔六路线等级〕, unlocked〔直购解锁清单〕, weapon/armor〔当前选中〕}`——初始持有与练满前一档为派生解锁不落档(派生单点 = 解锁判定) |
## 道具体系
@@ -94,7 +94,7 @@
| 术语 | 定义 |
|---|---|
| `seal_missed` | 封印落空事件(原 `flag_missed` 换代):封印动作落在安全格上时发出,订阅面据此做限次与豁免判定(迭代 31 卡② 落地) |
| `seal_missed` | 封印落空事件(旧名已换代):封印动作落在安全格上时发出,订阅面据此做限次与豁免判定(迭代 31 卡② 落地) |
| `forgive_seal_miss` | 本场首次封印落空豁免——专长「完美保险」的效果类型,`domain=battle` 首例;有效误标=误标总数 − 豁免数,豁免不改写误标账(迭代 31 卡② 落地) |
## 美术表现
@@ -120,9 +120,9 @@
## 用语规范(2026-10-15 用户令立)
词面纪律的登记处。通用禁用词与选词以**简明技术中文(STC)词表**为权威:外部技能文件 `C:\Users\DK\.zcode\skills\simplified-technical-chinese\词表.md`,约 170 条,配检查脚本 check.py。
词面纪律的登记处。通用禁用词与选词以**简明技术中文(STC)词表**为权威:外部同名词表,约 170 条,配检查脚本。
本仓库的机器闸 = `tools/doc_term_audit.py`,已吸收本节项目裁项。**词表冻结**:本节与该闸的禁用词表不再扩充,扩表唯一入口=用户实读反馈并经用户裁决(由工程/文档设计改动批写入,agent 禁自行增词)。本节只登记两类裁项:A 已裁替换、B 豁免条款。历史退役词(雷格/正主/落籍等 7 组)见下方「退役词对照」节,不与 A 表重复。
本仓库的机器闸 = 用语审计(闸件清单唯一出处=process-conventions 运行与验证节),已吸收本节项目裁项。**词表冻结**:本节与该闸的禁用词表不再扩充,扩表唯一入口=用户实读反馈并经用户裁决(由工程/文档设计改动批写入,agent 禁自行增词)。本节只登记两类裁项:A 已裁替换、B 豁免条款。历史退役词(雷格/正主/落籍等 7 组)见下方「退役词对照」节,不与 A 表重复。
### A. 已裁替换(写新文本必须用「用」列)
@@ -148,7 +148,7 @@
1. **历史文本**:git 提交说明、裁决记录中引用用户原话的句子——保留原用词,不按 A 表追改。
2. **对照性文本**:「退役词对照」表本身、「原 ××」式更名记载、禁令引举句——旧词在这些位置是内容本身,不是残留。
3. **玩家可见专名与机制词**:按「对外命名纪律」节与各系统文档现行用语使用(标中/踩雷等机制词在文档内部照常用)。
4. **被检查的禁字不算使用**:守卫代码里作为检查对象的禁字字面量——`game/tests/unit/core/adventure_feats_test.gd` 的 `contains("旗")` 检查项、`game/tests/unit/presentation/ui_font_asset_test.gd` 的字形集负探针、`game/data/tables/feats.tres` 头注的「desc 禁『雷/旗』字面」、`tools/doc_term_audit.py` 的退役词表定义行——不属换代范围:被检查的字不是对该字的使用,改写等于自毁守卫。术语清扫的复扫口径按 **game/ 全部文件类型、不排除任何扩展名**执行(迭代 31 卡① 实测:金币/插旗/雷格/惩罚格/`flag` 均 0 命中,残留仅为上述保留面)。
4. **被检查的禁字不算使用**:守卫里作为检查对象的禁字字面量——核心层检字断言所检查的禁字本身、呈现层字形集负探针、`game/data/tables/feats.tres` 头注的「desc 禁『雷/旗』字面」、用语审计闸的退役词表定义行——不属换代范围:被检查的字不是对该字的使用,改写等于自毁守卫。术语清扫的复扫口径按 **game/ 全部文件类型、不排除任何扩展名**执行(迭代 31 卡① 实测:金币/插旗/雷格/惩罚格/`flag` 均 0 命中,残留仅为上述保留面)。
存量口径:A 表生效前已入库的正文不做强制清扫;文件后续被批次触碰时,顺带按 A 表换代。
@@ -168,11 +168,11 @@
| 插旗 | 封印(2026-10-18 用户裁:封印=正式动作名,全库统一,非比喻非「对外表达」别名) |
| 旗(游戏概念语境) | 封印印记(2026-10-18 用户裁:「旗」概念不存在——封印动作落下的印记称封印印记) |
| flag_*(代码契约键/标识符) | seal_*(2026-10-18 用户裁全族换代;迭代 31 卡① 已清零) |
| 系统级断言套件 / 冒烟全量 | 系统测试(2026-10-22 用户裁——标准四级测试层之一:启动真实工程走真实玩法路径的断言面;依据=提案正文 §二)(《提案-测试术语与层级重构方案》已退役,考古=git 历史——删除批 53075baa,删除前全稿见历史版本 b4da36a8) |
| 系统级断言套件 / 冒烟全量 | 系统测试(2026-10-22 用户裁——标准四级测试层之一:启动真实工程走真实玩法路径的断言面;依据=提案正文 §二)(《提案-测试术语与层级重构方案》已退役,考古=git 历史——删除批与删除前全稿均可在其中查得) |
| 单元套件 | 单元测试(2026-10-22 用户裁——标准四级测试层之一,「套件」单独成词非必要) |
| 启动探针 / 秒级冒烟探针 / L0–L3 | 冒烟测试(2026-10-22 用户裁——极小启动场景:能否启动、能否加载表、能否进主屏,零逻辑判定) |
| 轻闸 / 重闸 / 三查 | (随 2026-10-22 频率规则消亡,无替代词——检出工作区零测试;卡内只测自己改的东西;全量只在收尾与合回两个时机。机制词「去重闸」含「重闸」二字但与此无关,不在退役之列) |
| 魔法道具 | 秘宝(2026-10-26 用户裁入表:AUXILIARY_ITEMS 旧中文规范名,2026-10-05 已更名) |
| 魔法道具 | 秘宝(2026-10-26 用户裁入表:秘宝系统旧中文规范名,2026-10-05 已更名) |
| 罕见(档位名) | 稀有(2026-10-26 用户裁入表:旧三档档位名,现行四级第三档=稀有;散文形容词义不受限) |
| 通关 | 关卡完成(单关)/冒险成功(整局)——2026-10-26 用户裁:主体明确短语族替代歧义单义词 |
| 冒险终结 | 冒险落幕——2026-10-26 通关口径统一批 |
Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

+55 -231
View File
@@ -27,19 +27,14 @@ var levels_total := 0 # 序列总关数(读 level 表行
var master_seed := 0 # 本局主种子(摘要第五件事)
var summary := {} # 最近一次结算的冒险摘要(idle 后保留——重开才新生成)
var _runner: LevelRunner # 当前关卡行进器(每关新建——关卡域状态天然隔离)
var _pending_next_level := false # 大奖励已兑付、等 continue_to_next_level 确认
var _last_level_payload := {} # 最近一次关卡结束载荷(失败结算的败退节点明细来源——数值验证取数面)
var _last_treasure_cleared := 0 # additive(最近一次关卡末清空计数,summary 取数面)
var _treasure_unlocked := {} # aux 解锁门控集(params.treasure_unlocked 接收面)
var _attunement: Array[Variant] = [] # 同调装配集(params.attunement 接收面,start_level 外下传 LevelRunner)
var _save_manager = null # 断点承载注入(null = 不写断点;模拟/冒烟缺省)
var _resume_bp := {} # 续玩快照暂存(resume_adventure → _start_current_level 单跳传递)
var _loadout_seeded := false # 同调行已种标记(每冒险一次——首关 bind 时点投行;行跨关存活后续关零动作)
# ---- 三选一停点(编排迁 CurioStop 件——停点三态/刷新三源/凭证出箱/信号面)----
var _curio: CurioDeck = null # 令牌池件(_init 建;纯池——多重集/抽签/cap/凭证判定唯一宿主)
var _stop: CurioStop = null # 停点件(_init 建;每冒险一次——关卡换实例不换件)
var _refresh_bank: RefreshBank = null # 刷新账件(_init 建——三源账与付费报价;宿主预算注入与断点片段直收)
var _loadout: AttuneLoadout = null # 同调配装件(_init 建;充能单源化——物化行唯一事实源)
var _bp_store: BreakpointStore # 断点组装与回放件(_init 建;六成员+27 键登记单源+读写侧机组随件——宿主读写经件)
var adventure_inventory: TreasureItems # 冒险级秘宝库存(单源化——同调未用行跨关存活的承载面;关卡域语义归 level 使用面)
var _tree_rules: Array[Variant] = [] # 树 rule 键集(Fork 激活侧 effects 透传;下传 enc.tree_rules 消费面)
var _shop_mode := "legacy" # 商店模式("legacy"=固定三件加定价〔off 对照承载,缺省零扰动〕/"pool"=共享池抽 3 买 1 重抽;真实入口 main.gd 显式投 pool)
@@ -57,6 +52,8 @@ func _init(db_ref: ConfigDb, rng_ref: RngServiceCore) -> void:
_snapshot_breakpoint)
_loadout = AttuneLoadout.new(db, _attunement)
adventure_inventory = TreasureItems.new(db)
_bp_store = BreakpointStore.new({"db": db, "rng": rng, "stats": _stats, "wallet": _wallet,
"journal": _journal, "curio": _curio, "stop": _stop, "bank": _refresh_bank, "loadout": _loadout})
# 件出口(组件交出非委托壳——呈现/测量面取主角账三件与令牌池单点;领域拆分批接口块)
@@ -107,7 +104,7 @@ func start_adventure(seed_val: int, params: Dictionary = {}) -> bool:
_reset_curio_state()
levels_total = db.run.level.level_count() # 表访问收口(关数读 level 表行数)
level_index = 1
_pending_next_level = false
_bp_store._pending_next_level = false
_shop_mode = "pool" if String(params.get("shop_mode", "legacy")) == "pool" else "legacy" # 缺省 legacy(off 对照零扰动)
_treasure_unlocked = params.get("treasure_unlocked", {}) if params.get("treasure_unlocked", {}) is Dictionary else {}
_attunement = params.get("attunement", []) if params.get("attunement", []) is Array else [] # additive
@@ -115,7 +112,7 @@ func start_adventure(seed_val: int, params: Dictionary = {}) -> bool:
_refresh_bank.set_refresh_y(maxi(0, int(params.get("attune_refresh_y", 0)))) # additive(Y 冒险周期池)
_loadout.set_attunement(_attunement) # 装配集注入(活引用——种行面)
adventure_inventory.reset() # 冒险级库存重置(新局空库存)
_loadout_seeded = false # 同调行投行延至首关 bind 时点(库存就位后)
_bp_store._loadout_seeded = false # 同调行投行延至首关 bind 时点(库存就位后)
adventure_counters = {} # 冒险桶清零(效果引擎 adv_ 计数器宿主——冒险开始归零)
# 刷新练习开局注入(refresh_stock_grant 装配即得一次性加仓:
# 装配集 kind 分发扫描;只入存量账、临时账不动=V8 契约;resume 不重注入〔存量随断点已在〕)
@@ -152,99 +149,50 @@ func resume_adventure(bp: Dictionary, params: Dictionary = {}) -> bool:
return false
master_seed = int(bp.get("master_seed", 0))
rng.restore_adventure(master_seed, int(bp.get("rng_counter", 0)))
_resume_ledger(bp, params)
_resume_curio_state(bp)
_resume_params(bp, params)
_resume_counters(bp)
# ---- 断点回放(R2 整族归件——件侧语句入 _bp_store、宿主侧语句按原语句序留本壳,序逐步保形)----
_bp_store.restore_ledger(bp, params) # 续玩账面回填——主角账三件片段各还原各键(件侧;clamp 类夹 ≥0;日记在档=推导比对载入、缺键=旧档汇总直载)
summary = {}
levels_total = db.run.level.level_count() # 表访问收口(关数读 level 表行数)
level_index = int(bp.get("level_index", 1))
_bp_store._pending_next_level = false
_reset_curio_state() # 续玩三选一态回填前置清理(池与件计数归件、停点态归本类;桶归宿主字典)
_bp_store.restore_curio_state(bp) # 续玩三选一态回填(池余库/获取计数/特性持有集——件侧;dual_merge/keep_on_null 策略见 BREAKPOINT_FIELDS)
_bp_store.apply_resume_params(params) # 续玩参数面——数值账规范化与越界钳制(件侧)
_shop_mode = "pool" if String(params.get("shop_mode", "legacy")) == "pool" else "legacy" # 续玩参数面同 start_adventure(缺省 legacy)
_treasure_unlocked = params.get("treasure_unlocked", {}) if params.get("treasure_unlocked", {}) is Dictionary else {}
_attunement = params.get("attunement", []) if params.get("attunement", []) is Array else [] # additive
_refresh_bank.set_refresh_x_cap(_attune_refresh_x_total()) # 刷新账 X 基数预算注入(续玩参数面同 start)
_bp_store.restore_stop_bank_fragments(bp, params) # 停点件/刷新账片段回填(件侧——凭证计数;刷新存量/Y 池缺键回退参数面)
_tree_rules = params.get("tree_rules", []) if params.get("tree_rules", []) is Array else [] # A/B 面 rule 键集(续玩参数面同 start_adventure 同式,消费面 set_tree_rules 下传)
# 续玩计数器回填(adventure 域计数——缺键 = 旧版断点防御空集;_reset_curio_state 已清零在先——桶归宿主字典)
var bp_counters = _bp_store._bp_read("adventure_counters", bp)
if bp_counters is Dictionary:
adventure_counters = (bp_counters as Dictionary).duplicate(true)
var bp_pending: Dictionary[Variant, Variant] = bp.get("bonus_pending", {}) as Dictionary
var bp_result: Dictionary[Variant, Variant] = bp.get("bonus_result", {}) as Dictionary
if not bp_pending.is_empty():
_pending_next_level = true
_bp_store._pending_next_level = true
_state = State.RUNNING
_stop.restore_pending(bp_pending) # 选择停点直回(续玩不重跑关卡——信号经停点件中继)
return true
if not bp_result.is_empty():
_pending_next_level = true
_bp_store._pending_next_level = true
_stop.restore_resolved(bp_result) # 已兑付不重兑付只重发(置态+重发收编一步——信号面归停点件)
_state = State.RUNNING
return true
_resume_bp = bp.duplicate(true)
_bp_store._resume_bp = bp.duplicate(true)
# 充能读侧以行集为源(键值仅校验读数——回填时点在首关 bind 行集就位后,经 _loadout_on_level_inventory)
_loadout_seeded = false
_bp_store._loadout_seeded = false
_loadout.set_attunement(_attunement)
adventure_inventory.reset()
_state = State.RUNNING
return _start_current_level()
# 续玩账面回填(生命/特性/钱包/加算区/已购档/钥石/逐杀明细/真视——主角账三件片段各还原各键;
# bonus 子键 clamp 类夹 ≥0;日记在档=推导比对载入、缺键=旧档汇总直载)
func _resume_ledger(bp: Dictionary, params: Dictionary) -> void:
_stats.restore_fragment(bp, params)
_wallet.restore_fragment(bp, params)
_journal.restore_fragment(bp, params)
summary = {}
levels_total = db.run.level.level_count() # 表访问收口(关数读 level 表行数)
level_index = int(bp.get("level_index", 1))
_pending_next_level = false
# 续玩三选一态回填(池与件计数归件、停点态归本类;dual_merge/keep_on_null 策略见 BREAKPOINT_FIELDS)
func _resume_curio_state(bp: Dictionary) -> void:
_reset_curio_state()
var bp_taken: Dictionary[Variant, Variant] = bp.get("bonus_taken", {}) as Dictionary
for id in _curio.taken.keys():
_curio.taken[id] = maxi(0, int(bp_taken.get(id, 0)))
for id in bp_taken.keys():
_curio.taken[String(id)] = maxi(0, int(bp_taken.get(id, 0))) # 身份维键(relic:<feat_id>)随快照还原
# 令牌池余库还原(TP0 v2.2——快照缺键 = 旧版断点,保持满库重建态:旧档只读一版周期的防御口径;
# relic 令牌 feat_id 随还原)
var bp_deck = _bp_read("bonus_deck", bp)
if bp_deck is Array:
var restored: Array[Variant] = []
for t in (bp_deck as Array):
var tok: Dictionary[Variant, Variant] = t as Dictionary
var rtok := {"kind": String(tok.get("kind", "")), "tier": String(tok.get("tier", ""))}
if String(rtok["kind"]) == "relic":
rtok["feat_id"] = String(tok.get("feat_id", "")) # relic 令牌 feat_id 随还原
restored.append(rtok)
_curio.deck = restored
# 特性持有集还原(缺键 = 旧版断点防御空集——主角数值账字段单点)
_stats.feats = []
for r in (bp.get("relics", []) as Array):
_stats.feats.append(String(r))
# 续玩参数面回填(同 start_adventure 参数面;生命账本越界钳制在此落——clamp 类)
func _resume_params(bp: Dictionary, params: Dictionary) -> void:
_stats.rebase_override(params.get("hero_override", {})) # 续玩参数面同 start_adventure(规范化归数值账)
_stats.attack_type = String(params.get("attack_type", "")) # 续玩参数面同 start_adventure(账号层选中态随 resume 重注入)
_stats.armor_type = String(params.get("armor_type", ""))
# 生命账本越界钳制(T17——spawn 守卫 EC16 免疫):断点可能带出高于生效上限的账本值
#(如调试浮窗调高期写出的值,实例:hero_hp=28 > 基础 26)——恢复后钳到生效上限,
# 否则首战 spawn「hero_hp 入参越界」拒收 → 「敌人系统 spawn 被拒」fatal。钳制式单点归
# 数值账 clamp_hp_to_resume_cap(保守口径不含加算区——与原钳制式逐字同)。
_stats.clamp_hp_to_resume_cap(int(db.combat.hero.max_hp))
_shop_mode = "pool" if String(params.get("shop_mode", "legacy")) == "pool" else "legacy" # 续玩参数面同 start_adventure(缺省 legacy)
_treasure_unlocked = params.get("treasure_unlocked", {}) if params.get("treasure_unlocked", {}) is Dictionary else {}
_attunement = params.get("attunement", []) if params.get("attunement", []) is Array else [] # additive
_refresh_bank.set_refresh_x_cap(_attune_refresh_x_total()) # 刷新账 X 基数预算注入(续玩参数面同 start)
_stop.restore_fragment(bp, params) # 停点件片段回填(凭证计数)
_refresh_bank.restore_fragment(bp, params) # 刷新账片段回填(刷新存量/Y 池——Y 缺键回退参数面 params_fallback 类)
_tree_rules = params.get("tree_rules", []) if params.get("tree_rules", []) is Array else [] # A/B 面 rule 键集(续玩参数面同 start_adventure 同式,消费面 set_tree_rules 下传)
# 续玩计数器回填(冒险域计数——凭证计数/刷新存量/Y 池随停点件片段回填)
func _resume_counters(bp: Dictionary) -> void:
# adventure 域计数器回填(缺键 = 旧版断点防御空集;_reset_curio_state 已清零在先——桶归宿主字典)
var bp_counters = _bp_read("adventure_counters", bp)
if bp_counters is Dictionary:
adventure_counters = (bp_counters as Dictionary).duplicate(true)
func _reset_curio_state() -> void:
_curio.reset() # 池与件获取计数(池半归件;停点态归停点件下行清理)
_stop.reset_adventure_state()
_loadout_seeded = false
_bp_store._loadout_seeded = false
_stats.feats = []
adventure_counters = {}
@@ -263,7 +211,7 @@ func effective_max_hp() -> int:
# 断点承载注入(组合根冒险开始时调用;模拟/冒烟不注入 = 断点面整体静默)
func set_save_manager(sm: SaveManagerCore) -> void:
_save_manager = sm
_bp_store._save_manager = sm
# 当前关卡行进器读面(呈现层/冒烟用——每关新建实例,调用方须在 level_started 后重取)
@@ -278,13 +226,13 @@ func apply_rest(pct: int, hp: int, max_hp: int) -> int:
# 大奖励确认 → 进下一关(仅兑付后受理——零自动推进的冒险级停点;三选一未兑付拒绝推进)
func continue_to_next_level() -> bool:
if not _pending_next_level:
if not _bp_store._pending_next_level:
push_error("[冒险结构] continue_to_next_level 拒绝——无待确认的关卡推进")
return false
if _stop.curio_stop_pending():
push_error("[冒险结构] continue_to_next_level 拒绝——三选一停点未兑付(零自动推进契约)")
return false
_pending_next_level = false
_bp_store._pending_next_level = false
_stop.clear_resolved()
level_index += 1
return _start_current_level()
@@ -343,9 +291,9 @@ func _loadout_on_level_inventory() -> void:
var inv = _runner.treasure_inventory
if inv == null:
return
if not _loadout_seeded:
_loadout_seeded = true
var bp_charges: Variant = _bp_read("attunement_charges", _resume_bp, null) if not _resume_bp.is_empty() else null
if not _bp_store._loadout_seeded:
_bp_store._loadout_seeded = true
var bp_charges: Variant = _bp_store._bp_read("attunement_charges", _bp_store._resume_bp, null) if not _bp_store._resume_bp.is_empty() else null
if bp_charges is Dictionary:
_loadout.restore_fragment({"attunement_charges": bp_charges}, inv) # 旧档读侧:行集为源+键值校验读数
else:
@@ -368,8 +316,8 @@ func _loadout_on_level_inventory() -> void:
# apply_adventure_summary 逐关卡完成关次置位〕;末关 Boss 照常入账;明细随摘要 additive 键供结算面归因)
func _boss_keystone_drop(li: int) -> void:
var first := true
if _save_manager != null:
first = not _save_manager.meta_state.career_state().boss_first_kill.has(str(li))
if _bp_store._save_manager != null:
first = not _bp_store._save_manager.meta_state.career_state().boss_first_kill.has(str(li))
var row: Dictionary[Variant, Variant] = db.crossrun.meta.boss_keystone_row(li)
var amount: int = int(row.get("first_kill", 0)) if first else int(row.get("repeat_kill", 0))
_journal.record_keystone_drop({"level": li, "first": first, "amount": amount}) # 逐杀明细+累计单写原语
@@ -419,9 +367,9 @@ func _start_current_level() -> bool:
# 断点续玩分支:图由主种子+参数档重生成同图(产图与计数器号位无关,停点零重抽语义随之消解),
# resume_state 带停点句柄与已到序——重建到停点后经 present_resumed_choice 呈现(信号顺序契约同入口)。
var resume_state: Dictionary[Variant, Variant] = {}
if not _resume_bp.is_empty():
resume_state = {"node_id": int(_bp_read("node_id", _resume_bp, -1)),
"visited_ids": _bp_read("visited_ids", _resume_bp, []) as Array}
if not _bp_store._resume_bp.is_empty():
resume_state = {"node_id": int(_bp_store._bp_read("node_id", _bp_store._resume_bp, -1)),
"visited_ids": _bp_store._bp_read("visited_ids", _bp_store._resume_bp, []) as Array}
# 接口①开始关卡:生命经主角账共享交接(账面当前值即开局生命——冒险开始置满 / 大奖励回满已写好);
# 主角账三件与冒险桶注入(构造注入 ctx——拆件批 T3 收口形态)。
# defer_entry=true 起每关(含首关)——先 emit level_started(呈现层在
@@ -431,7 +379,7 @@ func _start_current_level() -> bool:
if ok:
_emit_level_started()
_present_level_entry(resume_state)
_resume_bp = {}
_bp_store._resume_bp = {}
return ok
@@ -455,7 +403,7 @@ func _present_level_entry(resume_state: Dictionary) -> void:
if resume_state.is_empty() or int(resume_state.get("node_id", -1)) < 0:
_runner.present_entry_choice()
else:
_runner.restore_treasure_items(_bp_read("aux_items", _resume_bp, []) as Array)
_runner.restore_treasure_items(_bp_store._bp_read("aux_items", _bp_store._resume_bp, []) as Array)
_runner.present_resumed_choice()
@@ -464,7 +412,7 @@ func _on_level_finished(payload: Dictionary) -> void:
if state != "running":
push_error("[冒险结构] 重复关卡结束宣布拒绝——state=%s(账本与摘要零变化)" % state)
return
_last_level_payload = payload.duplicate(true)
_bp_store._last_level_payload = payload.duplicate(true)
var result := String(payload.get("result", ""))
if result == "defeat":
_stats.hero_hp = 0 # 倒下记 0(生命账本战后回写口径)
@@ -473,7 +421,7 @@ func _on_level_finished(payload: Dictionary) -> void:
if result != "victory":
push_error("[冒险结构] 关卡结束结果出域: %s" % result)
return
_last_treasure_cleared = int(payload.get("aux_cleared", 0)) # additive(末关 summary 取数面)
_bp_store._last_treasure_cleared = int(payload.get("aux_cleared", 0)) # additive(末关 summary 取数面)
# Boss 钥石逐杀掉落(击杀掉落渠道,末关照常入账;首杀/复杀读 meta.tres boss_keystone)
_boss_keystone_drop(level_index)
if level_index < levels_total:
@@ -481,7 +429,7 @@ func _on_level_finished(payload: Dictionary) -> void:
#(信号同步派发——处理器内立即确认时 _pending_next_level 必须已就位);
# 停点件内部分回血先行 → 加权洗牌掷 3 → 三选一停点(顺序即契约——回血按当刻账本与上限结算,
# 选择停点零自动推进)。载荷_base 随附钱包读数(停点件零钱包依赖——GP 件入账回调仍走 grant_curio_gp)
_pending_next_level = true
_bp_store._pending_next_level = true
var stop_base: Dictionary[Variant, Variant] = payload.duplicate(true)
stop_base["gp"] = _wallet.gp
_stop.open_level_clear(stop_base)
@@ -499,7 +447,7 @@ func _settle(result: String) -> void:
"stopped_at": 0 if result == "completed" else level_index,
"keystone_total": _journal.keystone_gained(),
"master_seed": master_seed,
"aux_cleared_last": _last_treasure_cleared, # additive 扩签(末关清空反馈;非末关走 bonus 载荷)
"aux_cleared_last": _bp_store._last_treasure_cleared, # additive 扩签(末关清空反馈;非末关走 bonus 载荷)
"keystone_drops": _journal.keystone_drop_log(), # additive 扩签(逐杀掉落明细;settle 入账明细/复盘归因数据源)
"vision_used_delta": _journal.vision_used(), # additive 扩签(真视使用本局计数;settle 聚合入档)
"pool_stock": _pool_stock_snapshot(), # additive 扩签(终局池读数:清账前快照,商店买走 vs 奖励领走 vs 枯竭的终局面)
@@ -507,19 +455,19 @@ func _settle(result: String) -> void:
}
# 败退明细(数值验证工具取数面——tools/balance_verifier.py 止步节点分布数据源;
# 仅失败局附加,键缺省 = 未败退,既有五件事消费方零感知)
if result == "failed" and not _last_level_payload.is_empty():
if result == "failed" and not _bp_store._last_level_payload.is_empty():
summary["defeat"] = {
"level_index": level_index,
"node_id": int(_last_level_payload.get("node_id", -1)),
"node_type": String(_last_level_payload.get("node_type", "")),
"node_id": int(_bp_store._last_level_payload.get("node_id", -1)),
"node_type": String(_bp_store._last_level_payload.get("node_type", "")),
}
if _runner != null:
summary["gp_final"] = int(_runner.gp) # gp_final 清账前快照(终局面板取数源=runner 钱包单点)
_runner.close_wallet() # GP 冒险收束清零(三结局都清——经转发发 wallet_changed "clear" 供日志/呈现)
_reset_curio_state() # 三选一停点态收束清零(结算受理只算一次语义——重复宣布零变化)
if _save_manager != null:
_save_manager.clear_breakpoint() # 三结局清断点(退出冒险=放弃流程+清除断点)
_save_manager.write_to_disk()
if _bp_store._save_manager != null:
_bp_store._save_manager.clear_breakpoint() # 三结局清断点(退出冒险=放弃流程+清除断点)
_bp_store._save_manager.write_to_disk()
_state = State.SETTLING
adventure_finished.emit(summary)
_state = State.IDLE
@@ -530,131 +478,7 @@ func _on_level_choices_presented(_candidates: Array) -> void:
_snapshot_breakpoint()
# ---- 断点快照(字段登记单源:写侧拼装与读侧回退策略同登记一表)----
# 键序即快照键序(27 顶层键——写侧/读侧/键集断言三面同源)。读侧回退策略词表:
# plain 无特殊回退面(缺键取代码内缺省)/clamp 数值夹 ≥0/keep_on_null 缺键或类型不符保持既有态
# dual_merge 双向合并(bonus_taken)/params_fallback 缺键回退参数面(attune_refresh_y)
# token_migration 旧版候选形态迁移(bonus_pending.candidates)
# 注入缺省 null = 整面静默(模拟/冒烟零扰动)。
const BREAKPOINT_FIELDS := {
"level_index": {"strategy": "plain"},
"node_id": {"strategy": "plain"},
"hero_hp": {"strategy": "clamp"},
"bonus": {"strategy": "clamp"},
"gp": {"strategy": "plain"},
"shop_purchased": {"strategy": "plain"},
"shop_shelf": {"strategy": "plain"},
"shop_visit_buys": {"strategy": "plain"},
"attunement_charges": {"strategy": "keep_on_null"},
"graph_gen_v2": {"strategy": "plain"},
"master_seed": {"strategy": "plain"},
"rng_counter": {"strategy": "plain"},
"keystone": {"strategy": "plain"},
"visited_ids": {"strategy": "plain"},
"aux_items": {"strategy": "plain"},
"bonus_taken": {"strategy": "dual_merge"},
"bonus_deck": {"strategy": "keep_on_null"},
"relics": {"strategy": "plain"},
"bonus_pending": {"strategy": "token_migration"},
"feat_ticket_pity": {"strategy": "plain"},
"feat_ticket_sold": {"strategy": "plain"},
"adventure_counters": {"strategy": "keep_on_null"},
"vision_counter_used": {"strategy": "clamp"},
"refresh_stock": {"strategy": "clamp"},
"attune_refresh_y": {"strategy": "params_fallback"},
"bonus_result": {"strategy": "plain"},
"keystone_drops": {"strategy": "plain"},
"gain_journal": {"strategy": "plain"}, # 获得日记(拆件批 T4 扩列——唯一声明的断点扩展;旧档缺键=汇总直载跳过比对)
}
# ---- 断点快照委托(组装与读侧策略机组归 breakpoint_store 件——六成员+27 键登记单源随件;
# 本壳一行转发:CurioStop 构造注入的 Callable 目标与本类 _on_level_choices_presented 调用点零改)----
func _snapshot_breakpoint() -> void:
if _save_manager == null or state != "running":
return
var parts: Dictionary[Variant, Variant] = _bp_parts()
var bp: Dictionary[Variant, Variant] = {}
for key in BREAKPOINT_FIELDS.keys():
bp[key] = parts[key]
_save_manager.set_breakpoint(bp)
_save_manager.write_to_disk()
# 断点写侧取值(键集以 BREAKPOINT_FIELDS 为准——未登记键即取值越界,fail-fast)
func _bp_parts() -> Dictionary[Variant, Variant]:
var stats_frag: Dictionary[Variant, Variant] = _stats.breakpoint_fragment()
var wallet_frag: Dictionary[Variant, Variant] = _wallet.breakpoint_fragment()
var journal_frag: Dictionary[Variant, Variant] = _journal.breakpoint_fragment()
var bank_frag: Dictionary[Variant, Variant] = _refresh_bank.breakpoint_fragment()
var stop_frag: Dictionary[Variant, Variant] = _stop.breakpoint_fragment()
var level_frag: Dictionary[Variant, Variant] = _runner.breakpoint_fragment() if _runner != null else {
"node_id": -1, "visited_ids": [] as Array, "aux_items": [] as Array,
"shop_shelf": [] as Array, "shop_visit_buys": 0} # 三选一停点续玩分支 _runner 为 null——节点域按缺省落档
# 该两态的续玩只消费 bonus_* 附随件(选择停点/已兑付停点快照)
var parts: Dictionary[Variant, Variant] = {
"level_index": level_index,
"node_id": int(level_frag.get("node_id", -1)),
"hero_hp": int(stats_frag.get("hero_hp", 0)),
"bonus": journal_frag.get("bonus", {}),
"gp": int(wallet_frag.get("gp", 0)),
"shop_purchased": journal_frag.get("shop_purchased", {}),
"shop_shelf": level_frag.get("shop_shelf", []), # 货架入断点(离开店/非店停点 = 空架合法态)
"shop_visit_buys": int(level_frag.get("shop_visit_buys", 0)), # 本次进店已购次数(A 链定价输入)
"attunement_charges": (_loadout.breakpoint_fragment(_runner.treasure_inventory) if _runner != null and _runner.treasure_inventory != null else {"attunement_charges": {}}).get("attunement_charges", {}), # 同调主动件充能余量随断点(行派生——save v4 域键名策略不变)
"graph_gen_v2": 1, # 生成图换代代差标记(缺键 = 换代前旧断点 → resume 显式拒绝)
"master_seed": master_seed,
"rng_counter": rng.counter(),
"keystone": int(journal_frag.get("keystone", 0)),
"visited_ids": level_frag.get("visited_ids", []),
"aux_items": level_frag.get("aux_items", []),
"bonus_taken": _curio.taken.duplicate(true), # 三选一件获取次数(kind 维度派生账本——断点附随件与读数承载)
"bonus_deck": _curio.deck.duplicate(true), # 令牌池余库(TP0 v2.2——池消耗即上限,续玩余库逐枚还原)
"relics": stats_frag.get("relics", []), # 特性持有集(局内随机渠道获得态续玩防丢失)
"bonus_pending": stop_frag.get("bonus_pending", {}), # 三选一停点态(空 = 无停点——选择停点可中断契约)
"feat_ticket_pity": int(stop_frag.get("feat_ticket_pity", 0)), # T5 专长凭证保底计数(扩列向后兼容——旧档缺键缺省 0)
"feat_ticket_sold": int(stop_frag.get("feat_ticket_sold", 0)), # T5 专长凭证限购计数(同上)
"adventure_counters": adventure_counters.duplicate(true), # adventure 域计数器随断点(续玩跨战账不丢——桶归宿主字典)
"vision_counter_used": int(journal_frag.get("vision_counter_used", 0)), # 真视使用计数随断点(续玩跨战账不丢)
"refresh_stock": int(bank_frag.get("refresh_stock", 0)), # 刷新存量账随断点
"attune_refresh_y": int(bank_frag.get("attune_refresh_y", 0)), # Y 冒险周期池余量随断点(扩列向后兼容——旧档缺键回退参数面)
"bonus_result": stop_frag.get("bonus_result", {}), # 已兑付待推进态(空 = 无——中断续玩不重兑付)
"keystone_drops": journal_frag.get("keystone_drops", []), # 逐杀掉落明细(摘要归因续接)
"gain_journal": journal_frag.get("gain_journal", {}), # 获得日记(唯一声明的断点扩列——日记为现行事实源)
}
# 拼盘完整性自断言(fail-fast——片段并集与登记键集不符即中止落盘)
var stray: Array[Variant] = []
for key in parts.keys():
if not BREAKPOINT_FIELDS.has(key):
stray.append(key)
if not stray.is_empty():
push_error("[冒险结构] 断点拼盘含未登记键: %s(fail-fast——片段与登记单源失同步)" % str(stray))
return parts
# 读侧单点(BREAKPOINT_FIELDS 策略标签分发;未登记键 fail-fast 不静默按 plain 兜)。
# 二次消费面(_start_current_level 经 _resume_bp 取 node_id/visited_ids/aux_items)同走此口。
func _bp_read(key: String, bp: Dictionary, fallback: Variant = null) -> Variant:
if not BREAKPOINT_FIELDS.has(key):
push_error("[冒险结构] 断点字段未登记(读侧): %s" % key)
var v: Variant = bp.get(key, fallback)
if _bp_strategy(key) == "keep_on_null" and v != null and not (v is Dictionary or v is Array):
return null # 类型不符——保持既有态(调用方跳过覆盖)
return v
# 读侧策略标签(BREAKPOINT_FIELDS 读侧消费面单点)
func _bp_strategy(key: String) -> String:
return String((BREAKPOINT_FIELDS.get(key, {}) as Dictionary).get("strategy", "plain"))
# 数值类读侧(clamp 夹 ≥0 / params_fallback 断点缺键回退参数面整额注入 / plain 直取)
func _bp_read_int(key: String, bp: Dictionary, fallback: int, params: Dictionary = {}) -> int:
match _bp_strategy(key):
"clamp":
return maxi(0, int(bp.get(key, fallback)))
"params_fallback":
return maxi(0, int(bp.get(key, int(params.get(key, fallback)))))
_:
return int(bp.get(key, fallback))
_bp_store.snapshot(state, level_index, master_seed, _runner, adventure_counters)
+13 -131
View File
@@ -36,10 +36,10 @@ const SOURCE_EXEMPT_CLASSES := ["hero_attack", "enemy_action", "clear_reward", "
var db: ConfigDb
var rng: RngServiceCore
# E1 封装收口:协作对象 board_generator/enemy_system/status_effects/reward_economy 私有化——跨层读取一律经 presentation_snapshot()/diagnostic_snapshot() 成文出口。
# E1 封装收口:协作对象 enemy_system/status_effects/reward_economy 私有化——跨层读取一律经 presentation_snapshot()/diagnostic_snapshot() 成文出口。
# minesweeper/action_economy 保持公有 = 架构文档 API Boundaries 的 HUD框架消费面(意图提交 settle_batch + compute_move_path
# 只读;ap/rap/相位读取)——非本文档登记的契约面,勿增新用途。
var _board_generator: BoardGenerator
# 装板域(BoardGenerator+装板六函数族)已拆 BoardInstaller——生成器实例随件自建,宿主零成员。
var minesweeper: MinesweeperRules
var action_economy: ActionEconomy
var _enemy_system: UnitContainer
@@ -230,13 +230,12 @@ var _hero_atk := 0 # 主角攻击基值快照(encounte
func _init(db_ref: ConfigDb, rng_ref: RngServiceCore) -> void:
db = db_ref
rng = rng_ref
_board_generator = BoardGenerator.new()
action_economy = ActionEconomy.new(db)
minesweeper = MinesweeperRules.new(db, action_economy)
_enemy_system = UnitContainer.new(db)
_status_effects = StatusContainer.new(db)
_reward_economy = RewardEconomy.new(db, rng)
_board_generator.fatal_handler = _fatal; _reward_economy.fatal_handler = _fatal # 协作件违约→本类 _fatal 封印(单点接线)
_reward_economy.fatal_handler = _fatal # 协作件违约→本类 _fatal 封印(单点接线)
_damage = DamageController.new(db, rng, _enemy_system, _status_effects)
_damage.emit_row_cb = _emit_row # 行协议归属本类(9 类行协议 + 来源断言不外泄)
_fx_host = BattleFxHost.new({"db": db, "rng": rng, "minesweeper": minesweeper, "action_economy": action_economy,
@@ -268,7 +267,7 @@ func begin_battle(enc: Dictionary) -> bool:
return false
if not _begin_battle_accept(enc):
return false
if not _install_new_board():
if not _install_and_reset():
return false
_reset_round_facts() # 首板 install 的初始展开事件不入轮 facts(resource 恒 false 的双保险)
_begin_battle_fx_state(enc)
@@ -411,34 +410,14 @@ func _begin_battle_preview_economy(enc: Dictionary) -> void:
action_economy.grant_reserve_ap(voucher_rap)
func _install_new_board(during_round := false) -> bool:
var stream: RandomNumberGenerator = rng.open_stream("board_gen")
var board: BoardData = _board_generator.generate(int(encounter.level_index), int(encounter.node_depth), stream, db)
if board == null:
# ---- 装板受理薄壳(BoardInstaller 拆件后的宿主承接面——begin_battle/中途刷新/轮内刷新三调用点唯一入口)----
# 件内装板(生成→全局变异决议→装板受理→资源摇号→变异布置)成功后执行宿主态复位:五处计数清零+
# 板序推进+board_changed 发射+秘宝叠加层退役——时序逐字;复位职责留宿主(成员单点),不随件。
func _install_and_reset(during_round := false) -> bool:
var installer := BoardInstaller.new({"db": db, "rng": rng, "minesweeper": minesweeper,
"reward_economy": _reward_economy, "encounter": encounter, "fatal_cb": _fatal})
if not installer.install(during_round):
return false
# 全局作用域变异决议(装板序内前置于 roll_board:图级偏斜旋钮须在资源摇号前定型——详见 _resolve_global_variant)
_resolve_global_variant(board)
var res: Dictionary[Variant, Variant] = minesweeper.install_board(board, during_round)
if not res.accepted:
_fatal("排雷玩法 install 拒绝(不变式违例): %s" % str(res))
return false
# 地图战斗资源 义务⑥:roll_board 恰一次(install 后、挖掘前);资格格 = 全部非封锁格(安全格 + 危险格,雷安同池)
var r0 := {}
for c in board.compute_r0():
r0[c] = true
var eligible: Array[Dictionary] = []
for c in board.safe_cells():
if not r0.has(c):
eligible.append({"cell": c})
for c in board.mines.keys():
if not r0.has(c):
eligible.append({"cell": c})
if not _reward_economy.roll_board(eligible):
_fatal("地图战斗资源 roll_board 被拒")
return false
# 地形变异 布置段(棋盘设置顺序第 4 步:生成棋盘 → 打开状态初始化 →
# 战斗资源格设置 → 变异格设置)——布置在初始展开与资源格之后,变异天然不落已开区
_place_variants(board)
_seal_consumed.clear() # 换图新雷 = 新实例,资格自然重置(行动经济 Rule 8)
_seal_miss_seen.clear()
_perfect_hit_true = 0 # 整图完美计数随 install 重置
@@ -452,103 +431,6 @@ func _install_new_board(during_round := false) -> bool:
return true
# ---- 全局作用域变异 决议(装板序内 roll_board 之前)----
# boss/elite 图命中全局型:写整图 board_variants(恰一行)+ 注入资源面偏斜旋钮(图级投影在
# RewardEconomy.roll_board 消费);不消费 variant_place 流(全局取用确定性——零取号合法态)。
# 全局池空(含 L1 Boss 免疫/unlock 门控未达):字段留空、旋钮归零——_place_variants 原路走
# region 布置 = 兜底回落合法态(防配置缺行静默裸奔——provisional)。
func _resolve_global_variant(board: BoardData) -> void:
board.board_variants.clear()
_reward_economy.board_skew = 0
var row: Dictionary[Variant, Variant] = db.combat.variation.global_variant_row(int(encounter.level_index), String(board.board_type),
String(encounter.get("node_type", "")))
if row.is_empty():
return
board.board_variants = [String(row.variant_id)]
_reward_economy.board_skew = int(row.get("effect_value", 0))
# ---- 地形变异 布置段(棋盘设置顺序第 4 步)----
# 候选池门控(unlock_level ≤ 关卡序号 + board_types 与本地形交集,∅ 通配)经 config_db.variant_pool;
# 池空 = 合法态,静默零布置(框架 P0 口径不变)。零特判:本段只写格子变异数据快照,不改扫雷规则本体。
# 候选格域 = 安全格 − 初始展开区(伤害型 placement=closed_only 的结构保障——布置发生在初始展开之后,
# 已开格天然排除);危险格不吃变异(挖雷一层惩罚 + 变异伤害双层叠罚污染逐行归因,首版排除——provisional)。
# 每图至多一种类型(候选池内均匀选一);数量 = round(候选池格数×percent) +
# (关卡序号−1)×per_level_bonus——基数为候选池而非总格数(percent 语义 = 占可挖格比例,
# 关卡递增由 per_level_bonus 绝对格数承载);连通片生长(8 邻),单片 ≤ pack_max。
# 替换制:整图 board_variants 非空 = 本图已带全局型,跳过 region 布置(详见 _resolve_global_variant)。
func _place_variants(board: BoardData) -> void:
if not board.board_variants.is_empty():
return
var pool: Array[Variant] = db.combat.variation.variant_pool(int(encounter.level_index), String(board.board_type))
if pool.is_empty():
return
var r0 := {}
for c in board.compute_r0():
r0[c] = true
var candidates: Array[Vector2i] = []
for c in board.safe_cells():
if not r0.has(c):
candidates.append(c)
if candidates.is_empty():
return
var stream: RandomNumberGenerator = rng.open_stream("variant_place") # 一板恰一 scope(换图/刷新图各取号一次)
var vrow: Dictionary[Variant, Variant] = pool[stream.randi_range(0, pool.size() - 1)]
var total: int = int(round(float(candidates.size()) * float(db.combat.variation.percent_of_cells) / 100.0)) \
+ (int(encounter.level_index) - 1) * int(db.combat.variation.per_level_bonus)
total = mini(total, candidates.size())
_place_variants_apply(board, candidates, stream, vrow, total)
# 变异片生长施加面(布置域=候选格,数量=total,vrow 单型贯穿;取号序=stream 顺序消费)
func _place_variants_apply(board: BoardData, candidates: Array[Vector2i], stream: RandomNumberGenerator, vrow: Dictionary, total: int) -> void:
var placed := {}
while placed.size() < total:
var pack_size: int = mini(total - placed.size(), stream.randi_range(2, int(db.combat.variation.pack_max)))
var free: Array[Vector2i] = []
for c in candidates:
# 新片种子/生长格禁与其他已布片 8 邻贴接——否则两片粘连成一个超 pack_max 的连通分量
# (R3 随机流下实测暴露:独立生长的相邻片合流击穿单片上限断言)
if placed.has(c) or _adjacent_to_packs(board, placed, c):
continue
free.append(c)
if free.is_empty():
break # 生长域耗尽——该片就地收束(数量不足总目标为合法态,候选域碎片化时触发)
var seed_c: Vector2i = free[stream.randi_range(0, free.size() - 1)]
placed[seed_c] = true
var pack: Array[Variant] = [seed_c]
var pack_set := {seed_c: true}
while pack.size() < pack_size:
var fringe := _variants_fringe(board, pack, candidates, placed, pack_set)
if fringe.is_empty():
break # 生长域耗尽——该片就地收束(数量不足总目标为合法态,候选域碎片化时触发)
var nxt: Vector2i = fringe[stream.randi_range(0, fringe.size() - 1)]
placed[nxt] = true
pack_set[nxt] = true
pack.append(nxt)
for c in placed.keys():
board.variants[c] = [String(vrow.variant_id)]
# 片生长待选格收集(本片内各生长格的 8 邻候选并集——未布置、未在途、不与他片贴接)
func _variants_fringe(board: BoardData, pack: Array, candidates: Array[Vector2i], placed: Dictionary, pack_set: Dictionary) -> Array[Vector2i]:
var fringe: Array[Vector2i] = []
for c in pack:
for n in board.neighbors8(c):
if candidates.has(n) and not placed.has(n) and not fringe.has(n) \
and not _adjacent_to_packs(board, placed, n, pack_set):
fringe.append(n)
return fringe
# 候选格是否与其他已布片(own_pack 之外的 placed 格)8 邻贴接——片间隔离保证连通分量 = 单片 ≤ pack_max
func _adjacent_to_packs(board: BoardData, placed: Dictionary, c: Vector2i, own_pack: Dictionary = {}) -> bool:
for m in board.neighbors8(c):
if placed.has(m) and not own_pack.has(m):
return true
return false
# ---- 事件缓冲(轮 facts 收集;结算触发 = Waiting 相位编排点,不依赖到达序)----
func _on_cell_revealed(evt: Dictionary) -> void:
@@ -798,7 +680,7 @@ func _exit_distribution() -> void:
if mode == "new_board":
_reward_economy.retire_mapping()
minesweeper.retire_board()
if not _install_new_board():
if not _install_and_reset():
_fatal("换图编排失败")
return
# 工兵晨令续队直调拆除(内容数据驱动扩展批 T4——round_start 订阅行承载,见 begin_battle 注)
@@ -832,7 +714,7 @@ func player_request_refresh() -> bool:
_refresh_used_this_round += 1
_reward_economy.retire_mapping() # 旧图批次退役(地图战斗资源 Ready→retired;E6 新批重置前提)
minesweeper.retire_board(true) # 旧板退役(轮内通道)
return _install_new_board(true) # 当场换图——失败即编排违例 fail-fast
return _install_and_reset(true) # 当场换图——失败即编排违例 fail-fast
func _battle_over(result: String) -> void:
+167
View File
@@ -0,0 +1,167 @@
## 棋盘安装与变异布置域件(B1 域·BoardInstaller):生成受理、全局作用域变异决议、装板受理、
## 资源摇号资格域组装(roll_board 恰一次——install 后、挖掘前)、region 变异决议与连通片布置。
## 棋盘设置顺序 = 生成棋盘 → 打开状态初始化 → 战斗资源格设置 → 变异格设置(布置在初始展开与
## 资源格之后,变异天然不落已开区)。宿主侧装板后状态复位(封印/完美计数清零、板序推进、
## board_changed 发射、秘宝叠加层退役)留宿主薄壳——本件零复位职责。零 UI 零 await;
## 随机只经注入 RngServiceCore 的 board_gen/variant_place 两封闭流(流名与开流时点不变,
## 生成器只消费传入流——同种子同输入逐位复现)。
class_name BoardInstaller
extends RefCounted
var db: ConfigDb
var rng: RngServiceCore
var minesweeper: MinesweeperRules
var reward_economy: RewardEconomy
var encounter: Dictionary[String, Variant] # 宿主 encounter 同对象引用(assign 原地变异——跨战活引用)
var fatal_cb: Callable # 协作件违约→宿主 _fatal 封印(单点接线——BoardGenerator 同款)
var generator: BoardGenerator # 件内自建自接线(原宿主 _board_generator 成员随件迁移)
func _init(bundle: Dictionary) -> void:
for k in ["db", "rng", "minesweeper", "reward_economy", "encounter", "fatal_cb"]:
assert(bundle.has(k), "[装板域件] 引用束缺键: %s" % k)
db = bundle.db
rng = bundle.rng
minesweeper = bundle.minesweeper
reward_economy = bundle.reward_economy
encounter = bundle.encounter
fatal_cb = bundle.fatal_cb
generator = BoardGenerator.new()
generator.fatal_handler = fatal_cb # 协作件违约→宿主 _fatal 封印(单点接线)
func _fatal(msg: String) -> void:
if fatal_cb.is_valid():
fatal_cb.call(msg) # 组装层注入 orchestrator._fatal(封印传导,不绕第二中止通道)
else:
push_error(msg)
assert(false, msg)
# 装板单入口(生成 → 全局变异决议 → 装板受理 → 资源摇号 → 变异布置);
# 宿主态复位归宿主薄壳(_install_and_reset)——本件返回即装板完成、复位未行。
func install(during_round := false) -> bool:
var stream: RandomNumberGenerator = rng.open_stream("board_gen")
var board: BoardData = generator.generate(int(encounter.level_index), int(encounter.node_depth), stream, db)
if board == null:
return false
# 全局作用域变异决议(装板序内前置于 roll_board:图级偏斜旋钮须在资源摇号前定型——详见 _resolve_global_variant)
_resolve_global_variant(board)
var res: Dictionary[Variant, Variant] = minesweeper.install_board(board, during_round)
if not res.accepted:
_fatal("排雷玩法 install 拒绝(不变式违例): %s" % str(res))
return false
# 地图战斗资源 义务⑥:roll_board 恰一次(install 后、挖掘前);资格格 = 全部非封锁格(安全格 + 危险格,雷安同池)
var r0 := {}
for c in board.compute_r0():
r0[c] = true
var eligible: Array[Dictionary] = []
for c in board.safe_cells():
if not r0.has(c):
eligible.append({"cell": c})
for c in board.mines.keys():
if not r0.has(c):
eligible.append({"cell": c})
if not reward_economy.roll_board(eligible):
_fatal("地图战斗资源 roll_board 被拒")
return false
# 地形变异 布置段(棋盘设置顺序第 4 步)——布置在初始展开与资源格之后,变异天然不落已开区
_place_variants(board)
return true
# ---- 全局作用域变异 决议(装板序内 roll_board 之前)----
# boss/elite 图命中全局型:写整图 board_variants(恰一行)+ 注入资源面偏斜旋钮(图级投影在
# RewardEconomy.roll_board 消费);不消费 variant_place 流(全局取用确定性——零取号合法态)。
# 全局池空(含 L1 Boss 免疫/unlock 门控未达):字段留空、旋钮归零——_place_variants 原路走
# region 布置 = 兜底回落合法态(防配置缺行静默裸奔——provisional)。
func _resolve_global_variant(board: BoardData) -> void:
board.board_variants.clear()
reward_economy.board_skew = 0
var row: Dictionary[Variant, Variant] = db.combat.variation.global_variant_row(int(encounter.level_index), String(board.board_type),
String(encounter.get("node_type", "")))
if row.is_empty():
return
board.board_variants = [String(row.variant_id)]
reward_economy.board_skew = int(row.get("effect_value", 0))
# ---- 地形变异 布置段(棋盘设置顺序第 4 步)----
# 候选池门控(unlock_level ≤ 关卡序号 + board_types 与本地形交集,∅ 通配)经 config_db.variant_pool;
# 池空 = 合法态,静默零布置(框架 P0 口径不变)。零特判:本段只写格子变异数据快照,不改扫雷规则本体。
# 候选格域 = 安全格 − 初始展开区(伤害型 placement=closed_only 的结构保障——布置发生在初始展开之后,
# 已开格天然排除);危险格不吃变异(挖雷一层惩罚 + 变异伤害双层叠罚污染逐行归因,首版排除——provisional)。
# 每图至多一种类型(候选池内均匀选一);数量 = round(候选池格数×percent) +
# (关卡序号−1)×per_level_bonus——基数为候选池而非总格数(percent 语义 = 占可挖格比例,
# 关卡递增由 per_level_bonus 绝对格数承载);连通片生长(8 邻),单片 ≤ pack_max。
# 替换制:整图 board_variants 非空 = 本图已带全局型,跳过 region 布置(详见 _resolve_global_variant)。
func _place_variants(board: BoardData) -> void:
if not board.board_variants.is_empty():
return
var pool: Array[Variant] = db.combat.variation.variant_pool(int(encounter.level_index), String(board.board_type))
if pool.is_empty():
return
var r0 := {}
for c in board.compute_r0():
r0[c] = true
var candidates: Array[Vector2i] = []
for c in board.safe_cells():
if not r0.has(c):
candidates.append(c)
if candidates.is_empty():
return
var stream: RandomNumberGenerator = rng.open_stream("variant_place") # 一板恰一 scope(换图/刷新图各取号一次)
var vrow: Dictionary[Variant, Variant] = pool[stream.randi_range(0, pool.size() - 1)]
var total: int = int(round(float(candidates.size()) * float(db.combat.variation.percent_of_cells) / 100.0)) \
+ (int(encounter.level_index) - 1) * int(db.combat.variation.per_level_bonus)
total = mini(total, candidates.size())
_place_variants_apply(board, candidates, stream, vrow, total)
# 变异片生长施加面(布置域=候选格,数量=total,vrow 单型贯穿;取号序=stream 顺序消费)
func _place_variants_apply(board: BoardData, candidates: Array[Vector2i], stream: RandomNumberGenerator, vrow: Dictionary, total: int) -> void:
var placed := {}
while placed.size() < total:
var pack_size: int = mini(total - placed.size(), stream.randi_range(2, int(db.combat.variation.pack_max)))
var free: Array[Vector2i] = []
for c in candidates:
# 新片种子/生长格禁与其他已布片 8 邻贴接——否则两片粘连成一个超 pack_max 的连通分量
# (R3 随机流下实测暴露:独立生长的相邻片合流击穿单片上限断言)
if placed.has(c) or _adjacent_to_packs(board, placed, c):
continue
free.append(c)
if free.is_empty():
break # 生长域耗尽——该片就地收束(数量不足总目标为合法态,候选域碎片化时触发)
var seed_c: Vector2i = free[stream.randi_range(0, free.size() - 1)]
placed[seed_c] = true
var pack: Array[Variant] = [seed_c]
var pack_set := {seed_c: true}
while pack.size() < pack_size:
var fringe := _variants_fringe(board, pack, candidates, placed, pack_set)
if fringe.is_empty():
break # 生长域耗尽——该片就地收束(数量不足总目标为合法态,候选域碎片化时触发)
var nxt: Vector2i = fringe[stream.randi_range(0, fringe.size() - 1)]
placed[nxt] = true
pack_set[nxt] = true
pack.append(nxt)
for c in placed.keys():
board.variants[c] = [String(vrow.variant_id)]
# 片生长待选格收集(本片内各生长格的 8 邻候选并集——未布置、未在途、不与他片贴接)
func _variants_fringe(board: BoardData, pack: Array, candidates: Array[Vector2i], placed: Dictionary, pack_set: Dictionary) -> Array[Vector2i]:
var fringe: Array[Vector2i] = []
for c in pack:
for n in board.neighbors8(c):
if candidates.has(n) and not placed.has(n) and not fringe.has(n) \
and not _adjacent_to_packs(board, placed, n, pack_set):
fringe.append(n)
return fringe
# 候选格是否与其他已布片(own_pack 之外的 placed 格)8 邻贴接——片间隔离保证连通分量 = 单片 ≤ pack_max
func _adjacent_to_packs(board: BoardData, placed: Dictionary, c: Vector2i, own_pack: Dictionary = {}) -> bool:
for m in board.neighbors8(c):
if placed.has(m) and not own_pack.has(m):
return true
return false
+1
View File
@@ -0,0 +1 @@
uid://di6u170vqf8ae
+218
View File
@@ -0,0 +1,218 @@
## VERTICAL SLICE - NOT FOR PRODUCTION
## 存档断点组装与回放唯一承载(AdventureRunner 拆件——单一变化原因=断点快照键面与回放策略):
## 断点快照拼盘、回放回填、读侧策略分发;BREAKPOINT_FIELDS 27 键登记单源随件(键名/策略标签/键序冻结)。
## 构造=引用束字典注入(db/rng/主角账三件/curio/stop/bank/loadout——件禁反向持宿主);
## 快照宿主输入(state/level_index/master_seed/runner/adventure_counters)逐调传参;
## resume_adventure 留宿主(壳+宿主侧回填语句——所有权缝分家,语句序逐步保形)。
class_name BreakpointStore
extends RefCounted
# ---- 断点快照(字段登记单源:写侧拼装与读侧回退策略同登记一表)----
# 键序即快照键序(27 顶层键——写侧/读侧/键集断言三面同源)。读侧回退策略词表:
# plain 无特殊回退面(缺键取代码内缺省)/clamp 数值夹 ≥0/keep_on_null 缺键或类型不符保持既有态
# dual_merge 双向合并(bonus_taken)/params_fallback 缺键回退参数面(attune_refresh_y)
# token_migration 旧版候选形态迁移(bonus_pending.candidates)
# 注入缺省 null = 整面静默(模拟/冒烟零扰动)。
const BREAKPOINT_FIELDS := {
"level_index": {"strategy": "plain"},
"node_id": {"strategy": "plain"},
"hero_hp": {"strategy": "clamp"},
"bonus": {"strategy": "clamp"},
"gp": {"strategy": "plain"},
"shop_purchased": {"strategy": "plain"},
"shop_shelf": {"strategy": "plain"},
"shop_visit_buys": {"strategy": "plain"},
"attunement_charges": {"strategy": "keep_on_null"},
"graph_gen_v2": {"strategy": "plain"},
"master_seed": {"strategy": "plain"},
"rng_counter": {"strategy": "plain"},
"keystone": {"strategy": "plain"},
"visited_ids": {"strategy": "plain"},
"aux_items": {"strategy": "plain"},
"bonus_taken": {"strategy": "dual_merge"},
"bonus_deck": {"strategy": "keep_on_null"},
"relics": {"strategy": "plain"},
"bonus_pending": {"strategy": "token_migration"},
"feat_ticket_pity": {"strategy": "plain"},
"feat_ticket_sold": {"strategy": "plain"},
"adventure_counters": {"strategy": "keep_on_null"},
"vision_counter_used": {"strategy": "clamp"},
"refresh_stock": {"strategy": "clamp"},
"attune_refresh_y": {"strategy": "params_fallback"},
"bonus_result": {"strategy": "plain"},
"keystone_drops": {"strategy": "plain"},
"gain_journal": {"strategy": "plain"}, # 获得日记(拆件批 T4 扩列——唯一声明的断点扩展;旧档缺键=汇总直载跳过比对)
}
# 引用束(宿主构造注入——成员名与宿主侧原名一致,迁移函数体逐字)
var db: ConfigDb
var rng: RngServiceCore
var _stats: HeroStats
var _wallet: GpWallet
var _journal: GainJournal
var _curio: CurioDeck = null # 令牌池件(池余库/获取计数随断点)
var _stop: CurioStop = null # 停点件(停点态/凭证计数片段)
var _refresh_bank: RefreshBank = null # 刷新账件(刷新存量/Y 池片段)
var _loadout: AttuneLoadout = null # 同调配装件(充能行集读侧)
# 断点域六成员(自宿主收编——宿主其余读写点经本件)
var _save_manager = null # 断点承载注入(null = 不写断点;模拟/冒烟缺省)
var _resume_bp := {} # 续玩快照暂存(resume_adventure → _start_current_level 单跳传递)
var _pending_next_level := false # 大奖励已兑付、等 continue_to_next_level 确认
var _last_level_payload := {} # 最近一次关卡结束载荷(失败结算的败退节点明细来源——数值验证取数面)
var _last_treasure_cleared := 0 # additive(最近一次关卡末清空计数,summary 取数面)
var _loadout_seeded := false # 同调行已种标记(每冒险一次——首关 bind 时点投行;行跨关存活后续关零动作)
func _init(refs: Dictionary) -> void:
db = refs["db"]
rng = refs["rng"]
_stats = refs["stats"]
_wallet = refs["wallet"]
_journal = refs["journal"]
_curio = refs["curio"]
_stop = refs["stop"]
_refresh_bank = refs["bank"]
_loadout = refs["loadout"]
# 断点快照拼盘落盘(宿主 _snapshot_breakpoint 委托目标——宿主输入逐调传参)
func snapshot(state: String, level_index: int, master_seed: int, runner: LevelRunner, counters: Dictionary[Variant, Variant]) -> void:
if _save_manager == null or state != "running":
return
var parts: Dictionary[Variant, Variant] = _bp_parts(level_index, master_seed, runner, counters)
var bp: Dictionary[Variant, Variant] = {}
for key in BREAKPOINT_FIELDS.keys():
bp[key] = parts[key]
_save_manager.set_breakpoint(bp)
_save_manager.write_to_disk()
# 断点写侧取值(键集以 BREAKPOINT_FIELDS 为准——未登记键即取值越界,fail-fast)
func _bp_parts(level_index: int, master_seed: int, runner: LevelRunner, counters: Dictionary[Variant, Variant]) -> Dictionary[Variant, Variant]:
var stats_frag: Dictionary[Variant, Variant] = _stats.breakpoint_fragment()
var wallet_frag: Dictionary[Variant, Variant] = _wallet.breakpoint_fragment()
var journal_frag: Dictionary[Variant, Variant] = _journal.breakpoint_fragment()
var bank_frag: Dictionary[Variant, Variant] = _refresh_bank.breakpoint_fragment()
var stop_frag: Dictionary[Variant, Variant] = _stop.breakpoint_fragment()
var level_frag: Dictionary[Variant, Variant] = runner.breakpoint_fragment() if runner != null else {
"node_id": -1, "visited_ids": [] as Array, "aux_items": [] as Array,
"shop_shelf": [] as Array, "shop_visit_buys": 0} # 三选一停点续玩分支 runner 为 null——节点域按缺省落档
# 该两态的续玩只消费 bonus_* 附随件(选择停点/已兑付停点快照)
var parts: Dictionary[Variant, Variant] = {
"level_index": level_index,
"node_id": int(level_frag.get("node_id", -1)),
"hero_hp": int(stats_frag.get("hero_hp", 0)),
"bonus": journal_frag.get("bonus", {}),
"gp": int(wallet_frag.get("gp", 0)),
"shop_purchased": journal_frag.get("shop_purchased", {}),
"shop_shelf": level_frag.get("shop_shelf", []), # 货架入断点(离开店/非店停点 = 空架合法态)
"shop_visit_buys": int(level_frag.get("shop_visit_buys", 0)), # 本次进店已购次数(A 链定价输入)
"attunement_charges": (_loadout.breakpoint_fragment(runner.treasure_inventory) if runner != null and runner.treasure_inventory != null else {"attunement_charges": {}}).get("attunement_charges", {}), # 同调主动件充能余量随断点(行派生——save v4 域键名策略不变)
"graph_gen_v2": 1, # 生成图换代代差标记(缺键 = 换代前旧断点 → resume 显式拒绝)
"master_seed": master_seed,
"rng_counter": rng.counter(),
"keystone": int(journal_frag.get("keystone", 0)),
"visited_ids": level_frag.get("visited_ids", []),
"aux_items": level_frag.get("aux_items", []),
"bonus_taken": _curio.taken.duplicate(true), # 三选一件获取次数(kind 维度派生账本——断点附随件与读数承载)
"bonus_deck": _curio.deck.duplicate(true), # 令牌池余库(TP0 v2.2——池消耗即上限,续玩余库逐枚还原)
"relics": stats_frag.get("relics", []), # 特性持有集(局内随机渠道获得态续玩防丢失)
"bonus_pending": stop_frag.get("bonus_pending", {}), # 三选一停点态(空 = 无停点——选择停点可中断契约)
"feat_ticket_pity": int(stop_frag.get("feat_ticket_pity", 0)), # T5 专长凭证保底计数(扩列向后兼容——旧档缺键缺省 0)
"feat_ticket_sold": int(stop_frag.get("feat_ticket_sold", 0)), # T5 专长凭证限购计数(同上)
"adventure_counters": counters.duplicate(true), # adventure 域计数器随断点(续玩跨战账不丢——桶归宿主字典)
"vision_counter_used": int(journal_frag.get("vision_counter_used", 0)), # 真视使用计数随断点(续玩跨战账不丢)
"refresh_stock": int(bank_frag.get("refresh_stock", 0)), # 刷新存量账随断点
"attune_refresh_y": int(bank_frag.get("attune_refresh_y", 0)), # Y 冒险周期池余量随断点(扩列向后兼容——旧档缺键回退参数面)
"bonus_result": stop_frag.get("bonus_result", {}), # 已兑付待推进态(空 = 无——中断续玩不重兑付)
"keystone_drops": journal_frag.get("keystone_drops", []), # 逐杀掉落明细(摘要归因续接)
"gain_journal": journal_frag.get("gain_journal", {}), # 获得日记(唯一声明的断点扩列——日记为现行事实源)
}
# 拼盘完整性自断言(fail-fast——片段并集与登记键集不符即中止落盘)
var stray: Array[Variant] = []
for key in parts.keys():
if not BREAKPOINT_FIELDS.has(key):
stray.append(key)
if not stray.is_empty():
push_error("[冒险结构] 断点拼盘含未登记键: %s(fail-fast——片段与登记单源失同步)" % str(stray))
return parts
# 续玩账面回填(生命/特性/钱包/加算区/已购档/钥石/逐杀明细/真视——主角账三件片段各还原各键;
# bonus 子键 clamp 类夹 ≥0;日记在档=推导比对载入、缺键=旧档汇总直载)
#(宿主侧账面语句——summary/levels_total/level_index/_pending_next_level——按语句序留宿主壳)
func restore_ledger(bp: Dictionary, params: Dictionary) -> void:
_stats.restore_fragment(bp, params)
_wallet.restore_fragment(bp, params)
_journal.restore_fragment(bp, params)
# 续玩三选一态回填(池与件计数归件、停点态归宿主;dual_merge/keep_on_null 策略见 BREAKPOINT_FIELDS)
#(前置清理 _reset_curio_state 留宿主——桶归宿主字典;本函数承接其后的件侧还原语句,序逐步保形)
func restore_curio_state(bp: Dictionary) -> void:
var bp_taken: Dictionary[Variant, Variant] = bp.get("bonus_taken", {}) as Dictionary
for id in _curio.taken.keys():
_curio.taken[id] = maxi(0, int(bp_taken.get(id, 0)))
for id in bp_taken.keys():
_curio.taken[String(id)] = maxi(0, int(bp_taken.get(id, 0))) # 身份维键(relic:<feat_id>)随快照还原
# 令牌池余库还原(TP0 v2.2——快照缺键 = 旧版断点,保持满库重建态:旧档只读一版周期的防御口径;
# relic 令牌 feat_id 随还原)
var bp_deck = _bp_read("bonus_deck", bp)
if bp_deck is Array:
var restored: Array[Variant] = []
for t in (bp_deck as Array):
var tok: Dictionary[Variant, Variant] = t as Dictionary
var rtok := {"kind": String(tok.get("kind", "")), "tier": String(tok.get("tier", ""))}
if String(rtok["kind"]) == "relic":
rtok["feat_id"] = String(tok.get("feat_id", "")) # relic 令牌 feat_id 随还原
restored.append(rtok)
_curio.deck = restored
# 特性持有集还原(缺键 = 旧版断点防御空集——主角数值账字段单点)
_stats.feats = []
for r in (bp.get("relics", []) as Array):
_stats.feats.append(String(r))
# 续玩参数面——数值账规范化与越界钳制(件侧;宿主侧四重绑定与预算注入按语句序夹在两件侧调用之间)
func apply_resume_params(params: Dictionary) -> void:
_stats.rebase_override(params.get("hero_override", {})) # 续玩参数面同 start_adventure(规范化归数值账)
_stats.attack_type = String(params.get("attack_type", "")) # 续玩参数面同 start_adventure(账号层选中态随 resume 重注入)
_stats.armor_type = String(params.get("armor_type", ""))
# 生命账本越界钳制(T17——spawn 守卫 EC16 免疫):断点可能带出高于生效上限的账本值
#(如调试浮窗调高期写出的值,实例:hero_hp=28 > 基础 26)——恢复后钳到生效上限,
# 否则首战 spawn「hero_hp 入参越界」拒收 → 「敌人系统 spawn 被拒」fatal。钳制式单点归
# 数值账 clamp_hp_to_resume_cap(保守口径不含加算区——与原钳制式逐字同)。
_stats.clamp_hp_to_resume_cap(int(db.combat.hero.max_hp))
# 停点件/刷新账片段回填(凭证计数;刷新存量/Y 池——Y 缺键回退参数面 params_fallback 类)
func restore_stop_bank_fragments(bp: Dictionary, params: Dictionary) -> void:
_stop.restore_fragment(bp, params)
_refresh_bank.restore_fragment(bp, params)
# 读侧单点(BREAKPOINT_FIELDS 策略标签分发;未登记键 fail-fast 不静默按 plain 兜)。
# 二次消费面(_start_current_level 经 _resume_bp 取 node_id/visited_ids/aux_items)同走此口。
func _bp_read(key: String, bp: Dictionary, fallback: Variant = null) -> Variant:
if not BREAKPOINT_FIELDS.has(key):
push_error("[冒险结构] 断点字段未登记(读侧): %s" % key)
var v: Variant = bp.get(key, fallback)
if _bp_strategy(key) == "keep_on_null" and v != null and not (v is Dictionary or v is Array):
return null # 类型不符——保持既有态(调用方跳过覆盖)
return v
# 读侧策略标签(BREAKPOINT_FIELDS 读侧消费面单点)
func _bp_strategy(key: String) -> String:
return String((BREAKPOINT_FIELDS.get(key, {}) as Dictionary).get("strategy", "plain"))
# 数值类读侧(clamp 夹 ≥0 / params_fallback 断点缺键回退参数面整额注入 / plain 直取)
func _bp_read_int(key: String, bp: Dictionary, fallback: int, params: Dictionary = {}) -> int:
match _bp_strategy(key):
"clamp":
return maxi(0, int(bp.get(key, fallback)))
"params_fallback":
return maxi(0, int(bp.get(key, int(params.get(key, fallback)))))
_:
return int(bp.get(key, fallback))
+1
View File
@@ -0,0 +1 @@
uid://cw5qdd012h728
+3 -4
View File
@@ -1,14 +1,13 @@
## VERTICAL SLICE - NOT FOR PRODUCTION
## 数值表单点访问入口:全部 .tres 表的加载、校验诊断与门面(垂直切片验证:改表即改玩法,数值零硬编码)。
## 玩法代码禁止绕过本单点自建 load();行查询归各表类(表管自己的行——2026-10-27 全清设计定稿),
## 玩法代码禁止绕过本单点自建 load();行查询归各表类(表管自己的行),
## 表持有按域收进三容器(combat 战斗编排域/run 冒险 runner 域/crossrun 跨局元进度域),
## 消费面经 db.<容器>.<表> 直连。「经 ConfigDB 单点读取」=经其持有的容器与表对象(架构 :88)。
## headless --script 模式无 autoload——冒烟脚本显式实例化本类;加载失败 is_ready=false 加 fatal 封印,调用方须查。
## 冒烟脚本可显式实例化本类(headless --script 亦会加载 autoload——共享 .tres 上的 resolver 归最后装载的实例);
## 加载失败 is_ready=false 加 fatal 封印,调用方须查。
class_name ConfigDb
extends Node
const SCHEMA_VERSION := 1
const TABLE_MANIFEST := {
"action_economy": "action_economy.tres",
"variation": "variation.tres",
+1 -1
View File
@@ -1,4 +1,4 @@
## 战斗域容器(D2 域容器——config_db 表持有按域收敛,2026-10-27 全清设计定稿):战斗编排域七表类型化持有。
## 战斗域容器(D2 域容器——config_db 表持有按域收敛):战斗编排域七表类型化持有。
## 零方法零行为——纯持有结构;「经 ConfigDB 单点读取」=经其持有的容器与表对象(架构 :88 定稿注记)。
class_name ConfigDomainCombat
extends Resource
+1 -1
View File
@@ -1,4 +1,4 @@
## 跨局域容器(D2 域容器——config_db 表持有按域收敛,2026-10-27 全清设计定稿):跨局元进度域五表类型化持有
## 跨局域容器(D2 域容器——config_db 表持有按域收敛):跨局元进度域五表类型化持有
## (跨局循环=单局之外的长线进度域)。零方法零行为——纯持有结构;
## 「经 ConfigDB 单点读取」=经其持有的容器与表对象(架构 :88 定稿注记)。
class_name ConfigDomainCrossrun
+1 -1
View File
@@ -1,4 +1,4 @@
## 冒险域容器(D2 域容器——config_db 表持有按域收敛,2026-10-27 全清设计定稿):冒险 runner 域七表类型化持有。
## 冒险域容器(D2 域容器——config_db 表持有按域收敛):冒险 runner 域七表类型化持有。
## 零方法零行为——纯持有结构;「经 ConfigDB 单点读取」=经其持有的容器与表对象(架构 :88 定稿注记)。
class_name ConfigDomainRun
extends Resource
+14 -94
View File
@@ -41,7 +41,7 @@ var hero_hp: int:
var gp: int: # GP 冒险钱包(局内货币——冒险开始 = 0、收束清零;不入存档不入摘要)
get: return _wallet.gp
set(v): _wallet.gp = v
var _shop: ShopSession = null # 商店件(_init 建;双模式货架/定价/购买/刷新唯一宿主)
var shop: ShopSession = null # 商店件(_init 建;双模式货架/定价/购买/刷新唯一宿主)
# 协作对象私有(E1/E3 封装收口):settlement 读取经 current_battle() 成文出口
var _settlement: BattleOrchestrator = null # 当前战斗编排器(关卡结束置 null)
var treasure_inventory: TreasureItems = null # 秘宝 关卡域库存(TreasureItems;跨战斗延续,
@@ -96,10 +96,10 @@ func _init(db_ref: ConfigDb, rng_ref: RngServiceCore, ctx: Dictionary = {}) -> v
_hero_armor_type = String(ctx.get("hero_armor_type", ""))
_voucher_rap = maxi(0, int(ctx.get("voucher_rap", 0)))
_voucher_time_sand = maxi(0, int(ctx.get("voucher_time_sand", 0)))
_shop = ShopSession.new(db, rng)
shop = ShopSession.new(db, rng)
var pool: Dictionary[Variant, Variant] = ctx.get("pool_wiring", {}) as Dictionary
if String(ctx.get("shop_mode", "")) == "pool" and not pool.is_empty():
_shop.set_shop_pool(pool.get("deck", []) as Array, pool.get("consume", Callable()) as Callable,
shop.set_shop_pool(pool.get("deck", []) as Array, pool.get("consume", Callable()) as Callable,
pool.get("ticket", Callable()) as Callable, pool.get("cap", Callable()) as Callable)
_bind_shop()
@@ -302,8 +302,8 @@ func breakpoint_fragment() -> Dictionary[Variant, Variant]:
"node_id": current_node_id(),
"visited_ids": visited_ids(),
"aux_items": treasure_snapshot,
"shop_shelf": _shop.shop_bp_shelf(),
"shop_visit_buys": _shop.shop_bp_visit_buys(),
"shop_shelf": shop.shop_bp_shelf(),
"shop_visit_buys": shop.shop_bp_visit_buys(),
}
@@ -503,11 +503,11 @@ func _enter_node(node: Dictionary) -> bool:
"shop":
# 商店房兑付:到达即开店(覆盖层归呈现层),购买出账/
# 离开归玩家意图——零自动推进;离开确认经 continue_after_node 回选路口
if _shop.pool_mode:
_shop.open_pool() # 进店抽 3(恰一 shop_draw scope;买后全重抽同签)
node_entered.emit(node, {"gp": gp, "shelf": true})
return true
node_entered.emit(node, {"gp": gp}) # legacy 固定三件(off 对照承载——零 RNG 零池消费)
var payload := {"gp": gp} # legacy 固定三件(off 对照承载——零 RNG 零池消费)
if shop.pool_mode:
shop.open_pool() # 进店抽 3(恰一 shop_draw scope;买后全重抽同签)
payload = {"gp": gp, "shelf": true}
node_entered.emit(node, payload)
return true
push_error("[关卡节点地图] 未知节点类型: %s" % str(node))
return false
@@ -701,7 +701,7 @@ func continue_after_node() -> bool:
if t != "reward" and t != "rest" and t != "shop":
return false
if t == "shop":
_shop.leave() # 离开店面货架态清零(断点快照 shop_shelf 键随离开落空架合法态)
shop.leave() # 离开店面货架态清零(断点快照 shop_shelf 键随离开落空架合法态)
return _present_choices()
@@ -721,12 +721,12 @@ func close_wallet() -> void:
# ---- 商店房兑付(GP+商店房实施批:呈现层只读投影 + 购买出账)----
# 实装归 ShopSession 件(双模式货架/定价/购买/刷新唯一宿主);本类保留同签名委托与件注入/
# 白盒入口——外部调用面与断点取数面零变化。
# 实装归 ShopSession 件(双模式货架/定价/购买/刷新唯一宿主);外部调用面=调用方经宿主公开
# 成员 shop 直连(调用直连不留委托壳——2026-10-26 Middle Man 裁定)。
# 件注入(建件与宿主引用换代时调用——钱包/主角账三件/图行/装配集为共享引用,出账直接落同一引用)
func _bind_shop() -> void:
_shop.bind({
shop.bind({
"wallet": _wallet,
"journal": _journal,
"level_row": level_row,
@@ -746,83 +746,3 @@ func _emit_wallet_event(event: String, gp_now: int, extra: Dictionary) -> void:
# 购血(商店 max_hp 商品——当前生命 +Δ 并封顶新上限,与账本置满/关卡完成回血同式)
func _gain_max_hp_flat(flat: int) -> void:
_stats.hero_hp = mini(_stats.hero_hp + flat, _stats.effective_max_hp())
func shop_products() -> Array:
return _shop.shop_products()
func current_price(prow: Dictionary) -> int:
return _shop.current_price(prow)
func purchased_tier(product_id: String) -> int:
return _shop.purchased_tier(product_id)
func buy_product(product_id: String) -> bool:
return _shop.buy_product(product_id)
func player_request_refresh() -> bool:
return _shop.player_request_refresh()
# 散折价单点(测试取数面沿用本类调用名)
func _spend_discounted(price: int) -> int:
return _shop._spend_discounted(price)
# 注入(AdventureRunner._start_current_level 唯一调用方——pool 模式专用):令牌库共享引用 +
# 池消费 handler + 专长凭证判定 + cap 检查回调(cap 满 kind 剔出货架候选视图)。
func set_shop_pool(deck_ref: Array, consume_handler: Callable, ticket_consider: Callable = Callable(), cap_check: Callable = Callable()) -> void:
_shop.set_shop_pool(deck_ref, consume_handler, ticket_consider, cap_check)
# 货架抽签白盒入口(测试取数面沿用本类调用名)
func _shop_draw_shelf() -> void:
_shop._draw_shelf()
func pool_stock(kind: String) -> int:
return _shop.pool_stock(kind)
func pool_price(kind: String) -> int:
return _shop.pool_price(kind)
func shop_shelf() -> Array:
return _shop.shop_shelf()
func shop_refresh_free_left() -> int:
return _shop.shop_refresh_free_left()
func shop_refresh_cost() -> int:
return _shop.shop_refresh_cost()
func shop_refresh() -> bool:
return _shop.shop_refresh()
func spend_gp(amount: int) -> bool:
return _shop.spend_gp(amount)
func buy_pool_item(kind: String) -> bool:
return _shop.buy_pool_item(kind)
func is_shop_pool() -> bool:
return _shop.is_shop_pool()
func shop_bp_shelf() -> Array:
return _shop.shop_bp_shelf()
func shop_bp_visit_buys() -> int:
return _shop.shop_bp_visit_buys()
+6 -6
View File
@@ -187,8 +187,8 @@ func _vo_edges(nodes: Array, by_id: Dictionary, indeg: Dictionary, errs: Array)
## 阶段三·流事实域:入口集(入度 0)/终点集(无出边)与 Boss 终点判据、去路数形态
func _vo_flow_facts(nodes: Array, indeg: Dictionary, errs: Array) -> Dictionary:
var entries := []
var terminals := []
var entries: Array[int] = []
var terminals: Array[int] = []
for n in nodes:
var id0: int = int(n["id"])
var outs = n["next"]
@@ -277,8 +277,8 @@ func _vo_width_rules(nodes: Array, errs: Array) -> void:
## 计数规则③·参数档对照:战斗保底/入口数/终点数/层高(params 为空时跳过)
func _vo_params_check(params: Dictionary, nodes: Array, by_id: Dictionary, flow_ends: Array, errs: Array) -> void:
var entries: Array = flow_ends[0]
var terminals: Array = flow_ends[1]
var entries: Array[int] = flow_ends[0]
var terminals: Array[int] = flow_ends[1]
var battles := 0
for n in nodes:
if String(n["type"]) == "battle":
@@ -309,7 +309,7 @@ func _build(rg: RandomNumberGenerator) -> Dictionary:
var entries: Array[int] = []
for i in range(en):
entries.append(_mk("battle", 0))
var prevs: Array = _build_trunk(t, entries.duplicate())
var prevs: Array[int] = _build_trunk(t, entries.duplicate())
var terminals: Array[int] = []
for r in range(e):
@@ -326,7 +326,7 @@ func _build(rg: RandomNumberGenerator) -> Dictionary:
## 主链段(深度 1..t 逐层单链,主链段零 RNG):返回链末节点集(e>1 时收束为一处即归属大岔口)
func _build_trunk(t: int, prevs: Array) -> Array:
func _build_trunk(t: int, prevs: Array[int]) -> Array[int]:
for d in range(1, t + 1):
var nid := _mk("battle", d)
for p in prevs:
+1 -1
View File
@@ -1,7 +1,7 @@
## VERTICAL SLICE - NOT FOR PRODUCTION
## 商店会话件:关卡商店双模式(legacy 固定三件加定价/pool 共享令牌池)的货架、定价、购买与刷新唯一宿主。
## 钱包/主角账/装配集归宿主(GpWallet/GainJournal 共享引用经 bind 注入——GP 读写走钱包、购买加算走日记单点);
## Core 层零 UI 依赖;公开面由 LevelRunner 同签名委托承载(外部调用面零变化);
## Core 层零 UI 依赖;外部调用面=调用方经宿主 LevelRunner 公开成员 shop 直连(调用直连不留委托壳);
## legacy 模式零 RNG 零池消费(off 对照承载)。
class_name ShopSession
extends RefCounted
+1 -1
View File
@@ -52,7 +52,7 @@ const TIER_QUOTAS := {"common": 70, "excellent": 25, "rare": 7, "legendary": 0}
@export var cap_segment: AdventureCapSegment = AdventureCapSegment.new() # 已拿上限段(curio_cap_* 9)
# —— 专长获取专长凭证(非 Boss 渠道的专长入口形态,奇物.md v2.7 渠道轴定位;
# 四口径契约④:拿到即开不可囤积/罕见只在概率不在价格/一局限购一次/计步保底连续 5 展示未出
# 四口径契约④:拿到即开不可囤积/稀有只在概率不在价格/一局限购一次/计步保底连续 5 展示未出
# 第 6 必出(计数=展示次数、刷新重展计入、节点与商店共享、触发清零、限购满不再触发)。
# 四参数全部 provisional 归曲线调参;limit/pity_step 系口径定死值,调参可复议)——
@export var feat_ticket_chance: int = 20 # [0,100] knob(provisional)——每次非 Boss 渠道展示专长凭证出现概率 %
+1 -1
View File
@@ -115,4 +115,4 @@ var _resolver # R1 解析协作件(ConfigDB load_tables
## 进度行解析委托(消费面 db.combat.board_gen.resolve_row——R1 ceil/clamp 语义归 ConfigDbResolver)
func resolve_row(L: int, D: int) -> Dictionary:
return _resolver.combat.board_gen.resolve_row(L, D)
return _resolver.resolve_board_gen(L, D)
+1 -1
View File
@@ -35,4 +35,4 @@ var _resolver # R1 解析协作件(ConfigDB load_tables
## 难度修饰解析委托(消费面 db.run.difficulty.resolve_modifiers——clamp 语义归 ConfigDbResolver)
func resolve_modifiers(L: int, D: int) -> Dictionary:
return _resolver.run.difficulty.resolve_modifiers(L, D)
return _resolver.resolve_difficulty_modifiers(L, D)
+1 -1
View File
@@ -214,4 +214,4 @@ var _resolver # R1 解析协作件(ConfigDB load_tables
## 带寻址行集解析委托(消费面 db.combat.enemy.resolve_rowset——D 维 band_of 落带语义归 ConfigDbResolver)
func resolve_rowset(L: int, D: int, row_kind: String) -> Array[Dictionary]:
return _resolver.combat.enemy.resolve_rowset(L, D, row_kind)
return _resolver.resolve_enemy_rowset(L, D, row_kind)
+3 -3
View File
@@ -7,9 +7,9 @@ extends RefCounted
## 三束按域收拢(u21——同 u20 形;views=视图句柄/getters=查询 Callable 活引用/flow=编排 Callable):
## 原 12 参长签名收 4 参——字段即原构造参数逐一同名迁移,键面=消费方改址合同。
var db
var views: Dictionary = {} # {camp_overlay, shop_overlay, toast, start_overlay, logger}
var getters: Dictionary = {} # {meta_get, save_get, runner_get}
var flow: Dictionary = {} # {open_modal, close_modal, refresh_presentations}
var views: Dictionary = {} # {camp_overlay, shop_overlay, toast, start_overlay, logger} # type-hint: ignore(三束异构混载——视图句柄/查询 Callable/编排 Callable)
var getters: Dictionary = {} # {meta_get, save_get, runner_get} # type-hint: ignore(同上——Callable 束)
var flow: Dictionary = {} # {open_modal, close_modal, refresh_presentations} # type-hint: ignore(同上——Callable 束)
func _init(db_ref, views_bundle: Dictionary, getters_bundle: Dictionary, flow_bundle: Dictionary) -> void:
+13 -13
View File
@@ -65,7 +65,7 @@ func camp_data() -> Dictionary:
"attune": meta.attune_camp_status() if meta != null else {}, # 同调装配面投影
"tree": meta.tree_camp_status()["rows"] if meta != null else [], # 树面投影(含 forge_workshop/ks_workshop 钥匙门判据行)
"fork_groups": meta.tree_camp_status()["fork_groups"] if meta != null else [],
"recent": _save_get.call().recent_summaries() if _save_get.call() != null else [],
"recent": _save_get.call().meta_state.career_state()["recent_summaries"] if _save_get.call() != null else [],
}
@@ -170,37 +170,37 @@ func on_shop_buy(product_id: String) -> void:
var runner = _runner_get.call()
if runner == null:
return
if runner.is_shop_pool():
if runner.shop.is_shop_pool():
# pool 面:买 1 → 核心全重抽——货架整架重投喂(重抽反馈;余额不足核心拒绝零副作用)
if not runner.buy_pool_item(product_id):
if not runner.shop.buy_pool_item(product_id):
logger.log_ux("ux_reject", {"source": "wallet", "sub_reason": "insufficient_gp"})
toast.show_toast("GP不足——买不起这件商品", "warn")
return
shop_overlay.open_shelf(runner.shop_shelf(), int(runner.gp))
shop_overlay.set_visit_info(int(runner.shop_bp_visit_buys()), float(db.run.shop.price_a)) # T6 爬价规则行
shop_overlay.set_refresh_display(runner.shop_refresh_free_left(), runner.shop_refresh_cost(), int(runner.gp) >= runner.shop_refresh_cost())
shop_overlay.open_shelf(runner.shop.shop_shelf(), int(runner.gp))
shop_overlay.set_visit_info(int(runner.shop.shop_bp_visit_buys()), float(db.run.shop.price_a)) # T6 爬价规则行
shop_overlay.set_refresh_display(runner.shop.shop_refresh_free_left(), runner.shop.shop_refresh_cost(), int(runner.gp) >= runner.shop.shop_refresh_cost())
_refresh_presentations.call()
return
if not runner.buy_product(product_id):
if not runner.shop.buy_product(product_id):
# 余额不足(按钮禁用为常态防线——兜底拒绝可见,pattern 1)
logger.log_ux("ux_reject", {"source": "wallet", "sub_reason": "insufficient_gp"})
toast.show_toast("GP不足——买不起这件商品", "warn")
return
shop_overlay.refresh_state(runner.shop_products(), int(runner.gp))
shop_overlay.refresh_state(runner.shop.shop_products(), int(runner.gp))
_refresh_presentations.call()
# MC-1:刷新意图(shop_overlay.refresh_requested——核心 shop_refresh 受理后整架重投喂=重抽反馈)
func on_shop_refresh() -> void:
var runner = _runner_get.call()
if runner == null or not runner.is_shop_pool():
if runner == null or not runner.shop.is_shop_pool():
return
if not runner.shop_refresh():
if not runner.shop.shop_refresh():
toast.show_toast("GP不足——刷新失败", "warn")
return
shop_overlay.open_shelf(runner.shop_shelf(), int(runner.gp))
shop_overlay.set_visit_info(int(runner.shop_bp_visit_buys()), float(db.run.shop.price_a)) # T6 爬价规则行
shop_overlay.set_refresh_display(runner.shop_refresh_free_left(), runner.shop_refresh_cost(), int(runner.gp) >= runner.shop_refresh_cost())
shop_overlay.open_shelf(runner.shop.shop_shelf(), int(runner.gp))
shop_overlay.set_visit_info(int(runner.shop.shop_bp_visit_buys()), float(db.run.shop.price_a)) # T6 爬价规则行
shop_overlay.set_refresh_display(runner.shop.shop_refresh_free_left(), runner.shop.shop_refresh_cost(), int(runner.gp) >= runner.shop.shop_refresh_cost())
_refresh_presentations.call()
+3 -3
View File
@@ -7,9 +7,9 @@ extends RefCounted
## 三束按域收拢(u20——views=视图句柄/getters=查询 Callable 活引用〔禁快照〕/flow=编排 Callable):
## 原 16 参长签名收 4 参——字段即原构造参数逐一同名迁移,键面=消费方改址合同。
var db
var views: Dictionary = {} # {curio_overlay, end_overlay, board_view, toast}
var getters: Dictionary = {} # {meta_get, save_get, adventure_get, runner_get, adventure_mode_get}
var flow: Dictionary = {} # {open_modal, open_modal_after_playback, close_modal, refresh_presentations, fatal_screen, gp_summary}
var views: Dictionary = {} # {curio_overlay, end_overlay, board_view, toast} # type-hint: ignore(三束异构混载——视图句柄/查询 Callable/编排 Callable)
var getters: Dictionary = {} # {meta_get, save_get, adventure_get, runner_get, adventure_mode_get} # type-hint: ignore(同上——Callable 束)
var flow: Dictionary = {} # {open_modal, open_modal_after_playback, close_modal, refresh_presentations, fatal_screen, gp_summary} # type-hint: ignore(同上——Callable 束)
func _init(db_ref, views_bundle: Dictionary, getters_bundle: Dictionary, flow_bundle: Dictionary) -> void:
@@ -78,7 +78,7 @@ func on_presented(payload: Dictionary) -> void:
return
ctx.views.end_overlay.open_victory(Narrator.battle_end_text("victory", false), "继续",
ctx.views.board_view.get_global_rect(),
"%s\n%s" % [String(ctx.flow.gp_summary.call()), Narrator.bonus_keystone_line(payload)])
{"gp_summary": "%s\n%s" % [String(ctx.flow.gp_summary.call()), Narrator.bonus_keystone_line(payload)]})
ctx.flow.open_modal_after_playback.call(ctx.views.end_overlay)
ctx.flow.refresh_presentations.call()
@@ -160,7 +160,7 @@ func on_refresh() -> void:
if not refreshed:
# 免费位(X/Y)已穷——GP 付费档(先扣钱包后重抽,余额不足拒绝零副作用)
var cost: int = adventure.refresh_bank().gp_cost()
if runner == null or not runner.spend_gp(cost):
if runner == null or not runner.shop.spend_gp(cost):
ctx.views.toast.show_toast("GP不足——刷新失败", "warn")
return
refreshed = adventure.stop().refresh_curio_paid()
+5 -5
View File
@@ -196,11 +196,11 @@ static func outcome_text(outcome: Dictionary) -> String:
## 统计束收拢(u19——stats 六键 {wins, dmg_all, hp_left_win, hp_boss, rounds_all, death_nodes})
static func tune_sim_report(n: int, atk_pct: int, hp_pct: int, stats: Dictionary, base_hp: int) -> String:
var wins: int = stats.get("wins", 0)
var dmg_all: Array = stats.get("dmg_all", [])
var hp_left_win: Array = stats.get("hp_left_win", [])
var hp_boss: Array = stats.get("hp_boss", [])
var rounds_all: Array = stats.get("rounds_all", [])
var death_nodes: Dictionary = stats.get("death_nodes", {})
var dmg_all: Array = stats.get("dmg_all", []) # type-hint: ignore(stats 束 Variant 出值——元素类型归模拟域写入面,未参数化)
var hp_left_win: Array = stats.get("hp_left_win", []) # type-hint: ignore(同上)
var hp_boss: Array = stats.get("hp_boss", []) # type-hint: ignore(同上)
var rounds_all: Array = stats.get("rounds_all", []) # type-hint: ignore(同上)
var death_nodes: Dictionary = stats.get("death_nodes", {}) # type-hint: ignore(同上——键为败北节点标签)
var lines: Array[String] = []
lines.append("[b]模拟 N=%d(atk+%d%% / hp+%d%%)[/b]" % [n, atk_pct, hp_pct])
lines.append("关卡完成率 [color=#%s]%.0f%%[/color](%d/%d)" % [UiKit.HEX_LOG_WIN, 100.0 * float(wins) / float(maxi(1, n)), wins, n])
+1 -1
View File
@@ -770,7 +770,7 @@ func _on_refresh_confirmed() -> void:
return
var ok: bool = false
if run_scope.level_active and run_scope.runner != null:
ok = run_scope.runner.player_request_refresh()
ok = run_scope.runner.shop.player_request_refresh()
elif run_scope.settlement != null:
ok = run_scope.settlement.player_request_refresh()
logger.log_action("refresh", Vector2i(-1, -1), ok)
+5 -5
View File
@@ -78,12 +78,12 @@ static func _on_runner_node(root: Variant, node: Dictionary, info: Dictionary) -
# 购买/离开归玩家意图(buy_requested/leave_pressed 接线),零自动推进。
# pool 面 = 共享池货架三选一同构卡;legacy 面 = 固定三件(off 对照承载)
root._open_modal(root.shop_overlay)
if root.run_scope.runner.is_shop_pool():
root.shop_overlay.open_shelf(root.run_scope.runner.shop_shelf(), int(root.run_scope.runner.gp))
root.shop_overlay.set_visit_info(int(root.run_scope.runner.shop_bp_visit_buys()), float(root.db.run.shop.price_a)) # 爬价规则行
root.shop_overlay.set_refresh_display(root.run_scope.runner.shop_refresh_free_left(), root.run_scope.runner.shop_refresh_cost(), int(root.run_scope.runner.gp) >= root.run_scope.runner.shop_refresh_cost()) # MC-1
if root.run_scope.runner.shop.is_shop_pool():
root.shop_overlay.open_shelf(root.run_scope.runner.shop.shop_shelf(), int(root.run_scope.runner.gp))
root.shop_overlay.set_visit_info(int(root.run_scope.runner.shop.shop_bp_visit_buys()), float(root.db.run.shop.price_a)) # 爬价规则行
root.shop_overlay.set_refresh_display(root.run_scope.runner.shop.shop_refresh_free_left(), root.run_scope.runner.shop.shop_refresh_cost(), int(root.run_scope.runner.gp) >= root.run_scope.runner.shop.shop_refresh_cost()) # MC-1
else:
root.shop_overlay.open_shop(root.run_scope.runner.shop_products(), int(root.run_scope.runner.gp))
root.shop_overlay.open_shop(root.run_scope.runner.shop.shop_products(), int(root.run_scope.runner.gp))
root.shop_overlay.set_visit_info(-1, 1.0) # legacy 面无爬价行(off 对照承载)
root.log_view.append_bb(root.Narrator.shop_line(int(root.run_scope.runner.gp)))
root.logger.log_node(node, info, root.run_scope.runner.node_index)
+2 -2
View File
@@ -132,10 +132,10 @@ static func _on_wallet_changed(root: Variant, event: String, gp: int, extra: Dic
if String(event) == "gain":
root.run_scope.last_gain_amount = int(extra.get("amount", 0)) # GP 增量取数(每战恰一笔 gain)
if root.shop_overlay.visible and root.run_scope.runner != null:
if root.run_scope.runner.is_shop_pool():
if root.run_scope.runner.shop.is_shop_pool():
root.shop_overlay.refresh_shelf_state(int(root.run_scope.runner.gp)) # pool 面余额联动(货架内容仅买后重抽变)
else:
root.shop_overlay.refresh_state(root.run_scope.runner.shop_products(), int(root.run_scope.runner.gp))
root.shop_overlay.refresh_state(root.run_scope.runner.shop.shop_products(), int(root.run_scope.runner.gp))
root._refresh_presentations()
+3 -3
View File
@@ -50,10 +50,12 @@ func run(n: int) -> void:
await panel.get_tree().process_frame
logger.close_session()
panel.set_sim_report(HudPresenter.tune_sim_report(n, panel.atk_pct(), panel.hp_pct(), stats, _base_hp))
panel.set_sim_running(false)
_running = false
## 单局模拟域(循环体提函数——结果四桶记账;u19 stats 六键同构承载)
func _run_one_level(autoplay, stats: Dictionary, i: int, panel, logger) -> void:
func _run_one_level(autoplay, stats: Dictionary, i: int, panel, logger) -> void: # type-hint: ignore(驱动/面板/日志件鸭子型注入——同 run 构造缝)
var st = autoplay.run_level(db, SEED_BASE + i, 1, panel.atk_pct(), panel.hp_pct(), false, logger)
(stats["dmg_all"] as Array).append(st.hero_dmg)
(stats["rounds_all"] as Array).append(st.rounds)
@@ -64,5 +66,3 @@ func _run_one_level(autoplay, stats: Dictionary, i: int, panel, logger) -> void:
elif st.result == "defeat":
var key := "%d.%s" % [st.defeat_node_index, st.defeat_node_type]
stats["death_nodes"][key] = int(stats["death_nodes"].get(key, 0)) + 1
panel.set_sim_running(false)
_running = false
+2 -2
View File
@@ -75,7 +75,7 @@ func _build_world_stage() -> void:
## Control 文本半区域(round_label / stage_center / log_view 原样保留——C1 永久 Control)
func _build_text_half(db_ref) -> void:
func _build_text_half(db_ref) -> void: # type-hint: ignore(db 鸭子型注入——单测以最小 stub 构造)
var vb := VBoxContainer.new()
vb.add_theme_constant_override("separation", 4)
vb.set_anchors_preset(Control.PRESET_FULL_RECT)
@@ -124,7 +124,7 @@ func _build_center_row(vb: VBoxContainer) -> void:
## 壳层伴随件层域(最顶——世界站桩之上的 Control 触达面)+主角站桩注册(世界)+ 状态行伴随件(壳层)
func _build_companion_layer(db_ref) -> void:
func _build_companion_layer(db_ref) -> void: # type-hint: ignore(db 鸭子型注入——单测以最小 stub 构造)
_companion_layer = Control.new()
_companion_layer.set_anchors_preset(Control.PRESET_FULL_RECT)
_companion_layer.mouse_filter = Control.MOUSE_FILTER_IGNORE
+44 -367
View File
@@ -1,128 +1,31 @@
## VERTICAL SLICE - NOT FOR PRODUCTION
## CellUnit——BoardView SubViewport 世界内逐格渲染件(Node2D),全部程序化 _draw 占位视觉(纹理槽位已留未装载)。
## CellUnit——BoardView SubViewport 世界内逐格渲染件(Node2D),被动绘制壳:_draw 六步时序器
## +视野迷雾域+微光子件生命周期+格件几何;基座层与标识叠加两绘制域件 _init 自建持有
## (cell_base_layer/cell_mark_overlay——单一变化原因=迷雾规格与格件节点生命周期)。
## 无 class_name(类名缓存面纪律)——使用方经 preload 引用。
## 内部状态件(u3 子域拆件——契约 9 职责语句「单格绘制输入集」):本件为被动绘制壳,
## 状态件 _CellPaintState 承载全部绘制入参(单一变化原因=格面呈现),setter 触发宿主重绘语义
## 经 _owner 回引保持逐字;探针直读冻结成员(glyph/fog_state/plate/glyph_color)与 _glow_layer 住宿主。
## 探针直读冻结成员(glyph/fog_state/plate/glyph_color)与 _glow_layer 住宿主;
## hl_color/hl_visible/dot_visible/mutation_mark 探针读 u.face.*。
extends Node2D
const _GLOW_LAYER := preload("res://presentation/views/cell_type_glow_layer.gd")
const _BASE_LAYER := preload("res://presentation/views/cell_base_layer.gd")
const _MARK_OVERLAY := preload("res://presentation/views/cell_mark_overlay.gd")
# ── D 投影档绘制常量(研究件实测取色——立面高光/双段暗带/地面投影;黑罩 alpha 叠加实测等效)──
const FACADE_HIGHLIGHT_PX := 2.0 # 口沿高光线厚(像素)
const FACADE_NEAR_FRAC := 0.16 # 立面近段高(格边比——研究件 10/64)
const FACADE_FAR_FRAC := 0.25 # 立面远段高(格边比——研究件 16/64)
const FACADE_NEAR_COL := Color(0, 0, 0, 0.60) # 立面近段黑罩(墙顶 132→52 实测 α≈0.61)
const FACADE_FAR_COL := Color(0, 0, 0, 0.82) # 立面远段黑罩(墙顶 132→24 实测 α≈0.82)
const PROJECTION_NEAR_COL := Color(0, 0, 0, 0.28) # 投影贴墙段(地面 66→46 实测 α≈0.28)
const PROJECTION_MID_COL := Color(0, 0, 0, 0.16) # 投影中段(渐隐)
const PROJECTION_EDGE_COL := Color(0, 0, 0, 0.06) # 投影远段(渐隐收边)
# ── E 格高墙面(圣经 v3.5 冻结①——地面格南邻墙→南部 30% 承接墙面:墙顶纹理原亮度
# 直贴零暗档零阴影;墙脚阴线只画地面/墙面交界;(b)-(c) 交界
# 无边框由 BoardView 侧跳过墙格北向描边承载)──
const E_FACADE_FRAC := 0.30 # 墙面承接高(格边比 30%)
## 单格绘制输入集(被动绘制壳的全部绘制入参——BoardView 直写面;setter 触发宿主重绘语义逐字)
class _CellPaintState extends RefCounted:
var _owner: Node2D = null
var cell := Vector2i.ZERO # 板坐标(诊断观测面)
var edge := 46.0: # 格边长(BoardView.set_cell_area 单点驱动)
set(v):
edge = v
if _owner._glow_layer != null and is_instance_valid(_owner._glow_layer):
_owner._glow_layer.setup(edge, glow_group)
_owner.queue_redraw()
var bg_sb: StyleBoxFlat = null # 格底 StyleBox(BoardView 每次 paint 重建;呼吸微光就地改边框)
# ── 接触带微光绘制面(可挖域微光画在英雄格周界空间侧——art-bible §3.2 v2.8;
# 仅英雄格单元承载,BoardView.refresh 按可挖域写边/角码、_process 逐拍更新呼吸色)──
var contact_bands: Array[int] = [] # 正交接触边码 0=N/1=S/2=W/3=E(该侧整条边)
var contact_corners: Array[int] = [] # 斜向共享角码 0=NW/1=NE/2=SW/3=SE(角点+两侧各半条边)
var contact_col := Color(0, 0, 0, 0) # 当前呼吸色(alpha 0 = 不画)
var outline_sides: Array[int] = [] # 墙格地面朝向描边码 0=N/1=S/2=W/3=E(程序侧结构件)
# ── 高墙感 D 投影档(研究件四变体定 D=C+地面投影,ITB 同款高度线索)──
# 南立面 = 墙格南缘内侧「口沿高光线 + 双段暗带」(邻地面格才画,墙群内聚);地面投影 = 北邻墙格
# 在本已开格北缘投渐隐暗带。参数按研究件 64px 拼版实测比例换算(立面双段 0.16/0.25 格边、投影带
# 0.22 格边;坐标推导留档 commit)。素材缺位程序化回退同样服役(结构归程序——art-bible §8.5)。
var facade_south := false: # 南立面开关(BoardView paint 按「南邻已开格」写入)
set(v):
facade_south = v
_owner.queue_redraw()
var proj_band := 0.0: # 地面投影带宽(像素,0 = 不画——BoardView 按北邻墙判定写入)
set(v):
proj_band = v
_owner.queue_redraw()
var badge_glyph := "": # 奖励徽章文字(右下角金——封印之下、变异纹之上、不进数字区)
set(v):
badge_glyph = v
if _owner._glow_layer != null and is_instance_valid(_owner._glow_layer):
_owner._glow_layer.set_badge_mask(v != "")
_owner.queue_redraw()
var dot_visible := false: # BFS 路径预览点迹(中心 6×6 小人蓝)
set(v):
dot_visible = v
_owner.queue_redraw()
var hl_visible := false: # 焦点高亮(悬停态边框覆盖层)
set(v):
hl_visible = v
_owner.queue_redraw()
var hl_color := UiKit.GOLD: # 高亮色(金目标/封印朱/禁入灰禁红)
set(v):
hl_color = v
_owner.queue_redraw()
var font: Font = null # 字体槽位(null = ThemeDB.fallback_font——BoardView.set_world_font 注入)
var bevel := 0.0: # 顶面倒角强度(0=关;档位 0/0.35/0.6/1.0)
set(v):
bevel = v
_owner.queue_redraw()
# ── 素材槽位(现全 null = 程序化占位服役;art-bible §8.2 格面 32×32 暂定档)──
var tex_base: Texture2D = null # ① 砖面底
var tex_mutation: Texture2D = null # ② 变异纹带
var tex_glyph: Texture2D = null # ③ 数字
var tex_badge: Texture2D = null # ③' 徽章
var tex_seal: Texture2D = null: # ④ 封印(槽位可运行时换装〔封印〕——同族 facade/treasure_mark
set(v): # 均 setter 触发重绘(普通 var 赋值不重绘=封印插上不显示))
if tex_seal != v:
tex_seal = v
_owner.queue_redraw()
var tex_facade: Texture2D = null # ⑥ E 格墙面材质(v3.5——南邻墙顶 center 瓦片同源,BoardView 注入)
var facade_strip := false: # E 格开关(BoardView paint 按「已开格且南邻未开墙」写入——瓦片态专用)
set(v):
facade_strip = v
_owner.queue_redraw()
# 变异角标(程序化,tex_mutation 纹带槽暂留):
# "flat_damage" = 未开格伤害型变异,左下角危险红三角(开格有代价的策略纹理标记)
# 叠加层标记(秘宝整图叠加层的格面呈现;派生信息层零回写):
# "mine_reveal" = 真视格(危险红内缩框——「这格是雷」的确定决策标记,封印照常计费);
# "reward_preview" 格不复用本字段——预读徽章走 badge_glyph 注入(board_view refresh 注入 REWARD_BADGE 字形)
var treasure_mark := "":
set(v):
if treasure_mark != v:
treasure_mark = v
_owner.queue_redraw()
var mutation_mark := "":
set(v):
if mutation_mark != v:
mutation_mark = v
_owner.queue_redraw()
# ── 未开格类型微光(英雄 8 向相邻未开格的组粒度类型提示)
# 作用集 = 可挖域 ∩ 身份可查格,由 BoardView 侧派生下发;本件只承接绘制与子件生命周期。
# 静态:不呼吸、不入动效预算;相位门控(结算/道具窗口态隐藏)在 BoardView 侧。
var glow_group := 0:
set(v):
if glow_group != v:
glow_group = v
_owner._sync_glow_layer()
var removed_dim := false: # 中立移除退色层(BoardView paint 按排雷玩法 is_removed 写入)
set(v):
removed_dim = v
_owner.queue_redraw()
var st := _CellPaintState.new()
var edge := 46.0: # 格边长(BoardView.set_cell_area 单点驱动)
set(v):
edge = v
if _glow_layer != null and is_instance_valid(_glow_layer):
_glow_layer.setup(edge, glow_group)
queue_redraw()
var cell := Vector2i.ZERO # 板坐标(诊断观测面)
# ── 未开格类型微光(英雄 8 向相邻未开格的组粒度类型提示)
# 作用集 = 可挖域 ∩ 身份可查格,由 BoardView 侧派生下发;本件只承接绘制与子件生命周期。
# 静态:不呼吸、不入动效预算;相位门控(结算/道具窗口态隐藏)在 BoardView 侧。
var glow_group := 0:
set(v):
if glow_group != v:
glow_group = v
_sync_glow_layer()
var glyph := "": # 文字位——数字/雷/封印/人/?(现行视觉封印与数字互斥,同位承载;探针直读冻结)
set(v):
glyph = v
@@ -141,267 +44,51 @@ var fog_state := 0: # 探针直读冻结
queue_redraw()
var _glow_layer: Node2D = null
var base = null # 格面基座层绘制域件(_init 自建)
var face = null # 格面标识与叠加层绘制域件(_init 自建)
func _init() -> void:
st._owner = self
base = _BASE_LAYER.new(self)
face = _MARK_OVERLAY.new(self)
func _draw() -> void:
var rect := Rect2(Vector2.ZERO, Vector2(st.edge, st.edge))
_draw_base_layer(rect)
_draw_mutation_marks()
_draw_glyph_layer(rect)
_draw_overlay_layers(rect)
## ① 砖面底层域(占位 = StyleBoxFlat:格底色 + 暗化描边 + 3px 圆角;瓦片态描边覆盖层;
## 呼吸微光/主角蓝框由 BoardView 改 bg_sb 后触发重绘。素材缺位回退走 elif 程序化原样,零观感变化)
func _draw_base_layer(rect: Rect2) -> void:
if st.tex_base != null:
draw_texture_rect(st.tex_base, rect, false)
# 轮廓加强(轮廓线不明显):墙格地面朝向边补 2px 深墨线(§8.5 结构归程序——
# 素材 1px 墨线在 45/36px 非整数缩放下视觉衰减,程序线保底;墙-墙内界不画,保墙群内聚;
# 坐标推导:各边内贴 2px 矩形,相邻边矩形全长相交=周界闭合)
if not st.outline_sides.is_empty():
_draw_outline_sides()
_draw_south_facade()
_draw_north_projection()
_draw_e_facade()
# 瓦片态描边覆盖层:tex_base 在位时 BoardView 传入的 bg_sb
# 已降级为「透明底 + 描边」载体——呼吸微光/主角蓝框画在瓦片之上(art-bible §1.2 叠层序
# 不变:底 < 纹带 < 数字 < 封印 < 焦点高亮);素材缺位回退走 elif 程序化原样,零观感变化
if st.bg_sb != null:
draw_style_box(st.bg_sb, rect)
_draw_contact_or_fallback(rect)
## 接触带微光或平色回退域(英雄格周界空间侧——正交邻墙=整条边;斜向=共享角点+两侧各半条边;光不进墙格):
## 带宽 4px 贴格边内侧(坐标推导:N=[0,0,edge,4] S=[0,edge-4,edge,4] W=[0,0,4,edge] E=[edge-4,0,4,edge];
## 半条边=沿邻边自角点起 edge/2;角点圆 r=6 贴角点圆心,近白芯 r=2.5 提亮)
func _draw_contact_or_fallback(rect: Rect2) -> void:
if st.contact_col.a > 0.0:
_draw_north_projection() # 平色回退+微光并发的英雄格补画(瓦片路径已画——同像素重复无观感差)
_draw_e_facade() # E 格墙面补画(同上——英雄格兼 E 格时瓦片路径已画,重复无害)
_draw_contact_bands()
elif st.bg_sb != null:
draw_style_box(st.bg_sb, rect)
_draw_south_facade() # 平色回退路径——D 投影档两件同样服役(结构归程序)
_draw_north_projection()
_draw_bevel()
## ②③④ 中层域:变异纹带与标记/数字色牌与字形/徽章/封印
func _draw_glyph_layer(rect: Rect2) -> void:
# ② 变异纹带(无程序化纹带——槽位先行,贴图落位即用)
if st.tex_mutation != null:
draw_texture_rect(st.tex_mutation, rect, false)
# ③ 数字/徽章(数字 ≥ 格高 50% 墨族对格底 ≥4.5:1;徽章右下角金,遮蔽态 = "?")
if glyph != "":
_draw_digit_plate()
if st.tex_glyph != null:
draw_texture_rect(st.tex_glyph, rect, false)
else:
_draw_glyph(glyph, glyph_color, maxi(18, int(ceil(st.edge * 0.5)))) # 字号下限 18(§7.4 冻结公式)
if st.badge_glyph != "":
if st.tex_badge != null:
draw_texture_rect(st.tex_badge, rect, false)
else:
_draw_badge(st.badge_glyph)
# ④ 封印(现行视觉封印文字在 ③ 文字位承载——独立槽位留给封印图)
if st.tex_seal != null:
draw_texture_rect(st.tex_seal, rect, false)
## 数字色牌后备域(圣经 v3.5 冻结④:数字亮墨直画已开格底须垫牌;
## 牌=后备件——雷/「?」维持牌载保读性(牌上深墨族 12:1);
## 牌尺寸 0.60/0.62 格边居中;封印=未开格不垫牌)
func _draw_digit_plate() -> void:
var pw := st.edge * 0.60
var ph := st.edge * 0.62
var pr := Rect2((st.edge - pw) * 0.5, (st.edge - ph) * 0.5, pw, ph)
draw_rect(pr, UiKit.DIGIT_PLATE, true)
draw_rect(pr, UiKit.DIGIT_PLATE_EDGE, false, 1.0)
## ⑤⑥⑦ 顶层域:路径点迹 + 焦点高亮 + 视野迷雾 + 中立移除退色
func _draw_overlay_layers(rect: Rect2) -> void:
# ⑤ 路径点迹 + 焦点高亮(悬停态覆盖层,不参与命中)
if st.dot_visible:
var ds := 6.0
draw_rect(Rect2(Vector2((st.edge - ds) * 0.5, (st.edge - ds) * 0.5), Vector2(ds, ds)), UiKit.HERO_BLUE, true)
if st.hl_visible:
# 悬停高亮减淡(金框太明显——绘制时 55% alpha,hl_color 属性与探针断言面不动)
draw_rect(Rect2(1, 1, st.edge - 2.0, st.edge - 2.0), Color(st.hl_color, 0.55), false, 2.0) # 2px 内描边
_draw_fog_layer()
# ⑦ 中立移除退色层(退色降档:暗幕压顶全层覆盖,暗淡记忆态同族呈现语义;
# 顶层于迷雾之上——移除格不再参与迷雾语义。本实现移除集=未揭示危险格(无数字无封印印))
if st.removed_dim:
draw_rect(Rect2(Vector2.ZERO, Vector2(st.edge, st.edge)), Color(0.12, 0.10, 0.09, 0.62), true)
var rect := Rect2(Vector2.ZERO, Vector2(edge, edge))
base.draw_base(self, rect) # 基座层整树(描边/立面/投影/接触带/倒角与其补画序)
face.draw_marks(self, rect) # 变异标记
face.draw_glyph_layer(self, rect, glyph, glyph_color, plate) # 字形/色牌/徽章/封印
face.draw_overlay_under(self, rect) # 点迹+高亮(雾层由宿主夹在其后)
_draw_fog_layer(rect) # 宿主迷雾域(原位——雾夹在 hl 与 removed 之间)
face.draw_removed_dim(self, rect) # 退色层
## ⑥ 视野迷雾层(最顶遮罩,§6.5 落文):
## 全黑=不透明纯黑盖全部叠层(含封印印/徽章/高亮——封印印记随格隐没,§6.5 显式推论);
## 记忆态=记忆板素色压平(纹理免疫——色牌/封印印/徽章随板隐没)+数字记忆墨重画(数字可读硬指标 ≥4.5:1)
func _draw_fog_layer() -> void:
func _draw_fog_layer(rect: Rect2) -> void:
if fog_state == 1:
draw_rect(Rect2(Vector2.ZERO, Vector2(st.edge, st.edge)), Color(0, 0, 0, 1.0), true)
draw_rect(rect, Color(0, 0, 0, 1.0), true)
elif fog_state == 2:
_draw_fog_memory()
## 墙格轮廓域:地面朝向边补 2px 深墨线(各边内贴 2px 矩形,相邻边矩形全长相交=周界闭合)
func _draw_outline_sides() -> void:
var ow := 2.0
var oc := UiKit.FOG_OUTLINE
for b in st.outline_sides:
var or_ := Rect2()
match int(b):
0: or_ = Rect2(0, 0, st.edge, ow)
1: or_ = Rect2(0, st.edge - ow, st.edge, ow)
2: or_ = Rect2(0, 0, ow, st.edge)
3: or_ = Rect2(st.edge - ow, 0, ow, st.edge)
draw_rect(or_, oc, true)
## 接触带微光域:正交整条边 + 斜向共享角点与两侧半条边
func _draw_contact_bands() -> void:
var band := 4.0
var half := st.edge * 0.5
for b in st.contact_bands:
var r := Rect2()
match int(b):
0: r = Rect2(0, 0, st.edge, band)
1: r = Rect2(0, st.edge - band, st.edge, band)
2: r = Rect2(0, 0, band, st.edge)
3: r = Rect2(st.edge - band, 0, band, st.edge)
draw_rect(r, st.contact_col, true)
for cc in st.contact_corners:
_draw_contact_corner(int(cc), band, half)
## 斜向角点域:角点圆 r=6 贴角点圆心 + 近白芯 r=2.5 提亮 + 半条边(角点沿两条邻边各延伸 edge/2——
## 坐标推导:横带沿 N/S 自角点向板心侧 half;NW/SE 半带 x=y=角点坐标,NE/SE 半带自 edge-half 收进——
## 正交整边时重叠同色无害)
func _draw_contact_corner(cc: int, band: float, half: float) -> void:
var pt := Vector2.ZERO
match cc:
0: pt = Vector2(0, 0)
1: pt = Vector2(st.edge, 0)
2: pt = Vector2(0, st.edge)
3: pt = Vector2(st.edge, st.edge)
draw_circle(pt, 6.0, st.contact_col)
draw_circle(pt, 2.5, Color(1, 1, 1, minf(1.0, st.contact_col.a * 0.95)))
if cc == 0 or cc == 1:
# N 侧横带:NW 自 x=0、NE 自 x=edge-half
draw_rect(Rect2(pt.x if cc == 0 else pt.x - half, 0.0, half, band), st.contact_col, true)
if cc == 2 or cc == 3:
# S 侧横带:SW 自 x=0、SE 自 x=edge-half
draw_rect(Rect2(pt.x if cc == 2 else pt.x - half, st.edge - band, half, band), st.contact_col, true)
if cc == 0 or cc == 2:
# W 侧竖带:NW 自 y=0、SW 自 y=edge-half
draw_rect(Rect2(0.0, pt.y if cc == 0 else pt.y - half, band, half), st.contact_col, true)
if cc == 1 or cc == 3:
# E 侧竖带:NE 自 y=0、SE 自 y=edge-half
draw_rect(Rect2(st.edge - band, pt.y if cc == 1 else pt.y - half, band, half), st.contact_col, true)
## 顶面倒角域(光源左上——上/左内沿受光 2px、下/右内沿背光 2px;内缩 2px 让
## 呼吸微光/主角蓝边框保持最外沿可见;强度随档位)
func _draw_bevel() -> void:
if st.bevel <= 0.0:
return
var base: Color = st.bg_sb.bg_color
var lit: Color = base.lightened(0.22 * st.bevel)
var dark: Color = base.darkened(0.22 * st.bevel)
var t := 2.0
draw_rect(Rect2(t, t, st.edge - t * 2.0, t), lit, true)
draw_rect(Rect2(t, t, t, st.edge - t * 2.0), lit, true)
draw_rect(Rect2(t, st.edge - t * 2.0, st.edge - t * 2.0, t), dark, true)
draw_rect(Rect2(st.edge - t * 2.0, t, t, st.edge - t * 2.0), dark, true)
## 变异标记域:真视格=危险红内缩框/未开格伤害型变异=左下角危险红三角
func _draw_mutation_marks() -> void:
if st.treasure_mark == "mine_reveal":
var inset := st.edge * 0.14
draw_rect(Rect2(inset, inset, st.edge - inset * 2.0, st.edge - inset * 2.0),
Color(UiKit.RED_MINE, 0.9), false, 2.0)
if st.mutation_mark == "flat_damage":
var mw := st.edge * 0.28
var mpts := PackedVector2Array([Vector2(0, st.edge - mw), Vector2(0, st.edge), Vector2(mw, st.edge)])
draw_colored_polygon(mpts, Color(UiKit.RED_MINE, 0.85))
_draw_fog_memory(rect)
## 记忆态换装域(demo 口径「地板纹理 + 灰罩 α.66」:
## 地板纹理原样直画 + FOG_MEMORY_PLATE α.66 灰罩压顶;素材零改动、格边长零改动。
## 记忆墨 FOG_MEMORY_INK 对合成底归一后(真实渲染面)三关 5.71–5.93:1 ≥4.5:1(§7.2 硬指标;
## 测点行值与素材随动,见 ui_contrast_probe 迷雾段))
func _draw_fog_memory() -> void:
if st.tex_base != null:
draw_texture_rect(st.tex_base, Rect2(Vector2.ZERO, Vector2(st.edge, st.edge)), false)
draw_rect(Rect2(Vector2.ZERO, Vector2(st.edge, st.edge)), Color(UiKit.FOG_MEMORY_PLATE, 0.66), true)
func _draw_fog_memory(rect: Rect2) -> void:
if base.tex_base != null:
draw_texture_rect(base.tex_base, rect, false)
draw_rect(rect, Color(UiKit.FOG_MEMORY_PLATE, 0.66), true)
if glyph != "":
_draw_glyph(glyph, UiKit.FOG_MEMORY_INK, maxi(18, int(ceil(st.edge * 0.5)))) # 字号下限 18(§7.4 冻结公式同源)
# 南立面(D 档件一——墙格南缘内侧,自底边向上:双段暗带在下、口沿高光线贴其上沿):
# 坐标推导(自格底边起算):远段=[edge−far, edge],近段=[edge−far−near, edge−far],
# 高光线=[edge−far−near−hl, edge−far−near]——与研究件「墙顶面→高光→暗段→更暗段→格界」下行序一致
func _draw_south_facade() -> void:
if not st.facade_south:
return
var far_h := st.edge * FACADE_FAR_FRAC
var near_h := st.edge * FACADE_NEAR_FRAC
var y_far := st.edge - far_h
var y_near := y_far - near_h
var y_hl := y_near - FACADE_HIGHLIGHT_PX
draw_rect(Rect2(0.0, y_hl, st.edge, FACADE_HIGHLIGHT_PX), UiKit.STAND_STONE_RIM, true) # 口沿高光(UiKit.STAND_STONE_RIM 并档——同值单点)
draw_rect(Rect2(0.0, y_near, st.edge, near_h), FACADE_NEAR_COL, true)
draw_rect(Rect2(0.0, y_far, st.edge, far_h), FACADE_FAR_COL, true)
# 地面投影(D 档件二——北邻墙格在本已开格北缘投渐隐暗带,自北缘向南三段衰减):
# 坐标推导:三等分 proj_band,α 0.28/0.16/0.06(研究件实测贴墙 α≈0.28、带末渐融入地面)
func _draw_north_projection() -> void:
if st.proj_band <= 0.0:
return
var seg := st.proj_band / 3.0
draw_rect(Rect2(0.0, 0.0, st.edge, seg), PROJECTION_NEAR_COL, true)
draw_rect(Rect2(0.0, seg, st.edge, seg), PROJECTION_MID_COL, true)
draw_rect(Rect2(0.0, seg * 2.0, st.edge, seg), PROJECTION_EDGE_COL, true)
# E 格高墙面(圣经 v3.5 冻结①——方向稿 draw_facade 移植):本格已开且南邻为墙 →
# 南部 30% 承接墙面。材质 = 墙顶 center 瓦片顶部 30% 区带**原亮度**直贴(零暗档零阴影);
# 墙脚阴线只画地面/墙面交界(strip 顶缘 1px);墙面底缘(格界处)不画任何线——直接接南侧墙顶
# (白边导致两截)。仅瓦片态服役(tex_facade 缺位 = 平色回退原语义不动)。
func _draw_e_facade() -> void:
if not st.facade_strip or st.tex_facade == null:
return
var strip_h := st.edge * E_FACADE_FRAC
var y0 := st.edge - strip_h
var ts := st.tex_facade.get_size()
draw_texture_rect_region(st.tex_facade, Rect2(0.0, y0, st.edge, strip_h),
Rect2(0.0, 0.0, ts.x, ts.y * E_FACADE_FRAC))
draw_rect(Rect2(0.0, y0, st.edge, 1.0), UiKit.E_FACADE_FOOT_COL, true)
# 文字位绘制:水平居中 + 垂直居中(基线 = (格高 − 字高)/2 + 上伸部)
func _draw_glyph(g: String, col: Color, fs: int) -> void:
var f := st.font if st.font != null else ThemeDB.fallback_font
if f == null:
return
var asc := f.get_ascent(fs)
var desc := f.get_descent(fs)
draw_string(f, Vector2(0.0, (st.edge - (asc + desc)) * 0.5 + asc), g,
HORIZONTAL_ALIGNMENT_CENTER, st.edge, fs, col)
face.draw_centered_text(self, rect, glyph, UiKit.FOG_MEMORY_INK, maxi(18, int(ceil(edge * 0.5)))) # 字号下限 18(§7.4 冻结公式同源)
# 微光子件生命周期:有组才建、组变即换、无组即撤——作用集 ≤8 格常驻,
# 其余格零节点零绘制成本。与父件 _draw() 分离的三条理由见本件头注(命令序列/重绘预算/材质挂点)。
func _sync_glow_layer() -> void:
if st.glow_group == 0:
if glow_group == 0:
if _glow_layer != null and is_instance_valid(_glow_layer):
_glow_layer.queue_free()
_glow_layer = null
@@ -409,15 +96,5 @@ func _sync_glow_layer() -> void:
if _glow_layer == null or not is_instance_valid(_glow_layer):
_glow_layer = _GLOW_LAYER.new()
add_child(_glow_layer)
_glow_layer.setup(st.edge, st.glow_group)
_glow_layer.set_badge_mask(st.badge_glyph != "")
# 徽章绘制:右下角金(文字贴角内缩 2–3px)
func _draw_badge(g: String) -> void:
var f := st.font if st.font != null else ThemeDB.fallback_font
if f == null:
return
var fs := maxi(10, int(st.edge * 0.28))
var sz := f.get_string_size(g, HORIZONTAL_ALIGNMENT_LEFT, -1, fs)
draw_string(f, Vector2(st.edge - sz.x - 2.0, st.edge - 3.0), g, HORIZONTAL_ALIGNMENT_LEFT, -1, fs, UiKit.GOLD)
_glow_layer.setup(edge, glow_group)
_glow_layer.set_badge_mask(face.badge_glyph != "")
+130
View File
@@ -0,0 +1,130 @@
## VERTICAL SLICE - NOT FOR PRODUCTION
## 悬停预承诺呈现域件(BoardView 拆件——单一变化原因=悬停反馈语义):
## 三语义光标、目标格边框、BFS 路径预览、chord 双击首遇锚的唯一承载(自 board_view 收编 11 函数族)。
## 无 class_name(类名缓存面纪律)——经宿主 board_view preload 引用;构造=引用束注入
## (cells/minesweeper/diggable 共享引用+格命中换算/壳级光标写入/hover_forbidden 与 chord 发射注入 Callable——
## 输入经宿主三入站口委托,禁反向持宿主引用);_r0 出生展开区成员留宿主。
extends RefCounted
const COL_HL_TARGET := UiKit.GOLD # 悬停目标格边框(金)
const COL_SEAL := UiKit.SEAL_BLACK # 封印黑(与宿主 :658 双侧服役——各自 alias UiKit 单源)
const CURSOR_DIG := Input.CURSOR_CROSS # 挖——镐形自绘纹理载体
const CURSOR_MOVE_SEM := Input.CURSOR_ARROW # 移动——箭头(命名避开 Control.CURSOR_MOVE 原生成员遮蔽)
const CHORD_WINDOW_MS := 350
var _cells := {} # 共享引用(宿主容器同对象——rebuild 只 clear 不重绑)
var _minesweeper = null # 排雷玩法 只读查询引用(宿主 rebuild 重绑时同拍回写本成员)
var _diggable := {} # 共享引用(可挖域——呼吸微光作用集同源)
var _cb_cell_at: Callable # 格命中换算(宿主 _cell_at——整图公式单点留宿主)
var _cb_cursor: Callable # 壳级光标写入(宿主 mouse_default_cursor_shape 单点)
var _cb_forbidden: Callable # hover_forbidden 信号发射(首遇 toast 去重归组合根)
var _cb_chord: Callable # chord_attempted 信号发射(chord 肌肉记忆提示锚)
var _hover := Vector2i(-9, -9)
var _last_click := {"cell": Vector2i(-9, -9), "ms": -100000}
func _init(bundle: Dictionary) -> void:
_cells = bundle["cells"]
_minesweeper = bundle["minesweeper"]
_diggable = bundle["diggable"]
_cb_cell_at = bundle["cell_at"]
_cb_cursor = bundle["cursor"]
_cb_forbidden = bundle["forbidden"]
_cb_chord = bundle["chord"]
func _hover_at(pos: Vector2) -> void:
var c: Vector2i = _cb_cell_at.call(pos)
if c.x < 0:
if _hover.x >= 0:
_on_cell_unhover(_hover)
elif c != _hover:
if _hover.x >= 0:
_on_cell_unhover(_hover)
_on_cell_hover(c)
func _on_shell_mouse_exited() -> void:
if _hover.x >= 0:
_on_cell_unhover(_hover)
# chord 肌肉记忆首遇锚:同格双左击快开尝试(350ms 窗)——每 run 一次提示由组合根去重
func _detect_chord(c: Vector2i) -> void:
var now := Time.get_ticks_msec()
if _last_click.cell == c and now - int(_last_click.ms) <= CHORD_WINDOW_MS:
_cb_chord.call(c)
_last_click.ms = -100000
return
_last_click = {"cell": c, "ms": now}
func _on_cell_hover(c: Vector2i) -> void:
_hover = c
_apply_hover_visuals(c)
func _on_cell_unhover(c: Vector2i) -> void:
if _hover == c:
_hover = Vector2i(-9, -9)
_clear_hover_visuals(c)
func _refresh_hover_after_paint() -> void:
# 状态随 refresh 变化后光标/边框语义需重算(悬停格四格态可能已变)
if _hover.x >= 0 and _cells.has(_hover):
_apply_hover_visuals(_hover)
func _apply_hover_visuals(c: Vector2i) -> void:
if _minesweeper == null or not _cells.has(c):
return
_clear_hover_visuals(c)
var u: Node2D = _cells[c]
var revealed: bool = _minesweeper.is_revealed(c)
var seal: bool = _minesweeper.has_seal(c)
var adjacent: bool = _diggable.has(c)
if revealed:
u.face.hl_visible = true
u.face.hl_color = COL_HL_TARGET # 移动目标格边框(金)
_set_cursor_shape(c, CURSOR_MOVE_SEM)
_show_path_preview(c)
elif adjacent:
u.face.hl_visible = true
u.face.hl_color = COL_HL_TARGET # 挖掘目标格边框(相邻封印格同此——左键直接挖)
_set_cursor_shape(c, CURSOR_DIG)
elif seal:
u.face.hl_visible = true
u.face.hl_color = COL_SEAL # 已承诺封印标记(封印黑;无交互可供)
_set_cursor_shape(c, Input.CURSOR_FORBIDDEN)
else:
u.face.hl_visible = true
u.face.hl_color = UiKit.RED_FORBID # 不可及域灰禁框(禁止光标+首遇 toast 双通道)
_set_cursor_shape(c, Input.CURSOR_FORBIDDEN)
_cb_forbidden.call(c)
func _clear_hover_visuals(c: Vector2i) -> void:
if not _cells.has(c):
return
_cells[c].face.hl_visible = false
_hide_path_preview()
func _set_cursor_shape(c: Vector2i, shape: int) -> void:
_cb_cursor.call(shape) # 壳级光标(悬停格语义决定——单格悬停恒一)
func _show_path_preview(c: Vector2i) -> void:
# 合法性指示:悬停已开格 → BFS 路径蓝细线点迹(compute_move_path 只读面)
if _minesweeper == null:
return
var path: Array[Variant] = _minesweeper.compute_move_path(c)
for pc in path:
if _cells.has(pc):
_cells[pc].face.dot_visible = true
func _hide_path_preview() -> void:
for c in _cells:
_cells[c].face.dot_visible = false
@@ -0,0 +1 @@
uid://dojreaughx7tf
+130 -174
View File
@@ -12,6 +12,7 @@ const _CELL_UNIT := preload("res://presentation/views/board_cell_unit.gd")
const _BOARD_WORLD := preload("res://presentation/views/board_world.gd")
const _TILE_PALETTE := preload("res://presentation/views/tile_palette.gd")
const _HERO_SPRITE := preload("res://presentation/views/hero_sprite.gd")
const _BOARD_HOVER := preload("res://presentation/views/board_hover.gd")
const COL_BRICK := UiKit.BRICK # 未开——掩尘完整地砖(色板原语 #C9AF83)
const COL_FLOOR := UiKit.FLOOR # 已开——裸土 #B39A78(碎裂裸露地面)
@@ -20,17 +21,13 @@ const COL_HERO := UiKit.HERO_BLUE # 小人边框——小人蓝
const COL_SEAL := UiKit.SEAL_BLACK # 封印黑 #000000
const COL_GOLD := UiKit.GOLD # 奖励金 #F0A828
const COL_CONTACT := UiKit.CONTACT_GLOW # 接触带微光基色(蓝族浅一档·近白蓝——§3.2 v2.8)
const COL_HL_TARGET := UiKit.GOLD # 悬停目标格边框(金)
const REWARD_BADGE := { # 已开格格面资源身份 icon(cell_type 九型键)
"attack": "攻", "defense": "守", "heal": "医", "blast": "爆", "weaken": "弱", "pierce": "穿", "magic": "魔",
"action": "行", # 行 = 行动点型(ap_up/ap_drain 两行)
"gp": "金", # 金 = GP 型(gp_gain/gp_loss 两行;金色系 ~40° 相位,禁入带紫赤 300–345° 外,取色 UiKit.GOLD 徽标色单点)
}
const BADGE_PLACEHOLDER := "?" # 未知图标键占位纹样(HUD框架:禁静默空图标)
const CURSOR_DIG := Input.CURSOR_CROSS # 挖——镐形自绘纹理载体
const CURSOR_SEAL := Input.CURSOR_POINTING_HAND # 封印——封印形自绘纹理载体
const CURSOR_MOVE_SEM := Input.CURSOR_ARROW # 移动——箭头(命名避开 Control.CURSOR_MOVE 原生成员遮蔽)
const CHORD_WINDOW_MS := 350
const SEP := 2 # 格间距(格尺寸公式与命中换算共用)
# 棋盘立体参数
@@ -67,8 +64,6 @@ var _contact_unit: Node2D = null # 接触带承载单元(=英雄格 CellUnit
var _install_tw: Tween # 入场淡入 tween(rebuild 重入先杀)
var _ripple_tws: Array[Tween] = [] # R0 涟漪逐格 tween(rebuild 重入全杀)
var _dig_glow := false # 挖掘期才允许唯一在动元素(art-bible §2.1)
var _hover := Vector2i(-9, -9)
var _last_click := {"cell": Vector2i(-9, -9), "ms": -100000}
var _r0 := {} # 出生展开区 R₀(地图战斗资源 mapping 资格域 = S∖R₀——徽章查询跳过,防 E19 诊断噪音)
var _desat_mat: ShaderMaterial
var _desat_tween: Tween
@@ -77,6 +72,7 @@ var _cell := 46.0 # 当前格边长(set_cell_area 按容器尺寸重
# ── 拆出件(状态单点在件内)──
var _palette = _TILE_PALETTE.new() # 瓦片件:装载缓存+查表+明度/墨族静态算法
var _hero_sprite = _HERO_SPRITE.new() # 英雄精灵件:_init 挂为本件子级(tween 需在树上)
var _hover_comp: _BOARD_HOVER # 悬停预承诺呈现域件:三语义光标/目标格边框/路径预览/chord 首遇锚(_init 建为子件——HeroSprite 挂载先例)
# ── 件成员同名转发(探针直读面零改动:读 _palette.seal_tex、读写 _hero_sprite.tex_idle;其余为随迁状态单点再导出)──
# ---- 视野迷雾(纯呈现层;现行事实源=HUD框架「视野迷雾」节 v0.13,渲染规格=art-bible §6.5 v3.5)----
@@ -120,6 +116,25 @@ func _init() -> void:
_hero_sprite.tex_idle = UiKit.load_tex(UiKit.TEX_HERO_IDLE)
_hero_sprite.tex_walk = UiKit.load_tex(UiKit.TEX_HERO_WALK)
_palette.load_board_tiles() # 高墙/地面瓦片整批守卫装载(缺位静默回退——英雄同款纪律,禁刷屏)
_hover_comp = _BOARD_HOVER.new({
"cells": _cells, "minesweeper": _minesweeper, "diggable": _diggable,
"cell_at": _cell_at, "cursor": _set_shell_cursor,
"forbidden": _emit_hover_forbidden, "chord": _emit_chord_attempted,
})
# ---- 悬停域注入面(件回调宿主的壳级单点——Callable 目标)----
func _set_shell_cursor(shape: int) -> void:
mouse_default_cursor_shape = shape # 壳级光标(悬停格语义决定——单格悬停恒一)
func _emit_hover_forbidden(c: Vector2i) -> void:
hover_forbidden.emit(c) ## 非相邻未开格悬停(首遇 toast 归组合根去重)
func _emit_chord_attempted(c: Vector2i) -> void:
chord_attempted.emit(c) ## 双击快开尝试(chord 肌肉记忆提示锚)
func board() -> BoardData:
@@ -128,7 +143,7 @@ func board() -> BoardData:
func _ready() -> void:
_apply_custom_cursors()
mouse_exited.connect(_on_shell_mouse_exited)
mouse_exited.connect(_hover_comp._on_shell_mouse_exited)
# 结算期/道具窗口态:D 区去饱和 + 金橙偏移锁输入(明度不变——art-bible §2);
@@ -182,7 +197,7 @@ func set_treasure_overlays(reveal_cells: Array, preview_cells: Array) -> void:
func set_world_font(f: Font) -> void:
_world.board_font = f
for c in _cells:
_cells[c].st.font = f
_cells[c].face.font = f
_cells[c].queue_redraw()
@@ -201,7 +216,7 @@ func set_cell_area(avail: Vector2) -> void:
var stride := _cell + float(SEP)
for c in _cells:
var u: Node2D = _cells[c]
u.st.edge = _cell
u.edge = _cell
u.position = Vector2(c) * stride
if _world.hero != null and _hero_sprite.last.x >= 0:
_place_hero(_hero_sprite.last, _hero_sprite.last, true) # 格边长变更(窗口缩放)——英雄即时随格重置(杀位移 tween 防飞陈旧落点)
@@ -224,6 +239,7 @@ func _refresh_slab() -> void:
func rebuild(board: BoardData, minesweeper: MinesweeperRules) -> void:
_board = board
_minesweeper = minesweeper
_hover_comp._minesweeper = _minesweeper # 件内只读引用随宿主重绑同拍回写(每战新排雷玩法对象)
_palette.bind_board(_board, _minesweeper) # 查表族棋盘态随板同步(换板后首拍 refresh 前置)
for child in _world.get_children():
child.queue_free()
@@ -234,7 +250,7 @@ func rebuild(board: BoardData, minesweeper: MinesweeperRules) -> void:
_contact_unit = null
_hero_sprite.last = Vector2i(-99, -99)
_r0.clear()
_hover = Vector2i(-9, -9)
_hover_comp._hover = Vector2i(-9, -9)
for c in _board.compute_r0():
_r0[c] = true
# 瓦片套随板图型切换(board_gen 词表 v1.1 dungeon/underdark/deep_underdark;
@@ -246,25 +262,30 @@ func rebuild(board: BoardData, minesweeper: MinesweeperRules) -> void:
for y in _board.height:
for x in _board.width:
var c := Vector2i(x, y)
var u: Node2D = _CELL_UNIT.new()
u.st.cell = c
u.st.edge = _cell
u.position = Vector2(c) * stride
u.st.bevel = DEPTH_BEVEL # 新建格单元继承
u.use_parent_material = true # 去饱和材质挂 BoardWorld——单元随世界材质灰化
if _palette.tiles_ok:
# NEAREST 采样(32×32 源 × 45/36px 格边非整数缩放接受档,
# 与英雄小人 1.5× 豁免同级(圣经 §8.2);只在瓦片
# 模式启用——程序化回退路径渲染零扰动(含格面文字采样不回退不变化)
u.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
u.st.font = _world.board_font
_world.add_child(u)
_cells[c] = u
_cells[c] = _build_cell_unit(c, stride)
set_cell_area(size)
_install_entrance_fx()
refresh()
# 逐格构建器(rebuild 建格循环唯一出函面):.new() 与属性装配逐字迁入,循环体只调构建器
func _build_cell_unit(c: Vector2i, stride: float) -> Node2D:
var u: Node2D = _CELL_UNIT.new()
u.cell = c
u.edge = _cell
u.position = Vector2(c) * stride
u.base.bevel = DEPTH_BEVEL # 新建格单元继承
u.use_parent_material = true # 去饱和材质挂 BoardWorld——单元随世界材质灰化
if _palette.tiles_ok:
# NEAREST 采样(32×32 源 × 45/36px 格边非整数缩放接受档,
# 与英雄小人 1.5× 豁免同级(圣经 §8.2);只在瓦片
# 模式启用——程序化回退路径渲染零扰动(含格面文字采样不回退不变化)
u.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
u.face.font = _world.board_font
_world.add_child(u)
return u
# 逐格重绘(挖掘/结算后调用)
func refresh() -> void:
if _board == null or _minesweeper == null:
@@ -278,7 +299,7 @@ func refresh() -> void:
for y in _board.height:
for x in _board.width:
_paint_cell(Vector2i(x, y), hero)
_refresh_hover_after_paint()
_hover_comp._refresh_hover_after_paint()
_apply_contact_bands()
_update_hero(hero) # 英雄精灵 diff 驱动
@@ -428,33 +449,18 @@ func _update_world_size() -> void:
# 真实输入路径(Node2D 迁移批 Decision 3):壳层 _gui_input → 整图公式换算 → 复用既有 hover/点选/chord 出口
#(悬停族已拆 board_hover 件——本壳留三入站口委托)
func _gui_input(ev: InputEvent) -> void:
if _minesweeper == null:
return
if ev is InputEventMouseMotion:
_hover_at(ev.position)
_hover_comp._hover_at(ev.position)
elif ev is InputEventMouseButton and ev.pressed:
var c := _cell_at(ev.position)
if c.x >= 0:
_on_cell_input(c, ev)
func _hover_at(pos: Vector2) -> void:
var c := _cell_at(pos)
if c.x < 0:
if _hover.x >= 0:
_on_cell_unhover(_hover)
elif c != _hover:
if _hover.x >= 0:
_on_cell_unhover(_hover)
_on_cell_hover(c)
func _on_shell_mouse_exited() -> void:
if _hover.x >= 0:
_on_cell_unhover(_hover)
func _on_cell_input(c: Vector2i, ev: InputEvent) -> void:
if _minesweeper == null or not (ev is InputEventMouseButton and ev.pressed):
return
@@ -463,7 +469,7 @@ func _on_cell_input(c: Vector2i, ev: InputEvent) -> void:
action_requested.emit(c, "move")
else:
action_requested.emit(c, "dig")
_detect_chord(c)
_hover_comp._detect_chord(c)
elif ev.button_index == MOUSE_BUTTON_RIGHT:
if not _minesweeper.has_seal(c):
action_requested.emit(c, "seal_place")
@@ -471,89 +477,6 @@ func _on_cell_input(c: Vector2i, ev: InputEvent) -> void:
# 左键相邻封印格直接挖(规则引擎放行)。
# chord 肌肉记忆首遇锚:同格双左击快开尝试(350ms 窗)——每 run 一次提示由组合根去重
func _detect_chord(c: Vector2i) -> void:
var now := Time.get_ticks_msec()
if _last_click.cell == c and now - int(_last_click.ms) <= CHORD_WINDOW_MS:
chord_attempted.emit(c)
_last_click.ms = -100000
return
_last_click = {"cell": c, "ms": now}
# ---- 悬停预承诺(pattern 4):三语义光标 + 目标格边框 + BFS 路径预览 ----
func _on_cell_hover(c: Vector2i) -> void:
_hover = c
_apply_hover_visuals(c)
func _on_cell_unhover(c: Vector2i) -> void:
if _hover == c:
_hover = Vector2i(-9, -9)
_clear_hover_visuals(c)
func _refresh_hover_after_paint() -> void:
# 状态随 refresh 变化后光标/边框语义需重算(悬停格四格态可能已变)
if _hover.x >= 0 and _cells.has(_hover):
_apply_hover_visuals(_hover)
func _apply_hover_visuals(c: Vector2i) -> void:
if _minesweeper == null or not _cells.has(c):
return
_clear_hover_visuals(c)
var u: Node2D = _cells[c]
var revealed: bool = _minesweeper.is_revealed(c)
var seal: bool = _minesweeper.has_seal(c)
var adjacent: bool = _diggable.has(c)
if revealed:
u.st.hl_visible = true
u.st.hl_color = COL_HL_TARGET # 移动目标格边框(金)
_set_cursor_shape(c, CURSOR_MOVE_SEM)
_show_path_preview(c)
elif adjacent:
u.st.hl_visible = true
u.st.hl_color = COL_HL_TARGET # 挖掘目标格边框(相邻封印格同此——左键直接挖)
_set_cursor_shape(c, CURSOR_DIG)
elif seal:
u.st.hl_visible = true
u.st.hl_color = COL_SEAL # 已承诺封印标记(封印黑;无交互可供)
_set_cursor_shape(c, Input.CURSOR_FORBIDDEN)
else:
u.st.hl_visible = true
u.st.hl_color = UiKit.RED_FORBID # 不可及域灰禁框(禁止光标+首遇 toast 双通道)
_set_cursor_shape(c, Input.CURSOR_FORBIDDEN)
hover_forbidden.emit(c)
func _clear_hover_visuals(c: Vector2i) -> void:
if not _cells.has(c):
return
_cells[c].st.hl_visible = false
_hide_path_preview()
func _set_cursor_shape(c: Vector2i, shape: int) -> void:
mouse_default_cursor_shape = shape # 壳级光标(悬停格语义决定——单格悬停恒一)
func _show_path_preview(c: Vector2i) -> void:
# 合法性指示:悬停已开格 → BFS 路径蓝细线点迹(compute_move_path 只读面)
if _minesweeper == null:
return
var path: Array[Variant] = _minesweeper.compute_move_path(c)
for pc in path:
if _cells.has(pc):
_cells[pc].st.dot_visible = true
func _hide_path_preview() -> void:
for c in _cells:
_cells[c].st.dot_visible = false
# ---- 奖励徽章(已开格身份 icon——封印之下、纹带之上、不进数字区) ----
func _update_badge(c: Vector2i) -> String:
@@ -606,16 +529,30 @@ func _paint_cell(c: Vector2i, hero: Vector2i) -> void:
var seal: bool = _minesweeper.has_seal(c)
var removed: bool = _minesweeper.is_removed(c) # 中立移除格(退色降档)
var is_hero: bool = c == hero
var glyph := ""
var bg: Color
var digit_col := COL_DIGIT
# 封印槽统一维护:封印格=封印印记纹理;其余格清 null(封印格挖开后残留在 tex_seal
# 会让 _draw 无条件把封印印画在已开格上——tex_seal 绘制无 revealed 条件)。缺盘走字形回退。
u.st.tex_seal = _palette.seal_tex if (seal and not revealed and _palette.seal_tex != null) else null
u.face.tex_seal = _palette.seal_tex if (seal and not revealed and _palette.seal_tex != null) else null
if removed:
revealed = false # 移除格固定未开呈现基座(退色暗幕层承载;危险格本无数字,周边数字冻结)
seal = false
u.st.tex_seal = null
u.face.tex_seal = null
# 绘制层五段(字形与色牌→基底瓦片→立面投影→秘宝/变异叠加→迷雾)——段间交换经单元状态面
#(u.base/u.face 域件与 u.glyph/u.glyph_color),唯一例外=基底色 bg 经 ink 段返回值交 base 段(无单元场域承载)
var bg: Color = _paint_cell_ink(c, u, revealed, seal)
_paint_cell_base(c, u, revealed, is_hero, bg)
_paint_cell_facade(c, u, revealed)
_paint_cell_overlays(c, u, revealed)
_paint_cell_fog(c, u, revealed, hero)
u.face.removed_dim = removed
u.queue_redraw()
# 字形与色牌段:reveal 记录→字形/墨色判定+u.glyph/u.glyph_color 终写+双峰纹理板落牌;
# 返回基底色 bg(平色回退 sb 构建的唯一消费方在基底段)
func _paint_cell_ink(c: Vector2i, u: Node2D, revealed: bool, seal: bool) -> Color:
var glyph := ""
var bg: Color
var digit_col := COL_DIGIT
if revealed:
var rec: Dictionary[Variant, Variant] = _minesweeper.reveal_record(c) # 已开记录经查询面
if rec.get("kind", "") == "mine":
@@ -639,6 +576,21 @@ func _paint_cell(c: Vector2i, hero: Vector2i) -> void:
digit_col = COL_SEAL
else:
bg = COL_BRICK
u.glyph = glyph
u.glyph_color = digit_col
# 色牌后备(数字直画退牌;「危」/「?」维持牌载保读性)+ v3.4:双峰纹理板
#(_palette.digit_plate——underdark 系亮白筋+近黑斑并存的直画不可救纹理)数字落牌,牌上深墨 12:1
var plate_digit: bool = _palette.digit_plate and glyph != "" and glyph != "危" and glyph != "?" and glyph != "封" and glyph != "人"
if plate_digit:
digit_col = COL_DIGIT # 牌上深墨族(素牌 12:1——双峰纹理免疫)
u.glyph_color = digit_col
u.plate = revealed and (glyph == "危" or glyph == "?" or plate_digit)
return bg
# 基底瓦片段:瓦片查表/平色回退 sb+英雄蓝框载体;英雄贴图缺位回退字形「人」在此段落
# u.glyph(先于叠加段消费,结果与原函数字形累计局部量逐字同值)
func _paint_cell_base(c: Vector2i, u: Node2D, revealed: bool, is_hero: bool, bg: Color) -> void:
# 瓦片模式:tex_base = 查表瓦片(未开=墙瓦片/已开=地面瓦片),
# bg_sb 降级为透明描边载体——只承载呼吸微光/主角蓝框(CellUnit 瓦片态画在瓦片之上),
# 瓦片分配=格坐标哈希,初始化落定后逐拍稳定(禁逐轮重掷——圣经原则三)
@@ -658,26 +610,21 @@ func _paint_cell(c: Vector2i, hero: Vector2i) -> void:
sb = UiKit.panel_flat(Color.TRANSPARENT, Color.TRANSPARENT,UiKit.RADIUS_OBJECT, 0)
sb.set_border_width_all(3)
sb.border_color = COL_HERO
if glyph == "" and _hero_sprite.tex_idle == null:
if u.glyph == "" and _hero_sprite.tex_idle == null:
# 贴图缺位回退字形「人」(项目纹理槽惯例——贴图在位=格内字形退役,单位本体由独立精灵承载)
glyph = "人"
digit_col = COL_HERO
u.st.tex_base = tile
u.st.bg_sb = sb
u.glyph = glyph
u.glyph_color = digit_col
# 色牌后备(数字直画退牌;「危」/「?」维持牌载保读性)+ v3.4:双峰纹理板
#(_palette.digit_plate——underdark 系亮白筋+近黑斑并存的直画不可救纹理)数字落牌,牌上深墨 12:1
var plate_digit: bool = _palette.digit_plate and glyph != "" and glyph != "危" and glyph != "?" and glyph != "封" and glyph != "人"
if plate_digit:
digit_col = COL_DIGIT # 牌上深墨族(素牌 12:1——双峰纹理免疫)
u.glyph_color = digit_col
u.plate = revealed and (glyph == "危" or glyph == "?" or plate_digit)
u.st.outline_sides.assign([]) # typed Array[int](assign 保持引用语义)
u.st.facade_south = false
u.st.proj_band = 0.0
u.st.tex_facade = null
u.st.facade_strip = false
u.glyph = "人"
u.glyph_color = COL_HERO
u.base.tex_base = tile
u.base.bg_sb = sb
# 立面投影段:未开墙格南缘立面/轮廓描边码;已开格北缘投影暗带/E 格高墙面——段内重置与赋值同序
func _paint_cell_facade(c: Vector2i, u: Node2D, revealed: bool) -> void:
u.base.outline_sides.assign([]) # typed Array[int](assign 保持引用语义)
u.base.facade_south = false
u.base.proj_band = 0.0
u.base.tex_facade = null
u.base.facade_strip = false
# 封印槽不在此重置:尾部重置会与此上方条件赋值构成双写踩踏(把封印纹理恒清 null=素材在位时封印不可见);
# 上方 else 分支已是全路径清残留,尾部重置系冗余且有害
var south_n: Vector2i = c + Vector2i(0, 1)
@@ -687,44 +634,55 @@ func _paint_cell(c: Vector2i, hero: Vector2i) -> void:
if not revealed:
# 高墙感 D 投影档:南邻地面格 → 墙格南缘立「口沿高光+双段暗带」立面
#(邻地面才画——墙-墙内界保墙群内聚);板外=墙不画
u.st.facade_south = south_in and _minesweeper.is_revealed(south_n)
u.base.facade_south = south_in and _minesweeper.is_revealed(south_n)
# 轮廓加强:墙格四邻中已开(地面)格朝向记描边码(板外=墙不描——保墙群外轮廓只在墙/地交界)
for d in [Vector2i(0, -1), Vector2i(0, 1), Vector2i(-1, 0), Vector2i(1, 0)]:
var n: Vector2i = c + d
if n.x >= 0 and n.y >= 0 and n.x < _board.width and n.y < _board.height and _minesweeper.is_revealed(n):
var code := 0 if d.y < 0 else (1 if d.y > 0 else (2 if d.x < 0 else 3))
if code == 1 and u.st.facade_south:
if code == 1 and u.base.facade_south:
continue # 南缘由立面件承载(高光+双段暗带)——2px 描边让位防三重叠黑
if code == 0 and _palette.tiles_ok:
continue # v3.5 冻结① (b)-(c) 交界无边框:墙面直贴接墙顶(E 格墙面件在邻格承载)——北向描边不画(平色回退态保留描边)
u.st.outline_sides.append(code)
u.base.outline_sides.append(code)
else:
# 地面投影:北邻墙格在本已开格北缘投渐隐暗带(ITB 同款高度线索——带宽按格边比例常量)
if north_in and not _minesweeper.is_revealed(north_n):
u.st.proj_band = u.st.edge * WALL_PROJECTION_FRAC
u.base.proj_band = u.edge * WALL_PROJECTION_FRAC
# E 格高墙面(圣经 v3.5 冻结①——方向稿 is_facade_cell 口径):已开格南邻未开墙 → 南部 30%
# 承接墙面(材质=同板墙顶 center 瓦片,原亮度直贴);仅瓦片态启用——平色回退保持原语义
if south_in and not _minesweeper.is_revealed(south_n) and _palette.tiles_ok:
u.st.facade_strip = true
u.st.tex_facade = _palette.tiles.get("wall_center")
u.base.facade_strip = true
u.base.tex_facade = _palette.tiles.get("wall_center")
# 秘宝/变异叠加段:真视红框/预读徽章/变异角标/奖励徽章/类型微光组号——glyph/digit_col 局部镜像
# 自 u.glyph/u.glyph_color(原函数字形累计局部量的段内重建,预读徽章分支的无效局部写入逐字保留)
func _paint_cell_overlays(c: Vector2i, u: Node2D, revealed: bool) -> void:
# ②( 秘宝叠加层:真视格=红内缩框;预读格=奖励身份徽章(identity_resolver 既有
# 只读面取字形——零数据复制,badge 位复用);已开格标记自然退位(refresh 逐拍重算)
var glyph: String = u.glyph
var digit_col: Color = u.glyph_color
if not revealed:
u.st.treasure_mark = "mine_reveal" if _treasure_reveal.has(c) else ""
u.face.treasure_mark = "mine_reveal" if _treasure_reveal.has(c) else ""
if _treasure_preview.has(c) and glyph == "":
var pid = _identity_cb.call(c) if _identity_cb.is_valid() else null
if pid != null and REWARD_BADGE.has(String(pid.get("cell_type", ""))):
glyph = String(REWARD_BADGE[String(pid.get("cell_type", ""))])
digit_col = COL_GOLD
u.st.badge_glyph = glyph
u.face.badge_glyph = glyph
# ②' 变异角标:未开格带伤害型变异 → 危险红角标(已开=威胁已兑现标记退位);
# 回调缺位 = 无标记(程序化角标,tex_mutation 纹带槽暂留)
if not revealed and _vmark_cb.is_valid():
u.st.mutation_mark = String(_vmark_cb.call(c))
u.face.mutation_mark = String(_vmark_cb.call(c))
else:
u.st.mutation_mark = ""
u.st.badge_glyph = _update_badge(c)
u.st.glow_group = int(_glow.get(c, UiKit.GLOW_NONE))
u.face.mutation_mark = ""
u.face.badge_glyph = _update_badge(c)
u.glow_group = int(_glow.get(c, UiKit.GLOW_NONE))
# 迷雾段:灯光区外未开格全黑/已开格记忆态灰显——纯呈现零逻辑(🔴 契约 1)
func _paint_cell_fog(c: Vector2i, u: Node2D, revealed: bool, hero: Vector2i) -> void:
# 视野迷雾呈态:曼哈顿距离 > 半径 → 区外——未开格全黑(现行事实源照抄)/
# 已开格记忆态(灰显可读);以英雄格为心逐格重算,refresh()/notify_hero_move() 既有重绘驱动=移动实时跟随。
# 纯呈现零逻辑——格态/数字真值/清图判定零触碰(🔴 契约 1);结算期去饱和叠加互斥由 CellUnit 记忆态终态档承载。
@@ -734,8 +692,6 @@ func _paint_cell(c: Vector2i, hero: Vector2i) -> void:
u.fog_state = (2 if revealed else 1) if fogged else 0
else:
u.fog_state = 0
u.st.removed_dim = removed
u.queue_redraw()
# ---- 可挖域接触带呼吸微光(挖掘期唯一在动元素——§3.2 v2.8 画法:光画英雄格周界空间侧,
@@ -765,7 +721,7 @@ func _sync_glow_to_units() -> void:
for c in touched:
var u: Node2D = _cells.get(c)
if u != null:
u.st.glow_group = int(_glow.get(c, UiKit.GLOW_NONE))
u.glow_group = int(_glow.get(c, UiKit.GLOW_NONE))
func _process(delta: float) -> void:
@@ -777,14 +733,14 @@ func _process(delta: float) -> void:
if UiKit.motion_scale < 1.0:
return # 减动效:呼吸停格(refresh/enable 时已施静态色——静态可辨、无持续运动)
var k := 0.5 + 0.5 * sin(_breath_t * 3.0) # 3 rad/s≈0.48Hz——无 >3 次/秒频闪(AC 基线)
_contact_unit.st.contact_col = COL_CONTACT.lerp(UiKit.CONTACT_GLOW_DEEP, 0.55 - 0.35 * k)
_contact_unit.base.contact_col = COL_CONTACT.lerp(UiKit.CONTACT_GLOW_DEEP, 0.55 - 0.35 * k)
_contact_unit.queue_redraw()
# 带几何写入(refresh / set_dig_glow_enabled(true) 挂点):清旧承载件→按英雄格可挖域写边/角码→施色
func _apply_contact_bands() -> void:
if _contact_unit != null and is_instance_valid(_contact_unit) and (_cells.get(_minesweeper.hero_pos()) != _contact_unit if _minesweeper != null else true):
_contact_unit.st.contact_col = Color(0, 0, 0, 0)
_contact_unit.base.contact_col = Color(0, 0, 0, 0)
_contact_unit.queue_redraw()
_contact_unit = null
if _board == null or _minesweeper == null or not _dig_glow:
@@ -801,19 +757,19 @@ func _apply_contact_bands() -> void:
for d in [Vector2i(-1, -1), Vector2i(1, -1), Vector2i(-1, 1), Vector2i(1, 1)]:
if _diggable.has(_minesweeper.hero_pos() + d):
corners.append(0 if (d.x < 0 and d.y < 0) else (1 if d.x > 0 and d.y < 0 else (2 if d.x < 0 else 3)))
hu.st.contact_bands = bands
hu.st.contact_corners = corners
hu.base.contact_bands = bands
hu.base.contact_corners = corners
# 减动效:呼吸停格——refresh/enable 重放时施**静态**色(本件头注「已施静态色」的落実);
# 0.5 = 呼吸周期中值(正常态 k 的均值)。否则减动效下每次 refresh 都会按当前相位重施色,
# 带色在 refresh 间跳变=持续运动假象,且令 on/off 双帧取证无法隔离单一变量。
var k := 0.5 if UiKit.motion_scale < 1.0 else 0.5 + 0.5 * sin(_breath_t * 3.0)
hu.st.contact_col = COL_CONTACT.lerp(UiKit.CONTACT_GLOW_DEEP, 0.55 - 0.35 * k)
hu.base.contact_col = COL_CONTACT.lerp(UiKit.CONTACT_GLOW_DEEP, 0.55 - 0.35 * k)
hu.queue_redraw()
func _reset_breath() -> void:
if _contact_unit != null and is_instance_valid(_contact_unit):
_contact_unit.st.contact_col = Color(0, 0, 0, 0)
_contact_unit.base.contact_col = Color(0, 0, 0, 0)
_contact_unit.queue_redraw()
@@ -860,9 +816,9 @@ func diggable_probe() -> Dictionary:
return _diggable.duplicate()
# 悬停格只读出口(case① 悬停到达断言消费面)
# 悬停格只读出口(case① 悬停到达断言消费面——读件投影,返回语义零变化)
func hover_probe() -> Vector2i:
return _hover
return _hover_comp._hover
# 迷雾参数只读快照(case⑮ 参数漂移断言消费面)
@@ -888,5 +844,5 @@ func cell_rect_probe(c: Vector2i) -> Rect2:
if host.size.x <= 0.0 or host.size.y <= 0.0 or vp_size.x <= 0.0 or vp_size.y <= 0.0:
return Rect2()
var k: Vector2 = host.size / vp_size
var local := Rect2(u.global_position, Vector2(u.st.edge, u.st.edge))
var local := Rect2(u.global_position, Vector2(u.edge, u.edge))
return Rect2(host.position + local.position * k, local.size * k)
+204
View File
@@ -0,0 +1,204 @@
## VERTICAL SLICE - NOT FOR PRODUCTION
## 格面基座层绘制域件(CellUnit 拆件——单一变化原因=基座层视觉规格):
## 底面/描边/高墙立面/地面投影/接触带微光/顶面倒角的全部绘制入参与绘制命令。
## 无 class_name(类名缓存面纪律)——经宿主 board_cell_unit preload 引用;宿主 _draw 按层序调
## draw_base(canvas, rect) 把绘制命令落到宿主画布;setter 经 _owner 回引触发宿主重绘语义逐字。
extends RefCounted
# ── D 投影档绘制常量(研究件实测取色——立面高光/双段暗带/地面投影;黑罩 alpha 叠加实测等效)──
const FACADE_HIGHLIGHT_PX := 2.0 # 口沿高光线厚(像素)
const FACADE_NEAR_FRAC := 0.16 # 立面近段高(格边比——研究件 10/64)
const FACADE_FAR_FRAC := 0.25 # 立面远段高(格边比——研究件 16/64)
const FACADE_NEAR_COL := Color(0, 0, 0, 0.60) # 立面近段黑罩(墙顶 132→52 实测 α≈0.61)
const FACADE_FAR_COL := Color(0, 0, 0, 0.82) # 立面远段黑罩(墙顶 132→24 实测 α≈0.82)
const PROJECTION_NEAR_COL := Color(0, 0, 0, 0.28) # 投影贴墙段(地面 66→46 实测 α≈0.28)
const PROJECTION_MID_COL := Color(0, 0, 0, 0.16) # 投影中段(渐隐)
const PROJECTION_EDGE_COL := Color(0, 0, 0, 0.06) # 投影远段(渐隐收边)
# ── E 格高墙面(圣经 v3.5 冻结①——地面格南邻墙→南部 30% 承接墙面:墙顶纹理原亮度
# 直贴零暗档零阴影;墙脚阴线只画地面/墙面交界;(b)-(c) 交界
# 无边框由 BoardView 侧跳过墙格北向描边承载)──
const E_FACADE_FRAC := 0.30 # 墙面承接高(格边比 30%)
var _owner: Node2D = null
var bg_sb: StyleBoxFlat = null # 格底 StyleBox(BoardView 每次 paint 重建;呼吸微光就地改边框)
# ── 接触带微光绘制面(可挖域微光画在英雄格周界空间侧——art-bible §3.2 v2.8;
# 仅英雄格单元承载,BoardView.refresh 按可挖域写边/角码、_process 逐拍更新呼吸色)──
var contact_bands: Array[int] = [] # 正交接触边码 0=N/1=S/2=W/3=E(该侧整条边)
var contact_corners: Array[int] = [] # 斜向共享角码 0=NW/1=NE/2=SW/3=SE(角点+两侧各半条边)
var contact_col := Color(0, 0, 0, 0) # 当前呼吸色(alpha 0 = 不画)
var outline_sides: Array[int] = [] # 墙格地面朝向描边码 0=N/1=S/2=W/3=E(程序侧结构件)
# ── 高墙感 D 投影档(研究件四变体定 D=C+地面投影,ITB 同款高度线索)──
# 南立面 = 墙格南缘内侧「口沿高光线 + 双段暗带」(邻地面格才画,墙群内聚);地面投影 = 北邻墙格
# 在本已开格北缘投渐隐暗带。参数按研究件 64px 拼版实测比例换算(立面双段 0.16/0.25 格边、投影带
# 0.22 格边;坐标推导留档 commit)。素材缺位程序化回退同样服役(结构归程序——art-bible §8.5)。
var facade_south := false: # 南立面开关(BoardView paint 按「南邻已开格」写入)
set(v):
facade_south = v
_owner.queue_redraw()
var proj_band := 0.0: # 地面投影带宽(像素,0 = 不画——BoardView 按北邻墙判定写入)
set(v):
proj_band = v
_owner.queue_redraw()
var bevel := 0.0: # 顶面倒角强度(0=关;档位 0/0.35/0.6/1.0)
set(v):
bevel = v
_owner.queue_redraw()
var tex_base: Texture2D = null # ① 砖面底(宿主迷雾记忆态公开单向读)
var tex_facade: Texture2D = null # ⑥ E 格墙面材质(v3.5——南邻墙顶 center 瓦片同源,BoardView 注入)
var facade_strip := false: # E 格开关(BoardView paint 按「已开格且南邻未开墙」写入——瓦片态专用)
set(v):
facade_strip = v
_owner.queue_redraw()
func _init(owner: Node2D) -> void:
_owner = owner
## ① 砖面底层域(占位 = StyleBoxFlat:格底色 + 暗化描边 + 3px 圆角;瓦片态描边覆盖层;
## 呼吸微光/主角蓝框由 BoardView 改 bg_sb 后触发重绘。素材缺位回退走 elif 程序化原样,零观感变化)
func draw_base(canvas: CanvasItem, rect: Rect2) -> void:
if tex_base != null:
canvas.draw_texture_rect(tex_base, rect, false)
# 轮廓加强(轮廓线不明显):墙格地面朝向边补 2px 深墨线(§8.5 结构归程序——
# 素材 1px 墨线在 45/36px 非整数缩放下视觉衰减,程序线保底;墙-墙内界不画,保墙群内聚;
# 坐标推导:各边内贴 2px 矩形,相邻边矩形全长相交=周界闭合)
if not outline_sides.is_empty():
_draw_outline_sides(canvas, rect)
_draw_south_facade(canvas, rect)
_draw_north_projection(canvas, rect)
_draw_e_facade(canvas, rect)
# 瓦片态描边覆盖层:tex_base 在位时 BoardView 传入的 bg_sb
# 已降级为「透明底 + 描边」载体——呼吸微光/主角蓝框画在瓦片之上(art-bible §1.2 叠层序
# 不变:底 < 纹带 < 数字 < 封印 < 焦点高亮);素材缺位回退走 elif 程序化原样,零观感变化
if bg_sb != null:
canvas.draw_style_box(bg_sb, rect)
_draw_contact_or_fallback(canvas, rect)
## 接触带微光或平色回退域(英雄格周界空间侧——正交邻墙=整条边;斜向=共享角点+两侧各半条边;光不进墙格):
## 带宽 4px 贴格边内侧(坐标推导:N=[0,0,edge,4] S=[0,edge-4,edge,4] W=[0,0,4,edge] E=[edge-4,0,4,edge];
## 半条边=沿邻边自角点起 edge/2;角点圆 r=6 贴角点圆心,近白芯 r=2.5 提亮)
func _draw_contact_or_fallback(canvas: CanvasItem, rect: Rect2) -> void:
if contact_col.a > 0.0:
_draw_north_projection(canvas, rect) # 平色回退+微光并发的英雄格补画(瓦片路径已画——同像素重复无观感差)
_draw_e_facade(canvas, rect) # E 格墙面补画(同上——英雄格兼 E 格时瓦片路径已画,重复无害)
_draw_contact_bands(canvas, rect)
elif bg_sb != null:
canvas.draw_style_box(bg_sb, rect)
_draw_south_facade(canvas, rect) # 平色回退路径——D 投影档两件同样服役(结构归程序)
_draw_north_projection(canvas, rect)
_draw_bevel(canvas, rect)
## 墙格轮廓域:地面朝向边补 2px 深墨线(各边内贴 2px 矩形,相邻边矩形全长相交=周界闭合)
func _draw_outline_sides(canvas: CanvasItem, rect: Rect2) -> void:
var ow := 2.0
var oc := UiKit.FOG_OUTLINE
for b in outline_sides:
var or_ := Rect2()
match int(b):
0: or_ = Rect2(0, 0, rect.size.x, ow)
1: or_ = Rect2(0, rect.size.x - ow, rect.size.x, ow)
2: or_ = Rect2(0, 0, ow, rect.size.x)
3: or_ = Rect2(rect.size.x - ow, 0, ow, rect.size.x)
canvas.draw_rect(or_, oc, true)
## 接触带微光域:正交整条边 + 斜向共享角点与两侧半条边
func _draw_contact_bands(canvas: CanvasItem, rect: Rect2) -> void:
var band := 4.0
var half := rect.size.x * 0.5
for b in contact_bands:
var r := Rect2()
match int(b):
0: r = Rect2(0, 0, rect.size.x, band)
1: r = Rect2(0, rect.size.x - band, rect.size.x, band)
2: r = Rect2(0, 0, band, rect.size.x)
3: r = Rect2(rect.size.x - band, 0, band, rect.size.x)
canvas.draw_rect(r, contact_col, true)
for cc in contact_corners:
_draw_contact_corner(canvas, rect, int(cc), band, half)
## 斜向角点域:角点圆 r=6 贴角点圆心 + 近白芯 r=2.5 提亮 + 半条边(角点沿两条邻边各延伸 edge/2——
## 坐标推导:横带沿 N/S 自角点向板心侧 half;NW/SE 半带 x=y=角点坐标,NE/SE 半带自 edge-half 收进——
## 正交整边时重叠同色无害)
func _draw_contact_corner(canvas: CanvasItem, rect: Rect2, cc: int, band: float, half: float) -> void:
var pt := Vector2.ZERO
match cc:
0: pt = Vector2(0, 0)
1: pt = Vector2(rect.size.x, 0)
2: pt = Vector2(0, rect.size.x)
3: pt = Vector2(rect.size.x, rect.size.x)
canvas.draw_circle(pt, 6.0, contact_col)
canvas.draw_circle(pt, 2.5, Color(1, 1, 1, minf(1.0, contact_col.a * 0.95)))
if cc == 0 or cc == 1:
# N 侧横带:NW 自 x=0、NE 自 x=edge-half
canvas.draw_rect(Rect2(pt.x if cc == 0 else pt.x - half, 0.0, half, band), contact_col, true)
if cc == 2 or cc == 3:
# S 侧横带:SW 自 x=0、SE 自 x=edge-half
canvas.draw_rect(Rect2(pt.x if cc == 2 else pt.x - half, rect.size.x - band, half, band), contact_col, true)
if cc == 0 or cc == 2:
# W 侧竖带:NW 自 y=0、SW 自 y=edge-half
canvas.draw_rect(Rect2(0.0, pt.y if cc == 0 else pt.y - half, band, half), contact_col, true)
if cc == 1 or cc == 3:
# E 侧竖带:NE 自 y=0、SE 自 y=edge-half
canvas.draw_rect(Rect2(rect.size.x - band, pt.y if cc == 1 else pt.y - half, band, half), contact_col, true)
## 顶面倒角域(光源左上——上/左内沿受光 2px、下/右内沿背光 2px;内缩 2px 让
## 呼吸微光/主角蓝边框保持最外沿可见;强度随档位)
func _draw_bevel(canvas: CanvasItem, rect: Rect2) -> void:
if bevel <= 0.0:
return
var base: Color = bg_sb.bg_color
var lit: Color = base.lightened(0.22 * bevel)
var dark: Color = base.darkened(0.22 * bevel)
var t := 2.0
canvas.draw_rect(Rect2(t, t, rect.size.x - t * 2.0, t), lit, true)
canvas.draw_rect(Rect2(t, t, t, rect.size.x - t * 2.0), lit, true)
canvas.draw_rect(Rect2(t, rect.size.x - t * 2.0, rect.size.x - t * 2.0, t), dark, true)
canvas.draw_rect(Rect2(rect.size.x - t * 2.0, t, t, rect.size.x - t * 2.0), dark, true)
# 南立面(D 档件一——墙格南缘内侧,自底边向上:双段暗带在下、口沿高光线贴其上沿):
# 坐标推导(自格底边起算):远段=[edge−far, edge],近段=[edge−far−near, edge−far],
# 高光线=[edge−far−near−hl, edge−far−near]——与研究件「墙顶面→高光→暗段→更暗段→格界」下行序一致
func _draw_south_facade(canvas: CanvasItem, rect: Rect2) -> void:
if not facade_south:
return
var far_h := rect.size.x * FACADE_FAR_FRAC
var near_h := rect.size.x * FACADE_NEAR_FRAC
var y_far := rect.size.x - far_h
var y_near := y_far - near_h
var y_hl := y_near - FACADE_HIGHLIGHT_PX
canvas.draw_rect(Rect2(0.0, y_hl, rect.size.x, FACADE_HIGHLIGHT_PX), UiKit.STAND_STONE_RIM, true) # 口沿高光(UiKit.STAND_STONE_RIM 并档——同值单点)
canvas.draw_rect(Rect2(0.0, y_near, rect.size.x, near_h), FACADE_NEAR_COL, true)
canvas.draw_rect(Rect2(0.0, y_far, rect.size.x, far_h), FACADE_FAR_COL, true)
# 地面投影(D 档件二——北邻墙格在本已开格北缘投渐隐暗带,自北缘向南三段衰减):
# 坐标推导:三等分 proj_band,α 0.28/0.16/0.06(研究件实测贴墙 α≈0.28、带末渐融入地面)
func _draw_north_projection(canvas: CanvasItem, rect: Rect2) -> void:
if proj_band <= 0.0:
return
var seg := proj_band / 3.0
canvas.draw_rect(Rect2(0.0, 0.0, rect.size.x, seg), PROJECTION_NEAR_COL, true)
canvas.draw_rect(Rect2(0.0, seg, rect.size.x, seg), PROJECTION_MID_COL, true)
canvas.draw_rect(Rect2(0.0, seg * 2.0, rect.size.x, seg), PROJECTION_EDGE_COL, true)
# E 格高墙面(圣经 v3.5 冻结①——方向稿 draw_facade 移植):本格已开且南邻为墙 →
# 南部 30% 承接墙面。材质 = 墙顶 center 瓦片顶部 30% 区带**原亮度**直贴(零暗档零阴影);
# 墙脚阴线只画地面/墙面交界(strip 顶缘 1px);墙面底缘(格界处)不画任何线——直接接南侧墙顶
# (白边导致两截)。仅瓦片态服役(tex_facade 缺位 = 平色回退原语义不动)。
func _draw_e_facade(canvas: CanvasItem, rect: Rect2) -> void:
if not facade_strip or tex_facade == null:
return
var strip_h := rect.size.x * E_FACADE_FRAC
var y0 := rect.size.x - strip_h
var ts := tex_facade.get_size()
canvas.draw_texture_rect_region(tex_facade, Rect2(0.0, y0, rect.size.x, strip_h),
Rect2(0.0, 0.0, ts.x, ts.y * E_FACADE_FRAC))
canvas.draw_rect(Rect2(0.0, y0, rect.size.x, 1.0), UiKit.E_FACADE_FOOT_COL, true)
@@ -0,0 +1 @@
uid://c2msg115y3oir
@@ -0,0 +1,145 @@
## VERTICAL SLICE - NOT FOR PRODUCTION
## 格面标识与顶层叠加绘制域件(CellUnit 拆件——单一变化原因=标识与叠加层视觉规格):
## 变异标记/数字色牌与字形/奖励徽章/封印/路径点迹/焦点高亮/中立移除退色的全部绘制入参与绘制命令。
## 无 class_name(类名缓存面纪律)——经宿主 board_cell_unit preload 引用;宿主 _draw 按层序调
## draw_marks/draw_glyph_layer/draw_overlay_under/draw_removed_dim(雾层由宿主夹在 overlay_under 与 removed_dim 之间);
## setter 经 _owner 回引触发宿主重绘语义逐字(badge_glyph 的 glow mask 回引 _owner._glow_layer 原样)。
extends RefCounted
var _owner: Node2D = null
var badge_glyph := "": # 奖励徽章文字(右下角金——封印之下、变异纹之上、不进数字区)
set(v):
badge_glyph = v
if _owner._glow_layer != null and is_instance_valid(_owner._glow_layer):
_owner._glow_layer.set_badge_mask(v != "")
_owner.queue_redraw()
var dot_visible := false: # BFS 路径预览点迹(中心 6×6 小人蓝)
set(v):
dot_visible = v
_owner.queue_redraw()
var hl_visible := false: # 焦点高亮(悬停态边框覆盖层)
set(v):
hl_visible = v
_owner.queue_redraw()
var hl_color := UiKit.GOLD: # 高亮色(金目标/封印朱/禁入灰禁红)
set(v):
hl_color = v
_owner.queue_redraw()
var font: Font = null # 字体槽位(null = ThemeDB.fallback_font——BoardView.set_world_font 注入)
# ── 素材槽位(现全 null = 程序化占位服役;art-bible §8.2 格面 32×32 暂定档)──
var tex_mutation: Texture2D = null # ② 变异纹带
var tex_glyph: Texture2D = null # ③ 数字
var tex_badge: Texture2D = null # ③' 徽章
var tex_seal: Texture2D = null: # ④ 封印(槽位可运行时换装〔封印〕——同族 facade/treasure_mark
set(v): # 均 setter 触发重绘(普通 var 赋值不重绘=封印插上不显示))
if tex_seal != v:
tex_seal = v
_owner.queue_redraw()
# 变异角标(程序化,tex_mutation 纹带槽暂留):
# "flat_damage" = 未开格伤害型变异,左下角危险红三角(开格有代价的策略纹理标记)
# 叠加层标记(秘宝整图叠加层的格面呈现;派生信息层零回写):
# "mine_reveal" = 真视格(危险红内缩框——「这格是雷」的确定决策标记,封印照常计费);
# "reward_preview" 格不复用本字段——预读徽章走 badge_glyph 注入(board_view refresh 注入 REWARD_BADGE 字形)
var treasure_mark := "":
set(v):
if treasure_mark != v:
treasure_mark = v
_owner.queue_redraw()
var mutation_mark := "":
set(v):
if mutation_mark != v:
mutation_mark = v
_owner.queue_redraw()
var removed_dim := false: # 中立移除退色层(BoardView paint 按排雷玩法 is_removed 写入)
set(v):
removed_dim = v
_owner.queue_redraw()
func _init(owner: Node2D) -> void:
_owner = owner
## 变异标记域:真视格=危险红内缩框/未开格伤害型变异=左下角危险红三角
func draw_marks(canvas: CanvasItem, rect: Rect2) -> void:
if treasure_mark == "mine_reveal":
var inset := rect.size.x * 0.14
canvas.draw_rect(Rect2(inset, inset, rect.size.x - inset * 2.0, rect.size.x - inset * 2.0),
Color(UiKit.RED_MINE, 0.9), false, 2.0)
if mutation_mark == "flat_damage":
var mw := rect.size.x * 0.28
var mpts := PackedVector2Array([Vector2(0, rect.size.x - mw), Vector2(0, rect.size.x), Vector2(mw, rect.size.x)])
canvas.draw_colored_polygon(mpts, Color(UiKit.RED_MINE, 0.85))
## ②③④ 中层域:变异纹带与标记/数字色牌与字形/徽章/封印
##(glyph/glyph_color/plate 三者住宿主冻结面——探针直读成员,作参数传入)
func draw_glyph_layer(canvas: CanvasItem, rect: Rect2, glyph: String, glyph_color: Color, plate: bool) -> void:
# ② 变异纹带(无程序化纹带——槽位先行,贴图落位即用)
if tex_mutation != null:
canvas.draw_texture_rect(tex_mutation, rect, false)
# ③ 数字/徽章(数字 ≥ 格高 50% 墨族对格底 ≥4.5:1;徽章右下角金,遮蔽态 = "?")
if glyph != "":
if plate:
_draw_digit_plate(canvas, rect)
if tex_glyph != null:
canvas.draw_texture_rect(tex_glyph, rect, false)
else:
draw_centered_text(canvas, rect, glyph, glyph_color, maxi(18, int(ceil(rect.size.x * 0.5)))) # 字号下限 18(§7.4 冻结公式)
if badge_glyph != "":
if tex_badge != null:
canvas.draw_texture_rect(tex_badge, rect, false)
else:
_draw_badge(canvas, rect, badge_glyph)
# ④ 封印(现行视觉封印文字在 ③ 文字位承载——独立槽位留给封印图)
if tex_seal != null:
canvas.draw_texture_rect(tex_seal, rect, false)
## 数字色牌后备域(圣经 v3.5 冻结④:数字亮墨直画已开格底须垫牌;
## 牌=后备件——雷/「?」维持牌载保读性(牌上深墨族 12:1);
## 牌尺寸 0.60/0.62 格边居中;封印=未开格不垫牌)
func _draw_digit_plate(canvas: CanvasItem, rect: Rect2) -> void:
var pw := rect.size.x * 0.60
var ph := rect.size.x * 0.62
var pr := Rect2((rect.size.x - pw) * 0.5, (rect.size.x - ph) * 0.5, pw, ph)
canvas.draw_rect(pr, UiKit.DIGIT_PLATE, true)
canvas.draw_rect(pr, UiKit.DIGIT_PLATE_EDGE, false, 1.0)
## ⑤ 路径点迹 + 焦点高亮(悬停态覆盖层,不参与命中)——宿主时序器在其后插雾层
func draw_overlay_under(canvas: CanvasItem, rect: Rect2) -> void:
if dot_visible:
var ds := 6.0
canvas.draw_rect(Rect2(Vector2((rect.size.x - ds) * 0.5, (rect.size.x - ds) * 0.5), Vector2(ds, ds)), UiKit.HERO_BLUE, true)
if hl_visible:
# 悬停高亮减淡(金框太明显——绘制时 55% alpha,hl_color 属性与探针断言面不动)
canvas.draw_rect(Rect2(1, 1, rect.size.x - 2.0, rect.size.x - 2.0), Color(hl_color, 0.55), false, 2.0) # 2px 内描边
## ⑦ 中立移除退色层(退色降档:暗幕压顶全层覆盖,暗淡记忆态同族呈现语义;
## 顶层于迷雾之上——移除格不再参与迷雾语义。本实现移除集=未揭示危险格(无数字无封印印))
func draw_removed_dim(canvas: CanvasItem, rect: Rect2) -> void:
if removed_dim:
canvas.draw_rect(rect, Color(0.12, 0.10, 0.09, 0.62), true)
## 文字位绘制单点(宿主迷雾记忆态复用——同公式同字号;水平居中 + 垂直居中,基线 = (格高 − 字高)/2 + 上伸部)
func draw_centered_text(canvas: CanvasItem, rect: Rect2, text: String, col: Color, fs: int) -> void:
var f := font if font != null else ThemeDB.fallback_font
if f == null:
return
var asc := f.get_ascent(fs)
var desc := f.get_descent(fs)
canvas.draw_string(f, Vector2(0.0, (rect.size.x - (asc + desc)) * 0.5 + asc), text,
HORIZONTAL_ALIGNMENT_CENTER, rect.size.x, fs, col)
# 徽章绘制:右下角金(文字贴角内缩 2–3px)
func _draw_badge(canvas: CanvasItem, rect: Rect2, g: String) -> void:
var f := font if font != null else ThemeDB.fallback_font
if f == null:
return
var fs := maxi(10, int(rect.size.x * 0.28))
var sz := f.get_string_size(g, HORIZONTAL_ALIGNMENT_LEFT, -1, fs)
canvas.draw_string(f, Vector2(rect.size.x - sz.x - 2.0, rect.size.x - 3.0), g, HORIZONTAL_ALIGNMENT_LEFT, -1, fs, UiKit.GOLD)
@@ -0,0 +1 @@
uid://c60e3su2qd1yq
+4 -4
View File
@@ -478,9 +478,9 @@ func _room_color(node: Dictionary, ctx: Dictionary) -> Color:
## 选路停点(候选非空)非候选通道降透明——金岔路从结构网分离(干线共线重叠缺陷的
## 视觉主因:不同源通道共用同一垂直干线,金边与石色边焊接成「整列可走」假象)
func _draw_passage_layer(canvas: Control, ctx: Dictionary) -> void:
var nodes: Array = ctx["nodes"]
var pos: Dictionary = ctx["pos"]
var cand_ids: Array = ctx["cand_ids"]
var nodes: Array = ctx["nodes"] # type-hint: ignore(ctx 束 Variant 出值——布局缓存数组未参数化)
var pos: Dictionary = ctx["pos"] # type-hint: ignore(同上——节点 id → 坐标)
var cand_ids: Array = ctx["cand_ids"] # type-hint: ignore(同上——候选 id 集)
var dim_passages: bool = not cand_ids.is_empty()
for node in nodes:
var from: Vector2 = pos[node]
@@ -496,7 +496,7 @@ func _draw_passage_layer(canvas: Control, ctx: Dictionary) -> void:
## 房间方块域:底色随行进态+Boss/候选描边+图标/字形+编号+类型文字标签
func _draw_room(canvas: Control, node: Dictionary, ctx: Dictionary) -> void:
var pos: Dictionary = ctx["pos"]
var pos: Dictionary = ctx["pos"] # type-hint: ignore(ctx 束 Variant 出值——节点 id → 坐标)
var p: Vector2 = pos[node]
var t := String(node.get("type", ""))
var nid := _id_of(node)
+2 -2
View File
@@ -85,7 +85,7 @@ func _xnum(v: float) -> String:
return "×%d" % int(round(v)) if absf(v - roundf(v)) < 0.005 else "×%.2f" % v
# 打开商店(products = runner.shop_products() 投影——[{product_id, display_name, attr, flat_value, price, purchased}])
# 打开商店(products = runner.shop.shop_products() 投影——[{product_id, display_name, attr, flat_value, price, purchased}])
func open_shop(products: Array, gp: int) -> void:
for child in _cards_box.get_children():
child.queue_free()
@@ -149,7 +149,7 @@ func _emit_buy_requested(p: Dictionary) -> void:
# ---- 共享池货架面(M-4 迭代 11 第②批 T4——P3 甲程序占位,三选一同构卡;UiKit 既有件)----
# 打开/重刷货架(cards = runner.shop_shelf() 投影——[{kind_id, display_name, value, price, stock_left}])。
# 打开/重刷货架(cards = runner.shop.shop_shelf() 投影——[{kind_id, display_name, value, price, stock_left}])。
# 买后组合根重投喂新货架 = 整架重建呈现(三件全重抽反馈——未买不保留);空架 = 池空硬闸合法态。
func open_shelf(cards: Array, gp: int) -> void:
for child in _cards_box.get_children():
+139 -194
View File
@@ -2,81 +2,42 @@
## 站桩本体:B 区主角/敌人无框立绘+底座+血条+顺位/意图徽标的世界精灵(Node2D)。
## 站桩形态为定案——禁回卡片式;立绘素材缺位回退字形占位;击杀呈现禁瞬消(灰化塌陷)。
## 无 class_name——经 preload 引用;壳层坐标换算单点在 BattleStageView.world_to_shell()。
## 内部状态件(u4 子域拆件——契约 9 职责语句「站桩演出状态」):单一变化原因=站桩呈现与演出,
## 成员共同表达站桩的行进态/演出计数/资产挂点。外部直访冻结成员(box/font/slot_row/has_world_hp_bar)
## 与源码锚承载成员(_intent_charge——theme 源锚句所在行逐字保留)住宿主。
## 内部状态两件(u4 拆件——st=身份命值态 standee_vitals、mo=资产演出态 standee_motion,_init 自建);
## 外部直访冻结成员(box/font/slot_row/has_world_hp_bar)与源码锚承载成员(_intent_charge——theme
## 源锚句所在行逐字保留)与三个演出探针计数器住宿主。
extends Node2D
const CHARGE_SKILL_IDS := ["heavy"]
# 护甲类型图标占位——形状+色相双通道(art-bible):轻甲=◇ 灰石中性 / 魔法护甲=◆ 小人蓝 /
# 重甲=▣ 深金(避开 Boss 专属紫赤与妨害紫)。
# 护甲类型图标三键(light/ward/heavy)——终稿 = 三枚 24×24 PNG(UiKit.TEX_ARMOR_*,art-bible §5.3
# 工单:形状承载身份、色相不承载身份;挂载底色 = 名字行素底 HP_BAR_BACK)。字形占位仅作素材缺位
# 回退(与立绘缺位回退链同构——素材不入 git,缺位不炸)。
const ARMOR_ICONS := {"light": "◇", "ward": "◆", "heavy": "▣"}
# 名行/底座纵向预算余量(盒底−1px「声明值刚好=容器值」系高危写法;
# ≥8px 硬余量 + 字形下探预算 ⇒ 12;取值不属色板,不进 ui_kit)
const STANDEE_FOOT_MARGIN := 12.0
const DEATH_SHARD_N := 5 # 碎块数(§8.4 冻结值)
const HIT_SPARK_N := 6 # 命中火花数(打击瞬间可读性一拍)
const _VITALS := preload("res://presentation/views/standee_vitals.gd")
const _MOTION := preload("res://presentation/views/standee_motion.gd")
## 站桩演出状态(全部内部态单点——含 setter 触发宿主重绘语义,_owner 回引保持逐字)
class _StandeeState extends RefCounted:
var _owner: Node2D = null
var _kind := "enemy"
var _portrait_sprite: Sprite2D = null # 资产挂点(null = 未落位,字形在位)
var _portrait_tex: Texture2D = null # 落位纹理引用(set_portrait_texture 装载;字形回退判据)
# 主角三态切换:state 名 → 纹理(battle_stage_view 组合点注册);缺态=保持现纹理
# (缺位回退链延伸——三态素材缺任一不炸不空)。敌站桩不注册不消费。
var _hero_tex := {}
var _hero_state: int = 0
var _state_revert_tw: Tween
var _order := 1
var _intent_glyph := ""
var _intent_col := Color.WHITE
var _intent_visible := false
var _intent_scale := 1.0: # 意图弹入动画参数
set(v):
_intent_scale = v
_owner.queue_redraw()
var _glyph_rot := 0.0: # 立绘前倾角(贴图态无此动画)
set(v):
_glyph_rot = v
_owner.queue_redraw()
var _display_name := ""
var _enemy_id := ""
var _armor := "light"
var _dead := false
var _hp_max := 1.0
var _hp_cur := 0 # 血量数字显示面(HUD框架 验收「血量数字可读」)
var hp_value := 1.0: # 血条值 0..1(直角递减——tween_property 目标,逐行刷新重启不累积)
set(v):
hp_value = clampf(v, 0.0, 1.0)
_owner.queue_redraw()
var _hp_tween: Tween
var _hp_flash_tw: Tween
var _death_shards := 0 # 探针出口计数(碎块节点回收后仍保留读数)
var _hit_sparks := 0 # 探针出口计数(命中火花累计)
var _flash_count := 0 # 探针出口计数(受击闪白触发次数——主角路由断言面)
var st := _StandeeState.new()
var st: _VITALS # 身份与命值态件实例(名字沿用——外部路径串 "st.hp_value" 与约 40 处引用零改)
var mo: _MOTION # 资产与演出态件实例(_init 自建)
var box := Vector2(150, 176) # 站桩盒尺寸(实际高随壳层 row 布局注入;外部直访冻结)
var font: Font = null # 世界字体槽位(null = ThemeDB.fallback_font——world.world_font 注入;外部直访冻结)
var slot_row: StatusSlotRow # 状态效果唯一展示面 = 壳层伴随件(挂 BattleStageView 壳层,本体进世界;外部直访冻结)
var _intent_charge := false # 蓄力档(pid ∈ CHARGE_SKILL_IDS——意图三档 ③ 分支判据;源码锚承载成员住宿主)
# 血条存在性探针出口(世界直角血条常在;外部直访冻结)
var has_world_hp_bar := true
# 演出探针计数器(写入方=宿主演出函数、读取方=宿主 fx_probe 出口——仪器跟着驱动它的函数走)
var _death_shards := 0 # 探针出口计数(碎块节点回收后仍保留读数)
var _hit_sparks := 0 # 探针出口计数(命中火花累计)
var _flash_count := 0 # 探针出口计数(受击闪白触发次数——主角路由断言面)
func _init(kind: String = "enemy") -> void:
st._owner = self
st._hero_state = HeroState.IDLE
st = _VITALS.new(self)
mo = _MOTION.new(self)
st._kind = kind
enum HeroState { IDLE, RESET, ATTACK, HIT } # 主角三态+复位哨兵(外部 String 契约=register/set 形参零变化)
const _HS_NAME := {HeroState.IDLE: "idle", HeroState.RESET: "reset", HeroState.ATTACK: "attack", HeroState.HIT: "hit"}
const _HS_VALUE := {"idle": HeroState.IDLE, "reset": HeroState.RESET, "attack": HeroState.ATTACK, "hit": HeroState.HIT}
mo._hero_state = _MOTION.HeroState.IDLE
func _efont() -> Font:
@@ -94,12 +55,21 @@ func enemy_id() -> String:
# 意图徽标探针出口
func intent_probe() -> Dictionary:
return {"visible": st._intent_visible, "text": st._intent_glyph}
return {"visible": mo._intent_visible, "text": mo._intent_glyph}
# 名字行探针出口
# 名字行探针出口(ui_probe 呈现口径 + 本批 V6/V8 断言面:armor_icon = 绑定纹理路径〔缺位回退字形〕、
# 几何 = 素底牌矩形与文字基线、素底色——V6 判据 = baseline_y < plinth_top_y)
func name_line_probe() -> Dictionary:
return {"name": st._display_name, "armor_icon": String(ARMOR_ICONS.get(st._armor, "◇"))}
var f := _efont()
var tex := UiKit.load_tex(_armor_tex_path(st._armor))
var plate := _name_plate_rect(f, tex)
return {"name": st._display_name,
"armor_icon": _armor_tex_path(st._armor) if tex != null else String(ARMOR_ICONS.get(st._armor, "◇")),
"armor_tex_bound": tex != null,
"plate": plate, "baseline_y": _name_baseline(plate).y,
"plinth_top_y": _pedestal_rect().position.y,
"plate_color": UiKit.HP_BAR_BACK}
# ---- setter 面(presenter/组合根零改排) ----
@@ -111,7 +81,7 @@ func set_data(d: Dictionary) -> void:
st._enemy_id = String(d.get("enemy_id", ""))
st._armor = String(d.get("armor_type", "light"))
st._hp_max = float(maxi(1, int(d.get("max_hp", 1))))
_set_hp(int(d.get("hp", 0)))
st.apply_hp(int(d.get("hp", 0)))
_set_order(int(d.get("order", 1)))
set_pending(String(d.get("pending_type", "")), String(d.get("pending_skill", "")))
set_effects(d.get("effects", []))
@@ -122,21 +92,11 @@ func set_data(d: Dictionary) -> void:
func set_hero(hp: int, max_hp: int) -> void:
st._hp_max = float(maxi(1, max_hp))
_set_hp(hp)
st.apply_hp(hp)
if st._dead and hp > 0:
_revive() # 新战斗开场 HP 回正——主角死亡残位随之复活(敌侧 set_data 同款语义)
# 血条短 tween 递减(直角递减占位);逐行刷新时重启 tween 不累积
func _set_hp(hp: int) -> void:
st._hp_cur = clampi(hp, 0, int(st._hp_max))
var target := float(st._hp_cur) / st._hp_max
if st._hp_tween != null and st._hp_tween.is_valid():
st._hp_tween.kill()
st._hp_tween = create_tween()
st._hp_tween.tween_property(self, "st.hp_value", target, UiKit.motion(0.15))
# 主角/敌方共用——状态效果唯一展示面(壳层伴随件转发;空态 = 图标行隐藏不占位)
func set_effects(effects: Array) -> void:
if slot_row == null:
@@ -175,12 +135,12 @@ func _set_order(i: int) -> void:
func set_pending(ptype: String, pid: String) -> void:
if st._dead:
_intent_charge = false
st._intent_visible = false
mo._intent_visible = false
queue_redraw()
return
if ptype == "" or ptype == "basic":
_intent_charge = false
st._intent_visible = false # 普通攻击零表示(完全不可预测——§2.4)
mo._intent_visible = false # 普通攻击零表示(完全不可预测——§2.4)
queue_redraw()
return
var glyph := "⚔" # 攻击系(damage)
@@ -194,60 +154,15 @@ func set_pending(ptype: String, pid: String) -> void:
_intent_charge = pid in CHARGE_SKILL_IDS
if _intent_charge:
col = UiKit.GOLD_INK # 重击类蓄力档(深金墨——浅垫牌上 ≥4.5:1)
st._intent_glyph = glyph
st._intent_col = col
st._intent_visible = true
_play_intent_motion()
mo._intent_glyph = glyph
mo._intent_col = col
mo._intent_visible = true
mo.play_intent_motion(_intent_charge)
# 意图三档动作动画(§4.6.4 三档:①普通攻击=零表示〔set_pending 早退〕
# ②特殊准备=徽标弹入+二次弹跳(高举语义,运动手段 §2)③重击/硬化=缓推蓄力+定格微顿+回落;
# 三档运动签名互异,灰度/剪影层可辨)。摇定时一次性短动画,随后静帧保持。
func _play_intent_motion() -> void:
var tw := create_tween()
tw.tween_property(self, "st._intent_scale", 1.6, UiKit.motion(0.10))
tw.tween_property(self, "st._intent_scale", 1.0, UiKit.motion(0.16))
tw.parallel().tween_property(self, "st._glyph_rot", 4.0, UiKit.motion(0.10))
tw.tween_property(self, "st._glyph_rot", 0.0, UiKit.motion(0.14))
if _intent_charge:
tw.tween_property(self, "st._intent_scale", 1.22, UiKit.motion(0.28)).set_trans(Tween.TRANS_SINE) # ③蓄力缓推
tw.tween_interval(UiKit.motion(0.40)) # 定格微顿
tw.tween_property(self, "st._intent_scale", 1.0, UiKit.motion(0.18))
else:
tw.tween_property(self, "st._intent_scale", 1.26, UiKit.motion(0.11)) # ②二次弹跳(高举)
tw.tween_property(self, "st._intent_scale", 1.0, UiKit.motion(0.13))
# 资产挂点:tex 落位后字形隐退、纹理立绘顶位——零代码换装契约;tex=null 回退字形。
# flip = 立绘朝向翻转(素材基准朝左时传 true 呈现朝右)。盒高 96px = 48px 立绘源整数 2×
# (圣经 §8.2 禁非整数缩放)——源换代时随源重算。
# 资产挂点转调壳(签名外形零变——box 由宿主传入件内)
func set_portrait_texture(tex: Texture2D, flip: bool = false) -> void:
if tex == null:
if st._portrait_sprite != null:
st._portrait_sprite.visible = false
queue_redraw()
return
st._portrait_tex = tex
if st._portrait_sprite == null:
st._portrait_sprite = Sprite2D.new()
st._portrait_sprite.centered = false
st._portrait_sprite.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST # 像素帧放大防糊
add_child(st._portrait_sprite)
st._portrait_sprite.texture = tex
st._portrait_sprite.flip_h = flip
st._portrait_sprite.visible = true
_place_portrait()
func _place_portrait() -> void:
# 立绘盒 = (0,44)-(box.x, box.y-36);48 源 ×2 整数档居中
if st._portrait_sprite == null or st._portrait_tex == null:
return
var box_h := box.y - 44.0 - 36.0
var w := st._portrait_tex.get_width() * 2.0
var h := st._portrait_tex.get_height() * 2.0
st._portrait_sprite.scale = Vector2(2.0, 2.0) # 整数 2×(C5)
st._portrait_sprite.position = Vector2((box.x - w) * 0.5, 44.0 + (box_h - h) * 0.5)
mo.set_portrait_texture(tex, flip, box)
func mark_dead() -> void:
@@ -261,8 +176,8 @@ func mark_dead() -> void:
tw.tween_property(self, "rotation_degrees", 0.0, UiKit.motion(0.08))
_spawn_death_shards() # 碎裂退场(§4.6.4 语义硬规则:灰化+碎裂禁瞬间消失;§8.4 v2 冻结 5 块 0.45s)
_intent_charge = false
st._intent_visible = false # 死亡残位意图退位
_set_hp(0)
mo._intent_visible = false # 死亡残位意图退位
st.apply_hp(0)
if slot_row != null:
slot_row.visible = false # 状态行随 mark_dead 同拍隐藏
@@ -272,7 +187,7 @@ func mark_dead() -> void:
# 死亡碎块弹飞:立绘盒中心五块碎石抛物线散落(程序化色块——确定性散布,禁全局随机)
func _spawn_death_shards() -> void:
st._death_shards = DEATH_SHARD_N
_death_shards = DEATH_SHARD_N
var center := _portrait_rect().get_center()
for i in DEATH_SHARD_N:
_spawn_death_shard(i, center)
@@ -298,7 +213,7 @@ func _spawn_death_shard(i: int, center: Vector2) -> void:
# 演出探针出口(fx_probe——死亡碎裂/命中火花/闪白计数断言面)
func fx_probe() -> Dictionary:
return {"death_shards": st._death_shards, "hit_sparks": st._hit_sparks, "flash_count": st._flash_count}
return {"death_shards": _death_shards, "hit_sparks": _hit_sparks, "flash_count": _flash_count}
# 命中瞬间打击特效:立绘盒中心六枚短火花放射(程序化色块,确定性方向
@@ -312,7 +227,7 @@ func play_hit_impact() -> void:
## 单火花域(循环体提函数——放射弹道+渐隐+回收)
func _spawn_hit_spark(i: int, center: Vector2) -> void:
st._hit_sparks += 1
_hit_sparks += 1
var spark := ColorRect.new()
spark.color = UiKit.GOLD_LIT if i % 2 == 0 else UiKit.WARM
spark.size = Vector2(4, 3)
@@ -333,7 +248,7 @@ func is_dead() -> bool:
# 受击闪白(结算演出占位——§2.2 受击反馈;强度时长维持现行)
func flash_hit() -> void:
st._flash_count += 1
_flash_count += 1
if st._hp_flash_tw != null and st._hp_flash_tw.is_valid():
st._hp_flash_tw.kill()
st._hp_flash_tw = create_tween()
@@ -346,8 +261,7 @@ func _revive() -> void:
modulate = Color(1, 1, 1)
rotation_degrees = 0.0
if st._kind == "hero":
st._hero_state = HeroState.RESET # 强制回 idle 态(绕过同态早退)
set_hero_state("idle")
mo.reset_state()
if slot_row != null:
slot_row.visible = true
queue_redraw()
@@ -365,45 +279,24 @@ func _portrait_glyph() -> String:
# 立绘落位探针出口(站桩纹理非空断言面;缺位回退链保持的对照面)
func portrait_probe() -> Dictionary:
return {"has_tex": st._portrait_sprite != null and st._portrait_sprite.texture != null}
return {"has_tex": mo._portrait_sprite != null and mo._portrait_sprite.texture != null}
# ---- 主角三态切换(攻击演出→attack/受击→hit/结算回 idle;§8.4 帧数档挂点) ----
# 组合点注册(battle_stage_view _init——UiKit 常量 load_tex,缺位 null 不注册=该态保持现纹理)
# 组合点注册转调壳(签名外形零变)
func register_hero_state(state: String, tex: Texture2D) -> void:
if tex != null:
st._hero_tex[state] = tex
mo.register_hero_state(state, tex)
# 状态切换:现纹理换注册态(attack/hit);未注册态名或缺位 = 保持现纹理不炸。
# 非 idle 态自动短驻回归 idle(0.35s——演出一拍即回,结算收尾另有显式 idle 兜底)。
# 状态切换转调壳(签名外形零变——is_hero 由宿主 vitals 参判传入,早退序逐字在件内)
func set_hero_state(state: String) -> void:
var target: int = _HS_VALUE.get(state, -1)
if st._kind != "hero" or target == st._hero_state:
return
if not st._hero_tex.has(state) and state != "idle":
return
st._hero_state = target
if st._portrait_sprite != null and st._hero_tex.has(state):
st._portrait_sprite.texture = st._hero_tex[state]
if st._state_revert_tw != null and st._state_revert_tw.is_valid():
st._state_revert_tw.kill()
if state != "idle":
st._state_revert_tw = create_tween()
st._state_revert_tw.tween_interval(UiKit.motion(0.35))
st._state_revert_tw.tween_callback(_settle_hero_idle)
mo.apply_hero_state(state, st._kind == "hero")
func _settle_hero_idle() -> void:
st._hero_state = HeroState.IDLE
if st._portrait_sprite != null and st._hero_tex.has("idle"):
st._portrait_sprite.texture = st._hero_tex["idle"]
# 三态探针出口(fx_probe——当前态名+注册态集合)
# 三态探针出口(fx_probe——当前态名+注册态集合;读件投影外形零变)
func hero_state_probe() -> Dictionary:
return {"state": _HS_NAME.get(st._hero_state, "idle"), "registered": st._hero_tex.keys()}
return mo.state_probe()
func _portrait_color() -> Color:
@@ -420,6 +313,36 @@ func _pedestal_rect() -> Rect2:
return Rect2(18.0, box.y - 18.0, box.x - 36.0, 12.0)
# 护甲图标纹理路径(甲档键 → UiKit.TEX_ARMOR_*——显式 match 单点,禁动态拼键取常量;
# 未知键回退轻甲路径,由 load_tex exists 守卫接住)
func _armor_tex_path(armor: String) -> String:
match armor:
"ward":
return UiKit.TEX_ARMOR_WARD
"heavy":
return UiKit.TEX_ARMOR_HEAVY
_:
return UiKit.TEX_ARMOR_LIGHT
# 名字行素底牌矩形(_draw 与 name_line_probe 共用几何——单一来源防两处漂移):
# 牌高 26 = 护甲图标 24px(甲类 1× 禁缩放)+ 上下各 1px;牌底沿 = 地台顶(box.y-18)——
# 文字禁直接压地台(§6.1/§7.2 素底落法);牌宽 = 行宽(图标+间距+名字)+ 8,水平居中
func _name_plate_rect(f: Font, tex: Texture2D) -> Rect2:
var icon_w := 24.0
if tex == null:
icon_w = f.get_string_size(String(ARMOR_ICONS.get(st._armor, "◇")),
HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_CAPTION).x
var name_w := f.get_string_size(st._display_name, HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_CAPTION).x
var total_w := icon_w + 3.0 + name_w
return Rect2((box.x - total_w - 8.0) * 0.5, box.y - 18.0 - 26.0, total_w + 8.0, 26.0)
# 名字行文字基线(牌内几何单点——图标 24px 垂直居中牌内〔中心=牌顶+13〕,12px 字形基线=中心+4)
func _name_baseline(plate: Rect2) -> Vector2:
return plate.position + Vector2(4.0, 17.0)
# 绘制内容矩形(世界局部;ui_struct_probe ⑥standee「不出框+下余量≥8px」断言读数面——
# 最低绘制元素 = 底座下缘)
func content_rect() -> Rect2:
@@ -438,8 +361,9 @@ func _draw() -> void:
## 地面域:椭圆落影(圣经 §6.1 地台落影压脚:方向稿椭圆 (0,0,0,70),压在地台
## 上缘周围;24 段多边形近似椭圆,中心=台面上方 6px、横半径=台宽一半)
## + 石板地台(v3.5——方向稿取色:板身/描边/顶缘受光线 2px——取色单点收 UiKit.STAND_STONE 族
## ;几何沿用现行底座位〔margin 18/高 12——按方向稿对齐〕)
## + 石板地台(§6.1 近景地台独立件:TEX_STAGE_PLAZA 源 48×12 九宫格横向拉伸、顶缘受光线 2px
## 不随拉伸变形、跨三关恒定;素材缺位回退程序化三段绘制〔STAND_STONE 族方向稿取色,几何同源
## _pedestal_rect——与 panel_skinned 缺位回退同构〕)
func _draw_ground(f: Font) -> void:
var sh_center := Vector2(box.x * 0.5, box.y - 24.0)
var sh_rx := (box.x - 36.0) * 0.5
@@ -450,26 +374,41 @@ func _draw_ground(f: Font) -> void:
pts.append(sh_center + Vector2(cos(ang) * sh_rx, sin(ang) * sh_ry))
draw_colored_polygon(pts, Color(0, 0, 0, 0.27))
var ped := _pedestal_rect()
draw_rect(ped, UiKit.STAND_STONE, true)
draw_rect(ped, UiKit.STAND_STONE_EDGE, false, 1.0)
draw_rect(Rect2(ped.position.x, ped.position.y, ped.size.x, 2.0), UiKit.STAND_STONE_RIM, true)
var plaza := UiKit.load_tex(UiKit.TEX_STAGE_PLAZA)
if plaza != null:
_draw_plinth_stretched(plaza, ped)
else:
draw_rect(ped, UiKit.STAND_STONE, true)
draw_rect(ped, UiKit.STAND_STONE_EDGE, false, 1.0)
draw_rect(Rect2(ped.position.x, ped.position.y, ped.size.x, 2.0), UiKit.STAND_STONE_RIM, true)
## 血条域(直角递减):敌附顺位徽标(GOLD_BRIGHT ①②③);血条几何左 8 / 右 -8;
## 血量数字「当前/最大」居中压条(白字+深描边双通道——11px 于 10px 条带垂直居中;
## 数字=目标值即时刷新,条 tween 只管填充宽度;死残位 0/max 照常可读)
## 地台九宫格横向拉伸域(循环体提函数——左右 4px 端头切片 + 中段拉伸;纵向恒 12px 源档,
## 顶缘受光线 2px 落纵向不缩放区,工单 §5.2 工艺要点)
func _draw_plinth_stretched(tex: Texture2D, ped: Rect2) -> void:
draw_texture_rect_region(tex, Rect2(ped.position, Vector2(4.0, 12.0)), Rect2(0, 0, 4, 12))
draw_texture_rect_region(tex, Rect2(ped.position + Vector2(4.0, 0.0),
Vector2(ped.size.x - 8.0, 12.0)), Rect2(4, 0, 40, 12))
draw_texture_rect_region(tex, Rect2(ped.position + Vector2(ped.size.x - 4.0, 0.0),
Vector2(4.0, 12.0)), Rect2(44, 0, 4, 12))
## 血条域(直角递减):敌附顺位徽标(GOLD_BRIGHT ①②③,字号 FS_HINT——art-bible §7.4 清单外
## 11–13px 提档归档);血条几何左 8 / 右 -8;血条填充 = 危险红 HP_BAR_FILL(§4.2 语义物件——
## 不因敌我分色);条底 = HP_BAR_TRACK;血量数字「当前/最大」居中压条(白字+深描边双通道——11px 于
## 10px 条带垂直居中;数字=目标值即时刷新,条 tween 只管填充宽度;死残位 0/max 照常可读)
func _draw_hp_bar(f: Font) -> void:
var bar_x := 8.0
if st._kind == "enemy":
var order_txt := String("①②③"[clampi(st._order - 1, 0, 2)])
f.draw_string(get_canvas_item(), Vector2(bar_x, 12), order_txt,
HORIZONTAL_ALIGNMENT_LEFT, -1, 13, UiKit.GOLD_BRIGHT)
HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_HINT, UiKit.GOLD_BRIGHT)
bar_x += 20.0
var bar_w := box.x - 8.0 - bar_x
draw_rect(Rect2(bar_x, 2, bar_w, 10), Color(0.10, 0.10, 0.11)) # 条底(引擎默认主题深底近似平移)
draw_rect(Rect2(bar_x, 2, bar_w, 10), UiKit.HP_BAR_TRACK) # 条底(值单点收 ui_kit)
var fill_w := bar_w * st.hp_value
if fill_w > 0.0:
draw_rect(Rect2(bar_x, 2, fill_w, 10), Color(0.41, 0.61, 0.91)) # 直角填充(默认主题蓝近似——直角递减)
draw_rect(Rect2(bar_x, 2, fill_w, 10), UiKit.HP_BAR_FILL) # 直角填充(危险红——§4.2 血条显式句)
var hp_txt := "%d/%d" % [st._hp_cur, int(st._hp_max)]
var hts: Vector2 = f.get_string_size(hp_txt, HORIZONTAL_ALIGNMENT_LEFT, -1, 11)
# 对比度垫牌(白 α.95 直压蓝条 2.67:1 违 §7.2;
@@ -482,7 +421,7 @@ func _draw_hp_bar(f: Font) -> void:
## 立绘域:贴图在位 = Sprite2D(set_portrait_texture 落位);缺位 = 字形回退
func _draw_portrait(f: Font) -> void:
if st._portrait_sprite != null and st._portrait_sprite.texture != null and st._portrait_sprite.visible:
if mo._portrait_sprite != null and mo._portrait_sprite.texture != null and mo._portrait_sprite.visible:
return
var prect := _portrait_rect()
var glyph := _portrait_glyph()
@@ -490,7 +429,7 @@ func _draw_portrait(f: Font) -> void:
# 坐标系注记:draw_set_transform 原点已置于 center——draw_string 的
# pos 是**变换后的局部坐标**,须传相对 center 的偏移(-w/2 水平居中、+0.35h 基线下移);
# 传绝对 center 会成双重偏移、把字形画到盒外。
draw_set_transform(center, deg_to_rad(st._glyph_rot), Vector2.ONE)
draw_set_transform(center, deg_to_rad(mo._glyph_rot), Vector2.ONE)
var ts := f.get_string_size(glyph, HORIZONTAL_ALIGNMENT_LEFT, -1, 42)
f.draw_string(get_canvas_item(), Vector2(-ts.x * 0.5, ts.y * 0.35), glyph,
HORIZONTAL_ALIGNMENT_LEFT, -1, 42, _portrait_color())
@@ -499,33 +438,39 @@ func _draw_portrait(f: Font) -> void:
## 意图徽标域(敌 only——立绘上半部居中悬浮,CENTER_TOP 74..98 等价):弹入 scale 动画
func _draw_intent_badge(f: Font) -> void:
if not st._intent_visible:
if not mo._intent_visible:
return
var icenter := Vector2(box.x * 0.5, 86.0)
draw_set_transform(icenter, 0.0, Vector2(st._intent_scale, st._intent_scale))
var its := f.get_string_size(st._intent_glyph, HORIZONTAL_ALIGNMENT_LEFT, -1, 15)
draw_set_transform(icenter, 0.0, Vector2(mo._intent_scale, mo._intent_scale))
var its := f.get_string_size(mo._intent_glyph, HORIZONTAL_ALIGNMENT_LEFT, -1, 15)
# 对比度垫牌(四色墨直压立绘纹理/暗舞台底 1.5-3.3:1 违 §7.2
# 「文字禁直压纹理底」;垫 PANEL_DATA 素牌后 atk 5.3/buf 4.8/debuff 4.7/charge 4.9 全 ≥4.5:1;
# atk/debuff 零换墨、buf 换 HERO_BLUE_DEEP、charge 换 GOLD_INK;随弹入 transform 同步缩放)
draw_rect(Rect2(-its.x * 0.5 - 4.0, -its.y * 0.75, its.x + 8.0, its.y * 1.1), UiKit.PANEL_DATA, true)
f.draw_string(get_canvas_item(), Vector2(-its.x * 0.5, its.y * 0.35), st._intent_glyph,
HORIZONTAL_ALIGNMENT_LEFT, -1, 15, st._intent_col) # 局部坐标(同上注记——双重偏移修复)
draw_set_transform(Vector2.ZERO, 0.0, Vector2.ONE)
f.draw_string(get_canvas_item(), Vector2(-its.x * 0.5, its.y * 0.35), mo._intent_glyph,
HORIZONTAL_ALIGNMENT_LEFT, -1, 15, mo._intent_col) # 局部坐标(同上注记——双重偏移修复)
## 底座下 护甲类型图标+名字 常驻行(敌 only——AC 数值不展示,类型图标化)
## 名字行域(敌 only——AC 数值不展示,类型图标化):整行垫 HP_BAR_BACK 素底牌(§6.1/§7.2
## 「文字禁直接压地台」素底落法——牌底沿 = 地台顶,几何单点 _name_plate_rect);护甲图标 =
## 24×24 PNG(甲类 1×,缺位回退字形,色随甲档亮档族);名字 = 暖白(暗底双色墨制)
func _draw_armor_name_line(f: Font) -> void:
var armor_txt := String(ARMOR_ICONS.get(st._armor, "◇"))
var col: Color = UiKit.WARM_FAINT # 轻甲 = 暖白弱化(v3.5 暗底双色墨制)
match st._armor:
"ward":
col = UiKit.HERO_BLUE_BRIGHT # 魔法护甲 = 小人蓝亮档
"heavy":
col = UiKit.GOLD_BRIGHT # 重甲 = 金族亮档
var name_w := f.get_string_size(st._display_name, HORIZONTAL_ALIGNMENT_LEFT, -1, 12).x
var armor_w := f.get_string_size(armor_txt, HORIZONTAL_ALIGNMENT_LEFT, -1, 12).x
var total_w := armor_w + 3.0 + name_w
var baseline := Vector2((box.x - total_w) * 0.5, box.y - 1.0 - STANDEE_FOOT_MARGIN) # 纵向余量纪律
f.draw_string(get_canvas_item(), baseline, armor_txt, HORIZONTAL_ALIGNMENT_LEFT, -1, 12, col)
f.draw_string(get_canvas_item(), baseline + Vector2(armor_w + 3.0, 0), st._display_name,
HORIZONTAL_ALIGNMENT_LEFT, -1, 12, UiKit.WARM) # v3.5 暗底双色墨制
var tex := UiKit.load_tex(_armor_tex_path(st._armor))
var plate := _name_plate_rect(f, tex)
draw_rect(plate, UiKit.HP_BAR_BACK, true)
var baseline := _name_baseline(plate)
var icon_w := 24.0
if tex != null:
draw_texture_rect(tex, Rect2(baseline.x, plate.position.y + 1.0, 24.0, 24.0), false)
else:
var armor_txt := String(ARMOR_ICONS.get(st._armor, "◇"))
icon_w = f.get_string_size(armor_txt, HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_CAPTION).x
var col: Color = UiKit.WARM_FAINT # 轻甲 = 暖白弱化(v3.5 暗底双色墨制)
match st._armor:
"ward":
col = UiKit.HERO_BLUE_BRIGHT # 魔法护甲 = 小人蓝亮档
"heavy":
col = UiKit.GOLD_BRIGHT # 重甲 = 金族亮档
f.draw_string(get_canvas_item(), baseline, armor_txt, HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_CAPTION, col)
f.draw_string(get_canvas_item(), baseline + Vector2(icon_w + 3.0, 0.0), st._display_name,
HORIZONTAL_ALIGNMENT_LEFT, -1, UiKit.FS_CAPTION, UiKit.WARM) # v3.5 暗底双色墨制
+128
View File
@@ -0,0 +1,128 @@
## VERTICAL SLICE - NOT FOR PRODUCTION
## 站桩资产与演出态件(StandeeBody 拆件——单一变化原因=美术素材落位规则与演出编排设计):
## 站桩的资产挂点与一次性演出——立绘精灵落位与换装、主角三态注册与 0.35s 短驻回归、意图徽标弹入动画。
## 无 class_name(类名缓存面纪律)——经宿主 standee_body preload 引用(mo 实例);
## 两个属性 setter 经 _owner 回引触发宿主重绘语义逐字;tween 经 _owner 创建(同一 Node 生命绑定)。
extends RefCounted
enum HeroState { IDLE, RESET, ATTACK, HIT } # 主角三态+复位哨兵(外部 String 契约=register/set 形参零变化)
const _HS_NAME := {HeroState.IDLE: "idle", HeroState.RESET: "reset", HeroState.ATTACK: "attack", HeroState.HIT: "hit"}
const _HS_VALUE := {"idle": HeroState.IDLE, "reset": HeroState.RESET, "attack": HeroState.ATTACK, "hit": HeroState.HIT}
var _owner: Node2D = null
var _portrait_sprite: Sprite2D = null # 资产挂点(null = 未落位,字形在位)
var _portrait_tex: Texture2D = null # 落位纹理引用(set_portrait_texture 装载;字形回退判据)
# 主角三态切换:state 名 → 纹理(battle_stage_view 组合点注册);缺态=保持现纹理
# (缺位回退链延伸——三态素材缺任一不炸不空)。敌站桩不注册不消费。
var _hero_tex := {}
var _hero_state: int = 0
var _state_revert_tw: Tween
var _intent_glyph := ""
var _intent_col := Color.WHITE
var _intent_visible := false
var _intent_scale := 1.0: # 意图弹入动画参数
set(v):
_intent_scale = v
_owner.queue_redraw()
var _glyph_rot := 0.0: # 立绘前倾角(贴图态无此动画)
set(v):
_glyph_rot = v
_owner.queue_redraw()
func _init(owner: Node2D) -> void:
_owner = owner
# 资产挂点:tex 落位后字形隐退、纹理立绘顶位——零代码换装契约;tex=null 回退字形。
# flip = 立绘朝向翻转(素材基准朝左时传 true 呈现朝右)。盒高 96px = 48px 立绘源整数 2×
# (圣经 §8.2 禁非整数缩放)——源换代时随源重算。(box = 宿主冻结 var,由宿主传入)
func set_portrait_texture(tex: Texture2D, flip: bool, box: Vector2) -> void:
if tex == null:
if _portrait_sprite != null:
_portrait_sprite.visible = false
_owner.queue_redraw()
return
_portrait_tex = tex
if _portrait_sprite == null:
_portrait_sprite = Sprite2D.new()
_portrait_sprite.centered = false
_portrait_sprite.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST # 像素帧放大防糊
_owner.add_child(_portrait_sprite)
_portrait_sprite.texture = tex
_portrait_sprite.flip_h = flip
_portrait_sprite.visible = true
_place_portrait(box)
func _place_portrait(box: Vector2) -> void:
# 立绘盒 = (0,44)-(box.x, box.y-36);48 源 ×2 整数档居中
if _portrait_sprite == null or _portrait_tex == null:
return
var box_h := box.y - 44.0 - 36.0
var w := _portrait_tex.get_width() * 2.0
var h := _portrait_tex.get_height() * 2.0
_portrait_sprite.scale = Vector2(2.0, 2.0) # 整数 2×(C5)
_portrait_sprite.position = Vector2((box.x - w) * 0.5, 44.0 + (box_h - h) * 0.5)
# 组合点注册(battle_stage_view _init——UiKit 常量 load_tex,缺位 null 不注册=该态保持现纹理)
func register_hero_state(state: String, tex: Texture2D) -> void:
if tex != null:
_hero_tex[state] = tex
# 状态切换:现纹理换注册态(attack/hit);未注册态名或缺位 = 保持现纹理不炸。
# 非 idle 态自动短驻回归 idle(0.35s——演出一拍即回,结算收尾另有显式 idle 兜底)。
#(is_hero = 宿主 vitals._kind == "hero" 参判传入——三连早退条件序逐字)
func apply_hero_state(state: String, is_hero: bool) -> void:
var target: int = _HS_VALUE.get(state, -1)
if not is_hero or target == _hero_state:
return
if not _hero_tex.has(state) and state != "idle":
return
_hero_state = target
if _portrait_sprite != null and _hero_tex.has(state):
_portrait_sprite.texture = _hero_tex[state]
if _state_revert_tw != null and _state_revert_tw.is_valid():
_state_revert_tw.kill()
if state != "idle":
_state_revert_tw = _owner.create_tween()
_state_revert_tw.tween_interval(UiKit.motion(0.35))
_state_revert_tw.tween_callback(_settle_hero_idle)
func _settle_hero_idle() -> void:
_hero_state = HeroState.IDLE
if _portrait_sprite != null and _hero_tex.has("idle"):
_portrait_sprite.texture = _hero_tex["idle"]
# 复位强制绕同态早退两拍封装(原 _revive 内 hero 分支——先置 RESET 哨兵再回 idle)
func reset_state() -> void:
_hero_state = HeroState.RESET # 强制回 idle 态(绕过同态早退)
apply_hero_state("idle", true)
# 意图三档动作动画(§4.6.4 三档:①普通攻击=零表示〔set_pending 早退〕
# ②特殊准备=徽标弹入+二次弹跳(高举语义,运动手段 §2)③重击/硬化=缓推蓄力+定格微顿+回落;
# 三档运动签名互异,灰度/剪影层可辨)。摇定时一次性短动画,随后静帧保持。
#(charge = 宿主 _intent_charge 分档布尔参判传入)
func play_intent_motion(charge: bool) -> void:
var tw := _owner.create_tween()
tw.tween_property(self, "_intent_scale", 1.6, UiKit.motion(0.10))
tw.tween_property(self, "_intent_scale", 1.0, UiKit.motion(0.16))
tw.parallel().tween_property(self, "_glyph_rot", 4.0, UiKit.motion(0.10))
tw.tween_property(self, "_glyph_rot", 0.0, UiKit.motion(0.14))
if charge:
tw.tween_property(self, "_intent_scale", 1.22, UiKit.motion(0.28)).set_trans(Tween.TRANS_SINE) # ③蓄力缓推
tw.tween_interval(UiKit.motion(0.40)) # 定格微顿
tw.tween_property(self, "_intent_scale", 1.0, UiKit.motion(0.18))
else:
tw.tween_property(self, "_intent_scale", 1.26, UiKit.motion(0.11)) # ②二次弹跳(高举)
tw.tween_property(self, "_intent_scale", 1.0, UiKit.motion(0.13))
# 三态探针出口(fx_probe——当前态名+注册态集合;宿主 hero_state_probe 读件投影,外形零变)
func state_probe() -> Dictionary:
return {"state": _HS_NAME.get(_hero_state, "idle"), "registered": _hero_tex.keys()}
@@ -0,0 +1 @@
uid://cdfo2jgp2w7ei
+36
View File
@@ -0,0 +1,36 @@
## VERTICAL SLICE - NOT FOR PRODUCTION
## 站桩身份与命值态件(StandeeBody 拆件——单一变化原因=战斗结算快照投影的字段形态):
## 站桩是谁、活没活、血量几何的唯一账面——身份五元组(种类/名/id/护甲/顺位)+存活位+血量账与两条血量系 tween 槽。
## 无 class_name(类名缓存面纪律)——经宿主 standee_body preload 引用(st 实例名沿用);
## hp_value 属性 setter 经 _owner 回引触发宿主重绘语义逐字。
extends RefCounted
var _owner: Node2D = null
var _kind := "enemy"
var _display_name := ""
var _enemy_id := ""
var _armor := "light"
var _order := 1
var _dead := false
var _hp_max := 1.0
var _hp_cur := 0 # 血量数字显示面(HUD框架 验收「血量数字可读」)
var hp_value := 1.0: # 血条值 0..1(直角递减——tween_property 目标,逐行刷新重启不累积)
set(v):
hp_value = clampf(v, 0.0, 1.0)
_owner.queue_redraw()
var _hp_tween: Tween
var _hp_flash_tw: Tween
func _init(owner: Node2D) -> void:
_owner = owner
# 血条短 tween 递减(直角递减占位);逐行刷新时重启 tween 不累积
func apply_hp(hp: int) -> void:
_hp_cur = clampi(hp, 0, int(_hp_max))
var target := float(_hp_cur) / _hp_max
if _hp_tween != null and _hp_tween.is_valid():
_hp_tween.kill()
_hp_tween = _owner.create_tween()
_hp_tween.tween_property(self, "hp_value", target, UiKit.motion(0.15))
@@ -0,0 +1 @@
uid://bjd7t5nmepbey
+14 -4
View File
@@ -190,7 +190,9 @@ const STAND_STONE_RIM := Color8(196, 172, 132) # 站桩石板地台·顶缘
const CAMP_HEADER_BAND := Color8(110, 69, 38) # 营地柜台头带深棕 #6E4526(4-camp.png 方向稿取色;对齐 demo --wood-deep)
const CAMP_ROW_PLATE := Color8(240, 230, 206) # 营地行板暖米(同上)
const CAMP_BADGE_PANEL := Color8(40, 32, 24) # 营地钥石徽暗底(同上)
const HP_BAR_BACK := Color8(40, 34, 32) # 迷你血条深底 #282220(兼血数垫牌)
const HP_BAR_BACK := Color8(40, 34, 32) # 迷你血条深底 #282220(兼血数垫牌;站桩名字行素底同源——§6.1/§7.2 文字禁压地台)
const HP_BAR_FILL := Color8(168, 50, 31) # 血条填充·危险红 #A8321F(§4.2 语义物件显式落法——不因敌我分色、不因关卡换族;蓝族 #689CE8 已登记违例退役)
const HP_BAR_TRACK := Color(0.10, 0.10, 0.11) # 血条条底(视图原裸值收口单点——非色板新增,现渲染值原样入册)
# BBCode 十六进制(RichTextLabel 用;与上同值)
const HEX_GOLD := "f0a828"
@@ -244,6 +246,13 @@ const TEX_ENEMY_DRIDER := "res://assets/art/character/character_enemy_drider.png
const TEX_ENEMY_DUERGAR := "res://assets/art/character/character_enemy_duergar.png" # 灰矮人
const TEX_ENEMY_HOOK_HORROR := "res://assets/art/character/character_enemy_hook_horror.png" # 钩爪恐魔
const TEX_ENEMY_DUERGAR_KING := "res://assets/art/character/character_enemy_duergar_king.png" # 灰矮人石君王
# 近景地台独立件(§6.1——源 48×12 九宫格横向拉伸、顶缘受光线 2px 不随拉伸变形;跨三关恒定不吃 wall_ambient tint)
const TEX_STAGE_PLAZA := "res://assets/art/scene/scene_stage_plaza.png"
# 护甲类型图标三键(art-bible §5.3 工单:对象键 = 甲档变体;源 24×24 显示 24px = 1× 甲类整数倍;
# 缺位 load_tex→null→字形回退,冒烟安全)
const TEX_ARMOR_LIGHT := "res://assets/ui/icons/ui_armor_light.png"
const TEX_ARMOR_WARD := "res://assets/ui/icons/ui_armor_ward.png"
const TEX_ARMOR_HEAVY := "res://assets/ui/icons/ui_armor_heavy.png"
# 框材组纹理槽(♻ 复用件量化改色入包,产物 = tools/quantize_ui_skin.py,
# 全 CC0;缺位 = load_tex null → 程序化回退原路径,冒烟安全)
@@ -464,12 +473,13 @@ const PANEL_DEFAULT := true # modal_shell 面板哨兵(非 StyleBox 实例
# 面板哨兵解析(六参收拢五参——三态:null=无面板〔原 with_panel=false〕/PANEL_DEFAULT=默认样式盒面板
# 〔原 with_panel=true+panel_sb=null〕/StyleBox 实例=自定义样式盒面板〔原双参形态〕)
static func _resolve_shell_panel(panel_sb) -> PanelContainer:
# 〔原 with_panel=true+panel_sb=null〕/StyleBox 实例=自定义样式盒面板〔原双参形态〕;
# 判别用 is StyleBox——StyleBox 与布尔哨兵直接 != 属异类操作数违例)
static func _resolve_shell_panel(panel_sb) -> PanelContainer: # type-hint: ignore(三态哨兵 bool/null/StyleBox 异构形参)
if panel_sb == null:
return null
var panel := PanelContainer.new()
if panel_sb != PANEL_DEFAULT:
if panel_sb is StyleBox:
panel.add_theme_stylebox_override("panel", panel_sb)
return panel
+11 -11
View File
@@ -231,8 +231,8 @@ func _ready() -> void:
if bv.hover_probe() != seal_t:
_problems.append("case① 悬停未到达(_hover=%s 应=%s)" % [bv.hover_probe(), seal_t])
var u1 = bv.cells_probe()[seal_t]
if not u1.hl_visible or u1.hl_color != UiKit.GOLD:
_problems.append("case① 悬停金框缺失(visible=%s color=%s)" % [str(u1.hl_visible), str(u1.hl_color)])
if not u1.face.hl_visible or u1.face.hl_color != UiKit.GOLD:
_problems.append("case① 悬停金框缺失(visible=%s color=%s)" % [str(u1.face.hl_visible), str(u1.face.hl_color)])
if bv.mouse_default_cursor_shape != Input.CURSOR_CROSS:
_problems.append("case① 挖掘光标未切十字(%d)" % bv.mouse_default_cursor_shape)
# ---- case② 悬停禁入:hover_forbidden 信号 + 灰禁红框 ----
@@ -240,14 +240,14 @@ func _ready() -> void:
await get_tree().process_frame
if _forbids.is_empty() or _forbids[_forbids.size() - 1] != forbid_t:
_problems.append("case② hover_forbidden 未达(%s)" % [str(_forbids)])
if bv.cells_probe()[forbid_t].hl_color != UiKit.RED_FORBID:
_problems.append("case② 禁入红框缺失(color=%s)" % str(bv.cells_probe()[forbid_t].hl_color))
if bv.cells_probe()[forbid_t].face.hl_color != UiKit.RED_FORBID:
_problems.append("case② 禁入红框缺失(color=%s)" % str(bv.cells_probe()[forbid_t].face.hl_color))
# ---- case③ 悬停已开格:路径预览点迹 + 移动光标 ----
_push_motion(_pos(bv, reveal_t))
await get_tree().process_frame
var dots := 0
for c in bv.cells_probe():
if bv.cells_probe()[c].dot_visible:
if bv.cells_probe()[c].face.dot_visible:
dots += 1
if dots < 1:
_problems.append("case③ 路径预览点迹未亮(dots=0)")
@@ -266,8 +266,8 @@ func _ready() -> void:
# 掩盖)——有盘断言纹理在槽、缺盘断言字形回退,两分支防双写踩踏复活 ----
var seal_unit = bv.cells_probe().get(seal_t)
if bv._palette.seal_tex != null:
if seal_unit == null or seal_unit.tex_seal != bv._palette.seal_tex:
_problems.append("case④b 封印纹理槽未挂封印印记纹理(tex_seal=%s)" % ["无单元" if seal_unit == null else str(seal_unit.tex_seal)])
if seal_unit == null or seal_unit.face.tex_seal != bv._palette.seal_tex:
_problems.append("case④b 封印纹理槽未挂封印印记纹理(tex_seal=%s)" % ["无单元" if seal_unit == null else str(seal_unit.face.tex_seal)])
elif seal_unit == null or seal_unit.glyph != "封":
_problems.append("case④b 缺盘字形回退缺失(glyph=%s)" % ["无单元" if seal_unit == null else String(seal_unit.glyph)])
# ---- case⑤ 双击 chord:禁入格双左击(核心拒挖零副作用)→ chord_attempted ----
@@ -371,12 +371,12 @@ func _ready() -> void:
if mark_t.x >= 0:
bv.set_variant_mark_resolver(func(_c): return "flat_damage")
bv.refresh()
if String(bv.cells_probe()[mark_t].mutation_mark) != "flat_damage":
_problems.append("case⑭ 变异角标未落位(mutation_mark=%s)" % str(bv.cells_probe()[mark_t].mutation_mark))
if String(bv.cells_probe()[mark_t].face.mutation_mark) != "flat_damage":
_problems.append("case⑭ 变异角标未落位(mutation_mark=%s)" % str(bv.cells_probe()[mark_t].face.mutation_mark))
bv.set_variant_mark_resolver(Callable())
bv.refresh()
if String(bv.cells_probe()[mark_t].mutation_mark) != "":
_problems.append("case⑭ 角标未随 resolver 复位(mutation_mark=%s)" % str(bv.cells_probe()[mark_t].mutation_mark))
if String(bv.cells_probe()[mark_t].face.mutation_mark) != "":
_problems.append("case⑭ 角标未随 resolver 复位(mutation_mark=%s)" % str(bv.cells_probe()[mark_t].face.mutation_mark))
else:
_problems.append("case⑭ 无未开格可验(板面异常)")
# ---- case⑮ 视野迷雾(三态呈态/半径圈/移动跟随/开关两态零扰动/提灯插值位;
+3 -3
View File
@@ -281,11 +281,11 @@ func _pick_battle_node(main: Node) -> int:
# 入口/兑付停点走 level_screen.open_choices 直传(不写 _pending_candidates)——
# 候选从视图态取:_cand_ids × runner.nodes() 的 type(编号解析=node_id_of 单一出口)
var ls: Node = main.level_screen
if ls._runner == null:
if ls._map._runner == null:
return -1
for nd in ls._runner.nodes():
for nd in ls._map._runner.nodes():
if String(nd.get("type", "")) in ["battle", "boss"]:
var nid: int = ls._runner.node_id_of(nd)
var nid: int = ls._map._runner.node_id_of(nd)
if nid in ls._cand_ids:
return nid
return -1
+8 -8
View File
@@ -332,13 +332,13 @@ static func _on_adventure_curio_resolved(result: Dictionary, st: Dictionary, adr
# 商店贪心买齐:GP 局内死钱——买得起就买( affordable 集里挑最便宜的
# 反复买到达不上任何商品为止,guard 防死循环)。确定性(零随机流);购买出账/加算区入账全走
# runner.buy_product 核心编排(与呈现层购买同一出账路径,wallet_changed 信号照常采集)。
# runner.shop.buy_product 核心编排(与呈现层购买同一出账路径,wallet_changed 信号照常采集)。
static func _autoplay_shop(r, st: Dictionary) -> void:
var guard := 30
while guard > 0:
guard -= 1
var affordable: Array = []
for p in r.shop_products():
for p in r.shop.shop_products():
if r.gp >= int(p.get("price", 1 << 30)):
affordable.append(p)
if affordable.is_empty():
@@ -347,20 +347,20 @@ static func _autoplay_shop(r, st: Dictionary) -> void:
for p in affordable:
if int(p.get("price", 1 << 30)) < int(pick.get("price", 1 << 30)):
pick = p
if not r.buy_product(String(pick.get("product_id", ""))):
if not r.shop.buy_product(String(pick.get("product_id", ""))):
return
st.shop_buys = int(st.get("shop_buys", 0)) + 1
# 商店共享池贪心:货架三选一同构面贪心买齐——affordable 集挑最便宜反复买
# (每次买后全重抽、货架随买随换,枯竭/不可负担即止,guard 防死循环)。购买走 runner.buy_pool_item
# (每次买后全重抽、货架随买随换,枯竭/不可负担即止,guard 防死循环)。购买走 runner.shop.buy_pool_item
# 核心编排(与呈现层购买同一出账+池消费路径,wallet_changed 信号照常采集)。确定性(零随机流)。
static func _autoplay_shop_pool(r, st: Dictionary) -> void:
var guard := 30
while guard > 0:
guard -= 1
var affordable: Array = []
for c in r.shop_shelf():
for c in r.shop.shop_shelf():
if r.gp >= int(c.get("price", 1 << 30)):
affordable.append(c)
if affordable.is_empty():
@@ -369,7 +369,7 @@ static func _autoplay_shop_pool(r, st: Dictionary) -> void:
for c in affordable:
if int(c.get("price", 1 << 30)) < int(pick.get("price", 1 << 30)):
pick = c
if not r.buy_pool_item(String(pick.get("kind_id", ""))):
if not r.shop.buy_pool_item(String(pick.get("kind_id", ""))):
return
st.shop_buys = int(st.get("shop_buys", 0)) + 1
@@ -415,10 +415,10 @@ static func _route_pick(runner, route: String, st: Dictionary) -> int:
s = 10.0
var cheapest := 1 << 30
if String(st.get("shop_mode", "legacy")) == "pool":
for c in runner.shop_shelf(): # pool 面:货架现价
for c in runner.shop.shop_shelf(): # pool 面:货架现价
cheapest = mini(cheapest, int(c.get("price", 1 << 30)))
else:
for p in runner.shop_products():
for p in runner.shop.shop_products():
cheapest = mini(cheapest, int(p.get("price", 1 << 30)))
if cheapest < (1 << 30) and runner.gp >= cheapest:
s = 80.0
+15 -19
View File
@@ -1,5 +1,5 @@
{
"note": "存量基线·首次自动生成;闸况变化时本脚本会判红,需人工确认后重生成;2026-10-17 人工确认重生成 06 条目:af94ce97 把 gdd_lint 记为存量红(01 篇 R5),该红已由 fcb8c3f8 补流程图消除,实测 --docs 域 06 exit=0,故基线改回绿。2026-10-18 新增闸件 08c 流水线闸(tools/pipeline_gate.py 注册上电),手工加入绿记录(roadmap 压缩批实测 --docs 域 exit=0),其余条目原样保留。2026-10-22 测试术语与层级重构批 A 改键:01 冒烟全量→01 系统测试(同一断言面 smoke_all.gd,运行器换 tools/run_system_test.py,过渡期判定口径不变)、02 单元套件→02 单元与集成测试(同一 run_all.gd 入口,名从实)、新增 00 冒烟测试(tools/run_smoke.py+game/tests/smoke_boot.tscn,重写后单跑实测 17 项 0 失败 PASS);09 静态扫描基线 exit=1(fp=4354b2aa72a7)系滞后红,本批单跑实测 exit=0(与 2026-10-22 16:20 回执一致),基线改回绿;其余条目原样保留。;2026-10-23 主会话记 07 doc_link 为存量红(用户令忽略:锻造工坊.md 死链的修复在另一会话未合入,合回闸豁免;外部修复合入后应重生成基线归绿);2026-10-26 用户特批带红合并(迭代 38 收口):09 静态扫描记存量红——gdstyle 恶化 2 条(battle_orchestrator.gd max-file-length 1314>1302=卡④头注必载内容、level_map_screen.gd max-class-variables 22>21=卡①缓存成员,均为卡片义务的记账漂移非缺陷,压缩还债经计算不可行),用户裁「不管引入的恶化直接提交、特许免测试重跑」;后续批次若触及两文件可顺带还债或经批准重生成基线归绿;2026-10-27 用户裁「标准是尺、不以现状为尺」:09 存量红照实记(exit=1+现行红项指纹,两条恶化各自点名可核),gdstyle 基线登记值回退 1302/21(波 0 的 18 条陈旧键清理保留),gdstyle_gate 逐条违规行加 FAIL 前缀并加「refresh 禁抬高登记值」守卫——存量红期间任何新增违规或进一步恶化都会改指纹被拦;阈值口径不变=gdstyle 默认值(文件 1000 行/类变量 15 等),还债归迭代 40 卡①(battle_orchestrator 1314→≤1000)与迭代 41 卡③(level_map_screen 22→≤15),还清后重新生成基线归绿;2026-10-27 用户特批带红合并(迭代39 拆件批):02 记存量红(fp f74b9a48ef4a=round_flow EV 锚 goblin 0.9148∉[1.00,1.20],触发器批有意行为改动,旧带宽锚触发器前设计,重锚归后续数值批待用户发起);08d 记存量红(red-nokeys=生涯.md:55 引 adventure_runner.gd:814 行号漂移,B1 拆分后 660 行,另 :50/:60 与 元进度.md:70 建议级,修复归合并后文档批,反哺点在册);07 doc_link 基线红→现绿改善随下次基线重生成记账;09 指纹经 S9 注解修复(f96632de)回归登记值 91d45583cf6d;2026-10-28 迭代40 收口记账(用户裁「刷」):卡① 拆件还债——battle_orchestrator 行数红项消失(实测 1036≤登记 1302;契约2 残余 36 行系合并适配带入 master 迭代39 内容,用户裁登记残余债归待办清单),09 红项由两条收敛为一条(level_map_screen 类变量 22>21=迭代38 存量,还债归迭代41 卡③),指纹 91d45583cf6d → 8467b4588a20(收口会话按闸壳同款算法对用户探跑日志实算,全量闸复验);02 存量红已随 master 侧 EV 重锚批(ba5105aa)归绿并入本合并;2026-10-28 EV 锚重锚批(工程改动·worktree ev-anchor-remeasure-20261028,用户特许会话内执行):02 基线红→现绿归绿——round_flow EV 锚 goblin 带宽按无情境口径(模拟器不过滤 trigger 行)重锚 [0.82,1.02](迭代39触发器批孤注守势入池稀释,实测 0.9148,重锚注记 enemy.tres 与测试注释;旧带 [1.00,1.20] 随池构成换代作废),撤销证明=带宽回退 [1.00,1.20] 断言复红;08d 存量红不变(生涯.md:55 行号漂移,修复归文档批)",
"note": "存量基线·闸况变化时本脚本会判红,需人工确认后重生成;2026-10-29 二次记账=03/04/05 三闸按 80b49c0f 先例经用户裁决记入现行红项指纹(03=8a3cae0d0446/04=591b27250b36/05=de89589e49ed)——master 同值复现非迭代42新增(stash 对照法取证,承「迭代 41 测试债修复」条目扩展);原 2026-10-17 06 条目人工重生成记录见 git 提交史",
"gates": {
"00 冒烟测试": {
"exit": "0",
@@ -10,20 +10,16 @@
"fp": "green"
},
"02 单元与集成测试": {
"exit": "0",
"fp": "green"
"exit": "1",
"fp": "f9865f1a5a44"
},
"03 探针 --click": {
"exit": "0",
"fp": "green"
},
"04 探针 --full": {
"03 场景探针": {
"exit": "0",
"fp": "green"
},
"05 渲染闸": {
"exit": "0",
"fp": "green"
"exit": "1",
"fp": "de89589e49ed"
},
"06 gdd_lint": {
"exit": "0",
@@ -34,8 +30,8 @@
"fp": "green"
},
"07 doc_link": {
"exit": "1",
"fp": "red-nokeys"
"exit": "0",
"fp": "green"
},
"08 doc_term": {
"exit": "0",
@@ -47,19 +43,19 @@
},
"09 静态扫描": {
"exit": "1",
"fp": "8467b4588a20"
"fp": "1a9ad773489f"
},
"10 熵增闸": {
"exit": "0",
"fp": "green"
},
"11 回放确定性对拍": {
"exit": "SKIP",
"fp": "skip"
},
"08d 引用可核": {
"exit": "1",
"fp": "red-nokeys"
"exit": "0",
"fp": "green"
},
"08e 能力审计": {
"exit": "0",
"fp": "green"
}
}
}
+127 -59
View File
@@ -2,7 +2,7 @@
**Engine**: Godot 4.7.2-stable(GDScript 单语言)
**Test Framework**: 标准四级测试层(冒烟/单元/集成/系统)+ headless 场景探针与渲染 golden;gdUnit4 **deferred**(D2 OQ1 关闭形态——本仓库不引第三方测试框架,需求见下「门禁」节)
**门禁**: 本地闸——`tools/run_all_gates.sh`(收口唯一验收入口,按改动域选档 `--code`/`--docs`,跨两域或改闸件本身不带参数=全量)。本仓库**无远端、无 CI**(`.github/workflows/` 已删除,不建不留不参考);闸清单与域划分只在本脚本定义,文档不另列
**门禁**: 本地闸——`tools/run_all_gates.sh`(收口唯一验收入口,按改动域选档 `--code`/`--docs`,跨两域或改闸件本身不带参数=全量;代码域 02 按关联档选套件,算法与套件族映射表只在脚本内定义)。本仓库**无远端、无 CI**(`.github/workflows/` 已删除,不建不留不参考);闸清单与域划分只在本脚本定义,文档不另列
**Setup date**: 2026-09-12(2026-09-27 `7f24b640` 三层收敛:根 tests/ 并入 `game/tests/`、docs 并入 `design/engineering/`、production 解散)
**参考实现**: `game/probe/`(场景探针族)· `game/sim/`(测量/诊断/模拟驱动件)(场景探针族——正式工程的活样板;系统测试断言面过渡宿主 `smoke_all.gd` 亦在此,迁移归断言迁移批)
@@ -33,82 +33,149 @@ tests/
| **单元测试** | 领域类的原子行为对不对(公式/状态机/纯逻辑)——从对外方法进、断言钉对外可观测面(写法判据见 test-conventions §8.2) | `tests/unit/` | `run_all.gd` manifest(闸 02) |
| **集成测试** | 跨系统的闭环对不对 | `tests/integration/` | 同上(与单元测试同一入口、同一协议) |
| **系统测试** | 启动真实工程走真实玩法路径 | 过渡期 `game/probe/smoke_all.gd`(断言迁移批后=`tests/system_test.gd`) | `run_system_test.py`(闸 01) |
| **UI 探针+渲染 golden** | 跑起来之后 UI 与场景切换对不对;画面基线 | `game/probe/*.tscn` 探针 | `probe_gate.sh`(闸 03/04)、`render_gate.sh`(闸 05) |
| **UI 探针+渲染 golden** | 跑起来之后 UI 与场景切换对不对;画面基线 | `game/probe/*.tscn` 探针 | `probe_gate.sh`(闸 03)、`render_gate.sh`(闸 05) |
> **integration/ 已建承载**(迭代 29 T3——此前只有章程句无实体,空壳曾于迭代 19 卡① T4 删过一次)。
> 首个集成用例 = `save_rng_roundtrip_test.gd`(存档⇄RNG 快照往返)。章程登记的四类集成用例里,
> 回放确定性已由 `tools/parity_anchor.py` 承担并收编为全量域闸 11 号条件闸件;
> Core-Core 与 A1×A2 端到端仍随属主批增量登记;各 GDD 登记的 deferral 集成用例以对侧登记为生效条件。
>
> **分层判据**:能不能在 `--script` 模式下不加载 autoload 就验完?能 = 单元测试;
> 需要两个以上真实系统协同并走落盘/落库 = 集成测试;需要完整项目引导与场景树 = 冒烟/系统/UI 探针。
**能力清单 v1**(2026-10-28 立——验证与清单体系整改阶段 1 的覆盖索引:一行=一个玩家或系统可观测的能力,代表用例只给指针、不复制断言细节;原「集成旅程清单」五条跨系统旅程已并入本表。首期覆盖核心四域(29 行)+跨域条件闸 1 行,共 30 行;其余域按同一形态扩面):
**能力清单**(2026-10-28 立,2026-10-29 改版定稿——验证与清单体系整改的能力义务清单:一行=一个玩家或系统可观测的能力,只宣布「要验证什么」,不记「是否已验证/是否跑过」;定位=实现指导+阅读导航+义务声明,代表用例只给指针、不复制断言细节;原「集成旅程清单」五条跨系统旅程已并入本表。七段=核心四域+排雷循环+表现与支撑+数据配置与跨系统契约,行数随清单生长不在此记账;系统文档逐篇对照见下方「覆盖域表」):
> **与验证集清单的关系**:`tests/验证集清单.md` 已于阶段 2「存量断言精简」完成后删除——冻结对账基准(基点 `b9260138`/1587 条)与精简对账结果(33 站点并为 7、1587→1561,合回 `87d241c1`)留 git 历史。本表是该清单退役后的唯一覆盖索引(维护锚=test-conventions §8.3)。本表不是闸,不替代改动—验收对照表、体验验证清单与静态纪律;每行的唯一事实源仍是 `game/tests/` 下的测试代码。
> **与验证集清单的关系**:`tests/验证集清单.md` 已于「存量断言精简」阶段完成后删除(对账基准与结果留 git 历史)。本表是该清单退役后的唯一能力义务清单(维护锚=test-conventions §8.3 清单归属+§8.9 三层模型)。本表不是闸,不替代改动—验收对照表、体验验证清单与静态纪律;已落地行的唯一事实源是 `game/tests/` 下的测试代码,计划中的行由需求卡片锚定(见维护规则)。
>
> **代表用例口径**:写 `文件:函数`,每行 2–3 个;函数内可含 `Kit.check_quiet` 静默通道(逐断言提取器口径外,test-conventions §5.2 已备案)——本表以函数为锚,不受该工具局限影响。
> **代表用例口径**:写 `文件:函数`,每行 1–3 个;函数内可含 `Kit.check_quiet` 静默通道(逐断言提取器口径外,test-conventions §5.2 已备案)——本表以函数为锚,不受该工具局限影响。计划中的用例=卡内定死的测试名,实现落地后转为代码实锚(机检双通道:代码在或卡在,test-conventions §8.9)。
>
> **维护规则(每批收口核对本批受影响行)**:本批改到哪个能力,收口时核对该行代表用例可 grep、在本批真实跑批中执行、真实入口未绕过改动点,并把「最后验证批次」刷新为本批回执;新增能力加行,能力退役删行。全表核对频率与抽样规则归阶段 3。首期未覆盖:排雷循环(棋盘生成/排雷玩法/行动经济)、表现与支撑(HUD/主题/字体/地形瓦片/模态)、数据配置与跨系统契约——按同一形态后续扩面。
> **维护规则(写卡段维护,实现批禁写本表)**:写需求卡片时当场入表——本批新增能力当场增行(真实入口取自设计文档已定的入口;代表用例=卡内定死的计划测试 `文件:函数`,实现照单落名,名实不符=卡片没写清=停卡退回);受影响存量行(入口/用例名变更)同批更新;能力退役删行。批末收尾只核对表上名字与实际落地一致(改名则回表),不刷任何批次字段(test-conventions §8.3/§8.9)。
>
> **旅程补录方法**:新旅程=加一行,「系统」列写涉及边界;源=architecture「API 边界」表+「数据流」存档/读档路径+各 GDD 登记的 deferral 集成用例。
>
> 「最后验证批次」列记回执 commit;多数行初值 `20c13c3a`=存量断言精简 A+B 首批的全量域闸回执,RNG 行随 C 档批刷新为 `fd6cf968`。
**旅程段一:开机与存档**
| 能力 | 系统 | 真实入口 | 代表用例(文件:函数) | 最后验证批次 | 缺口 |
|---|---|---|---|---|---|
| 存档写盘⇄读回往返保真 | 存档序列化 | `SaveManagerCore.write_to_disk()`/`load_from_disk()` | `save_manager_domain_test.gd:_smoke_save` | `20c13c3a` | — |
| 三槽位隔离与激活失败回滚 | 存档序列化 | `SaveManagerCore.activate_slot()`/`create_slot()`/`delete_slot()` | `save_slot_isolation_test.gd:_test_three_slot_roundtrip_and_isolation`;`save_slot_isolation_test.gd:_test_activate_failure_restores_previous_slot` | `20c13c3a` | — |
| 槽位摘要窥视与坏槽三态 | 存档序列化 | `SaveManagerCore.peek_slot_summary()` | `save_slot_summary_test.gd:_test_peek_three_slots_distinct_values`;`save_slot_summary_test.gd:_test_peek_empty_and_unreadable_states`;`save_slot_summary_test.gd:_test_peek_zero_side_effect` | `20c13c3a` | — |
| 启动态无激活不写盘 | 存档序列化 | `SaveManagerCore.has_write_target()`/`write_to_disk()` | `save_boot_no_activate_test.gd:_test_write_rejected_without_target`;`save_boot_no_activate_test.gd:_test_out_of_range_slots_rejected` | `20c13c3a` | — |
| 旧档迁移链与断点续玩零跳号(集成) | 存档序列化×冒险结构 | `SaveManagerCore.load_from_disk()`(内置迁移链)× `AdventureRunner.resume_adventure()` | `save_rng_roundtrip_test.gd:_test_old_version_save_migrates_and_resumes` | `20c13c3a` | — |
| 存档⇄RNG 快照往返保真(集成) | 存档序列化×RNG 服务×冒险结构 | `AdventureRunner.start_adventure()` → `SaveManagerCore.write_to_disk()`/`load_from_disk()` | `save_rng_roundtrip_test.gd:_test_disk_roundtrip_preserves_breakpoint` | `20c13c3a` | — |
| RNG 统一流派生与取号账本 | RNG 服务 | `RngServiceCore.derive_at()`/`open_stream()`/`counter()` | `rng_service_test.gd:_test_derive_determinism`;`rng_service_test.gd:_test_stream_draw_determinism`;`rng_stream_boot_test.gd:_smoke_initialize` | `fd6cf968` | — |
| 断点片段往返与续玩幂等 | 冒险结构×关卡节点地图 | `LevelRunner.breakpoint_fragment()`/`restore_fragment()`;`AdventureRunner.resume_adventure()` | `breakpoint_resume_test.gd:_init` | `20c13c3a` | — |
| 跨系统附随面:事件日志落盘与断点附随件(集成) | RNG 服务×存档序列化×冒险结构 | `RngServiceCore.new_adventure()`(开事件日志会话);`SaveManagerCore.breakpoint_snapshot()`(断点附随键) | `cross_system_flow_test.gd:_rng_event_log_session`;`cross_system_flow_test.gd:_feats_breakpoint_roundtrip` | `20c13c3a` | 日志面仅此一条会话覆盖 |
| 能力 | 系统 | 真实入口 | 代表用例(文件:函数) |
|---|---|---|---|
| 存档写盘⇄读回往返保真 | 存档序列化 | `SaveManagerCore.write_to_disk()`/`load_from_disk()` | `save_manager_domain_test.gd:_smoke_save` |
| 三槽位隔离与激活失败回滚 | 存档序列化 | `SaveManagerCore.activate_slot()`/`create_slot()`/`delete_slot()` | `save_slot_isolation_test.gd:_test_three_slot_roundtrip_and_isolation`;`save_slot_isolation_test.gd:_test_activate_failure_restores_previous_slot` |
| 槽位摘要窥视与坏槽三态 | 存档序列化 | `SaveManagerCore.peek_slot_summary()` | `save_slot_summary_test.gd:_test_peek_three_slots_distinct_values`;`save_slot_summary_test.gd:_test_peek_empty_and_unreadable_states`;`save_slot_summary_test.gd:_test_peek_zero_side_effect` |
| 启动态无激活不写盘 | 存档序列化 | `SaveManagerCore.has_write_target()`/`write_to_disk()` | `save_boot_no_activate_test.gd:_test_write_rejected_without_target`;`save_boot_no_activate_test.gd:_test_out_of_range_slots_rejected` |
| 旧档迁移链与断点续玩零跳号(集成) | 存档序列化×冒险结构 | `SaveManagerCore.load_from_disk()`(内置迁移链)× `AdventureRunner.resume_adventure()` | `save_rng_roundtrip_test.gd:_test_old_version_save_migrates_and_resumes` |
| 存档⇄RNG 快照往返保真(集成) | 存档序列化×RNG 服务×冒险结构 | `AdventureRunner.start_adventure()` → `SaveManagerCore.write_to_disk()`/`load_from_disk()` | `save_rng_roundtrip_test.gd:_test_disk_roundtrip_preserves_breakpoint` |
| RNG 统一流派生与取号账本 | RNG 服务 | `RngServiceCore.derive_at()`/`open_stream()`/`counter()` | `rng_service_test.gd:_test_derive_determinism`;`rng_service_test.gd:_test_stream_draw_determinism`;`rng_stream_boot_test.gd:_smoke_initialize` |
| 断点片段往返与续玩幂等 | 冒险结构×关卡节点地图 | `LevelRunner.breakpoint_fragment()`/`restore_fragment()`;`AdventureRunner.resume_adventure()` | `breakpoint_resume_test.gd:_init` |
| 跨系统附随面:事件日志落盘与断点附随件(集成) | RNG 服务×存档序列化×冒险结构 | `RngServiceCore.new_adventure()`(开事件日志会话);`SaveManagerCore.breakpoint_snapshot()`(断点附随键) | `cross_system_flow_test.gd:_rng_event_log_session`;`cross_system_flow_test.gd:_feats_breakpoint_roundtrip` |
**旅程段二:冒险开局与选路**
| 能力 | 系统 | 真实入口 | 代表用例(文件:函数) | 最后验证批次 | 缺口 |
|---|---|---|---|---|---|
| 冒险生命周期:开局受理/三关序列/败北线 | 冒险结构 | `AdventureRunner.start_adventure()`/`continue_to_next_level()` | `adventure_feats_test.gd:_smoke_adventure_api`;`adventure_feats_test.gd:_smoke_adventure` | `20c13c3a` | — |
| 专长(奇物)授予与凭证保底 | 奇物 | `AdventureRunner.present_node_curio()`/`feats_held()` × 效果引擎兑付 | `adventure_feats_test.gd:_smoke_feats`;`feat_vouchers_test.gd:_init` | `20c13c3a` | — |
| 节点图生成合法性与同种子复现 | 关卡节点图生成 | `NodeMapGenerator.generate()`/`validate_output()` | `node_map_generator_test.gd:_test_output_ok`;`node_map_generator_test.gd:_test_reproducible`;`node_map_generator_test.gd:_test_exit_structure` | `20c13c3a` | — |
| 节点图生长递增与无解 fail-fast | 关卡节点图生成 | `NodeMapGenerator.generate()`/`is_fatal()` | `node_map_growth_test.gd:_test_growth`;`node_map_growth_test.gd:_test_fatal_subprocess` | `20c13c3a` | — |
| 起关/选路/断点重生成同图(集成) | 关卡节点地图×关卡节点图生成×冒险结构 | `LevelRunner.start_level()`/`start_level_external()`/`pick_next_node()`;`AdventureRunner.resume_adventure()` | `node_map_determinism_test.gd:_smoke_generated_map_determinism` | `20c13c3a` | — |
| 信息迷雾类型可见性 | 关卡节点地图 | `LevelRunner.type_visible_ids()` | `level_map_type_vis_test.gd:_test_layer_distance`;`level_map_type_vis_test.gd:_test_boss_exempt`;`level_map_type_vis_test.gd:_test_resume_rebuild` | `20c13c3a` | — |
| 关卡表消费侧校验与关卡推进 | 关卡节点地图×数据配置 | `LevelTable.validate_graph()`;`LevelRunner.start_level()` | `level_table_validate_test.gd:_test_positive`;`level_table_validate_test.gd:_test_negative`;`level_shop_economy_test.gd:_smoke_level` | `20c13c3a` | — |
| 能力 | 系统 | 真实入口 | 代表用例(文件:函数) |
|---|---|---|---|
| 冒险生命周期:开局受理/三关序列/败北线 | 冒险结构 | `AdventureRunner.start_adventure()`/`continue_to_next_level()` | `adventure_feats_test.gd:_smoke_adventure_api`;`adventure_feats_test.gd:_smoke_adventure` |
| 专长(奇物)授予与凭证保底 | 奇物 | `AdventureRunner.present_node_curio()`/`feats_held()` × 效果引擎兑付 | `adventure_feats_test.gd:_smoke_feats`;`feat_vouchers_test.gd:_init` |
| 节点图生成合法性与同种子复现 | 关卡节点图生成 | `NodeMapGenerator.generate()`/`validate_output()` | `node_map_generator_test.gd:_test_output_ok`;`node_map_generator_test.gd:_test_reproducible`;`node_map_generator_test.gd:_test_exit_structure` |
| 节点图生长递增与无解 fail-fast | 关卡节点图生成 | `NodeMapGenerator.generate()`/`is_fatal()` | `node_map_growth_test.gd:_test_growth`;`node_map_growth_test.gd:_test_fatal_subprocess` |
| 起关/选路/断点重生成同图(集成) | 关卡节点地图×关卡节点图生成×冒险结构 | `LevelRunner.start_level()`/`start_level_external()`/`pick_next_node()`;`AdventureRunner.resume_adventure()` | `node_map_determinism_test.gd:_smoke_generated_map_determinism` |
| 信息迷雾类型可见性 | 关卡节点地图 | `LevelRunner.type_visible_ids()` | `level_map_type_vis_test.gd:_test_layer_distance`;`level_map_type_vis_test.gd:_test_boss_exempt`;`level_map_type_vis_test.gd:_test_resume_rebuild` |
| 关卡表消费侧校验与关卡推进 | 关卡节点地图×数据配置 | `LevelTable.validate_graph()`;`LevelRunner.start_level()` | `level_table_validate_test.gd:_test_positive`;`level_table_validate_test.gd:_test_negative`;`level_shop_economy_test.gd:_smoke_level` |
**旅程段三:战斗结算**
| 能力 | 系统 | 真实入口 | 代表用例(文件:函数) | 最后验证批次 | 缺口 |
|---|---|---|---|---|---|
| 伤害公式与掷点乘区 | 战斗结算 | `DamageMath.pool_damage()`/`roll_discount_percent()`/`rolled_component()` | `damage_math_test.gd:_test_pool_damage`;`damage_math_test.gd:_test_roll_discount_percent`;`roll_multiplier_test.gd:_smoke_armor_roll` | `20c13c3a` | — |
| 伤害单据编排与回放 | 战斗结算 | `DamageController.submit()`/`open_ticket()`/`flush()` | `damage_controller_test.gd:_run_recipe_sequence`;`damage_controller_test.gd:_test_five_recipes_and_replay` | `20c13c3a` | — |
| 轮内流与结算五段全序 | 战斗结算 | `BattleOrchestrator.begin_battle()` | `round_flow_skill_pool_test.gd:_smoke_full_battle`;`round_flow_skill_pool_test.gd:_smoke_settlement_segments` | `20c13c3a` | — |
| 技能池数据面与回放独立 | 敌人系统 | `BattleOrchestrator.begin_battle()`(技能池抽号/校验) | `round_flow_skill_pool_test.gd:_smoke_skill_pool_data`;`round_flow_skill_pool_test.gd:_smoke_skill_pool_replay_independence` | `20c13c3a` | — |
| Boss 半血解锁技门控 | 敌人系统 | `BattleOrchestrator.begin_battle()`(Boss 行) | `skill_unlock_test.gd:_test_gate_predicate`;`skill_unlock_test.gd:_test_latch_irreversible` | `20c13c3a` | — |
| 封印与极性路由/不可逆 | 地图战斗资源×战斗结算 | 效果引擎 × `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` | `20c13c3a` | — |
| 变异布置门控 | 地形变异 | `BattleOrchestrator.begin_battle()`(变异布置段) | `variant_placement_test.gd:_smoke_variant_placement`;`variant_placement_test.gd:_smoke_global_variant` | `20c13c3a` | — |
| 能力 | 系统 | 真实入口 | 代表用例(文件:函数) |
|---|---|---|---|
| 伤害公式与掷点乘区 | 战斗结算 | `DamageMath.pool_damage()`/`roll_discount_percent()`/`rolled_component()` | `damage_math_test.gd:_test_pool_damage`;`damage_math_test.gd:_test_roll_discount_percent`;`roll_multiplier_test.gd:_smoke_armor_roll` |
| 伤害单据编排与回放 | 战斗结算 | `DamageController.submit()`/`open_ticket()`/`flush()` | `damage_controller_test.gd:_run_recipe_sequence`;`damage_controller_test.gd:_test_five_recipes_and_replay` |
| 轮内流与结算五段全序 | 战斗结算 | `BattleOrchestrator.begin_battle()` | `round_flow_skill_pool_test.gd:_smoke_full_battle`;`round_flow_skill_pool_test.gd:_smoke_settlement_segments` |
| 技能池数据面与回放独立 | 敌人系统 | `BattleOrchestrator.begin_battle()`(技能池抽号/校验) | `round_flow_skill_pool_test.gd:_smoke_skill_pool_data`;`round_flow_skill_pool_test.gd:_smoke_skill_pool_replay_independence` |
| 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()`(变异布置段) | `variant_placement_test.gd:_smoke_variant_placement`;`variant_placement_test.gd:_smoke_global_variant` |
**旅程段四:奖励、经济与局外成长**
| 能力 | 系统 | 真实入口 | 代表用例(文件:函数) | 最后验证批次 | 缺口 |
|---|---|---|---|---|---|
| 清图奖励双份与零路径 | 地图战斗资源 | `BattleOrchestrator.begin_battle()` → 步骤流行(`source_class=clear_reward`) | `seal_polarity_test.gd:_smoke_clear_reward_chain`;`seal_polarity_test.gd:_smoke_clear_reward_zero_paths` | `20c13c3a` | — |
| 奖励三选一候选/刷新付费/呈现 | 奇物×节点奖励屏 | `AdventureRunner.present_node_curio()`(数据面);奖励节点覆盖层场景(呈现面) | `curio_refresh_paid_test.gd:_init`;`reward_overlay_test.gd:_run` | `20c13c3a` | — |
| GP 钱包/escrow/商店收口/共享池 | 地图战斗资源×商店 | `LevelRunner.buy_product()`/`player_request_refresh()`/`close_wallet()`/`set_shop_pool()` | `level_shop_economy_test.gd:_smoke_gp_wallet`;`level_shop_economy_test.gd:_smoke_shop_room`;`level_shop_economy_test.gd:_smoke_shop_pool` | `20c13c3a` | — |
| 元进度入账与锻造两轴 | 元进度×锻造工坊 | `SaveManagerCore.add_keystone()`/`spend_keystone()`/`set_forge_route_level()` | `meta_progression_forge_test.gd:_meta_pricing_and_buy`;`meta_progression_forge_test.gd:_smoke_forge_axes` | `20c13c3a` | — |
| 天赋树购买与六键合成 | 天赋树 | `SaveManagerCore.tree_nodes()`/`set_tree_level()` | `meta_progression_forge_test.gd:_smoke_tree`;`meta_progression_forge_test.gd:_smoke_tree_rules`;`tree_rules_v11_test.gd:_init` | `20c13c3a` | — |
| 秘宝结构冻结与 12 件效果 | 秘宝 | `TreasureItems.add_item()`/`query_inventory()`/`validate_use()` | `treasure_items_test.gd:_init`;`treasure_effects_test.gd:_init` | `20c13c3a` | — |
| 能力 | 系统 | 真实入口 | 代表用例(文件:函数) |
|---|---|---|---|
| 清图奖励双份与零路径 | 地图战斗资源 | `BattleOrchestrator.begin_battle()` → 步骤流行(`source_class=clear_reward`) | `seal_polarity_test.gd:_smoke_clear_reward_chain`;`seal_polarity_test.gd:_smoke_clear_reward_zero_paths` |
| 奖励三选一候选/刷新付费/呈现 | 奇物×节点奖励屏 | `AdventureRunner.present_node_curio()`(数据面);奖励节点覆盖层场景(呈现面) | `curio_refresh_paid_test.gd:_init`;`reward_overlay_test.gd:_run` |
| GP 钱包/escrow/商店收口/共享池 | 地图战斗资源×商店 | `LevelRunner.shop.buy_product()`/`shop.player_request_refresh()`/`LevelRunner.close_wallet()`/`shop.set_shop_pool()` | `level_shop_economy_test.gd:_smoke_gp_wallet`;`level_shop_economy_test.gd:_smoke_shop_room`;`level_shop_economy_test.gd:_smoke_shop_pool` |
| 元进度入账与锻造两轴 | 元进度×锻造工坊 | `MetaStateStore.apply_adventure_summary()`/`MetaStateStore.spend_keystone()`/`MetaStateStore.set_forge_route_level()` | `meta_progression_forge_test.gd:_meta_pricing_and_buy`;`meta_progression_forge_test.gd:_smoke_forge_axes` |
| 天赋树购买与六键合成 | 天赋树 | `MetaProgression.tree_buy()`/`MetaStateStore.tree_state()`/`MetaStateStore.set_tree_level()` | `meta_progression_forge_test.gd:_smoke_tree`;`meta_progression_forge_test.gd:_smoke_tree_rules`;`tree_rules_v11_test.gd:_init` |
| 秘宝结构冻结与 12 件效果 | 秘宝 | `TreasureItems.add_item()`/`query_inventory()`/`validate_use()` | `treasure_items_test.gd:_init`;`treasure_effects_test.gd:_init` |
**跨域条件闸**
**旅程段五:排雷循环**
| 能力 | 系统 | 真实入口 | 代表用例 | 最后验证批次 | 缺口 |
|---|---|---|---|---|---|
| 回放确定性(同种子三变体逐位) | 全玩法链 | `tools/parity_anchor.py`(闸 11 条件闸,按批发起) | `tools/parity_anchor.py`(整件为条件闸) | —(条件闸) | 条件闸未随本批执行 |
| 能力 | 系统 | 真实入口 | 代表用例(文件:函数) |
|---|---|---|---|
| 棋盘按参数行出图、数字恒真 | 棋盘生成 | `BoardGenerator.generate()` | `board_generator_test.gd:_test_generate_shape_and_mines`;`board_generator_test.gd:_test_digits_equal_neighbor_mine_count` |
| 同参数同种子逐位复现、异种子不退化 | 棋盘生成 | `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` |
| 装板与开局免费展开(封锁格无资源、计入清图) | 排雷玩法 | `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` |
| 封印不可逆与挖开封印格放行(兑付改判四情况) | 排雷玩法 | `MinesweeperRules.settle_batch()` | `seal_polarity_test.gd:_smoke_seal_irreversible_quadrants`;`minesweeper_rules_test.gd:_test_seal_place` |
| 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` |
| 下轮行动点修正排队与兑现 | 行动经济 | `ActionEconomy.pending_ap_delta()`(排队经 `ActionEconomy.queue_ap_delta()`,写入方为效果引擎) | `seal_polarity_test.gd:_smoke_negative_dictionary`;`feat_vouchers_test.gd:_init` |
**旅程段六:表现与支撑**
| 能力 | 系统 | 真实入口 | 代表用例(文件:函数) |
|---|---|---|---|
| 拒绝反馈分面可辨与未知兜底文案 | HUD框架 | `HudPresenter.outcome_text()` | `hud_presenter_test.gd:_test_reject_text_by_reason`;`hud_presenter_test.gd:_test_unknown_reason_fallback`;`hud_presenter_test.gd:_test_accepted_text` |
| 结算明细带逐行呈现与排播节奏 | HUD框架 | `BattleLogView.append_row()`/`RowPacer.pace_delay_for()` | `theme_projection_test.gd:_smoke_battle_log_view`;`player_copy_sweep_test.gd:_sweep_source_names`;`pacing_queue_test.gd:_init` |
| 模态覆盖层编排与输入锁 | HUD框架 | `ModalFlow.locks_input()`/`ModalFlow.open_after_playback()` | `modal_flow_test.gd:_init`;`reward_overlay_test.gd:_run` |
| 未开格类型微光(8 邻作用集/五组色相/零玩法写入) | HUD框架 | `BoardView.type_glow_probe()`/`UiKit.glow_group_for_cell_type()` | `theme_projection_test.gd:_smoke_type_glow`;`type_glow_test.gd:_test_grouping_closed`;`type_glow_test.gd:_test_frozen_hue_face` |
| 棋盘悬停反馈(三语义光标/目标格边框/路径预览点迹) | HUD框架 | `ui_input_probe` 合成鼠标事件→`BoardView._gui_input()`;读面 `BoardView.hover_probe()` | `ui_input_probe.gd:_ready`(case①到达②禁入③路径预览三语义) |
| UI 全局主题与按钮五态(含对比度锚) | HUD框架 | `UiKit.button()`/`UiKit.primary_button()` | `theme_projection_test.gd:_smoke_global_theme`;`theme_projection_test.gd:_smoke_button_five_states`;`theme_projection_test.gd:_smoke_contrast_inks` |
| 中文字体随包与字形覆盖 | HUD框架 | `UiKit.load_font()` | `ui_font_asset_test.gd:_init`;`theme_projection_test.gd:_smoke_global_theme` |
| 地形瓦片套与格面数字可读 | HUD框架 | `TilePalette.digit_ink_mode()`/`TilePalette.normalize_floor_luma()` | `terrain_tile_sets_test.gd:_test_set_completeness`;`terrain_tile_sets_test.gd:_test_hue_domains`;`terrain_tile_sets_test.gd:_test_digit_ink_modes` |
| 站桩敌人呈现与结算演出落点 | 战斗表现 | `BattleStageView.enemy_standee_center()`/`BattleEndOverlay.open_victory()` | `standee_fx_sweep_test.gd:_init`;`pacing_queue_test.gd:_init` |
| 调参测速批量模拟(逐帧步进与统计读数) | 调参测量 | `TuneSimController.run()`(调试浮窗批量模拟入口) | `tune_sim_batch_parity_test.gd:_init`(配对对拍套件,随测速循环批建) |
| 战斗叙述与终局文案(数值带入/胜负互异) | 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框架 | `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` |
**旅程段七:数据配置与跨系统契约**
| 能力 | 系统 | 真实入口 | 代表用例(文件:函数) |
|---|---|---|---|
| 全表装载、就绪态与表清单目录对账 | 数据配置 | `ConfigDB.load_tables()`/`ConfigDB.diagnostics_count()` | `config_db_test.gd:_test_manifest_dir_sync`;`rng_stream_boot_test.gd:_smoke_initialize` |
| 进度坐标查行:精确命中/向上取整/封顶/警告去重 | 数据配置 | `BoardGenTable.resolve_row()`/`ConfigDbResolver.resolve_enemy_rowset()` | `config_db_test.gd:_test_progress_resolution`;`config_db_resolver_test.gd:_test_band_hit`;`config_db_resolver_test.gd:_test_top_band_clamp` |
| 行集寻址、行序保序与难度乘数 clamp | 数据配置×难度曲线与Boss | `ConfigDbResolver.resolve_enemy_rowset()`/`ConfigDbResolver.resolve_difficulty_modifiers()` | `config_db_resolver_test.gd:_test_rowset_order_preserved`;`config_db_resolver_test.gd:_test_row_kind_routing`;`config_db_resolver_test.gd:_test_difficulty_clamp` |
| 运行期越域致命与进程非 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` |
| 表结构守卫:域校验/行序键/跨字段互锁/配额锚 | 数据配置×敌人系统×地形变异×冒险结构 | `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` |
| 难度修饰套乘:空表零行为/套乘生效/越域 clamp | 难度曲线与Boss | `UnitContainer.spawn()`/`ConfigDbResolver.resolve_difficulty_modifiers()` | `table_structure_guard_test.gd:_smoke_difficulty_table`;`config_db_resolver_test.gd:_test_difficulty_clamp` |
| 锻造表 schema 正反与几何价格梯 | 锻造工坊 | `ForgeTable.level_price()`/`ForgeTable.route_rows()` | `forge_table_test.gd:_test_production_rows`;`forge_table_test.gd:_test_price_ladder`;`forge_table_test.gd:_test_negative_cases` |
| 系统间契约词表与受理口径:五配方互异/掷点标签成员性/增益布尔受理 | 战斗结算×数据配置×增益状态 | `DamageController.open_ticket()`/`StatusContainer.apply_effect()` | `system_contracts_test.gd:_test_damage_controller_vocabularies`;`system_contracts_test.gd:_test_rng_tag_closure`;`system_contracts_test.gd:_test_status_boolean_acceptance` |
| 敌人技能池跨表链接校验 | 数据配置×敌人系统 | `ConfigDbCrossValidator.validate_skill_pool_links()` | `config_db_cross_validator_test.gd:_test_all_links_valid`;`config_db_cross_validator_test.gd:_test_dangling_skill_id`;`config_db_cross_validator_test.gd:_test_cast_side_mismatch` |
**覆盖域表**(`design/gdd/systems/` 逐篇对照——状态三档:已覆盖/部分覆盖/未覆盖;部分与未覆盖行的缺口指待办清单条目,覆盖面提升时同批改本表):
| 域 | 系统文档 | 能力行 | 状态 | 缺口 |
|---|---|---|---|---|
| 冒险循环 | 冒险结构.md | 冒险生命周期:开局受理/三关序列/败北线;断点片段往返与续玩幂等;起关/选路/断点重生成同图(集成) | 已覆盖 | — |
| 冒险循环 | 关卡节点图生成.md | 节点图生成合法性与同种子复现;节点图生长递增与无解 fail-fast | 已覆盖 | — |
| 冒险循环 | 关卡节点地图.md | 起关/选路/断点重生成同图(集成);信息迷雾类型可见性;关卡表消费侧校验与关卡推进 | 已覆盖 | — |
| 冒险循环 | 奇物.md | 专长(奇物)授予与凭证保底;奖励三选一候选/刷新付费/呈现 | 已覆盖 | — |
| 冒险循环 | 难度曲线与Boss.md | Boss 半血解锁技门控;行集寻址、行序保序与难度乘数 clamp;难度修饰套乘:空表零行为/套乘生效/越域 clamp | 部分覆盖 | 难度曲线整链与 Boss 出场门控无专项断言;见待办清单「能力清单覆盖缺口补齐」条 |
| 战斗循环 | 地图战斗资源.md | 清图奖励双份与零路径;GP 钱包/escrow/商店收口/共享池;封印与极性路由/不可逆 | 已覆盖 | — |
| 战斗循环 | 增益状态.md | 系统间契约词表与受理口径:五配方互异/掷点标签成员性/增益布尔受理;封印与极性路由/不可逆 | 部分覆盖 | 增益叠层/衰减/清除结算链无断言;见待办清单「能力清单覆盖缺口补齐」条 |
| 战斗循环 | 战斗结算.md | 伤害公式与掷点乘区;伤害单据编排与回放;轮内流与结算五段全序 | 已覆盖 | — |
| 战斗循环 | 战斗表现.md | 站桩敌人呈现与结算演出落点 | 部分覆盖 | 死亡灰化与减动效演出档仅探针与人工目检;见待办清单「能力清单覆盖缺口补齐」条 |
| 战斗循环 | 敌人系统.md | 技能池数据面与回放独立;Boss 半血解锁技门控;敌人技能池跨表链接校验 | 已覆盖 | — |
| 排雷循环 | 地形变异.md | 变异布置门控;表结构守卫:域校验/行序键/跨字段互锁/配额锚 | 已覆盖 | — |
| 排雷循环 | 排雷玩法.md | 装板与开局免费展开(封锁格无资源、计入清图);挖/封印合法性与可辨拒绝(拒绝零副作用);封印不可逆与挖开封印格放行(兑付改判四情况) | 已覆盖 | — |
| 排雷循环 | 棋盘生成.md | 棋盘按参数行出图、数字恒真;同参数同种子逐位复现、异种子不退化;可推理率与清图可达(合法性先于质量分)、重试有界、降级诚实 | 已覆盖 | — |
| 排雷循环 | 行动经济.md | AP 扣费、末点耗尽即收轮与战斗收束清零;停手转存储备与轮内刷新(上限/AP 不重置/刷新图零清图奖励);下轮行动点修正排队与兑现 | 已覆盖 | — |
| 表现与支撑 | HUD框架.md | 拒绝反馈分面可辨与未知兜底文案;结算明细带逐行呈现与排播节奏;模态覆盖层编排与输入锁;未开格类型微光(8 邻作用集/五组色相/零玩法写入);UI 全局主题与按钮五态(含对比度锚);中文字体随包与字形覆盖;地形瓦片套与格面数字可读;战斗叙述与终局文案(数值带入/胜负互异);玩家面文案与危险格格面字形 | 已覆盖 | — |
| 表现与支撑 | 存档序列化.md | 存档写盘⇄读回往返保真;三槽位隔离与激活失败回滚;槽位摘要窥视与坏槽三态;启动态无激活不写盘;旧档迁移链与断点续玩零跳号(集成);存档⇄RNG 快照往返保真(集成) | 已覆盖 | — |
| 表现与支撑 | 教学引导.md | — | 未覆盖 | 教学形态与首遇时机待设计;见待办清单「教学形态未定」条 |
| 表现与支撑 | 数据配置.md | 全表装载、就绪态与表清单目录对账;进度坐标查行:精确命中/向上取整/封顶/警告去重;运行期越域致命与进程非 0 退出;加载期违规表拒绝:跨表悬空/计数器前缀/真视窄域;表结构守卫:域校验/行序键/跨字段互锁/配额锚 | 已覆盖 | — |
| 表现与支撑 | 设置与本地化.md | — | 未覆盖 | 减动效开关本体仅系统测试与冒烟覆盖、无单元/集成断言,多语言切换面未建;见待办清单「能力清单覆盖缺口补齐」条 |
| 表现与支撑 | 音频.md | — | 未覆盖 | MVP 无音频(P1 后置,无断言面);见待办清单「能力清单覆盖缺口补齐」条 |
| 跨局循环 | 元进度.md | 元进度入账与锻造两轴 | 已覆盖 | — |
| 跨局循环 | 天赋树.md | 天赋树购买与六键合成 | 已覆盖 | — |
| 跨局循环 | 生涯.md | — | 未覆盖 | P6 后置未实装;见待办清单「「生涯」界面——冒险中数据回看的唯一承接处」条 |
| 跨局循环 | 秘宝.md | 秘宝结构冻结与 12 件效果;加载期违规表拒绝:跨表悬空/计数器前缀/真视窄域 | 已覆盖 | — |
| 跨局循环 | 锻造工坊.md | 锻造表 schema 正反与几何价格梯;元进度入账与锻造两轴 | 部分覆盖 | 价格梯仅长剑路线逐级验,GDD 无验收标准节(机检豁免在册);见待办清单「能力清单覆盖缺口补齐」条 |
## 断言计数双口径(2026-10-08 迭代 19 卡① T4 订正)
@@ -125,11 +192,10 @@ tests/
|---|---|---|---|
| `tools/run_smoke.py`(冒烟测试) | 这版能否启动、能否加载表、能否进主屏——零逻辑判定 | 退出码+脚本错误扫描 | 开机路径/表加载改动后的快速自检;收口由闸编排 |
| `tools/run_system_test.py`(系统测试) | 真实玩法路径的行为断言面(推理→战斗→结算→进度推进) | 退出码+脚本错误扫描 | 玩法链路改动的调试期确认 |
| `tests/run_all.gd`(单元与集成) | 公式/状态机/契约/跨系统闭环(64 套件 manifest) | 退出码+三硬闸(见下);每套件子进程带截止时间守护——超时先 taskkill /T 整树回收再判该套件 FAIL、批继续(默认 120s,环境变量 `RUN_ALL_SUITE_TIMEOUT_SEC` 可覆盖) | 新套件单跑调试;逻辑改动的最小单元复跑;开发期选跑——追加 `-- --only=<词[,词…]>` 只跑路径命中词的套件(零命中=用法错 exit 2;选跑态仅供开发期最窄确认,不产闸回执、不作验收凭据) |
| `tests/run_all.gd`(单元与集成) | 公式/状态机/契约/跨系统闭环(65 套件 manifest) | 退出码+三硬闸(见下);每套件子进程带截止时间守护——超时先 taskkill /T 整树回收再判该套件 FAIL、批继续(默认 120s,环境变量 `RUN_ALL_SUITE_TIMEOUT_SEC` 可覆盖);连续 3 个套件超时=红树整批挂死,第 3 个即中止整轮、汇总已见失败与超时清单后非 0 退出(阈值=可调常量,不连续的超时照旧逐个回收) | 新套件单跑调试;逻辑改动的最小单元复跑;开发期选跑——追加 `-- --only=<词[,词…]>` 只跑路径命中词的套件(零命中=用法错 exit 2;此形态仅供开发期最窄确认,不产闸回执、不作验收凭据);闸机关联档选跑——同一过滤机制加 `-- --only-source=gates`,由 `tools/run_all_gates.sh` 在 02 闸传入(回执 scope=related,是验收跑批本体) |
| `tools/probe_gate.sh`(场景探针,`--click`/`--full` 两模式) | UI 可达性、可见性、状态——真实实例化场景+真实输入路径 | 探针自检+退出码 | 新增 UI 区域的配套探针直跑与断言复核 |
| `tools/render_gate.sh`(渲染 golden) | 画面基线——截图与基线图逐像素容差比对 | golden 比对脚本(依赖 PIL) | 主题/素材/排版类改动;窗口化运行,需开显示器 |
| `tools/render_gate.sh`(渲染 golden) | 画面基线——截图与基线图逐像素容差比对 | golden 比对脚本(依赖 PIL)+退出码/取证双检/三段探针日志脚本错误扫描(`error_scan.py`) | 主题/素材/排版类改动;窗口化运行,需开显示器 |
| `game/tests/static_scan.sh`(S 域) | 项目纪律+第三方质量规则:RNG 单点/core 纯度/类型标注/文件头/注释禁词/旧符号残留;S13=gdstyle 质量规则(重复 load、循环内 await、循环内分配、不可达代码等真缺陷类;基线键=文件|规则|函数名(类/文件级=文件|规则,无数字条目带消息),数字漂移不假红,同键指标恶化超基线登记值即红) | 退出码(逐规则 FAIL 行) | 改产品码前后的快速自检;新增纪律先补扫描规则再修码 |
| `tools/parity_anchor.py`(回放对拍) | 同种子下三变体逐位确定性 | 工具脚本逐位比对 | 本批触及数值/存档/RNG/结算面时;须用户批准发起 |
| 测量件(`game/sim/`,逐件见下「游离脚本台账」) | 期望/分布读数——只给读数,不判对错 | 人工读 stdout 或配套工具脚本 | 调参与归因;MC 类一律用户发起(档位表见 `sim-data/README.md`「MC 采集档位表」) |
> 单件直跑是调试期最窄确认手段,**不构成验收**——验收只有 `tools/run_all_gates.sh` 一个入口(判定三硬闸见下「本地闸」节)。
@@ -153,10 +219,12 @@ godot --headless --path . res://probe/<probe>.tscn
# 挂死防护内建于 run_all.gd(引擎无死锁探测,超时靠外部判):每套件子进程带截止时间——
# 默认 120s,环境变量 RUN_ALL_SUITE_TIMEOUT_SEC 可覆盖;超时先 taskkill /T 整树回收
#(cmd wrapper 连引擎孙进程一起杀,不留孤儿),该套件判 FAIL、批继续——单套件挂死不拖死整闸
#(cmd wrapper 连引擎孙进程一起杀,不留孤儿),该套件判 FAIL、批继续——单套件挂死不拖死整闸;
# 连续 3 个套件超时=红树整批挂死,第 3 个即中止整轮(汇总已见失败与超时清单、退出码非 0),
# 不连续的超时照旧逐个回收;阈值是 run_all.gd 内可调常量
```
> 套件 manifest 现况:`_suites()` 登记 **64 条**(61 单元+3 集成,2026-10-28 实数;口径=manifest 条目数,
> 套件 manifest 现况:`_suites()` 登记 **65 条**(62 单元+3 集成,2026-10-29 实数;口径=manifest 条目数,
> 随套件增减浮动)——data_config(ConfigDB 加载/进度坐标 ceil 解析/fatal 退出码/统一随机流)、core(秘宝结构冻结/断点续玩/存档槽位/结算五段等)、battle_settlement(DamageMath 纯函数/DamageController 伤害单据五配方)、contracts(系统间接口契约断言)、presentation(节奏队列/奖励浮层/字体资产/地形瓦片集/模态编排等);集成 3 条存 `tests/integration/`。致命类独立进程 `expect=1`;负面套件 `negative=true` 只豁免错误扫描一闸。期望值一律由表读值推导(零玩法数值字面量)、随机只经 RngService 统一流。
**协议要点**(D2 冒烟协议):
@@ -191,7 +259,7 @@ godot --headless --path . res://probe/<probe>.tscn
| 脚本 | 定性 | 用途与触发方式 | 结果由谁判 |
|---|---|---|---|
| `adventure_monte_carlo.gd` | **在役**(`AGENTS.md` 在册入口) | 全冒险期望 MC;`tools/parity_anchor.py` 的比对载体 | 工具脚本逐位比对 |
| `adventure_monte_carlo.gd` | **在役**(`AGENTS.md` 在册入口) | 全冒险期望 MC | 人工读 stdout |
| `verifier_batch.gd` | **在役**(`AGENTS.md` 在册入口) | `tools/balance_verifier.py` 的采集端(数值验证) | 报告与原始数据落 `sim-data/` |
| `reward_expectation.gd` | **在役**(`AGENTS.md` 在册入口) | 奖励期望测量(非封锁格分布/资源类型频次) | 人工读 stdout |
| `monte_carlo.gd` | 在役 | 战斗期望 MC(胜轮数/承伤/清图/开格分布) | 人工读 stdout |
@@ -225,9 +293,9 @@ S12 效果引擎无状态化旧件零残留:扫描 game/ 全域 `.gd` 与 `gam
## 本地闸(唯一验收门禁)
本仓库无远端、无 CI——**验收只在本地发生**,跑 `tools/run_all_gates.sh` 是收口唯一入口,按本批改动域选档(`--code`/`--docs`/跨两域或改闸件本身=不带参数全量),
跑完写回执 `game/tests/.gates/receipt.json`(含 `domain` 字段),合回 master 由 worktree-guard 按 diff 文件性质推域校验回执(`game/` 内 `.md` 归文档域)。
闸清单与域划分的唯一定义处就是那个脚本,本文档不另列清单(清单散落多份文档正是历史漏跑闸的成因)。
本仓库无远端、无 CI——**验收只在本地发生**,跑 `tools/run_all_gates.sh` 是收口唯一入口,按本批改动域选档(`--code`/`--docs`/跨两域或改闸件本身=不带参数全量;代码域 02 按关联档选套件,回执 `scope` 字段记 full|related),
跑完写回执 `game/tests/.gates/receipt.json`(含 `domain` 与 `scope` 字段),合回 master 由 worktree-guard 按 diff 文件性质推域校验回执(`game/` 内 `.md` 归文档域)。
闸清单与域划分(含选闸算法与套件族映射表)的唯一定义处就是那个脚本,本文档不另列清单(清单散落多份文档正是历史漏跑闸的成因)。
**判定三硬闸**(各闸一律适用,缺一即判定有洞):
①**退出码为唯一权威判据**——日志里的 PASS 串只是日志,不作判据;
-166
View File
@@ -1,166 +0,0 @@
{
"variants": {
"base": {
"runsum": [
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":3,\"choices\":2,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":8,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71000\",\"1#71000\",\"1#71000\"],\"levels_cleared\":0,\"mine_dmg\":16,\"mine_hits\":4,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":5,\"route\":\"min\",\"seal_hit\":22,\"seal_hit_gain\":79,\"seal_miss\":3,\"seal_miss_penalty\":8,\"seal_placed\":25,\"seed\":71000,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":24,\"visited_count\":3,\"wallet_count\":4}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":3,\"choices\":2,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":10,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71001\",\"1#71001\",\"1#71001\"],\"levels_cleared\":0,\"mine_dmg\":0,\"mine_hits\":6,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":6,\"route\":\"min\",\"seal_hit\":21,\"seal_hit_gain\":-296,\"seal_miss\":7,\"seal_miss_penalty\":16,\"seal_placed\":31,\"seed\":71001,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":10,\"visited_count\":3,\"wallet_count\":4}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":2,\"choices\":1,\"cleared\":false,\"encounter_max_hp_seq\":[26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":5,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71002\",\"1#71002\"],\"levels_cleared\":0,\"mine_dmg\":16,\"mine_hits\":2,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":5,\"route\":\"min\",\"seal_hit\":17,\"seal_hit_gain\":391,\"seal_miss\":1,\"seal_miss_penalty\":8,\"seal_placed\":19,\"seed\":71002,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":21,\"visited_count\":2,\"wallet_count\":3}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":5,\"choices\":4,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":15,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71003\",\"1#71003\",\"1#71003\",\"1#71003\",\"1#71003\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":6,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":13,\"route\":\"min\",\"seal_hit\":28,\"seal_hit_gain\":317,\"seal_miss\":9,\"seal_miss_penalty\":24,\"seal_placed\":44,\"seed\":71003,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":23,\"visited_count\":5,\"wallet_count\":6}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":6,\"choices\":6,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,32],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":39,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71004\",\"1#71004\",\"1#71004\",\"1#71004\",\"1#71004\",\"1#71004\",\"1#71004\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":17,\"policy\":\"normal\",\"refreshes\":1,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":28,\"route\":\"min\",\"seal_hit\":70,\"seal_hit_gain\":23,\"seal_miss\":17,\"seal_miss_penalty\":8,\"seal_placed\":93,\"seed\":71004,\"shop_gp_seq\":[19],\"stopped_at\":1,\"taken\":47,\"visited_count\":7,\"wallet_count\":11}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":5,\"choices\":4,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":26,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71005\",\"1#71005\",\"1#71005\",\"1#71005\",\"1#71005\"],\"levels_cleared\":0,\"mine_dmg\":22,\"mine_hits\":8,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":15,\"route\":\"min\",\"seal_hit\":39,\"seal_hit_gain\":284,\"seal_miss\":11,\"seal_miss_penalty\":0,\"seal_placed\":56,\"seed\":71005,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":48,\"visited_count\":5,\"wallet_count\":6}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":5,\"choices\":4,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":17,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71006\",\"1#71006\",\"1#71006\",\"1#71006\",\"1#71006\"],\"levels_cleared\":0,\"mine_dmg\":6,\"mine_hits\":6,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":13,\"route\":\"min\",\"seal_hit\":39,\"seal_hit_gain\":291,\"seal_miss\":5,\"seal_miss_penalty\":6,\"seal_placed\":50,\"seed\":71006,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":23,\"visited_count\":5,\"wallet_count\":6}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":6,\"choices\":6,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,35],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":28,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71007\",\"1#71007\",\"1#71007\",\"1#71007\",\"1#71007\",\"1#71007\",\"1#71007\"],\"levels_cleared\":0,\"mine_dmg\":16,\"mine_hits\":8,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":24,\"route\":\"min\",\"seal_hit\":59,\"seal_hit_gain\":-70,\"seal_miss\":11,\"seal_miss_penalty\":12,\"seal_placed\":74,\"seed\":71007,\"shop_gp_seq\":[39],\"stopped_at\":1,\"taken\":44,\"visited_count\":7,\"wallet_count\":14}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":7,\"choices\":7,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,32,32,32],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":38,\"hp_pct\":0,\"keystone_total\":3,\"level_maps\":[\"1#71008\",\"1#71008\",\"1#71008\",\"1#71008\",\"1#71008\",\"1#71008\",\"1#71008\",\"2#71008\",\"2#71008\"],\"levels_cleared\":1,\"mine_dmg\":16,\"mine_hits\":18,\"policy\":\"normal\",\"refreshes\":1,\"relics\":[\"hard_hat\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"hard_hat\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":22,\"heal_gained\":6,\"hp_after\":11,\"hp_before\":5,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"hard_hat\",\"feat_name\":\"安全帽\",\"hp_after\":11,\"hp_before\":11,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":33,\"route\":\"min\",\"seal_hit\":83,\"seal_hit_gain\":483,\"seal_miss\":14,\"seal_miss_penalty\":8,\"seal_placed\":102,\"seed\":71008,\"shop_gp_seq\":[19],\"stopped_at\":2,\"taken\":54,\"visited_count\":9,\"wallet_count\":12}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":4,\"choices\":3,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":18,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71009\",\"1#71009\",\"1#71009\",\"1#71009\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":3,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":9,\"route\":\"min\",\"seal_hit\":30,\"seal_hit_gain\":-28,\"seal_miss\":4,\"seal_miss_penalty\":8,\"seal_placed\":35,\"seed\":71009,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":26,\"visited_count\":4,\"wallet_count\":5}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":9,\"choices\":8,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":60,\"hp_pct\":0,\"keystone_total\":3,\"level_maps\":[\"1#71010\",\"1#71010\",\"1#71010\",\"1#71010\",\"1#71010\",\"1#71010\",\"1#71010\",\"2#71010\",\"2#71010\",\"2#71010\"],\"levels_cleared\":1,\"mine_dmg\":24,\"mine_hits\":13,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[\"hard_hat\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"hard_hat\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"breaker_strike\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":13,\"heal_gained\":7,\"hp_after\":18,\"hp_before\":11,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"hard_hat\",\"feat_name\":\"安全帽\",\"hp_after\":18,\"hp_before\":18,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":47,\"route\":\"min\",\"seal_hit\":109,\"seal_hit_gain\":309,\"seal_miss\":14,\"seal_miss_penalty\":8,\"seal_placed\":129,\"seed\":71010,\"shop_gp_seq\":[27],\"stopped_at\":2,\"taken\":84,\"visited_count\":10,\"wallet_count\":16}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":5,\"choices\":4,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":18,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71011\",\"1#71011\",\"1#71011\",\"1#71011\",\"1#71011\"],\"levels_cleared\":0,\"mine_dmg\":0,\"mine_hits\":7,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":15,\"route\":\"min\",\"seal_hit\":47,\"seal_hit_gain\":-119,\"seal_miss\":9,\"seal_miss_penalty\":24,\"seal_placed\":61,\"seed\":71011,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":18,\"visited_count\":5,\"wallet_count\":6}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":4,\"choices\":3,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":15,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71012\",\"1#71012\",\"1#71012\",\"1#71012\"],\"levels_cleared\":0,\"mine_dmg\":0,\"mine_hits\":8,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":11,\"route\":\"min\",\"seal_hit\":34,\"seal_hit_gain\":89,\"seal_miss\":10,\"seal_miss_penalty\":14,\"seal_placed\":47,\"seed\":71012,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":15,\"visited_count\":4,\"wallet_count\":5}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":2,\"choices\":1,\"cleared\":false,\"encounter_max_hp_seq\":[26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":6,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71013\",\"1#71013\"],\"levels_cleared\":0,\"mine_dmg\":16,\"mine_hits\":4,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":3,\"route\":\"min\",\"seal_hit\":10,\"seal_hit_gain\":-21,\"seal_miss\":2,\"seal_miss_penalty\":8,\"seal_placed\":15,\"seed\":71013,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":22,\"visited_count\":2,\"wallet_count\":3}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":5,\"choices\":4,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":24,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71014\",\"1#71014\",\"1#71014\",\"1#71014\",\"1#71014\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":6,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":11,\"route\":\"min\",\"seal_hit\":32,\"seal_hit_gain\":-62,\"seal_miss\":2,\"seal_miss_penalty\":0,\"seal_placed\":40,\"seed\":71014,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":32,\"visited_count\":5,\"wallet_count\":6}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":5,\"choices\":6,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,32],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":24,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71015\",\"1#71015\",\"1#71015\",\"1#71015\",\"1#71015\",\"1#71015\",\"1#71015\"],\"levels_cleared\":0,\"mine_dmg\":16,\"mine_hits\":8,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":17,\"route\":\"min\",\"seal_hit\":51,\"seal_hit_gain\":8,\"seal_miss\":9,\"seal_miss_penalty\":14,\"seal_placed\":68,\"seed\":71015,\"shop_gp_seq\":[25],\"stopped_at\":1,\"taken\":40,\"visited_count\":7,\"wallet_count\":11}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":5,\"choices\":4,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":25,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71016\",\"1#71016\",\"1#71016\",\"1#71016\",\"1#71016\"],\"levels_cleared\":0,\"mine_dmg\":6,\"mine_hits\":4,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":14,\"route\":\"min\",\"seal_hit\":50,\"seal_hit_gain\":421,\"seal_miss\":6,\"seal_miss_penalty\":4,\"seal_placed\":61,\"seed\":71016,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":31,\"visited_count\":5,\"wallet_count\":6}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":1,\"choices\":0,\"cleared\":false,\"encounter_max_hp_seq\":[26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":1,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71017\"],\"levels_cleared\":0,\"mine_dmg\":16,\"mine_hits\":2,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":2,\"route\":\"min\",\"seal_hit\":7,\"seal_hit_gain\":7,\"seal_miss\":4,\"seal_miss_penalty\":16,\"seal_placed\":11,\"seed\":71017,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":17,\"visited_count\":1,\"wallet_count\":2}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":4,\"choices\":3,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":33,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71018\",\"1#71018\",\"1#71018\",\"1#71018\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":3,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":11,\"route\":\"min\",\"seal_hit\":40,\"seal_hit_gain\":416,\"seal_miss\":2,\"seal_miss_penalty\":-2,\"seal_placed\":45,\"seed\":71018,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":41,\"visited_count\":4,\"wallet_count\":5}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":2,\"choices\":1,\"cleared\":false,\"encounter_max_hp_seq\":[26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":7,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71019\",\"1#71019\"],\"levels_cleared\":0,\"mine_dmg\":0,\"mine_hits\":10,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":5,\"route\":\"min\",\"seal_hit\":11,\"seal_hit_gain\":-85,\"seal_miss\":10,\"seal_miss_penalty\":24,\"seal_placed\":22,\"seed\":71019,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":7,\"visited_count\":2,\"wallet_count\":3}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":20,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,41,41,41,41,41,41,41,41,44],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":154,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#71020\",\"1#71020\",\"1#71020\",\"1#71020\",\"1#71020\",\"1#71020\",\"1#71020\",\"2#71020\",\"2#71020\",\"2#71020\",\"2#71020\",\"2#71020\",\"2#71020\",\"2#71020\",\"2#71020\",\"2#71020\",\"2#71020\",\"3#71020\",\"3#71020\",\"3#71020\",\"3#71020\",\"3#71020\",\"3#71020\",\"3#71020\",\"3#71020\",\"3#71020\",\"3#71020\",\"3#71020\",\"3#71020\",\"3#71020\",\"3#71020\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":2,\"relics\":[\"pain_memory\",\"map_exchange\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"pain_memory\",\"kind\":\"relic\",\"tier\":\"rare\"},{\"feat_id\":\"executioner\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":20,\"heal_gained\":7,\"hp_after\":25,\"hp_before\":18,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"pain_memory\",\"feat_name\":\"疼痛记忆\",\"hp_after\":25,\"hp_before\":25,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"map_exchange\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":27,\"heal_gained\":6,\"hp_after\":41,\"hp_before\":35,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"map_exchange\",\"feat_name\":\"弃图兑换\",\"hp_after\":41,\"hp_before\":41,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":102,\"route\":\"min\",\"seal_hit\":345,\"seal_hit_gain\":1539,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":362,\"seed\":71020,\"shop_gp_seq\":[27,62,86],\"stopped_at\":0,\"taken\":154,\"visited_count\":31,\"wallet_count\":38}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":19,\"choices\":23,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,38,38,38,38,38,38,38,38,38],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":139,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#71021\",\"1#71021\",\"1#71021\",\"1#71021\",\"1#71021\",\"1#71021\",\"1#71021\",\"2#71021\",\"2#71021\",\"2#71021\",\"2#71021\",\"2#71021\",\"2#71021\",\"2#71021\",\"2#71021\",\"2#71021\",\"2#71021\",\"3#71021\",\"3#71021\",\"3#71021\",\"3#71021\",\"3#71021\",\"3#71021\",\"3#71021\",\"3#71021\",\"3#71021\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":2,\"relics\":[\"executioner\",\"seal_echo\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"executioner\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":16,\"heal_gained\":3,\"hp_after\":35,\"hp_before\":32,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"executioner\",\"feat_name\":\"处刑台\",\"hp_after\":35,\"hp_before\":35,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"seal_echo\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":16,\"heal_gained\":0,\"hp_after\":38,\"hp_before\":38,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"seal_echo\",\"feat_name\":\"封印回响\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":85,\"route\":\"min\",\"seal_hit\":282,\"seal_hit_gain\":1672,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":307,\"seed\":71021,\"shop_gp_seq\":[34,47],\"stopped_at\":3,\"taken\":139,\"visited_count\":26,\"wallet_count\":31}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":17,\"choices\":19,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,41,41,41,41,41,41],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":117,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#71022\",\"1#71022\",\"1#71022\",\"1#71022\",\"1#71022\",\"1#71022\",\"1#71022\",\"2#71022\",\"2#71022\",\"2#71022\",\"2#71022\",\"2#71022\",\"2#71022\",\"2#71022\",\"2#71022\",\"2#71022\",\"2#71022\",\"3#71022\",\"3#71022\",\"3#71022\",\"3#71022\",\"3#71022\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"breaker_strike\",\"trap_burst\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"breaker_strike\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":25,\"heal_gained\":3,\"hp_after\":35,\"hp_before\":32,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"breaker_strike\",\"feat_name\":\"破封一击\",\"hp_after\":35,\"hp_before\":35,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"trap_burst\",\"kind\":\"relic\",\"tier\":\"rare\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":23,\"heal_gained\":2,\"hp_after\":41,\"hp_before\":39,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"trap_burst\",\"feat_name\":\"陷阱爆发\",\"hp_after\":41,\"hp_before\":41,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}}],\"rounds\":78,\"route\":\"min\",\"seal_hit\":269,\"seal_hit_gain\":1054,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":288,\"seed\":71022,\"shop_gp_seq\":[39,61],\"stopped_at\":3,\"taken\":117,\"visited_count\":22,\"wallet_count\":30}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":16,\"choices\":19,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,35,35,35,35,35,35,38,38,38,38,38,38],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":131,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#71023\",\"1#71023\",\"1#71023\",\"1#71023\",\"1#71023\",\"1#71023\",\"1#71023\",\"2#71023\",\"2#71023\",\"2#71023\",\"2#71023\",\"2#71023\",\"2#71023\",\"2#71023\",\"2#71023\",\"2#71023\",\"2#71023\",\"3#71023\",\"3#71023\",\"3#71023\",\"3#71023\",\"3#71023\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"blood_honey\",\"skip_mining\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":10,\"heal_gained\":5,\"hp_after\":35,\"hp_before\":30,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"blood_honey\",\"feat_name\":\"血蜜\",\"hp_after\":35,\"hp_before\":35,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"skip_mining\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":16,\"heal_gained\":0,\"hp_after\":38,\"hp_before\":38,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"skip_mining\",\"feat_name\":\"跳格采掘\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":80,\"route\":\"min\",\"seal_hit\":255,\"seal_hit_gain\":650,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":274,\"seed\":71023,\"shop_gp_seq\":[26,37],\"stopped_at\":3,\"taken\":131,\"visited_count\":22,\"wallet_count\":26}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":19,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,32,32,32,32,32,32,38,38,38,38,38,38,38,38,44],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":142,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#71024\",\"1#71024\",\"1#71024\",\"1#71024\",\"1#71024\",\"1#71024\",\"1#71024\",\"2#71024\",\"2#71024\",\"2#71024\",\"2#71024\",\"2#71024\",\"2#71024\",\"2#71024\",\"2#71024\",\"2#71024\",\"2#71024\",\"3#71024\",\"3#71024\",\"3#71024\",\"3#71024\",\"3#71024\",\"3#71024\",\"3#71024\",\"3#71024\",\"3#71024\",\"3#71024\",\"3#71024\",\"3#71024\",\"3#71024\",\"3#71024\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":2,\"relics\":[\"chain_traps\",\"map_exchange\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"chain_traps\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":21,\"heal_gained\":1,\"hp_after\":32,\"hp_before\":31,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"chain_traps\",\"feat_name\":\"连环陷阱\",\"hp_after\":32,\"hp_before\":32,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"map_exchange\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"seal_echo\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":16,\"heal_gained\":5,\"hp_after\":38,\"hp_before\":33,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"map_exchange\",\"feat_name\":\"弃图兑换\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":102,\"route\":\"min\",\"seal_hit\":338,\"seal_hit_gain\":1807,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":354,\"seed\":71024,\"shop_gp_seq\":[16,68,68],\"stopped_at\":0,\"taken\":142,\"visited_count\":31,\"wallet_count\":35}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":19,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,41,41,41,41,41,41,41,47],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":139,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#71025\",\"1#71025\",\"1#71025\",\"1#71025\",\"1#71025\",\"1#71025\",\"1#71025\",\"2#71025\",\"2#71025\",\"2#71025\",\"2#71025\",\"2#71025\",\"2#71025\",\"2#71025\",\"2#71025\",\"2#71025\",\"2#71025\",\"3#71025\",\"3#71025\",\"3#71025\",\"3#71025\",\"3#71025\",\"3#71025\",\"3#71025\",\"3#71025\",\"3#71025\",\"3#71025\",\"3#71025\",\"3#71025\",\"3#71025\",\"3#71025\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":0,\"relics\":[\"market_close\",\"warning_beacon\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":16,\"heal_gained\":5,\"hp_after\":35,\"hp_before\":30,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"market_close\",\"feat_name\":\"收盘\",\"hp_after\":35,\"hp_before\":35,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":42,\"heal_gained\":8,\"hp_after\":25,\"hp_before\":17,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"warning_beacon\",\"feat_name\":\"示警烟火\",\"hp_after\":25,\"hp_before\":25,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":96,\"route\":\"min\",\"seal_hit\":329,\"seal_hit_gain\":1701,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":350,\"seed\":71025,\"shop_gp_seq\":[33,79,101],\"stopped_at\":0,\"taken\":139,\"visited_count\":31,\"wallet_count\":38}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":20,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,32,32,32,32,32,32,41,41,41,41,41,41,41,41,47],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":131,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#71026\",\"1#71026\",\"1#71026\",\"1#71026\",\"1#71026\",\"1#71026\",\"1#71026\",\"2#71026\",\"2#71026\",\"2#71026\",\"2#71026\",\"2#71026\",\"2#71026\",\"2#71026\",\"2#71026\",\"2#71026\",\"2#71026\",\"3#71026\",\"3#71026\",\"3#71026\",\"3#71026\",\"3#71026\",\"3#71026\",\"3#71026\",\"3#71026\",\"3#71026\",\"3#71026\",\"3#71026\",\"3#71026\",\"3#71026\",\"3#71026\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":0,\"relics\":[\"market_close\",\"execution_scholar\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":19,\"heal_gained\":4,\"hp_after\":32,\"hp_before\":28,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"market_close\",\"feat_name\":\"收盘\",\"hp_after\":32,\"hp_before\":32,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":19,\"heal_gained\":7,\"hp_after\":41,\"hp_before\":34,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"execution_scholar\",\"feat_name\":\"斩首学者\",\"hp_after\":41,\"hp_before\":41,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":92,\"route\":\"min\",\"seal_hit\":299,\"seal_hit_gain\":1397,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":323,\"seed\":71026,\"shop_gp_seq\":[22,72,114],\"stopped_at\":0,\"taken\":131,\"visited_count\":31,\"wallet_count\":39}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":16,\"choices\":18,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,32,32,32,32,32,32,38,38,38,38,38],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":119,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#71027\",\"1#71027\",\"1#71027\",\"1#71027\",\"1#71027\",\"1#71027\",\"1#71027\",\"2#71027\",\"2#71027\",\"2#71027\",\"2#71027\",\"2#71027\",\"2#71027\",\"2#71027\",\"2#71027\",\"2#71027\",\"2#71027\",\"3#71027\",\"3#71027\",\"3#71027\",\"3#71027\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"hard_hat\",\"fuse_wire\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"hard_hat\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"chain_traps\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":12,\"heal_gained\":6,\"hp_after\":20,\"hp_before\":14,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"hard_hat\",\"feat_name\":\"安全帽\",\"hp_after\":20,\"hp_before\":20,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"fuse_wire\",\"kind\":\"relic\",\"tier\":\"rare\"},{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"venom_edge\",\"kind\":\"relic\",\"tier\":\"rare\"}],\"gp\":15,\"heal_gained\":7,\"hp_after\":35,\"hp_before\":28,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"fuse_wire\",\"feat_name\":\"保险丝\",\"hp_after\":35,\"hp_before\":35,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}}],\"rounds\":75,\"route\":\"min\",\"seal_hit\":255,\"seal_hit_gain\":1770,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":272,\"seed\":71027,\"shop_gp_seq\":[20,50],\"stopped_at\":3,\"taken\":119,\"visited_count\":21,\"wallet_count\":27}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":5,\"choices\":4,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":38,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#71028\",\"1#71028\",\"1#71028\",\"1#71028\",\"1#71028\"],\"levels_cleared\":0,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":16,\"route\":\"min\",\"seal_hit\":60,\"seal_hit_gain\":-8,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":62,\"seed\":71028,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":38,\"visited_count\":5,\"wallet_count\":6}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":15,\"choices\":18,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,32,32,32,32,32,38,38,38,38,38],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":105,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#71029\",\"1#71029\",\"1#71029\",\"1#71029\",\"1#71029\",\"1#71029\",\"1#71029\",\"2#71029\",\"2#71029\",\"2#71029\",\"2#71029\",\"2#71029\",\"2#71029\",\"2#71029\",\"2#71029\",\"2#71029\",\"2#71029\",\"3#71029\",\"3#71029\",\"3#71029\",\"3#71029\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"last_drop\",\"twin_pick\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":24,\"heal_gained\":4,\"hp_after\":32,\"hp_before\":28,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"last_drop\",\"feat_name\":\"一滴不剩\",\"hp_after\":32,\"hp_before\":32,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":29,\"heal_gained\":7,\"hp_after\":37,\"hp_before\":30,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"twin_pick\",\"feat_name\":\"双管镐\",\"hp_after\":37,\"hp_before\":37,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":64,\"route\":\"min\",\"seal_hit\":244,\"seal_hit_gain\":1307,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":262,\"seed\":71029,\"shop_gp_seq\":[24,57],\"stopped_at\":3,\"taken\":105,\"visited_count\":21,\"wallet_count\":26}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":15,\"choices\":19,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,32,32,32,32,32,38,38,38,38,38],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":114,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#71030\",\"1#71030\",\"1#71030\",\"1#71030\",\"1#71030\",\"1#71030\",\"1#71030\",\"2#71030\",\"2#71030\",\"2#71030\",\"2#71030\",\"2#71030\",\"2#71030\",\"2#71030\",\"2#71030\",\"2#71030\",\"2#71030\",\"3#71030\",\"3#71030\",\"3#71030\",\"3#71030\",\"3#71030\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"market_close\",\"chain_traps\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":13,\"heal_gained\":2,\"hp_after\":32,\"hp_before\":30,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"market_close\",\"feat_name\":\"收盘\",\"hp_after\":32,\"hp_before\":32,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"chain_traps\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":42,\"heal_gained\":7,\"hp_after\":35,\"hp_before\":28,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"chain_traps\",\"feat_name\":\"连环陷阱\",\"hp_after\":35,\"hp_before\":35,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":71,\"route\":\"min\",\"seal_hit\":234,\"seal_hit_gain\":1765,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":255,\"seed\":71030,\"shop_gp_seq\":[23,54],\"stopped_at\":3,\"taken\":114,\"visited_count\":22,\"wallet_count\":26}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":19,\"choices\":23,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,32,32,32,32,32,32,38,38,38,38,38,38,38,38,38],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":142,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#71031\",\"1#71031\",\"1#71031\",\"1#71031\",\"1#71031\",\"1#71031\",\"1#71031\",\"2#71031\",\"2#71031\",\"2#71031\",\"2#71031\",\"2#71031\",\"2#71031\",\"2#71031\",\"2#71031\",\"2#71031\",\"2#71031\",\"3#71031\",\"3#71031\",\"3#71031\",\"3#71031\",\"3#71031\",\"3#71031\",\"3#71031\",\"3#71031\",\"3#71031\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":2,\"relics\":[\"chain_traps\",\"seal_echo\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"chain_traps\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":28,\"heal_gained\":6,\"hp_after\":31,\"hp_before\":25,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"chain_traps\",\"feat_name\":\"连环陷阱\",\"hp_after\":31,\"hp_before\":31,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"seal_echo\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"skip_mining\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":23,\"heal_gained\":7,\"hp_after\":37,\"hp_before\":30,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"seal_echo\",\"feat_name\":\"封印回响\",\"hp_after\":37,\"hp_before\":37,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":89,\"route\":\"min\",\"seal_hit\":303,\"seal_hit_gain\":1540,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":324,\"seed\":71031,\"shop_gp_seq\":[21,69],\"stopped_at\":3,\"taken\":142,\"visited_count\":26,\"wallet_count\":31}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":19,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,41,41,41,41,41,41,41,44],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":144,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#71032\",\"1#71032\",\"1#71032\",\"1#71032\",\"1#71032\",\"1#71032\",\"1#71032\",\"2#71032\",\"2#71032\",\"2#71032\",\"2#71032\",\"2#71032\",\"2#71032\",\"2#71032\",\"2#71032\",\"2#71032\",\"2#71032\",\"3#71032\",\"3#71032\",\"3#71032\",\"3#71032\",\"3#71032\",\"3#71032\",\"3#71032\",\"3#71032\",\"3#71032\",\"3#71032\",\"3#71032\",\"3#71032\",\"3#71032\",\"3#71032\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":3,\"relics\":[\"executioner\",\"market_close\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"executioner\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":19,\"heal_gained\":5,\"hp_after\":35,\"hp_before\":30,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"executioner\",\"feat_name\":\"处刑台\",\"hp_after\":35,\"hp_before\":35,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":16,\"heal_gained\":3,\"hp_after\":41,\"hp_before\":38,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"market_close\",\"feat_name\":\"收盘\",\"hp_after\":41,\"hp_before\":41,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":105,\"route\":\"min\",\"seal_hit\":330,\"seal_hit_gain\":1031,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":362,\"seed\":71032,\"shop_gp_seq\":[27,64,78],\"stopped_at\":0,\"taken\":144,\"visited_count\":31,\"wallet_count\":36}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":16,\"choices\":19,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,32,32,32,32,32,32,38,38,38,38,38,38],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":117,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#71033\",\"1#71033\",\"1#71033\",\"1#71033\",\"1#71033\",\"1#71033\",\"1#71033\",\"2#71033\",\"2#71033\",\"2#71033\",\"2#71033\",\"2#71033\",\"2#71033\",\"2#71033\",\"2#71033\",\"2#71033\",\"2#71033\",\"3#71033\",\"3#71033\",\"3#71033\",\"3#71033\",\"3#71033\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"map_exchange\",\"skip_mining\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"map_exchange\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":16,\"heal_gained\":5,\"hp_after\":32,\"hp_before\":27,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"map_exchange\",\"feat_name\":\"弃图兑换\",\"hp_after\":32,\"hp_before\":32,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"skip_mining\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"executioner\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":23,\"heal_gained\":5,\"hp_after\":38,\"hp_before\":33,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"skip_mining\",\"feat_name\":\"跳格采掘\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":78,\"route\":\"min\",\"seal_hit\":240,\"seal_hit_gain\":654,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":255,\"seed\":71033,\"shop_gp_seq\":[20,45],\"stopped_at\":3,\"taken\":117,\"visited_count\":22,\"wallet_count\":26}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":19,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,41,41,41,41,41,41,41,44],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":151,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#71034\",\"1#71034\",\"1#71034\",\"1#71034\",\"1#71034\",\"1#71034\",\"1#71034\",\"2#71034\",\"2#71034\",\"2#71034\",\"2#71034\",\"2#71034\",\"2#71034\",\"2#71034\",\"2#71034\",\"2#71034\",\"2#71034\",\"3#71034\",\"3#71034\",\"3#71034\",\"3#71034\",\"3#71034\",\"3#71034\",\"3#71034\",\"3#71034\",\"3#71034\",\"3#71034\",\"3#71034\",\"3#71034\",\"3#71034\",\"3#71034\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"executioner\",\"blood_insight\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"executioner\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":22,\"heal_gained\":7,\"hp_after\":30,\"hp_before\":23,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"executioner\",\"feat_name\":\"处刑台\",\"hp_after\":30,\"hp_before\":30,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":13,\"heal_gained\":5,\"hp_after\":41,\"hp_before\":36,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"blood_insight\",\"feat_name\":\"见血开窍\",\"hp_after\":41,\"hp_before\":41,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":106,\"route\":\"min\",\"seal_hit\":332,\"seal_hit_gain\":1732,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":351,\"seed\":71034,\"shop_gp_seq\":[29,74,76],\"stopped_at\":0,\"taken\":151,\"visited_count\":31,\"wallet_count\":37}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":19,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,41,41,41,41,41,41,41,47],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":144,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#71035\",\"1#71035\",\"1#71035\",\"1#71035\",\"1#71035\",\"1#71035\",\"1#71035\",\"2#71035\",\"2#71035\",\"2#71035\",\"2#71035\",\"2#71035\",\"2#71035\",\"2#71035\",\"2#71035\",\"2#71035\",\"2#71035\",\"3#71035\",\"3#71035\",\"3#71035\",\"3#71035\",\"3#71035\",\"3#71035\",\"3#71035\",\"3#71035\",\"3#71035\",\"3#71035\",\"3#71035\",\"3#71035\",\"3#71035\",\"3#71035\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"trap_instinct\",\"blast_accounting\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"trap_instinct\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":13,\"heal_gained\":4,\"hp_after\":35,\"hp_before\":31,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"trap_instinct\",\"feat_name\":\"陷阱本能\",\"hp_after\":35,\"hp_before\":35,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":33,\"heal_gained\":6,\"hp_after\":41,\"hp_before\":35,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"blast_accounting\",\"feat_name\":\"爆破会计\",\"hp_after\":41,\"hp_before\":41,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":96,\"route\":\"min\",\"seal_hit\":316,\"seal_hit_gain\":1841,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":340,\"seed\":71035,\"shop_gp_seq\":[32,58,100],\"stopped_at\":0,\"taken\":144,\"visited_count\":31,\"wallet_count\":38}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":19,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,32,32,32,32,32,32,38,38,38,38,38,38,38,44],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":148,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#71036\",\"1#71036\",\"1#71036\",\"1#71036\",\"1#71036\",\"1#71036\",\"1#71036\",\"2#71036\",\"2#71036\",\"2#71036\",\"2#71036\",\"2#71036\",\"2#71036\",\"2#71036\",\"2#71036\",\"2#71036\",\"2#71036\",\"3#71036\",\"3#71036\",\"3#71036\",\"3#71036\",\"3#71036\",\"3#71036\",\"3#71036\",\"3#71036\",\"3#71036\",\"3#71036\",\"3#71036\",\"3#71036\",\"3#71036\",\"3#71036\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"skip_mining\",\"frontier_miner\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"skip_mining\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":26,\"heal_gained\":6,\"hp_after\":23,\"hp_before\":17,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"skip_mining\",\"feat_name\":\"跳格采掘\",\"hp_after\":23,\"hp_before\":23,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":23,\"heal_gained\":7,\"hp_after\":38,\"hp_before\":31,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"frontier_miner\",\"feat_name\":\"边陲矿工\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":100,\"route\":\"min\",\"seal_hit\":331,\"seal_hit_gain\":1293,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":354,\"seed\":71036,\"shop_gp_seq\":[18,68,74],\"stopped_at\":0,\"taken\":148,\"visited_count\":31,\"wallet_count\":35}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":17,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,29,29,29,29,29,35,35,35,35,35,35,35,41],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":155,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#71037\",\"1#71037\",\"1#71037\",\"1#71037\",\"1#71037\",\"1#71037\",\"1#71037\",\"2#71037\",\"2#71037\",\"2#71037\",\"2#71037\",\"2#71037\",\"2#71037\",\"2#71037\",\"2#71037\",\"2#71037\",\"2#71037\",\"3#71037\",\"3#71037\",\"3#71037\",\"3#71037\",\"3#71037\",\"3#71037\",\"3#71037\",\"3#71037\",\"3#71037\",\"3#71037\",\"3#71037\",\"3#71037\",\"3#71037\",\"3#71037\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":2,\"relics\":[\"breaker_strike\",\"field_dressing\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":3,\"candidates\":[{\"feat_id\":\"breaker_strike\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":15,\"heal_gained\":1,\"hp_after\":29,\"hp_before\":28,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"breaker_strike\",\"feat_name\":\"破封一击\",\"hp_after\":29,\"hp_before\":29,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":35,\"heal_gained\":7,\"hp_after\":35,\"hp_before\":28,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"field_dressing\",\"feat_name\":\"战地包扎\",\"hp_after\":35,\"hp_before\":35,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":95,\"route\":\"min\",\"seal_hit\":290,\"seal_hit_gain\":191,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":310,\"seed\":71037,\"shop_gp_seq\":[9,43,95],\"stopped_at\":0,\"taken\":155,\"visited_count\":31,\"wallet_count\":32}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":19,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,38,38,38,38,38,38,38,44],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":127,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#71038\",\"1#71038\",\"1#71038\",\"1#71038\",\"1#71038\",\"1#71038\",\"1#71038\",\"2#71038\",\"2#71038\",\"2#71038\",\"2#71038\",\"2#71038\",\"2#71038\",\"2#71038\",\"2#71038\",\"2#71038\",\"2#71038\",\"3#71038\",\"3#71038\",\"3#71038\",\"3#71038\",\"3#71038\",\"3#71038\",\"3#71038\",\"3#71038\",\"3#71038\",\"3#71038\",\"3#71038\",\"3#71038\",\"3#71038\",\"3#71038\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":0,\"relics\":[\"last_stand\",\"blast_accounting\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"last_stand\",\"kind\":\"relic\",\"tier\":\"rare\"},{\"feat_id\":\"executioner\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":19,\"heal_gained\":6,\"hp_after\":35,\"hp_before\":29,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"last_stand\",\"feat_name\":\"背水\",\"hp_after\":35,\"hp_before\":35,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":20,\"heal_gained\":6,\"hp_after\":38,\"hp_before\":32,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"blast_accounting\",\"feat_name\":\"爆破会计\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":97,\"route\":\"min\",\"seal_hit\":316,\"seal_hit_gain\":941,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":335,\"seed\":71038,\"shop_gp_seq\":[30,60,95],\"stopped_at\":0,\"taken\":127,\"visited_count\":31,\"wallet_count\":37}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":19,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,41,41,41,41,41,41,41,47],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":141,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#71039\",\"1#71039\",\"1#71039\",\"1#71039\",\"1#71039\",\"1#71039\",\"1#71039\",\"2#71039\",\"2#71039\",\"2#71039\",\"2#71039\",\"2#71039\",\"2#71039\",\"2#71039\",\"2#71039\",\"2#71039\",\"2#71039\",\"3#71039\",\"3#71039\",\"3#71039\",\"3#71039\",\"3#71039\",\"3#71039\",\"3#71039\",\"3#71039\",\"3#71039\",\"3#71039\",\"3#71039\",\"3#71039\",\"3#71039\",\"3#71039\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"skip_mining\",\"last_drop\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"skip_mining\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"map_exchange\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":16,\"heal_gained\":7,\"hp_after\":23,\"hp_before\":16,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"skip_mining\",\"feat_name\":\"跳格采掘\",\"hp_after\":23,\"hp_before\":23,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":34,\"heal_gained\":8,\"hp_after\":36,\"hp_before\":28,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"last_drop\",\"feat_name\":\"一滴不剩\",\"hp_after\":36,\"hp_before\":36,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":91,\"route\":\"min\",\"seal_hit\":316,\"seal_hit_gain\":955,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":332,\"seed\":71039,\"shop_gp_seq\":[39,76,84],\"stopped_at\":0,\"taken\":141,\"visited_count\":31,\"wallet_count\":38}"
],
"jsonl": {
"normal": {
"sha256": "19ee7ccdfb3780f5152b30f830c1168852c4fb4df73e2c27463a3a4695ef35ed",
"rows": 9216
},
"perfect": {
"sha256": "962b6f68440bcf95f2b21ac4cc07a8523655f044ae6355aa674d0db27bdecc1d",
"rows": 60774
}
}
},
"attune": {
"runsum": [
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":8,\"choices\":7,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":38,\"hp_pct\":0,\"keystone_total\":3,\"level_maps\":[\"1#72000\",\"1#72000\",\"1#72000\",\"1#72000\",\"1#72000\",\"1#72000\",\"1#72000\",\"2#72000\",\"2#72000\"],\"levels_cleared\":1,\"mine_dmg\":22,\"mine_hits\":11,\"policy\":\"normal\",\"refreshes\":1,\"relics\":[\"seal_stake\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":18,\"heal_gained\":7,\"hp_after\":14,\"hp_before\":7,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"seal_stake\",\"feat_name\":\"封印桩\",\"hp_after\":14,\"hp_before\":14,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":32,\"route\":\"min\",\"seal_hit\":91,\"seal_hit_gain\":738,\"seal_miss\":9,\"seal_miss_penalty\":-2,\"seal_placed\":108,\"seed\":72000,\"shop_gp_seq\":[29],\"stopped_at\":2,\"taken\":60,\"visited_count\":9,\"wallet_count\":15}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":5,\"choices\":6,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,32,32],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":39,\"hp_pct\":0,\"keystone_total\":3,\"level_maps\":[\"1#72001\",\"1#72001\",\"1#72001\",\"1#72001\",\"1#72001\",\"1#72001\",\"1#72001\",\"2#72001\"],\"levels_cleared\":1,\"mine_dmg\":14,\"mine_hits\":10,\"policy\":\"normal\",\"refreshes\":1,\"relics\":[\"skip_mining\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"skip_mining\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"stone_skin\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":27,\"heal_gained\":6,\"hp_after\":9,\"hp_before\":3,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"skip_mining\",\"feat_name\":\"跳格采掘\",\"hp_after\":9,\"hp_before\":9,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":23,\"route\":\"min\",\"seal_hit\":63,\"seal_hit_gain\":556,\"seal_miss\":9,\"seal_miss_penalty\":20,\"seal_placed\":78,\"seed\":72001,\"shop_gp_seq\":[17],\"stopped_at\":2,\"taken\":53,\"visited_count\":8,\"wallet_count\":10}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":3,\"choices\":3,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":9,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#72002\",\"1#72002\",\"1#72002\",\"1#72002\"],\"levels_cleared\":0,\"mine_dmg\":16,\"mine_hits\":4,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":5,\"route\":\"min\",\"seal_hit\":11,\"seal_hit_gain\":-127,\"seal_miss\":5,\"seal_miss_penalty\":8,\"seal_placed\":23,\"seed\":72002,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":25,\"visited_count\":4,\"wallet_count\":4}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":5,\"choices\":4,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":28,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#72003\",\"1#72003\",\"1#72003\",\"1#72003\",\"1#72003\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":7,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":16,\"route\":\"min\",\"seal_hit\":60,\"seal_hit_gain\":234,\"seal_miss\":6,\"seal_miss_penalty\":8,\"seal_placed\":70,\"seed\":72003,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":36,\"visited_count\":5,\"wallet_count\":6}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":4,\"choices\":3,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":13,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#72004\",\"1#72004\",\"1#72004\",\"1#72004\"],\"levels_cleared\":0,\"mine_dmg\":16,\"mine_hits\":9,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":8,\"route\":\"min\",\"seal_hit\":21,\"seal_hit_gain\":323,\"seal_miss\":5,\"seal_miss_penalty\":6,\"seal_placed\":28,\"seed\":72004,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":29,\"visited_count\":4,\"wallet_count\":5}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":4,\"choices\":3,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":21,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#72005\",\"1#72005\",\"1#72005\",\"1#72005\"],\"levels_cleared\":0,\"mine_dmg\":6,\"mine_hits\":7,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":12,\"route\":\"min\",\"seal_hit\":35,\"seal_hit_gain\":321,\"seal_miss\":3,\"seal_miss_penalty\":4,\"seal_placed\":42,\"seed\":72005,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":27,\"visited_count\":4,\"wallet_count\":5}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":5,\"choices\":4,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":17,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#72006\",\"1#72006\",\"1#72006\",\"1#72006\",\"1#72006\"],\"levels_cleared\":0,\"mine_dmg\":6,\"mine_hits\":8,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":16,\"route\":\"min\",\"seal_hit\":48,\"seal_hit_gain\":316,\"seal_miss\":7,\"seal_miss_penalty\":14,\"seal_placed\":68,\"seed\":72006,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":23,\"visited_count\":5,\"wallet_count\":6}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":3,\"choices\":2,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":10,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#72007\",\"1#72007\",\"1#72007\"],\"levels_cleared\":0,\"mine_dmg\":0,\"mine_hits\":2,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":7,\"route\":\"min\",\"seal_hit\":26,\"seal_hit_gain\":363,\"seal_miss\":3,\"seal_miss_penalty\":14,\"seal_placed\":34,\"seed\":72007,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":10,\"visited_count\":3,\"wallet_count\":4}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":3,\"choices\":2,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":8,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#72008\",\"1#72008\",\"1#72008\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":3,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":8,\"route\":\"min\",\"seal_hit\":27,\"seal_hit_gain\":-20,\"seal_miss\":3,\"seal_miss_penalty\":14,\"seal_placed\":34,\"seed\":72008,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":16,\"visited_count\":3,\"wallet_count\":4}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":5,\"choices\":4,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":35,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#72009\",\"1#72009\",\"1#72009\",\"1#72009\",\"1#72009\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":11,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":16,\"route\":\"min\",\"seal_hit\":51,\"seal_hit_gain\":281,\"seal_miss\":8,\"seal_miss_penalty\":0,\"seal_placed\":63,\"seed\":72009,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":43,\"visited_count\":5,\"wallet_count\":6}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":4,\"choices\":3,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":11,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#72010\",\"1#72010\",\"1#72010\",\"1#72010\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":4,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":8,\"route\":\"min\",\"seal_hit\":21,\"seal_hit_gain\":-53,\"seal_miss\":4,\"seal_miss_penalty\":8,\"seal_placed\":30,\"seed\":72010,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":19,\"visited_count\":4,\"wallet_count\":5}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":7,\"choices\":7,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,32,32,32],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":44,\"hp_pct\":0,\"keystone_total\":3,\"level_maps\":[\"1#72011\",\"1#72011\",\"1#72011\",\"1#72011\",\"1#72011\",\"1#72011\",\"1#72011\",\"2#72011\",\"2#72011\"],\"levels_cleared\":1,\"mine_dmg\":30,\"mine_hits\":16,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[\"map_exchange\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"map_exchange\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":21,\"heal_gained\":6,\"hp_after\":17,\"hp_before\":11,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"map_exchange\",\"feat_name\":\"弃图兑换\",\"hp_after\":17,\"hp_before\":17,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":34,\"route\":\"min\",\"seal_hit\":80,\"seal_hit_gain\":200,\"seal_miss\":15,\"seal_miss_penalty\":24,\"seal_placed\":101,\"seed\":72011,\"shop_gp_seq\":[16],\"stopped_at\":2,\"taken\":74,\"visited_count\":9,\"wallet_count\":12}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":3,\"choices\":2,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":5,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#72012\",\"1#72012\",\"1#72012\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":3,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":6,\"route\":\"min\",\"seal_hit\":18,\"seal_hit_gain\":107,\"seal_miss\":5,\"seal_miss_penalty\":14,\"seal_placed\":25,\"seed\":72012,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":13,\"visited_count\":3,\"wallet_count\":4}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":4,\"choices\":4,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":14,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#72013\",\"1#72013\",\"1#72013\",\"1#72013\",\"1#72013\"],\"levels_cleared\":0,\"mine_dmg\":14,\"mine_hits\":10,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":11,\"route\":\"min\",\"seal_hit\":38,\"seal_hit_gain\":289,\"seal_miss\":14,\"seal_miss_penalty\":16,\"seal_placed\":54,\"seed\":72013,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":28,\"visited_count\":5,\"wallet_count\":5}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":7,\"choices\":7,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,32,32,32],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":34,\"hp_pct\":0,\"keystone_total\":3,\"level_maps\":[\"1#72014\",\"1#72014\",\"1#72014\",\"1#72014\",\"1#72014\",\"1#72014\",\"1#72014\",\"2#72014\",\"2#72014\"],\"levels_cleared\":1,\"mine_dmg\":16,\"mine_hits\":7,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[\"seal_echo\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"seal_echo\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"trap_instinct\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":18,\"heal_gained\":6,\"hp_after\":22,\"hp_before\":16,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"seal_echo\",\"feat_name\":\"封印回响\",\"hp_after\":22,\"hp_before\":22,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":32,\"route\":\"min\",\"seal_hit\":85,\"seal_hit_gain\":373,\"seal_miss\":11,\"seal_miss_penalty\":12,\"seal_placed\":104,\"seed\":72014,\"shop_gp_seq\":[19],\"stopped_at\":2,\"taken\":50,\"visited_count\":9,\"wallet_count\":12}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":3,\"choices\":2,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":7,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#72015\",\"1#72015\",\"1#72015\"],\"levels_cleared\":0,\"mine_dmg\":16,\"mine_hits\":4,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":5,\"route\":\"min\",\"seal_hit\":22,\"seal_hit_gain\":243,\"seal_miss\":3,\"seal_miss_penalty\":8,\"seal_placed\":26,\"seed\":72015,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":23,\"visited_count\":3,\"wallet_count\":4}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":6,\"choices\":6,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,32,32],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":28,\"hp_pct\":0,\"keystone_total\":3,\"level_maps\":[\"1#72016\",\"1#72016\",\"1#72016\",\"1#72016\",\"1#72016\",\"1#72016\",\"1#72016\",\"2#72016\"],\"levels_cleared\":1,\"mine_dmg\":16,\"mine_hits\":11,\"policy\":\"normal\",\"refreshes\":1,\"relics\":[\"perfect_insurance\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"perfect_insurance\",\"kind\":\"relic\",\"tier\":\"rare\"},{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":29,\"heal_gained\":6,\"hp_after\":11,\"hp_before\":5,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"perfect_insurance\",\"feat_name\":\"完美保险\",\"hp_after\":11,\"hp_before\":11,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}}],\"rounds\":25,\"route\":\"min\",\"seal_hit\":78,\"seal_hit_gain\":740,\"seal_miss\":10,\"seal_miss_penalty\":24,\"seal_placed\":92,\"seed\":72016,\"shop_gp_seq\":[15],\"stopped_at\":2,\"taken\":44,\"visited_count\":8,\"wallet_count\":11}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":4,\"choices\":3,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":18,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#72017\",\"1#72017\",\"1#72017\",\"1#72017\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":9,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":9,\"route\":\"min\",\"seal_hit\":30,\"seal_hit_gain\":-413,\"seal_miss\":9,\"seal_miss_penalty\":8,\"seal_placed\":40,\"seed\":72017,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":26,\"visited_count\":4,\"wallet_count\":5}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":1,\"choices\":0,\"cleared\":false,\"encounter_max_hp_seq\":[26],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":2,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#72018\"],\"levels_cleared\":0,\"mine_dmg\":16,\"mine_hits\":2,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":1,\"route\":\"min\",\"seal_hit\":2,\"seal_hit_gain\":64,\"seal_miss\":3,\"seal_miss_penalty\":8,\"seal_placed\":7,\"seed\":72018,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":18,\"visited_count\":1,\"wallet_count\":2}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":3,\"choices\":3,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":9,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#72019\",\"1#72019\",\"1#72019\",\"1#72019\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":4,\"policy\":\"normal\",\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":7,\"route\":\"min\",\"seal_hit\":24,\"seal_hit_gain\":319,\"seal_miss\":5,\"seal_miss_penalty\":22,\"seal_placed\":33,\"seed\":72019,\"shop_gp_seq\":[],\"stopped_at\":1,\"taken\":17,\"visited_count\":4,\"wallet_count\":4}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":17,\"choices\":20,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,32,32,32,32,32,32,38,38,38,38,38,38],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":128,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#72020\",\"1#72020\",\"1#72020\",\"1#72020\",\"1#72020\",\"1#72020\",\"1#72020\",\"2#72020\",\"2#72020\",\"2#72020\",\"2#72020\",\"2#72020\",\"2#72020\",\"2#72020\",\"2#72020\",\"2#72020\",\"2#72020\",\"3#72020\",\"3#72020\",\"3#72020\",\"3#72020\",\"3#72020\",\"3#72020\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"geologist\",\"skip_mining\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":19,\"heal_gained\":6,\"hp_after\":32,\"hp_before\":26,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"geologist\",\"feat_name\":\"地质学家\",\"hp_after\":32,\"hp_before\":32,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"skip_mining\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":19,\"heal_gained\":1,\"hp_after\":38,\"hp_before\":37,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"skip_mining\",\"feat_name\":\"跳格采掘\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":79,\"route\":\"min\",\"seal_hit\":267,\"seal_hit_gain\":884,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":285,\"seed\":72020,\"shop_gp_seq\":[14,63],\"stopped_at\":3,\"taken\":128,\"visited_count\":23,\"wallet_count\":28}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":19,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,32,32,32,32,32,32,41,41,41,41,41,41,41,44],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":160,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#72021\",\"1#72021\",\"1#72021\",\"1#72021\",\"1#72021\",\"1#72021\",\"1#72021\",\"2#72021\",\"2#72021\",\"2#72021\",\"2#72021\",\"2#72021\",\"2#72021\",\"2#72021\",\"2#72021\",\"2#72021\",\"2#72021\",\"3#72021\",\"3#72021\",\"3#72021\",\"3#72021\",\"3#72021\",\"3#72021\",\"3#72021\",\"3#72021\",\"3#72021\",\"3#72021\",\"3#72021\",\"3#72021\",\"3#72021\",\"3#72021\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"breaker_strike\",\"map_exchange\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"breaker_strike\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"hard_hat\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":33,\"heal_gained\":6,\"hp_after\":27,\"hp_before\":21,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"breaker_strike\",\"feat_name\":\"破封一击\",\"hp_after\":27,\"hp_before\":27,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"map_exchange\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":21,\"heal_gained\":4,\"hp_after\":41,\"hp_before\":37,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"map_exchange\",\"feat_name\":\"弃图兑换\",\"hp_after\":41,\"hp_before\":41,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":97,\"route\":\"min\",\"seal_hit\":352,\"seal_hit_gain\":1330,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":373,\"seed\":72021,\"shop_gp_seq\":[22,77,90],\"stopped_at\":0,\"taken\":160,\"visited_count\":31,\"wallet_count\":37}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":17,\"choices\":19,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,32,32,32,32,32,32,38,38,38,38,38,38],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":124,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#72022\",\"1#72022\",\"1#72022\",\"1#72022\",\"1#72022\",\"1#72022\",\"1#72022\",\"2#72022\",\"2#72022\",\"2#72022\",\"2#72022\",\"2#72022\",\"2#72022\",\"2#72022\",\"2#72022\",\"2#72022\",\"2#72022\",\"3#72022\",\"3#72022\",\"3#72022\",\"3#72022\",\"3#72022\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":2,\"relics\":[\"hard_hat\",\"frontier_miner\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"hard_hat\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":26,\"heal_gained\":1,\"hp_after\":32,\"hp_before\":31,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"hard_hat\",\"feat_name\":\"安全帽\",\"hp_after\":32,\"hp_before\":32,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":29,\"heal_gained\":7,\"hp_after\":37,\"hp_before\":30,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"frontier_miner\",\"feat_name\":\"边陲矿工\",\"hp_after\":37,\"hp_before\":37,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":81,\"route\":\"min\",\"seal_hit\":300,\"seal_hit_gain\":1123,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":329,\"seed\":72022,\"shop_gp_seq\":[17,73],\"stopped_at\":3,\"taken\":124,\"visited_count\":22,\"wallet_count\":29}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":17,\"choices\":19,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,38,38,38,38,38,38],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":115,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#72023\",\"1#72023\",\"1#72023\",\"1#72023\",\"1#72023\",\"1#72023\",\"1#72023\",\"2#72023\",\"2#72023\",\"2#72023\",\"2#72023\",\"2#72023\",\"2#72023\",\"2#72023\",\"2#72023\",\"2#72023\",\"2#72023\",\"3#72023\",\"3#72023\",\"3#72023\",\"3#72023\",\"3#72023\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"blood_honey\",\"executioner\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":11,\"heal_gained\":5,\"hp_after\":35,\"hp_before\":30,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"blood_honey\",\"feat_name\":\"血蜜\",\"hp_after\":35,\"hp_before\":35,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"executioner\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":31,\"heal_gained\":4,\"hp_after\":38,\"hp_before\":34,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"executioner\",\"feat_name\":\"处刑台\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":75,\"route\":\"min\",\"seal_hit\":286,\"seal_hit_gain\":643,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":304,\"seed\":72023,\"shop_gp_seq\":[34,48],\"stopped_at\":3,\"taken\":115,\"visited_count\":22,\"wallet_count\":29}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":20,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,38,38,38,38,38,38,38,38,41],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":75,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#72024\",\"1#72024\",\"1#72024\",\"1#72024\",\"1#72024\",\"1#72024\",\"1#72024\",\"2#72024\",\"2#72024\",\"2#72024\",\"2#72024\",\"2#72024\",\"2#72024\",\"2#72024\",\"2#72024\",\"2#72024\",\"2#72024\",\"3#72024\",\"3#72024\",\"3#72024\",\"3#72024\",\"3#72024\",\"3#72024\",\"3#72024\",\"3#72024\",\"3#72024\",\"3#72024\",\"3#72024\",\"3#72024\",\"3#72024\",\"3#72024\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":0,\"relics\":[\"seal_burst\",\"perfect_insurance\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"seal_burst\",\"kind\":\"relic\",\"tier\":\"rare\"},{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":11,\"heal_gained\":7,\"hp_after\":32,\"hp_before\":25,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"seal_burst\",\"feat_name\":\"封印爆裂\",\"hp_after\":32,\"hp_before\":32,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"perfect_insurance\",\"kind\":\"relic\",\"tier\":\"rare\"},{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":20,\"heal_gained\":2,\"hp_after\":38,\"hp_before\":36,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"perfect_insurance\",\"feat_name\":\"完美保险\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}}],\"rounds\":55,\"route\":\"min\",\"seal_hit\":229,\"seal_hit_gain\":-27,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":256,\"seed\":72024,\"shop_gp_seq\":[34,42,59],\"stopped_at\":0,\"taken\":75,\"visited_count\":31,\"wallet_count\":35}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":23,\"choices\":26,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,32,32,32,32,32,32,38,38,38,38,38,38,38,38,38,38,38,47],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":150,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#72025\",\"1#72025\",\"1#72025\",\"1#72025\",\"1#72025\",\"1#72025\",\"1#72025\",\"2#72025\",\"2#72025\",\"2#72025\",\"2#72025\",\"2#72025\",\"2#72025\",\"2#72025\",\"2#72025\",\"2#72025\",\"2#72025\",\"3#72025\",\"3#72025\",\"3#72025\",\"3#72025\",\"3#72025\",\"3#72025\",\"3#72025\",\"3#72025\",\"3#72025\",\"3#72025\",\"3#72025\",\"3#72025\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":0,\"relics\":[\"field_dressing\",\"hard_hat\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":15,\"heal_gained\":6,\"hp_after\":29,\"hp_before\":23,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"field_dressing\",\"feat_name\":\"战地包扎\",\"hp_after\":29,\"hp_before\":29,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"hard_hat\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":27,\"heal_gained\":0,\"hp_after\":38,\"hp_before\":38,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"hard_hat\",\"feat_name\":\"安全帽\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":103,\"route\":\"min\",\"seal_hit\":408,\"seal_hit_gain\":2142,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":435,\"seed\":72025,\"shop_gp_seq\":[22,64,116],\"stopped_at\":0,\"taken\":150,\"visited_count\":29,\"wallet_count\":42}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":15,\"choices\":17,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,38,38,38,38],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":121,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#72026\",\"1#72026\",\"1#72026\",\"1#72026\",\"1#72026\",\"1#72026\",\"1#72026\",\"2#72026\",\"2#72026\",\"2#72026\",\"2#72026\",\"2#72026\",\"2#72026\",\"2#72026\",\"2#72026\",\"2#72026\",\"2#72026\",\"3#72026\",\"3#72026\",\"3#72026\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"frontier_miner\",\"perfect_insurance\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":15,\"heal_gained\":7,\"hp_after\":23,\"hp_before\":16,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"frontier_miner\",\"feat_name\":\"边陲矿工\",\"hp_after\":23,\"hp_before\":23,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"perfect_insurance\",\"kind\":\"relic\",\"tier\":\"rare\"},{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"trap_instinct\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":26,\"heal_gained\":3,\"hp_after\":38,\"hp_before\":35,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"perfect_insurance\",\"feat_name\":\"完美保险\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}}],\"rounds\":64,\"route\":\"min\",\"seal_hit\":227,\"seal_hit_gain\":370,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":245,\"seed\":72026,\"shop_gp_seq\":[35,51],\"stopped_at\":3,\"taken\":121,\"visited_count\":20,\"wallet_count\":27}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":18,\"choices\":21,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,32,32,32,32,32,32,38,38,38,38,38,38,38],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":125,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#72027\",\"1#72027\",\"1#72027\",\"1#72027\",\"1#72027\",\"1#72027\",\"1#72027\",\"2#72027\",\"2#72027\",\"2#72027\",\"2#72027\",\"2#72027\",\"2#72027\",\"2#72027\",\"2#72027\",\"2#72027\",\"2#72027\",\"3#72027\",\"3#72027\",\"3#72027\",\"3#72027\",\"3#72027\",\"3#72027\",\"3#72027\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":0,\"relics\":[\"geologist\",\"last_drop\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":20,\"heal_gained\":2,\"hp_after\":32,\"hp_before\":30,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"geologist\",\"feat_name\":\"地质学家\",\"hp_after\":32,\"hp_before\":32,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":24,\"heal_gained\":6,\"hp_after\":38,\"hp_before\":32,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"last_drop\",\"feat_name\":\"一滴不剩\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":78,\"route\":\"min\",\"seal_hit\":277,\"seal_hit_gain\":1113,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":301,\"seed\":72027,\"shop_gp_seq\":[23,55],\"stopped_at\":3,\"taken\":125,\"visited_count\":24,\"wallet_count\":29}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":15,\"choices\":17,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,38,38,38,38],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":102,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#72028\",\"1#72028\",\"1#72028\",\"1#72028\",\"1#72028\",\"1#72028\",\"1#72028\",\"2#72028\",\"2#72028\",\"2#72028\",\"2#72028\",\"2#72028\",\"2#72028\",\"2#72028\",\"2#72028\",\"2#72028\",\"2#72028\",\"3#72028\",\"3#72028\",\"3#72028\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":0,\"relics\":[\"executioner\",\"seal_echo\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"executioner\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":14,\"heal_gained\":7,\"hp_after\":28,\"hp_before\":21,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"executioner\",\"feat_name\":\"处刑台\",\"hp_after\":28,\"hp_before\":28,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"seal_echo\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"breaker_strike\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":27,\"heal_gained\":4,\"hp_after\":38,\"hp_before\":34,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"seal_echo\",\"feat_name\":\"封印回响\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":67,\"route\":\"min\",\"seal_hit\":244,\"seal_hit_gain\":1907,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":262,\"seed\":72028,\"shop_gp_seq\":[26,50],\"stopped_at\":3,\"taken\":102,\"visited_count\":20,\"wallet_count\":27}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":19,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,32,32,32,32,32,32,38,38,38,38,38,38,38,44],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":124,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#72029\",\"1#72029\",\"1#72029\",\"1#72029\",\"1#72029\",\"1#72029\",\"1#72029\",\"2#72029\",\"2#72029\",\"2#72029\",\"2#72029\",\"2#72029\",\"2#72029\",\"2#72029\",\"2#72029\",\"2#72029\",\"2#72029\",\"3#72029\",\"3#72029\",\"3#72029\",\"3#72029\",\"3#72029\",\"3#72029\",\"3#72029\",\"3#72029\",\"3#72029\",\"3#72029\",\"3#72029\",\"3#72029\",\"3#72029\",\"3#72029\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":0,\"relics\":[\"frontier_miner\",\"warning_beacon\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":22,\"heal_gained\":2,\"hp_after\":32,\"hp_before\":30,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"frontier_miner\",\"feat_name\":\"边陲矿工\",\"hp_after\":32,\"hp_before\":32,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":22,\"heal_gained\":7,\"hp_after\":37,\"hp_before\":30,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"warning_beacon\",\"feat_name\":\"示警烟火\",\"hp_after\":37,\"hp_before\":37,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":87,\"route\":\"min\",\"seal_hit\":345,\"seal_hit_gain\":1813,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":369,\"seed\":72029,\"shop_gp_seq\":[13,77,90],\"stopped_at\":0,\"taken\":124,\"visited_count\":31,\"wallet_count\":36}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":19,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,41,41,41,41,41,41,41,47],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":125,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#72030\",\"1#72030\",\"1#72030\",\"1#72030\",\"1#72030\",\"1#72030\",\"1#72030\",\"2#72030\",\"2#72030\",\"2#72030\",\"2#72030\",\"2#72030\",\"2#72030\",\"2#72030\",\"2#72030\",\"2#72030\",\"2#72030\",\"3#72030\",\"3#72030\",\"3#72030\",\"3#72030\",\"3#72030\",\"3#72030\",\"3#72030\",\"3#72030\",\"3#72030\",\"3#72030\",\"3#72030\",\"3#72030\",\"3#72030\",\"3#72030\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"executioner\",\"trap_instinct\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"executioner\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":16,\"heal_gained\":7,\"hp_after\":34,\"hp_before\":27,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"executioner\",\"feat_name\":\"处刑台\",\"hp_after\":34,\"hp_before\":34,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"trap_instinct\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":30,\"heal_gained\":2,\"hp_after\":41,\"hp_before\":39,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"trap_instinct\",\"feat_name\":\"陷阱本能\",\"hp_after\":41,\"hp_before\":41,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":92,\"route\":\"min\",\"seal_hit\":335,\"seal_hit_gain\":1855,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":358,\"seed\":72030,\"shop_gp_seq\":[32,90,103],\"stopped_at\":0,\"taken\":125,\"visited_count\":31,\"wallet_count\":39}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":16,\"choices\":18,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,32,32,32,32,32,32,38,38,38,38,38],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":121,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#72031\",\"1#72031\",\"1#72031\",\"1#72031\",\"1#72031\",\"1#72031\",\"1#72031\",\"2#72031\",\"2#72031\",\"2#72031\",\"2#72031\",\"2#72031\",\"2#72031\",\"2#72031\",\"2#72031\",\"2#72031\",\"2#72031\",\"3#72031\",\"3#72031\",\"3#72031\",\"3#72031\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":2,\"relics\":[\"hard_hat\",\"perfect_insurance\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"hard_hat\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":17,\"heal_gained\":1,\"hp_after\":32,\"hp_before\":31,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"hard_hat\",\"feat_name\":\"安全帽\",\"hp_after\":32,\"hp_before\":32,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"perfect_insurance\",\"kind\":\"relic\",\"tier\":\"rare\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":23,\"heal_gained\":7,\"hp_after\":35,\"hp_before\":28,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"perfect_insurance\",\"feat_name\":\"完美保险\",\"hp_after\":35,\"hp_before\":35,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}}],\"rounds\":72,\"route\":\"min\",\"seal_hit\":249,\"seal_hit_gain\":1056,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":273,\"seed\":72031,\"shop_gp_seq\":[20,50],\"stopped_at\":3,\"taken\":121,\"visited_count\":21,\"wallet_count\":27}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":19,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,32,32,32,32,32,32,38,38,38,38,38,38,38,44],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":176,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#72032\",\"1#72032\",\"1#72032\",\"1#72032\",\"1#72032\",\"1#72032\",\"1#72032\",\"2#72032\",\"2#72032\",\"2#72032\",\"2#72032\",\"2#72032\",\"2#72032\",\"2#72032\",\"2#72032\",\"2#72032\",\"2#72032\",\"3#72032\",\"3#72032\",\"3#72032\",\"3#72032\",\"3#72032\",\"3#72032\",\"3#72032\",\"3#72032\",\"3#72032\",\"3#72032\",\"3#72032\",\"3#72032\",\"3#72032\",\"3#72032\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":3,\"relics\":[\"seal_echo\",\"executioner\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"seal_echo\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":18,\"heal_gained\":6,\"hp_after\":22,\"hp_before\":16,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"seal_echo\",\"feat_name\":\"封印回响\",\"hp_after\":22,\"hp_before\":22,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"executioner\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":27,\"heal_gained\":5,\"hp_after\":38,\"hp_before\":33,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"executioner\",\"feat_name\":\"处刑台\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":104,\"route\":\"min\",\"seal_hit\":406,\"seal_hit_gain\":523,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":434,\"seed\":72032,\"shop_gp_seq\":[12,58,112],\"stopped_at\":0,\"taken\":176,\"visited_count\":31,\"wallet_count\":36}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":12,\"choices\":15,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,38],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":105,\"hp_pct\":0,\"keystone_total\":3,\"level_maps\":[\"1#72033\",\"1#72033\",\"1#72033\",\"1#72033\",\"1#72033\",\"1#72033\",\"1#72033\",\"2#72033\",\"2#72033\",\"2#72033\",\"2#72033\",\"2#72033\",\"2#72033\",\"2#72033\",\"2#72033\",\"2#72033\",\"2#72033\"],\"levels_cleared\":1,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":0,\"relics\":[\"geologist\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":13,\"heal_gained\":7,\"hp_after\":34,\"hp_before\":27,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"geologist\",\"feat_name\":\"地质学家\",\"hp_after\":34,\"hp_before\":34,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":51,\"route\":\"min\",\"seal_hit\":181,\"seal_hit_gain\":512,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":195,\"seed\":72033,\"shop_gp_seq\":[36,46],\"stopped_at\":2,\"taken\":105,\"visited_count\":17,\"wallet_count\":24}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":23,\"choices\":26,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,32,32,32,32,32,32,41,41,41,41,41,41,41,41,41,41,41,47],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":127,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#72034\",\"1#72034\",\"1#72034\",\"1#72034\",\"1#72034\",\"1#72034\",\"1#72034\",\"2#72034\",\"2#72034\",\"2#72034\",\"2#72034\",\"2#72034\",\"2#72034\",\"2#72034\",\"2#72034\",\"2#72034\",\"2#72034\",\"3#72034\",\"3#72034\",\"3#72034\",\"3#72034\",\"3#72034\",\"3#72034\",\"3#72034\",\"3#72034\",\"3#72034\",\"3#72034\",\"3#72034\",\"3#72034\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":0,\"relics\":[\"map_exchange\",\"seal_burst\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"map_exchange\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":11,\"heal_gained\":6,\"hp_after\":32,\"hp_before\":26,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"map_exchange\",\"feat_name\":\"弃图兑换\",\"hp_after\":32,\"hp_before\":32,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"chain_traps\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"seal_burst\",\"kind\":\"relic\",\"tier\":\"rare\"}],\"gp\":23,\"heal_gained\":7,\"hp_after\":41,\"hp_before\":34,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"seal_burst\",\"feat_name\":\"封印爆裂\",\"hp_after\":41,\"hp_before\":41,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}}],\"rounds\":80,\"route\":\"min\",\"seal_hit\":312,\"seal_hit_gain\":2332,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":350,\"seed\":72034,\"shop_gp_seq\":[25,72,101],\"stopped_at\":0,\"taken\":127,\"visited_count\":29,\"wallet_count\":42}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":17,\"choices\":19,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,41,41,41,41,41,41],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":125,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#72035\",\"1#72035\",\"1#72035\",\"1#72035\",\"1#72035\",\"1#72035\",\"1#72035\",\"2#72035\",\"2#72035\",\"2#72035\",\"2#72035\",\"2#72035\",\"2#72035\",\"2#72035\",\"2#72035\",\"2#72035\",\"2#72035\",\"3#72035\",\"3#72035\",\"3#72035\",\"3#72035\",\"3#72035\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"seal_echo\",\"perfect_insurance\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"seal_echo\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":12,\"heal_gained\":7,\"hp_after\":32,\"hp_before\":25,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"seal_echo\",\"feat_name\":\"封印回响\",\"hp_after\":32,\"hp_before\":32,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"perfect_insurance\",\"kind\":\"relic\",\"tier\":\"rare\"}],\"gp\":23,\"heal_gained\":1,\"hp_after\":41,\"hp_before\":40,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"perfect_insurance\",\"feat_name\":\"完美保险\",\"hp_after\":41,\"hp_before\":41,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}}],\"rounds\":73,\"route\":\"min\",\"seal_hit\":281,\"seal_hit_gain\":2343,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":308,\"seed\":72035,\"shop_gp_seq\":[28,71],\"stopped_at\":3,\"taken\":125,\"visited_count\":22,\"wallet_count\":30}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":19,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,38,38,38,38,38,38,38,38,44],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":137,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#72036\",\"1#72036\",\"1#72036\",\"1#72036\",\"1#72036\",\"1#72036\",\"1#72036\",\"2#72036\",\"2#72036\",\"2#72036\",\"2#72036\",\"2#72036\",\"2#72036\",\"2#72036\",\"2#72036\",\"2#72036\",\"2#72036\",\"3#72036\",\"3#72036\",\"3#72036\",\"3#72036\",\"3#72036\",\"3#72036\",\"3#72036\",\"3#72036\",\"3#72036\",\"3#72036\",\"3#72036\",\"3#72036\",\"3#72036\",\"3#72036\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"stone_skin\",\"executioner\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"stone_skin\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":19,\"heal_gained\":4,\"hp_after\":35,\"hp_before\":31,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"stone_skin\",\"feat_name\":\"石肤\",\"hp_after\":35,\"hp_before\":35,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"executioner\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":21,\"heal_gained\":7,\"hp_after\":36,\"hp_before\":29,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"executioner\",\"feat_name\":\"处刑台\",\"hp_after\":36,\"hp_before\":36,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":97,\"route\":\"min\",\"seal_hit\":358,\"seal_hit_gain\":948,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":385,\"seed\":72036,\"shop_gp_seq\":[38,48,70],\"stopped_at\":0,\"taken\":137,\"visited_count\":31,\"wallet_count\":35}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":23,\"choices\":26,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,32,32,32,32,32,32,38,38,38,38,38,38,38,38,38,38,38,47],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":108,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#72037\",\"1#72037\",\"1#72037\",\"1#72037\",\"1#72037\",\"1#72037\",\"1#72037\",\"2#72037\",\"2#72037\",\"2#72037\",\"2#72037\",\"2#72037\",\"2#72037\",\"2#72037\",\"2#72037\",\"2#72037\",\"2#72037\",\"3#72037\",\"3#72037\",\"3#72037\",\"3#72037\",\"3#72037\",\"3#72037\",\"3#72037\",\"3#72037\",\"3#72037\",\"3#72037\",\"3#72037\",\"3#72037\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"market_close\",\"blood_tax\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":6,\"candidates\":[{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":18,\"heal_gained\":6,\"hp_after\":22,\"hp_before\":16,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"market_close\",\"feat_name\":\"收盘\",\"hp_after\":22,\"hp_before\":22,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":12,\"candidates\":[{\"feat_id\":\"blood_tax\",\"kind\":\"relic\",\"tier\":\"rare\"},{\"feat_id\":\"skip_mining\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"map_exchange\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":17,\"heal_gained\":2,\"hp_after\":38,\"hp_before\":36,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"blood_tax\",\"feat_name\":\"血税\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}}],\"rounds\":86,\"route\":\"min\",\"seal_hit\":346,\"seal_hit_gain\":1916,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":387,\"seed\":72037,\"shop_gp_seq\":[17,70,125],\"stopped_at\":0,\"taken\":108,\"visited_count\":29,\"wallet_count\":42}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":20,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,41,41,41,41,41,41,41,41,47],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":159,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#72038\",\"1#72038\",\"1#72038\",\"1#72038\",\"1#72038\",\"1#72038\",\"1#72038\",\"2#72038\",\"2#72038\",\"2#72038\",\"2#72038\",\"2#72038\",\"2#72038\",\"2#72038\",\"2#72038\",\"2#72038\",\"2#72038\",\"3#72038\",\"3#72038\",\"3#72038\",\"3#72038\",\"3#72038\",\"3#72038\",\"3#72038\",\"3#72038\",\"3#72038\",\"3#72038\",\"3#72038\",\"3#72038\",\"3#72038\",\"3#72038\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"map_exchange\",\"skip_mining\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"map_exchange\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":10,\"heal_gained\":5,\"hp_after\":35,\"hp_before\":30,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"map_exchange\",\"feat_name\":\"弃图兑换\",\"hp_after\":35,\"hp_before\":35,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"skip_mining\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":22,\"heal_gained\":6,\"hp_after\":41,\"hp_before\":35,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"skip_mining\",\"feat_name\":\"跳格采掘\",\"hp_after\":41,\"hp_before\":41,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":97,\"route\":\"min\",\"seal_hit\":378,\"seal_hit_gain\":2246,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":401,\"seed\":72038,\"shop_gp_seq\":[32,55,100],\"stopped_at\":0,\"taken\":159,\"visited_count\":31,\"wallet_count\":39}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"on\",\"battles\":15,\"choices\":17,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,35,35,35,35,35,35,41,41,41,41],\"equipped\":[\"morning_order\",\"wide_scout_band\",\"trial_pick\"],\"feat_mode\":\"off\",\"hero_dmg\":100,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#72039\",\"1#72039\",\"1#72039\",\"1#72039\",\"1#72039\",\"1#72039\",\"1#72039\",\"2#72039\",\"2#72039\",\"2#72039\",\"2#72039\",\"2#72039\",\"2#72039\",\"2#72039\",\"2#72039\",\"2#72039\",\"2#72039\",\"3#72039\",\"3#72039\",\"3#72039\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"refreshes\":1,\"relics\":[\"geologist\",\"pain_memory\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":9,\"candidates\":[{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":20,\"heal_gained\":6,\"hp_after\":35,\"hp_before\":29,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"geologist\",\"feat_name\":\"地质学家\",\"hp_after\":35,\"hp_before\":35,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"stone_skin\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"pain_memory\",\"kind\":\"relic\",\"tier\":\"rare\"}],\"gp\":29,\"heal_gained\":6,\"hp_after\":41,\"hp_before\":35,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"pain_memory\",\"feat_name\":\"疼痛记忆\",\"hp_after\":41,\"hp_before\":41,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}}],\"rounds\":62,\"route\":\"min\",\"seal_hit\":224,\"seal_hit_gain\":711,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":244,\"seed\":72039,\"shop_gp_seq\":[32,63],\"stopped_at\":3,\"taken\":100,\"visited_count\":20,\"wallet_count\":28}"
],
"jsonl": {
"normal": {
"sha256": "b732bfeda9521de4896ebc11936670bd015032131bc871036896c1761ded12c8",
"rows": 9670
},
"perfect": {
"sha256": "06cb4dcc26c56343c61bc8d972238be81b88e3132d7e9b274399f4cfd04cb56e",
"rows": 62765
}
}
},
"shop": {
"runsum": [
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":3,\"choices\":2,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":9,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73000\",\"1#73000\",\"1#73000\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":4,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":5,\"route\":\"min\",\"seal_hit\":19,\"seal_hit_gain\":-30,\"seal_miss\":5,\"seal_miss_penalty\":8,\"seal_placed\":27,\"seed\":73000,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":17,\"visited_count\":3,\"wallet_count\":4}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":5,\"choices\":4,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":19,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73001\",\"1#73001\",\"1#73001\",\"1#73001\",\"1#73001\"],\"levels_cleared\":0,\"mine_dmg\":0,\"mine_hits\":6,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":15,\"route\":\"min\",\"seal_hit\":43,\"seal_hit_gain\":437,\"seal_miss\":8,\"seal_miss_penalty\":6,\"seal_placed\":56,\"seed\":73001,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":19,\"visited_count\":5,\"wallet_count\":6}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":5,\"choices\":4,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":15,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73002\",\"1#73002\",\"1#73002\",\"1#73002\",\"1#73002\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":6,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":9,\"route\":\"min\",\"seal_hit\":35,\"seal_hit_gain\":-120,\"seal_miss\":6,\"seal_miss_penalty\":8,\"seal_placed\":46,\"seed\":73002,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":23,\"visited_count\":5,\"wallet_count\":6}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":3,\"choices\":2,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":6,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73003\",\"1#73003\",\"1#73003\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":3,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":5,\"route\":\"min\",\"seal_hit\":16,\"seal_hit_gain\":-158,\"seal_miss\":4,\"seal_miss_penalty\":14,\"seal_placed\":22,\"seed\":73003,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":14,\"visited_count\":3,\"wallet_count\":4}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":4,\"choices\":3,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":13,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73004\",\"1#73004\",\"1#73004\",\"1#73004\"],\"levels_cleared\":0,\"mine_dmg\":16,\"mine_hits\":8,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":10,\"route\":\"min\",\"seal_hit\":30,\"seal_hit_gain\":-37,\"seal_miss\":8,\"seal_miss_penalty\":8,\"seal_placed\":47,\"seed\":73004,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":29,\"visited_count\":4,\"wallet_count\":5}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":5,\"choices\":4,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":20,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73005\",\"1#73005\",\"1#73005\",\"1#73005\",\"1#73005\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":5,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":14,\"route\":\"min\",\"seal_hit\":36,\"seal_hit_gain\":596,\"seal_miss\":3,\"seal_miss_penalty\":6,\"seal_placed\":43,\"seed\":73005,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":28,\"visited_count\":5,\"wallet_count\":6}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":6,\"choices\":6,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,41],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":19,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73006\",\"1#73006\",\"1#73006\",\"1#73006\",\"1#73006\",\"1#73006\",\"1#73006\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":12,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":19},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":21,\"route\":\"min\",\"seal_hit\":61,\"seal_hit_gain\":393,\"seal_miss\":14,\"seal_miss_penalty\":22,\"seal_placed\":81,\"seed\":73006,\"shop_buys\":3,\"shop_gp_seq\":[36],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":27,\"visited_count\":7,\"wallet_count\":10}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":3,\"choices\":2,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":9,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73007\",\"1#73007\",\"1#73007\"],\"levels_cleared\":0,\"mine_dmg\":0,\"mine_hits\":5,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":6,\"route\":\"min\",\"seal_hit\":20,\"seal_hit_gain\":-92,\"seal_miss\":5,\"seal_miss_penalty\":22,\"seal_placed\":25,\"seed\":73007,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":9,\"visited_count\":3,\"wallet_count\":4}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":5,\"choices\":6,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,31],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":25,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73008\",\"1#73008\",\"1#73008\",\"1#73008\",\"1#73008\",\"1#73008\",\"1#73008\"],\"levels_cleared\":0,\"mine_dmg\":16,\"mine_hits\":7,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":21,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":21},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":21,\"route\":\"min\",\"seal_hit\":63,\"seal_hit_gain\":398,\"seal_miss\":8,\"seal_miss_penalty\":14,\"seal_placed\":73,\"seed\":73008,\"shop_buys\":2,\"shop_gp_seq\":[23],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":41,\"visited_count\":7,\"wallet_count\":8}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":4,\"choices\":3,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":23,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73009\",\"1#73009\",\"1#73009\",\"1#73009\"],\"levels_cleared\":0,\"mine_dmg\":0,\"mine_hits\":2,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":11,\"route\":\"min\",\"seal_hit\":34,\"seal_hit_gain\":4,\"seal_miss\":3,\"seal_miss_penalty\":6,\"seal_placed\":40,\"seed\":73009,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":23,\"visited_count\":4,\"wallet_count\":5}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":3,\"choices\":2,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":11,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73010\",\"1#73010\",\"1#73010\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":7,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":10,\"route\":\"min\",\"seal_hit\":25,\"seal_hit_gain\":469,\"seal_miss\":6,\"seal_miss_penalty\":14,\"seal_placed\":37,\"seed\":73010,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":19,\"visited_count\":3,\"wallet_count\":4}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":7,\"choices\":7,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":39,\"hp_pct\":0,\"keystone_total\":3,\"level_maps\":[\"1#73011\",\"1#73011\",\"1#73011\",\"1#73011\",\"1#73011\",\"1#73011\",\"1#73011\",\"2#73011\",\"2#73011\"],\"levels_cleared\":1,\"mine_dmg\":8,\"mine_hits\":6,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":21,\"attack\":22,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[\"blood_honey\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":0,\"candidates\":[{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":17,\"heal_gained\":5,\"hp_after\":21,\"hp_before\":16,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"blood_honey\",\"feat_name\":\"血蜜\",\"hp_after\":21,\"hp_before\":21,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":28,\"route\":\"min\",\"seal_hit\":79,\"seal_hit_gain\":0,\"seal_miss\":6,\"seal_miss_penalty\":16,\"seal_placed\":89,\"seed\":73011,\"shop_buys\":2,\"shop_gp_seq\":[17],\"shop_mode\":\"pool\",\"stopped_at\":2,\"taken\":47,\"visited_count\":9,\"wallet_count\":10}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":5,\"choices\":6,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,31],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":23,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73012\",\"1#73012\",\"1#73012\",\"1#73012\",\"1#73012\",\"1#73012\",\"1#73012\"],\"levels_cleared\":0,\"mine_dmg\":16,\"mine_hits\":8,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":21},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":21,\"route\":\"min\",\"seal_hit\":57,\"seal_hit_gain\":-348,\"seal_miss\":10,\"seal_miss_penalty\":4,\"seal_placed\":70,\"seed\":73012,\"shop_buys\":1,\"shop_gp_seq\":[10],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":39,\"visited_count\":7,\"wallet_count\":7}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":1,\"choices\":0,\"cleared\":false,\"encounter_max_hp_seq\":[26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":4,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73013\"],\"levels_cleared\":0,\"mine_dmg\":14,\"mine_hits\":4,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":2,\"route\":\"min\",\"seal_hit\":7,\"seal_hit_gain\":114,\"seal_miss\":2,\"seal_miss_penalty\":14,\"seal_placed\":9,\"seed\":73013,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":18,\"visited_count\":1,\"wallet_count\":2}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":2,\"choices\":1,\"cleared\":false,\"encounter_max_hp_seq\":[26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":4,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73014\",\"1#73014\"],\"levels_cleared\":0,\"mine_dmg\":22,\"mine_hits\":4,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":3,\"route\":\"min\",\"seal_hit\":10,\"seal_hit_gain\":240,\"seal_miss\":3,\"seal_miss_penalty\":0,\"seal_placed\":15,\"seed\":73014,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":26,\"visited_count\":2,\"wallet_count\":3}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":4,\"choices\":3,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":19,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73015\",\"1#73015\",\"1#73015\",\"1#73015\"],\"levels_cleared\":0,\"mine_dmg\":8,\"mine_hits\":8,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":8,\"route\":\"min\",\"seal_hit\":24,\"seal_hit_gain\":127,\"seal_miss\":6,\"seal_miss_penalty\":12,\"seal_placed\":32,\"seed\":73015,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":27,\"visited_count\":4,\"wallet_count\":5}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":3,\"choices\":2,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":14,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73016\",\"1#73016\",\"1#73016\"],\"levels_cleared\":0,\"mine_dmg\":14,\"mine_hits\":5,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":10,\"route\":\"min\",\"seal_hit\":20,\"seal_hit_gain\":86,\"seal_miss\":4,\"seal_miss_penalty\":-2,\"seal_placed\":26,\"seed\":73016,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":28,\"visited_count\":3,\"wallet_count\":4}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":2,\"choices\":1,\"cleared\":false,\"encounter_max_hp_seq\":[26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":5,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73017\",\"1#73017\"],\"levels_cleared\":0,\"mine_dmg\":16,\"mine_hits\":3,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":4,\"route\":\"min\",\"seal_hit\":10,\"seal_hit_gain\":320,\"seal_miss\":2,\"seal_miss_penalty\":8,\"seal_placed\":14,\"seed\":73017,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":21,\"visited_count\":2,\"wallet_count\":3}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":4,\"choices\":3,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":13,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73018\",\"1#73018\",\"1#73018\",\"1#73018\"],\"levels_cleared\":0,\"mine_dmg\":0,\"mine_hits\":3,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":10,\"route\":\"min\",\"seal_hit\":24,\"seal_hit_gain\":509,\"seal_miss\":5,\"seal_miss_penalty\":20,\"seal_placed\":33,\"seed\":73018,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":13,\"visited_count\":4,\"wallet_count\":5}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":4,\"choices\":3,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":17,\"hp_pct\":0,\"keystone_total\":0,\"level_maps\":[\"1#73019\",\"1#73019\",\"1#73019\",\"1#73019\"],\"levels_cleared\":0,\"mine_dmg\":14,\"mine_hits\":2,\"policy\":\"normal\",\"pool_stock\":{\"ap\":3,\"armor\":22,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[],\"result\":\"failed\",\"reward_events\":[],\"rounds\":8,\"route\":\"min\",\"seal_hit\":26,\"seal_hit_gain\":387,\"seal_miss\":3,\"seal_miss_penalty\":6,\"seal_placed\":35,\"seed\":73019,\"shop_buys\":0,\"shop_gp_seq\":[],\"shop_mode\":\"pool\",\"stopped_at\":1,\"taken\":31,\"visited_count\":4,\"wallet_count\":5}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":17,\"choices\":19,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,26,26,26,26,26,26,36,36,36,36,36,36],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":131,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73020\",\"1#73020\",\"1#73020\",\"1#73020\",\"1#73020\",\"1#73020\",\"1#73020\",\"2#73020\",\"2#73020\",\"2#73020\",\"2#73020\",\"2#73020\",\"2#73020\",\"2#73020\",\"2#73020\",\"2#73020\",\"2#73020\",\"3#73020\",\"3#73020\",\"3#73020\",\"3#73020\",\"3#73020\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":20,\"attack\":20,\"feat_ticket\":0,\"heal\":3,\"max_hp\":20},\"refreshes\":0,\"relics\":[\"executioner\",\"field_dressing\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":0,\"candidates\":[{\"feat_id\":\"executioner\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"chain_traps\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":30,\"heal_gained\":5,\"hp_after\":21,\"hp_before\":16,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"executioner\",\"feat_name\":\"处刑台\",\"hp_after\":21,\"hp_before\":21,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":10,\"candidates\":[{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":19,\"heal_gained\":7,\"hp_after\":35,\"hp_before\":28,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"field_dressing\",\"feat_name\":\"战地包扎\",\"hp_after\":35,\"hp_before\":35,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":79,\"route\":\"min\",\"seal_hit\":263,\"seal_hit_gain\":1207,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":278,\"seed\":73020,\"shop_buys\":7,\"shop_gp_seq\":[43,60],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":131,\"visited_count\":22,\"wallet_count\":25}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":16,\"choices\":18,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,31,31,31,31,31,31,36,36,36,36,36],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":141,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73021\",\"1#73021\",\"1#73021\",\"1#73021\",\"1#73021\",\"1#73021\",\"1#73021\",\"2#73021\",\"2#73021\",\"2#73021\",\"2#73021\",\"2#73021\",\"2#73021\",\"2#73021\",\"2#73021\",\"2#73021\",\"2#73021\",\"3#73021\",\"3#73021\",\"3#73021\",\"3#73021\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":20,\"attack\":21,\"feat_ticket\":0,\"heal\":3,\"max_hp\":20},\"refreshes\":2,\"relics\":[\"skip_mining\",\"venom_edge\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":5,\"candidates\":[{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"skip_mining\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":24,\"heal_gained\":1,\"hp_after\":31,\"hp_before\":30,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"skip_mining\",\"feat_name\":\"跳格采掘\",\"hp_after\":31,\"hp_before\":31,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":10,\"candidates\":[{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"venom_edge\",\"kind\":\"relic\",\"tier\":\"rare\"}],\"gp\":40,\"heal_gained\":6,\"hp_after\":36,\"hp_before\":30,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"venom_edge\",\"feat_name\":\"淬毒刃纹\",\"hp_after\":36,\"hp_before\":36,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}}],\"rounds\":83,\"route\":\"min\",\"seal_hit\":291,\"seal_hit_gain\":2396,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":316,\"seed\":73021,\"shop_buys\":6,\"shop_gp_seq\":[22,79],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":141,\"visited_count\":21,\"wallet_count\":23}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":19,\"choices\":21,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,31,31,31,31,31,31,41,41,41,41,41,41,41,41],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":141,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73022\",\"1#73022\",\"1#73022\",\"1#73022\",\"1#73022\",\"1#73022\",\"1#73022\",\"2#73022\",\"2#73022\",\"2#73022\",\"2#73022\",\"2#73022\",\"2#73022\",\"2#73022\",\"2#73022\",\"2#73022\",\"2#73022\",\"3#73022\",\"3#73022\",\"3#73022\",\"3#73022\",\"3#73022\",\"3#73022\",\"3#73022\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":19,\"attack\":22,\"feat_ticket\":0,\"heal\":3,\"max_hp\":20},\"refreshes\":2,\"relics\":[\"breaker_strike\",\"trap_instinct\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":5,\"candidates\":[{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"breaker_strike\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":23,\"heal_gained\":6,\"hp_after\":23,\"hp_before\":17,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"breaker_strike\",\"feat_name\":\"破封一击\",\"hp_after\":23,\"hp_before\":23,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"trap_instinct\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":26,\"heal_gained\":8,\"hp_after\":39,\"hp_before\":31,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"trap_instinct\",\"feat_name\":\"陷阱本能\",\"hp_after\":39,\"hp_before\":39,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":101,\"route\":\"min\",\"seal_hit\":359,\"seal_hit_gain\":1765,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":374,\"seed\":73022,\"shop_buys\":6,\"shop_gp_seq\":[17,63],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":141,\"visited_count\":24,\"wallet_count\":26}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":19,\"choices\":21,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,26,26,26,26,26,26,36,36,36,36,36,36,36,36],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":152,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73023\",\"1#73023\",\"1#73023\",\"1#73023\",\"1#73023\",\"1#73023\",\"1#73023\",\"2#73023\",\"2#73023\",\"2#73023\",\"2#73023\",\"2#73023\",\"2#73023\",\"2#73023\",\"2#73023\",\"2#73023\",\"2#73023\",\"3#73023\",\"3#73023\",\"3#73023\",\"3#73023\",\"3#73023\",\"3#73023\",\"3#73023\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":20,\"attack\":19,\"feat_ticket\":0,\"heal\":3,\"max_hp\":21},\"refreshes\":0,\"relics\":[\"map_exchange\",\"perfect_insurance\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":0,\"candidates\":[{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"map_exchange\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":21,\"heal_gained\":5,\"hp_after\":21,\"hp_before\":16,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"map_exchange\",\"feat_name\":\"弃图兑换\",\"hp_after\":21,\"hp_before\":21,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":10,\"candidates\":[{\"feat_id\":\"seal_echo\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"perfect_insurance\",\"kind\":\"relic\",\"tier\":\"rare\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":29,\"heal_gained\":7,\"hp_after\":35,\"hp_before\":28,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"perfect_insurance\",\"feat_name\":\"完美保险\",\"hp_after\":35,\"hp_before\":35,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}}],\"rounds\":87,\"route\":\"min\",\"seal_hit\":285,\"seal_hit_gain\":1841,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":308,\"seed\":73023,\"shop_buys\":7,\"shop_gp_seq\":[30,71],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":152,\"visited_count\":24,\"wallet_count\":27}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":16,\"choices\":19,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,36,36,36,36,36,46,46,46,46,46,46],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":100,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73024\",\"1#73024\",\"1#73024\",\"1#73024\",\"1#73024\",\"1#73024\",\"1#73024\",\"2#73024\",\"2#73024\",\"2#73024\",\"2#73024\",\"2#73024\",\"2#73024\",\"2#73024\",\"2#73024\",\"2#73024\",\"2#73024\",\"3#73024\",\"3#73024\",\"3#73024\",\"3#73024\",\"3#73024\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":21,\"attack\":20,\"feat_ticket\":0,\"heal\":3,\"max_hp\":19},\"refreshes\":2,\"relics\":[\"blood_honey\",\"seal_burst\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":10,\"candidates\":[{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":9,\"heal_gained\":7,\"hp_after\":36,\"hp_before\":29,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"blood_honey\",\"feat_name\":\"血蜜\",\"hp_after\":36,\"hp_before\":36,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":20,\"candidates\":[{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"seal_burst\",\"kind\":\"relic\",\"tier\":\"rare\"}],\"gp\":11,\"heal_gained\":9,\"hp_after\":32,\"hp_before\":23,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"seal_burst\",\"feat_name\":\"封印爆裂\",\"hp_after\":32,\"hp_before\":32,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}}],\"rounds\":65,\"route\":\"min\",\"seal_hit\":218,\"seal_hit_gain\":416,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":241,\"seed\":73024,\"shop_buys\":7,\"shop_gp_seq\":[25,55],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":100,\"visited_count\":22,\"wallet_count\":24}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":19,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,36,36,36,36,36,36,41,41,41,41,41,41,41,51],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":157,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#73025\",\"1#73025\",\"1#73025\",\"1#73025\",\"1#73025\",\"1#73025\",\"1#73025\",\"2#73025\",\"2#73025\",\"2#73025\",\"2#73025\",\"2#73025\",\"2#73025\",\"2#73025\",\"2#73025\",\"2#73025\",\"2#73025\",\"3#73025\",\"3#73025\",\"3#73025\",\"3#73025\",\"3#73025\",\"3#73025\",\"3#73025\",\"3#73025\",\"3#73025\",\"3#73025\",\"3#73025\",\"3#73025\",\"3#73025\",\"3#73025\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":19,\"attack\":19,\"feat_ticket\":0,\"heal\":3,\"max_hp\":17},\"refreshes\":3,\"relics\":[\"last_stand\",\"seal_stake\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":10,\"candidates\":[{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"last_stand\",\"kind\":\"relic\",\"tier\":\"rare\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":26,\"heal_gained\":7,\"hp_after\":30,\"hp_before\":23,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"last_stand\",\"feat_name\":\"背水\",\"hp_after\":30,\"hp_before\":30,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":44,\"heal_gained\":8,\"hp_after\":38,\"hp_before\":30,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"seal_stake\",\"feat_name\":\"封印桩\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":118,\"route\":\"min\",\"seal_hit\":367,\"seal_hit_gain\":1643,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":385,\"seed\":73025,\"shop_buys\":12,\"shop_gp_seq\":[33,72,116],\"shop_mode\":\"pool\",\"stopped_at\":0,\"taken\":157,\"visited_count\":31,\"wallet_count\":32}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":15,\"choices\":17,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,36,36,36,36,36,36,36,36,36,36],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":140,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73026\",\"1#73026\",\"1#73026\",\"1#73026\",\"1#73026\",\"1#73026\",\"1#73026\",\"2#73026\",\"2#73026\",\"2#73026\",\"2#73026\",\"2#73026\",\"2#73026\",\"2#73026\",\"2#73026\",\"2#73026\",\"2#73026\",\"3#73026\",\"3#73026\",\"3#73026\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":19,\"attack\":21,\"feat_ticket\":0,\"heal\":3,\"max_hp\":20},\"refreshes\":1,\"relics\":[\"geologist\",\"seal_echo\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":10,\"candidates\":[{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":19,\"heal_gained\":7,\"hp_after\":31,\"hp_before\":24,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"geologist\",\"feat_name\":\"地质学家\",\"hp_after\":31,\"hp_before\":31,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":10,\"candidates\":[{\"feat_id\":\"seal_echo\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"trap_instinct\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":29,\"heal_gained\":7,\"hp_after\":23,\"hp_before\":16,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"seal_echo\",\"feat_name\":\"封印回响\",\"hp_after\":23,\"hp_before\":23,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":81,\"route\":\"min\",\"seal_hit\":267,\"seal_hit_gain\":1267,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":280,\"seed\":73026,\"shop_buys\":7,\"shop_gp_seq\":[29,72],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":140,\"visited_count\":20,\"wallet_count\":23}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":15,\"choices\":18,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,26,26,26,26,26,36,36,36,36,36],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":126,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73027\",\"1#73027\",\"1#73027\",\"1#73027\",\"1#73027\",\"1#73027\",\"1#73027\",\"2#73027\",\"2#73027\",\"2#73027\",\"2#73027\",\"2#73027\",\"2#73027\",\"2#73027\",\"2#73027\",\"2#73027\",\"2#73027\",\"3#73027\",\"3#73027\",\"3#73027\",\"3#73027\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":19,\"attack\":22,\"feat_ticket\":0,\"heal\":3,\"max_hp\":20},\"refreshes\":2,\"relics\":[\"last_drop\",\"executioner\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":0,\"candidates\":[{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":12,\"heal_gained\":1,\"hp_after\":26,\"hp_before\":25,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"last_drop\",\"feat_name\":\"一滴不剩\",\"hp_after\":26,\"hp_before\":26,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":10,\"candidates\":[{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"executioner\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":60,\"heal_gained\":7,\"hp_after\":33,\"hp_before\":26,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"executioner\",\"feat_name\":\"处刑台\",\"hp_after\":33,\"hp_before\":33,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":78,\"route\":\"min\",\"seal_hit\":276,\"seal_hit_gain\":954,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":289,\"seed\":73027,\"shop_buys\":6,\"shop_gp_seq\":[18,82],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":126,\"visited_count\":21,\"wallet_count\":22}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":15,\"choices\":17,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,31,31,31,31,31,31,31,31,31,31],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":127,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73028\",\"1#73028\",\"1#73028\",\"1#73028\",\"1#73028\",\"1#73028\",\"1#73028\",\"2#73028\",\"2#73028\",\"2#73028\",\"2#73028\",\"2#73028\",\"2#73028\",\"2#73028\",\"2#73028\",\"2#73028\",\"2#73028\",\"3#73028\",\"3#73028\",\"3#73028\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":18,\"attack\":21,\"feat_ticket\":0,\"heal\":3,\"max_hp\":21},\"refreshes\":0,\"relics\":[\"geologist\",\"market_close\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":5,\"candidates\":[{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":17,\"heal_gained\":5,\"hp_after\":31,\"hp_before\":26,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"geologist\",\"feat_name\":\"地质学家\",\"hp_after\":31,\"hp_before\":31,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":5,\"candidates\":[{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":30,\"heal_gained\":6,\"hp_after\":28,\"hp_before\":22,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"market_close\",\"feat_name\":\"收盘\",\"hp_after\":28,\"hp_before\":28,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":87,\"route\":\"min\",\"seal_hit\":225,\"seal_hit_gain\":1838,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":244,\"seed\":73028,\"shop_buys\":7,\"shop_gp_seq\":[27,67],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":127,\"visited_count\":20,\"wallet_count\":23}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":15,\"choices\":17,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,31,31,31,31,31,31,31,31,31,31],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":107,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73029\",\"1#73029\",\"1#73029\",\"1#73029\",\"1#73029\",\"1#73029\",\"1#73029\",\"2#73029\",\"2#73029\",\"2#73029\",\"2#73029\",\"2#73029\",\"2#73029\",\"2#73029\",\"2#73029\",\"2#73029\",\"2#73029\",\"3#73029\",\"3#73029\",\"3#73029\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":18,\"attack\":21,\"feat_ticket\":0,\"heal\":3,\"max_hp\":21},\"refreshes\":1,\"relics\":[\"breaker_strike\",\"stone_skin\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":5,\"candidates\":[{\"feat_id\":\"breaker_strike\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":28,\"heal_gained\":6,\"hp_after\":12,\"hp_before\":6,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"breaker_strike\",\"feat_name\":\"破封一击\",\"hp_after\":12,\"hp_before\":12,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":5,\"candidates\":[{\"feat_id\":\"stone_skin\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":16,\"heal_gained\":6,\"hp_after\":25,\"hp_before\":19,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"stone_skin\",\"feat_name\":\"石肤\",\"hp_after\":25,\"hp_before\":25,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":66,\"route\":\"min\",\"seal_hit\":233,\"seal_hit_gain\":1341,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":248,\"seed\":73029,\"shop_buys\":7,\"shop_gp_seq\":[40,58],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":107,\"visited_count\":20,\"wallet_count\":23}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":16,\"choices\":18,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,31,31,31,31,31,31,51,51,51,51,51],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":156,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73030\",\"1#73030\",\"1#73030\",\"1#73030\",\"1#73030\",\"1#73030\",\"1#73030\",\"2#73030\",\"2#73030\",\"2#73030\",\"2#73030\",\"2#73030\",\"2#73030\",\"2#73030\",\"2#73030\",\"2#73030\",\"2#73030\",\"3#73030\",\"3#73030\",\"3#73030\",\"3#73030\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":20,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":17},\"refreshes\":2,\"relics\":[\"blood_insight\",\"seal_smith\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":5,\"candidates\":[{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":37,\"heal_gained\":6,\"hp_after\":19,\"hp_before\":13,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"blood_insight\",\"feat_name\":\"见血开窍\",\"hp_after\":19,\"hp_before\":19,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":25,\"candidates\":[{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"seal_smith\",\"kind\":\"relic\",\"tier\":\"rare\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":57,\"heal_gained\":10,\"hp_after\":39,\"hp_before\":29,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"seal_smith\",\"feat_name\":\"封印匠\",\"hp_after\":39,\"hp_before\":39,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}}],\"rounds\":93,\"route\":\"min\",\"seal_hit\":300,\"seal_hit_gain\":1749,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":313,\"seed\":73030,\"shop_buys\":7,\"shop_gp_seq\":[38,89],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":156,\"visited_count\":21,\"wallet_count\":24}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":15,\"choices\":18,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,31,31,31,31,31,41,41,41,41,41],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":138,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73031\",\"1#73031\",\"1#73031\",\"1#73031\",\"1#73031\",\"1#73031\",\"1#73031\",\"2#73031\",\"2#73031\",\"2#73031\",\"2#73031\",\"2#73031\",\"2#73031\",\"2#73031\",\"2#73031\",\"2#73031\",\"2#73031\",\"3#73031\",\"3#73031\",\"3#73031\",\"3#73031\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":19,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":19},\"refreshes\":1,\"relics\":[\"perfect_insurance\",\"market_close\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":5,\"candidates\":[{\"feat_id\":\"perfect_insurance\",\"kind\":\"relic\",\"tier\":\"rare\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"executioner\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":31,\"heal_gained\":6,\"hp_after\":31,\"hp_before\":25,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"perfect_insurance\",\"feat_name\":\"完美保险\",\"hp_after\":31,\"hp_before\":31,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":38,\"heal_gained\":8,\"hp_after\":34,\"hp_before\":26,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"market_close\",\"feat_name\":\"收盘\",\"hp_after\":34,\"hp_before\":34,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":85,\"route\":\"min\",\"seal_hit\":281,\"seal_hit_gain\":635,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":295,\"seed\":73031,\"shop_buys\":6,\"shop_gp_seq\":[21,66],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":138,\"visited_count\":21,\"wallet_count\":22}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":17,\"choices\":19,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,31,31,31,31,31,31,36,36,36,36,36,36],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":124,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73032\",\"1#73032\",\"1#73032\",\"1#73032\",\"1#73032\",\"1#73032\",\"1#73032\",\"2#73032\",\"2#73032\",\"2#73032\",\"2#73032\",\"2#73032\",\"2#73032\",\"2#73032\",\"2#73032\",\"2#73032\",\"2#73032\",\"3#73032\",\"3#73032\",\"3#73032\",\"3#73032\",\"3#73032\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":19,\"attack\":21,\"feat_ticket\":0,\"heal\":3,\"max_hp\":20},\"refreshes\":0,\"relics\":[\"execution_scholar\",\"venom_edge\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":5,\"candidates\":[{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":21,\"heal_gained\":6,\"hp_after\":23,\"hp_before\":17,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"execution_scholar\",\"feat_name\":\"斩首学者\",\"hp_after\":23,\"hp_before\":23,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":10,\"candidates\":[{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"venom_edge\",\"kind\":\"relic\",\"tier\":\"rare\"}],\"gp\":49,\"heal_gained\":7,\"hp_after\":31,\"hp_before\":24,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"venom_edge\",\"feat_name\":\"淬毒刃纹\",\"hp_after\":31,\"hp_before\":31,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}}],\"rounds\":82,\"route\":\"min\",\"seal_hit\":284,\"seal_hit_gain\":931,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":309,\"seed\":73032,\"shop_buys\":7,\"shop_gp_seq\":[28,90],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":124,\"visited_count\":22,\"wallet_count\":25}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":19,\"choices\":23,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,41,41,41,41,41,41,41,41,41,41,41,41,41,41],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":164,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73033\",\"1#73033\",\"1#73033\",\"1#73033\",\"1#73033\",\"1#73033\",\"1#73033\",\"2#73033\",\"2#73033\",\"2#73033\",\"2#73033\",\"2#73033\",\"2#73033\",\"2#73033\",\"2#73033\",\"2#73033\",\"2#73033\",\"3#73033\",\"3#73033\",\"3#73033\",\"3#73033\",\"3#73033\",\"3#73033\",\"3#73033\",\"3#73033\",\"3#73033\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":18,\"attack\":22,\"feat_ticket\":0,\"heal\":3,\"max_hp\":20},\"refreshes\":1,\"relics\":[\"blood_insight\",\"last_drop\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":24,\"heal_gained\":8,\"hp_after\":28,\"hp_before\":20,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"blood_insight\",\"feat_name\":\"见血开窍\",\"hp_after\":28,\"hp_before\":28,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":30,\"heal_gained\":1,\"hp_after\":41,\"hp_before\":40,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"last_drop\",\"feat_name\":\"一滴不剩\",\"hp_after\":41,\"hp_before\":41,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":99,\"route\":\"min\",\"seal_hit\":336,\"seal_hit_gain\":1256,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":352,\"seed\":73033,\"shop_buys\":7,\"shop_gp_seq\":[35,66],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":164,\"visited_count\":26,\"wallet_count\":27}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":17,\"choices\":20,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,36,36,36,36,36,36,36,36,36,36,36,36],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":142,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73034\",\"1#73034\",\"1#73034\",\"1#73034\",\"1#73034\",\"1#73034\",\"1#73034\",\"2#73034\",\"2#73034\",\"2#73034\",\"2#73034\",\"2#73034\",\"2#73034\",\"2#73034\",\"2#73034\",\"2#73034\",\"2#73034\",\"3#73034\",\"3#73034\",\"3#73034\",\"3#73034\",\"3#73034\",\"3#73034\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":18,\"attack\":21,\"feat_ticket\":0,\"heal\":3,\"max_hp\":21},\"refreshes\":1,\"relics\":[\"last_drop\",\"field_dressing\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":10,\"candidates\":[{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":30,\"heal_gained\":7,\"hp_after\":31,\"hp_before\":24,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"last_drop\",\"feat_name\":\"一滴不剩\",\"hp_after\":31,\"hp_before\":31,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":10,\"candidates\":[{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_insight\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"market_close\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":38,\"heal_gained\":2,\"hp_after\":36,\"hp_before\":34,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"field_dressing\",\"feat_name\":\"战地包扎\",\"hp_after\":36,\"hp_before\":36,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":83,\"route\":\"min\",\"seal_hit\":286,\"seal_hit_gain\":1785,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":302,\"seed\":73034,\"shop_buys\":7,\"shop_gp_seq\":[38,75],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":142,\"visited_count\":23,\"wallet_count\":25}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":17,\"choices\":21,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,31,31,31,31,31,31,31,31,31,31,31,31],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":124,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73035\",\"1#73035\",\"1#73035\",\"1#73035\",\"1#73035\",\"1#73035\",\"1#73035\",\"2#73035\",\"2#73035\",\"2#73035\",\"2#73035\",\"2#73035\",\"2#73035\",\"2#73035\",\"2#73035\",\"2#73035\",\"2#73035\",\"3#73035\",\"3#73035\",\"3#73035\",\"3#73035\",\"3#73035\",\"3#73035\",\"3#73035\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":21,\"attack\":18,\"feat_ticket\":0,\"heal\":3,\"max_hp\":21},\"refreshes\":0,\"relics\":[\"hard_hat\",\"blast_accounting\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":5,\"candidates\":[{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"hard_hat\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"seal_stake\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":17,\"heal_gained\":6,\"hp_after\":20,\"hp_before\":14,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"hard_hat\",\"feat_name\":\"安全帽\",\"hp_after\":20,\"hp_before\":20,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":5,\"candidates\":[{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"geologist\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":17,\"heal_gained\":6,\"hp_after\":30,\"hp_before\":24,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"blast_accounting\",\"feat_name\":\"爆破会计\",\"hp_after\":30,\"hp_before\":30,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":80,\"route\":\"min\",\"seal_hit\":273,\"seal_hit_gain\":304,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":284,\"seed\":73035,\"shop_buys\":7,\"shop_gp_seq\":[34,56],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":124,\"visited_count\":24,\"wallet_count\":25}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":18,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,36,36,36,36,36,36,51,51,51,51,51,51,56],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":131,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#73036\",\"1#73036\",\"1#73036\",\"1#73036\",\"1#73036\",\"1#73036\",\"1#73036\",\"2#73036\",\"2#73036\",\"2#73036\",\"2#73036\",\"2#73036\",\"2#73036\",\"2#73036\",\"2#73036\",\"2#73036\",\"2#73036\",\"3#73036\",\"3#73036\",\"3#73036\",\"3#73036\",\"3#73036\",\"3#73036\",\"3#73036\",\"3#73036\",\"3#73036\",\"3#73036\",\"3#73036\",\"3#73036\",\"3#73036\",\"3#73036\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":19,\"attack\":19,\"feat_ticket\":0,\"heal\":3,\"max_hp\":17},\"refreshes\":0,\"relics\":[\"frontier_miner\",\"blood_honey\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":10,\"candidates\":[{\"feat_id\":\"frontier_miner\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":17,\"heal_gained\":7,\"hp_after\":35,\"hp_before\":28,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"frontier_miner\",\"feat_name\":\"边陲矿工\",\"hp_after\":35,\"hp_before\":35,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":25,\"candidates\":[{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"twin_pick\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":26,\"heal_gained\":10,\"hp_after\":38,\"hp_before\":28,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"blood_honey\",\"feat_name\":\"血蜜\",\"hp_after\":38,\"hp_before\":38,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":93,\"route\":\"min\",\"seal_hit\":302,\"seal_hit_gain\":720,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":328,\"seed\":73036,\"shop_buys\":12,\"shop_gp_seq\":[26,106,76],\"shop_mode\":\"pool\",\"stopped_at\":0,\"taken\":131,\"visited_count\":31,\"wallet_count\":31}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":16,\"choices\":18,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":108,\"hp_pct\":0,\"keystone_total\":6,\"level_maps\":[\"1#73037\",\"1#73037\",\"1#73037\",\"1#73037\",\"1#73037\",\"1#73037\",\"1#73037\",\"2#73037\",\"2#73037\",\"2#73037\",\"2#73037\",\"2#73037\",\"2#73037\",\"2#73037\",\"2#73037\",\"2#73037\",\"2#73037\",\"3#73037\",\"3#73037\",\"3#73037\",\"3#73037\"],\"levels_cleared\":2,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":17,\"attack\":21,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":1,\"relics\":[\"blood_honey\",\"stone_skin\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":0,\"candidates\":[{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":14,\"heal_gained\":5,\"hp_after\":19,\"hp_before\":14,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"blood_honey\",\"feat_name\":\"血蜜\",\"hp_after\":19,\"hp_before\":19,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":0,\"candidates\":[{\"feat_id\":\"execution_scholar\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"stone_skin\",\"kind\":\"relic\",\"tier\":\"excellent\"}],\"gp\":51,\"heal_gained\":5,\"hp_after\":21,\"hp_before\":16,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"stone_skin\",\"feat_name\":\"石肤\",\"hp_after\":21,\"hp_before\":21,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":78,\"route\":\"min\",\"seal_hit\":250,\"seal_hit_gain\":1410,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":265,\"seed\":73037,\"shop_buys\":7,\"shop_gp_seq\":[27,73],\"shop_mode\":\"pool\",\"stopped_at\":3,\"taken\":108,\"visited_count\":21,\"wallet_count\":24}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":20,\"choices\":28,\"cleared\":true,\"encounter_max_hp_seq\":[26,26,26,26,26,26,26,26,26,26,26,41,41,41,41,41,41,41,41,41],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":177,\"hp_pct\":0,\"keystone_total\":9,\"level_maps\":[\"1#73038\",\"1#73038\",\"1#73038\",\"1#73038\",\"1#73038\",\"1#73038\",\"1#73038\",\"2#73038\",\"2#73038\",\"2#73038\",\"2#73038\",\"2#73038\",\"2#73038\",\"2#73038\",\"2#73038\",\"2#73038\",\"2#73038\",\"3#73038\",\"3#73038\",\"3#73038\",\"3#73038\",\"3#73038\",\"3#73038\",\"3#73038\",\"3#73038\",\"3#73038\",\"3#73038\",\"3#73038\",\"3#73038\",\"3#73038\",\"3#73038\"],\"levels_cleared\":3,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":19,\"attack\":18,\"feat_ticket\":0,\"heal\":3,\"max_hp\":19},\"refreshes\":2,\"relics\":[\"trap_burst\",\"field_dressing\"],\"result\":\"completed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":0,\"candidates\":[{\"feat_id\":\"trap_instinct\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"seal_echo\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"trap_burst\",\"kind\":\"relic\",\"tier\":\"rare\"}],\"gp\":27,\"heal_gained\":5,\"hp_after\":25,\"hp_before\":20,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"trap_burst\",\"feat_name\":\"陷阱爆发\",\"hp_after\":25,\"hp_before\":25,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"rare\",\"value\":0}},{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":15,\"candidates\":[{\"feat_id\":\"field_dressing\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blood_honey\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"warning_beacon\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":32,\"heal_gained\":8,\"hp_after\":37,\"hp_before\":29,\"keystone_gained\":3,\"keystone_total\":6,\"level_index\":2}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"field_dressing\",\"feat_name\":\"战地包扎\",\"hp_after\":37,\"hp_before\":37,\"level_index\":2,\"picked\":\"relic\",\"tier\":\"common\",\"value\":0}}],\"rounds\":111,\"route\":\"min\",\"seal_hit\":364,\"seal_hit_gain\":1711,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":388,\"seed\":73038,\"shop_buys\":11,\"shop_gp_seq\":[26,70,106],\"shop_mode\":\"pool\",\"stopped_at\":0,\"taken\":177,\"visited_count\":31,\"wallet_count\":32}",
"RUNSUM {\"atk_pct\":0,\"attune\":\"off\",\"battles\":9,\"choices\":8,\"cleared\":false,\"encounter_max_hp_seq\":[26,26,26,26,26,26,26,26,26],\"equipped\":[],\"feat_mode\":\"off\",\"hero_dmg\":58,\"hp_pct\":0,\"keystone_total\":3,\"level_maps\":[\"1#73039\",\"1#73039\",\"1#73039\",\"1#73039\",\"1#73039\",\"1#73039\",\"1#73039\",\"2#73039\",\"2#73039\",\"2#73039\"],\"levels_cleared\":1,\"mine_dmg\":0,\"mine_hits\":0,\"policy\":\"perfect\",\"pool_stock\":{\"ap\":3,\"armor\":20,\"attack\":23,\"feat_ticket\":0,\"heal\":3,\"max_hp\":22},\"refreshes\":0,\"relics\":[\"breaker_strike\"],\"result\":\"failed\",\"reward_events\":[{\"curio_pick\":{\"aux_cleared\":0,\"bonus_max_hp\":0,\"candidates\":[{\"feat_id\":\"breaker_strike\",\"kind\":\"relic\",\"tier\":\"excellent\"},{\"feat_id\":\"last_drop\",\"kind\":\"relic\",\"tier\":\"common\"},{\"feat_id\":\"blast_accounting\",\"kind\":\"relic\",\"tier\":\"common\"}],\"gp\":21,\"heal_gained\":5,\"hp_after\":21,\"hp_before\":16,\"keystone_gained\":3,\"keystone_total\":3,\"level_index\":1}},{\"curio_resolved\":{\"feat_archetype\":\"\",\"feat_id\":\"breaker_strike\",\"feat_name\":\"破封一击\",\"hp_after\":21,\"hp_before\":21,\"level_index\":1,\"picked\":\"relic\",\"tier\":\"excellent\",\"value\":0}}],\"rounds\":43,\"route\":\"min\",\"seal_hit\":139,\"seal_hit_gain\":2048,\"seal_miss\":0,\"seal_miss_penalty\":0,\"seal_placed\":149,\"seed\":73039,\"shop_buys\":2,\"shop_gp_seq\":[23],\"shop_mode\":\"pool\",\"stopped_at\":2,\"taken\":58,\"visited_count\":10,\"wallet_count\":12}"
],
"jsonl": {
"normal": {
"sha256": "b39d5a5a659776e6e3a25a7a1f24af4d8a98b138b2c52cec846bfd7d394364fb",
"rows": 7124
},
"perfect": {
"sha256": "c3d0d37c5f40d208fb35d323b4c7a11c4f7ebe77f9f0eaba0fc3445f00971277",
"rows": 59435
}
}
}
}
}
+2
View File
@@ -5,6 +5,8 @@
比对判据与工具见 `tools/golden_compare.py`
(逐像素灰度差 >16 的像素占比 ≤2%)。
**未建锚面备案(2026-10-29 迭代 41 收尾登记)**:营地/设置/战斗三屏与战末结算/三选一/图例/调试浮窗四浮层无改前 golden 锚——迭代 41 测试特许移交(2026-10-28 用户裁,码先行动)致改前帧无法补建;这些呈现面的等价证据承载=现役探针/单元测试断言面+实机目检(体验验证清单 ㊵ 节)。
## 时效判定纪律(迭代 29 T7 立)
基线冻结于 2026-09-30(v3.5 视觉落码后)。**判定先于动作**:每代换代面(视觉/素材/布局改动)
Loaded 100 of 159 files, more files were not shown because too many files have changed in this diff. Show more