Merge branch 'master' into board-material-fix

# Conflicts:
#	reports/需求卡片-棋盘瓦片与立体表现重做批-2026-11-07.md
This commit is contained in:
DKChan committed 2026-11-10 03:54:48 +08:00
commit d3018a5948
174 files changed
+2682 -970

No files matched your search

+20 -7
View File
@@ -84,6 +84,7 @@ tests/
| 效果发射端口单点 | 战斗结算 | `BattleOrchestrator.begin_battle()`(真实装配链端口接线+合成行闭面守卫经 `DamageController.flush_submit()` 承伤路径) | `effect_port_test.gd:_smoke_effect_port_wiring`;`effect_port_test.gd:_test_business_classes_engine_free`;`effect_port_test.gd:_test_biz_fact_face_closed` |
| 轮内流与结算五段全序 | 战斗结算 | `BattleOrchestrator.begin_battle()` | `round_flow_skill_pool_test.gd:_smoke_full_battle`;`round_flow_skill_pool_test.gd:_smoke_settlement_segments`;`settle_segments_test.gd:_init`;`settlement_wiring_snapshot_test.gd:_init`;`encapsulation_sweep_test.gd:_init` |
| 技能池数据面与回放独立 | 敌人系统 | `BattleOrchestrator.begin_battle()`(技能池抽号/校验) | `round_flow_skill_pool_test.gd:_smoke_skill_pool_data`;`round_flow_skill_pool_test.gd:_smoke_skill_pool_replay_independence`;`trigger_cond_test.gd:_init`;`pool_case_d_test.gd:_init` |
| 全局特殊间隔闸 | 敌人系统 | `BattleOrchestrator.begin_battle()`(开轮摇号池节奏闸——特殊技兑现后强制普攻) | `round_flow_skill_pool_test.gd:_smoke_skill_pool_interval_gate`;`round_flow_skill_pool_test.gd:_smoke_skill_pool_interval_pity`(计划——需求卡片「全局特殊间隔闸批」2026-11-09 锚定) |
| Boss 半血解锁技门控 | 敌人系统 | `BattleOrchestrator.begin_battle()`(Boss 行) | `skill_unlock_test.gd:_test_gate_predicate`;`skill_unlock_test.gd:_test_latch_irreversible` |
| 封印与极性路由/不可逆 | 地图战斗资源×战斗结算 | 效果引擎 × `BattleOrchestrator.begin_battle()` | `seal_polarity_test.gd:_smoke_seal_ap_exhausted`;`seal_polarity_test.gd:_smoke_seal_irreversible_quadrants`;`seal_polarity_test.gd:_smoke_polarity_routing` |
| 状态效果施加与行值(减伤/持续/叠层读表) | 战斗结算 | `BattleOrchestrator.begin_battle()`(状态施加段) | `round_flow_skill_pool_test.gd:_check_defensive_stance_values`(计划——需求卡片「QA覆盖余量收口批」2026-11-07 锚定) |
@@ -112,7 +113,8 @@ tests/
| 棋盘按参数行出图、数字恒真 | 棋盘生成 | `BoardGenerator.generate()` | `board_generator_test.gd:_test_generate_shape_and_mines`;`board_generator_test.gd:_test_digits_equal_neighbor_mine_count`;`board_generator_test.gd:_test_spawn_edge_from_table` |
| 出生区边长表单点(布雷域基/R₀ 下限/剃雷域半径全由 spawn_edge 导出) | 棋盘生成 | `BoardGenerator.generate()`/`BoardGenTable.validate()` | `board_generator_test.gd:_test_spawn_edge_from_table` |
| 同参数同种子逐位复现、异种子不退化 | 棋盘生成 | `BoardGenerator.generate()` | `board_generator_test.gd:_test_same_seed_bit_identical`;`board_gen_reward_test.gd:_smoke_board_generator` |
| 可推理率与清图可达(合法性先于质量分)、重试有界、降级诚实 | 棋盘生成 | `BoardGenerator.measure_inferability()`/`BoardGenerator.is_clearable()` | `board_generator_test.gd:_test_clearable_and_inferability_selfconsistent`;`board_generator_test.gd:_test_target_mine_count_single_source`;`board_gen_reward_test.gd:_smoke_board_generator` |
| 出板检查(出生区无雷/开局不全开、白给板同流重摇、指标集换代) | 棋盘生成 | `BoardGenerator.generate()` | `board_generator_test.gd:_test_board_check_and_reroll`(计划——需求卡片「可推理率退役批」2026-11-09 锚定);`board_gen_reward_test.gd:_smoke_board_generator`(键集断言段) |
| 棋盘可推理率离线测量(仅 sim,不入生成管线) | 棋盘生成 | `SimInferabilityMeasure.measure()`(类计划——本卡 T2 落件;经 `res://sim/calibrate_boards.gd` 缩样直跑消费) | `inferability_measure.gd:measure`(工具直跑读数——登记进实现报告,不进闸)(计划——需求卡片「可推理率退役批」2026-11-09 锚定) |
| 装板与开局免费展开(封锁格无资源、计入清图) | 排雷玩法 | `MinesweeperRules.install_board()` | `minesweeper_rules_test.gd:_test_install_invariants`;`seal_polarity_test.gd:_smoke_resource_surface` |
| 挖/封印合法性与可辨拒绝(拒绝零副作用、挖封印格被拒) | 排雷玩法 | `MinesweeperRules.settle_batch()` | `minesweeper_rules_test.gd:_test_dig_face_rules`;`minesweeper_rules_test.gd:_test_seal_place`;`minesweeper_rules_test.gd:_test_reject_out_of_catalog`;`minesweeper_rules_test.gd:_test_dig_sealed_rejected`;`minesweeper_rules_test.gd:_test_classify_seal_clears`(计划——需求卡片「封印动作改版批」2026-11-07 锚定) |
| 棋盘揭示预览只读口(零状态写入/与实挖揭示集同口径) | 排雷玩法 | `MinesweeperRules.preview_reveal()` | `minesweeper_rules_test.gd:_test_preview_reveal_readonly` |
@@ -122,6 +124,8 @@ tests/
| 棋盘格面绘制显示(渲染闸棋盘三图 golden 逐像素——变异标记/奖励徽章/移除退色) | 排雷玩法 | `board_shot_probe.tscn` 窗口化真渲染(`BoardView.rebuild()` 固定种子单关直构)→`golden_compare.py` 逐像素 | `board_shot_probe.gd:_ready`(棋盘三图采集——渲染闸基线面)(计划——需求卡片「QA覆盖余量收口批」2026-11-07 锚定) |
| AP 扣费、末点耗尽即收轮与战斗收束清零 | 行动经济 | `MinesweeperRules.settle_batch()`(→`ActionEconomy.try_spend()`/`ActionEconomy.notify_combat_end()`) | `seal_polarity_test.gd:_smoke_seal_ap_exhausted`;`round_flow_skill_pool_test.gd:_smoke_full_battle`;`round_flow_skill_pool_test.gd:_smoke_active_refresh` |
| 停手转存储备与轮内刷新(上限/AP 不重置/刷新图零清图奖励) | 行动经济 | `BattleOrchestrator.player_request_refresh()`/`MinesweeperRules.settle_batch()` | `round_flow_skill_pool_test.gd:_smoke_active_refresh`;`seal_polarity_test.gd:_smoke_refresh_provenance_guard`;`refresh_feats_test.gd:test_no_feats_baseline` |
| 储备点整局冒险携带与冒险收束清零 | 行动经济 | `AdventureRunner.adventure_counters["rap"]`→`BattleOrchestrator.begin_battle()`/`AdventureRunner._settle()` | `round_flow_skill_pool_test.gd:_test_rap_carries_across_battles`;`round_flow_skill_pool_test.gd:_test_rap_cleared_on_adventure_settle`;`feat_vouchers_test.gd:_test_rap_breakpoint_roundtrip`(计划——需求卡片「刷新经济改版批」2026-11-09 锚定) |
| 储能秘宝关首注入与正确动作产储备点 | 行动经济×秘宝 | `BattleOrchestrator._begin_battle_preview_economy()`/`GrantSegment._apply_rap_hits()` | `treasure_effects_test.gd:_test_level_start_rap_grant`;`treasure_effects_test.gd:_test_correct_action_rap`;`treasure_effects_test.gd:_test_wrong_action_gives_no_rap`(计划——需求卡片「刷新经济改版批」2026-11-09 锚定) |
| 换图系刷新链路与效果词表接线 | 行动经济×战斗结算×奇物 | `MinesweeperRules.settle_batch()`/`BattleOrchestrator.player_request_refresh()` | `effect_words_t1_test.gd:_init`;`forge_table_test.gd:_test_effect_kinds_closed`;`refresh_feats_test.gd:test_board_refresh_fact_only_on_success` |
| 换图基座:挖格产 RAP 与刷新折扣 | 行动经济×奇物 | `MinesweeperRules.settle_batch()`/`BattleOrchestrator.player_request_refresh()` | `refresh_feats_test.gd:test_reserve_on_accepted_dig`;`refresh_feats_test.gd:test_refresh_discount_gate_and_charge`;`refresh_feats_test.gd:test_double_base_stack` |
| 换图输出:刷新群伤与蓄力攻击 | 战斗结算×奇物 | `BattleOrchestrator.player_request_refresh()`→轮末 `MinesweeperRules.settle_batch(stop)` | `refresh_feats_test.gd:test_blast_defers_to_combat_segment`;`refresh_feats_test.gd:test_charge_layers_consumed_same_round`;`run_time_fatal_test.gd:_init` |
@@ -152,15 +156,22 @@ tests/
| 站桩敌人呈现与结算演出落点 | 战斗表现 | `BattleStageView.enemy_standee_center()`/`BattleEndOverlay.open_victory()` | `standee_fx_sweep_test.gd:_init`;`pacing_queue_test.gd:_init` |
| 站桩呈现定值与素材绑定 | 战斗表现 | `UiKit.load_tex()`/`StandeeBody.name_line_probe()` | `standee_present_values_test.gd:_init` |
| 站桩显示档与素材分辨率绑定 | 战斗表现 | `StandeeBody.portrait_probe()`/`StandeeMotion.PORTRAIT_DISPLAY_H` | `standee_present_values_test.gd:_check_display_tier` |
| 敌方意图徽标类型级预告 | 战斗表现 | `StandeeBody.set_pending()` → `StandeeBody.intent_probe()` | `standee_fx_sweep_test.gd:_init` |
| B 区舞台背景三关变体与连续地面层(按 board_type 选图/地面层高度读布局表/四柱光柱退役) | HUD框架 | `BattleStageView.set_board_type()` | `stage_background_test.gd:_test_background_selection`;`stage_background_test.gd:_test_ground_layer_geometry`;`stage_background_test.gd:_test_beams_retired` |
| 动画帧数规格(待机/攻击/受击;现役单帧形制锚定) | 战斗表现 | `UiKit.load_tex()`(`TEX_HERO_*` 四态件装载链——棋盘站立/行走与舞台三态同源) | `animation_frame_spec_test.gd:_test_spec_table`;`animation_frame_spec_test.gd:_test_current_form` |
| 战斗屏三区几何与棋盘格边长(分辨率两档×四档板型) | HUD框架 | `BoardView.set_cell_area()`(D 区可用面积 → 格边长);读面 `BoardView.cell_size` | `layout_probe.gd:_ready`;`board_gen_reward_test.gd:_smoke_layout_cell_formula`;`stage_background_test.gd:_test_side_rail_width_from_table`/`_test_log_band_settle_height`(计划——需求卡片「QA覆盖余量收口批」2026-11-07 锚定) |
| 战斗屏三区几何与棋盘格边长(分辨率两档×四档板型) | HUD框架 | `BoardView.set_cell_area()`(D 区可用面积 → 格边长);读面 `BoardView.cell_size` | `layout_probe.gd:_ready`;`board_gen_reward_test.gd:_smoke_layout_cell_formula`;`stage_background_test.gd:_test_side_rail_width_from_table`(`_test_log_band_settle_height` 计划用例随明细带退役作废——需求卡片「明细带退役呈现改版批」2026-11-10) |
| 调参测速批量模拟(逐帧步进与统计读数) | 调参测量 | `TuneSimController.run()`(调试浮窗批量模拟入口) | `tune_sim_batch_parity_test.gd:_init`(配对对拍套件) |
| sim 驱动循环单点(缺省零变化与策略/日志回调形态) | 调参测量 | `BattleDriver.drive_round()`(两参缺省与五参回调两形态) | `battle_driver_drive_test.gd:_smoke_drive_round_contract` |
| 模拟玩家 0 格连锁算子(经真实闭包,零盲挖语义保持) | 调参测量×排雷玩法 | `AutoPlayer._deduce()`(经 `perfect_action()` 装配链) | `auto_player_deduce_test.gd:_smoke_zero_chain_rule` |
| 刷新提示文案读表拼接(RAP 不足/轮上限两 toast 零字面量) | HUD框架 | `Main._on_refresh_confirmed()`(两 toast 装配面)+`player_copy_sweep` 源扫描 | `player_copy_sweep_test.gd:_sweep_refresh_toast_no_literals` |
| 试玩日志器 ap_per_round 必填注入守卫(未注入拒绝开会话) | 表现与支撑 | `PlaytestLogger.start_session()` | `playtest_logger_guard_test.gd:_smoke_required_injection` |
| 战斗叙述与终局文案(数值带入/胜负互异) | HUD框架 | `BattleNarrator.battle_end_text()`/`BattleNarrator.boss_name()` | `battle_narrator_test.gd:_test_numeric_lines_carry_values`;`battle_narrator_test.gd:_test_end_text_differs_by_result`;`battle_narrator_test.gd:_test_boss_name_uses_boss_rowset` |
| 终局判定文案与战末账行 | HUD框架 | `BattleEndOverlay.open_victory()`/`open_defeat()`(verdict_line 由组合根直拼传入) | `ui_click_probe.gd:_ready`(终局浮层段) |
| B 区零文字带 | HUD框架 | `Main._ready()`(组合根场景树装配)+节点推进/恢复/商店/终局真实流 | `log_band_retired_test.gd:_test_no_log_view_node`;`log_band_retired_test.gd:_test_b_zone_zero_text` |
| 清图兑付浮字 | HUD框架 | `BoardZoneView.spawn_clear_reward_text()`(round_end clear 分支装配) | `clear_reward_text_test.gd:_test_spawn_and_decay`;`clear_reward_text_test.gd:_test_no_overlap`;`clear_reward_text_test.gd:_test_decay_curves` |
| 解锁拍零新增呈现 | HUD框架 | `RowPacer.enqueue()`→`consume_now()`(skill_unlock 高光行消费流,快照取消费时刻) | `unlock_zero_ui_test.gd:_test_zero_delta` |
| 文案承载单点 | 数据配置与跨系统契约 | `TranslationServer.set_locale()` 后场景 `Label.tr()` 真实查表 | `player_copy_sweep_test.gd:_sweep_tr_roundtrip` |
| 表行文案 key 化 | 数据配置与跨系统契约 | `ConfigDB._ready()`(autoload 加载真实表+schema 校验闸) | `config_table_key_test.gd:_test_display_key_format` |
| 文案漏网清零 | 数据配置×表现与支撑 | `Main._ready()`(组合根装配链全量加载)+`player_copy_sweep` 源扫描 | `player_copy_sweep_test.gd:_sweep_zero_product_literals` |
| 玩家面文案与危险格格面字形 | HUD框架 | `BoardView.rebuild()`/`StatusSlotRow.set_effects()` | `player_copy_sweep_test.gd:_sweep_board_glyph`;`player_copy_sweep_test.gd:_sweep_legend`;`player_copy_sweep_test.gd:_sweep_hero_panel` |
| 营地场景图十层铺底与门洞留空呈现 | 营地场景视图 | 进入存档→选档→进档→营地场景屏(`CampSceneView.setup_layers()` 驱动);单元测试载入 `camp_scene_layout.tres` | `shot_probe.gd:_ready`(camp 截图段);`camp_scene_layout_test.gd:_test_layout_hotspot_geometry` |
| 营地七物件命中区点选与分界面可达 | 营地场景视图 | 七物件命中区 → 合成鼠标事件经 `push_input` 真点(`ProbeUiUtil.push_click_at` 热点中心)→ `CampSceneView._gui_input()`(命中发 `object_pressed` 信号) → 组合根开界面(2026-11-06 真输入化,残险登记撤) | `ui_click_probe.gd:_ready`(七物件合成点击段——真输入驱动) |
@@ -182,6 +193,8 @@ tests/
| 停手钮真输入命中与停手收轮落效 | 行动经济 | ui_click_probe 使能窗真输入点击(AP 条停手钮经 `ProbeUiUtil.push_click()`)+journey_player 全线跑批(sim) | `ui_click_probe.gd:_stoptest_tick`(计划测试——需求卡片「QA harness 缺陷与覆盖遗漏收口批」2026-11-06 锚定) |
| 停点链与控件级真输入命中 | HUD框架 | 探针与测试宿主真输入驱动(节点继续/三选一选卡·确认/弃图刷新确认/奖励刷新/地图候选矩形中心/调试浮窗钮,一律经 `ProbeUiUtil.push_click()`/`push_click_at()` 进 `push_input`) | `ui_click_probe.gd:_ready`(停点链段——计划测试,需求卡片「QA harness 缺陷与覆盖遗漏收口批」2026-11-06 锚定) |
| 控件动线扩面真输入可达(图例关闭/节点继续/三选一与商店/秘宝架/树高档与先手/弃图链/地图放弃/Esc 设置/减动效开关) | HUD框架×各屏 | 合成 InputEvent 经 Viewport push_input 真点注入(`ProbeUiUtil.push_click_at()`;扩面十一段,高档钮经调试注钥使能) | `ui_click_probe.gd:_ready`(动线扩面段)(计划——需求卡片「QA覆盖余量收口批」2026-11-07 锚定) |
| 冒险簇选路两段式与战斗HUD实采样结构审计 | HUD框架×关卡画面 | 合成鼠标事件经 Viewport push_input 真点候选命中矩形中心(`ProbeUiUtil.push_click_at()`)→ `LevelMapScreen._submit_choice()` → `route_chosen` → 组合根回战斗屏;第一段 emit 接线断言快速失败、不充当真实入口 | `ui_struct_probe.gd:_adventure_wiring_stage`/`ui_struct_probe.gd:_adventure_real_stage`(计划——需求卡片「测试面四项收口批」2026-11-10 锚定) |
| 图例层两段式开合 | HUD框架 | AP 条图例钮 `ProbeUiUtil.push_click()` 真点开层 → 「关闭」钮真点收层(`find_button()` 寻钮);第一段 `pressed.emit()` 标〔接线断言〕 | `ui_struct_probe.gd:_legend_two_stage`(计划——需求卡片「测试面四项收口批」2026-11-10 锚定) |
**旅程段七:数据配置与跨系统契约**
@@ -193,7 +206,7 @@ tests/
| 运行期越域致命与进程非 0 退出 | 数据配置 | `BoardGenTable.resolve_row()`/`ConfigDbResolver.resolve_enemy_rowset()` | `config_db_fatal_oob_test.gd:_trigger_oob`;`config_db_resolver_test.gd:_test_request_oob` |
| 加载期违规表拒绝:跨表悬空/计数器前缀/真视窄域/效果类型出域 | 数据配置×秘宝×奇物 | `ConfigDB.load_tables()` | `reward_dangling_treasure_test.gd:_init`;`counter_prefix_fatal_test.gd:_assert_rejected`;`treasure_target_violation_test.gd:_init`;`effect_kind_retired_test.gd:_assert_rejected`;`extended_row_violation_test.gd:_init` |
| 表结构守卫:域校验/行序键/跨字段互锁/配额锚 | 数据配置×敌人系统×地形变异×冒险结构 | `EnemyTable.validate()`/`VariationTable.variant_pool()`/`AdventureTable.validate()` | `table_structure_guard_test.gd:_smoke_enemy_bands`;`table_structure_guard_test.gd:_smoke_variation_framework`;`table_structure_guard_test.gd:_smoke_adventure_table`;`table_structure_guard_test.gd:_test_feat_cap_required` |
| schema 违约词拒绝路径与关键表值钉(空表/冻结/出域/白名单/settlement 钉/cap 段七槽钉) | 数据配置×战斗结算 | 各表 schema `validate()` 直调注入坏行(`BoardGenTable.validate()` 同款面)/表行读值 | `schema_vocab_violation_test.gd:_check_empty_tables`;`table_structure_guard_test.gd:_check_settlement_pin_values`;`table_structure_guard_test.gd:_check_curio_cap_segment_pins`(计划——需求卡片「QA覆盖余量收口批」2026-11-07 锚定) |
| schema 违约词拒绝路径与关键表值钉(空表/出域/白名单/settlement 钉/cap 段七槽钉+退役列零违例钉) | 数据配置×战斗结算 | 各表 schema `validate()` 直调注入坏行(`BoardGenTable.validate()` 同款面)/表行读值 | `schema_vocab_violation_test.gd:_check_empty_tables`;`table_structure_guard_test.gd:_check_settlement_pin_values`;`table_structure_guard_test.gd:_check_curio_cap_segment_pins`(计划——需求卡片「QA覆盖余量收口批」2026-11-07 锚定) |
| 变异表头域校验(地形变异) | 地形变异 | `VariationTable.validate()` | `table_structure_guard_test.gd:_test_variation_header_domains` |
| 难度修饰套乘:空表零行为/套乘生效/越域 clamp | 难度曲线与Boss | `UnitContainer.spawn()`/`ConfigDbResolver.resolve_difficulty_modifiers()` | `table_structure_guard_test.gd:_smoke_difficulty_table`;`config_db_resolver_test.gd:_test_difficulty_clamp` |
| Boss 出场门控(每区域恰一 Boss 终点/Boss 节点开战必选 Boss 行集) | 难度曲线与Boss | `NodeMapGenerator.generate()`/`BattleOrchestrator.begin_battle()` | `node_map_generator_test.gd:_test_boss_exit_per_region`;`boss_gate_test.gd:_test_boss_node_spawns_boss_rowset` |
@@ -219,13 +232,13 @@ tests/
| 战斗循环 | 地图战斗资源.md | 清图奖励双份与零路径;GP 钱包/escrow/商店收口/共享池;封印与极性路由/不可逆 | 已覆盖 | — |
| 战斗循环 | 增益状态.md | 系统间契约词表与受理口径:五配方互异/掷点标签成员性/增益布尔受理;同名状态合并策略(叠加/累加/并存)与剩余次数语义;状态效果结算链(逐值衰减/到期移除/战斗结束全清/满层拒绝/独立并存/首授快照);状态实例按个体归属:个体隔离/全体授予逐体发/死亡即清/同体合并照旧;敌方增益自体落点与乘区池按个体;封印与极性路由/不可逆 | 部分覆盖 | 结算链剩余缺口由「断言补齐批」承接;见待办清单「能力清单覆盖缺口补齐」条 |
| 战斗循环 | 战斗结算.md | 伤害公式与掷点乘区;伤害单据编排与回放;轮内流与结算五段全序 | 已覆盖 | — |
| 战斗循环 | 战斗表现.md | 站桩敌人呈现与结算演出落点;站桩呈现定值与素材绑定;站桩显示档与素材分辨率绑定 | 已覆盖 | 死亡灰化与减动效演出档以探针+人工目检为终态(2026-11-02 用户裁除名,不再补自动断言) |
| 战斗循环 | 战斗表现.md | 站桩敌人呈现与结算演出落点;站桩呈现定值与素材绑定;站桩显示档与素材分辨率绑定;敌方意图徽标类型级预告 | 已覆盖 | 死亡灰化与减动效演出档以探针+人工目检为终态(2026-11-02 用户裁除名,不再补自动断言) |
| 战斗循环 | 敌人系统.md | 技能池数据面与回放独立;Boss 半血解锁技门控;敌人技能池跨表链接校验;精英行:池继承合并、加载期校验与暂不接线 | 部分覆盖 | 精英行「开战快照拿到合并后池」随接线批验收;见待办清单「战斗节点遭遇编排方式」条 |
| 排雷循环 | 地形变异.md | 变异布置门控;表结构守卫:域校验/行序键/跨字段互锁/配额锚 | 已覆盖 | — |
| 排雷循环 | 排雷玩法.md | 装板与开局免费展开(封锁格无资源、计入清图);挖/封印合法性与可辨拒绝(拒绝零副作用、挖封印格被拒);封印受理即揭示(身份可查、受理零事件);清图口径换代(挖开∪封印、封印可完成清图) | 已覆盖 | — |
| 排雷循环 | 棋盘生成.md | 棋盘按参数行出图、数字恒真;同参数同种子逐位复现、异种子不退化;可推理率与清图可达(合法性先于质量分)、重试有界、降级诚实 | 已覆盖 | — |
| 排雷循环 | 棋盘生成.md | 棋盘按参数行出图、数字恒真;同参数同种子逐位复现、异种子不退化;出板检查(出生区无雷/开局不全开、白给板同流重摇、指标集换代);棋盘可推理率离线测量(仅 sim,不入生成管线) | 已覆盖 | — |
| 排雷循环 | 行动经济.md | AP 扣费、末点耗尽即收轮与战斗收束清零;停手转存储备与轮内刷新(上限/AP 不重置/刷新图零清图奖励);下轮行动点修正排队与兑现 | 已覆盖 | — |
| 表现与支撑 | HUD框架.md | 拒绝反馈分面可辨与未知兜底文案;结算期零逐行文字与 FX 排播链保持;模态覆盖层编排与输入锁;未开格类型微光(8 邻作用集、五组色相、零玩法写入);UI 全局主题与按钮五态(含对比度锚);中文字体随包与字形覆盖;地形瓦片套与格面数字可读(旧行保留,删行归写卡段后续,实现批禁写);棋盘合并岩体与连续地面(深度遮挡、投影、崖面);棋盘浮空数字与引导线(最顶层、顶部预留);D 区行动资源侧栏(AP 左栏、RAP 右栏、全高棋盘);棋盘点击命中与格边公式(逻辑格矩形);旧瓦片退役与普通数字零底牌;棋盘顶面锚点与迷雾几何(微光、变异岩顶偏移,封印格心);战斗叙述与终局文案(数值带入/胜负互异);玩家面文案与危险格格面字形;战斗屏三区几何与棋盘格边长(分辨率两档×四档板型);B 区舞台背景三关变体与连续地面层(按 board_type 选图/地面层高度读布局表/四柱光柱退役);模态句柄分域寻址面 | 已覆盖 | — |
| 表现与支撑 | HUD框架.md | 拒绝反馈分面可辨与未知兜底文案;结算期零逐行文字与 FX 排播链保持;模态覆盖层编排与输入锁;未开格类型微光(8 邻作用集、五组色相、零玩法写入);UI 全局主题与按钮五态(含对比度锚);中文字体随包与字形覆盖;地形瓦片套与格面数字可读(旧行保留,删行归写卡段后续,实现批禁写);棋盘合并岩体与连续地面(深度遮挡、投影、崖面);棋盘浮空数字与引导线(最顶层、顶部预留);D 区行动资源侧栏(AP 左栏、RAP 右栏、全高棋盘);棋盘点击命中与格边公式(逻辑格矩形);旧瓦片退役与普通数字零底牌;棋盘顶面锚点与迷雾几何(微光、变异岩顶偏移,封印格心);终局判定文案与战末账行;B 区零文字带;清图兑付浮字;解锁拍零新增呈现;玩家面文案与危险格格面字形;战斗屏三区几何与棋盘格边长(分辨率两档×四档板型);B 区舞台背景三关变体与连续地面层(按 board_type 选图/地面层高度读布局表/四柱光柱退役);模态句柄分域寻址面 | 已覆盖 | — |
| 表现与支撑 | 存档序列化.md | 存档写盘⇄读回往返保真;三槽位隔离与激活失败回滚;槽位摘要窥视与坏槽三态;启动态无激活不写盘;旧档迁移链与断点续玩零跳号;存档⇄RNG 快照往返保真 | 已覆盖 | — |
| 表现与支撑 | 教学引导.md | — | 未覆盖 | 教学形态与首遇时机待设计;见待办清单「教学形态未定」条 |
| 表现与支撑 | 数据配置.md | 全表装载、就绪态与表清单目录对账;进度坐标查行:精确命中/向上取整/封顶/警告去重;运行期越域致命与进程非 0 退出;加载期违规表拒绝:跨表悬空/计数器前缀/真视窄域;表结构守卫:域校验/行序键/跨字段互锁/配额锚 | 已覆盖 | — |
+2
View File
@@ -39,6 +39,8 @@
|---|---|---|---|
| 2026-11-08 | 棋盘三图+menu_boot+lmap 两 Shot+单基线合并(6 张) | DKChan | 确认 |
| 2026-11-08 | 屏态五锚+营地窗态五锚+浮层四锚(14 张补锚) | DKChan | 确认 |
| 2026-11-09 | menu_boot 换代(调试角标恢复批——右下角「调试」角标重现,预期面视觉变化显式重制) | DKChan | 确认 |
| 2026-11-09 | 全屏 14 锚换代(调试角标恢复批后续——角标入帧,实测 0.06–0.15% 容差内;逐张差异包围盒同一 44×36 角标区,画面其余零变化;棋盘三图与 lmap 两 Shot 实测 0.00% 不动) | DKChan | 确认 |
## 时效判定纪律
Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 310 KiB

After

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 KiB

After

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 KiB

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 493 KiB

After

Width:  |  Height:  |  Size: 494 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 KiB

After

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 KiB

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 KiB

After

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 195 KiB

+3 -3
View File
@@ -16,7 +16,7 @@ var _checks: int = 0
func check(cond: bool, label: String) -> void:
# 判据出处: design/engineering/test-conventions.md「测试层三元组」冒烟测试行 (测试层三元组——冒烟存活检查组)
# 判据出处: design/engineering/test-conventions.md「1.1 测试层三元组」测试层三元组 测试层三元组(测试层三元组——冒烟存活检查组)
_checks += 1
if cond:
print(" [PASS] " + label)
@@ -35,7 +35,7 @@ func _ready() -> void:
# 开机前置面:autoload 注册与资源可加载(挂主屏之前先查,失败时主屏断言整段跳过)
func _check_autoloads() -> void:
# 判据出处: design/engineering/test-conventions.md「测试层三元组」冒烟测试行 (测试层三元组——冒烟存活检查组)
# 判据出处: design/engineering/test-conventions.md「1.1 测试层三元组」测试层三元组 测试层三元组(测试层三元组——冒烟存活检查组)
for autoload_name in ["ConfigDB", "RngService", "SaveManager", "MetaProgression"]:
var node: Node = get_node_or_null(NodePath("/root/" + autoload_name))
check(node != null, "autoload %s 在位" % autoload_name)
@@ -64,7 +64,7 @@ func _boot_main_scene() -> Node:
# 主屏存活面:组合根装配句柄在位(main.X 一级句柄契约,探针挂载假设的启动侧证明)
func _check_main_scene(main: Node) -> void:
# 判据出处: design/engineering/test-conventions.md「测试层三元组」冒烟测试行 (测试层三元组——冒烟存活检查组)
# 判据出处: design/engineering/test-conventions.md「1.1 测试层三元组」测试层三元组 测试层三元组(测试层三元组——冒烟存活检查组)
check(main != null and main.is_inside_tree(), "主屏场景已实例化并在树")
if main == null:
return
+10 -10
View File
@@ -34,7 +34,7 @@ func _initialize() -> void:
# (自 game/smoke/smoke_all.gd 剪切迁入——断言 label 逐字原样;G12 两套调用不随迁,
# 归 source_guard_test.gd,断言迁移批 B G1)
func _split_tail() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
await process_frame
await process_frame
var autoload_ok: bool = get_root().get_node_or_null("/root/ConfigDB") != null and get_root().get_node_or_null("/root/SaveManager") != null
@@ -54,7 +54,7 @@ func _split_tail() -> void:
# ---- 三屏场景化断言(V2——独立实例化+关键节点在位+组合根树序/z 序保序)----
# (自 game/smoke/smoke_all.gd 剪切迁入——label 与 cond 逐字原样,断言迁移批 B G1)
func _smoke_scene_split() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
print("--- 迭代27 T1 三屏场景化(V2:屏壳独立实例化+组合根装配保序)---")
# ① 三屏壳独立实例化(F6 等价——headless 直挂;视图代码构建在屏壳 _ready)
var menu: Node = load("res://presentation/scenes/menu_screen.tscn").instantiate()
@@ -151,7 +151,7 @@ func _count_visible_buttons(node: Node) -> int:
# ---- boot 链路时序后置条件(启动态六断言;只立行为可判断言,不造假时序)----
func _smoke_boot_chain() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
print("--- 迭代28 T2 boot 链路时序后置条件(V2:六断言)---")
var main: Node = load("res://presentation/main.tscn").instantiate()
root.add_child(main)
@@ -206,8 +206,8 @@ func _smoke_boot_chain() -> void:
# 入口=开始屏右下角「调试」角标+对局中两屏角标)
check(not main.ui.modals.menu.debug_overlay.visible,
"V2f 调试浮窗 boot 不自动开(菜单优先)〔2026-10-16 用户令〕")
check(main.ui.screens.debug_badge != null and not main.ui.screens.debug_badge.visible,
"V2f 调试浮层角标发布态恒隐(2026-10-25 删写死行批)")
check(main.ui.screens.debug_badge != null and main.ui.screens.debug_badge.visible,
"V2f 调试浮层角标 boot 可见(全局浮层入口在座——2026-11-09 特批恢复批)")
main.queue_free()
await process_frame
for p in ["user://smoke_boot_chain.json", "user://smoke_boot_chain.json.tmp"]:
@@ -216,7 +216,7 @@ func _smoke_boot_chain() -> void:
func _smoke_run_lifecycle() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
print("--- 迭代27 T1 会话物化(V3:两连局复位+脏状态不残留)---")
var main: Node = load("res://presentation/main.tscn").instantiate()
root.add_child(main)
@@ -274,7 +274,7 @@ func _smoke_run_lifecycle() -> void:
# ---- d6/d7 批量模拟互斥守卫(wd6/wd7——白盒置态直调入口,以守卫早退的可见后果为断言面)----
func _smoke_sim_guards() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
print("--- 卡① T2:批量模拟互斥两守卫(d6/d7)---")
var main: Node = load("res://presentation/main.tscn").instantiate()
root.add_child(main)
@@ -348,7 +348,7 @@ func _face_snapshot(main: Node) -> Dictionary:
# 阶段面断言:adv/run/set=alive|null|both(会话三面存活态);恒活面每阶段必查;
# 现值回调与 run_scope 成员必须同源(回调链无悬挂铁证);extra=阶段附加判据。
func _stage_faces(main: Node, tag: String, adv: String, run: String, set: String, extra: Dictionary = {}) -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var snap := _face_snapshot(main)
var bad := ""
for k in ["bonus_meta", "bonus_save", "camp_meta", "camp_save", "rp_stage", "rp_board_zone", "rp_fx", "rp_board"]:
@@ -417,7 +417,7 @@ func _face_liveness(name: String, v, want: String) -> String:
#(level_started→choices_presented 同步到达,无可观测中间态)——合并为 V3b 一处断言。
# (自 game/smoke/smoke_all.gd 剪切迁入——label 与 cond 逐字原样,断言迁移批 B G1)
func _smoke_lifecycle_matrix() -> void:
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md:284 (生命周期矩阵——三关序列组)
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「验收标准」开始新冒险 开始新冒险(生命周期矩阵——三关序列组)
print("--- 迭代28 T3 生命周期存活性矩阵(V3:九阶段×五引用面)---")
var main: Node = load("res://presentation/main.tscn").instantiate()
root.add_child(main)
@@ -608,7 +608,7 @@ func _smoke_lifecycle_matrix() -> void:
func _smoke_camp_hud_band() -> void:
# 判据出处: design/ux/camp.md:41 (营地顶栏栏体定值与落座——几何/色值/吃点击五钉组)
# 判据出处: design/ux/camp.md「顶栏」钥石余额常驻画面顶部一行小 钥石余额常驻画面顶部一行小(营地顶栏栏体定值与落座——几何/色值/吃点击五钉组)
print("--- 营地交互修复批 T3 顶栏栏体(R5:色值/铺满/不吃点击/首子件/徽章落座)---")
var main: Node = load("res://presentation/main.tscn").instantiate()
root.add_child(main)
@@ -8,13 +8,13 @@ const Kit := preload("res://tests/unit/test_kit.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:293 Boss 节点开战行集宿主(装载组)
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「调参表」配置表共三张 配置表共三张(装载组)
_test_boss_node_spawns_boss_rowset()
quit(Kit.finish("boss_gate_test"))
func _test_boss_node_spawns_boss_rowset() -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:295 开战生成按遭遇坐标取行集(Boss 行集组)
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「调参表」Boss Boss(Boss 行集组)
var db = load("res://core/config_db.gd").new()
var load_ok: bool = db.load_tables("res://data/tables", true) and db.diagnostics_count("error") == 0
Kit.check("前置:表加载零 error", load_ok)
@@ -23,7 +23,7 @@ var _rows: Array = [] # 当前 run 的行协议收集(_on_row 绑定法—
func _init() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 伤害单据编排宿主(装载组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(装载组)
var db = ConfigDBScript.new()
var load_ok: bool = db.load_tables("res://data/tables", true)
Kit.check("前置:表加载零 error", load_ok and db.diagnostics_count("error") == 0)
@@ -71,7 +71,7 @@ func _row_by_display_prefix(prefix: String) -> Dictionary:
# ---- 五配方一次全流程 + 双跑逐位复现 ----
func _run_recipe_sequence(db) -> Array:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (五段全序——配方序列组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(五段全序——配方序列组)
_rows = []
var h = _harness(db)
var units = h.units
@@ -178,7 +178,7 @@ func _run_recipe_sequence(db) -> Array:
func _test_five_recipes_and_replay(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:363 (同种子回放逐行相同组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「明细流水:每一行都能指回你刚才的哪一步棋」结算过程中每一件事都写一行明细 结算过程中每一件事都写一行明细(同种子回放逐行相同组)
var run1: Array = _run_recipe_sequence(db)
Kit.check("五配方序列产出 5 行伤害行", run1.size() == 5)
var run2: Array = _run_recipe_sequence(db)
@@ -188,7 +188,7 @@ func _test_five_recipes_and_replay(db) -> void:
# ---- A 模式(开单即结——回切位) ----
func _test_policy_immediate_mode(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (结算策略即时面组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(结算策略即时面组)
_rows = []
var h = _harness(db)
if not h.spawn_ok:
@@ -204,7 +204,7 @@ func _test_policy_immediate_mode(db) -> void:
# ---- 来源敌死亡:队列中未结单据作废(死亡即不动手) ----
func _test_source_death_void(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:133 (摇定后兑现前被杀本拍作废组)
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「技能池:每敌种一张带权技能池,每拍开轮摇号出招」每种敌人有一张技能池 每种敌人有一张技能池(摇定后兑现前被杀本拍作废组)
_rows = []
var h = _harness(db)
if not h.spawn_ok:
@@ -238,7 +238,7 @@ func _unit_fixture() -> Dictionary:
func _test_identical_content_dual_enemy(db: ConfigDb) -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:303 (双敌同内容顺位组)
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「开战生成:主角数据行与一场 1–4 个敌人」战斗开始时 战斗开始时(双敌同内容顺位组)
var a := _unit_fixture()
var b := _unit_fixture()
Kit.check("前置:双敌字典内容全同且非同一实例", a == b and not is_same(a, b))
@@ -268,7 +268,7 @@ func _test_identical_content_dual_enemy(db: ConfigDb) -> void:
# d12 产发端增键:目标身份随行/随载荷下发(同名敌按 id 精确解析的产发半)
func _test_target_id_payload(db: ConfigDb) -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
_rows = []
var h = _harness(db)
if not h.spawn_ok:
@@ -291,7 +291,7 @@ func _test_target_id_payload(db: ConfigDb) -> void:
func _test_requires_gate_and_zero(db) -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
_rows = []
var h = _harness(db)
if not h.spawn_ok:
@@ -318,7 +318,7 @@ func _test_requires_gate_and_zero(db) -> void:
# ---- 主角倒下:flush 余单全部作废(_halted 终止) ----
func _test_hero_death_halt(db) -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
_rows = []
var h = _harness(db)
if not h.spawn_ok:
@@ -336,7 +336,7 @@ func _test_hero_death_halt(db) -> void:
# ---- AC 合流:override 入参 / 表值兜底 / ac 型状态叠层(不入池) ----
func _test_ac_merge(db) -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
_rows = []
var h = _harness(db)
if not h.spawn_ok:
@@ -364,7 +364,7 @@ func _test_ac_merge(db) -> void:
# ---- 池乘区收口:池内加算 → clamp;ac 型不入池 ----
func _test_pool_clamp(db) -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
_rows = []
var h = _harness(db)
if not h.spawn_ok:
@@ -422,7 +422,7 @@ func _test_pool_clamp(db) -> void:
# ---- 个体池读数 / 个体 AC 合流(增益状态 v1.5——敌方状态个体化批)----
func _test_pool_consumption_per_unit(db) -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var h = _harness(db, 3) # depth 3 = 混编行集(熊地精 1 + 地精 1–2,最少 2 只——个体对照面需 ≥2 敌)
if not h.spawn_ok:
return
@@ -442,7 +442,7 @@ func _test_pool_consumption_per_unit(db) -> void:
func _test_defender_ac_per_unit(db) -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var h = _harness(db, 3)
if not h.spawn_ok:
return
@@ -12,7 +12,7 @@ var db
func _init() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (伤害公式宿主——装载组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(伤害公式宿主——装载组)
db = ConfigDBScript.new()
var load_ok: bool = db.load_tables("res://data/tables", true)
Kit.check("前置:settlement 表加载零 error", load_ok and db.diagnostics_count("error") == 0)
@@ -31,7 +31,7 @@ func _floor_val() -> int:
# ---- F2 乘区:池内加算 → 池间乘算 → floor(单一取整规则)----
func _test_pool_damage() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (池伤害公式组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(池伤害公式组)
var d := _floor_val() + 9 # 表值推导的任意正探针量(非玩法行值)
Kit.check("中性双池 (0,0) 原样透传", DamageMathScript.pool_damage(d, 0, 0) == d)
Kit.check("负敌方池压低不增高", DamageMathScript.pool_damage(d, 0, int(db.combat.settlement.core.pool_clamp_lo)) <= d)
@@ -44,7 +44,7 @@ func _test_pool_damage() -> void:
# ---- 克制分量:空桶不吃修正恒 0;落地下限保底([1,+∞) 全来源)----
func _test_counter_component() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (计数器分量组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(计数器分量组)
var floor_v := _floor_val()
Kit.check("空桶(点数≤0)恒 0 不吃修正", DamageMathScript.counter_component(0, floor_v, floor_v) == 0
and DamageMathScript.counter_component(-1, 5, floor_v) == 0)
@@ -56,7 +56,7 @@ func _test_counter_component() -> void:
# ---- 掷点折扣查档(纯函数):满阈值恒全额;档位边界/末档语义与表数组一致 ----
func _test_roll_discount_percent() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (乘区折扣组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(乘区折扣组)
var threshold := 10 # 查档探针阈值(夹具值——档位参数本身全部来自表)
var bounds: Array = db.combat.settlement.damage_roll.roll_tier_bounds
var discounts: Array = db.combat.settlement.damage_roll.roll_tier_discounts
@@ -81,7 +81,7 @@ func _test_roll_discount_percent() -> void:
# ---- 吃掷点分量算术:折扣→(暴击)→floor→+克制修正(单一取整链)----
func _test_rolled_component() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (掷点分量组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(掷点分量组)
var base := float(_floor_val() + 7) # 表值推导探针基线
var crit_mult: int = int(db.combat.settlement.damage_roll.crit_multiplier)
Kit.check("满额折扣无暴击 = floor(基线) + 修正 0", DamageMathScript.rolled_component(base, 100, false, crit_mult, 0) == int(floor(base)))
@@ -19,7 +19,7 @@ var _db
func _init() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「扩展行:专长插入的结算效果」 (效果端口宿主——装载组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「扩展行:专长插入的结算效果」类写的是裸机制的账 类写的是裸机制的账(效果端口宿主——装载组)
_db = ConfigDBScript.new()
var load_ok: bool = _db.load_tables("res://data/tables", true)
Kit.check("前置:表加载零 error", load_ok and _db.diagnostics_count("error") == 0)
@@ -54,7 +54,7 @@ func _hero_attack_value(rows: Array) -> int:
# ---- V1 端口单实例与真实发射路由 ----
func _smoke_effect_port_wiring() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「扩展行:专长插入的结算效果」 (端口单实例与六 Callable 路由组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「扩展行:专长插入的结算效果」类写的是裸机制的账 类写的是裸机制的账(端口单实例与六 Callable 路由组)
print("--- 效果端口:装配链单实例+真实发射路由 ---")
# 充能跑(蓄力周转 charge_rotation 在册——attack_commit 订阅行 attack_bonus per 蓄力周转计数器)
var orch_c = _orch(TEST_SEED)
@@ -88,7 +88,7 @@ func _smoke_effect_port_wiring() -> void:
# ---- V2 业务类零引擎直连(源码契约锚——theme_projection_test 源码锚惯例)----
func _test_business_classes_engine_free() -> void:
# 判据出处: design/gdd/术语表.md「效果端口件」 (业务类零引擎直连组)
# 判据出处: design/gdd/术语表.md「战斗与效果」效果端口件 效果端口件(业务类零引擎直连组)
print("--- 效果端口:业务类零引擎直连源码锚 ---")
for path in ["res://core/damage_controller.gd", "res://core/action_economy.gd"]:
var src := FileAccess.get_file_as_string(path)
@@ -100,7 +100,7 @@ func _test_business_classes_engine_free() -> void:
# ---- V3 伤害域事实面闭集(合成行两对照——damage_taken 真实单据流)----
func _test_biz_fact_face_closed() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「扩展行:专长插入的结算效果」 (闭面四键 biz_fact 组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「扩展行:专长插入的结算效果」类写的是裸机制的账 类写的是裸机制的账(闭面四键 biz_fact 组)
print("--- 效果端口:业务发射事实面闭集 ---")
var orch = _orch(TEST_SEED)
Kit.check("V3 begin_battle 受理", orch.begin_battle(_enc([])))
@@ -11,7 +11,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:199 (扩展行必载 effect_id——加载致命组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(扩展行必载 effect_id——加载致命组)
var db = load("res://core/config_db.gd").new()
if not db.load_tables("res://data/tables", false):
push_error("[extended_row_violation_test] 表加载失败")
@@ -154,7 +154,7 @@ func _seal_direct_with_expansion(orch) -> Vector2i:
# 四条真实路径(敌方攻击/危险格/错误封印/地形)逐路驱动:每条至少一张主角承伤单据在案,
# 且承伤计数器 == 主角承伤单据行数(每单据恰发射一次的全量判据——重复发射即计数器>行数)。
func test_all_hero_damage_paths_emit_once() -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (换图生存:全局固定减伤全伤害路径恰一次组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(换图生存:全局固定减伤全伤害路径恰一次组)
print("--- V5 全局 damage_taken:四路径逐路恰一次 ---")
# ① 敌方攻击路径(Boss 战零挖掘连停三轮——干净样本:零地形零资源单据;多轮保证伤害技在案)
var orch1 = _orch(46001)
@@ -224,7 +224,7 @@ func _plan_seal(orch, target: Vector2i) -> Dictionary:
# 同一伤害不得出现两次消费(重复发射=计数器>行数):敌方路径与地形路径两样本逐位核对——
# 地形单据带 hero_damage_consumed 标记,战斗段末 _resolve_board_flat_hero 跳过二次发射由此钉住。
func test_no_duplicate_damage_taken_event() -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (受击事件零重复组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(受击事件零重复组)
print("--- V5 全局 damage_taken:无重复消费 ---")
var orch1 = _orch(46011)
var rows1 := _collect_hero_rows(orch1)
@@ -266,7 +266,7 @@ func _auto_dig(orch) -> void:
# V2 矿脉储能:受理的付费挖格 RAP 恰 +1、AP 按表扣、板资源不变
func test_reserve_on_accepted_dig() -> void:
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:256 (换图基座:挖格产 RAP 组)
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P0 最小闭环」战斗结算发开轮通知 战斗结算发开轮通知(换图基座:挖格产 RAP 组)
print("--- V2 矿脉储能:付费挖格产 RAP ---")
var orch = _orch(46021)
Kit.check("V2 前置:战斗受理", orch.begin_battle(_enc(["vein_reserve"])))
@@ -304,7 +304,7 @@ func _drain_round_rap_accounting(orch) -> bool:
# V3 省力周转:折价门槛与扣费(can 与执行同源;base 8→扣 4)
func test_refresh_discount_gate_and_charge() -> void:
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:256 (刷新折扣门控与充能组)
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P0 最小闭环」战斗结算发开轮通知 战斗结算发开轮通知(刷新折扣门控与充能组)
print("--- V3 省力周转:折价门槛与扣费 ---")
var orch = _orch(46022)
Kit.check("V3 前置:战斗受理", orch.begin_battle(_enc(["easy_swap"])))
@@ -326,7 +326,7 @@ func test_refresh_discount_gate_and_charge() -> void:
# V3 双基座叠加:挖格产 RAP 与刷新折价同场生效
func test_double_base_stack() -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (双基座叠加组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(双基座叠加组)
print("--- V3 双基座叠加 ---")
var orch = _orch(46023)
Kit.check("V3 前置:战斗受理", orch.begin_battle(_enc(["vein_reserve", "easy_swap"])))
@@ -343,7 +343,7 @@ func test_double_base_stack() -> void:
# V12(refresh_feats 侧):无专长基线——挖格零产 RAP、刷新按表基线扣、AP 保留、上限照旧
func test_no_feats_baseline() -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (零专长基线组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(零专长基线组)
print("--- V12 无专长基线(refresh_feats 侧) ---")
var orch = _orch(46024)
Kit.check("V12 前置:战斗受理", orch.begin_battle(_enc([])))
@@ -379,7 +379,7 @@ func _br_count(orch) -> int:
# V4 成功事实只在新板就位后发射:成功恰一次;非 Active/每轮上限/RAP 不足三拒面全零事实零换图
func test_board_refresh_fact_only_on_success() -> void:
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:256 (弃图刷新事实面仅成功态组)
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P0 最小闭环」战斗结算发开轮通知 战斗结算发开轮通知(弃图刷新事实面仅成功态组)
print("--- V4 成功刷新事实:拒绝零事实 ---")
_install_br_probe()
var orch = _orch(46031)
@@ -414,7 +414,7 @@ func test_board_refresh_fact_only_on_success() -> void:
# V10 矿道红利:每次成功刷新 escrow 恰 +1 且 fx_grant_gp 行在案;拒绝零变化
func test_mine_profit_gp() -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (换图资源:刷新固定 GP 收益组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(换图资源:刷新固定 GP 收益组)
print("--- V10 矿道红利:刷新固定 GP ---")
var orch = _orch(46032)
var gp_rows := {"n": 0}
@@ -461,7 +461,7 @@ func _damage_rows_by_source(rows: Array, source: String) -> Array:
# V6 石层缓冲:全局固定减伤(危险格 pierce 8→6 两档钉死:单刷减 2·同轮多刷不叠加·未刷新轮不减;
# 地形路径减后值=max(下限, effect_value−2)——含下限保持;敌方路径照常单次发射)
func test_stone_mitigation_all_damage() -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (全局减伤全覆盖组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(全局减伤全覆盖组)
print("--- V6 石层缓冲:全局固定减伤 ---")
# S1 同轮双刷 → 危险格 pierce 8 减 2=6(叠加即 4——多刷不增钉死)
var orch1 = _orch(46041)
@@ -517,7 +517,7 @@ func test_stone_mitigation_all_damage() -> void:
# V9 坑道小憩:轮末合计回复(白盒预置承载上限 3——计数器直改属数据面注入;
# 自然累计 2 与满血未生效两形态分战场钉死)
func test_rest_rotation_cap_and_clear() -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (轮末恢复 cap 与清账组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(轮末恢复 cap 与清账组)
print("--- V9 坑道小憩:轮末恢复 ---")
# R1 白盒预置 3 层 + 刷新闸(when<3 拒第 4 层)→ 停手回复 min(3, 缺血)——护甲降档保缺血 ≥3
var orch1 = _orch(46051)
@@ -575,7 +575,7 @@ func test_rest_rotation_cap_and_clear() -> void:
# V8 蓄力周转:当轮攻击消费全部层数(上限 3 闸=白盒预置;战斗新建自然清空)
func test_charge_layers_consumed_same_round() -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (充能当轮消耗组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(充能当轮消耗组)
print("--- V8 蓄力周转:攻击消费层 ---")
var orch1 = _orch(46061)
var rows1 := _collect_damage_rows(orch1)
@@ -602,7 +602,7 @@ func test_charge_layers_consumed_same_round() -> void:
# V7 崩壁冲击:延迟群伤单(刷新时点零伤害行——战斗段末按存活目标结账)
func test_blast_defers_to_combat_segment() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (刷新群伤让位战斗段组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(刷新群伤让位战斗段组)
print("--- V7 崩壁冲击:延迟群伤 ---")
var orch = _orch(46071)
var rows := _collect_damage_rows(orch)
@@ -621,7 +621,7 @@ func test_blast_defers_to_combat_segment() -> void:
# 七件 validate/在册/稀有度 cap 对表/跨表计数器引用闭合/desc 禁词
func test_seven_feats_validate_and_pool() -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (换图系七件校验与池组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(换图系七件校验与池组)
print("--- V11 七件数据与池 ---")
var seven := {"vein_reserve": "excellent", "easy_swap": "excellent", "wall_blast": "excellent",
"charge_rotation": "excellent", "stone_mitigation": "common", "tunnel_rest": "common", "mine_profit": "rare"}
@@ -16,8 +16,8 @@ var _db
func _init() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:80 奖励未生效行=满层拒收、满血治疗等合法例外一行
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:87 显示名等玩家可见文案是数据面字段(日志消费端零文案——reason 结构化替代)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「明细流水:每一行都能指回你刚才的哪一步棋」结算过程中每一件事都写一行明细 结算过程中每一件事都写一行明细、满血治疗等合法例外一行
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「明细流水:每一行都能指回你刚才的哪一步棋」reason reason(日志消费端零文案——reason 结构化替代)
_db = ConfigDBScript.new()
if not _db.load_tables("res://data/tables", true):
print("[reward_ineffective_reason_test] FAIL — 数值表加载失败")
@@ -61,7 +61,7 @@ func _ineffective_rows(rows: Array) -> Array:
# 四类 reason 逐一命中(断言前提=各类未生效行在案;reason 键取值=分析判读契约四值)
func _assert_four_reasons() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:80 奖励未生效行四类合法例外
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「明细流水:每一行都能指回你刚才的哪一步棋」结算过程中每一件事都写一行明细 结算过程中每一件事都写一行明细
print("--- 奖励未生效 reason 四类逐一命中 ---")
# ---- ① full_hp:满血主角 + heal 型格正向(_flat_heal 满血分支即时兑付)----
@@ -19,7 +19,7 @@ var _db
func _init() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (掷点与乘区宿主——装载组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(掷点与乘区宿主——装载组)
_db = ConfigDBScript.new()
# 表加载失败不中止(承 G2/G3 同款:表损坏的红落在具体断言上——
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
@@ -44,7 +44,7 @@ func _init() -> void:
# 受理后不变量(encounter 受理后只读)。攻击单 base_value 贯通由 _smoke_damage_types 的
# hero_atk_val=100 全链路行值承载(同夹具既有覆盖——派生读在攻击链上工作即行值随 override 走)----
func _smoke_hero_atk_derived() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (英雄攻击派生组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(英雄攻击派生组)
var rng_a = load("res://core/rng_service.gd").new()
rng_a.set_master_seed(4242)
var s_a = load("res://core/battle_orchestrator.gd").new(_db, rng_a)
@@ -67,7 +67,7 @@ func _smoke_hero_atk_derived() -> void:
# → heavy 伤害 == light −1、ward == light +1(要求基线伤害 ≥ 2——地板 1 会吞 −1 位移)。
# 承伤位移红线(卡片 §8 L3):全局位移只允许 ±1 量级——非此量级 = 矩阵消费面有未盘点的第二落点(停机)。
func _smoke_enemy_attack_type() -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:295 (敌攻击类型行集组)
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「调参表」配置表共三张 配置表共三张(敌攻击类型行集组)
print("--- 敌方攻击类型轴(迭代 24 N3)---")
# ① 表列:20 行全填 normal(N3 全填不做差异化——Q9)
var at_ok := true
@@ -126,7 +126,7 @@ func _smoke_enemy_attack_type() -> void:
# ---- 护甲等级掷点·行为面(折扣档分布 / nat20 暴击 / 伤害下限 / 棋盘来源必中)----
func _smoke_armor_roll() -> void:
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:254 (护甲掷点与叠层合并组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(护甲掷点与叠层合并组)
print("--- 护甲等级掷点(查档纯函数 + 暴击 + 伤害下限 + AC12 分布 + 棋盘必中)---")
# ① 查档纯函数:全掷点域逐位对照(AC10 / AC12)+ EV 锚(AC10 期望减免 21.25% —— registry 参考数)
var expect_ac10 := {100: 11, 75: 3, 50: 4, 25: 2} # 掷 10-20 全额 / 7-9 / 3-6 / 1-2
@@ -345,7 +345,7 @@ func _auto_play_round(settlement, out: Dictionary) -> void:
# 基线构成:基线 100——hero 攻击类型=normal(锻造工坊配置默认值,
# hero.tres 无两轴字段)对轻甲中性 0 修正(目标 = L1 地精轻甲;AC 0 恒全额非暴击种子)。
func _smoke_pool_wiring() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
print("--- 主角乘区接线 + 硬化折半方向 ---")
var base_row := _hero_attack_row_with({}, 100, 20260918)
var up_row := _hero_attack_row_with({"effects": ["attack_up"]}, 100, 20260918)
@@ -387,7 +387,7 @@ func _hero_attack_row_with(opts: Dictionary, hero_atk_val: int, seed_val: int) -
# ---- 攻击类型 × 护甲克制 + 标错惩罚冒烟(护甲快照/克制矩阵/充能/反噬三选一)----
func _smoke_damage_types() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
print("--- 攻击类型 × 护甲克制 + 标错惩罚 ---")
# ① 护甲类型快照传播(spawn 行值 → 单位字典)
var enemy_system = load("res://core/unit_container.gd").new(_db)
@@ -482,7 +482,7 @@ func _find_seal_target(minesweeper, want_mine: bool) -> Dictionary:
# d_tick = max(damage_floor, pool_damage(floor(基线×档位%), 0, 0)),档位读数随行重建可归因)----
func _smoke_attack_chain_fresh_pool() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
print("--- 战斗结算·fresh 池攻击链回归(Bug#2·掷点口径)---")
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(20260913)
@@ -22,7 +22,7 @@ var _db
func _init() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:360 (轮内流与技能池宿主——装载组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(轮内流与技能池宿主——装载组)
_db = ConfigDBScript.new()
# 表加载失败不中止(承 G2/G3/G4/G5 同款:表损坏的红落在具体断言上——
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
@@ -49,7 +49,7 @@ func _init() -> void:
# ---- 完整战斗回放(自动玩家,确定性)——回放断言:同种子两遍步骤流逐行相同 ----
func _smoke_full_battle(L: int, D: int, label: String) -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (全战斗回放——五段全序组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(全战斗回放——五段全序组)
print("--- 完整战斗回放:%s ---" % label)
var run1 = _run_battle(L, D)
var run2 = _run_battle(L, D)
@@ -84,7 +84,7 @@ func _smoke_full_battle(L: int, D: int, label: String) -> void:
func _run_battle(L: int, D: int, axes: Dictionary = {}) -> Dictionary:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (战斗驱动组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(战斗驱动组)
# 每遍全新 RngService(同 master 种子)——回放断言的隔离前提(地图战斗资源 AC"两套全新 RngService+地图战斗资源"同款)
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(42)
@@ -149,7 +149,7 @@ func _auto_play_round(settlement, out: Dictionary) -> void:
# ---- 行动经济·轮内刷新冒烟(方案 A:Active 相位当场换图继续挖)----
func _smoke_active_refresh() -> void:
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:262 (停手转存储备与轮内刷新组)
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P1 / P2 后置」后置原因 后置原因(停手转存储备与轮内刷新组)
print("--- 行动经济·轮内刷新(方案 A)---")
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(20260912)
@@ -256,7 +256,7 @@ func _active_refresh_replay() -> Array:
# ---- 遭遇随机化冒烟(难度曲线与Boss Core Rule 8:区间骰/encounter 流/可回放/空表定值路径)----
func _smoke_encounter_roll() -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:296 (遭遇区间骰——摇号确定性组)
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「调参表」配置表共三张 配置表共三张(遭遇区间骰——摇号确定性组)
print("--- 遭遇随机化(unit_count 区间骰)---")
var counts: Array = []
for i in range(20):
@@ -391,7 +391,7 @@ func _encounter_replay(seed_val: int) -> Array:
# 五段全序断言(战斗结算 验收"五段全序"+ 行型封闭 10 类):逐轮行相位序 = 授予 → 增益/减益 → 战斗 → 衰减 → 判定。
func _smoke_settlement_segments() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
print("--- 五段全序 + 行型封闭 ---")
Kit.check("segment_order 五段冻结在位(表值 = 拍板序恒等)",
Array(_db.combat.settlement.segment_order) == SettlementTable.FROZEN_SEGMENT_ORDER
@@ -510,7 +510,7 @@ func _smoke_skill_pool() -> void:
# ① 数据面:技能表行集 + 普攻锁死 + 建议池行值 + 空池不可能(结构断言)
func _smoke_skill_pool_data() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
Kit.check("技能表十六行(普攻/突刺/蓄力/重击/硬化 + 撕咬/毒爆/蛛网束缚 + 大地脉动 + 震地怒击/遏毒/岩崩 + 毒吐/盾击——前三批 + Boss 半血解锁技三行〔迭代14④ T5〕+ 普通敌错峰两行〔迭代 24 N2〕+ 触发条件批示范两行〔孤注守势/趁隙偷袭〕)", _db.combat.skill.rows.size() == 16)
var basic: Dictionary = _db.combat.skill.row_by_id("attack")
Kit.check("普攻行:倍率恒 1 · 冷却恒 0(域校验锁死——池恒非空的结构前提)",
@@ -727,7 +727,7 @@ func _fresh_rng(seed_val: int):
# 单敌轨迹不独立复放——轨迹取数与其它流交错,无法脱离全序重建;
# 同种子全战斗逐位复现由 ② 全对拍承载,单点定位归事件日志。
func _smoke_skill_pool_replay_independence() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var seed_val := -1
for s in range(1, 60):
var seqs := _record_pool_trajectories(s, 1)
@@ -781,7 +781,7 @@ func _record_pool_trajectories(seed_val: int, rounds: int) -> Dictionary:
# 2026-10-28 重锚 [0.82, 1.02](照酋长先例 ±0.10 绝对幅度,中值取理论稳态 0.92;旧带 [1.00,1.20] 系触发器前
# 唯一特殊技=突刺的池结构下登记,随池构成换代作废;撤销证明=带宽回退旧值本断言复红)→ 宽带登记。
func _smoke_skill_pool_ev_anchor() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var bands := {"goblin": [0.82, 1.02], "bugbear": [0.97, 1.03], "ogre_chief": [1.10, 1.30]} # 地精重锚 2026-10-28(触发条件批孤注守势入池稀释,无情境口径实测 0.9148;EV 锚注 enemy.tres)· 酋长重锚(震地怒击半血解锁入池,含闸长期速率上移:实测 1.1948;EV 锚注 enemy.tres)
var species := ["goblin", "bugbear", "ogre_chief"]
var rng = load("res://core/rng_service.gd").new()
@@ -837,7 +837,7 @@ func _smoke_skill_pool_ev_anchor() -> void:
# ⑤ 死亡打断作废(摇定后、兑现前死亡 → 本拍技能作废、不动手、不进账)
func _smoke_skill_pool_death_void() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var void_seed := -1
for s in range(1, 400):
var rg = load("res://core/rng_service.gd").new()
@@ -877,7 +877,7 @@ func _smoke_skill_pool_death_void() -> void:
# ⑥ 加载校验拒绝(单表域校验 + 跨表池构成纪律)
func _smoke_skill_pool_validation_reject() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var skill_table = load("res://data/schemas/skill_table.gd").new()
var enemy_table = load("res://data/schemas/enemy_table.gd").new()
enemy_table.rows.assign([{"enemy_id": "x", "display_name": "x", "pool": [{"skill_id": "ghost", "weight": 1}]}])
@@ -936,7 +936,7 @@ func _has_err_category(errs: Array, category: String) -> bool:
# 停手轮驱动 (2,9)——零挖掘零封印 → 零池,伤害行可逐拍精确复算;种子 hunt 至少各命一粒毒爆伤害行
# 与蛛网束缚施放行;毒分量随开战掷定的攻击基线缩放(atk 区间 2–4 → rider 1–3)。
func _smoke_debuff_rider() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var venom_seed := -1
var venom_check_ok := true
var venom_rows_seen := 0
@@ -1007,7 +1007,7 @@ func _smoke_debuff_rider() -> void:
# ---- 天赋树六键行为冒烟(V10:开局姿态窗/危险直觉限次/财富之道聚散/守侧失误补偿;
# 引擎直构 + 编排授予段直注(_grant_seg._judge_seal=结算授予段封印判定单口))----
func _smoke_counter_buckets() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
print("--- 效果引擎无状态化四桶正向验收(卡② §9 V1/V6)---")
# V1——adventure 桶跨战持久:同一宿主字典下两战各真实 request_dig 一次,
# 断付费计数经 ctx 就地写入宿主字典并跨战累积(副本搬运态:读不到上一战值→第 2 战仍 1,此断言会红)。
@@ -1070,7 +1070,7 @@ func _smoke_counter_buckets() -> void:
# V6 形态先例同源:直入真实管线缝(_judge_seal 直调同款口径)。
func _smoke_extended_rows() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
print("--- 扩展行收敛:fx_reveal 兑付/落空 ---")
var RigS = load("res://core/battle_orchestrator.gd") # 局部装配别名(_smoke_counter_buckets 同款——跨函数不共享局部量)
var enc_fx = {"level_index": 1, "node_depth": 0, "hero_hp": 40, "hero_atk": 8, "hero_max_hp": 40,
@@ -1116,7 +1116,7 @@ func _smoke_extended_rows() -> void:
# 蓄力表值 2 拍衰减后剩 1 拍仍在池)→ 逐敌读敌方输出池。判据=施放者与被他敌的池读数差。
func _smoke_enemy_buff_targets_self() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var emp_mag: int = int(_db.combat.status_effects.row_by_id("empower").magnitude)
var sc_script = load("res://core/status_container.gd")
var found_seed := -1
@@ -1165,7 +1165,7 @@ func _smoke_enemy_buff_targets_self() -> void:
# 种子狩猎沿 _smoke_enemy_buff_targets_self 同款;叠层行为=容器级再授(roll_multiplier 先例形态)。
func _check_defensive_stance_values() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var row: Dictionary = _db.combat.status_effects.row_by_id("defensive_stance")
Kit.check("defensive_stance 生产行值:magnitude=-25 percent/duration_settlements=2/accumulate max_stack=1〔QA余 V9〕",
int(row.get("magnitude", 0)) == -25 and String(row.get("unit", "")) == "percent"
@@ -22,7 +22,7 @@ var _db
func _init() -> void:
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:231 (封印与极性宿主——装载组)
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「调参表」本系统无自有参数 本系统无自有参数(封印与极性宿主——装载组)
_db = ConfigDBScript.new()
# 表加载失败不中止(承 G2/G3/G4 同款:表损坏的红落在具体断言上——
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
@@ -48,8 +48,8 @@ func _init() -> void:
# ---- 末点 AP 封印轮末结算(playtest 缺陷②回归:末点 AP 花在封印必须终结轮次进入下一轮)----
func _smoke_seal_ap_exhausted() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:139 封印判定批与溢价兑付链照常(保留组——封印受理即揭示改版零改动)〔封印改 V5〕
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:260 (末点 AP 耗尽即收轮组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「授予段兑付:极性路由,四类动作各归各系统资源」授予段消费结算队列 授予段消费结算队列(保留组——封印受理即揭示改版零改动)〔封印改 V5〕
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P1 / P2 后置」后置原因 后置原因(末点 AP 耗尽即收轮组)
print("--- 排雷玩法·封印动作耗尽末点 AP 回归 ---")
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(20260911)
@@ -327,8 +327,8 @@ func _rows_at(rows: Array, source_class: String, cell) -> Array:
func _smoke_clear_reward_chain() -> void:
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:235 (清图奖励链——清图槽对象身份组)
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:235 (清图奖励链——清图槽对象身份组)
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「格面资源:每个非封锁格都带一个,摇号纪律不变」每张雷图装上时 每张雷图装上时(清图奖励链——清图槽对象身份组)
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「格面资源:每个非封锁格都带一个,摇号纪律不变」每张雷图装上时 每张雷图装上时(清图奖励链——清图槽对象身份组)
print("--- 清图奖励·双份兑付链(完美封印 / 零兑付 / 第二份被拒 / 高光记实)---")
# ① 真实流完美封印:标中一面真雷封印 + 零误标 + 清全图 → grant_clear 身份(clear_blast)双份真实兑付
var rows: Array = []
@@ -357,8 +357,8 @@ func _smoke_clear_reward_chain() -> void:
# 弱形式登记:正常战斗流下"授段时刻无存活敌"不可达——敌全灭当轮判定段即判胜并终止战斗,而清图批在判定段之前,
# 恒有存活敌;故本组直调编排私有面构造状态,只断言"路径存在 + 行为符合契约"(构造手法见各行注释)。
func _smoke_clear_reward_zero_paths() -> void:
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:240 (无存活敌群伤记「奖励未生效」组)
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:240 (无存活敌群伤记「奖励未生效」组)
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「验收标准」奖励未生效 奖励未生效(无存活敌群伤记「奖励未生效」组)
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「验收标准」奖励未生效 奖励未生效(无存活敌群伤记「奖励未生效」组)
# ②-a 首份零兑付判定(无存活敌)→ first_ok=false + 未生效行
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(20260915)
@@ -413,8 +413,8 @@ func _smoke_clear_reward_zero_paths() -> void:
# 轮内刷新 provenance 守卫:刷新换来的图同轮清图不发清图奖励(_board_from_midround_refresh 守卫)
func _smoke_refresh_provenance_guard() -> void:
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:237 (换图重置:旧封印印记先判定后消失组)
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:237 (换图重置:旧封印印记先判定后消失组)
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」换图重置 换图重置(换图重置:旧封印印记先判定后消失组)
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」换图重置 换图重置(换图重置:旧封印印记先判定后消失组)
print("--- 轮内刷新 provenance 守卫(刷新图清图不发清图奖励)---")
var rows: Array = []
var run := _run_full_clear(20260916, true, rows)
@@ -441,9 +441,9 @@ func _smoke_refresh_provenance_guard() -> void:
func _smoke_polarity_routing() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:139 封印判定批与溢价兑付链照常(保留组——封印受理即揭示改版零改动)〔封印改 V5〕
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:366 (极性路由:正向只兑正向、负向只兑负向组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:366 (极性路由:正向只兑正向、负向只兑负向组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「授予段兑付:极性路由,四类动作各归各系统资源」授予段消费结算队列 授予段消费结算队列(保留组——封印受理即揭示改版零改动)〔封印改 V5〕
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「轮末五段结算:一轮从收场走到判定」玩家行动点花完 玩家行动点花完(极性路由:正向只兑正向、负向只兑负向组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「轮末五段结算:一轮从收场走到判定」玩家行动点花完 玩家行动点花完(极性路由:正向只兑正向、负向只兑负向组)
print("--- 极性路由(挖安全格正向 / 挖危险格负向 / 标中正向 / 标空负向)---")
# 战斗随机值面随全局序漂移——构造种子按行为面扫描(谓词见 _polarity_probe_accepts)
var probe := {}
@@ -581,8 +581,8 @@ func _smoke_polarity_routing() -> void:
# 场景 B(② 改判〔封印改 V2〕):标危险格 → 挖封印格被拒 → 收轮(标中判定照发)。
# 场景 C(①③):标安全格 + 标危险格 → 不挖收轮 → 标空/标中判定照常。
func _smoke_seal_irreversible_quadrants() -> void:
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:231 (封印不可逆四情况组)
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:231 (封印不可逆四情况组)
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「调参表」本系统无自有参数 本系统无自有参数(封印不可逆四情况组)
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「调参表」本系统无自有参数 本系统无自有参数(封印不可逆四情况组)
print("--- 封印不可逆四情况(禁撤封印 + 挖封印格兑付改判)---")
# 场景 A:安全格直挖(情况④)+ seal_pull/重复封印拒绝面
var rng_a = load("res://core/rng_service.gd").new()
@@ -696,8 +696,8 @@ func _smoke_seal_irreversible_quadrants() -> void:
# 负向字典逐型直验(类型化兑付行协议):找真实板上各型非封锁格,直调 grant_routed 负向路由(att 归因束形态),
# 断言每型的兑付形态(enrage/off_guard/sapped 效果行、heal 直伤行、blast 警觉行、action 行动点排队)。
func _smoke_negative_dictionary() -> void:
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:256 (下轮行动点修正排队与兑现组)
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:256 (下轮行动点修正排队与兑现组)
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P0 最小闭环」战斗结算发开轮通知 战斗结算发开轮通知(下轮行动点修正排队与兑现组)
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P0 最小闭环」战斗结算发开轮通知 战斗结算发开轮通知(下轮行动点修正排队与兑现组)
print("--- 负向字典逐型直验(sapped 在位 / heal 直伤 / blast 警觉 / action 行动点)---")
# 数据面:sapped 行在位(状态表七行 + effect_pool_map 映射在位)
var sapped: Dictionary = _db.combat.status_effects.row_by_id("sapped")
@@ -791,8 +791,8 @@ func _smoke_negative_dictionary() -> void:
# 资源面断言:chain/dig 事件恒携带 resource=true(危险格同权);initial 恒 false(封锁格);
# 封锁格查询 = null、危险格未开恒可查。
func _smoke_resource_surface() -> void:
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:235 (资源面只读查询组)
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:235 (资源面只读查询组)
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「格面资源:每个非封锁格都带一个,摇号纪律不变」每张雷图装上时 每张雷图装上时(资源面只读查询组)
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「格面资源:每个非封锁格都带一个,摇号纪律不变」每张雷图装上时 每张雷图装上时(资源面只读查询组)
print("--- 格面资源资格面(危险格携带 / 封锁格无资源)---")
var run1 = _run_battle(1, 0)
var run2 = _run_battle(2, 0)
@@ -843,7 +843,7 @@ func _smoke_resource_surface() -> void:
# 断言真值依赖生产行值(行值变更即红)。合成行旧断言保留并存(零删除)。
func _check_enemy_alert_production_row() -> void:
# 判据出处: design/engineering/test-conventions.md:133 (真实入口断言——生产行值驱动)
# 判据出处: design/engineering/test-conventions.md「8.4 真实入口断言」真实入口断言 真实入口断言(真实入口断言——生产行值驱动)
var row: Dictionary = _db.run.reward.row_by_id("enemy_alert")
Kit.check("enemy_alert 生产行值:blast 负向 effect=alert power0 weight0(不入池警觉行)〔QA余 V12〕",
String(row.get("cell_type", "")) == "blast" and String(row.get("polarity", "")) == "negative"
@@ -863,7 +863,7 @@ func _check_enemy_alert_production_row() -> void:
func _check_ap_drain_production_row() -> void:
# 判据出处: design/engineering/test-conventions.md:133 (真实入口断言——生产行值驱动)
# 判据出处: design/engineering/test-conventions.md「8.4 真实入口断言」真实入口断言 真实入口断言(真实入口断言——生产行值驱动)
var row: Dictionary = _db.run.reward.row_by_id("ap_drain")
Kit.check("ap_drain 生产行值:action 负向 power=1 weight0〔QA余 V12〕",
String(row.get("cell_type", "")) == "action" and String(row.get("polarity", "")) == "negative"
@@ -419,8 +419,8 @@ var _db
func _init() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (结算接线同种子逐项 golden 对拍组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:134 受理零兑付、改判路径死——流水零「奖励作废(封印格直接挖开)」行、
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(结算接线同种子逐项 golden 对拍组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「授予段兑付:极性路由,四类动作各归各系统资源」授予段消费结算队列 授予段消费结算队列、改判路径死——流水零「奖励作废(封印格直接挖开)」行、
# 同种子驱动序 golden 实测零漂移零重录(挖封印格被拒——驱动序不含该路径)〔封印改 V6〕
_db = ConfigDBScript.new()
var load_ok: bool = _db.load_tables("res://data/tables", true)
@@ -13,7 +13,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:293 Boss 半血解锁技宿主(装载组)
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「调参表」配置表共三张 配置表共三张(装载组)
var db = ConfigDBScript.new()
var load_ok: bool = db.load_tables("res://data/tables", true)
Kit.check("前置:表加载零 error", load_ok and db.diagnostics_count("error") == 0)
@@ -26,7 +26,7 @@ func _init() -> void:
# 门谓词:卓尔 (2,9) hp 130(×mult 1.0)→ venom_curb unlock 50 → 阈值 round(130×0.5)=65
func _boss(db, L: int, D: int, kind := "boss"):
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var ec = UnitContainerScript.new(db)
var ok: bool = ec.spawn({"level_index": L, "node_depth": D, "hero_hp": int(db.combat.hero.max_hp), "row_kind": kind})
Kit.check("前置:spawn (%d,%d) 受理" % [L, D], ok)
@@ -45,7 +45,7 @@ func _has_sid(arr: Array, sid: String) -> bool:
func _test_gate_predicate(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:143 (门谓词:条件不满足不进可摇集合组)
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「精英行:现役敌种的强化版,池=继承基础池+附加技」精英怪是某个现役敌种的强化版本 精英怪是某个现役敌种的强化版本(门谓词:条件不满足不进可摇集合组)
var ec = _boss(db, 2, 9)
var u: Dictionary = _boss_u(ec)
var mhp: int = int(u.max_hp)
@@ -74,7 +74,7 @@ func _test_gate_predicate(db) -> void:
# 闩不可逆:解锁后治疗抬回满血 → 复查零新解锁、可摇集合不回退
func _test_latch_irreversible(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:143 (闩型条件首次为真整场保持组)
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「精英行:现役敌种的强化版,池=继承基础池+附加技」精英怪是某个现役敌种的强化版本 精英怪是某个现役敌种的强化版本(闩型条件首次为真整场保持组)
var ec = _boss(db, 2, 9)
var u: Dictionary = _boss_u(ec)
ec.apply_damage(u, int(u.max_hp) / 2) # → 半血触发
@@ -86,7 +86,7 @@ func _test_latch_irreversible(db) -> void:
# 普通行无字段逐位零扰动:地精 (1,0) 池快照零 unlock 键、过滤恒空转、可摇=全池
func _test_plain_rows_zero_drift(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:301 (普攻倍率 1 特例——零漂移组)
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「开战生成:主角数据行与一场 1–4 个敌人」战斗开始时 战斗开始时(普攻倍率 1 特例——零漂移组)
var ec = load("res://core/unit_container.gd").new(db)
Kit.check("零扰动前置:巨蜘蛛首遇带 spawn(池三行全无 trigger——快照键策略钉死载体)", ec.spawn({"level_index": 2, "node_depth": 1, "hero_hp": int(db.combat.hero.max_hp)}))
var u: Dictionary = ec.all_enemies()[0]
@@ -9,7 +9,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:143 (触发条件机制 V1–V10 组)
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「精英行:现役敌种的强化版,池=继承基础池+附加技」精英怪是某个现役敌种的强化版本 精英怪是某个现役敌种的强化版本(触发条件机制 V1–V10 组)
var db = load("res://core/config_db.gd").new()
if not db.load_tables("res://data/tables", false):
print("[trigger_cond_test] FAIL — 数值表加载失败")
@@ -15,7 +15,7 @@ var _db
func _init() -> void:
# 判据出处: design/gdd/systems/排雷循环/地形变异.md:151 变异布置宿主(装载组)
# 判据出处: design/gdd/systems/排雷循环/地形变异.md「验收标准」候选池空合法 候选池空合法(装载组)
_db = ConfigDBScript.new()
# 表加载失败不中止(承 G2/G3/G4/G5 同款:表损坏的红落在具体断言上——
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
@@ -55,7 +55,7 @@ class _CountVariantRng extends RngServiceCore:
# 本段经 begin_battle 走完整初始化序后断言:门控一致性 / 布置域 / 数量公式 / 连通片上限 / 确定性。
func _smoke_variant_placement(L: int) -> void:
# 判据出处: design/gdd/systems/排雷循环/地形变异.md:63 (战内布置段门控组)
# 判据出处: design/gdd/systems/排雷循环/地形变异.md「变异框架与类型清单」每种变异是配置表里的一行具名声明 每种变异是配置表里的一行具名声明(战内布置段门控组)
print("--- 地形变异 布置段(L%d)---" % L)
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(42)
@@ -149,7 +149,7 @@ func _variant_dump(b) -> String:
func _smoke_global_variant() -> void:
# 判据出处: design/gdd/systems/排雷循环/地形变异.md:74 (全局替换制与回落组)
# 判据出处: design/gdd/systems/排雷循环/地形变异.md「全局作用域型」型变异是 型变异是(全局替换制与回落组)
print("--- 全局作用域变异(门控三维 + 全局池空兜底回落 + 资源面偏斜)---")
# ① 跨字段互锁负样本(resource_face ⟺ scope=global 三条 + effect_value 新域 [0,50])
var vt = load("res://data/schemas/variation_table.gd").new()
@@ -344,7 +344,7 @@ func _errs_has_cross_field(errs: Array) -> bool:
# 全称不可断)。可达判据=①静态(布置面零字面量下界)+②同种子改值产物互异(真实入口=begin_battle 布置段)。
func _test_pack_min_from_table() -> void:
# 判据出处: design/gdd/systems/排雷循环/地形变异.md:63 (连通片格数 [pack_min,pack_max] 读表组)
# 判据出处: design/gdd/systems/排雷循环/地形变异.md「变异框架与类型清单」每种变异是配置表里的一行具名声明 每种变异是配置表里的一行具名声明(连通片格数 [pack_min,pack_max] 读表组)
# ① 静态:布置面零字面量下界(randi_range(2, 退役——下界读 pack_min 表头单点)
var src := FileAccess.get_file_as_string("res://core/board_installer.gd")
Kit.check("布置面零字面量下界(randi_range(2, 退役、下界读表单点在位)〔架构整改 V10·静态〕",
@@ -376,7 +376,7 @@ func _test_pack_min_from_table() -> void:
# 授予段地形批(on_open 兑现 flat_damage);mine_dust=信息型遮蔽解析数据面(board.variant_ids×表行 effect)。
func _test_l3_rockfall_minedust_rows() -> void:
# 判据出处: design/gdd/systems/排雷循环/地形变异.md:63 (L3 布置段门控与效果兑现组)
# 判据出处: design/gdd/systems/排雷循环/地形变异.md「变异框架与类型清单」每种变异是配置表里的一行具名声明 每种变异是配置表里的一行具名声明(L3 布置段门控与效果兑现组)
var pool := {}
for r in _db.combat.variation.variant_pool(3, "deep_underdark"):
pool[String(r.variant_id)] = r
@@ -27,7 +27,7 @@ func _init() -> void:
# ---- 类型闸断言(V7——project.godot warning 配置在位〔源码断言〕+审计器脚本在位;
# 审计器归零判定走 static_scan S9 闸机,此处兜配置面)----
func _smoke_type_gate() -> void:
# 判据出处: design/engineering/code-conventions.md:41 (封装边界——类型闸源码扫描组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」封装边界 封装边界(封装边界——类型闸源码扫描组)
var pj: String = FileAccess.get_file_as_string("res://project.godot")
Kit.check("V7 类型闸 warning 配置在位(untyped_declaration=1 显形)〔迭代27 T5〕",
pj.contains("gdscript/warnings/untyped_declaration=1"))
@@ -38,7 +38,7 @@ func _smoke_type_gate() -> void:
# ---- 卫生件 grep 闸(V8——死代码/字符串 Callable/影子账残留零命中;源码扫描面)----
func _smoke_hygiene_gates() -> void:
# 判据出处: design/engineering/code-conventions.md:54 (模态覆盖层层级与登记纪律——卫生闸组)
# 判据出处: design/engineering/code-conventions.md「2.3 模态覆盖层层级规则」打开任何模态覆盖层时 打开任何模态覆盖层时(模态覆盖层层级与登记纪律——卫生闸组)
var callables := 0
for d in ["res://core", "res://presentation", "res://data"]:
var dir := DirAccess.open(d)
@@ -18,7 +18,7 @@ const Kit := preload("res://tests/unit/test_kit.gd") # T6 收口:_check/汇
func _init() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var db = ConfigDBScript.new()
var load_ok: bool = db.load_tables("res://data/tables", true)
Kit.check("前置:表加载零 error", load_ok and db.diagnostics_count("error") == 0)
@@ -41,8 +41,8 @@ func _init() -> void:
# ---- B1 兑付配方词表:五配方/三目标规则/双结账政策——常量非空且互异(封闭枚举负空间) ----
func _test_damage_controller_vocabularies() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「伤害单据与伤害控制器」 (事件/事实/效果类型/算子四词表封闭——契约词表组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「伤害单据与伤害控制器」 (事件/事实/效果类型/算子四词表封闭——契约词表组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「伤害单据与伤害控制器:所有伤害走同一道门」游戏里的每一份伤害 游戏里的每一份伤害(事件/事实/效果类型/算子四词表封闭——契约词表组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「伤害单据与伤害控制器:所有伤害走同一道门」游戏里的每一份伤害 游戏里的每一份伤害(事件/事实/效果类型/算子四词表封闭——契约词表组)
var kinds: Array = [
DamageControllerScript.KIND_HERO_ATTACK, DamageControllerScript.KIND_ENEMY_SKILL,
DamageControllerScript.KIND_BOARD_TYPED, DamageControllerScript.KIND_BOARD_BLAST,
@@ -72,8 +72,8 @@ func _test_damage_controller_vocabularies() -> void:
# ---- D2↔B1:掷点用途标签 ∈ RngService 封闭词表(EC12——跨系统字面量契约的成员性断言) ----
func _test_rng_tag_closure(db) -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流」 (流 scope 封闭词表组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流」 (流 scope 封闭词表组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流:随机只从一个服务按号取,同种子必同局」用户两轮复裁 用户两轮复裁(流 scope 封闭词表组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流:随机只从一个服务按号取,同种子必同局」用户两轮复裁 用户两轮复裁(流 scope 封闭词表组)
var stream_label: String = String(db.combat.settlement.damage_roll.armor_roll_stream)
Kit.check("settlement.armor_roll_stream ∈ RngService 封闭标签词表(EC12)",
RngServiceScript.PURPOSE_TAGS.has(stream_label))
@@ -87,8 +87,8 @@ func _test_rng_tag_closure(db) -> void:
# ---- B1→D1 行协议:单据九栏缺省齐备 + 协议公共键形态 ----
func _test_ticket_nine_columns() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (单据九列协议组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (单据九列协议组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(单据九列协议组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(单据九列协议组)
var ctrl = _bare_controller()
var t: Dictionary = ctrl.open_ticket(DamageControllerScript.KIND_BOARD_FLAT_HERO, "mine_hit", "契约探针",
{"channel": "棋盘兑付", "base_value": 1, "target_rule": DamageControllerScript.TARGET_HERO, "ri": 0})
@@ -118,8 +118,8 @@ func _bare_controller():
# ---- B4→B3:增益授予布尔受理口径(受理/拒绝二元面 + 投影一致性) ----
func _test_status_boolean_acceptance(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:250 (受理布尔面组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:250 (受理布尔面组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(受理布尔面组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(受理布尔面组)
var effects = StatusContainerScript.new(db)
# EC1 域闭:notify_battle_start 前授予 = false(受理面封闭)
var any_row: Dictionary = {}
@@ -146,8 +146,8 @@ func _test_status_boolean_acceptance(db) -> void:
# 个体键直传字面量("e1"/"e2"/"e3"——拼写约定单点在 StatusContainer.owner_key_for,测试面模拟授予路径逐只授)
func _test_status_individual_isolation(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:251 (按个体归属组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:251 (按个体归属组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(按个体归属组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(按个体归属组)
var effects = StatusContainerScript.new(db)
effects.notify_battle_start()
var src := {"source_class": "seal_hit", "origin_cell": Vector2i(-1, -1), "round_index": 0}
@@ -169,8 +169,8 @@ func _test_status_individual_isolation(db) -> void:
func _test_status_grant_all_per_unit(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:252 (授予即生效组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:252 (授予即生效组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(授予即生效组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(授予即生效组)
var effects = StatusContainerScript.new(db)
effects.notify_battle_start()
var src := {"source_class": "mine_hit", "origin_cell": Vector2i(-1, -1), "round_index": 0}
@@ -197,8 +197,8 @@ func _test_status_grant_all_per_unit(db) -> void:
func _test_status_death_clears(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:250 (战斗结束清空组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:250 (战斗结束清空组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(战斗结束清空组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(战斗结束清空组)
var effects = StatusContainerScript.new(db)
effects.notify_battle_start()
var src := {"source_class": "seal_hit", "origin_cell": Vector2i(-1, -1), "round_index": 0}
@@ -212,8 +212,8 @@ func _test_status_death_clears(db) -> void:
func _test_status_merge_per_unit(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:253 (只登记不去重组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:253 (只登记不去重组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(只登记不去重组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(只登记不去重组)
var effects = StatusContainerScript.new(db)
effects.notify_battle_start()
var src := {"source_class": "enemy_action", "origin_cell": Vector2i(-1, -1), "round_index": 0}
@@ -236,8 +236,8 @@ func _test_status_merge_per_unit(db) -> void:
# ---- B4 结算链契约(断言补齐批——①增益状态结算链):衰减逐值/战斗结束全清/满层拒绝/独立并存/首授快照 ----
func _test_status_decay_and_clear(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:21 (先兑付后衰减组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:21 (先兑付后衰减组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「系统范围」边界这样划 边界这样划(先兑付后衰减组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「系统范围」边界这样划 边界这样划(先兑付后衰减组)
var effects = StatusContainerScript.new(db)
effects.notify_battle_start()
var src := {"source_class": "seal_hit", "origin_cell": Vector2i(-1, -1), "round_index": 0}
@@ -258,8 +258,8 @@ func _test_status_decay_and_clear(db) -> void:
func _test_status_stack_full_reject(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:255 (满层拒绝原子且留痕组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:255 (满层拒绝原子且留痕组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(满层拒绝原子且留痕组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(满层拒绝原子且留痕组)
var effects = StatusContainerScript.new(db)
effects.notify_battle_start()
var src := {"source_class": "seal_hit", "origin_cell": Vector2i(-1, -1), "round_index": 0}
@@ -277,8 +277,8 @@ func _test_status_stack_full_reject(db) -> void:
func _test_status_independent_branch(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:257 (合成不设上下限组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:257 (合成不设上下限组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(合成不设上下限组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(合成不设上下限组)
var effects = StatusContainerScript.new(db)
effects.notify_battle_start()
var probe := {
@@ -303,8 +303,8 @@ func _test_status_independent_branch(db) -> void:
func _test_status_snapshot_first_grant(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:258 (快照抗重载组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md:258 (快照抗重载组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(快照抗重载组)
# 判据出处: design/gdd/systems/战斗循环/增益状态.md「验收标准」状态池寿命可答 状态池寿命可答(快照抗重载组)
var effects = StatusContainerScript.new(db)
effects.notify_battle_start()
var src_first := {"source_class": "seal_hit", "origin_cell": Vector2i(3, 4), "round_index": 1}
+5 -5
View File
@@ -17,7 +17,7 @@ var _db
func _init() -> void:
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md:281 冒险结构与专长宿主(装载组)
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「验收标准」开始新冒险 开始新冒险(装载组)
_db = ConfigDBScript.new()
# 表加载失败不中止(承 G2/G3/G4/G5 同款:表损坏的红落在具体断言上——
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
@@ -59,7 +59,7 @@ func _hits_kind(hits: Array, kind: String) -> Array:
# ② 冒险结构 API 闸(状态机受理面——重复开始拒绝 / 入口停点 / 放弃两态)
func _smoke_adventure_api() -> void:
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md:283 (冒险 API 组:开始受理/序列/回调)
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「冒险的一生:开始、推进与三种结局」在本文是一个计量单位 在本文是一个计量单位(冒险 API 组:开始受理/序列/回调)
print("--- 冒险结构 API 闸(重复开始拒绝 · 入口停点 · 放弃两态受理)---")
var adr = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(42))
adr.set_hero_override(900, 400) # 首战速胜档(放弃的非战斗受理要走到选路态)
@@ -122,7 +122,7 @@ func _api_mark_node(_node: Dictionary, _info: Dictionary, seq: Array) -> void:
# ③ 冒险验收断言(映射 冒险结构.md 验收标准——表覆盖/满配冒险成功/种子复现/大奖励/败北线/
# 重复拒绝/GP 跨关延续/加算区同账/恢复数学/放弃)
func _smoke_adventure() -> void:
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md:284 (冒险生命周期组:推进/末关/倒下/重开/生命账)
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「验收标准」开始新冒险 开始新冒险(冒险生命周期组:推进/末关/倒下/重开/生命账)
print("--- 冒险结构验收(三关序列 · 大奖励 · 摘要五件事 · 账本封闭)---")
var autoplay = load("res://sim/level_autoplay.gd")
# ① 表与覆盖义务(序列关数 = 行集关数;节点源 = 参数档在固定种子下的生成图,
@@ -465,7 +465,7 @@ func _smoke_adventure() -> void:
# ---- 专长冒烟(feats 四级 · 案D 池接线 · V3 订阅面逐件三列)----
func _smoke_feats() -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (奇物授予与凭证保底组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(奇物授予与凭证保底组)
print("--- 专长重设计实装(feat_table 四级 · 专长带池接线 · 订阅面逐件)---")
# ① 现行表牌库构成:36 件全量入池(破封一击随封印受理即揭示退役〔退役改 V7〕)——102 数值令牌+36 relic 令牌(四级 rarity 直映射)
Kit.check("feat_table 已加载(36 件=基础 27+迁入 2+完美保险 1+迭代 46 换图系七件−破封一击退役〔退役改 V7〕——换代)", _db.crossrun.feats != null and (_db.crossrun.feats.rows as Array).size() == 36)
@@ -920,7 +920,7 @@ func _level_active_nodes(level_index: int) -> Array:
# 生产 feat_ticket_quota==2 读表驱动;保底同置满使 false 只能来自配额分支(先于概率掷点)。
# 真实入口链 = node_curio_candidates→draw_candidates("reward_node")→feat_ticket_consider。
func _check_ticket_quota_exhausted(a_t) -> void:
# 判据出处: design/engineering/test-conventions.md:133 (真实入口断言——配额满分支售满后恒 false)
# 判据出处: design/engineering/test-conventions.md「8.4 真实入口断言」真实入口断言 真实入口断言(真实入口断言——配额满分支售满后恒 false)
Kit.check("生产配额值在役:feat_ticket_quota==2〔QA余 V4〕", int(a_t.db.run.adventure.feat_ticket_quota) == 2)
a_t.stop()._deck.ticket_appeared = int(a_t.db.run.adventure.feat_ticket_quota) # 配额满注入(A6 同款测试通道直填)
a_t.stop()._deck.ticket_pity = int(a_t.db.run.adventure.feat_ticket_pity_step) # 保底同置满——false 唯一来源=配额分支
@@ -16,7 +16,7 @@ func _init() -> void:
func _smoke_zero_chain_rule() -> void:
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:230 (0 格连锁传播闭包——模拟玩家算子组)
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」每条都可单独验证 每条都可单独验证(0 格连锁传播闭包——模拟玩家算子组)
var db = load("res://core/config_db.gd").new()
var load_ok: bool = db.load_tables("res://data/tables", true) and db.diagnostics_count("error") == 0
Kit.check("前置:表加载零 error", load_ok)
@@ -55,7 +55,7 @@ func _init() -> void:
# ① 缺省两参(真编排器):同种子两跑整轮驱动逐位(确定性自证——动作序列快照经 cell_revealed 事件流)
func _smoke_drive_round_contract() -> void:
# 判据出处: design/gdd/术语表.md「效果端口件」 (效果端口件:收事件交结算取回命中批——驱动循环契约组)
# 判据出处: design/gdd/术语表.md「战斗与效果」效果端口件 效果端口件(效果端口件:收事件交结算取回命中批——驱动循环契约组)
var db = load("res://core/config_db.gd").new()
var load_ok: bool = db.load_tables("res://data/tables", true) and db.diagnostics_count("error") == 0
Kit.check("前置:表加载零 error", load_ok)
@@ -81,7 +81,7 @@ func _smoke_drive_round_contract() -> void:
# ② provider 形态:策略回调产出 dig/seal_place/refresh 各一——提交与日志回调四元组在案
func _provider_shapes() -> void:
# 判据出处: game/sim/battle_driver.gd「战斗驱动循环单点」 (端口应答束形状组)
# 判据出处: game/sim/battle_driver.gd「战斗驱动循环单点」族探针共用的 族探针共用的(端口应答束形状组)
var st := _StubSettlement.new()
var script := [ {"kind": "dig", "cell": Vector2i(1, 1)}, {"kind": "seal", "cell": Vector2i(2, 2)}, {"kind": "refresh"}, {"kind": "stop"} ]
var logs: Array = []
@@ -102,7 +102,7 @@ func _provider_shapes() -> void:
# ③ max_rejects:策略恒返被拒动作——第 3 拒后停手出环(循环次数=3)
func _max_rejects() -> void:
# 判据出处: game/sim/battle_driver.gd「战斗驱动循环单点」 (拒绝通道组)
# 判据出处: game/sim/battle_driver.gd「战斗驱动循环单点」族探针共用的 族探针共用的(拒绝通道组)
var st := _StubSettlement.new()
st.minesweeper.accept = false
st.minesweeper.reject_cells = {Vector2i(9, 9): true}
@@ -122,7 +122,7 @@ func _max_rejects() -> void:
# ④ 合步 next:move 后相位变更即断弃 dig(桩 on_submit 钩子把 phase 推离 Active)
func _combined_step_next() -> void:
# 判据出处: game/sim/battle_driver.gd「战斗驱动循环单点」 (合并步进组)
# 判据出处: game/sim/battle_driver.gd「战斗驱动循环单点」族探针共用的 族探针共用的(合并步进组)
var st := _StubSettlement.new()
st.minesweeper.on_submit = func(action: String) -> void:
if action == "move":
@@ -18,7 +18,7 @@ var _rng
func _init() -> void:
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:219 棋盘生成宿主(装载组)
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「验收标准」确定性复现 确定性复现(装载组)
_db = ConfigDBScript.new()
# 表加载失败不中止(承 G2 同款:表损坏的红落在具体断言上——
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
@@ -52,7 +52,7 @@ func _mk_stream(stream_name: String, scope: int) -> RandomNumberGenerator:
# 公式 N×cell ≤ 可用高−12 必须计入 (N−1)×2px 网格间距,否则网格实高溢出被 clip_contents 裁掉;
# 现公式 = 计入间距 + 垂直预留 24px〔上 12/下 12——底部不贴 D 区边框〕)----
func _smoke_layout_cell_formula() -> void:
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:75 (出生区边长表单点——格边长公式组)
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「出生区安全与反退化布雷:脚下无雷、白给板不出厂」玩家开局站在棋盘上的 玩家开局站在棋盘上的(出生区边长表单点——格边长公式组)
print("--- 棋盘布局格边长公式(底部预留回归·四档板型)---")
var board_generator = load("res://core/board_generator.gd").new()
var board_view = load("res://presentation/views/board_view.gd").new()
@@ -82,7 +82,7 @@ func _smoke_layout_cell_formula() -> void:
# ---- 地图战斗资源·身份面单元冒烟(格面资源:roll 恰一次 / 雷安同池 / 幂等 / 清图批尾)----
func _smoke_reward_identity_unit() -> void:
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:233 (格面资源身份——三分出口与资源身份组)
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「验收标准」每格必有货 每格必有货(格面资源身份——三分出口与资源身份组)
print("--- 地图战斗资源·格面资源身份面 ---")
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(20260911)
@@ -144,7 +144,7 @@ class _BoardRowStub:
func _smoke_board_generator() -> void:
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:221 (确定性复现+布雷纪律组)
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「P1 / P2 后置」确定性复现 确定性复现(确定性复现+布雷纪律组)
print("--- 棋盘生成 ---")
var board_generator = load("res://core/board_generator.gd").new()
for L in [1, 2]:
@@ -239,7 +239,7 @@ func _board_dump(b) -> String:
# ---- 地图战斗资源·伤害量值区间冒烟(roll 域内 + 中点锚 + 变异实际流动 + 定值行不受扰)----
func _smoke_power_interval() -> void:
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:233 (资源量值区间——伤害量值区间组)
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「验收标准」每格必有货 每格必有货(资源量值区间——伤害量值区间组)
print("--- 地图战斗资源·伤害量值区间(上阶/下阶随机)---")
# ① 表侧静态锚(配置推导——改表不断锚):凡带 power_min/power_max 的行 = 区间行,
# 校验配对齐全(lo ≤ hi)+ power = floor 中点(行动经济 条款①期望当量锚);其余行必须零区间字段。
+7 -7
View File
@@ -13,7 +13,7 @@ var _db: ConfigDb
func _init() -> void:
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:219 棋盘生成(装载组)
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「验收标准」确定性复现 确定性复现(装载组)
_db = load("res://core/config_db.gd").new() as ConfigDb
if not _db.load_tables("res://data/tables", false):
Kit.check("数值表加载", false)
@@ -40,7 +40,7 @@ func _generate(L: int, D: int, seed0: int) -> BoardData:
func _test_generate_shape_and_mines() -> void:
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:224 (布雷纪律组)
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「验收标准」确定性复现 确定性复现(布雷纪律组)
var b := _generate(1, 0, 71000)
if b == null:
Kit.check("生成返回棋盘", false)
@@ -61,7 +61,7 @@ func _test_generate_shape_and_mines() -> void:
# 目标雷数公式单点(d14):同参同值对拍原式 + 真实产图指标读数同源
func _test_target_mine_count_single_source() -> void:
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:224 (雷数单源组)
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「验收标准」确定性复现 确定性复现(雷数单源组)
var bad := 0
var checked := 0
for L in [1, 2, 3]:
@@ -92,7 +92,7 @@ func _test_target_mine_count_single_source() -> void:
func _test_digits_equal_neighbor_mine_count() -> void:
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:223 (数字恒真组)
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「出生区安全与反退化布雷:脚下无雷、白给板不出厂」玩家开局站在棋盘上的 玩家开局站在棋盘上的(数字恒真组)
var b := _generate(1, 1, 72000)
if b == null:
Kit.check("生成返回棋盘(数字段)", false)
@@ -113,7 +113,7 @@ func _test_digits_equal_neighbor_mine_count() -> void:
func _test_same_seed_bit_identical() -> void:
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:221 (同种子逐位复现组)
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「P1 / P2 后置」后置原因 后置原因(同种子逐位复现组)
var a := _generate(2, 0, 73000)
var b := _generate(2, 0, 73000)
if a == null or b == null:
@@ -124,7 +124,7 @@ func _test_same_seed_bit_identical() -> void:
func _test_clearable_and_inferability_selfconsistent() -> void:
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:226 (可清图与及格线自洽组)
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「棋盘生成」棋盘怎么生成 棋盘怎么生成(可清图与及格线自洽组)
var b := _generate(1, 0, 74000)
if b == null:
Kit.check("生成返回棋盘(可推理段)", false)
@@ -140,7 +140,7 @@ func _test_clearable_and_inferability_selfconsistent() -> void:
# ---- V8 出生区边长表单点(架构整改——spawn_edge 表头驱动布雷域基/几何/护栏全导出)----
func _test_spawn_edge_from_table() -> void:
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md:75 (出生区边长读表组)
# 判据出处: design/gdd/systems/排雷循环/棋盘生成.md「出生区安全与反退化布雷:脚下无雷、白给板不出厂」玩家开局站在棋盘上的 玩家开局站在棋盘上的(出生区边长读表组)
# ① 纯函数对拍:edge=5 夹具 → target = round(d×(W×H−25))(25 格布雷域基可观测)
var p5 := {"w": 12, "h": 12, "density": 0.15, "spawn_edge": 5}
Kit.check("V8 纯函数:edge=5 布雷域基 25 格(target=round(d×(144−25)))〔架构整改 V8〕",
@@ -15,7 +15,7 @@ var _bp_path := "user://test_breakpoint_resume.json"
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:180 (断点域契约:七字段往返/续玩确定性/幂等/三结局清除组)
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「验收标准」断点域契约 断点域契约(断点域契约:七字段往返/续玩确定性/幂等/三结局清除组)
var db = load("res://core/config_db.gd").new()
if not db.load_tables("res://data/tables", false):
print("[breakpoint_resume_test] FAIL — 数值表加载失败")
@@ -13,7 +13,7 @@ const StatusTableScript := preload("res://data/schemas/status_effect_table.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:195 (跨表校验宿主——装载组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「P1 / P2 后置」后置原因 后置原因(跨表校验宿主——装载组)
_test_all_links_valid()
_test_dangling_skill_id()
_test_cast_side_mismatch()
@@ -47,7 +47,7 @@ func _cats(errs: Array) -> Array[String]:
# ---- 正向:技能池全对齿(普攻恰一行、buff 挂敌方侧)应零错,防校验误伤 ----
func _test_all_links_valid() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:195 (悬空引用类别:跨表链接全有效组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「P1 / P2 后置」后置原因 后置原因(悬空引用类别:跨表链接全有效组)
var skills := _skill([
{"skill_id": "attack", "type": "basic"},
{"skill_id": "raise_morale", "type": "buff", "buff_ref": "st_strong"},
@@ -63,7 +63,7 @@ func _test_all_links_valid() -> void:
# ---- 负向:技能池引用表里不存在的 skill_id 必须报 ----
func _test_dangling_skill_id() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:195 (悬空引用类别:skill_id 悬空组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「P1 / P2 后置」后置原因 后置原因(悬空引用类别:skill_id 悬空组)
var skills := _skill([{"skill_id": "attack", "type": "basic"}])
var enemies := _enemy([
{"level_index": 1, "row_kind": "battle", "depth_band": 0, "enemy_id": "goblin", "pool": [
@@ -76,7 +76,7 @@ func _test_dangling_skill_id() -> void:
# ---- 负向:buff 挂到主角侧状态(side 反向)必须报 ----
func _test_cast_side_mismatch() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:195 (side 反向校验组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「P1 / P2 后置」后置原因 后置原因(side 反向校验组)
var skills := _skill([{"skill_id": "raise_morale", "type": "buff", "buff_ref": "st_hero_side"}])
var enemies := _enemy([
{"level_index": 1, "row_kind": "battle", "depth_band": 0, "enemy_id": "goblin", "pool": [
@@ -12,7 +12,7 @@ var _resolver: ConfigDbResolver
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:202 (解析器宿主——装载组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(解析器宿主——装载组)
_resolver = ResolverScript.new(
func(level, category, message) -> void: # 诊断通道签名按调用实参收(首参为表 id 字符串)
_diags.append("%s/%s/%s" % [str(level), str(category), str(message)]),
@@ -55,7 +55,7 @@ func _difficulty_table():
func _test_band_hit() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:202 (精确命中零警告组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(精确命中零警告组)
var hit: Array = _resolver.resolve_enemy_rowset(1, 4, "battle")
Kit.check("带命中取偏难一侧:请求深度 4 命中带 5(逐字不回带 0)〔fv1〕",
hit.size() == 1 and String((hit[0] as Dictionary).get("enemy_id", "")) == "giant_spider")
@@ -65,7 +65,7 @@ func _test_band_hit() -> void:
func _test_rowset_order_preserved() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:202 (行集寻址与行序保序组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(行集寻址与行序保序组)
var rows: Array = _resolver.resolve_enemy_rowset(1, 0, "battle")
var ids: Array[String] = []
for r in rows:
@@ -75,7 +75,7 @@ func _test_rowset_order_preserved() -> void:
func _test_top_band_clamp() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:202 (超最大行走封顶取最大行组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(超最大行走封顶取最大行组)
_diags.clear()
var rows: Array = _resolver.resolve_enemy_rowset(1, 99, "battle")
Kit.check("越顶带 clamp 取顶带行集(battle 顶带 5)〔fv3〕",
@@ -91,7 +91,7 @@ func _test_top_band_clamp() -> void:
func _test_row_kind_routing() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:202 (行类别路由组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(行类别路由组)
var battle_rows: Array = _resolver.resolve_enemy_rowset(1, 0, "battle")
var boss_rows: Array = _resolver.resolve_enemy_rowset(1, 0, "boss")
Kit.check("行类路由:同请求深度 battle 与 boss 命中不同键域〔fv4〕",
@@ -100,7 +100,7 @@ func _test_row_kind_routing() -> void:
func _test_request_oob() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:203 (越域致命中止组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(越域致命中止组)
_diags.clear()
_resolver.resolve_enemy_rowset(0, 0, "battle")
Kit.check("关卡序号 <1 → fatal request_oob〔fv5〕", _has_fatal_oob())
@@ -120,7 +120,7 @@ func _has_fatal_oob() -> bool:
func _test_difficulty_clamp() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:202 (难度 clamp 组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(难度 clamp 组)
var m: Dictionary = _resolver.resolve_difficulty_modifiers(1, 0)
Kit.check("难度乘数越域被 clamp:hp 99 → 上限 10", absf(float(m.get("hp_mult", 0.0)) - 10.0) < 0.001)
Kit.check("难度乘数越域被 clamp:atk 0.01 → 下限 0.1", absf(float(m.get("atk_mult", 0.0)) - 0.1) < 0.001)
@@ -8,7 +8,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/跨局循环/秘宝.md「定位与形态」 (CurioDeck:三选一/商店共享池、抽签、cap 库存——刷新付费组)
# 判据出处: design/gdd/systems/跨局循环/秘宝.md「定位与形态」现行形态 现行形态(CurioDeck:三选一/商店共享池、抽签、cap 库存——刷新付费组)
var db = load("res://core/config_db.gd").new()
if not db.load_tables("res://data/tables", false):
print("[curio_refresh_paid_test] FAIL — 数值表加载失败")
+1 -1
View File
@@ -11,7 +11,7 @@ const EffectEngineScript = preload("res://core/effect_engine.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md「扩签登记」 (效果词表封闭——扩签封闭性组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「扩签登记」落地结果 落地结果(效果词表封闭——扩签封闭性组)
# ① 词表在册断言(扩签面:2 事件+8 事实+7 效果类型+1 算子)
Kit.check_quiet(EffectEngineScript.EVENTS.has("dig_stop") and EffectEngineScript.EVENTS.has("battle_won"),
"新事件在册:dig_stop/battle_won〔专长批 V1〕")
@@ -11,34 +11,34 @@ const Kit := preload("res://tests/unit/test_kit.gd")
func _init() -> void:
# 判据出处: design/engineering/code-conventions.md:41 (封装边界:跨对象往来只走公开方法与属性——P2 词表单点扫描组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」封装边界 封装边界(封装边界:跨对象往来只走公开方法与属性——P2 词表单点扫描组)
_sweep_generator()
_sweep_production_face()
quit(Kit.finish("encapsulation_p2_sweep_test"))
func _src(path: String) -> String:
# 判据出处: design/engineering/code-conventions.md:41 (源码采样组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(源码采样组)
var src := FileAccess.get_file_as_string(path)
Kit.check("扫描面非空前置:%s" % path, src.length() > 0)
return src
func _zero(pattern: String, src: String, label: String) -> void:
# 判据出处: design/engineering/code-conventions.md:41 (零命中扫描组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(零命中扫描组)
var re := RegEx.create_from_string(pattern)
Kit.check("%s:%s 零命中〔架构P2〕" % [label, pattern], re.search(src) == null)
func _anchor(pattern: String, src: String, label: String) -> void:
# 判据出处: design/engineering/code-conventions.md:41 (正锚存在组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(正锚存在组)
var re := RegEx.create_from_string(pattern)
Kit.check("%s:%s 正锚在案〔架构P2〕" % [label, pattern], re.search(src) != null)
# ① V1 生成器词表定义删除与改指
func _sweep_generator() -> void:
# 判据出处: design/engineering/code-conventions.md:41 (生成器本地副本归零组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(生成器本地副本归零组)
var src := _src("res://core/node_map_generator.gd")
if src.length() == 0:
return
@@ -48,7 +48,7 @@ func _sweep_generator() -> void:
# ② V2 生产三目录定义唯一性(递归扫 .gd,恰好 1 处且落 level_table.gd)
func _sweep_production_face() -> void:
# 判据出处: design/engineering/code-conventions.md:41 (schema 唯一定点组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(schema 唯一定点组)
var files: Array[String] = []
for dir_path in ["res://core", "res://data", "res://presentation"]:
_collect_gd(dir_path, files)
@@ -14,7 +14,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
func _init() -> void:
# 判据出处: design/engineering/code-conventions.md:41 (封装边界——五处结构性零命中扫描组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」封装边界 封装边界(封装边界——五处结构性零命中扫描组)
_sweep_settlement_segments()
_sweep_orchestrator_methods()
_sweep_breakpoint_pair()
@@ -26,7 +26,7 @@ func _init() -> void:
# 源文件读取+非空前置(返 "" 即已判红——调用侧跳过后续正则断言)
func _src(path: String) -> String:
# 判据出处: design/engineering/code-conventions.md:41 (源码采样组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(源码采样组)
var src := FileAccess.get_file_as_string(path)
Kit.check("扫描面非空前置:%s" % path, src.length() > 0)
return src
@@ -34,21 +34,21 @@ func _src(path: String) -> String:
# 正则零命中断言(-pattern 意图写入断言文案——可 grep 定位)
func _zero(pattern: String, src: String, label: String, path: String) -> void:
# 判据出处: design/engineering/code-conventions.md:41 (零命中扫描组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(零命中扫描组)
var re := RegEx.create_from_string(pattern)
Kit.check("%s:%s 零命中〔封装5.1〕" % [label, pattern], re.search(src) == null)
# 正锚在案断言(正则命中 ≥1——新公开面/新形态在用)
func _anchor(pattern: String, src: String, label: String, path: String) -> void:
# 判据出处: design/engineering/code-conventions.md:41 (正锚存在组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(正锚存在组)
var re := RegEx.create_from_string(pattern)
Kit.check("%s:%s 正锚在案〔封装5.1〕" % [label, pattern], re.search(src) != null)
# ① V2 settlement 七文件(束注入换代——对编排器引用归零)
func _sweep_settlement_segments() -> void:
# 判据出处: design/engineering/code-conventions.md:41 (结算段封装扫描组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(结算段封装扫描组)
var classes := {
"res://core/settlement/grant_segment.gd": "GrantSegment",
"res://core/settlement/combat_segment.gd": "CombatSegment",
@@ -68,7 +68,7 @@ func _sweep_settlement_segments() -> void:
# ② V3 编排器搬家五方法零残留
func _sweep_orchestrator_methods() -> void:
# 判据出处: design/engineering/code-conventions.md:41 (编排器方法面扫描组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(编排器方法面扫描组)
var src := _src("res://core/battle_orchestrator.gd")
if src.length() == 0:
return
@@ -78,7 +78,7 @@ func _sweep_orchestrator_methods() -> void:
# ③ V4 断点域(adventure_runner → BreakpointStore 公开面)
func _sweep_breakpoint_pair() -> void:
# 判据出处: design/engineering/code-conventions.md:41 (断点对封装扫描组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(断点对封装扫描组)
var src := _src("res://core/adventure_runner.gd")
if src.length() == 0:
return
@@ -88,7 +88,7 @@ func _sweep_breakpoint_pair() -> void:
# ④ V5 存档双向公开面(save_manager↔slot_store)
func _sweep_save_pair() -> void:
# 判据出处: design/engineering/code-conventions.md:41 (存档对封装扫描组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(存档对封装扫描组)
var src_m := _src("res://core/save_manager.gd")
if src_m.length() > 0:
_zero("slots\\._", src_m, "save_manager 对槽位件私取归零", "res://core/save_manager.gd")
@@ -102,7 +102,7 @@ func _sweep_save_pair() -> void:
# ⑤ V6 效果宿主累积面(grant → BattleFxHost 公开累积方法)
func _sweep_fx_host_accumulators() -> void:
# 判据出处: design/engineering/code-conventions.md:41 (特效宿主累积面扫描组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(特效宿主累积面扫描组)
var src := _src("res://core/settlement/grant_segment.gd")
if src.length() == 0:
return
@@ -112,7 +112,7 @@ func _sweep_fx_host_accumulators() -> void:
# ⑥ V7 配置挂载面(config_db → 三 schema bind_resolver)
func _sweep_config_resolver() -> void:
# 判据出处: design/engineering/code-conventions.md:41 (配置挂载面扫描组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(配置挂载面扫描组)
var src := _src("res://core/config_db.gd")
if src.length() == 0:
return
+1 -1
View File
@@ -16,7 +16,7 @@ func EffectEngineKindProbe(_db) -> bool:
func _init() -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (奇物凭证五件与留任二件组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「验收标准」三个分类走同一套获取流程 三个分类走同一套获取流程(奇物凭证五件与留任二件组)
var db = load("res://core/config_db.gd").new()
if not db.load_tables("res://data/tables", false):
print("[feat_vouchers_test] FAIL — 数值表加载失败")
+1 -1
View File
@@ -14,7 +14,7 @@ const LevelRunnerScript := preload("res://core/level_runner.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md:288 (生命一致性:三写入口封顶 [0,生效上限]——主角账组)
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「验收标准」生命一致性 生命一致性(生命一致性:三写入口封顶 [0,生效上限]——主角账组)
var db = load("res://core/config_db.gd").new()
if not db.load_tables("res://data/tables", false):
print("[hero_ledger_test] FAIL — 数值表加载失败")
@@ -10,7 +10,7 @@ const LevelTableScript := preload("res://data/schemas/level_table.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (信息迷雾类型可见性宿主——装载组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(信息迷雾类型可见性宿主——装载组)
var db = load("res://core/config_db.gd").new()
var loaded: bool = db.load_tables("res://data/tables", false)
Kit.check_quiet(loaded, "可见性用例:数值表加载成功")
@@ -103,7 +103,7 @@ func _runner(db, nodes: Array, anchor_id: int, candidates: Array, n: int = 2):
# ---- ⑥ N 进数据表(含越域校验)〔fv6〕----
func _test_field_in_table(db) -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (迷雾参数读表——字段在表组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(迷雾参数读表——字段在表组)
var n_in_table: int = int(db.run.level.info_visible_layers)
Kit.check("N 落表:level.tres 读数 2(实际 %d)〔fv6〕" % n_in_table, n_in_table == 2)
var t := LevelTableScript.new()
@@ -127,7 +127,7 @@ func _has_n_domain_err(errs: Array) -> bool:
# ---- ① 邻近 N 层见类型(层距边界)〔fv1〕----
func _test_layer_distance(db) -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (层距 N 可见性组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(层距 N 可见性组)
var nodes := _graph_nodes()
var r = _runner(db, nodes, 1, [nodes[2]]) # 锚 = 节点 1(层 1),候选 = 节点 2
var vis: Array = r.type_visible_ids()
@@ -139,7 +139,7 @@ func _test_layer_distance(db) -> void:
# ---- ② 下一跳恒可见(跨层跳边候选)〔fv4〕----
func _test_candidate_exempt(db) -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (候选豁免组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(候选豁免组)
var nodes := _graph_nodes()
var r = _runner(db, nodes, 6, [nodes[3]]) # 锚 = 节点 6(层 5),候选 = 节点 3(层 2,层距 3)
var vis: Array = r.type_visible_ids()
@@ -150,7 +150,7 @@ func _test_candidate_exempt(db) -> void:
# ---- ③ Boss/终点不入雾+⑤ 入口停点锚层 0〔fv3〕〔fv1〕----
func _test_boss_exempt(db) -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (Boss 豁免组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」Boss Boss(Boss 豁免组)
var nodes := _graph_nodes()
var r = _runner(db, nodes, -1, [nodes[0]]) # 入口停点(无当前节点,锚层 0)
var vis: Array = r.type_visible_ids()
@@ -163,7 +163,7 @@ func _test_boss_exempt(db) -> void:
# ---- ④ 单圈回雾(visited 不豁免)〔fv7〕----
func _test_single_circle(db) -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (单圈可见组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(单圈可见组)
var nodes := _graph_nodes()
var r = _runner(db, nodes, 6, [nodes[7], nodes[3]])
r.visited.assign([nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], nodes[6]])
@@ -176,7 +176,7 @@ func _test_single_circle(db) -> void:
# ---- ⑤ 单链退化形态(出度 ≤1 图,编号 = id 句柄)〔fv1〕----
func _test_single_chain_entry(db) -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (单链入口组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(单链入口组)
var nodes := _chain_nodes()
var r = _runner(db, nodes, -1, [nodes[0]])
var vis: Array = r.type_visible_ids()
@@ -189,7 +189,7 @@ func _test_single_chain_entry(db) -> void:
# ---- ⑥ N 读表:可见窗随表值随动〔fv6〕----
func _test_n_from_table(db) -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:176 (N 读表组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(N 读表组)
var nodes := _graph_nodes()
var r = _runner(db, nodes, 1, [nodes[2]]) # 锚层 1
db.run.level.info_visible_layers = 1
@@ -207,7 +207,7 @@ func _test_n_from_table(db) -> void:
# ---- ⑦ 续玩重建同值〔fv7〕----
func _test_resume_rebuild(db) -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var t := LevelTableScript.new()
t.info_visible_layers = 2
t.rows = [{"level_index": 1, "display_name": "夹具关", "rest_heal_pct": 30}]
+14 -14
View File
@@ -232,7 +232,7 @@ func _board_row_exact(level_index: int, depth: int) -> bool:
func _init() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
_db = ConfigDBScript.new()
# 表加载失败不中止(承 G2/G3/G4/G5 同款:表损坏的红落在具体断言上——
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
@@ -262,7 +262,7 @@ func _init() -> void:
# ---- 数值入表等价证明(d11/d16a——原字面量迁移:表值 == 迁移前字面量,消费端读表)----
func _smoke_table_migration() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:195 (行集纪律——表迁移组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「P1 / P2 后置」后置原因 后置原因(行集纪律——表迁移组)
print("--- 数值入表(shop 两 knob + hero 显示名 · 原值迁移)---")
Kit.check("shop.relic_base_price 表值 == 迁移前字面量(15.0)〔wd11〕", _db.run.shop.relic_base_price == 15.0)
Kit.check("hero.display_name 表值 == 迁移前字面量(探险者)〔wd16〕", _db.combat.hero.display_name == "探险者")
@@ -277,7 +277,7 @@ func _smoke_table_migration() -> void:
# 敌侧/板侧解析一律走 ConfigDB 真实消费链,禁直读行集自算)----
func _smoke_generated_coverage() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:184 (每终点前恰一店——生成覆盖扫描组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(每终点前恰一店——生成覆盖扫描组)
var enemy_ok := true
var board_ok := true
var boss_band_ok := true
@@ -328,7 +328,7 @@ func _smoke_generated_coverage() -> void:
# ---- 关卡节点图·生成图推进冒烟(图 = 该关参数档 × 种子)----
func _smoke_level() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (关卡图校验推进组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(关卡图校验推进组)
print("--- 关卡节点图·生成图推进(参数档×种子产图·满配冒险成功/恢复公式/败北线/回放确定性)---")
var autoplay = load("res://sim/level_autoplay.gd")
var hero_base := {"atk": int(_db.combat.hero.atk), "hp": int(_db.combat.hero.max_hp), "ac": int(_db.combat.hero.armor_class)} # 配置基线快照——⑤ 回基线对比用(改表自动跟随,不再硬编码)
@@ -442,7 +442,7 @@ func _drive_to_rest(level_index: int, seed_val: int, gap: int) -> Dictionary:
# ---- 分支节点图冒烟:图合法性校验 + L2 幽暗地域生成图行进(图 = 参数档 × 种子)----
func _smoke_level_graph() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (图结构与行进纪律组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(图结构与行进纪律组)
print("--- 关卡节点图·分支节点图(L2 幽暗地域·生成图)---")
var autoplay = load("res://sim/level_autoplay.gd")
# ① 关卡表行级校验零错误(关卡表只承载序号/显示名/恢复比例——图合法性由 validate_graph 在起关时承担)
@@ -801,7 +801,7 @@ func _fresh_rng(seed_val: int):
# ---- ① GP 冒险钱包·到账 ----
func _smoke_gp_wallet() -> void:
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:233 (GP 钱包入账组)
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「验收标准」每格必有货 每格必有货(GP 钱包入账组)
print("--- GP 冒险钱包·到账(战斗完成入账恰一次 + Boss 加值)---")
var autoplay = load("res://sim/level_autoplay.gd")
# ① L1 首战(普通战档——掷定 [2,4] + 关级加值 0):runner 驱动,收集 battle_finished 与钱包事件
@@ -867,7 +867,7 @@ func _escrow_sum_of(rows: Array) -> int:
# ---- ② escrow 隔离(GP安全格兑付 / 破财直验 / 钱包 clamp)----
func _smoke_gp_escrow() -> void:
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md:233 (GP escrow 组)
# 判据出处: design/gdd/systems/战斗循环/地图战斗资源.md「验收标准」每格必有货 每格必有货(GP escrow 组)
print("--- GP escrow 隔离(GP安全格兑付入缓冲 · 破财不透支)---")
# ① 种子扫描:找GP 袋(gp 型安全格)可挖掘局——挖开兑付 +3 入 escrow,战斗末随 gp_dropped 一次上抛
var scan := {}
@@ -981,7 +981,7 @@ func _find_gp_dig(minesweeper, settlement) -> Dictionary:
# ---- ③ 商店房三收口 ----
func _smoke_shop_room() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:184 (商店房呈现组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(商店房呈现组)
print("--- 商店房三收口(现价/加算区/余额不足拒/离开回选路/收束清零)---")
var autoplay = load("res://sim/level_autoplay.gd")
# 行进到商店房(按图型别定位商店节点——候选取最小句柄行进,到达即停):
@@ -1115,7 +1115,7 @@ func _shop_products_by_id(prods: Array) -> Dictionary:
# ---- ④ 商店编排性质(生成图扫描面——三条性质 + 终点跨表解析)----
func _smoke_shop_graph() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:184 (必经恰一店图纪律组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(必经恰一店图纪律组)
print("--- 商店编排性质(每终点前一位恰一店 · 店数=终点数 · 全路径恰穿一店)---")
var pred_bad := 0
var term_total := 0
@@ -1186,7 +1186,7 @@ func _smoke_shop_graph() -> void:
# ---- ⑥ 大岔口分区域兑付(V3——多终点图走哪条路决定打谁,任一 Boss 胜即收束恰一次)----
func _smoke_multi_terminal_settlement() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:185 (多终局收束组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(多终局收束组)
print("--- 大岔口分区域兑付(L2 两轴各打各的终点)---")
var autoplay = load("res://sim/level_autoplay.gd")
var nodes: Array = _generated_graph(2, 42).get("nodes", [])
@@ -1254,7 +1254,7 @@ func _paths_all_one_shop(nodes: Array) -> bool:
# ---- ⑤ 商店共享池(三选一同构/乘法价/跨渠道共账/切边/断点扩键)----
func _smoke_shop_pool() -> void:
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「共享池账本」 (商店共享池组)
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「GP:战斗掉落的局内钱包与统一冒险加算区」是冒险内的一次性属性提升货币 是冒险内的一次性属性提升货币(商店共享池组)
print("--- 商店共享池(抽3买1全重抽 · 乘法定价 ceil · 池空硬闸 · 切边零入店)---")
var autoplay = load("res://sim/level_autoplay.gd")
var shelf_kinds: Array = []
@@ -1417,7 +1417,7 @@ func _smoke_shop_pool() -> void:
# ---- 商店房 node_entered 载荷(尾波 V1——_enter_node pool/legacy 双发射路径归一后的行为保持断言)----
func _test_shop_node_entered_payload() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:184 (行进至此打开商店覆盖层——载荷组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行进至此打开商店覆盖层 行进至此打开商店覆盖层(行进至此打开商店覆盖层——载荷组)
print("--- 商店房 node_entered 载荷(pool 含 shelf:true+gp 现值/legacy 无 shelf 键)---")
var autoplay = load("res://sim/level_autoplay.gd")
# pool 态:载荷字典经信号闭包当场取样(字典为引用累积器——lambda 按值捕获标量的绕行惯例)
@@ -1576,7 +1576,7 @@ func _has_err_category(errs: Array, category: String) -> bool:
# ---- 货架位数读表(架构整改——shelf_size 表头单点:进店与重抽同源)----
func _test_shelf_size_from_table() -> void:
# 判据出处: design/ux/shop.md:13 (货架位数读表组)
# 判据出处: design/ux/shop.md「布局与交互」模态覆盖层 模态覆盖层(货架位数读表组)
var autoplay = load("res://sim/level_autoplay.gd")
var st = _db.run.shop
var saved: int = int(st.shelf_size)
@@ -1598,7 +1598,7 @@ func _test_shelf_size_from_table() -> void:
# ---- 散折价收回规则键(架构整改 R2——shop.spend_discount 表字段退役,折价读 economy_spend.discount_pct)----
func _test_spend_discount_from_rule_key() -> void:
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:256 (换图基座:挖格产 RAP 与刷新折扣组)
# 判据出处: design/gdd/systems/排雷循环/行动经济.md「P0 最小闭环」战斗结算发开轮通知 战斗结算发开轮通知(换图基座:挖格产 RAP 与刷新折扣组)
# 字段真删:shop.tres 加载零诊断 + spend_discount 属性不在位
Kit.check("shop.tres 加载零诊断(spend_discount 字段真删——schema 与表行同卸)〔架构整改 V2〕",
_db.diagnostics_count("error") == 0 and _db.run.shop.get("spend_discount") == null)
@@ -11,7 +11,7 @@ const LevelTableScript := preload("res://data/schemas/level_table.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (关卡表消费侧校验宿主)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(关卡表消费侧校验宿主)
_test_positive()
_test_negative()
_test_scope_not_extended()
@@ -38,7 +38,7 @@ func _has(errs: Array, cat: String, needle: String = "") -> bool:
# ---- 正例(四检全过)----
func _test_positive() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (良构基底正向组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(良构基底正向组)
# 多入口多终点:两入口共汇入一岔口,两终点各在互异深度
var multi := [
_n(0, "battle", 0, [2]), _n(1, "battle", 0, [2]),
@@ -61,7 +61,7 @@ func _test_positive() -> void:
# ---- 负例九类(各报对应类别与判据消息)----
func _test_negative() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (违规配置加载期致命——负向组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」违规配置加载期致命 违规配置加载期致命(违规配置加载期致命——负向组)
var non_boss_end := [_n(0, "battle", 0, [1]), _n(1, "battle", 1, [])]
Kit.check("负例:终点非 Boss 命中「终点恒为 Boss」〔v1〕",
_has(_errs(non_boss_end), "structural", "终点 1 非 Boss"))
@@ -95,7 +95,7 @@ func _test_negative() -> void:
# ---- 「勿扩勿缩」反证:本检不含商店位与个数对参数档的核对 ----
func _test_scope_not_extended() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (校验范围不外扩组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(校验范围不外扩组)
# 合法形状但全程无商店/三个终点同入口图——四检不该因此报错(商店位归冒烟断言、个数归产出侧)
var no_shop := [_n(0, "battle", 0, [1, 2]), _n(1, "battle", 1, [3]), _n(2, "rest", 1, [3]), _n(3, "boss", 2, [])]
Kit.check("范围反证:无商店图不在加载校验内报错(商店位由冒烟断言把关)〔v1〕", _errs(no_shop).is_empty())
@@ -21,7 +21,7 @@ var _db
func _init() -> void:
# 判据出处: design/gdd/systems/跨局循环/元进度.md:148 元进度与锻造宿主(装载组)
# 判据出处: design/gdd/systems/跨局循环/元进度.md「验收标准」钥石不丢 钥石不丢(装载组)
_db = ConfigDBScript.new()
# 表加载失败不中止(承 G2/G3/G4/G5 同款:表损坏的红落在具体断言上——
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
@@ -139,7 +139,7 @@ func _auto_play_round(settlement, out: Dictionary) -> void:
# ---- 元进度 ②树购买面(购买受理/持久/余额不足拒绝/未知节点拒绝;
# 行价=表值 flat 单价)----
func _meta_pricing_and_buy() -> void:
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:198 (单币可判:购买只扣钥石、余额不足拒绝零变化组)
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「验收标准」单币可判 单币可判(单币可判:购买只扣钥石、余额不足拒绝零变化组)
print("--- 元进度·树购买面(隔离档 smoke_meta_buy/dry)---")
_meta_smoke_cleanup()
var sv = _meta_new_save(_META_SMOKE_PATHS[0])
@@ -166,7 +166,7 @@ func _meta_pricing_and_buy() -> void:
# ---- 元进度 ⑥Boss 两档 ⑦钥石不丢 ⑧工坊解锁 ⑩摘要副本与 cap(合成摘要驱动——settle 纯账面零跑局)----
func _meta_settle_and_workshop() -> void:
# 判据出处: design/gdd/systems/跨局循环/元进度.md:150 (钥石收束入账不丢组)
# 判据出处: design/gdd/systems/跨局循环/元进度.md「验收标准」钥石不丢 钥石不丢(钥石收束入账不丢组)
print("--- 元进度·收束入账与工坊(隔离档 smoke_meta_settle/workshop/cap)---")
var sv = _meta_new_save(_META_SMOKE_PATHS[2])
var mp = load("res://core/meta_progression.gd").new(_db, sv)
@@ -359,7 +359,7 @@ func _meta_settle_and_workshop() -> void:
# ---- 元进度 ④注入可见 + 白板成立(验收 4/2/3——程序面;MC 逐位回归归 T7 全量验证)----
func _meta_injection() -> void:
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:201 (注入可判:开局覆盖值分层可加组)
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「验收标准」注入可判 注入可判(注入可判:开局覆盖值分层可加组)
print("--- 元进度·注入可见与白板(隔离档 smoke_meta_white/dry)---")
var sv = _meta_new_save(_META_SMOKE_PATHS[1])
var mp = load("res://core/meta_progression.gd").new(_db, sv)
@@ -403,7 +403,7 @@ func _meta_injection() -> void:
# ---- 锻造工坊·两根类型轴所有权移交(V5 前半:hero.tres 两轴删除+锻造配置默认值)----
# 后半(build_adventure_params 注入默认值/选中覆盖)随 T4 注入接线同批断言;写口/解锁面归 T3。
func _smoke_forge_axes() -> void:
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md:220 (锻造两轴单选注入与树零攻防组)
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「验收标准」本节判据全部绑结构与关系 本节判据全部绑结构与关系(锻造两轴单选注入与树零攻防组)
print("--- 锻造工坊·类型轴所有权移交(T2)---")
# V5:hero.tres 静态表两轴已删(全表加载零违例——config_db_test 同款闸;此处钉字段不在位)
Kit.check("hero.tres 无 attack_type/armor_type 字段(契约 2——静态表两轴删除)〔锻造工坊批 V5〕",
@@ -566,7 +566,7 @@ func _smoke_forge_axes() -> void:
# ---- 天赋树冒烟(v0.8 12 节点:schema/购买面/Fork 一节点双态/彩蛋特化)----
func _smoke_tree() -> void:
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:194 (天赋树购买与六键合成组)
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「验收标准」结构封闭 结构封闭(天赋树购买与六键合成组)
print("--- 天赋树(12 节点 · 购买面 · Fork 双态 · 彩蛋觉醒)---")
# 〔V1〕结构:12 行 + schema 零违例
Kit.check("meta_tree 已加载(12 节点=脊柱 2〔生命/命中淬炼一线一节点 cap4〕+锻造 2〔钥匙+彩蛋——彩蛋含在锻造 2 内非第 13 行〕+钥石 2〔秘宝匣/刷新升级〕+同调 6〔socket 3+Fork 3 双态〕——v0.8 终态)〔天赋树批 V1〕",
@@ -649,7 +649,7 @@ func _smoke_tree() -> void:
# ---- 天赋树六键行为冒烟(V10:开局姿态窗/危险直觉限次/财富之道聚散/守侧失误补偿;
# 引擎直构 + 编排授予段直注(_grant_seg._judge_seal=结算授予段封印判定单口))----
func _smoke_tree_rules() -> void:
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:194 (规则键参数读表组)
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「验收标准」结构封闭 结构封闭(规则键参数读表组)
print("--- 天赋树六键行为(V10:窗/限次/聚散/守侧)---")
# 开局姿态组:每关首轮窗(battle_index 事实——引擎直构 + 自建 ctx)
var fx = load("res://core/effect_engine.gd").new(null)
@@ -790,7 +790,7 @@ func _smoke_tree_rules() -> void:
# ---- 锻造契约补齐(断言补齐批——⑥锻造工坊):拒购零副作用/祝福件零泄漏/默认值解耦/甲型双轴 ----
func _test_forge_buy_reject() -> void:
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md:222 (钥石不足购买被拒、余额与等级零变化组)
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「验收标准」本节判据全部绑结构与关系 本节判据全部绑结构与关系(钥石不足购买被拒、余额与等级零变化组)
var sv = _meta_new_save("user://smoke_meta_reject.json")
var mp = load("res://core/meta_progression.gd").new(_db, sv)
sv.meta_state._add_keystone(10) # 低于首购价 20——余额不足面
@@ -805,7 +805,7 @@ func _test_forge_buy_reject() -> void:
func _test_blessing_no_forge_leak() -> void:
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md:220 (树淬炼对攻击与 AC 零贡献组)
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「验收标准」树淬炼对攻击与 树淬炼对攻击与(树淬炼对攻击与 AC 零贡献组)
var sv = _meta_new_save("user://smoke_meta_blessing.json")
var mp = load("res://core/meta_progression.gd").new(_db, sv)
var fs0: Dictionary = sv.meta_state.forge_state().duplicate(true)
@@ -824,7 +824,7 @@ func _test_blessing_no_forge_leak() -> void:
func _test_default_axes_pre_key() -> void:
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md:217 (未点亮期间默认值照常注入组)
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「验收标准」本节判据全部绑结构与关系 本节判据全部绑结构与关系(未点亮期间默认值照常注入组)
var sv = _meta_new_save("user://smoke_meta_axesw.json")
var mp = load("res://core/meta_progression.gd").new(_db, sv)
var ax: Dictionary = mp.hero_type_axes()
@@ -833,7 +833,7 @@ func _test_default_axes_pre_key() -> void:
func _test_armor_switch_dual_axes() -> void:
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md:221 (换装不丢级不生效——双轴组)
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「验收标准」换装不丢级不生效 换装不丢级不生效(换装不丢级不生效——双轴组)
var sv = _meta_new_save("user://smoke_meta_axesw.json")
sv.meta_state._add_keystone(1000)
var mp = load("res://core/meta_progression.gd").new(_db, sv)
@@ -863,7 +863,7 @@ func _test_armor_switch_dual_axes() -> void:
# ---- G5 天赋树行与投影断言(迭代 55「QA覆盖余量收口批」T5——ks_workshop/ks_refresh/fork 两行/侧投影+spine 读行)----
func _check_ks_workshop_row() -> void:
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:30 (钥匙门行——前置/零价/柜台展开)
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「系统范围」边界这样划 边界这样划(钥匙门行——前置/零价/柜台展开)
var row: Dictionary = _db.crossrun.meta_tree.row_by_id("ks_workshop")
Kit.check("ks_workshop 行值:keystone 脉络 unlock 行且前置=[sp_hp](脊柱生命第 1 级)〔QA余 V7〕",
String(row.get("vein", "")) == "keystone" and String(row.get("kind", "")) == "unlock"
@@ -892,7 +892,7 @@ func _ks_row_level(mp, node_id: String) -> int:
func _check_ks_refresh_row() -> void:
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:30 (刷新升级行——同账路由与零刷新分支)
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「系统范围」边界这样划 边界这样划(刷新升级行——同账路由与零刷新分支)
var row: Dictionary = _db.crossrun.meta_tree.row_by_id("ks_refresh")
Kit.check("ks_refresh 行值:rule 行 keystone 币 price=30 cap=2 前置=[ks_workshop]〔QA余 V7〕",
String(row.get("kind", "")) == "rule" and String(row.get("currency", "")) == "keystone"
@@ -915,7 +915,7 @@ func _check_ks_refresh_row() -> void:
func _check_fork_rows() -> void:
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:30 (fork 一节点双态行——行值经购买面驱动)
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「系统范围」fork fork(fork 一节点双态行——行值经购买面驱动)
for spec in [{"id": "fork_sense", "group": "fg_sense", "na": "锋", "nb": "守"},
{"id": "fork_economy", "group": "fg_economy", "na": "聚", "nb": "散"}]:
var row: Dictionary = _db.crossrun.meta_tree.row_by_id(String(spec["id"]))
@@ -941,7 +941,7 @@ func _check_fork_rows() -> void:
func _check_fork_side_projection() -> void:
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:30 (组侧投影与脉络行板——真实表行读出)
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「系统范围」边界这样划 边界这样划(组侧投影与脉络行板——真实表行读出)
var sv = _meta_new_save("user://smoke_meta_fork_side.json")
var mp = load("res://core/meta_progression.gd").new(_db, sv)
sv.meta_state._add_keystone(1000)
+11 -11
View File
@@ -17,7 +17,7 @@ var _ae: ActionEconomy
func _init() -> void:
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:224 (排雷规则宿主——装载组)
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」每条都可单独验证 每条都可单独验证(排雷规则宿主——装载组)
_db = load("res://core/config_db.gd").new() as ConfigDb
if not _db.load_tables("res://data/tables", false):
Kit.check("数值表加载", false)
@@ -50,7 +50,7 @@ func _init() -> void:
func _test_install_invariants() -> void:
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:228 (装板四不变式组)
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「挖开空地整片塌开:数字提示与连锁展开」每个已开安全格都亮着一个数字 每个已开安全格都亮着一个数字(装板四不变式组)
_rules.install_board(_board)
Kit.check("装板后 current_board 即所装棋盘", _rules.current_board() == _board)
var opened: int = _rules.revealed_cells().size()
@@ -74,7 +74,7 @@ func _unrevealed_safe() -> Vector2i:
func _test_dig_face_rules() -> void:
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:231 (挖/封印合法性与可辨拒绝组)
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「调参表」本系统无自有参数 本系统无自有参数(挖/封印合法性与可辨拒绝组)
var revealed_first = _rules.revealed_cells()[0] as Vector2i
var out: Array = _rules.settle_batch([{"action": "dig", "cell": revealed_first}])
var o: Dictionary = (out[0] as Dictionary) if not out.is_empty() else {}
@@ -89,7 +89,7 @@ func _test_dig_face_rules() -> void:
func _test_reveal_advances() -> void:
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:230 (揭示推进与连锁组)
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」每条都可单独验证 每条都可单独验证(揭示推进与连锁组)
var c := _unrevealed_safe()
if c == Vector2i(-1, -1):
Kit.check("存在未揭示安全格(揭示推进前置)", false)
@@ -103,7 +103,7 @@ func _test_reveal_advances() -> void:
func _test_seal_place() -> void:
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:231 (重复封印拒绝组)
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「调参表」本系统无自有参数 本系统无自有参数(重复封印拒绝组)
var c := _unrevealed_safe()
if c == Vector2i(-1, -1):
Kit.check("存在未揭示安全格(封印前置)", false)
@@ -116,7 +116,7 @@ func _test_seal_place() -> void:
func _test_reject_out_of_catalog() -> void:
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:236 (目录外拒绝组)
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「验收标准」每条都可单独验证 每条都可单独验证(目录外拒绝组)
var out: Array = _rules.settle_batch([{"action": "not_a_real_action", "cell": Vector2i(0, 0)}])
var o: Dictionary = (out[0] as Dictionary) if not out.is_empty() else {}
Kit.check("目录外意图被拒(不静默吞掉)——实际载荷 %s" % str(o).substr(0, 80),
@@ -126,7 +126,7 @@ func _test_reject_out_of_catalog() -> void:
# ---- V14 棋盘揭示预览只读口(架构整改——preview_reveal 与实挖揭示集同口径、零状态写入零事件)----
func _test_preview_reveal_readonly() -> void:
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「核心规则」 (preview_reveal 只读预览口——零写入零事件组)
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「核心规则」玩家对棋盘只做三件事 玩家对棋盘只做三件事(preview_reveal 只读预览口——零写入零事件组)
var events := 0
_rules.cell_revealed.connect(func(_evt): events += 1) # 零发射哨兵(preview 全程不触发揭示事件)
# 形态 A:封印在场——preview(未开格) 不越封印且零状态写入
@@ -199,7 +199,7 @@ func _unrevealed_unsealed_safe() -> Vector2i:
# V1 封印受理即揭示:身份当场可查(sealed_identity 与板事实逐位一致)、受理零事件零兑付
func _test_seal_reveal_identity() -> void:
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:52 封印受理那一刻身份当场可见、受理当场零兑付零事件
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「挖、封印、移动:每个动作怎么才算合法」玩家对棋盘只做三件事 玩家对棋盘只做三件事、受理当场零兑付零事件
_ae.grant_ap(20)
_rules.seal_range_free = true
var safe_c := _unrevealed_unsealed_safe()
@@ -232,7 +232,7 @@ func _test_seal_reveal_identity() -> void:
# V2 挖已封印格被拒:原因可辨 target_sealed、封印/揭示/AP 三态零变化
func _test_dig_sealed_rejected() -> void:
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:56 动作合法性表——挖的拒绝情形含已封印
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「挖、封印、移动:每个动作怎么才算合法」玩家对棋盘只做三件事 玩家对棋盘只做三件事
var sealed_c := Vector2i(-1, -1)
for c in _board.all_cells():
if _rules.has_seal(c) and not _rules.is_revealed(c):
@@ -253,7 +253,7 @@ func _test_dig_sealed_rejected() -> void:
# V3 清图口径换代:封印可完成清图(封掉最后安全格→cleared 收束);非末封印不清图
func _test_clear_by_seal() -> void:
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:139 清图=全部安全格完成,完成=挖开或封印
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「封印立得住、也带不走:封印印记的生命周期与换图重置」挖开或封印 挖开或封印,完成=挖开或封印
_ae.grant_ap(20)
_rules.seal_range_free = true
# 阶段 a:封一张非末安全格 → clear_map_cleared 仍 false(封印计入完成但未清完)
@@ -290,7 +290,7 @@ func _test_clear_by_seal() -> void:
# V4 批次语义序:同批「停手 + 能清图的封」提交 → 赢家=清图收束而非停手
func _test_classify_seal_clears() -> void:
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:167 最先=能清图的挖或封——防耗尽优先把清图高光结算成最差结局
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md「一帧一个意图、对外只有三种事件:批次仲裁与事件面」玩家每帧只提交一个意图 玩家每帧只提交一个意图
# 收敛未完成格到恰 1 格(封它即清图;fx_reveal 连锁不可控——逐格揭至剩 1,连锁越格则换种子重试)
var left: Array = []
var last_c := Vector2i(-1, -1)
+11 -11
View File
@@ -16,7 +16,7 @@ var _gen
func _init() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
_db = ConfigDBScript.new()
var load_ok: bool = _db.load_tables("res://data/tables", true)
if not load_ok:
@@ -78,7 +78,7 @@ func _max_depth(g: Dictionary) -> int:
# ---- V1 产出合格:三档×种子扫描,自证零错误 ----
func _test_output_ok() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:129 (产出约束六条+结构铁律组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「验收标准」产出约束六条 产出约束六条(产出约束六条+结构铁律组)
var all_ok := true
var entry_exit_ok := true
for L in [1, 2, 3]:
@@ -96,7 +96,7 @@ func _test_output_ok() -> void:
# ---- V3 可复现:纯函数+counter 无关 ----
func _test_reproducible() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:134 (同种子同参数同图组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「图的规格:什么算一张合法的图」合法图是一张岔路发散式道路系统 合法图是一张岔路发散式道路系统(同种子同参数同图组)
var same := true
for L in [1, 2, 3]:
if _sig(_graph(L, 42)) != _sig(_graph(L, 42)):
@@ -127,7 +127,7 @@ func _test_reproducible() -> void:
# ---- V5 岔路取舍两条 ----
func _test_fork_rules() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:88 (岔路取舍组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「节点类型配比:类型分布怎么掷、内容归谁」配比是生成旋钮 配比是生成旋钮(岔路取舍组)
var next_hop_ok := true
var comp_ok := true
for L in [1, 2, 3]:
@@ -203,7 +203,7 @@ func _branch_types(g: Dictionary, head_id: int, sibling_outs: Array) -> Array:
# ---- V6 必经恰一店+归属锁定+多终点深度互异 ----
func _test_shop_and_attribution() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:48 (必经恰一店与归属锁定组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「图的规格:什么算一张合法的图」合法图是一张岔路发散式道路系统 合法图是一张岔路发散式道路系统(必经恰一店与归属锁定组)
var paths_ok := true
var lock_ok := true
var depth_ok := true
@@ -256,7 +256,7 @@ func _all_paths(g: Dictionary) -> Array:
# ---- V7 战斗保底 ----
func _test_battle_floor() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:129 (战斗保底组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「验收标准」产出合格 产出合格(战斗保底组)
var ok := true
for L in [1, 2, 3]:
for s in range(42, 52):
@@ -268,7 +268,7 @@ func _test_battle_floor() -> void:
# ---- V9 含岔口与出口结构 ----
func _test_exit_structure() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:48 (出口结构与分支互斥组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「图的规格:什么算一张合法的图」合法图是一张岔路发散式道路系统 合法图是一张岔路发散式道路系统(出口结构与分支互斥组)
var fork_all := true
var l1_single := true
var big_fork_ok := true
@@ -315,7 +315,7 @@ func _terminals_reachable(g: Dictionary, id: int) -> int:
# ---- V9 Boss 出场门控(难度曲线与Boss——每区域恰一 Boss 终点)----
func _test_boss_exit_per_region() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:48 (每区域 Boss 出口组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「图的规格:什么算一张合法的图」Boss Boss(每区域 Boss 出口组)
# 真实生成多区域图:全部终点 type=="boss"、boss 终点数==exit_count、深度=L−r(r∈[0,exit_count)
# ——每区域恰一 boss、深度互异即分属不同区域)
# 节点 depth 字段=入口起最长路径深(生成器校验轴);区域序号 r 的可观测形态=最深 boss(r=0)
@@ -351,7 +351,7 @@ func _test_boss_exit_per_region() -> void:
# ---- V10 RNG 单点(纯流面 counter 不变)----
func _test_rng_single_point() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:134 (RNG 单点流组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「图的规格:什么算一张合法的图」合法图是一张岔路发散式道路系统 合法图是一张岔路发散式道路系统(RNG 单点流组)
var svc = RngScript.new()
svc.new_adventure(4242)
var before: int = svc.counter()
@@ -366,7 +366,7 @@ func _test_rng_single_point() -> void:
# ---- V1 违规夹具:各报对应错误类别 ----
func _test_negative_fixtures() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:198 (无解 fail-fast 夹具组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(无解 fail-fast 夹具组)
# 夹具构造器:手写 nodes/entries/terminals
var dup := _fx([
{"id": 0, "type": "battle", "depth": 0, "next": [1]},
@@ -493,7 +493,7 @@ func _has_msg(errs: Array, needle: String) -> bool:
# ---- V6 节点图三参数表值驱动(架构整改——fork_third_way_pct/fill_rest_first_pct/width_max 入 level_gen_params)----
func _test_gen_params_table_driven() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:129 (参数档读表驱动组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「验收标准」产出合格 产出合格(参数档读表驱动组)
# ① 同种子真实表行产图逐位(表值驱动回归锚)
var g1 := _graph(2, 42)
var g2 := _graph(2, 42)
+5 -5
View File
@@ -12,7 +12,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
func _init() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
if OS.get_cmdline_user_args().has("fatal-fixture"):
_trigger_fatal()
return
@@ -39,7 +39,7 @@ func _reading(gen, db, L: int) -> Dictionary:
# ---- V8 生长递增(三档×多种子逐档读数)----
func _test_growth(gen, db) -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:130 (生长递增组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「验收标准」产出合格 产出合格(生长递增组)
var steps_ok := true
var count_ok := true
for s in [42, 43, 44, 45, 46]:
@@ -63,7 +63,7 @@ func _test_growth(gen, db) -> void:
# ---- V4 参数无解判定(静态面:域/预算无解夹具必须被 check_params 拦下)----
func _test_fail_fast_static(gen, db) -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:198 (参数无解静态拒绝组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(参数无解静态拒绝组)
Kit.check("生产三档参数档可行性判定零错误〔fv4〕",
NodeMapGenerator.check_params(db.run.level_gen_params.row_by_level_index(1)).is_empty()
and NodeMapGenerator.check_params(db.run.level_gen_params.row_by_level_index(3)).is_empty())
@@ -82,7 +82,7 @@ func _test_fail_fast_static(gen, db) -> void:
# ---- V4 致命中止真实通道(子进程退出码非零;零回退分支=件核)----
func _test_fatal_subprocess() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:199 (无解致命子进程组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(无解致命子进程组)
var bin := _engine_bin()
if bin == "":
Kit.check("未找到引擎二进制,致命子进程通道未跑(如实标注)〔fv4〕", false)
@@ -98,7 +98,7 @@ func _test_fatal_subprocess() -> void:
func _trigger_fatal() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var gen = GenScript.new(RngScript.new())
# 域内合法但深度预算无解:层深 6 放三出口(check_params 拦下 → 致命中止)
var unsolvable := {"layers": 6, "branch_density": 0.0, "battle_ratio": 0.5, "reward_ratio": 0.2,
@@ -13,7 +13,7 @@ func _init() -> void:
func _smoke_required_injection() -> void:
# 判据出处: design/engineering/code-conventions.md:40 (拆分交接:依赖构造期一次交付——日志器必填注入守卫组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」拆分交接 拆分交接(拆分交接:依赖构造期一次交付——日志器必填注入守卫组)
# 未注入(缺省 0):start_session 返回空串、零文件产出
var lg0 = load("res://presentation/playtest_logger.gd").new()
var p0: String = lg0.start_session(42)
+5 -5
View File
@@ -9,7 +9,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取(重设计 v1)」 (池结构案 D:候选抽取与池纪律组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取」令牌牌库 令牌牌库(池结构案 D:候选抽取与池纪律组)
var db = load("res://core/config_db.gd").new()
if not db.load_tables("res://data/tables", false):
print("[pool_case_d_test] FAIL — 数值表加载失败")
@@ -66,7 +66,7 @@ func _tiers_of(cands: Array) -> Array:
func check_v7(a, db) -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取(重设计 v1)」 (池案 D V7 组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取」令牌牌库 令牌牌库(池案 D V7 组)
if not a.start_adventure(201):
Kit.check_quiet(false, "V7 前置:冒险启动")
return
@@ -112,7 +112,7 @@ func check_v7(a, db) -> void:
func check_v6(b, db) -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取(重设计 v1)」 (池案 D V6 组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取」令牌牌库 令牌牌库(池案 D V6 组)
if not b.start_adventure(202):
Kit.check_quiet(false, "V6 前置:冒险启动")
return
@@ -142,7 +142,7 @@ func check_v6(b, db) -> void:
func check_v12(m, db) -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取(重设计 v1)」 (池案 D V12 组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取」令牌牌库 令牌牌库(池案 D V12 组)
if not m.start_adventure(401):
Kit.check_quiet(false, "V12 前置:冒险启动")
return
@@ -161,7 +161,7 @@ func check_v12(m, db) -> void:
func check_v8(c, db) -> void:
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取(重设计 v1)」 (池案 D V8 组)
# 判据出处: design/gdd/systems/冒险循环/奇物.md「池结构与抽取」令牌牌库 令牌牌库(池案 D V8 组)
if not c.start_adventure(203):
Kit.check_quiet(false, "V8 前置:冒险启动")
return
+6 -6
View File
@@ -20,7 +20,7 @@ const TAG_OK := "board_gen" # 在册合法标签(PURPOSE_TAGS 含;wr7 必
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:199 (运行期违约通道——致命真的会死组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(运行期违约通道——致命真的会死组)
var db = ConfigDBScript.new()
if not db.load_tables("res://data/tables", true):
push_error("[run_time_fatal_test] 表加载失败——夹具不可用(回归)")
@@ -45,7 +45,7 @@ func _init() -> void:
# 缺省形态(契约 2):不接组装点的协作件违约只落自身 push_error+assert,不外溢封印
func _default_form(db) -> bool:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var rng = RngScript.new()
rng.set_master_seed(3)
var oc = OrchestratorScript.new(db, rng)
@@ -70,7 +70,7 @@ func _default_form(db) -> bool:
# (棋盘生成半边:装板域拆件后生成器随 BoardInstaller 件内自建——组装点=引用束 fatal_cb 接线,
# 经新组装点构建后触发生成器违约,封印传导断言不变)
func _seal_propagation(db) -> bool:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var rng_a = RngScript.new()
rng_a.set_master_seed(5)
var oc_bg = OrchestratorScript.new(db, rng_a)
@@ -92,7 +92,7 @@ func _seal_propagation(db) -> bool:
# ②wr6(p6):未知用途标签 → handler 记录位为真(判据主体)+拿不到可用 RNG;合法标签对照另行验过
func _unknown_tag_channel() -> bool:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var rng_bad = RngScript.new()
rng_bad.set_master_seed(7)
if not _inject_handler(rng_bad, "wr6"):
@@ -111,7 +111,7 @@ func _unknown_tag_channel() -> bool:
# ③wr7(p7):未播种取数 → handler 记录位为真+拿不到可用 RNG;同标签播种对照另行验过
func _unseeded_channel() -> bool:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var rng_bad = RngScript.new() # 不播种(_master_seed 缺省 -1)
if not _inject_handler(rng_bad, "wr7"):
return false
@@ -129,7 +129,7 @@ func _unseeded_channel() -> bool:
# 成员在位前提检查(成员被移除时走干净退出 2,不落「赋值不存在的属性」式中途中断)
func _inject_handler(rng, label: String) -> bool:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
if not (rng.get("violation_handler") is Callable):
push_error("[run_time_fatal_test/%s] violation_handler 成员缺失(p6/p7 形态未实装——回归)" % label)
return false
@@ -22,7 +22,7 @@ func _init() -> void:
# ① 无参实例(autoload 实例化形态)=无激活态+默认合法空态(sv2 类级)
func _test_no_arg_instance_has_no_activation() -> void:
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:61 (启动态无激活不读写组)
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「系统范围」边界这样划 边界这样划(启动态无激活不读写组)
var sm := SaveManagerScript.new()
Kit.check_quiet(sm.slots.active_slot() == 0 and not sm.slots.has_write_target(),
"sv2 无参实例无激活态(路径空/激活号 0/写盘目标空)〔卡① sv2〕")
@@ -41,7 +41,7 @@ func _test_no_arg_instance_has_no_activation() -> void:
# 判别锚:空 _path 的退化写目标=裸 ".tmp"(落 res://,拆闸实验实测杂散落点)——
# 断言先清退化目标再核零新增,闸短路缺陷(拒绝口旁路、写盘真实发生)必红。
func _test_write_rejected_without_target() -> void:
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:61 (无激活态写盘拒绝组)
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「系统范围」边界这样划 边界这样划(无激活态写盘拒绝组)
var sm := SaveManagerScript.new()
var before := {}
for i in range(1, 4):
@@ -81,7 +81,7 @@ func _test_write_rejected_without_target() -> void:
# (生产结算链全段在位:mark_first_adventure_done→apply_adventure_summary→refresh_treasure_unlocks
# →write_to_disk;无激活态下落账内存、写盘拒绝、盘面零触碰——已知中间态的机检面)
func _test_settle_chain_write_rejected() -> void:
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:61 (结算链写盘拒绝组)
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「系统范围」边界这样划 边界这样划(结算链写盘拒绝组)
var db = load("res://core/config_db.gd").new()
if not db.load_tables("res://data/tables", false):
Kit.check_quiet(false, "sv3 链测试前置:数值表加载失败〔卡① sv3〕")
@@ -104,7 +104,7 @@ func _test_settle_chain_write_rejected() -> void:
# ③ 越界槽号三原语拒绝+窥视越界返回不可读(原语边界 fail-safe)
func _test_out_of_range_slots_rejected() -> void:
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:61 (三存档位域界——越域槽拒绝组)
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「系统范围」边界这样划 边界这样划(三存档位域界——越域槽拒绝组)
var sm := SaveManagerScript.new()
sm.slots.attach_slot_template("user://smoke_boot_noact_%d.json")
Kit.check_quiet(not sm.slots.activate_slot(0) and not sm.slots.activate_slot(4)
@@ -19,7 +19,7 @@ var _db
func _init() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
_db = ConfigDBScript.new()
# 表加载失败不中止(承 G2–G5 同款:表损坏的红落在具体断言上)
var load_ok: bool = _db.load_tables("res://data/tables", true)
@@ -47,7 +47,7 @@ func _fresh_rng(seed_val: int):
# 损坏兜底/迁移链/域界干净/摘要 cap/摘要跨系统块/生涯终身计数域 v6)。测试文件统一 user://smoke_save_*.json 隔离,
# 段首清场+段尾清理——绝不碰 user://save.json(红线)。
func _smoke_save() -> void:
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:176 (存档域读写往返/迁移链/损坏兜底/域界组)
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「验收标准」往返一致 往返一致(存档域读写往返/迁移链/损坏兜底/域界组)
print("--- SaveManager 存档读写/迁移/兜底 ---")
var sm_script = load("res://core/save_manager.gd")
var paths := ["user://smoke_save_roundtrip.json", "user://smoke_save_fresh.json",
@@ -340,7 +340,7 @@ func _smoke_save() -> void:
# 测试文件统一 user://smoke_save_slot_%d.json 模板隔离(attach_slot_template 注入口——禁各自拼槽名),
# 段首清场+段尾清理——绝不碰 user://save.json 与真实槽 user://save_slot_N.json(红线)。
func _smoke_save_slots() -> void:
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:61 (三槽位与摘要 cap——槽位域组)
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「系统范围」边界这样划 边界这样划(三槽位与摘要 cap——槽位域组)
print("--- SaveManager 三存档位承载(迭代 33 卡①)---")
var sm_script = load("res://core/save_manager.gd")
var slot_tpl := "user://smoke_save_slot_%d.json"
@@ -38,7 +38,7 @@ func _write_v7_keystone(path: String, keystone: int) -> void:
# ① 三槽往返:各槽写异值 → 写盘 → 新实例按位读回逐域相等;改槽 1 槽 2 字节不动(sv1)
func _test_three_slot_roundtrip_and_isolation() -> void:
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:61 (三槽位独立文件隔离组)
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「系统范围」边界这样划 边界这样划(三槽位独立文件隔离组)
var t := SaveManagerScript.new()
t.slots.attach_slot_template(TPL)
for i in range(1, 4):
@@ -66,7 +66,7 @@ func _test_three_slot_roundtrip_and_isolation() -> void:
# ② 高版本槽进档失败:拒绝+恢复切换前三态(路径/激活号/数据)+拒读槽零误写(sv9/sv10)
func _test_activate_failure_restores_previous_slot() -> void:
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:61 (激活失败回滚组)
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「系统范围」边界这样划 边界这样划(激活失败回滚组)
var t := SaveManagerScript.new()
t.slots.attach_slot_template(TPL)
_write_v7_keystone(TPL % 1, 311)
@@ -88,7 +88,7 @@ func _test_activate_failure_restores_previous_slot() -> void:
# ③ MetaProgression 宿主链切槽:引用同一性保持+写盘落当前槽(sv10——禁换实例先例)
func _test_metaprogression_reference_identity() -> void:
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:176 (元进度引用同一性——往返一致组)
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「验收标准」往返一致 往返一致(元进度引用同一性——往返一致组)
var t := SaveManagerScript.new()
t.slots.attach_slot_template(TPL)
_write_v7_keystone(TPL % 1, 533)
@@ -36,7 +36,7 @@ func _write_slot_json(path: String, content: String) -> void:
# ① 三槽异值逐槽三项正确+不激活不写内存(sv7)
func _test_peek_three_slots_distinct_values() -> void:
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:174 (槽位摘要按槽窥视组)
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「验收标准」往返一致 往返一致(槽位摘要按槽窥视组)
var t := SaveManagerScript.new()
t.slots.attach_slot_template(TPL)
for i in range(1, 4):
@@ -58,7 +58,7 @@ func _test_peek_three_slots_distinct_values() -> void:
# ② 空槽零值合法态+不可读三态显式标记(sv7/契约 9)
func _test_peek_empty_and_unreadable_states() -> void:
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:174 (坏槽三态组)
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「验收标准」往返一致 往返一致(坏槽三态组)
var t := SaveManagerScript.new()
t.slots.attach_slot_template(TPL)
DirAccess.remove_absolute(TPL % 3) # 清①段残留——空槽夹具
@@ -79,7 +79,7 @@ func _test_peek_empty_and_unreadable_states() -> void:
# ③ 窥视零副作用:字节+mtime 双比对不变+零 .corrupt.bak 改名(sv8——真实入口冒烟段同判据)
func _test_peek_zero_side_effect() -> void:
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:174 (窥视零副作用组)
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「验收标准」往返一致 往返一致(窥视零副作用组)
var t := SaveManagerScript.new()
t.slots.attach_slot_template(TPL)
_write_slot_json(TPL % 1, "corrupt bytes {{{{")
+1 -1
View File
@@ -9,7 +9,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (结算五段 Segment——五段全序组)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「验收标准」五段全序 五段全序(结算五段 Segment——五段全序组)
var db = load("res://core/config_db.gd").new()
if not db.load_tables("res://data/tables", false):
print("[settle_segments_test] FAIL — 数值表加载失败")
@@ -10,7 +10,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/跨局循环/秘宝.md:246 (秘宝 12 件逐件行为——效果行为组)
# 判据出处: design/gdd/systems/跨局循环/秘宝.md「验收标准」护栏强制 护栏强制(秘宝 12 件逐件行为——效果行为组)
var db = load("res://core/config_db.gd").new()
if not db.load_tables("res://data/tables", false):
Kit.check_quiet(false, "数值表加载")
@@ -424,7 +424,7 @@ class StubAutoInvRunner:
# 保留并存;本函数断言全链依赖生产行值:add_item 入库→装配集直注(套件既定调试注入口径)→attune 参数和
# ==行值 125→转存兑付按 grant_segment 生产入参形态(装配面读数为入参)兑现。行值变更即红。
func _test_rap_transfer_row_e2e(db) -> void:
# 判据出处: design/gdd/systems/跨局循环/秘宝.md:246 (秘宝逐件行为——储备罐转存率行值)
# 判据出处: design/gdd/systems/跨局循环/秘宝.md「验收标准」护栏强制 护栏强制(秘宝逐件行为——储备罐转存率行值)
var inv = load("res://core/treasure_items.gd").new()
var got: Dictionary = inv.add_item("reserve_jar", "clear_reward", Vector2i(-1, -1), 0)
Kit.check_quiet(not got.is_empty() and String(got.get("item_id", "")) == "reserve_jar",
+1 -1
View File
@@ -53,7 +53,7 @@ func _all_revealed(_c: Vector2i) -> bool:
func _init() -> void:
# 判据出处: design/gdd/systems/跨局循环/秘宝.md:246 (秘宝结构冻结与护栏校验——结构组)
# 判据出处: design/gdd/systems/跨局循环/秘宝.md「验收标准」护栏强制 护栏强制(秘宝结构冻结与护栏校验——结构组)
# ① 授予归因+受理序+Used 不可逆
var inv = _new_inv()
var r1: Dictionary = inv.add_item("morning_order", "safe_cell", Vector2i(3, 4), 2)
@@ -7,7 +7,7 @@ extends SceneTree
func _init() -> void:
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:195 (等级阈值前置:schema 四拒一过+判定三态+投影两态组)
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「验收标准」等级阈值前置 等级阈值前置(等级阈值前置:schema 四拒一过+判定三态+投影两态组)
var failures := 0
var db = load("res://core/config_db.gd").new()
var mt = load("res://data/schemas/meta_tree_table.gd").new()
+2 -2
View File
@@ -12,7 +12,7 @@ extends SceneTree
func _init() -> void:
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:194 (结构封闭:六键合成行闭集校验组)
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「验收标准」结构封闭 结构封闭(结构封闭:六键合成行闭集校验组)
var eng = load("res://core/effect_engine.gd")
var tree_tbl = load("res://data/schemas/meta_tree_table.gd")
var db = load("res://core/config_db.gd").new()
@@ -89,7 +89,7 @@ func _init() -> void:
# ---- 规则键参数域校验(架构整改批 R1——六键参数字典):正例全过/缺参数拒/多参数拒/越域拒/非字典拒 ----
func _test_rule_key_params(eng, tree_tbl, db) -> Array:
# 判据出处: design/gdd/systems/跨局循环/天赋树.md:194 (规则键参数字典——参数名/取值域合规组)
# 判据出处: design/gdd/systems/跨局循环/天赋树.md「验收标准」结构封闭 结构封闭(规则键参数字典——参数名/取值域合规组)
var errs: Array = []
var params_tbl: Dictionary = tree_tbl.RULE_KEY_PARAMS
# 正例:meta_tree.tres 现行 Fork 行逐键过 validate(加载期已验——此处显式复核)
+5 -5
View File
@@ -20,7 +20,7 @@ var _db
func _init() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
_db = ConfigDBScript.new()
# 表加载失败不中止(承 G2–G5 同款:表损坏的红落在具体断言上)
var load_ok: bool = _db.load_tables("res://data/tables", true)
@@ -47,7 +47,7 @@ func _fresh_rng(seed_val: int):
# ---- ① RNG 事件日志会话落盘(源 `_initialize` :70,主会话裁决一改判跨系统闭环承载——
# 驱动沿源 :60–70 取号序列自持:master 种子 42 → 前置取号 → new_adventure 开日志会话 → 会话内取号)----
func _rng_event_log_session() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流」 (事件日志落盘会话组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流:随机只从一个服务按号取,同种子必同局」用户两轮复裁 用户两轮复裁(事件日志落盘会话组)
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(42)
rng.open_stream("board_gen")
@@ -62,7 +62,7 @@ func _rng_event_log_session() -> void:
# _on_level_finished(victory)+breakpoint_snapshot 取读+clear_breakpoint;
# 起局与兑付两步的受理断言留单元宿主(adventure_feats_test),此处纯驱动——前置失败自然落红)----
func _feats_breakpoint_roundtrip() -> void:
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md:180 (专长断点附随件往返组)
# 判据出处: design/gdd/systems/表现与支撑/存档序列化.md「验收标准」往返一致 往返一致(专长断点附随件往返组)
var rt := FeatTable.new()
rt.rows = [
{"feat_id": "x1", "display_name": "试一", "rarity": "common", "desc": "测试揭示", "cap": 1,
@@ -108,7 +108,7 @@ func _feats_breakpoint_roundtrip() -> void:
# level_autoplay 真局摘要 → apply 原语 → 域读数 → 写盘读回保持;临时档 user://smoke_save_integration.json
# 段首清场+段尾清理(源 _smoke_save 隔离纪律),绝不碰 user://save.json(红线))----
func _save_summary_integration() -> void:
# 判据出处: design/gdd/systems/跨局循环/元进度.md:150 (摘要跨系统块与钥石只增不减组)
# 判据出处: design/gdd/systems/跨局循环/元进度.md「验收标准」钥石不丢 钥石不丢(摘要跨系统块与钥石只增不减组)
var sm_script = load("res://core/save_manager.gd")
var path9 := "user://smoke_save_integration.json" # 源 paths[8]
if FileAccess.file_exists(path9):
@@ -141,7 +141,7 @@ func _save_summary_integration() -> void:
# ---- ④ 试玩记录仪(源 `_smoke_playtest_logger` 整套八条,主会话裁决七改判跨系统闭环承载——
# PlaytestLogger 挂真实结算流:会话文件/逐结算快照/字段齐备/spawn_count 回归/诊断转储/JSONL 回读)----
func _smoke_playtest_logger() -> void:
# 判据出处: design/engineering/code-conventions.md:40 (试玩日志器跨系统接线组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(试玩日志器跨系统接线组)
print("--- PlaytestLogger(结算快照 JSONL + 诊断转储)---")
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(20260912)
@@ -12,7 +12,7 @@ var _db
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:200 致命真的会死:正式通道加载进程非 0 退出(装载前提组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(装载前提组)
_db = ConfigDBScript.new()
var load_ok: bool = _db.load_tables("res://data/tables", true)
if not load_ok:
@@ -24,7 +24,7 @@ func _init() -> void:
func _trigger_oob() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:204 越域请求在进入解析前致命中止(Fatal 级诊断+进程非 0,无兜底)(越域组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(Fatal 级诊断+进程非 0,无兜底)(越域组)
# 共享 .tres 上的 resolver 归最后装载的实例——autoload ConfigDB 的 _ready 在测试 _init 之后
# 二次注入覆盖私有实例,故触发前把解析通道归还被测实例(诊断落 _db,退出码判据才成立)
_db.combat.board_gen._resolver = _db._resolver
@@ -9,7 +9,7 @@ const Kit := preload("res://tests/unit/test_kit.gd") # T6 收口:_check/汇
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:198 干净检出:表清单内全部表加载成功、就绪态断言(装载组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者、就绪态断言(装载组)
var db = ConfigDBScript.new()
var load_ok: bool = db.load_tables("res://data/tables", true)
Kit.check("全部表加载 + 校验通过(含跨表护栏零 error 诊断)〔fv6〕", load_ok and db.diagnostics_count("error") == 0)
@@ -31,7 +31,7 @@ func _init() -> void:
# ---- 进度坐标 ceil 解析(R1:向上下取整保证偏难;越最大行 clamp 取最大值 + 警告去重)----
func _test_progress_resolution(db) -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:203 向上取整解析:请求无精确行返回不低于请求坐标的最近行(进度查行组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(进度查行组)
var bg_rows: Array = db.combat.board_gen.rows
# 行键全集自表推导(禁写死关卡/深度数值)
var level_keys: Array = []
@@ -88,7 +88,7 @@ func _test_progress_resolution(db) -> void:
# ---- 变异池门控(unlock_level 闸 + ∅ board_types 通配 + 节点身份第三维)----
func _test_variant_pool_gate(db) -> void:
# 判据出处: design/gdd/systems/排雷循环/地形变异.md:153 候选池空合法:门控筛空时静默零布置(变异门控组)
# 判据出处: design/gdd/systems/排雷循环/地形变异.md「验收标准」候选池空合法 候选池空合法(变异门控组)
var rows: Array = db.combat.variation.rows
var gated_row := {}
var wildcard_row := {}
@@ -131,7 +131,7 @@ func _rows_contain(pool: Array, row: Dictionary) -> bool:
# ---- ShopTable 消费面(行集解析单点——runner/编排禁自扫表的契约消费侧验证)----
func _test_shop_accessors(db) -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:199 校验类别全覆盖:行结构与引用闭合(商店访问器行结构组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(商店访问器行结构组)
var products: Array = db.run.shop.product_rows()
if products.is_empty():
Kit.check("ShopTable products 行族非空(表已已入库前提)", false)
@@ -159,7 +159,7 @@ func _test_shop_accessors(db) -> void:
# ---- MetaTable 消费面 ----
func _test_meta_accessors(db) -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:199 校验类别全覆盖:行结构与引用闭合(元进度访问器行结构组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(元进度访问器行结构组)
# 无 forge_products 行族断言(行族/访问器不在表,V20 清单)
var key_rows: Array = db.crossrun.meta.boss_keystone
if not key_rows.is_empty():
@@ -179,7 +179,7 @@ func _test_meta_accessors(db) -> void:
# ---- TABLE_MANIFEST ↔ data/tables 目录同步(各系统→D2 单点契约的登记面)----
func _test_manifest_dir_sync(db) -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:198 表目录无清单外文件(清单对账组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(清单对账组)
var manifest: Dictionary = db.TABLE_MANIFEST
var dir := DirAccess.open("res://data/tables")
var disk_files: Array = []
@@ -204,7 +204,7 @@ func _test_manifest_dir_sync(db) -> void:
# (rowset_rule——行序即契约,R6 加载期兜底)③行集实例总数 ≤4(骰后值运行面,spawn 守卫——冒烟侧验证)。
func _test_rowset_discipline() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:199 校验类别:重复键与缺锚行逐类断言(行集纪律组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(行集纪律组)
# 行集用 rows.assign([...]) 而非直接赋值:rows 是 Array[Dictionary] 定型属性,直接赋 untyped
# 数组字面量会触发「Invalid assignment」脚本错误——该错误不改退出码,却会**中断本函数剩余断言**
#(本函数五条纪律断言曾因此全部静默不跑,套件仍报 all green,是零覆盖假象)。
@@ -20,7 +20,7 @@ const PROBE_REF := ' {\n "feat_id": "ref_probe",\n "display_name": "引用探
func _inject(dir: String, probe: String) -> bool:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:199 校验类别全覆盖:前缀违规夹具注入(前缀夹具组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(前缀夹具组)
var path := dir + "/feats.tres"
var f := FileAccess.open(path, FileAccess.READ)
if f == null:
@@ -45,7 +45,7 @@ func _inject(dir: String, probe: String) -> bool:
func _assert_rejected(bad_dir: String, probe: String, label: String) -> bool:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:200 致命真的会死:违规表拒绝且进程非 0(拒绝判定组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(拒绝判定组)
# 返回 true=正确拒绝;false=放行或夹具失败(调用方据此退出 2)
if not Kit.copy_tables(SRC_DIR, bad_dir) or not _inject(bad_dir, probe):
push_error("[%s] 夹具目录准备失败" % label)
@@ -39,7 +39,7 @@ const PROBE_TRADE_KEY := ' {
func _inject(dir: String, probe: String) -> bool:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:199 校验类别全覆盖:退役词夹具注入(退役词夹具组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(退役词夹具组)
var path := dir + "/feats.tres"
var f := FileAccess.open(path, FileAccess.READ)
if f == null:
@@ -64,7 +64,7 @@ func _inject(dir: String, probe: String) -> bool:
func _assert_rejected(bad_dir: String, probe: String, label: String) -> bool:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:200 致命真的会死:退役词加载致命中止(拒绝判定组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(拒绝判定组)
# 返回 true=正确拒绝;false=放行或夹具失败(调用方据此退出 2)
if not Kit.copy_tables(SRC_DIR, bad_dir) or not _inject(bad_dir, probe):
push_error("[%s] 夹具目录准备失败" % label)
@@ -58,7 +58,7 @@ func _count_cat(errs: Array, cat: String) -> int:
# ---- R1:elite 行类合法与字段互锁、引用校验(合法零错+十一违例各自「含」预期类别)----
func _test_elite_validation_rejects() -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:325 elite 行字段互锁与基础引用违例加载期返回错误
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「验收标准」开战生成 开战生成
var t_ok = EnemyTableScript.new()
t_ok.rows.assign(_legal_rows())
var errs: Array = t_ok.validate()
@@ -130,7 +130,7 @@ func _validate_rows(rows: Array) -> Array:
# ---- R2:有效池=基础池+附加技,基础池取深度带最小行(深带行在前防取首行假绿)----
func _test_effective_pool_merge() -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:149 精英有效池=同关战斗行类基础敌种深度带最小行的池+附加技
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「精英行:现役敌种的强化版,池=继承基础池+附加技」精英怪是某个现役敌种的强化版本 精英怪是某个现役敌种的强化版本
var rows := [
_mk_row(1, "battle", 3, "goblin"), # 深带行在前(取首行的错误实现必红)
_mk_row(1, "battle", 0, "goblin"),
@@ -155,7 +155,7 @@ func _test_effective_pool_merge() -> void:
# ---- R3:继承不复制——基础池改表传到精英、改写返回数组不回灌 ----
func _test_base_pool_change_propagates() -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:149 继承不复制——基础池调参自动传到精英
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「精英行:现役敌种的强化版,池=继承基础池+附加技」精英怪是某个现役敌种的强化版本 精英怪是某个现役敌种的强化版本
var rows := [
_mk_row(1, "battle", 3, "goblin"),
_mk_row(1, "battle", 0, "goblin"),
@@ -181,7 +181,7 @@ func _test_base_pool_change_propagates() -> void:
# ---- R4:合并池过池构成纪律(跨表件校验对象=合并后的池)----
func _test_merged_pool_composition() -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:150 池构成纪律校验对象是合并后的池
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「精英行:现役敌种的强化版,池=继承基础池+附加技」精英怪是某个现役敌种的强化版本 精英怪是某个现役敌种的强化版本
var skills := SkillTableScript.new()
skills.rows.assign([
{"skill_id": "attack", "type": "basic"},
@@ -239,7 +239,7 @@ func _msgs(errs: Array) -> Array[String]:
# ---- R5:暂不接线——表里有 elite 行时寻址拿不到它(行类门改动特有判据)----
func _test_elite_unreachable_by_encounter() -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:151 精英行接线前不会被任何节点读到
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「精英行:现役敌种的强化版,池=继承基础池+附加技」精英怪是某个现役敌种的强化版本 精英怪是某个现役敌种的强化版本
_diags.clear()
var resolver = ResolverScript.new(
func(level, category, message) -> void:
@@ -272,7 +272,7 @@ func _test_elite_unreachable_by_encounter() -> void:
# ---- R6:生产表地精精英落表(真实加载零错+行值逐位+有效池字典)----
func _test_production_goblin_elite() -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:147 精英=敌人表行类为 elite 的独立一行
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「精英行:现役敌种的强化版,池=继承基础池+附加技」精英怪是某个现役敌种的强化版本 精英怪是某个现役敌种的强化版本
var db = load("res://core/config_db.gd").new()
var ok: bool = db.load_tables("res://data/tables", true)
Kit.check("生产表 ConfigDB.load_tables 装载(is_ready=%s)〔精英批 V6〕" % str(db.is_ready), ok and db.is_ready)
@@ -12,7 +12,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:198 锻造表装载与就绪态(装载组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(装载组)
var db = ConfigDBScript.new()
var load_ok: bool = db.load_tables("res://data/tables", true)
Kit.check("生产 forge.tres 随全表加载 + validate 零违例〔锻造工坊批 V1〕", load_ok and db.diagnostics_count("error") == 0)
@@ -27,7 +27,7 @@ func _init() -> void:
# ---- 生产表六行正向(V1 生产面 + V11 行字段闭集)----
func _test_production_rows(db) -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:199 校验类别全覆盖:行 schema 正反逐类断言(生产行结构组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(生产行结构组)
var rows: Array = db.crossrun.forge.route_rows()
Kit.check("六路线行族规模恰 6(三武器+三甲)〔锻造工坊批 V1〕", rows.size() == 6)
var ids := []
@@ -91,7 +91,7 @@ func _test_production_rows(db) -> void:
# ---- 几何价格梯(V2 价格面单测半边——购买写在 T3 冒烟)----
func _test_price_ladder(db) -> void:
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md:220 定价结构:每级价格随已购级数几何递增、基价与公比读表单点(价格梯组)
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「验收标准」基价与公比读表单点 基价与公比读表单点、基价与公比读表单点(价格梯组)
var row: Dictionary = db.crossrun.forge.route("sword")
var prices := []
for owned in range(5):
@@ -150,7 +150,7 @@ func _mut_spear_initial(t) -> void:
func _test_negative_cases() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:199 校验类别全覆盖(负向 schema 组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(负向 schema 组)
# 夹具本身须零违例(否则负向判读失效)
var t_ok = ForgeTableScript.new()
t_ok.routes = _base_rows()
@@ -218,7 +218,7 @@ func _test_negative_cases() -> void:
# 现行 30;本套件零扩签,钉现行数(将来任何加词即转红提示复核)。
func _test_effect_kinds_closed() -> void:
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「满级特效扩展位」 事件/事实/效果类型/算子四词表封闭(特效闭集组)
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「满级特效扩展位」满级特效 满级特效(特效闭集组)
Kit.check("效果引擎效果类型闭集 30 种〔锻造工坊批 V11〕",
EffectEngineScript.EFFECT_KINDS.size() == 30)
Kit.check("效果引擎事件词表在册 21 种(charge_full 位摘名——蓄力层删键批)〔锻造工坊批 V11〕",
@@ -11,7 +11,7 @@ const Kit := preload("res://tests/unit/test_kit.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:198 参数档表装载与就绪态(装载组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(装载组)
var db = ConfigDBScript.new()
var load_ok: bool = db.load_tables("res://data/tables", true)
Kit.check("生产 level_gen_params.tres 随全表加载 + validate 零违例〔fv2〕",
@@ -43,7 +43,7 @@ func _table(rows: Array) -> Variant:
# ---- 生产三行正向(V2)----
func _test_production(db) -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:127 产出合格:任意参数档产出的图必过产出约束(生产档组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「验收标准」产出合格 产出合格(生产档组)
var r1: Dictionary = db.run.level_gen_params.row_by_level_index(1)
var r2: Dictionary = db.run.level_gen_params.row_by_level_index(2)
var r3: Dictionary = db.run.level_gen_params.row_by_level_index(3)
@@ -61,7 +61,7 @@ func _test_production(db) -> void:
# ---- 访问器缺行防御 ----
func _test_accessor() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:127 参数档访问器读回与产出约束(访问器组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「验收标准」产出合格 产出合格(访问器组)
var t = _table([_row(1, 6, 0.3, [0.5, 0.2, 0.2, 0.1], 1, 1, 4)])
Kit.check("row_by_level_index 缺行返回空字典〔fv2〕", t.row_by_level_index(9).is_empty())
@@ -69,7 +69,7 @@ func _test_accessor() -> void:
# ---- 域校验逐类负向(V2)----
func _test_negative() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:199 校验类别全覆盖:参数档 schema 拒绝(负向组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(负向组)
# 合法基线三行
var base := [_row(1, 6, 0.3, [0.5, 0.2, 0.2, 0.1], 1, 1, 4),
_row(2, 9, 0.5, [0.5, 0.2, 0.15, 0.15], 2, 2, 6),
@@ -14,7 +14,7 @@ const BAD_DIR := "user://treasure_fixture_dangling"
func _inject_violation() -> bool:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:199 校验类别:悬空引用夹具(悬空引用组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(悬空引用组)
var path := BAD_DIR + "/reward.tres"
var f := FileAccess.open(path, FileAccess.READ)
if f == null:
@@ -37,7 +37,7 @@ func _inject_violation() -> bool:
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:200 致命真的会死:悬空引用被拒绝、进程非 0(拒绝组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者、进程非 0(拒绝组)
if not Kit.copy_tables(SRC_DIR, BAD_DIR) or not _inject_violation():
push_error("[reward_dangling_treasure_test] 夹具目录准备失败")
quit(2)
@@ -12,7 +12,7 @@ const TEST_SEED := 20260928 # 夹具种子(任意固定值;语义 = 可复
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:201 黄金向量:登记向量逐个复算(装载组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(装载组)
_test_derive_determinism()
_test_counter_ledger()
_test_stream_draw_determinism()
@@ -28,7 +28,7 @@ func _fresh_service():
# 单盐派生纯函数:两全新实例同种子逐位一致(derive_at 不推计数器——纯函数契约)
func _test_derive_determinism() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:201 黄金向量:随机派生纯函数对登记向量逐个复算相等、同输入恒同输出(派生确定性组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者、同输入恒同输出(派生确定性组)
var a = _fresh_service()
var b = _fresh_service()
var same := true
@@ -44,7 +44,7 @@ func _test_derive_determinism() -> void:
# 全局取数计数器:唯一账本——open_stream 逐次 +1(scope 单调)
func _test_counter_ledger() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:202 计数器纪律:连续取号跨模拟关卡切换单调不重置(计数账本组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(计数账本组)
var rng = _fresh_service()
var c0: int = rng.counter()
rng.open_stream("armor_roll")
@@ -62,7 +62,7 @@ func _test_counter_ledger() -> void:
# 同种子两实例同标签流的实际取数序列逐位一致(回放确定性契约——存档快照=主种子+计数器的前提)
func _test_stream_draw_determinism() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:201 同输入恒同输出:流取号确定性(流取号组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(流取号组)
var faces := 20 # d20 探针面数(夹具值,非玩法表值——只用于产生可比较序列)
var a = _fresh_service()
var b = _fresh_service()
@@ -77,7 +77,7 @@ func _test_stream_draw_determinism() -> void:
# 负输入 abs 归一化(警告通道)——|−s| 与 s 同派生
func _test_negative_seed_normalization() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流」 RngService:master_seed 与各流 scope 计数器单点(种子规约组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流:随机只从一个服务按号取,同种子必同局」用户两轮复裁 用户两轮复裁(种子规约组)
var pos = _fresh_service()
var neg = RngServiceScript.new()
neg.set_master_seed(-TEST_SEED)
@@ -22,7 +22,7 @@ func _init() -> void:
# 单元宿主改由 `_init` 显式调用,断言逐字未动;源 :70 事件日志落盘条经主会话裁决一
# 改判跨系统闭环套件——不随本宿主,见迁移账本转办清单)----
func _smoke_initialize() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流」 RngService autoload:open_stream 有状态门面与启动初始化(启动流组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「统一随机流:随机只从一个服务按号取,同种子必同局」用户两轮复裁 用户两轮复裁(启动流组)
print("=== Dungeon Sweeper 垂直切片冒烟 ===")
var db = ConfigDBScript.new()
var load_ok: bool = db.load_tables("res://data/tables", true)
@@ -29,7 +29,7 @@ var _db
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:198 表结构守卫装载与就绪态(装载组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(装载组)
_db = ConfigDBScript.new()
# 表加载失败不中止(沿被迁断言面的源语义:表损坏的红落在具体断言上——
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
@@ -96,7 +96,7 @@ func _first_encounter_band(level_index: int, enemy_id: String) -> int:
# ① 冒险表(单行全局 Rule 4 豁免——建表与接线闸;TP0 令牌池:配额结构/件值对/池总量域检)
func _smoke_adventure_table() -> void:
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md:281 冒险结构表校验(冒险表组)
# 判据出处: design/gdd/systems/冒险循环/冒险结构.md「验收标准」开始新冒险 开始新冒险(冒险表组)
print("--- 冒险表(AdventureTable——令牌池行值单点:回血/配额/件值对/同调位)---")
Kit.check("db.adventure 已加载(adventure.tres 入 manifest)", _db.run.adventure != null)
if _db.run.adventure == null:
@@ -215,7 +215,7 @@ func _smoke_adventure_table() -> void:
# ---- 敌人表深度带键结构(迭代 34 建·L1 混编批换代:30 行键序=覆盖表序·(1,3) 混编行集·Boss 行集带键清单·精英行)----
func _smoke_enemy_bands() -> void:
# 判据出处: design/gdd/systems/冒险循环/难度曲线与Boss.md:316 难度与敌人带校验(敌人带组)
# 判据出处: design/gdd/systems/冒险循环/难度曲线与Boss.md「验收标准」坐标行齐备 坐标行齐备(敌人带组)
print("--- 敌人表深度带键结构(30 行键序 · (1,3) 混编 · Boss 带键覆盖表 · 精英行)---")
# ① 30 行计数 + 键序 = 覆盖表序(文件行序不变——行序即契约;(1,3) 两行相邻、熊地精在前;精英行随精英专属池批)
# 迭代 35 生成图深度扩面覆盖批随动:战斗带顶扩到各关最大生成深度(L1→6/L2→9/L3→13)、
@@ -304,7 +304,7 @@ func _smoke_enemy_bands() -> void:
# ④ 掷点参数域:档位边界升序/档位值降序无零档/骰面与暴击参数在域(加载校验双保险)。
func _smoke_ac_swap_guard() -> void:
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md:219 切换语义:一次冒险=一个武器类型+一个甲型,冒险开始后锁死(AC 换装守卫组)
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「验收标准」冒险开始后锁死 冒险开始后锁死,冒险开始后锁死(AC 换装守卫组)
print("--- 护甲等级掷点批·换装护栏 ---")
# ① 三处无双轨
Kit.check("状态表 defense_up 行已退役(无双轨)", _db.combat.status_effects.row_by_id("defense_up").is_empty())
@@ -425,7 +425,7 @@ func _smoke_ac_swap_guard() -> void:
# ---- 地形变异 框架面(四行两轴×两关 + 门控 + 跨字段互锁)----
func _smoke_variation_framework() -> void:
# 判据出处: design/gdd/systems/排雷循环/地形变异.md:153 候选池门控与静默零布置(变异框架组)
# 判据出处: design/gdd/systems/排雷循环/地形变异.md「验收标准」候选池空合法 候选池空合法(变异框架组)
print("--- 地形变异 框架面(首批四类型 + 候选池门控 + 跨字段互锁)---")
Kit.check("变异清单 6 行(荆棘丛/藤蔓缠绕/岩浆/烬覆 + 落石/矿尘——首批类型定稿批 + 第三关内容批;贫矿脉 2026-10-16 用户令屏蔽删行)",
_db.combat.variation.rows.size() == 6)
@@ -461,7 +461,7 @@ func _smoke_variation_framework() -> void:
# ---- 难度曲线与Boss DifficultyTable 结构位冒烟(AC-10:空表零行为 + 套乘点 = 行值快照前)----
func _smoke_difficulty_table() -> void:
# 判据出处: design/gdd/systems/冒险循环/难度曲线与Boss.md:316 难度修饰套乘(难度表组)
# 判据出处: design/gdd/systems/冒险循环/难度曲线与Boss.md「验收标准」坐标行齐备 坐标行齐备(难度表组)
print("--- 难度曲线与Boss·DifficultyTable 结构位 ---")
Kit.check("DifficultyTable MVP 空表加载(结构位)", _db.run.difficulty != null and _db.run.difficulty.rows.is_empty())
# ① 空表零行为:敌人系统.spawn 敌值 = EnemyTable 行值原样
@@ -492,7 +492,7 @@ func _smoke_difficulty_table() -> void:
# ---- ⑤ 格面资源九型 + gp_drop 流(黄金向量)----
func _smoke_nine_types_gp_stream() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:199 校验类别全覆盖:九型 GP 流校验(九型流组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(九型流组)
print("--- 格面资源九型 + gp_drop 流(奖励字典 18 格 + 黄金向量)---")
Kit.check("格面资源十型封闭(第九型 gp 九型批 2026-09-20 / 第十型 treasure_item 秘宝内容批 2026-09-29——词表 v1.2)",
RewardTable.CELL_TYPES.size() == 10 and RewardTable.CELL_TYPES.has("gp") and RewardTable.CELL_TYPES.has("treasure_item"))
@@ -542,7 +542,7 @@ func _smoke_nine_types_gp_stream() -> void:
# ---- 元进度·MetaTable 表结构(行值全 provisional 归元进度设计文档配读数;
# conversion 覆盖恰三,Boss 两档 first ≥ repeat)----
func _smoke_meta() -> void:
# 判据出处: design/gdd/systems/跨局循环/元进度.md:148 元进度行族校验(meta 行族组)
# 判据出处: design/gdd/systems/跨局循环/元进度.md「验收标准」钥石不丢 钥石不丢(meta 行族组)
print("--- 元进度·MetaTable 表结构 ---")
var meta_tbl = _db.crossrun.meta
Kit.check("MetaTable 非空 + validate 零错(三行族词表封闭/唯一/连续/域界/first≥repeat/ratio 全过)",
@@ -582,7 +582,7 @@ func _conversion_row_of(rows: Array, attr: String) -> Dictionary:
# ---- V7 节点图三新键域校验(架构整改——缺新键行拒/width_max 越域拒/两 pct 越域拒/表值全过)----
func _test_level_gen_new_fields() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var tbl = _db.run.level_gen_params
var mk := func(mod: Dictionary) -> Dictionary:
var row := {"level_index": 1, "layers": 6, "branch_density": 0.3, "battle_ratio": 0.5, "reward_ratio": 0.2,
@@ -619,7 +619,7 @@ func _test_level_gen_new_fields() -> void:
# ---- 变异表头域校验 / feat cap 必填(架构整改——丁案三件的数据面守卫)----
func _test_variation_header_domains() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var inst = load("res://data/schemas/variation_table.gd").new()
inst.percent_of_cells = 5
inst.per_level_bonus = 0
@@ -637,7 +637,7 @@ func _test_variation_header_domains() -> void:
func _test_feat_cap_required() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var inst = load("res://data/schemas/feat_table.gd").new()
# 生产表全行 cap 在场(加载期已验——此处显式复核 37 行)
var all_cap := true
@@ -669,8 +669,8 @@ func _test_feat_cap_required() -> void:
# ---- G2 结算数值钉(迭代 55「QA覆盖余量收口批」T2——equivalence_ref_damage/p_perfect 钉+p_perfect 读数活性)----
func _check_settlement_pin_values() -> void:
# 判据出处: design/engineering/test-conventions.md:119 (表值钉值——漂移即红)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:124 (完美第二份兑付读表——接线后该句由声称变属实)
# 判据出处: design/engineering/test-conventions.md「8.3 改动—验收对照表」需求卡片列需求侧对照表 需求卡片列需求侧对照表(表值钉值——漂移即红)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「收益对照表:所有收益共用同一把尺子」开安全格给正向 开安全格给正向(完美第二份兑付读表——接线后该句由声称变属实)
var core = _db.combat.settlement.core
var roll = _db.combat.settlement.damage_roll
Kit.check("equivalence_ref_damage 钉 4(离线审计镜像 tools/clear_dominance_audit.py D_REF 同源——表值漂移即审计口径静默失效)〔QA余 V2〕",
@@ -703,7 +703,7 @@ func _check_settlement_pin_values() -> void:
# ---- G10 换算率钉(迭代 55「QA覆盖余量收口批」T2——per_level_shift_pct 三关档 6/9/1)----
func _check_meta_per_level_pins() -> void:
# 判据出处: design/engineering/test-conventions.md:119 (表值钉值——漂移即红;离线 verifier 消费端同源)
# 判据出处: design/engineering/test-conventions.md「8.3 改动—验收对照表」需求卡片列需求侧对照表 需求卡片列需求侧对照表(表值钉值——漂移即红;离线 verifier 消费端同源)
var pins := {"max_hp": 6, "atk": 9, "armor_class": 1}
for attr in pins.keys():
var row: Dictionary = {}
@@ -717,7 +717,7 @@ func _check_meta_per_level_pins() -> void:
# ---- G3 cap 段七槽钉值(迭代 55「QA覆盖余量收口批」T3——与 gp/attack 同款占位形态)----
func _check_curio_cap_segment_pins() -> void:
# 判据出处: design/engineering/test-conventions.md:119 (表值钉值——漂移即红)
# 判据出处: design/engineering/test-conventions.md「8.3 改动—验收对照表」需求卡片列需求侧对照表 需求卡片列需求侧对照表(表值钉值——漂移即红)
for kind in ["ap", "armor", "heal", "max_hp", "rap", "refresh", "time_sand"]:
Kit.check("curio_cap 七槽钉值:%s==99(案②提前退役占位——99=实质无上限,实数归调参批)〔QA余 V3〕" % kind,
int(_db.run.adventure.curio_cap(String(kind))) == 99)
@@ -726,7 +726,7 @@ func _check_curio_cap_segment_pins() -> void:
# ---- G8 reward stacks 行钉(迭代 55「QA覆盖余量收口批」T8——生产行 stacks 值面,合成行键未读生产行的缺口补钉)----
func _check_reward_row_pins() -> void:
# 判据出处: design/engineering/test-conventions.md:119 (表值钉值——漂移即红)
# 判据出处: design/engineering/test-conventions.md「8.3 改动—验收对照表」需求卡片列需求侧对照表 需求卡片列需求侧对照表(表值钉值——漂移即红)
Kit.check("reward 行扫描面非空(18 行在册——防空表静默绿)", (_db.run.reward.rows as Array).size() > 0)
var stacks_drift: Array[String] = []
for row in _db.run.reward.rows:
@@ -15,7 +15,7 @@ const BAD_DIR := "user://treasure_fixture_target_violation"
func _inject_violation() -> bool:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:199 校验类别全覆盖:违规夹具逐类注入(真视窄域夹具组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者(真视窄域夹具组)
var path := BAD_DIR + "/treasure_items.tres"
var f := FileAccess.open(path, FileAccess.READ)
if f == null:
@@ -40,7 +40,7 @@ func _inject_violation() -> bool:
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md:200 致命真的会死:违规表被拒绝、进程非 0(违规拒绝组)
# 判据出处: design/gdd/systems/表现与支撑/数据配置.md「调参表」本文是表的管理者 本文是表的管理者、进程非 0(违规拒绝组)
if not Kit.copy_tables(SRC_DIR, BAD_DIR) or not _inject_violation():
push_error("[treasure_target_violation_test] 夹具目录准备失败")
quit(2)
+1 -1
View File
@@ -10,7 +10,7 @@ extends SceneTree
const Kit := preload("res://tests/unit/test_kit.gd") # T6 收口:check/汇总退出样板单点
func _init() -> void:
# 判据出处: design/engineering/test-conventions.md:37 (套件协议模板——执行载体与退出码范例组)
# 判据出处: design/engineering/test-conventions.md「2. 场景级探针标配」每新增一个可交互 每新增一个可交互(套件协议模板——执行载体与退出码范例组)
Kit.check("headless SceneTree 协议可用(quit(code) 通道)", _test_headless_protocol())
Kit.check("命名规范可执行:test_[scenario]_[expected]", _test_naming_convention_followed())
quit(Kit.finish("example_test"))
+2 -2
View File
@@ -19,7 +19,7 @@ var _bp_path := "user://smoke_node_map_save.json"
func _init() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
_db = load("res://core/config_db.gd").new()
# 表加载失败不中止(承 G2/G3/G4/G5 同款:表损坏的红落在具体断言上)
var load_ok: bool = _db.load_tables("res://data/tables", true)
@@ -34,7 +34,7 @@ func _init() -> void:
# ---- 关卡节点图生成·确定性承载断言面 ----
func _smoke_generated_map_determinism() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md:134 (起关/选路/断点重生成同图组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点图生成.md「图的规格:什么算一张合法的图」合法图是一张岔路发散式道路系统 合法图是一张岔路发散式道路系统(起关/选路/断点重生成同图组)
# ① 纯函数复现:图 = f(参数档, 种子)——同档同种子两次产图逐位同图,换种子必变图
var gen = NodeMapGenerator.new(_fresh_rng(910001))
var params2: Dictionary = _db.run.level_gen_params.row_by_level_index(2)
@@ -20,7 +20,7 @@ const CURRENT_FORM := {
func _init() -> void:
# 判据出处: design/art/art-bible.md:539 (帧数规格条——样张冻结定值组)
# 判据出处: design/art/art-bible.md「8.2 像素基准与画布」缩放纪律 缩放纪律(帧数规格条——样张冻结定值组)
_test_spec_table()
_test_current_form()
quit(Kit.finish("animation_frame_spec_test"))
@@ -28,7 +28,7 @@ func _init() -> void:
# ① 规格表冻结面(帧数档定值单点=本表)
func _test_spec_table() -> void:
# 判据出处: design/art/art-bible.md:539 (帧数规格表冻结组)
# 判据出处: design/art/art-bible.md「8.2 像素基准与画布」缩放纪律 缩放纪律(帧数规格表冻结组)
Kit.check("待机循环 4 帧在表〔帧规格 V1〕", SPEC.get("idle", 0) == 4)
Kit.check("攻击准备 6 帧单次在表〔帧规格 V2〕", SPEC.get("attack", 0) == 6)
Kit.check("受击 2 帧在表〔帧规格 V3〕", SPEC.get("hit", 0) == 2)
@@ -36,7 +36,7 @@ func _test_spec_table() -> void:
# ② 现役单帧形制锚定(真实加载链——资产被换形制而未走规格表时此处红)
func _test_current_form() -> void:
# 判据出处: design/art/art-bible.md:539 (现役单帧形制组)
# 判据出处: design/art/art-bible.md「8.2 像素基准与画布」缩放纪律 缩放纪律(现役单帧形制组)
for fn: String in CURRENT_FORM:
var tex: Texture2D = load("res://assets/art/character/" + fn)
var want := Vector2(CURRENT_FORM[fn])
@@ -12,18 +12,18 @@ var _problems: Array = []
func check(cond: bool, msg: String) -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
if not cond:
_problems.append(msg)
func _init() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
_smoke_settle_zero_rows()
func _smoke_settle_zero_rows() -> void:
# 判据出处: design/gdd/08-Alpha版本标准.md:154 战斗演出链(弹道 / 受击 / 血条 / 灰化)在役;
# 判据出处: design/gdd/08-Alpha版本标准.md「五、表现」事实源 事实源(弹道 / 受击 / 血条 / 灰化)在役;
# 逐行结算排播行已随 v1.29 退役——结算期 B 区零逐行文字、FX 排播链保持
var main: Node = load("res://presentation/main.tscn").instantiate()
root.add_child(main)
@@ -96,7 +96,7 @@ func _count_row(row: Dictionary, arr: Array) -> void:
func _finish() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
for p in ["user://test_log_zero_text_save.json", "user://test_log_zero_text_save.json.tmp"]:
if FileAccess.file_exists(p):
DirAccess.remove_absolute(p)
@@ -18,7 +18,7 @@ class _BossRunner:
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:260 (战斗叙述宿主——装载组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「信号载荷契约:消息带着当场就能用的数据来」核心发给呈现的每份消息都必须 核心发给呈现的每份消息都必须(战斗叙述宿主——装载组)
_test_numeric_lines_carry_values()
_test_end_text_differs_by_result()
_test_phase_text_nonempty()
@@ -29,7 +29,7 @@ func _init() -> void:
func _test_numeric_lines_carry_values() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:272 (结算行数值带入组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(结算行数值带入组)
var rest: String = NarratorScript.rest_line(12, 30, 40)
Kit.check("休整叙述带入回复量与当前血量(实际「%s」)" % rest,
rest.contains("12") and rest.contains("30") and rest.contains("40"))
@@ -40,7 +40,7 @@ func _test_numeric_lines_carry_values() -> void:
func _test_end_text_differs_by_result() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:272 (胜负互异文案组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(胜负互异文案组)
# 关卡收束(level_end=true)恒为「关卡完成!」——单场胜负文案只在非收束态出现
var level: String = NarratorScript.battle_end_text("lose", true)
Kit.check("关卡收束态恒为「关卡完成!」(实际「%s」)" % level, level == "关卡完成!")
@@ -53,7 +53,7 @@ func _test_end_text_differs_by_result() -> void:
func _test_phase_text_nonempty() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:272 (阶段行非空组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(阶段行非空组)
var t: String = NarratorScript.phase_text(1, "", false, false, "")
Kit.check("相位叙述非空(实际「%s」)" % t, t != "")
var boss: String = NarratorScript.phase_text(2, "", false, true, "灰矮人石君王")
@@ -63,7 +63,7 @@ func _test_phase_text_nonempty() -> void:
# 叙述寻址按行类取 Boss 行集(S 清单 S15 换代):Boss 节点名必须来自 (关卡, boss, 带) 行集,
# 不能落到同深度的战斗行集——期望名由表行集首行读出,不写死字面量。
func _test_boss_name_uses_boss_rowset() -> void:
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md:295 (Boss 名读行集组)
# 判据出处: design/gdd/systems/战斗循环/敌人系统.md「调参表」Boss Boss(Boss 名读行集组)
var db = load("res://core/config_db.gd").new()
var loaded: bool = db.load_tables("res://data/tables", false)
Kit.check_quiet(loaded, "叙述寻址用例:数值表加载成功")
@@ -92,7 +92,7 @@ func _test_boss_name_uses_boss_rowset() -> void:
# 关卡完成停点文案族措辞钉子(口径换代批):回血行/满血合法态/渠道句/摘要关数行——
# 旧措辞退役后玩家可见面由本组断言钉在新措辞上(撤销证明:回退 battle_narrator 对应行→断言红→复原复绿)
func _test_level_clear_wording() -> void:
# 判据出处: design/ux/level-clear.md:11 (关卡结算屏文案组)
# 判据出处: design/ux/level-clear.md「Purpose & Player Need」关卡结算屏是关卡收束时刻的清算与 关卡结算屏是关卡收束时刻的清算与(关卡结算屏文案组)
var healed: String = NarratorScript.curio_pick_header({"level_index": 1, "heal_gained": 5, "hp_before": 10, "hp_after": 15})
Kit.check("关卡完成回血行带入回血量与生命区间(实际「%s」)〔口径换代 V1〕" % healed,
healed.contains("关卡完成回血 +5(生命 10 → 15)"))
@@ -112,7 +112,7 @@ func _test_level_clear_wording() -> void:
# 真实入口=呈现状态快照函数 presentation_snapshot:A 有削弱 B 无 → 两卡投影各现各的(零共享引用)
func _test_snapshot_effects_per_unit() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var db = load("res://core/config_db.gd").new()
Kit.check("V8 前置:表加载零 error", db.load_tables("res://data/tables", true) and db.diagnostics_count("error") == 0)
var rng = load("res://core/rng_service.gd").new()
@@ -10,19 +10,19 @@ const _EXPECTED_KEYS: Array[StringName] = [&"gate", &"forge", &"dummy", &"chest"
func _initialize() -> void:
# 判据出处: design/ux/camp.md:29 (营地场景布局数据件——纵深与地平线组)
# 判据出处: design/ux/camp.md「场景构成与七物件绑定」半开的门扇 半开的门扇(营地场景布局数据件——纵深与地平线组)
call_deferred("_run_all")
func _run_all() -> void:
# 判据出处: design/ux/camp.md:29 (套件统一收尾——双测试函数单进程单 quit)
# 判据出处: design/ux/camp.md「场景构成与七物件绑定」半开的门扇 半开的门扇(套件统一收尾——双测试函数单进程单 quit)
await _test_layout_hotspot_geometry()
await _test_hud_band_contrast_over_bg()
quit(Kit.finish("camp_scene_layout_test", "PASS — 布局几何+顶栏栏体对比 全过"))
func _test_layout_hotspot_geometry() -> void:
# 判据出处: design/ux/camp.md:16 (七物件命中区几何红线组)
# 判据出处: design/ux/camp.md「场景构成与七物件绑定」半开的门扇 半开的门扇(七物件命中区几何红线组)
var table: CampSceneLayoutTable = load("res://data/tables/camp_scene_layout.tres")
Kit.check("V14 布局表加载且 schema 类在位〔营地图批 V14〕", table is CampSceneLayoutTable and table != null)
if table == null:
@@ -126,7 +126,7 @@ func _test_layout_hotspot_geometry() -> void:
# 按规格句在测试内写死 #6E4526 与 α0.80,与背景贴图顶带实测均色做 α 合成后算 WCAG 对比 ≥3.0。
# 禁把视图件的 color 直接当预期值喂进算式(判据镜像——test-conventions §8.7 判红)。
func _test_hud_band_contrast_over_bg() -> void:
# 判据出处: design/ux/camp.md:41 (顶栏栏体定值——对落位带底色对比 ≥3:1 组)
# 判据出处: design/ux/camp.md「顶栏」钥石余额常驻画面顶部一行小 钥石余额常驻画面顶部一行小(顶栏栏体定值——对落位带底色对比 ≥3:1 组)
var table: CampSceneLayoutTable = load("res://data/tables/camp_scene_layout.tres")
var band_h := 48
if table != null:
@@ -10,7 +10,7 @@ const ConfirmDialogScript := preload("res://presentation/views/confirm_dialog.gd
func _initialize() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:90 (确认弹窗按钮位次定值——位次与语义同钉组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「提示与弹层:轻提示随起随消、重弹层排队进出」界面弹出的东西分两族 界面弹出的东西分两族(确认弹窗按钮位次定值——位次与语义同钉组)
call_deferred("_run")
@@ -27,7 +27,7 @@ func _find_btn_row(node: Node) -> HBoxContainer:
func _test_two_button_row_order() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:90 双钮形态位次=推进在左、维持在右(两钮同钉组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「提示与弹层:轻提示随起随消、重弹层排队进出」界面弹出的东西分两族 界面弹出的东西分两族、维持在右(两钮同钉组)
var ov: Control = ConfirmDialogScript.new()
root.add_child(ov)
ov.open("t", "推进", "维持")
@@ -40,7 +40,7 @@ func _test_two_button_row_order() -> void:
func _test_three_button_row_order() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:90 三钮形态位次=推进/次推/维持(三钮同钉组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「提示与弹层:轻提示随起随消、重弹层排队进出」界面弹出的东西分两族 界面弹出的东西分两族(三钮同钉组)
var ov: Control = ConfirmDialogScript.new()
root.add_child(ov)
ov.open_three("t", "推进", "次推", "维持")
@@ -10,7 +10,7 @@ const _TEST_SAVE := "user://test_forge_workbench.json"
func _initialize() -> void:
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md:219 (工作间两区六路线——装载组)
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「验收标准」本节判据全部绑结构与关系 本节判据全部绑结构与关系(工作间两区六路线——装载组)
call_deferred("_run")
@@ -22,7 +22,7 @@ func _row_by_id(ov) -> Dictionary:
func _run() -> void:
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md:219 (六路线 UI 直验组)
# 判据出处: design/gdd/systems/跨局循环/锻造工坊.md「验收标准」本节判据全部绑结构与关系 本节判据全部绑结构与关系(六路线 UI 直验组)
var db = load("res://core/config_db.gd").new()
var load_ok: bool = db.load_tables("res://data/tables", true)
if not load_ok:
@@ -9,7 +9,7 @@ const HudScript := preload("res://presentation/hud_presenter.gd")
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:260 (HUD 投影宿主——装载组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「信号载荷契约:消息带着当场就能用的数据来」核心发给呈现的每份消息都必须 核心发给呈现的每份消息都必须(HUD 投影宿主——装载组)
_test_accepted_text()
_test_reject_text_by_reason()
_test_unknown_reason_fallback()
@@ -17,13 +17,13 @@ func _init() -> void:
func _test_accepted_text() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:212 (受理反馈呈现组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「设计目的」归因得了的界面 归因得了的界面(受理反馈呈现组)
var t: String = HudScript.outcome_text({"accepted": true})
Kit.check("受理态文案固定为「执行完成。」(实际「%s」)" % t, t == "执行完成。")
func _test_reject_text_by_reason() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:212 (拒绝三源可辨文案组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「设计目的」归因得了的界面 归因得了的界面(拒绝三源可辨文案组)
var cases := {
"not_adjacent": "不能执行:目标与小人不相邻",
"target_revealed": "不能执行:目标已开",
@@ -43,7 +43,7 @@ func _test_reject_text_by_reason() -> void:
func _test_unknown_reason_fallback() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:212 (未知兜底文案组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「设计目的」归因得了的界面 归因得了的界面(未知兜底文案组)
var t: String = HudScript.outcome_text({"accepted": false, "reject_reason": "brand_new_reason"})
Kit.check("未知拒绝原因兜底为「动作被拒。」而非空串(实际「%s」)" % t, t == "动作被拒。")
var sub: String = HudScript.outcome_text({
@@ -11,12 +11,12 @@ const ScreenScript := preload("res://presentation/views/level_map_screen.gd")
func _initialize() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (信息迷雾呈现宿主——装载组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(信息迷雾呈现宿主——装载组)
call_deferred("_run")
func _run() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (迷雾显隐宿主组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(迷雾显隐宿主组)
var db = load("res://core/config_db.gd").new()
var loaded: bool = db.load_tables("res://data/tables", false)
Kit.check_quiet(loaded, "迷雾呈现用例:数值表加载成功")
@@ -48,7 +48,7 @@ func _runner(db, nodes: Array, candidates: Array, n: int = 2):
# ---- ① 范围外只见结构:雾下节点类型图标与文字均不绘制〔fv2〕----
func _test_fog_hides_type() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (雾下类型隐藏组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(雾下类型隐藏组)
var node := {"id": 3, "type": "battle", "depth": 3, "next": []}
var shown: Dictionary = ScreenScript.node_display(node, 2, [2], false, false)
Kit.check("可见集内节点:图标/类型文字均绘制〔fv2〕",
@@ -62,7 +62,7 @@ func _test_fog_hides_type() -> void:
# ---- ② Boss/终点不入雾+多终点标记〔fv3〕----
func _test_boss_exempt_and_multi_boss() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (Boss 描边豁免与多 Boss 组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」Boss Boss(Boss 描边豁免与多 Boss 组)
var type_vis: Array = [1, 7, 9] # 双 Boss 图:7/9 均在可见集
var boss_a: Dictionary = ScreenScript.node_display({"id": 7, "type": "boss", "depth": 7, "next": []}, 7, type_vis, false, false)
var boss_b: Dictionary = ScreenScript.node_display({"id": 9, "type": "boss", "depth": 9, "next": []}, 9, type_vis, false, false)
@@ -80,7 +80,7 @@ func _test_boss_exempt_and_multi_boss() -> void:
# ---- ③ 节点内详情图上从不显示〔fv5〕----
func _test_details_never_shown() -> void:
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md:178 (详情零显示组)
# 判据出处: design/gdd/systems/冒险循环/关卡节点地图.md「验收标准」行集通过加载校验 行集通过加载校验(详情零显示组)
var plain := {"id": 3, "type": "battle", "depth": 3, "next": [4]}
var loaded := {"id": 3, "type": "battle", "depth": 3, "next": [4], "enemy_id": "goblin_secret", "reward_id": "reward_secret"}
var a: Dictionary = ScreenScript.node_display(plain, 3, [3], false, true)
@@ -97,7 +97,7 @@ func _test_details_never_shown() -> void:
# ---- ④ label_text 三态文案〔fv2〕----
func _test_label_three_states() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var node := {"id": 3, "type": "battle", "depth": 3, "next": [4]}
Kit.check("当前位文案=「当前位置」〔fv2〕",
String(ScreenScript.node_display(node, 3, [3], true, false)["label_text"]) == "当前位置")
@@ -150,7 +150,7 @@ func _big_graph_nodes() -> Array:
func _test_big_graph_fit(db) -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var nodes := _big_graph_nodes()
var entry: Dictionary = nodes[0]
var runner = _runner(db, nodes, [nodes[1]])
@@ -204,7 +204,7 @@ func _test_big_graph_fit(db) -> void:
# 命中读数 = is_same 同实例判别(重算必产新字典、命中返回缓存原实例)——零生产计数器。
func _test_layout_cache(db) -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var nodes := _big_graph_nodes()
var runner = _runner(db, nodes, [nodes[1]])
var screen = ScreenScript.new()
@@ -11,7 +11,7 @@ const ModalStackScript := preload("res://presentation/modal_stack.gd")
func _init() -> void:
# 判据出处: design/engineering/code-conventions.md:54 (模态编排纯逻辑——层级与输入锁组)
# 判据出处: design/engineering/code-conventions.md「2.3 模态覆盖层层级规则」打开任何模态覆盖层时 打开任何模态覆盖层时(模态编排纯逻辑——层级与输入锁组)
# 哑层与桩 Callable(纯逻辑类零场景前提的证明面)
var start := Control.new()
var inter := Control.new()
@@ -44,13 +44,13 @@ class FakeFx extends SettlementFxView:
func check(cond: bool, msg: String) -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
if not cond:
_problems.append(msg)
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:272 (排播节奏——排空零分叉/零丢行/延迟双态组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(排播节奏——排空零分叉/零丢行/延迟双态组)
var main: Node = load("res://presentation/main.tscn").instantiate()
root.add_child(main)
await process_frame
@@ -157,8 +157,8 @@ func _count_row(row: Dictionary, arr: Array) -> void:
# FX 排播链断言(逐行文字列表退役后的行落地面——〔退役改 V-退役卡 R2〕):
# 判据出处: design/ux/battle.md:439 动效:结算逐行兑现为信息载体不可整体跳过,可加倍(减动效只调时长)
# 判据出处: design/gdd/08-Alpha版本标准.md:154 战斗演出链(弹道 / 受击 / 血条 / 灰化)在役
# 判据出处: design/ux/battle.md「Transitions & Animations」进入战斗屏 进入战斗屏,可加倍(减动效只调时长)
# 判据出处: design/gdd/08-Alpha版本标准.md「五、表现」事实源 事实源(弹道 / 受击 / 血条 / 灰化)在役
# 真实行集(夹具采样的 step_row 载荷)驱动独立 RowPacer,断言:
# ① 每行恰好一拍站桩反馈(on_step_row_fx 计数=行数);② 弹道/标出调用计数与行型分布逐位对上
# (期望从行集独立推导、实际从记参假件读——不镜像实现);③ 断言前提=行集非空(非空自检)。
@@ -188,7 +188,7 @@ class FakeBoardZone extends BoardZoneView:
func _assert_fx_chain(main: Node, rows_seen: Array) -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:272 (结算逐行实时滚出——行→FX 排播链计数逐位一致)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(结算逐行实时滚出——行→FX 排播链计数逐位一致)
var rp = RowPacerScript.new()
var fstage := FakeStage.new(null, root.get_node("/root/ConfigDB").presentation.battle_layout)
var ffx := FakeFx.new()
@@ -262,7 +262,7 @@ func _assert_fx_chain(main: Node, rows_seen: Array) -> void:
func _finish() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
for p in ["user://test_pacing_queue_save.json", "user://test_pacing_queue_save.json.tmp"]:
if FileAccess.file_exists(p):
DirAccess.remove_absolute(p)
@@ -57,7 +57,7 @@ const EXEMPT_LEDGER := {
func _init() -> void:
# 判据出处: design/art/art-bible.md:220 (色板增量纪律条——存量两两互查组)
# 判据出处: design/art/art-bible.md「4.1 主色板」色板增量纪律条 色板增量纪律条(色板增量纪律条——存量两两互查组)
_test_pairwise()
quit(Kit.finish("palette_token_pairwise_test"))
@@ -78,7 +78,7 @@ func _hex(c: Color) -> String:
# 存量两两互查:豁免账外零近色对(扫描面>0 前置防静默绿)
func _test_pairwise() -> void:
# 判据出处: design/art/art-bible.md:220 (色板增量纪律条——存量两两互查组)
# 判据出处: design/art/art-bible.md「4.1 主色板」色板增量纪律条 色板增量纪律条(色板增量纪律条——存量两两互查组)
var tokens := _token_colors()
Kit.check("token 面非空(扫描面>0)〔token互查 V1〕", tokens.size() >= 40)
var names: Array = tokens.keys()
@@ -23,7 +23,7 @@ var _db
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:281 (玩家面文案清扫宿主——装载组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(玩家面文案清扫宿主——装载组)
_db = ConfigDBScript.new()
var load_ok: bool = _db.load_tables("res://data/tables", true)
if not load_ok:
@@ -43,7 +43,7 @@ func _init() -> void:
# ① C 区两段头(u1/u2——直建 hero 面板,adventure_feats_test ⑦c 族同构)
func _sweep_hero_panel() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:274 (英雄面板文案组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(英雄面板文案组)
var panel = load("res://presentation/views/hero_info_panel_view.gd").new(_db.presentation.battle_layout)
var feat_head := _first_label(panel._feat_section)
var curio_head := _first_label(panel._curio_section)
@@ -55,7 +55,7 @@ func _sweep_hero_panel() -> void:
# ②③ 奖励节点头部+专长卡兜底(u3/u11——静态直调)
func _sweep_narrator() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:272 (叙述文案组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(叙述文案组)
var narrator = load("res://presentation/battle_narrator.gd")
var head := String(narrator.node_curio_header())
Kit.check("奖励点头部含「冒险牌库」(u3 机制事实①同库)〔wa4〕", head.contains("冒险牌库"))
@@ -68,7 +68,7 @@ func _sweep_narrator() -> void:
# ④ 图例封印行(u4——直建 LegendOverlay 读 ENTRIES 常量)
func _sweep_legend() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:267 (图例文案组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「核心规则」本章七节 本章七节(图例文案组)
load("res://presentation/views/legend_overlay.gd").new() # 直建(_init(rap_cost) 现签名)
var seal_row: Array = []
for e in load("res://presentation/views/legend_overlay.gd").ENTRIES:
@@ -87,7 +87,7 @@ func _sweep_legend() -> void:
# ⑤⑥ 来源名双源(u5/u6——状态槽消费半+表值 ConfigDB 真装载+battle_log 行消费半)
func _sweep_source_names() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:274 (来源名读表组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(来源名读表组)
var row_view = load("res://presentation/views/status_slot_row.gd").new()
row_view.set_effects([{"effect_id": "alert", "source_class": "mine_hit",
"display_name": "危险格受击", "remaining_settlements": 2, "round_index": 1}])
@@ -119,7 +119,7 @@ func _sweep_source_names() -> void:
# ⑦⑧ 已开危险格字形族(u7/u8/u9——BoardView rebuild 真实刷新路径+源 token 扫描)
func _sweep_board_glyph() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:264 (危险格字形组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「验收标准」以下判据逐条可测 以下判据逐条可测(危险格字形组)
var board_generator = load("res://core/board_generator.gd").new()
var b = board_generator.generate(1, 0, _mk_stream("board_gen", 4242), _db)
var ae = load("res://core/action_economy.gd").new(_db)
@@ -158,7 +158,7 @@ func _sweep_board_glyph() -> void:
# ⑧⑩ 源 token 扫描(注释剥离=行首 # 判——契约 2 保留面不入域)
func _sweep_token_scans() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var board_src := FileAccess.get_file_as_string("res://presentation/views/board_view.gd")
Kit.check("board_view.gd 源零 \"雷\" 字面量(u7/u8/u9 哨兵族统一钉住)〔wa8〕",
board_src.count("\"雷\"") == 0)
@@ -176,7 +176,7 @@ func _sweep_token_scans() -> void:
# 刷新两 toast 文案零数字字面量(架构整改 R4——格式串零数字、插值位与表字段一一对应;
# 静态判据+评审注记观测面局限:真机文案随表值由实机目检兜——T10 清单两项)
func _sweep_refresh_toast_no_literals() -> void:
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md:260 (刷新提示读表拼接——零字面量组)
# 判据出处: design/gdd/systems/表现与支撑/HUD框架.md「信号载荷契约:消息带着当场就能用的数据来」核心发给呈现的每份消息都必须 核心发给呈现的每份消息都必须(刷新提示读表拼接——零字面量组)
var main_src := FileAccess.get_file_as_string("res://presentation/main.gd")
var rap_toast := ""
var cap_toast := ""
@@ -17,13 +17,13 @@ var _problems: Array = []
func check(cond: bool, msg: String) -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
if not cond:
_problems.append(msg)
func _init() -> void:
# 判据出处: design/gdd/08-Alpha版本标准.md:154 演出链在役(逐行结算排播已随 v1.29 退役)——
# 判据出处: design/gdd/08-Alpha版本标准.md「五、表现」事实源 事实源(逐行结算排播已随 v1.29 退役)——
# 日志零文案只存字段(text/display_name 不落盘),其余全字段与 payload 逐键保留
var db = ConfigDBScript.new()
if not db.load_tables("res://data/tables", true):
@@ -35,7 +35,7 @@ func _init() -> void:
func _assert_no_text_and_full_payload(db) -> void:
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:87 显示名等玩家可见文案是数据面字段(日志消费端零文案)
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md「明细流水:每一行都能指回你刚才的哪一步棋」结算过程中每一件事都写一行明细 结算过程中每一件事都写一行明细(日志消费端零文案)
var logger = load("res://presentation/playtest_logger.gd").new()
logger.ap_per_round = int(db.run.action_economy.ap_per_round) # 注入序前置(守卫拒后开——R5 必填)
var log_path: String = logger.start_session(4242)
@@ -97,7 +97,7 @@ func _assert_no_text_and_full_payload(db) -> void:
func _finish() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
if _problems.is_empty():
print("[playtest_logger_step_fields_test] PASS — 日志 step 行零文案与全字段落盘 全绿")
quit(0)
@@ -33,7 +33,7 @@ const A1_FILES := {
func _init() -> void:
# 判据出处: design/engineering/code-conventions.md:41 (presentation 封装——四族零命中扫描组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(presentation 封装——四族零命中扫描组)
_sweep_a1_data_classes()
_sweep_a2_subparts()
_sweep_b_combo_root()
@@ -43,7 +43,7 @@ func _init() -> void:
# 源文件读取+非空前置(返 "" 即已判红——调用侧跳过后续正则断言)
func _src(path: String) -> String:
# 判据出处: design/engineering/code-conventions.md:41 (源码采样组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(源码采样组)
var src := FileAccess.get_file_as_string(path)
Kit.check("扫描面非空前置:%s" % path, src.length() > 0)
return src
@@ -51,21 +51,21 @@ func _src(path: String) -> String:
# 正则零命中断言(-pattern 意图写入断言文案——可 grep 定位;suffix 区分族组)
func _zero(pattern: String, src: String, label: String, suffix: String = "pres封装 V1") -> void:
# 判据出处: design/engineering/code-conventions.md:41 (零命中扫描组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(零命中扫描组)
var re := RegEx.create_from_string(pattern)
Kit.check("%s:%s 零命中〔%s〕" % [label, pattern, suffix], re.search(src) == null)
# 正锚在案断言(正则命中 ≥1——新公开面/新形态在用;suffix 区分族组)
func _anchor(pattern: String, src: String, label: String, suffix: String = "pres封装 V1") -> void:
# 判据出处: design/engineering/code-conventions.md:41 (正锚存在组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(正锚存在组)
var re := RegEx.create_from_string(pattern)
Kit.check("%s:%s 正锚在案〔%s〕" % [label, pattern, suffix], re.search(src) != null)
# ② V2 A2 拆件子件(行为归位子件公开方法、读走公开读法、身份构造交付)
func _sweep_a2_subparts() -> void:
# 判据出处: design/engineering/code-conventions.md:41 (A2 子件封装扫描组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(A2 子件封装扫描组)
var body := _src("res://presentation/views/standee_body.gd")
if body.length() > 0:
_zero("\\bst\\._|\\bmo\\._", body, "子件私取模式零命中(standee_body)", "pres封装 V2")
@@ -82,7 +82,7 @@ func _sweep_a2_subparts() -> void:
# ③ V3 B 组合根交接面(main+五分文件——成对单行转发梯换代为公开入口+Callable 束)
func _sweep_b_combo_root() -> void:
# 判据出处: design/engineering/code-conventions.md:41 (组合根束封装扫描组)
# 判据出处: design/engineering/code-conventions.md「1.6 拆分交接与封装边界」本节管拆分类改动的交接面与封装面 本节管拆分类改动的交接面与封装面(组合根束封装扫描组)
var b_files := {
"res://presentation/main.gd": false,
"res://presentation/main_ui_build.gd": true,
@@ -117,7 +117,7 @@ func _sweep_b_combo_root() -> void:
# ④ V4 C 杂项(UiKit 私有工厂公开化+cell_mark 构造交付)
func _sweep_c_misc() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
var offenders: PackedStringArray = []
var scanned := 0
_walk_gd_for("res://", "UiKit\\._[a-zA-Z]", "res://presentation/views/ui_kit.gd", offenders)
@@ -155,7 +155,7 @@ func _walk_gd_for(dir_path: String, pattern: String, exclude: String, offenders:
# ① V1 A1 三内部数据类(字段公开化——宿主直读写内类私有字段清零)
func _sweep_a1_data_classes() -> void:
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
# 判据出处: design/engineering/test-conventions.md「5. 测试函数怎么写——验收清单条目的落码规范」需求卡片 需求卡片(判定上报通道——验证函数组)
for path in A1_FILES:
var spec: Dictionary = A1_FILES[path]
var src := _src(path)
@@ -10,7 +10,7 @@ const ProbeUiUtil := preload("res://probe/probe_ui_util.gd") # 真输入合成
# 断言 + 失败即停(原直写 print FAIL + quit(1) + return 样板单点化——早退语义逐位保持)
func _req(desc: String, ok: bool) -> bool:
# 判据出处: design/ux/node-reward.md:9 (奖励覆盖层直验——需求包装组)
# 判据出处: design/ux/node-reward.md「定位」奖励节点 奖励节点(奖励覆盖层直验——需求包装组)
Kit.check(desc, ok)
if not ok:
quit(1)
@@ -18,11 +18,11 @@ func _req(desc: String, ok: bool) -> bool:
return true
func _initialize() -> void:
# 判据出处: design/ux/node-reward.md:9 (奖励节点装载组)
# 判据出处: design/ux/node-reward.md「定位」奖励节点 奖励节点(奖励节点装载组)
call_deferred("_run")
func _run() -> void:
# 判据出处: design/ux/node-reward.md:9 (奖励三选一呈现组)
# 判据出处: design/ux/node-reward.md「定位」奖励节点 奖励节点(奖励三选一呈现组)
var ov = load("res://presentation/views/curio_pick_overlay.gd").new()
root.add_child(ov)
var picked := []
@@ -10,7 +10,7 @@ const CELL_UNIT := preload("res://presentation/views/board_cell_unit.gd")
func _init() -> void:
# 判据出处: design/ux/battle.md:128 (封印印记参数宿主——装载组)
# 判据出处: design/ux/battle.md「Layout Zones」采用用户拍板的布局图 采用用户拍板的布局图(封印印记参数宿主——装载组)
_test_param_values()
_test_shader_uniforms()
_test_fog_gate()
@@ -20,7 +20,7 @@ func _init() -> void:
# R1–R3/R7 前置:五常量取值逐项相等(art-bible §8.2 定值)
func _test_param_values() -> void:
# 判据出处: design/ux/battle.md:128 (环径与法阵定值组)
# 判据出处: design/ux/battle.md「Layout Zones」采用用户拍板的布局图 采用用户拍板的布局图(环径与法阵定值组)
Kit.check("SEAL_RING_FRAC = 0.82〔seal批 V1〕", UiKit.SEAL_RING_FRAC == 0.82)
Kit.check("SEAL_WALL_FRAC = 0.11〔seal批 V2〕", UiKit.SEAL_WALL_FRAC == 0.11)
Kit.check("SEAL_ARM_FRAC = 0.156〔seal批 V2〕", UiKit.SEAL_ARM_FRAC == 0.156)
@@ -30,7 +30,7 @@ func _test_param_values() -> void:
# R1–R3/R7:着色器存在+七个 uniform 名在文(参数注入面契约)
func _test_shader_uniforms() -> void:
# 判据出处: design/ux/battle.md:128 (着色器参数化绘制组)
# 判据出处: design/ux/battle.md「Layout Zones」采用用户拍板的布局图 采用用户拍板的布局图(着色器参数化绘制组)
var src := FileAccess.get_file_as_string(SEAL_SHADER)
Kit.check("着色器文件存在且非空:%s〔seal批 V1〕" % SEAL_SHADER, src.length() > 0)
if src.length() == 0:
@@ -44,7 +44,7 @@ func _test_shader_uniforms() -> void:
# R4 迷雾门控:seal_on × fog_state → 封印子件可见性(内部字段直查=受控例外——子件可见性无公开可观测面,
# 卡面 R4 断言即 prescribe 子件 visible 直查;对照表该行注记理由)
func _test_fog_gate() -> void:
# 判据出处: design/ux/battle.md:128 (迷雾联动门控组)
# 判据出处: design/ux/battle.md「Layout Zones」采用用户拍板的布局图 采用用户拍板的布局图(迷雾联动门控组)
var u: Node2D = CELL_UNIT.new()
u.seal_on = true
Kit.check("seal_on 即挂封印子件〔seal批 V4〕", u._seal_layer != null)
@@ -60,7 +60,7 @@ func _test_fog_gate() -> void:
# R8 新组合态:seal_on 与已揭示同真时印记子件仍可见(封印受理即揭示改版——印记可见性不依赖
# 揭示态;内部字段直查=受控例外同 _test_fog_gate——子件可见性无公开可观测面,对照表随行申报)
func _test_seal_on_revealed_visible() -> void:
# 判据出处: design/ux/battle.md「封印格呈现预览」受理即揭示——印记承载面换代(已揭示格承载合法)
# 判据出处: design/ux/battle.md「封印格呈现预览」封印受理后格子进入 封印受理后格子进入(已揭示格承载合法)
var u: Node2D = CELL_UNIT.new()
u.seal_on = true
Kit.check("R8 前提:seal_on 挂封印子件〔封印改 V8〕", u._seal_layer != null)
@@ -12,7 +12,7 @@ const ISO_PATH := "user://settings_store_unit_test.cfg" # 隔离注路径(
func _init() -> void:
# 判据出处: design/gdd/systems/表现与支撑/设置与本地化.md:4 (设置存储宿主——装载组)
# 判据出处: design/gdd/systems/表现与支撑/设置与本地化.md「设置与本地化」设置项与多语言 设置项与多语言(设置存储宿主——装载组)
_test_settings_roundtrip()
_test_settings_default()
_test_settings_apply_chain()
@@ -27,7 +27,7 @@ func _cleanup() -> void:
# ---- 持久化回读(写 true→存→新实例回读 true;节/键 motion/reduced)----
func _test_settings_roundtrip() -> void:
# 判据出处: design/gdd/systems/表现与支撑/设置与本地化.md:4 (设置写读往返组)
# 判据出处: design/gdd/systems/表现与支撑/设置与本地化.md「设置与本地化」设置项与多语言 设置项与多语言(设置写读往返组)
var w = StoreScript.new(ISO_PATH)
w.reduced_motion = true
Kit.check("前置:save_settings 落盘成功", w.save_settings())
@@ -44,7 +44,7 @@ func _test_settings_roundtrip() -> void:
# ---- 缺省值(无文件缺省 false)----
func _test_settings_default() -> void:
# 判据出处: design/gdd/systems/表现与支撑/设置与本地化.md:4 (出厂默认组)
# 判据出处: design/gdd/systems/表现与支撑/设置与本地化.md「设置与本地化」设置项与多语言 设置项与多语言(出厂默认组)
var absent_path := "user://settings_store_unit_absent_%d.cfg" % (Time.get_ticks_msec())
DirAccess.remove_absolute(ProjectSettings.globalize_path(absent_path)) # 确保无文件
var d = StoreScript.new(absent_path)
@@ -55,7 +55,7 @@ func _test_settings_default() -> void:
# ---- 引擎档应用链(reduced→apply()→UiKit.motion_scale==0.5,false→1.0;测毕还原静态初值)----
func _test_settings_apply_chain() -> void:
# 判据出处: design/gdd/systems/表现与支撑/设置与本地化.md:4 (应用链组)
# 判据出处: design/gdd/systems/表现与支撑/设置与本地化.md「设置与本地化」设置项与多语言 设置项与多语言(应用链组)
var saved_scale: float = UiKit.motion_scale # 静态初值留底——测毕还原
var a = StoreScript.new(ISO_PATH)
a.reduced_motion = true
Loaded 100 of 174 files, more files were not shown because too many files have changed in this diff. Show more