diff --git a/game/tests/unit/core/breakpoint_resume_test.gd b/game/tests/unit/core/breakpoint_resume_test.gd index ec28fabe..14e0b478 100644 --- a/game/tests/unit/core/breakpoint_resume_test.gd +++ b/game/tests/unit/core/breakpoint_resume_test.gd @@ -110,13 +110,13 @@ func _init() -> void: Kit.check_quiet(adr_f.resume_adventure(bp_f, params_e), "P5 续玩受理(选择态分支)") Kit.check_quiet(adr_f.runner() == null, "P5 续玩不重跑关卡(三选一停点直回,_start_current_level 未走)") Kit.check_quiet(got_cands["cands"] == cands_e, "P5 续玩候选不重抽(逐位一致)") - Kit.check_quiet(int(adr_f._curio.taken["attack"]) == 1, "P5 次数计数恢复一致(牌库剔除态续接)") + Kit.check_quiet(int(adr_f.deck().taken["attack"]) == 1, "P5 次数计数恢复一致(牌库剔除态续接)") Kit.check_quiet(not adr_f.continue_to_next_level(), "P5 未兑付推进拒绝(续玩态零自动推进同契约)") var pick_e: Dictionary = cands_e[0] Kit.check_quiet(adr_f.stop().pick_curio(String(pick_e.get("kind", "")), String(pick_e.get("tier", "")), String(pick_e.get("feat_id", ""))), "P5 点选兑付受理") var picked_e: String = String(adr_f.stop()._resolved.get("picked", "")) - if adr_f._curio.taken.has(picked_e): - Kit.check_quiet(int(adr_f._curio.taken[picked_e]) == (2 if picked_e == "attack" else 1), + if adr_f.deck().taken.has(picked_e): + Kit.check_quiet(int(adr_f.deck().taken[picked_e]) == (2 if picked_e == "attack" else 1), "P5 兑付计数一致(%s——预置 1 + 本次兑付)" % picked_e) Kit.check_quiet(sm_f.has_breakpoint(), "P5 兑付后停点快照在档(已兑付待推进态可中断)") var bp_g: Dictionary = sm_f.breakpoint_snapshot() diff --git a/game/tests/unit/core/hero_ledger_test.gd b/game/tests/unit/core/hero_ledger_test.gd index de96b9d1..a32a8021 100644 --- a/game/tests/unit/core/hero_ledger_test.gd +++ b/game/tests/unit/core/hero_ledger_test.gd @@ -119,7 +119,8 @@ func _init() -> void: Kit.check_quiet(w3.gp == 37 and j3.keystone_gained() == 3 and j3.vision_used() == 1 and s3.hero_hp == 21 and (s3.feats_held() as Array).has("twin_pick"), "hr2 片段往返:三件账面键逐值(生命/特性/钱包/钥石/真视)") - Kit.check_quiet((j3._gain_log as Array).size() == 3 and (j3._bonus_detail as Array).size() == 3, + var jfrag: Dictionary = j3.breakpoint_fragment().get("gain_journal", {}) as Dictionary + Kit.check_quiet((jfrag.get("records", []) as Array).size() == 3 and (jfrag.get("details", []) as Array).size() == 3, "hr2 片段往返:日记全量还原") # hr2 旧档回退(无日记键→汇总直载跳过比对) @@ -127,7 +128,8 @@ func _init() -> void: legacy.erase("gain_journal") var j4 = GainJournalScript.new() j4.restore_fragment(legacy, {}) - Kit.check_quiet(j4.bonus_total("atk") == 7 and j4.bonus_total("armor_class") == 1 and (j4._gain_log as Array).is_empty(), + Kit.check_quiet(j4.bonus_total("atk") == 7 and j4.bonus_total("armor_class") == 1 + and ((j4.breakpoint_fragment().get("gain_journal", {}) as Dictionary).get("records", []) as Array).is_empty(), "hr2 旧档缺日记→汇总键直载(跳过比对——旧档行为零变化)") # hr2 日记在档推导比对不符→拒绝载入(fail-fast——汇总不回填) diff --git a/game/tests/unit/core/level_shop_economy_test.gd b/game/tests/unit/core/level_shop_economy_test.gd index 704bd083..f75a944d 100644 --- a/game/tests/unit/core/level_shop_economy_test.gd +++ b/game/tests/unit/core/level_shop_economy_test.gd @@ -1322,7 +1322,7 @@ func _smoke_shop_pool() -> void: Kit.check("购买受理(pool 口——%s|%s)" % [kind, tier], r8.buy_pool_item(kind)) Kit.check("钱包扣现价(%d → %d)" % [gp0, int(r8.gp)], int(r8.gp) == gp0 - int(buy_c.get("price", 0))) Kit.check("加算区 +令牌档位件值(池件=奖励件本体——%s|%s %+d)" % [kind, tier, int(_db.adventure.curio_value(kind, tier))], a8.journal().bonus_total(String(val_map[kind])) == val0 + int(_db.adventure.curio_value(kind, tier))) - Kit.check("共享池账本 -1(跨渠道单点——taken %d → %d)" % [taken0, int(a8._curio.taken.get(kind, 0))], int(a8._curio.taken.get(kind, 0)) == taken0 + 1) + Kit.check("共享池账本 -1(跨渠道单点——taken %d → %d)" % [taken0, int(a8.deck().taken.get(kind, 0))], int(a8.deck().taken.get(kind, 0)) == taken0 + 1) # A 链:同visit 第二购现价 = ceil(base×b^(l2−1)×A^1)(货架已全重抽——新卡新价同公式) # A 链:白盒抬 GP 保证第二购场景确定构造(直改测试基建——非生产行为) r8.gp = int(r8.gp) + 64 diff --git a/game/tests/unit/core/meta_progression_forge_test.gd b/game/tests/unit/core/meta_progression_forge_test.gd index 4e8683b7..d1dd3429 100644 --- a/game/tests/unit/core/meta_progression_forge_test.gd +++ b/game/tests/unit/core/meta_progression_forge_test.gd @@ -294,13 +294,13 @@ func _meta_settle_and_workshop() -> void: a12.refresh_bank()._refresh_y = 2 a12.stop()._pending = {"candidates": [{"kind": "gp", "tier": "common"}, {"kind": "attack", "tier": "common"}, {"kind": "max_hp", "tier": "common"}], "payload": {}} Kit.check("刷新双计数器——X 优先消耗(x1y2 → x0y2)", - a12.stop().refresh_curio() and a12.refresh_bank()._refresh_x == 0 and a12.refresh_bank()._refresh_y == 2) + a12.stop().refresh_curio() and a12.refresh_bank().refresh_y() == 2 and a12.refresh_bank().free_left() == 2 + a12.refresh_bank().refresh_stock()) Kit.check("刷新双计数器——X 耗尽转 Y 池、池竭拒绝(x0y2 → y0 → 第四次 false 零副作用)", - a12.stop().refresh_curio() and a12.stop().refresh_curio() and a12.refresh_bank()._refresh_y == 0 + a12.stop().refresh_curio() and a12.stop().refresh_curio() and a12.refresh_bank().refresh_y() == 0 and a12.stop().refresh_curio() == false) a12.refresh_bank().reset_x() Kit.check("刷新 X 每碰三选一重置(不结转;新目录无 bonus_refresh 行源——X 机制保留恒 0 空转,存量加仓走 _refresh_stock=刷新练习 V8)〔秘宝批换代〕", - a12.refresh_bank()._refresh_x == 0 and a12.refresh_bank().free_left() == 0) + a12.refresh_bank().free_left() == 0) # ⑬ 主菜单开局传参面(开新/续玩两入口同调三键随开局下传防回归:真实入口曾 # 三键恒空(缺陷①),冒烟夹具直呼 runner 参数面拦不住——此处直呼 main.build_adventure_params # 单测统一构造面(static 免实例化整菜单场景;真实两入口共用本构造),取值与营地投影同源) @@ -338,7 +338,8 @@ func _meta_settle_and_workshop() -> void: Kit.check("继续上局受理面:resume_adventure 受理三键参数面(尾裁微批b 受理闭环——受理不再吃白板)", adr_res.resume_adventure(bp_min, p_resume)) Kit.check("继续上局受理面:tree_rules 随参数面进 runner._tree_rules(消费面 set_tree_rules 下传现成)", - (adr_res._tree_rules as Array) == rules_e) + adr_res.runner() != null and adr_res.runner().pick_next_node(int(adr_res.runner().next_candidate_ids()[0])) + and ((adr_res.runner().current_battle().encounter.get("tree_rules", []) as Array) == rules_e)) _meta_smoke_cleanup() @@ -730,11 +731,13 @@ func _smoke_tree_rules() -> void: # 财富之道·散:商品标价折价(level_runner 计价单点) var lr = load("res://core/level_runner.gd").new(_db, _fresh_rng(777004), {"tree_rules": []}) # 构造注入(拆件批 T3——setter 群退役) - Kit.check("散未激活:商品标价原价(无 economy_spend 键)", int(lr._spend_discounted(100)) == 100) + Kit.check("散未激活:商品标价原价(无 economy_spend 键)", + int(lr.current_price({"base_price": 100, "price_increment": 0})) == 100 + int(_db.shop_price_level_bonus(0))) lr = load("res://core/level_runner.gd").new(_db, _fresh_rng(777005), {"tree_rules": ["economy_spend"]}) # 构造注入(拆件批 T3——setter 群退役) Kit.check("散激活:商品购买价 ×80%(provisional 折率——floor 偏向玩家、下限 1;刷新价不折=另一计价点零触碰)", - int(lr._spend_discounted(100)) == 80 and int(lr._spend_discounted(1)) == 1) + int(lr.current_price({"base_price": 100, "price_increment": 0})) == maxi(1, int(floor(float(100 + int(_db.shop_price_level_bonus(0))) * float(_db.shop.spend_discount)))) + and int(lr.current_price({"base_price": 1, "price_increment": 0})) == maxi(1, int(floor(float(1 + int(_db.shop_price_level_bonus(0))) * float(_db.shop.spend_discount))))) # 财富之道·聚:战斗掉落乘算·入账前(编排 _roll_gp_drop——同种子配对对拍 1.5×) var orch3 = load("res://core/battle_orchestrator.gd").new(_db, _fresh_rng(777005)) Kit.check("聚 rig:基线编排启动(无增益侧)", diff --git a/game/tests/unit/core/pool_case_d_test.gd b/game/tests/unit/core/pool_case_d_test.gd index c7768486..3319f765 100644 --- a/game/tests/unit/core/pool_case_d_test.gd +++ b/game/tests/unit/core/pool_case_d_test.gd @@ -36,7 +36,7 @@ func _init() -> void: var e = load("res://core/adventure_runner.gd").new(db, load("res://core/rng_service.gd").new()) e.start_adventure(501) e.stop()._pending = {"candidates": []} - Kit.check_quiet(e.stop().skip_empty_curio() and e.stop()._pending.is_empty(), + Kit.check_quiet(e.stop().skip_empty_curio() and (e.stop().breakpoint_fragment().get("bonus_pending", {}) as Dictionary).is_empty(), "空配置闸:三选一池空=停点整体跳过(skip_empty_curio 消化)〔专长批 T10〕") e.stop()._pending = {"candidates": [{"kind": "gp", "tier": "common"}]} Kit.check_quiet(not e.stop().skip_empty_curio(), @@ -170,12 +170,12 @@ func check_v8(c, db) -> void: c._curio.deck = [_tok("gp", "common"), _tok("attack", "common"), _tok("max_hp", "common")] for i in 20: c.deck().draw_candidates("reward_node") - Kit.check_quiet(bool(c._curio.cap_ok("gp", "")) and int(c._curio.taken.get("gp", 0)) == 0, + Kit.check_quiet(bool(c.deck().cap_ok("gp", "")) and int(c.deck().taken.get("gp", 0)) == 0, "cap 刷出不计:20 次抽签后 gp 未拿、cap 未触发〔专长批 V8〕") # 拿了才计:pick 一次→cap 满→提前退役(候选视图剔除、牌库本体不动) c.stop()._pending = {"candidates": [_tok("gp", "common"), _tok("attack", "common"), _tok("max_hp", "common")]} Kit.check_quiet(c.stop().pick_curio("gp", "common"), "V8 前置:兑付 gp 一枚") - Kit.check_quiet(not bool(c._curio.cap_ok("gp", "")), "cap 拿了才计:兑付后 cap 满(taken 1/1)〔专长批 V8〕") + Kit.check_quiet(not bool(c.deck().cap_ok("gp", "")), "cap 拿了才计:兑付后 cap 满(taken 1/1)〔专长批 V8〕") var gp_in_deck := 0 for t in c._curio.deck: if String((t as Dictionary).get("kind", "")) == "gp": diff --git a/game/tests/unit/core/save_boot_no_activate_test.gd b/game/tests/unit/core/save_boot_no_activate_test.gd index 7f6a60e1..2c0725f7 100644 --- a/game/tests/unit/core/save_boot_no_activate_test.gd +++ b/game/tests/unit/core/save_boot_no_activate_test.gd @@ -23,7 +23,7 @@ func _init() -> void: # ① 无参实例(autoload 实例化形态)=无激活态+默认合法空态(sv2 类级) func _test_no_arg_instance_has_no_activation() -> void: var sm := SaveManagerScript.new() - Kit.check_quiet(sm._path == "" and sm.active_slot() == 0 and not sm.has_write_target(), + Kit.check_quiet(sm.active_slot() == 0 and not sm.has_write_target(), "sv2 无参实例无激活态(路径空/激活号 0/写盘目标空)〔卡① sv2〕") Kit.check_quiet(sm.keystone_balance() == 0 and not sm.has_breakpoint() and sm.adventure_total() == 0 and sm.adventure_cleared() == 0, diff --git a/game/tests/unit/core/settle_segments_test.gd b/game/tests/unit/core/settle_segments_test.gd index 7e15cf4c..dd469fc8 100644 --- a/game/tests/unit/core/settle_segments_test.gd +++ b/game/tests/unit/core/settle_segments_test.gd @@ -29,8 +29,39 @@ func _init() -> void: Kit.check_quiet(oc._combat_seg != null and oc._combat_seg.oc == oc, "V4 编排器接线·战斗段〔迭代27 T2〕") Kit.check_quiet(oc._decay_seg != null and oc._decay_seg.oc == oc, "V4 编排器接线·衰减段〔迭代27 T2〕") Kit.check_quiet(oc._verdict_seg != null and oc._verdict_seg.oc == oc, "V4 编排器接线·判定段〔迭代27 T2〕") - Kit.check_quiet(oc._grant_seg._apply_counter_hit({"counter_id": "geo_types", "value": 1}) == null - and EffectEngine.counter(oc.fx_host().counters_ctx, "geo_types") == 1, "V4 counter_add 助手单点(原五位三行组收拢后行为等价——写口经 ctx 落 battle 桶)〔迭代27 T2〕") + # counter_add 写口真实路径(geologist 订阅行承载:公共命令链 begin_battle→move→dig→stop + # 经授予段 counter_add 单点落 counters_ctx battle 桶——受理载荷+公开读数口 fx_host().counters_ctx) + var rng_c = load("res://core/rng_service.gd").new() + rng_c.set_master_seed(4241) + var orch_c = load("res://core/battle_orchestrator.gd").new(db, rng_c) + var orch_ok: bool = orch_c.begin_battle({"level_index": 1, "node_depth": 0, "hero_hp": int(db.hero.max_hp), "feats": ["geologist"]}) + var tgt_c := Vector2i(-9, -9) + var dig_acc := false + if orch_ok: + var b_c = orch_c.minesweeper.current_board() + var front_c := Vector2i(-9, -9) + for y in b_c.height: + for x in b_c.width: + var cell_c := Vector2i(x, y) + if not orch_c.minesweeper.is_revealed(cell_c) or not b_c.is_safe(cell_c): + continue + for nb in b_c.neighbors8(cell_c): + if b_c.in_bounds(nb) and not orch_c.minesweeper.is_revealed(nb) and b_c.is_safe(nb) \ + and b_c.digit_of(nb) != 0 and not orch_c.minesweeper.has_seal(nb): + front_c = cell_c + tgt_c = nb + break + if tgt_c != Vector2i(-9, -9): + break + if tgt_c != Vector2i(-9, -9): + break + if tgt_c != Vector2i(-9, -9): + orch_c.minesweeper.settle_batch([{"action": "move", "cell": front_c}]) + var dg_c: Array = orch_c.minesweeper.settle_batch([{"action": "dig", "cell": tgt_c}]) + orch_c.minesweeper.settle_batch([{"action": "stop"}]) + dig_acc = not (dg_c as Array).is_empty() and bool((dg_c[0] as Dictionary).get("accepted", false)) + Kit.check_quiet(orch_ok and tgt_c != Vector2i(-9, -9) and dig_acc + and EffectEngine.counter(orch_c.fx_host().counters_ctx, "geo_types") == 1, "V4 counter_add 助手单点(原五位三行组收拢后行为等价——写口经 ctx 落 battle 桶)〔迭代27 T2〕") # V4-3 真实一轮结算走段序(begin_battle→停手→_maybe_settle→五段→裁定行) var rng = load("res://core/rng_service.gd").new() diff --git a/game/tests/unit/presentation/standee_fx_sweep_test.gd b/game/tests/unit/presentation/standee_fx_sweep_test.gd index f7496895..b886e92b 100644 --- a/game/tests/unit/presentation/standee_fx_sweep_test.gd +++ b/game/tests/unit/presentation/standee_fx_sweep_test.gd @@ -81,7 +81,7 @@ func _init() -> void: stage.on_step_row_fx({"type": "damage", "target": "地精", "target_id": "goblin_b"}) await create_timer(0.6).timeout # 弹道到达拍 0.33s + 余量 Kit.check("伤害行按 target_id 命中正确站桩(闪白落点)〔wd12〕", - s2._flash_count == 1 and s1._flash_count == 0) + s2.fx_probe().flash_count == 1 and s1.fx_probe().flash_count == 0) # 口二:enemy_standee_center —— id 先、display_name 兜底 var c_b = stage.enemy_standee_center("goblin_b", "地精") var c_b_expect: Vector2 = stage.world_to_shell(s2.position + s2.box * 0.5)