iter51-卡2

This commit is contained in:
DKChan committed 2026-11-04 05:08:31 +08:00
1 parent 1cd6e2b1b0
commit 372b4fdc31
27 files changed
+1231 -356

No files matched your search

@@ -0,0 +1,501 @@
# tests/unit/battle_settlement/settlement_wiring_snapshot_test.gd — 结算接线同种子逐项 golden 对拍宿主(架构审查 5.1 封装修复批 R1 主证)
# 断言面 = 同种子定死驱动序下 step_row 全量行流 + settlement_snapshot 全量载荷 + battle_finished
# 载荷 + 收束 presentation_snapshot 关键键(round/battle_result/hero.hp/enemies.size()),
# 与 GOLDEN 常量逐位相等〔封装5.1 V1〕——段类束注入改造的零行为变更主证:
# 改前基线在未改树上固化(GOLDEN 为空时走转储通道取数),改后全程保持绿。
# 驱动序(卡面逐字定死):begin_battle(voucher_rap=20) → 轮1 choose_dig 移动/挖/封邻格/停 →
# player_request_refresh(换图刷新链入流)→ 轮2 一挖一停 → 轮3 径直停手。
# 协议照单元侧惯例:extends SceneTree+Kit.check 主通道;--script 模式无 autoload,
# ConfigDB 显式实例化构造注入+自建 RngService(掷点隔离形态)。
# 取数通道:GOLDEN 为空时打印捕获序列 JSON(两格缩进)后按专用码 3 退出——非判定码族(0 绿/1 红/2 空跑)。
# 运行:godot --headless --path game --script res://tests/unit/battle_settlement/settlement_wiring_snapshot_test.gd
extends SceneTree
const Kit := preload("res://tests/unit/test_kit.gd")
const ConfigDBScript := preload("res://core/config_db.gd")
const AutoPlayer := preload("res://sim/auto_player.gd")
const TEST_SEED := 4242 # golden 固化种子(卡面定死——改前改后同种子对拍前提)
const DUMP_EXIT := 3 # 空跑转储专用退出码(GOLDEN 未固化态取数用)
# 改前基线(JSON 两格缩进单文件固化——与捕获序列 JSON.stringify 逐字相等即绿;空串=未固化→转储模式)
const GOLDEN := r"""
{
"final": {
"battle_result": "",
"enemies_n": 2,
"hero_hp": 21,
"round": 4
},
"finished": [],
"rows": [
{
"display_name": "迟滞(下轮行动点 -1)",
"effect_id": "ap_delta",
"origin_cell": [
1,
0
],
"pool_value": -1,
"round_index": 1,
"source_class": "mine_hit",
"type": "effect",
"value": -1
},
{
"display_name": "行动点(下轮行动点 +1)",
"effect_id": "ap_delta",
"highlight": "seal_hit",
"origin_cell": [
1,
1
],
"pool_value": 0,
"round_index": 1,
"source_class": "seal_hit",
"type": "effect",
"value": 1
},
{
"ac": 1,
"display_name": "主角攻击",
"killed": false,
"normal": 2,
"origin_cell": [
-1,
-1
],
"roll": 12,
"round_index": 1,
"source_class": "hero_attack",
"target": "地精一伙",
"target_id": "goblin",
"tier": 100,
"type": "damage",
"value": 2
},
{
"ac": 10,
"attack_type": "normal",
"baseline": 1,
"crit": true,
"display_name": "地精一伙 普通攻击(暴击)",
"origin_cell": [
-1,
-1
],
"roll": 20,
"round_index": 1,
"skill_id": "attack",
"source_class": "enemy_action",
"target": "hero",
"tier": 100,
"type": "damage",
"value": 2
},
{
"ac": 10,
"attack_type": "normal",
"baseline": 1,
"display_name": "地精一伙 普通攻击(被压制)",
"origin_cell": [
-1,
-1
],
"roll": 2,
"round_index": 1,
"skill_id": "attack",
"source_class": "enemy_action",
"target": "hero",
"tier": 25,
"type": "damage",
"value": 1
},
{
"display_name": "状态衰减",
"origin_cell": [
-1,
-1
],
"round_index": 1,
"source_class": "",
"type": "decay",
"value": 0
},
{
"display_name": "下一轮次",
"origin_cell": [
-1,
-1
],
"round_index": 1,
"source_class": "",
"type": "verdict",
"value": 0
},
{
"display_name": "暴走",
"effect_id": "enrage",
"origin_cell": [
0,
0
],
"pool_value": 25,
"round_index": 2,
"source_class": "mine_hit",
"type": "effect",
"value": 25
},
{
"ac": 1,
"display_name": "主角攻击",
"killed": true,
"normal": 2,
"origin_cell": [
-1,
-1
],
"roll": 2,
"round_index": 2,
"source_class": "hero_attack",
"target": "地精一伙",
"target_id": "goblin",
"tier": 100,
"type": "damage",
"value": 2
},
{
"ac": 10,
"attack_type": "normal",
"baseline": 1,
"display_name": "地精一伙 普通攻击(被压制)",
"origin_cell": [
-1,
-1
],
"roll": 1,
"round_index": 2,
"skill_id": "attack",
"source_class": "enemy_action",
"target": "hero",
"tier": 25,
"type": "damage",
"value": 1
},
{
"display_name": "状态衰减",
"origin_cell": [
-1,
-1
],
"round_index": 2,
"source_class": "",
"type": "decay",
"value": 1
},
{
"display_name": "下一轮次",
"origin_cell": [
-1,
-1
],
"round_index": 2,
"source_class": "",
"type": "verdict",
"value": 0
},
{
"ac": 1,
"display_name": "主角攻击",
"killed": false,
"normal": 2,
"origin_cell": [
-1,
-1
],
"roll": 8,
"round_index": 3,
"source_class": "hero_attack",
"target": "地精一伙",
"target_id": "goblin",
"tier": 100,
"type": "damage",
"value": 2
},
{
"ac": 10,
"attack_type": "normal",
"baseline": 1,
"display_name": "地精一伙 普通攻击(被压制)",
"origin_cell": [
-1,
-1
],
"roll": 6,
"round_index": 3,
"skill_id": "attack",
"source_class": "enemy_action",
"target": "hero",
"tier": 50,
"type": "damage",
"value": 1
},
{
"display_name": "状态衰减",
"origin_cell": [
-1,
-1
],
"round_index": 3,
"source_class": "",
"type": "decay",
"value": 0
},
{
"display_name": "下一轮次",
"origin_cell": [
-1,
-1
],
"round_index": 3,
"source_class": "",
"type": "verdict",
"value": 0
}
],
"snaps": [
{
"board": {
"h": 10,
"revealed": 42,
"seals": 1,
"seq": 1,
"w": 10
},
"buffs": [],
"depth": 1,
"economy": {
"ap": 0,
"phase": "Waiting",
"rap": 26,
"refresh_used": 0
},
"enemies": [
{
"armor": "light",
"armor_class": 1,
"atk": 1,
"hp": 2,
"id": "goblin",
"max_hp": 4,
"pending_skill": ""
},
{
"armor": "light",
"armor_class": 1,
"atk": 1,
"hp": 4,
"id": "goblin",
"max_hp": 4,
"pending_skill": ""
}
],
"hero": {
"armor_class": 10,
"atk": 2,
"hp": 23,
"max_hp": 26
},
"kind": "settlement",
"level": 1,
"round": 1,
"round_facts": {
"mines": 1,
"path": "stopped",
"safe": 0,
"seal_events": 1
},
"spawn_count": 2,
"unit_count": 2,
"verdict": "continue"
},
{
"board": {
"h": 10,
"revealed": 43,
"seals": 0,
"seq": 2,
"w": 10
},
"buffs": [],
"depth": 1,
"economy": {
"ap": 0,
"phase": "Waiting",
"rap": 25,
"refresh_used": 1
},
"enemies": [
{
"armor": "light",
"armor_class": 1,
"atk": 1,
"hp": 4,
"id": "goblin",
"max_hp": 4,
"pending_skill": ""
}
],
"hero": {
"armor_class": 10,
"atk": 2,
"hp": 22,
"max_hp": 26
},
"kind": "settlement",
"level": 1,
"round": 2,
"round_facts": {
"mines": 1,
"path": "stopped",
"safe": 42,
"seal_events": 0
},
"spawn_count": 2,
"unit_count": 1,
"verdict": "continue"
},
{
"board": {
"h": 10,
"revealed": 43,
"seals": 0,
"seq": 2,
"w": 10
},
"buffs": [],
"depth": 1,
"economy": {
"ap": 0,
"phase": "Waiting",
"rap": 33,
"refresh_used": 0
},
"enemies": [
{
"armor": "light",
"armor_class": 1,
"atk": 1,
"hp": 2,
"id": "goblin",
"max_hp": 4,
"pending_skill": ""
}
],
"hero": {
"armor_class": 10,
"atk": 2,
"hp": 21,
"max_hp": 26
},
"kind": "settlement",
"level": 1,
"round": 3,
"round_facts": {
"mines": 0,
"path": "stopped",
"safe": 0,
"seal_events": 0
},
"spawn_count": 2,
"unit_count": 1,
"verdict": "continue"
}
]
}
"""
var _db
func _init() -> void:
_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)
var orch = load("res://core/battle_orchestrator.gd").new(_db, _make_rng())
var rows: Array = []
var snaps: Array = []
var finished: Array = []
orch.step_row.connect(func(row: Dictionary) -> void: rows.append(row))
orch.settlement_snapshot.connect(func(s: Dictionary) -> void: snaps.append(s))
orch.battle_finished.connect(func(p: Dictionary) -> void: finished.append(p))
var accepted: bool = orch.begin_battle({"level_index": 1, "node_depth": 1,
"hero_hp": int(_db.combat.hero.max_hp), "voucher_rap": 20})
Kit.check("前置:begin_battle 受理", accepted)
if accepted:
_drive(orch)
var final_snap: Dictionary = orch.presentation_snapshot()
var captured := {"rows": rows, "snaps": snaps, "finished": finished,
"final": {"round": int(final_snap.get("round", -1)),
"battle_result": String(final_snap.get("battle_result", "")),
"hero_hp": int((final_snap.get("hero", {}) as Dictionary).get("hp", -1)),
"enemies_n": (final_snap.get("enemies", []) as Array).size()}}
if GOLDEN == "":
print("[golden-dump] begin")
print(JSON.stringify(captured, " "))
print("[golden-dump] end")
quit(DUMP_EXIT)
return
# GOLDEN 三引号字面量首尾各带一个换行(多行字符串语法载体)——对拍两侧 strip 首尾空白后逐位比
var captured_json := JSON.stringify(captured, " ").strip_edges()
var golden_json := GOLDEN.strip_edges()
if captured_json != golden_json:
print("[captured-dump] begin")
print(JSON.stringify(captured, " "))
print("[captured-dump] end")
Kit.check("封装5.1 V1 同种子逐项对拍:行流/快照/终局载荷/presentation 逐位同 golden",
captured_json == golden_json)
quit(Kit.finish("settlement_wiring_snapshot_test"))
func _make_rng():
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(TEST_SEED)
return rng
# 驱动序(卡面定死):轮1 挖+封+停 → 刷新 → 轮2 一挖一停 → 轮3 停手
func _drive(orch) -> void:
var ms = orch.minesweeper
# 轮 1:choose_dig 非空则 move→dig→封首个未揭示主角邻格→stop
var pick: Dictionary = AutoPlayer.choose_dig(ms)
if not pick.is_empty() and pick.get("dig_cell", null) != null:
ms.settle_batch([{"action": "move", "cell": pick["hero_cell"]}])
ms.settle_batch([{"action": "dig", "cell": pick["dig_cell"]}])
var c := _first_unrevealed_adjacent(orch)
if c.x >= 0:
ms.settle_batch([{"action": "seal_place", "cell": c}])
ms.settle_batch([{"action": "stop"}])
# 轮 1 结算后刷新(voucher_rap=20 保证 RAP 抵折后价——覆盖换图刷新链)
orch.player_request_refresh()
# 轮 2:一挖一停
var pick2: Dictionary = AutoPlayer.choose_dig(ms)
if not pick2.is_empty() and pick2.get("dig_cell", null) != null:
ms.settle_batch([{"action": "move", "cell": pick2["hero_cell"]}])
ms.settle_batch([{"action": "dig", "cell": pick2["dig_cell"]}])
ms.settle_batch([{"action": "stop"}])
# 轮 3:径直停手
ms.settle_batch([{"action": "stop"}])
# 首个未揭示且与主角 8 邻接的格(卡面定死封印目标选取;无候选=返回 (-1,-1) 跳过封印)
func _first_unrevealed_adjacent(orch) -> Vector2i:
var ms = orch.minesweeper
var hero: Vector2i = ms.hero_pos()
var board = ms.current_board()
for y in board.height:
for x in board.width:
var c := Vector2i(x, y)
if not ms.is_revealed(c) and board.neighbors8(hero).has(c):
return c
return Vector2i(-1, -1)
@@ -0,0 +1 @@
uid://uys0a2kxc8a6
+3 -3
View File
@@ -668,7 +668,7 @@ func _smoke_feats() -> void:
apply_fx.call(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {}))
var pm_hits: Array = fx.dispatch(orch.fx_host().counters_ctx, "attack_commit", {"atk": 10, "target": "敌", "matchup": "", "dig_streak": 0, "nest_count": 0})
var pm_bonus := 0
for h in orch._hits_of(pm_hits, "attack_bonus"):
for h in DamageController.hits_of(pm_hits, "attack_bonus"):
pm_bonus = EffectEngine.counter(orch.fx_host().counters_ctx, String(h.get("value_counter", "")))
Kit.check("疼痛记忆:攻击附加层值伤害=层值 2·用后清零(set 行随施加面)〔专长批 V3〕", pm_bonus == 2)
fx.rebuild(["fuse_wire"], [], {})
@@ -688,7 +688,7 @@ func _smoke_feats() -> void:
apply_fx.call(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {}))
var ti_hits: Array = fx.dispatch(orch.fx_host().counters_ctx, "attack_commit", {"atk": 10, "target": "敌", "matchup": "", "dig_streak": 0, "nest_count": 0})
var ti_val := 0
for h in orch._hits_of(ti_hits, "attack_bonus"):
for h in DamageController.hits_of(ti_hits, "attack_bonus"):
ti_val = EffectEngine.counter(orch.fx_host().counters_ctx, String(h.get("value_counter", "")))
Kit.check("陷阱本能:踩雷本轮攻击 +2(attack_bonus 通道——面板加算)〔专长批 V3〕", ti_val == 2)
fx.rebuild(["chain_traps", "pain_memory"], [], {})
@@ -724,7 +724,7 @@ func _smoke_feats() -> void:
EffectEngine.counter_add(orch.fx_host().counters_ctx, "stop_swap", 4) # value_event="ap_left" 解析归施加面(action_economy 载荷取值)——冒烟手动落账
Kit.check("弃图兑换:停手剩余 AP≥3 入账〔专长批 V3〕", _hits_kind(me_hits, "counter_add").size() == 1)
var me_atk := 0
for h in orch._hits_of(fx.dispatch(orch.fx_host().counters_ctx, "attack_commit", {"atk": 10, "target": "敌", "matchup": "", "dig_streak": 0, "nest_count": 0}), "attack_bonus"):
for h in DamageController.hits_of(fx.dispatch(orch.fx_host().counters_ctx, "attack_commit", {"atk": 10, "target": "敌", "matchup": "", "dig_streak": 0, "nest_count": 0}), "attack_bonus"):
me_atk = EffectEngine.counter(orch.fx_host().counters_ctx, String(h.get("value_counter", "")))
Kit.check("弃图兑换:折为攻击伤害=剩余 AP 全额·用后清零〔专长批 V3〕", me_atk == 4)
Kit.check("弃图兑换反例:剩余 AP<3 不触发〔专长批 V3〕", _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "dig_stop", {"ap_left": 2}), "counter_add").is_empty())
@@ -0,0 +1,110 @@
# tests/unit/core/encapsulation_sweep_test.gd — 架构审查 5.1 封装修复·五处结构性零命中扫描宿主
# 断言面 = 七段断言组(全部带「扫描面非空前置+正锚」——非空防扫描面为空静默绿,正锚证新面在用):
# V2 settlement 七文件:非空+class_name 正锚+\boc\b 全文零命中(段类对编排器引用归零,含头注)
# V3 battle_orchestrator:非空+搬家五方法定义零命中(宿主原方法删除禁留壳)
# V4 adventure_runner:非空+_bp_store._ 零命中+bp_read 正锚(公开面在用)
# V5 save_manager:非空+slots._ 零命中+active_path 正锚;slot_store:非空+_save._ 零命中+公开面正锚
# V6 grant_segment:非空+两 fx 私键零命中+mark_new_resource_type 正锚
# V7 config_db:非空+._resolver 直写零命中+bind_resolver 正锚
# 手法沿 player_copy_sweep_test 源 token 扫描先例(不并件——扫描面归属与尾缀语义本批特有)。
# 运行:godot --headless --path game --script res://tests/unit/core/encapsulation_sweep_test.gd
extends SceneTree
const Kit := preload("res://tests/unit/test_kit.gd")
func _init() -> void:
_sweep_settlement_segments()
_sweep_orchestrator_methods()
_sweep_breakpoint_pair()
_sweep_save_pair()
_sweep_fx_host_accumulators()
_sweep_config_resolver()
quit(Kit.finish("encapsulation_sweep_test"))
# 源文件读取+非空前置(返 "" 即已判红——调用侧跳过后续正则断言)
func _src(path: String) -> String:
var src := FileAccess.get_file_as_string(path)
Kit.check("扫描面非空前置:%s" % path, src.length() > 0)
return src
# 正则零命中断言(-pattern 意图写入断言文案——可 grep 定位)
func _zero(pattern: String, src: String, label: String, path: String) -> void:
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:
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:
var classes := {
"res://core/settlement/grant_segment.gd": "GrantSegment",
"res://core/settlement/combat_segment.gd": "CombatSegment",
"res://core/settlement/round_cycle.gd": "RoundCycle",
"res://core/settlement/verdict_segment.gd": "VerdictSegment",
"res://core/settlement/battle_refresh_flow.gd": "BattleRefreshFlow",
"res://core/settlement/aura_segment.gd": "AuraSegment",
"res://core/settlement/decay_segment.gd": "DecaySegment",
}
for path in classes:
var src := _src(path)
if src.length() == 0:
continue
_anchor("class_name %s" % classes[path], src, "class_name 正锚(%s)" % classes[path], path)
_zero("\\boc\\b", src, "对编排器标识符全归零(%s)" % classes[path], path)
# ② V3 编排器搬家五方法零残留
func _sweep_orchestrator_methods() -> void:
var src := _src("res://core/battle_orchestrator.gd")
if src.length() == 0:
return
_zero("func _hero_atk\\(|func _feat_yield_adjust\\(|func _harmful_variants\\(|func _harmful_adjacent\\(|func _hits_of\\(",
src, "编排器搬家五方法定义零残留(宿主删除禁留壳)", "res://core/battle_orchestrator.gd")
# ③ V4 断点域(adventure_runner → BreakpointStore 公开面)
func _sweep_breakpoint_pair() -> void:
var src := _src("res://core/adventure_runner.gd")
if src.length() == 0:
return
_zero("_bp_store\\._", src, "宿主对断点件私取归零", "res://core/adventure_runner.gd")
_anchor("_bp_store\\.bp_read\\(", src, "断点公开读侧在用", "res://core/adventure_runner.gd")
# ④ V5 存档双向公开面(save_manager↔slot_store)
func _sweep_save_pair() -> void:
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")
_anchor("slots\\.active_path\\(\\)", src_m, "槽路径读投影在用", "res://core/save_manager.gd")
var src_s := _src("res://core/slot_store.gd")
if src_s.length() > 0:
_zero("_save\\._", src_s, "slot_store 反向私取归零", "res://core/slot_store.gd")
_anchor("_save\\.(set_read_only|read_only|reset_to_default|data_snapshot|restore_data|peek_summary_at|rename_overwrite)",
src_s, "存档公开承接面在用", "res://core/slot_store.gd")
# ⑤ V6 效果宿主累积面(grant → BattleFxHost 公开累积方法)
func _sweep_fx_host_accumulators() -> void:
var src := _src("res://core/settlement/grant_segment.gd")
if src.length() == 0:
return
_zero("_fx_new_resource_types|_fx_bonus_delta", src, "授予段对效果宿主私键直写归零", "res://core/settlement/grant_segment.gd")
_anchor("mark_new_resource_type\\(", src, "首见登记公开方法在用", "res://core/settlement/grant_segment.gd")
# ⑥ V7 配置挂载面(config_db → 三 schema bind_resolver)
func _sweep_config_resolver() -> void:
var src := _src("res://core/config_db.gd")
if src.length() == 0:
return
_zero("\\._resolver\\s*=", src, "解析协作件直写归零", "res://core/config_db.gd")
_anchor("bind_resolver\\(_resolver\\)", src, "挂载口在用", "res://core/config_db.gd")
@@ -0,0 +1 @@
uid://dq1huyomw37m2
+23 -13
View File
@@ -15,23 +15,33 @@ func _init() -> void:
quit(1)
return
# V4-1 段类直接 new()(构造收宿主引用——五类同构)
# V4-1 段类直接 new()(引用束注入——编排器 _init 同款 20 键束组装,逐段 new(bundle) 成功断言)
var oc = load("res://core/battle_orchestrator.gd").new(db, load("res://core/rng_service.gd").new())
Kit.check_quiet(load("res://core/settlement/grant_segment.gd").new(oc, oc.fx_host(), oc.reward_grant()) != null, "V4 GrantSegment 直接 new()〔迭代27 T2〕")
Kit.check_quiet(load("res://core/settlement/aura_segment.gd").new(oc) != null, "V4 AuraSegment 直接 new()〔迭代27 T2〕")
Kit.check_quiet(load("res://core/settlement/combat_segment.gd").new(oc, oc.fx_host(), oc.reward_grant()) != null, "V4 CombatSegment 直接 new()〔迭代27 T2〕")
Kit.check_quiet(load("res://core/settlement/decay_segment.gd").new(oc) != null, "V4 DecaySegment 直接 new()〔迭代27 T2〕")
Kit.check_quiet(load("res://core/settlement/verdict_segment.gd").new(oc) != null, "V4 VerdictSegment 直接 new()〔迭代27 T2〕")
var seg_bundle: Dictionary[Variant, Variant] = {
"facts": oc._facts, "units": oc._enemy_system, "damage": oc._damage,
"status_effects": oc._status_effects, "reward_economy": oc._reward_economy,
"reward_grant": oc.reward_grant(), "fx_host": oc.fx_host(), "minesweeper": oc.minesweeper,
"db": oc.db, "action_economy": oc.action_economy, "rng": oc.rng,
"emit_row_cb": oc._emit_row, "fatal_cb": oc._fatal, "install_cb": oc._install_and_reset,
"battle_over_cb": oc._battle_over, "exit_distribution_cb": oc._exit_distribution,
"emit_snapshot_cb": oc._emit_settlement_snapshot, "emit_composition_cb": oc._emit_composition_effects,
"attune_param_sum_cb": oc.attune_param_sum, "perfect_sweep_cb": oc.perfect_sweep_earned,
}
Kit.check_quiet(load("res://core/settlement/grant_segment.gd").new(seg_bundle) != null, "V4 GrantSegment 束构造〔迭代27 T2〕")
Kit.check_quiet(load("res://core/settlement/aura_segment.gd").new(seg_bundle) != null, "V4 AuraSegment 束构造〔迭代27 T2〕")
Kit.check_quiet(load("res://core/settlement/combat_segment.gd").new(seg_bundle) != null, "V4 CombatSegment 束构造〔迭代27 T2〕")
Kit.check_quiet(load("res://core/settlement/decay_segment.gd").new(seg_bundle) != null, "V4 DecaySegment 束构造〔迭代27 T2〕")
Kit.check_quiet(load("res://core/settlement/verdict_segment.gd").new(seg_bundle) != null, "V4 VerdictSegment 束构造〔迭代27 T2〕")
# V4-2 编排器 _init 接线(段持宿主引用;段序编排面在位)——注册面批同代归约 V1:
# V4-2 编排器 _init 接线(段持注入引用同一性——宿主回指对象随束注入退役;段序编排面在位):
# 段件宿主直持改经 _rounds(轮循环驱动件)承载,接线断言改指 _rounds 段族
Kit.check_quiet(oc._rounds != null and oc._rounds.oc == oc, "V1 编排器接线·轮循环驱动件在座且宿主回指〔编排归约 V1〕")
Kit.check_quiet(oc._rounds != null and oc._rounds.facts == oc._facts, "V1 编排器接线·轮循环驱动件在座且束注入同一性〔编排归约 V1〕")
Kit.check_quiet(oc._facts != null, "V1 编排器接线·战斗事实件在座〔编排归约 V1〕")
Kit.check_quiet(oc._rounds._grant_seg != null and oc._rounds._grant_seg.oc == oc, "V4 编排器接线·授予段(宿主回指)〔迭代27 T2〕")
Kit.check_quiet(oc._rounds._aura_seg != null and oc._rounds._aura_seg.oc == oc, "V4 编排器接线·增益/减益段〔迭代27 T2〕")
Kit.check_quiet(oc._rounds._combat_seg != null and oc._rounds._combat_seg.oc == oc, "V4 编排器接线·战斗段〔迭代27 T2〕")
Kit.check_quiet(oc._rounds._decay_seg != null and oc._rounds._decay_seg.oc == oc, "V4 编排器接线·衰减段〔迭代27 T2〕")
Kit.check_quiet(oc._rounds._verdict_seg != null and oc._rounds._verdict_seg.oc == oc, "V4 编排器接线·判定段〔迭代27 T2〕")
Kit.check_quiet(oc._rounds._grant_seg != null and oc._rounds._grant_seg.facts == oc._facts, "V4 编排器接线·授予段(束注入同一性·facts)〔迭代27 T2〕")
Kit.check_quiet(oc._rounds._aura_seg != null and oc._rounds._aura_seg.emit_composition_cb.get_object() == oc, "V4 编排器接线·增益/减益段(回调对象同一性)〔迭代27 T2〕")
Kit.check_quiet(oc._rounds._combat_seg != null and oc._rounds._combat_seg.fx_host == oc.fx_host(), "V4 编排器接线·战斗段(束注入同一性·fx_host)〔迭代27 T2〕")
Kit.check_quiet(oc._rounds._decay_seg != null and oc._rounds._decay_seg.status_effects == oc._status_effects, "V4 编排器接线·衰减段(束注入同一性·status_effects)〔迭代27 T2〕")
Kit.check_quiet(oc._rounds._verdict_seg != null and oc._rounds._verdict_seg.units == oc._enemy_system, "V4 编排器接线·判定段(束注入同一性·units)〔迭代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()