iter51-卡2
This commit is contained in:
1 parent
1cd6e2b1b0
commit
372b4fdc31
27 files changed
+1231
-356
No files matched your search
@@ -208,6 +208,7 @@ func _suites() -> Array:
|
||||
{"path": "res://tests/unit/battle_settlement/damage_controller_test.gd", "expect": 0},
|
||||
{"path": "res://tests/unit/battle_settlement/effect_port_test.gd", "expect": 0}, # 效果端口件(效果端口与掷格分件批 V1–V3——端口单实例/业务类零引擎直连源码锚/事实面闭集两对照)
|
||||
{"path": "res://tests/unit/battle_settlement/roll_multiplier_test.gd", "expect": 0}, # 掷点与乘区宿主(敌攻击类型轴/护甲掷点行为面/乘区接线/伤害类型克制与标错/fresh 池攻击链——批 B 自 smoke_all 迁入)
|
||||
{"path": "res://tests/unit/battle_settlement/settlement_wiring_snapshot_test.gd", "expect": 0}, # 结算接线同种子逐项 golden 对拍主证〔封装5.1〕(架构审查 5.1 封装修复——段类束注入改造零行为变更基线)
|
||||
{"path": "res://tests/unit/battle_settlement/seal_polarity_test.gd", "expect": 0}, # 封印与极性宿主(末点 AP 封印/封印不可逆四情况/清图奖励双份与弱形式/刷新 provenance 守卫/极性路由与封印溢价/负向字典/格面资源资格——批 B 自 smoke_all 迁入)
|
||||
{"path": "res://tests/unit/battle_settlement/round_flow_skill_pool_test.gd", "expect": 0}, # 轮内流与技能池宿主(全战斗回放/轮内刷新与 V5 快照单源/遭遇区间骰/结算五段全序/技能池数据面·回放独立·EV 锚·死亡打断·校验拒绝/妨害附加/四桶计数——批 B 自 smoke_all 迁入)
|
||||
{"path": "res://tests/unit/battle_settlement/refresh_feats_test.gd", "expect": 0}, # 换图系专长七件宿主(迭代 46 卡A——基座产 RAP 与折价同源/成功事实恰一次/全局受伤四路径恰一次/石层缓冲/崩壁延迟/蓄力周转/坑道小憩/矿道红利 GP/七件数据与牌库/无专长基线;原经卡片申报走 02 关联档选跑,卡片退役后补登记由 02 全套件承接)
|
||||
@@ -225,7 +226,8 @@ func _suites() -> Array:
|
||||
{"path": "res://tests/unit/core/tree_requires_level_test.gd", "expect": 0}, # R1 requires_level 等级阈值前置(schema 四拒一过+判定三态+投影两态)
|
||||
{"path": "res://tests/unit/core/pool_case_d_test.gd", "expect": 0}, # 池结构案D 行为(V6 令牌三态/V7 曝光槽 2+1 回退/V8 概率上限解耦提前退役)
|
||||
{"path": "res://tests/unit/core/feat_vouchers_test.gd", "expect": 0}, # 凭证五件+留任二件(V9 路由逐件/F-1 存量账/V10 留任路由+AP 属性轴)
|
||||
{"path": "res://tests/unit/core/settle_segments_test.gd", "expect": 0}, # 结算五段 Segment(V4:直接 new/编排器接线/真实一轮走段序)
|
||||
{"path": "res://tests/unit/core/settle_segments_test.gd", "expect": 0}, # 结算五段 Segment(V4:束构造/编排器接线/真实一轮走段序)
|
||||
{"path": "res://tests/unit/core/encapsulation_sweep_test.gd", "expect": 0}, # 五处结构性零命中扫描〔封装5.1 V2–V7〕(架构审查 5.1 封装修复——七段对编排器零引用/五方法零残留/断点存档公开面/效果累积面/配置挂载面,非空前置+正锚)
|
||||
{"path": "res://tests/unit/core/save_slot_isolation_test.gd", "expect": 0}, # 卡① 三槽位间隔离/进档失败恢复/宿主链引用同一(sv1/sv5/sv9/sv10)
|
||||
{"path": "res://tests/unit/core/save_boot_no_activate_test.gd", "expect": 0}, # 卡① 启动态类级契约:无激活态/拒写盘面零触碰/越界拒绝(sv2/sv3)
|
||||
{"path": "res://tests/unit/core/save_slot_summary_test.gd", "expect": 0}, # 卡① 摘要三项按槽窥视:异值/空槽/坏槽三态/零副作用(sv7/sv8)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
Reference in new issue
Block a user