diff --git a/game/tests/unit/core/feat_vouchers_test.gd b/game/tests/unit/core/feat_vouchers_test.gd index 6b1c555d..a48c6090 100644 --- a/game/tests/unit/core/feat_vouchers_test.gd +++ b/game/tests/unit/core/feat_vouchers_test.gd @@ -187,6 +187,77 @@ func _init() -> void: "跨战清零:domain=battle 豁免账每战重建——次战首次标错再豁免一次〔卡② R2〕") Kit.check_quiet(EffectEngineKindProbe(db), "词表闭集:forgive_seal_miss 在 EFFECT_KINDS(出域即加载致命——扩签合规)〔卡② R4〕") + # ── N7 归因锚两态验收组(卡① T7:seal_miss 行 highlight 改用有效误标判据)── + # A10 未豁免态:无 perfect_insurance,首次标错 → seal_miss 行 highlight=="perfect_broken" 且完美不成立 + var rows10: Array[Dictionary] = [] + var rng10 = RngScript.new() + rng10.set_master_seed(779010) + var o10 = RigScript.new(db, rng10) + o10.step_row.connect(func(row): rows10.append(row)) + Kit.check_quiet(o10.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": 40, "hero_atk": 8, "hero_max_hp": 40, + "hero_armor_class": 10, "hero_ap_bonus": 0, "attunement": [], "attune_charges": {}, + "feats": [], "tree_rules": [], "battle_index": 1, + "bonus_ref": {"atk": 0, "max_hp": 0, "armor_class": 0}, "adventure_counters": {}, + "voucher_rap": 0, "voucher_time_sand": 0, "node_type": "battle"}), + "A10 rig:无保险战斗启动〔卡① N7〕") + var sc10: Variant = null + for c10 in o10.minesweeper.current_board().all_cells(): + if not o10.minesweeper.current_board().is_mine(c10): + sc10 = c10 + break + o10._grant_seg._judge_seal({"cell": sc10, "hit": false}, 1) + var sm10: Dictionary = {} + for r10 in rows10: + if String(r10.get("type", "")) == "seal_miss": + sm10 = r10 + Kit.check_quiet(String(sm10.get("highlight", "")) == "perfect_broken", + "A10 未豁免:首次标错 seal_miss 行 highlight==perfect_broken〔卡① N7〕") + Kit.check_quiet(not o10.perfect_sweep_earned(), + "A10 真值:无保险首标 → 有效误标 1 → 完美不成立(与 highlight 一致)〔卡① N7〕") + + # A11 豁免态:有 perfect_insurance,首次标错 → seal_miss 行 highlight=="" 且完美仍成立 + var rows11: Array[Dictionary] = [] + var rng11 = RngScript.new() + rng11.set_master_seed(779011) + var o11 = RigScript.new(db, rng11) + o11.step_row.connect(func(row): rows11.append(row)) + Kit.check_quiet(o11.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": 40, "hero_atk": 8, "hero_max_hp": 40, + "hero_armor_class": 10, "hero_ap_bonus": 0, "attunement": [], "attune_charges": {}, + "feats": ["perfect_insurance"], "tree_rules": [], "battle_index": 1, + "bonus_ref": {"atk": 0, "max_hp": 0, "armor_class": 0}, "adventure_counters": {}, + "voucher_rap": 0, "voucher_time_sand": 0, "node_type": "battle"}), + "A11 rig:带保险战斗启动〔卡① N7〕") + var sc11: Variant = null + for c11 in o11.minesweeper.current_board().all_cells(): + if not o11.minesweeper.current_board().is_mine(c11): + sc11 = c11 + break + o11._grant_seg._judge_seal({"cell": sc11, "hit": false}, 1) + var sm11: Dictionary = {} + for r11 in rows11: + if String(r11.get("type", "")) == "seal_miss": + sm11 = r11 + Kit.check_quiet(String(sm11.get("highlight", "")) == "", + "A11 豁免:首次标错获豁免 → seal_miss 行 highlight==空串〔卡① N7〕") + o11._perfect_hit_true = 1 + Kit.check_quiet(o11.perfect_sweep_earned(), + "A11 真值:误标 1 − 豁免 1 = 有效 0 且标中≥1 → 完美成立(与 highlight==空 一致)〔卡① N7〕") + + # A12 呈现两态文案与 _format_row 一致:两态均零「雷」字面 + var LogViewScript := load("res://presentation/views/battle_log_view.gd") + var lv = LogViewScript.new(db) + var broken_row := {"type": "seal_miss", "source_class": "seal_miss", "origin_cell": [0, 0], + "round_index": 1, "display_name": "封印未中", "value": 0, "highlight": "perfect_broken"} + var forgiven_row := {"type": "seal_miss", "source_class": "seal_miss", "origin_cell": [0, 0], + "round_index": 1, "display_name": "封印未中", "value": 0} + var s_broken := String(lv._format_row(broken_row)) + var s_forgiven := String(lv._format_row(forgiven_row)) + Kit.check_quiet(s_broken.find("完美封印已破") >= 0 and s_broken.find("雷") == -1, + "A12 已破态:_format_row 输出「完美封印已破」且零「雷」字面〔卡① N7〕") + Kit.check_quiet(s_forgiven.find("已豁免") >= 0 and s_forgiven.find("雷") == -1, + "A12 豁免态:_format_row 输出「已豁免」且零「雷」字面〔卡① N7〕") + lv.free() + sm.clear_breakpoint() quit(Kit.finish("feat_vouchers"))