test(迁移): 批 B 波 1 G4 套1 敌方攻击类型轴四条迁入 roll_multiplier_test.gd——新宿主落位+manifest 登记+剪切挂载绿+按条变异 4/4 验红(表列越轨/快照清空连带载荷矩阵/载荷置空/矩阵查表短路各验红);smoke_all.gd 同批删函数节头与调用行;闸01 剩余面 1015 绿

This commit is contained in:
DKChan committed 2026-10-23 02:52:55 +08:00
1 parent 5f190bc354
commit fdb77ffeea
4 files changed
+101 -62

No files matched your search

+1
View File
@@ -59,6 +59,7 @@ func _suites() -> Array:
{"path": "res://tests/unit/presentation/forge_workbench_test.gd", "expect": 0}, # 工作间两区六路线 UI 直验(V13 自动化前置面)
{"path": "res://tests/unit/battle_settlement/damage_math_test.gd", "expect": 0},
{"path": "res://tests/unit/battle_settlement/damage_controller_test.gd", "expect": 0},
{"path": "res://tests/unit/battle_settlement/roll_multiplier_test.gd", "expect": 0}, # 掷点与乘区宿主(敌攻击类型轴/护甲掷点行为面/乘区接线/伤害类型克制与标错/fresh 池攻击链——批 B 自 smoke_all 迁入)
{"path": "res://tests/unit/battle_settlement/skill_unlock_test.gd", "expect": 0}, # Boss 半血解锁技·容器机制(门谓词/闩不可逆/双面过滤/保底不逼锁定/零扰动)
{"path": "res://tests/unit/contracts/system_contracts_test.gd", "expect": 0},
{"path": "res://tests/unit/presentation/ui_font_asset_test.gd", "expect": 0},
@@ -0,0 +1,93 @@
# tests/unit/battle_settlement/roll_multiplier_test.gd — 掷点与乘区单元测试宿主
# 断言面 = 五套(批 B 断言迁移自 smoke_all.gd,G4 施工组;五套按源编排序分五笔原子提交迁入):
# 敌方攻击类型轴(表列全 normal / spawn 快照注入 / 单据载荷第 9 参 / 克制矩阵命中证词 ±1 位移)
# 护甲等级掷点·行为面(查档纯函数分布 / EV 锚 / nat20 暴击 / 削弱续时 / AC11 逐拍判定 / 伤害下限 / 棋盘来源必中)
# 主角乘区接线 + 硬化折半方向(×1.5 / ×0.75 / ×0.5——池乘区通道)
# 攻击类型 × 护甲克制 + 标错惩罚(护甲快照 / 克制矩阵表值 / 标错负向与标中正向兑付 / 同种子回放)
# 战斗结算 fresh 池攻击链回归(Bug#2——池空时按掷点档位足额兑现)
# 协议照单元侧惯例:extends SceneTree+Kit.check 主通道;--script 模式无 autoload,
# ConfigDB 显式实例化构造注入(各套自建 RngService——源套掷点隔离形态,宿主不持统一流);
# 表加载失败不中止(沿被迁断言面的源语义——诊断在此展开,表值变异的红由具体断言落,承 G2/G3 同款)。
# 运行:godot --headless --path game --script res://tests/unit/battle_settlement/roll_multiplier_test.gd
extends SceneTree
const Kit := preload("res://tests/unit/test_kit.gd")
const ConfigDBScript := preload("res://core/config_db.gd")
var _db
func _init() -> void:
_db = ConfigDBScript.new()
# 表加载失败不中止(承 G2/G3 同款:表损坏的红落在具体断言上——
# 诊断在此展开,后续断言按坏表实况逐条验红;collect_only=true 下成员照常赋值可评)
var load_ok: bool = _db.load_tables("res://data/tables", true)
if not load_ok:
push_error("[roll_multiplier_test] 表加载返回失败——诊断如下(红由具体断言落)")
for d in _db.diagnostics():
if d.severity == "error" or d.severity == "fatal":
push_error(" [%s] %s: %s" % [d.severity, d.category, d.message])
# 套执行序沿源编排序
_smoke_enemy_attack_type()
quit(Kit.finish("roll_multiplier_test"))
# ---- 敌方攻击类型轴(表列/单位快照/单据载荷/矩阵命中证词)----
# 克制矩阵命中证词 = 同种子三甲型配对实测(不是查表存在性证词):同种子下 armor_roll 流消费逐位一致、
# 阈值(hero armor_class)不变,三甲型唯一差异 = 克制点数 cdelta(normal_vs_light 0 / heavy −1 / ward +1)
# → heavy 伤害 == light −1、ward == light +1(要求基线伤害 ≥ 2——地板 1 会吞 −1 位移)。
# 承伤位移红线(卡片 §8 L3):全局位移只允许 ±1 量级——非此量级 = 矩阵消费面有未盘点的第二落点(停机)。
func _smoke_enemy_attack_type() -> void:
print("--- 敌方攻击类型轴(迭代 24 N3)---")
# ① 表列:20 行全填 normal(N3 全填不做差异化——Q9)
var at_ok := true
var at_detail := ""
for row in _db.enemy.rows:
var at := String(row.get("attack_type", ""))
if at != "normal":
at_ok = false
at_detail += " %s:%s" % [String(row.get("enemy_id", "?")), at]
Kit.check("敌方 %d 行 attack_type 全填 normal(迭代 24 N3 轴开列,越轨行%s)" % [
_db.enemy.rows.size(), at_detail if at_detail != "" else "无"], at_ok)
# ②③④ 矩阵命中证词扫描:(3,0) 灰矮人 atk 区间 [2,4] 基线足够((1,2) 熊地精 atk 1 会塌地板);
# 同 seed 三甲型各开一场、各取首个敌方伤害行,对拍 ±1。
var matrix_found := false
var snap_ok := true
var payload_at := ""
var t_light := -1
var t_heavy := -1
var t_ward := -1
for seed_offset in range(40):
var totals := {}
for armor in ["light", "heavy", "ward"]:
var rng = load("res://core/rng_service.gd").new()
rng.set_master_seed(20261013 + seed_offset)
var settlement = load("res://core/battle_orchestrator.gd").new(_db, rng)
var rows: Array = []
settlement.step_row.connect(func(row): rows.append(row))
if not settlement.begin_battle({"level_index": 3, "node_depth": 0, "hero_hp": int(_db.hero.max_hp), "armor_type": armor}):
totals[armor] = -1
continue
if armor == "light":
for u in settlement._enemy_system.all_enemies():
if String(u.get("attack_type", "")) == "":
snap_ok = false
settlement.minesweeper.settle_batch([{"action": "stop"}])
for row in rows:
if String(row.get("type", "")) == "damage" and String(row.get("source_class", "")) == "enemy_action":
totals[armor] = int(row.get("value", 0))
if armor == "light":
payload_at = String(row.get("attack_type", "")) # 载荷摊平在行顶层(_emit_row 摊平 extra)
break
if not totals.has(armor):
totals[armor] = -1
if int(totals.get("light", -1)) >= 2 and int(totals.get("heavy", -1)) >= 1 and int(totals.get("ward", -1)) >= 1:
t_light = int(totals["light"])
t_heavy = int(totals["heavy"])
t_ward = int(totals["ward"])
matrix_found = (t_heavy == t_light - 1 and t_ward == t_light + 1)
break
Kit.check("敌方单位快照 attack_type 非空(spawn 注入面——迭代 24 N3)", snap_ok)
Kit.check("克制矩阵命中证词:同种子三甲型实测 heavy %d == light %d − 1 · ward %d == light %d + 1(迭代 24 N3 全局平移 −1/0/+1)" % [
t_heavy, t_light, t_ward, t_light], matrix_found and t_light >= 2)
Kit.check("敌方伤害技单据载荷 attack_type 非空(= %s——第 9 参传值面,迭代 24 N3)" % payload_at, payload_at == "normal")